[Edu-sig] Algebra + Python

Kirby Urner pdx4d@teleport.com
Sun, 6 May 2001 09:30:11 -0700


Getting Poly, Fraction and Matrix to interoperate has been fun.
I get into these operator precedence situations where two 
objects have different implementations of __mul__, so the 
__rmul__ of one triggers where what I want is the __mul__
of the other.  So I end up doing type checking to force the
result I want.

For example, Poly knows how to coerce a Fraction into becoming
a polynomial of degree 0, but Fraction shouldn't ever try to
change a polynomial into a Fraction.  So when it comes to 
a Fraction * a Poly, it's the Poly version of * that takes
precedence over the Fraction version -- but only because I
type check, e.g.

    def __mul__(self,n):
        if type(n).__name__=='instance':
            if n.__class__.__name__ == "Poly":
                print "Fraction -> Poly"
                return n.__mul__(self)
            if n.__class__.__name__ == "Matrix":
                print "Fraction -> Fraction"
                return n.__mul__(self)
        
        f = self.mkfract(n)
        return Fraction(self.numer*f.numer,
                        self.denom*f.denom)

Anyway, below is an example of a session at the command line:
  
  >>> C = Matrix([map(Fraction,[1,1,1]),
                  map(Fraction,[2,3,4]),
                  map(Fraction,[5,8,9])])
  >>> C
  [1, 1, 1]
  [2, 3, 4]
  [5, 8, 9]

  >>> C.inverse()
  [(5.0/2), (1.0/2), (-1.0/2)]
  [-1.0, -2.0, 1.0]
  [(-1.0/2), (3.0/2), (-1.0/2)]

  >>> A = Matrix([[Poly([1,-3],'t'),2],
                  [Fraction(1,2),Poly([1,-4],'t')]])
  >>> A
  [t - 3, 2]
  [(1/2), t - 4]

  >>> A.det()        # determinant of A
  x**2 - 7*x + 11


  >>> I = Matrix([[1,0,0],[0,1,0],[0,0,1]])  # identity matrix
  >>> t = Poly([1,0],'t')                    # t
  >>> t*I
  [t, 0, 0]
  [0, t, 0]
  [0, 0, t]

  >>> A = Matrix([[1,1,2],[0,3,2],[1,3,9]])
  >>> A
  [1, 1, 2]
  [0, 3, 2]
  [1, 3, 9]

  >>> (t*I-A).det()           # characteristic polynomial of A
  t**3 - 13*t**2 + 31*t - 17

  >>> p=(t*I-A).det()         # t = 10
  >>> p(10)
  -7

Note that polynomials now optionally permit some variable 
other than x.  However, you can't multiply two polynomials
with differing variables and expect their identities to 
stay separate.  Getting evaluation to work no matter the 
letter required a small modification to __call__ in 
polynomial.py.

I've stowed polynomial,pyfraction and simplematrix as a package
called mathobjects.  simplematrix is dependent on ciphers.py 
however, which was my last project, and which has to do with 
permutations in the context of group theory and cryptography.  

A simple way to compute the determinant is to add the signed 
products of all permutations of matrix elements, choosing one 
from each row (a total of row! possibilities).  ciphers.py is
in charge of returning a list of all those possibilities 
(breaks down when n is double-digit or higher -- but that's
OK, as this is throwaway code)).

Kirby