This morning I posted to the Math Forum about how an algebra student, armed with Python, might explore 'composition of functions' using operator overloading. Wrap ordinary function definitions in the Function class below, and you still have __call__ (to get range outputs from domain inputs), plus you have the ability to write h = f * g where f and g and Function objects, and h is a new function object such that h(x) == f(g(x)) for all x. An important aspect of algebra is polymorphism around * and + (multiplication and addition). These become known in terms of their field, ring and group properties, somewhat obscuring their origins in basic arithmetic. We multiply matrices and polynomials, quaternions and permutations. Python's operator overloading makes it easier to see what's going on: we're putting the definition of __mul__ under the programmer-mathematician's control One of the most primitive of all functions is the mapping of letters to letters, e.g. A->R, B->Q, C->C, D->Z... according to whatever random shuffle. The composition of P1 and P2 then becomes the result of mapping A to R per P2, then R to whatever per P1 (say Z), such that A->Z is the result of P1 * P2. The notions of inverse and identity mapping are well defined. Group properties may be explored (the beginning of abstract algebra). Notice that my algebraic functions below (a quadratic and a linear) need to have their inverses specified by the programmer, should it be that negative powering is likely to happen (for example). Some languages attempt to provide this automatically in simple cases, leaving it to the user to supply it otherwise (I'm thinking of J in particular). I'm not trying to be that fancy. Kirby Relevant post to math-teach: http://mathforum.org/kb/plaintext.jspa?messageID=3863728 #=====================================
def f(x): return x*x
def g(x): return 2*x + 3
class Function(object):
def __init__(self, f, invf = None): self.f = f self.invf = invf def __call__(self,x): return self.f(x) def __mul__(self, other): def newf(x): return self.f( other.f(x)) return Function( newf ) def __pow__(self, exp): if exp==1: return self newself = Function(self.f) if exp < 1: newself = Function(self.invf) for i in range(exp-1): newself *= self return newself #--- composition of function objects using __mul__
of = Function(f) og = Function(g) oh = of * og oh(10) 529 oj = og * of oj(10) 203
import math def invf(x): return math.sqrt(x)
#--- expanding to integer powers (including negative powers).
of = Function(f, invf) newf = of**(-1) h = newf * of h(10) 10.0 h(20) 20.0
# excerpt from class Function (see earlier in thread):
def __pow__(self, exp): if exp==1: return self newself = Function(self.f) if exp < 1: newself = Function(self.invf) for i in range(exp-1): newself *= self return newself
Note that my __pow__ definition fails to return the identify function (e.g. def e(x): return x) when the exponent is 0. f**0 should return e, where f is some Function object. Rather than fix my code right here and now, I'll leave it broken and point to this note as a cue to readers (and I'm one of those readers): feel free to add the missing functionality. Good habit in open source world: feel free to fix stuff that's broken. Sometimes the original coder just didn't need what you're adding, so it may be your job to put icing on the cake or whatever it is (hey, maybe the original coder didn't like icing). In the other hand, be aware that your fixing stuff may also break stuff, which is why in collaborative environments we like to have an audit trail and sometimes a way of rolling back repository commits, if only to establish a branch point along which to pursue some alternative (forked) development. We might call this a "schism" but often it's far friendlier than that: two promising stratagems suggest themselves and crews explore both possibilities -- no crime in that. Kirby PS: I useful title/chapter for guiding explorations of permutations, per a recommended connected topic at this point is: I.N. Herstein. Abstract Algebra. New York: Macmillan Publishing Company (c) 1986. ISBN 0-02-353820-1. See: Chapter 1, Sec. 4: A(S) (The Set of 1-1 Mappings of S Onto Itself).
participants (1)
-
Kirby Urner