""" precalc: module for helping kids grok calculus Last updated: Sept. 25, 2000 Thanks to David Scherer, Dustin Mitchell, and Jeff Cogswell for suggestions """ import povray, functions, string from coords import Vector from math import * from functions import mkdomain def wiggle(function,input,epsilon=1e-10): """Accepts a function, value and returns delta f / delta x for small epsilon (default of 10^-10 may be overridden) """ return (function(input+epsilon) - function(input))/epsilon def runtotal(function): """Accepts a function, returns (x, running total) pairs -- analogous to definite integral """ # initialize rtotal = 0 output = [] lastx,lasty = function[0] for x,y in function[1:]: avgy = (lasty + y)/2.0 # average f(x) avgx = (lastx + x)/2.0 # average x incre = x - lastx # domain increment rtotal = rtotal + (avgy * incre) output.append((avgx,rtotal)) lastx = x lasty = y return output def printit(myfunc): print " x f(x)" print " ----------------------" for i in myfunc: print " %+f %+f" % i def graphit(myfunc, myfile): # draws function xaxislen = max( abs(myfunc[0][0]),abs(myfunc[-1][0]) ) functions.xyzaxes(myfile,xaxislen) # draw edges between pairs of 3-tuples (x,y,z), z=0 for p1,p2 in zip(myfunc,myfunc[1:]): v1,v2 = (p1[:]+(0,)),(p2[:]+(0,)) myfile.edge(Vector(v1),Vector(v2)) # draw edge between the two def wiggle1(): dom = mkdomain(-pi,pi,0.1) # note step by 0.1 rng = [wiggle(sin,x) for x in dom] func = zip(dom,rng) sine = zip(dom,[sin(x) for x in dom]) # sine function drawfile = povray.Povray("wiggle1.pov",cf=15,cx=0,cy=0) graphit(func,drawfile) # accepts list of [(dom,rng)] pairs drawfile.cylcolor = "Red" drawfile.sphcolor = "Red" graphit(sine,drawfile) drawfile.close() def G(x): return sin(x**2) def derivG(x): return 2*cos(x**2)*x def linear(x): return 2*x def wiggle2(): dom = mkdomain(-pi,pi,0.1) # note step by 0.1 funcG = zip(dom,[G(x) for x in dom]) wiggleG = zip(dom,[wiggle(G,x) for x in dom]) drawfile = povray.Povray("wiggle2.pov",cf=38,cx=0,cy=0) # [3] graphit(wiggleG,drawfile) # accepts list of [(dom,rng)] pairs drawfile.cylcolor = "Red" drawfile.sphcolor = "Red" graphit(funcG,drawfile) drawfile.close() def wiggle3(): dom = mkdomain(-pi,pi,0.1) # note step by 0.1 derivfuncG = zip(dom,[derivG(x) for x in dom]) drawfile = povray.Povray("wiggle3.pov",cf=38,cx=0,cy=0) # [3] graphit(derivfuncG,drawfile) # accepts list of [(dom,rng)] pairs drawfile.close() def accumulate1(): dom = mkdomain(-2,2,0.1) f = zip(dom,[linear(x) for x in dom]) intf = runtotal(f) drawfile = povray.Povray("int1.pov",cf=15,cx=0,cy=0) # [3] graphit(intf,drawfile) drawfile.cylcolor = "Red" drawfile.sphcolor = "Red" graphit(f,drawfile) drawfile.close() def accumulate2(): dom = mkdomain(-pi,pi,0.1) # note step by 0.1 derivfuncG = zip(dom,[derivG(x) for x in dom]) integral = runtotal(derivfuncG) drawfile = povray.Povray("int2.pov",cf=38,cx=0,cy=0) # [3] graphit(integral,drawfile) drawfile.cylcolor = "Red" drawfile.sphcolor = "Red" graphit(derivfuncG,drawfile) drawfile.close() def accumulate3(): dom = mkdomain(-pi,pi,0.1) # note step by 0.1 sine = zip(dom,[sin(x) for x in dom]) # sine function integral = runtotal(sine) drawfile = povray.Povray("int3.pov",cf=15,cx=0,cy=0) # [3] graphit(integral,drawfile) drawfile.cylcolor = "Red" drawfile.sphcolor = "Red" graphit(sine,drawfile) drawfile.close() def wiggle4(): dom = mkdomain(-3,1.2,0.1) # note step by 0.1 rng = [wiggle(exp,x) for x in dom] deriv = zip(dom,rng) expf = zip(dom,[exp(x) for x in dom]) # exponential function drawfile = povray.Povray("wiggle4.pov",cf=15,cx=0,cy=0) graphit(deriv,drawfile) # accepts list of [(dom,rng)] pairs drawfile.cylcolor = "Red" drawfile.sphcolor = "Red" graphit(expf,drawfile) drawfile.close() def accumulate4(): dom = mkdomain(-3,1.2,0.1) # note step by 0.1 expf = zip(dom,[exp(x) for x in dom]) # e**x integral = runtotal(expf) drawfile = povray.Povray("int4.pov",cf=15,cx=0,cy=0) # [3] graphit(integral,drawfile) drawfile.cylcolor = "Red" drawfile.sphcolor = "Red" graphit(expf,drawfile) drawfile.close() class camera: """ Accepts algebraic rule as text string in terms of variable x e.g. '2*x**2 - 3*x + 10' -- evaluates f(x) and/or f'(x) over the supplied domain (defined by low, high and step values) """ def __init__(self,txtRule,low=-1,high=1,interval = 0.125, epsilon=1e-10): self.interval = 0.125 # turn text rule into a function self.rule = eval("lambda x : %s" % txtRule) self.dom = mkdomain(low,high,interval) def gety(self,x): # return f(x) return self.rule(x) def getrange(self): # evaluate rule over entire domain return [self.gety(x) for x in self.dom] def getderiv(self,x): # return approximate derivate for given x return wiggle(self.gety,x) def getfunction(self): return zip(self.dom,self.getrange()) def getmovie(self): # return approximate derivative over entire domain return zip(self.dom,[self.getderiv(x) for x in self.dom])