[Edu-sig] Python 2.0 and teaching precalculus

Kirby Urner urner@alumni.Princeton.EDU
Sun, 10 Sep 2000 02:01:59 -0700


Keywords:  Python 2.0, cli, precalc, discrete math, graphing, domain, 
range, function, povray, derivative, epsilon, ocn

Originally posted to: edu-sig@python.org (list), comp.lang.python (news)
Cross-posted to:      calc-reform (list, Swarthmore Math Forum) 
             
Web anchor:  http://www.inetarena.com/~pdx4d/ocn/precalc.html

The newest Python (2.0 in beta) has some useful constructs for 
those of you using CLI for teaching precalc/calc.[1]

For example, zip() will compose (domain,range) pairs from separate 
lists [x1,x2..] [f(x1), f(x2)..]...

 >>> dom = [-3,-2,-1,0,1,2,3]
 >>> rng = [x*x for x in dom]  # see note below
 >>> rng
 [9, 4, 1, 0, 1, 4, 9]
 >>> func = zip(dom,rng)
 >>> func
 [(-3, 9), (-2, 4), (-1, 1), (0, 0), (1, 1), (2, 4), (3, 9)]

Note:  this [f(x) for x in list] "list comprehension" construct 
is also new with 2.0.

Of course [-3,-2,-1,0,1,2,3] could be generated using the built-in 
range function:

 >>> dom = range(-3,3,1)

Be careful not to use key term 'range' as your output list name, 
as you'll obscure the built-in range() with your variable and 
get an error message next time you try the built-in.  Like this:

 >>> range = [x*x for x in dom]
 >>> range
 [9, 4, 1, 0, 1, 4, 9]
 >>> range(-10,10,1)
 Traceback (innermost last):
   File "<pyshell#27>", line 1, in ?
     range(-10,10,1)
 TypeError: call of non-function (type list)

Uh oh.  Now you've gotta go:
 
 >>> del range 

to erase your variable and get the built-in back.

Given range() only works with integers, my precalc.py module 
uses a longer mkdomain() function.  See source code.[2]

In precalc classes, one obvious use of these functions is to
build a discrete math analog of the derivative using definite
epsilon.  Let's call this function wiggle() in that we're
"wiggling" a variable x to compute [f(x+epsilon)-f(x)]/epsilon

Here's wiggle():

def wiggle(function,input,epsilon=1e-10):
    """
    Accepts a function, value and returns delta f / delta x
    for small epsilon (default of 1^-10 may be overridden)
    """    
    return (function(input+epsilon) - function(input))/epsilon

Let's go to trig and run wiggle on the sine function, for a 
domain -pi <= x <= pi.

 >>> from precalc import *
 >>> dom = mkdomain(-math.pi,math.pi,0.1)  # note step by 0.1
 >>> rng = [wiggle(math.sin,x) for x in dom]
 >>> func = zip(dom,rng)
 >>> sine = zip(dom,[math.sin(x) for x in dom]) # sine function

So func now contains wiggled-sine values, which we can graph and 
compare with the graph of cosine x.

Lets graph the sine and func (domain,range) pairs.  My graphit() 
function is a "connect the dots" type, i.e. assume continuity 
and fills in spaces between vertices.  This gives us the smooth
curves students are used to seeing in text books.

 >>> import povray
 >>> drawfile = povray.Povray("wiggle1.pov",cf=15,cx=0,cy=0) # [3]
 >>> graphit(func,drawfile)   # accepts list of [(dom,rng)] pairs
 >>> drawfile.cylcolor = "Red"
 >>> drawfile.sphcolor = "Red"
 >>> graphit(sine,drawfile) 
 >>> drawfile.close()

The output graph is of both the original sine wave, and the wiggle 
function (a discrete math analog of the derivative).  See 

See Graph 1 at:  http://www.inetarena.com/~pdx4d/ocn/precalc.html

Let's do one more example:  f(x) = sin(x^2) x:-pi<=x<=pi

 >>> def G(x): return math.sin(x**2)  # ** = Python's exponentiator

 >>> 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=35,cx=0,cy=0) 
 >>> graphit(wiggleG,drawfile)   # accepts list of [(dom,rng)] pairs
 >>> drawfile.cylcolor = "Red"
 >>> drawfile.sphcolor = "Red"
 >>> graphit(funcG,drawfile) 
 >>> drawfile.close()

See Graph 2.

If you've learned to differentiate composite functions, you know
that the derivative of f(g(x)) = f'(g(x))*g'(x).  In this case,
that'd be 2*cos(x**2)*x.  Lets plot this function and compare 
with wiggleG above:

 >>> def derivG(x): return 2*math.cos(x**2)*x

 >>> derivfuncG = zip(dom,[derivG(x) for x in dom]) 
 >>> drawfile = povray.Povray("wiggle3.pov",cf=35,cx=0,cy=0) 
 >>> graphit(derivfuncG,drawfile)   # accepts list of [(dom,rng)] pairs
 >>> drawfile.close()

See Graph 3.

Clearly this looks like the same function.  Note that this 
roller coaster function provides a good opportunity to discuss 
local minima and maxima, to show how the derivative crosses 
the x axis whenever slope = 0, is positive when original 
function is rising, negative when falling, and so forth.

In sum, using the compact syntax of Python 2.0, you can make use of 
the CLI to facilitate comprehension of the derivative concept.  With 
some tweaking of the above code, your functions could become 
multi-variable, setting the stage for multivariable calculus later 
on.

Kirby Urner
Curriculum writer
Oregon Curriculum Network
http://www.inetarena.com/~pdx4d/ocn/

[1] 2.0b is a free download from here:
    http://www.pythonlabs.com/tech/python2.0/index.html
    CLI = "command line interface"

[2] http://www.inetarena.com/~pdx4d/ocn/python/precalc.html
    For code minus extraneous HTML tags:
    http://www.inetarena.com/~pdx4d/ocn/python/precalc.py
    Also see catenary.html (& .py), which uses much of the 
    same functionality.

[3] parameters and source for these additional graphing 
    functions are described in my 'Numeracy + Computer  
    Literacy' series starting at 
    http://www.inetarena.com/~pdx4d/ocn/numeracy0.html
    You also need Povray at www.povray.org
    Many other solutions for creating graphs with Python 
    have been developed, so don't feel overly tied to my
    Povray approach

--------------------------------------------------------------
         Cool Math Site of the Week:  
         'Synergetics on the Web' via
         http://west.camel.math.ca/Kabol/
--------------------------------------------------------------