[Edu-sig] Overcoming the prejudice...

Kirby Urner pdx4d@teleport.com
Tue, 09 Jan 2001 17:11:27 -0800


                      WE SHALL OVERCOME:=20
        REGARDING THE USE OF A VERY HIGH LEVEL LANGUAGE
          IN THE PRE-COLLEGE MATHEMATICS CLASSROOM

                        by Kirby Urner
                  Oregon Curriculum Network
                       January 9, 2001


Table of Contents:

Overcoming a Prejudice
The Case of APL
Python as a "Math Language"
Case Study: SIGMA Notation
Operating on Operators
The Advantage of Immediate Feedback
Case Study: PI Notation
Advanced Topics for Further Exploration
A Final Word on Prejudice

   First posted to edu-sig@python.org listserv, with=20
   a copy to math-teach@forum.mathforum.com (expect a=20
   web version with typos fixed at the Oregon Curriculum=20
   Network website: http://www.inetarena.com/~pdx4d/ocn/ )

=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

OVERCOMING A PREJUDICE

Yes, I think it's mostly just a prejudice that math teachers=20
have against mixing programming languages with their "pure"=20
math language. =20

They're still thinking back to the days of punch card FORTRAN=20
(some of them), or basing their conclusions on trying to program=20
a TI -- neither experience being that great a basis upon which=20
to judge what it'd be like to use a VHLL (very high level=20
language) like Python in the math classroom.

THE CASE OF APL

I don't know how much exposure Guido had to APL (A Programming=20
Language) before coming up with Python, but in my own case,
APL was the first real computer language I ever learned=20
(not counting programming my friend's dad's HP-65 calculator
when in high school).  In those days, most programming really
was still with punch cards, and APL was one of the few=20
languages offering an "environment" -- a place to interact
with the language at a command line, in a "you type, computer
responds" session.  All around campus, including in my dorm,
were these "APL terminals" connected directly to the=20
IBM 370 at the computer center.  Instead of normal keyboards,
they had these weird greek-looking squiggles for upper case
options.  These were the APL symbols.

APL originally evolved as a chalkboard notation.  It could
easily "pass" for a math notation, because that's exactly=20
was it was, to start.  Kenneth Iverson wanted a math notation
that could be implemented directly in an interpreted=20
environment.  A single operator, like i (squiggly-looking
i) would output a list of values, like i(6) meant (gave
you) [0,1,2,3,4,5] -- or something like that (I forget if
6 was included, or if the values really had commas in=20
between, or just spaces -- doesn't matter right now).

Using APL notation, you could express rather involved=20
mathematical operations in a single line, just as you can
with regular "pure" math typography.  APL, like text book
math notation, is highly "crypto-compressed".  Perhaps too
crypto-compressed -- which is one reason why it failed to
take the programming world by storm (I think Princeton had
all those APL terminals around campus because some anticipated
that it might -- this is 1976-77, and APL seemed like the wave
of the future).

PYTHON AS "MATH LANGUAGE"

Python is, in a lot of ways, a lot like APL.  Instead of
i(6), you write range(6).  The greek-looking symbols have
been replaced with old fashioned English-type words.  But
you can still build with them, like Leggos [TM], to make
rather complex expressions.  The basic built-in functions
and operators fit together in all kinds of interesting=20
ways; the language is highly "orthogonal" as computer=20
scientists like to put it.

So what I think about Python is that it's really another
math language, like APL was/is -- not "just" a programming
language.  By this I mean, it's human-readable, a way to
capture math concepts and algorithms in a communicative=20
format, just as math typography is.  A VHLL like Python=20
isn't just about "talking to machines", it's about "talking
to other humans" (_and_ its machine-executable -- as are=20
conventional math typographies these days, in packages=20
such as MathCad).=20

And so if you're having some trouble getting what's going=20
on using the conventional math typography, then here's=20
Python, executable, interactive, and likewise fairly concise,=20
giving you a second chance, an alternative approach, a=20
different way of saying the same thing.  I think for a=20
lot of students, it's the introduction of an alternative=20
entr=E9 that will make math come alive.  It's like being able
to "see in stereo" all of a sudden, because now you have=20
two images, each from a slightly different angle.  This=20
can make a world of difference.

SIGMA NOTATION

Consider sigma notation: a capital greek Sigma (somewhat
alien-looking to students, as we don't teach Greek anymore=20
in most curricula, the "classical education" template having
been long ago abandoned in large degree), followed by some=20
expression with indexing in it (some i, or j, to be=20
successively replaced with successive integer values, starting=20
and stopping according to what's written at the bottom and=20
top of the Sigma sign. =20

And so we write (using ascii SIGMA in place of the greek symbol):

          n
        SIGMA (A[i])^2
         i=3D0

...except that would be "A sub i" -- the i as a superscript,
indicating we're accessing some sequence of values labeled A.
This is a specific SIGMA expression, and involves raising=20
successive terms to the 2nd power, and summing them ("to=20
sigma" is "to sum").

But the above expression is not something you can "do" yet.
We don't know what n is, nor what the sequence A looks like.
So to actually generate a value corresponding to the above=20
expression, you have to define both n and A.  These then=20
become your "parameters", are the variables relative to=20
which the above expression makes sense.

Now consider the same concept using Python:

        def sigma(A,n):
           sum =3D 0
           for i in range(n+1):
              sum =3D sum + A[i]**2
           return sum

So far, this is as general as the SIGMA version, as we haven't
defined either A or n.  Translation involves understanding the
range() function -- outputs a list up to _but not including_=20
the single argument (2 or 3 argument forms an option -- see=20
below).  So we say range(n+1), i.e range(3) -> [0, 1, 2].

So let's consider A to be a sequence of numbers:

       A[0] =3D 1, A[1] =3D 3  A[3] =3D 5  A[4] =3D 7...

Looks like the odd numbers.  OK, A =3D odd numbers.  Now we just=20
have to decide how many of them we want.  Let's say n =3D 10.

          n
        SIGMA (A[i])^2 where n=3D10, and A[0]=3D1, A[i] =3D 2i+1
         i=3D0

        Result:  1771

Now in Python (>>> is the prompt, where the user types, with=20
lines flush to the left being what the computer answers):

  >>> A =3D range(1,100,2)
  >>> A
  [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29,=20
  31, 33, 35, 37, 39, 41, 43,   45, 47, 49, 51, 53, 55, 57,=20
  59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85,=20
  87, 89, 91, 93, 95, 97, 99]

... another use of range(), from 1, to 100 -- not including 100)=20
-- step by 2.

  >>> sigma(A,n)
  1771

OPERATING ON OPERATORS

Notice that we expressed the set of odd numbers using a rule,
in the SIGMA example.  A[i] =3D 2i + 1.  That's interesting, as=20
it suggests turning A into a function of i.

  >>> def A(i):  return 2*i + 1

  >>> A(10)
  21

Let's rewrite the sigma function to accept a _function_ as a=20
parameter.  This is starting to get interesting, because any higher=20
math teacher will tell you that students often have conceptual
difficulty trying to look at functions as _objects_ of other=20
operators.  Yet that's what we're going to do:

        def sigma(A,n):
           sum =3D 0
           for i in range(n+1):
              sum =3D sum + A(i)**2
           return sum

Notice the subtle difference:  'A' is coming in as a function, and
A(i) is derived by working the function using 'i' as input.

Interactively now:

  >>> sigma(A,10)
  1771

Now write another function named B for the even numbers:

  >>> def B(i):  return 2*i

  >>> sigma(B,10)
  1540

Remember, our specific sigma expression (above) is summing the=20
_2nd powers_ of the terms generated by A(i) or B(i).  Since=20
this isn't really what SIGMA means by itself, generically, it=20
makes more sense to define SIGMA as simply the sum of whatever=20
terms. =20

We can do this even more succinctly using orthongonal=20
"leggo language" constructs:

  >>> import operator
  >>> def SIGMA(f,n):
         return reduce(operator.add,map(f,range(n+1))

The use of f is specifically designed to have us think=20
'function'.  To map a function is to apply it to the=20
list that follows, i.e.=20

   map(f,[1,2,3,4,5]) =3D [f(1),f(2),f(3),f(4),f(5)]

To reduce with an operator is to go=20

   1 op (2 op (3 op (4 op 5)))=20

-- whatever op might be, in this case add (+).

So if we want to sum the squares of the first 10 odd=20
numbers, the burden of generating these terms should be=20
on f:

   >>> def f(x):  return (2*x + 1)**2

Then pass this as a parameter to sigma:

   >>> SIGMA(f,10)
   1771

Or change f to make it return the square of the ith even
number:

  >>> def f(x):  return pow(2*x,2)  # alternative powering notation

  >>> SIGMA(f,10)
  1540

So we now have a Python definition of sigma that's consistent
with the following, using more traditional typography:

          n
        SIGMA f(i)
         i=3D0

We're free to define our f however we like, and pass it to=20
SIGMA() as a parameter, i.e. SIGMA(f,n).

THE ADVANTAGE OF IMMEDIATE FEEDBACK

Now, in the above interactive session with Python, were we=20
somehow criss-crossing between two separate disciplines,=20
math and computer programming.  I suppose you could say so.
But from my point of view, the VHLL is acting very much like
a math notation, with the added advantage that it's interactive
and therefore gives instantaneous feedback.  You don't have
to wait for the teacher to correct your homework to know
whether you're doing the syntax properly.

Plus I think you've done something which more traditional
K-12 text books have a hard time communicating:  by writing
both sigma and f as functions, and passing f to sigma as=20
a parameter, you're better helping students form the generic=20
concept of an 'operator' -- operators which work on other
operators.

PI NOTATION

Last note:  It really makes sense, while you're developing a
notion of SIGMA, to develop the corresponding notion of PI
(capital greek letter -- not to be confused with lowercase
pi, which is about circles).  SIGMA is to PI as addition is
to multiplication.

Note that we're taking advantage of Python's case sensitivity=20
and capitalizing both SIGMA and PI, to help make the hyperlink=20
to the capital greek letter equivalents:

  >>> def SIGMA(f,n):
         return reduce(operator.add,map(f,range(n+1)))

  >>> def PI(f,n):
         return reduce(operator.mult,map(f,range(n+1)))

So now you want to product of the first 20 prime numbers?
Well, we need a function that outputs the ith prime. =20
I'm going to simply import something I wrote and saved=20
earlier for that purpose:

  >>> import primes
  >>> def getprime(i): =20
          """
          Return last term from first i primes in sequence
          """
          return primes.get2nb(i+1)[-1]

  >>> getprime(0)  # 0th prime is 1st in the list
  2
  >>> getprime(1)  # and so on...
  3
  >>> getprime(2)
  5
  >>> map(getprime,range(20))
  [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,=20
  59, 61, 67, 71] =20

  >>> PI(getprime,5)  # range(5) =3D [0,1,2,3,4]; 2 is 0th prime
  30030

That's 2*3*5*7*11*13 -- builds up quickly, so if you plan to go
a lot higher you'll want your getprime() to output "long integers". =20
Something to discuss in another lesson, e.g. when we start generating=20
primes of 100 digits or more:

  >>> primes.bigppr()
  Working...
  Percent chance of being prime: 99.9999999999
  Elapsed time: 4.75655894333 seconds
  372106324940930886970978581418419848613328680550192993614919012
  38607299599499654601573369854695139659L

The L on the end means "long integer" -- calculators usually
can't get into this territory at all, but in the math classroom
of the future, students will as a matter of routine (or so
I would hope).

ADVANCED TOPICS FOR FURTHER EXPLORATION

Because of the alternate meaning of + (add) with regard to=20
strings, we can limber up student minds a little by using
our sigma function a little differently:

   >>> def wordscan(i): return "CAT"[i]

   >>> sigma(wordscan,2)
   'CAT'

This may seem like a trivial "programming trick" and not very=20
"math oriented" but this is not the case.  What's true about=20
algebra systems is that whereas we might use the symbols + and
* for operations, we don't prejudice ourselves regarding=20
(a) what these might mean or (b) what kind of object they might
operate upon. =20

For example, in group theory, we define an operator and a set=20
of objects such that various rules are followed e.g. there's
an identity object such that:
 =20
   object.op(identity) --> object

and an inverse object.inv() for every object such that:

   object.op(object.inv()) --> identity

Note that I'm using object oriented notation to express math
concepts here.  It works, plus reinforces the syntax of the
Python language -- and most other OO languages as well.  For=20
a discussion of OO notation with regard to math concepts, see
my "OOP Meets Algebra, Suggesting New "Ways of Looking" at
http://www.inetarena.com/~pdx4d/ocn/oopalgebra.html

Because Python lets you override the meaning of + and * when
defining objects (as well as other operators), we're in an
ideal environment in which to explore SIGMA with respect to
different meanings of + (as in the case of 'CAT' above).

To take another example, consider vectors as objects under=20
consideration and define a function that returns a random=20
vector with integer coordinates between -10 and 10:

   >>> import random, coords  # coords.py is an OCN module
   >>> def randomvector(i):
	   x =3D random.randint(-10,10)
	   y =3D random.randint(-10,10)
	   z =3D random.randint(-10,10)
	   return coords.Vector((x,y,z))

   >>> randomvector(1)
   Vector (2.0, 3.0, -5.0)
   >>> randomvector(1)
   Vector (7.0, 4.0, 0.0)

So now we can apply sigma to a list of random vectors, without=20
changing the code in any way, and get a vector result:

   >>> sigma(randomvector,10)
   Vector (-23.0, 19.0, 18.0)

Even though sigma is defined around the concept of 'add' (uses=20
the 'add' operator), the meaning of 'add' is specific to the=20
algebra at hand.  In a vector algebra + means we add the vectors=20
to return a vector. =20

We can talk about the "closure" property here -- another=20
characteristic of groups is that ops with objects always get=20
you more objects of the same type.

A FINAL WORD ON PREJUDICE

We're going to see other objections from math purists against
using Python as an alternative math lingo.  A lot of people
will say it's confusing to have 0-based indexing, i.e. in many
math games, it's more the norm to start your subscripting with
1 and not 0. =20

It's possible to write around these conventions, to accommodate
them.  On the other hand, there's a limit as to how far we should=20
go to make allowances for this kind of rigidity, as there's=20
nothing about SIGMA per se, for example, which dictates that=20
indexing should start with 1 or 0.  A lot of these conventions
are "just cultural", and in some cases the "culture" has gotten
too inbred and closed-minded for its own good.

A far better approach than always bending over backwards to=20
conform to current conventions is to alert students to the fact=20
that these various different conventions (e.g. 0-based and 1-based=20
indexing) do in fact exist, including within mathematics itself=20
(nevermind about Python).  It's flexibility that we want to=20
foster, keeping minds limber, adaptable.

Teachers may argue that it's "confusing" to keep switching between=20
different sets of rules, doing things one way here, and another=20
way there -- but this is also the "real world" we're talking=20
about.  We want to keep up a level of complexity that mirrors=20
the kinds of challenges for which school is designed to help=20
students prepare.  Life is often complex and confusing -- best=20
to train for that then.

Math classes should _not_ just about teaching the math you need to=20
know to be a math teacher, as if the goal were to create some=20
hermetically sealed subcultural feedback loop that has nothing=20
whatever to do with math in the real world.  This "math through=20
programming" approach is designed to foster just such a "worldly=20
feel" to mathematics, because most students will be using math=20
in some way, shape or form "on the job" -- but without necessarily=20
themselves becoming "pure mathematicians".

This is not to say that an approach to learning mathematics which
includes one or more computer languages is in any way a "dumbed
down" approach, not suitable for would-be purists.  That's the
prejudice I'm trying to address. =20

On the contrary, I hope I've showed in this paper that a Pythonic=20
approach may stimulate thinking at an even _higher_ level of=20
abstraction than is normally achieved in K-12 today, in part=20
because of:

* the "operator override" feature (making + or * mean different=20
  things)

* the "operating on operators" feature (passing functions to=20
  other functions)=20

* the interactive, immediate feedback environment in general,=20
  which frees the student to concentrate on the problem even=20
  while relying on tools previously programmed and/or introduced=20
  in earlier lessons.

This is an exciting world we could be entering.  I would think=20
professional educators would be chomping at the bit to make this=20
world a reality for more students.

Certainly many students are anxious to learn how to use their=20
computers, which are becoming ever more powerful, affordable=20
and ubiquitous.  The mathematics classroom is a logical place to=20
see to it that this real student need is addressed, and in a=20
way consistent with the larger goals of an intelligently=20
designed, high quality math curriculum.

For further reading:
http://www.inetarena.com/~pdx4d/ocn/cp4e.html#python