Index: sage/algebras/free_algebra.py
===================================================================
--- sage/algebras/free_algebra.py	(revision 1860)
+++ sage/algebras/free_algebra.py	(revision 4007)
@@ -13,4 +13,26 @@
     sage: G.base_ring()
     Free Algebra on 3 generators (x, y, z) over Integer Ring        
+
+TESTS:
+    sage: F = FreeAlgebra(GF(5),3,'x')
+    sage: F == loads(dumps(F))
+    True
+
+    sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
+    sage: F == loads(dumps(F))
+    True
+
+    sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'])
+    sage: F == loads(dumps(F))
+    True
+
+    sage: F = FreeAlgebra(GF(5),3, 'abc')
+    sage: F == loads(dumps(F))
+    True
+
+    sage: F = FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x')
+    sage: F == loads(dumps(F))
+    True
+
 """
 
@@ -198,5 +220,5 @@
             if P is self:
                 return x
-            if not (P == self.base_ring()):
+            if not (P is self.base_ring()):
                 return FreeAlgebraElement(self, x)
         # ok, not a free algebra element (or should not be viewed as one).
@@ -204,5 +226,5 @@
         R = self.base_ring()
         # coercion from free monoid
-        if isinstance(x, FreeMonoidElement) and x.parent() == F:
+        if isinstance(x, FreeMonoidElement) and x.parent() is F:
             return FreeAlgebraElement(self,{x:R(1)})
         # coercion via base ring
@@ -268,5 +290,5 @@
 
             # monoid
-            if R == self.__monoid:
+            if R is self.__monoid:
                 return self(x)
 
Index: sage/algebras/free_algebra_element.py
===================================================================
--- sage/algebras/free_algebra_element.py	(revision 1859)
+++ sage/algebras/free_algebra_element.py	(revision 4007)
@@ -3,4 +3,9 @@
 
 AUTHOR: David Kohel, 2005-09
+
+TESTS:
+    sage: R.<x,y> = FreeAlgebra(QQ,2)
+    sage: x == loads(dumps(x))
+    True
 """
 
@@ -44,5 +49,5 @@
             self.__monomial_coefficients = { x:R(1) }
         elif True:
-            self.__monomial_coefficients = x
+            self.__monomial_coefficients = dict([ (A.monoid()(e1),R(e2)) for e1,e2 in x.items()])
         else:
             raise TypeError, "Argument x (= %s) is of the wrong type."%x
Index: sage/algebras/free_algebra_quotient.py
===================================================================
--- sage/algebras/free_algebra_quotient.py	(revision 1840)
+++ sage/algebras/free_algebra_quotient.py	(revision 4149)
@@ -1,4 +1,19 @@
 """
 Free algebra quotients
+
+TESTS:
+    sage: n = 2
+    sage: A = FreeAlgebra(QQ,n,'x')
+    sage: F = A.monoid()
+    sage: i, j = F.gens()
+    sage: mons = [ F(1), i, j, i*j ]
+    sage: r = len(mons)
+    sage: M = MatrixSpace(QQ,r)
+    sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]) ]
+    sage: H2.<i,j> = A.quotient(mons,mats)
+    sage: H2 == loads(dumps(H2))
+    True
+    sage: i == loads(dumps(i))
+    True
 """
 
@@ -77,6 +92,6 @@
             raise TypeError, "Argument A must be an algebra."
         R = A.base_ring()
-        if not R.is_field():
-            raise TypeError, "Base ring of argument A must be a field."
+#        if not R.is_field():  # TODO: why?
+#            raise TypeError, "Base ring of argument A must be a field."
         n = A.ngens()
         assert n == len(mats)
@@ -89,4 +104,13 @@
         ParentWithGens.__init__(self, R, names, normalize=False)
 
+    def __eq__(self,right):
+        return type(self) == type(right) and \
+               self.ngens() == right.ngens() and \
+               self.rank() == right.rank() and \
+               self.module() == right.module() and \
+               self.matrix_action() == right.matrix_action() and \
+               self.monomial_basis() == right.monomial_basis()
+    
+
     def __call__(self, x):
         if isinstance(x, FreeAlgebraQuotientElement) and x.parent() is self: 
@@ -139,4 +163,10 @@
         return self.__dim
 
+    def matrix_action(self):
+        return self.__matrix_action
+
+    def monomial_basis(self):
+        return self.__monomial_basis
+
     def rank(self):
         """
Index: sage/algebras/free_algebra_quotient_element.py
===================================================================
--- sage/algebras/free_algebra_quotient_element.py	(revision 1855)
+++ sage/algebras/free_algebra_quotient_element.py	(revision 4149)
@@ -46,6 +46,11 @@
         if isinstance(x, FreeAlgebraQuotientElement) and x.parent() is A:
             return x
+
         AlgebraElement.__init__(self, A)
         Q = self.parent()
+
+        if isinstance(x, FreeAlgebraQuotientElement) and x.parent() == Q:
+            self.__vector = Q.module()(x.vector())
+            return
         if isinstance(x, (int, long, Integer)):
             self.__vector = Q.module().gen(0) * x
@@ -61,4 +66,5 @@
         F = A.monoid()
         B = A.monomial_basis()
+                
         if isinstance(x, (int, long, Integer)):
             self.__vector = x*M.gen(0)
@@ -89,6 +95,4 @@
             self.__vector = x.ambient_algebra_element().vector()
         else:
-            print "x =", x
-            print "type(x) =", type(x)
             raise TypeError, "Argument x (= %s) is of the wrong type."%x
                                         
@@ -104,7 +108,22 @@
             else:
                 return x
+                
+    def _latex_(self):
+        Q = self.parent()
+        M = Q.monoid()
+        with localvars(M, Q.variable_names()):
+            cffs = list(self.__vector)
+            mons = Q.monomial_basis()
+            x = repr_lincomb(mons, cffs, True).replace("*1 "," ")
+            if x[len(x)-2:] == "*1":
+                return x[:len(x)-2]
+            else:
+                return x
         
     def vector(self):
         return self.__vector
+
+    def __cmp__(self, right):
+        return cmp(self.vector(),right.vector())
 
     def __neg__(self):
@@ -141,18 +160,12 @@
             if c != 0: z.__vector += monomial_product(A,c*u,B[i])
         return z
-
-    def __pow__(self, n):
-        if not isinstance(n, (int, long, Integer)):
-            raise TypeError, "Argument n (= %s) must be an integer."%n
-        if n < 0: 
-            raise IndexError, "Argument n (= %s) must be positive."%n
-        elif n == 0:
-            return self.parent()(1)
-        elif n == 1:
-            return self
-        elif n == 2:
-            return self * self
-        k = n//2
-        return self**k * self**(n-k)
+        
+    def _rmul_(self, c):
+        return self.parent([c*a for a in self.__vector])
+        
+    def _lmul_(self, c):
+        return self.parent([a*c for a in self.__vector])
 
 
+
+
Index: sage/algebras/quaternion_algebra.py
===================================================================
--- sage/algebras/quaternion_algebra.py	(revision 3729)
+++ sage/algebras/quaternion_algebra.py	(revision 4069)
@@ -3,4 +3,13 @@
 
 AUTHOR: David Kohel, 2005-09
+
+TESTS:
+    sage: A = QuaternionAlgebra(QQ, -1,-1, names=list('ijk'))
+    sage: A == loads(dumps(A))
+    True
+    sage: i, j, k = A.gens()
+    sage: i == loads(dumps(i))
+    True
+
 """
 
@@ -111,5 +120,5 @@
 _cache = {}
 
-def QuaternionAlgebra(K, a, b, names, denom=1):
+def QuaternionAlgebra(K, a, b, names=['i','j','k'], denom=1):
     """
     Return the quaternion algebra over $K$ generated by $i$, $j$, and $k$
@@ -141,4 +150,16 @@
         raise ValueError, "Base ring K (= %s) must be a field."%K
 
+    if K(2) == 0:
+        raise ValueError, "Base ring K (= %s) must be a field of characteristic different from 2."%K
+
+    try: 
+        a = K(a)
+    except TypeError:
+        raise ValueError, "Arguments a = %s and b = %s must coerce into K (= %s)."%(a,b,K)
+    try: 
+        b = K(b)
+    except TypeError:
+        raise ValueError, "Arguments a = %s and b = %s must coerce into K (= %s)."%(a,b,K)
+
     if a == 0 or b == 0:
         raise ValueError, "Arguments a = %s and b = %s must be nonzero."%(a,b)
@@ -159,7 +180,7 @@
     if K is RationalField():
         prms = ramified_primes(a,b)
-        H = QuaternionAlgebra_generic(K, prms)
+        H = QuaternionAlgebra_generic(K, [2,0,0,0], prms)
     else:
-        H = QuaternionAlgebra_generic(K)
+        H = QuaternionAlgebra_generic(K, [2,0,0,0])
     A = FreeAlgebra(K,3, names=names)
     F = A.monoid()
@@ -222,5 +243,5 @@
     vki = V([ -t13, t3, 0, t1 ]) - vik
     vjk = V([ -t23, 0, t3, t2 ]) - vkj
-    H = QuaternionAlgebra_generic(K)
+    H = QuaternionAlgebra_generic(K, [2,t1,t2,t3])
     A = FreeAlgebra(K,3, names=names)
     F = A.monoid()
@@ -245,5 +266,5 @@
     return QuaternionAlgebraWithInnerProduct(K,norms,traces,names=names)
 
-def QuaternionAlgebraWithDiscriminants(D1, D2, T, names, M=2):
+def QuaternionAlgebraWithDiscriminants(D1, D2, T, names=['i','j','k'], M=2):
     r"""
     Return the quaternion algebra over the rationals generated by $i$,
@@ -306,8 +327,9 @@
     mj = MQ([0,0,1,0, 0,0,0,1, -n2,0,t2,0, 0,-n2,0,t2])
     # N.B. mk = mi*mj
-    mk = MQ([0,0,0,1, 0,0,-n1,t1,  -n2*t1,n2,t1*t2-t12,0, -n1*n2,0,0,t1*t2-t12])
+    t3 = t1*t2-t12
+    mk = MQ([0,0,0,1, 0,0,-n1,t1,  -n2*t1,n2,t3,0, -n1*n2,0,0,t3])
     mats = [ mi, mj, mk ] 
     prms = ramified_primes_from_discs(D1,D2,T)
-    H = QuaternionAlgebra_generic(QQ, prms)
+    H = QuaternionAlgebra_generic(QQ, [2,t1,t2,t3], prms)
     A = FreeAlgebra(QQ,3, names=names)
     F = A.monoid()
@@ -318,10 +340,11 @@
 class QuaternionAlgebra_generic(FreeAlgebraQuotient):
 
-    def __init__(self, K, ramified_primes=None):
-        """
-        """
-        self.__vector_space = VectorSpace(K,4)
+    def __init__(self, K, basis_traces = None, ramified_primes=None):
+        """
+        """
         if ramified_primes != None:
-            self.__ramified_primes = ramified_primes
+            self._ramified_primes = ramified_primes
+        if basis_traces != None:
+	    self._basis_traces = basis_traces
         
     def __call__(self, x):
@@ -357,21 +380,22 @@
 
     def gram_matrix(self):
-        V = self.__vector_space
-        if not V._FreeModule_generic__inner_product_is_dot_product:
-            return V.inner_product_matrix()
-        K = self.base_ring()
-        M = MatrixSpace(K,4)(0)
-        B = self.basis()
-        for i in range(4):
-            x = B[i]
-            M[i,i] = 2*(x.reduced_norm())
-            for j in range(i+1,4):
-                y = B[j]
-                c = (x * y.conjugate()).reduced_trace()
-                M[i,j] = c
-                M[j,i] = c
-        # TODO: Make it so one can correctly set these things.
-        V._FreeModule_generic__inner_product_is_dot_product = False
-        V._FreeModule_generic__inner_product_matrix = M
+        """
+	The Gram matrix of the inner product determined by the norm.
+        """
+        try: 
+            M = self.__vector_space.inner_product_matrix()
+        except:	
+            K = self.base_ring()
+            M = MatrixSpace(K,4)(0)
+            B = self.basis()
+            for i in range(4):
+	        x = B[i]
+                M[i,i] = 2*(x.reduced_norm())
+                for j in range(i+1,4):
+                    y = B[j]
+                    c = (x * y.conjugate()).reduced_trace()
+                    M[i,j] = c
+                    M[j,i] = c
+            self.__vector_space = VectorSpace(K,4,inner_product_matrix = M)
         return M
         
@@ -388,10 +412,7 @@
         return False
     
-    def _set_ramified_primes(self, prms):
-        self.__ramified_primes = prms
-
     def ramified_primes(self):
         try:
-            return self.__ramified_primes
+            return self._ramified_primes
         except:
             raise AttributeError, "Ramified primes have not been computed."
@@ -402,10 +423,10 @@
 
     def vector_space(self):
-        V = self.__vector_space
         try:
-            _ = V._FreeModule_generic__inner_product_matrix
+            V = self.__vector_space
         except:
-            V._FreeModule_generic__inner_product_matrix = self.gram_matrix()
-        return self.__vector_space
+            M = self.gram_matrix() # induces construction of V
+            V = self.__vector_space
+        return V
 
 
Index: sage/all.py
===================================================================
--- sage/all.py	(revision 3696)
+++ sage/all.py	(revision 4317)
@@ -71,5 +71,5 @@
 from sage.interfaces.all import *
 from sage.functions.all  import *
-#from sage.calculus.all   import *
+from sage.calculus.all   import *
 from sage.server.all     import *
 from sage.dsage.all      import *
@@ -114,5 +114,4 @@
 # very useful 2-letter shortcuts
 CC = ComplexField()
-I = CC.gen(0)
 QQ = RationalField()
 RR = RealField()  # default real field
@@ -136,5 +135,5 @@
 
 oo = infinity
-x = PolynomialRing(QQ,'x').gen()
+#x = PolynomialRing(QQ,'x').gen()
 
 # grab signal handling back from PARI or other C libraries
@@ -233,4 +232,22 @@
     from sage.interfaces.quit import expect_quitall
     expect_quitall(verbose=verbose)
+
+
+    # The following code close all open file descriptors,
+    # so that on shared file systems the delete_tmpfiles
+    # command below works.
+    # AUTHOR:
+    #    * Kate Minola (2007-05-03)
+    import resource             # Resource usage information.
+    maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
+    if maxfd != resource.RLIM_INFINITY:
+        # Iterate through and close all file descriptors.
+        for fd in range(0, maxfd):
+            try:
+                os.close(fd)
+            except OSError:  # ERROR, fd wasn't open to begin with (ignored)
+                pass
+
+    # Now delete the temp files
     from sage.misc.misc import delete_tmpfiles
     delete_tmpfiles()
Index: sage/calculus/all.py
===================================================================
--- sage/calculus/all.py	(revision 2327)
+++ sage/calculus/all.py	(revision 4308)
@@ -1,7 +1,78 @@
-from calculus import (SER,
-                      var,
-                      sin, cos, sec,
-                      x, y, z, w, t)
+from equations import SymbolicEquation, forget, assume, assumptions, solve
+
+from calculus import (SymbolicExpressionRing,
+                      is_SymbolicExpressionRing,
+                      is_SymbolicExpression,
+                      CallableSymbolicExpressionRing,
+                      is_CallableSymbolicExpressionRing,
+                      is_CallableSymbolicExpression,
+                      SR,
+                      sin, cos, sec, tan, log, erf, sqrt, asin, acos, atan,
+                      tanh, sinh, cosh, coth, sech, csch, ln,
+                      ceil, floor,
+                      polylog,
+                      abs_symbolic, exp,
+                      is_SymbolicExpression,
+                      is_SymbolicExpressionRing)
 
 
-from functional import diff
+from functional import (diff, derivative,
+                        laplace, inverse_laplace,
+                        expand,
+                        integrate, limit, lim,
+                        taylor, simplify)
+
+from var import (var, function)
+
+from predefined import (a,
+                      b,
+                      c,
+                      d,
+                      f,
+                      g,
+                      h,
+                      j,
+                      k,
+                      l,
+                      m,
+                      n,
+                      o,
+                      p,
+                      q,
+                      r,
+                      s,
+                      t,
+                      u,
+                      v,
+                      w,
+                      x,
+                      y,
+                      z,
+                      A,
+                      B,
+                      C,
+                      D,
+                      E,
+                      F,
+                      G,
+                      H,
+                      J,
+                      K,
+                      L,
+                      M,
+                      N,
+                      P,
+                      Q,
+                      R,
+                      S,
+                      T,
+                      U,
+                      V,
+                      W,
+                      X,
+                      Y,
+                      Z)
+
+def symbolic_expression(x):
+    return SR(x)
+
Index: sage/calculus/calculus.py
===================================================================
--- sage/calculus/calculus.py	(revision 2630)
+++ sage/calculus/calculus.py	(revision 4313)
@@ -1,9 +1,200 @@
-"""nodoctest"""
+r"""
+Symbolic Computation.
+
+AUTHORS:
+    Bobby Moretti and William Stein: 2006--2007
+
+The \sage calculus module is loosely based on the \sage Enhahcement Proposal
+found at: http://www.sagemath.org:9001/CalculusSEP.
+
+EXAMPLES:
+
+    The basic units of the calculus package are symbolic expressions
+    which are elements of the symbolic expression ring (SR). There are
+    many subclasses of SymbolicExpression. The most basic of these is
+    the formal indeterminate class, SymbolicVariable. To create a
+    SymbolicVariable object in \sage, use the var() method, whose
+    argument is the text of that variable.  Note that \sage is
+    intelligent about {\LaTeX}ing variable names.
+
+        sage: x1 = var('x1'); x1
+        x1
+        sage: latex(x1)
+        x_{1}
+        sage: theta = var('theta'); theta
+        theta
+        sage: latex(theta)
+        \theta
+
+    \sage predefines upper and lowercase letters as global
+    indeterminates. Thus the following works:
+        sage: x^2
+        x^2
+        sage: type(x)
+        <class 'sage.calculus.calculus.SymbolicVariable'>
+
+    More complicated expressions in SAGE can be built up using
+    ordinary arithmetic. The following are valid, and follow the rules
+    of Python arithmetic: (The '=' operator represents assignment, and
+    not equality)
+        sage: f = x + y + z/(2*sin(y*z/55))
+        sage: g = f^f; g
+        (z/(2*sin(y*z/55)) + y + x)^(z/(2*sin(y*z/55)) + y + x)
+
+    Differentiation and integration are available, but behind the
+    scenes through maxima:
+
+        sage: f = sin(x)/cos(2*y)
+        sage: f.derivative(y)
+        2*sin(x)*sin(2*y)/(cos(2*y)^2)
+        sage: g = f.integral(x); g
+        -cos(x)/(cos(2*y))
+
+    Note that these methods require an explicit variable name. If none
+    is given, \sage will try to find one for you.
+        sage: f = sin(x); f.derivative()
+        cos(x)
+
+    However when this is ambiguous, \sage will raise an exception:
+        sage: f = sin(x+y); f.derivative()
+        Traceback (most recent call last):
+        ...
+        ValueError: must supply an explicit variable for an expression containing more than one variable
+
+    Substitution works similarly. We can substitute with a python dict:
+        sage: f = sin(x*y - z)
+        sage: f({x: t, y: z})
+        sin(t*z - z)
+    
+    Also we can substitute with keywords:
+        sage: f = sin(x*y - z)
+        sage: f(x = t, y = z)
+        sin(t*z - z)
+
+    If there is no ambiguity of variable names, we don't have to specify them:
+        sage: f = sin(x)
+        sage: f(y)
+        sin(y)
+        sage: f(pi)
+        0
+
+    However if there is ambiguity, we must explicitly state what
+    variables we're substituting for:
+    
+        sage: f = sin(2*pi*x/y)
+        sage: f(4)
+        sin(8*pi/y)
+
+    We can also make CallableSymbolicExpressions, which is a SymbolicExpression
+    that are functions of variables in a fixed order. Each
+    SymbolicExpression has a function() method used to create a
+    CallableSymbolicExpression.
+    
+        sage: u = log((2-x)/(y+5))
+        sage: f = u.function(x, y); f
+        (x, y) |--> log((2 - x)/(y + 5))
+
+    There is an easier way of creating a CallableSymbolicExpression, which
+    relies on the \sage preparser.
+    
+        sage: f(x,y) = log(x)*cos(y); f
+        (x, y) |--> log(x)*cos(y)
+
+    Then we have fixed an order of variables and there is no ambiguity
+    substituting or evaluating:
+    
+        sage: f(x,y) = log((2-x)/(y+5))
+        sage: f(7,t)
+        log(-5/(t + 5))
+
+    Some further examples:
+    
+        sage: f = 5*sin(x)
+        sage: f
+        5*sin(x)
+        sage: f(2)
+        5*sin(2)
+        sage: f(pi)
+        0
+        sage: float(f(pi))             # random low order bits
+        6.1232339957367663e-16
+
+COERCION EXAMPLES:
+
+We coerce various symbolic expressions into the complex numbers:
+
+    sage: CC(I)
+    1.00000000000000*I
+    sage: CC(2*I)
+    2.00000000000000*I
+    sage: ComplexField(200)(2*I)
+    2.0000000000000000000000000000000000000000000000000000000000*I
+    sage: ComplexField(200)(sin(I))
+    1.1752011936438014568823818505956008151557179813340958702296*I
+    sage: f = sin(I) + cos(I/2); f
+    I*sinh(1) + cosh(1/2)
+    sage: CC(f)
+    1.12762596520638 + 1.17520119364380*I
+    sage: ComplexField(200)(f)
+    1.1276259652063807852262251614026720125478471180986674836290 + 1.1752011936438014568823818505956008151557179813340958702296*I
+    sage: ComplexField(100)(f)
+    1.1276259652063807852262251614 + 1.1752011936438014568823818506*I
+
+We illustrate construction of an inverse sum where each denominator
+has a new variable name:
+    sage: f = sum(1/var('n%s'%i)^i for i in range(10))
+    sage: print f
+                 1     1     1     1     1     1     1     1    1
+                --- + --- + --- + --- + --- + --- + --- + --- + -- + 1
+                  9     8     7     6     5     4     3     2   n1
+                n9    n8    n7    n6    n5    n4    n3    n2
+                
+Note that after calling var, the variables are immediately available for use:
+    sage: (n1 + n2)^5
+    (n2 + n1)^5
+
+We can, of course, substitute:
+    sage: print f(n9=9,n7=n6)
+            1     1     1     1     1     1     1    1    387420490
+           --- + --- + --- + --- + --- + --- + --- + -- + ---------
+             8     6     7     5     4     3     2   n1   387420489
+           n8    n6    n6    n5    n4    n3    n2
+
+TESTS:
+We test pickling:
+    sage: f = -sqrt(pi)*(x^3 + sin(x/cos(y)))
+    sage: bool(loads(dumps(f)) == f)
+    True
+
+Substitution:
+    sage: f = x
+    sage: f(x=5)
+    5
+
+The symbolic Calculus package uses its own copy of Maxima for
+simplification, etc., which is separate from the default system-wide
+version:
+    sage: maxima.eval('[x,y]: [1,2]')
+    '[1,2]'
+    sage: maxima.eval('expand((x+y)^3)')
+    '27'
+
+If the copy of maxima used by the symbolic calculus package were
+the same as the default one, then the following would return 27,
+which would be very confusing indeed!
+    sage: expand((x+y)^3)
+    y^3 + 3*x*y^2 + 3*x^2*y + x^3
+"""
+
+import weakref
 
 from sage.rings.all import (CommutativeRing, RealField, is_Polynomial,
+                            is_MPolynomial, is_MPolynomialRing,
                             is_RealNumber, is_ComplexNumber, RR,
-                            Integer, Rational, CC)
-#import sage.rings.rational
-from sage.structure.element import RingElement
+                            Integer, Rational, CC,
+                            QuadDoubleElement,
+                            PolynomialRing, ComplexField)
+
+from sage.structure.element import RingElement, is_Element
 from sage.structure.parent_base import ParentWithBase
 
@@ -13,16 +204,69 @@
 
 from sage.interfaces.maxima import MaximaElement, Maxima
-from sage.interfaces.all import maxima
+
+# The calculus package uses its own copy of maxima, which is
+# separate from the default system-wide version.
+maxima = Maxima()
 
 from sage.misc.sage_eval import sage_eval
 
-from sage.functions.constants import Constant
-import sage.functions.constants as c
-
-# There will only ever be one instance of this class
+from sage.calculus.equations import SymbolicEquation
+from sage.rings.real_mpfr import RealNumber
+from sage.rings.complex_number import ComplexNumber
+from sage.rings.real_double import RealDoubleElement
+from sage.rings.complex_double import ComplexDoubleElement
+from sage.rings.real_mpfi import RealIntervalFieldElement
+from sage.rings.infinity import InfinityElement
+
+from sage.libs.pari.gen import pari, PariError, gen as PariGen
+
+from sage.rings.complex_double import ComplexDoubleElement
+
+import sage.functions.constants
+
+import math
+
+is_simplified = False
+
+infixops = {operator.add: '+',
+            operator.sub: '-', 
+            operator.mul: '*',
+            operator.div: '/',
+            operator.pow: '^'}
+
+
+def is_SymbolicExpression(x):
+    """
+    EXAMPLES:
+        sage: is_SymbolicExpression(sin(x))
+        True
+        sage: is_SymbolicExpression(2/3)
+        False
+        sage: is_SymbolicExpression(sqrt(2))
+        True
+    """
+    return isinstance(x, SymbolicExpression)
+
+def is_SymbolicExpressionRing(x):
+    """
+    EXAMPLES:
+        sage: is_SymbolicExpressionRing(QQ)
+        False
+        sage: is_SymbolicExpressionRing(SR)
+        True
+    """
+    return isinstance(x, SymbolicExpressionRing_class)
+
+
 class SymbolicExpressionRing_class(CommutativeRing):
-    '''
-    A Ring of formal expressions.
-    '''
+    """
+    The ring of all formal symbolic expressions.
+
+    EXAMPLES:
+        sage: SR
+        Symbolic Ring
+        sage: type(SR)
+        <class 'sage.calculus.calculus.SymbolicExpressionRing_class'>
+    """
     def __init__(self):
         self._default_precision = 53 # default precision bits
@@ -30,8 +274,32 @@
 
     def __call__(self, x):
+        """
+        Coerce x into the symbolic expression ring SR.
+        
+        EXAMPLES:
+            sage: a = SR(-3/4); a
+            -3/4
+            sage: type(a)
+            <class 'sage.calculus.calculus.SymbolicConstant'>
+            sage: a.parent()
+            Symbolic Ring
+
+        If a is already in the symblic expression ring, coercing returns
+        a itself (not a copy):
+            sage: SR(a) is a
+            True
+
+        A Python complex number:
+            sage: SR(complex(2,-3))
+            2.00000000000000 - 3.00000000000000*I
+        """
+        if is_Element(x) and x.parent() is self:
+            return x
+        elif hasattr(x, '_symbolic_'):
+            return x._symbolic_(self)
         return self._coerce_impl(x)
 
     def _coerce_impl(self, x):
-        if isinstance(x, CallableFunction):
+        if isinstance(x, CallableSymbolicExpression):
             return x._expr
         elif isinstance(x, SymbolicExpression):
@@ -39,16 +307,34 @@
         elif isinstance(x, MaximaElement):
             return symbolic_expression_from_maxima_element(x)
-        elif is_Polynomial(x):
+        elif is_Polynomial(x) or is_MPolynomial(x):
             return SymbolicPolynomial(x)
-        elif isinstance(x, Integer):
-            return Constant_object(x)
+        elif isinstance(x, (RealNumber, 
+                            RealDoubleElement,
+                            RealIntervalFieldElement,
+                            float,
+                            sage.functions.constants.Constant,
+                            Integer,
+                            int,
+                            Rational,
+                            PariGen,
+                            ComplexNumber,
+                            ComplexDoubleElement,
+                            QuadDoubleElement,
+                            InfinityElement
+                            )):
+            return SymbolicConstant(x)
+        elif isinstance(x, complex):
+            return evaled_symbolic_expression_from_maxima_string('%s+%%i*%s'%(x.real,x.imag))
         else:
-            return Symbolic_object(x)
+            raise TypeError, "cannot coerce type '%s' into a SymbolicExpression."%type(x)
 
     def _repr_(self):
-        return  "Ring of Symbolic Expressions"
+        return 'Symbolic Ring'
 
     def _latex_(self):
-        return "SymbolicExpressionRing"
+        return 'SymbolicExpressionRing'
+
+    def var(self, x):
+        return var(x)
 
     def characteristic(self):
@@ -61,88 +347,409 @@
         return True
 
-# ... and here it is:
-SymbolicExpressionRing = SymbolicExpressionRing_class()
-SER = SymbolicExpressionRing
-# conversions is the dict of the form system:command
+    def is_exact(self):
+        return False
+
+# Define the unique symbolic expression ring.
+SR = SymbolicExpressionRing_class()
+
+# The factory function that returns the unique SR.
+def SymbolicExpressionRing():
+    """
+    Return the symbolic expression ring.
+    
+    EXAMPLES:
+        sage: SymbolicExpressionRing()
+        Symbolic Ring
+        sage: SymbolicExpressionRing() is SR
+        True
+    """
+    return SR
 
 class SymbolicExpression(RingElement):
     """
-    A Symbolic Expression.
-    """
-    def __init__(self, conversions={}):
-        RingElement.__init__(self, SymbolicExpressionRing)
-
-    def _maxima_(self, maxima=maxima):
+    A Symbolic Expression. 
+
+    EXAMPLES:
+        Some types of SymbolicExpressions:
+
+        sage: a = SR(2+2); a
+        4
+        sage: type(a)
+        <class 'sage.calculus.calculus.SymbolicConstant'>
+    
+    """
+    def __init__(self):
+        RingElement.__init__(self, SR)
+        if is_simplified:
+            self._simp = self
+
+    def __hash__(self):
+        return hash(self._repr_(simplify=False))
+
+    def __nonzero__(self):
         try:
-            return self.__maxima
+            return self.__nonzero
         except AttributeError:
-            m = maxima(self._maxima_init_())
-            self.__maxima = m
-            return m
+            ans = not bool(self == SR.zero_element())
+            self.__nonzero = ans
+        return ans
+
+    def __str__(self):
+        """
+        Printing an object explicitly gives ASCII art:
+
+        EXAMPLES:
+            sage: f = y^2/(y+1)^3 + x/(x-1)^3
+            sage: f
+            y^2/(y + 1)^3 + x/(x - 1)^3
+            sage: print f
+                                              2
+                                             y          x
+                                          -------- + --------
+                                                 3          3
+                                          (y + 1)    (x - 1)
+        
+        """
+        return self.display2d(onscreen=False)
+
+    def show(self):
+        from sage.misc.functional import _do_show
+        return _do_show(self)
+
+    def display2d(self, onscreen=True):
+        """
+        Display self using ASCII art.
+
+        INPUT:
+            onscreen -- string (optional, default True) If True,
+                displays; if False, returns string.
+
+        EXAMPLES:
+        We display a fraction:
+            sage: f = (x^3+y)/(x+3*y^2+1); f
+            (y + x^3)/(3*y^2 + x + 1)
+            sage: print f
+                                                     3
+                                                y + x
+                                             ------------
+                                                2
+                                             3 y  + x + 1
+
+        Use onscreen=False to get the 2d string:
+             sage: f.display2d(onscreen=False)
+             '\t\t\t\t\t 3\r\n\t\t\t\t    y + x\r\n         \t\t\t ------------\r\n\t\t\t\t    2\r\n\t\t\t\t 3 y  + x + 1'
+
+        ASCII art is really helps for the following integral:
+            sage: f = integral(sin(x^2)); f
+            sqrt(pi)*((sqrt(2)*I + sqrt(2))*erf((sqrt(2)*I + sqrt(2))*x/2) + (sqrt(2)*I - sqrt(2))*erf((sqrt(2)*I - sqrt(2))*x/2))/8
+            sage: print f
+                                                         (sqrt(2)  I + sqrt(2)) x
+                   sqrt( pi) ((sqrt(2)  I + sqrt(2)) erf(------------------------)
+                                                                    2
+                                                               (sqrt(2)  I - sqrt(2)) x
+                                  + (sqrt(2)  I - sqrt(2)) erf(------------------------))/8
+                                                                          2
+        """
+        if not self.is_simplified():
+            self = self.simplify()
+        s = self._maxima_().display2d(onscreen=False)
+        s = s.replace('%pi',' pi').replace('%i',' I').replace('%e', ' e')
+        if onscreen:
+            print s
+        else:
+            return s
+    
+    def is_simplified(self):
+        return hasattr(self, '_simp') and self._simp is self
+
+    def _declare_simplified(self):
+        self._simp = self
+
+    def hash(self):
+        return hash(self._repr_(simplify=False))
+
+    def plot(self, *args, **kwds):
+        from sage.plot.plot import plot
+
+        # see if the user passed a variable in.
+        if kwds.has_key('param'):
+            param = kwds['param']
+        else:
+            param = None
+            for i in range(len(args)):
+                if isinstance(args[i], SymbolicVariable):
+                    param = args[i]
+                    args = args[:i] + args[i+1:]
+                    break
+
+        F = self.simplify()
+        if isinstance(F, Symbolic_object):
+            if hasattr(F._obj, '__call__'):
+                f = lambda x: F._obj(x)
+            else:
+                y = float(F._obj)
+                f = lambda x: y
+        
+        elif param is None:
+            if isinstance(self, CallableSymbolicExpression):
+                A = self.arguments()
+                if len(A) == 0:
+                    raise ValueError, "function has no input arguments"
+                else:
+                    param = A[0]
+                f = lambda x: self(x)
+            else:
+                A = self.variables()
+                if len(A) == 0:
+                    y = float(self)
+                    f = lambda x: y
+                else:
+                    param = A[0]
+                f = self.function(param)
+        else:
+            f = self.function(param)
+        return plot(f, *args, **kwds)
+
+    def __lt__(self, right):
+        return SymbolicEquation(self, SR(right), operator.lt)
+
+    def __le__(self, right):
+        return SymbolicEquation(self, SR(right), operator.le)
+
+    def __eq__(self, right):
+        return SymbolicEquation(self, SR(right), operator.eq)
+
+    def __ne__(self, right):
+        return SymbolicEquation(self, SR(right), operator.ne)
+
+    def __ge__(self, right):
+        return SymbolicEquation(self, SR(right), operator.ge)
+
+    def __gt__(self, right):
+        return SymbolicEquation(self, SR(right), operator.gt)
+
+    def __cmp__(self, right):
+        """
+        Compares self and right.
+
+        This is by definition the comparison of the underlying Maxima
+        objects.
+
+        EXAMPLES:
+        These two are equal:
+            sage: cmp(e+e, e*2)
+            0
+        """
+        return cmp(maxima(self), maxima(right))
 
     def _neg_(self):
+        """
+        Return the formal negative of self.
+
+        EXAMPLES:
+            sage: -a
+            -a
+            sage: -(x+y)
+            -y - x
+        """
         return SymbolicArithmetic([self], operator.neg)
 
-    def __cmp__(self, right):
-        return cmp(maxima(self), maxima(right))
+    ##################################################################
+    # Coercions to interfaces
+    ##################################################################
+    # The maxima one is special:
+    def _maxima_(self, session=None):
+        if session is None:
+            return RingElement._maxima_(self, maxima)
+        else:
+            return RingElement._maxima_(self, session)
         
+    def _maxima_init_(self):
+        return self._repr_(simplify=False)
+
+
+    # The others all go through _sys_init_, which is defined below,
+    # and does all interfaces in a unified manner.
+    
+    def _axiom_init_(self):
+        return self._sys_init_('axiom')
+
+    def _gp_init_(self):
+        return self._sys_init_('pari')   # yes, gp goes through pari
+
+    def _maple_init_(self):
+        return self._sys_init_('maple')
+
+    def _magma_init_(self):
+        return '"%s"'%self.str()
+
+    def _kash_init_(self):
+        return self._sys_init_('kash')
+
+    def _macaulay2_init_(self):
+        return self._sys_init_('macaulay2')
+
+    def _mathematica_init_(self):
+        return self._sys_init_('mathematica')
+
+    def _octave_init_(self):
+        return self._sys_init_('octave')
+
+    def _pari_init_(self):
+        return self._sys_init_('pari')
+
+    def _sys_init_(self, system):
+        return repr(self)
+
+    ##################################################################
+    # These systems have no symbolic or numerical capabilities at all,
+    # really, so we always just coerce to a string
+    ##################################################################
+    def _gap_init_(self):
+        """
+        Conversion of symbolic object to GAP always results in a GAP string.
+        
+        EXAMPLES:
+            sage: gap(e+pi^2 + x^3)
+            "x^3 + pi^2 + e"
+        """
+        return '"%s"'%repr(self)
+
+    def _singular_init_(self):
+        """
+        Conversion of symbolic object to Singular always results in a Singular string.
+        
+        EXAMPLES:
+            sage: singular(e+pi^2 + x^3)
+            x^3 + pi^2 + e
+        """
+        return '"%s"'%repr(self)
+
+    ##################################################################
+    # Non-canonical coercions to compiled built-in rings and fields
+    ##################################################################
+    def __int__(self):
+        """
+        EXAMPLES:
+            sage: int(sin(2)*100)
+            90
+        """
+        try:
+            return int(repr(self))
+        except (ValueError, TypeError):
+            return int(float(self))
+
+    def __long__(self):
+        """
+        EXAMPLES:
+            sage: long(sin(2)*100)
+            90L
+        """
+        return long(int(self))
+
+    
+    def _mpfr_(self, field):
+        raise TypeError
+
+    def _complex_mpfr_field_(self, field):
+        raise TypeError
+
+    def _complex_double_(self, C):
+        raise TypeError
+
+    def _real_double_(self, R):
+        raise TypeError
+
+    def _real_rqdf_(self, R):
+        raise TypeError
+
+    def _rational_(self):
+        return Rational(repr(self))
+
+    def __abs__(self):
+        return abs_symbolic(self)
+    
+    def _integer_(self):
+        """
+        EXAMPLES:
+        
+        """
+        return Integer(repr(self))
+    
     def _add_(self, right):
-        # if we are adding a negation, instead subtract the operand of negation
-        #if isinstance(right, SymbolicArithmetic):
-        #    if right._operator is operator.neg:
-        #        return SymbolicArithmetic([self, right._operands[0]], operator.sub)
-        #elif isinstance(right, Symbolic_object) and right < 0:
-        #    return SymbolicArithmetic([self, SER(abs(right._obj))], operator.sub)
-        #else:
-            return SymbolicArithmetic([self, right], operator.add)
+        """
+        EXAMPLES:
+            sage: x + y
+            y + x
+            sage: x._add_(y)
+            y + x
+        """
+        return SymbolicArithmetic([self, right], operator.add)
 
     def _sub_(self, right):
+        """
+        EXAMPLES:
+            sage: x - y
+            x - y
+        """
         return SymbolicArithmetic([self, right], operator.sub)
 
     def _mul_(self, right):
-        # do some simplification... pull out negatives from the operands and put it
-        # in front of this multiplication
-        #if isinstance(self, SymbolicArithmetic) and isinstance(right, SymbolicArithmetic):
-        #    if self._operator is operator.neg and right._operator is operator.neg:
-        #        s_unneg = self._operands[0]
-        #        r_unneg = right._operands[0]
-        #        return SymbolicArithmetic([s_unneg, r_unneg], operator.mul)
-        #if isinstance(self, SymbolicArithmetic):
-        #    if self._operator is operator.neg and (not isinstance(right, SymbolicArithmetic) \
-        #    or not (right._operator is operator.neg)):
-        #        s_unneg = self._operands[0]
-        #        return -SymbolicArithmetic([s_unneg, right], operator.mul)
-        #if isinstance(right, SymbolicArithmetic):
-        #    if not isinstance(self, SymbolicArithmetic) or (not (self._operator is operator.neg)) \
-        #    and right._operator is operator.neg:
-        #        r_unneg = right._operands[0]
-        #        return -SymbolicArithmetic([self, r_unneg], operator.mul)
-            
+        """
+        EXAMPLES:
+            sage: x * y
+            x*y
+        """
         return SymbolicArithmetic([self, right], operator.mul)
 
     def _div_(self, right):
-        # do some simplification... pull out negatives from the operands and put it
-        # in front of this division
-        #if isinstance(self, SymbolicArithmetic) and isinstance(right, SymbolicArithmetic):
-        #    if self._operator is operator.neg and right._operator is operator.neg:
-        #        s_unneg = self._operands[0]
-        #        r_unneg = right._operands[0]
-        #        return SymbolicArithmetic([s_unneg, r_unneg], operator.div)
-        #elif isinstance(self, SymbolicArithmetic):
-        #    if self._operator is operator.neg and (not isinstance(right, SymbolicArithmetic) \
-        #    or not (right._operator is operator.neg)):
-        #        s_unneg = self._operands[0]
-        #        return -SymbolicArithmetic([s_unneg, right], operator.div)
-        #elif isinstance(right, SymbolicArithmetic):
-        #    if not isinstance(self, SymbolicArithmetic) or (not (self._operator is operator.neg)) \
-        #    and right._operator is operator.neg:
-        #        r_unneg = right._operands[0]
-        #        return -SymbolicArithmetic([self, r_unneg], operator.div)
-
+        """
+        EXAMPLES:
+            sage: x / y
+            x/y
+        """
         return SymbolicArithmetic([self, right], operator.div)
 
     def __pow__(self, right):
+        """
+        EXAMPLES:
+            sage: x^(n+1)
+            x^(n + 1)
+        """
         right = self.parent()(right)
         return SymbolicArithmetic([self, right], operator.pow)
+
+    def variables(self, vars=tuple([])):
+        """
+        Return sorted list of variables that occur in the simplified
+        form of self.
+
+        OUTPUT:
+            a Python set
+            
+        EXAMPLES:
+            sage: f = x^(n+1) + sin(pi/19); f
+            x^(n + 1) + sin(pi/19)
+            sage: f.variables()
+            (n, x)
+            
+            sage: a = e^x
+            sage: a.variables()
+            (x,)            
+        """
+        return vars
+
+    def _first_variable(self):
+        try:
+            return self.__first_variable
+        except AttributeError:
+            pass
+        v = self.variables()
+        if len(v) == 0:
+            ans = var('x')
+        else:
+            ans = v[0]
+        self.__first_variable = ans
+        return ans
 
     def _has_op(self, operator):
@@ -186,11 +793,166 @@
 
 
-    def __call__(self, **kwds):
-        return self.substitute(**kwds)
+    def __call__(self, dict=None, **kwds):
+        return self.substitute(dict, **kwds)
+
+    def power_series(self, base_ring):
+        """
+        Return algebraic power series associated to this symbolic
+        expression, which must be a polynomial in one variable, with
+        coefficients coercible to the base ring.
+        
+        The power series is truncated one more than the degree.
+
+        EXAMPLES:
+            sage: var('theta')
+            theta
+            sage: f = theta^3 + (1/3)*theta - 17/3
+            sage: g = f.power_series(QQ); g
+            -17/3 + 1/3*theta + theta^3 + O(theta^4)
+            sage: g^3
+            -4913/27 + 289/9*theta - 17/9*theta^2 + 2602/27*theta^3 + O(theta^4)
+            sage: g.parent()
+            Power Series Ring in theta over Rational Field
+        """
+        v = self.variables()
+        if len(v) != 1:
+            raise ValueError, "self must be a polynomial in one variable but it is in the variables %s"%tuple([v])
+        f = self.polynomial(base_ring)
+        from sage.rings.all import PowerSeriesRing
+        R = PowerSeriesRing(base_ring, names=f.parent().variable_names())
+        return R(f, f.degree()+1)
+
+    def polynomial(self, base_ring):
+        r"""
+        Return self as an algebraic polynomial over the given base ring, if
+        possible.
+
+        The point of this function is that it converts purely symbolic
+        polynomials into optimized algebraic polynomials over a given
+        base ring.
+
+        WARNING: This is different from \code{self.poly(x)} which is used
+        to rewrite self as a polynomial in x.
+
+        INPUT:
+           base_ring -- a ring
+
+        EXAMPLES:
+            sage: f = x^2 -2/3*x + 1
+            sage: f.polynomial(QQ)
+            x^2 - 2/3*x + 1
+            sage: f.polynomial(GF(19))
+            x^2 + 12*x + 1
+
+            sage: f = x^2*e + x + pi/e
+            sage: f.polynomial(RDF)
+            2.71828182846*x^2 + 1.0*x + 1.15572734979
+            sage: g = f.polynomial(RR); g
+            2.71828182845905*x^2 + 1.00000000000000*x + 1.15572734979092
+            sage: g.parent()
+            Univariate Polynomial Ring in x over Real Field with 53 bits of precision            
+            sage: f.polynomial(RealField(100))
+            2.7182818284590452353602874714*x^2 + 1.0000000000000000000000000000*x + 1.1557273497909217179100931833
+            sage: f.polynomial(CDF)
+            2.71828182846*x^2 + 1.0*x + 1.15572734979
+            sage: f.polynomial(CC)
+            2.71828182845905*x^2 + 1.00000000000000*x + 1.15572734979092
+
+        We coerce a multivariate polynomial with complex symbolic coefficients:
+            sage: f = pi^3*x - y^2*e - I; f
+            -1*e*y^2 + pi^3*x - I
+            sage: f.polynomial(CDF)
+            -1.0*I + (-2.71828182846)*y^2 + 31.0062766803*x
+            sage: f.polynomial(CC)
+            -1.00000000000000*I + (-2.71828182845905)*y^2 + 31.0062766802998*x
+            sage: f.polynomial(ComplexField(70))
+            -1.0000000000000000000*I + (-2.7182818284590452354)*y^2 + 31.006276680299820175*x
+
+        Another polynomial:
+            sage: f = sum((e*I)^n*x^n for n in range(5)); f
+            e^4*x^4 - e^3*I*x^3 - e^2*x^2 + e*I*x + 1
+            sage: f.polynomial(CDF)
+            54.5981500331*x^4 + (-20.0855369232*I)*x^3 + (-7.38905609893)*x^2 + 2.71828182846*I*x + 1.0
+            sage: f.polynomial(CC)
+            54.5981500331442*x^4 + (-20.0855369231877*I)*x^3 + (-7.38905609893065)*x^2 + 2.71828182845905*I*x + 1.00000000000000
+
+        A multivariate polynomial over a finite field:
+            sage: f = (3*x^5 - 5*y^5)^7; f
+            (3*x^5 - 5*y^5)^7
+            sage: g = f.polynomial(GF(7)); g
+            2*y^35 + 3*x^35
+            sage: parent(g)
+            Polynomial Ring in x, y over Finite Field of size 7
+        """
+        vars = self.variables()
+        if len(vars) == 0:
+            vars = ['x']
+        R = PolynomialRing(base_ring, names=vars)  
+        G = R.gens()
+        V = R.variable_names()
+        return self.substitute_over_ring(
+             dict([(var(V[i]),G[i]) for i in range(len(G))]), ring=R)
+    
+    def _polynomial_(self, R):
+        """
+        Coerce this symbolic expression to a polynomial in R.
+
+        EXAMPLES:
+            sage: R = QQ[x,y,z]
+            sage: R(x^2 + y)
+            y + x^2
+            sage: R = QQ[w]
+            sage: R(w^3 + w + 1)
+            w^3 + w + 1
+            sage: R = GF(7)[z]
+            sage: R(z^3 + 10*z)
+            z^3 + 3*z
+
+        NOTE: If the base ring of the polynomial ring is the symbolic
+        ring, then a constant polynomial is always returned.
+            sage: R = SR[x]
+            sage: a = R(sqrt(2) + x^3 + y)
+            sage: a
+            y + x^3 + sqrt(2)
+            sage: type(a)
+            <type 'sage.rings.polynomial_element.Polynomial_generic_dense'>
+            sage: a.degree()
+            0
+
+        We coerce to a double precision complex polynomial ring:
+            sage: f = e*x^3 + pi*y^3 + sqrt(2) + I; f
+            pi*y^3 + e*x^3 + I + sqrt(2)
+            sage: R = CDF[x,y]
+            sage: R(f)
+            1.41421356237 + 1.0*I + 3.14159265359*y^3 + 2.71828182846*x^3
+
+        We coerce to a higher-precision polynomial ring
+            sage: R = ComplexField(100)[x,y]
+            sage: R(f)
+            1.4142135623730950066967437806 + 1.0000000000000000000000000000*I + 3.1415926535897932384626433833*y^3 + 2.7182818284590452353602874714*x^3
+            
+        """
+        vars = self.variables()
+        B = R.base_ring()
+        if B == SR:
+            if is_MPolynomialRing(R):
+                return R({tuple([0]*R.ngens()):self})
+            else:
+                return R([self])
+        G = R.gens()
+        sub = []
+        for v in vars:
+            r = repr(v)
+            for g in G:
+                if repr(g) == r:
+                    sub.append((v,g))
+        if len(sub) == 0:
+            return R(B(self))
+        return self.substitute_over_ring(dict(sub), ring=R)
 
     def function(self, *args):
         """
-        Return a CallableFunction, fixing a variable order to be the order of
-        args.
+        Return a CallableSymbolicExpression, fixing a variable order
+        to be the order of args.
 
         EXAMPLES:
@@ -198,11 +960,37 @@
            sage: g = u.function(x,y)
            sage: g(x,y)
-           sin(x) + x*cos(y)
+           x*cos(y) + sin(x)
            sage: g(t,z)
-           sin(t) + t*cos(z)
-           sage: g(x^2, log(y))
-           sin(x^2) + x^2*cos(log(y))
-        """
-        return CallableFunction(self, args)
+           t*cos(z) + sin(t)
+           sage: g(x^2, x^y)
+           x^2*cos(x^y) + sin(x^2)
+
+            sage: f = (x^2 + sin(a*w)).function(a,x,w); f
+            (a, x, w) |--> x^2 + sin(a*w)
+            sage: f(1,2,3)
+            sin(3) + 4
+
+        Using the function method we can obtain the above function f,
+        but viewed as a function of different variables:
+            sage: h = f.function(w,a); h
+            (w, a) |--> x^2 + sin(a*w)
+
+        This notation also works:
+            sage: h(w,a) = f
+            sage: h
+            (w, a) |--> x^2 + sin(a*w)
+
+        You can even make a symbolic expression $f$ into a function by
+        writing \code{f(x,y) = f}:
+            sage: f = x^n + y^n; f
+            y^n + x^n
+            sage: f(x,y) = f
+            sage: f
+            (x, y) |--> y^n + x^n
+            sage: f(2,3)
+            3^n + 2^n
+        """
+        R = CallableSymbolicExpressionRing(args)
+        return R(self)
 
 
@@ -212,4 +1000,18 @@
     def derivative(self, *args):
         """
+        Returns the derivative of itself. If self has exactly one variable, then
+        it differentiates with respect to that variable. If there is more than one
+        variable in the expression, then you must explicitly supply a variable.
+        If you supply a variable $x$ followed by a number $n$, then it will
+        differentiate with respect to $n$ times with respect to $n$.
+
+        You may supply more than one variable. Each variable may optionally be
+        followed by a positive integer. Then SAGE will differentiate with
+        respect to the first variable $n$ times, where $n$ is the number
+        immediately following the variable in the parameter list. If the
+        variable is not followed by an integer, then SAGE will differentiate
+        once. Then SAGE will differentiate by the second variables, and if that
+        is followed by a number $m$, it will differentiate $m$ times, and so on.
+
         EXAMPLES:
             sage: h = sin(x)/cos(x)
@@ -222,14 +1024,48 @@
             sage: diff(u,x,y)
             sin(x)*sin(y) - cos(x)*cos(y)            
+            sage: f = ((x^2+1)/(x^2-1))^(1/4)
+            sage: g = diff(f, x); g # this is a complex expression
+            x/(2*(x^2 - 1)^(1/4)*(x^2 + 1)^(3/4)) - (x*(x^2 + 1)^(1/4)/(2*(x^2 - 1)^(5/4)))
+            sage: g.simplify_rational()
+            -x/((x^2 - 1)^(5/4)*(x^2 + 1)^(3/4))
+            
+            sage: f = y^(sin(x))
+            sage: diff(f, x)
+            cos(x)*y^sin(x)*log(y)
+
+            sage: g(x) = sqrt(5-2*x)
+            sage: g_3 = diff(g, x, 3); g_3(2)
+            -3
+            
+            sage: f = x*e^(-x)
+            sage: diff(f, 100)
+            x*e^(-x) - 100*e^(-x)
+
+            sage: g = 1/(sqrt((x^2-1)*(x+5)^6))
+            sage: diff(g, x)
+            -3/((x + 5)^3*sqrt(x^2 - 1)*abs(x + 5)) - (x/((x^2 - 1)^(3/2)*abs(x + 5)^3))
         """
         # check each time
         s = ""
+        # see if we can implicitly supply a variable name
+        try:
+            a = args[0]
+        except IndexError:
+            # if there were NO arguments, try assuming 
+            a = 1
+        if a is None or isinstance(a, (int, long, Integer)):
+            vars = self.variables()
+            if len(vars) == 1:
+                s = "%s, %s" % (vars[0], a)
+            else:
+                raise ValueError, "must supply an explicit variable for an " +\
+                                "expression containing more than one variable"
         for i in range(len(args)):
             if isinstance(args[i], SymbolicVariable):
-                s = s + '%s, ' %str(args[i])
+                s = s + '%s, ' %repr(args[i])
                 # check to see if this is followed by an integer
                 try:
                     if isinstance(args[i+1], (int, long, Integer)):
-                        s = s + '%s, ' %str(args[i+1])
+                        s = s + '%s, ' %repr(args[i+1])
                     else:
                         s = s + '1, '
@@ -253,19 +1089,655 @@
         f = self.parent()(t)
         return f
+
+    differentiate = derivative
+    diff = derivative
         
     
     ###################################################################
-    # integral
+    # Taylor series
     ###################################################################
-    def integral(self, v):
-        """
-        EXAMPLES:
-            sage: h = sin(x)/cos(x)
+    def taylor(self, v, a, n):
+        """
+        Expands self in a truncated Taylor or Laurent series in the
+        variable v around the point a, containing terms through $(x - a)^n$.
+
+        INPUT:
+            v -- variable
+            a -- number
+            n -- integer
+
+        EXAMPLES:
+            sage: taylor(a*log(z), z, 2, 3)
+            log(2)*a + a*(z - 2)/2 - (a*(z - 2)^2/8) + a*(z - 2)^3/24
+            sage: taylor(sqrt (sin(x) + a*x + 1), x, 0, 3)
+            1 + (a + 1)*x/2 - ((a^2 + 2*a + 1)*x^2/8) + (3*a^3 + 9*a^2 + 9*a - 1)*x^3/48
+            sage: taylor (sqrt (x + 1), x, 0, 5)
+            1 + x/2 - (x^2/8) + x^3/16 - (5*x^4/128) + 7*x^5/256
+            sage: taylor (1/log (x + 1), x, 0, 3)
+            1/x + 1/2 - (x/12) + x^2/24 - (19*x^3/720)
+            sage: taylor (cos(x) - sec(x), x, 0, 5)
+            -x^2 - (x^4/6)
+            sage: taylor ((cos(x) - sec(x))^3, x, 0, 9)
+            -x^6 - (x^8/2)
+            sage: taylor (1/(cos(x) - sec(x))^3, x, 0, 5)
+            -1/x^6 + 1/(2*x^4) + 11/(120*x^2) - 347/15120 - (6767*x^2/604800) - (15377*x^4/7983360)
+        """
+        v = var(v)
+        l = self._maxima_().taylor(v, SR(a), Integer(n))
+        return self.parent()(l)
+
+    ###################################################################
+    # limits
+    ###################################################################
+    def limit(self, dir=None, **argv):
+        r"""
+        Return the limit as the variable v approaches a from the
+        given direction.
+
+        \begin{verbatim}
+        expr.limit(x = a)
+        expr.limit(x = a, dir='above')
+        \end{verbatim}
+
+        INPUT:
+            dir -- (default: None); dir may have the value `plus' (or 'above')
+                   for a limit from above, `minus' (or 'below') for a limit from
+                   below, or may be omitted (implying a two-sided
+                   limit is to be computed).
+            **argv -- 1 named parameter
+
+        NOTE: Output it may also use `und' (undefined), `ind'
+        (indefinite but bounded), and `infinity' (complex infinity).
+
+        EXAMPLES:
+            sage: f = (1+1/x)^x
+            sage: f.limit(x = oo)
+            e
+            sage: f.limit(x = 5)
+            7776/3125
+            sage: f.limit(x = 1.2)
+            2.069615754672029
+            sage: f.limit(x = I)
+            e^(I*log(1 - I))
+            sage: f(1.2)
+            2.069615754672029
+            sage: f(I)
+            (1 - I)^I
+            sage: CDF(f(I))
+            2.06287223508 + 0.74500706218*I
+            sage: CDF(f.limit(x = I))
+            2.06287223508 + 0.74500706218*I
+
+        More examples:
+            sage: limit(x*log(x), x = 0, dir='above')
+            0
+            sage: lim((x+1)^(1/x),x = 0)
+            e
+            sage: lim(e^x/x, x = oo)
+            +Infinity
+            sage: lim(e^x/x, x = -oo)
+            0
+            sage: lim(-e^x/x, x = oo)
+            -Infinity
+            sage: lim((cos(x))/(x^2), x = 0)
+            +Infinity
+            sage: lim(sqrt(x^2+1) - x, x = oo)
+            0
+            sage: lim(x^2/(sec(x)-1), x=0)
+            2
+            sage: lim(cos(x)/(cos(x)-1), x=0)
+            -Infinity
+            sage: lim(x*sin(1/x), x=0)
+            0
+            
+            Traceback (most recent call last):
+            ...
+            TypeError: Computation failed since Maxima requested additional constraints (use assume):
+            Is  x  positive or negative?
+
+            sage: f = log(log(x))/log(x)
+            sage: forget(); assume(x<-2); lim(f, x=0)
+            limit(log(log(x))/log(x), x=0)
+
+        The following means "indefinite but bounded":
+            sage: lim(sin(1/x), x = 0)
+            ind            
+        """
+        if len(argv) != 1:
+            raise ValueError, "call the limit function like this, e.g. limit(expr, x=2)."
+        else:
+            k = argv.keys()[0]
+            v = var(k, create=False)
+            a = argv[k]
+        if dir is None:
+            l = self._maxima_().limit(v, a)
+        elif dir == 'plus' or dir == 'above':
+            l = self._maxima_().limit(v, a, 'plus')
+        elif dir == 'minus' or dir == 'below':
+            l = self._maxima_().limit(v, a, 'minus')
+        else:
+            raise ValueError, "dir must be one of 'plus' or 'minus'"
+        return self.parent()(l)
+
+    ###################################################################
+    # Laplace transform
+    ###################################################################
+    def laplace(self, t, s):
+        r"""
+        Attempts to compute and return the Laplace transform of self
+        with respect to the variable t and transform parameter s.  If
+        Laplace cannot find a solution, a formal function is returned.
+
+        The function that is returned maybe be viewed as a function of s.
+
+        DEFINITION:
+        The Laplace transform of a function $f(t)$, defined for all
+        real numbers $t \geq 0$, is the function $F(s)$ defined by
+        $$
+             F(s) = \int_{0}^{\infty} e^{-st} f(t) dt.
+        $$
+
+        EXAMPLES:
+        We compute a few Laplace transforms:
+            sage: sin(x).laplace(x, s)
+            1/(s^2 + 1)
+            sage: (z + exp(x)).laplace(x, s)
+            z/s + 1/(s - 1)
+            sage: var('t0')
+            t0
+            sage: log(t/t0).laplace(t, s)
+            (-log(t0) - log(s) - euler_gamma)/s
+
+        We do a formal calculation:
+            sage: f = function('f', x)
+            sage: g = f.diff(x); g
+            diff(f(x), x, 1)
+            sage: g.laplace(x, s)
+            s*laplace(f(x), x, s) - f(0)
+
+        EXAMPLE: A BATTLE BETWEEN the X-women and the Y-men (by David Joyner):
+        Solve
+        $$
+          x' = -16y, x(0)=270,  y' = -x + 1, y(0) = 90.
+        $$
+        This models a fight between two sides, the "X-women"
+        and the "Y-men", where the X-women have 270 initially and
+        the Y-men have 90, but the Y-men are better at fighting,
+        because of the higher factor of "-16" vs "-1", and also get
+        an occasional reinforcement, because of the "+1" term.
+
+            sage: var('t')
+            t
+            sage: t = var('t')
+            sage: x = function('x', t)
+            sage: y = function('y', t)
+            sage: de1 = x.diff(t) + 16*y
+            sage: de2 = y.diff(t) + x - 1
+            sage: de1.laplace(t, s)
+            16*laplace(y(t), t, s) + s*laplace(x(t), t, s) - x(0)
+            sage: de2.laplace(t, s)
+            s*laplace(y(t), t, s) + laplace(x(t), t, s) - (1/s) - y(0)
+
+        Next we form the augmented matrix of the above system:
+            sage: A = matrix([[s, 16, 270],[1, s, 90+1/s]])   
+            sage: E = A.echelon_form()
+            sage: xt = E[0,2].inverse_laplace(s,t)
+            sage: yt = E[1,2].inverse_laplace(s,t)
+            sage: print xt
+				4 t	    - 4 t
+			   91  e      629  e
+        		 - -------- + ----------- + 1
+			      2		   2
+            sage: print yt
+				 4 t	     - 4 t
+			    91  e      629  e
+        		    -------- + -----------
+			       8	    8
+            sage: p1 = plot(xt,0,1/2,rgbcolor=(1,0,0))
+            sage: p2 = plot(yt,0,1/2,rgbcolor=(0,1,0))
+            sage: (p1+p2).save()
+        """
+        return self.parent()(self._maxima_().laplace(var(t), var(s)))
+
+    def inverse_laplace(self, t, s):
+        r"""
+        Attempts to compute the inverse Laplace transform of self with
+        respect to the variable t and transform parameter s.  If
+        Laplace cannot find a solution, a formal function is returned.
+
+        The function that is returned maybe be viewed as a function of s.
+
+
+        DEFINITION:
+        The inverse Laplace transform of a function $F(s)$,
+        is the function $f(t)$ defined by
+        $$
+             F(s) = \frac{1}{2\pi i} \int_{\gamma-i\infty}^{\gamma + i\infty} e^{st} F(s) dt,
+        $$
+        where $\gamma$ is chosen so that the contour path of
+        integration is in the region of convergence of $F(s)$.
+
+        EXAMPLES:
+            sage: f = (1/(w^2+10)).inverse_laplace(w, m); f
+            sin(sqrt(10)*m)/sqrt(10)
+            sage: laplace(f, m, w)
+            1/(w^2 + 10)        
+        """
+        return self.parent()(self._maxima_().ilt(var(t), var(s)))
+    
+
+    ###################################################################
+    # a default variable, for convenience.
+    ###################################################################
+    def default_variable(self):
+        vars = self.variables()
+        if len(vars) < 1:
+            return var('x')
+        else:
+            return vars[0]
+
+    ###################################################################
+    # integration
+    ###################################################################
+    def integral(self, v=None, a=None, b=None):
+        """
+        Returns the indefinite integral with respect to the variable
+        $v$, ignoring the constant of integration. Or, if endpoints
+        $a$ and $b$ are specified, returns the definite integral over
+        the interval $[a, b]$.
+
+        If \code{self} has only one variable, then it returns the
+        integral with respect to that variable.
+
+        INPUT:
+            v -- (optional) a variable or variable name
+            a -- (optional) lower endpoint of definite integral
+            b -- (optional) upper endpoint of definite integral
+            
+        
+        EXAMPLES:
+            sage: h = sin(x)/(cos(x))^2
             sage: h.integral(x)
-        """
+            1/cos(x)
+
+            sage: f = x^2/(x+1)^3
+            sage: f.integral()
+            log(x + 1) + (4*x + 3)/(2*x^2 + 4*x + 2)
+
+            sage: f = x*cos(x^2)
+            sage: f.integral(x, 0, sqrt(pi))
+            0
+            sage: f.integral(a=-pi, b=pi)
+            0
+            
+            sage: f(x) = sin(x)
+            sage: f.integral(x, 0, pi/2)
+            1
+
+        Constraints are sometimes needed:
+            sage: integral(x^n,x)
+            Traceback (most recent call last):
+            ...
+            TypeError: Computation failed since Maxima requested additional constraints (use assume):
+            Is  n+1  zero or nonzero?
+            sage: assume(n > 0)
+            sage: integral(x^n,x)
+            x^(n + 1)/(n + 1)
+            sage: forget()
+
+        NOTE: Above, putting assume(n == -1) does not yield the right behavior.
+        Directly in maxima, doing
+
+        The examples in the Maxima documentation:
+            sage: integral(sin(x)^3)
+            cos(x)^3/3 - cos(x)
+            sage: integral(x/sqrt(b^2-x^2))
+            x*log(2*sqrt(b^2 - x^2) + 2*b)
+            sage: integral(x/sqrt(b^2-x^2), x)
+            -sqrt(b^2 - x^2)
+            sage: integral(cos(x)^2 * exp(x), x, 0, pi)
+            3*e^pi/5 - 3/5
+            sage: integral(x^2 * exp(-x^2), x, -oo, oo)
+            sqrt(pi)/2
+
+        We integrate the same function in both Mathematica and SAGE (via Maxima):
+            sage: f = sin(x^2) + y^z
+            sage: g = mathematica(f)                           # optional  -- requires mathematica
+            sage: print g                                      # optional
+                      z        2
+                     y  + Sin[x ]
+            sage: print g.Integrate(x)                         # optional
+                        z        Pi                2
+                     x y  + Sqrt[--] FresnelS[Sqrt[--] x]
+                                 2                 Pi
+            sage: print f.integral(x)
+                  z                                         (sqrt(2)  I + sqrt(2)) x
+               x y  + sqrt( pi) ((sqrt(2)  I + sqrt(2)) erf(------------------------)
+                                                                       2
+                                                           (sqrt(2)  I - sqrt(2)) x
+                              + (sqrt(2)  I - sqrt(2)) erf(------------------------))/8
+                                                                      2
+                                                                          
+        We integrate the above function in maple now:
+            sage: g = maple(f); g                             # optional -- requires maple
+            sin(x^2)+y^z
+            sage: g.integrate(x)                              # optional -- requires maple
+            1/2*2^(1/2)*Pi^(1/2)*FresnelS(2^(1/2)/Pi^(1/2)*x)+y^z*x
+
+        We next integrate a function with no closed form integral.  Notice that
+        the answer comes back as an expression that contains an integral itself.
+            sage: A = integral(1/ ((x-4) * (x^3+2*x+1)), x); A
+            log(x - 4)/73 - (integrate((x^2 + 4*x + 18)/(x^3 + 2*x + 1), x)/73)
+            sage: print A
+                                     /  2
+                                     [ x  + 4 x + 18
+                                     I ------------- dx
+                                     ]  3
+                        log(x - 4)   / x  + 2 x + 1
+                        ---------- - ------------------
+                            73               73            
+
+        ALIASES:
+            integral() and integrate() are the same.
+            
+        """
+
+        if v is None:
+            v = self.default_variable()
+            
         if not isinstance(v, SymbolicVariable):
-            raise TypeError, "second argument to diff must be a variable"
-        return self.parent()(self._maxima_().integrate(v))
+            v = var(repr(v))
+            #raise TypeError, 'must integrate with respect to a variable'
+        if (a is None and (not b is None)) or (b is None and (not a is None)):
+            raise TypeError, 'only one endpoint given'
+        if a is None:
+            return self.parent()(self._maxima_().integrate(v))
+        else:
+            return self.parent()(self._maxima_().integrate(v, a, b))
+
+    integrate = integral
+ 
+    def nintegral(self, x, a, b,
+                  desired_relative_error='1e-8',
+                  maximum_num_subintervals=200):
+        r"""
+        Return a numerical approximation to the integral of self from
+        a to b.
+
+        INPUT:
+            x -- variable to integrate with respect to
+            a -- lower endpoint of integration
+            b -- upper endpoint of integration
+            desired_relative_error -- (default: '1e-8') the desired
+                 relative error
+            maximum_num_subintervals -- (default: 200) maxima number
+                 of subintervals
+
+        OUTPUT:
+            -- float: approximation to the integral
+            -- float: estimated absolute error of the approximation
+            -- the number of integrand evaluations
+            -- an error code:
+                  0 -- no problems were encountered
+                  1 -- too many subintervals were done
+                  2 -- excessive roundoff error
+                  3 -- extremely bad integrand behavior
+                  4 -- failed to converge
+                  5 -- integral is probably divergent or slowly convergent
+                  6 -- the input is invalid
+
+        ALIAS:
+            nintegrate is the same as nintegral
+
+        REMARK:
+            There is also a function \code{numerical_integral} that implements
+            numerical integration using the GSL C library.  It is potentially
+            much faster and applies to arbitrary user defined functions. 
+
+        EXAMPLES:
+            sage: f(x) = exp(-sqrt(x))
+            sage: f.nintegral(x, 0, 1)
+            (0.52848223531423055, 4.1633141378838452e-11, 231, 0)
+
+        We can also use the \code{numerical_integral} function, which calls
+        the GSL C library.
+            sage: numerical_integral(f, 0, 1)       # random low-order bits
+            (0.52848223225314706, 6.8392846084921134e-07)
+        """
+        v = self._maxima_().quad_qags(var(x),
+                                      a, b, desired_relative_error,
+                                      maximum_num_subintervals)
+        return float(v[0]), float(v[1]), Integer(v[2]), Integer(v[3])
+
+    nintegrate = nintegral
+
+    
+    ###################################################################
+    # Manipulating epxressions
+    ###################################################################
+    def coeff(self, x, n=1):
+        """
+        Returns the coefficient of $x^n$ in self.
+
+        INPUT:
+            x -- variable, function, expression, etc.
+            n -- integer, default 1.
+
+        Sometimes it may be necessary to expand or factor first, since
+        this is not done automatically.
+
+        EXAMPLES:
+            sage: f = (a*sqrt(2))*x^2 + sin(y)*x^(1/2) + z^z   
+            sage: f.coeff(sin(y))
+            sqrt(x)        
+            sage: f.coeff(x^2)
+            sqrt(2)*a
+            sage: f.coeff(x^(1/2))
+            sin(y)
+            sage: f.coeff(1)
+            0
+            sage: f.coeff(x, 0)
+            z^z
+        """
+        return self.parent()(self._maxima_().coeff(x, n))
+
+    def coeffs(self, x=None):
+        """
+        Coefficients of self as a polynomial in x.
+
+        INPUT:
+            x -- optional variable
+        OUTPUT:
+            list of pairs [expr, n], where expr is a symbolic expression and n is a power.
+
+        EXAMPLES:
+            sage: p = x^3 - (x-3)*(x^2+x) + 1
+            sage: p.coeffs()
+            [[1, 0], [3, 1], [2, 2]]
+            sage: p = expand((x-a*sqrt(2))^2 + x + 1); p
+            x^2 - 2*sqrt(2)*a*x + x + 2*a^2 + 1
+            sage: p.coeffs(a)
+            [[x^2 + x + 1, 0], [-2*sqrt(2)*x, 1], [2, 2]]
+            sage: p.coeffs(x)
+            [[2*a^2 + 1, 0], [1 - 2*sqrt(2)*a, 1], [1, 2]]
+
+        A polynomial with wacky exponents:
+            sage: p = (17/3*a)*x^(3/2) + x*y + 1/x + x^x
+            sage: p.coeffs(x)
+            [[1, -1], [x^x, 0], [y, 1], [17*a/3, 3/2]]        
+        """
+        f = self._maxima_()
+        P = f.parent()
+        P._eval_line('load(coeflist)')
+        if x is None:
+            x = self.default_variable()
+        x = var(x)
+        G = f.coeffs(x)
+        S = symbolic_expression_from_maxima_string(repr(G))
+        return S[1:]
+
+    def poly(self, x=None):
+        r"""
+        Express self as a polynomial in x.  Is self is not a polynomial
+        in x, then some coefficients may be functions of x.
+
+        WARNING: This is different from \code{self.polynomial()} which
+        returns a SAGE polynomial over a given base ring.
+
+        EXAMPLES:
+            sage: p = expand((x-a*sqrt(2))^2 + x + 1); p
+            x^2 - 2*sqrt(2)*a*x + x + 2*a^2 + 1
+            sage: p.poly(a)
+            (x^2 + x + 1)*1 + -2*sqrt(2)*x*a + 2*a^2
+            sage: bool(expand(p.poly(a)) == p)
+            True            
+            sage: p.poly(x)
+            (2*a^2 + 1)*1 + (1 - 2*sqrt(2)*a)*x + 1*x^2        
+        """
+        f = self._maxima_()
+        P = f.parent()
+        P._eval_line('load(coeflist)')
+        if x is None:
+            x = self.default_variable()
+        x = var(x)
+        G = f.coeffs(x)
+        ans = None
+        for i in range(1, len(G)):
+            Z = G[i]
+            coeff = SR(Z[0])
+            n = SR(Z[1])
+            if repr(coeff) != '0':
+                if repr(n) == '0':
+                    xpow = SR(1)
+                elif repr(n) == '1':
+                    xpow = x
+                else:
+                    xpow = x**n
+                if ans is None:
+                    ans = coeff*xpow
+                else:
+                    ans += coeff*xpow
+        ans._declare_simplified()
+        return ans
+
+    def combine(self):
+        """
+        Simplifies self by combining all terms with the same
+        denominator into a single term.
+
+        EXAMPLES:
+            sage: f = x*(x-1)/(x^2 - 7) + y^2/(x^2-7) + 1/(x+1) + b/a + c/a
+            sage: print f
+                                     2
+                                    y      (x - 1) x     1     c   b
+                                  ------ + --------- + ----- + - + -
+                                   2         2         x + 1   a   a
+                                  x  - 7    x  - 7
+            sage: print f.combine()
+                                     2
+                                    y  + (x - 1) x     1     c + b
+                                    -------------- + ----- + -----
+                                         2           x + 1     a
+                                        x  - 7        
+        """
+        return self.parent()(self._maxima_().combine())
+    
+    def numerator(self):
+        """
+        EXAMPLES:
+            sage: f = x*(x-a)/((x^2 - y)*(x-a))
+            sage: print f
+                                                  x
+                                                ------
+                                                 2
+                                                x  - y
+            sage: f.numerator()
+            x
+            sage: f.denominator()
+            x^2 - y
+        """
+        return self.parent()(self._maxima_().num())
+
+    def denominator(self):
+        """
+        EXAMPLES:
+            sage: f = (sqrt(x) + sqrt(y) + sqrt(z))/(x^10 - y^10 - sqrt(var('theta')))
+            sage: print f
+                                      sqrt(z) + sqrt(y) + sqrt(x)
+                                      ---------------------------
+                                          10    10
+                                       - y   + x   - sqrt(theta)
+            sage: f.denominator()
+            -y^10 + x^10 - sqrt(theta)
+        """
+        return self.parent()(self._maxima_().denom())
+    
+    ###################################################################
+    # solve
+    ###################################################################
+    def roots(self, x=None):
+        r"""
+        Returns the roots of self, with multiplicities.
+
+        INPUT:
+            x -- variable to view the function in terms of
+                   (use default variable if not given)
+        OUTPUT:
+            list of pairs (root, multiplicity)
+
+        If there are infinitely many roots, e.g., a function
+        like sin(x), only one is returned. 
         
+        EXAMPLES:
+        A simple example:
+            sage: ((x^2-1)^2).roots()
+            [(-1, 2), (1, 2)]
+
+        A complicated example.
+            sage: f = expand((x^2 - 1)^3*(x^2 + 1)*(x-a)); f
+            x^9 - a*x^8 - 2*x^7 + 2*a*x^6 + 2*x^3 - 2*a*x^2 - x + a
+
+        The default variable is a, since it is the first in alphabetical order:
+            sage: f.roots()
+            [(x, 1)]
+
+        As a polynomial in a, x is indeed a root:
+            sage: f.poly(a)
+            (x^9 - 2*x^7 + 2*x^3 - x)*1 + (-x^8 + 2*x^6 - 2*x^2 + 1)*a
+            sage: f(a=x)
+            0
+
+        The roots in terms of x are what we expect:
+            sage: f.roots(x)
+            [(a, 1), (-1*I, 1), (I, 1), (1, 3), (-1, 3)]
+
+        Only one root of $\sin(x) = 0$ is given:
+            sage: f = sin(x)    
+            sage: f.roots(x)
+            [(0, 1)]
+
+        We derive the roots of a general quadratic polynomial:
+            sage: (a*x^2 + b*x + c).roots(x)
+            [((-sqrt(b^2 - 4*a*c) - b)/(2*a), 1), ((sqrt(b^2 - 4*a*c) - b)/(2*a), 1)]        
+        """
+        if x is None:
+            x = self.default_variable()
+        S, mul = self.solve(x, multiplicities=True)
+        return [(S[i].rhs(), mul[i]) for i in range(len(mul))]
+
+    def solve(self, x, multiplicities=False):
+        r"""
+        Solve the equation \code{self == 0} for the variable x.
+
+        INPUT:
+            x -- variable to solve for
+            multiplicities -- bool (default: False); if True, return corresponding multiplicities. 
+
+        EXAMPLES:
+            sage: (z^5 - 1).solve(z)
+            [z == e^(2*I*pi/5), z == e^(4*I*pi/5), z == e^(-(4*I*pi/5)), z == e^(-(2*I*pi/5)), z == 1]        
+        """
+        x = var(x)
+        return (self == 0).solve(x, multiplicities=multiplicities)
 
     ###################################################################
@@ -273,13 +1745,20 @@
     ###################################################################
     def simplify(self):
-        return self.parent()(self._maxima_())
+        try:
+            return self._simp
+        except AttributeError:
+            S = evaled_symbolic_expression_from_maxima_string(self._maxima_init_())
+            S._simp = S
+            self._simp = S
+            return S
 
     def simplify_trig(self):
         r"""
-        Employs the identities $\sin(x)^2 + \cos(x)^2 = 1$ and
-        $\cosh(x)^2 - \sin(x)^2 = 1$ to simplify expressions
-        containing tan, sec, etc., to sin, cos, sinh, cosh.
-
-        trig_simplify() and simplify_trig() are the same method.
+        First expands using trig_expand, then employs the identities
+        $\sin(x)^2 + \cos(x)^2 = 1$ and $\cosh(x)^2 - \sin(x)^2 = 1$
+        to simplify expressions containing tan, sec, etc., to sin,
+        cos, sinh, cosh.
+
+        ALIAS: trig_simplify and simplify_trig are the same
         
         EXAMPLES:
@@ -290,9 +1769,121 @@
             sage: f.simplify_trig()
             1
-            
-        """
-        return self.parent()(self._maxima_().trigsimp())
+        """
+        # much better to expand first, since it often doesn't work
+        # right otherwise!
+        return self.parent()(self._maxima_().trigexpand().trigsimp())
 
     trig_simplify = simplify_trig
+
+    def simplify_rational(self):
+        """
+        Simplify by expanding repeatedly rational expressions.
+        
+        ALIAS: rational_simplify and simplify_rational are the same
+
+        EXAMPLES:
+            sage: f = sin(x/(x^2 + x))
+            sage: f
+            sin(x/(x^2 + x))
+            sage: f.simplify_rational()
+            sin(1/(x + 1))
+
+            sage: f = ((x - 1)^(3/2) - (x + 1)*sqrt(x - 1))/sqrt((x - 1)*(x + 1))
+            sage: print f
+                                          3/2
+                                   (x - 1)    - sqrt(x - 1) (x + 1)
+                                   --------------------------------
+                                        sqrt((x - 1) (x + 1))
+            sage: print f.simplify_rational()
+                                              2 sqrt(x - 1)
+                                            - -------------
+                                                    2
+                                              sqrt(x  - 1)            
+        """
+        return self.parent()(self._maxima_().fullratsimp())
+
+    rational_simplify = simplify_rational
+
+    # TODO: come up with a way to intelligently wrap Maxima's way of
+    # fine-tuning all simplificationsrational
+
+    def simplify_radical(self):
+        r"""
+        Wraps the Maxima radcan() command. From the Maxima documentation: 
+
+            Simplifies this expression, which can contain logs, exponentials,
+            and radicals, by converting it into a form which is canonical over a
+            large class of expressions and a given ordering of variables; that
+            is, all functionally equivalent forms are mapped into a unique form.
+            For a somewhat larger class of expressions, produces a regular form.
+            Two equivalent expressions in this class do not necessarily have the
+            same appearance, but their difference can be simplified by radcan to
+            zero.
+
+            For some expressions radcan is quite time consuming. This is the
+            cost of exploring certain relationships among the components of the
+            expression for simplifications based on factoring and partial
+            fraction expansions of exponents. 
+
+        ALIAS: radical_simplify, simplify_log, log_simplify, exp_simplify,
+        simplify_exp are all the same
+
+        EXAMPLES:
+
+            sage: f = log(x*y)
+            sage: f.simplify_radical()
+            log(y) + log(x)
+
+            sage: f = (log(x+x^2)-log(x))^a/log(1+x)^(a/2)
+            sage: f.simplify_radical()
+            log(x + 1)^(a/2)
+
+            sage: f = (e^x-1)/(1+e^(x/2))
+            sage: f.simplify_exp()
+            e^(x/2) - 1
+        """
+        return self.parent()(self._maxima_().radcan())
+
+    radical_simplify = simplify_log = log_simplify = simplify_radical
+    simplify_exp = exp_simplify = simplify_radical
+        
+    ###################################################################
+    # factor
+    ###################################################################
+    def factor(self, dontfactor=[]):
+        """
+        Factors self, containing any number of variables or functions,
+        into factors irreducible over the integers.
+
+        INPUT:
+            self -- a symbolic expression
+            dontfactor -- list (default: []), a list of variables with
+                          respect to which factoring is not to occur.
+                          Factoring also will not take place with
+                          respect to any variables which are less
+                          important (using the variable ordering
+                          assumed for CRE form) than those on the
+                          `dontfactor' list.
+
+        EXAMPLES:
+            sage: (x^3-y^3).factor()
+            (-(y - x))*(y^2 + x*y + x^2)
+            sage: factor(-8*y - 4*x + z^2*(2*y + x))
+            (2*y + x)*(z - 2)*(z + 2)
+            sage: f = -1 - 2*x - x^2 + y^2 + 2*x*y^2 + x^2*y^2
+            sage: F = factor(f/(36*(1 + 2*y + y^2)), dontfactor=[x])
+            sage: print F
+                                          2
+                                        (x  + 2 x + 1) (y - 1)
+                                        ----------------------
+                                              36 (y + 1)
+        """
+        if len(dontfactor) > 0:
+            m = self._maxima_()
+            name = m.name()
+            cmd = 'block([dontfactor:%s],factor(%s))'%(dontfactor, name)
+            return evaled_symbolic_expression_from_maxima_string(cmd)
+        else:
+            return self.parent()(self._maxima_().factor())
         
     ###################################################################
@@ -302,5 +1893,10 @@
         """
         """
-        return self.parent()(self._maxima_().expand())
+        try:
+            return self.__expand
+        except AttributeError:
+            e = self.parent()(self._maxima_().expand())
+            self.__expand = e
+        return e
 
     def expand_trig(self):
@@ -313,5 +1909,5 @@
             cos(2*x)*cos(y) - sin(2*x)*sin(y)
 
-        ALIAS: trig_expand
+        ALIAS: trig_expand and expand_trig are the same
         """
         return self.parent()(self._maxima_().trigexpand())
@@ -320,196 +1916,304 @@
 
 
-       
     ###################################################################
     # substitute
     ###################################################################
-    def substitute(self, dict=None, **kwds):
+    def substitute(self, in_dict=None, **kwds):
         """
         Takes the symbolic variables given as dict keys or as keywords and
         replaces them with the symbolic expressions given as dict values or as
-        keyword values. Also run when you call a SymbolicExpression.
-        
-        EXAMPLES:
-            sage: u = (x^3 - 3*y + 4*t)
+        keyword values.  Also run when you call a SymbolicExpression.
+
+        INPUT:
+            in_dict -- (optional) dictionary of inputs
+            **kwds  -- named parameters
+
+        EXAMPLES:
+            sage: x,y,t = var('x,y,t')
+            sage: u = 3*y
+            sage: u.substitute(y=t)
+            3*t
+
+            sage: u = x^3 - 3*y + 4*t
             sage: u.substitute(x=y, y=t)
-            y^3 - 3*t + 4*t
+            y^3 + t
 
             sage: f = sin(x)^2 + 32*x^(y/2)
-            sage: f.substitute(x=2, y = 10)
-            sin(2)^2 + 32*2^(10/2)
+            sage: f(x=2, y = 10)
+            sin(2)^2 + 1024
 
             sage: f(x=pi, y=t)
-            sin(pi)^2 + 32*pi^(t/2)
-
-            sage: f(x=pi, y=t).simplify()
+            32*pi^(t/2)
+
+            sage: f = x
+            sage: f.variables()
+            (x,)
+
+            sage: f = 2*x
+            sage: f.variables()
+            (x,)
+
+            sage: f = 2*x^2 - sin(x)
+            sage: f.variables()
+            (x,)
+            sage: f(pi)
+            2*pi^2
+            sage: f(x=pi)
+            2*pi^2
             
-
         AUTHORS:
             -- Bobby Moretti: Initial version
         """
-        if dict is not None:
-            for k, v in dict.iteritems():
-               kwds[str(k)] = v 
-        # find the keys from the keywords
-        return self._recursive_sub(kwds) 
+        X = self.simplify()
+        kwds = self.__parse_in_dict(in_dict, kwds)
+        kwds = self.__varify_kwds(kwds)
+        return X._recursive_sub(kwds)
+
+    def subs(self, *args, **kwds):
+        return self.substitute(*args, **kwds)
 
     def _recursive_sub(self, kwds):
-        # if we have operands, call ourself on each operand
-        try:
-            ops = self._operands
-        except AttributeError:
-            pass
-        if isinstance(self, SymbolicVariable):
-            s = str(self)
-            if s in kwds:
-                return kwds[s]
+        raise NotImplementedError, "implement _recursive_sub for type '%s'!"%(type(self))
+
+    def _recursive_sub_over_ring(self, kwds, ring):
+        raise NotImplementedError, "implement _recursive_sub_over_ring for type '%s'!"%(type(self))
+    
+    def __parse_in_dict(self, in_dict, kwds):
+        if in_dict is None:
+            return kwds
+        
+        if not isinstance(in_dict, dict):
+            if len(kwds) > 0:
+                raise ValueError, "you must not both give the variable and specify it explicitly when doing a substitution."
+            in_dict = SR(in_dict)
+            vars = self.variables()
+            #if len(vars) > 1:
+            #    raise ValueError, "you must specify the variable when doing a substitution, e.g., f(x=5)"
+            if len(vars) == 0:
+                return {}
             else:
-                return self
-        elif isinstance(self, SymbolicConstant):
-            return self
-        elif isinstance(self, SymbolicArithmetic):
-            new_ops = [op._recursive_sub(kwds) for op in ops]
-            return SymbolicArithmetic([new_ops[0], new_ops[1]], self._operator) 
-        elif isinstance(self, SymbolicComposition):
-            return SymbolicComposition(ops[0], ops[1]._recursive_sub(kwds))
-
-class PrimitiveFunction(SymbolicExpression):
-    def __init__(self):
-        pass
-
-    def __call__(self, x):
-        # if we're calling with a symbolic expression, do function composition
-        if isinstance(x, SymbolicExpression) and not isinstance(x, Constant):
-            return SymbolicComposition(self, x)
-
-        # if x is a polynomial object, first turn it into a function and
-        # compose self with x
-        elif is_Polynomial(x):
-            return Function_composition(self, SymbolicPolynomial(x))
-
-        # if we can't figure out what x is, return a symbolic version of x
-        elif isinstance(x, (Integer, Rational,
-                            int, long, float, complex)):
-            return self(Constant_object(x))
-
+                return {vars[0]: in_dict}
+
+        # merge dictionaries
+        kwds.update(in_dict)
+        return kwds
+
+    def __varify_kwds(self, kwds):
+        return dict([(var(k),w) for k,w in kwds.iteritems()])
+        
+    def substitute_over_ring(self, in_dict=None, ring=None, **kwds):
+        X = self.simplify()
+        kwds = self.__parse_in_dict(in_dict, kwds)
+        kwds = self.__varify_kwds(kwds)
+        if ring is None:
+            return X._recursive_sub(kwds)
         else:
-            return self(Symbolic_object(x))
- 
-
-class CallableFunction(SageObject):
-    r'''
-    A callable, symbolic function that knows the variables on which it depends.
-    '''
-    def __init__(self, expr, args):
-        if args == [] or args == () or args is None:
-            raise ValueError, "A CallableFunction must know at least one of \
-                                its variables."
-        for arg in args:
-            if not isinstance(arg, SymbolicExpression):
-                raise TypeError, "Must construct a function with a list of \
-                                  SymbolicVariables."
-
-            self._varlist = args
-            self._expr = expr
+            return X._recursive_sub_over_ring(kwds, ring)
+
         
-
-    def __call__(self, *args):
-        vars = self._varlist
-        dct = {}
-        for i in range(len(args)):
-            dct[vars[i]] = args[i]
-
-        return self._expr.substitute(dct)
-
-    def _repr_(self):
-        if len(self._varlist) == 1:
-            return "%s |--> %s" % (self._varlist[0], self._expr._repr_())
-        else:
-            vars = ", ".join(map(str, self._varlist))
-            return "(%s) |--> %s" % (vars, self._expr._repr_())
-
-    def _latex_(self):
-        if len(self._varlist) == 1:
-            return "%s \\ {\mapsto}\\ %s" % (self._varlist[0],
-                    self._expr._latex_())
-        else:
-            vars = ", ".join(map(latex, self._varlist))
-            # the weird TeX is to workaround an apparent JsMath bug
-            return "\left(%s \\right)\\ {\\mapsto}\\ %s" % (vars, self._expr._latex_())
-
-    def derivative(self, dt):
-        return CallableFunction(self._expr.derivative(dt), self._varlist)
-
-    def integral(self, dx):
-        return CallableFunction(self._expr.integral(dx), self._varlist)
-
-    def substitute(self, dict=None, **kwds):
-        return CallableFunction(self._expr.substitute(dict, kwds), self._varlist)
-
-    def simplify(self):
-        return CallableFunction(self._expr.simplify(), self._varlist)
-
-    def trig_simplify(self):
-        return CallableFunction(self._expr.trig_simplify(), self._varlist)
-
-    #TODO: Arithmetic, expand, trig_expand, etc...
+    ###################################################################
+    # Real and imaginary parts
+    ###################################################################
+    def real(self):
+        """
+        Return the real part of self.
+
+        EXAMPLES:
+            sage: a = log(3+4*I)
+            sage: print a
+                                             log(4  I + 3)
+            sage: print a.real()
+                                                log(5)
+            sage: print a.imag()
+                                                     4
+                                                atan(-)
+                                                     3
+
+        Now make a and b symbolic and compute the general real part:
+            sage: restore('a,b')    
+            sage: f = log(a + b*I)
+            sage: f.real()
+            log(b^2 + a^2)/2
+        """
+        return self.parent()(self._maxima_().real())
+        
+    def imag(self):
+        """
+        Return the imaginary part of self.
+
+        EXAMPLES:
+            sage: sqrt(-2).imag()
+            sqrt(2)
+
+        We simplify Ln(Exp(z)) to z for -Pi<Im(z)<=Pi:
+
+            sage: f = log(exp(z))
+            sage: assume(-pi < imag(z))
+            sage: assume(imag(z) <= pi)
+            sage: print f
+        			       z
+            sage: forget()
+
+        A more symbolic example:
+            sage: f = log(a + b*I)
+            sage: f.imag()
+            atan(b/a)
+        """
+        return self.parent()(self._maxima_().imag())
+
+    def conjugate(self):
+        """
+        The complex conjugate of self.
+        
+        EXAMPLES:
+            sage: a = 1 + 2*I 
+            sage: a.conjugate()
+            1 - 2*I
+            sage: a = sqrt(2) + 3^(1/3)*I; a
+            3^(1/3)*I + sqrt(2)
+            sage: a.conjugate()
+            sqrt(2) - 3^(1/3)*I
+        """
+        return self.parent()(self._maxima_().conjugate())
+
+    def norm(self):
+        """
+        The complex norm of self, i.e., self times its complex conjugate.
+
+        EXAMPLES:
+            sage: a = 1 + 2*I 
+            sage: a.norm()
+            5
+            sage: a = sqrt(2) + 3^(1/3)*I; a
+            3^(1/3)*I + sqrt(2)
+            sage: a.norm()
+            3^(2/3) + 2
+            sage: CDF(a).norm()
+            4.08008382305
+            sage: CDF(a.norm())
+            4.08008382305            
+        """
+        m = self._maxima_()
+        return self.parent()((m*m.conjugate()).expand())
+
+    ###################################################################
+    # Partial fractions
+    ###################################################################
+    def partial_fraction(self, var=None):
+        """
+        Return the partial fraction expansion of self with respect to
+        the given variable.
+
+        INPUT:
+            var -- variable name or string (default: first variable)
+
+        OUTPUT:
+            Symbolic expression
+
+        EXAMPLES:
+            sage: f = x^2/(x+1)^3
+            sage: f.partial_fraction()
+            1/(x + 1) - (2/(x + 1)^2) + 1/(x + 1)^3
+            sage: print f.partial_fraction()
+                                        1        2          1
+                                      ----- - -------- + --------
+                                      x + 1          2          3
+                                              (x + 1)    (x + 1)
+
+        Notice that the first variable in the expression is used by default:
+            sage: f = y^2/(y+1)^3
+            sage: f.partial_fraction()
+            1/(y + 1) - (2/(y + 1)^2) + 1/(y + 1)^3
+
+            sage: f = y^2/(y+1)^3 + x/(x-1)^3
+            sage: f.partial_fraction()
+            y^2/(y^3 + 3*y^2 + 3*y + 1) + 1/(x - 1)^2 + 1/(x - 1)^3
+
+        You can explicitly specify which variable is used. 
+            sage: f.partial_fraction(y)
+            1/(y + 1) - (2/(y + 1)^2) + 1/(y + 1)^3 + x/(x^3 - 3*x^2 + 3*x - 1)
+        """
+        if var is None:
+            var = self._first_variable()
+        return self.parent()(self._maxima_().partfrac(var))
+
+
+
 
 class Symbolic_object(SymbolicExpression):
-    r'''
-    A class representing a symbolic expression in terms of a SageObject.
-    '''
-
+    r"""
+    A class representing a symbolic expression in terms of a SageObject (not
+    necessarily a 'constant').
+    """
     def __init__(self, obj):
         SymbolicExpression.__init__(self)
         self._obj = obj
 
+    def __hash__(self):
+        return hash(self._obj)
+
+    #def derivative(self, *args):
+        # TODO: remove
+    #    return self.parent().zero_element()
+
     def obj(self):
+        """
+        EXAMPLES:
+        """
         return self._obj
 
-    def _repr_(self):
-        return str(self._obj)
+    def __float__(self):
+        """
+        EXAMPLES:
+        """
+        return float(self._obj)
+
+    def __complex__(self):
+        """
+        EXAMPLES:
+        """
+        return complex(self._obj)
+
+    def _mpfr_(self, field):
+        """
+        EXAMPLES:
+        """
+        return field(self._obj)
+    
+    def _complex_mpfr_field_(self, C):
+        """
+        EXAMPLES:
+        """
+        return C(self._obj)
+
+    def _complex_double_(self, C):
+        """
+        EXAMPLES:
+        """
+        return C(self._obj)
+
+    def _real_double_(self, R):
+        """
+        EXAMPLES:
+        """
+        return R(self._obj)
+
+    def _real_rqdf_(self, R):
+        """
+        EXAMPLES:
+        """
+        return R(self._obj)
+       
+    def _repr_(self, simplify=True):
+        """
+        EXAMPLES:
+        """
+        return repr(self._obj)
 
     def _latex_(self):
+        """
+        EXAMPLES:
+        """
         return latex(self._obj)
-
-    def __pow__(self, right):
-        if isinstance(right, Symbolic_object):
-            try:
-                return Symbolic_object(self._obj + right._obj)
-            except TypeError:
-                pass
-        return SymbolicExpression.__pow__(self, right)
-
-    def _add_(self, right):
-        if isinstance(right, Symbolic_object):
-            try:
-                return Symbolic_object(self._obj + right._obj)
-            except TypeError:
-                pass
-        return SymbolicExpression._add_(self, right)
-
-    def _sub_(self, right):
-        if isinstance(right, Symbolic_object):
-            try:
-                return Symbolic_object(self._obj - right._obj)
-            except TypeError:
-                pass
-        return SymbolicExpression._sub_(self, right)
-
-    def _mul_(self, right):
-        if isinstance(right, Symbolic_object):
-            try:
-                return Symbolic_object(self._obj * right._obj)
-            except TypeError:
-                pass
-        return SymbolicExpression._mul_(self, right)
-
-    def _div_(self, right):
-        if isinstance(right, Symbolic_object):
-            try:
-                return Symbolic_object(self._obj / right._obj)
-            except TypeError:
-                pass
-        return SymbolicExpression._div_(self, right)
 
     def str(self, bits=None):
@@ -520,28 +2224,144 @@
             return str(R(self._obj))
 
-    def _maxima_(self, maxima=maxima):
+    def _maxima_init_(self):
+        return maxima_init(self._obj)    
+
+    def _sys_init_(self, system):
+        return sys_init(self._obj, system)
+
+def maxima_init(x):
+    try:
+        return x._maxima_init_()
+    except AttributeError:
+        return repr(x)
+
+def sys_init(x, system):
+    try:
+        return x.__getattribute__('_%s_init_'%system)()
+    except AttributeError:
         try:
-            return self.__maxima
+            return x._system_init_(system)
         except AttributeError:
-            m = maxima(self._obj)
-            self.__maxima = m
-            return m
+            return repr(x)
+
+class SymbolicConstant(Symbolic_object):
+    def __init__(self, x):
+        Symbolic_object.__init__(self, x)
+
+    def _is_atomic(self):
+        try:
+            return self._atomic
+        except AttributeError:
+            if isinstance(self, Rational):
+                self._atomic = False
+            else:
+                self._atomic = True
+            return self._atomic
+
+    def _recursive_sub(self, kwds):
+        """
+        EXAMPLES:
+            sage: a = SR(5/6)
+            sage: type(a)
+            <class 'sage.calculus.calculus.SymbolicConstant'>
+            sage: a(x=3)
+            5/6
+        """
+        return self
+
+    def _recursive_sub_over_ring(self, kwds, ring):
+        return ring(self)
+    
+
 
 class SymbolicPolynomial(Symbolic_object):
-    "An element of a polynomial ring as a formal symbolic expression."
-
-    # for now we do nothing except pass the info on to the supercontructor. It's
+    """
+    An element of a polynomial ring as a formal symbolic expression.
+
+    EXAMPLES:
+    A single variate polynomial:
+        sage: R.<x> = QQ[]
+        sage: f = SR(x^3 + x)
+        sage: f(y=7)
+        x^3 + x
+        sage: f(x=5)
+        130
+        sage: f.integral(x)
+        x^4/4 + x^2/2
+        sage: f(x=y)
+        y^3 + y
+
+    A multivariate polynomial:
+    
+        sage: R.<x,y,theta> = ZZ[]
+        sage: f = SR(x^3 + x + y + theta^2); f
+        theta^2 + y + x + x^3
+        sage: f(x=y, theta=y)
+        y^3 + y^2 + 2*y
+        sage: f(x=5)
+        y + theta^2 + 130
+        
+    The polynomial must be over a field of characteristic 0.
+        sage: R.<w> = GF(7)[]
+        sage: f = SR(w^3 + 1)
+        Traceback (most recent call last):
+        ...
+        TypeError: polynomial must be over a field of characteristic 0.    
+    """
+    # for now we do nothing except pass the info on to the superconstructor. It's
     # not clear to me why we need anything else in this class -Bobby
     def __init__(self, p):
-       Symbolic_object.__init__(self, p) 
-
-class SymbolicConstant(SymbolicExpression):
-    def __call__(self, x):
-        return self
-
-class Constant_object(SymbolicConstant, Symbolic_object):
-    pass
-
-zero_constant = Constant_object(Integer(0))
+        if p.parent().base_ring().characteristic() != 0:
+            raise TypeError, "polynomial must be over a field of characteristic 0."
+        Symbolic_object.__init__(self, p)
+
+    def _recursive_sub(self, kwds):
+        return self._recursive_sub_over_ring(kwds, ring)
+
+    def _recursive_sub_over_ring(self, kwds, ring):
+        f = self._obj
+        if is_Polynomial(f):
+            # Single variable case
+            v = f.parent().variable_name()
+            if kwds.has_key(v):
+                return ring(f(kwds[v]))
+            else:
+                if not ring is SR:
+                    return ring(self)
+        else:
+            # Multivariable case
+            t = []
+            for g in f.parent().gens():
+                s = repr(g)
+                if kwds.has_key(s):
+                    t.append(kwds[s])
+                else:
+                    t.append(g)
+            return ring(f(*t))
+
+    def polynomial(self, base_ring):
+        """
+        Return self as a polynomial over the given base ring, if possible.
+
+        INPUT:
+           base_ring -- a ring
+
+        EXAMPLES:
+            sage: R.<x> = QQ[]
+            sage: f = SR(x^2 -2/3*x + 1)
+            sage: f.polynomial(QQ)
+            x^2 - 2/3*x + 1
+            sage: f.polynomial(GF(19))
+            x^2 + 12*x + 1
+        """
+        f = self._obj
+        if base_ring is f.base_ring():
+            return f
+        return f.change_ring(base_ring)
+
+##################################################################
+        
+
+zero_constant = SymbolicConstant(Integer(0))
 
 class SymbolicOperation(SymbolicExpression):
@@ -551,33 +2371,40 @@
     def __init__(self, operands):
         SymbolicExpression.__init__(self)
-        self._operands = [SER(op) for op in operands]
-
-class SymbolicComposition(SymbolicOperation):
-    r'''
-    Represents the symbolic composition of $f \circ g$.
-    '''
-    def __init__(self, f, g):
-        SymbolicOperation.__init__(self, [f,g])
-
-    def _is_atomic(self):
-        return True
-
-    def _repr_(self):
-        ops = self._operands
-        return "%s(%s)"% (ops[0]._repr_(), ops[1]._repr_())
-
-    def _latex_(self):
-        ops = self._operands
-        return r"%s \left( %s \right)"% (latex(ops[0]), latex(ops[1]))
-
-    def _maxima_(self, maxima=maxima):
+        self._operands = operands   # don't even make a copy -- ok, since immutable.
+
+    def variables(self, vars=tuple([])):
+        """
+        Return sorted list of variables that occur in the simplified
+        form of self.  The ordering is alphabetic.
+
+        EXAMPLES:
+            sage: x,y,z,w = var('x,y,z,w')
+            sage: f = (x - x) + y^2 - z/z + (w^2-1)/(w+1); f
+            y^2 + (w^2 - 1)/(w + 1) - 1
+            sage: f.variables()
+            (w, y)
+
+            sage: (x + y + z + a + b + c).variables()
+            (a, b, c, x, y, z)
+
+            sage: (x^2 + x).variables()
+            (x,)
+        """
+        if not self.is_simplified():
+            return self.simplify().variables(vars)
+        
         try:
-            return self.__maxima
+            return self.__variables
         except AttributeError:
-            ops = self._operands
-            m = ops[0]._maxima_(maxima)(ops[1]._maxima_(maxima))
-            self.__maxima = m
-            return m
+            pass
+        vars = list(set(sum([list(op.variables()) for op in self._operands], list(vars))))
         
+        vars.sort(var_cmp)
+        vars = tuple(vars)
+        self.__variables = vars
+        return vars
+
+def var_cmp(x,y):
+    return cmp(repr(x), repr(y))
 
 symbols = {operator.add:' + ', operator.sub:' - ', operator.mul:'*',
@@ -586,82 +2413,178 @@
 
 class SymbolicArithmetic(SymbolicOperation):
-    r'''
+    r"""
     Represents the result of an arithemtic operation on
     $f$ and $g$.
-    '''
-
+    """
     def __init__(self, operands, op):
         SymbolicOperation.__init__(self, operands)
+        self._operator = op
+
+    def _recursive_sub(self, kwds):
+        """
+        EXAMPLES:
+            sage: f = (x - x) + y^2 - z/z + (w^2-1)/(w+1); f
+            y^2 + (w^2 - 1)/(w + 1) - 1
+            sage: f(y=10)
+            (w^2 - 1)/(w + 1) + 99
+            sage: f(w=1,y=10)
+            99
+            sage: f(y=w,w=y)
+            (y^2 - 1)/(y + 1) + w^2 - 1
+
+            sage: f = y^5 - sqrt(2)
+            sage: f(10)
+            100000 - sqrt(2)
+        """
+        ops = self._operands
+        new_ops = [SR(op._recursive_sub(kwds)) for op in ops]
+        return self._operator(*new_ops)
+
+    def _recursive_sub_over_ring(self, kwds, ring):
+        ops = self._operands
+        if self._operator == operator.pow:
+            new_ops = [ops[0]._recursive_sub_over_ring(kwds, ring=ring), Integer(ops[1])]
+        else:
+            new_ops = [op._recursive_sub_over_ring(kwds, ring=ring) for op in ops]                
+        return ring(self._operator(*new_ops))
         
-        if op is operator.add:
-            self._atomic = False
-        elif op is operator.sub:
-            self._atomic = False
-        elif op is operator.mul:
-            self._atomic = True
-        elif op is operator.div:
-            self._atomic = False
-        elif op is operator.pow:
-            self._atomic = True
-        elif op is operator.neg:
-            self._atomic = False
-
-        self._operator = op
+    def __float__(self):
+        fops = [float(op) for op in self._operands]
+        return self._operator(*fops)
+
+    def __complex__(self):
+        fops = [complex(op) for op in self._operands]
+        return self._operator(*fops)
+
+    def _mpfr_(self, field):
+        if not self.is_simplified():
+            return self.simplify()._mpfr_(field)
+        rops = [op._mpfr_(field) for op in self._operands]
+        return self._operator(*rops)
+
+    def _complex_mpfr_field_(self, field):
+        if not self.is_simplified():
+            return self.simplify()._complex_mpfr_field_(field)
+        rops = [op._complex_mpfr_field_(field) for op in self._operands]
+        return self._operator(*rops)
+
+    def _complex_double_(self, field):
+        if not self.is_simplified():
+            return self.simplify()._complex_double_(field)
+        rops = [op._complex_double_(field) for op in self._operands]
+        return self._operator(*rops)
+
+    def _real_double_(self, field):
+        if not self.is_simplified():
+            return self.simplify()._real_double_(field)
+        rops = [op._real_double_(field) for op in self._operands]
+        return self._operator(*rops)
+
+    def _real_rqdf_(self, field):
+        if not self.is_simplified():
+            return self.simplify()._real_rqdf_(field)
+        rops = [op._real_rqdf_(field) for op in self._operands]
+        return self._operator(*rops)
 
     def _is_atomic(self):
-        return self._atomic
-
-    def _repr_(self):
+        try:
+            return self._atomic
+        except AttributeError:
+            op = self._operator
+            # todo: optimize with a dictionary
+            if op is operator.add:
+                self._atomic = False
+            elif op is operator.sub:
+                self._atomic = False
+            elif op is operator.mul:
+                self._atomic = True
+            elif op is operator.div:
+                self._atomic = False
+            elif op is operator.pow:
+                self._atomic = True
+            elif op is operator.neg:
+                self._atomic = False
+            return self._atomic
+
+    def _repr_(self, simplify=True):
+        """
+        TESTS:
+            sage: a = (1-1/r)^(-1); a
+            1/(1 - (1/r))
+            sage: a.derivative(r)
+            -1/((1 - (1/r))^2*r^2)
+
+            sage: reset('a,b')
+            sage: s = 0*(1/a) + -b*(1/a)*(1 + -1*0*(1/a))*(1/(a*b + -1*b*(1/a)))
+            sage: s
+            -b/(a*(a*b - (b/a)))
+            sage: s(a=2,b=3)
+            -1/3
+            sage: -3/(2*(2*3-(3/2)))
+            -1/3
+        """
+        if simplify:
+            if hasattr(self, '_simp'):
+                return self._simp._repr_(simplify=False)
+            else:
+                return self.simplify()._repr_(simplify=False)
 
         ops = self._operands
         op = self._operator
+
+        s = [o._repr_(simplify=False) for o in ops]
         
-        s = [str(o) for o in ops]
         # for the left operand, we need to surround it in parens when the
         # operator is mul/div/pow, and when the left operand contains an
         # operation of lower precedence
-        if op in [operator.mul, operator.div, operator.pow]:
+        if op in [operator.mul, operator.div]: 
             if ops[0]._has_op(operator.add) or ops[0]._has_op(operator.sub):
                 if not ops[0]._is_atomic():
                     s[0] = '(%s)' % s[0]
-        # for the right operand, we need to surround it in parens when the
-        # operation is mul/div/sub and the, and when the right operand contains
-        # a + or -.
-        if op in [operator.mul, operator.div, operator.sub]:
-            if ops[1]._has_op(operator.add) or ops[1]._has_op(operator.sub):
+            else:
+                try:
+                    if isinstance(ops[0]._obj, Rational):
+                        s[0] = '(%s)' % s[0]
+                except AttributeError:
+                    pass
+                try:
+                    if isinstance(ops[1]._obj, Rational):
+                        s[1] = '(%s)' % s[1]
+                except AttributeError:
+                    pass
+
+        # for the right operand, we need to surround it in parens when
+        # the operation is mul/div/sub, and when the right operand
+        # contains a + or -.
+        if op in [operator.mul, operator.sub]:
                 # avoid drawing parens if s1 an atomic operation
                 if not ops[1]._is_atomic():
                     s[1] = '(%s)' % s[1]
-        # if we have a compound expression on the right, then we need parens on
-        # the right... but in TeX, this is expressed by font size and position
+
+        elif op is operator.div:
+            if not ops[1]._is_atomic() or ops[1]._has_op(operator.mul):
+                s[1] = '(%s)' % s[1]
+
         elif op is operator.pow:
-            if ops[1]._has_op(operator.add) or  \
-            ops[1]._has_op(operator.sub) or  \
-            ops[1]._has_op(operator.mul) or  \
-            ops[1]._has_op(operator.div) or  \
-            ops[1]._has_op(operator.pow):
-                s[1] = '(%s)' % s[1]
+            if not ops[0]._is_atomic():
+                s[0] = '(%s)'% s[0]
+            if not ops[1]._is_atomic() or ('/' in s[1] or '*' in s[1]):
+                s[1] = '(%s)'% s[1]
+
         if op is operator.neg:
-            return '-%s' % s[0]
+            if ops[0]._is_atomic():
+                return '-%s' % s[0]
+            else:
+                return '-(%s)'%s[0]
         else:
             return '%s%s%s' % (s[0], symbols[op], s[1])
 
     def _latex_(self):
+        # if we are not simplified, return the latex of a simplified version
+        if not self.is_simplified():
+            return self.simplify()._latex_()
         op = self._operator
         ops = self._operands
-        ops_tex = [x._latex_() for x in self._operands]
-
-        s = [o._latex_() for o in ops]
-        
-        # follow a very similar logic to _repr_, but we don't parenthesize
-        # exponents
-        if op in [operator.mul, operator.div, operator.pow]:
-            if ops[0]._has_op(operator.add) or ops[0]._has_op(operator.sub):
-                if not ops[0]._is_atomic():
-                    s[0] = '\\left( %s \\right)' % s[0]
-        if op in [operator.mul, operator.div, operator.sub]:
-            if ops[1]._has_op(operator.add) or ops[1]._has_op(operator.sub):
-                if not ops[1]._is_atomic():
-                    s[1] = '\\left( %s \\right)' % s[1]
+        s = [x._latex_() for x in self._operands]
 
         if op is operator.add:
@@ -670,24 +2593,37 @@
             return '%s - %s' % (s[0], s[1])
         elif op is operator.mul:
+            if ops[0]._has_op(operator.add) or ops[0]._has_op(operator.sub):
+                s[0] = r'\left( %s \right)' %s[0]
+            if ops[1]._has_op(operator.add) or ops[1]._has_op(operator.sub):
+                s[1] = r'\left( %s \right)' %s[1]
             return '{%s \\cdot %s}' % (s[0], s[1])
         elif op is operator.div:
             return '\\frac{%s}{%s}' % (s[0], s[1])
         elif op is operator.pow:
+            if ops[0]._has_op(operator.add) or ops[0]._has_op(operator.sub) \
+               or ops[0]._has_op(operator.mul) or ops[0]._has_op(operator.div) \
+               or ops[0]._has_op(operator.pow):
+                s[0] = r'\left( %s \right)' % s[0]
             return '{%s}^{%s} ' % (s[0], s[1])
         elif op is operator.neg:
             return '-%s' % s[0]
 
-    def _maxima_(self, maxima=maxima):
-        try:
-            return self.__maxima
-        except AttributeError:
-            ops = self._operands
-            if self._operator is operator.neg:
-                m = self._operator(ops[0]._maxima_(maxima))
-            else:
-                m = self._operator(ops[0]._maxima_(maxima),
-                                      ops[1]._maxima_(maxima))
-            self.__maxima = m
-            return m
+    def _maxima_init_(self):
+        ops = self._operands
+        if self._operator is operator.neg:
+            return '-(%s)' % ops[0]._maxima_init_()
+        else:
+            return '(%s) %s (%s)' % (ops[0]._maxima_init_(),
+                             infixops[self._operator],
+                             ops[1]._maxima_init_())
+
+    def _sys_init_(self, system):
+        ops = self._operands
+        if self._operator is operator.neg:
+            return '-(%s)' % sys_init(ops[0], system)
+        else:
+            return '(%s) %s (%s)' % (sys_init(ops[0], system),
+                             infixops[self._operator],
+                             sys_init(ops[1], system))
 
 import re
@@ -700,8 +2636,37 @@
             raise ValueError, "variable name must be nonempty"
 
-    def __call__(self, x):
-        raise AttributeError, "A symbolic variable is not callable."
-
-    def _repr_(self):
+    def __hash__(self):
+        return hash(self._name)
+
+    def _recursive_sub(self, kwds):
+        # do the replacement if needed
+        if kwds.has_key(self):
+            return kwds[self]
+        else:
+            return self
+
+    def _recursive_sub_over_ring(self, kwds, ring):
+        if kwds.has_key(self):
+            return ring(kwds[self])
+        else:
+            return ring(self)
+
+    def variables(self, vars=tuple([])):
+        """
+        Return sorted list of variables that occur in the simplified
+        form of self.
+        """
+        return (self, )
+
+    def __cmp__(self, right):
+        if isinstance(right, SymbolicVariable):
+            return cmp(self._repr_(), right._repr_())
+        else:
+            return SymbolicExpression.__cmp__(self, right)
+
+    def _repr_(self, simplify=True):
+        return self._name
+
+    def __str__(self):
         return self._name
 
@@ -723,11 +2688,9 @@
         return a
 
-    def _maxima_(self, maxima=maxima):
-        try:
-            return self.__maxima
-        except AttributeError:
-            m = maxima(self._name)
-            self.__maxima = m
-            return m
+    def _maxima_init_(self):
+        return self._name
+
+    def _sys_init_(self, system):
+        return self._name
 
 common_varnames = ['alpha',
@@ -766,32 +2729,849 @@
 
 def tex_varify(a):
-    if a in common_varnames: 
+    if a in common_varnames:
         return "\\" + a
+    elif len(a) == 1:
+        return a
     else:
         return '\\mbox{%s}'%a
     
 _vars = {}
-def var(s):
-    r''' Create a symbolic variable with the name \emph{s}'''
+def var(s, create=True):
+    r"""
+    Create a symbolic variable with the name \emph{s}.
+
+    EXAMPLES:
+        sage: var('xx')
+        xx
+    """
+    if isinstance(s, SymbolicVariable):
+        return s
+    s = str(s)
+    if ',' in s:
+        return tuple([var(x.strip()) for x in s.split(',')])
+    elif ' ' in s:
+        return tuple([var(x.strip()) for x in s.split()])
     try:
-        return _vars[s]
+        v = _vars[s]
+        _syms[s] = v
+        return v
     except KeyError:
-        v = SymbolicVariable(s)
-        _vars[s] = v
-        return v
+        if not create:
+            raise ValueError, "the variable '%s' has not been defined"%var
+        pass
+    v = SymbolicVariable(s)
+    _vars[s] = v
+    _syms[s] = v
+    return v
+
+
+#########################################################################################
+#  Callable functions
+#########################################################################################
+def is_CallableSymbolicExpressionRing(x):
+    """
+    EXAMPLES:
+        sage: is_CallableSymbolicExpressionRing(QQ)
+        False
+        sage: is_CallableSymbolicExpressionRing(CallableSymbolicExpressionRing((x,y,z)))
+        True
+    """
+    return isinstance(x, CallableSymbolicExpressionRing_class)
+
+class CallableSymbolicExpressionRing_class(CommutativeRing):
+    def __init__(self, args):
+        self._default_precision = 53 # default precision bits
+        self._args = args
+        ParentWithBase.__init__(self, RR)
+
+    def __call__(self, x):
+        """
+
+        TESTS:
+            sage: f(x) = x+1; g(y) = y+1
+            sage: f.parent()(g)
+            x |--> y + 1
+            sage: g.parent()(f)
+            y |--> x + 1
+            sage: f(x) = x+2*y; g(y) = y+3*x
+            sage: f.parent()(g)
+            x |--> y + 3*x
+            sage: g.parent()(f)
+            y |--> 2*y + x
+        """
+        return self._coerce_impl(x)
+
+    def _coerce_impl(self, x):
+        if isinstance(x, SymbolicExpression):
+            if isinstance(x, CallableSymbolicExpression):
+                x = x._expr
+            return CallableSymbolicExpression(self, x)
+        return self._coerce_try(x, [SR])
+
+    def _repr_(self):
+        return "Callable function ring with arguments %s"%(self._args,)
+
+    def args(self):
+        return self._args
+
+    def arguments(self):
+        return self.args()
+
+    def zero_element(self):
+        try:
+            return self.__zero_element
+        except AttributeError:
+            z = CallableSymbolicExpression(SR.zero_element(), self._args)
+            self.__zero_element = z
+            return z
+
+    def _an_element_impl(self):
+        return self.zero_element()
+
+
+_cfr_cache = {}
+def CallableSymbolicExpressionRing(args, check=True):
+    if check:
+        if len(args) == 1 and isinstance(args[0], (list, tuple)):
+            args = args[0]
+        for arg in args:
+            if not isinstance(arg, SymbolicVariable):
+                raise TypeError, "Must construct a function with a tuple (or list) of" \
+                                +" SymbolicVariables."
+        args = tuple(args)
+    if _cfr_cache.has_key(args):
+        R = _cfr_cache[args]()
+        if not R is None:
+            return R
+    R = CallableSymbolicExpressionRing_class(args)
+    _cfr_cache[args] = weakref.ref(R)
+    return R
+
+def is_CallableSymbolicExpression(x):
+    """
+    Returns true if x is a callable symbolic expression.
+    
+    EXAMPLES:
+        sage: f(x,y) = a + 2*x + 3*y + z
+        sage: is_CallableSymbolicExpression(f)
+        True
+        sage: is_CallableSymbolicExpression(a+2*x)
+        False
+        sage: def foo(n): return n^2
+        ...
+        sage: is_CallableSymbolicExpression(foo)
+        False
+    """
+    return isinstance(x, CallableSymbolicExpression)
+
+class CallableSymbolicExpression(SymbolicExpression):
+    r"""
+    A callable symbolic expression that knows the ordered list of
+    variables on which it depends.
+
+    EXAMPLES:
+        sage: f(x,y) = a + 2*x + 3*y + z
+        sage: f
+        (x, y) |--> z + 3*y + 2*x + a
+        sage: f(1,2)
+        z + a + 8
+    """
+    def __init__(self, parent, expr):
+        RingElement.__init__(self, parent)
+        self._expr = expr
+
+    def variables(self):
+        """
+        EXAMPLES:
+            sage: g(x) = sin(x) + a
+            sage: g.variables()
+            (a, x)
+            sage: g.args()
+            (x,)
+            sage: g(y,x,z) = sin(x) + a - a
+            sage: g
+            (y, x, z) |--> sin(x)
+            sage: g.args()
+            (y, x, z)
+        """
+        return self._expr.variables()
+
+    def integral(self, x=None, a=None, b=None):
+        """
+        Returns an integral of self. 
+        """
+        if a is None:
+            return SymbolicExpression.integral(self, x, None, None)
+            # if l. endpoint is None, compute an indefinite integral
+        else:
+            if x is None:
+                x = self.default_variable()
+            if not isinstance(x, SymbolicVariable):
+                x = var(repr(x))
+                # if we supplied an endpoint, then we want to return a number.
+            return SR(self._maxima_().integrate(x, a, b))
+
+    integrate = integral
+
+    def expression(self):
+        """
+        Return the underlying symbolic expression (i.e., forget the
+        extra map structure).
+        """
+        return self._expr
+
+    def args(self):
+        return self.parent().args()
+
+    def arguments(self):
+        return self.args()
+
+    def _maxima_init_(self):
+        return self._expr._maxima_init_()
+
+    def __float__(self):
+        return float(self._expr)
+
+    def __complex__(self):
+        return complex(self._expr)
+    
+    def _mpfr_(self, field):
+        """
+        Coerce to a multiprecision real number.
+
+        EXAMPLES:
+            sage: RealField(100)(SR(10))
+            10.000000000000000000000000000
+        """
+        return (self._expr)._mpfr_(field)
+
+    def _complex_mpfr_field_(self, field):
+        return field(self._expr)
+
+    def _complex_double_(self, C):
+        return C(self._expr)
+
+    def _real_double_(self, R):
+        return R(self._expr)
+
+    def _real_rqdf_(self, R):
+        return R(self._expr)
+
+    # TODO: should len(args) == len(vars)?
+    def __call__(self, *args):
+        vars = self.args()
+        dct = dict( (vars[i], args[i]) for i in range(len(args)) )
+        return self._expr.substitute(dct)
+
+    def _repr_(self, simplify=True):
+        args = self.args()
+        if len(args) == 1:
+            return "%s |--> %s" % (args[0], self._expr._repr_(simplify=simplify))
+        else:
+            args = ", ".join(map(str, args))
+            return "(%s) |--> %s" % (args, self._expr._repr_(simplify=simplify))
+
+    def _latex_(self):
+        args = self.args()
+        if len(args) == 1:
+            return "%s \\ {\mapsto}\\ %s" % (args[0],
+                    self._expr._latex_())
+        else:
+            vars = ", ".join(map(latex, args))
+            # the weird TeX is to workaround an apparent JsMath bug
+            return "\\left(%s \\right)\\ {\\mapsto}\\ %s" % (args, self._expr._latex_())
+
+    def _neg_(self):
+        return CallableSymbolicExpression(self.parent(), -self._expr)
+
+    def __add__(self, right):
+        """        
+        EXAMPLES:
+            sage: f(x,n,y) = x^n + y^m;  g(x,n,m,z) = x^n +z^m
+            sage: f + g
+            (x, n, m, y, z) |--> z^m + y^m + 2*x^n
+            sage: g + f
+            (x, n, m, y, z) |--> z^m + y^m + 2*x^n
+        """
+        if isinstance(right, CallableSymbolicExpression):
+            if self.parent() is right.parent():
+                return self._add_(right)
+            else:
+                args = self._unify_args(right)
+                R = CallableSymbolicExpressionRing(args)
+                return R(self) + R(right)
+        else:
+            return RingElement.__add__(self, right)
+
+    def _add_(self, right):
+        return CallableSymbolicExpression(self.parent(), self._expr + right._expr)
+
+    def __sub__(self, right):
+        """
+        EXAMPLES:
+            sage: f(x,n,y) = x^n + y^m;  g(x,n,m,z) = x^n +z^m            
+            sage: f - g
+            (x, n, m, y, z) |--> y^m - z^m
+            sage: g - f
+            (x, n, m, y, z) |--> z^m - y^m
+        """
+        if isinstance(right, CallableSymbolicExpression):
+            if self.parent() is right.parent():
+                return self._sub_(right)
+            else:
+                args = self._unify_args(right)
+                R = CallableSymbolicExpressionRing(args)
+                return R(self) - R(right)
+        else:
+            return RingElement.__sub__(self, right)
+
+    def _sub_(self, right):
+        return CallableSymbolicExpression(self.parent(), self._expr - right._expr)
+
+    def __mul__(self, right):
+        """
+        EXAMPLES:
+            sage: f(x) = x+2*y; g(y) = y+3*x
+            sage: f*(2/3)
+            x |--> 2*(2*y + x)/3
+            sage: f*g
+            (x, y) |--> (y + 3*x)*(2*y + x)
+            sage: (2/3)*f
+            x |--> 2*(2*y + x)/3
+            
+            sage: f(x,y,z,a,b) = x+y+z-a-b; f
+            (x, y, z, a, b) |--> z + y + x - b - a
+            sage: f * (b*c)
+            (x, y, z, a, b) |--> b*c*(z + y + x - b - a)
+            sage: g(x,y,w,t) = x*y*w*t
+            sage: f*g
+            (x, y, a, b, t, w, z) |--> t*w*x*y*(z + y + x - b - a)
+            sage: (f*g)(2,3)
+            6*t*w*(z - b - a + 5)
+
+            sage: f(x,n,y) = x^n + y^m;  g(x,n,m,z) = x^n +z^m
+            sage: f * g
+            (x, n, m, y, z) |--> (y^m + x^n)*(z^m + x^n)
+            sage: g * f
+            (x, n, m, y, z) |--> (y^m + x^n)*(z^m + x^n)
+        """
+        if isinstance(right, CallableSymbolicExpression):
+            if self.parent() is right.parent():
+                return self._mul_(right)
+            else:
+                args = self._unify_args(right)
+                R = CallableSymbolicExpressionRing(args)
+                return R(self)*R(right)
+        else:
+            return RingElement.__mul__(self, right)
+
+    def _mul_(self, right):
+        return CallableSymbolicExpression(self.parent(), self._expr * right._expr)
+
+    def __div__(self, right):
+        """
+        EXAMPLES:
+
+            sage: f(x,n,y) = x^n + y^m;  g(x,n,m,z) = x^n +z^m            
+            sage: f / g
+            (x, n, m, y, z) |--> (y^m + x^n)/(z^m + x^n)
+            sage: g / f
+            (x, n, m, y, z) |--> (z^m + x^n)/(y^m + x^n)
+        """
+        if isinstance(right, CallableSymbolicExpression):
+            if self.parent() is right.parent():
+                return self._div_(right)
+            else:
+                args = self._unify_args(right)
+                R = CallableSymbolicExpressionRing(args)
+                return R(self) / R(right)
+        else:
+            return RingElement.__div__(self, right)
+
+    def _div_(self, right):
+        return CallableSymbolicExpression(self.parent(), self._expr / right._expr)
+    
+    def __pow__(self, right):
+        return CallableSymbolicExpression(self.parent(), self._expr ** right)
+
+    def _unify_args(self, x):
+        r"""
+        Takes the variable list from another CallableSymbolicExpression object and
+        compares it with the current CallableSymbolicExpression object's variable list,
+        combining them according to the following rules:
+
+        Let \code{a} be \code{self}'s variable list, let \code{b} be
+        \code{y}'s variable list. 
+        
+        \begin{enumerate}
+
+        \item If \code{a == b}, then the variable lists are identical,
+              so return that variable list.
+
+        \item If \code{a} $\neq$ \code{b}, then check if the first $n$
+              items in \code{a} are the first $n$ items in \code{b},
+              or vice-versa. If so, return a list with these $n$
+              items, followed by the remaining items in \code{a} and
+              \code{b} sorted together in alphabetical order.
+        
+        \end{enumerate}
+
+        Note: When used for arithmetic between CallableSymbolicExpressions,
+        these rules ensure that the set of CallableSymbolicExpressions will have
+        certain properties.  In particular, it ensures that the set is
+        a \emph{commutative} ring, i.e., the order of the input
+        variables is the same no matter in which order arithmetic is
+        done.
+
+        INPUT:
+            x -- A CallableSymbolicExpression
+
+        OUTPUT:
+            A tuple of variables.
+        
+        EXAMPLES:
+            sage: f(x, y, z) = sin(x+y+z)
+            sage: f
+            (x, y, z) |--> sin(z + y + x)
+            sage: g(x, y) = y + 2*x
+            sage: g
+            (x, y) |--> y + 2*x
+            sage: f._unify_args(g)
+            (x, y, z)
+            sage: g._unify_args(f)
+            (x, y, z)
+
+            sage: f(x, y, z) = sin(x+y+z)
+            sage: g(w, t) = cos(w - t)
+            sage: g
+            (w, t) |--> cos(w - t)
+            sage: f._unify_args(g)
+            (t, w, x, y, z)
+
+            sage: f(x, y, t) = y*(x^2-t)
+            sage: f
+            (x, y, t) |--> (x^2 - t)*y
+            sage: g(x, y, w) = x + y - cos(w)
+            sage: f._unify_args(g)
+            (x, y, t, w)
+            sage: g._unify_args(f)
+            (x, y, t, w)
+            sage: f*g
+            (x, y, t, w) |--> (x^2 - t)*y*(y + x - cos(w))
+            
+            sage: f(x,y, t) = x+y
+            sage: g(x, y, w) = w + t
+            sage: f._unify_args(g)
+            (x, y, t, w)
+            sage: g._unify_args(f)
+            (x, y, t, w)
+            sage: f + g
+            (x, y, t, w) |--> y + x + w + t
+
+        AUTHORS:
+            -- Bobby Moretti, thanks to William Stein for the rules
+
+        """
+        a = self.args()
+        b = x.args()
+
+        # Rule #1
+        if [str(x) for x in a] == [str(x) for x in b]:
+            return a
+
+        # Rule #2
+        new_list = []
+        done = False
+        i = 0
+        while not done and i < min(len(a), len(b)):
+            if var_cmp(a[i], b[i]) == 0:
+                new_list.append(a[i])
+                i += 1
+            else:
+                done = True
+        
+        temp = set([])
+        # Sorting remaining variables.
+        for j in range(i, len(a)):
+            if not a[j] in temp:
+                temp.add(a[j])
+        
+        for j in range(i, len(b)):
+            if not b[j] in temp:
+                temp.add(b[j])
+
+        temp = list(temp)
+        temp.sort(var_cmp)
+        new_list.extend(temp)
+        return tuple(new_list)
+
+
+#########################################################################################
+#  End callable functions
+#########################################################################################
+
+class SymbolicComposition(SymbolicOperation):
+    r"""
+    Represents the symbolic composition of $f \circ g$.
+    """
+    def __init__(self, f, g):
+        """
+        INPUT:
+            f, g -- both must be in the symbolic expression ring.
+        """
+        SymbolicOperation.__init__(self, [f,g])
+
+    def _recursive_sub(self, kwds):
+        ops = self._operands
+        return ops[0](ops[1]._recursive_sub(kwds))
+    
+    def _recursive_sub_over_ring(self, kwds, ring):
+        ops = self._operands
+        return ring(ops[0](ops[1]._recursive_sub_over_ring(kwds, ring=ring)))
+
+    def _is_atomic(self):
+        return True
+
+    def _repr_(self, simplify=True):
+        if simplify:
+            if hasattr(self, '_simp'):
+                return self._simp._repr_(simplify=False)
+            else:
+                return self.simplify()._repr_(simplify=False)
+        ops = self._operands
+        try:
+            return ops[0]._repr_evaled_(ops[1]._repr_(simplify=False))
+        except AttributeError:
+            return "%s(%s)"% (ops[0]._repr_(simplify=False), ops[1]._repr_(simplify=False))
+
+    def _maxima_init_(self):
+        ops = self._operands
+        try:
+            return ops[0]._maxima_init_evaled_(ops[1]._maxima_init_())
+        except AttributeError:
+            return '%s(%s)' % (ops[0]._maxima_init_(), ops[1]._maxima_init_())
+        
+    def _latex_(self):
+        if not self.is_simplified():
+            return self.simplify()._latex_()
+        ops = self._operands
+        # certain functions (such as \sqrt) need braces in LaTeX
+        if (ops[0]).tex_needs_braces():
+            return r"%s{ %s }" % ( (ops[0])._latex_(), (ops[1])._latex_())
+        # ... while others (such as \cos) don't
+        return r"%s \left( %s \right)"%((ops[0])._latex_(),(ops[1])._latex_())
+
+    def _sys_init_(self, system):
+        ops = self._operands
+        return '%s(%s)' % (sys_init(ops[0],system), sys_init(ops[1],system))
+
+    def _mathematica_init_(self):
+        system = 'mathematica'
+        ops = self._operands
+        return '%s[%s]' % (sys_init(ops[0],system).capitalize(), sys_init(ops[1],system))
+
+    def __float__(self):
+        f = self._operands[0]
+        g = self._operands[1]
+        return float(f._approx_(float(g)))
+
+    def __complex__(self):
+        f = self._operands[0]
+        g = self._operands[1]
+        return complex(f._approx_(float(g)))
+
+    def _mpfr_(self, field):
+        """
+        Coerce to a multiprecision real number.
+        
+        EXAMPLES:
+            sage: RealField(100)(sin(2)+cos(2))
+            0.49315059027853930839845163641
+
+            sage: RR(sin(pi))
+            0.000000000000000
+            
+            sage: type(RR(sqrt(163)*pi))
+            <type 'sage.rings.real_mpfr.RealNumber'>
+
+            sage: RR(coth(pi))
+            1.00374187319732
+            sage: RealField(100)(coth(pi))
+            1.0037418731973212882015526912
+            sage: RealField(200)(acos(1/10))
+            1.4706289056333368228857985121870581235299087274579233690964            
+        """
+        if not self.is_simplified():
+            return self.simplify()._mpfr_(field)
+        f = self._operands[0]
+        g = self._operands[1]
+        x = f(g._mpfr_(field))
+        if isinstance(x, SymbolicExpression):
+            if field.prec() <= 53:
+                return field(float(x))
+            else:
+                raise TypeError, "precision loss"
+        else:
+            return x
+
+
+    def _complex_mpfr_field_(self, field):
+        """
+        Coerce to a multiprecision complex number.
+        
+        EXAMPLES:
+            sage: ComplexField(100)(sin(2)+cos(2)+I)
+            0.49315059027853930839845163641 + 1.0000000000000000000000000000*I
+            
+        """
+        if not self.is_simplified():
+            return self.simplify()._complex_mpfr_field_(field)
+        f = self._operands[0]
+        g = self._operands[1]
+        x = f(g._complex_mpfr_field_(field))
+        if isinstance(x, SymbolicExpression):
+            if field.prec() <= 53:
+                return field(complex(x))
+            else:
+                raise TypeError, "precision loss"
+        else:
+            return x
+
+    def _complex_double_(self, field):
+        """
+        Coerce to a complex double.
+        
+        EXAMPLES:
+            sage: CDF(sin(2)+cos(2)+I)
+            0.493150590279 + 1.0*I
+            sage: CDF(coth(pi))
+            1.0037418732
+        """
+        if not self.is_simplified():
+            return self.simplify()._complex_double_(field)
+        f = self._operands[0]
+        g = self._operands[1]
+        z = f(g._complex_double_(field))
+        if isinstance(z, SymbolicExpression):
+            return field(complex(z))
+        return z
+
+    def _real_double_(self, field):
+        """
+        Coerce to a real double.
+        
+        EXAMPLES:
+            sage: RDF(sin(2)+cos(2))
+            0.493150590279
+        """
+        if not self.is_simplified():
+            return self.simplify()._real_double_(field)
+        f = self._operands[0]
+        g = self._operands[1]
+        z = f(g._real_double_(field))
+        if isinstance(z, SymbolicExpression):
+            return field(float(z))
+        return z
+
+    def _real_rqdf_(self, field):
+        """
+        Coerce to a real qdrf.
+        
+        EXAMPLES:
+            
+        """
+        if not self.is_simplified():
+            return self.simplify()._real_rqdf_(field)
+        f = self._operands[0]
+        g = self._operands[1]
+        z = f(g._real_rqdf_(field))
+        if isinstance(z, SymbolicExpression):
+            raise TypeError, "precision loss"
+        else:
+            return z
+
+class PrimitiveFunction(SymbolicExpression):
+    def __init__(self, needs_braces=False):
+        SymbolicExpression.__init__(self)
+        self._tex_needs_braces = needs_braces
+
+    def _recursive_sub(self, kwds):
+        if kwds.has_key(self):
+            return kwds[self]
+        return self
+
+    def _recursive_sub_over_ring(self, kwds, ring):
+        if kwds.has_key(self):
+            return kwds[self]
+        return self
+
+    def plot(self, *args, **kwds):
+        f = self(var('x'))
+        return SymbolicExpression.plot(f, *args, **kwds)
+
+    def _is_atomic(self):
+        return True
+
+    def tex_needs_braces(self):
+        return self._tex_needs_braces
+
+    def __call__(self, x, *args):
+        if isinstance(x, float):
+            return self._approx_(x)
+        try:
+            return getattr(x, self._repr_())(*args)
+        except AttributeError:
+            return SymbolicComposition(self, SR(x))
+
+    def _approx_(self, x):  # must *always* be called with a float x as input.
+        s = '%s(%s), numer'%(self._repr_(), float(x))
+        return float(maxima.eval(s))
 
 _syms = {}
 
-t = var('t')
-x = var('x')
-y = var('y')
-z = var('z')
-w = var('w')
+class Function_erf(PrimitiveFunction):
+    r"""
+    The error function, defined as $\text{erf}(x) =
+    \frac{2}{\sqrt{\pi}}\int_0^x e^{-t^2} dt$.
+    """
+
+    def _repr_(self, simplify=True):
+        return "erf"
+
+    def _latex_(self):
+        return "\\text{erf}"
+
+    def _approx_(self, x):
+        return float(1 - pari(float(x)).erfc())
+    
+
+erf = Function_erf()
+_syms['erf'] = erf
+
+class Function_abs(PrimitiveFunction):
+    """
+    The absolute value function.
+
+    EXAMPLES:
+        sage: abs(x)
+        abs(x)
+        sage: abs(x^2 + y^2)
+        y^2 + x^2
+        sage: abs(-2)
+        2
+        sage: sqrt(x^2)
+        abs(x)
+        sage: abs(sqrt(x))
+        sqrt(x)        
+    """
+    def _repr_(self, simplify=True):
+        return "abs"
+
+    def _latex_(self):
+        return "\\abs"
+
+    def _approx_(self, x):
+        return float(x.__abs__())
+
+    def __call__(self, x): # special case
+        return SymbolicComposition(self, SR(x))
+
+abs_symbolic = Function_abs()
+_syms['abs'] = abs_symbolic
+
+
+
+class Function_ceil(PrimitiveFunction):
+    """
+    The ceiling function.
+
+    EXAMPLES:
+        sage: a = ceil(2/5 + x)
+        sage: a
+        ceil(x + 2/5)
+        sage: a(4)
+        5
+        sage: a(4.0)
+        5
+        sage: ZZ(a(3))
+        4
+        sage: a = ceil(x^3 + x + 5/2)
+        sage: a
+        ceil(x^3 + x + 1/2) + 2
+        sage: a(x=2)
+        13
+
+        sage: ceil(5.4)
+        6
+        sage: type(ceil(5.4))
+        <type 'sage.rings.integer.Integer'>        
+    """
+    def _repr_(self, simplify=True):
+        return "ceil"
+
+    def _latex_(self):
+        return "\\text{ceil}"
+
+    def _maxima_init_(self):
+        return "ceiling"
+
+    _approx_ = math.ceil
+
+    def __call__(self, x):
+        try:
+            return x.ceil()
+        except AttributeError:
+            if isinstance(x, float):
+                return math.ceil(x)
+        return SymbolicComposition(self, SR(x))
+
+ceil = Function_ceil()
+_syms['ceiling'] = ceil   # spelled ceiling in maxima
+
+
+class Function_floor(PrimitiveFunction):
+    """
+    The floor function.
+
+    EXAMPLES:
+        sage: floor(5.4)
+        5
+        sage: type(floor(5.4))
+        <type 'sage.rings.integer.Integer'>
+        sage: var('x')
+        x
+        sage: a = floor(5.4 + x); a
+        floor(x + 0.4000000000000004) + 5
+        sage: a(2)
+        7        
+    """
+    def _repr_(self, simplify=True):
+        return "floor"
+
+    def _latex_(self):
+        return "\\text{floor}"
+
+    def _maxima_init_(self):
+        return "floor"
+
+    _approx_ = math.floor
+
+    def __call__(self, x):
+        try:
+            return x.floor()
+        except AttributeError:
+            if isinstance(x, float):
+                return math.floor(x)
+        return SymbolicComposition(self, SR(x))
+
+floor = Function_floor()
+_syms['floor'] = floor   # spelled ceiling in maxima
+
 
 class Function_sin(PrimitiveFunction):
-    '''
+    """
     The sine function
-    '''
-    def _repr_(self):
+    """
+    def _repr_(self, simplify=True):
         return "sin"
 
@@ -799,78 +3579,982 @@
         return "\\sin"
 
+    _approx_ = math.sin
+
+    def __call__(self, x):
+        try:
+            return x.sin()
+        except AttributeError:
+            if isinstance(x, float):
+                return math.sin(x)
+        return SymbolicComposition(self, SR(x))
+
+sin = Function_sin()
+_syms['sin'] = sin
+
+class Function_cos(PrimitiveFunction):
+    """
+    The cosine function
+    """
+    def _repr_(self, simplify=True):
+        return "cos"
+
+    def _latex_(self):
+        return "\\cos"
+
+    _approx_ = math.cos
+
+    def __call__(self, x):
+        try:
+            return x.cos()
+        except AttributeError:
+            if isinstance(x, float):
+                return math.cos(x)
+        return SymbolicComposition(self, SR(x))
+
+   
+cos = Function_cos()
+_syms['cos'] = cos
+
+class Function_sec(PrimitiveFunction):
+    """
+    The secant function
+
+    EXAMPLES:
+        sage: sec(pi/4)
+        sqrt(2)
+        sage: RR(sec(pi/4))
+        1.41421356237310
+        sage: sec(1/2)
+        sec(1/2)
+        sage: sec(0.5)
+        1.139493927324549
+    """
+    def _repr_(self, simplify=True):
+        return "sec"
+
+    def _latex_(self):
+        return "\\sec"
+
+    def _approx_(self, x):
+        return 1/math.cos(x)
+
+sec = Function_sec()
+_syms['sec'] = sec
+
+class Function_tan(PrimitiveFunction):
+    """
+    The tangent function
+
+    EXAMPLES:
+        sage: tan(pi)
+        0
+        sage: tan(3.1415)
+        -0.0000926535900581913
+        sage: tan(3.1415/4)
+        0.999953674278156
+        sage: tan(pi/4)
+        1
+        sage: tan(1/2)
+        tan(1/2)
+        sage: RR(tan(1/2))
+        0.546302489843790
+    """
+    def _repr_(self, simplify=True):
+        return "tan"
+
+    def _latex_(self):
+        return "\\tan"
+
+    def _approx_(self, x):
+        return math.tan(x)
+
+tan = Function_tan()
+_syms['tan'] = tan
+
+def atan2(y, x):
+    return atan(y/x)
+
+_syms['atan2'] = atan2
+
+class Function_asin(PrimitiveFunction):
+    """
+    The arcsine function
+
+    EXAMPLES:
+        sage: asin(0.5)
+        0.523598775598299
+        sage: asin(1/2)
+        pi/6
+        sage: asin(1 + I*1.0)
+        1.061275061905036*I + 0.6662394324925153
+    """
+    def _repr_(self, simplify=True):
+        return "asin"
+
+    def _latex_(self):
+        return "\\sin^{-1}"
+
+    def _approx_(self, x):
+        return math.asin(x)
+
+asin = Function_asin()
+_syms['asin'] = asin
+
+class Function_acos(PrimitiveFunction):
+    """
+    The arccosine function
+
+    EXAMPLES:
+        sage: acos(0.5)
+        1.04719755119660
+        sage: acos(1/2)
+        pi/3
+        sage: acos(1 + I*1.0)
+        0.9045568943023813 - 1.061275061905036*I
+    """
+    def _repr_(self, simplify=True):
+        return "acos"
+
+    def _latex_(self):
+        return "\\cos^{-1}"
+
+    def _approx_(self, x):
+        return math.acos(x)
+
+acos = Function_acos()
+_syms['acos'] = acos
+
+
+class Function_atan(PrimitiveFunction):
+    """
+    The arctangent function.
+
+    EXAMPLES:
+        sage: atan(1/2)
+        atan(1/2)
+        sage: RDF(atan(1/2))
+        0.463647609001
+        sage: atan(1 + I)
+        atan(I + 1)
+    """
+    def _repr_(self, simplify=True):
+        return "atan"
+
+    def _latex_(self):
+        return "\\tan^{-1}"
+
+    def _approx_(self, x):
+        return math.atan(x)
+
+atan = Function_atan()
+_syms['atan'] = atan
+
+
+#######
+# Hyperbolic functions
+#######
+
+#tanh
+class Function_tanh(PrimitiveFunction):
+    """
+    The hyperbolic tangent function.
+
+    EXAMPLES:
+        sage: tanh(pi)
+        tanh(pi)
+        sage: tanh(3.1415)
+        0.996271386633702
+        sage: float(tanh(pi))       # random low-order bits
+        0.99627207622074987
+        sage: tan(3.1415/4)
+        0.999953674278156
+        sage: tanh(pi/4)
+        tanh(pi/4)
+        sage: RR(tanh(1/2))
+        0.462117157260010
+        
+        sage: CC(tanh(pi + I*e))
+        0.997524731976164 - 0.00279068768100315*I
+        sage: ComplexField(100)(tanh(pi + I*e))
+        0.99752473197616361034204366446 - 0.0027906876810031453884245163923*I
+        sage: CDF(tanh(pi + I*e))
+        0.997524731976 - 0.002790687681*I
+    """
+    def _repr_(self, simplify=True):
+        return "tanh"
+
+    def _latex_(self):
+        return "\\tanh"
+
+    def _approx_(self, x):
+        return math.tanh(x)
+
+tanh = Function_tanh()
+_syms['tanh'] = tanh
+
+#sinh
+class Function_sinh(PrimitiveFunction):
+    """
+    The hyperbolic sine function.
+
+    EXAMPLES:
+        sage: sinh(pi)
+        sinh(pi)
+        sage: sinh(3.1415)
+        11.5476653707437
+        sage: float(sinh(pi))              # random low-order bits
+        11.548739357257748
+        sage: RR(sinh(pi))
+        11.5487393572577        
+    """
+    def _repr_(self, simplify=True):
+        return "sinh"
+
+    def _latex_(self):
+        return "\\sinh"
+
+    def _approx_(self, x):
+        return math.sinh(x)
+
+sinh = Function_sinh()
+_syms['sinh'] = sinh
+
+#cosh
+class Function_cosh(PrimitiveFunction):
+    """
+    The hyperbolic cosine function.
+
+    EXAMPLES:
+        sage: cosh(pi)
+        cosh(pi)
+        sage: cosh(3.1415)
+        11.5908832931176
+        sage: float(cosh(pi))       # random low order bits
+        11.591953275521519        
+        sage: RR(cosh(1/2))
+        1.12762596520638
+    """
+    def _repr_(self, simplify=True):
+        return "cosh"
+
+    def _latex_(self):
+        return "\\cosh"
+
+    def _approx_(self, x):
+        return math.cosh(x)
+
+cosh = Function_cosh()
+_syms['cosh'] = cosh
+
+#coth
+class Function_coth(PrimitiveFunction):
+    """
+    The hyperbolic cotangent function.
+
+    EXAMPLES:
+        sage: coth(pi)
+        coth(pi)
+        sage: coth(3.1415)
+        1.00374256795520
+        sage: float(coth(pi))
+        1.0037418731973213
+        sage: RR(coth(pi))
+        1.00374187319732
+    """
+    def _repr_(self, simplify=True):
+        return "coth"
+
+    def _latex_(self):
+        return "\\coth"
+
+    def _approx_(self, x):
+        return 1/math.tanh(x)
+
+coth = Function_coth()
+_syms['coth'] = coth
+
+#sech
+class Function_sech(PrimitiveFunction):
+    """
+    The hyperbolic secant function.
+
+    EXAMPLES:
+        sage: sech(pi)        
+        sech(pi)
+        sage: sech(3.1415)
+        0.0862747018248192
+        sage: float(sech(pi))    # random low order bits
+        0.086266738334054432
+        sage: RR(sech(pi))
+        0.0862667383340544
+    """
+    def _repr_(self, simplify=True):
+        return "sech"
+
+    def _latex_(self):
+        return "\\sech"
+
+    def _approx_(self, x):
+        return 1/math.cosh(x)
+
+sech = Function_sech()
+_syms['sech'] = sech
+
+
+#csch
+class Function_csch(PrimitiveFunction):
+    """
+    The hyperbolic cosecant function.
+
+    EXAMPLES:
+        sage: csch(pi)
+        csch(pi)
+        sage: csch(3.1415)
+        0.0865975907592133
+        sage: float(csch(pi))           # random low-order bits
+        0.086589537530046945
+        sage: RR(csch(pi))
+        0.0865895375300470
+    """
+    def _repr_(self, simplify=True):
+        return "csch"
+
+    def _latex_(self):
+        return "\\csch"
+
+    def _approx_(self, x):
+        return 1/math.sinh(x)
+
+csch = Function_csch()
+_syms['csch'] = csch
+
+#############
+# log 
+#############
+
+class Function_log(PrimitiveFunction):
+    """
+    The log function. 
+
+    EXAMPLES:
+        sage: log(e^2)
+        2 
+        sage: log(1024, 2) # the following is ugly (for now)
+        log(1024)/log(2)
+        sage: log(10, 4)
+        log(10)/log(4)
+
+        sage: RDF(log(10,2))
+        3.32192809489
+        sage: RDF(log(8, 2))
+        3.0
+        sage: log(RDF(10))
+        2.30258509299
+        sage: log(2.718)
+        0.999896315728952
+    """
+    def __init__(self):
+        PrimitiveFunction.__init__(self)
+
+    def _repr_(self, simplify=True):
+        return "log"
+        
+    def _latex_(self):
+        return "\\log"
+
+    _approx_ = math.log
+
+function_log = Function_log()
+ln = function_log
+
+def log(x, base=None):
+    if base is None:
+        try:
+            return x.log()
+        except AttributeError: 
+            return function_log(x)
+    else:
+        try:
+            return x.log(base)
+        except AttributeError:
+            return function_log(x) / function_log(base)
+
+#####################
+# The polylogarithm
+#####################
+
+
+class Function_polylog(PrimitiveFunction):
+    r"""
+    The polylog function $\text{Li}_n(z) = \sum_{k=1}^{\infty} z^k / k^n$.
+
+    INPUT:
+        n -- object
+        z -- object
+
+    EXAMPLES:
+        
+    """
+    def __init__(self, n):
+        PrimitiveFunction.__init__(self)
+        self._n = n
+
+    def _repr_(self, simplify=True):
+        return "polylog(%s)"%self._n
+
+    def _repr_evaled_(self, args):
+        return 'polylog(%s, %s)'%(self._n, args)
+
+    def _maxima_init_(self):
+        if self._n in [1,2,3]:
+            return 'li[%s]'%self._n
+        else:
+            return 'polylog(%s)'%self._n
+
+    def _maxima_init_evaled_(self, args):
+        if self._n in [1,2,3]:
+            return 'li[%s](%s)'%(self._n, args)
+        else:
+            return 'polylog(%s, %s)'%(self._n, args)
+
+    def n(self):
+        return self._n
+
+    def _latex_(self):
+        return "\\text{Li}"
+
+    def _approx_(self, x):
+        try:
+            return float(pari(x).polylog(self._n))
+        except PariError:
+            raise TypeError, 'unable to coerce polylogarithm to float'
+        
+
+def polylog(n, z):
+    r"""
+    The polylog function $\text{Li}_n(z) = \sum_{k=1}^{\infty} z^k / k^n$.
+
+    EXAMPLES:
+        sage: polylog(2,1)
+        pi^2/6
+        sage: polylog(2,x^2+1)
+        polylog(2, x^2 + 1)
+        sage: polylog(4,0.5)
+        polylog(4, 0.500000000000000)
+        sage: float(polylog(4,0.5))
+        0.51747906167389934
+        sage: polylog(2,z).taylor(z, 1/2, 3)
+        (-(6*log(2)^2 - pi^2))/12 + 2*log(2)*(z - 1/2) + (-2*log(2) + 2)*(z - 1/2)^2 + (8*log(2) - 4)*(z - 1/2)^3/3
+    """
+    return Function_polylog(n)(z)
+
+_syms['polylog2'] = Function_polylog(2)
+_syms['polylog3'] = Function_polylog(3)
+
+##############################
+# square root
+##############################
+
+class Function_sqrt(PrimitiveFunction):
+    """
+    The square root function. This is a symbolic square root.
+
+    EXAMPLES:
+        sage: sqrt(-1)
+        I
+        sage: sqrt(2)
+        sqrt(2)
+        sage: sqrt(x^2)
+        abs(x)
+    """
+    def __init__(self):
+        PrimitiveFunction.__init__(self, needs_braces=True)
+    
+    def _repr_(self, simplify=True):
+        return "sqrt"
+
+    def _latex_(self):
+        return "\\sqrt"
+
+    def _do_sqrt(self, x, prec=None, extend=True, all=False):
+        if prec:
+            return ComplexField(prec)(x).sqrt(all=all)
+        z = SymbolicComposition(self, SR(x))
+        if all:
+            return [z, -z]
+        return z
+
+    def __call__(self, x, *args, **kwds):
+        """
+        
+        POSSIBLE INPUTS INCLUDE:
+            x -- a number
+            prec -- integer (default: None): if None, returns an exact
+                 square root; otherwise returns a numerical square
+                 root if necessary, to the given bits of precision.
+            extend -- bool (default: True); if True, return a square
+                 root in an extension ring, if necessary. Otherwise,
+                 raise a ValueError if the square is not in the base
+                 ring.
+            all -- bool (default: False); if True, return all square
+                 roots of self, instead of just one.
+        """
+        if isinstance(x, float):
+            return math.sqrt(x)
+        if not isinstance(x, (Integer, Rational)):
+            try:
+                return x.sqrt(*args, **kwds)
+            except AttributeError:
+                pass
+        return self._do_sqrt(x, *args, **kwds)
+
+    def _approx_(self, x):
+        return math.sqrt(x)
+
+sqrt = Function_sqrt()
+_syms['sqrt'] = sqrt
+
+class Function_exp(PrimitiveFunction):
+    r"""
+    The exponential function, $\exp(x) = e^x$.
+
+    EXAMPLES:
+        sage: exp(-1)
+        e^-1
+        sage: exp(2)
+        e^2
+        sage: exp(x^2 + log(x))
+        x*e^x^2
+        sage: exp(2.5)
+        12.1824939607035
+        sage: exp(float(2.5))         # random low order bits
+        12.182493960703473
+        sage: exp(RDF('2.5'))
+        12.1824939607
+    """
+    def __init__(self):
+        PrimitiveFunction.__init__(self, needs_braces=True)
+    
+    def _repr_(self, simplify=True):
+        return "exp"
+
+    def _latex_(self):
+        return "\\exp"
+
+    def __call__(self, x):
+        # if x is an integer or rational, never call the sqrt method
+        if isinstance(x, float):
+            return self._approx_(x)
+        if not isinstance(x, (Integer, Rational)):
+            try:
+                return x.exp()
+            except AttributeError:
+                pass
+        return SymbolicComposition(self, SR(x))
+    
+
+    def _approx_(self, x):
+        return math.exp(x)
+
+exp = Function_exp()
+_syms['exp'] = exp
+
+
+#######################################################
+# Symbolic functions
+#######################################################
+
+class SymbolicFunction(PrimitiveFunction):
+    """
+    A formal symbolic function.
+
+    EXAMPLES:
+        sage: f = function('foo')
+        sage: g = f(x,y,z)
+        sage: g
+        foo(x, y, z)
+        sage: g(x=var('theta'))
+        foo(theta, y, z)
+    """
+    def __init__(self, name):
+        PrimitiveFunction.__init__(self, needs_braces=True)
+        self._name = str(name)
+    
+    def __hash__(self):
+        return hash(self._name)
+
+    def _repr_(self, simplify=True):
+        return self._name
+
+
     def _is_atomic(self):
         return True
 
-sin = Function_sin()
-_syms['sin'] = sin
-
-class Function_cos(PrimitiveFunction):
-    '''
-    The cosine function
-    '''
-    def _repr_(self):
-        return "cos"
-
     def _latex_(self):
-        return "\\cos"
+        return "{\\rm %s}"%self._name
+
+    def _maxima_init_(self):
+        return "'%s"%self._name
+
+    def _approx_(self, x):
+        raise TypeError
+
+    def __call__(self, *args, **kwds):
+        return SymbolicFunctionEvaluation(self, [SR(x) for x in args])
+
+    
+
+class SymbolicFunction_delayed(SymbolicFunction):
+    def simplify(self):
+        return self
+
+    def is_simplified(self):
+        return True
+
+    def _maxima_init_(self):
+        return "%s"%self._name
+
+    def __call__(self, *args):
+        return SymbolicFunctionEvaluation_delayed(self, [SR(x) for x in args])
+    
+    
+
+class SymbolicFunctionEvaluation(SymbolicExpression):
+    """
+    The result of evaluating a formal symbolic function.
+
+    EXAMPLES:
+        sage: h = function('gfun', x); h
+        gfun(x)
+        sage: k = h.integral(x); k
+        integrate(gfun(x), x)
+        sage: k(gfun=sin)
+        -cos(x)
+        sage: k(gfun=cos)
+        sin(x)
+        sage: k.diff(x)
+        gfun(x)
+    """
+    def __init__(self, f, args=None, kwds=None):
+        """
+        INPUT:
+            f -- symbolic function
+            args -- a tuple or list of symbolic expressions, at which
+                    f is formally evaluated.
+        """
+        SymbolicExpression.__init__(self)
+        self._f = f
+        if not args is None:
+            if not isinstance(args, tuple):
+                args = tuple(args)
+        self._args = args
+        self._kwds = kwds
 
     def _is_atomic(self):
         return True
+
+    def arguments(self):
+        return tuple(self._args)
+
+    def keyword_arguments(self):
+        return self._kwds
     
-cos = Function_cos()
-_syms['cos'] = cos
-
-class Function_sec(PrimitiveFunction):
-    '''
-    The secant function
-    '''
-    def _repr_(self):
-        return "sec"
-
+    def _repr_(self, simplify=True):
+        if simplify:
+            return self.simplify()._repr_(simplify=False)
+        else:
+            args = ', '.join([x._repr_(simplify=simplify) for x in
+                                                      self._args])
+            if not self._kwds is None:
+                kwds = ', '.join(["%s=%s" %(x, y) for x,y in self._kwds.iteritems()])
+                return '%s(%s, %s)' % (self._f._name, args, kwds)
+            else:
+                return '%s(%s)' % (self._f._name, args)
+            
     def _latex_(self):
-        return "\\sec"
-
-sec = Function_sec()
-_syms['sec'] = sec
-
-class Function_log(PrimitiveFunction):
-    '''
-    The log function
-    '''
-    def _repr_(self):
-        return "log"
-
-    def _latex_(self):
-        return "\\log"
-
-log = Function_log()
-_syms['log'] = log
-
+        return "{\\rm %s}(%s)"%(self._f._name, ', '.join([x._latex_() for
+                                                       x in self._args]))
+
+    def _maxima_init_(self):
+        try:
+            return self.__maxima_init
+        except AttributeError:
+            n = self._f._name
+            if not (n in ['integrate', 'diff']):
+                n = "'" + n
+            s = "%s(%s)"%(n, ', '.join([x._maxima_init_()
+                                           for x in self._args]))
+            self.__maxima_init = s
+        return s
+
+    def _recursive_sub(self, kwds):
+        """
+        EXAMPLES:
+            sage: f = function('foo',x); f
+            foo(x)
+            sage: f(foo=sin)
+            sin(x)
+            sage: f(x+y)
+            foo(y + x)
+            sage: a = f(pi)
+            sage: a.substitute(foo = sin)
+            0
+            sage: a = f(pi/2)
+            sage: a.substitute(foo = sin)
+            1
+            sage: b = f(pi/3) + x + y
+            sage: b
+            y + x + foo(pi/3)
+            sage: b(foo = sin)
+            y + x + sqrt(3)/2
+            sage: b(foo = cos)
+            y + x + 1/2
+            sage: b(foo = cos, x=y)
+            2*y + 1/2
+        """
+        function_sub = False
+        for x in kwds.keys():
+            if repr(x) == self._f._name:
+                g = kwds[x]
+                function_sub = True
+                break
+        if function_sub:
+            # Very important to make a copy, since we are mutating a dictionary
+            # that will get used again by the calling function!
+            kwds = dict(kwds)
+            del kwds[x]
+
+        arg = tuple([SR(x._recursive_sub(kwds)) for x in self._args])
+
+        if function_sub:
+            return g(*arg)
+        else:
+            return self.__class__(self._f, arg)
+
+    def _recursive_sub_over_ring(self, kwds, ring):
+        raise TypeError, "no way to coerce the formal function to ring."
+
+    def variables(self):
+        """
+        Return the variables appearing in the simplified form of self.
+        
+        EXAMPLES:
+            sage: foo = function('foo')
+            sage: w = foo(x,y,a,b,z) + t
+            sage: w
+            foo(x, y, a, b, z) + t
+            sage: w.variables()
+            (a, b, t, x, y, z)
+        """
+        try:
+            return self.__variables
+        except AttributeError:
+            pass
+        vars = sum([list(op.variables()) for op in self._args], [])
+        vars.sort(var_cmp)
+        vars = tuple(vars)
+        self.__variables = vars
+        return vars
+
+class SymbolicFunctionEvaluation_delayed(SymbolicFunctionEvaluation):
+    def simplify(self):
+        return self
+
+    def is_simplified(self):
+        return True
+
+    def __float__(self):
+        return float(self._maxima_())
+
+    def __complex__(self):
+        return complex(self._maxima_())
+
+    def _real_double_(self, R):
+        return R(float(self))
+
+    def _real_rqdf_(self, R):
+        raise TypeError
+
+    def _complex_double_(self, C):
+        return C(float(self))
+
+    def _mpfr_(self, field):
+        if field.prec() <= 53:
+            return field(float(self))
+        raise TypeError
+
+    def _complex_mpfr_field_(self, field):
+        if field.prec() <= 53:
+            return field(float(self))
+        raise TypeError
+
+    def _maxima_init_(self):
+        try:
+            return self.__maxima_init
+        except AttributeError:
+            n = self._f._name
+            s = "%s(%s)"%(n, ', '.join([x._maxima_init_()
+                                           for x in self._args]))
+            self.__maxima_init = s
+        return s
+    
+
+    
+_functions = {}
+def function(s, *args):
+    """
+    Create a formal symbolic function with the name \emph{s}.
+
+    EXAMPLES:
+        sage: f = function('cr', a)
+        sage: g = f.diff(a).integral(b)
+        sage: g
+        diff(cr(a), a, 1)*b
+        sage: g(cr=cos)
+        -sin(a)*b
+        sage: g(cr=sin(x) + cos(x))
+        (cos(a) - sin(a))*b
+
+    Basic arithmetic:
+        sage: x = var('x')
+        sage: h = function('f',x)
+        sage: 2*f
+        2*f
+        sage: 2*h
+        2*f(x)
+    """
+    if len(args) > 0:
+        return function(s)(*args)
+    if isinstance(s, SymbolicFunction):
+        return s
+    s = str(s)
+    if ',' in s:
+        return tuple([function(x.strip()) for x in s.split(',')])
+    elif ' ' in s:
+        return tuple([function(x.strip()) for x in s.split()])
+    try:
+        f =  _functions[s]
+        _syms[s] = f
+        return f
+    except KeyError:
+        pass
+    v = SymbolicFunction(s)
+    _functions[s] = v
+    _syms[s] = v
+    return v
+    
 #######################################################
-symtable = {'%pi':'_Pi_', '%e': '_E_', '%i':'_I_'}
-import sage.functions.constants as c
-_syms['_Pi_'] = SER(c.Pi)
-_syms['_E_'] = SER(c.E)
-_syms['_I_'] = SER(CC.gen(0))  # change when we create a symbolic I.
-
-def symbolic_expression_from_maxima_string(x):
-    global _syms
-    maxima.eval('listdummyvars: false')
-    maxima.eval('_tmp_: %s'%x)
-    r = maxima.eval('listofvars(_tmp_)')[1:-1]
-    if len(r) > 0:
-        # Now r is a list of all the indeterminate variables that
-        # appear in the expression x.
-        v = r.split(',')
-        for a in v:
-            _syms[a] = var(a)
-    s = maxima.eval('_tmp_')
-    for x, y in symtable.iteritems():
-        s = s.replace(x, y)
-    #print s
-    #print _syms
-    return SymbolicExpressionRing(sage_eval(s, _syms))
+# This is buggy as is:
+# sage: a = lim(exp(x^2)*(1-erf(x)), x=infinity)
+# sage: maxima(a)
+# 'limit(%e^x^2-%e^x^2*erf(x))
+#  ??? -- what happened to the infinity in the above.
+# With the old version one gets
+# sage: maxima(a)
+# 'limit(%e^x^2-%e^x^2*erf(x),x,inf)
+# Which is right, since:
+# (%i3) limit(%e^x^2-%e^x^2*erf(x),x,inf);
+# (%o3) 'limit(%e^x^2-%e^x^2*erf(x),x,inf)
+#a
+def dummy_limit(*args):
+    s = str(args[1])
+    return SymbolicFunctionEvaluation(function('limit'), args=(args[0],), kwds={s: args[2]})
+
+######################################i################
+
+
+
+
+#######################################################
+
+symtable = {'%pi':'pi', '%e': 'e', '%i':'I', '%gamma':'euler_gamma',
+            'li[2]':'polylog2', 'li[3]':'polylog3'}
+
+from sage.rings.infinity import infinity, minus_infinity
+
+_syms['inf'] = infinity
+_syms['minf'] = minus_infinity
+
+from sage.misc.multireplace import multiple_replace
+
+maxima_tick = re.compile("'[a-z|A-Z|0-9|_]*")
+
+maxima_qp = re.compile("\?\%[a-z|A-Z|0-9|_]*")  # e.g., ?%jacobi_cd
+
+maxima_var = re.compile("\%[a-z|A-Z|0-9|_]*")  # e.g., ?%jacobi_cd
+
+def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima):
+    syms = dict(_syms)
+
+    if len(x) == 0:
+        raise RuntimeError, "invalid symbolic expression -- ''"
+    maxima.set('_tmp_',x)
+
+    # This is inefficient since it so rarely is needed:
+    #r = maxima._eval_line('listofvars(_tmp_);')[1:-1]
+    
+    s = maxima._eval_line('_tmp_;')
+
+    formal_functions = maxima_tick.findall(s)
+    if len(formal_functions) > 0:
+        for X in formal_functions:
+            syms[X[1:]] = function(X[1:])
+        # You might think there is a potential very subtle bug if 'foo is in a string literal --
+        # but string literals should *never* ever be part of a symbolic expression.
+        s = s.replace("'","")  
+
+    delayed_functions = maxima_qp.findall(s)
+    if len(delayed_functions) > 0:
+        for X in delayed_functions:
+            syms[X[2:]] = SymbolicFunction_delayed(X[2:])
+        s = s.replace("?%","")
+
+    s = multiple_replace(symtable, s)
+    s = s.replace("%","")
+
+    if equals_sub:
+        s = s.replace('=','==')
+      
+    # have to do this here, otherwise maxima_tick catches it
+    syms['limit'] = dummy_limit
+
+    global is_simplified
+    try:
+        # use a global flag so all expressions obtained via
+        # evaluation of maxima code are assumed pre-simplified
+        is_simplified = True
+        last_msg = ''
+        while True:
+            try:
+                w = sage_eval(s, syms)
+            except NameError, msg:
+                if msg == last_msg:
+                    raise NameError, msg
+                msg = str(msg)
+                last_msg = msg
+                i = msg.find("'")
+                j = msg.rfind("'")
+                nm = msg[i+1:j]
+                syms[nm] = var(nm)
+            else:
+                break
+        if isinstance(w, (list, tuple)):
+            return w
+        else:
+            x = SR(w)
+        return x
+    except SyntaxError:
+        raise TypeError, "unable to make sense of Maxima expression '%s' in SAGE"%s
+    finally:
+        is_simplified = False
 
 def symbolic_expression_from_maxima_element(x):
     return symbolic_expression_from_maxima_string(x.name())
 
+def evaled_symbolic_expression_from_maxima_string(x):
+    return symbolic_expression_from_maxima_string(maxima.eval(x))
+
+
+# External access used by restore
+syms_cur = _syms
+syms_default = dict(syms_cur)
Index: sage/calculus/equations.py
===================================================================
--- sage/calculus/equations.py	(revision 4316)
+++ sage/calculus/equations.py	(revision 4316)
@@ -0,0 +1,388 @@
+r"""
+Symbolic Equations and Inequalities.
+
+SAGE can solving symbolic equations and expressing inequalities.
+For example, we derive the quadratic formula as follows:
+
+    sage: qe = (a*x^2 + b*x + c == 0)
+    sage: print qe
+                                     2
+                                  a x  + b x + c == 0
+    sage: print solve(qe, x)
+    [
+                                          2
+                                  - sqrt(b  - 4 a c) - b
+                              x == ----------------------
+                                           2 a,
+                                         2
+                                   sqrt(b  - 4 a c) - b
+                               x == --------------------
+                                           2 a
+    ]
+
+AUTHORS:
+    -- Bobby Moretti: initial version
+    -- William Stein: second version
+
+EXAMPLES:
+    sage: f = x^2 + y^2 == 1
+    sage: f.solve(x)
+    [x == (-sqrt(1 - y^2)), x == sqrt(1 - y^2)]
+
+    sage: f = x^5 + a
+    sage: solve(f==0,x)
+    [x == -e^(2*I*pi/5)*a^(1/5), x == -e^(4*I*pi/5)*a^(1/5), x == -e^(-(4*I*pi/5))*a^(1/5), x == -e^(-(2*I*pi/5))*a^(1/5), x == (-a^(1/5))]
+"""
+
+_assumptions = []
+
+from sage.structure.sage_object import SageObject
+from sage.structure.sequence    import Sequence
+from sage.misc.sage_eval        import sage_eval
+
+from calculus                   import maxima
+
+import operator
+
+symbols = {operator.lt:' < ', operator.le:' <= ', operator.eq:' == ',
+           operator.ne:' != ',
+            operator.ge:' >= ', operator.gt:' > '}
+
+maxima_symbols = dict(symbols)
+maxima_symbols[operator.eq] = '='
+maxima_symbols[operator.ne] = '#'
+
+
+latex_symbols = {operator.lt:' < ', operator.le:' \\leq ', operator.eq:' = ',
+                 operator.ne:' \\neq ',
+            operator.ge:' \\geq ', operator.gt:' > '}
+
+comparisons = {operator.lt:set([-1]), operator.le:set([-1,0]), operator.eq:set([0]),
+               operator.ne:set([-1,1]),  operator.ge:set([0,1]), operator.gt:set([1])}
+
+def var_cmp(x,y):
+    return cmp(str(x), str(y))
+
+def paren(x):
+    if x._is_atomic():
+        return repr(x)
+    else:
+        return '(%s)'%repr(x)
+
+class SymbolicEquation(SageObject):
+    def __init__(self, left, right, op):
+        self._left = left
+        self._right = right
+        self._op = op
+
+    def __call__(self, *args, **argv):
+        return self._op(self._left(*args, **argv), self._right(*args,**argv))
+
+    # The maxima one is special:
+    def _maxima_(self, session=None):
+        if session is None:
+            return SageObject._maxima_(self, sage.calculus.calculus.maxima)
+        else:
+            return SageObject._maxima_(self, session)
+
+    def substitute(self, *args, **kwds):
+        return self.__call__(*args, **kwds)
+
+    subs = substitute
+
+    def __cmp__(self, right):
+        """
+        EXAMPLES:
+            sage: (x>0) == (x>0)
+            True
+            sage: (x>0) == (x>1)
+            False
+            sage: (x>0) != (x>1)
+            True
+        """
+        if not isinstance(right, SymbolicEquation):
+            return cmp(type(self), type(right))
+        c = cmp(self._op, right._op)
+        if c: return c
+        i = bool(self._left == right._left)
+        if not i: return -1
+        i = bool(self._right == right._right)
+        if not i: return 1
+        return 0
+
+    def _repr_(self):
+        return "%s%s%s" %(paren(self._left), symbols[self._op], paren(self._right))
+
+    def variables(self):
+        """
+        EXAMPLES:
+            sage: f =  (x+y+w) == (x^2 - y^2 - z^3);   f
+            (y + x + w) == (-z^3 - y^2 + x^2)
+            sage: f.variables()
+            [w, x, y, z]
+        """
+        try:
+            return self.__variables
+        except AttributeError:
+            v = list(set(list(self._left.variables()) + list(self._right.variables())))
+            v.sort(var_cmp)
+            self.__variables = v
+            return v
+
+    def operator(self):
+        return self._op
+
+    def left(self):
+        return self._left
+    lhs = left
+    left_hand_side = left
+
+    def right(self):
+        return self._right
+    rhs = right
+    right_hand_side = right
+
+    def __str__(self):
+        """
+        EXAMPLES:
+            sage: f =  (x^2 - x == 0)
+            sage: f
+            (x^2 - x) == 0
+            sage: print f
+                                               2
+                                              x  - x == 0
+        """
+        s = self._maxima_().display2d(onscreen=False)
+        s = s.replace('%pi','pi').replace('%i',' I').replace('%e', ' e').replace(' = ',' == ')
+        return s
+
+    def _latex_(self):
+        return "%s %s %s" %(self._left._latex_(), latex_symbols[self._op],
+                            self._right._latex_())
+
+    # this is an excellent idea by Robert Bradshaw
+    #def __nonzero__(self):
+    #    result = self._left.__cmp__(self._right)
+    #    return result in comparisons[self._op]
+    def __nonzero__(self):
+        """
+        Return True if this equality is definitely true.  Return False
+        if it is false or the algorithm for testing equality is
+        inconclusive.
+        """
+        m = self._maxima_()
+        try:
+            s = m.parent()._eval_line('is (%s)'%m.name())
+        except TypeError, msg:
+            #raise ValueError, "unable to evaluate the predicate '%s'"%repr(self)
+            return cmp(self._left._maxima_() , self._right._maxima_()) == 0
+        return s == 'true'
+
+    def _maxima_init_(self, maxima=maxima, assume=False):
+        l = self._left._maxima_init_()
+        r = self._right._maxima_init_()
+        if assume and self._op == operator.eq:
+            return 'equal(%s, %s)'%(l, r)
+        return '(%s)%s(%s)' % (l, maxima_symbols[self._op], r)
+
+    def assume(self):
+        if not self in _assumptions:
+            m = self._maxima_init_(assume=True)
+            maxima.assume(m)
+            _assumptions.append(self)
+
+    def forget(self):
+        """
+        Forget the given constraint.
+        """
+        m = self._maxima_()
+        m.parent().forget(m)
+        try:
+            _assumptions.remove(self)
+        except ValueError:
+            pass
+
+    def solve(self, x=None, multiplicities=False):
+        """
+        Symbolically solve for the given variable.
+
+        WARNING: In many cases, only one solution is computed. 
+
+        INPUT:
+            x -- a SymbolicVariable object (if not given, the first in the expression is used)
+            multiplicities -- (default: False) if True, also returns the multiplicities
+                          of each solution, in order. 
+
+        OUTPUT:
+            A list of SymbolicEquations with the variable to solve for on the
+            left hand side.
+
+        EXAMPLES:
+            sage: S = solve(x^3 - 1 == 0, x)
+            sage: S
+            [x == ((sqrt(3)*I - 1)/2), x == ((-sqrt(3)*I - 1)/2), x == 1]
+            sage: S[0]
+            x == ((sqrt(3)*I - 1)/2)
+            sage: S[0].right()
+            (sqrt(3)*I - 1)/2
+
+        We illustrate finding multiplicities of solutions:
+            sage: f = (x-1)^5*(x^2+1)
+            sage: solve(f == 0, x)
+            [x == -1*I, x == I, x == 1]
+            sage: solve(f == 0, x, multiplicities=True)
+            ([x == -1*I, x == I, x == 1], [1, 1, 5])
+            sage: solve(g == 0, x)
+            []            
+        """
+        if not self._op is operator.eq:
+            raise ValueError, "solving only implemented for equalities"
+        if x is None:
+            v = self.variables()
+            if len(v) == 0:
+                if multiplicities:
+                    return [], []
+                else:
+                    return []
+            x = v[0]
+
+        m = self._maxima_()
+        P = m.parent()
+        s = m.solve(x).str()
+
+        X = string_to_list_of_solutions(s)
+        if multiplicities:
+            if len(X) == 0:
+                return X, []
+            else:
+                return X, sage_eval(P.get('multiplicities'))
+        else:
+            return X
+        
+        
+
+def assume(*args):
+    """
+    Make the given assumptions.
+
+    INPUT:
+        *args -- assumptions
+
+    EXAMPLES:
+        sage: assume(x > 0)
+        sage: bool(sqrt(x^2) == x)
+        True
+        sage: forget()
+        sage: bool(sqrt(x^2) == x)
+        False
+    """
+    for x in args:
+        if isinstance(x, (tuple, list)):
+            for y in x:
+                assume(y)
+        else:
+            try:
+                x.assume()
+            except KeyError:
+                raise TypeError, "assume not defined for objects of type '%s'"%type(x)
+
+def forget(*args):
+    """
+    Forget the given assumption, or call with no arguments to forget
+    all assumptions.
+
+    Here an assumption is some sort of symbolic constraint. 
+
+    INPUT:
+        *args -- assumptions (default: forget all assumptions)
+
+    EXAMPLES:
+    We define and forget multiple assumptions:
+        sage: assume(x>0, y>0, z == 1, y>0)
+        sage: assumptions()
+        [x > 0, y > 0, z == 1]
+        sage: forget(x>0, z==1)
+        sage: assumptions()
+        [y > 0]
+    """
+    if len(args) == 0:
+        forget_all()
+        return
+    for x in args:
+        if isinstance(x, (tuple, list)):
+            for y in x:
+                assume(y)
+        else:
+            try:
+                x.forget()
+            except KeyError:
+                raise TypeError, "forget not defined for objects of type '%s'"%type(x)
+
+def assumptions():
+    """
+    List all current symbolic assumptions.
+    
+    EXAMPLES:
+        sage: forget()
+        sage: assume(x^2+y^2 > 0)
+        sage: assumptions()
+        [(y^2 + x^2) > 0]
+        sage: forget(x^2+y^2 > 0)
+        sage: assumptions()
+        []
+        sage: assume(x > y)
+        sage: assume(z > w)
+        sage: assumptions()
+        [x > y, z > w]
+        sage: forget()
+        sage: assumptions()
+        []
+    """
+    return list(_assumptions)
+
+def forget_all():
+    global _assumptions
+    if len(_assumptions) == 0:
+        return
+    maxima._eval_line('forget(facts());')
+    #maxima._eval_line('forget([%s]);'%(','.join([x._maxima_init_() for x in _assumptions])))
+    _assumptions = []
+
+def solve(f, *args, **kwds):
+    """
+    Algebraically solve an equation of system of equations for given variables.
+
+    INPUT:
+        f -- equation or system of equations (given by a list or tuple)
+        *args -- variables to solve for.
+
+    EXAMPLES:
+        sage: solve([x+y==6, x-y==4], x, y)
+        [[x == 5, y == 1]]
+        sage: solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y)
+        [[x == ((-sqrt(3)*I - 1)/2), y == ((-sqrt(3 - sqrt(3)*I))/sqrt(2))],
+         [x == ((-sqrt(3)*I - 1)/2), y == (sqrt(3 - sqrt(3)*I)/sqrt(2))],
+         [x == ((sqrt(3)*I - 1)/2), y == ((-sqrt(sqrt(3)*I + 3))/sqrt(2))],
+         [x == ((sqrt(3)*I - 1)/2), y == (sqrt(sqrt(3)*I + 3)/sqrt(2))],
+         [x == 0, y == -1],
+         [x == 0, y == 1]]
+    """
+    if isinstance(f, (list, tuple)):
+        m = maxima(list(f))
+        try:
+            s = m.solve(args)
+        except:
+            raise ValueError, "Unable to solve %s for %s"%(f, args)
+        a = repr(s)
+        return string_to_list_of_solutions(a)
+    else:
+        return f.solve(*args, **kwds)
+
+import sage.categories.all
+objs = sage.categories.all.Objects()
+
+def string_to_list_of_solutions(s):
+    from sage.calculus.calculus import symbolic_expression_from_maxima_string
+    v = symbolic_expression_from_maxima_string(s, equals_sub=True)
+    return Sequence(v, universe=objs)
+
Index: sage/calculus/functional.py
===================================================================
--- sage/calculus/functional.py	(revision 2327)
+++ sage/calculus/functional.py	(revision 4294)
@@ -1,10 +1,326 @@
-from calculus import SER, SymbolicExpression
-
-def diff(f, *args):
-    if not isinstance(f, SymbolicExpression):
-        f = SER(f)
-    return f.derivative(*args)
-
-derivative = diff
-
+"""
+Functional notation support for common calculus methods.
+"""
+
+from calculus import SR, SymbolicExpression, CallableSymbolicExpression
+
+def simplify(f):
+    """
+    Simplify the expression f.
+    """
+    try:
+        return f.simplify()
+    except AttributeError:
+        return f
+
+def derivative(f, *args, **kwds):
+    """
+    The derivative of f.
+
+    EXAMPLES:
+    We differentiate a callable symbolic function:
+        sage: f(x,y) = x*y + sin(x^2) + e^(-x)
+        sage: f 
+        (x, y) |--> x*y + sin(x^2) + e^(-x)
+        sage: derivative(f, x)
+        (x, y) |--> y + 2*x*cos(x^2) - e^(-x)
+        sage: derivative(f, y)
+        (x, y) |--> x
+
+    We differentiate a polynomial:
+        sage: t = polygen(QQ, 't')
+        sage: f = (1-t)^5; f
+        -t^5 + 5*t^4 - 10*t^3 + 10*t^2 - 5*t + 1
+        sage: derivative(f)
+        -5*t^4 + 20*t^3 - 30*t^2 + 20*t - 5
+
+    We differentiate a symbolic expression:
+        sage: f = exp(sin(a - x^2))/x
+        sage: diff(f, x)
+        -2*cos(x^2 - a)*e^(-sin(x^2 - a)) - (e^(-sin(x^2 - a))/x^2)
+        sage: diff(f, a)
+        cos(x^2 - a)*e^(-sin(x^2 - a))/x        
+    """
+    try:
+        return f.derivative(*args, **kwds)
+    except AttributeError:
+        pass
+    if not isinstance(f, SymbolicExpression):
+        f = SR(f)
+    return f.derivative(*args, **kwds)
+
+diff = derivative
+differentiate = derivative
+
+def integral(f, *args, **kwds):
+    """
+    The integral of f.
+
+    EXAMPLES:
+        sage: integral(sin(x), x)
+        -cos(x)
+        sage: integral(sin(x)^2, x, pi, 123*pi/2)
+        121*pi/4
+        sage: integral( sin(x), x, 0, pi)
+        2
+
+    We integrate a symbolic function:
+        sage: f(x,y) = x*y/z + sin(z)
+        sage: integral(f, z)
+        (x, y) |--> x*y*log(z) - cos(z)
+
+        sage: assume(b-a>0)
+        sage: integral( sin(x), x, a, b)
+        cos(a) - cos(b)
+        sage: forget()
+        
+        sage: print integral(x/(x^3-1), x)
+                                         2 x + 1
+                       2            atan(-------)
+                  log(x  + x + 1)        sqrt(3)    log(x - 1)
+                - --------------- + ------------- + ----------
+                         6             sqrt(3)          3
+                         
+        sage: print integral( exp(-x^2), x )
+                               sqrt( pi) erf(x)
+                               ----------------
+                                      2
+
+    You can have SAGE calculate multiple integrals.  For example,
+    consider the function $exp(y^2)$ on the region between the lines
+    $x=y$, $x=1$, and $y=0$. We find the value of the integral on
+    this region using the command:
+        sage: area = integral(integral(exp(y^2),x,0,y),y,0,1); area
+        e/2 - 1/2
+        sage: float(area)
+        0.85914091422952255
+
+    We compute the line integral of sin(x) along the arc of the curve
+    $x=y^4$ from $(1,-1)$ to $(1,1)$:
+        sage: (x,y) = (t^4,t)
+        sage: (dx,dy) = (diff(x,t), diff(y,t))
+        sage: integral(sin(x)*dx, t,-1, 1)
+        0    
+        sage: restore('x,y')   # restore the symbolic variables x and y
+
+    SAGE is unable to do anything with the following integral:
     
+        sage: print integral( exp(-x^2)*log(x), x )
+                              /      2
+                              [   - x
+                              I  e     log(x) dx
+                              ]
+                              /
+
+    SAGE does not know how to compute this integral either. 
+        sage: print integral( exp(-x^2)*ln(x), x, 0, oo)
+                              inf
+                             /         2
+                             [      - x
+                             I     e     log(x) dx
+                             ]
+                             /
+                              0
+
+    This definite integral is easy:
+        sage: integral( ln(x)/x, x, 1, 2)
+        log(2)^2/2
+
+    SAGE can't do this elliptic integral (yet):
+        sage: integral(1/sqrt(2*t^4 - 3*t^2 - 2), t, 2, 3)
+        integrate(1/(sqrt(2*t^4 - 3*t^2 - 2)), t, 2, 3)
+
+    A double integral:
+        sage: integral(integral(x*y^2, x, 0, y), y, -2, 2)
+        32/5
+
+    This illustrates using assumptions:
+        sage: integral(abs(x), x, 0, 5)
+        25/2
+        sage: integral(abs(x), x, 0, a)
+        integrate(abs(x), x, 0, a)
+        sage: assume(a>0)
+        sage: integral(abs(x), x, 0, a)
+        a^2/2
+        sage: forget()      # forget the assumptions.
+
+    We integrate and differentiate a huge mess:
+        sage: f = (x^2-1+3*(1+x^2)^(1/3))/(1+x^2)^(2/3)*x/(x^2+2)^2
+        sage: g = integral(f, x)
+        sage: h = f - diff(g, x)
+
+    Numerically h is 0, but the symbolic equality checker
+    unfortunately can't tell for sure:
+        sage: [float(h(i)) for i in range(5)]     # random low-order bits
+        [0.0, -1.1102230246251565e-16, -8.3266726846886741e-17, -4.163336342344337e-17, -6.9388939039072284e-17]
+        sage: bool(h == 0) 
+        False
+    """
+    try:
+        return f.integral(*args, **kwds)
+    except AttributeError:
+        pass
+    if not isinstance(f, SymbolicExpression):
+        f = SR(f)
+    return f.integral(*args, **kwds)
+
+integrate = integral
+
+def limit(f, dir=None, **argv):
+    r"""
+    Return the limit as the variable v approaches a from the
+    given direction.
+
+        \begin{verbatim}
+        limit(expr, x = a)
+        limit(expr, x = a, dir='above')
+        \end{verbatim}
+
+    INPUT:
+        dir -- (default: None); dir may have the value `plus' (or 'above')
+               for a limit from above, `minus' (or 'below') for a limit from
+               below, or may be omitted (implying a two-sided
+               limit is to be computed).
+        **argv -- 1 named parameter
+
+    ALIAS: You can also use lim instead of limit. 
+
+    EXAMPLES:
+        sage: limit(sin(x)/x, x=0)
+        1
+        sage: limit(exp(x), x=oo)
+        +Infinity
+        sage: lim(exp(x), x=-oo)
+        0
+        sage: lim(1/x, x=0) 
+        und
+
+    SAGE does not know how to do this limit (which is 0),
+    so it returns it unevaluated:
+        sage: lim(exp(x^2)*(1-erf(x)), x=infinity)
+         limit(e^x^2 - e^x^2*erf(x), x=+Infinity)
+    """
+    if not isinstance(f, SymbolicExpression):
+        f = SR(f)
+    return f.limit(dir=dir, **argv)
+
+lim = limit
+
+def taylor(f, v, a, n):
+    """
+    Expands self in a truncated Taylor or Laurent series in the
+    variable v around the point a, containing terms through $(x - a)^n$.
+
+    INPUT:
+        v -- variable
+        a -- number
+        n -- integer
+
+    EXAMPLES:
+        sage: taylor (sqrt (1 - k^2*sin(x)^2), x, 0, 6)
+        1 - (k^2*x^2/2) - ((3*k^4 - 4*k^2)*x^4/24) - ((45*k^6 - 60*k^4 + 16*k^2)*x^6/720)
+        sage: taylor ((x + 1)^n, x, 0, 4)
+        1 + n*x + (n^2 - n)*x^2/2 + (n^3 - 3*n^2 + 2*n)*x^3/6 + (n^4 - 6*n^3 + 11*n^2 - 6*n)*x^4/24        
+        
+    """
+    if not isinstance(f, SymbolicExpression):
+        f = SR(f)
+    return f.taylor(v=v,a=a,n=n)
+    
+
+def expand(x, *args, **kwds):
+    """
+    EXAMPLES:
+        sage: a = (1+I)*(2-sqrt(3)*I); a
+        (I + 1)*(2 - sqrt(3)*I)
+        sage: expand(a)
+        -sqrt(3)*I + 2*I + sqrt(3) + 2
+        sage: a = (x-1)*(x^2 - 1); a
+        (x - 1)*(x^2 - 1)
+        sage: expand(a)
+        x^3 - x^2 - x + 1
+
+    You can also use expand on polynomial, integer, and other
+    factorizations:
+        sage: x = polygen(ZZ)
+        sage: F = factor(x^12 - 1); F
+        (x - 1) * (x + 1) * (x^2 - x + 1) * (x^2 + 1) * (x^2 + x + 1) * (x^4 - x^2 + 1)
+        sage: expand(F)
+        x^12 - 1
+        sage: F.expand()
+        x^12 - 1
+        sage: F = factor(2007); F
+        3^2 * 223
+        sage: expand(F)
+        2007
+    
+    Note: If you want to compute the expanded form of a polynomial
+    arithmetic operation quickly and the coefficients of the polynomial
+    all lie in some ring, e.g., the integers, it is vastly faster to
+    create a polynomial ring and do the arithmetic there.
+
+        sage: x = polygen(ZZ)      # polynomial over a given base ring.
+        sage: f = sum(x^n for n in range(5))
+        sage: f*f                  # much faster, even if the degree is huge
+        x^8 + 2*x^7 + 3*x^6 + 4*x^5 + 5*x^4 + 4*x^3 + 3*x^2 + 2*x + 1
+
+    """
+    try:
+        return x.expand(*args, **kwds)
+    except AttributeError:
+        return x
+
+
+def laplace(f, t, s):
+    r"""
+    Attempts to compute and return the Laplace transform of self
+    with respect to the variable t and transform parameter s.  If
+    Laplace cannot find a solution, a delayed function is returned.
+
+    The function that is returned maybe be viewed as a function of s.
+        
+    EXAMPLES:
+        sage: f = exp (2*t + a) * sin(t) * t; f       
+        t*e^(2*t + a)*sin(t)
+        sage: L = laplace(f, t, s); L
+        e^a*(2*s - 4)/((s^2 - 4*s + 5)^2)
+        sage: inverse_laplace(L, s, t)
+        t*e^(2*t + a)*sin(t)
+
+    Unable to compute solution:
+        sage: laplace(1/s, s, t)
+        laplace(1/s, s, t)    
+    """
+    if not isinstance(f, SymbolicExpression):
+        f = SR(f)
+    return f.laplace(t,s)
+
+def inverse_laplace(f, t, s):
+    r"""
+    Attempts to compute and return the inverse Laplace transform of
+    self with respect to the variable t and transform parameter s.  If
+    Laplace cannot find a solution, a delayed function is returned, which
+    is called \code{ilt}.
+
+    EXAMPLES:
+        sage: f = t*cos(t)
+        sage: L = laplace(f, t, s); L
+        2*s^2/(s^2 + 1)^2 - (1/(s^2 + 1))
+        sage: inverse_laplace(L, s, t)
+        t*cos(t)
+        sage: print inverse_laplace(1/(s^3+1), s, t)
+                           sqrt(3) t        sqrt(3) t
+                       sin(---------)   cos(---------)      - t
+                  t/2          2                2          e
+                 e    (-------------- - --------------) + -----
+                          sqrt(3)             3             3
+
+    No explicit inverse Laplace transform, so one is returned formally as a function ilt.
+        sage: inverse_laplace(cos(s), s, t)
+        ilt(cos(s), s, t)
+    """
+    if not isinstance(f, SymbolicExpression):
+        f = SR(f)
+    return f.inverse_laplace(t,s)
+
+
Index: sage/calculus/notes.txt
===================================================================
--- sage/calculus/notes.txt	(revision 4057)
+++ sage/calculus/notes.txt	(revision 4057)
@@ -0,0 +1,43 @@
+On 4/22/07, Ondrej Certik <ondrej.certik@gmail.com> wrote:
+> As to the extensibility  -  I think it would be quite difficult to
+> extend for example Maxima's limits facility (there are some limits
+> that Maxima cannot do, but SymPy can), or Maxima's differential
+> equations solver module. Either it would have to be done in LISP, or
+> rewrite the whole module to python, neither of which I find easy. Or
+> is there a better approach?
+
+I had in mind the following iterative approach:
+
+  (1) Implement the basic limit formulas for products, sums, quotients, etc.,
+        in Python. 
+  (2) This reduces computing limits of symbolic expressions to computing
+        the limits of the leaves in the tree, i.e., symbolic variables, constants, and 
+        primitive functions (like sinh, exp, log, erf).
+ (3)  Limits of symbolic variables and constants are trivial.
+ (4) For some special functions one writes an optional method _limit_
+       that computes the limit of that special function at a point from a given
+       direction.  The default _limit_ method in the base class computes the
+       limit using maxima.  So for each function for which you want better
+       speed or a different behavior from maxima, you just fill in the _limit_ method.
+
+Exactly the steps above would also work for symbolic differentiation.
+(Integration is a completely different story.)
+
+Ondrej doesn't this will work (I totally disagree):
+
+"I don't think that would work for limits (it should work for
+differentiation though) except some simple cases. As an example, let's
+take this limit, that Maxima cannot do:
+
+limit((5**x+3**x)**(1/x), x, infty)
+
+(if you type this in SymPy, you will get 5, because we use the Gruntz
+algorithm, as described here:
+http://sympy.googlecode.com/svn/trunk/doc/gruntz.pdf). The only thing
+that occurs to me how to fix maxima is to match the expression and
+return 5 immediatelly, or implement the whole algorithm from scratch,
+but then you will just write the same code as we did for SymPy.
+
+Integration is quite easy - just match the expression and return a
+table integral. The general Risch algorithm is difficult, but I think
+Axiom can do it."
Index: sage/calculus/predefined.py
===================================================================
--- sage/calculus/predefined.py	(revision 4270)
+++ sage/calculus/predefined.py	(revision 4270)
@@ -0,0 +1,52 @@
+from calculus import var
+
+a = var('a')
+b = var('b')
+c = var('c')
+d = var('d')
+f = var('f')
+g = var('g')
+h = var('h')
+j = var('j')
+k = var('k')
+l = var('l')
+m = var('m')
+n = var('n')
+o = var('o')
+p = var('p')
+q = var('q')
+r = var('r')
+s = var('s')
+t = var('t')
+u = var('u')
+v = var('v')
+w = var('w')
+x = var('x')
+y = var('y')
+z = var('z')
+A = var('A')
+B = var('B')
+C = var('C')
+D = var('D')
+E = var('E')
+F = var('F')
+G = var('G')
+H = var('H')
+J = var('J')
+K = var('K')
+L = var('L')
+M = var('M')
+N = var('N')
+O = var('O')
+P = var('P')
+Q = var('Q')
+R = var('R')
+S = var('S')
+T = var('T')
+U = var('U')
+V = var('V')
+W = var('W')
+X = var('X')
+Y = var('Y')
+Z = var('Z')
+
Index: sage/calculus/tests.py
===================================================================
--- sage/calculus/tests.py	(revision 4359)
+++ sage/calculus/tests.py	(revision 4359)
@@ -0,0 +1,196 @@
+"""
+Further Examples.
+
+Compute the Christoffel symbol.
+
+    sage: var('r theta phi')
+    (r, theta, phi)
+    sage: m = matrix(SR, [[(1-1/r),0,0,0],[0,-(1-1/r)^(-1),0,0],[0,0,-r^2,0],[0,0,0,-r^2*(sin(theta))^2]])
+    sage: print m
+    [        1 - (1/r)                 0                 0                 0]
+    [                0    -1/(1 - (1/r))                 0                 0]
+    [                0                 0              -r^2                 0]
+    [                0                 0                 0 -r^2*sin(theta)^2]    
+
+    sage: def christoffel(i,j,k,vars,g):
+    ...   s = 0
+    ...   ginv = g^(-1)
+    ...   for l in range(g.nrows()):
+    ...      s = s + (1/2)*ginv[k,l]*(g[j,l].diff(vars[i])+g[i,l].diff(vars[j])-g[i,j].diff(vars[l]))
+    ...   return s
+
+    sage: christoffel(3,3,2, [t,r,theta,phi], m)
+    -cos(theta)*sin(theta)
+    sage: X = christoffel(1,1,1,[t,r,theta,phi],m)
+    sage: print X
+                                     1
+                                     - - 1
+                                     r
+                                 -------------
+                                        1 2  2
+                                 2 (1 - -)  r
+                                        r    
+    sage: print X.rational_simplify()
+                                       1
+                                 - ----------
+                                      2
+                                   2 r  - 2 r    
+
+Some basic things:
+
+    sage: f(x,y) = x^3 + sinh(1/y)                   
+    sage: f
+    (x, y) |--> sinh(1/y) + x^3
+    sage: f^3
+    (x, y) |--> (sinh(1/y) + x^3)^3
+    sage: (f^3).expand()
+    (x, y) |--> sinh(1/y)^3 + 3*x^3*sinh(1/y)^2 + 3*x^6*sinh(1/y) + x^9
+
+A polynomial over a symbolic base ring:
+    sage: R = SR[x]
+    sage: f = R([1/sqrt(2), 1/(4*sqrt(2))])
+    sage: f
+    1/(4*sqrt(2))*x + 1/sqrt(2)
+    sage: -f
+    (-1/(4*sqrt(2)))*x + -1/sqrt(2)
+    sage: (-f).degree()
+    1
+
+Something that was a printing bug.  This tests that we print
+the simplified version using ASCII art:
+    sage: A = exp(I*pi/5)       
+    sage: print A*A*A*A*A*A*A*A*A*A       
+                                           1
+
+We check a statement made at the beginning of Friedlander and Joshi's book
+on Distributions:
+    sage: f = sin(x^2)
+    sage: g = cos(x) + x^3
+    sage: u = f(x+t) + g(x-t)
+    sage: u
+    sin((x + t)^2) + cos(x - t) + (x - t)^3
+    sage: u.diff(t,2) - u.diff(x,2)
+    0
+
+Restoring variables after they have been turned into functions:
+    sage: x = function('x')
+    sage: sin(x).variables()
+    ()
+    sage: restore('x')
+    sage: sin(x).variables()
+    (x,)
+
+MATHEMATICA:
+Some examples of integration and differentiation taken from some
+Mathematica docs:
+    sage: diff(x^n, x)
+    n*x^(n - 1)
+    sage: diff(x^2 * log(x+a), x)
+    2*x*log(x + a) + x^2/(x + a)
+    sage: derivative(atan(x), x)
+    1/(x^2 + 1)
+    sage: derivative(x^n, x, 3)
+    (n - 2)*(n - 1)*n*x^(n - 3)
+    sage: derivative( function('f')(x), x)
+    diff(f(x), x, 1)
+    sage: diff( 2*x*f(x^2), x)
+    2*x*diff(f(x^2), x, 1) + 2*f(x^2)
+    sage: print integrate( 1/(x^4 - a^4), x)
+                                                           x
+                                                      atan(-)
+                            log(x + a)   log(x - a)	       a
+                          - ---------- + ---------- - -------
+                                  3		   3	      3
+                               4 a	        4 a	   2 a
+    sage: expand(integrate(log(1-x^2), x))
+    x*log(1 - x^2) + log(x + 1) - log(x - 1) - 2*x
+    sage: integrate(log(1-x^2)/x, x)
+    log(x)*log(1 - x^2) + polylog(2, 1 - x^2)/2
+    sage: integrate(exp(1-x^2),x)
+    sqrt(pi)*e*erf(x)/2
+    sage: integrate(sin(x^2),x)
+    sqrt(pi)*((sqrt(2)*I + sqrt(2))*erf((sqrt(2)*I + sqrt(2))*x/2) + (sqrt(2)*I - sqrt(2))*erf((sqrt(2)*I - sqrt(2))*x/2))/8
+    sage: integrate((1-x^2)^n,x)
+    integrate((1 - x^2)^n, x)
+    sage: integrate(x^x,x)
+    integrate(x^x, x)
+    sage: print integrate(1/(x^3+1),x)
+                                             2 x - 1
+                           2	    atan(-------)
+                      log(x  - x + 1)	 sqrt(3)    log(x + 1)
+                    - --------------- + ------------- + ----------
+                             6	       sqrt(3)	        3
+    sage: integrate(1/(x^3+1), x, 0, 1)
+    (6*log(2) + sqrt(3)*pi)/18 + sqrt(3)*pi/18
+    
+    sage: forget(); assume(c > 0)
+    sage: integrate(exp(-c*x^2), x, -oo, oo)
+    sqrt(pi)/sqrt(c)
+    sage: forget()
+
+The following are a bunch of examples of integrals that Mathematica
+can do, but SAGE currently can't do:
+    sage: integrate(sqrt(x + sqrt(x)), x)    # todo -- mathematica can do this
+    integrate(sqrt(x + sqrt(x)), x)
+    sage: integrate(log(x)*exp(-x^2))        # todo -- mathematica can do this
+    integrate(e^(-x^2)*log(x), x)
+    
+    sage.: # Todo -- Mathematica can do this and gets pi^2/15
+    sage.: # integrate(log(1+sqrt(1+4*x)/2)/x, x, 0, 1)
+    [boom!]
+    Integral is divergent
+    
+    sage: integrate(ceil(x^2 + floor(x)), x, 0, 5)    # todo: mathematica can do this
+    integrate(ceil(x^2) + floor(x), x, 0, 5)
+    
+
+MAPLE:
+The basic differentiation and integration examples in the
+Maple documentation:
+
+    sage: diff(sin(x), x)
+    cos(x)
+    sage: diff(sin(x), y)
+    0
+    sage: diff(sin(x), x, 3)
+    -cos(x)
+    sage: diff(x*sin(cos(x)), x)
+    sin(cos(x)) - x*sin(x)*cos(cos(x))
+    sage: diff(tan(x), x)
+    sec(x)^2
+    sage: f = function('f'); f
+    f
+    sage: diff(f(x), x)
+    diff(f(x), x, 1)
+    sage: diff(f(x,y), x, y)
+    diff(f(x, y), x, 1, y, 1)
+    sage: diff(f(x,y), x, y) - diff(f(x,y), y, x)
+    0
+    sage: g = function('g')
+    sage: diff(g(x,y,z), x,z,z)
+    diff(g(x, y, z), x, 1, z, 2)
+    sage: integrate(sin(x), x)
+    -cos(x)
+    sage: integrate(sin(x), x, 0, pi)
+    2
+    sage: assume(b-a>0)      # annoying -- maple doesn't require this...
+    sage: print integrate(sin(x), x, a, b)
+                                    cos(a) - cos(b)
+    sage: forget()
+
+    
+    sage: integrate( x/(x^3-1), x)
+    (-log(x^2 + x + 1))/6 + atan((2*x + 1)/sqrt(3))/sqrt(3) + log(x - 1)/3
+    sage: integrate(exp(-x^2), x)
+    sqrt(pi)*erf(x)/2
+    sage: integrate(exp(-x^2)*log(x), x)       # todo: maple can compute this exactly.
+    integrate(e^(-x^2)*log(x), x)
+    sage: f = exp(-x^2)*log(x)
+    sage: f.nintegral(x, 0, 999)
+    (-0.87005772672831549, 7.5584116743243612e-10, 567, 0)
+    sage: integral(1/sqrt(2*t^4 - 3*t^2 - 2), t, 2, 3)     # todo: maple can do this
+    integrate(1/(sqrt(2*t^4 - 3*t^2 - 2)), t, 2, 3)
+    sage: integral(integral(x*y^2, x, 0, y), y, -2, 2)
+    32/5
+    
+"""
Index: sage/calculus/todo.txt
===================================================================
--- sage/calculus/todo.txt	(revision 4270)
+++ sage/calculus/todo.txt	(revision 4270)
@@ -0,0 +1,3 @@
+[ ] Limits.  See the comments around dummy_limit in calculus.py
+
+[ ] 
Index: sage/calculus/var.pyx
===================================================================
--- sage/calculus/var.pyx	(revision 4270)
+++ sage/calculus/var.pyx	(revision 4270)
@@ -0,0 +1,111 @@
+import calculus
+
+def var(s):
+    """
+    Create a symbolic variable with the name \emph{s}.
+
+    INPUT:
+        s -- a string, either a single variable name,
+             or a space or comma separated list of
+             variable names.
+
+    NOTE: The new variable is both returned and automatically injected
+    into the global namespace.  If you use var in library code, it is
+    better to use sage.calculus.calculus.var, since it won't touch the
+    global namespace.
+
+    EXAMPLES:
+    We define three variables:
+        sage: var('xx yy zz')
+        (xx, yy, zz)
+
+    Then we make an algebraic expression out of them.
+        sage: f = xx^n + yy^n + zz^n; f
+        zz^n + yy^n + xx^n
+
+    We can substitute a new variable name for n.
+        sage: f(n = var('sigma'))
+        zz^sigma + yy^sigma + xx^sigma
+
+    If you make an important builtin variable into a symbolic variable,
+    you can get back the original value using restore:
+        sage: var('QQ RR')
+        (QQ, RR)
+        sage: QQ
+        QQ
+        sage: restore('QQ')
+        sage: QQ
+        Rational Field
+
+    We make two new variables separated by commas:
+        sage: var('theta, gamma')
+        (theta, gamma)
+        sage: theta^2 + gamma^3
+        gamma^3 + theta^2
+
+    The new variables are of type SymbolicVariable, and belong
+    to the symbolic expression ring:
+        sage: type(theta)
+        <class 'sage.calculus.calculus.SymbolicVariable'>
+        sage: parent(theta)
+        Symbolic Ring
+    """
+    G = globals()  # this is the reason the code must be in SageX.
+    v = calculus.var(s)
+    if isinstance(v, tuple):
+        for x in v:
+            G[repr(x)] = x
+    else:
+        G[repr(v)] = v
+    return v
+
+def function(s, *args):
+    """
+    Create a formal symbolic function with the name \emph{s}.
+
+    INPUT:
+        s -- a string, either a single variable name,
+             or a space or comma separated list of
+             variable names.
+
+    NOTE: The new function is both returned and automatically injected
+    into the global namespace.  If you use var in library code, it is
+    better to use sage.calculus.calculus.function, since it won't
+    touch the global namespace.
+
+    EXAMPLES:
+    We create a formal function called supersin.
+        sage: f = function('supersin', x)
+        sage: f
+        supersin(x)
+
+    We can immediately use supersin in symbolic expressions:
+        sage: supersin(y+z) + A^3
+        A^3 + supersin(z + y)
+
+    We can define other functions in terms of supersin.
+        sage: g(x,y) = supersin(x)^2 + sin(y/2)
+        sage: g
+        (x, y) |--> sin(y/2) + supersin(x)^2
+        sage: g.diff(y)
+        (x, y) |--> cos(y/2)/2
+        sage: g.diff(x)
+        (x, y) |--> 2*supersin(x)*diff(supersin(x), x, 1)
+        sage: k = g.diff(x); k
+        (x, y) |--> 2*supersin(x)*diff(supersin(x), x, 1)
+        sage: k.substitute(supersin=sin)
+        2*cos(x)*sin(x)
+    """
+    if len(args) > 0:
+        return function(s)(*args)
+    
+    G = globals()  # this is the reason the code must be in SageX.
+    v = calculus.function(s)
+    if isinstance(v, tuple):
+        for x in v:
+            G[repr(x)] = x
+    else:
+        G[repr(v)] = v
+    return v
+
+
Index: sage/calculus/wester.py
===================================================================
--- sage/calculus/wester.py	(revision 4359)
+++ sage/calculus/wester.py	(revision 4359)
@@ -0,0 +1,540 @@
+"""
+Further examples from Wester's paper
+
+These are all the problems at 
+    http://yacas.sourceforge.net/essaysmanual.html
+
+They come from the 1994 paper "Review of CAS mathematical capabilities",
+by Michael Wester, who put forward 123 problems that a reasonable computer
+algebra system should be able to solve and tested the then current
+versions of various commercial CAS on this list.   SAGE can do most of
+the problems natively now, i.e., with no explicit calls to maxima or
+other systems. 
+
+
+sage: factorial(50)
+30414093201713378043612608166064768844377641568960512000000000000
+sage: factor(factorial(50))
+2^47 * 3^22 * 5^12 * 7^8 * 11^4 * 13^3 * 17^2 * 19^2 * 23^2 * 29 * 31 * 37 * 41 * 43 * 47
+
+sage: # 1/2+...+1/10 = 4861/2520
+sage: sum(1/n for n in range(2,10+1)) == 4861/2520
+True
+
+sage: # Evaluate  e^(Pi*Sqrt(163)) to 50 decimal digits
+sage: a = e^(pi*sqrt(163)); a
+e^(sqrt(163)*pi)
+sage: print RealField(150)(a)
+262537412640768743.99999999999925007259719819
+
+sage: # Evaluate the Bessel function J[2] numerically at z=1+I.
+sage: # NOTE -- we get a different answer than yacas
+sage: bessel_J(2.0,1.0+I)
+0.874211097673326 - 0.222469792478650*I
+
+sage: # Obtain period of decimal fraction 1/7=0.(142857).
+sage: a = 1/7
+sage: print a
+1/7
+sage: print a.period()
+6
+
+sage: # Continued fraction of 3.1415926535
+sage: a = 3.1415926535
+sage: continued_fraction(a)
+[3, 7, 15, 1, 292, 1, 1, 6, 2, 13, 4]
+
+sage: # (not exactly ok) Sqrt(2*Sqrt(3)+4)=1+Sqrt(3).
+sage: # The maxima backend equality checker fails this; maybe it *should*, since
+sage: # the equality only holds for one choice of sign.
+sage: a = sqrt(2*sqrt(3) + 4); b = 1 + sqrt(3)
+sage: print float(a-b)
+0.0
+sage: print bool(a == b)
+False
+sage: # We can, of course, do this in a quadratic field
+sage: k.<sqrt3> = QuadraticField(3)
+sage: asqr = 2*sqrt3 + 4
+sage: b = 1+sqrt3
+sage: asqr == b^2
+True
+
+sage: # (not exactly ok) Sqrt(14+3*Sqrt(3+2*Sqrt(5-12*Sqrt(3-2*Sqrt(2)))))=3+Sqrt(2).
+sage: a = sqrt(14+3*sqrt(3+2*sqrt(5-12*sqrt(3-2*sqrt(2)))))
+sage: b = 3+sqrt(2)
+sage: print a, b
+sqrt(3 sqrt(2 sqrt(5 - 12 sqrt(3 - 2 sqrt(2))) + 3) + 14)                                  sqrt(2) + 3
+sage: print bool(a==b)
+False
+sage: print float(a-b)
+1.7763568394e-15
+sage: # 2*Infinity-3=Infinity.
+sage: 2*infinity-3 == infinity
+True
+
+sage: # (YES) Standard deviation of the sample (1, 2, 3, 4, 5).
+sage: v = vector(RDF, 5, [1,2,3,4,5])
+sage: v.standard_deviation()
+1.5811388300841898
+
+sage: # (NO) Hypothesis testing with t-distribution.
+sage: # (NO) Hypothesis testing with chi^2 distribution
+
+sage: # (YES) (x^2-4)/(x^2+4*x+4)=(x-2)/(x+2).
+sage: R.<x> = QQ[]
+sage: (x^2-4)/(x^2+4*x+4) == (x-2)/(x+2)
+True
+sage: restore('x')
+
+sage: # (NO -- Maxima doesn't consider them equal.) 
+sage: # (Exp(x)-1)/(Exp(x/2)+1)=Exp(x/2)-1.
+sage: f = (exp(x)-1)/(exp(x/2)+1)
+sage: g = exp(x/2)-1
+sage: f
+(e^x - 1)/(e^(x/2) + 1)
+sage: g
+e^(x/2) - 1
+sage: print f(10.0), g(10.0)
+147.4131591025766 147.4131591025766
+sage: print bool(f == g)
+False
+
+sage: # (YES) Expand (1+x)^20, take derivative and factorize.
+sage: # first do it is using algebraic polys
+sage: R.<x> = QQ[]
+sage: f = (1+x)^20
+sage: print f
+x^20 + 20*x^19 + 190*x^18 + 1140*x^17 + 4845*x^16 + 15504*x^15 + 38760*x^14 + 77520*x^13 + 125970*x^12 + 167960*x^11 + 184756*x^10 + 167960*x^9 + 125970*x^8 + 77520*x^7 + 38760*x^6 + 15504*x^5 + 4845*x^4 + 1140*x^3 + 190*x^2 + 20*x + 1
+sage: print f.factor()
+(x + 1)^20
+sage: # next do it symbolically
+sage: restore('x')
+sage: f = (1+x)^20; f
+(x + 1)^20
+sage: g = f.expand(); g
+x^20 + 20*x^19 + 190*x^18 + 1140*x^17 + 4845*x^16 + 15504*x^15 + 38760*x^14 + 77520*x^13 + 125970*x^12 + 167960*x^11 + 184756*x^10 + 167960*x^9 + 125970*x^8 + 77520*x^7 + 38760*x^6 + 15504*x^5 + 4845*x^4 + 1140*x^3 + 190*x^2 + 20*x + 1
+sage: g.factor()
+(x + 1)^20
+
+
+sage: # (YES) Factorize x^100-1.
+sage: factor(x^100-1)
+(x - 1)*(x + 1)*(x^2 + 1)*(x^4 - x^3 + x^2 - x + 1)*(x^4 + x^3 + x^2 + x + 1)*(x^8 - x^6 + x^4 - x^2 + 1)*(x^20 - x^15 + x^10 - x^5 + 1)*(x^20 + x^15 + x^10 + x^5 + 1)*(x^40 - x^30 + x^20 - x^10 + 1)
+sage: # Also, algebraically
+sage: x = polygen(QQ)
+sage: factor(x^100 - 1)
+(x - 1) * (x + 1) * (x^2 + 1) * (x^4 - x^3 + x^2 - x + 1) * (x^4 + x^3 + x^2 + x + 1) * (x^8 - x^6 + x^4 - x^2 + 1) * (x^20 - x^15 + x^10 - x^5 + 1) * (x^20 + x^15 + x^10 + x^5 + 1) * (x^40 - x^30 + x^20 - x^10 + 1)
+sage: restore('x')
+
+
+sage: # (YES) Factorize  x^4-3*x^2+1 in the field of rational numbers extended by roots of  x^2-x-1.
+sage: k.< a> = NumberField(x^2 - x -1)
+sage: R.< y> = k[]
+sage: f = y^4 - 3*y^2 + 1
+sage: f
+y^4 + (-3)*y^2 + 1
+sage: factor(f)
+(y + -a) * (y + -a + 1) * (y + a - 1) * (y + a)
+
+sage: # (YES) Factorize  x^4-3*x^2+1 mod 5.
+sage: k.< x > = GF(5) [ ]
+sage: f = x^4 - 3*x^2 + 1
+sage: f.factor()
+(x + 2)^2 * (x + 3)^2
+sage: # Alternatively, from symbol x as follows:
+sage: reset('x')
+sage: f = x^4 - 3*x^2 + 1
+sage: f.polynomial(GF(5)).factor()
+(x + 2)^2 * (x + 3)^2
+
+sage: # (YES) Partial fraction decomposition of (x^2+2*x+3)/(x^3+4*x^2+5*x+2)
+sage: f = (x^2+2*x+3)/(x^3+4*x^2+5*x+2)
+sage: print f
+                                  2
+                                 x  + 2 x + 3
+                              -------------------
+                               3      2
+                              x  + 4 x  + 5 x + 2
+
+sage: print f.partial_fraction()
+                             3	     2	      2
+                           ----- - ----- + --------
+                           x + 2   x + 1	  2
+                                           (x + 1)
+
+                                           
+sage: # (BUG?) Assuming  x>=y,  y>=z,  z>=x, deduce  x=z.
+sage: # Maxima doesn't agree that x==z is a conclusion...
+sage: forget()
+sage: restore('x,y,z')
+sage: assume(x>=y, y>=z,z>=x)
+sage: print bool(x==z)
+False
+
+sage: # (YES) Assuming x>y, y>0, deduce 2*x^2>2*y^2.
+sage: forget()
+sage: assume(x>y, y>0)
+sage: print assumptions()
+[x > y, y > 0]
+sage: print bool(2*x^2 > 2*y^2)
+True
+sage: forget()
+sage: print assumptions()
+[]
+sage: # Solve the inequality Abs(x-1)>2.
+
+sage: # (NO) Maxima doesn't solve inequalities:
+sage: eqn = abs(x-1) > 2
+sage: print eqn
+                                abs(x - 1) > 2
+
+sage: # (NO) Solve the inequality (x-1)*...*(x-5)<0.
+sage: eqn = prod(x-i for i in range(1,5 +1)) < 0
+sage: # but don't know how to solve
+sage: print eqn
+                  (x - 5) (x - 4) (x - 3) (x - 2) (x - 1) < 0
+
+
+sage: # (YES) Cos(3*x)/Cos(x)=Cos(x)^2-3*Sin(x)^2 or similar equivalent combination.
+sage: f = cos(3*x)/cos(x)
+sage: g = cos(x)^2 - 3*sin(x)^2
+sage: h = f-g
+sage: print h.trig_simplify()
+                                       0
+
+sage: # (YES) Cos(3*x)/Cos(x)=2*Cos(2*x)-1.
+sage: f = cos(3*x)/cos(x)
+sage: g = 2*cos(2*x) - 1
+sage: h = f-g
+sage: print h.trig_simplify()
+                                       0
+sage: # (NO) Define rewrite rules to match  Cos(3*x)/Cos(x)=Cos(x)^2-3*Sin(x)^2.
+sage: # SAGE has no notion of "rewrite rules". 
+
+
+sage: # (YES) Sqrt(997)-(997^3)^(1/6)=0
+sage: a = sqrt(997) - (997^3)^(1/6)
+sage: print a
+                                       0
+sage: print bool(a == 0)
+True
+
+sage: # (NO) Sqrt(99983)-99983^3^(1/6)=0
+sage: # For some reason Maxima decides its not zero because of the factorization. 
+sage: a = sqrt(99983) - (99983^3)^(1/6)
+sage: print a
+                       sqrt(99983) - sqrt(13) sqrt(7691)
+sage: print bool(a==0)
+False
+sage: float(a)    # random low order bits
+1.13686837722e-13
+sage: print 13*7691
+99983
+
+sage: # (YES) (2^(1/3) + 4^(1/3))^3 - 6*(2^(1/3) + 4^(1/3))-6 = 0
+sage: ## same issue as above -- can only do using number fields
+sage: a = (2^(1/3) + 4^(1/3))^3 - 6*(2^(1/3) + 4^(1/3)) - 6
+sage: print a
+		       1/3    1/3 3	  1/3	 1/3
+        	     (4	   + 2	 )  - 6 (4    + 2   ) - 6
+sage: print bool(a==0)
+False
+sage: print float(a)
+3.5527136788e-15
+sage: ## but we can do it using number fields.
+sage: reset('x')
+sage: k.<b> = NumberField(x^3-2)
+sage: a = (b  + b^2)^3 - 6*(b  + b^2) - 6
+sage: print a
+0
+
+sage: # (YES) Ln(Tan(x/2+Pi/4))-ArcSinh(Tan(x))=0
+sage: # Yes, in that the thing is clearly not equal to 0!
+sage: f = log(tan(x/2 + pi/4)) - asin(tan(x))
+sage: bool(f == 0)
+False
+sage: [float(f(i/10)) for i in range(1,5)]           # random low order bits
+[-0.00033670040754082975, -0.0027778004096620235, -0.0098909940914040928, -0.025411145508414501]
+
+sage: # (YES) Numerically, the expression Ln(Tan(x/2+Pi/4))-ArcSinh(Tan(x))=0 and its derivative at x=0 are zero.
+sage: g = f.derivative()
+sage: abs(float(f(0))) < 1e-10
+True
+sage: abs(float(g(0))) < 1e-10
+True
+sage: print g
+                         2 x    pi
+                      sec (- + ---)            2
+                           2    4           sec (x)
+                      -------------- - -----------------
+                            x    pi                2
+                      2 tan(- + ---)   sqrt(1 - tan (x))
+                            2    4
+                            
+
+sage: # (NO?) Ln((2*Sqrt(r) + 1)/Sqrt(4*r 4*Sqrt(r) 1))=0.
+sage: f = log( (2*sqrt(r) + 1) / sqrt(4*r  + 4*sqrt(r) +  1))
+sage: print f
+                                  2 sqrt(r) + 1
+                        log(-------------------------)
+                            sqrt(4 r + 4 sqrt(r) + 1)
+sage: print bool(f == 0)
+False
+sage: print [float(f(i)) for i in [0.1,0.3,0.5]]
+[0.0, 0.0, 0.0]
+
+
+sage: # (NO, except numerically)
+sage: # (4*r+4*Sqrt(r)+1)^(Sqrt(r)/(2*Sqrt(r)+1))*(2*Sqrt(r)+1)^(2*Sqrt(r)+1)^(-1)-2*Sqrt(r)-1=0, assuming r>0.
+sage: assume(r>0)
+sage: f = (4*r+4*sqrt(r)+1)^(sqrt(r)/(2*sqrt(r)+1))*(2*sqrt(r)+1)^(2*sqrt(r)+1)^(-1)-2*sqrt(r)-1
+sage: print f
+                             1				     sqrt(r)
+                       -------------			  -------------
+                       2 sqrt(r) + 1			  2 sqrt(r) + 1
+        (2 sqrt(r) + 1)		     (4 r + 4 sqrt(r) + 1)
+                                                                - 2 sqrt(r) - 1
+sage: bool(f == 0)
+False
+sage: [float(f(i)) for i in [0.1,0.3,0.5]]     # random low-order bits
+[0.0, 0.0, -2.2204460492503131e-16]
+
+
+sage: # (YES) Obtain real and imaginary parts of Ln(3+4*I).
+sage: a = log(3+4*I)
+sage: print a
+                                 log(4  I + 3)
+sage: print a.real()
+                                    log(5)
+sage: print a.imag()
+                                         4
+                                    atan(-)
+                                         3
+
+sage: # (YES) Obtain real and imaginary parts of Tan(x+I*y)
+sage: a = tan(x + I*y)
+sage: print a
+                                 tan( I y + x)
+sage: print a.real()
+                                   sin(2 x)
+                             --------------------
+                             cosh(2 y) + cos(2 x)
+sage: print a.imag()
+                                  sinh(2 y)
+                             --------------------
+                             cosh(2 y) + cos(2 x)
+
+sage: # (YES) Simplify Ln(Exp(z)) to z for -Pi<Im(z)<=Pi.
+sage: f = log(exp(z))
+sage: # (except it does it even without the constraint)
+sage: assume(-pi < imag(z))
+sage: assume(imag(z) <= pi)
+sage: f
+z
+sage: forget()
+
+sage: # (YES) Assuming Re(x)>0, Re(y)>0, deduce x^(1/n)*y^(1/n)-(x*y)^(1/n)=0.
+sage: assume(real(x) > 0, real(y) > 0)
+sage: f = x^(1/n)*y^(1/n)-(x*y)^(1/n)
+sage: print f
+                                       0
+sage: forget()
+
+sage: # (??) Transform equations, (x==2)/2+(1==1)=>x/2+1==2.
+sage: # This doesn't make any sense, in my opinion.  Adding equations
+
+sage: # (SOMEWHAT) Solve Exp(x)=1 and get all solutions.
+sage: solve(exp(x) == 1)
+[x == 0]
+
+sage: # (SOMEWHAT) Solve Tan(x)=1 and get all solutions.
+sage: solve(tan(x) == 1)
+[x == (pi/4)]
+
+sage: # (YES) Solve a degenerate 3x3 linear system.
+sage: # x+y+z==6,2*x+y+2*z==10,x+3*y+z==10
+sage: # First symbolically:
+sage: solve([x+y+z==6, 2*x+y+2*z==10, x+3*y+z==10], x,y,z)   
+[[x == (4 - r1), y == 2, z == r1]]
+
+sage: # (YES) Invert a 2x2 symbolic matrix.
+sage: # [[a,b],[1,a*b]]
+sage: # Using multivariate poly ring -- much nicer
+sage: R.<a,b> = QQ[]
+sage: m = matrix(2,2,[a,b,  1, a*b])
+sage: zz = m^(-1)
+sage: print zz
+[       a/(-1 + a^2)     (-1)/(-1 + a^2)]
+[(-1)/(-1*b + a^2*b)    a/(-1*b + a^2*b)]
+
+sage: # (YES) Compute and factor the determinant of the 4x4 Vandermonde matrix in a, b, c, d.
+sage: restore('a,b,c,d')
+sage: m = matrix(SR, 4, 4, [[z^i for i in range(4)] for z in [a,b,c,d]])
+sage: print m
+    [  1   a a^2 a^3]
+    [  1   b b^2 b^3]
+    [  1   c c^2 c^3]
+    [  1   d d^2 d^3]
+sage: d = m.determinant()
+sage: print d.factor()
+                (b - a) (c - a) (c - b) (d - a) (d - b) (d - c)
+                
+sage: # (YES) Compute and factor the determinant of the 4x4 Vandermonde matrix in a, b, c, d.
+sage: # Do it instead in a multivariate ring
+sage: R.<a,b,c,d> = QQ[]
+sage: m = matrix(R, 4, 4, [[z^i for i in range(4)] for z in [a,b,c,d]])
+sage: print m
+[  1   a a^2 a^3]
+[  1   b b^2 b^3]
+[  1   c c^2 c^3]
+[  1   d d^2 d^3]
+sage: d = m.determinant()
+sage: print d
+b*c^2*d^3 - b*c^3*d^2 - b^2*c*d^3 + b^2*c^3*d + b^3*c*d^2 - b^3*c^2*d - a*c^2*d^3 + a*c^3*d^2 + a*b^2*d^3 - a*b^2*c^3 - a*b^3*d^2 + a*b^3*c^2 + a^2*c*d^3 - a^2*c^3*d - a^2*b*d^3 + a^2*b*c^3 + a^2*b^3*d - a^2*b^3*c - a^3*c*d^2 + a^3*c^2*d + a^3*b*d^2 - a^3*b*c^2 - a^3*b^2*d + a^3*b^2*c
+sage: print d.factor()
+(-1) * (-1*d + c) * (-1*d + b) * (-1*c + b) * (b - a) * (-1*d + a) * (-1*c + a)
+
+sage: # Find the eigenvalues of a 3x3 integer matrix.
+sage: m = matrix(QQ, 3, [5,-3,-7, -2,1,2, 2,-3,-4])
+sage: m.eigenspaces()
+[
+(3, [
+(1, 0, -1)
+]),
+(1, [
+(1, 1, -1)
+]),
+(-2, [
+(0, 1, 1)
+])
+]
+
+sage: # OK Verify some standard limits found by L'Hopital's rule:
+sage: #   Verify(Limit(x,Infinity) (1+1/x)^x, Exp(1));
+sage: #   Verify(Limit(x,0) (1-Cos(x))/x^2, 1/2);
+sage: print limit( (1+1/x)^x, x = oo)
+e
+sage: print limit( (1-cos(x))/(x^2), x = 1/2)
+                                           1
+                                 4 - 4 cos(-)
+                                           2
+
+sage: # (OK-ish) D(x)Abs(x)
+sage: #    Verify(D(x) Abs(x), Sign(x));
+sage: diff(abs(x))
+x/abs(x)
+
+sage: # (NO) (Integrate(x)Abs(x))=Abs(x)*x/2
+sage: integral(abs(x), x)
+integrate(abs(x), x)
+
+sage: #  (YES) Compute derivative of Abs(x), piecewise defined.
+sage: #     Verify(D(x)if(x<0) (-x) else x,
+sage: #        Simplify(if(x<0) -1 else 1))
+Piecewise defined function with 2 parts, [[(-10, 0), -1], [(0, 10), 1]]
+sage: #  (NOT really) Integrate Abs(x), piecewise defined.
+sage: #      Verify(Simplify(Integrate(x)
+sage: #        if(x<0) (-x) else x),
+sage: #        Simplify(if(x<0) (-x^2/2) else x^2/2));
+sage: f = piecewise([ [[-10,0], -x], [[0,10], x]])
+sage: f.integral()
+100
+
+sage: # (YES) Taylor series of 1/Sqrt(1-v^2/c^2) at v=0.
+sage: restore('v,c')
+sage: taylor(1/sqrt(1-v^2/c^2), v, 0, 7)
+1 + v^2/(2*c^2) + 3*v^4/(8*c^4) + 5*v^6/(16*c^6)
+
+sage: # (OK-ish) (Taylor expansion of Sin(x))/(Taylor expansion of Cos(x)) = (Taylor expansion of Tan(x)).
+sage: #      TestYacas(Taylor(x,0,5)(Taylor(x,0,5)Sin(x))/
+sage: #        (Taylor(x,0,5)Cos(x)), Taylor(x,0,5)Tan(x));
+sage: f = taylor(sin(x), x, 0, 8)
+sage: g = taylor(cos(x), x, 0, 8)
+sage: h = taylor(tan(x), x, 0, 8)
+sage: f = f.power_series(QQ)
+sage: g = g.power_series(QQ)
+sage: h = h.power_series(QQ)
+sage: f - g*h
+O(x^8)
+
+sage: # (YES) Taylor expansion of Ln(x)^a*Exp(-b*x) at x=1.
+sage: taylor(log(x)^a * exp(-b*x), x, 1, 3)
+(x - 1)^a/e^b - (((x - 1)^a*a + 2*b*(x - 1)^a)*(x - 1)/(2*e^b)) + (3*(x - 1)^a*a^2 + (12*b + 5)*(x - 1)^a*a + 12*b^2*(x - 1)^a)*(x - 1)^2/(24*e^b) - (((x - 1)^a*a^3 + (6*b + 5)*(x - 1)^a*a^2 + (12*b^2 + 10*b + 6)*(x - 1)^a*a + 8*b^3*(x - 1)^a)*(x - 1)^3/(48*e^b))
+
+sage: # (YES) Taylor expansion of Ln(Sin(x)/x) at x=0.
+sage: taylor(log(sin(x)/x), x, 0, 10)
+-x^2/6 - (x^4/180) - (x^6/2835) - (x^8/37800) - (x^10/467775)
+
+sage: # (NO) Compute n-th term of the Taylor series of Ln(Sin(x)/x) at x=0.
+sage: # need formal functions
+
+sage: # (NO) Compute n-th term of the Taylor series of Exp(-x)*Sin(x) at x=0.
+sage: # (Sort of, with some work)
+sage: # Solve x=Sin(y)+Cos(y) for y as Taylor series in x at x=1.
+sage: #      TestYacas(InverseTaylor(y,0,4) Sin(y)+Cos(y),
+sage: #        (y-1)+(y-1)^2/2+2*(y-1)^3/3+(y-1)^4);
+sage: #       Note that InverseTaylor does not give the series in terms of x but in terms of y which is semantically 
+sage: # wrong. But other CAS do the same.
+sage: f = sin(y) + cos(y)
+sage: g = f.taylor(y, 0, 10)
+sage: h = g.power_series(QQ)
+sage: k = (h - 1).reversion()
+sage: print k
+y + 1/2*y^2 + 2/3*y^3 + y^4 + 17/10*y^5 + 37/12*y^6 + 41/7*y^7 + 23/2*y^8 + 1667/72*y^9 + 3803/80*y^10 + O(y^11)
+
+sage: # [OK] Compute Legendre polynomials directly from Rodrigues's formula, P[n]=1/(2^n*n!) *(Deriv(x,n)(x^2-1)^n).
+sage: #      P(n,x) := Simplify( 1/(2*n)!! *
+sage: #        Deriv(x,n) (x^2-1)^n );
+sage: #      TestYacas(P(4,x), (35*x^4)/8+(-15*x^2)/4+3/8);
+sage: def P(n,x):
+...    return   simplify(diff((x^2-1)^n,x,n) / (2^n * factorial(n)))
+...
+sage: print P(4,x).expand()
+                                   4	   2
+                               35 x    15 x    3
+                               ----- - ----- + -
+                                 8	 4     8
+
+sage: # (YES) Define the polynomial p=Sum(i,1,5,a[i]*x^i).
+sage: # symbolically
+sage: ps = sum(var('a%s'%i)*x^i for i in range(1,6))
+sage: print 'symbolic\n',ps
+symbolic
+                         5	 4	 3	 2
+                     a5 x  + a4 x  + a3 x  + a2 x  + a1 x
+sage: # algebraically
+sage: R = PolynomialRing(QQ,5,names='a')
+sage: S.<x> = PolynomialRing(R)
+sage: p = S(list(R.gens()))*x
+sage: print 'algebraic\n',p
+algebraic
+a4*x^5 + a3*x^4 + a2*x^3 + a1*x^2 + a0*x
+
+sage: # (YES) Convert the above to Horner's form.
+sage: #      Verify(Horner(p, x), ((((a[5]*x+a[4])*x
+sage: #        +a[3])*x+a[2])*x+a[1])*x);
+sage: # We use the trick of evaluating the algebraic poly at a symbolic variable:
+sage: restore('x')
+sage: p(x)
+x*(x*(x*(x*(a4*x + a3) + a2) + a1) + a0)
+
+sage: # (NO) Convert the result of problem 127 to Fortran syntax.
+sage: #      CForm(Horner(p, x));
+
+sage: # (YES) Verify that True And False=False.
+sage: (True and False) == False
+True
+
+sage: # (YES) Prove x Or Not x.
+sage: for x in [True, False]:
+...    print x or (not x)
+True
+True
+
+sage: # (YES) Prove x Or y Or x And y=>x Or y.
+sage: for x in [True, False]:
+...   for y in [True, False]:
+...       if x or y or x and y:
+...           if not (x or y):
+...              print "failed!"
+"""    
Index: sage/catalogue/catalogue.py
===================================================================
--- sage/catalogue/catalogue.py	(revision 2320)
+++ sage/catalogue/catalogue.py	(revision 3983)
@@ -120,7 +120,6 @@
 elementary = Elementary()
 function.elementary = elementary
-import sage.functions.all
-elementary.sin = sage.functions.all.sin
-elementary.cos = sage.functions.all.cos
-    
-    
+import sage.calculus.all
+elementary.sin = sage.calculus.all.sin
+elementary.cos = sage.calculus.all.cos
+elementary.log = sage.calculus.all.log
Index: sage/coding/all.py
===================================================================
--- sage/coding/all.py	(revision 2132)
+++ sage/coding/all.py	(revision 3972)
@@ -24,3 +24,19 @@
 from ag_code import ag_code
 
-from code_bounds import *
+from code_bounds import (codesize_upper_bound,
+                         dimension_upper_bound,
+                         volume_hamming,
+                         gilbert_lower_bound,
+                         plotkin_upper_bound,
+                         griesmer_upper_bound,
+                         elias_upper_bound,
+                         hamming_upper_bound,
+                         singleton_upper_bound,
+                         gv_info_rate,
+                         entropy,
+                         gv_bound_asymp,
+                         hamming_bound_asymp,
+                         singleton_bound_asymp,
+                         plotkin_bound_asymp,
+                         elias_bound_asymp,
+                         mrrw1_bound_asymp)
Index: sage/coding/code_bounds.py
===================================================================
--- sage/coding/code_bounds.py	(revision 3290)
+++ sage/coding/code_bounds.py	(revision 4062)
@@ -136,5 +136,5 @@
 
 from sage.interfaces.all import gap
-from sage.rings.all import QQ, RR, ZZ
+from sage.rings.all import QQ, RR, ZZ, RDF
 from sage.rings.arith import factorial
 from sage.misc.functional import log, sqrt
@@ -373,8 +373,8 @@
     EXAMPLES:
         sage: elias_bound_asymp(1/4,2)
-        0.399123963307144
+        0.399123963308
     """
     r = 1-1/q
-    return (1-entropy(r-sqrt(r*(r-delta)), q))
+    return RDF((1-entropy(r-sqrt(r*(r-delta)), q)))
 
 def mrrw1_bound_asymp(delta,q):
@@ -385,11 +385,11 @@
     EXAMPLES:
         sage: mrrw1_bound_asymp(1/4,2)
-        0.354578902665270
-
-    """
-    return entropy((q-1-delta*(q-2)-2*sqrt((q-1)*delta*(1-delta)))/q,q)
-
-
-
-
-
+        0.354578902665
+
+    """
+    return RDF(entropy((q-1-delta*(q-2)-2*sqrt((q-1)*delta*(1-delta)))/q,q))
+
+
+
+
+
Index: sage/coding/linear_code.py
===================================================================
--- sage/coding/linear_code.py	(revision 2779)
+++ sage/coding/linear_code.py	(revision 4063)
@@ -142,4 +142,11 @@
 added LinearCode_from_vectorspace, extended_code, zeta_function
     -- Nick Alexander (2006-12-10): factor GUAVA code to guava.py
+
+TESTS:
+   sage: MS = MatrixSpace(GF(2),4,7)
+   sage: G  = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
+   sage: C  = LinearCode(G)
+   sage: C == loads(dumps(C))
+   True
 """
 
@@ -627,5 +634,7 @@
 
     def __cmp__(self, right):
-        raise NotImplementedError
+        if not isinstance(right, LinearCode):
+            return cmp(type(self), type(right))
+        return cmp(self.__gen_mat, right.__gen_mat)
 
     def decode(self, right):
@@ -776,5 +785,4 @@
  
         EXAMPLES:
- 
         """
         slength = self.length()
@@ -785,9 +793,9 @@
         rF = right.base_ring()
         if slength != rlength:
-            return 0
+            return False
         if sdim != rdim:
-            return 0
+            return False
         if sF != rF:
-            return 0
+            return False
         V = VectorSpace(sF,sdim)
         sbasis = self.gens()
@@ -796,10 +804,10 @@
         rcheck = right.check_mat()
         for c in sbasis:
-            if rcheck*c != V(0):
-                return 0
+            if rcheck*c:
+                return False
         for c in rbasis:
-            if scheck*c != V(0):
-                return 0
-        return 1
+            if scheck*c:
+                return False
+        return True
 
     def is_permutation_automorphism(self,g):
Index: sage/combinat/combinat.py
===================================================================
--- sage/combinat/combinat.py	(revision 2664)
+++ sage/combinat/combinat.py	(revision 4022)
@@ -16,101 +16,108 @@
 \item Bell numbers, \code{bell_number}
 
-\item Bernoulli numbers, \code{bernoulli_number} (though PARI's bernoulli is 
-  better)
-
-\item Catalan numbers, \code{catalan_number} (not to be confused with the
-  Catalan constant)
+\item Bernoulli numbers, \code{bernoulli_number} (though PARI's
+  bernoulli is better)
+
+\item Catalan numbers, \code{catalan_number} (not to be confused with
+  the Catalan constant)
 
 \item Eulerian/Euler numbers, \code{euler_number} (Maxima)
 
-\item Fibonacci numbers, \code{fibonacci} (PARI) and \code{fibonacci_number} (GAP)
-  The PARI version is better.
+\item Fibonacci numbers, \code{fibonacci} (PARI) and
+  \code{fibonacci_number} (GAP) The PARI version is better.
 
 \item Lucas numbers, \code{lucas_number1}, \code{lucas_number2}.
  
-\item Stirling numbers, \code{stirling_number1}, \code{stirling_number2}.
+\item Stirling numbers, \code{stirling_number1},
+\code{stirling_number2}.
+
 \end{itemize}
  
 Set-theoretic constructions:
 \begin{itemize}
-\item Combinations of a multiset, \code{combinations}, \code{combinations_iterator},
-and \code{number_of_combinations}. These are unordered selections without
-repetition of k objects from a multiset S.
-
-\item Arrangements of a multiset, \code{arrangements} and \code{number_of_arrangements}
-  These are ordered selections without repetition of k objects from a 
-  multiset S.
-
-\item Derangements of a multiset, \code{derangements} and \code{number_of_derangements}.
+
+\item Combinations of a multiset, \code{combinations},
+\code{combinations_iterator}, and \code{number_of_combinations}. These
+are unordered selections without repetition of k objects from a
+multiset S.
+
+\item Arrangements of a multiset, \code{arrangements} and
+  \code{number_of_arrangements} These are ordered selections without
+  repetition of k objects from a multiset S.
+
+\item Derangements of a multiset, \code{derangements} and
+\code{number_of_derangements}.
 
 \item Tuples of a multiset, \code{tuples} and \code{number_of_tuples}.
-  An ordered tuple of length k of set S is a ordered selection with 
-  repetitions of S and is represented by a sorted list of length k 
-  containing elements from S. 
-
-\item Unordered tuples of a set, \code{unordered_tuple} and \code{number_of_unordered_tuples}.
-  An unordered tuple of length k of set S is a unordered selection with 
-  repetitions of S and is represented by a sorted list of length k 
-  containing elements from S. 
-
-\item Permutations of a multiset, \code{permutations}, \code{permutations_iterator},
-\code{number_of_permutations}. A permutation is a list that contains exactly the same elements but 
+  An ordered tuple of length k of set S is a ordered selection with
+  repetitions of S and is represented by a sorted list of length k
+  containing elements from S.
+
+\item Unordered tuples of a set, \code{unordered_tuple} and
+  \code{number_of_unordered_tuples}.  An unordered tuple of length k
+  of set S is a unordered selection with repetitions of S and is
+  represented by a sorted list of length k containing elements from S.
+
+\item Permutations of a multiset, \code{permutations},
+\code{permutations_iterator}, \code{number_of_permutations}. A
+permutation is a list that contains exactly the same elements but
 possibly in different order.
+
 \end{itemize}
 
 Partitions:
 \begin{itemize}
-\item Partitions of a set, \code{partitions_set}, \code{number_of_partitions_set}.
-  An unordered partition of set S is a set of pairwise disjoint 
-  nonempty sets with union S and is represented by a sorted list of 
-  such sets. 
-
-\item Partitions of an integer, \code{partitions_list}, \code{number_of_partitions_list}.
-  An unordered partition of n is an unordered sum 
-  $n = p_1+p_2 +\ldots+ p_k$ of positive integers and is represented by 
-  the list $p = [p_1,p_2,\ldots,p_k]$, in nonincreasing order, i.e., 
-  $p1\geq p_2 ...\geq p_k$. 
-
-\item Ordered partitions of an integer, \code{ordered_partitions}, 
-  \code{number_of_ordered_partitions}.
-  An ordered partition of n is an ordered sum $n = p_1+p_2 +\ldots+ p_k$ 
-  of positive integers and is represented by 
-  the list $p = [p_1,p_2,\ldots,p_k]$, in nonincreasing order, i.e., 
-  $p1\geq p_2 ...\geq p_k$. 
-
-\item Restricted partitions of an integer, \code{partitions_restricted}, 
-  \code{number_of_partitions_restricted}.
-  An unordered restricted partition of n is an unordered sum 
-  $n = p_1+p_2 +\ldots+ p_k$ of positive integers $p_i$ belonging to a
-  given set $S$, and is represented by the list $p = [p_1,p_2,\ldots,p_k]$, 
-  in nonincreasing order, i.e., $p1\geq p_2 ...\geq p_k$. 
-
-\item \code{partitions_greatest}
-   implements a special type of restricted partition.
-
-\item \code{partitions_greatest_eq} is another type of restricted partition.
+
+\item Partitions of a set, \code{partitions_set},
+  \code{number_of_partitions_set}.  An unordered partition of set S is
+  a set of pairwise disjoint nonempty sets with union S and is
+  represented by a sorted list of such sets.
+
+\item Partitions of an integer, \code{partitions_list},
+  \code{number_of_partitions_list}.  An unordered partition of n is an
+  unordered sum $n = p_1+p_2 +\ldots+ p_k$ of positive integers and is
+  represented by the list $p = [p_1,p_2,\ldots,p_k]$, in nonincreasing
+  order, i.e., $p1\geq p_2 ...\geq p_k$.
+
+\item Ordered partitions of an integer, \code{ordered_partitions},
+  \code{number_of_ordered_partitions}.  An ordered partition of n is
+  an ordered sum $n = p_1+p_2 +\ldots+ p_k$ of positive integers and
+  is represented by the list $p = [p_1,p_2,\ldots,p_k]$, in
+  nonincreasing order, i.e., $p1\geq p_2 ...\geq p_k$.
+
+\item Restricted partitions of an integer,
+  \code{partitions_restricted},
+  \code{number_of_partitions_restricted}.  An unordered restricted
+  partition of n is an unordered sum $n = p_1+p_2 +\ldots+ p_k$ of
+  positive integers $p_i$ belonging to a given set $S$, and is
+  represented by the list $p = [p_1,p_2,\ldots,p_k]$, in nonincreasing
+  order, i.e., $p1\geq p_2 ...\geq p_k$.
+
+\item \code{partitions_greatest} implements a special type of
+   restricted partition.
+
+\item \code{partitions_greatest_eq} is another type of restricted
+partition.
 
 \item Tuples of partitions, \code{partition_tuples},
-  \code{number_of_partition_tuples}.
-  A $k$-tuple of partitions is represented by a list of all $k$-tuples 
-  of partitions which together form a partition of $n$. 
-
-\item Powers of a partition, \code{partition_power(pi, k)}.
-  The power of a partition corresponds to the $k$-th power of a 
-  permutation with cycle structure $\pi$.
-
-\item Sign of a partition, \code{partition_sign( pi ) }
-  This means the sign of a permutation with cycle structure given by the 
-  partition pi.
-
-\item Associated partition, \code{partition_associated( pi )}
-  The ``associated'' (also called ``conjugate'' in the literature) 
-  partition of the partition pi which is obtained by transposing the 
+  \code{number_of_partition_tuples}.  A $k$-tuple of partitions is
+  represented by a list of all $k$-tuples of partitions which together
+  form a partition of $n$.
+
+\item Powers of a partition, \code{partition_power(pi, k)}.  The power
+  of a partition corresponds to the $k$-th power of a permutation with
+  cycle structure $\pi$.
+
+\item Sign of a partition, \code{partition_sign( pi ) } This means the
+  sign of a permutation with cycle structure given by the partition
+  pi.
+
+\item Associated partition, \code{partition_associated( pi )} The
+  ``associated'' (also called ``conjugate'' in the literature)
+  partition of the partition pi which is obtained by transposing the
   corresponding Ferrers diagram.
 
-\item Ferrers diagram, \code{ferrers_diagram}.
-  Analogous to the Young diagram of an irredicible representation 
-  of $S_n$.
-  \end{itemize}
+\item Ferrers diagram, \code{ferrers_diagram}.  Analogous to the Young
+  diagram of an irredicible representation of $S_n$.  \end{itemize}
 
 Related functions:
@@ -259,5 +266,5 @@
         [1, 1, 2, 5, 14, 42, 132]
         sage: maxima.eval("-(1/2)*taylor (sqrt (1-4*x^2), x, 0, 15)")
-        '-1/2 + x^2 + x^4 + 2*x^6 + 5*x^8 + 14*x^10 + 42*x^12 + 132*x^14'
+        '-1/2+x^2+x^4+2*x^6+5*x^8+14*x^10+42*x^12+132*x^14'
         sage: [catalan_number(i) for i in range(-7,7) if i != -1]
         [0, 0, 0, 0, 0, 0, 1, 1, 2, 5, 14, 42, 132]
@@ -287,5 +294,5 @@
         [1, 0, -1, 0, 5, 0, -61, 0, 1385, 0]
         sage: maxima.eval("taylor (2/(exp(x)+exp(-x)), x, 0, 10)")
-        '1 - x^2/2 + 5*x^4/24 - 61*x^6/720 + 277*x^8/8064 - 50521*x^10/3628800'
+        '1-x^2/2+5*x^4/24-61*x^6/720+277*x^8/8064-50521*x^10/3628800'
         sage: [euler_number(i)/factorial(i) for i in range(11)]
         [1, 0, -1/2, 0, 5/24, 0, -61/720, 0, 277/8064, 0, -50521/3628800]
Index: sage/combinat/sloane_functions.py
===================================================================
--- sage/combinat/sloane_functions.py	(revision 3537)
+++ sage/combinat/sloane_functions.py	(revision 4064)
@@ -35,4 +35,9 @@
     sage: a
     The integer sequence tau(n), which is the number of divisors of n.
+
+TESTS:
+    sage: a = sloane.A000001;
+    sage: a == loads(dumps(a))
+    True
 
 AUTHORS:
@@ -94,4 +99,5 @@
 from sage.misc.misc import srange
 from sage.rings.integer_ring import ZZ
+import sage.calculus.all as calculus
 Integer = ZZ
 
@@ -111,4 +117,9 @@
     def _repr_(self):
         raise NotImplementedError
+
+    def __cmp__(self, other):
+        if not isinstance(other, SloaneSequence):
+            return cmp(type(self), type(other))
+        return cmp(repr(self), repr(other))
 
     def __call__(self, n):
@@ -3386,5 +3397,5 @@
 
     def _eval(self, n):
-        return arith.binomial(n,arith.floor(n//2))
+        return arith.binomial(n, int(calculus.floor(n//2)))
 
 class A000292(SloaneSequence):
Index: sage/crypto/all.py
===================================================================
--- sage/crypto/all.py	(revision 2699)
+++ sage/crypto/all.py	(revision 4359)
@@ -11,4 +11,2 @@
                   lfsr_connection_polynomial)
 
-from rsa import rsa_encrypt, rsa_decrypt
-
Index: sage/crypto/cipher.py
===================================================================
--- sage/crypto/cipher.py	(revision 2447)
+++ sage/crypto/cipher.py	(revision 4359)
@@ -1,2 +1,6 @@
+"""
+Ciphers.
+"""
+
 #*****************************************************************************
 #       Copyright (C) 2007 David Kohel <kohel@maths.usyd.edu.au>
@@ -28,4 +32,7 @@
 	self._key = key
 	
+    def __eq__(self, right):
+        return type(self) == type(right) and self._parent == right._parent and self._key == right._key
+
     def __repr__(self):
 	return str(self._key)
Index: sage/crypto/classical.py
===================================================================
--- sage/crypto/classical.py	(revision 2784)
+++ sage/crypto/classical.py	(revision 4359)
@@ -1,2 +1,6 @@
+"""
+Classical Cryptosystems
+"""
+
 #*****************************************************************************
 #       Copyright (C) 2007 David Kohel <kohel@maths.usyd.edu.au>
@@ -44,4 +48,11 @@
             sage: e(m)
             GSVXZGRMGSVSZG
+
+        TESTS:
+            sage: M = AlphabeticStrings()
+            sage: E = SubstitutionCryptosystem(M)
+            sage: E == loads(dumps(E))
+            True
+
         """
         if not isinstance(S, StringMonoid_class):
@@ -141,4 +152,11 @@
             sage: e(S("THECATINTHEHAT"))
             TAHEHTNITACEHT
+
+        EXAMPLES:
+            sage: S = AlphabeticStrings()
+            sage: E = TranspositionCryptosystem(S,14)
+            sage: E == loads(dumps(E))
+            True
+
         """
         if not isinstance(S, StringMonoid_class):
@@ -235,4 +253,11 @@
             sage: e(S("THECATINTHEHAT"))
             TIGFEYOUBQOSMG
+
+        TESTS:
+            sage: S = AlphabeticStrings()
+            sage: E = VigenereCryptosystem(S,14)
+            sage: E == loads(dumps(E))
+            True
+            
         """
         if not isinstance(S, StringMonoid_class):
Index: sage/crypto/classical_cipher.py
===================================================================
--- sage/crypto/classical_cipher.py	(revision 2688)
+++ sage/crypto/classical_cipher.py	(revision 4359)
@@ -1,2 +1,6 @@
+"""
+Classical Ciphers.
+"""
+
 #*****************************************************************************
 #       Copyright (C) 2007 David Kohel <kohel@maths.usyd.edu.au>
@@ -32,6 +36,15 @@
 	    sage: e(m)
 	    GSVXZGRMGSVSZG
+
+        TESTS:
+            sage: S = AlphabeticStrings()
+            sage: E = SubstitutionCryptosystem(S)
+            sage: E == loads(dumps(E))
+            True
         """
 	SymmetricKeyCipher.__init__(self, parent, key)
+
+    def __eq__(self, right):
+        return type(self) == type(right) and self.parent() == right.parent() and self.key() == right.key()
 
     def __call__(self, M):
@@ -84,4 +97,12 @@
 	    sage: e(m)
 	    EHTTACDNAEHTTAH
+
+
+        TESTS:
+            sage: S = AlphabeticStrings()
+            sage: E = TranspositionCryptosystem(S,14)
+            sage: E == loads(dumps(E))
+            True
+
         """
 	n = parent.block_length()
@@ -131,4 +152,11 @@
             sage: e(m)
             LOEMELXRTYIZHT
+
+        TESTS:
+            sage: S = AlphabeticStrings()
+            sage: E = VigenereCryptosystem(S,11)
+            sage: E == loads(dumps(E))
+            True
+
         """
 	SymmetricKeyCipher.__init__(self, parent, key)
Index: sage/crypto/cryptosystem.py
===================================================================
--- sage/crypto/cryptosystem.py	(revision 2688)
+++ sage/crypto/cryptosystem.py	(revision 4359)
@@ -1,2 +1,6 @@
+"""
+Cryptosystems.
+"""
+
 #*****************************************************************************
 #       Copyright (C) 2007 David Kohel <kohel@maths.usyd.edu.au>
@@ -10,5 +14,5 @@
 
 class Cryptosystem(Set_generic):
-      """
+      r"""
       A cryptosystem is a pair of maps 
       $$
@@ -42,4 +46,13 @@
 	  self._block_length = block_length
 	  self._period = period
+
+      def __eq__(self,right):
+            return type(self) == type(right) and  \
+                   self._cipher_domain == right._cipher_domain and \
+                   self._cipher_codomain == right._cipher_codomain and \
+                   self._key_space ==  right._key_space and \
+                   self._block_length == right._block_length and \
+                   self._period == right._period
+
       
       def plaintext_space(self):
Index: sage/crypto/lfsr.py
===================================================================
--- sage/crypto/lfsr.py	(revision 1097)
+++ sage/crypto/lfsr.py	(revision 4359)
@@ -1,5 +1,4 @@
-"""
-Linear feedback shift register (LFSR) sequence commands
-
+r"""
+Linear feedback shift register (LFSR) sequence commands.
 
 Stream ciphers have been used for 
Index: age/crypto/rsa.py
===================================================================
--- sage/crypto/rsa.py	(revision 2055)
+++ 	(revision )
@@ -1,63 +1,0 @@
-"""
-Basic RSA commands
-
-Created 11-24-2005 by wdj. Last updated 12-02-2005.
-"""
-
-###########################################################################
-#  Copyright (C) 2006 David Joyner <wdj@usna.edu> and William Stein <wstein@gmail.com>
-#
-#  Distributed under the terms of the GNU General Public License (GPL)
-#
-#                  http://www.gnu.org/licenses/
-###########################################################################
-
-def rsa_encrypt(m, N, e):
-    """
-    INPUT:
-        N -- typically a product of distinct primes.
-        e -- element of Z/phiN Z.
-        m -- integer relatively prime to e.
-    
-    OUTPUT:
-        RSA encryption $m^e \pmod N$.
-
-    EXAMPLES:
-        sage: p = 53
-        sage: q = 61
-        sage: N = p*q
-        sage: phiN = euler_phi(N)
-        sage: R = IntegerModRing(int(phiN))
-        sage: e = R(17)
-        sage: rsa_encrypt(123,N,e)
-        855
-
-    AUTHOR: David Joyner (11-2005)
-    """
-    return (m**e)%N
-
-def rsa_decrypt(c,N,e):
-    """
-    Inverse function to rsa_encrypt.
-
-    INPUT:
-        N -- typically a product of distinct primes.
-        e -- in Z/phiN Z.
-        c -- an integer relatively prime to e.
-
-    EXAMPLES:
-        sage: p = 53
-        sage: q = 61
-        sage: N = p*q
-        sage: phiN = euler_phi(N)
-        sage: R = IntegerModRing(int(phiN))
-        sage: e = R(17)
-        sage: rsa_decrypt(855,N,e)
-        123
-
-    AUTHOR:
-        -- David Joyner (11-2005)
-    """
-    d = 1/e;
-    return (c**d)%N
-
Index: sage/crypto/stream.py
===================================================================
--- sage/crypto/stream.py	(revision 2771)
+++ sage/crypto/stream.py	(revision 4359)
@@ -1,2 +1,6 @@
+"""
+Stream Cryptosystems.
+"""
+
 #*****************************************************************************
 #       Copyright (C) 2007 David Kohel <kohel@maths.usyd.edu.au>
@@ -33,4 +37,10 @@
             LFSR cryptosystem over Finite Field of size 2
 
+        TESTS:
+            sage: E = LFSRCryptosystem(FiniteField(2))
+	    sage: E == loads(dumps(E))
+            True
+
+
 	TODO: Implement LFSR cryptosytem for arbitrary rings. The current 
 	implementation if limitated to the finite field of 2 elements only 
@@ -45,4 +55,7 @@
         SymmetricKeyCryptosystem.__init__(self, S, S, None)
 	self._field = field
+
+    def __eq__(self,right):
+        return type(self) == type(right) and self._field == right._field
 
     def __call__(self, key):
Index: sage/crypto/stream_cipher.py
===================================================================
--- sage/crypto/stream_cipher.py	(revision 2710)
+++ sage/crypto/stream_cipher.py	(revision 4359)
@@ -44,4 +44,12 @@
             sage: m == e(e(m))
             True            
+
+        TESTS:
+            sage: FF = FiniteField(2)
+            sage: P.<x> = PolynomialRing(FF)
+            sage: E = LFSRCryptosystem(FF)
+            sage: E == loads(dumps(E))
+            True
+
         """
         SymmetricKeyCipher.__init__(self, parent, key = (poly, IS))
@@ -113,5 +121,5 @@
 
     def __call__(self, M, mode = "ECB"):
-        """
+        r"""
         EXAMPLES:
             sage: FF = FiniteField(2)   
Index: sage/databases/conway.py
===================================================================
--- sage/databases/conway.py	(revision 3702)
+++ sage/databases/conway.py	(revision 4182)
@@ -66,5 +66,5 @@
 import sage.misc.misc
 import sage.databases.db   # very important that this be fully qualified
-_CONWAYDATA = "%s/data/src/conway/conway_table.py.bz2"%sage.misc.misc.SAGE_ROOT
+_CONWAYDATA = "%s/conway_polynomials/"%sage.databases.db.DB_HOME
 
 
@@ -84,7 +84,8 @@
     def _init(self):
         if not os.path.exists(_CONWAYDATA):
-            raise RuntimeError, "In order to initialize the database, the file %s must exist."%_CONWAYDATA
-        os.system("cp %s ."%_CONWAYDATA)
-        os.system("bunzip2 conway_table.py.bz2")
+            raise RuntimeError, "In order to initialize the database, the directory must exist."%_CONWAYDATA
+        os.chdir(_CONWAYDATA)
+        if os.system("bunzip2 -k conway_table.py.bz2"):
+            raise RuntimeError, "error decompressing table"
         from conway_table import conway_polynomials
         for X in conway_polynomials:
@@ -94,5 +95,6 @@
             self[p][n] = v
             self[p] = self[p]  # so database knows it was changed
-        os.system("bzip2 conway_table.py; rm conway_table.pyc; cp conway_table.py %s"%_CONWAYDATA)
+        os.unlink("conway_table.pyc")
+        os.unlink("conway_table.py")
         self.commit()
 
Index: sage/databases/cremona.py
===================================================================
--- sage/databases/cremona.py	(revision 1097)
+++ sage/databases/cremona.py	(revision 4053)
@@ -256,4 +256,5 @@
         sage: c.allcurves(11)
         {'a1': [[0, -1, 1, -10, -20], 0, 5], 'a3': [[0, -1, 1, 0, 0], 0, 5], 'a2': [[0, -1, 1, -7820, -263580], 0, 1]}
+
     """
     def __init__(self, read_only=True):
Index: age/dsage/INSTALL.txt
===================================================================
--- sage/dsage/INSTALL.txt	(revision 2888)
+++ 	(revision )
@@ -1,5 +1,0 @@
-INSTALLATION
-    Currently, installation is deadly simple.  Just untar the archive and 
-    run the programs in there.  No need for install.  
-
-    *WARNING* This will probably change in the future.
Index: sage/dsage/__version__.py
===================================================================
--- sage/dsage/__version__.py	(revision 2951)
+++ sage/dsage/__version__.py	(revision 4248)
@@ -1,4 +1,2 @@
-"""nodoctest
-"""
 ############################################################################
 #                                                                     
@@ -19,3 +17,3 @@
 ############################################################################
 
-version='0.2'
+version='0.4'
Index: sage/dsage/all.py
===================================================================
--- sage/dsage/all.py	(revision 3901)
+++ sage/dsage/all.py	(revision 4339)
@@ -17,10 +17,40 @@
 #
 ##############################################################################
+
+import os
 from sage.dsage.dsage import dsage
 from sage.dsage.dist_functions.all import *
 
-def DSage(server=None, port=None, username=None, pubkey_file=None, privkey_file=None):
-    from sage.dsage.interface.dsage_interface import BlockingDSage
-    return BlockingDSage(server=server, port=port, username=username,
-                         pubkey_file=pubkey_file, privkey_file=privkey_file)
+DSAGE_DIR = os.path.join(os.getenv('DOT_SAGE'), 'dsage')
 
+def DSage(server='localhost', port=8081, username=os.getenv('USER'), 
+          pubkey_file=os.path.join(DSAGE_DIR,'dsage_key.pub'),
+          privkey_file=os.path.join(DSAGE_DIR, 'dsage_key'),
+          log_file = 'stdout',
+          log_level = 0,
+          ssl = True):
+          
+      """
+      This object represents a connection to the distributed SAGE server.
+
+      Parameters:
+      server -- str (Default: 'localhost')
+      port -- int (Default: 8081)
+      username -- str
+      pubkey_file -- str (Default: None)
+      privkey_file -- str (Default: None)
+      log_file -- str (Default: stdout)
+      log_level -- int (Default: 0)
+      ssl -- int (Default: 1)
+
+      """
+      
+      from sage.dsage.interface.dsage_interface import BlockingDSage
+      return BlockingDSage(server=server, port=port, 
+                           username=username,
+                           pubkey_file=pubkey_file, 
+                           privkey_file=privkey_file,
+                           log_file = log_file,
+                           log_level = log_level,
+                           ssl = ssl)
+
Index: sage/dsage/database/clientdb.py
===================================================================
--- sage/dsage/database/clientdb.py	(revision 3866)
+++ sage/dsage/database/clientdb.py	(revision 4353)
@@ -20,8 +20,9 @@
 import datetime
 import os
-import sqlite3 as sqlite
+import sqlite3
 
 from twisted.python import log
 
+from sage.dsage.twisted.pubkeyauth import get_pubkey_string
 import sage.dsage.database.sql_functions as sql_functions
 from sage.dsage.misc.config import get_conf
@@ -56,9 +57,9 @@
         """
         
-        self.conf = get_conf(type='clientdb')
         self.tablename = self.TABLENAME
         if test:
             self.db_file = 'clientdb_test.db'
         else:
+            self.conf = get_conf(type='clientdb')
             self.db_file = self.conf['db_file']
             if not os.path.exists(self.db_file):
@@ -66,8 +67,11 @@
                 if not os.path.isdir(dir):
                     os.mkdir(dir)
-        self.con = sqlite.connect(self.db_file,
-                    detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES)
+        self.con = sqlite3.connect(self.db_file,
+                isolation_level=None,
+                detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
+        # Don't use this slow!
+        # self.con.text_factory = sqlite3.OptimizedUnicode
+        sql_functions.optimize_sqlite(self.con)
         self.con.text_factory = str
-        
         if sql_functions.table_exists(self.con, self.tablename) is None:
             sql_functions.create_table(self.con, 
@@ -86,5 +90,7 @@
         """
         
-        query = """SELECT username, public_key FROM clients WHERE username = ?"""
+        query = """SELECT username, public_key 
+                   FROM clients 
+                   WHERE username = ?"""
         
         cur = self.con.cursor()
@@ -112,4 +118,8 @@
         """
         Adds a user to the database.
+        
+        Parameters:
+        username -- username
+        pubkey -- public key string (must be pre-parsed already)
         
         """
@@ -119,16 +129,7 @@
                    VALUES (?, ?, ?)
                 """
-        
-        try:
-            f = open(pubkey)
-            type_, key = f.readlines()[0].split()[:2]
-            f.close()
-            if not type_ == 'ssh-rsa':
-                raise TypeError
-        except IOError:
-            key = pubkey
-            
-        cur = self.con.cursor()
-        cur.execute(query, (username, key, datetime.datetime.now()))
+                            
+        cur = self.con.cursor()
+        cur.execute(query, (username, pubkey, datetime.datetime.now()))
         self.con.commit()        
     
Index: sage/dsage/database/job.py
===================================================================
--- sage/dsage/database/job.py	(revision 3866)
+++ sage/dsage/database/job.py	(revision 4238)
@@ -70,5 +70,6 @@
         self.jdict['failures'] = 0
         self.jdict['verifiable'] = False # is this job easily verified?
-        
+        self.jdict['timeout'] = 600 # default timeout for jobs in seconds
+        self.jdict['private'] = False 
         # These might become deprecated
         self.jdict['parent'] = parent
@@ -83,5 +84,5 @@
                 self.__dict__[name] = value
             else:
-                raise ValueError, 'Do not reassign Job.jdict.'
+                raise ValueError('Do not reassign Job.jdict.')
         else:
             Persistent.__setattr__(self, name, value)
@@ -197,8 +198,4 @@
         return self.jdict['type']
     def set_type(self, value):
-        types = ['sage', 'spyx', 'py']
-        if value not in types:
-            raise TypeError
-
         self.jdict['type'] = value
     type = property(fget=get_type, fset=set_type,
@@ -236,4 +233,24 @@
             raise TypeError
         self.jdict['verifiable'] = value         
+        
+    def timeout():
+        doc = "Job timeout in seconds. Set to 0 to disable."
+        def fget(self):
+            return self.jdict['timeout']
+        def fset(self, value):
+            if not isinstance(value, int):
+                raise TypeError('Timeout must be an integer.')
+            self.jdict['timeout']  = value
+        return locals()
+    timeout = property(**timeout())
+    
+    def private():
+        doc = "Sets whether a job is private or not."
+        def fget(self):
+            return self.jdict['private']
+        def fset(self, value):
+            self.jdict['private'] = value
+        return locals()
+    private = property(**private())
     
     def attach(self, var, obj, file_name=None):
Index: sage/dsage/database/jobdb.py
===================================================================
--- sage/dsage/database/jobdb.py	(revision 3895)
+++ sage/dsage/database/jobdb.py	(revision 4353)
@@ -42,11 +42,19 @@
     """
     
-    def __init__(self):
-        self.conf = get_conf(type='jobdb')
-        self.db_file = self.conf['db_file']
-        self.job_failure_threshold = int(self.conf['job_failure_threshold'])
-        self.log_file = self.conf['log_file']
-        self.log_level = int(self.conf['log_level'])
-        self.prune_in_days = int(self.conf['prune_in_days'])
+    def __init__(self, test=False):
+        if test:
+            self.db_file = 'dsage_test.db'
+            self.log_file = 'dsage_test.log'
+            self.log_level = 5
+            self.prune_in_days = 10
+            self.job_failure_threshold = 3
+        else:
+            self.conf = get_conf(type='jobdb')
+            self.db_file = self.conf['db_file']
+            self.job_failure_threshold =int(
+                                        self.conf['job_failure_threshold'])
+            self.log_file = self.conf['log_file']
+            self.log_level = int(self.conf['log_level'])
+            self.prune_in_days = int(self.conf['prune_in_days'])
         
     def random_string(self, length=10):
@@ -85,5 +93,5 @@
     
     def __init__(self, test=False, read_only=False):
-        JobDatabase.__init__(self)
+        JobDatabase.__init__(self, test=test)
         if test:
             self.db_file = 'test_db.db'
@@ -359,5 +367,9 @@
     Parameters:
     test -- set to true for unittesting purposes
-
+    
+    AUTHORS:
+    Yi Qiang
+    Alex Clemesha
+    
     """
 
@@ -383,4 +395,6 @@
      finish_time timestamp,
      verifiable BOOL,
+     private BOOL DEFAULT 0,
+     timeout INTEGER DEFAULT 600, 
      killed BOOL DEFAULT 0 
     );
@@ -388,5 +402,5 @@
     
     def __init__(self, test=False):
-        JobDatabase.__init__(self)
+        JobDatabase.__init__(self, test=test)
         if test:
             self.db_file = 'test_jobdb.db'
@@ -399,49 +413,15 @@
         self.tablename = 'jobs'
         self.con = sqlite3.connect(
-                   self.db_file,
-                   detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
-        self.con.text_factory = str # Don't want unicode objects 
+                  self.db_file,
+                  isolation_level=None,
+                  detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
+        sql_functions.optimize_sqlite(self.con)
+        # Don't use this, slow!
+        # self.con.text_factory = sqlite3.OptimizedUnicode 
+        self.con.text_factory = str
         if not sql_functions.table_exists(self.con, self.tablename):
             sql_functions.create_table(self.con,
                                        self.tablename, 
                                        self.CREATE_JOBS_TABLE)
-                                       
-    def __add_test_data(self):
-        INSERT_JOB = """INSERT INTO jobs 
-        (uid, 
-         username, 
-         code,
-         data, 
-         output, 
-         worker_id,
-         status, 
-         priority, 
-         creation_time, 
-         update_time, 
-         finish_time
-        ) 
-        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
-        """
-
-        dn = lambda: datetime.datetime.now() # short hand
-        D = [(self.random_string(), 1, None, None, None, 1, 
-             'new', 1, dn(), dn(), None),
-             (self.random_string(), 1, None, None, None, 1, 
-             0, 1, dn(), dn(), None),
-             (self.random_string(), 1, None, None, None, 1, 
-             0, 1, dn(), dn(), None)]
-             
-        log.msg('Sleeping for 0.5 second to test timestamps...')
-        time.sleep(0.5)
-        
-        D.extend([(self.random_string(), 1, None, None, None, 1, 
-                   0, 1, dn(), dn(), None),
-                  (self.random_string(), 1, None, None, None, 1, 
-                   0, 1, dn(), dn(), None),
-                  (self.random_string(), 1, None, None, None, 1, 
-                   0, 1, dn(), dn(), None)])
-
-        self.con.executemany(INSERT_JOB, D)
-        self.con.commit()
         
     def _shutdown(self):
@@ -481,9 +461,26 @@
         
     def get_job_by_id(self, job_id):
-        query = "SELECT * FROM jobs WHERE job_id = ?"
-        cur = self.con.cursor()
-        cur.execute(query, (job_id,)) # Need to cast it to int for SAGE
+        """
+        Returns a jdict given a job id.
+        
+        """
+        
+        query = """SELECT 
+                job_id, 
+                status, 
+                output, 
+                result, 
+                killed, 
+                verifiable,
+                monitor_id,
+                failures
+                FROM jobs WHERE job_id = ?"""
+        cur = self.con.cursor()
+        cur.execute(query, (job_id,))
         jtuple = cur.fetchone()
-        return self.create_jdict(jtuple, cur.description)
+        jdict = self.create_jdict(jtuple, cur.description)
+        del jtuple
+        
+        return jdict
     
     def _get_jobs_by_parameter(self, key, value):
@@ -534,19 +531,22 @@
         
         Parameters:
-        job -- a sage.dsage.database.Job object
-        
-        """
-        
-        job_id = jdict['job_id']
-
+        jdict -- sage.dsage.database.Job.jdict 
+        
+        """
+        
+        try:
+            job_id = jdict['job_id']
+        except KeyError, msg:
+            job_id = None
+            
         if job_id is None: 
             job_id = self.random_string()
             if self.log_level > 3:
-                log.msg('[JobDB] Creating a new job with id:', job_id)
+                log.msg('[JobDB] Creating a new job with id: ', job_id)
             query = """INSERT INTO jobs 
                     (job_id, status, creation_time) VALUES (?, ?, ?)"""
             cur = self.con.cursor()
             cur.execute(query, (job_id, 'new', datetime.datetime.now()))
-            self.con.commit()
+            # self.con.commit()
             
         for k, v in jdict.iteritems():
@@ -561,5 +561,5 @@
                 continue    
         
-        return self.get_job_by_id(job_id)
+        return job_id
     
     def create_jdict(self, jtuple, row_description):
@@ -580,7 +580,13 @@
         
         # Convert buffer objects back to string
-        jdict['data'] = str(jdict['data'])
-        jdict['result'] = str(jdict['result'])
-        
+        try:
+            jdict['data'] = str(jdict['data'])
+        except Exception, msg:
+            pass
+        try:
+            jdict['result'] = str(jdict['result'])
+        except Exception, msg:
+            pass
+            
         return jdict
         
@@ -590,8 +596,10 @@
         
         """
+        
         query = "SELECT * from jobs where killed = 1 AND status <> 'completed'"
         cur = self.con.cursor()
         cur.execute(query)
         killed_jobs = cur.fetchall()
+
         return [self.create_jdict(jdict, cur.description) 
                 for jdict in killed_jobs]
@@ -626,7 +634,17 @@
     
     def set_killed(self, job_id, killed=True):
-        self._update_value(job_id, 'killed', killed)
+        """
+        Sets the value of killed for a job.
+        
+        """
+        
+        return self._update_value(job_id, 'killed', killed)
     
     def get_active_jobs(self):
+        """
+        Returns a list of jdicts whose status is 'processing'
+        
+        """
+        
         return self._get_jobs_by_parameter('status', 'processing')
         
Index: sage/dsage/database/monitordb.py
===================================================================
--- sage/dsage/database/monitordb.py	(revision 3866)
+++ sage/dsage/database/monitordb.py	(revision 4353)
@@ -20,5 +20,5 @@
 import datetime
 import os
-import sqlite3 as sqlite
+import sqlite3
 
 from twisted.python import log
@@ -55,9 +55,11 @@
     
     def __init__(self, test=False):
-        self.conf = get_conf(type='monitordb')
         self.tablename = 'monitors'
         if test:
-            self.db_file = 'monitordb-test.db'
-        else:
+            self.db_file = 'monitordb_test.db'
+            self.log_level = 5
+            self.log_file = 'monitordb_test.log'
+        else:
+            self.conf = get_conf(type='monitordb')
             self.db_file = self.conf['db_file']
             if not os.path.exists(self.db_file):
@@ -65,8 +67,12 @@
                 if not os.path.isdir(dir):
                     os.mkdir(dir)
-        self.log_level = self.conf['log_level']
-        self.log_file = self.conf['log_file']
-        self.con = sqlite.connect(self.db_file,
-                    detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES)
+            self.log_level = self.conf['log_level']
+            self.log_file = self.conf['log_file']
+        self.con = sqlite3.connect(self.db_file,
+                isolation_level=None,
+                detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
+        sql_functions.optimize_sqlite(self.con)
+        # Don't use this, it's slow!
+        # self.con.text_factory = sqlite3.OptimizedUnicode
         self.con.text_factory = str
         
Index: sage/dsage/database/sql_functions.py
===================================================================
--- sage/dsage/database/sql_functions.py	(revision 3866)
+++ sage/dsage/database/sql_functions.py	(revision 4238)
@@ -20,4 +20,19 @@
 from twisted.python import log
 
+def optimize_sqlite(con):
+    """
+    Sets some pragma settings that are supposed to optimize SQLite.
+    Settings taken from:
+    http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html
+    
+    """
+    
+    cur = con.cursor()
+    cur.execute("pragma cache_size=4000") # Use double the default cache_size
+    cur.execute("pragma synchronous=off") # do not wait for disk writes
+    cur.execute("pragma temp_store=2") # store temporary results in memory
+    
+    return con
+    
 def table_exists(con, tablename):
     """
@@ -34,4 +49,5 @@
     cur.execute(query, (tablename,))
     result = cur.fetchone()
+    
     return result
     
@@ -58,4 +74,14 @@
     return results
 
+def drop_table(con, table):
+    """
+    Drops a table, use with caution!
+    
+    """
+    
+    cur = con.cursor()
+    query = "DROP TABLE ?"
+    cursor.execute(query, (table,))
+    
 def add_trigger(con, trigger):
     con.execute(trigger)
Index: sage/dsage/database/tests/test_clientdb.py
===================================================================
--- sage/dsage/database/tests/test_clientdb.py	(revision 3866)
+++ sage/dsage/database/tests/test_clientdb.py	(revision 4355)
@@ -69,5 +69,5 @@
         self.clientdb.update_login_time(username)
         post_login_time = self.clientdb.get_parameter(username, 'last_login')
-        self.assert_(datetime.datetime.now() > post_login_time)
+        self.assert_(datetime.datetime.now() >= post_login_time)
         
 if __name__ == '__main__':
Index: sage/dsage/database/tests/test_jobdb.py
===================================================================
--- sage/dsage/database/tests/test_jobdb.py	(revision 3866)
+++ sage/dsage/database/tests/test_jobdb.py	(revision 4345)
@@ -127,29 +127,31 @@
         job.status = 'new'
         job.killed = False
-        jdict = self.jobdb.store_job(job.reduce())
-        self.assertEquals(jdict['job_id'], self.jobdb.get_job()['job_id'])
+        job_id = self.jobdb.store_job(job.reduce())
+        self.assertEquals(job_id, self.jobdb.get_job()['job_id'])
         
     def teststore_job(self):
         job = Job()
-        self.assert_(isinstance(self.jobdb.store_job(job.reduce()), dict))
+        self.assert_(isinstance(self.jobdb.store_job(job.reduce()), str))
         
     def testget_job_by_id(self):
         job = Job()
-        jdict = self.jobdb.store_job(job.reduce())
-        self.assert_(self.jobdb.get_job_by_id(jdict['job_id']) is not None)
+        job_id = self.jobdb.store_job(job.reduce())
+        self.assert_(self.jobdb.get_job_by_id(job_id) is not None)
     
     def testhas_job(self):
         job = Job()
-        jdict = self.jobdb.store_job(job.reduce())
-        self.assertEquals(self.jobdb.has_job(jdict['job_id']), True)
+        job_id = self.jobdb.store_job(job.reduce())
+        self.assertEquals(self.jobdb.has_job(job_id), True)
     
     def testcreate_jdict(self):
         job = Job()
-        jdict = self.jobdb.store_job(job.reduce())
+        job_id = self.jobdb.store_job(job.reduce())
+        jdict = self.jobdb.get_job_by_id(job_id)
         self.assert_(isinstance(jdict, dict))
     
     def testget_killed_jobs_list(self):
         job = Job()
-        jdict = self.jobdb.store_job(job.reduce())
+        job_id = self.jobdb.store_job(job.reduce())
+        jdict = self.jobdb.get_job_by_id(job_id)
         self.jobdb.set_killed(jdict['job_id'], killed=True)
         self.assertEquals(len(self.jobdb.get_killed_jobs_list()), 1)
Index: sage/dsage/dist_functions/dist_factor.py
===================================================================
--- sage/dsage/dist_functions/dist_factor.py	(revision 3874)
+++ sage/dsage/dist_functions/dist_factor.py	(revision 4245)
@@ -17,6 +17,6 @@
     """
     
-    def __init__(self, DSage, n, concurrent=10, verbosity=0, trial_division_limit=10000,
-                 name='DistributedFactor'):
+    def __init__(self, DSage, n, concurrent=10, verbosity=0, 
+                 trial_division_limit=10000, name='DistributedFactor'):
         """
         Parameters:
@@ -75,4 +75,8 @@
         job.n = int(n) # otherwise cPickle will crash
         job.algorithm = 'qsieve'
+        job.verifiable = True
+        job.type = 'qsieve'
+        job.timeout = 60*60*24
+        
         return job
     
@@ -95,4 +99,7 @@
         job.n = int(n)
         job.algorithm = 'ecm'
+        job.verifiable = True
+        job.type = 'ecm'
+        job.timeout = 60*60*24
         return job
     
@@ -111,4 +118,10 @@
             self.done = True
             return
+            
+        for factor in self.composite_factors:
+            if is_prime(factor):
+                self.prime_factors.append(factor)
+                self.composite_factors.remove(factor)
+            
         if self.verbosity > 2:
             print "process_result(): ", job, job.output, job.result
Index: sage/dsage/dist_functions/dist_function.py
===================================================================
--- sage/dsage/dist_functions/dist_function.py	(revision 3905)
+++ sage/dsage/dist_functions/dist_function.py	(revision 4350)
@@ -113,5 +113,5 @@
         if dsage.remoteobj is None:
             # XXX This is a hack because dsage.remoteobj is not set yet
-            reactor.callLater(1.0, self.restore, dsage)
+            reactor.callLater(0.5, self.restore, dsage)
             return
         self.DSage = dsage
@@ -121,6 +121,6 @@
             self.submit_jobs(self.name)
             
-        self.checker_task = task.LoopingCall(self.check_results)
-        reactor.callFromThread(self.checker_task.start, 1.0, now=True)
+        self.checker_task = task.LoopingCall(self.check_waiting_jobs)
+        reactor.callFromThread(self.checker_task.start, 5.0, now=True)
 
     def submit_job(self, job, job_name='job', async=True):
@@ -135,14 +135,19 @@
                 self.waiting_jobs.append(self.DSage.send_job(job, async=True))
             else:
-                self.waiting_jobs.append(self.DSage.eval(job, job_name=job_name, async=True))
+                self.waiting_jobs.append(self.DSage.eval(job,
+                                                         job_name=job_name, 
+                                                         async=True))
         else:
             if isinstance(job, Job):
-                self.waiting_jobs.append(self.DSage.send_job(job, async=False))
+                self.waiting_jobs.append(self.DSage.send_job(job,
+                                                             async=False))
             else:
-                self.waiting_jobs.append(self.DSage.eval(job, job_name=job_name))
+                self.waiting_jobs.append(self.DSage.eval(job,
+                                                         job_name=job_name))
     
     def submit_jobs(self, job_name='job', async=True):
         """
-        Repeatedly calls submit_job until we have no more jobs in outstanding_jobs
+        Repeatedly calls submit_job until we have no more jobs in
+        outstanding_jobs
         
         """
@@ -156,4 +161,11 @@
 
     def start(self):
+        """
+        Starts the Distributed Function. It will submit all jobs in the
+        outstanding_jobs queue and also start a checker tasks that polls for
+        new information about jobs in the waiting_jobs queue
+        
+        """
+        
         from twisted.internet import reactor, task
         if self.DSage is None:
@@ -162,10 +174,12 @@
         self.start_time = datetime.datetime.now()
         reactor.callFromThread(self.submit_jobs, self.name, async=True)
-        self.checker_task = blocking_call_from_thread(task.LoopingCall, self.check_results)
-        reactor.callFromThread(self.checker_task.start, 1.0, now=True)
+        self.checker_task = blocking_call_from_thread(task.LoopingCall,
+                                                      self.check_waiting_jobs)
+        reactor.callFromThread(self.checker_task.start, 5.0, now=True)
     
     def process_result(self):
         """
-        Any class subclassing DistributedFunction should implement this method.
+        Any class subclassing DistributedFunction should implement this
+        method.
         
         """
@@ -173,13 +187,20 @@
         pass
         
-    def check_results(self):
+    def check_waiting_jobs(self):
+        """
+        Checks the status of jobs in the waiting queue.
+        
+        """
+        
         from twisted.internet import reactor
         from twisted.spread import pb
         for wrapped_job in self.waiting_jobs:
+            if wrapped_job.killed == True:
+                self.waiting_jobs.remove(wrapped_job)
+                continue
             if isinstance(wrapped_job, JobWrapper):
                 try:
                     wrapped_job.get_job()
-                except pb.DeadReferenceError:
-                    print 'Disconnected from the server, stopping checker_task.'
+                except pb.DeadReferenceError, msg:
                     if self.checker_task.running:
                         reactor.callFromThread(self.checker_task.stop)
Index: sage/dsage/dsage.py
===================================================================
--- sage/dsage/dsage.py	(revision 3914)
+++ sage/dsage/dsage.py	(revision 4352)
@@ -7,37 +7,31 @@
 
 import os
+import subprocess
+import sys
 
 import sage.interfaces.cleaner
 from sage.misc.all import DOT_SAGE
-import pexpect
-
-## def spawn(cmd, logfile=None, verbose=True):
-##     pid = os.fork()
-##     if pid != 0:
-##         sage.interfaces.cleaner.cleaner(pid)
-##         if verbose:
-##             print "Started %s (pid = %s, logfile = '%s')"%(cmd, pid, logfile)
-##         return pid
-##     if pid == 0:
-##         if not logfile is None:
-##             cmd += ' 2>&1 > ' + logfile
-##         os.system(cmd)
-
-## def start_process(typ, hostname, address, port):
-##     cmd = 'dsage_%s.py &'%typ
-##     os.system(cmd)
-##     dir = '%s/dsage/'%os.environ['DOT_SAGE']
-##     pid_file = '%s/server-hostname-address-port.pid'%dir
-##     while True:
-##         try:
-##             if os.path.exists(pid_file):
-##                 return int(open(pid_file).read())
-##         except Exception, msg:
-##             print msg
-       
+from sage.misc.all import SAGE_ROOT
+
+def spawn(cmd, logfile=None, verbose=True):
+    """
+    Spawns a process and registers it with the SAGE cleaner.
+    
+    """
+
+    if not logfile is None:
+        log = open(logfile, 'a')
+    else:
+        log = sys.stdout
+    
+    process = subprocess.Popen(['%s/%s' % (SAGE_ROOT + '/local/bin', cmd)],
+                               stdout=log, stderr=log)
+                               
+    print 'Spawned %s (pid = %s, logfile = %s)' % (cmd, process.pid, log.name)
+    sage.interfaces.cleaner.cleaner(process.pid, cmd)
 
 class DistributedSage(object):
     r"""
-    DistributedSage allows you to do distributed computing using SAGE.
+    Distributed SAGE allows you to do distributed computing in SAGE.
 
     To get up and running quickly, run dsage.setup() to run the 
@@ -105,4 +99,5 @@
         The configuration file should be self explanatory.
     """
+    
     def __init__(self):
         pass
@@ -115,28 +110,5 @@
         return DSage()
         
-##     def server(self, blocking=True, logfile=None):
-##         r"""
-##         Run the Distributed SAGE server.
-        
-##         Doing \code{dsage.server()} will spawn a server process which
-##         listens by default on port 8081.
-
-##         INPUT:
-##             blocking -- boolean (default: True) -- if False the dsage
-##                         server will run and you'll still be able to
-##                         enter commands at the command prompt (though
-##                         logging will make this hard).
-##             logfile  -- only used if blocking=True; the default is
-##                         to log to $DOT_SAGE/dsage/server.log
-##         """
-##         cmd = 'dsage_server.py'
-##         if not blocking:
-##             if logfile is None:
-##                 logfile = '%s/dsage/server.log'%DOT_SAGE
-##             spawn(cmd, logfile)
-##         else:
-##             os.system(cmd)
-
-    def server(self):
+    def server(self, blocking=True, clear_jobs=False, logfile=None):
         r"""
         Run the Distributed SAGE server.
@@ -144,43 +116,24 @@
         Doing \code{dsage.server()} will spawn a server process which
         listens by default on port 8081.
-        """
+
+        INPUT:
+            blocking -- boolean (default: True) -- if False the dsage
+                        server will run and you'll still be able to
+                        enter commands at the command prompt (though
+                        logging will make this hard).
+            logfile  -- only used if blocking=True; the default is
+                        to log to $DOT_SAGE/dsage/server.log
+                        
+        """
+        
         cmd = 'dsage_server.py'
-        os.system(cmd)
-            
-
-##     def worker(self, server=None, port=None, blocking=True, logfile=None):
-##         r"""
-##         Run the Distributed SAGE worker. 
-
-##         Typing \code{sage.worker()} will launch a worker which by
-##         default connects to localhost on port 8081 to fetch jobs.
-        
-##         INPUT:
-
-##             server -- (string, default: None) the server you want to
-##                       connect to if None, connects to the server
-##                       specified in .sage/dsage/worker.conf
-##             port -- (integer, default: None) the port that the server
-##                       listens on for workers.
-##             blocking -- (bool, default: True) whether or not to make a
-##                         blocking connection.
-##             logfile -- only used if blocking=True; the default is
-##                        to log to $DOT_SAGE/dsage/worker.log
-##         """
-##         cmd = 'dsage_worker.py'
-##         if blocking:
-##             cmd += ' %s' % server
-##             cmd += ' %s' % port
-##             os.system(cmd)
-##         else:
-##             if not server is None or not port is None:
-##                 args = [str(server), str(port)]
-##             else:
-##                 args = []
-##             if logfile is None:
-##                 logfile = '%s/dsage/worker.log'%DOT_SAGE
-##             spawn(cmd + ' '.join(args), logfile)
-
-    def worker(self, server=None, port=None):
+        if not blocking:
+            if logfile is None:
+                logfile = '%s/dsage/server.log' % (DOT_SAGE)
+            spawn(cmd, logfile)
+        else:
+            os.system(cmd)
+
+    def worker(self, server=None, port=None, blocking=True, logfile=None):
         r"""
         Run the Distributed SAGE worker. 
@@ -190,5 +143,4 @@
         
         INPUT:
-
             server -- (string, default: None) the server you want to
                       connect to if None, connects to the server
@@ -196,9 +148,24 @@
             port -- (integer, default: None) the port that the server
                       listens on for workers.
-        """
+            blocking -- (bool, default: True) whether or not to make a
+                        blocking connection.
+            logfile -- only used if blocking=True; the default is
+                       to log to $DOT_SAGE/dsage/worker.log
+        """
+        
         cmd = 'dsage_worker.py'
-        cmd += ' %s' % server
-        cmd += ' %s' % port
-        os.system(cmd)
+        if blocking:
+            cmd += ' %s' % server
+            cmd += ' %s' % port
+            os.system(cmd)
+        else:
+            if not server is None or not port is None:
+                args = [str(server), str(port)]
+            else:
+                args = []
+            if logfile is None:
+                logfile = '%s/dsage/worker.log'%DOT_SAGE
+            spawn(cmd + ' '.join(args), logfile)
+
 
     def setup(self):
@@ -211,5 +178,7 @@
         \code{dsage.setup_server()}, \code{dsage.setup\_worker()}
         or \code{dsage.setup()}.
-        """
+        
+        """
+        
         cmd = 'dsage_setup.py'
         os.system(cmd)
@@ -219,4 +188,5 @@
         This method runs the configuration utility for the server.
         """
+        
         cmd = 'dsage_setup.py server'
         os.system(cmd)
@@ -233,4 +203,5 @@
         This method runs the configuration utility for the client.
         """
+        
         cmd = 'dsage_setup.py client'
         os.system(cmd)
Index: sage/dsage/interface/dsage_interface.py
===================================================================
--- sage/dsage/interface/dsage_interface.py	(revision 3903)
+++ sage/dsage/interface/dsage_interface.py	(revision 4350)
@@ -28,5 +28,8 @@
 from sage.dsage.database.job import Job, expand_job
 from sage.dsage.twisted.misc import blocking_call_from_thread
-from sage.dsage.misc.config import get_conf
+from sage.dsage.misc.config import get_conf, get_bool
+
+DOT_SAGE = os.getenv('DOT_SAGE')
+DSAGE_DIR = os.path.join(DOT_SAGE, 'dsage')
 
 class DSageThread(threading.Thread):
@@ -39,17 +42,24 @@
     """
     This object represents a connection to the distributed SAGE server.
+    
+    Parameters:
+    server -- str
+    port -- int
+    username -- str
+    pubkey_file -- str (Default: None)
+    privkey_file -- str (Default: None)
+    log_file -- str (Default: stdout)
+    log_level -- int (Default: 0)
+    ssl -- int (Default: 1)
+    
     """
-    
-    def __init__(self, server=None, port=8081, username=None, 
-                 pubkey_file=None, privkey_file=None):
-        """
-        Parameters:
-        server -- str
-        port -- int
-        username -- str
-        pubkey_file -- str (Default: None)
-        privkey_file -- str (Default: None)
-        
-        """
+
+    def __init__(self, server=None, port=8081, 
+                 username=None, 
+                 pubkey_file=None,
+                 privkey_file=None,
+                 log_file = 'stdout',
+                 log_level = 0,
+                 ssl = True):
         
         from twisted.cred import credentials
@@ -80,5 +90,5 @@
             self.privkey_file = privkey_file
         
-        self.ssl = int(self.conf['ssl'])
+        self.ssl = get_bool(self.conf['ssl'])
         self.log_level = int(conf['log_level'])
         self.remoteobj = None
@@ -89,10 +99,12 @@
         # try getting the private key object without a passphrase first
         try:
-            self.priv_key = keys.getPrivateKeyObject(filename=self.privkey_file)
-        except keys.BadKeyError:
+            self.priv_key = keys.getPrivateKeyObject(
+                            filename=self.privkey_file)
+        except keys.BadKeyError, msg:
             passphrase = self._getpassphrase()
             self.priv_key = keys.getPrivateKeyObject(
                             filename=self.privkey_file,
                             passphrase=passphrase)
+                            
         self.pub_key = keys.getPublicKeyObject(self.pubkey_str)
         self.alg_name = 'rsa'
@@ -128,4 +140,5 @@
         d = copy.copy(self.__dict__)
         d['remoteobj'] = None
+        
         return d
         
@@ -141,6 +154,7 @@
             print 'Remote server %s refused the connection.'  % (self.server)
         else:
-            print "Error: ", failure.getErrorMessage()
-            print "Traceback: ", failure.printTraceback()
+            pass
+            # print "Error: ", failure.getErrorMessage()
+            # print "Traceback: ", failure.printTraceback()
 
     def _connected(self, remoteobj):
@@ -347,6 +361,12 @@
     
     """
-
-    def __init__(self, server=None, port=None, username=None, pubkey_file=None, privkey_file=None):
+    def __init__(self, server=None, port=8081, 
+                 username=None, 
+                 pubkey_file=None,
+                 privkey_file=None,
+                 log_file = 'stdout',
+                 log_level = 0,
+                 ssl = True):
+                 
         from twisted.cred import credentials
         from twisted.conch.ssh import keys
@@ -381,5 +401,5 @@
         
         self.data = self.conf['data']
-        self.ssl = int(self.conf['ssl'])
+        self.ssl = get_bool(self.conf['ssl'])
         self.log_level = int(self.conf['log_level'])
         self.remoteobj = None
@@ -528,5 +548,6 @@
         self.check_connected()
 
-        return blocking_call_from_thread(self.remoteobj.callRemote, 'get_cluster_speed')
+        return blocking_call_from_thread(self.remoteobj.callRemote,
+                                         'get_cluster_speed')
     
     def get_monitors_list(self):
@@ -537,5 +558,6 @@
         self.check_connected()
         
-        return blocking_call_from_thread(self.remoteobj.callRemote, 'get_monitor_list')
+        return blocking_call_from_thread(self.remoteobj.callRemote,
+                                         'get_monitor_list')
     
     def get_clients_list(self):
@@ -546,5 +568,6 @@
         self.check_connected()
         
-        return blocking_call_from_thread(self.remoteobj.callRemote, 'get_client_list')
+        return blocking_call_from_thread(self.remoteobj.callRemote,
+                                         'get_client_list')
     
     def get_worker_count(self):
@@ -556,5 +579,6 @@
         self.check_connected()
         
-        return blocking_call_from_thread(self.remoteobj.callRemote, 'get_worker_count')
+        return blocking_call_from_thread(self.remoteobj.callRemote,
+                                         'get_worker_count')
         
 class JobWrapper(object):
@@ -576,5 +600,9 @@
 
         # d = self.remoteobj.callRemote('get_next_job_id')
-        d = self.remoteobj.callRemote('submit_job', job.reduce())
+        try:
+            d = self.remoteobj.callRemote('submit_job', job.reduce())
+        except Exception, msg:
+            print msg
+        d.addCallback(self._got_job_id)
         d.addCallback(self._got_jdict)
         d.addErrback(self._catch_failure)
@@ -610,5 +638,5 @@
     def wait(self):
         from twisted.internet import reactor
-        timeout = 0.1
+        timeout = 0.5
         while self._job.result is None:
             reactor.iterate(timeout)
@@ -632,7 +660,16 @@
             print 'Disconnected from server.'
         else:
-            print "Error: ", failure.getErrorMessage()
-            print "Traceback: ", failure.printTraceback()
-    
+            pass
+            # print "Error: ", failure.getErrorMessage()
+            # print "Traceback: ", failure.printTraceback()
+    
+    def _got_job_id(self, job_id):
+        try:
+            d = self.remoteobj.callRemote('get_job_by_id', job_id)
+        except Exception, msg:
+            raise
+            
+        return d
+        
     def _got_job(self, job):
         if job == None:
@@ -653,5 +690,9 @@
         if self.job_id is None:
             return
-        d = self.remoteobj.callRemote('get_job_by_id', self.job_id)
+        try:
+            d = self.remoteobj.callRemote('get_job_by_id', self.job_id)
+        except Exception, msg:
+            raise
+            
         d.addCallback(self._got_job)
         d.addErrback(self._catch_failure)
@@ -662,5 +703,10 @@
         if self.remoteobj == None:
             return
-        d = self.remoteobj.callRemote('get_job_output_by_id', self._job.job_id)
+        try:
+            d = self.remoteobj.callRemote('get_job_output_by_id',
+                                          self._job.job_id)
+        except Exception, msg:
+            raise
+            
         d.addCallback(self._got_job_output)
         d.addErrback(self._catch_failure)
@@ -675,5 +721,10 @@
         if self.remoteobj == None:
             return
-        d = self.remoteobj.callRemote('get_job_result_by_id', self._job.job_id)
+        try:
+            job_id = self._job.job_id
+            d = self.remoteobj.callRemote('get_job_result_by_id', job_id)
+        except Exception, msg:
+            raise
+            
         d.addCallback(self._got_job_result)
         d.addErrback(self._catch_failure)
@@ -726,5 +777,9 @@
         
         if self.job_id is not None:
-            d = self.remoteobj.callRemote('kill_job', self.job_id)
+            try:
+                d = self.remoteobj.callRemote('kill_job', self.job_id)
+            except Exception, msg:
+                print 'Unable to kill %s because %s'  % (self.job_id, msg)
+                return
             d.addCallback(self._killed_job)
             d.addErrback(self._catch_failure)
@@ -749,5 +804,6 @@
         self._update_job(job)
 
-        jdict = blocking_call_from_thread(self.remoteobj.callRemote, 'submit_job', job.reduce())
+        jdict = blocking_call_from_thread(self.remoteobj.callRemote,
+                                          'submit_job', job.reduce())
         self._job = expand_job(jdict)
 
@@ -772,6 +828,6 @@
             return
         
-        job = blocking_call_from_thread(
-                        self.remoteobj.callRemote, 'get_job_by_id', self._job.job_id)
+        job = blocking_call_from_thread(self.remoteobj.callRemote, 
+                                        'get_job_by_id', self._job.job_id)
         
         self._update_job(expand_job(job))
@@ -786,5 +842,6 @@
         """
         
-        job_id = blocking_call_from_thread(self.remoteobj.callRemote, 'kill_job', self._job.job_id)
+        job_id = blocking_call_from_thread(self.remoteobj.callRemote,
+                                           'kill_job', self._job.job_id)
         self.job_id = job_id
         self.killed = True
@@ -823,5 +880,5 @@
         else:
             def handler(signum, frame):
-                raise RuntimeError, 'Maximum wait time exceeded.'
+                raise RuntimeError('Maximum wait time exceeded.')
             signal.signal(signal.SIGALRM, handler)
             signal.alarm(timeout)
Index: sage/dsage/misc/config.py
===================================================================
--- sage/dsage/misc/config.py	(revision 3902)
+++ sage/dsage/misc/config.py	(revision 4342)
@@ -20,15 +20,19 @@
 """
 Gets the different configuration options for the various components of DSAGE.
+
 """
 
 import os
-import random
 import ConfigParser
 import uuid
+
+from sage.dsage.misc.misc import random_str
 
 def check_version(old_version):
     from sage.dsage.__version__ import version
     if version != old_version:
-        raise ValueError, "Incompatible version. You have %s, need %s." % (old_version, version)
+        msg = "Version mismatch:\nHas:\t%s\nNeeds:\t%s" % (old_version,
+                                                           version)
+        raise ValueError(msg)
 
 def read_conf(config):
@@ -36,15 +40,21 @@
     for sec in config.sections():
         conf.update(dict(config.items(sec)))
-    check_version(conf['version'])
+    try:
+        check_version(conf['version'])
+    except ValueError, msg:
+        raise ValueError(msg)
 
     return conf
     
-def get_conf(type):
-    DSAGE_DIR = os.path.join(os.getenv('DOT_SAGE'), 'dsage')
+def get_conf(type, test=False):
+    if test:
+        DSAGE_DIR = os.path.join(os.getenv('DOT_SAGE'), 'tmp')
+    else:
+        DSAGE_DIR = os.path.join(os.getenv('DOT_SAGE'), 'dsage')
     config = ConfigParser.ConfigParser()
     try:
         if type == 'client':   
             conf_file = os.path.join(DSAGE_DIR, 'client.conf')
-            DATA =  ''.join([chr(i) for i in [random.randint(65, 123) for n in range(500)]])
+            DATA =  random_str(length=500)
             config.read(conf_file)
             conf = read_conf(config)
@@ -69,10 +79,12 @@
             conf['log_level'] = config.get('db_log', 'log_level')
             conf['log_file'] = config.get('db_log', 'log_file')
-
+        
+        conf['conf_file'] = conf_file
+        
         return conf 
     except Exception, msg:
         print msg
         print "Error reading '%s', run dsage.setup()" % conf_file     
-
+    
 def get_bool(value):
     boolean_states = {'0': False,
@@ -85,5 +97,5 @@
     'yes': True}
     if value.lower() not in boolean_states:
-        raise ValueError, 'Not a boolean: %s' % value
+        raise ValueError('Not a boolean: %s' % value)
     
     return boolean_states[value.lower()]
Index: sage/dsage/misc/countrefs.py
===================================================================
--- sage/dsage/misc/countrefs.py	(revision 4233)
+++ sage/dsage/misc/countrefs.py	(revision 4233)
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# Copyright 2003-2005 Andrew Bennetts.
+
+# Simple object counting for CPython.  Abuses the gc module to find most class
+# and type objects, and then reports their reference counts.  Because instances
+# hold a reference to their class/type, this is a good approximation of the
+# number of instances, particularly as the number of instances gets large.
+# Non-heaptype types probably aren't reported, but that's not usually
+# significant.
+
+# TODO:
+#  * Make this a script wrapper, like profile.py, so that you can use:
+#       countrefs.py --log=refs.log -t 5 -n 30 some-script.py
+#    to run some-script.py, logging the top 30 reference counts to refs.log
+#    every 5 seconds.  It should still be an importable module, of course.
+
+import gc, sys, types
+import threading, time
+
+__all__ = ['logInThread', 'mostRefs', 'printCounts']
+
+def mostRefs(n=30):
+    d = {}
+    for obj in gc.get_objects():
+        if type(obj) is types.InstanceType:
+            cls = obj.__class__
+        else:
+            cls = type(obj)
+        d[cls] = d.get(cls, 0) + 1
+    counts = [(x[1],x[0]) for x in d.items()]
+    counts.sort()
+    counts = counts[-n:]
+    counts.reverse()
+    return counts
+
+
+def printCounts(counts, file=None):
+    for c, obj in counts:
+        if file is None:
+            print c, obj
+        else:
+            file.write("%s %s\n" % (c, obj))
+
+
+def logInThread(n=30):
+    """Start a thread to log the top n ref counts every second."""
+    reflog = file('/tmp/refs.log','w')
+    t = threading.Thread(target=_logRefsEverySecond, args=(reflog, n))
+    t.setDaemon(True) # allow process to exit without explicitly stopping thread
+    t.start()
+    return t
+
+
+def _logRefsEverySecond(log, n):
+    while True:
+        printCounts(mostRefs(n=n), file=log)
+        log.write('\n')
+        log.flush()
+        time.sleep(1)
+
+
+if __name__ == '__main__':
+    counts = mostRefs()
+    printCounts(counts)
+
Index: sage/dsage/misc/hostinfo.py
===================================================================
--- sage/dsage/misc/hostinfo.py	(revision 3866)
+++ sage/dsage/misc/hostinfo.py	(revision 4218)
@@ -248,5 +248,8 @@
             
     def canonical_info(self, platform_host_info):
-        """Standarize host info so we can parse it easily"""
+        """
+        Standarize host info so we can parse it easily.
+        
+        """
 
         unify_info = {'model name': 'cpu_model', 
Index: sage/dsage/misc/misc.py
===================================================================
--- sage/dsage/misc/misc.py	(revision 4231)
+++ sage/dsage/misc/misc.py	(revision 4231)
@@ -0,0 +1,36 @@
+##############################################################################
+#                                                                     
+#  DSAGE: Distributed SAGE                     
+#                                                                             
+#       Copyright (C) 2006, 2007 Yi Qiang <yqiang@gmail.com>               
+#                                                                            
+#  Distributed under the terms of the GNU General Public License (GPL)        
+#
+#    This code is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#    General Public License for more details.
+#
+#  The full text of the GPL is available at:
+#
+#                  http://www.gnu.org/licenses/
+#
+##############################################################################
+"""
+Miscellaneous helper methods. 
+
+"""
+
+import random
+
+def random_str(length=500):
+    """
+    Generates a random string.
+    
+    INPUT:
+    length -- the length of the string
+    
+    """
+    s = [chr(i) for i in [random.randint(65, 123) for n in range(length)]]
+    
+    return ''.join(s)
Index: sage/dsage/scripts/dsage_server.py
===================================================================
--- sage/dsage/scripts/dsage_server.py	(revision 3906)
+++ sage/dsage/scripts/dsage_server.py	(revision 4353)
@@ -17,14 +17,11 @@
 #                  http://www.gnu.org/licenses/
 ############################################################################
-
+# 
+# import gc
+# gc.set_debug(gc.DEBUG_LEAK)
 
 import sys
 import os
-import socket
-
-
-
 from optparse import OptionParser
-import ConfigParser
 import socket
 
@@ -34,16 +31,13 @@
 from twisted.cred import portal
 
-from sage.dsage.database.jobdb import JobDatabaseZODB, JobDatabaseSQLite
-from sage.dsage.database.jobdb import DatabasePruner
+from sage.dsage.database.jobdb import JobDatabaseSQLite
 from sage.dsage.database.clientdb import ClientDatabase
 from sage.dsage.database.monitordb import MonitorDatabase
 from sage.dsage.twisted.pb import Realm
-from sage.dsage.twisted.pb import WorkerPBServerFactory
 from sage.dsage.twisted.pb import _SSHKeyPortalRoot
-from sage.dsage.twisted.pubkeyauth import PublicKeyCredentialsChecker
 from sage.dsage.twisted.pubkeyauth import PublicKeyCredentialsCheckerDB
-from sage.dsage.server.server import DSageServer, DSageWorkerServer
+from sage.dsage.server.server import DSageServer
+from sage.dsage.misc.config import get_conf, get_bool
 from sage.dsage.misc.constants import delimiter as DELIMITER
-from sage.dsage.__version__ import version
 
 DSAGE_DIR = os.path.join(os.getenv('DOT_SAGE'), 'dsage')
@@ -72,5 +66,4 @@
 
 def write_stats(dsage_server, stats_file):
-    # Put this entire thing in a try block, should not cause the server to die in any way.
     try:
         fname = os.path.join(DSAGE_DIR, stats_file)
@@ -83,11 +76,17 @@
         
 def startLogging(log_file):
-    """This method initializes the logging facilities for the server. """
+    """
+    This method initializes the logging facilities for the server. 
+    
+    """
+    
     if log_file == 'stdout':
         log.startLogging(sys.stdout)
+        log.msg('WARNING: DSAGE Server ONLY logging to stdout!')
     else:
-        print "DSAGE Server logging to file: ", log_file
         server_log = open(log_file, 'a')
+        log.startLogging(sys.stdout)
         log.startLogging(server_log)
+        log.msg("DSAGE Server: Logging to file: ", log_file)
 
 def main():
@@ -97,25 +96,14 @@
     """
     
-    try:
-        conf_file = os.path.join(DSAGE_DIR, 'server.conf')
-        config = ConfigParser.ConfigParser()
-        config.read(conf_file)
+    config = get_conf('server')
+    LOG_FILE = config['log_file']
+    LOG_LEVEL = config['log_level']
+    SSL = get_bool(config['ssl'])
+    SSL_PRIVKEY = config['privkey_file']
+    SSL_CERT = config['cert_file']
+    CLIENT_PORT = int(config['client_port'])
+    PUBKEY_DATABASE = os.path.expanduser(config['pubkey_database'])
+    STATS_FILE = config['stats_file']
 
-        LOG_FILE = config.get('server_log', 'log_file')
-        LOG_LEVEL = config.getint('server_log', 'log_level')
-        SSL = config.getint('ssl', 'ssl')
-        SSL_PRIVKEY = config.get('ssl', 'privkey_file')
-        SSL_CERT = config.get('ssl', 'cert_file')
-        CLIENT_PORT = config.getint('server', 'client_port')
-        PUBKEY_DATABASE = os.path.expanduser(config.get('auth', 'pubkey_database'))
-        STATS_FILE = config.get('general', 'stats_file')
-        old_version = config.get('general', 'version')
-        if version != old_version:
-            raise ValueError, "Incompatible version. You have %s, need %s." % (old_version, version)
-    except Exception, msg:
-        print msg
-        print "Error reading %s, run dsage.setup()" % conf_file
-        sys.exit(-1)
-    
     # start logging
     startLogging(LOG_FILE)
@@ -131,5 +119,6 @@
     
     # Create the main DSage object
-    dsage_server = DSageServer(jobdb, monitordb, clientdb, log_level=LOG_LEVEL)
+    dsage_server = DSageServer(jobdb, monitordb, 
+                               clientdb, log_level=LOG_LEVEL)
     p = _SSHKeyPortalRoot(portal.Portal(Realm(dsage_server)))
     
@@ -168,6 +157,6 @@
             if not port_used:
                 if SSL:
-                    log.msg('Using SSL...')
-                    ssl_context = ssl.DefaultOpenSSLContextFactory(SSL_PRIVKEY, SSL_CERT)
+                    ssl_context = ssl.DefaultOpenSSLContextFactory(
+                                    SSL_PRIVKEY, SSL_CERT)
                     reactor.listenSSL(NEW_CLIENT_PORT,
                                       client_factory,
@@ -178,5 +167,5 @@
                     break
             else:
-                raise SystemError, 'Trying to bind to open port: %s.' % (NEW_CLIENT_PORT)
+                raise SystemError('Trying to bind to open port: %s.' % (NEW_CLIENT_PORT))
         except (SystemError, error.CannotListenError):
             attempts += 1
@@ -188,14 +177,21 @@
         log.msg("Changing listening port in server.conf to %s" % (NEW_CLIENT_PORT))
         log.msg(DELIMITER)
-        config.set('server', 'client_port', NEW_CLIENT_PORT)
-        config.write(open(conf_file, 'w'))
+        import ConfigParser
+        cparser = ConfigParser.ConfigParser()
+        cparser.read(config['conf_file'])
+        cparser.set('server', 'client_port', NEW_CLIENT_PORT)
+        cparser.write(open(config['conf_file'], 'w'))
         
     log.msg(DELIMITER)
     log.msg('DSAGE Server')
-    log.msg('PID %s'%os.getpid())
+    log.msg('Started with PID: %s' % (os.getpid()))
+    if SSL:
+        log.msg('Using SSL...')    
     log.msg('Listening on %s' % (NEW_CLIENT_PORT))
     log.msg(DELIMITER)
 
-    # start the reactor.    
+    # from sage.dsage.misc.countrefs import logInThread
+    # logInThread(n=15)
+    
     reactor.run(installSignalHandlers=1)
 
Index: sage/dsage/scripts/dsage_setup.py
===================================================================
--- sage/dsage/scripts/dsage_setup.py	(revision 3905)
+++ sage/dsage/scripts/dsage_setup.py	(revision 4353)
@@ -18,5 +18,4 @@
 ############################################################################
 
-
 import os
 import ConfigParser
@@ -25,4 +24,5 @@
 
 from sage.dsage.database.clientdb import ClientDatabase
+from sage.dsage.twisted.pubkeyauth import get_pubkey_string
 from sage.dsage.misc.constants import delimiter as DELIMITER
 from sage.dsage.__version__ import version
@@ -70,5 +70,4 @@
     config.set('log', 'log_file', 'stdout')
     config.set('log', 'log_level', '0')
-    # set public key authentication info
     print DELIMITER
     print "Generating public/private key pair for authentication..."
@@ -88,14 +87,13 @@
 def setup_worker():
     check_dsage_dir()
-     # Get ConfigParser object
     config = get_config('worker')
-
+    LOG_FILE = os.path.join(DSAGE_DIR, 'worker.log')
     config.set('general', 'server', 'localhost')
     config.set('general', 'port', 8081)
-    config.set('general', 'nice_level', 20)
+    config.set('general', 'priority', 20)
     config.set('general', 'workers', 2)
     config.set('uuid', 'id', '')
     config.set('ssl', 'ssl', 1)
-    config.set('log', 'log_file', 'stdout')
+    config.set('log', 'log_file', LOG_FILE)
     config.set('log', 'log_level', '0')
     config.set('general', 'delay', '5')
@@ -107,11 +105,11 @@
 def setup_server():
     check_dsage_dir()
-    # Get ConfigParser object
     config = get_config('server')
+    LOG_FILE = os.path.join(DSAGE_DIR, 'server.log')
     config.set('server', 'client_port', 8081)
     config.set('ssl', 'ssl', 1)
-    config.set('server_log', 'log_file', 'stdout')
+    config.set('server_log', 'log_file', LOG_FILE)
     config.set('server_log', 'log_level', '0')
-    config.set('db_log', 'log_file', 'stdout')
+    config.set('db_log', 'log_file', LOG_FILE)
     config.set('db_log', 'log_level', '0')
     config.set('auth', 'pubkey_database', os.path.join(DB_DIR, 'dsage.db'))
@@ -142,4 +140,7 @@
         
     # add default user
+    from twisted.conch.ssh import keys
+    import base64
+    
     c = ConfigParser.ConfigParser()
     c.read(os.path.join(DSAGE_DIR, 'client.conf'))
@@ -147,14 +148,15 @@
     pubkey_file = c.get('auth', 'pubkey_file')
     clientdb = ClientDatabase()
-    if clientdb.get_user_and_key(username) is None:
-        clientdb.add_user(username, pubkey_file)
-        print 'Added user %s\n' % (username)
+    pubkey = base64.encodestring(
+                    keys.getPublicKeyString(filename=pubkey_file).strip())
+    if clientdb.get_user(username) is None:
+        clientdb.add_user(username, pubkey)
+        print 'Added user %s.\n' % (username)
     else:
-        (user, key) = clientdb.get_user_and_key(username)
-        pubkey = open(pubkey_file).read()
-        if pubkey != key:
+        user, key = clientdb.get_user_and_key(username)
+        if key != pubkey:
             clientdb.del_user(username)
-            clientdb.add_user(username, pubkey_file)            
-            print 'User %s exists, changing public key' % (username)
+            clientdb.add_user(username, pubkey)
+            print "User %s's pubkey changed, setting to new one." % (username)
         else:
             print 'User %s already exists.' % (username)
Index: sage/dsage/scripts/dsage_worker.py
===================================================================
--- sage/dsage/scripts/dsage_worker.py	(revision 3906)
+++ sage/dsage/scripts/dsage_worker.py	(revision 4353)
@@ -25,5 +25,4 @@
 import zlib
 import pexpect
-import time
 
 from twisted.spread import pb
@@ -42,4 +41,5 @@
 from sage.dsage.twisted.pb import PBClientFactory
 from sage.dsage.misc.constants import delimiter as DELIMITER
+from sage.dsage.misc.misc import random_str
 
 pb.setUnjellyableForClass(HostInfo, HostInfo)
@@ -49,8 +49,9 @@
 START_MARKER = '___BEGIN___'
 END_MARKER = '___END___'
+LOG_PREFIX = "[Worker %s] "
 
 def unpickle(pickled_job):
     return cPickle.loads(zlib.decompress(pickled_job))
-    
+
 class Worker(object):
     """
@@ -70,17 +71,12 @@
         self.log_level = self.conf['log_level']
         self.delay = self.conf['delay']
-        if self.log_level > 3:
-            self.sage = Sage(logfile=DSAGE_DIR + '/%s-pexpect.log'\
-                             % self.id)
-        else:
-            self.sage = Sage()
+        self.checker_task = task.LoopingCall(self.check_work)
+        self.checker_timeout = 0.5
+        self.got_output = False
+        self.start()
             
         # import some basic modules into our Sage() instance
         self.sage.eval('import time')
-        self.sage.eval('import sys')
         self.sage.eval('import os')
-        
-        # Initialize getting of jobs
-        self.get_job()
         
     def _catch_failure(self, failure):
@@ -91,10 +87,9 @@
         try:
             if self.log_level > 3:
-                log.msg('Worker %s: Getting job...' % (self.id))
+                log.msg(LOG_PREFIX % self.id +  'Getting job...') 
             d = self.remoteobj.callRemote('get_job')
         except Exception, msg:
             log.msg(msg)
-            log.msg('[Worker: %s, get_job] Disconnected from remote server.'\
-                    % self.id)
+            log.msg(LOG_PREFIX % self.id +  'Disconnected...')
             reactor.callLater(self.delay, self.get_job)
             return
@@ -113,17 +108,17 @@
         """
         
+        if self.log_level > 1:
+            if jdict is None:
+                log.msg(LOG_PREFIX % self.id + 'No new job.')
         if self.log_level > 3:
-            log.msg('[Worker %s, gotJob] %s' % (self.id, jdict))
-            
+            if jdict is not None:
+                log.msg(LOG_PREFIX % self.id + 'Got Job: %s' % jdict)
         self.job = expand_job(jdict)
-        
         if not isinstance(self.job, Job):
             raise NoJobException
-        
-        log.msg('[Worker: %s] Got job (%s, %s)' % (self.id, self.job.name, self.job.job_id))
         try:
             self.doJob(self.job)
         except Exception, msg:
-            log.msg(msg)
+            log.err(msg)
             d = self.remoteobj.callRemote('job_failed', self.job.job_id, msg)
             d.addErrback(self._catch_failure)
@@ -151,7 +146,9 @@
             log.msg('[Worker: %s, job_done] Disconnected, reconnecting in %s'\
                     % (self.id, self.delay))
-            reactor.callLater(self.delay, self.job_done, output, result, completed)
+            reactor.callLater(self.delay, self.job_done, 
+                              output, result, completed)
             d = defer.Deferred()
             d.errback(error.ConnectionLost())
+            
             return d
         
@@ -173,9 +170,10 @@
         if failure.check(NoJobException):
             if self.log_level > 3:
-                log.msg('[Worker %s, noJob] Sleeping for %s seconds' % (self.id, sleep_time))
+                msg = 'Sleeping for %s seconds' % sleep_time
+                log.msg(LOG_PREFIX % self.id + msg)
             reactor.callLater(sleep_time, self.get_job)
         else:
-            print "Error: ", failure.getErrorMessage()
-            print "Traceback: ", failure.printTraceback()
+            log.err("Error: ", failure.getErrorMessage())
+            log.err("Traceback: ", failure.printTraceback())
     
     def setup_tmp_dir(self, job):
@@ -205,5 +203,6 @@
         if isinstance(job.data, list):
             if self.log_level > 2:
-                log.msg('Extracting job data...')
+                msg = 'Extracting job data...'
+                log.msg(LOG_PREFIX % self.id + msg)
             try:
                 for var, data, kind in job.data:
@@ -218,5 +217,6 @@
                         f.close()
                         if self.log_level > 2:
-                            log.msg('[Worker: %s] Extracted %s. ' % (self.id, f))
+                            msg = 'Extracted %s' % f
+                            log.msg(LOG_PREFIX % self.id + msg)
                     if kind == 'object':
                         fname = var + '.sobj'
@@ -228,7 +228,8 @@
                         self.sage.eval("%s = load('%s')" % (var, fname))
                         if self.log_level > 2:
-                            log.msg('[Worker: %s] Loaded %s' % (self.id, fname))
+                            msg = 'Loaded %s' % fname
+                            log.msg(LOG_PREFIX % self.id + msg)
             except Exception, msg:
-                log.err(msg)
+                log.err(LOG_PREFIX % self.id + msg)
 
     def write_job_file(self, job):
@@ -238,14 +239,22 @@
         """
         
-        parsed_file = preparse_file(job.code, magic=False, do_time=False, ignore_prompts=False)
+        parsed_file = preparse_file(job.code, magic=False, 
+                                    do_time=False, ignore_prompts=False)
 
         job_filename = str(job.name) + '.py'
         job_file = open(job_filename, 'w')
+        timeout = job.timeout
         BEGIN = "print '%s'\n\n" % (START_MARKER)
         END = "print '%s'\n\n" % (END_MARKER)
+        SAVE_RESULT = """try: 
+    save(DSAGE_RESULT, 'result.sobj', compress=True)
+except:
+    save('No DSAGE_RESULT', 'result.sobj', compress=True)"""
+        job_file.write("alarm(%s)\n\n" % (timeout))
         job_file.write(BEGIN)
         job_file.write(parsed_file)
         job_file.write("\n\n")
         job_file.write(END)
+        job_file.write(SAVE_RESULT)
         job_file.close()
         if self.log_level > 2:
@@ -264,8 +273,16 @@
         
         if self.log_level > 3:
-            log.msg('[Worker %s, doJob] Beginning job execution...' % (self.id))
+            log.msg(LOG_PREFIX % self.id + 'Executing job %s ' % job.job_id)
             
         self.free = False
+        self.got_output = False
         d = defer.Deferred()
+        
+        try:
+            self.checker_task.start(self.checker_timeout, now=False)
+        except AssertionError:
+            self.checker_task.stop()
+            self.checker_task.start(self.checker_timeout, now=False)
+        log.msg(LOG_PREFIX % self.id + 'Starting checker task...')
         
         self.tmp_job_dir = self.setup_tmp_dir(job)
@@ -277,10 +294,140 @@
         self.sage._send("execfile('%s')" % (f))
         if self.log_level > 2:
-            log.msg('[Worker: %s] File to execute: %s' % (self.id, f))
+            msg = 'File to execute: %s' % f
+            log.msg(LOG_PREFIX % self.id + msg)
         
         d.callback(True)
-        
-        return d
-    
+            
+    def reset_checker(self):
+        """
+        Resets the output/result checker for the worker.
+        
+        """
+        
+        if self.checker_task.running:
+            self.checker_task.stop()
+        self.checker_timeout = 1.0
+        self.checker_task = task.LoopingCall(self.check_work)
+        
+    def check_work(self):
+        """
+        check_work periodically polls workers for new output. The period is
+        determined by an exponential back off algorithm.
+        
+        This figures out whether or not there is anything new output that we
+        should submit to the server.
+        
+        """
+        
+        if self.sage == None:
+            return
+        if self.job == None or self.free == True:
+            if self.checker_task.running:
+                self.checker_task.stop()
+            return
+                
+        if self.log_level > 1:
+            msg = 'Checking job %s' % self.job.job_id
+            log.msg(LOG_PREFIX % self.id + msg)
+        try:
+            foo, output, new = self.sage._so_far()
+            os.chdir(self.tmp_job_dir)
+            result = open('result.sobj', 'rb').read()
+            done = True
+        except RuntimeError, msg: # Error in calling worker.sage._so_far()
+            done = False
+            log.err(LOG_PREFIX % self.id + 'RuntimeError: %s' % msg)
+            self.increase_checker_task_timeout()
+            return
+        except IOError, msg: # File does not exist yet
+            done = False
+        if done:
+            self.free = True
+            self.reset_checker()
+        else:
+            result = cPickle.dumps('Job not done yet.', 2)
+        if self.check_failure(new):
+            self.report_failure(new)
+            self.restart()
+            return
+            
+        sanitized_output = self.clean_output(new)    
+        if sanitized_output == '' and not done:
+            self.increase_checker_task_timeout()
+        else:
+            d = self.job_done(sanitized_output, result, done)
+            d.addErrback(self._catch_failure)
+    
+    def report_failure(self, failure):
+        msg = 'Job %s failed!' % (self.job.job_id)
+        log.err(LOG_PREFIX % self.id + msg)
+        log.err('Traceback: \n%s' % failure)
+        d = self.remoteobj.callRemote('job_failed', self.job.job_id, failure)
+        d.addErrback(self._catch_failure)
+        
+    def increase_checker_task_timeout(self):
+        """
+        Quickly decreases the number of times a worker checks for output
+        
+        """
+        
+        if self.checker_task.running:
+            self.checker_task.stop()
+        
+        self.checker_timeout = self.checker_timeout * 2
+        if self.checker_timeout > 300.0:
+            self.checker_timeout = 300.0
+        self.checker_task = task.LoopingCall(self.check_work)
+        self.checker_task.start(self.checker_timeout, now=False)
+        msg = 'Checking output again in %s' % self.checker_timeout
+        log.msg(LOG_PREFIX % self.id + msg)
+        
+    def clean_output(self, sage_output):
+        """
+        clean_output attempts to clean up the output string from sage. 
+
+        """
+        
+        begin = sage_output.find(START_MARKER)
+        if begin != -1:
+            self.got_output = True
+            begin += len(START_MARKER)
+        else:
+            begin = 0
+        end = sage_output.find(END_MARKER)
+        if end != -1:
+            end -= 1
+        else:
+            if not self.got_output:
+                end = 0
+            else:
+                end = len(sage_output)
+        output = sage_output[begin:end]
+        output = output.strip()
+        output = output.replace('\r', '')
+        
+        if 'execfile' or 'load' in output and self.got_output:
+            output = ''           
+            
+        return output
+        
+    def check_failure(self, sage_output):
+        """
+        Checks for signs of exceptions or errors in the output.
+
+        """
+
+        if sage_output == None:
+            return False
+        else:
+            sage_output = ''.join(sage_output)
+
+        if 'Traceback' in sage_output:
+            return True
+        elif 'Error' in sage_output:
+            return True
+        else:
+            return False
+                
     def stop(self):
         """
@@ -289,17 +436,29 @@
         """
         
-        INTERRUPT_TRIES = 10
-        timeout = 0.05
-        for i in range(INTERRUPT_TRIES):    
-            try: 
-                self.sage._expect.sendline(chr(3))  # send ctrl-c            
-                self.sage._expect.expect(self.sage._prompt, timeout=timeout)            
-                self.sage._expect.expect(self.sage._prompt, timeout=timeout)
-                success = True
-                break
-            except (pexpect.TIMEOUT, pexpect.EOF), msg:
-                if self.log_level > 3:
-                    log.err("Trying again to interrupt SAGE (try %s)..." % i)
-        
+        INTERRUPT_TRIES = 20
+        timeout = 0.3
+        e = self.sage._expect
+        try:
+            for i in range(INTERRUPT_TRIES):    
+                self.sage._expect.sendline('q')
+                self.sage._expect.sendline(chr(3))  # send ctrl-c 
+                try: 
+                    e.expect(self.sage._prompt, timeout=timeout)            
+                    success = True
+                    break
+                except (pexpect.TIMEOUT, pexpect.EOF), msg:
+                    if self.log_level > 3:
+                        log.msg("Trying to interrupt SAGE (try %s)..." % i)
+        except Exception, msg:
+            success = False
+            log.err(msg)
+            log.err(LOG_PREFIX % self.id + "Performing hard reset.")
+        
+        if not success:
+            pid = self.sage.pid()
+            cmd = 'kill -9 -%s'%pid
+            os.system(cmd)
+            self.sage = Sage()
+            
         self.sage.reset()
         self.free = True
@@ -312,9 +471,18 @@
         """
         
-        if self.sage is None:
+        if not hasattr(self, 'sage'):
             if self.log_level > 3:
-                self.sage = Sage(logfile=DSAGE_DIR + '/%s-pexpect.out' % self.id)
+                logfile = DSAGE_DIR + '/%s-pexpect.log' % self.id
+                self.sage = Sage(logfile=logfile)
             else:
                 self.sage = Sage()
+            try:
+                self.sage._start(block_during_init=True)
+                self.sage._expect.delaybeforesend = 0.2
+            except RuntimeError, msg: # Could not start SAGE
+                print msg
+                reactor.stop()
+                sys.exit(-1)
+        
         self.get_job()
     
@@ -325,8 +493,9 @@
         """
         
-        log.msg('[Worker: %s] Restarting...' % (self.id))
         self.stop()
         self.start()
-
+        self.reset_checker()
+        log.msg('[Worker: %s] Restarting...' % (self.id))
+        
 class Monitor(object):
     """
@@ -338,8 +507,11 @@
     hostname -- the hostname of the server we want to connect to (str)
     port -- the port of the server we want to connect to (int)
-    
+
     """
     
-    def __init__(self, server, port):
+    def __init__(self, server='localhost', port=8081, ssl=True, 
+                 workers=2, anonymous=False, priority=20, delay=5.0,
+                 log_level=0):
+        
         self.conf = get_conf('monitor')
         self.uuid = self.conf['id']
@@ -350,4 +522,5 @@
         self.anonymous = get_bool(self.conf['anonymous'])
         self.ssl = get_bool(self.conf['ssl'])
+        self.priority = int(self.conf['priority'])
         if server is None:
             self.server = self.conf['server']
@@ -372,4 +545,9 @@
         self._startLogging(self.log_file)
         
+        try:
+            os.nice(self.priority)
+        except OSError, msg:
+            log.err('Error setting priority: %s' % (self.priority))
+            pass        
         if not self.anonymous:
             from twisted.cred import credentials
@@ -377,12 +555,12 @@
             self._get_auth_info()
             # public key authentication information
-            self.pubkey_str =keys.getPublicKeyString(filename=self.pubkey_file)
+            self.pubkey_str =keys.getPublicKeyString(self.pubkey_file)
             # try getting the private key object without a passphrase first
             try:
-                self.priv_key = keys.getPrivateKeyObject(filename=self.privkey_file)
+                self.priv_key = keys.getPrivateKeyObject(self.privkey_file)
             except keys.BadKeyError:
                 pphrase = self._getpassphrase()
-                self.priv_key = keys.getPrivateKeyObject(filename=self.privkey_file,
-                                                         passphrase=pphrase)
+                self.priv_key = keys.getPrivateKeyObject(self.privkey_file,
+                                                         pphrase)
             self.pub_key = keys.getPublicKeyObject(self.pubkey_str)
             self.alg_name = 'rsa'
@@ -399,13 +577,14 @@
         if log_file == 'stdout':
             log.startLogging(sys.stdout)
-        else:
-            print "Logging to file: ", log_file
-            server_log = open(log_file, 'a')
-            log.startLogging(server_log)
+            log.msg('WARNING: Only loggint to stdout!')
+        else:
+            worker_log = open(log_file, 'a')
+            log.startLogging(sys.stdout)
+            log.startLogging(worker_log)
+            log.msg("Logging to file: ", log_file)
+            
 
     def _get_auth_info(self):
-        import random
-        self.DATA =  ''.join([chr(i) for i in [random.randint(65, 123) for n in
-                        range(500)]])
+        self.DATA =  random_str(500)
         self.DSAGE_DIR = os.path.join(os.getenv('DOT_SAGE'), 'dsage')
         # Begin reading configuration
@@ -416,6 +595,8 @@
             
             self.username = config.get('auth', 'username')
-            self.privkey_file = os.path.expanduser(config.get('auth', 'privkey_file'))
-            self.pubkey_file = os.path.expanduser(config.get('auth', 'pubkey_file'))
+            self.privkey_file = os.path.expanduser(config.get('auth',
+                                                   'privkey_file'))
+            self.pubkey_file = os.path.expanduser(config.get('auth',
+                                                  'pubkey_file'))
         except Exception, msg:
             print msg
@@ -460,22 +641,17 @@
                     continue
                 if worker.job.job_id == job.job_id:
-                    log.msg('[Worker: %s] Processing a killed job, restarting...' % worker.id)
+                    msg = 'Processing killed job, restarting...'
+                    log.msg(LOG_PREFIX % worker.id + msg)
                     worker.restart()
     
     def _retryConnect(self):
         log.err('[Monitor] Disconnected, reconnecting in %s' % self.delay)
-        reactor.callLater(self.delay, self.connect)
-    
-    def _catchConnectionFailure(self, failure):
-        # If we lost the connection to the server somehow
-        # if failure.check(error.ConnectionRefusedError,
-        #                 error.ConnectionLost,
-        #                 pb.DeadReferenceError):
-        
-        self.connected = False
-        self._retryConnect()
-        
+        if not self.connected:
+            reactor.callLater(self.delay, self.connect)
+    
+    def _catchConnectionFailure(self, failure):                
         log.err("Error: ", failure.getErrorMessage())
         log.err("Traceback: ", failure.printTraceback())
+        self._disconnected(None)
     
     def _catch_failure(self, failure):
@@ -495,14 +671,15 @@
         log.msg(DELIMITER)
         log.msg('DSAGE Worker')
-        log.msg('PID %s'%os.getpid())
+        log.msg('Started with PID: %s' % (os.getpid()))
         log.msg('Connecting to %s:%s' % (self.server, self.port))
         log.msg(DELIMITER)
         
         self.factory = PBClientFactory()
-        if self.ssl == 1:
+        if self.ssl:
             from twisted.internet import ssl
             contextFactory = ssl.ClientContextFactory()
             reactor.connectSSL(self.server, self.port,
                                self.factory, contextFactory) 
+            log.msg('Using SSL...')
         else:
             reactor.connectTCP(self.server, self.port, self.factory)
@@ -510,8 +687,10 @@
         if not self.anonymous:
             log.msg('Connecting as authenticated worker...\n')
-            d = self.factory.login(self.creds, (pb.Referenceable(), self.host_info))
+            d = self.factory.login(self.creds, 
+                                   (pb.Referenceable(), self.host_info))
         else:
             log.msg('Connecting as anonymous worker...\n')
-            d = self.factory.login('Anonymous', (pb.Referenceable(), self.host_info))
+            d = self.factory.login('Anonymous', 
+                                   (pb.Referenceable(), self.host_info))
         d.addCallback(self._connected)
         d.addErrback(self._catchConnectionFailure)
@@ -524,92 +703,7 @@
         
         """
-        
+
         log.msg('[Monitor] Starting %s workers...' % (self.workers))
         self.worker_pool = [Worker(remoteobj, x) for x in range(self.workers)]
-    
-    def check_output(self):
-        """
-        check_output periodically polls workers for new output.
-        
-        This figures out whether or not there is anything new output that we
-        should submit to the server.
-        
-        """
-
-        if self.worker_pool == None:
-            return
-        
-        for worker in self.worker_pool:
-            if worker.job == None:
-                continue
-            if worker.free == True:
-                continue
-            
-            if self.log_level > 1:
-                log.msg('[Monitor] Checking for job output of worker %s' % (worker.id))
-            try:
-                done, output, new = worker.sage._so_far()
-            except Exception, msg:
-                log.err('Exception raised when checking output.')
-                log.err(msg)
-                continue
-            if new == '' or new.isspace():
-                continue
-            if done:
-                worker.free = True
-                sobj = worker.sage.get('DSAGE_RESULT')
-                timeout = 0.1
-                while sobj == '' or sobj.isspace():
-                    sobj = worker.sage.get('DSAGE_RESULT')
-                    time.sleep(timeout)
-                if 'NameError: name \'DSAGE_RESULT\' is not defined' in sobj:
-                    if self.log_level > 1:
-                        log.msg('DSAGE_RESULT does not exist')
-                    result = cPickle.dumps('No result saved.', 2)
-                else:
-                    try:
-                        os.chdir(worker.tmp_job_dir)
-                        worker.sage.eval("os.chdir('%s')" % (worker.tmp_job_dir))
-                        worker.sage.eval("save(DSAGE_RESULT, 'result', compress=True)")
-                        result = open('result.sobj', 'rb').read() # Already in compressed form.
-                    except Exception, msg:
-                        if self.log_level > 1:
-                            log.err(msg)
-                        result = cPickle.dumps(msg, 2)
-                log.msg("[Worker: %s] Job '%s' finished" % (worker.id, worker.job.job_id))
-            else:
-                result = cPickle.dumps('Job not done yet.', 2)
-                                       
-            sanitized_output = self.clean_output(new)
-            if self.check_failure(sanitized_output):
-                s = ['[Monitor] Error in result for ',
-                     '%s:%s ' % (worker.job.name, worker.job.job_id),
-                     'Worker ID:%s' % (worker.id)]
-                log.err(''.join(s))
-                log.err('[Monitor] Traceback: \n%s' % sanitized_output)
-                d = self.remoteobj.callRemote('job_failed', worker.job.job_id, sanitized_output)
-                d.addErrback(self._catch_failure)
-                worker.restart()
-                continue
-            d = worker.job_done(sanitized_output, result, done)
-            d.addErrback(self._catchConnectionFailure)
-    
-    def check_failure(self, sage_output):
-        """
-        Checks for signs of exceptions or errors in the output.
-        
-        """
-        
-        if sage_output == None:
-            return False
-        else:
-            sage_output = ''.join(sage_output)
-        
-        if 'Traceback' in sage_output:
-            return True
-        elif 'Error' in sage_output:
-            return True
-        else:
-            return False
     
     def check_killed_jobs(self):
@@ -625,27 +719,5 @@
         killed_jobs.addCallback(self._got_killed_jobs)
         killed_jobs.addErrback(self._catch_failure)
-    
-    def clean_output(self, sage_output):
-        """
-        clean_output attempts to clean up the output string from sage. 
-        
-        """
-        
-        begin = sage_output.find(START_MARKER)
-        if begin != -1:
-            begin += len(START_MARKER)
-        else:
-            begin = 0
-        end = sage_output.find(END_MARKER)
-        if end != -1:
-            end -= 1
-        else:
-            end = len(sage_output)
-        output = sage_output[begin:end]
-        output = output.strip()
-        output = output.replace('\r', '')
-        
-        return output
-    
+
     def start_looping_calls(self):
         """
@@ -653,7 +725,9 @@
         
         """
-        
-        self.tsk1 = task.LoopingCall(self.check_output)
-        self.tsk1.start(0.1, now=False)
+        # 
+        # self.check_output_timeout = 1
+        # self.tsk1 = task.LoopingCall(self.check_output)
+        # self.tsk1.start(self.check_output_timeout, now=False)
+        
         interval = 5.0
         self.tsk2 = task.LoopingCall(self.check_killed_jobs)
@@ -666,5 +740,5 @@
         """
         
-        self.tsk1.stop()
+        # self.tsk1.stop()
         self.tsk2.stop()
 
@@ -688,5 +762,5 @@
                 hostname = str(hostname)
             except Exception, msg:
-                print msg
+                log.err(msg)
                 hostname = None
     else:
@@ -705,3 +779,2 @@
 if __name__ == '__main__':
     main()
-
Index: sage/dsage/server/benchmark_job.py
===================================================================
--- sage/dsage/server/benchmark_job.py	(revision 4217)
+++ sage/dsage/server/benchmark_job.py	(revision 4217)
@@ -0,0 +1,40 @@
+##############################################################################
+#                                                                     
+#  DSAGE: Distributed SAGE                     
+#                                                                             
+#       Copyright (C) 2006, 2007 Yi Qiang <yqiang@gmail.com>               
+#                                                                            
+#  Distributed under the terms of the GNU General Public License (GPL)        
+#
+#    This code is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#    General Public License for more details.
+#
+#  The full text of the GPL is available at:
+#
+#                  http://www.gnu.org/licenses/
+#
+##############################################################################
+
+from sage.dsage.database.job import Job
+
+class BenchmarkJob(object):
+    """
+    This job is sent to workers as a way to benchmark their performance.
+    
+    """
+    
+    def __init__(self):
+        pass
+    
+    def get_job(self):
+        job = Job()
+        job.code = """import time
+start = time.time()
+os.system("openssl speed rsa1024")
+end = time.time()
+DSAGE_RESULT = end - start
+"""
+        
+        return job
Index: sage/dsage/server/server.py
===================================================================
--- sage/dsage/server/server.py	(revision 3895)
+++ sage/dsage/server/server.py	(revision 4353)
@@ -77,8 +77,9 @@
             return None
         else:
+            job_id = jdict['job_id']
             if self.LOG_LEVEL > 3:
-                log.msg('[DSage, get_job]' + ' Returning Job %s to client' % (jdict['job_id']))
+                log.msg('[DSage, get_job]' + ' Sending job %s' % job_id)
             jdict['status'] = 'processing'
-            jdict = self.jobdb.store_job(jdict)
+            self.jobdb.store_job(jdict)
             
         return jdict
@@ -98,5 +99,5 @@
         
         """
-
+        
         jdict = self.jobdb.get_job_by_id(job_id)
         uuid = jdict['monitor_id']
@@ -132,13 +133,5 @@
     def sync_job(self, job_id):
         raise NotImplementedError
-        # job = self.jobdb.get_job_by_id(job_id)
-        # new_job = copy.deepcopy(job)
-        # print new_job
-        # # Set file, data to 'Omitted' so we don't need to transfer it 
-        # new_job.code = 'Omitted...'
-        # new_job.data = 'Omitted...'
-
-        # return job.pickle()
-
+        
     def get_jobs_by_username(self, username, active=False):
         """
@@ -156,4 +149,5 @@
         if self.LOG_LEVEL > 3:
             log.msg(jobs)
+            
         return jobs
 
@@ -175,4 +169,5 @@
         if jdict['name'] is None:
             jdict['name'] = 'Default'
+            
         jdict['update_time'] = datetime.datetime.now()
         
@@ -203,7 +198,9 @@
         """
         Returns a list of killed job jdicts. 
+        
         """
         
         killed_jobs = self.jobdb.get_killed_jobs_list()
+        
         return killed_jobs
 
@@ -224,5 +221,5 @@
 
         Parameters:
-        job_id -- job id (str)
+        job_id -- job id (string)
         output -- the stdout from the worker (string)
         result -- the result from the client (compressed pickle string)
@@ -287,10 +284,14 @@
         if job_id == None:
             if self.LOG_LEVEL > 0:
-                log.msg('[DSage, kill_job] No such job id %s' % job_id)
+                log.msg('[DSage, kill_job] Invalid job id')
             return None
         else:
-            self.jobdb.set_killed(job_id, killed=True)
-            if self.LOG_LEVEL > 0:
-                log.msg('Killed job %s' % (job_id))
+            try:
+                self.jobdb.set_killed(job_id, killed=True)
+                if self.LOG_LEVEL > 0:
+                    log.msg('Killed job %s' % (job_id))
+            except Exception, msg:
+                log.err(msg)
+                log.msg('Failed to kill job %s' % job_id)
                 
         return job_id
@@ -305,4 +306,5 @@
 
         """
+        
         return self.monitordb.get_monitor_list()
     
@@ -340,6 +342,8 @@
         
         count = {}
-        free_workers = self.monitordb.get_worker_count(connected=True, busy=False)
-        working_workers = self.monitordb.get_worker_count(connected=True, busy=True)
+        free_workers = self.monitordb.get_worker_count(connected=True,
+                                                       busy=False)
+        working_workers = self.monitordb.get_worker_count(connected=True,
+                                                          busy=True)
         
         count['free'] = free_workers
@@ -449,5 +453,6 @@
             workingMegaHertz = doc.createElement('workingMegaHertz')
             gauge.appendChild(workingMegaHertz)
-            cpu_speed = self.monitordb.get_cpu_speed(connected=True, busy=True)
+            cpu_speed = self.monitordb.get_cpu_speed(connected=True,
+                                                     busy=True)
             mhz = doc.createTextNode(str(cpu_speed))
             workingMegaHertz.appendChild(mhz)
Index: sage/dsage/server/tests/test_server.py
===================================================================
--- sage/dsage/server/tests/test_server.py	(revision 3866)
+++ sage/dsage/server/tests/test_server.py	(revision 4353)
@@ -60,15 +60,14 @@
         job = Job()
         job.code = '2+2'
-        jdict = self.dsage_server.submit_job(job.reduce())
-        self.assertEquals(type(jdict['job_id']), str)
+        job_id = self.dsage_server.submit_job(job.reduce())
+        self.assertEquals(type(job_id), str)
+        self.assertEquals(len(job_id), 10)
 
     def testget_job_result_by_id(self):
-        job = self.create_jobs(1)[0]
         job = expand_job(self.dsage_server.get_job())
         job.result = 'test'
-        jdict = self.dsage_server.submit_job(job.reduce())
-        self.assertEquals(
-                    self.dsage_server.get_job_result_by_id(jdict['job_id']),
-                    'test')
+        job_id = self.dsage_server.submit_job(job.reduce())
+        result = self.dsage_server.get_job_result_by_id(job_id)
+        self.assertEquals(result, 'test')
 
     def testget_jobs_by_username(self):
@@ -84,5 +83,6 @@
         job.code = ''
         jdict = self.dsage_server.submit_job(job.reduce())
-        j = expand_job(self.dsage_server.get_jobs_by_username('testing123')[0])
+        j = expand_job(
+                self.dsage_server.get_jobs_by_username('testing123')[0])
         self.assertEquals(j.username, job.username)
 
@@ -90,7 +90,7 @@
         jobs = self.create_jobs(10)
         for job in jobs:
-            jdict = self.dsage_server.submit_job(job.reduce())
-            self.assertEquals(type(jdict), dict)
-            j = expand_job(self.dsage_server.get_job_by_id(jdict['job_id']))
+            job_id = self.dsage_server.submit_job(job.reduce())
+            self.assertEquals(type(job_id), str)
+            j = expand_job(self.dsage_server.get_job_by_id(job_id))
             self.assert_(isinstance(j, Job))
 
@@ -142,6 +142,7 @@
         output = 'done '
         completed = True
-        jdict = self.dsage_server.job_done(job.job_id, output, result, completed)
-        job = expand_job(self.dsage_server.get_job_by_id(jdict['job_id']))
+        job_id = self.dsage_server.job_done(job.job_id, 
+                                            output, result, completed)
+        job = expand_job(self.dsage_server.get_job_by_id(job_id))
         self.assertEquals(job.output, output)
         self.assertEquals(job.result, result)
@@ -152,6 +153,7 @@
         output = 'testing'
         completed = False
-        jdict = self.dsage_server.job_done(job.job_id, output, result, completed)
-        job = expand_job(self.dsage_server.get_job_by_id(jdict['job_id']))
+        job_id = self.dsage_server.job_done(job.job_id, output, result,
+                                            completed)
+        job = expand_job(self.dsage_server.get_job_by_id(job_id))
         self.assert_(isinstance(job.output, str))
         self.assert_(job.status != 'completed')
Index: sage/dsage/twisted/pb.py
===================================================================
--- sage/dsage/twisted/pb.py	(revision 3895)
+++ sage/dsage/twisted/pb.py	(revision 4244)
@@ -129,5 +129,5 @@
 class DefaultPerspective(pb.Avatar):
     """
-    Custom implementation of pb.Avatar so we can keep track of the broker. 
+    Custom implementation of pb.Avatar.
     
     """
@@ -137,7 +137,5 @@
         self.avatarID = avatarID
         self.connections = 0
-        
-        log.msg('%s connected' % self.avatarID)
-        
+                
     def perspectiveMessageReceived(self, broker, message, args, kw):
         self.broker = broker
@@ -159,5 +157,6 @@
         else:
             self.DSageServer.clientdb.update_login_time(self.avatarID)
-            self.DSageServer.clientdb.set_connected(self.avatarID, connected=True)
+            self.DSageServer.clientdb.set_connected(self.avatarID,
+                                                    connected=True)
 
     def detached(self, avatar, mind):
@@ -165,7 +164,9 @@
         log.msg('%s disconnected' % (self.avatarID))
         if isinstance(mind, tuple):
-            self.DSageServer.monitordb.set_connected(self.host_info['uuid'], connected=False)
-        else:
-            self.DSageServer.clientdb.set_connected(self.avatarID, connected=False)
+            self.DSageServer.monitordb.set_connected(self.host_info['uuid'],
+                                                     connected=False)
+        else:
+            self.DSageServer.clientdb.set_connected(self.avatarID,
+                                                    connected=False)
             
 class AnonymousMonitorPerspective(DefaultPerspective):
@@ -193,5 +194,6 @@
         self.connections -= 1
         log.msg('%s disconnected' % (self.avatarID))
-        self.DSageServer.monitordb.set_connected(self.host_info['uuid'], connected=False)
+        self.DSageServer.monitordb.set_connected(self.host_info['uuid'],
+                                                 connected=False)
             
     def perspective_get_job(self):
@@ -217,5 +219,5 @@
     def perspective_job_failed(self, job_id, traceback):
         if not isinstance(job_id, str):
-            log.msg('Bad job_id [%s] passed to perspective_job_failed' % (job_id))
+            log.msg('Bad job_id %s' % (job_id))
             raise BadTypeError()
 
@@ -241,4 +243,5 @@
         if not isinstance(hostinfo, dict):
             raise BadTypeError()
+            
         return self.DSageServer.submit_host_info(hostinfo)
 
@@ -269,5 +272,9 @@
         """
         
-        uuid = self.mind[1]['uuid']
+        try:
+            uuid = self.mind[1]['uuid']
+        except Exception, msg:
+            raise ValueError("Could not match a uuid to the monitor.")
+        
         jdict = self.DSageServer.get_job(anonymous=False)
         if jdict is not None:
@@ -378,17 +385,39 @@
     def __init__(self, DSageServer):
         self.DSageServer = DSageServer
-
+        self.avatars = {}
+        self.max_connections = 100
+        
     def requestAvatar(self, avatarID, mind, *interfaces):        
         if not pb.IPerspective in interfaces:
-            raise NotImplementedError, "No supported avatar interface."
+            raise NotImplementedError("No supported avatar interface.")
         else:
             if avatarID == 'admin':
-                avatar = AdminPerspective(self.DSageServer, avatarID)
+                kind = 'admin'
             elif avatarID == 'Anonymous' and mind:
-                avatar = AnonymousMonitorPerspective(self.DSageServer, avatarID)
+                kind = 'anonymous_monitor'
             elif mind:
-                avatar = MonitorPerspective(self.DSageServer, avatarID)
+                kind = 'monitor'
             else:
-                avatar = UserPerspective(self.DSageServer, avatarID)
+                kind = 'client'
+                
+            if (avatarID, kind) in self.avatars.keys():
+                avatar = self.avatars[(avatarID, kind)]
+            else:
+                if kind == 'admin':
+                    avatar = AdminPerspective(self.DSageServer, avatarID)
+                elif kind == 'anonymous_monitor':
+                    avatar = AnonymousMonitorPerspective(self.DSageServer,
+                                                         avatarID)
+                elif kind == 'monitor':
+                    avatar = MonitorPerspective(self.DSageServer, avatarID)
+                elif kind == 'client':
+                    avatar = UserPerspective(self.DSageServer, avatarID)
+                self.avatars[(avatarID, kind)] = avatar
+        if avatar.connections >= self.max_connections:
+            raise ValueError('Too many connections for user %s' % avatarID)
+        
         avatar.attached(avatar, mind)
-        return pb.IPerspective, avatar, lambda a=avatar:a.detached(avatar, mind)
+        log.msg('(%s, %s) connected' % (avatarID, kind))
+    
+        return pb.IPerspective, avatar, lambda a=avatar:a.detached(avatar,
+                                                                   mind)
Index: sage/dsage/twisted/pubkeyauth.py
===================================================================
--- sage/dsage/twisted/pubkeyauth.py	(revision 3898)
+++ sage/dsage/twisted/pubkeyauth.py	(revision 4353)
@@ -26,9 +26,19 @@
 from twisted.internet import defer
 from twisted.python import log
-from twisted.spread import pb
 
-from sage.dsage.database.clientdb import ClientDatabase
 from sage.dsage.errors.exceptions import AuthenticationError
 
+def get_pubkey_string(filename=None):
+    try:
+        f = open(filename)
+        type_, key = f.readlines()[0].split()[:2]
+        f.close()
+        if not type_ == 'ssh-rsa':
+            raise TypeError('Invalid key type.')
+    except IOError, msg:
+        key = pubkey_file
+    
+    return key
+    
 class PublicKeyCredentialsChecker(object):
     """
@@ -86,4 +96,5 @@
     
     def __init__(self, clientdb):
+        from sage.dsage.database.clientdb import ClientDatabase
         if not isinstance(clientdb, ClientDatabase):
             raise TypeError
Index: sage/dsage/twisted/tests/test_pubkeyauth.py
===================================================================
--- sage/dsage/twisted/tests/test_pubkeyauth.py	(revision 3905)
+++ sage/dsage/twisted/tests/test_pubkeyauth.py	(revision 4351)
@@ -20,4 +20,5 @@
 import os
 import random
+import base64
 from glob import glob 
 
@@ -39,30 +40,38 @@
 
 DSAGE_DIR = os.path.join(os.getenv('DOT_SAGE'), 'dsage')
-# Begin reading configuration
-try:
-    conf_file = os.path.join(DSAGE_DIR, 'server.conf')
-    config = ConfigParser.ConfigParser()
-    config.read(conf_file)
 
-    LOG_FILE = config.get('server_log', 'log_file')
-    SSL = config.getint('ssl', 'ssl')
-    CLIENT_PORT = config.getint('server', 'client_port')
-    PUBKEY_DATABASE = os.path.expanduser(config.get('auth',
-                                                    'pubkey_database'))
+TEST_PUB_KEY = """ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAusOUk3wZof9orc7YuKZP/wxog2uAU5BsagK4lkHgdfBc+ZR3s+Rk+k6prvuNuUXIfn2A+UkPa0xmjtQnMlqClrZXXMHhDV8iXto/vM1BopF+Ja1Y+pCK2vRRZVsZsdzL7XqyVc+kstsgKWrrguNCMIuEyc37wcsgdd1PxPmuB8Mwm3YZmNRV6yEq8Qq3IprZHfBl5S6htmwTXt4VEzvJgX1PJBLg4BauJtLxeEzYgMLY4VG3buJ2VDwlqwVPO/oVZwK3uXifXtxVx6VJO4pKUBdDSyjudPQTHxogos+8scaClx0XMh0eM7xw92j4SpA+mtzXnAKM4CqCSFH3w+/LbQ== yqiang@six
+"""
 
-    conf_file = os.path.join(DSAGE_DIR, 'client.conf')
-    config = ConfigParser.ConfigParser()
-    config.read(conf_file)
+TEST_PRIV_KEY = """-----BEGIN RSA PRIVATE KEY-----
+MIIEoQIBAAKCAQEAusOUk3wZof9orc7YuKZP/wxog2uAU5BsagK4lkHgdfBc+ZR3
+s+Rk+k6prvuNuUXIfn2A+UkPa0xmjtQnMlqClrZXXMHhDV8iXto/vM1BopF+Ja1Y
++pCK2vRRZVsZsdzL7XqyVc+kstsgKWrrguNCMIuEyc37wcsgdd1PxPmuB8Mwm3YZ
+mNRV6yEq8Qq3IprZHfBl5S6htmwTXt4VEzvJgX1PJBLg4BauJtLxeEzYgMLY4VG3
+buJ2VDwlqwVPO/oVZwK3uXifXtxVx6VJO4pKUBdDSyjudPQTHxogos+8scaClx0X
+Mh0eM7xw92j4SpA+mtzXnAKM4CqCSFH3w+/LbQIBIwKCAQBFXpZFaJvOdM8b/F8g
+A0JIyhgw0ChZjWoYvy6eNbnFZ+gE7gCTRjQidP0yXW8njvKyo6Tu4J9TvUqqFEkS
+s+dcjN6ey6tcvO+CURBcEblLAtcVTwPKx/kPf1FuyhDbqcgWYMXlW8DUt8oeAyRG
+juyy8f4fEf5sjUaSLaFJKYnIXc4UNTiBckcM0ffk+achcuikZKtoJ7scJVHRzS//
+cz2Y/L7ma/JOASDbybwIvnZ+C+iiOrDSwCgqBWw0R48p80W3kqrPjzxMOEVtI5ON
+epaM+MqWWMvpjoMBWC0ZpGl35QOLfjFjFUXzdWENfWuyjE7a6iu3S5MOBk8E21zD
+OV1LAoGBAO7Df7zVUXTBNunIOlxu1fqkkAXrPUWSr9hod/kiCDM5Gtjn1519xYM7
+IYtA6lipIVLVTPZlbTUd/QGxDXLloG/Ll7f0aQXz24PyF4TsVxp0cNURrsViaYEb
+QCmqFqCd5fkrPGy5Qi11S+cgco2u2h6ZoyHEc4VxvMml+fv/JeG9AoGBAMg/GE56
+sau4oUNKMDZGBac07uFD/IvERA/o7ul8hyuFHHRGBPIaJr7DVzDkxC0h0DscK6nl
+vq2xa54yI4JH3mAPpQyCjfcT8yqcBpmDhq44udaksno7RfY7Twdk6sUMKTEbtEzk
+PzRqDSIVGuYxKK4p/lPWYRkNl9AyzlDK4LNxAoGBAIGdU/jLkp53hDXEd3QBp1wt
+csFicbgNzSxV9/xFrK4Xr30QJJdS55Bh7aNdwQuPA3YcBTVNAMUQR4STUHGSmOw7
+UlyL/n+TAiMOZIn8pFAwlQXzqATAZSjUR2cTMNrZX5XkRV+XxNbZRnYnjqSvYHcC
+8ihGEtNpoP/AgGQ6DUAHAoGAESn6xOXx+MauvJ/1gP6wBwSJgQXT0Xc5CK2Q0i8+
+yTdLlPAPDW/0sUPxh9kYISAnyo1i1AxgzQ81HDAu7ejnLM4kFwPgSGDLszHx7+az
+xcpZEmXjaZANT56vAKJAAkLe9ZSpDeetpWgtAuvdu/WVxckVzKv5sbC1Pbs2QXB5
+qPsCgYA1GcxkJk70lyMX9W1eZ97jorqeo1+wN0IM0dAtKhB+3OCLQXEaAibtlUDL
+vfFTV+I4/tOelzdrADsjxugr1RMbfBqocfaI3xJpjwNXNtqgJk8u50aFz0SlJu6y
+4tizRIkoVlcZYqs9qtxEzHKryAecM8EcumKBJEJZdtdCV0O6vw==
+-----END RSA PRIVATE KEY-----
+"""
 
-    LOG_FILE = config.get('log', 'log_file')
-    SSL = config.getint('ssl', 'ssl')
-    USERNAME = config.get('auth', 'username')
-    PRIVKEY_FILE = os.path.expanduser(config.get('auth', 'privkey_file'))
-    PUBKEY_FILE = os.path.expanduser(config.get('auth', 'pubkey_file'))
-except:
-    raise 
-# End reading configuration
-
-Data =  ''.join([chr(i) for i in [random.randint(65, 123) for n in
+RANDOM_DATA =  ''.join([chr(i) for i in [random.randint(65, 123) for n in
                 range(500)]])
 
@@ -87,13 +96,14 @@
 
         # public key authentication information
-        self.username = USERNAME
-        self.pubkey_file = PUBKEY_FILE
-        self.privkey_file = PRIVKEY_FILE
-        self.public_key_string = keys.getPublicKeyString(filename=self.pubkey_file)
-        self.private_key = keys.getPrivateKeyObject(filename=self.privkey_file)
-        self.public_key = keys.getPublicKeyObject(self.public_key_string)
+        self.username = 'unit_test'
+        self.pubkey_file = TEST_PUB_KEY
+        self.privkey_file = TEST_PRIV_KEY
+        self.data = RANDOM_DATA
+        self.public_key_str = keys.getPublicKeyString(data=TEST_PUB_KEY)
+        self.private_key = keys.getPrivateKeyObject(
+                            data=TEST_PRIV_KEY)
+        self.public_key = keys.getPublicKeyObject(self.public_key_str)
         self.alg_name = 'rsa'
         self.blob = keys.makePublicKeyBlob(self.public_key)
-        self.data = Data
         self.signature = keys.signData(self.private_key, self.data)
         self.creds = credentials.SSHPrivateKey(self.username,
@@ -102,9 +112,6 @@
                                                self.data,
                                                self.signature)
-        c = ConfigParser.ConfigParser()
-        c.read(os.path.join(DSAGE_DIR, 'client.conf'))
-        username = c.get('auth', 'username')
-        pubkey_file = c.get('auth', 'pubkey_file')
-        self.clientdb.add_user(username, pubkey_file)
+        pubkey = base64.encodestring(self.public_key_str).strip()       
+        self.clientdb.add_user(self.username, pubkey)
         
     def tearDown(self):
@@ -118,6 +125,6 @@
     def testLogin(self):
         factory = PBClientFactory()
-        self.connection = reactor.connectTCP(self.hostname, self.port, factory)
-
+        self.connection = reactor.connectTCP(self.hostname, self.port,
+                                             factory)
         d = factory.login(self.creds, None)
         d.addCallback(self._LoginConnected)
@@ -130,8 +137,11 @@
     def testBadLogin(self):
         factory = PBClientFactory()
-        self.connection = reactor.connectTCP(self.hostname, self.port, factory)
+        self.connection = reactor.connectTCP(self.hostname, 
+                                             self.port,
+                                             factory)
 
         d = factory.login(None, None)
-        d.addErrback(lambda f: self.assertEquals(TypeError, f.check(TypeError)))
+        d.addErrback(lambda f: self.assertEquals(TypeError,
+                                                 f.check(TypeError)))
 
         return d
@@ -139,6 +149,8 @@
     def testBadLogin2(self):
         factory = PBClientFactory()
-        self.connection = reactor.connectTCP(self.hostname, self.port, factory)
-        bad_creds = credentials.SSHPrivateKey('this user name should not exit',
+        self.connection = reactor.connectTCP(self.hostname, 
+                                             self.port, 
+                                            factory)
+        bad_creds = credentials.SSHPrivateKey('bad username',
                                                self.alg_name,
                                                self.blob, 
@@ -147,4 +159,5 @@
         d = factory.login(bad_creds, None)
         d.addErrback(self._BadLoginFailure)
+        
         return d
     
@@ -154,5 +167,7 @@
     def testBadLogin3(self):
         factory = PBClientFactory()
-        self.connection = reactor.connectTCP(self.hostname, self.port, factory)
+        self.connection = reactor.connectTCP(self.hostname, 
+                                             self.port, 
+                                             factory)
         bad_creds = credentials.SSHPrivateKey(self.username,
                                               self.alg_name,
Index: sage/dsage/twisted/tests/test_remote.py
===================================================================
--- sage/dsage/twisted/tests/test_remote.py	(revision 3905)
+++ sage/dsage/twisted/tests/test_remote.py	(revision 4351)
@@ -24,4 +24,5 @@
 import zlib
 import uuid
+import base64
 
 from twisted.trial import unittest
@@ -43,47 +44,14 @@
 from sage.dsage.errors.exceptions import BadJobError
 from sage.dsage.misc.hostinfo import ClassicHostInfo
+from sage.dsage.twisted.tests.test_pubkeyauth import TEST_PUB_KEY
+from sage.dsage.twisted.tests.test_pubkeyauth import TEST_PRIV_KEY
 
 DSAGE_DIR = os.path.join(os.getenv('DOT_SAGE'), 'dsage')
-# Begin reading configuration
-try:
-    conf_file = os.path.join(DSAGE_DIR, 'server.conf')
-    config = ConfigParser.ConfigParser()
-    config.read(conf_file)
-
-    LOG_FILE = config.get('server_log', 'log_file')
-    SSL = config.getint('ssl', 'ssl')
-    CLIENT_PORT = config.getint('server', 'client_port')
-    PUBKEY_DATABASE = os.path.expanduser(config.get('auth', 'pubkey_database'))
-
-    conf_file = os.path.join(DSAGE_DIR, 'client.conf')
-    config = ConfigParser.ConfigParser()
-    config.read(conf_file)
-
-    LOG_FILE = config.get('log', 'log_file')
-    SSL = config.getint('ssl', 'ssl')
-    USERNAME = config.get('auth', 'username')
-    PRIVKEY_FILE = os.path.expanduser(config.get('auth', 'privkey_file'))
-    PUBKEY_FILE = os.path.expanduser(config.get('auth', 'pubkey_file'))
-    
-    conf_file = os.path.join(DSAGE_DIR, 'worker.conf')
-    config = ConfigParser.ConfigParser()
-    config.read(conf_file)
-    if len(config.get('uuid', 'id')) != 36:
-        config.set('uuid', 'id', str(uuid.uuid1()))
-        f = open(conf_file, 'w')
-        config.write(f)
-    UUID = config.get('uuid', 'id')
-    WORKERS = config.getint('general', 'workers')
-    
-except Exception, msg:
-    log.msg(msg)
-    raise 
-# End reading configuration
 hf = ClassicHostInfo().host_info
-hf['uuid'] = UUID
-hf['workers'] = WORKERS
-
-Data =  ''.join([chr(i) for i in [random.randint(65, 123) for n in
-                range(500)]])
+hf['uuid'] = ''
+hf['workers'] = 2
+
+RANDOM_DATA =  ''.join([chr(i) for i in [random.randint(65, 123) for n in
+                       range(500)]])
 
 class ClientRemoteCallsTest(unittest.TestCase):
@@ -107,5 +75,6 @@
         self.p = _SSHKeyPortalRoot(portal.Portal(self.realm))
         self.clientdb = ClientDatabase(test=True)
-        self.p.portal.registerChecker(PublicKeyCredentialsCheckerDB(self.clientdb))
+        self.p.portal.registerChecker(
+                            PublicKeyCredentialsCheckerDB(self.clientdb))
         self.client_factory = pb.PBServerFactory(self.p)
         self.hostname = 'localhost'
@@ -114,13 +83,14 @@
         
         # public key authentication information
-        self.username = USERNAME
-        self.pubkey_file = PUBKEY_FILE
-        self.privkey_file = PRIVKEY_FILE
-        self.public_key_string = keys.getPublicKeyString(filename=self.pubkey_file)
-        self.private_key = keys.getPrivateKeyObject(filename=self.privkey_file)
-        self.public_key = keys.getPublicKeyObject(self.public_key_string)
+        self.username = 'unit_test'
+        self.pubkey_file = TEST_PUB_KEY
+        self.privkey_file = TEST_PRIV_KEY
+        self.data = RANDOM_DATA
+        self.public_key_str = keys.getPublicKeyString(data=TEST_PUB_KEY)
+        self.private_key = keys.getPrivateKeyObject(
+                            data=TEST_PRIV_KEY)
+        self.public_key = keys.getPublicKeyObject(self.public_key_str)
         self.alg_name = 'rsa'
         self.blob = keys.makePublicKeyBlob(self.public_key)
-        self.data = Data
         self.signature = keys.signData(self.private_key, self.data)
         self.creds = credentials.SSHPrivateKey(self.username,
@@ -129,9 +99,6 @@
                                                self.data,
                                                self.signature)
-        c = ConfigParser.ConfigParser()
-        c.read(os.path.join(DSAGE_DIR, 'client.conf'))
-        username = c.get('auth', 'username')
-        pubkey_file = c.get('auth', 'pubkey_file')
-        self.clientdb.add_user(username, pubkey_file)
+        pubkey = base64.encodestring(self.public_key_str).strip()       
+        self.clientdb.add_user(self.username, pubkey)
         
     def tearDown(self):
@@ -164,10 +131,9 @@
         job.code = "2+2"
         d = remoteobj.callRemote('submit_job', job.reduce())
-        d.addCallback(self._got_jdict)
-        return d
-
-    def _got_jdict(self, jdict):
-        self.assertEquals(type(jdict), dict)
-        self.assertEquals(type(jdict['job_id']), str)
+        d.addCallback(self._got_job_id)
+        return d
+
+    def _got_job_id(self, job_id):
+        self.assertEquals(type(job_id), str)
 
     def testremoteSubmitBadJob(self):
@@ -222,15 +188,16 @@
         self.server = reactor.listenTCP(0, self.client_factory)
         self.port = self.server.getHost().port
+
         # public key authentication information
-        self.username = USERNAME
-        self.pubkey_file = PUBKEY_FILE
-        self.privkey_file = PRIVKEY_FILE
-        self.public_key_string = keys.getPublicKeyString(
-                                 filename=self.pubkey_file)
-        self.private_key = keys.getPrivateKeyObject(filename=self.privkey_file)
-        self.public_key = keys.getPublicKeyObject(self.public_key_string)
+        self.username = 'unit_test'
+        self.pubkey_file = TEST_PUB_KEY
+        self.privkey_file = TEST_PRIV_KEY
+        self.data = RANDOM_DATA
+        self.public_key_str = keys.getPublicKeyString(data=TEST_PUB_KEY)
+        self.private_key = keys.getPrivateKeyObject(
+                            data=TEST_PRIV_KEY)
+        self.public_key = keys.getPublicKeyObject(self.public_key_str)
         self.alg_name = 'rsa'
         self.blob = keys.makePublicKeyBlob(self.public_key)
-        self.data = Data
         self.signature = keys.signData(self.private_key, self.data)
         self.creds = credentials.SSHPrivateKey(self.username,
@@ -239,9 +206,6 @@
                                                self.data,
                                                self.signature)
-        c = ConfigParser.ConfigParser()
-        c.read(os.path.join(DSAGE_DIR, 'client.conf'))
-        username = c.get('auth', 'username')
-        pubkey_file = c.get('auth', 'pubkey_file')
-        self.clientdb.add_user(username, pubkey_file)  
+        pubkey = base64.encodestring(self.public_key_str).strip()       
+        self.clientdb.add_user(self.username, pubkey)
         
     def tearDown(self):
@@ -287,5 +251,6 @@
         job = Job()
         job.code = "2+2"
-        jdict = self.dsage_server.submit_job(job.reduce())
+        job_id = self.dsage_server.submit_job(job.reduce())
+        jdict = self.dsage_server.get_job_by_id(job_id)
         d.addCallback(self._logged_in)
         d.addCallback(self._job_done, jdict)
@@ -296,11 +261,13 @@
         job_id = jdict['job_id']
         result = jdict['result']
-        d = remoteobj.callRemote('job_done', job_id, 'Nothing.', result, False)
+        d = remoteobj.callRemote('job_done', job_id, 
+                                 'Nothing.', result, False)
         d.addCallback(self._done_job)
         
         return d
     
-    def _done_job(self, jdict):
-        self.assertEquals(type(jdict), dict)
+    def _done_job(self, job_id):
+        self.assertEquals(type(job_id), str)
+        jdict = self.dsage_server.get_job_by_id(job_id)
         self.assertEquals(jdict['status'], 'new')
         self.assertEquals(jdict['output'], 'Nothing.')
@@ -313,5 +280,6 @@
         job = Job()
         job.code = "2+2"
-        jdict = self.dsage_server.submit_job(job.reduce())
+        job_id = self.dsage_server.submit_job(job.reduce())
+        jdict = self.dsage_server.get_job_by_id(job_id)
         d = factory.login(self.creds, (pb.Referenceable(), hf))
         d.addCallback(self._logged_in)
@@ -326,6 +294,7 @@
         return d
         
-    def _failed_job(self, jdict):
-        self.assertEquals(type(jdict), dict) 
+    def _failed_job(self, job_id):
+        self.assertEquals(type(job_id), str) 
+        jdict = self.dsage_server.get_job_by_id(job_id)
         self.assertEquals(jdict['failures'], 1)
         self.assertEquals(jdict['output'], 'Failure')
@@ -340,5 +309,6 @@
         job.code = "2+2"
         job.killed = True
-        jdict = self.dsage_server.submit_job(job.reduce())
+        job_id = self.dsage_server.submit_job(job.reduce())
+        jdict = self.dsage_server.get_job_by_id(job_id)
         d = factory.login(self.creds, (pb.Referenceable(), hf))
         d.addCallback(self._logged_in)
Index: sage/ext/cdefs.pxi
===================================================================
--- sage/ext/cdefs.pxi	(revision 3922)
+++ sage/ext/cdefs.pxi	(revision 4171)
@@ -43,4 +43,5 @@
     void mpz_abs (mpz_t rop, mpz_t op)
     void mpz_add (mpz_t rop, mpz_t op1, mpz_t op2)
+    void mpz_add_ui (mpz_t rop, mpz_t op1, unsigned long int op2)
     void mpz_addmul (mpz_t rop, mpz_t op1, mpz_t op2)
     void mpz_and (mpz_t rop, mpz_t op1, mpz_t op2)
@@ -48,4 +49,5 @@
     void mpz_clear(mpz_t integer)
     int  mpz_cmp(mpz_t op1, mpz_t op2)
+    int  mpz_cmpabs(mpz_t op1, mpz_t op2)
     int  mpz_cmp_si(mpz_t op1, signed long int op2)
     int  mpz_cmp_ui(mpz_t op1, unsigned long int op2)
@@ -62,4 +64,5 @@
     void mpz_tdiv_qr (mpz_t q, mpz_t r, mpz_t n, mpz_t d)
     double mpz_get_d (mpz_t op)
+    double mpz_get_d_2exp (long int *exp, mpz_t op)
     unsigned long int mpz_fdiv_ui (mpz_t n, unsigned long int d)
     unsigned long int mpz_fdiv_q_ui(mpz_t q, mpz_t n, unsigned long int d)    
@@ -91,6 +94,8 @@
     void mpz_set_ui(mpz_t integer, unsigned long int n)   
     int  mpz_set_str(mpz_t rop, char *str, int base)
+    int  mpz_set_d(mpz_t rop, double d)
     int  mpz_sgn(mpz_t op)
     void mpz_sqrt (mpz_t rop, mpz_t op) 
+    void mpz_sqrtrem (mpz_t rop, mpz_t rem, mpz_t op)
     void mpz_sub (mpz_t rop, mpz_t op1, mpz_t op2)
     void mpz_sub_ui(mpz_t rop, mpz_t op1, unsigned long int op2) 
Index: sage/ext/interactive_constructors_c.pyx
===================================================================
--- sage/ext/interactive_constructors_c.pyx	(revision 1854)
+++ sage/ext/interactive_constructors_c.pyx	(revision 4077)
@@ -34,13 +34,11 @@
         sage: GF(9,'c')
         Finite Field in c of size 3^2
-        sage: c
-        Traceback (most recent call last):
-        ...
-        NameError: name 'c' is not defined
+        sage: c^3
+		c^3
         sage: inject_on(verbose=False)
         sage: GF(9,'c')
         Finite Field in c of size 3^2
-        sage: c
-        c    
+        sage: c^3
+		2*c + 1
 
     ROLL YOUR OWN: If a constructor you would like to auto inject
@@ -196,5 +194,5 @@
         sage: S = quo(R, (x^3, x^2 + y^2), 'a,b')
         sage: S
-        Quotient of Polynomial Ring in x, y over Rational Field by the ideal (y^2 + x^2, x^3)
+        Quotient of Polynomial Ring in x, y over Rational Field by the ideal (x^3, y^2 + x^2)
         sage: a^2
         -1*b^2
Index: sage/functions/all.py
===================================================================
--- sage/functions/all.py	(revision 2106)
+++ sage/functions/all.py	(revision 4270)
@@ -1,4 +1,6 @@
 
 from piecewise import Piecewise
+
+piecewise = Piecewise
 
 from transcendental import (exponential_integral_1,
@@ -6,5 +8,4 @@
                             zeta, zeta_symmetric)
 
-# This is too terrible code.
 #from elementary import (cosine, sine, exponential,
 #                        ElementaryFunction,
@@ -12,10 +13,9 @@
 
 from special    import (bessel_I, bessel_J, bessel_K, bessel_Y,
-                        hypergeometric_U, incomplete_gamma,
+                        hypergeometric_U,
                         spherical_bessel_J, spherical_bessel_Y,
                         spherical_hankel1, spherical_hankel2,
                         spherical_harmonic, jacobi,
-                        inverse_jacobi, sinh, cosh,
-                        tanh, coth, sech, csch, dilog,
+                        inverse_jacobi, dilog,
                         lngamma, exp_int, error_fcn)
                         
@@ -36,4 +36,6 @@
 
 from constants import (pi, e, NaN, golden_ratio, log2, euler_gamma, catalan,
-                       khinchin, twinprime, merten, brun)
+                       khinchin, twinprime, merten, brun, I)
 
+i = I  # alias
+
Index: sage/functions/constants.py
===================================================================
--- sage/functions/constants.py	(revision 3290)
+++ sage/functions/constants.py	(revision 4316)
@@ -19,7 +19,13 @@
     euler_gamma
     sage: catalan       # the Catalon constant
-    K
+    catalan
     sage: khinchin      # Khinchin's constant
     khinchin
+    sage: twinprime
+    twinprime
+    sage: merten
+    merten
+    sage: brun
+    brun
 
 Support for coercion into the various systems means that if, e.g.,
@@ -54,13 +60,13 @@
 can be coerced into other systems or evaluated.
     sage: a = pi + e*4/5; a
-    (pi + ((e*4)/5))
+    pi + 4*e/5
     sage: maxima(a)
-    %pi + 4*%e/5
-    sage: a.str(15)      # 15 *bits* of precision
-    '5.316'
-    sage: gp(a)
-    5.316218116357029426750873360            # 32-bit
-    5.3162181163570294267508733603616328824  # 64-bit
-    sage: mathematica(a)                     # optional
+    %pi+4*%e/5
+    sage: RealField(15)(a)           # 15 *bits* of precision
+    5.316
+    sage: gp(a)             
+    5.316218116357029426750873360              # 32-bit
+    5.3162181163570294267508733603616328824    # 64-bit
+    sage: print mathematica(a)                     # optional
      4 E
      --- + Pi
@@ -102,12 +108,16 @@
 
 EXAMPLES: Arithmetic with constants
+    sage: f = I*(e+1); f
+    (e + 1)*I
+    sage: f^2
+    -(e + 1)^2
 
     sage: pp = pi+pi; pp
-    (pi + pi)
+    2*pi
     sage: R(pp)
     6.2831853071795864769252867665590057683943387987502116419499
     
-    sage: s = (1 + e^pi);s
-    (1 + (e^pi))
+    sage: s = (1 + e^pi); s
+    e^pi + 1
     sage: R(s)
     24.140692632779269005729086367948547380266106242600211993445
@@ -115,6 +125,6 @@
     23.140692632779269005729086367948547380266106242600211993445
 
-    sage: l = (1-log2)/(1+log2);l
-    ((1 - log2)/(1 + log2))
+    sage: l = (1-log2)/(1+log2); l
+    (1 - log(2))/(log(2) + 1)
     sage: R(l)
     0.18123221829928249948761381864650311423330609774776013488056
@@ -132,4 +142,60 @@
     -- William Stein
     -- Alex Clemesha \& William Stein (2006-02-20): added new constants; removed todos
+    -- didier deshommes <dfdeshom@gmail.com> (2007-03-27): added constants from RQDF
+
+TESTS:
+    Coercion of each constant to the RQDF:
+        sage: RQDF(e)
+        2.718281828459045235360287471352662497757247093699959574966967630
+        sage: RQDF(pi)
+        3.141592653589793238462643383279502884197169399375105820974944590
+        sage: RQDF(e)
+        2.718281828459045235360287471352662497757247093699959574966967630
+        sage: RQDF(I)
+        Traceback (most recent call last):
+        ...
+        TypeError
+        sage: RQDF(golden_ratio)
+        1.618033988749894848204586834365638117720309179805762862135448620
+        sage: RQDF(log2)
+        0.693147180559945309417232121458176568075500134360255254120680009
+        sage: RQDF(euler_gamma)
+        0.577215664901532860606512090082402431042159335939923598805767234
+        sage: RQDF(catalan)
+        0.915965594177219015054603514932384110774149374281672134266498119
+        sage: RQDF(khinchin)
+        2.685452001065306445309714835481795693820382293994462953051152345
+        sage: RQDF(twinprime)
+        0.660161815846869573927812110014555778432623360284733413319448422
+        sage: RQDF(merten)
+        0.261497212847642783755426838608695859051566648261199206192064212
+        sage: RQDF(brun)
+        Traceback (most recent call last):
+        ...
+        TypeError: Brun's constant only available up to 41 bits
+
+
+Coercing the sum of a bunch of the constants to many different floating point rings:
+
+    sage: a = pi + e + golden_ratio + log2 + euler_gamma + catalan + khinchin + twinprime + merten; a
+    twinprime + merten + khinchin + euler_gamma + catalan + log(2) + pi + e + (sqrt(5) + 1)/2
+    sage: parent(a)
+    Symbolic Ring
+    sage: RQDF(a)
+    13.27134794019724931009881919957581394087110682000307481783297119
+    sage: RR(a)
+    13.2713479401972
+    sage: RealField(212)(a)
+    13.2713479401972493100988191995758139408711068200030748178329712
+    sage: RealField(230)(a)
+    13.271347940197249310098819199575813940871106820003074817832971189555
+    sage: CC(a)
+    13.2713479401972
+    sage: CDF(a)
+    13.2713479402
+    sage: ComplexField(230)(a)
+    13.271347940197249310098819199575813940871106820003074817832971189555
+    sage: RDF(a)
+    13.2713479402
 """
 
@@ -156,30 +222,31 @@
 from functions import Function_gen, Function_arith, Function, FunctionRing_class
 
+
 ######################
 # Ring of Constants
 ######################
 
-class ConstantRing_class(FunctionRing_class):
-    def _repr_(self):
-        return "Ring of Real Mathematical Constants"
-
-    def __cmp__(self, right):
-        if isinstance(right, ConstantRing_class):
-            return 0
-        return -1
+## class ConstantRing_class(FunctionRing_class):
+##     def _repr_(self):
+##         return "Ring of Real Mathematical Constants"
+
+##     def __cmp__(self, right):
+##         if isinstance(right, ConstantRing_class):
+##             return 0
+##         return -1
         
-    def __call__(self, x):
-        try:
-            return self._coerce_(x)
-        except TypeError:
-            return Constant_gen(x)
-
-    def _coerce_impl(self, x):
-        if isinstance(x, (sage.rings.integer.Integer,
-                          sage.rings.rational.Rational, int, long)):
-            return Constant_gen(x)
-        raise TypeError, 'no canonical coercion of element into self.'
-
-ConstantRing = ConstantRing_class()
+##     def __call__(self, x):
+##         try:
+##             return self._coerce_(x)
+##         except TypeError:
+##             return Constant_gen(x)
+
+##     def _coerce_impl(self, x):
+##         if isinstance(x, (sage.rings.integer.Integer,
+##                           sage.rings.rational.Rational, int, long)):
+##             return Constant_gen(x)
+##         raise TypeError, 'no canonical coercion of element into self.'
+
+## ConstantRing = ConstantRing_class()
 
 
@@ -187,9 +254,42 @@
 # Constant functions
 ######################
+import sage.calculus.calculus
 
 class Constant(Function):
     def __init__(self, conversions={}):
         self._conversions = conversions
-        RingElement.__init__(self, ConstantRing)
+        RingElement.__init__(self, sage.calculus.calculus.SR)
+
+    # The maxima one is special:
+    def _maxima_(self, session=None):
+        if session is None:
+            return RingElement._maxima_(self, maxima)
+        else:
+            return RingElement._maxima_(self, session)
+
+    def _has_op(self, x):
+        return False
+
+    def substitute(self, *args, **kwds):
+        return self
+
+    def _recursive_sub(self, kwds):
+        return self
+
+    def _recursive_sub(self, kwds):
+        return self
+
+    def _recursive_sub_over_ring(self, kwds, ring):
+        return ring(self)
+
+    def variables(self):
+        return []
+
+    def _ser(self):
+        try:
+            return self.__ser
+        except AttributeError:
+            self.__ser = sage.calculus.calculus.SR._coerce_impl(self)
+            return self.__ser
 
     def _neg_(self):
@@ -202,23 +302,31 @@
         return Integer(int(float(self)))
 
+    def _latex_(self):
+        return '\\text{%s}'%self
+    
+    def _complex_mpfr_field_(self, R):
+        return R(self._mpfr_(R._real_field()))
+
+    def _real_double_(self, R):
+        return R(float(self))
+
+    def _complex_double_(self, R):
+        return R(float(self))
+    
     # The following adds formal arithmetic support for generic constant
     def _add_(self, right):
-        return Constant_arith(self, right, operator.add)
+        return self._ser() + right
 
     def _sub_(self, right):
-        return Constant_arith(self, right, operator.sub)
+        return self._ser() - right
 
     def _mul_(self, right):
-        return Constant_arith(self, right, operator.mul)
+        return self._ser() * right
 
     def _div_(self, right):
-        return Constant_arith(self, right, operator.div)
+        return self._ser() / right
 
     def __pow__(self, right):
-        try:
-            right = self.parent()._coerce_(right)
-        except TypeError:
-            raise TypeError, "computation of %s^%s not defined"%(self, right)
-        return Constant_arith(self, right, operator.pow)
+        return self._ser() ** right
 
     def _interface_is_cached_(self):
@@ -260,6 +368,5 @@
         Function_arith.__init__(self, x, y, op)
         Constant.__init__(self)
-        
-
+       
 class Pi(Constant):
     """
@@ -281,5 +388,5 @@
         3.1415926535897932384626433832795028841971693993751058209749
         sage: pp = pi+pi; pp
-        (pi + pi)
+        2*pi
         sage: R(pp)
         6.2831853071795864769252867665590057683943387987502116419499
@@ -295,5 +402,5 @@
              'matlab':'pi','maple':'Pi','octave':'pi','pari':'Pi'})
         
-    def _repr_(self):
+    def _repr_(self, simplify=True):
         return "pi"
 
@@ -310,7 +417,10 @@
         return R.pi()
 
-    def _real_double_(self):
-        return sage.rings.all.RD.pi()
-
+    def _real_double_(self,R):
+        return R.pi()
+
+    def _real_rqdf_(self, R):
+        return R.pi()
+    
     def __abs__(self):
         if self.str()[0] != '-':
@@ -329,4 +439,75 @@
 pi = Pi()
 
+
+class I_class(Constant):
+    """
+    The formal square root of -1.
+    
+    EXAMPLES:
+        sage: I
+        I
+        sage: I^2
+        -1
+        sage: float(I)
+        Traceback (most recent call last):
+        ...
+        TypeError
+        sage: gp(I)
+        I
+        sage: RR(I)
+        Traceback (most recent call last):
+        ...
+        TypeError
+        sage: C = ComplexField(200); C
+        Complex Field with 200 bits of precision
+        sage: C(I)
+        1.0000000000000000000000000000000000000000000000000000000000*I
+        sage: z = I + I; z
+        2*I
+        sage: C(z)
+        2.0000000000000000000000000000000000000000000000000000000000*I
+        sage: maxima(2*I)
+        2*%i
+    """
+    def __init__(self):
+        Constant.__init__(self,
+            {'axiom':'%i', 
+             'maxima':'%i','gp':'I','mathematica':'I',
+             'matlab':'i','maple':'I','octave':'i','pari':'I'})
+        
+    def _repr_(self, simplify=True):
+        return "I"
+
+    def _latex_(self):
+        return "i"
+
+    def _mathml_(self):
+        return "<mi>&i;</mi>"
+
+    def __float__(self):
+        raise TypeError
+
+    def _mpfr_(self, R):
+        raise TypeError
+
+    def _real_rqdf_(self, R):
+        raise TypeError
+
+    def _complex_mpfr_field_(self, R):
+        return R.gen()
+
+    def _complex_double_(self, C):
+        return C.gen()
+
+    def _real_double_(self, R):
+        raise TypeError        
+
+    def __abs__(self):
+        return Integer(1)
+
+    def floor(self):
+        raise TypeError
+
+I = I_class()
 
 class E(Constant):
@@ -342,5 +523,5 @@
         2.7182818284590452353602874713526624977572470936999595749670
         sage: em = 1 + e^(1-e); em
-        (1 + (e^(1 - e)))
+        e^(1 - e) + 1
         sage: R(em)
         1.1793740787340171819619895873183164984596816017589156131574
@@ -364,5 +545,5 @@
              'octave':'e'}) 
     
-    def _repr_(self):
+    def _repr_(self, simplify=True):
         return 'e'
 
@@ -379,7 +560,16 @@
         return Integer(2)
 
-    def _real_double_(self):
-        return sage.rings.all.RD.e()
-
+    def _real_double_(self, R):
+        return R(1).exp()
+
+    def _real_rqdf_(self, R):
+        """
+        EXAMPLES:
+            sage: RQDF = RealQuadDoubleField ()
+            sage: RQDF.e()
+            2.718281828459045235360287471352662497757247093699959574966967630
+        """
+        return R.e()
+    
     # This just gives a string in singular anyways, and it's
     # *REALLY* slow!
@@ -391,6 +581,4 @@
 ee = e
 
-
-
 class NotANumber(Constant): 
     """
@@ -401,5 +589,5 @@
 	    {'matlab':'NaN'})
     
-    def _repr_(self):
+    def _repr_(self, simplify=True):
         return 'NaN'
  
@@ -407,7 +595,15 @@
         return R('NaN') #??? nan in mpfr: void mpfr_set_nan (mpfr_t x)
 
-    def _real_double_(self):
-        return sage.rings.all.RD.nan()
-
+    def _real_double_(self, R):
+        return R.nan()
+
+    def _real_rqdf_(self, R):
+        """
+        EXAMPLES:
+            sage: RQDF (NaN)
+            'NaN'
+        """
+        return R.NaN()
+    
 NaN = NotANumber()
 
@@ -424,7 +620,7 @@
         1.6180339887498948482045868343656381177203091798057628621354
         sage: grm = maxima(golden_ratio);grm
-        (sqrt(5) + 1)/2
+        (sqrt(5)+1)/2
         sage: grm + grm
-        sqrt(5) + 1
+        sqrt(5)+1
         sage: float(grm + grm)
         3.2360679774997898
@@ -435,5 +631,5 @@
 				'pari':'(1+sqrt(5))/2','octave':'(1+sqrt(5))/2',
 				'kash':'(1+Sqrt(5))/2'})
-    def _repr_(self):
+    def _repr_(self, simplify=True):
         return 'golden_ratio'
 
@@ -444,5 +640,5 @@
         return float(0.5)*(float(1.0)+math.sqrt(float(5.0)))
 
-    def _real_double_(self):
+    def _real_double_(self, R):
         """
         EXAMPLES:
@@ -450,6 +646,9 @@
             1.61803398875
         """
-        return sage.rings.all.RDF(1.61803398874989484820458)
-
+        return R('1.61803398874989484820458')
+
+    def _real_rqdf_(self, R):
+        return R('1.61803398874989484820458683436563811772030917980576286213544862')
+    
     def _mpfr_(self,R):  #is this OK for _mpfr_ ?
 	return (R(1)+R(5).sqrt())*R(0.5)
@@ -472,6 +671,6 @@
         sage: R(log2)
         0.69314718055994530941723212145817656807550013436025525412068
-        sage: l = (1-log2)/(1+log2);l
-        ((1 - log2)/(1 + log2))
+        sage: l = (1-log2)/(1+log2); l
+        (1 - log(2))/(log(2) + 1)
         sage: R(l)
         0.18123221829928249948761381864650311423330609774776013488056
@@ -492,5 +691,5 @@
 				'pari':'log(2)','octave':'log(2)'})
 
-    def _repr_(self):
+    def _repr_(self, simplify=True):
         return 'log2'
 
@@ -501,5 +700,5 @@
         return math.log(2) 
 
-    def _real_double_(self):
+    def _real_double_(self, R):
         """
         EXAMPLES:
@@ -507,6 +706,14 @@
             0.69314718056
         """
-        return sage.rings.all.RD.log2()
-
+        return R.log2()
+
+    def _real_rqdf_(self, R):
+        """
+        EXAMPLES:
+            sage: RQDF(log2)
+            0.693147180559945309417232121458176568075500134360255254120680009
+        """
+        return R.log2()
+    
     def _mpfr_(self,R):
         return R.log2()
@@ -529,6 +736,6 @@
         sage: R(euler_gamma)
         0.57721566490153286060651209008240243104215933593992359880577
-        sage: eg = euler_gamma + euler_gamma;eg
-        (euler_gamma + euler_gamma)
+        sage: eg = euler_gamma + euler_gamma; eg
+        2*euler_gamma
         sage: R(eg)
         1.1544313298030657212130241801648048620843186718798471976115
@@ -537,7 +744,8 @@
         Constant.__init__(self,
 	    {'kash':'EulerGamma(R)','maple':'gamma', 
-             'mathematica':'EulerGamma','pari':'Euler'})    
-
-    def _repr_(self):
+             'mathematica':'EulerGamma','pari':'Euler',
+             'maxima':'%gamma', 'maxima':'euler_gamma'})    
+
+    def _repr_(self, simplify=True):
         return 'euler_gamma'
 
@@ -548,5 +756,5 @@
         return R.euler_constant()
 
-    def _real_double_(self):
+    def _real_double_(self, R):
         """
         EXAMPLES:
@@ -554,6 +762,9 @@
             0.577215664902
         """
-        return sage.rings.all.RD.euler()
-
+        return R.euler_constant()
+
+    def _real_rqdf_(self, R):
+        return R('0.577215664901532860606512090082402431042159335939923598805767235')
+    
     def floor(self):
         return Integer(0)
@@ -567,20 +778,19 @@
 
     EXAMPLES:
+        sage: catalan^2 + merten
+        merten + catalan^2
     """
     def __init__(self):
         Constant.__init__(self,
              {'mathematica':'Catalan','kash':'Catalan(R)', #kash: R is default prec
-	      'maple':'Catalan'}) 
+              'maple':'Catalan', 'maxima':'catalan'}) 
                                          
-    def _repr_(self):
-        return 'K'
-
-    def _latex_(self):
-        return 'K'
+    def _repr_(self, simplify=True):
+        return 'catalan'
 
     def _mpfr_(self, R):  
         return R.catalan_constant() 
 
-    def _real_double_(self):
+    def _real_double_(self, R):
         """
         EXAMPLES:
@@ -589,6 +799,9 @@
             0.915965594177
         """
-        return sage.rings.all.RDF(0.91596559417721901505460351493252)
-
+        return R('0.91596559417721901505460351493252')
+
+    def _real_rqdf_(self, R):
+        return R('0.915965594177219015054603514932384110774149374281672134266498120')
+    
     def __float__(self):
         """
@@ -617,14 +830,10 @@
         Khinchin
         sage: m.N(200)                                 # optional
-             2.685452001065306445309714835481795693820382293994462953051152345557     # 32-bit
-        >    218859537152002801141174931847697995153465905288090082897677716410963051 # 32-bit
-        >    7925334832596683818523154213321194996260393285220448194096181            # 32-bit
-             2.685452001065306445309714835481795693820382293994462953051152345557     # 64-bit
-        >    218859537152002801141174931847697995153465905288090082897677716410963051 # 64-bit
-        >    7925334832596683818523154213321194996260393285220448194096181            # 64-bit
+             2.6854520010653064453097148354817956938203822939944629530511523455572188595371520028011411749318476979951534659052880900828976777164109630517925334832596683818523154213321194996260393285220448194096180686641664289    # 32-bit
+             2.6854520010653064453097148354817956938203822939944629530511523455572188595371520028011411749318476979951534659052880900828976777164109630517925334832596683818523154213321194996260393285220448194096181                # 64-bit
     """
     def __init__(self):
         Constant.__init__(self,
-             {'mathematica':'Khinchin'}) #Khinchin is only implemented in Mathematica
+             {'maxima':'khinchin', 'mathematica':'Khinchin'}) #Khinchin is only implemented in Mathematica
         
         # digits come from http://pi.lacim.uqam.ca/piDATA/khintchine.txt
@@ -632,5 +841,5 @@
         self.__bits = len(self.__value)*3-1   # underestimate
 
-    def _repr_(self):
+    def _repr_(self, simplify=True):
         return 'khinchin'
 
@@ -640,5 +849,5 @@
         raise NotImplementedError, "Khinchin's constant only available up to %s bits"%self.__bits
 
-    def _real_double_(self):
+    def _real_double_(self, R):
         """
         EXAMPLES:
@@ -646,7 +855,9 @@
             2.68545200107
         """
-	return sage.rings.all.RDF(2.685452001065306445309714835481795693820)
-
-
+	return R('2.685452001065306445309714835481795693820')
+
+    def _real_rqdf_(self, R):
+        return R(self.__value[:65])
+    
     def __float__(self): 
         return 2.685452001065306445309714835481795693820
@@ -672,5 +883,5 @@
     """
     def __init__(self):
-        Constant.__init__(self,{}) #Twin prime is not implemented in any other algebra systems.
+        Constant.__init__(self,{'maxima':'twinprime'}) #Twin prime is not implemented in any other algebra systems.
 	
         #digits come from http://www.gn-50uma.de/alula/essays/Moree/Moree-details.en.shtml
@@ -683,5 +894,5 @@
         return Integer(0)
 
-    def _repr_(self):
+    def _repr_(self, simplify=True):
         return 'twinprime'
 
@@ -691,5 +902,5 @@
         raise NotImplementedError, "Twin Prime constant only available up to %s bits"%self.__bits
 
-    def _real_double_(self):
+    def _real_double_(self, R):
         """
         EXAMPLES:
@@ -697,6 +908,9 @@
             0.660161815847
         """
-	return sage.rings.all.RDF(0.660161815846869573927812110014555778432)
-
+	return R('0.660161815846869573927812110014555778432')
+
+    def _real_rqdf_(self, R):
+        return R(self.__value[:65])
+    
     def __float__(self):
         """
@@ -724,5 +938,5 @@
     """
     def __init__(self):
-        Constant.__init__(self,{}) #Merten's constant is not implemented in any other algebra systems.
+        Constant.__init__(self,{'maxima':'merten'}) #Merten's constant is not implemented in any other algebra systems.
 
         # digits come from Sloane's tables at http://www.research.att.com/~njas/sequences/table?a=77761&fmt=0
@@ -735,5 +949,5 @@
         return Integer(0)
 
-    def _repr_(self):
+    def _repr_(self, simplify=True):
         return 'merten'
 
@@ -752,5 +966,5 @@
         raise NotImplementedError, "Merten's constant only available up to %s bits"%self.__bits
 
-    def _real_double_(self):
+    def _real_double_(self, R):
         """
         EXAMPLES:
@@ -758,6 +972,9 @@
             0.261497212848
         """
-        return sage.rings.all.RDF(0.261497212847642783755426838608695859051)
-
+        return R('0.261497212847642783755426838608695859051')
+
+    def _real_rqdf_(self, R):
+        return R(self.__value[:65])
+    
     def __float__(self):
         """
@@ -767,4 +984,5 @@
         """
 	return 0.261497212847642783755426838608695859051
+
 
 merten = Merten()
@@ -787,5 +1005,5 @@
     """
     def __init__(self):
-        Constant.__init__(self,{}) #Brun's constant is not implemented in any other algebra systems.
+        Constant.__init__(self,{'maxima':"brun"}) #Brun's constant is not implemented in any other algebra systems.
 
         # digits come from Sloane's tables at http://www.research.att.com/~njas/sequences/table?a=65421&fmt=0
@@ -798,5 +1016,5 @@
         return Integer(1)
 
-    def _repr_(self):
+    def _repr_(self, simplify=True):
         return 'brun'
 
@@ -807,5 +1025,5 @@
             Traceback (most recent call last):
             ...
-            NotImplementedError: Brun's constant only available up to 41 bits
+            TypeError: Brun's constant only available up to 41 bits
             sage: RealField(41)(brun)
             1.90216058310
@@ -813,7 +1031,7 @@
         if R.precision() <= self.__bits:
             return R(self.__value)
-        raise NotImplementedError, "Brun's constant only available up to %s bits"%self.__bits
-
-    def _real_double_(self):
+        raise TypeError, "Brun's constant only available up to %s bits"%self.__bits
+
+    def _real_double_(self, R):
         """
         EXAMPLES:
@@ -821,6 +1039,9 @@
             1.9021605831
         """
-        return sage.rings.all.RDF(1.9021605831040)
-
+        return R('1.9021605831040')
+
+    def _real_rqdf_(self, R):
+        raise TypeError, "Brun's constant only available up to %s bits"%self.__bits
+    
     def __float__(self):
         """
@@ -833,49 +1054,2 @@
 brun=Brun()
 
-class UniversalPolynomialElement(Constant):
-    """
-    A universal indeterminate.
-    
-    EXAMPLES:
-        sage: x
-        x
-        sage: x.parent()
-        Univariate Polynomial Ring in x over Rational Field
-    """
-    def __init__(self, name):
-        self._name = name
-        Constant.__init__(self,
-            {'axiom':name, 
-             'maxima':name,
-             'gp':name,'kash':name,
-             'mathematica':name,
-             'matlab':name,
-             'maple':name,
-             'octave':name,
-             'pari':name})
-        
-    def _repr_(self):
-        return self._name
-
-    def _latex_(self):
-        return self._name
-
-    def _mathml_(self):
-        return "<mi>%s</mi>"%self._name
-
-    def __float__(self):
-        raise TypeError
-
-    def _mpfr_(self, R):
-        raise TypeError
-
-    def _real_double_(self):
-        raise TypeError
-
-    def __abs__(self):
-        raise TypeError
-
-    def floor(self):
-        raise TypeError
-
-x = UniversalPolynomialElement('x')
Index: sage/functions/functions.py
===================================================================
--- sage/functions/functions.py	(revision 3290)
+++ sage/functions/functions.py	(revision 4316)
@@ -2,14 +2,7 @@
 SAGE Functions Class
 
-EXAMPLES:
-    sage: f = 5*sin(x)
-    sage: f
-    (5*sin(x))
-    sage: f(2)
-    (5*sin(2))
-    sage: f(pi)
-    (5*sin(((1*pi) + 0)))
-    sage: float(f(pi))
-    6.1232339957367663e-16
+AUTHORS:
+   -- William Stein
+   -- didier deshommes <dfdeshom@gmail.com>(2007-03-26): added support for RQDF
 """
 import weakref
@@ -26,5 +19,5 @@
 import operator
 from   sage.misc.latex import latex
-from   sage.interfaces.maxima import maxima, MaximaFunction
+from   sage.calculus.calculus import maxima
 import sage.functions.special as special
 from   sage.libs.all import  pari
@@ -113,6 +106,4 @@
 
     def _coerce_impl(self, x):
-        if is_Polynomial(x):
-            return self(x)
         return self(x)
 
@@ -218,11 +209,6 @@
         """
         EXAMPLES:
-            sage: singular(e)
+            sage: s = singular(e); s
             2.71828182845905
-            sage: P = e.parent()
-            sage: old_prec = P.set_precision(200)
-            sage: singular(e)
-            2.7182818284590452353602874713526624977572470936999595749670
-            sage: _ = P.set_precision(old_prec)
         """
         try:
@@ -264,16 +250,16 @@
         EXAMPLES:
             sage: s = e + pi
-            sage: s == 0
+            sage: bool(s == 0)
             False
             sage: t = e^2  +pi
-            sage: s == t
+            sage: bool(s == t)
             False
-            sage: s == s
+            sage: bool(s == s)
             True
-            sage: t == t
+            sage: bool(t == t)
             True
-            sage: s < t
+            sage: bool(s < t)
             True
-            sage: t < s
+            sage: bool(t < s)
             False
         """
@@ -335,18 +321,18 @@
         sage: s = (pi + pi) * e + e
         sage: s
-        (((pi + pi)*e) + e)
+        2*e*pi + e
         sage: RR(s)
         19.7977502738062
         sage: maxima(s)
-        2*%e*%pi + %e
+        2*%e*%pi+%e
 
         sage: t = e^2 + pi + 2/3; t
-        (((e^2) + pi) + 2/3)
+        pi + e^2 + 2/3
         sage: RR(t)
         11.1973154191871
         sage: maxima(t)
-        %pi + %e^2 + 2/3
+        %pi+%e^2+2/3
         sage: t^e
-        ((((e^2) + pi) + 2/3)^e)
+        (pi + e^2 + 2/3)^e
         sage: RR(t^e)
         710.865247688858
@@ -360,9 +346,16 @@
         self.__op = op  # a binary operator, e.g., operator.sub
 
+    def _maxima_init_(self):
+        x = self.__x
+        y = self.__y
+        op = self.__op
+        return '(%s) %s (%s)'%(x._maxima_init_(), symbols[op] ,y._maxima_init_())
+            
+
     def _repr_(self):
         """
         EXAMPLES:
             sage: log2 * e + pi^2/2
-            ((log2*e) + ((pi^2)/2))
+            e*log(2) + pi^2/2
         """
         return '(%s%s%s)'%(self.__x, symbols[self.__op], self.__y)
@@ -372,9 +365,9 @@
         EXAMPLES:
             sage: latex(log2 * e + pi^2/2)
-            \log(2) \cdot e + \frac{\pi^{2}}{2}
+            {e \cdot \log \left( 2 \right)} + \frac{{\pi}^{2} }{2}
             sage: latex(NaN^3 + 1/golden_ratio)
-            \text{NaN}^{3} + \frac{1}{\phi}
+            {\text{NaN}}^{3}  + \frac{2}{\sqrt{ 5 } + 1}
             sage: latex(log2 + euler_gamma + catalan + khinchin + twinprime + merten + brun)
-            \log(2) + \gamma + K + \text{khinchin} + \text{twinprime} + \text{merten} + \text{brun}
+            \text{twinprime} + \text{merten} + \text{khinchin} + \gamma + \text{catalan} + \text{brun} + \log \left( 2 \right)
         """
         if self.__op == operator.div:
@@ -400,5 +393,5 @@
         EXAMPLES:
             sage: gap(e + pi)
-            "5.85987448204884"
+            "pi + e"
         """
         return '"%s"'%self.str()
@@ -441,5 +434,5 @@
         EXAMPLES:
             sage: maxima(e + pi)
-            %pi + %e
+            %pi+%e
         """
         return self.__op(self.__x._maxima_(maxima), self.__y._maxima_(maxima)) 
@@ -469,5 +462,5 @@
         EXAMPLES:
             sage: singular(e + pi)
-            5.85987448204884
+            pi + e
         """
         return '"%s"'%self.str()
@@ -481,4 +474,6 @@
         return self.__op(self.__x._mpfr_(R), self.__y._mpfr_(R))
 
+    def _real_rqdf_(self, R):
+        return self.__op(self.__x._real_rqdf_(R), self.__y._real_rqdf_(R))
 
 class Function_gen(Function):
@@ -490,7 +485,7 @@
         sage: a = pi/2 + e
         sage: a
-        ((pi/2) + e)
+        pi/2 + e
         sage: maxima(a)
-        %pi/2 + %e
+        %pi/2+%e
         sage: RR(a)
         4.28907815525394
@@ -500,5 +495,5 @@
         sage: b = e + 5/7
         sage: maxima(b)
-        %e + 5/7
+        %e+5/7
         sage: RR(b)
         3.43256754274476
@@ -520,4 +515,7 @@
         return R(self.__x)
 
+    def _real_rqdf_(self, R):
+        return R(self.__x)
+    
     def str(self, bits=None):
         if bits is None:
@@ -600,4 +598,8 @@
         return self.__f(x)
 
+    def _real_rqdf_(self, R):
+        x = R(self.__x)
+        return self.__f(x)
+    
     def _maxima_init_(self):
         try:
@@ -765,6 +767,4 @@
 class Function_maxima(Function):
     def __init__(self, var, defn, repr, latex):
-        #if not isinstance(x, MaximaFunction):
-        #    raise TypeError, "x (=%s) must be a MaximaFunction"
         Function.__init__(self, {'maxima':defn})
         self.__var = var
Index: sage/functions/orthogonal_polys.py
===================================================================
--- sage/functions/orthogonal_polys.py	(revision 3301)
+++ sage/functions/orthogonal_polys.py	(revision 4016)
@@ -386,9 +386,9 @@
         sage: t = PolynomialRing(QQ, "t").gen()
         sage: gen_legendre_P(2,0,t)
-        '3*(1 - t)^2/2 - 3*(1 - t) + 1'
+        '3*(1-t)^2/2-3*(1-t)+1'
         sage: legendre_P(2,t)
         3/2*t^2 - 1/2
         sage: gen_legendre_P(3,1,t)
-        '-6*(5*(1 - t)^2/4 - 5*(1 - t)/2 + 1)*sqrt(1 - t^2)'
+        '-6*(5*(1-t)^2/4-5*(1-t)/2+1)*sqrt(1-t^2)'
     """
     _init()
@@ -412,7 +412,7 @@
         sage: t = PolynomialRing(QQ, "t").gen()
         sage: gen_legendre_Q(2,0,t)
-        '(3*log( - (t + 1)/(t - 1))*t^2 - 6*t - log( - (t + 1)/(t - 1)))/4'
+        '(3*log(-(t+1)/(t-1))*t^2-6*t-log(-(t+1)/(t-1)))/4'
         sage: legendre_Q(2,t)
-        '(3*log( - (t + 1)/(t - 1))*t^2 - 6*t - log( - (t + 1)/(t - 1)))/4'
+        '(3*log(-(t+1)/(t-1))*t^2-6*t-log(-(t+1)/(t-1)))/4'
         sage: gen_legendre_Q(3,1,0.5)
         2.49185259171
@@ -523,5 +523,5 @@
         sage: t = PolynomialRing(QQ, 't').gen()
         sage: legendre_Q(2,t)
-        '(3*log( - (t + 1)/(t - 1))*t^2 - 6*t - log( - (t + 1)/(t - 1)))/4'
+        '(3*log(-(t+1)/(t-1))*t^2-6*t-log(-(t+1)/(t-1)))/4'
         sage: legendre_Q(3,0.5)
         -0.198654771479
Index: sage/functions/piecewise.py
===================================================================
--- sage/functions/piecewise.py	(revision 3636)
+++ sage/functions/piecewise.py	(revision 4316)
@@ -2,10 +2,7 @@
 Piecewise-defined Functions.
 
-\sage implements a very simple class of piecewise-defined functions.
-Functions must be piecewise polynomial, though some methods apply more
-generally. Only compactly supported functions are currently
-implemented. Moreover, the coefficients should be rational and the
-support should be 'connected'. The intervals of polynomial support can
-be in terms of rationals and $\pi$, or in terms of floats.
+\sage implements a very simple class of piecewise-defined functions.  Functions
+may be any type of symbolic expression.  Infinite intervals are not supported.
+The endpoints of each interval must line up.
 
 Implemented methods:
@@ -58,8 +55,4 @@
       way is to use an element class and only define _mul_, and
       have a parent, so anything gets coerced properly.
-   
-(For more general non-polynomial piecewise functions, it appears
-a new class of functions (for example, 'ElementaryFunctionRing') is 
-needed. This a preliminary 'todo'.)
 
 AUTHOR: David Joyner (2006-04) -- initial version
@@ -99,4 +92,11 @@
 from sage.rings.all import QQ, RR, Integer, Rational
 
+from sage.calculus.calculus import SR, var, maxima
+
+def meval(x):
+    from sage.calculus.calculus import symbolic_expression_from_maxima_element
+    return symbolic_expression_from_maxima_element(maxima(x))
+
+
 class PiecewisePolynomial:
     def __init__(self, list_of_pairs):
@@ -125,33 +125,42 @@
             self.length(),self.list())
  
-    def latex(self):
+    def _latex_(self):
+	r"""
+	EXAMPLES:
+            sage: f1(x) = 1
+            sage: f2(x) = 1 - x
+            sage: f = Piecewise([[(0,1),f1],[(1,2),f2]])
+            sage: latex(f)
+            \begin{cases}
+            x \ {\mapsto}\ 1 &\text{on $(0, 1)$}\cr
+            x \ {\mapsto}\ 1 - x &\text{on $(1, 2)$}
+            \end{cases}
+
+            sage: f(x) = sin(x*pi/2)
+            sage: g(x) = 1-(x-1)^2
+            sage: h(x) = -x
+            sage: P = Piecewise([[(0,1), f], [(1,3),g], [(3,5), h]])
+            sage: latex(P)
+            \begin{cases}
+            x \ {\mapsto}\ \sin \left( \frac{{\pi \cdot x}}{2} \right) &\text{on $(0, 1)$}\cr
+            x \ {\mapsto}\ 1 - {\left( x - 1 \right)}^{2}  &\text{on $(1, 3)$}\cr
+            x \ {\mapsto}\ -x &\text{on  $(3, 5)$}
+            \end{cases}
 	"""
-	EXAMPLES:
-            sage: f1 = lambda x:1
-            sage: f2 = lambda x:1-x
-            sage: f = Piecewise([[(0,1),f1],[(1,2),f2]])
-            sage: f.latex()
-            '\\begin{array}{ll} \\left\\{ 1,& 0 < x < 1 ,\\right. \\end{array}'
-
-	"""
-        x = PolynomialRing(QQ,'x').gen()
-        intvls = self.intervals()
-        fcn_list = [p[1] for p in self.list()]
-        tex = ["\\begin{array}{ll} \left\\{"]
-        for i in range(len(fcn_list)):
-	    f = fcn_list[i]
-	    a = intvls[i][0]
-	    b = intvls[i][1]
-            tex.append(str(f(x)))
-	    tex.append(",& %s < x < %s ,\\"%(a,b))
-        tex = tex[:-2]
-	tex.append("\right\. \end{array}")
-	ltex = ""
-        for i in range(len(tex)-1):
-            ltex = ltex + tex[i]
-        ltex = ltex + str(tex[len(tex)-1]).replace("%","")
-        ltex = ltex.replace("\\\right\\.","\\right.")
-        ltex = ltex.replace("\\left\\{","\\left\{ ")
-        return ltex
+        intervals = self.intervals()
+        funcs = [p[1] for p in self.list()]
+        tex = ['\\begin{cases}\n']
+        for i in range(len(funcs)):
+            f = funcs[i]
+            # left endpoint
+            a = intervals[i][0]
+            # right endpoint
+            b = intervals[i][1]
+            tex.append(r'%s &\text{on $(%s, %s)$}' % (f._latex_(), a, b))
+            tex.append('\\cr\n')
+        # remove the last TeX newline
+        tex = tex[:-1]
+        tex.append('\n\\end{cases}')
+        return ''.join(tex)
 
     def intervals(self):
@@ -160,8 +169,8 @@
 	
         EXAMPLES:
-            sage: f1 = lambda x:1
-            sage: f2 = lambda x:1-x
-            sage: f3 = lambda x:exp(x)
-            sage: f4 = lambda x:sin(2*x)
+            sage: f1(x) = 1
+            sage: f2(x) = 1-x
+            sage: f3(x) = exp(x)
+            sage: f4(x) = sin(2*x)
             sage: f = Piecewise([[(0,1),f1],[(1,2),f2],[(2,3),f3],[(3,10),f4]])
             sage: f.intervals()
@@ -176,4 +185,13 @@
         """
         Returns the list of functions (the "pieces").
+
+        EXAMPLES:
+            sage: f1(x) = 1
+            sage: f2(x) = 1-x
+            sage: f3(x) = exp(x)
+            sage: f4(x) = sin(2*x)
+            sage: f = Piecewise([[(0,1),f1],[(1,2),f2],[(2,3),f3],[(3,10),f4]])
+            sage: f.functions()
+            [x |--> 1, x |--> 1 - x, x |--> e^x, x |--> sin(2*x)]
         """
         return self._functions
@@ -244,18 +262,18 @@
         Riemann sums in numerical integration based on a subdivision
         into N subintervals.
-	Set mode="midpoint" for the height of the rectangles to be 
-	determined by the midpoint of the subinterval;
+    	Set mode="midpoint" for the height of the rectangles to be 
+        determined by the midpoint of the subinterval;
         set mode="right" for the height of the rectangles to be 
-	determined by the right-hand endpoint of the subinterval;
-	the default is mode="left" (the height of the rectangles to be 
-	determined by the leftt-hand endpoint of the subinterval).
-	
-        EXAMPLES:
-            sage: f1 = lambda x:x^2                   ## example 1
-            sage: f2 = lambda x:5-x^2
+        determined by the right-hand endpoint of the subinterval;
+        the default is mode="left" (the height of the rectangles to be 
+        determined by the leftt-hand endpoint of the subinterval).
+            
+        EXAMPLES:
+            sage: f1 = x^2                   ## example 1
+            sage: f2 = 5-x^2
             sage: f = Piecewise([[(0,1),f1],[(1,2),f2]])
             sage: f.riemann_sum_integral_approximation(6)
             17/6
-	    sage: f.riemann_sum_integral_approximation(6,mode="right")
+            sage: f.riemann_sum_integral_approximation(6,mode="right")
             19/6
             sage: f.riemann_sum_integral_approximation(6,mode="midpoint")
@@ -303,10 +321,9 @@
 	
         EXAMPLES:
-            sage: f1 = lambda x:x^2                   ## example 1
-            sage: f2 = lambda x:5-x^2
+            sage: f1(x) = x^2
+            sage: f2(x) = 5-x^2
             sage: f = Piecewise([[(0,1),f1],[(1,2),f2]])
             sage: f.riemann_sum(6,mode="midpoint")
             Piecewise defined function with 6 parts, [[(0, 1/3), 1/36], [(1/3, 2/3), 1/4], [(2/3, 1), 25/36], [(1, 4/3), 131/36], [(4/3, 5/3), 11/4], [(5/3, 2), 59/36]]
-            sage: x = PolynomialRing(QQ,'x').gen()        ## example 2
             sage: f = Piecewise([[(-1,1),1-x^2]])
             sage: rsf = f.riemann_sum(7)
@@ -394,6 +411,6 @@
 
         EXAMPLES:
-            sage: f1 = lambda x:x^2                      ## example 1
-            sage: f2 = lambda x:1-(1-x)^2
+            sage: f1(x) = x^2                      ## example 1
+            sage: f2(x) = 1-(1-x)^2
             sage: f = Piecewise([[(0,1),f1],[(1,2),f2]])
             sage: P = f.plot(rgbcolor=(0.7,0.1,0.5), plot_points=40)
@@ -427,18 +444,19 @@
     def critical_points(self):
         """
-        Function to return the critical points. Uses maxima, which
-        prints the warning to use results with caution. Only works for
-        piecewise functions whose parts are polynomials with real
-        critical not occurring on the interval endpoints.
+        Return the critical points of this piecewise function.
+
+        WARNINGS: Uses maxima, which prints the warning to use results
+        with caution. Only works for piecewise functions whose parts
+        are polynomials with real critical not occurring on the
+        interval endpoints.
 
         EXAMPLES:
             sage: x = PolynomialRing(QQ, 'x').0
             sage: f1 = x^0
-            sage: f2 = 1-x
-            sage: f3 = 2*x
-            sage: f4 = 10*x-x^2
-            sage: f = Piecewise([[(0,1),f1],[(1,2),f2],[(2,3),f3],[(3,10),f4]])
+            sage: f2 = 10*x - x^2
+            sage: f3 = 3*x^4 - 156*x^3 + 3036*x^2 - 26208*x
+            sage: f = Piecewise([[(0,3),f1],[(3,10),f2],[(10,20),f3]])
             sage: f.critical_points()
-            [5.0]
+            [5.0, 12.000000000000171, 12.9999999999996, 14.000000000000229]
         """
         maxima = sage.interfaces.all.maxima
@@ -447,13 +465,20 @@
         N = len(fcns)
         crit_pts = []
+        I = self.intervals()
         for i in range(N):
             maxima.eval("eqn:diff(%s,x)=0"%fcns[i])
             ans = maxima.eval("allroots(eqn)")
-            if "[x =" in ans:
-                i1 = ans.index("[x =")
-                i2 = ans.index("]")
-                r = eval(ans[i1+4:i2])
-                if self.intervals()[i][0] < r < self.intervals()[i][1]:
+            while True:
+                start = ans.find('x=')
+                if start == -1:
+                    break
+                ans = ans[start+2:]
+                end = ans.find(',')
+                if end == -1:
+                    end = ans.find(']')
+                r = float(ans[:end])
+                if I[i][0] < r < I[i][1]:
                     crit_pts.append(r)
+                ans = ans[end+1:]
         return crit_pts
 
@@ -475,17 +500,17 @@
         """
         Evaluates self at x0. Returns the average value of the jump if x0 is
-	an interior endpoint of one of the intervals of self and the
-	usual value otherwise.
+        an interior endpoint of one of the intervals of self and the
+        usual value otherwise.
         
         EXAMPLES:
-            sage: f1 = lambda x:1
-            sage: f2 = lambda x:1-x
-            sage: f3 = lambda x:exp(x)
-            sage: f4 = lambda x:sin(2*x)
+            sage: f1(x) = 1
+            sage: f2(x) = 1-x
+            sage: f3(x) = exp(x)
+            sage: f4(x) = sin(2*x)
             sage: f = Piecewise([[(0,1),f1],[(1,2),f2],[(2,3),f3],[(3,10),f4]])
             sage: f(0.5)
             1
             sage: f(2.5)
-            12.1824939607035
+            12.18249396070347
             sage: f(1)
             1/2
@@ -511,12 +536,11 @@
         
         EXAMPLES:
-	    sage: x = PolynomialRing(QQ,'x').gen()
-            sage: f1 = lambda z:1
+            sage: f1 = z
             sage: f2 = 1-x
-            sage: f3 = lambda y:exp(y)
-            sage: f4 = lambda t:sin(2*t)
+            sage: f3 = exp(y)
+            sage: f4 = sin(2*t)
             sage: f = Piecewise([[(0,1),f1],[(1,2),f2],[(2,3),f3],[(3,10),f4]])
             sage: f.which_function(3/2)
-	    -x + 1
+            1 - x
         """
         n = self.length()
@@ -534,5 +558,5 @@
         raise ValueError,"Function not defined outside of domain."
 	
-    def integral(self):
+    def integral(self, x=None):
         r"""
         Returns the definite integral (as computed by maxima)
@@ -541,20 +565,24 @@
 
         EXAMPLES:
-            sage: f1 = lambda x:1
-            sage: f2 = lambda x:1-x
+            sage: f1(x) = 1
+            sage: f2(x) = 1-x
             sage: f = Piecewise([[(0,1),f1],[(1,2),f2]])
             sage: f.integral()
             1/2
-	    sage: f1 = lambda x:-1
-            sage: f2 = lambda x:2
+            sage: f1(x) = -1
+            sage: f2(x) = 2
             sage: f = Piecewise([[(0,pi/2),f1],[(pi/2,pi),f2]])
             sage: f.integral()
-            (pi/2)
-        """
-        maxima = sage.interfaces.all.maxima
-        x = PolynomialRing(QQ,'x').gen()
-        ints = [maxima('%s'%p[1](x)).integral('x', p[0][0], p[0][1]) \
-                 for p in self.list()]  
-        return sage_eval(str(sum(ints)).replace("%",""))
+            pi/2
+        """
+        #maxima = sage.interfaces.all.maxima
+        #x = PolynomialRing(QQ,'x').gen()
+        #ints = [maxima('%s'%p[1](x)).integral('x', p[0][0], p[0][1]) \
+        #         for p in self.list()]
+        #RETURN MEVAl(repr(sum(ints)))
+        funcs = self.functions()
+        invs = self.intervals()
+        n = len(funcs)
+        return sum([funcs[i].integral(x,invs[i][0],invs[i][1]) for i in range(n)])
 
     def convolution(self,other):
@@ -596,5 +624,5 @@
         R1 = f0.parent()
         xx = R1.gen()
-        var = str(xx)
+        var = repr(xx)
         if len(f.intervals())==1 and len(g.intervals())==1:
             f = f.unextend()
@@ -604,6 +632,6 @@
             b1 = g.intervals()[0][0]
             b2 = g.intervals()[0][1]
-            i1 = str(f0).replace(var,str(uu))
-            i2 = str(g0).replace(var,"("+str(tt-uu)+")")
+            i1 = repr(f0).replace(var,repr(uu))
+            i2 = repr(g0).replace(var,"("+repr(tt-uu)+")")
             cmd1 = "integrate((%s)*(%s),%s,%s,%s)"%(i1,i2, uu, a1,    tt-b1)    ## if a1+b1 < tt < a2+b1
             cmd2 = "integrate((%s)*(%s),%s,%s,%s)"%(i1,i2, uu, tt-b2, tt-b1)    ## if a1+b2 < tt < a2+b1
@@ -614,8 +642,10 @@
             conv3 = maxima.eval(cmd3)
             conv4 = maxima.eval(cmd4)
-            fg1 = sage_eval(conv1.replace("tt",var)) ## should be = R2(conv1)
-            fg2 = sage_eval(conv2.replace("tt",var)) ## should be = R2(conv2)
-            fg3 = sage_eval(conv3.replace("tt",var)) ## should be = R2(conv3)
-            fg4 = sage_eval(conv4.replace("tt",var)) ## should be = R2(conv4)
+            # this is a very, very, very ugly hack
+            x = PolynomialRing(QQ,'x').gen()
+            fg1 = sage_eval(conv1.replace("tt",var), {'x':x}) ## should be = R2(conv1)
+            fg2 = sage_eval(conv2.replace("tt",var), {'x':x}) ## should be = R2(conv2)
+            fg3 = sage_eval(conv3.replace("tt",var), {'x':x}) ## should be = R2(conv3)
+            fg4 = sage_eval(conv4.replace("tt",var), {'x':x}) ## should be = R2(conv4)
             if a1-b1<a2-b2:
                 if a2+b1!=a1+b2:
@@ -628,6 +658,6 @@
                 else:
                     h = Piecewise([[(a1+b1,a2+b1),fg1],[(a2+b1,a2+b2),fg3]])
-            #return h.unextend()
             return h
+        
         if len(f.intervals())>1 or len(g.intervals())>1:
             z = Piecewise([[(-3*abs(N-M),3*abs(N-M)),0*xx**0]])
@@ -660,5 +690,5 @@
             sage: f = Piecewise([[(0,pi/2),f1],[(pi/2,pi),f2]])
             sage: f.derivative()
-            Piecewise defined function with 2 parts, [[(0, (pi/2)), 0], [((pi/2), pi), 0]]
+            Piecewise defined function with 2 parts, [[(0, pi/2), 0], [(pi/2, pi), 0]]
         """
         maxima = sage.interfaces.all.maxima
@@ -667,5 +697,7 @@
         diffs = [maxima('%s'%p[1](x)).diff('x') \
                  for p in self.list()]  
-        dlist = [[(p[0][0], p[0][1]), R(sage_eval(str(maxima('%s'%p[1](x)).diff('x')).replace("%","")))] for p in self.list()]
+        dlist = [[(p[0][0], p[0][1]),
+            R(sage_eval(repr(maxima('%s'%p[1](x)).diff('x')).replace("%",""),
+                {'x':x}))] for p in self.list()]
         return Piecewise(dlist)
  
@@ -692,5 +724,5 @@
         return Piecewise(dlist)
         
-    def plot(self, **kwds):
+    def plot(self, *args, **kwds):
         """
         Returns the plot of self.
@@ -712,5 +744,5 @@
         """
         plot = sage.plot.plot.plot
-        return sum([plot(p[1], p[0][0], p[0][1], **kwds ) for p in self.list()])
+        return sum([plot(p[1], p[0][0], p[0][1], *args, **kwds ) for p in self.list()])
  
     def fourier_series_cosine_coefficient(self,n,L):
@@ -730,5 +762,5 @@
             sage: f = Piecewise([[(-1,1),f]])
             sage: f.fourier_series_cosine_coefficient(2,1)
-            (1/(pi^2))
+            1/pi^2
 	    sage: f = lambda x:x^2
             sage: f = Piecewise([[(-pi,pi),f]])
@@ -739,5 +771,5 @@
             sage: f = Piecewise([[(0,pi/2),f1],[(pi/2,pi),f2]])
             sage: f.fourier_series_cosine_coefficient(5,pi)
-            (-3/(5*pi))
+            -3/(5*pi)
         """
         maxima = sage.interfaces.all.maxima
@@ -747,11 +779,11 @@
             fcn = '(%s)*cos('%p[1](x) + 'pi*x*%s/%s)/%s'%(n,L,L)
             fcn = fcn.replace("pi","%"+"pi")
-	    a = str(p[0][0]).replace("pi","%"+"pi")
-	    b = str(p[0][1]).replace("pi","%"+"pi")
+	    a = repr(p[0][0]).replace("pi","%"+"pi")
+	    b = repr(p[0][1]).replace("pi","%"+"pi")
 	    cmd = "integrate("+fcn+", x, %s, %s )"%(a, b)
 	    int = maxima(cmd).trigsimp()
             ints.append(int)
         ans = sum(ints)
-        return sage_eval(str(ans).replace("%",""))
+        return meval(repr(ans))
 
     def fourier_series_sine_coefficient(self,n,L):
@@ -779,11 +811,11 @@
             fcn = '(%s)*sin('%p[1](x) + 'pi*x*%s/%s)/%s'%(n,L,L)
             fcn = fcn.replace("pi","%"+"pi")
-	    a = str(p[0][0]).replace("pi","%"+"pi")
-	    b = str(p[0][1]).replace("pi","%"+"pi")
+	    a = repr(p[0][0]).replace("pi","%"+"pi")
+	    b = repr(p[0][1]).replace("pi","%"+"pi")
 	    cmd = "integrate("+fcn+", x, %s, %s )"%(a, b)
 	    int = maxima(cmd).trigsimp()
             ints.append(int)
         ans = sum(ints)
-        return sage_eval(str(ans).replace("%",""))
+        return meval(repr(ans))
 
     def fourier_series_partial_sum(self,N,L):
@@ -800,20 +832,19 @@
             sage: f = Piecewise([[(-1,1),f]])
             sage: f.fourier_series_partial_sum(3,1)
-            '1/3 + ((-4/(pi^2))*cos(1*pi*x/1) + 0*sin(1*pi*x/1)) + ((1/(pi^2))*cos(2*pi*x/1) + 0*sin(2*pi*x/1))'
+            cos(2*pi*x)/pi^2 - (4*cos(pi*x)/pi^2) + 1/3
             sage: f1 = lambda x:-1
             sage: f2 = lambda x:2
             sage: f = Piecewise([[(0,pi/2),f1],[(pi/2,pi),f2]])
             sage: f.fourier_series_partial_sum(3,pi)
-            '1/4 + ((-3/pi)*cos(1*pi*x/pi) + (1/pi)*sin(1*pi*x/pi)) + (0*cos(2*pi*x/pi) + (-3/pi)*sin(2*pi*x/pi))'
-
+            -3*sin(2*x)/pi + sin(x)/pi - (3*cos(x)/pi) + 1/4
         """
         a0 = self.fourier_series_cosine_coefficient(0,L)
-        A = [str(self.fourier_series_cosine_coefficient(n,L))+"*cos(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
-        B = [str(self.fourier_series_sine_coefficient(n,L))+"*sin(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
+        A = [repr(self.fourier_series_cosine_coefficient(n,L))+"*cos(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
+        B = [repr(self.fourier_series_sine_coefficient(n,L))+"*sin(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
         FS =  ["("+A[i] +" + " + B[i]+")" for i in range(0,N-1)]
-        sumFS = str(a0/2)+" + "
+        sumFS = repr(a0/2)+" + "
         for s in FS:
             sumFS = sumFS+s+ " + "
-        return sumFS[:-3]
+        return meval(sumFS[:-3])
   
     def fourier_series_partial_sum_cesaro(self,N,L):
@@ -830,20 +861,20 @@
             sage: f = Piecewise([[(-1,1),f]])
             sage: f.fourier_series_partial_sum_cesaro(3,1)
-            '1/3 + ((2/3*(-4/(pi^2)))*cos(1*pi*x/1) + 0*sin(1*pi*x/1)) + ((1/3*(1/(pi^2)))*cos(2*pi*x/1) + 0*sin(2*pi*x/1))'
+            cos(2*pi*x)/(3*pi^2) - (8*cos(pi*x)/(3*pi^2)) + 1/3
             sage: f1 = lambda x:-1
             sage: f2 = lambda x:2
             sage: f = Piecewise([[(0,pi/2),f1],[(pi/2,pi),f2]])
             sage: f.fourier_series_partial_sum_cesaro(3,pi)
-            '1/4 + ((2/3*(-3/pi))*cos(1*pi*x/pi) + (2/3*(1/pi))*sin(1*pi*x/pi)) + (0*cos(2*pi*x/pi) + (1/3*(-3/pi))*sin(2*pi*x/pi))'
+            -sin(2*x)/pi + 2*sin(x)/(3*pi) - (2*cos(x)/pi) + 1/4
 
         """
         a0 = self.fourier_series_cosine_coefficient(0,L)
-        A = [str((1-n/N)*self.fourier_series_cosine_coefficient(n,L))+"*cos(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
-        B = [str((1-n/N)*self.fourier_series_sine_coefficient(n,L))+"*sin(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
+        A = [repr((1-n/N)*self.fourier_series_cosine_coefficient(n,L))+"*cos(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
+        B = [repr((1-n/N)*self.fourier_series_sine_coefficient(n,L))+"*sin(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
         FS =  ["("+A[i] +" + " + B[i]+")" for i in range(0,N-1)]
-        sumFS = str(a0/2)+" + "
+        sumFS = repr(a0/2)+" + "
         for s in FS:
             sumFS = sumFS+s+ " + "
-        return sumFS[:-3]
+        return meval(sumFS[:-3])
 
     def fourier_series_partial_sum_hann(self,N,L):
@@ -860,20 +891,19 @@
             sage: f = Piecewise([[(-1,1),f]])
             sage: f.fourier_series_partial_sum_hann(3,1)
-            '1/3 + ((1+cos(pi*1/3))*(0.5*(-4/(pi^2)))*cos(1*pi*x/1) + (1+cos(pi*1/3))*0.0*sin(1*pi*x/1)) + ((1+cos(pi*2/3))*(0.5*(1/(pi^2)))*cos(2*pi*x/1) + (1+cos(pi*2/3))*0.0*sin(2*pi*x/1))'
+            0.500000000000000*(cos(2*pi/3) + 1)*cos(2*pi*x)/pi^2 - (2.00000000000000*(cos(pi/3) + 1)*cos(pi*x)/pi^2) + 1/3
             sage: f1 = lambda x:-1
             sage: f2 = lambda x:2
             sage: f = Piecewise([[(0,pi/2),f1],[(pi/2,pi),f2]])
             sage: f.fourier_series_partial_sum_hann(3,pi)
-            '1/4 + ((1+cos(pi*1/3))*(0.5*(-3/pi))*cos(1*pi*x/pi) + (1+cos(pi*1/3))*(0.5*(1/pi))*sin(1*pi*x/pi)) + ((1+cos(pi*2/3))*0.0*cos(2*pi*x/pi) + (1+cos(pi*2/3))*(0.5*(-3/pi))*sin(2*pi*x/pi))'
-
+            -1.50000000000000*(cos(2*pi/3) + 1)*sin(2*x)/pi + 0.500000000000000*(cos(pi/3) + 1)*sin(x)/pi - (1.50000000000000*(cos(pi/3) + 1)*cos(x)/pi) + 1/4
         """
         a0 = self.fourier_series_cosine_coefficient(0,L)
-        A = ["(1+cos(pi*%s/%s))*"%(n,N)+str((0.5)*self.fourier_series_cosine_coefficient(n,L))+"*cos(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
-        B = ["(1+cos(pi*%s/%s))*"%(n,N)+str((0.5)*self.fourier_series_sine_coefficient(n,L))+"*sin(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
+        A = ["(1+cos(pi*%s/%s))*"%(n,N)+repr((0.5)*self.fourier_series_cosine_coefficient(n,L))+"*cos(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
+        B = ["(1+cos(pi*%s/%s))*"%(n,N)+repr((0.5)*self.fourier_series_sine_coefficient(n,L))+"*sin(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
         FS =  ["("+A[i] +" + " + B[i]+")" for i in range(0,N-1)]
-        sumFS = str(a0/2)+" + "
+        sumFS = repr(a0/2)+" + "
         for s in FS:
             sumFS = sumFS+s+ " + "
-        return sumFS[:-3]
+        return meval(sumFS[:-3])
 
     def fourier_series_partial_sum_filtered(self,N,L,F):
@@ -891,20 +921,19 @@
             sage: f = Piecewise([[(-1,1),f]])
             sage: f.fourier_series_partial_sum_filtered(3,1,[1,1,1])
-            '1/3 + ((1*(-4/(pi^2)))*cos(1*pi*x/1) + 0*sin(1*pi*x/1)) + ((1*(1/(pi^2)))*cos(2*pi*x/1) + 0*sin(2*pi*x/1))'
+            cos(2*pi*x)/pi^2 - (4*cos(pi*x)/pi^2) + 1/3
             sage: f1 = lambda x:-1
             sage: f2 = lambda x:2
             sage: f = Piecewise([[(0,pi/2),f1],[(pi/2,pi),f2]])
             sage: f.fourier_series_partial_sum_filtered(3,pi,[1,1,1])
-            '1/4 + ((1*(-3/pi))*cos(1*pi*x/pi) + (1*(1/pi))*sin(1*pi*x/pi)) + (0*cos(2*pi*x/pi) + (1*(-3/pi))*sin(2*pi*x/pi))'
-
+            -3*sin(2*x)/pi + sin(x)/pi - (3*cos(x)/pi) + 1/4
         """
         a0 = self.fourier_series_cosine_coefficient(0,L)
-        A = [str((F[n])*self.fourier_series_cosine_coefficient(n,L))+"*cos(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
-        B = [str((F[n])*self.fourier_series_sine_coefficient(n,L))+"*sin(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
+        A = [repr((F[n])*self.fourier_series_cosine_coefficient(n,L))+"*cos(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
+        B = [repr((F[n])*self.fourier_series_sine_coefficient(n,L))+"*sin(%s*pi*x/%s)"%(n,L) for n in range(1,N)]
         FS =  ["("+A[i] +" + " + B[i]+")" for i in range(0,N-1)]
-        sumFS = str(a0/2)+" + "
+        sumFS = repr(a0/2)+" + "
         for s in FS:
             sumFS = sumFS+s+ " + "
-        return sumFS[:-3]
+        return meval(sumFS[:-3])
 	
     def plot_fourier_series_partial_sum(self,N,L,xmin,xmax, **kwds):
@@ -941,6 +970,6 @@
             pi = 3.14159265
             xi = xmin + i*h
-            yi = ff.replace("pi",str(RR(pi)))
-            yi = sage_eval(yi.replace("x",str(xi)))
+            yi = ff.replace("pi",repr(RR(pi)))
+            yi = sage_eval(yi.replace("x",repr(xi)))
             pts.append([xi,yi])
         return line(pts, **kwds)
@@ -979,6 +1008,6 @@
             pi = 3.14159265
             xi = xmin + i*h
-            yi = ff.replace("pi",str(RR(pi)))
-            yi = sage_eval(yi.replace("x",str(xi)))
+            yi = ff.replace("pi",repr(RR(pi)))
+            yi = sage_eval(yi.replace("x",repr(xi)))
             pts.append([xi,yi])
         return line(pts, **kwds)
@@ -1017,6 +1046,6 @@
             pi = 3.14159265
             xi = xmin + i*h
-            yi = ff.replace("pi",str(RR(pi)))
-            yi = sage_eval(yi.replace("x",str(xi)))
+            yi = ff.replace("pi",repr(RR(pi)))
+            yi = sage_eval(yi.replace("x",repr(xi)))
             pts.append([xi,yi])
         return line(pts, **kwds)
@@ -1057,6 +1086,6 @@
             pi = 3.14159265
             xi = xmin + i*h
-            yi = ff.replace("pi",str(RR(pi)))
-            yi = sage_eval(yi.replace("x",str(xi)))
+            yi = ff.replace("pi",repr(RR(pi)))
+            yi = sage_eval(yi.replace("x",repr(xi)))
             pts.append([xi,yi])
         return line(pts, **kwds)
@@ -1139,5 +1168,5 @@
             0
             sage: f.cosine_series_coefficient(3,1)
-            (-4/(9*(pi^2)))
+            -4/(9*pi^2)
             sage: f1 = lambda x:-1
             sage: f2 = lambda x:2
@@ -1146,7 +1175,7 @@
             0
             sage: f.cosine_series_coefficient(3,pi)
-            (2/pi)
+            2/pi
             sage: f.cosine_series_coefficient(111,pi)
-            (2/(37*pi))
+            2/(37*pi)
 
         """
@@ -1157,11 +1186,12 @@
             fcn = '2*(%s)*cos('%p[1](x) + 'pi*x*%s/%s)/%s'%(n,L,L)
             fcn = fcn.replace("pi","%"+"pi")
-	    a = str(p[0][0]).replace("pi","%"+"pi")
-	    b = str(p[0][1]).replace("pi","%"+"pi")
+	    a = repr(p[0][0]).replace("pi","%"+"pi")
+	    b = repr(p[0][1]).replace("pi","%"+"pi")
 	    cmd = "integrate("+fcn+", x, %s, %s )"%(a, b)
 	    I = maxima(cmd).trigsimp()
             ints.append(I)
         ans = sum(ints)
-        return sage_eval(str(ans).replace("%",""))
+        return meval(repr(ans))
+
 
     def sine_series_coefficient(self,n,L):
@@ -1187,6 +1217,5 @@
             0
             sage: f.sine_series_coefficient(3,1)
-            (4/(3*pi))
-
+            4/(3*pi)
         """
 	maxima = sage.interfaces.all.maxima
@@ -1196,54 +1225,48 @@
             fcn = '2*(%s)*sin('%p[1](x) + 'pi*x*%s/%s)/%s'%(n,L,L)
             fcn = fcn.replace("pi","%"+"pi")
-	    a = str(p[0][0]).replace("pi","%"+"pi")
-	    b = str(p[0][1]).replace("pi","%"+"pi")
+	    a = repr(p[0][0]).replace("pi","%"+"pi")
+	    b = repr(p[0][1]).replace("pi","%"+"pi")
 	    cmd = "integrate("+fcn+", x, %s, %s )"%(a, b)
 	    I = maxima(cmd).trigsimp()
             ints.append(I)
         ans = sum(ints)
-        return sage_eval(str(ans).replace("%",""))
-
-    def laplace_transform(self,var = "s",latex_output=0):
-        r"""
-        Returns the laplace transform of self, as a function of var.
+        return meval(repr(ans))
+
+    def laplace(self, x, s):
+        r"""
+        Returns the Laplace transform of self with respect to the
+        variable var.
+
+        INPUT:
+            x -- variable of self
+            s -- variable of Laplace transform.
+
         We assume that a piecewise function is 0 outside of its domain
         and that the left-most endpoint of the domain is 0.
 
         EXAMPLES:
-            sage: f1 = lambda x:1
-            sage: f2 = lambda x:1-x
-            sage: f = Piecewise([[(0,1),f1],[(1,2),f2]])
-            sage: f.laplace_transform()
-            '1/s - e^-s/s + (s + 1)*e^-(2*s)/s^2 - e^-s/s^2'
-            sage: f.laplace_transform("w",latex_output=1)
-            ' - {{e^{ - w}}\\over{w}} - {{e^{ - w}}\\over{w^2}} + {{\\left(w + 1\\right)\\,e^{ - 2\\,w}}\\over{w^2}} + {{1}\\over{w}}'
-            sage: f.laplace_transform("w",True)
-            ' - {{e^{ - w}}\\over{w}} - {{e^{ - w}}\\over{w^2}} + {{\\left(w + 1\\right)\\,e^{ - 2\\,w}}\\over{w^2}} + {{1}\\over{w}}'
-            sage: f.laplace_transform("w")
-            '1/w - e^-w/w + (w + 1)*e^-(2*w)/w^2 - e^-w/w^2'
-
-        """
-        maxima = sage.interfaces.all.maxima
-        x = PolynomialRing(QQ,'x').gen()
+            sage: f = Piecewise([[(0,1),1],[(1,2), 1-x]])
+            sage: f.laplace(x, s)
+            -e^(-s)/s - (e^(-s)/s^2) + (s + 1)*e^(-2*s)/s^2 + 1/s
+            sage: f.laplace(x, w)
+            -e^(-w)/w - (e^(-w)/w^2) + (w + 1)*e^(-2*w)/w^2 + 1/w
+
+            sage: f = Piecewise([[(1,2), 1-y]]) 
+            sage: f.laplace(y, t)
+            (t + 1)*e^(-2*t)/t^2 - (e^(-t)/t^2)
+        """
+        x = var(x)
+        s = var(s)
         ints = []
         for p in self.list():
-            fcn = '(%s)*exp(-%s*x)'%(p[1](x),var)
-            ints.append(maxima(fcn).integral('x', p[0][0], p[0][1]))  
+            g = SR(p[1])
+            fcn = maxima('(%s)*exp(-%s*%s)'%(g._maxima_init_(), s, x))
+            ints.append(fcn.integral(x, p[0][0], p[0][1]))
         ans = ""
-        ans_latex = ""
         for i in range(len(ints)-1):
-            ans = ans+str(ints[i]).replace("%","")+" + "
-            ans_latex = ans_latex+str(ints[i])+" + "
-        ans = ans+str(ints[len(ints)-1]).replace("%","")
-        ans_latex = ans_latex + str(ints[len(ints)-1])
-        
-        if latex_output == 0:
-            return ans
-        if latex_output == 1:
-            ans0 = maxima.eval("tex("+ans_latex+")")
-            ans0 = ans0.replace("$$","")
-            ans0 = ans0.replace("false","")
-            return ans0
-
+            ans = ans+repr(ints[i]) + " + "
+        ans = ans+repr(ints[len(ints)-1])
+        return meval(ans)
+    
     def __add__(self,other):
 	"""
Index: sage/functions/special.py
===================================================================
--- sage/functions/special.py	(revision 2641)
+++ sage/functions/special.py	(revision 4053)
@@ -1,3 +1,3 @@
-r"""nodoctest -- TODO remove
+r"""
 Special Functions
 
@@ -5,5 +5,6 @@
    -- David Joyner (2006-13-06)
 
-Some of Maxima's and Pari's special functions are wrapped.
+This module provides easy access to many of Maxima and PARI's
+special functions.
 
 Maxima's special functions package (which includes spherical harmonic
@@ -331,12 +332,17 @@
 from sage.rings.rational_field import RationalField
 from sage.rings.real_mpfr import RealField
+from sage.rings.complex_field import ComplexField
 from sage.misc.sage_eval import sage_eval
-from sage.rings.all import QQ, RR
+from sage.rings.all import ZZ, QQ, RR
 import sage.rings.commutative_ring as commutative_ring
 import sage.rings.ring as ring
 
+from sage.interfaces.maxima import maxima
+
+def meval(x):
+    from sage.calculus.calculus import symbolic_expression_from_maxima_element
+    return symbolic_expression_from_maxima_element(maxima(x))
+
 from functions import *
-
-from sage.misc.functional import exp
 
 _done = False
@@ -355,4 +361,9 @@
     return RR, a
 
+def _setup_CC(prec):
+    from sage.libs.pari.all import pari
+    CC = ComplexField(prec) 
+    a = pari.set_real_precision(int(prec/3.3)+1)    ## 3.3 < log(10,2)
+    return CC, a
 
 def bessel_I(nu,z,alg = "pari",prec=53):
@@ -399,7 +410,7 @@
     EXAMPLES:
         sage: bessel_I(1,1,"pari",500)
-        0.56515910399248502720769602760986330732889962162109200948029448947925564096437113409266499776681441006467788605552630267685763768491717981204113120812118
+        0.565159103992485027207696027609863307328899621621092009480294489479255640964371134092664997766814410064677886055526302676857637684917179812041131208121
         sage: bessel_I(1,1)
-        0.56515910399248503
+        0.565159103992485
         sage: bessel_I(2,1.1,"maxima")  # last few digits are random
         0.16708949925104899
@@ -416,5 +427,5 @@
         return b
     else:
-        return eval(maxima.eval("bessel_i(%s,%s)"%(float(nu),float(z))))
+        return sage_eval(maxima.eval("bessel_i(%s,%s)"%(float(nu),float(z))))
         
 def bessel_J(nu,z,alg="pari",prec=53):
@@ -473,10 +484,12 @@
     if alg=="pari":
         from sage.libs.pari.all import pari
-        R,a = _setup(prec)
-        b = R(pari(z).besselj(nu))
+        K,a = _setup(prec)
+        if not (z in K):
+            K, a = _setup_CC(prec)
+        b = K(pari(z).besselj(nu))
         pari.set_real_precision(a)
         return b
     else:
-        return RR(maxima.eval("bessel_j(%s,%s)"%(float(nu),float(z))))
+        return meval("bessel_j(%s,%s)"%(nu, z))
 
 def bessel_K(nu,z,prec=53):
@@ -500,7 +513,7 @@
     EXAMPLES:
         sage: bessel_K(1,1)
-        0.60190723019723458
+        0.601907230197235
         sage: bessel_K(1,1,500)
-        0.60190723019723457473754000153561733926158688996810645601776795916855358294623784016886370695825821535464409978314005090846929281349329460565572696199608
+        0.601907230197234574737540001535617339261586889968106456017767959168553582946237840168863706958258215354644099783140050908469292813493294605655726961996
     """
     from sage.libs.pari.all import pari
@@ -551,7 +564,7 @@
     EXAMPLES:
         sage: hypergeometric_U(1,1,1)
-        0.59634736232319407
+        0.596347362323194
         sage: hypergeometric_U(1,1,1,70)
-        0.59634736232319407434152
+        0.59634736232319407434
     """
     from sage.libs.pari.all import pari
@@ -561,59 +574,23 @@
     return b
 
-def incomplete_gamma(s,x,prec=53):
-    r"""
-    Implements the incomplete Gamma function.
-
-    INPUT:
-        s, x -- ocmplex numbers.
-        prec -- bits of precision.
-
-    The argument x and s are complex numbers
-    (x must be a positive real number if s = 0).
-    The result returned is $\int_x^\infty e^{-t}t^{s-1}dt$.
-
-    EXAMPLES:
-        sage: incomplete_gamma(0.1,6,200)
-        119.99999984701215693242493354706493878953914933130704861011488
-        sage: incomplete_gamma(0,6,200)
-        120.00000000000000000000000000000000000000000000000000000000000
-        sage: incomplete_gamma(0.3,6,200)
-        119.99990598341125737887779259683594390225182610507857843438320
-        sage: incomplete_gamma(0.3,6)
-        119.99990598341125
-        sage: incomplete_gamma(0.5,6)
-        119.99830020752132
-        sage: incomplete_gamma(0.5,6,100)
-        119.99830020752131890111421425093
-    """
-    from sage.libs.pari.all import pari
-    R,a = _setup(prec)
-    b = R(pari(x).incgam(s))
-    pari.set_real_precision(a)
-    return b
-
-def spherical_bessel_J(n,x):
+def spherical_bessel_J(n, var):
     r"""
     Returns the spherical Bessel function of the first kind
     for integers n > -1.
+    
     Reference: A&S 10.1.8 page 437 and A&S 10.1.15 page 439.
 
     EXAMPLES:
-        sage: x = PolynomialRing(QQ, 'x').gen()
         sage: spherical_bessel_J(2,x)
-        '( - (1 - 24/(8*x^2))*sin(x) - 3*cos(x)/x)/x'
-
-    Here I = sqrt(-1).
-    
+        ((-(1 - (24/(8*x^2))))*sin(x) - (3*cos(x)/x))/x
     """
     _init()
-    R = x.parent()
-    y = R.gen()
-    return maxima.eval("spherical_bessel_j(%s,%s)"%(n,y)).replace("%i","I")
-
-def spherical_bessel_Y(n,x):
+    return meval("spherical_bessel_j(%s,%s)"%(ZZ(n),var))
+
+def spherical_bessel_Y(n,var):
     r"""
     Returns the spherical Bessel function of the second kind
     for integers n > -1.
+    
     Reference: A&S 10.1.9 page 437 and A&S 10.1.15 page 439.
 
@@ -621,15 +598,10 @@
         sage: x = PolynomialRing(QQ, 'x').gen()
         sage: spherical_bessel_Y(2,x)
-        '-(3*sin(x)/x - (1 - 24/(8*x^2))*cos(x))/x'
-
-    Here I = sqrt(-1).
-    
+        (-(3*sin(x)/x - (1 - (24/(8*x^2)))*cos(x)))/x
     """
     _init()
-    R = x.parent()
-    y = R.gen()
-    return maxima.eval("spherical_bessel_y(%s,%s)"%(n,y)).replace("%i","I")
-
-def spherical_hankel1(n,x):
+    return meval("spherical_bessel_y(%s,%s)"%(ZZ(n),var))
+
+def spherical_hankel1(n,var):
     r"""
     Returns the spherical Hankel function of the first
@@ -639,12 +611,8 @@
     EXAMPLES:
         sage: spherical_hankel1(2,'x')
-        '-3*I*( - x^2/3 - I*x + 1)*%e^(I*x)/x^3'
-
-    Here I = sqrt(-1).
-    
+        -3*I*(-x^2/3 - I*x + 1)*e^(I*x)/x^3
     """
     _init()
-    y = str(x)
-    return maxima.eval("spherical_hankel1(%s,%s)"%(n,y)).replace("%i","I")
+    return meval("spherical_hankel1(%s,%s)"%(ZZ(n),var))
 
 def spherical_hankel2(n,x):
@@ -656,5 +624,5 @@
     EXAMPLES:
         sage: spherical_hankel2(2,'x')
-        '3*I*( - x^2/3 + I*x + 1)*%e^-(I*x)/x^3'
+        '3*I*(-x^2/3+I*x+1)*%e^-(I*x)/x^3'
 
     Here I = sqrt(-1).
@@ -672,30 +640,11 @@
 
     EXAMPLES:
-        sage: x = PolynomialRing(QQ, 'x').gen()
-        sage: y = PolynomialRing(QQ, 'y').gen()
         sage: spherical_harmonic(3,2,x,y)
-        '15*sqrt(7)*cos(x)*sin(x)^2*e^(2*I*y)/(4*sqrt(30)*sqrt(pi))'
+        15*sqrt(7)*cos(x)*sin(x)^2*e^(2*I*y)/(4*sqrt(30)*sqrt(pi))
         sage: spherical_harmonic(3,2,1,2)
-        -0.25556469795208248 - 0.29589824630616246*I
-
-    Here I = sqrt(-1).
-    
+        15*sqrt(7)*e^(4*I)*cos(1)*sin(1)^2/(4*sqrt(30)*sqrt(pi))
     """
     _init()
-    if not(is_Polynomial(x) and is_Polynomial(y)):
-        s1 = maxima.eval("spherical_harmonic(%s,%s,%s,%s)"%(m,n,x,y))
-        s2 = s1.replace("%i","I")
-        s3 = s2.replace("%pi","pi")
-        s4 = s3.replace("%e","CC(e)")
-        return sage_eval(s4)
-    R = x.parent()
-    x1 = R.gen()
-    R = y.parent()
-    y1 = R.gen()
-    s1 = maxima.eval("spherical_harmonic(%s,%s,%s,%s)"%(m,n,x,y))
-    s2 = s1.replace("%i","I")
-    s3 = s2.replace("%pi","pi")
-    s4 = s3.replace("%e","e")
-    return s4
+    return meval("spherical_harmonic(%s,%s,%s,%s)"%(ZZ(m),ZZ(n),x,y))
 
 ####### elliptic functions and integrals 
@@ -710,18 +659,19 @@
     EXAMPLES:
         sage: jacobi("sn",1,1)
-        0.76159415595576485
+        tanh(1)
         sage: jacobi("cd",1,1/2)
-        0.72400972165937116
-        sage: jacobi("cn",1,1/2);jacobi("dn",1,1/2);jacobi("cn",1,1/2)/jacobi("dn",1,1/2)
-        0.59597656767214113
-        0.82316100163159622
-        0.72400972165937116
-        sage: jsn = lambda x: jacobi("sn",x,1)
-        sage: P= plot(jsn,0,1)
-
-    Now to view this, just type show(P).
-    
-    """
-    return eval(maxima.eval("jacobi_%s(%s,%s)"%(sym, float(x), float(m))))
+        jacobi_cd(1, 1/2)
+        sage: RDF(jacobi("cd",1,1/2))
+        0.724009721659
+        sage: RDF(jacobi("cn",1,1/2)); RDF(jacobi("dn",1,1/2)); RDF(jacobi("cn",1,1/2)/jacobi("dn",1,1/2))
+        0.595976567672
+        0.823161001632
+        0.724009721659
+        sage: jsn = jacobi("sn",x,1)
+        sage: P = plot(jsn,0,1)
+        sage.: P.show()
+    """
+    _init()
+    return meval("jacobi_%s(%s,%s)"%(sym, x, m))
 
 def inverse_jacobi(sym,x,m):
@@ -733,15 +683,17 @@
     EXAMPLES:
         sage: jacobi("sn",1/2,1/2)
+        jacobi_sn(1/2, 1/2)
+        sage: float(jacobi("sn",1/2,1/2))
         0.4707504736556572
-        sage: inverse_jacobi("sn",0.47,1/2)
+        sage: float(inverse_jacobi("sn",0.47,1/2))
         0.4990982313222197
-        sage: inverse_jacobi("sn",0.4707504,1/2)
+        sage: float(inverse_jacobi("sn",0.4707504,0.5))
         0.49999991146655459
-        sage: ijsn = lambda x: inverse_jacobi("sn",x,1/2)
-        sage: P= plot(ijsn,0,1)
+        sage: P = plot(inverse_jacobi('sn', x, 0.5), 0, 1, plot_points=20)
 
     Now to view this, just type show(P).
     """
-    return eval(maxima.eval("inverse_jacobi_%s(%s,%s)"%(sym, float(x),float(m))))
+    _init()
+    return meval("inverse_jacobi_%s(%s,%s)"%(sym, x,m))
 
 #### elliptic integrals
@@ -750,39 +702,35 @@
 #### of Jacobi elliptic functions but faster to evaluate directly)
 
-def sinh(t):
-    try:
-        return t.sinh()
-    except AttributeError:
-        return (exp(t)-exp(-t))/2
-
-def cosh(t):
-    try:
-        return t.cosh()
-    except AttributeError:
-        return (exp(t)+exp(-t))/2
-
-def tanh(t):
-    try:
-        return t.tanh()
-    except AttributeError:
-        return sinh(t)/cosh(t)
-
-def coth(t):
-    try:
-        return t.coth()
-    except AttributeError:
-        return 1/tanh(t)
-
-def sech(t):
-    try:
-        return t.sech()
-    except AttributeError:
-        return 1/cosh(t)
-
-def csch(t):
-    try:
-        return t.csch()
-    except AttributeError:
-        return 1/sinh(t)
+## def sinh(t):
+##     try:
+##         return t.sinh()
+##     except AttributeError:
+##         from sage.calculus.calculus import exp
+##         return (exp(t)-exp(-t))/2
+
+## def cosh(t):
+##     try:
+##         return t.cosh()
+##     except AttributeError:
+##         from sage.calculus.calculus import exp        
+##         return (exp(t)+exp(-t))/2
+
+## def coth(t):
+##     try:
+##         return t.coth()
+##     except AttributeError:
+##         return 1/tanh(t)
+
+## def sech(t):
+##     try:
+##         return t.sech()
+##     except AttributeError:
+##         return 1/cosh(t)
+
+## def csch(t):
+##     try:
+##         return t.csch()
+##     except AttributeError:
+##         return 1/sinh(t)
 
 def dilog(t):
Index: sage/functions/transcendental.py
===================================================================
--- sage/functions/transcendental.py	(revision 3301)
+++ sage/functions/transcendental.py	(revision 4055)
@@ -148,16 +148,11 @@
         sage: zeta(RR(2))
         1.6449340668482264364724151666460251892189499012067984377356
+        sage: zeta(I)
+        0.00330022368532410 - 0.418155449141322*I
     """
     try:
         return s.zeta()
     except AttributeError:
-        return RealField()(s).zeta()
-
-##     prec = s.prec()
-##     s = pari.new_with_prec(s, prec)
-##     z = s.zeta()._sage_()
-##     if z.prec() < prec:
-##         raise RuntimeError, "Error computing zeta(%s) -- precision loss."%s
-##     return z
+        return ComplexField()(s).zeta()
 
 def zeta_symmetric(s):
Index: sage/geometry/lattice_polytope.py
===================================================================
--- sage/geometry/lattice_polytope.py	(revision 2915)
+++ sage/geometry/lattice_polytope.py	(revision 4061)
@@ -1098,5 +1098,5 @@
         Return a string representation of this face.
         """
-        return str(self._vertices)
+        return repr(self._vertices)
 
     def boundary_points(self):
Index: sage/graphs/graph.py
===================================================================
--- sage/graphs/graph.py	(revision 3741)
+++ sage/graphs/graph.py	(revision 4359)
@@ -8,5 +8,5 @@
         NetworkX-0.33, fixed plotting bugs
                         (2007-01-23): basic tutorial, edge labels, loops,
-        multiple edges & arcs
+                                      multiple edges and arcs
                         (2007-02-07): graph6 and sparse6 formats, matrix input
     -- Emily Kirkmann (2007-02-11): added graph_border option to plot and show
@@ -216,4 +216,7 @@
 from sage.plot.plot import Graphics, GraphicPrimitive_NetworkXGraph
 import sage.graphs.graph_fast as graph_fast
+from sage.rings.integer import Integer
+from sage.rings.integer_ring import ZZ
+
 
 class GenericGraph(SageObject):
@@ -645,15 +648,19 @@
         return self._nxg.nodes()
 
-    def relabel(self, perm, inplace=True):
+    def relabel(self, perm, inplace=True, quick=False):
         r"""
         Uses a dictionary or permutation to relabel the (di)graph.
         If perm is a dictionary, each old vertex v is a key in the
         dictionary, and its new label is d[v]. If perm is a list,
-        we think of it as a map i \mapsto perm[i] (only for graphs
-        with V = {0,1,...,n-1} ). If perm is a per mutation, the
+        we think of it as a map $i \mapsto perm[i]$ (only for graphs
+        with $V = \{0,1,...,n-1\}$ ). If perm is a per mutation, the
         permutation is simply applied to the graph, under the
-        assumption that V = {0,1,...,n-1} is the vertex set, and
-        the permutation acts on the set {1,2,...,n}, where we think
-        of n = 0.
+        assumption that $V = \{0,1,...,n-1\}$ is the vertex set, and
+        the permutation acts on the set $\{1,2,...,n\}$, where we think
+        of $n = 0$.
+        
+        INPUT:
+            quick -- if True, simply return the enumeration of the new graph
+        without constructing it. Requires that perm is of type list.
         
         EXAMPLES:
@@ -689,4 +696,15 @@
         """
         if type(perm) == list:
+            if quick:
+                n = self.order()
+                numbr = 0
+                if isinstance(self, Graph):
+                    for i,j,l in self.edge_iterator():
+                        numbr += 1<<((n-(perm[i]+1))*n + n-(perm[j]+1))
+                        numbr += 1<<((n-(perm[j]+1))*n + n-(perm[i]+1))
+                elif isinstance(self, DiGraph):
+                    for i,j,l in self.arc_iterator():
+                        numbr += 1<<((n-(perm[i]+1))*n + n-(perm[j]+1))
+                return numbr
             if isinstance(self, Graph):
                 oldd = self._nxg.adj
@@ -808,5 +826,5 @@
     def plot(self, pos=None, layout=None, vertex_labels=True, edge_labels=False,
              node_size=200, graph_border=False, color_dict=None, partition=None,
-             edge_colors=None, scaling_term=0.05):
+             edge_colors=None, scaling_term=0.05, xmin=None, xmax=None):  # xmin and xmax are ignored
         """
         Returns a graphics object representing the (di)graph.
@@ -1141,5 +1159,4 @@
             if not isinstance(data, str):
                 raise ValueError, 'If input format is graph6, then data must be a string'
-            from sage.rings.integer import Integer
             n = data.find('\n')
             if n == -1:
@@ -1151,14 +1168,12 @@
             k = 0
             for i in range(n):
+                d[i] = {}
                 for j in range(i):
                     if m[k] == '1':
-                        if d.has_key(i):
-                            d[i][j] = None
-                        else:
-                            d[i] = {j : None}
+                        d[i][j] = None
                     k += 1
             self._nxg = networkx.XGraph(d)
         elif format == 'sparse6':
-            from sage.rings.arith import ceil, floor
+            from math import ceil, floor
             from sage.misc.functional import log
             n = data.find('\n')
@@ -1167,5 +1182,5 @@
             s = data[:n]
             n, s = graph_fast.N_inverse(s[1:])
-            k = ceil(log(n,2))
+            k = int(ceil(log(n,2)))
             l = [graph_fast.binary(ord(i)-63) for i in s]
             for i in range(len(l)):
@@ -1174,5 +1189,5 @@
             b = []
             x = []
-            for i in range(floor(len(bits)/(k+1))):
+            for i in range(int(floor(len(bits)/(k+1)))):
                 b.append(int(bits[(k+1)*i:(k+1)*i+1],2))
                 x.append(int(bits[(k+1)*i+1:(k+1)*i+k+1],2))
@@ -1910,7 +1925,7 @@
 
             # encode bit vector
-            from sage.rings.arith import ceil
+            from math import ceil
             from sage.misc.functional import log
-            k = ceil(log(n,2))
+            k = int(ceil(log(n,2)))
             v = 0
             i = 0
@@ -2022,5 +2037,8 @@
     ### Visualization
 
-    def plot3d(self, bgcolor=(1,1,1), vertex_color=(1,0,0), edge_color=(0,0,0), pos3d=None):
+    def plot3d(self, bgcolor=(1,1,1),
+               vertex_color=(1,0,0), vertex_size=0.06,
+               edge_color=(0,0,0), edge_size=0.02,
+               pos3d=None, **kwds):
         """
         Plots the graph using Tachyon, and returns a Tachyon object containing
@@ -2028,8 +2046,11 @@
         
         INPUT:
-            bgcolor
-            vertex_color
-            edge_color
+            bgcolor -- rgb tuple (default: (1,1,1))
+            vertex_color -- rgb tuple (default: (1,0,0))
+            vertex_size -- float (default: 0.06)
+            edge_color -- rgb tuple (default: (0,0,0))
+            edge_size -- float (default: 0.02)
             pos3d -- a position dictionary for the vertices
+            **kwds -- passed on to the Tachyon command
         
         EXAMPLES:
@@ -2044,9 +2065,10 @@
             sage: C.plot3d(edge_color=(0,1,0), vertex_color=(1,1,1), bgcolor=(0,0,0)).save('sage.png') # long time
         """
-        TT, pos3d = tachyon_vertex_plot(self, bgcolor=bgcolor, vertex_color=vertex_color, pos3d=pos3d)
+        TT, pos3d = tachyon_vertex_plot(self, bgcolor=bgcolor, vertex_color=vertex_color,
+                                        vertex_size=vertex_size, pos3d=pos3d, **kwds)
         TT.texture('edge', ambient=0.1, diffuse=0.9, specular=0.03, opacity=1.0, color=edge_color)
         for u,v,l in self.edges():
             TT.fcylinder( (pos3d[u][0],pos3d[u][1],pos3d[u][2]),\
-                          (pos3d[v][0],pos3d[v][1],pos3d[v][2]), .02,'edge')
+                          (pos3d[v][0],pos3d[v][1],pos3d[v][2]), edge_size,'edge')
         return TT
 
@@ -2205,5 +2227,8 @@
             else:
                 a = search_tree(self, partition, dict=False, lab=False, dig=self.loops())
-            a = PermutationGroup([perm_group_elt(aa) for aa in a])
+            if len(a) != 0:
+                a = PermutationGroup([perm_group_elt(aa) for aa in a])
+            else:
+                a = PermutationGroup([[]])
             if translation:
                 return a,b
@@ -3199,5 +3224,5 @@
         Returns a copy of digraph with arcs reversed in direction.
         
-        TODO: results in error because of the following NetworkX bug (0.33) - trac #92
+        TODO: results in error because of the following NetworkX bug (0.33) - trac 92
         
         EXAMPLES:
@@ -3248,5 +3273,9 @@
     ### Visualization
 
-    def plot3d(self, bgcolor=(1,1,1), vertex_color=(1,0,0), arc_color=(0,0,0), pos3d=None):
+    def plot3d(self, bgcolor=(1,1,1), vertex_color=(1,0,0),
+               vertex_size=0.06,
+               arc_size=0.02,
+               arc_size2=0.0325,
+               arc_color=(0,0,0), pos3d=None, **kwds):
         """
         Plots the graph using Tachyon, and returns a Tachyon object containing
@@ -3254,9 +3283,13 @@
         
         INPUT:
-            bgcolor
-            vertex_color
-            arc_color
+            bgcolor -- rgb tuple (default: (1,1,1))
+            vertex_color -- rgb tuple (default: (1,0,0))
+            vertex_size -- float (default: 0.06)
+            arc_color -- rgb tuple (default: (0,0,0))
+            arc_size -- float (default: 0.02)
+            arc_size2 -- float (default: 0.0325)   
             pos3d -- a position dictionary for the vertices
-        
+            **kwds -- passed on to the Tachyon command
+            
         NOTE:
             The weaknesses of the NetworkX spring layout are illustrated even further in the
@@ -3265,29 +3298,30 @@
         
         EXAMPLE:
-            # This is a running example
+        This is a running example
             
-            # A directed version of the dodecahedron
+        A directed version of the dodecahedron
             sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19], 19: []} )
             
-            # If I use an undirected version of my graph, the output is as expected
+        If I use an undirected version of my graph, the output is as expected
             sage: import networkx
             sage: pos3d=networkx.spring_layout(graphs.DodecahedralGraph()._nxg, dim=3)
             sage: D.plot3d(pos3d=pos3d).save('sage.png') # long time
             
-            # However, if I use the directed version, everything gets skewed bizarrely:
+        However, if I use the directed version, everything gets skewed bizarrely:
             sage: D.plot3d().save('sage.png') # long time
         """
-        TT, pos3d = tachyon_vertex_plot(self, bgcolor=bgcolor, vertex_color=vertex_color, pos3d=pos3d)
+        TT, pos3d = tachyon_vertex_plot(self, bgcolor=bgcolor, vertex_color=vertex_color,
+                                        vertex_size=vertex_size, pos3d=pos3d, **kwds)
         TT.texture('arc', ambient=0.1, diffuse=0.9, specular=0.03, opacity=1.0, color=arc_color)
         for u,v,l in self.arcs():
             TT.fcylinder( (pos3d[u][0],pos3d[u][1],pos3d[u][2]),\
-                          (pos3d[v][0],pos3d[v][1],pos3d[v][2]), .02,'arc')
+                          (pos3d[v][0],pos3d[v][1],pos3d[v][2]), arc_size,'arc')
             TT.fcylinder( (0.25*pos3d[u][0] + 0.75*pos3d[v][0],\
                            0.25*pos3d[u][1] + 0.75*pos3d[v][1],\
                            0.25*pos3d[u][2] + 0.75*pos3d[v][2],),
-                          (pos3d[v][0],pos3d[v][1],pos3d[v][2]), .0325,'arc')
+                          (pos3d[v][0],pos3d[v][1],pos3d[v][2]), arc_size2,'arc')
         return TT
 
-    def show3d(self, bgcolor=(1,1,1), vertex_color=(1,0,0), edge_color=(0,0,0), pos3d=None, **kwds):
+    def show3d(self, bgcolor=(1,1,1), vertex_color=(1,0,0), arc_color=(0,0,0), pos3d=None, **kwds):
         """
         Plots the graph using Tachyon, and shows the resulting plot.
@@ -3305,15 +3339,15 @@
         
         EXAMPLE:
-            # This is a running example
+        This is a running example
             
-            # A directed version of the dodecahedron
+        A directed version of the dodecahedron
             sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19], 19: []} )
             
-            # If I use an undirected version of my graph, the output is as expected
+        If I use an undirected version of my graph, the output is as expected
             sage: import networkx
             sage: pos3d=networkx.spring_layout(graphs.DodecahedralGraph()._nxg, dim=3)
             sage: D.plot3d(pos3d=pos3d).save('sage.png') # long time
             
-            # However, if I use the directed version, everything gets skewed bizarrely:
+        However, if I use the directed version, everything gets skewed bizarrely:
             sage: D.plot3d().save('sage.png') # long time
         """
@@ -3351,5 +3385,8 @@
             else:
                 a = search_tree(self, partition, dict=False, lab=False, dig=True)
-            a = PermutationGroup([perm_group_elt(aa) for aa in a])
+            if len(a) != 0:
+                a = PermutationGroup([perm_group_elt(aa) for aa in a])
+            else:
+                a = PermutationGroup([[]])
             if translation:
                 return a,b
@@ -3383,5 +3420,5 @@
                             break
                 return True, map
-            else:
+            else: 
                 return False, None
         else:
@@ -3411,5 +3448,8 @@
             return b
 
-def tachyon_vertex_plot(g, bgcolor=(1,1,1), vertex_color=(1,0,0), pos3d=None):
+def tachyon_vertex_plot(g, bgcolor=(1,1,1),
+                        vertex_color=(1,0,0),
+                        vertex_size=0.06,
+                        pos3d=None, **kwds):
     import networkx
     from math import sqrt
@@ -3442,5 +3482,5 @@
         pos3d[v][1] = pos3d[v][1]/r
         pos3d[v][2] = pos3d[v][2]/r
-    TT = Tachyon(camera_center=(1.4,1.4,1.4), antialiasing=13)
+    TT = Tachyon(camera_center=(1.4,1.4,1.4), antialiasing=13, **kwds)
     TT.light((4,3,2), 0.02, (1,1,1))
     TT.texture('node', ambient=0.1, diffuse=0.9, specular=0.03, opacity=1.0, color=vertex_color)
@@ -3448,34 +3488,48 @@
     TT.plane((-1.6,-1.6,-1.6), (1.6,1.6,1.6), 'bg')
     for v in verts:
-        TT.sphere((pos3d[v][0],pos3d[v][1],pos3d[v][2]), .06, 'node')
+        TT.sphere((pos3d[v][0],pos3d[v][1],pos3d[v][2]), vertex_size, 'node')
     return TT, pos3d
 
-def enum(graph):
+def enum(graph, quick=False):
     """
     Used for isomorphism checking.
+    
+    INPUT:
+        quick -- now we know that the vertices are 0,1,...,n-1
     
     EXAMPLES:
         sage: from sage.graphs.graph import enum
         sage: enum(graphs.DodecahedralGraph())
-        646827340296833569479885332381965103655612500627043016896502674924517797573929148319427466126170568392555309533861838850L
+        646827340296833569479885332381965103655612500627043016896502674924517797573929148319427466126170568392555309533861838850
         sage: enum(graphs.MoebiusKantorGraph())
-        29627597595494233374689380190219099810725571659745484382284031717525232288040L
+        29627597595494233374689380190219099810725571659745484382284031717525232288040
         sage: enum(graphs.FlowerSnark())
-        645682215283153372602620320081348424178216159521280462146968720908564261127120716040952785862033320307812724373694972050L
+        645682215283153372602620320081348424178216159521280462146968720908564261127120716040952785862033320307812724373694972050
         sage: enum(graphs.CubeGraph(3))
-        6100215452666565930L
+        6100215452666565930
         sage: enum(graphs.CubeGraph(4))
-        31323620658472264895128471376615338141839885567113523525061169966087480352810L
+        31323620658472264895128471376615338141839885567113523525061169966087480352810
         sage: enum(graphs.CubeGraph(5))
-        56178607138625465573345383656463935701397275938329921399526324254684498525419117323217491887221387354861371989089284563861938014744765036177184164647909535771592043875566488828479926184925998575521710064024379281086266290501476331004707336065735087197243607743454550839234461575558930808225081956823877550090L
+        56178607138625465573345383656463935701397275938329921399526324254684498525419117323217491887221387354861371989089284563861938014744765036177184164647909535771592043875566488828479926184925998575521710064024379281086266290501476331004707336065735087197243607743454550839234461575558930808225081956823877550090
         sage: enum(graphs.CubeGraph(6))
-        17009933328531023098235951265708015080189260525466600242007791872273951170067729430659625711869482140011822425402311004663919203785115296476561677814427201708237805402966561863692388687547518491537427897858240566495945005294876576523289206747123399572439707189803821880345487300688962557172856432472391025950779306221469432919735886988596366979797317084123956762362685536557279604675024249987913439836592296340787741671304722135394212035449285260308821361913500205796919484488876249630521666898413890977354122918711285458724686283296097840711521153201188450783978019001984591992381570913097193343212274205747843852376395748070926193308573472616983062165141386183945049871456376379041631456999916186868438148001405477879591035696239287238767746380404501285533026300096772164676955425088646172718295360584249310479706751274583871684827338312536787740914529353458829503642591918761588296961192261166874864565050490306157300749101788751129640698534818737753110920871293122429238702542726347017441416450649382146313791818349648006634724962025571237208317435310419071153813687071275479812184286929976456778629116002591936357623320676067640749567446551071011889378108453641887998273235139859889734259803684619153716302058849155208478850L
+        17009933328531023098235951265708015080189260525466600242007791872273951170067729430659625711869482140011822425402311004663919203785115296476561677814427201708237805402966561863692388687547518491537427897858240566495945005294876576523289206747123399572439707189803821880345487300688962557172856432472391025950779306221469432919735886988596366979797317084123956762362685536557279604675024249987913439836592296340787741671304722135394212035449285260308821361913500205796919484488876249630521666898413890977354122918711285458724686283296097840711521153201188450783978019001984591992381570913097193343212274205747843852376395748070926193308573472616983062165141386183945049871456376379041631456999916186868438148001405477879591035696239287238767746380404501285533026300096772164676955425088646172718295360584249310479706751274583871684827338312536787740914529353458829503642591918761588296961192261166874864565050490306157300749101788751129640698534818737753110920871293122429238702542726347017441416450649382146313791818349648006634724962025571237208317435310419071153813687071275479812184286929976456778629116002591936357623320676067640749567446551071011889378108453641887998273235139859889734259803684619153716302058849155208478850
     """
-    M = graph.am()
     enumeration = 0
     n = graph.order()
+    if quick:
+        if isinstance(graph, Graph):
+            for i, j, l in graph.edge_iterator():
+                enumeration += 1 << ((n-(i+1))*n + n-(j+1))
+                enumeration += 1 << ((n-(j+1))*n + n-(i+1))
+        elif isinstance(graph, DiGraph):
+            for i, j, l in graph.arc_iterator():
+                enumeration += 1 << ((n-(i+1))*n + n-(j+1))
+        return enumeration
+    M = graph.am()
     for i, j in M.nonzero_positions():
         enumeration += 1 << ((n-(i+1))*n + n-(j+1))
-    return enumeration
-
-
+    return ZZ(enumeration)
+
+
+
+
Index: sage/graphs/graph_database.py
===================================================================
--- sage/graphs/graph_database.py	(revision 3734)
+++ sage/graphs/graph_database.py	(revision 4359)
@@ -156,23 +156,23 @@
         
         EXAMPLES:
-            # Obtain a list of graphs:
+        Obtain a list of graphs:
             sage: glist = graphs_query.get_list_of_graphs(max_degree=4, min_degree=3)
             
-            # Inspect and display graphs individually:
+        Inspect and display graphs individually:
             sage: glist[0]
             Graph on 5 vertices
             sage.: glist[8].show(layout='circular')
             
-            # Now we can use functions from the graphs_list.
-            # Convert to graph6 format:
+        Now we can use functions from the graphs_list.
+        Convert to graph6 format:
             sage: graph6list = graphs_list.to_graph6(glist, output_list=True)
             
-            # View the graph6 format of the first graph:
+        View the graph6 format of the first graph:
             sage: graph6list[0]
             'Dl{'
             
-            # Convert to list of graphics arrays:
+        Convert to list of graphics arrays:
             garray = graphs_list.to_graphics_arrays(glist)
-            # Show the last graphics array in the list:
+        Show the last graphics array in the list:
             sage.: garray[len(garray)-1].show()
         """
@@ -215,6 +215,6 @@
         
         EXAMPLES:
-            # Recursive searching:
-            # First note the following sizes of output:
+        Recursive searching:
+        First note the following sizes of output:
             sage: graphs_query.number_of(nodes=5)
             34
@@ -224,5 +224,5 @@
             6
             
-            # Now find all graphs with 5 vertices and 4 edges:
+        Now find all graphs with 5 vertices and 4 edges:
             sage: data = graphs_query.get_data_set(nodes=5)
             sage: redata = graphs_query.get_data_set(data_dict=data, edges=4)
@@ -230,5 +230,5 @@
             6
             
-            # Note that this is equivalent to searching both at once:
+        Note that this is equivalent to searching both at once:
             sage: redata == graphs_query.get_data_set(nodes=5, edges=4)
             True
@@ -280,21 +280,22 @@
         
         EXAMPLES:
-            # Can obtain a list of graphics arrays for all graphs with 7 or fewer nodes:
-            # (pretty fast too -- time it)
+        Can obtain a list of graphics arrays for all graphs with 7 or fewer nodes:
+        (pretty fast too -- time it)
             sage: all_7 = graphs_query.get_list_of_graphics_arrays()
             
-            # And notice that Networkx's ordering structure is preserved.
-            # Display the first graphics array in the list:
+        And notice that Networkx's ordering structure is preserved.
+        Display the first graphics array in the list:
             sage.: all_7[0].show()
-            # And the last:
+            
+        And the last:
             sage.: all_7[len(all_7)-1].show()
             
-            # And also notice that displaying properties will make the list longer:
-            # (Twice as many graphics objects in the arrays)
+        And also notice that displaying properties will make the list longer:
+        (Twice as many graphics objects in the arrays)
             sage: all_7_with_props = graphs_query.get_list_of_graphics_arrays(with_properties=True)
             sage: len(all_7) < len(all_7_with_props)
             True
             
-            # Properties are displayed to the right of each graph
+        Properties are displayed to the right of each graph
             sage.: all_7_with_props[5].show()
         """
@@ -416,15 +417,16 @@
         
         EXAMPLES:
-            # Properties are displayed to the right of each graph:
+        Properties are displayed to the right of each graph:
             sage.: graphs_query.show_graphs(nodes=3, with_properties=True)
             
-            # Without properties, you can show up to 20 graphs.
-            # But with properties, you are limited to 10.
+        Without properties, you can show up to 20 graphs.
+        But with properties, you are limited to 10.
             sage: graphs_query.number_of(nodes=4)
             11
             
-            # Without displaying properties (default):
+        Without displaying properties (default):
             sage.: graphs_query.show_graphs(nodes=4)
-            # But with properties, we will raise an exception:
+            
+        But with properties, we will raise an exception:
             sage: graphs_query.show_graphs(nodes=4, with_properties=True)
             Traceback (most recent call last):
@@ -433,5 +435,5 @@
             If more than 10 graphs, try get_list_of_graphics_arrays.
             
-            # In this case, use get_list_of_graphics_arrays:
+        In this case, use get_list_of_graphics_arrays:
             sage: garray = graphs_query.get_list_of_graphics_arrays(nodes=4, with_properties=True)
             sage.: garray[0].show()
Index: sage/graphs/graph_fast.pyx
===================================================================
--- sage/graphs/graph_fast.pyx	(revision 3744)
+++ sage/graphs/graph_fast.pyx	(revision 4176)
@@ -229,7 +229,4 @@
     sage_free(disp)
 
-
-
-
 def binary(n, length=None):
     """
Index: sage/graphs/graph_generators.py
===================================================================
--- sage/graphs/graph_generators.py	(revision 3734)
+++ sage/graphs/graph_generators.py	(revision 4359)
@@ -178,10 +178,10 @@
         
         EXAMPLES:
-            # Construct and show a barbell graph
-            # Bar = 4, Bells = 9
+        Construct and show a barbell graph
+        Bar = 4, Bells = 9
             sage: g = graphs.BarbellGraph(9,4)
             sage.: g.show()
             
-            # Create several barbell graphs in a SAGE graphics array
+        Create several barbell graphs in a SAGE graphics array
             sage: g = []
             sage: j = []
@@ -237,5 +237,5 @@
         
         EXAMPLES:
-            # Construct and show a bull graph
+        Construct and show a bull graph
             sage: g = graphs.BullGraph()
             sage.: g.show()
@@ -268,9 +268,9 @@
         
         EXAMPLES:
-            # Construct and show a circular ladder graph with 26 nodes
+        Construct and show a circular ladder graph with 26 nodes
             sage: g = graphs.CircularLadderGraph(13)
             sage.: g.show()
             
-            # Create several circular ladder graphs in a SAGE graphics array
+        Create several circular ladder graphs in a SAGE graphics array
             sage: g = []
             sage: j = []
@@ -312,8 +312,8 @@
         
         EXAMPLES:
-            # Show a Claw graph
+        Show a Claw graph
             sage.: (graphs.ClawGraph()).show()
             
-            # Inspect a Claw graph
+        Inspect a Claw graph
             sage: G = graphs.ClawGraph()
             sage: G
@@ -347,26 +347,14 @@
         
         Filling the position dictionary in advance adds O(n) to the
-        constructor.  Feel free to race the constructors below in the
-        examples section.  The much larger difference is the time added
-        by the spring-layout algorithm when plotting.  (Also shown in the
-        example below).  The spring  model is typically described as O(n^3),
-        as appears to be the case in the NetworkX source code.
-        
-        EXAMPLES:
-            # Compare the constructors (results will vary)
+        constructor.  
+        
+        EXAMPLES:
+        Compare plotting using the predefined layout and networkx:
             sage: import networkx            
-            sage.: time n = networkx.cycle_graph(3989); spring3989 = Graph(n)
-            # CPU time: 0.05 s,  Wall time: 0.07 s
-            sage.: time posdict3989 = graphs.CycleGraph(3989)
-            # CPU time: 5.18 s,  Wall time: 6.17 s
-            
-            # Compare the plotting speeds (results will vary)
             sage: n = networkx.cycle_graph(23)
             sage: spring23 = Graph(n)
             sage: posdict23 = graphs.CycleGraph(23)
-            sage.: time spring23.show()
-            # CPU time: 2.04 s,  Wall time: 2.72 s
-            sage.: time posdict23.show()
-            # CPU time: 0.57 s,  Wall time: 0.71 s
+            sage.: spring23.show()
+            sage.: posdict23.show()
             
         We next view many cycle graphs as a SAGE graphics array.
@@ -432,5 +420,5 @@
         
         EXAMPLES:
-            # Construct and show a diamond graph
+        Construct and show a diamond graph
             sage: g = graphs.DiamondGraph()
             sage.: g.show()
@@ -457,10 +445,10 @@
         
         EXAMPLES:
-            # Construct and show a Dodecahdedral graph
+        Construct and show a Dodecahdedral graph
             sage: g = graphs.DodecahedralGraph()
             sage.: g.show()
             
-            # Create several dodecahedral graphs in a SAGE graphics array
-            # They will be drawn differently due to the use of the spring-layout algorithm
+        Create several dodecahedral graphs in a SAGE graphics array
+        They will be drawn differently due to the use of the spring-layout algorithm
             sage: g = []
             sage: j = []
@@ -494,10 +482,10 @@
         
         EXAMPLES:
-            # Add one vertex to an empty graph and then show:
+        Add one vertex to an empty graph and then show:
             sage: empty1 = graphs.EmptyGraph()
             sage: empty1.add_vertex()
             sage.: empty1.show()
             
-            # Use for loops to build a graph from an empty graph:
+        Use for loops to build a graph from an empty graph:
             sage: empty2 = graphs.EmptyGraph()
             sage: for i in range(5):
@@ -532,6 +520,6 @@
         
         EXAMPLES:
-            # Construct and show a grid 2d graph
-            # Rows = 5, Columns = 7
+        Construct and show a grid 2d graph
+        Rows = 5, Columns = 7
             sage: g = graphs.Grid2dGraph(5,7)
             sage.: g.show()
@@ -567,5 +555,5 @@
         
         EXAMPLES:
-            # Construct and show a house graph
+        Construct and show a house graph
             sage: g = graphs.HouseGraph()
             sage.: g.show()
@@ -597,5 +585,5 @@
         
         EXAMPLES:
-            # Construct and show a house X graph
+        Construct and show a house X graph
             sage: g = graphs.HouseXGraph()
             sage.: g.show()
@@ -638,5 +626,5 @@
         
         EXAMPLE:
-            # Construct and show a Krackhardt kite graph
+        Construct and show a Krackhardt kite graph
             sage: g = graphs.KrackhardtKiteGraph()
             sage.: g.show()
@@ -664,9 +652,9 @@
         
         EXAMPLES:
-            # Construct and show a ladder graph with 14 nodes
+        Construct and show a ladder graph with 14 nodes
             sage: g = graphs.LadderGraph(7)
             sage.: g.show()
             
-            # Create several ladder graphs in a SAGE graphics array
+        Create several ladder graphs in a SAGE graphics array
             sage: g = []
             sage: j = []
@@ -711,10 +699,10 @@
         
         EXAMPLES:
-            # Construct and show a lollipop graph
-            # Candy = 13, Stick = 4
+        Construct and show a lollipop graph
+        Candy = 13, Stick = 4
             sage: g = graphs.LollipopGraph(13,4)
             sage.: g.show()
             
-            # Create several lollipop graphs in a SAGE graphics array
+        Create several lollipop graphs in a SAGE graphics array
             sage: g = []
             sage: j = []
@@ -765,10 +753,10 @@
         
         EXAMPLES:
-            # Construct and show an Octahedral graph
+        Construct and show an Octahedral graph
             sage: g = graphs.OctahedralGraph()
             sage.: g.show()
             
-            # Create several octahedral graphs in a SAGE graphics array
-            # They will be drawn differently due to the use of the spring-layout algorithm
+        Create several octahedral graphs in a SAGE graphics array
+        They will be drawn differently due to the use of the spring-layout algorithm
             sage: g = []
             sage: j = []
@@ -818,18 +806,18 @@
         
         EXAMPLES:
-            # Show default drawing by size:
-            # 'line': n < 11
+        Show default drawing by size:
+        'line': n < 11
             sage: p = graphs.PathGraph(10)
             sage.: p.show()
             
-            # 'circle': 10 < n < 41
+        'circle': 10 < n < 41
             sage: q = graphs.PathGraph(25)
             sage.: q.show()
             
-            # 'line': n > 40
+        'line': n > 40
             sage: r = graphs.PathGraph(55)
             sage.: r.show()
             
-            # Override the default drawing:
+        Override the default drawing:
             sage: s = graphs.PathGraph(5,'circle')
             sage.: s.show()
@@ -902,29 +890,14 @@
         other nodes away from the (0) node, and thus look very similar to
         this constructor's positioning.
-        
-        Filling the position dictionary in advance adds O(n) to the
-        constructor.  Feel free to race the constructors below in the
-        examples section.  The much larger difference is the time added
-        by the spring-layout algorithm when plotting.  (Also shown in the
-        example below).  The spring model is typically described as O(n^3),
-        as appears to be the case in the NetworkX source code.
-        
+
         EXAMPLES:
             sage: import networkx
 
-        Compare the constructors (results will vary)
-            sage.: time n = networkx.star_graph(3989); spring3989 = Graph(n)
-            # CPU time: 0.08 s,  Wall time: 0.10 s
-            sage.: time posdict3989 = graphs.StarGraph(3989)
-            # CPU time: 5.43 s,  Wall time: 7.41 s
-
-        Compare the plotting speeds (results will vary)
+        Compare the plots:
             sage: n = networkx.star_graph(23)
             sage: spring23 = Graph(n)
             sage: posdict23 = graphs.StarGraph(23)
-            sage.: time spring23.show()
-            # CPU time: 2.31 s,  Wall time: 3.14 s
-            sage.: time posdict23.show()
-            # CPU time: 0.68 s,  Wall time: 0.80 s
+            sage.: spring23.show()
+            sage.: posdict23.show()
 
         View many star graphs as a SAGE Graphics Array
@@ -995,14 +968,14 @@
         
         EXAMPLES:
-            # Construct and show a Tetrahedral graph
+        Construct and show a Tetrahedral graph
             sage: g = graphs.TetrahedralGraph()
             sage: g.save('sage.png')
             
-            # The following example requires networkx:
+        The following example requires networkx:
             sage: import networkx as NX
 
-            # Compare this Tetrahedral, Wheel(4), Complete(4), and the 
-            # Tetrahedral plotted with the spring-layout algorithm below
-            # in a SAGE graphics array:
+        Compare this Tetrahedral, Wheel(4), Complete(4), and the 
+        Tetrahedral plotted with the spring-layout algorithm below
+        in a SAGE graphics array:
             sage: tetra_pos = graphs.TetrahedralGraph()
             sage: tetra_spring = Graph(NX.tetrahedral_graph())
@@ -1043,11 +1016,4 @@
         (See Graphics Array examples below).
         
-        Filling the position dictionary in advance adds O(n) to the
-        constructor.  Feel free to race the constructors below in the
-        examples section.  The much larger difference is the time added
-        by the spring-layout algorithm when plotting.  (Also shown in the
-        example below).  The spring model is typically described as O(n^3),
-        as appears to be the case in the NetworkX source code.
-        
         EXAMPLES:
         We view many wheel graphs with a SAGE Graphics Array, first
@@ -1086,18 +1052,10 @@
             sage.: G.show()
 
-        Compare the constructors (results will vary):
-            sage.: time n = networkx.wheel_graph(3989); spring3989 = Graph(n)
-            # CPU time: 0.07 s,  Wall time: 0.09 s
-            sage.: time posdict3989 = graphs.WheelGraph(3989)
-            # CPU time: 5.99 s,  Wall time: 8.74 s
-
-            # Compare the plotting speeds (results will vary)
+        Compare the plotting:
             sage: n = networkx.wheel_graph(23)
             sage: spring23 = Graph(n)
             sage: posdict23 = graphs.WheelGraph(23)
-            sage.: time spring23.show()
-            # CPU time: 2.24 s,  Wall time: 3.00 s
-            sage.: time posdict23.show()
-            # CPU time: 0.68 s,  Wall time: 1.14 s
+            sage.: spring23.show()
+            sage.: posdict23.show()
         """
         pos_dict = {}
@@ -1133,5 +1091,5 @@
         
         EXAMPLES:
-            # Inspect a flower snark:
+        Inspect a flower snark:
             sage: F = graphs.FlowerSnark()
             sage: F
@@ -1140,5 +1098,5 @@
             'ShCGHC@?GGg@?@?Gp?K??C?CA?G?_G?Cc'
             
-            # Now show it:
+        Now show it:
             sage.: F.show()
         """
@@ -1371,11 +1329,4 @@
         below).
         
-        Filling the position dictionary in advance adds O(n) to the
-        constructor.  Feel free to race the constructors below in the
-        examples section.  The much larger difference is the time added
-        by the spring-layout algorithm when plotting.  (Also shown in the
-        example below).  The spring model is typically described as O(n^3),
-        as appears to be the case in the NetworkX source code.
-        
         EXAMPLES:
         We view many Complete graphs with a SAGE Graphics Array, first
@@ -1413,18 +1364,19 @@
             sage.: G = sage.plot.plot.GraphicsArray(j)
             sage.: G.show()
-            # Compare the constructors (results will vary)
+
+        Compare the constructors (results will vary)
+            sage: import networkx                
             sage.: time n = networkx.complete_graph(1559); spring1559 = Graph(n)
-            # CPU time: 6.85 s,  Wall time: 9.71 s
+            CPU time: 6.85 s,  Wall time: 9.71 s
             sage.: time posdict1559 = graphs.CompleteGraph(1559)
-            #CPU time: 9.67 s,  Wall time: 11.75 s
-
-        We compare the plotting speeds (results will vary):
+            CPU time: 9.67 s,  Wall time: 11.75 s
+
+        We compare plotting:
+            sage: import networkx        
             sage: n = networkx.complete_graph(23)
             sage: spring23 = Graph(n)
             sage: posdict23 = graphs.CompleteGraph(23)
-            sage.: time spring23.show()
-            # CPU time: 3.51 s,  Wall time: 4.29 s
-            sage.: time posdict23.show()
-            # CPU time: 0.82 s,  Wall time: 0.96 s
+            sage.: spring23.show()
+            sage.: posdict23.show()
         """
         pos_dict = {}
@@ -1470,5 +1422,5 @@
         examples section.  The much larger difference is the time added by
         the spring-layout algorithm when plotting.  (Also shown in the
-        example below).  The spring model is typically described as O(n^3),
+        example below).  The spring model is typically described as $O(n^3)$,
         as appears to be the case in the NetworkX source code.
         
@@ -1558,5 +1510,5 @@
         
         EXAMPLES:
-            # Plot several n-cubes in a SAGE Graphics Array
+        Plot several n-cubes in a SAGE Graphics Array
             sage: g = []
             sage: j = []
@@ -1574,5 +1526,5 @@
             sage.: G.show(figsize=[6,4])
             
-            # Use the plot options to display larger n-cubes
+        Use the plot options to display larger n-cubes
             sage: g = graphs.CubeGraph(9)
             sage.: g.show(figsize=[12,12],vertex_labels=False, node_size=20)
@@ -1660,11 +1612,11 @@
         
             time regular_sparse = graphs.RandomGNP(1559,.22)
-            # CPU time: 31.79 s,  Wall time: 38.78 s
+            CPU time: 31.79 s,  Wall time: 38.78 s
             time fast_sparse =  graphs.RandomGNPFast(1559,.22)
-            # CPU time: 21.72 s,  Wall time: 26.44 s
+            CPU time: 21.72 s,  Wall time: 26.44 s
             time regular_dense = graphs.RandomGNP(1559,.88)
-            # CPU time: 38.75 s,  Wall time: 47.65 s
+            CPU time: 38.75 s,  Wall time: 47.65 s
             time fast_dense = graphs.RandomGNP(1559,.88)
-            # CPU time: 39.15 s,  Wall time: 48.22 s
+            CPU time: 39.15 s,  Wall time: 48.22 s
         """
         import networkx
@@ -1684,9 +1636,9 @@
         
         EXAMPLES:
-            # Plot a random graph on 12 nodes with p = .71
+        Plot a random graph on 12 nodes with p = .71
             sage: fast = graphs.RandomGNPFast(12,.71)
             sage.: fast.show()
 
-            # View many random graphs using a SAGE Graphics Array
+        View many random graphs using a SAGE Graphics Array
             sage: g = []
             sage: j = []
Index: sage/graphs/graph_isom.py
===================================================================
--- sage/graphs/graph_isom.py	(revision 3880)
+++ sage/graphs/graph_isom.py	(revision 4359)
@@ -1,14 +1,36 @@
 """
-Automorphism group computation and isomorphism checking for graphs
-
-This is a new open source implementation of Brendan McKay's algorithm
-for graph automorphism and isomorphism.  This is not a derived work of
-nauty (one of the other restrictively licensed implementations of
-McKay's algorithm), and is completely open source (released under the
-GPL).
+N.I.C.E. - Nice (as in open source) Isomorphism Check Engine
+
+Automorphism group computation and isomorphism checking for graphs.
+
+This is an open source implementation of Brendan McKay's algorithm for graph
+automorphism and isomorphism. McKay released a C version of his algorithm,
+named nauty (No AUTomorphisms, Yes?) under a license that is not GPL
+compatible. Although the program is open source, reading the source disallows
+anyone from recreating anything similar and releasing it under the GPL. Also,
+many people have complained that the code is difficult to understand. The
+first main goal of NICE was to produce a genuinely open graph isomorphism
+program, which has been accomplished. The second goal is for this code to be
+understandable, so that computed results can be trusted and further derived
+work will be possible.
+
+To determine the isomorphism type of a graph, it is convenient to define a
+canonical label for each isomorphism class- essentially an equivalence class
+representative. Loosely (albeit incorrectly), the canonical label is defined
+by enumerating all labeled graphs, then picking the maximal one in each
+isomorphism class. The NICE algorithm is essentially a backtrack search. It
+searches through the rooted tree of partition nests (where each partition is
+equitable) for implicit and explicit automorphisms, and uses this information
+to eliminate large parts of the tree from further searching. Since the leaves
+of the search tree are all discrete ordered partitions, each one of these
+corresponds to an ordering of the vertices of the graph, i.e. another member
+of the isomorphism class. Once the algorithm has finished searching the tree,
+it will know which leaf corresponds to the canonical label. In the process,
+generators for the automorphism group are also produced.
 
 AUTHORS:
-    Robert L. Miller -- (2007-03-20) initial version
-    Tom Boothby -- (2007-03-20) help with indicator function
+    * Robert L. Miller -- (2007-03-20) initial version
+    * Tom Boothby -- (2007-03-20) help with indicator function
+    * Robert L. Miller -- (2007-04-07--17) optimizations
 
 REFERENCE:
@@ -17,17 +39,13 @@
 
 NOTE:
-    Often we assume that G is a graph on vertices {0,1,...,n-1}, and gamma is
-    an element of SymmetricGroup(n), considered as action on the set
-    {1,2,...,n} where we take 0 == n.
+    Often we assume that G is a graph on vertices {0,1,...,n-1}.
 """
 
-##############################################################################
-#
-#          Copyright (C) 2007 Robert L. Miller <rlmillster@gmail.com>
+#*****************************************************************************
+#      Copyright (C) 2006 - 2007 Robert L. Miller <rlmillster@gmail.com>
 #
 # Distributed  under  the  terms  of  the  GNU  General  Public  License (GPL)
 #                         http://www.gnu.org/licenses/
-#
-##############################################################################
+#*****************************************************************************
 
 from sage.graphs.graph import Graph, DiGraph
@@ -149,5 +167,5 @@
     INPUT:
         list_perm -- if True, assumes gamma is a list representing the map
-    i \mapsto gamma[i].
+                     i \mapsto gamma[i].
 
     EXAMPLES:
@@ -206,5 +224,5 @@
     else: return False
 
-def degree(G, v, W):
+def degree(G, v, W, bool_matrix_format=False):
     """
     Returns the number of edges from v to vertices in W, i.e. the degree of v
@@ -216,11 +234,35 @@
         sage: from sage.graphs.graph_isom import degree
         sage: P = graphs.PetersenGraph()
+        sage: M = P.adjacency_matrix()
         sage: Pi1 = [[0,2,3,4],[5,7,8,1],[6,9]]
         sage: degree(P, 6, Pi1[1])
         2
+        sage: degree(M, 6, Pi1[1], bool_matrix_format=True)
+        2
 
     To see what is going on:
         sage.: P.show(partition=Pi1)
-    """
+    
+    NOTE:
+    Regarding the bool_matrix_format option, see the following timings:
+        sage.: import sage.graphs.graph_isom
+        sage.: from sage.graphs.graph_isom import degree
+        sage.: P = graphs.PetersenGraph()
+        sage.: M = P.adjacency_matrix()
+        sage.: str(M).replace('\n',',').replace(' ',',').replace('1','True').replace('0','False')
+        '[False,True,False,False,True,True,False,False,False,False],[True,False,True,False,False,False,True,False,False,False],[False,True,False,True,False,False,False,True,False,False],[False,False,True,False,True,False,False,False,True,False],[True,False,False,True,False,False,False,False,False,True],[True,False,False,False,False,False,False,True,True,False],[False,True,False,False,False,False,False,False,True,True],[False,False,True,False,False,True,False,False,False,True],[False,False,False,True,False,True,True,False,False,False],[False,False,False,False,True,False,True,True,False,False]'
+        sage.: M = [[False,True,False,False,True,True,False,False,False,False],[True,False,True,False,False,False,True,False,False,False],[False,True,False,True,False,False,False,True,False,False],[False,False,True,False,True,False,False,False,True,False],[True,False,False,True,False,False,False,False,False,True],[True,False,False,False,False,False,False,True,True,False],[False,True,False,False,False,False,False,False,True,True],[False,False,True,False,False,True,False,False,False,True],[False,False,False,True,False,True,True,False,False,False],[False,False,False,False,True,False,True,True,False,False]]
+        sage.: Pi1 = [[0,2,3,4],[5,7,8,1],[6,9]]
+        sage.: timeit degree(P, 6, Pi1[1])
+        10000 loops, best of 3: 24.9 [micro]s per loop
+        sage.: timeit degree(M, 6, Pi1[1], bool_matrix_format=True)
+        100000 loops, best of 3: 8.27 [micro]s per loop
+    """
+    if bool_matrix_format:
+        i = 0
+        for u in W:
+            if G[u][v]:
+                i += 1
+        return i
     i = 0
     for u in W:
@@ -293,5 +335,5 @@
     return PiNew
 
-def sort_by_degree(G, A, B):
+def sort_by_degree(G, A, B, bool_matrix_format=False):
     """
     Assuming A and B are subsets of the vertex set of G, returns an ordered
@@ -311,5 +353,5 @@
     ddict = {}
     for a in A:
-        dd = degree(G, a, B)
+        dd = degree(G, a, B, bool_matrix_format=bool_matrix_format)
         if ddict.has_key(dd):
             ddict[dd].append(a)
@@ -318,5 +360,5 @@
     return ddict.values()
 
-def refine(G, Pi, alpha):
+def refine(G, Pi, alpha, bool_matrix_format=False):
     """
     The key refinement procedure. Given a graph G, a partition Pi of the
@@ -372,5 +414,5 @@
         r = len(PiT)
         while k < r:
-            X = sort_by_degree(G, PiT[k], W)
+            X = sort_by_degree(G, PiT[k], W, bool_matrix_format=bool_matrix_format)
             s = len(X)
             if s != 1:
@@ -414,12 +456,12 @@
         return replace_in(Pi, i, [[v], L])
 
-def perp(G, Pi, v):
+def perp(G, Pi, v, bool_matrix_format=False):
     """
     Refines the partition Pi by cutting out a vertex, then using refine,
     comparing against only that vertex.
     """
-    return refine(G, comp(Pi, v), [[v]])
-
-def partition_nest(G, Pi, V):
+    return refine(G, comp(Pi, v), [[v]], bool_matrix_format=bool_matrix_format)
+
+def partition_nest(G, Pi, V, bool_matrix_format=False):
     """
     Given a sequence of vertices V = (v_1,...,v_{m-1}) of a graph G, and a
@@ -434,7 +476,7 @@
     C.f. 2.9 in [1].
     """
-    L = [refine(G, Pi, Pi)]
+    L = [refine(G, Pi, Pi, bool_matrix_format=bool_matrix_format)]
     for i in range(len(V)):
-        L.append(perp(G, L[i], V[i]))
+        L.append(perp(G, L[i], V[i], bool_matrix_format=bool_matrix_format))
     return L
 
@@ -453,12 +495,8 @@
             return Pi[i]
 
-def indicator(G, Pi, V):
+def indicator(G, Pi, V, k=None, bool_matrix_format=False):
     """
     Takes a labelled graph, an ordered partition, and a partition nest, and
     outputs an integer, which is the same under any fixed permutation.
-    
-    AUTHORS:    
-        Tom Boothby -- sum then product method
-        Robert Miller -- vertex degree check
     
     EXAMPLES:
@@ -493,14 +531,23 @@
         sage: indicator(G, [range(93)], partition_nest(G, [range(93)], V)) == indicator(H, [range(93)], partition_nest(H, [range(93)], [g.list()[v-1] for v in V]))
         True
-    """
+
+    AUTHORS:    
+        * Tom Boothby -- sum then product method
+        * Robert Miller -- vertex degree check
+    """
+    if k is not None:
+        V = V[:k]
+    if bool_matrix_format:
+        n = len(G)
+    else:
+        n = G.order()
     from sage.misc.misc import prod
-    LL = [0]*G.order()
+    LL = []
     for partition in V:
         a = len(partition)
         for k in range(a):
-            LL[k] += len(partition[k])*(1 + \
-                sum(  [  degree(G, partition[k][0], partition[i]) for i in range(len(partition))  ]  ) \
-                                        )
-    return prod([l for l in LL if l!=0])
+            LL.append( len(partition[k])*(1 + \
+                sum(  [  degree(G, partition[k][0], partition[i], bool_matrix_format=bool_matrix_format) for i in range(a)  ]  ) ) )
+    return prod(LL)
 
 def get_permutation(eta, nu, list_perm=False):
@@ -591,5 +638,5 @@
         return H
 
-def search_tree(G, Pi, lab=True, dig=False, dict=False, proof=False):
+def search_tree(G, Pi, lab=True, dig=False, dict=False, proof=False, verbosity=0):
     """
     Assumes that the vertex set of G is {0,1,...,n-1} for some n.
@@ -987,6 +1034,28 @@
     from copy import copy
     from sage.rings.infinity import Infinity
+    from sage.graphs.graph import enum
     n = G.order()
     Pi = copy(Pi)
+    
+    if n == 0:
+        if lab:
+            H = copy(G)
+        if dict:
+            ddd = {}
+        if proof:
+            dd = {}
+            if dict:
+                return [[]], ddd, H, dd
+            else:
+                return [[]], H, dd
+        if lab and dict:
+            return [[]], ddd, H
+        elif lab:
+            return [[]], H
+        elif dict:
+            return [[]], ddd
+        else:
+            return [[]]
+        
     
     if proof:
@@ -1010,4 +1079,16 @@
     Pi = Pi2
 
+    # create the boolean matrix
+    M = []
+    for _ in range(n):
+        M.append( [False]*n )
+    if isinstance(G, Graph):
+        for i, j, l in G.edge_iterator():
+            M[i][j] = True
+            M[j][i] = True
+    elif isinstance(G, DiGraph):
+        for i, j, l in G.arc_iterator():
+            M[i][j] = True
+
     #begin BDM's algorithm:
     L = 100
@@ -1026,25 +1107,27 @@
     output = []
     k = None
-#    h = None
-#    hh = None
+    h = None
+    hh = None
     hb = None
-#    hzb = None
-#    hzf = None
-#    qzb = None
+    hzb = None
+    hzf = None
+    qzb = None
     while not state is None:
-#        print 'e: ' + str(e)
-#        print 'k: ' + str(k)
-#        print 'hh: ' + str(hh)
-#        print 'hb: ' + str(hb)
-#        print 'h: ' + str(h)
-#        print 'nu: ' + str(nu)
-#        print 'eta: ' + str(eta)
-#        print 'rho: ' + str(rho)
-#        print 'zb: ' + str(zb)
-#        print 'hzb: ' + str(hzb)
-#        print 'hzf: ' + str(hzf)
-#        print 'qzb: ' + str(qzb)
+        if verbosity > 1:
+            print 'k: ' + str(k)
+            print 'nu: ' + str(nu)
+            print 'rho: ' + str(rho)
+        if verbosity > 3:
+            print 'e: ' + str(e)
+            print 'hh: ' + str(hh)
+            print 'hb: ' + str(hb)
+            print 'h: ' + str(h)
+            print 'eta: ' + str(eta)
+            print 'zb: ' + str(zb)
+            print 'hzb: ' + str(hzb)
+            print 'hzf: ' + str(hzf)
+            print 'qzb: ' + str(qzb)
         if state == 1:
-#            print 'state: 1'
+            if verbosity > 0: print 'state: 1'
             size = 1
             k = 1
@@ -1054,5 +1137,5 @@
             l = 0
             Theta = [[i] for i in range(n)]
-            nu[1] = refine(G, Pi, Pi)
+            nu[1] = refine(M, Pi, Pi, bool_matrix_format=True)
             hh = 2
             if not dig:
@@ -1066,8 +1149,8 @@
                 state = 2
         elif state == 2:
-#            print 'state: 2'
+            if verbosity > 0: print 'state: 2'
             k += 1
-            nu[k] = perp(G, nu[k-1], v[k-1])
-            Lambda[k] = indicator(G, Pi, nu.values())
+            nu[k] = perp(M, nu[k-1], v[k-1], bool_matrix_format=True)
+            Lambda[k] = indicator(M, Pi, nu.values(), k, bool_matrix_format=True)
             if h == 0: state = 5
             else:
@@ -1077,17 +1160,14 @@
                     state = 3
                 else:
-                    if zb[k] == Infinity:       # This replaces the last line,
-                        qzb = -1                # since MinusInfinity is not
-                    else:                       # yet implemented.
-                        qzb = Lambda[k] - zb[k] # 
+                    qzb = Lambda[k] - zb[k]
                     if hzb == k-1 and qzb == 0: hzb = k
                     if qzb > 0: zb[k] = Lambda[k]
                     state = 3
         elif state == 3:
-#            print 'state: 3'
+            if verbosity > 0: print 'state: 3'
             if hzf <= k or (lab and qzb >= 0): state = 4 ##changed hzb to hzf, == to <=
             else: state = 6
         elif state == 4:
-#            print 'state: 4'
+            if verbosity > 0: print 'state: 4'
             if is_discrete(nu[k]): state = 7
             else:
@@ -1098,10 +1178,10 @@
                 state = 2
         elif state == 5:
-#            print 'state: 5'
+            if verbosity > 0: print 'state: 5'
             zf[k] = Lambda[k]
             zb[k] = Lambda[k]
             state = 4
         elif state == 6:
-#            print 'state: 6'
+            if verbosity > 0: print 'state: 6'
             kprime = k
             k = min([ hh-1, max(ht-1,hzb) ])
@@ -1114,16 +1194,16 @@
                 state = 12
         elif state == 7:
-#            print 'state: 7'
+            if verbosity > 0: print 'state: 7'
             if h == 0: state = 18
             elif k < hzf: state = 8 ## BDM had !=, broke at G = Graph({0:[],1:[],2:[]}), Pi = [[0,1,2]]
             else:
                 gamma = get_permutation(eta.values(), nu.values(), list_perm=True)
-    #            print gamma
-                if G == G.relabel(gamma, inplace=False): # if G^gamma == G:
+                if verbosity > 2: print gamma
+                if enum(G, quick=True) == G.relabel(gamma, inplace=False, quick=True): # if G^gamma == G:
                     state = 10
                 else:
                     state = 8
         elif state == 8:
-#            print 'state: 8'
+            if verbosity > 0: print 'state: 8'
             if (not lab) or (qzb < 0): state = 6
             elif (qzb > 0) or (k < len(rho)): state = 9
@@ -1132,8 +1212,8 @@
             else:
                 gamma = get_permutation(nu.values(), rho.values(), list_perm=True)
-    #            print gamma
+                if verbosity > 2: print gamma
                 state = 10
         elif state == 9:
-#            print 'state: 9'
+            if verbosity > 0: print 'state: 9'
             rho = copy(nu)
             qzb = 0
@@ -1143,5 +1223,5 @@
             state = 6
         elif state == 10:
-#            print 'state: 10'
+            if verbosity > 0: print 'state: 10'
             l = min([l+1,L])
             Omega[l] = min_cell_reps(orbit_partition(gamma, list_perm=True))
@@ -1158,14 +1238,14 @@
                     state = 13
         elif state == 11:
-#            print 'state: 11'
+            if verbosity > 0: print 'state: 11'
             k = hb
             state = 12
         elif state == 12:
-#            print 'state: 12'
+            if verbosity > 0: print 'state: 12'
             if e[k] == 1:
                 W[k] = [v for v in W[k] if v in Omega[l]]
             state = 13
         elif state == 13:
-#            print 'state: 13'
+            if verbosity > 0: print 'state: 13'
             if k == 0: state = None
             else:
@@ -1178,5 +1258,5 @@
                 state = 14
         elif state == 14:
-#            print 'state: 14'
+            if verbosity > 0: print 'state: 14'
             for cell in Theta:
                 if v[k] in cell:
@@ -1193,5 +1273,5 @@
             else: state = 15
         elif state == 15:
-#            print 'state: 15'
+            if verbosity > 0: print 'state: 15'
             hh = min(hh,k+1)
             hzf = min(hzf,k)
@@ -1202,5 +1282,5 @@
                 state = 2
         elif state == 16:
-#            print 'state: 16'
+            if verbosity > 0: print 'state: 16'
             if len(W[k]) == index and ht == k+1: ht = k
             size = size*index
@@ -1209,7 +1289,7 @@
             state = 13
         elif state == 17:
-#            print 'state: 17'
+            if verbosity > 0: print 'state: 17'
             if e[k] == 0:
-                l = W[k]
+                li = W[k]
                 for i in range(1,l+1):
                     boo = True
@@ -1219,5 +1299,5 @@
                             break
                     if boo:
-                        l = [v for v in l if v in Omega[i]]
+                        li = [v for v in li if v in Omega[i]]
                     W[k] = l
             e[k] = 1
@@ -1231,5 +1311,5 @@
             state = 13
         elif state == 18:
-#            print 'state: 18'
+            if verbosity > 0: print 'state: 18'
             h = k
             ht = k
@@ -1241,6 +1321,6 @@
             else:
                 rho = copy(nu)
-                hzb = k#+1 # ???
-                hb = k#+1  # ???
+                hzb = k ## BDM had k+1
+                hb = k ## BDM had k+1
                 zb[k+2] = Infinity
                 qzb = 0
Index: sage/graphs/graph_list.py
===================================================================
--- sage/graphs/graph_list.py	(revision 3734)
+++ sage/graphs/graph_list.py	(revision 4359)
@@ -58,5 +58,5 @@
         sage: l = ['N@@?N@UGAGG?gGlKCMO','XsGGWOW?CC?C@HQKHqOjYKC_uHWGX?P?~TqIKA`OA@SAOEcEA??']
         sage: graphs_list.from_graph6(l)
-        [Graph on 14 vertices, Graph on 25 vertices]
+        [Graph on 15 vertices, Graph on 25 vertices]
     """
     from sage.graphs.graph import Graph
@@ -217,8 +217,8 @@
         sage: garray = graphs_list.to_graphics_arrays(glist)
         
-        # Display the first graphics array in the list.
+    Display the first graphics array in the list.
         sage.: garray[0].show()
         
-        # Display the last graphics array in the list.
+    Display the last graphics array in the list.
         sage.: garray[len(garray)-1].show()
     """
@@ -280,5 +280,5 @@
     
     EXAMPLES:
-        # Create a list of graphs:
+    Create a list of graphs:
         sage: glist = []
         sage: glist.append(graphs.CompleteGraph(6))
@@ -297,12 +297,12 @@
         sage: glist.append(graphs.WheelGraph(9))
         
-        # Check that length is <= 20:
+    Check that length is <= 20:
         sage: len(glist)
         14
         
-        # Show the graphs in a graphics array:
+    Show the graphs in a graphics array:
         sage.: graphs_list.show_graphs(glist)
         
-        # But more than 20 graphs will raise an exception:
+    But more than 20 graphs will raise an exception:
         sage: glist21 = []
         sage: for i in range(21):
@@ -314,5 +314,5 @@
         ValueError: List is too long to display in a graphics array.  Try using the to_graphics_arrays function.
         
-        # In this case, use to_graphics_arrays instead:
+    In this case, use to_graphics_arrays instead:
         sage: garrays = graphs_list.to_graphics_arrays(glist21)
         sage.: garrays[0].show()
Index: sage/groups/abelian_gps/dual_abelian_group_element.py
===================================================================
--- sage/groups/abelian_gps/dual_abelian_group_element.py	(revision 3290)
+++ sage/groups/abelian_gps/dual_abelian_group_element.py	(revision 4063)
@@ -270,5 +270,6 @@
         if is_ComplexField(F):
             I = F.gen()
-            ans = prod([exp(2*pi*I*expsX[i]*expsg[i]/invs[i]) for i in range(len(expsX))])
+            PI = F(pi)
+            ans = prod([exp(2*PI*I*expsX[i]*expsg[i]/invs[i]) for i in range(len(expsX))])
             return ans
         ans = F(1)  ## assumes F is the cyclotomic field
Index: sage/groups/group.pyx
===================================================================
--- sage/groups/group.pyx	(revision 2419)
+++ sage/groups/group.pyx	(revision 3977)
@@ -121,4 +121,20 @@
         return True
 
+    def cayley_graph(self):
+        from sage.graphs.graph import DiGraph
+        arrows = {}
+        for g in self:
+            for s in self.gens():
+                gs = g*s
+                if not gs == g:
+                    try:
+                        _ = arrows[g]
+                    except KeyError:
+                        arrows[g] = {}
+
+                    arrows[g][gs] = s
+
+        return DiGraph(arrows)
+
 cdef class AlgebraicGroup(Group):
     """
Index: sage/gsl/dft.py
===================================================================
--- sage/gsl/dft.py	(revision 3627)
+++ sage/gsl/dft.py	(revision 4063)
@@ -67,8 +67,6 @@
 from sage.rings.real_mpfr import RR
 from sage.rings.all import CC, I
-from math import sin
-from math import cos
-from sage.functions.constants import Pi
-pi = Pi()
+from sage.calculus.all import sin, cos
+from sage.functions.constants import pi
 from sage.gsl.fft import FastFourierTransform
 from sage.gsl.dwt import WaveletTransform
@@ -319,6 +317,7 @@
         J = self.index_object()   ## must be = range(N)
         N = len(J)
-        S = self.list()        
-        FT = [sum([S[i]*cos(2*pi*i/N) for i in J]) for j in J]
+        S = self.list()
+        PI = F(pi)
+        FT = [sum([S[i]*cos(2*PI*i/N) for i in J]) for j in J]
         return IndexedSequence(FT,J)
 
@@ -329,4 +328,5 @@
         EXAMPLES:
             sage: J = range(5)
+            sage: I = CC.0; pi = CC(pi)
             sage: A = [exp(-2*pi*i*I/5) for i in J]
             sage: s = IndexedSequence(A,J)
@@ -338,6 +338,7 @@
         J = self.index_object()   ## must be = range(N)
         N = len(J)
-        S = self.list()        
-        FT = [sum([S[i]*sin(2*pi*i/N) for i in J]) for j in J]
+        S = self.list()
+        PI = F(pi)
+        FT = [sum([S[i]*sin(2*PI*i/N) for i in J]) for j in J]
         return IndexedSequence(FT,J)
 
Index: sage/gsl/integration.pyx
===================================================================
--- sage/gsl/integration.pyx	(revision 3908)
+++ sage/gsl/integration.pyx	(revision 4062)
@@ -75,5 +75,5 @@
 
       We check this with a symbolic integration:
-         sage: maxima('sin(x)^3+sin(x)').integral(x,0,pi)
+         sage: (sin(x)^3+sin(x)).integral(x,0,pi)
          10/3
 
@@ -103,4 +103,10 @@
        the answer and whose second component is an error estimate.
 
+   REMARK:
+       There is also a method \code{nintegral} on symbolic expressions
+       that implements numerical integration using Maxima.  It is potentially
+       very useful for symbolic expressions.
+   
+
    MORE EXAMPLES:
    If we want to change the error tolerances and gauss rule used
@@ -138,10 +144,16 @@
 
    One can integrate any real-valued callable function:
-       sage: numerical_integral(zeta, [1.1,1.5])           # slightly random output
+       sage: numerical_integral(lambda x: abs(zeta(x)), [1.1,1.5])           # slightly random output
        (1.8488570602160455, 2.052643677492633e-14)
-       
+
+   We can also numerically integrate symbolic expressions using either this
+   function (which uses GSL) or the native integration (which uses Maxima):
+       sage: exp(-1/x).nintegral(x, 1, 2)   # via maxima
+       (0.50479221787318396, 5.6043194293440752e-15, 21, 0)
+       sage: numerical_integral(exp(-1/x), 1, 2)
+       (0.50479221787318407, 5.6043194293440744e-15)
        
    IMPLEMENTATION NOTES:
-       Uses GSL -- the GNU Scientific Library
+       Uses calls to the GSL -- the GNU Scientific Library -- C library.
 
    AUTHORS:
Index: sage/interfaces/cleaner.py
===================================================================
--- sage/interfaces/cleaner.py	(revision 3882)
+++ sage/interfaces/cleaner.py	(revision 4016)
@@ -1,2 +1,5 @@
+"""nodoctest
+"""
+
 ###############################################################################
 #   SAGE: System for Algebra and Geometry Experimentation    
Index: sage/interfaces/expect.py
===================================================================
--- sage/interfaces/expect.py	(revision 3704)
+++ sage/interfaces/expect.py	(revision 4296)
@@ -345,7 +345,7 @@
                 self._expect.close = dummy
             except Exception, msg:
-                print msg
+                pass
         except Exception, msg:
-            print msg
+            pass
 
     def cputime(self):
@@ -356,4 +356,14 @@
 
     def quit(self, verbose=False):
+        """
+        EXAMPLES:
+            sage: a = maxima('y')
+            sage: maxima.quit()
+            sage: a._check_valid()
+            Traceback (most recent call last):
+            ...
+            ValueError: The maxima session in which this object was defined is no longer running.
+        """
+        self._session_number += 1
         if self._expect is None:
             return
@@ -459,4 +469,28 @@
             raise KeyboardInterrupt, "Ctrl-c pressed while running %s"%self
 
+    def interrupt(self, tries=20, timeout=0.3):
+        E = self._expect
+        if E is None:
+            return True
+        success = False
+        try:
+            for i in range(tries):
+                E.sendline(self._quit_string())
+                E.sendline(chr(3))
+                try:
+                    E.expect(self._prompt, timeout=timeout)
+                    success= True
+                    break
+                except (pexpect.TIMEOUT, pexpect.EOF), msg:
+                    #print msg
+                    pass
+        except Exception, msg:
+            pass
+        if success:
+            pass
+        else:
+            self.quit()
+        return success
+        
     def eval(self, code, strip=True):
         """
@@ -466,5 +500,6 @@
                      (ignored in the base class).
         """
-        code = str(code)
+        if not isinstance(code, str):
+            raise TypeError, 'input code must be a string.'
         code = code.strip()
         try:
@@ -473,5 +508,5 @@
             self._keyboard_interrupt()
         except TypeError, s:
-            return 'error evaluating "%s":\n%s'%(code,s)
+            raise TypeError, 'error evaluating "%s":\n%s'%(code,s)
 
     def execute(self, *args, **kwds):
@@ -744,5 +779,5 @@
 
     def _reduce(self):
-        return str(self)
+        return repr(self)
 
     def _r_action(self, x):   # used for coercion
@@ -785,6 +820,6 @@
         try:
             P = self.parent()
-            if P is None is None or P._session_number == BAD_SESSION or self._session_number == -1 or \
-                          (P._restart_on_ctrlc and P._session_number != self._session_number):
+            if P is None or P._session_number == BAD_SESSION or self._session_number == -1 or \
+                          P._session_number != self._session_number:
                 raise ValueError, "The %s session in which this object was defined is no longer running."%P.name()
         except AttributeError:
@@ -809,5 +844,6 @@
                 if not (P is None):
                     P.clear(self._name)
-        except RuntimeError, msg:    # needed to avoid infinite loops in some rare cases
+                
+        except (RuntimeError, pexpect.ExceptionPexpect), msg:    # needed to avoid infinite loops in some rare cases
             #print msg
             pass
@@ -820,5 +856,5 @@
 
     def sage(self):
-        return sage.misc.sage_eval.sage_eval(str(self))
+        return sage.misc.sage_eval.sage_eval(repr(self))
 
     def __repr__(self):
@@ -874,5 +910,5 @@
     
     def __int__(self):
-        return int(str(self))
+        return int(repr(self))
 
     def bool(self):
@@ -887,16 +923,16 @@
 
     def __long__(self):
-        return long(str(self))
+        return long(repr(self))
 
     def __float____(self):
-        return float(str(self))
+        return float(repr(self))
 
     def _integer_(self):
         import sage.rings.all
-        return sage.rings.all.Integer(str(self))
+        return sage.rings.all.Integer(repr(self))
 
     def _rational_(self):
         import sage.rings.all        
-        return sage.rings.all.Rational(str(self))
+        return sage.rings.all.Rational(repr(self))
 
     def name(self):
Index: sage/interfaces/gap.py
===================================================================
--- sage/interfaces/gap.py	(revision 3634)
+++ sage/interfaces/gap.py	(revision 4059)
@@ -592,4 +592,7 @@
         return s
 
+    def __nonzero__(self):
+        return self.bool()
+
     def __len__(self):
         """
Index: sage/interfaces/macaulay2.py
===================================================================
--- sage/interfaces/macaulay2.py	(revision 3690)
+++ sage/interfaces/macaulay2.py	(revision 4059)
@@ -377,7 +377,7 @@
             return self.parent().new('%s %% %s'%(self.name(), x.name()))
 
-    def is_zero(self):
+    def __nonzero__(self):
         P = self.parent()
-        return P.eval('%s == 0'%self.name()) == 'true'        
+        return P.eval('%s == 0'%self.name()) == 'false'        
 
     def sage_polystring(self):
Index: sage/interfaces/mathematica.py
===================================================================
--- sage/interfaces/mathematica.py	(revision 3690)
+++ sage/interfaces/mathematica.py	(revision 4026)
@@ -78,7 +78,7 @@
 
     sage: c = m(5)
-    sage: m('b + c x')
+    sage: print m('b + c x')
                  b + c x
-    sage: m('b') + c*m('x')
+    sage: print m('b') + c*m('x')
              b + 5 x
 
@@ -182,5 +182,5 @@
 
     sage: x = mathematica(pi/2)
-    sage: x
+    sage: print x
              Pi
              --
@@ -193,10 +193,4 @@
     sage: loads(dumps(n)) == n
     True
-
-This example illustrates saving to a file in the local directory
-and to one in the \sage database directory.
-
-    sage.: n.save('n')
-    sage.: n.db('n')
 
 AUTHOR:
@@ -442,9 +436,9 @@
     def __repr__(self):
         P = self._check_valid()
-        return P.get(self._name, ascii_art=True)
+        return P.get(self._name, ascii_art=False).strip()
 
     def __str__(self):
         P = self._check_valid()
-        return P.get(self._name, ascii_art=False).strip()
+        return P.get(self._name, ascii_art=True)
 
     def str(self):
Index: sage/interfaces/maxima.py
===================================================================
--- sage/interfaces/maxima.py	(revision 3828)
+++ sage/interfaces/maxima.py	(revision 4320)
@@ -32,37 +32,29 @@
     sage: F = maxima.factor('x^5 - y^5')
     sage: F
-    -(y - x)*(y^4 + x*y^3 + x^2*y^2 + x^3*y + x^4)
+    -(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4)
     sage: type(F)
     <class 'sage.interfaces.maxima.MaximaElement'>
 
 Note that Maxima objects can also be displayed using ``ASCII art'';
-to see a normal linear representation of any Maxima object x,
+to see a normal linear representation of any Maxima object x.
+Just use the print command:
 use \code{str(x)}.
-    sage: F.display2d()
+    sage: print F
                                4      3    2  2    3      4
                    - (y - x) (y  + x y  + x  y  + x  y + x )
 
-We can make this the default:
-    sage: maxima.display2d(True)
-    sage: F
-                               4      3    2  2    3      4
-                   - (y - x) (y  + x y  + x  y  + x  y + x )
-
-You can always use \code{x.str()} to obtain the linear representation
-of an object, even without changing the display2d flag.  This can
-be useful for moving maxima data to other systems. 
+You can always use \code{repr(x)} to obtain the linear representation
+of an object.  This can be useful for moving maxima data to other
+systems.
+    sage: repr(F)
+    '-(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4)'
     sage: F.str()
-    '-(y - x)*(y^4 + x*y^3 + x^2*y^2 + x^3*y + x^4)'
+    '-(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4)'
     
-    sage: maxima.display2d(False)
-    sage: F
-    -(y - x)*(y^4 + x*y^3 + x^2*y^2 + x^3*y + x^4)
-
-
 The \code{maxima.eval} command evaluates an expression in maxima
-and returns the result as a string.
+and returns the result as a \emph{string} not a maxima object.
 
     sage: print maxima.eval('factor(x^5 - y^5)')
-    -(y - x)*(y^4 + x*y^3 + x^2*y^2 + x^3*y + x^4)
+    -(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4)
 
 We can create the polynomial $f$ as a Maxima polynomial, then call
@@ -71,7 +63,7 @@
     sage: f = maxima('x^5 - y^5')
     sage: f^2
-    (x^5 - y^5)^2
+    (x^5-y^5)^2
     sage: f.factor()
-    -(y - x)*(y^4 + x*y^3 + x^2*y^2 + x^3*y + x^4)
+    -(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4)
 
 Control-C interruption works well with the maxima interface,
@@ -90,7 +82,7 @@
 
     sage: a = maxima('(1 + sqrt(2))^5'); a
-    (sqrt(2) + 1)^5
+    (sqrt(2)+1)^5
     sage: a.expand()
-    29*sqrt(2) + 41
+    29*sqrt(2)+41
 
     sage: a = maxima('(1 + sqrt(2))^5')
@@ -110,22 +102,22 @@
     sage: f = maxima('(x + 3*y + x^2*y)^3')
     sage: f.expand()
-    x^6*y^3 + 9*x^4*y^3 + 27*x^2*y^3 + 27*y^3 + 3*x^5*y^2 + 18*x^3*y^2 + 27*x*y^2 + 3*x^4*y + 9*x^2*y + x^3
+    x^6*y^3+9*x^4*y^3+27*x^2*y^3+27*y^3+3*x^5*y^2+18*x^3*y^2+27*x*y^2+3*x^4*y+9*x^2*y+x^3
     sage: f.subst('x=5/z')
-    (5/z + 25*y/z^2 + 3*y)^3
+    (5/z+25*y/z^2+3*y)^3
     sage: g = f.subst('x=5/z')
     sage: h = g.ratsimp(); h
-    (27*y^3*z^6 + 135*y^2*z^5 + (675*y^3 + 225*y)*z^4 + (2250*y^2 + 125)*z^3 + (5625*y^3 + 1875*y)*z^2 + 9375*y^2*z + 15625*y^3)/z^6
+    (27*y^3*z^6+135*y^2*z^5+(675*y^3+225*y)*z^4+(2250*y^2+125)*z^3+(5625*y^3+1875*y)*z^2+9375*y^2*z+15625*y^3)/z^6
     sage: h.factor()
-    (3*y*z^2 + 5*z + 25*y)^3/z^6
+    (3*y*z^2+5*z+25*y)^3/z^6
 
     sage: eqn = maxima(['a+b*c=1', 'b-a*c=0', 'a+b=5'])
     sage: s = eqn.solve('[a,b,c]'); s
-    [[a = (25*sqrt(79)*%i + 25)/(6*sqrt(79)*%i - 34),b = (5*sqrt(79)*%i + 5)/(sqrt(79)*%i + 11),c = (sqrt(79)*%i + 1)/10],[a = (25*sqrt(79)*%i - 25)/(6*sqrt(79)*%i + 34),b = (5*sqrt(79)*%i - 5)/(sqrt(79)*%i - 11),c =  - (sqrt(79)*%i - 1)/10]]
+    [[a=(25*sqrt(79)*%i+25)/(6*sqrt(79)*%i-34),b=(5*sqrt(79)*%i+5)/(sqrt(79)*%i+11),c=(sqrt(79)*%i+1)/10],[a=(25*sqrt(79)*%i-25)/(6*sqrt(79)*%i+34),b=(5*sqrt(79)*%i-5)/(sqrt(79)*%i-11),c=-(sqrt(79)*%i-1)/10]]
 
 Here is an example of solving an algebraic equation:
     sage: maxima('x^2+y^2=1').solve('y')
-    [y =  - sqrt(1 - x^2),y = sqrt(1 - x^2)]
+    [y=-sqrt(1-x^2),y=sqrt(1-x^2)]
     sage: maxima('x^2 + y^2 = (x^2 - y^2)/sqrt(x^2 + y^2)').solve('y')
-    [y =  - sqrt(( - y^2 - x^2)*sqrt(y^2 + x^2) + x^2),y = sqrt(( - y^2 - x^2)*sqrt(y^2 + x^2) + x^2)]
+    [y=-sqrt((-y^2-x^2)*sqrt(y^2+x^2)+x^2),y=sqrt((-y^2-x^2)*sqrt(y^2+x^2)+x^2)]
 
 You can even nicely typeset the solution in latex:
@@ -137,20 +129,20 @@
 
     sage: e = maxima('sin(u + v) * cos(u)^3'); e
-    cos(u)^3*sin(v + u)
+    cos(u)^3*sin(v+u)
     sage: f = e.trigexpand(); f
-    cos(u)^3*(cos(u)*sin(v) + sin(u)*cos(v))
+    cos(u)^3*(cos(u)*sin(v)+sin(u)*cos(v))
     sage: f.trigreduce()
-    (sin(v + 4*u) + sin(v - 2*u))/8 + (3*sin(v + 2*u) + 3*sin(v))/8
+    (sin(v+4*u)+sin(v-2*u))/8+(3*sin(v+2*u)+3*sin(v))/8
     sage: w = maxima('3 + k*%i')
     sage: f = w^2 + maxima('%e')^w
     sage: f.realpart()
-    %e^3*cos(k) - k^2 + 9
+    %e^3*cos(k)-k^2+9
     
     sage: f = maxima('x^3 * %e^(k*x) * sin(w*x)'); f
     x^3*%e^(k*x)*sin(w*x)
     sage: f.diff('x')
-    k*x^3*%e^(k*x)*sin(w*x) + 3*x^2*%e^(k*x)*sin(w*x) + w*x^3*%e^(k*x)*cos(w*x)
+    k*x^3*%e^(k*x)*sin(w*x)+3*x^2*%e^(k*x)*sin(w*x)+w*x^3*%e^(k*x)*cos(w*x)
     sage: f.integrate('x')
-    (((k*w^6 + 3*k^3*w^4 + 3*k^5*w^2 + k^7)*x^3 + (3*w^6 + 3*k^2*w^4 - 3*k^4*w^2 - 3*k^6)*x^2 + ( - 18*k*w^4 - 12*k^3*w^2 + 6*k^5)*x - 6*w^4 + 36*k^2*w^2 - 6*k^4)*%e^(k*x)*sin(w*x) + (( - w^7 - 3*k^2*w^5 - 3*k^4*w^3 - k^6*w)*x^3 + (6*k*w^5 + 12*k^3*w^3 + 6*k^5*w)*x^2 + (6*w^5 - 12*k^2*w^3 - 18*k^4*w)*x - 24*k*w^3 + 24*k^3*w)*%e^(k*x)*cos(w*x))/(w^8 + 4*k^2*w^6 + 6*k^4*w^4 + 4*k^6*w^2 + k^8)
+    (((k*w^6+3*k^3*w^4+3*k^5*w^2+k^7)*x^3+(3*w^6+3*k^2*w^4-3*k^4*w^2-3*k^6)*x^2+(-18*k*w^4-12*k^3*w^2+6*k^5)*x-6*w^4+36*k^2*w^2-6*k^4)*%e^(k*x)*sin(w*x)+((-w^7-3*k^2*w^5-3*k^4*w^3-k^6*w)*x^3+(6*k*w^5+12*k^3*w^3+6*k^5*w)*x^2+(6*w^5-12*k^2*w^3-18*k^4*w)*x-24*k*w^3+24*k^3*w)*%e^(k*x)*cos(w*x))/(w^8+4*k^2*w^6+6*k^4*w^4+4*k^6*w^2+k^8)
 
     sage: f = maxima('1/x^2')
@@ -159,8 +151,8 @@
     sage: g = maxima('f/sinh(k*x)^4')
     sage: g.taylor('x', 0, 3)
-    f/(k^4*x^4) - 2*f/(3*k^2*x^2) + 11*f/45 - 62*k^2*f*x^2/945
+    f/(k^4*x^4)-2*f/(3*k^2*x^2)+11*f/45-62*k^2*f*x^2/945
 
     sage: maxima.taylor('asin(x)','x',0, 10)
-    x + x^3/6 + 3*x^5/40 + 5*x^7/112 + 35*x^9/1152
+    x+x^3/6+3*x^5/40+5*x^7/112+35*x^9/1152
 
 \subsection{Examples involving matrices}
@@ -178,5 +170,5 @@
     [[0,4],[3,1]]
     sage: A.eigenvectors()
-    [[[0,4],[3,1]],[1,0,0, - 4],[0,1,0, - 2],[0,0,1, - 4/3],[1,2,3,4]]
+    [[[0,4],[3,1]],[1,0,0,-4],[0,1,0,-2],[0,0,1,-4/3],[1,2,3,4]]
 
 We can also compute the echelon form in \sage:
@@ -194,5 +186,5 @@
     sage: _ = maxima.eval("f(t) := t*sin(t)")
     sage: maxima("laplace(f(t),t,s)")
-    2*s/(s^2 + 1)^2
+    2*s/(s^2+1)^2
 
     sage: maxima("laplace(delta(t-3),t,s)") #Dirac delta function
@@ -201,10 +193,10 @@
     sage: _ = maxima.eval("f(t) := exp(t)*sin(t)")
     sage: maxima("laplace(f(t),t,s)")
-    1/(s^2 - 2*s + 2)
+    1/(s^2-2*s+2)
     
     sage: _ = maxima.eval("f(t) := t^5*exp(t)*sin(t)")
     sage: maxima("laplace(f(t),t,s)")
-    360*(2*s - 2)/(s^2 - 2*s + 2)^4 - 480*(2*s - 2)^3/(s^2 - 2*s + 2)^5 + 120*(2*s - 2)^5/(s^2 - 2*s + 2)^6
-    sage: maxima("laplace(f(t),t,s)").display2d()
+    360*(2*s-2)/(s^2-2*s+2)^4-480*(2*s-2)^3/(s^2-2*s+2)^5+120*(2*s-2)^5/(s^2-2*s+2)^6
+    sage: print maxima("laplace(f(t),t,s)")
                                              3                 5
                360 (2 s - 2)    480 (2 s - 2)     120 (2 s - 2)
@@ -214,11 +206,11 @@
 
     sage: maxima("laplace(diff(x(t),t),t,s)")
-    s*?%laplace(x(t),t,s) - x(0)
+    s*?%laplace(x(t),t,s)-x(0)
     
     sage: maxima("laplace(diff(x(t),t,2),t,s)")
-    -?%at('diff(x(t),t,1),t = 0) + s^2*?%laplace(x(t),t,s) - x(0)*s
+    -?%at('diff(x(t),t,1),t=0)+s^2*?%laplace(x(t),t,s)-x(0)*s
 
 It is difficult to read some of these without the 2d representation:
-    sage.: maxima("laplace(diff(x(t),t,2),t,s)").display2d()
+    sage: print maxima("laplace(diff(x(t),t,2),t,s)")
                          !
                 d        !         2
@@ -262,5 +254,5 @@
 
     sage: S = maxima('nusum(exp(1+2*i/n),i,1,n)')
-    sage.: S.display2d()
+    sage: print S
                             2/n + 3                   2/n + 1
                           %e                        %e
@@ -273,5 +265,5 @@
     sage: T = S*maxima('2/n')
     sage: T.tlimit('n','inf')
-    %e^3 - %e
+    %e^3-%e
 
 \subsection{Miscellaneous}
@@ -284,5 +276,5 @@
 Defining functions in maxima:
     sage: maxima.eval('fun[a] := a^2')
-    'fun[a] := a^2'
+    'fun[a]:=a^2'
     sage: maxima('fun[10]')
     100
@@ -298,19 +290,8 @@
 
 \subsection{Latex Output}
-The latex output of Maxima is not perfect.  E.g.,
-
-    sage: maxima.eval('tex(sin(u) + sinh(v^2))')
-    '$$\\sinhv^2 + \\sinu$$false'
-    
-Notice the lack of space after the sin macro, which is a latex syntax
-error.  In \sage this is automatically fixed via a substition for
-trig functions, which may have potentially bad side effects:
+To tex a maxima object do this:
 
     sage: latex(maxima('sin(u) + sinh(v^2)'))
     \sinh v^2+\sin u
-
-It would be nice if somebody would fix this problem.  One way would
-be to improve Maxima by making the fix to Maxima and giving this back
-to the Maxima people.
 
 Here's another example:
@@ -338,4 +319,10 @@
     sage: maxima(sin(x))
     sin(x)
+
+A long complicated input expression:
+
+    sage: maxima._eval_line('((((((((((0) + ((1) / ((n0) ^ (0)))) + ((1) / ((n1) ^ (1)))) + ((1) / ((n2) ^ (2)))) + ((1) / ((n3) ^ (3)))) + ((1) / ((n4) ^ (4)))) + ((1) / ((n5) ^ (5)))) + ((1) / ((n6) ^ (6)))) + ((1) / ((n7) ^ (7)))) + ((1) / ((n8) ^ (8)))) + ((1) / ((n9) ^ (9)));')
+    '1/n9^9+1/n8^8+1/n7^7+1/n6^6+1/n5^5+1/n4^4+1/n3^3+1/n2^2+1/n1+1'
+    
 """
 
@@ -355,5 +342,5 @@
 #*****************************************************************************
 
-import os, re
+import os, re, sys
 import pexpect
 cygwin = os.uname()[0][:6]=="CYGWIN"
@@ -362,15 +349,11 @@
 from pexpect import EOF
 
+import random
+
 import sage.rings.all
-#import sage.rings.complex_number2 as complex_number
 
 from sage.misc.misc import verbose, DOT_SAGE, SAGE_ROOT
 
 from sage.misc.multireplace import multiple_replace
-
-SAGE_START = '_s_start_'
-SAGE_END = '_s_stop_'
-cnt = 0
-seq = 0
 
 COMMANDS_CACHE = '%s/maxima_commandlist_cache.sobj'%DOT_SAGE
@@ -389,8 +372,5 @@
     def __call__(self, x):
         import sage.rings.all
-        if sage.rings.all.is_Infinite(x):
-            return Expect.__call__(self, 'inf')
-        else:
-            return Expect.__call__(self, x)
+        return Expect.__call__(self, x)
         
     def __init__(self, script_subdirectory=None, logfile=None, server=None):
@@ -400,11 +380,14 @@
         # TODO: Input and output prompts in maxima can be changed by
         # setting inchar and outchar..
-        eval_using_file_cutoff = 200
+        eval_using_file_cutoff = 256
         self.__eval_using_file_cutoff = eval_using_file_cutoff
+        STARTUP = '%s/local/bin/sage-maxima.lisp'%SAGE_ROOT
+        if not os.path.exists(STARTUP):
+            raise RuntimeError, 'You must get the file local/bin/sage-maxima.lisp'
         Expect.__init__(self,
                         name = 'maxima',
                         prompt = '\(\%i[0-9]+\)',
-                        command = "maxima --disable-readline",
-                        maxread = 1,    # CRUCIAL to use less buffering for maxima (or get all kinds of hangs on OS X and 64-bit machines, etc!
+                        command = 'maxima -p "%s"'%STARTUP, 
+                        maxread = 10000, 
                         script_subdirectory = script_subdirectory,
                         restart_on_ctrlc = False,
@@ -415,5 +398,11 @@
                         logfile = logfile,
                         eval_using_file_cutoff=eval_using_file_cutoff)
+        self._display_prompt = '<sage-display>'  # must match what is in the file local/ibn/sage-maxima.lisp!!
+        self._output_prompt_re = re.compile('\(\%o[0-9]+\)')
+        self._ask = ['zero or nonzero?', 'an integer?', 'positive, negative, or zero?', 'positive or negative?']
+        self._prompt_wait = [self._prompt] + [re.compile(x) for x in self._ask]
+        self._error_re = re.compile('(debugmode|Incorrect syntax|Maxima encountered a Lisp error)')
         self._display2d = False
+
 
     def __getattr__(self, attrname):
@@ -423,115 +412,185 @@
 
     def _start(self):
-        # For some reason sending a single input line at startup avoids
-        # lots of weird timing issues when doing doctests.
         Expect._start(self)
-        self(1)    
-
-    # this doesn't work.
-    #def x_start(self):
-    #    Expect._start(self)
-    #    self._expect.sendline('inchar:"__SAGE__";')
-    #    self._change_prompt('__SAGE__[0-9]+\)')
-    #    self.expect().expect('__SAGE__[0-9]+\)')
-
-    def _eval_line_using_file(self, line, tmp):
-        F = open(tmp, 'w')
-        F.write(line)
-        F.close()
+        self._eval_line('0;')
+
+    def __reduce__(self):
+        return reduce_load_Maxima, tuple([])
+
+    def _quit_string(self):
+        return 'quit();'
+
+    def _sendline(self, str):
+        self._sendstr(str)
+        os.write(self._expect.child_fd, os.linesep)
+
+    def _sendstr(self, str):
         if self._expect is None:
             self._start()
-        # For some reason this trivial comp
-        # keeps certain random freezes from occuring.  Do not remove this.
-        # The space before the \n is also important.
-        self._expect.sendline('0;batchload("%s"); \n'%tmp)
-        self._expect.expect(self._prompt)
-        return ''
-
-    def __reduce__(self):
-        return reduce_load_Maxima, tuple([])
-
-    def _quit_string(self):
-        return 'quit();'
+        try:
+            os.write(self._expect.child_fd, str)
+        except OSError:
+            self._crash_msg()
+            self.quit()
+            self._sendstr(str)
+
+    def _crash_msg(self):
+        print "Maxima crashed -- automatically restarting."
+
+    def _expect_expr(self, expr=None, timeout=None):
+        if expr is None:
+            expr = self._prompt_wait
+        if self._expect is None:
+            self._start()
+        try:
+            if timeout:
+                i = self._expect.expect(expr,timeout=timeout)
+            else:
+                i = self._expect.expect(expr)
+            if i > 0:
+                v = self._expect.before
+                j = v.find('Is ')
+                v = v[j:]
+                msg = "Computation failed since Maxima requested additional constraints (use assume):\n" + v + self._ask[i-1]
+                self._sendstr(chr(3))
+                self._sendstr(chr(3))
+                self._expect_expr()
+                raise ValueError, msg
+        except KeyboardInterrupt, msg:
+            #print self._expect.before
+            i = 0
+            while True:
+                try:
+                    print "Control-C pressed.  Interrupting Maxima. Please wait a few seconds..."
+                    self._sendstr('quit;\n'+chr(3))
+                    self._sendstr('quit;\n'+chr(3))
+                    self.interrupt()
+                    self.interrupt()
+                except KeyboardInterrupt:
+                    i += 1
+                    if i > 10:
+                        break
+                    pass
+                else:
+                    break
+            raise KeyboardInterrupt, msg
+
+    def _interrupt(self):
+        for i in range(15):
+            try:
+                self._sendstr('quit;\n'+chr(3))
+                self._expect_expr(timeout=2)
+            except pexpect.TIMEOUT:
+                pass
+            except pexpect.EOF:
+                self._crash_msg()                
+                self.quit()
+            else:
+                return
+
+    def _before(self):
+        return self._expect.before
+
+    def _batch(self, str, batchload=True):
+        F = open(tmp, 'w')
+        F.write(str)
+        F.close()
+        if batchload:
+            cmd = 'batchload("%s");'%tmp
+        else:
+            cmd = 'batch("%s");'%tmp
+        self._sendline(cmd)
+        self._expect_expr()
+        out = self._before()
+        self._error_check(str, out)
+        return out
+
+    def _error_check(self, str, out):
+        r = self._error_re
+        m = r.search(out)
+        if not m is None:
+            self._error_msg(str, out)
+            
+    def _error_msg(self, str, out):
+        raise TypeError, "Error executing code in Maxima\nCODE:\n\t%s\nMaxima ERROR:\n\t%s"%(str, out.replace('-- an error.  To debug this try debugmode(true);',''))
 
     def _eval_line(self, line, reformat=True, allow_use_file=False,
                    wait_for_prompt=True):
-        if self._expect is None:
-            self._start()
+        if len(line) == 0:
+            return ''
+        line = line.rstrip()
+        if line[-1] != '$' and line[-1] != ';':
+            line += ';'
+
+        self._synchronize()
+
+        if len(line) > self.__eval_using_file_cutoff:
+            a = self(line)
+            return repr(a)
+        else:
+            self._sendline(line)
+
         if not wait_for_prompt:
-            return Expect._eval_line(self, line)
-        line = line.rstrip().rstrip(';')
-        if line == '':
-            return ''
-        global seq
-        seq += 1
-        start = SAGE_START + str(seq)
-        end = SAGE_END + str(seq)
-        line = '%s;\n%s; %s;'%(start, line, end)
-        if self._expect is None:
-            self._start()
-        if allow_use_file and self.__eval_using_file_cutoff and \
-                            len(line) > self.__eval_using_file_cutoff:
-            return self._eval_line_using_file(line, tmp)
-        try:
-            E = self._expect
-            #print "in = '%s'"%line
-            E.sendline(line)
-            self._expect.expect(end)
-            # We have timeouts below, since getting the end above
-            # means the computation completed, but on some systems
-            # (Cygwin) the expect interface can sometimes hang getting
-            # the final prompts. 
-            try:
-                self._expect.expect(end, timeout=1)
-                out = self._expect.before
-                self._expect.expect(self._prompt, timeout=1)
-                out += self._expect.before
-            except pexpect.TIMEOUT:
-                out = self._expect.before
-            if not '(%o' in out:
-                self._expect.expect(self._prompt)
-
-        except EOF:
-            if self._quit_string() in line:
-                return ''
-        except KeyboardInterrupt:
-            self._keyboard_interrupt()
-            return ''
-
-        if 'Incorrect syntax:' in out:
-            raise RuntimeError, out
-
-        import os
-        if cygwin:
-            # for reasons I can't deduce yet, maxima behaves somewhat
-            # differently under cygwin...
-            out = out.lstrip(';')
-        else:
-	    i = out.rfind(start)
-	    j = out.rfind(end)
-            out = out[i+len(start):j]
-
+            return
+
+        self._expect_expr(self._display_prompt)
+        self._expect_expr()
+        out = self._before()
+        self._error_check(line, out)
+        
         if not reformat:
             return out
-        if 'error' in out:
-            return out
-        out = out.lstrip()
-        i = out.find('(%o')
-        out0 = out[:i].strip()
-        i += out[i:].find(')')
-        out1 = out[i+1:].strip()
-        out = out0 + out1
-        out = ''.join(out.split())    # no whitespace
-        i = out.rfind(';;')
-        if i != -1:
-            out = out[i+2:]
-        out = out.replace('-', ' - ').replace('+',' + ').replace('=',' = ').replace(': =',' :=').replace('^ - ','^-')
-        if out[:3] == ' - ':
-            out = '-' + out[3:]
-        out = out.replace('E - ', 'E-')
-        out = out.replace('%e - ', '%e-')
-        i = out.rfind('(%o')
-        return out[:i]
-
+        
+        r = self._output_prompt_re
+        m = r.search(out)
+        if m is None:
+            o = out[:-2]
+        else:
+            o = out[m.end()+1:-2]
+        o = ''.join([x.strip() for x in o.split()])
+        return o
+
+        i = o.rfind('(%o')
+        return o[:i]
+
+
+    def _synchronize(self):
+        """
+        Synchronize pexpect interface.
+
+        This put a random integer (plus one!) into the output stream,
+        then waits for it, thus resynchronizing the stream.  If the
+        random integer doesn't appear within 1 second, maxima is sent
+        interrupt signals.
+
+        This way, even if you somehow left maxima in a busy state
+        computing, calling _synchronize gets everything fixed.
+
+        EXAMPLES:
+        This makes Maxima start a calculation:
+            sage: maxima._sendstr('1/1'*500)
+
+        When you type this command, this synchronize command is implicitly
+        called, and the above running calculation is interrupted:
+            sage: maxima('2+2')
+            4
+        """
+        if self._expect is None: return
+        r = random.randrange(2147483647)
+        s = str(r+1)
+        cmd = "1+%s;\n"%r
+        self._sendstr(cmd)
+        try:
+            self._expect_expr(timeout=0.5)
+            if not s in self._before():
+                self._expect_expr(s,timeout=0.5)
+                self._expect_expr(timeout=0.5)
+        except pexpect.TIMEOUT, msg:
+            self._interrupt()
+        except pexpect.EOF:
+            self._crash_msg()
+            self.quit()
+
+            
 
     ###########################################
@@ -626,5 +685,5 @@
         return 'false'
 
-    def function(self, args, defn, repr=None, latex=None):
+    def function(self, args, defn, rep=None, latex=None):
         """
         Return the Maxima function with given arguments
@@ -635,5 +694,5 @@
             defn -- a string (or Maxima expression) that defines
                     a function of the arguments in Maxima.
-            repr -- an optional string; if given, this is how the function will print.
+            rep  -- an optional string; if given, this is how the function will print.
         
         EXAMPLES:
@@ -643,12 +702,13 @@
             sage: f = maxima.function('x,y', 'sin(x)+cos(y)')
             sage: f(2,3.5)
-            sin(2) - .9364566872907963
+            sin(2)-.9364566872907963
             sage: f
             sin(x)+cos(y)
             
-            sage: g = f.integrate('z'); g
-            (cos(y) + sin(x))*z
+            sage: g = f.integrate('z')
+            sage: g
+            (cos(y)+sin(x))*z
             sage: g(1,2,3)
-            3*(cos(2) + sin(1))
+            3*(cos(2)+sin(1))
 
         The function definition can be a maxima object:
@@ -658,19 +718,24 @@
             gamma(x)*sin(x)
             sage: t(2)
-            sin(2)
+             sin(2)
             sage: float(t(2))
             0.90929742682568171
             sage: loads(t.dumps())
             gamma(x)*sin(x)
-
-            
         """
         name = self._next_var_name()
-        defn = str(defn)
-        args = str(args)
-        maxima.eval('%s(%s) := %s'%(name, args, defn))
-        if repr is None:
-            repr = defn
-        f = MaximaFunction(self, name, repr, args, latex)
+        if isinstance(defn, MaximaElement):
+            defn = defn.str()
+        elif not isinstance(defn, str):
+            defn = str(defn)
+        if isinstance(args, MaximaElement):
+            args = args.str()
+        elif not isinstance(args, str):
+            args = str(args)
+        cmd = '%s(%s) := %s'%(name, args, defn)
+        maxima._eval_line(cmd)
+        if rep is None:
+            rep = defn
+        f = MaximaFunction(self, name, rep, args, latex)
         return f
 
@@ -678,11 +743,20 @@
         """
         Set the variable var to the given value.
-        """
-        cmd = '%s : %s$"";'%(var, str(value).rstrip(';'))
-        out = self._eval_line(cmd, reformat=False, allow_use_file=True)
-        
-        if out.find("error") != -1:
-            raise TypeError, "Error executing code in Maxima\nCODE:\n\t%s\nMaxima ERROR:\n\t%s"%(cmd, out)
-
+
+        INPUT:
+            var -- string
+            value -- string
+        """
+        if not isinstance(value, str):
+            raise TypeError
+        cmd = '%s : %s$'%(var, value.rstrip(';'))
+        if len(cmd) > self.__eval_using_file_cutoff:
+            self._batch(cmd, batchload=True)
+        else:
+            self._eval_line(cmd)
+            #self._sendline(cmd)
+            #self._expect_expr()
+            #out = self._before()
+            #self._error_check(cmd, out)
 
     def get(self, var):
@@ -690,17 +764,15 @@
         Get the string value of the variable var.
         """
-        s = self._eval_line('%s'%var)
+        s = self._eval_line('%s;'%var)
         return s
         
     def clear(self, var):
-         """
-         Clear the variable named var.
-         """
-         if self._expect is None:
-             return
-         try:
-             self._expect.sendline('kill(%s);\n'%var)
-         except:  # program around weirdness in pexpect
-             pass
+        """
+        Clear the variable named var.
+        """
+        try:
+            self._eval_line('kill(%s)$'%var, reformat=False)
+        except TypeError:
+            pass
         
     def console(self):
@@ -710,25 +782,25 @@
         return maxima_version()
 
-    def display2d(self, flag=True):
-        """
-        Set the flag that determines whether Maxima objects are
-        printed using their 2-d ASCII art representation.  When the
-        maxima interface starts the default is that objects are not
-        represented in 2-d.
-
-        INPUT:
-            flag -- bool (default: True)
-
-        EXAMPLES
-            sage: maxima('1/2')
-            1/2
-            sage: maxima.display2d(True)
-            sage: maxima('1/2')
-                                           1
-                                           -
-                                           2
-            sage: maxima.display2d(False)
-        """
-        self._display2d = bool(flag)
+##     def display2d(self, flag=True):
+##         """
+##         Set the flag that determines whether Maxima objects are
+##         printed using their 2-d ASCII art representation.  When the
+##         maxima interface starts the default is that objects are not
+##         represented in 2-d.
+
+##         INPUT:
+##             flag -- bool (default: True)
+
+##         EXAMPLES
+##             sage: maxima('1/2')
+##             1/2
+##             sage: maxima.display2d(True)
+##             sage: maxima('1/2')
+##                                            1
+##                                            -
+##                                            2
+##             sage: maxima.display2d(False)
+##         """
+##         self._display2d = bool(flag)
 
     def plot2d(self, *args):
@@ -862,12 +934,12 @@
                    
         EXAMPLES:
-            sage.: maxima.de_solve('diff(y,x,2) + 3*x = y', ['x','y'], [1,1,1])
-            y = 3*x - 2*%e^(x - 1)
-            sage.: maxima.de_solve('diff(y,x,2) + 3*x = y', ['x','y'])
-            y = %k1*%e^x + %k2*%e^ - x + 3*x
-            sage.: maxima.de_solve('diff(y,x) + 3*x = y', ['x','y'])
-            y = (%c - 3*( - x - 1)*%e^ - x)*%e^x
-            sage.: maxima.de_solve('diff(y,x) + 3*x = y', ['x','y'],[1,1])
-            y =  - %e^ - 1*(5*%e^x - 3*%e*x - 3*%e)
+            sage: maxima.de_solve('diff(y,x,2) + 3*x = y', ['x','y'], [1,1,1])
+            y=3*x-2*%e^(x-1)
+            sage: maxima.de_solve('diff(y,x,2) + 3*x = y', ['x','y'])
+            y=%k1*%e^x+%k2*%e^-x+3*x
+            sage: maxima.de_solve('diff(y,x) + 3*x = y', ['x','y'])
+            y=(%c-3*(-x-1)*%e^-x)*%e^x
+            sage: maxima.de_solve('diff(y,x) + 3*x = y', ['x','y'],[1,1])
+            y=-%e^-1*(5*%e^x-3*%e*x-3*%e)
         """
         if not isinstance(vars, str):
@@ -900,13 +972,13 @@
 
         EXAMPLES:
-            sage.: maxima.clear('x'); maxima.clear('f')
-            sage.: maxima.de_solve_laplace("diff(f(x),x,2) = 2*diff(f(x),x)-f(x)", ["x","f"], [0,1,2])
-            f(x) = x*%e^x + %e^x
+            sage: maxima.clear('x'); maxima.clear('f')
+            sage: maxima.de_solve_laplace("diff(f(x),x,2) = 2*diff(f(x),x)-f(x)", ["x","f"], [0,1,2])
+            f(x)=x*%e^x+%e^x
             
-            sage.: maxima.clear('x'); maxima.clear('f')            
-            sage.: f = maxima.de_solve_laplace("diff(f(x),x,2) = 2*diff(f(x),x)-f(x)", ["x","f"])
-            sage.: f
-            f(x) = x*%e^x*(at('diff(f(x),x,1),x = 0)) - f(0)*x*%e^x + f(0)*%e^x
-            sage.: f.display2d()
+            sage: maxima.clear('x'); maxima.clear('f')            
+            sage: f = maxima.de_solve_laplace("diff(f(x),x,2) = 2*diff(f(x),x)-f(x)", ["x","f"])
+            sage: f
+            f(x)=x*%e^x*(?%at('diff(f(x),x,1),x=0))-f(0)*x*%e^x+f(0)*%e^x
+            sage: print f
                                                !
                                    x  d        !                  x          x
@@ -941,6 +1013,6 @@
             sage: eqns = ["x + z = y","2*a*x - y = 2*a^2","y - 2*z = 2"]    
             sage: vars = ["x","y","z"]                                      
-            sage.: maxima.solve_linear(eqns, vars)                         
-            [x = a + 1,y = 2*a,z = a - 1]
+            sage: maxima.solve_linear(eqns, vars)
+            [x=a+1,y=2*a,z=a-1]
         """
         eqs = "["
@@ -958,33 +1030,33 @@
         return self('linsolve(%s, %s)'%(eqs, vrs))
 
-    def unit_quadratic_integer(self, n):
-        r"""
-        Finds a unit of the ring of integers of the quadratic number
-        field $\Q(\sqrt{n})$, $n>1$, using the qunit maxima command.
-
-        EXAMPLE:
-            sage: u = maxima.unit_quadratic_integer(101)           
-            sage: u.parent()                                       
-            Number Field in a with defining polynomial x^2 - 101
-            sage: u                                                
-            a + 10
-            sage: u = maxima.unit_quadratic_integer(13)            
-            sage: u                                                
-            5*a + 18
-            sage: u.parent()                                       
-            Number Field in a with defining polynomial x^2 - 13
-        """
-        from sage.rings.all import QuadraticField, Integer
-        # Take square-free part so sqrt(n) doesn't get simplified further by maxima
-        # (The original version of this function would yield wrong answers if
-        # n is not squarefree.)
-        n = Integer(n).square_free_part()  
-        if n < 1:
-            raise ValueError, "n (=%s) must be >= 1"%n
-        s = str(self('qunit(%s)'%n)).lower()
-        r = re.compile('sqrt\(.*\)')
-        s = r.sub('a', s)
-        a = QuadraticField(n, 'a').gen()
-        return eval(s)
+##     def unit_quadratic_integer(self, n):
+##         r"""
+##         Finds a unit of the ring of integers of the quadratic number
+##         field $\Q(\sqrt{n})$, $n>1$, using the qunit maxima command.
+
+##         EXAMPLE:
+##             sage: u = maxima.unit_quadratic_integer(101)           
+##             sage: u.parent()                                       
+##             Number Field in a with defining polynomial x^2 - 101
+##             sage: u                                                
+##             a + 10
+##             sage: u = maxima.unit_quadratic_integer(13)            
+##             sage: u                                                
+##             5*a + 18
+##             sage: u.parent()                                       
+##             Number Field in a with defining polynomial x^2 - 13
+##         """
+##         from sage.rings.all import QuadraticField, Integer
+##         # Take square-free part so sqrt(n) doesn't get simplified further by maxima
+##         # (The original version of this function would yield wrong answers if
+##         # n is not squarefree.)
+##         n = Integer(n).square_free_part()  
+##         if n < 1:
+##             raise ValueError, "n (=%s) must be >= 1"%n
+##         s = str(self('qunit(%s)'%n)).lower()
+##         r = re.compile('sqrt\(.*\)')
+##         s = r.sub('a', s)
+##         a = QuadraticField(n, 'a').gen()
+##         return eval(s)
 
     def plot_list(self, ptsx, ptsy, options=None):
@@ -1005,6 +1077,6 @@
 
         EXAMPLES:
-            sage.: zeta_ptsx = [ (pari(1/2 + i*I/10).zeta().real()).precision(1) for i in range (70,150)]  
-            sage.: zeta_ptsy = [ (pari(1/2 + i*I/10).zeta().imag()).precision(1) for i in range (70,150)]  
+            sage: zeta_ptsx = [ (pari(1/2 + i*I/10).zeta().real()).precision(1) for i in range (70,150)]  
+            sage: zeta_ptsy = [ (pari(1/2 + i*I/10).zeta().imag()).precision(1) for i in range (70,150)]  
             sage.: maxima.plot_list(zeta_ptsx, zeta_ptsy)                   
             sage.: opts='[gnuplot_preamble, "set nokey"], [gnuplot_term, ps], [gnuplot_out_file, "zeta.eps"]'
@@ -1064,4 +1136,20 @@
         return P('%s(%s)'%(self.name(), x))
     
+    def __str__(self):
+        """
+        Printing an object explicitly gives ASCII art:
+
+        EXAMPLES:
+            sage: f = maxima('1/(x-1)^3'); f
+            1/(x-1)^3
+            sage: print f
+                                                  1
+                                               --------
+                                                      3
+                                               (x - 1)
+
+        """
+        return self.display2d(onscreen=False)
+
     def __cmp__(self, other):
         """
@@ -1087,13 +1175,21 @@
         # thanks to David Joyner for telling me about using "is".
         P = self.parent()
-        if P.eval("is (%s < %s)"%(self.name(), other.name())) == P._true_symbol():
-            return -1
-        elif P.eval("is (%s > %s)"%(self.name(), other.name())) == P._true_symbol():
-            return 1
-        elif P.eval("is (%s = %s)"%(self.name(), other.name())) == P._true_symbol():
-            return 0
-        else:
-            return -1  # everything is supposed to be comparable in Python, so we define
-                       # the comparison thus when no comparable in interfaced system.
+        try:
+            if P.eval("is (%s < %s)"%(self.name(), other.name())) == P._true_symbol():
+                return -1
+            elif P.eval("is (%s > %s)"%(self.name(), other.name())) == P._true_symbol():
+                return 1
+            elif P.eval("is (%s = %s)"%(self.name(), other.name())) == P._true_symbol():
+                return 0
+        except TypeError:
+            pass
+        return cmp(repr(self),repr(other))
+                   # everything is supposed to be comparable in Python, so we define
+                   # the comparison thus when no comparable in interfaced system.
+
+    def sage_object(self):
+         from sage.calculus.calculus import symbolic_expression_from_maxima_string
+         return symbolic_expression_from_maxima_string(self.name(), maxima=self.parent())
+
     def numer(self):
         return self.comma('numer')
@@ -1118,15 +1214,16 @@
 
     def str(self):
-        self._check_valid()
-        P = self.parent()
+        P = self._check_valid()
         return P.get(self._name)
 
     def __repr__(self):
-        self._check_valid()
-        P = self.parent()
-        if P._display2d:
-            return self.display2d(onscreen=False)
-        else:
-            return P.get(self._name)
+        P = self._check_valid()
+        try:
+            return self.__repr
+        except AttributeError:
+            pass
+        r = P.get(self._name)
+        self.__repr = r
+        return r
 
     def display2d(self, onscreen=True):
@@ -1141,17 +1238,17 @@
         P = self.parent()
         s = P._eval_line('display2d : true; %s'%self.name(), reformat=False)
-        P._eval_line('display2d : false', reformat=False)
-        if not cygwin:
-            i = s.find('true')
-            i += s[i:].find('\n')
-            s = s[i+1:]
-        i = s.find('true')
-        i += s[i:].find('\n')
-        j = s.rfind('(%o')
-        s = s[i:j-2]
-        i = s.find('(%o')
-        j = i + s[i:].find(')')
-        s = s[:i] + ' '*(j-i+1) + s[j+1:]
-        s = s.lstrip('\n')
+        P._eval_line('display2d : false;', reformat=False)
+
+        r = P._output_prompt_re
+
+        m = r.search(s)
+        s = s[m.start():]
+        i = s.find('\n')
+        s = s[i+1 + len(P._display_prompt):]
+        m = r.search(s)
+        if not m is None:
+            s = s[:m.start()] + ' '*(m.end() - m.start()) + s[m.end():].rstrip()
+        # if ever want to dedent, see
+        # http://mail.python.org/pipermail/python-list/2006-December/420033.html
         if onscreen:
             print s
@@ -1178,10 +1275,10 @@
             sage: f.diff('x', 2)                             
             2
-            sage: maxima('sin(x^2)').diff('x',4)             
-            16*x^4*sin(x^2) - 12*sin(x^2) - 48*x^2*cos(x^2)  
+            sage: maxima('sin(x^2)').diff('x',4)
+            16*x^4*sin(x^2)-12*sin(x^2)-48*x^2*cos(x^2)
 
             sage: f = maxima('x^2 + 17*y^2')                 
             sage: f.diff('x')
-            2*x
+            34*y*'diff(y,x,1)+2*x
             sage: f.diff('y')                                
             34*y
@@ -1252,12 +1349,12 @@
         EXAMPLES:
             sage: maxima('x^2+1').integral()                   
-            x^3/3 + x
+            x^3/3+x
             sage: maxima('x^2+ 1 + y^2').integral('y')         
-            y^3/3 + x^2*y + y
+            y^3/3+x^2*y+y
             sage: maxima('x / (x^2+1)').integral()             
-            log(x^2 + 1)/2
+            log(x^2+1)/2
             sage: maxima('1/(x^2+1)').integral()               
             atan(x)
-            sage.: maxima('1/(x^2+1)').integral('x', 0, infinity) 
+            sage: maxima('1/(x^2+1)').integral('x', 0, infinity) 
             %pi/2
             sage: maxima('x/(x^2+1)').integral('x', -1, 1)     
@@ -1283,5 +1380,8 @@
 
     def __float__(self):
-        return float(str(self.numer()))
+        try:
+            return float(repr(self.numer()))
+        except ValueError:
+            raise TypeError, "unable to coerce '%s' to float"%repr(self)
 
     def __len__(self):
@@ -1324,5 +1424,16 @@
         if n < 0 or n >= len(self):
             raise IndexError, "n = (%s) must be between %s and %s"%(n, 0, len(self)-1)
+        # If you change the n+1 to n below, better change __iter__ as well.
         return ExpectElement.__getitem__(self, n+1)
+
+    def __iter__(self):
+        """
+        EXAMPLE:
+            sage: v = maxima('create_list(i*x^i,i,0,5)')
+            sage: list(v)
+            [0, x, 2*x^2, 3*x^3, 4*x^4, 5*x^5]
+        """
+        for i in range(len(self)):
+            yield self[i]
 
     def subst(self, val):
@@ -1337,5 +1448,5 @@
         self._check_valid()
         P = self.parent()
-        s = P._eval_line('tex(%s)'%self.name(), reformat=False)
+        s = P._eval_line('tex(%s);'%self.name(), reformat=False)
         if not '$$' in s:
             raise RuntimeError, "Error texing maxima object."
@@ -1411,6 +1522,6 @@
             sage: f = maxima('1/((1+x)*(x-1))')            
             sage: f.partial_fraction_decomposition('x')    
-            1/(2*(x - 1)) - 1/(2*(x + 1))
-            sage: f.partial_fraction_decomposition('x').display2d() 
+            1/(2*(x-1))-1/(2*(x+1))
+            sage: print f.partial_fraction_decomposition('x')
                                  1           1
                              --------- - ---------
@@ -1436,4 +1547,7 @@
         self.__args = args
         self.__latex = latex
+
+    def __reduce__(self):
+        return reduce_load_Maxima_function, (self.parent(), self.__defn, self.__args, self.__latex)
         
     def __call__(self, *x):
@@ -1464,5 +1578,5 @@
         else:
             args = self.__args + ',' + var
-        return P.function(args, str(f))
+        return P.function(args, repr(f))
 
 
@@ -1475,4 +1589,8 @@
 def reduce_load_Maxima():
     return maxima
+
+def reduce_load_Maxima_function(parent, defn, args, latex):
+    return parent.function(args, defn, defn, latex)
+    
 
 import os
@@ -1486,2 +1604,4 @@
     import sage.interfaces.quit
     sage.interfaces.quit.expect_quitall()
+
+
Index: sage/interfaces/mwrank.py
===================================================================
--- sage/interfaces/mwrank.py	(revision 1097)
+++ sage/interfaces/mwrank.py	(revision 4062)
@@ -68,5 +68,5 @@
 
     def __call__(self, cmd):
-        return self.eval(cmd)
+        return self.eval(str(cmd))
 
     def console(self):
Index: sage/interfaces/qsieve.py
===================================================================
--- sage/interfaces/qsieve.py	(revision 2550)
+++ sage/interfaces/qsieve.py	(revision 4331)
@@ -8,4 +8,15 @@
 
 import sage.rings.integer
+
+from sage.misc.all import tmp_dir
+
+_tmp_dir = False
+def tmpdir():
+    global _tmp_dir
+    if _tmp_dir:
+        return
+    X = tmp_dir('qsieve')
+    os.environ['TMPDIR'] = X
+    _tmp_dir = True
 
 def qsieve(n, block=True, time=False, verbose=False):
@@ -31,5 +42,6 @@
             sieve computation is complete before using SAGE further.
             If False, SAGE will run while the sieve computation
-            runs in parallel.
+            runs in parallel.  If q is the returned object, use
+            q.quit() to terminate a running factorization.
         time -- (default: False) if True, time the command using
             the UNIX "time" command (which you might have to install).
@@ -75,4 +87,5 @@
     else:
         t = ''
+    tmpdir()
     out = os.popen('echo "%s" | %s QuadraticSieve 2>&1'%(n,t)).read()
     z = data_to_list(out, n, time=time)
@@ -152,4 +165,5 @@
         else:
             cmd = 'QuadraticSieve'
+        tmpdir()        
         self._p = pexpect.spawn(cmd)
         cleaner.cleaner(self._p.pid, 'QuadraticSieve')
@@ -184,4 +198,6 @@
         """
         if self._done:
+            if hasattr(self, '_killed') and self._killed:
+                return "Factorization was terminated early."
             v = data_to_list(self._get(), self._n, self._do_time)
             if self._do_time:
@@ -239,6 +255,18 @@
         Terminate the QuadraticSieve process, in case you want
         to give up on computing this factorization.
-        """
-        self._p.close()
+
+        EXAMPLES:
+            sage: n = next_prime(2^110)*next_prime(2^100)
+            sage: qs = qsieve(n, block=False)
+            sage: qs
+            Proper factors so far: []
+            sage: qs.quit()
+            sage: qs
+            Factorization was terminated early.
+        """
+        pid = self.pid()
+        os.killpg(int(pid),9)
+        #self._p.close()
+        self._killed = True
         self._done = True
 
Index: sage/interfaces/quit.py
===================================================================
--- sage/interfaces/quit.py	(revision 2920)
+++ sage/interfaces/quit.py	(revision 4022)
@@ -1,5 +1,5 @@
 """nodoctest"""
 
-import os, time
+import os, time, pexpect
 
 expect_objects = []
@@ -11,7 +11,7 @@
             try:
                 R.quit(verbose=verbose)
-            except RuntimeError, msg:
-                if verbose:
-                    print msg
+                pass
+            except RuntimeError:
+                pass
     kill_spawned_jobs()
 
@@ -24,18 +24,12 @@
         pid = L[:i].strip()
         cmd = L[i+1:].strip()
-        j = 0
-        while j < 3:
-            j += 1
-            if not is_running(pid):
-                break
-            try:
-                os.killpg(int(pid), 9)
-            except OSError, msg:
-                pass
-            else:
-                j += 1
-                if j > 5:
-                    os.kill(int(pid), 9)
-                    break
+        try:
+            #s = "Killing spawned job %s"%pid
+            #if len(cmd) > 0:
+            #    s += ' (%s)'%cmd
+            #print s
+            os.killpg(int(pid), 9)
+        except:
+            pass
             
 def is_running(pid):
Index: sage/interfaces/singular.py
===================================================================
--- sage/interfaces/singular.py	(revision 3036)
+++ sage/interfaces/singular.py	(revision 4269)
@@ -262,4 +262,5 @@
 
 import sage.misc.misc as misc
+import sage.rings.integer
 
 
@@ -546,12 +547,16 @@
         return SingularElement(self, None, name, True)
 
-    def ring(self, char=0, vars='(x)', order='lp'):
+    def ring(self, char=0, vars='(x)', order='lp', check=True):
         r"""
         Create a Singular ring and makes it the current ring.
 
         INPUT:
-            char -- characteristic of the base ring (see examples below)
+            char -- characteristic of the base ring (see examples below),
+                    which must be either 0, prime (!), or one of
+                    several special codes (see examples below).
             vars -- a tuple or string that defines the variable names
             order -- string -- the monomial order (default: 'lp')
+            check -- if True, check primality of the characteristic
+                     if it is an integer.  
 
         OUTPUT:
@@ -582,5 +587,5 @@
             sage: R3 = singular.ring(7, '(x(1..10))', 'ds')
 
-        This is a polynomial ring over the transcendtal extension $\Q(a)$ of $\Q$:
+        This is a polynomial ring over the transcendental extension $\Q(a)$ of $\Q$:
             sage: R4 = singular.ring('(0,a)', '(mu,nu)', 'lp')
 
@@ -607,4 +612,9 @@
         except RuntimeError, TypeError:  # error if variable is not already defined.
             pass
+        if check and isinstance(char, (int, long, sage.rings.integer.Integer)):
+            if char != 0:
+                n = sage.rings.integer.Integer(char)
+                if not n.is_prime():
+                    raise ValueError, "the characteristic must be 0 or prime"
         R = self('%s,%s,%s'%(char, vars, order), 'ring')
         self.eval('short=0')  # make output include *'s for multiplication for *THIS* ring.
@@ -794,7 +804,7 @@
             P.eval('%s[%s] = %s'%(self.name(), n, value.name()))
 
-    def is_zero(self):
+    def __nonzero__(self):
         P = self.parent()
-        return P.eval('%s == 0'%self.name()) == '1'
+        return P.eval('%s == 0'%self.name()) == '0'
             
     def sage_polystring(self):
Index: sage/lfunctions/dokchitser.py
===================================================================
--- sage/lfunctions/dokchitser.py	(revision 3709)
+++ sage/lfunctions/dokchitser.py	(revision 4287)
@@ -366,20 +366,31 @@
             sage: L.taylor_series(1)
             0.305999773834052*z + 0.186547797268162*z^2 + -0.136791463097188*z^3 + 0.0161066468496401*z^4 + 0.0185955175398802*z^5 + O(z^6)
+
+        We compute a Taylor series where each coefficient is to high precision.
+            sage: E = EllipticCurve('389a')
+            sage: L = E.Lseries_dokchitser(200)
+            sage: L.taylor_series(1,3)
+            6.2239725530250970363983975962696997888173850098274602272589e-73 + (-3.5271062035449946049211903242820246129524508593200000161038e-73)*z + 0.75931650028842677023019260789472201907809751649492435158581*z^2 + O(z^3)                          # 32-bit
+            6.2239725530250970363983942830358807065824196704980264311105e-73 + (-3.5271062035449946049211884466825561834034352383203420991340e-73)*z + 0.75931650028842677023019260789472201907809751649492435158581*z^2 + O(z^3)                          # 64-bit
         """
         self.__check_init()        
         a = self.__CC(a)
         k = Integer(k)
-        z = self.gp().eval('Lseries(%s,,%s)'%(a,k-1))
-        if 'pole' in z:
-            raise ArithmeticError, z
-        elif 'Warning' in z:
-            i = z.rfind('\n')
-            msg = z[:i].replace('digits','decimal digits')
+        try:
+            z = self.gp()('Vec(Lseries(%s,,%s))'%(a,k-1))
+        except TypeError, msg:
+            raise RuntimeError, "%s\nUnable to compute Taylor expansion (try lowering the number of terms)"%msg
+        r = repr(z)
+        if 'pole' in r:
+            raise ArithmeticError, r
+        elif 'Warning' in r:
+            i = r.rfind('\n')
+            msg = r[:i].replace('digits','decimal digits')
             verbose(msg, level=-1)
-            z = z[i+1:]
-        t = self.__CC[[var]].gen(0)
-        z = z.replace('S',var).replace('.E','.0E').replace(' ','')
-        f = sage_eval(z, locals={var:t})
-        return f
+        v = list(z)
+        K = self.__CC
+        v = [K(repr(x)) for x in v]
+        R = self.__CC[[var]]
+        return R(v,len(v))
         
     def check_functional_equation(self, T=1.2):
Index: age/libs/cf/cf.pyxe
===================================================================
--- sage/libs/cf/cf.pyxe	(revision 2755)
+++ 	(revision )
@@ -1,1528 +1,0 @@
-r"""
-Interface to the Factory library.
-
-AUTHORS:
-    -- Martin Albrecht <malb@informatik.uni-bremen.de> (2006-05-01)
-    -- William Stein (2006-05-07): trivial reformating of long lines
-
-From the Factory manual:
-
-    Factory is a C++ class library which implements a recursive
-    canonical form representation of polynomial data. The library
-    enables the user to use multivariate polynomials over different
-    base domains such as Z, Q, GF(q) and algebraic as well as
-    transcendental extensions of Q and GF(q).
-
-    Factory was developed at the University of Kaiserslautern as an
-    independent part of the computer algebra system singular which
-    uses parts of Factory such as polynomial gcd's and polynomial
-    factorization. This manual describes the features of Factory and
-    how to use it. Since Factory uses inheritance, operator
-    overloading and templates, it will be helpful if the reader has
-    already some experience in C++ programming.
-
-    Factory uses a recursive representation of multivariate polynomial
-    data. Each polynomial in Factory is represented as a univariate
-    polynomial with coefficients that can be polynomials too. To have
-    a unique representation of polynomials we have to fix an ordering
-    on the variables. This ordering is managed by Factory's level
-    system. The basic data type which is introduced by Factory is the
-    class CanonicalForm which handles polynomials as well as elements
-    of the base domain.
-
-This interface is mainly a one-to-one copy of the low level polynomial
-arithmetic implemented in the Factory. It follows Factory's concept of
-representing multivariate polynomials recursive as univariate
-polynomials over polynomial rings.
-
-When using this library keep that in mind and avoid relying on
-variable names (i.e. strings) when interfacing this code with the rest
-of SAGE. Variables in the Factory are uniquely represented through
-their level and not their name (which may only have one character
-btw.)
-
-So far only integers, GF(p), and GF(p^n) have been inplemented as base
-domains.
-
-EXAMPLES:
-    sage: F = GF(5)
-    sage: cf.setBaseDomain(F)
-    sage: R = MPolynomialRing(F,2, names = ['x','y'])
-    sage: x,y = R.gens()
-    sage: f = y**2-x**9-x
-    sage: f == (cf.CF(y)**2-cf.CF(x)**9 - x)._sage_(R)
-    True
-    sage: n = 3
-    sage: astr = ['a'+str(i) for i in range(1,2*n)]
-    sage: R0 = MPolynomialRing(F,2*n+2,names = [str(x),str(y),'t']+astr)
-    sage: vars0 = R0.gens()
-    sage: t = vars0[2]
-    sage: xt = add([vars0[i]*t**(i-2) for i in range(3,2*n+2)])
-    sage: yt = t
-    sage: ft = f(xt,yt)
-    sage: ft == cf.CF(f)([(x,cf.CF(xt)),(y,cf.CF(yt))])._sage_(R0) #fast!
-    True 
-
-\note{This interface is not very SAGE-ish and is rather meant to
-function as a backend for higher level classes like
-MPolynomial_polydict for fast polynomial arithmetic.  This libary is a
-bit behind Singluar if we shuffle few data to the engine, do lot's of
-computation and shuffle some data back. This loss of performance is
-believed to be due to the clumsy way we deal with memory allocation
-which can be addresses. If we shuffle around alot of data between SAGE
-and Singular it's performance decreases alot as much IPC overhead is
-involved, while Factory beats the native implementation.}
-
-TODO: Refactor to avoid memory allocations.
-"""
-
-#*****************************************************************************
-#
-#   SAGE: System for Algebra and Geometry Experimentation    
-#
-#       Copyright (C) 2006 William Stein <wstein@ucsd.edu>
-#
-#  Distributed under the terms of the GNU General Public License (GPL)
-#
-#    This code is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#    General Public License for more details.
-#
-#  The full text of the GPL is available at:
-#
-#                  http://www.gnu.org/licenses/
-#*****************************************************************************
-
-
-#header{
-#include <factory.h>
-#include <iostream>
-#include <sstream>
-using namespace std;
-#}header
-
-cdef extern from "stdlib.h":
-    void free(void *ptr)
-
-#################################
-#cdef int _sig_on
-#cdef int _sig_off
-#cdef int _sig_check
-include '../../../ext/stdsage.pxi' # path is a hack for pyrexembed
-include '../../../ext/interrupt.pxi' # path is a hack for pyrexembed
-#################################
-
-include 'misc.pxi'
-
-
-
-cdef class Variable:
-
-    """
-    The class Variable defines a programming interface to the level
-    system of Factory.  Each object of class Variable refers to a
-    level and thus to a variable (determined by the level) of the
-    polynomial ring. Objects of class Variable must not only refer to
-    variables of the polynomial ring, but also to so called algebraic
-    and transcendental variables.
-
-    Arithmetic with Variables can be pretty weird, consider this:
-
-        sage: 1000*cf.Variable(1)
-        v_1*v_1000
-
-    This behavior is correct as 1000 is coerced into a Variable of
-    level 1000 whichs default name happens to be'v_1000'
-    """
-
-    cdef void *thisptr
-
-    def __init__(self, name=None, level=None):
-        """
-        The class Variable defines a programming interface to the
-        level system of Factory.  Each object of class Variable refers
-        to a level and thus to a variable (determined by the level) of
-        the polynomial ring. Objects of class Variable must not only
-        refer to variables of the polynomial ring, but also to so
-        called algebraic and transcendental variables.
-
-        INPUT:
-
-            name -- The level of the variable is specified to be the
-                    level of the variable which has name name. That means that
-                    the generated object can not only be a polynomial variable
-                    but also an algebraic or transcendental variable. In the
-                    case that there is no variable with name name the
-                    generated variable refers to the anonymous polynomial
-                    variable which has the lowest level. After the
-                    construction the name of the variable is set to name.
-
-            If name is an integer it is interpreted as a level.
-
-            level -- The constructor generates an object of class
-                     Variable with level set to level.  level has to be a level
-                     of a polynomial variable or of a transcendental variable.
-
-        The default constructor creates an object with level set to
-        LEVEL_BASEDOMAIN. Such a variable evaluates into the unit
-        element of the current base domain when converted to a
-        CanonicalForm
-        """
-        #embed{ void *Variable_init()
-            return new Variable();
-        #}embed
-
-        #embed{ void *Variable_initn(char name)
-            return new Variable(name);
-        #}embed
-
-        #embed{ void *Variable_initl(int level)
-            return new Variable(level);
-        #}embed
-
-        #embed{ void *Variable_initln( int level, char name)
-            return new Variable(level,name);
-        #}embed
-
-        cdef char *cNameStr
-        cdef char cName
-
-        from sage.rings.integer import Integer
-
-        if isinstance(name,int) or isinstance(name,Integer):
-            level=name
-            name =None
-
-        if name != None and isinstance(name,str):
-            cNameStr = name
-            cName = cNameStr[0]
-            if level!=None:
-                self.thisptr = Variable_initln(int(level), cName)
-            else:
-                self.thisptr = Variable_initn(cName)
-        else:
-            if level!=None:
-                self.thisptr = Variable_initl(int(level))
-            else:
-                self.thisptr = Variable_init()
-
-    def __dealloc__(Variable self):
-        delete_Variable(self.thisptr)
-
-    def level(self):
-        """
-        Returns the level of this variable.
-        """
-        #embed{ int Variable_level(void *obj)
-        return ((Variable *)obj)->level();
-        #}embed
-
-        return Variable_level(self.thisptr)
-
-    def name(Variable self):
-        """
-        Returns the name of this variable. Do not identify a Variable
-        via it's name() us it's level() instead.
-        """
-        #embed{ char Variable_name(void *obj)
-        return ((Variable *)obj)->name();
-        #}embed
-
-        # this is slow, but I crashed the nativ way
-        return str(CanonicalForm(self))
-
-    def highest(self):
-        #embed{ void *Variable_highest(void *obj)
-            return new Variable(((Variable *)obj)->highest());
-        #}embed
-        _sig_on
-        return make_Variable(Variable_highest(self.thisptr))
-
-    def next(self):
-        """
-        This method returns an object of class Variable which refers
-        to the variable which has the same level as self increased by
-        one.
-        """
-        #embed{ void *Variable_next(void *obj)
-            return new Variable(((Variable *)obj)->next());
-        #}embed
-        _sig_on
-        return make_Variable(Variable_next(self.thisptr))
-
-    def __cmp__(self, Variable other):
-        """
-        Comparison is performed by comparing the levels.
-        """
-        #embed{ int Variable_cmp(void *obj,void *obj2)
-        if(*(Variable *)obj == *(Variable *)obj2) {
-           return 0;
-        } else if( *(Variable *)obj < *(Variable *)obj2) {
-           return -1;
-        } else if( *(Variable *)obj > *(Variable *)obj2) {
-           return 1;
-        }    
-        #}embed
-
-        return Variable_cmp(self.thisptr,other.thisptr)
-
-    def __add__(self, other):
-        return CanonicalForm(self) + CanonicalForm(other)
-
-    def __sub__(self, other):
-        return CanonicalForm(self) - CanonicalForm(other)
-
-    def __mul__(self, other):
-        return CanonicalForm(self) * CanonicalForm(other)
-
-    def __div__(self, other):
-        return CanonicalForm(self) / CanonicalForm(other)
-
-    def __pow__(self, long other, ignored):
-        return CanonicalForm(self)**other
-
-    def __mod__(self, other):
-        return CanonicalForm(self) % CanonicalForm(other)
-
-    def __repr__(self):
-        #embed{ char *Variable_to_str(void* x)
-        ostringstream instore;
-        instore << *(Variable*)x ;
-        int n = strlen(instore.str().data());
-        char* buf = (char*)malloc(n+1);
-        strcpy(buf, instore.str().data());
-        #}embed
-
-##         cdef char *ret
-##         _sig_on
-##         ret = Variable_to_str(self.thisptr)
-##         _sig_off
-##         return string(ret)
-
-        #might be slow but it kept crashing otherwise
-        return str(CanonicalForm(self))
-
-
-
-
-#embed{ void delete_Variable( void *obj)
-if(obj) {
-    delete ((Variable*)obj);
-}
-#}embed
-
-cdef make_Variable(void *x):
-    """
-    """
-    cdef Variable y
-    _sig_off
-    y = Variable()
-    delete_Variable(y.thisptr)
-    y.thisptr = x
-    return y
-
-cdef class CanonicalForm:
-    """
-    CanonicalForm is the main class in the Factory
-    """
-    cdef void *thisptr
-    cdef void *iterator
-
-    def __init__(self,arg=None, arg2=None, kcache=None):
-        """
-        If arg is a Variable and exp==None this constructor generates
-        a canonical form out of the variable arg.  If the level of x
-        is the level of the base domain (LEVEL_BASEDOMAIN) then the
-        unit element of the current base domain is created.
-
-        If arg is an integer this constructor generates an object of
-        class CanonicalForm out of this integer. In the case of a
-        finite base domain the canonical mapping of the integers into
-        the domain is used.
-
-        If arg is a Variable and exp is an integer this constructor
-        generates an object of class CanonicalForm, which is the
-        polynomial arg^exp. In the case that x has level
-        LEVEL_BASEDOMAIN the unit element of the current base domain
-        is created.
-
-        If arg is a SAGE polynomial this constructor generates an
-        object of class CanonicalForm, which is a representaion of arg
-        over currently active base domain.  If arg is defined over a
-        finite extension field arg2 must be an algebraic Variable
-        representing this field. Those variables are returned by
-        setBaseDomain when called with a finite extension field as
-        parameter.
-
-        If arg is a string it is parsed by the CF library. It is not
-        recommended to use string IO for communication with this
-        library as names are not unique in this library and the result
-        might not match the expectations. The best practice here is to
-        construct a SAGE ring, pass the string to that ring and pass
-        the newly constructed SAGE polynomial to this library.
-
-        INPUT:
-            arg --   integer, Variable, Polynomial, or string
-            arg2 --  optional second argument in dependence of first one
-            kcache -- optional base field cache to use MPolynomial elements
-
-        EXAMPLES:
-            sage: R=PolynomialRing(GF(127),2)
-            sage: f=R('3234*x0*x1+6575*x0^2+52')
-            sage: cf.setBaseDomain(GF(127))
-            sage: cf.CF(f)
-            59*v_1*v_2+98*v_1^2+52
-            sage: cf.CF(f)._sage_(R)
-            52 + 59*x0*x1 + 98*x0^2
-            sage: cf.CF(f)._sage_(R)==f
-            True
-        """
-        #embed{ void *CF_init()
-            return new CanonicalForm();    
-        #}embed
-
-        #embed{ void *CF_initi(int arg)
-            return new CanonicalForm(arg);    
-        #}embed
-    
-        #embed{ void *CF_initV(void *arg)
-            return new CanonicalForm(*(Variable *)arg);
-        #}embed
-
-        #embed{ void *CF_initVn(void *arg, int exp)
-            return new CanonicalForm(*(Variable *)arg,exp);
-        #}embed
-
-        #embed{ void *CF_copy(void *arg)
-            return new CanonicalForm(*(CanonicalForm *)arg);
-        #}embed
-
-        #embed{ void *str_to_CF(char* s) 
-            istringstream in;
-            in.str( s );
-            CanonicalForm* y = new CanonicalForm();
-            in >> *y;
-            return y;
-        #}embed
-
-        #embed{ void CF_polygen(void *ret, int c, int level, long e)
-            *(CanonicalForm*)ret += c * CanonicalForm(Variable(level),e);
-        #}embed
-
-        #embed{ void CF_mongen(void *ret, int level, long e)
-            if(e!=0)
-                *(CanonicalForm*)ret *= CanonicalForm(Variable(level),e);
-        #}embed
-
-        cdef CanonicalForm cPoly
-        cdef CanonicalForm t
-        cdef int varlevel
-
-        from sage.rings.multi_polynomial_element import is_MPolynomial
-        from sage.rings.field_element import is_FieldElement
-        from sage.rings.polynomial_element import is_Polynomial
-
-        # maybe a switch-case dict might be faster here?
-        if is_FieldElement(arg) and arg.parent().degree()!=1:
-            cPoly = CF(0)
-            if not isinstance(arg2,Variable):
-                arg2 = setBaseDomain(arg.parent())
-            varlevel  = arg2.level()
-            f = arg._pari_().lift().lift()
-            if f.poldegree() == 0:
-                self.thisptr = CF_initi(int(f))
-                return 
-            for i from 0 <= i <= f.poldegree():
-                CF_polygen(cPoly.thisptr,int(f[i]),varlevel,i)
-            self.thisptr = cPoly.thisptr
-            return
-
-        elif is_MPolynomial(arg):
-            poly = CF(0)
-            for e,c in arg.element().dict().iteritems():
-                t = CF(0)
-                if kcache!=None:
-                    if not kcache.has_key(c):
-                        kcache[c]=CF(c,arg2)
-                    t = t + kcache[c]
-                else:
-                    t = t + CF(c,arg2)
-                for i in e.nonzero_positions():
-                    CF_mongen(t.thisptr,i+1,e[i])
-                poly = poly + t
-            cPoly = poly
-            self.thisptr = cPoly.thisptr
-            return
-
-        elif is_Polynomial(arg):
-            cPoly = CF(0)
-            v = Variable(1)
-            #TODO: speed can be improved here
-            for i from 0 <= i <= arg.degree():
-                cPoly = cPoly + CF(arg[i])*CF(v,i)
-            self.thisptr = cPoly.thisptr
-
-        elif isinstance(arg,CanonicalForm):
-            self.thisptr = CF_copy(<void*>(<CanonicalForm>arg).thisptr)
-
-        elif isinstance(arg,Variable) and arg2==None:
-            self.thisptr = CF_initV(<void*>(<Variable>arg).thisptr)
-
-        elif isinstance(arg,Variable) and arg2!=None:
-            self.thisptr = CF_initVn(<void*>(<Variable>arg).thisptr,int(arg2))
-
-        elif isinstance(arg,str):
-            arg = "".join([arg,";"])
-            self.thisptr = str_to_CF(arg)
-
-        elif arg==None:
-            self.thisptr = CF_init()
-
-        else:
-            try:
-                arg = int(arg)
-                self.thisptr = CF_initi(arg)
-            except:
-                raise TypeError, "Cannot create CanonicalForm with params %s and %s"%(arg, arg2)
-
-    def __repr__(self):#
-        """
-        """
-        #embed{ char *CF_to_str(void* x)
-        ostringstream instore;
-        instore << *(CanonicalForm*)x ;
-        int n = strlen(instore.str().data());
-        char* buf = (char*)malloc(n+1);
-        strcpy(buf, instore.str().data());
-        return buf;
-        #}embed
-
-        cdef char *ret
-        _sig_on
-        ret = CF_to_str(self.thisptr)
-        return string(ret)
-
-    def __add__(left, right):
-        #embed{ void *CF_add(void *l, void *r)
-        return new CanonicalForm((*(CanonicalForm*)l) + (*(CanonicalForm*)r));
-        #}embed
-
-        if not isinstance(left,CanonicalForm):
-            left,right = right,left
-        if not isinstance(right,CanonicalForm):
-            right = CanonicalForm(right)
-        _sig_on
-        return make_CF(CF_add((<CanonicalForm>left).thisptr,(<CanonicalForm>right).thisptr))
-
-    def __sub__(left, right):
-        #embed{ void *CF_sub(void *l, void *r)
-        return new CanonicalForm((*(CanonicalForm*)l) - (*(CanonicalForm*)r));
-        #}embed
-        cdef CanonicalForm cRight
-        cdef CanonicalForm cLeft
-        try:
-            cRight = CanonicalForm(right)
-            cLeft = CanonicalForm(left)
-        except TypeError:
-            raise ArithmeticError, "Cannot subtract %s from %s"%(right,left)
-        _sig_on
-        return make_CF(CF_sub(cLeft.thisptr,cRight.thisptr))
-
-    def __mul__(left, right):
-        #embed{ void *CF_mul(void *l, void *r)
-        return new CanonicalForm((*(CanonicalForm*)l) * (*(CanonicalForm*)r));
-        #}embed
-
-        cdef CanonicalForm cRight
-        cdef CanonicalForm cLeft
-        try:
-            cRight = CanonicalForm(right)
-            cLeft = CanonicalForm(left)
-        except TypeError:
-            raise ArithmeticError, "Cannot multiply %s and %s"%(left,right)
-        _sig_on
-        return make_CF(CF_mul(cLeft.thisptr,cRight.thisptr))
-
-    def __div__(left, right):
-        #embed{ void *CF_div(void *l, void *r)
-        return new CanonicalForm((*(CanonicalForm*)l) / (*(CanonicalForm*)r));
-        #}embed
-
-        cdef CanonicalForm cRight
-        cdef CanonicalForm cLeft
-        try:
-            cRight = CanonicalForm(right)
-            cLeft = CanonicalForm(left)
-        except TypeError:
-            raise ArithmeticError, "Cannot divide %s through %s"%(left,right)
-        _sig_on
-        return make_CF(CF_div(cLeft.thisptr,cRight.thisptr))
-
-    def __pow__(CanonicalForm self,long e, ignored):
-        #embed{ void *CF_pow(void *l, long e)
-        return new CanonicalForm( power((*(CanonicalForm*)l),e) );
-        #}embed
-        _sig_on
-        return make_CF(CF_pow(self.thisptr, e))
-
-    def __neg__(CanonicalForm self):
-        #embed{ void *CF_neg(void *l)
-        return new CanonicalForm(-(*(CanonicalForm*)l));
-        #}embed
-        _sig_on
-        return make_CF(CF_neg(self.thisptr))
-
-##    Commenting out all in place arithmetic as SAGE does not use in
-##    place arithmetic, e.g. when you e += 1 for an element which is
-##    also an element of a list the element in the list does not
-##    change in SAGE.
-
-##
-##     def __iadd__(CanonicalForm self,other):
-##         #embed{ void CF_iadd(void *l, void *r)
-##         (*(CanonicalForm*)l) += (*(CanonicalForm*)r);
-##         #}embed
-
-##         cdef CanonicalForm cOther
-##         try:
-##             cOther = CanonicalForm(other)
-##         except TypeError:
-##             raise ArithmeticError, "Cannot add %s and %s"%(self,other)
-
-##         CF_iadd(self.thisptr,cOther.thisptr)
-##         return self
-
-##     def __isub__(CanonicalForm self, other):
-##         #embed{ void *CF_isub(void *l, void *r)
-##         (*(CanonicalForm*)l) -= (*(CanonicalForm*)r);
-##         #}embed
-##         cdef CanonicalForm cOther
-##         try:
-##             cOther = CanonicalForm(other)
-##         except TypeError:
-##             raise ArithmeticError, "Cannot subtract %s from %s"%(other,self)
-##         CF_isub(self.thisptr,cOther.thisptr)
-##         return self
-
-##     def __imul__(CanonicalForm self, other):
-##         #embed{ void *CF_imul(void *l, void *r)
-##         (*(CanonicalForm*)l) *= (*(CanonicalForm*)r);
-##         #}embed
-
-##         cdef CanonicalForm cOther
-##         try:
-##             cOther = CanonicalForm(other)
-##         except TypeError:
-##             raise ArithmeticError, "Cannot multiply %s and %s"%(self,other)
-
-##         CF_imul(self.thisptr,cOther.thisptr)
-##         return self
-
-##     def __idiv__(CanonicalForm self, other):
-##         #embed{ void CF_idiv(void *l, void *r)
-##         (*(CanonicalForm*)l) /= (*(CanonicalForm*)r);
-##         #}embed
-
-##         cdef CanonicalForm cOther
-##         try:
-##             cOther = CanonicalForm(other)
-##         except TypeError:
-##             raise ArithmeticError, "Cannot divide %s through %s"%(self,other)
-
-##         CF_idiv(self.thisptr,cOther.thisptr)
-##         return self
-
-##     def __ipow__(CanonicalForm self,long e, ignored):
-##         #embed{ void CF_ipow(void *l, long e)
-##         (*(CanonicalForm*)l) = power((*(CanonicalForm*)l),e);
-##         #}embed
-##         CF_ipow(self.thisptr,e)
-##         return self
-
-
-    def __cmp__(CanonicalForm self,other):
-        """
-        It is possible to compare two canonical forms. Therefore, you can use
-        this operator. The behaviour of < and > in the case of polynomials is
-        not fixed yet, but may deal with levels and degrees in a future
-        release of the Factory library.
-        """
-        #embed{ int CF_cmp(void *obj,void *obj2)
-        if( *(CanonicalForm *)obj == *(CanonicalForm *)obj2 ) {
-           return 0;
-        } else if(*(CanonicalForm *)obj < *(CanonicalForm *)obj2) {
-           return -1;
-        } else if(*(CanonicalForm *)obj > *(CanonicalForm *)obj2) {
-           return 1;
-        }
-        #}embed
-
-        cdef int res
-        cdef CanonicalForm cOther
-        if not isinstance(other, CanonicalForm):
-            try:
-                cOther = CanonicalForm(other)
-            except TypeError:
-                raise TypeError, "Cannot compare %s and %s"%(self,other)
-        else:
-            cOther = other
-        _sig_on
-        res = CF_cmp(self.thisptr,cOther.thisptr)
-        _sig_off
-        return res
-
-    def __mod__(CanonicalForm self, other):
-        #embed{ void *CF_mod(void *l, void *r)
-        return new CanonicalForm((*(CanonicalForm*)l) % (*(CanonicalForm*)r));
-        #}embed
-
-        cdef CanonicalForm cOther
-        try:
-            cOther = CanonicalForm(other)
-        except TypeError:
-            raise ArithmeticError, "Cannot take %s modulo %s"%(self,other)
-        _sig_on
-        return make_CF(CF_mod(self.thisptr,cOther.thisptr))
-
-    def __getitem__(CanonicalForm self, i):
-        """
-        operator [] - return i'th coefficient from self.
-
-        Returns self if self is in a base domain and i equals zero.
-        Returns zero (from the current domain) if self is in a base
-        domain and i is larger than zero.  Otherwise, returns the
-        coefficient to x^i in self (if x denotes the main variable of
-        self) or zero if self does not contain x^i.  Elements in an
-        algebraic extension are considered polynomials.  i should be
-        larger or equal zero.
-
-        INPUT:
-            i -- exponent, this may be a tuple of exponents
-
-        EXAMPLE:
-            sage: r=MPolynomialRing(ZZ,2,['x','y'])
-            sage: x,y = r.gens()
-            sage: cf.setBaseDomain(ZZ)
-            sage: f=cf.CF(3*x*y^2)
-            sage: f[1]
-            0
-            sage: f[2]
-            3*v_1
-            sage: f[2,1]
-            3
-
-        NOTE:
-            Never use a loop like
-
-            for i in range(f.degree( )):
-                print f[ i ]
-
-            which is much slower than
-
-            for c in f:
-                print c
-
-        """
-        #embed{ void *CF_getitem(void *e,int i)
-        if (((CanonicalForm*)e)->degree() < i) {
-            return new CanonicalForm(0);
-        } else {
-            return new CanonicalForm((*(CanonicalForm*)e)[i]);
-        }
-        #}embed
-        cdef void *ret
-        if isinstance(i,int):
-            _sig_on
-            ret = CF_getitem(self.thisptr,i)
-            return make_CF(ret)
-        elif isinstance(i,tuple):
-            _sig_on
-            ret = self.thisptr
-            for j in i:
-                ret = CF_getitem(ret,int(j))
-            return make_CF(ret)
-        else:
-            raise TypeError, "Cannot return coefficent for %s"%i
-
-    def __iter__(CanonicalForm self):
-        """
-        Iterator with respect to the main variable. It returns
-        coeffients and expontents of terms. You may get the
-        variable these refer to by calling mvar() on self.
-        """
-        return self
-
-    def __next__(CanonicalForm self):
-        """
-        Iterator implementation.
-        """
-        #embed{ void *CF_iterinit(void *e)
-        return new CFIterator(*(CanonicalForm*)e);
-        #}embed
-
-        #embed{ void *CF_iter(void *it, int *exp)
-        if(((CFIterator*)it)->hasTerms()) {
-            CanonicalForm *ret = new CanonicalForm(((CFIterator*)it)->coeff());
-            *exp = ((CFIterator*)it)->exp();
-            (*(CFIterator*)it)++;
-            return ret;
-        } else {
-            return NULL;
-        }
-        #}embed
-
-        cdef void *ret
-        cdef int exp
-
-        if self.is_zero():
-            raise StopIteration
-
-        if self.iterator == NULL:
-            self.iterator = CF_iterinit(self.thisptr)
-
-        _sig_on
-        ret = CF_iter(self.iterator,&exp)
-        _sig_off
-        if ret!=NULL:
-            _sig_on
-            return (make_CF(ret),exp)
-        else:
-            self.iterator = CF_iterinit(self.thisptr)
-            raise StopIteration
-
-    def __call__(CanonicalForm self, arg):
-        """
-        Returns the current object with the substitution described
-        through arg performed.
-
-        If arg is a list or tuple and it's elements are not tuples it
-        is interpreted as a list of values to substituted in at their
-        list index.
-
-        If arg is a list or tuple and it's elements are tuples with
-        two elements then it is interpreted to hold the variable to be
-        substitute as the first element of those tuples and the value
-        to be substituted in as the second.
-
-        If arg is a dict it's keys are interpreted to describe the
-        variables and the matching values the values to be substituted
-        in.
-
-        INPUT:
-            arg -- tuple, list or dict to describe substitution
-
-        EXAMPLES:
-            sage: f=cf.CF(3)*cf.Variable(1)*cf.Variable(2)
-            sage: f
-            3*v_1*v_2
-            sage: f((cf.Variable(1),'2'))
-            6*v_1
-            sage: f((3,2))
-            18
-
-        """
-        #embed{ void CF_call(void *self, void *f, void *x)
-        (*(CanonicalForm*)self) = (*(CanonicalForm*)self)(*(CanonicalForm*)f,*(Variable*)x);
-        #}embed
-
-        cdef void *r
-        cdef Variable x
-        cdef CanonicalForm f
-
-        if isinstance(arg,tuple) or isinstance(arg,list):
-            if not isinstance(arg[0],tuple) and len(arg)==self.mvar().level():
-                r = CF_copy(self.thisptr)    
-                _sig_on
-                for i from 0 <= i < len(arg):
-                    f = CanonicalForm(arg[i])
-                    x = Variable(i+1)
-                    CF_call(r,f.thisptr,x.thisptr)
-                return make_CF(r)
-            elif len(arg[0])==2:
-                r = CF_copy(self.thisptr)
-                _sig_on
-                for var,val in arg:
-                    f = CanonicalForm(val)
-                    x = CanonicalForm(var).mvar() #safer than calling Variable
-                    CF_call(r,f.thisptr,x.thisptr)
-                return make_CF(r)
-        elif isinstance(arg,dict):
-            r = CF_copy(self.thisptr)
-            _sig_on
-            for var,val in arg.iteritems():
-                f = CanonicalForm(val)
-                x = CanonicalForm(var).mvar() #safer than calling Variable
-                CF_call(r,f.thisptr,x.thisptr)
-            return make_CF(r)
-        else:
-            raise TypeError, "Cannot substitute with parameter %s"%arg
-
-    def is_one(CanonicalForm self):
-        """
-        This predicate returns true if self represents the unit
-        element of the current base domain. There is also the
-        possibiliy to test if a CanonicalForm f is one via f == 1, but
-        f.is_one() is faster since there is no conversion of the
-        integer 1 into a CanonicalForm and then doing a comparison of
-        two objects of class CanonicalForm.
-        """
-        #embed{ int CF_isOne(void *e)
-        return ((CanonicalForm*)e)->isOne();
-        #}embed
-        return bool(CF_isOne(self.thisptr))
-
-    def is_zero(CanonicalForm self):
-        """
-        This predicate returns true if self represents the zero
-        element of the current base domain. Like the predicate is_one
-        using the predicate f.is_zero() is also faster than a
-        comparison via f == 0.
-        """
-        #embed{ int CF_isZero(void *e)
-        return ((CanonicalForm*)e)->isZero();
-        #}embed
-
-        return bool(CF_isZero(self.thisptr))
-
-    def is_imm(CanonicalForm self):
-        """
-        This predicate returns true if self is represented as an
-        immediate object (e.g. is a small integer or an object of a
-        finite base field).  See Chapter 14 [Internal Design], page
-        21, for information about how immediate objects are
-        represented.
-
-        The return value represents if self is represented as a
-        immediate value in the Factory and makes no statement about
-        this element in SAGE.
-        """
-        #embed{ int CF_isImm(void *e)
-        return ((CanonicalForm*)e)->isImm();
-        #}embed
-        return bool(CF_isImm(self.thisptr))
-
-    def _int_(CanonicalForm self):
-        """
-        This selector returns the integer value of self. This is only
-        valid if the value of self is in the range of the machine
-        integers. A good way to find out if this is the case is to
-        test if the current object is an immediate object via
-        self.is_imm().
-        """
-        #embed{ int CF_intval(void *e)
-        return ((CanonicalForm*)e)->intval();
-        #}embed
-        return CF_intval(self.thisptr)
-
-    def lc(CanonicalForm self):
-        """
-        Returns the leading coefficient of self with respect to
-        lexicographic ordering.  Elements in an algebraic extension
-        are considered polynomials so lc() always returns a leading
-        coefficient in a base domain.  This method is useful to get
-        the base domain over which self is defined.
-
-        Returns self if self is in a base domain.
-        """
-        #embed{ void *CF_lc(void *e)
-        return new CanonicalForm(((CanonicalForm*)e)->lc());
-        #}embed
-        _sig_on
-        return make_CF(CF_lc(self.thisptr))
-
-    def Lc(CanonicalForm self):
-        """
-        Returns the leading coefficient of self with respect to
-        lexicographic ordering.  In contrast to lc() elements in an
-        algebraic extension are considered coefficients so Lc() always
-        returns a leading coefficient in a coefficient domain.
-
-        Returns self if self is in a base domain.
-        """
-        #embed{ void *CF_Lc(void *e)
-        return new CanonicalForm(((CanonicalForm*)e)->Lc());
-        #}embed
-        _sig_on
-        return make_CF(CF_Lc(self.thisptr))
-
-    def LC(CanonicalForm self, v=None):
-        """
-        LC( ) returns the leading coefficient of self where self is
-        considered a univariate polynomial in its main variable.  An
-        element of an algebraic extension is considered an univariate
-        polynomial, too.
-
-        LC( v ) returns the leading coefficient of CO where CO is
-        considered an univariate polynomial in the polynomial variable v.
-
-        Returns self if self is in a base domain.
-
-        INPUT:
-            v -- if set the leading coefficient with respect to this
-                variable is returned.
-        OUTPUT:
-            CanonicalForm representing the lead coefficient.
-
-
-        """
-        #embed{ void *CF_LC(void *e,void *v)
-        if (v == NULL) {
-            return new CanonicalForm(((CanonicalForm*)e)->LC());
-        } else {
-            return new CanonicalForm( ((CanonicalForm*)e)->LC( *((Variable*)v) ) );
-        }
-        #}embed
-
-        if v==None:
-            _sig_on
-            return make_CF(CF_LC(self.thisptr,NULL))
-
-        if not isinstance(v, Variable):
-            v = Variable(v)
-        _sig_on
-        return make_CF(CF_LC(self.thisptr,(<Variable>v).thisptr))
-
-    def total_degree(CanonicalForm self):
-        """
-        Returns the total degree of self.
-        """
-        #embed{ int CF_total_degree(void *e)
-        return totaldegree(*(CanonicalForm*)e);
-        #}embed
-        return CF_total_degree(self.thisptr)
-
-    def degree(CanonicalForm self, x=None):
-        """
-        This selector returns the degree of self with respect to its
-        main variable or a provided variable.  If self is an element
-        of a coefficient domain the returned degree is zero except
-        that the current object represents the zero of a base domain
-        in which case -1 is returned.
-
-        INPUT:
-            variable -- if set the degree with respect to this
-            variable will be returned.
-        """
-
-        #embed{ int CF_degree(void *e,void *x)
-        if (x == NULL) {
-            return ((CanonicalForm*)e)->degree();
-        } else {
-            return ((CanonicalForm*)e)->degree( *((Variable*)x) );
-        }
-        #}embed
-
-        if x==None:
-            return CF_degree(self.thisptr,NULL)
-
-        if not isinstance(x,Variable):
-            variable = Variable(x)
-        return CF_degree(self.thisptr,(<Variable>x).thisptr)
-
-    def lt(CanonicalForm self):
-        """
-        Returns the leading term with respect to the main variable.
-
-        This is equivalent to head() in the Factory C++ API.
-        """
-        #embed{ void *CF_head(void *e)
-        return new CanonicalForm(head(*(CanonicalForm*)e));
-        #}embed
-        _sig_on
-        return make_CF(CF_head(self.thisptr))
-
-    def tail(CanonicalForm self):
-        """
-        Returns f - lt(f)
-        """
-        #embed{ void *CF_tail(void *e)
-        return new CanonicalForm((*(CanonicalForm*)e) - head(*(CanonicalForm*)e));
-        #}embed
-        _sig_on
-        return make_CF(CF_tail(self.thisptr))
-
-
-    def tailcoeff(CanonicalForm self):
-        """
-        This selector returns the tail coefficient of self. That is
-        the non vanishing coefficient of the term with the lowest
-        exponent. If self represents the zero element of a base domain
-        then zero is returned.
-        """
-        #embed{ void *CF_tailcoeff(void *e)
-        return new CanonicalForm(((CanonicalForm*)e)->tailcoeff());
-        #}embed
-        _sig_on
-        return make_CF(CF_tailcoeff(self.thisptr))
-
-    def taildegree(CanonicalForm self):
-        """
-        This selector returns the lowest exponent of the terms of self
-        that have non vanishing coefficients. If the self represents
-        the zero element of a base domain then None is returned.
-        """
-        #embed{ int CF_taildegree(void *e)
-        return ((CanonicalForm*)e)->taildegree();
-        #}embed
-
-        cdef res
-        res = CF_taildegree(self.thisptr)
-        if res==-1:
-            return
-        else:
-            return res
-
-    def mvar(CanonicalForm self):
-        """
-        This selector returns the main varible of self.  If self is an
-        element of a base domain then Variable(LEVEL_BASEDOMAIN) is
-        returned.
-        """
-        #embed{ void *CF_mvar(void *e)
-        return new Variable(((CanonicalForm*)e)->mvar());
-        #}embed
-        _sig_on
-        return make_Variable(CF_mvar(self.thisptr))
-
-    def level(CanonicalForm self):
-        """
-        This selector returns the level of the main variable of self.
-        """
-
-        #embed{ int CF_level(void *e)
-        return ((CanonicalForm*)e)->level();
-        #}embed
-
-        return CF_level(self.thisptr)
-
-    def mapinto(CanonicalForm self, mapMe = False):
-        """
-        This method returns the mapping of the current object into the
-        current base domain.  If the current object is a polynomial,
-        then the value returned by mapdomain is the polynomial mapped
-        into the polynomial ring over the current base domain.
-
-        INPUT:
-            mapMe -- if True this object is mappend and nothing is returned 
-                (default: False)
-        """
-
-        #embed{ void *CF_mapinto(void *self)
-        return new CanonicalForm(((CanonicalForm*)self)->mapinto());
-        #}embed
-        #embed{ void CF_mapintos(void *self)
-        *(CanonicalForm*)self = ((CanonicalForm*)self)->mapinto();
-        #}embed
-
-        if mapMe:
-            CF_mapintos(self.thisptr)
-        else:
-            _sig_on
-            return make_CF(CF_mapinto(self.thisptr))
-
-    def inZ(CanonicalForm self):
-        """
-        This method returns true if the object is a rational integer.
-        """
-        #embed{ int CF_inZ(void *self)
-        return ((CanonicalForm*)self)->inZ();
-        #}embed
-        return bool(CF_inZ(self.thisptr))
-
-    def inQ(CanonicalForm self):
-        """
-        This method returns true if the object is a rational number.
-        """
-        #embed{ int CF_inQ(void *self)
-        return ((CanonicalForm*)self)->inQ();
-        #}embed
-        return bool(CF_inQ(self.thisptr))
-
-    def inFF(CanonicalForm self):
-        """
-        This method returns true if the object is an element of Fp.
-        """
-        #embed{ int CF_inFF(void *self)
-        return ((CanonicalForm*)self)->inFF();
-        #}embed
-        return bool(CF_inFF(self.thisptr))
-
-    def inGF(CanonicalForm self):
-        """
-        This method returns true if the object is an element of GF(q).
-            """
-        #embed{ int CF_inGF(void *self)
-        return ((CanonicalForm*)self)->inGF();
-        #}embed
-        return bool(CF_inGF(self.thisptr))
-
-    def inPP(CanonicalForm self):
-        """
-        This method returns true if the object is in a prime power domain.
-        """
-        #embed{ int CF_inPP(void *self)
-        return ((CanonicalForm*)self)->inPP();
-        #}embed
-        return bool(CF_inPP(self.thisptr))
-
-    def inBaseDomain(CanonicalForm self):
-        """
-        This method returns true if the object is an element of a base domain,
-        e.g. Z, Q, Z mod p, Fp or GF(q).
-        """
-        #embed{ int CF_inBaseDomain(void *self)
-        return ((CanonicalForm*)self)->inBaseDomain();
-        #}embed
-        return bool(CF_inBaseDomain(self.thisptr))
-
-    def inExtension(CanonicalForm self):
-        r"""
-        This method returns true if the object is an element of an algebraic
-        extension.
-
-        \code{In Factory this means that the object is not an element
-        of GF(q) even if that would be true mathematically. All that
-        can be said when inExtension returns true is, that the object
-        contains an algebraic variable.}
-        """
-        #embed{ int CF_inExtension(void *self)
-        return ((CanonicalForm*)self)->inExtension();
-        #}embed
-        return bool(CF_inExtension(self.thisptr))
-
-    def inCoeffDomain(CanonicalForm self):
-        """
-        This method returns true if the object is not a polynomial.
-        """
-        #embed{ int CF_inCoeffDomain(void *self)
-        return ((CanonicalForm*)self)->inCoeffDomain();
-        #}embed
-        return bool(CF_inCoeffDomain(self.thisptr))
-
-    def inPolyDomain(CanonicalForm self):
-        """
-        This method returns true if the object is a polynomial.
-        """
-        #embed{ int CF_inPolyDomain(void *self)
-        return ((CanonicalForm*)self)->inPolyDomain();
-        #}embed
-        return bool(CF_inPolyDomain(self.thisptr))
-
-
-    def isFFinGF(CanonicalForm self):
-        """
-        """
-        #embed{ int CF_isFFinGF(void *self)
-        return ((CanonicalForm*)self)->isFFinGF();
-        #}embed
-        return bool(CF_isFFinGF(self.thisptr))
-
-    def is_univariate(CanonicalForm self):
-        """
-        Returns True if self is univariate, False otherwise
-        """
-        #embed{ int CF_isUnivariate(void *self)
-        return ((CanonicalForm*)self)->isUnivariate();
-        #}embed
-        return bool(CF_isUnivariate(self.thisptr))
-
-    def is_homogeneous(CanonicalForm self):
-        """
-        Returns True if self is homogeneous, False otherwise
-        """
-        #embed{ int CF_isHomogeneous(void *self)
-        return ((CanonicalForm*)self)->isHomogeneous();
-        #}embed
-        return bool(CF_isHomogeneous(self.thisptr))
-
-    def __cflist__(self, f, e):
-        level = f.level()-1
-        if f.inCoeffDomain():
-            return  [] + [tuple([f,e])]
-        else:
-            retval = []
-            for c,e2 in f:
-                new_e = e.copy()
-                if e2!=0:
-                   new_e[level]=e2
-                retval = retval + self.__cflist__(c,new_e)
-            return retval 
-
-    def _sage_(self, R, kcache=None):
-        """
-        Coerces self into R.
-
-        A very simple coercion strategy is used: The variable with
-        level=1 is mapped to the first variable in the ring, the
-        variable with level=2 to the second, etc. Elements of the
-        coefficient domain are coerced via strings. So in that case
-        variable names (e.g. of an algebraic variable) do matter in
-        contrast to the warning stated earlier.
-
-        INPUT:
-            R      -- ring to coerce to
-            kcache -- optional finite field cache
-
-        EXAMPLES:
-            sage: cf.setBaseDomain(GF(127))
-            sage: R=MPolynomialRing(GF(127),2,'x')
-            sage: f=cf.CF(R('3*x0+2'))
-            sage: f._sage_(R)
-            2 + 3*x0
-            sage: k = GF(2**8)
-            sage: v = cf.setBaseDomain(k)
-            sage: R=MPolynomialRing(k,2,'x')
-            sage: f=cf.CF(R('a^20*x0+a^10'),v);f
-            a_1^7*v_1+a_1^5*v_1+a_1^4*v_1+a_1^2*v_1+a_1^6+a_1^5+a_1^4+a_1^2
-            sage: f._sage_(R)
-            a^6 + a^5 + a^4 + a^2 + (a^7 + a^5 + a^4 + a^2)*x0
-        """
-        from sage.rings.polynomial_ring import is_PolynomialRing
-
-        self.mapinto(mapMe=True)
-
-        if is_PolynomialRing(R):
-            l = [0]*(self.degree()+1)
-            base = R.base_ring()
-            for c,e in self:
-                cs = str(c)
-                if kcache!=None:
-                    if not kcache.has_key(cs):
-                        kcache[cs]=base(cs)
-                    l[e]=kcache[cs]
-                else:
-                    l[e]=base(cs)
-            return R(l)
-        else:
-            d={}
-            level = self.level()-1
-            ngens = R.ngens()
-
-            from sage.rings.polydict import PolyDict,ETuple
-
-            kgen = str(R.base_ring().gen())
-
-            if self.is_zero():
-                # obey binary compatibility
-                return R(PolyDict({}))
-
-            if self.inCoeffDomain():
-                # catch the constant case
-                cs = str(self)
-                if not self.inFF():
-                    cs = cs.replace(str(self.mvar()),kgen)
-                d[ETuple({},ngens)]=R.base_ring()(cs)
-                return R(PolyDict(d,force_int_exponents=False,force_etuples=False))
-
-            for c,e in self:
-                exp = {}
-                if e!=0:
-                   exp[level]= e
-                l = self.__cflist__(c,exp)
-                for c2,e2 in l:
-                    if c2.is_zero():
-                        continue
-                    cs = str(c2)
-                    if not c2.inFF():
-                        cs = cs.replace(str(c2.mvar()),kgen)
-                    if kcache!=None:
-                        if not kcache.has_key(cs):
-                            kcache[cs]=R.base_ring()(cs)
-                        d[ETuple(e2,ngens)]=kcache[cs]
-                    else:
-                        d[ETuple(e2,ngens)]=R.base_ring()(cs)
-            return R(PolyDict(d,force_int_exponents=False,force_etuples=False))
-
-    def lcm(CanonicalForm self,right):
-        #embed{ void *CF_lcm(void *l, void *r)
-        return new CanonicalForm(lcm(*(CanonicalForm*)l,(*(CanonicalForm*)r)));
-        #}embed
-
-        if not isinstance(right,CanonicalForm):
-            right = CanonicalForm(right)
-        _sig_on
-        return make_CF(CF_lcm(self.thisptr,(<CanonicalForm>right).thisptr))
-
-
-
-CF =  CanonicalForm
-
-#embed{ void delete_CF( void *obj)
-if(obj) {
-    delete ((CanonicalForm*)obj);
-}
-#}embed
-
-cdef make_CF(void *x):
-    """
-    """
-    cdef CanonicalForm y
-    _sig_off
-    y = CanonicalForm()
-    delete_CF(y.thisptr)
-    y.thisptr = x
-    return y
-
-
-def setCharacteristic(int p):
-    """
-    Sets the characteristic for all following Factory operations to
-    p. We also accept SAGE finite fields here which will be
-    automatically coerced to a format the Factory can understand. If
-    the finite fieldis an extension field the algebraic element 'a' is
-    returned which is the root of the defining polynomial of the
-    extension field.
-
-    INPUT:
-        p -- characteristic to use in Factory
-
-    TODO:
-        The Factory also supports p^n as base chacteristic but that
-        would need the gftable lookup which is not provided in the
-        format needed by the Factory through Singular.  Use rootOf()
-        if you need to to construct GF(p^n) which however - I guess -
-        is slower than the setCharacteristic(p,n) approach. If you
-        provide this function with a SAGE finite field this behavior
-        is implemented.
-    """
-    #embed{ void setCharacteristicp(int p)
-    setCharacteristic(p);
-    #}embed
-
-    #embed{ void setCharacteristicpn(int p, int n)
-    setCharacteristic(p,n);
-    #}embed
-
-    #embed{ void setCharacteristicpnn(int p, int n, char name)
-    setCharacteristic(p,n,n);
-    #}embed
-
-    setCharacteristicp(p)
-
-__domains__ = dict()
-
-def setBaseDomain(k,force=False):
-    """
-    Sets the CF BaseDomain so it matches k. At the moment
-    GF(p), GF(p^n), and ZZ are supported. If an extension
-    field is provided the algebraic variable used to describe
-    this extension field is returned nothing otherwise. This
-    variable is needed to coerce SAGE polynomials to CF polynomials.
-
-    This variable is also cached locally so if the same finite
-    extension field is provided twice the same variable will be
-    returned. This behavior can be overriden by setting force to True.
-
-    Caching the algebraic variable locally not only is faster than
-    recreating one when needed it alsoe ensures coercion from SAGE
-    polynomials yields the same results evertime, even if one lost
-    track of the algebraic variable needed to coerce.
-
-    INPUT:
-        force -- enforce creation of a new algebraic variable (default: False)
-
-    """
-    global __domains__
-
-    from sage.rings.finite_field import is_FiniteField
-
-    setCharacteristicp(int(k.characteristic()))
-
-    if is_FiniteField(k) and k.degree()!=1:
-        if not __domains__.has_key(k) or force==True:
-            setCharacteristic(0) #make sure nex step works
-            __domains__[k] = rootOf(k.polynomial())
-            setCharacteristic(k.characteristic())
-        return  __domains__[k]
-
-
-
-def getCharacteristic():
-    """
-    Returns the currently set characteristic
-    """
-    #embed{ int getCharacteristicp()
-    return getCharacteristic();
-    #}embed
-    return getCharacteristicp()
-
-def rootOf(mipo, char *name = NULL):
-    r"""
-    This function returns the algebraic variable that is defined by
-    the minimal polynomial mipo.  name has to be a name that is not
-    yet assigned to a variable. This is the only way to define an
-    algebraic variable. The level of the returned variable depends on
-    how many algebraic variables are defined so far. The variable
-    remains anonymous if the user does not specify a name.  mipo has
-    to be an irreducible univariate polynomial over the current base
-    domain.
-
-    INPUT:
-        mipo -- minimal polynomial to define the algebraic variable,
-            this must be a CanonicalForm or something coercable to
-            ca CanonicalForm via the CanonicalForm constructor
-
-        name -- name to assign to the algebraic variable
-
-    \note{Do not use this function to construct a base domain for
-    finite extension fields. Use setBaseDomain() instead.}
-    """
-    #embed{ void *rootOfpn(void *mipo, char name)
-    return new Variable(rootOf(*(CanonicalForm*)mipo, name));
-    #}embed
-    #embed{ void *rootOfp(void *mipo)
-    return new Variable(rootOf(*(CanonicalForm*)mipo));
-    #}embed
-
-    cdef char *cName
-    cdef char cChar
-    cdef CanonicalForm cMipo
-
-    if not isinstance(mipo,CanonicalForm):
-        cMipo = CanonicalForm(mipo)
-    else:
-        cMipo = mipo
-
-    if name == NULL or len(name)==0:
-        _sig_on
-        return make_Variable(rootOfp(cMipo.thisptr))
-    else:
-        cName = name
-        cChar = cName[0]
-        _sig_on
-        return make_Variable(rootOfpn(cMipo.thisptr,cChar))
-
-def getMipo( a,  x=None ):
-    """
-    This function returns the minimal polynomial that defines the
-    algebraic variable a. The minimal polynomial is returned as a
-    CanonicalForm of variable x.
-
-    INPUT:
-        a -- algebraic variable
-        x -- variable the minimal polynomial is expressed in
-    """
-    #embed{ void *CF_getMipo(void *a, void *x)
-    return new CanonicalForm(getMipo(*(Variable*)a,*(Variable*)x));
-    #}embed
-
-    cdef Variable cA
-    cdef Variable cX
-
-    if x==None:
-        x='x'
-
-    if not isinstance(a,Variable):
-        cA = Variable(a)
-    else:
-        cA = a
-    if not isinstance(x,Variable):
-        cX = Variable(x)
-    else:
-        cX = x
-
-    _sig_on
-    return make_CF(CF_getMipo(cA.thisptr,cX.thisptr))
-
-
Index: age/libs/cf/ftmpl_inst.cc
===================================================================
--- sage/libs/cf/ftmpl_inst.cc	(revision 1088)
+++ 	(revision )
@@ -1,80 +1,0 @@
-/* emacs edit mode for this file is -*- C++ -*- */
-/* $Id: ftmpl_inst.cc,v 1.10 2006/05/15 09:03:05 Singular Exp $ */
-
-//{{{ docu
-//
-// ftmpl_inst.cc - Factory's template instantiations.
-//
-// For a detailed description how to instantiate Factory's
-// template classes and functions and how to add new
-// instantiations see the `README' file.
-//
-//}}}
-
-#include <factoryconf.h>
-
-#ifdef macintosh
-#include <:templates:ftmpl_array.cc>
-#include <:templates:ftmpl_factor.cc>
-#include <:templates:ftmpl_list.cc>
-#include <:templates:ftmpl_functions.h>
-#include <:templates:ftmpl_matrix.cc>
-#else
-#include <templates/ftmpl_array.cc>
-#include <templates/ftmpl_factor.cc>
-#include <templates/ftmpl_list.cc>
-#include <templates/ftmpl_functions.h>
-#include <templates/ftmpl_matrix.cc>
-#endif
-
-#include <factory.h>
-
-
-//{{{ explicit template class instantiations
-template class Factor<CanonicalForm>;
-template class List<CFFactor>;
-template class ListItem<CFFactor>;
-template class ListIterator<CFFactor>;
-template class List<CanonicalForm>;
-template class ListItem<CanonicalForm>;
-template class ListIterator<CanonicalForm>;
-template class Array<CanonicalForm>;
-template class List<MapPair>;
-template class ListItem<MapPair>;
-template class ListIterator<MapPair>;
-template class Matrix<CanonicalForm>;
-template class SubMatrix<CanonicalForm>;
-template class Array<REvaluation>;
-//}}}
-
-//{{{ explicit template function instantiations
-#ifndef NOSTREAMIO
-template OSTREAM & operator << ( OSTREAM &, const List<CanonicalForm> & );
-template OSTREAM & operator << ( OSTREAM &, const List<CFFactor> & );
-template OSTREAM & operator << ( OSTREAM &, const List<MapPair> & );
-template OSTREAM & operator << ( OSTREAM &, const Array<CanonicalForm> & );
-template OSTREAM & operator << ( OSTREAM &, const Factor<CanonicalForm> & );
-template OSTREAM & operator << ( OSTREAM &, const Matrix<CanonicalForm> & );
-template OSTREAM & operator << ( OSTREAM &, const Array<REvaluation> & );
-#endif /* NOSTREAMIO */
-
-template int operator == ( const Factor<CanonicalForm> &, const Factor<CanonicalForm> & );
-
-template List<CFFactor> Union ( const List<CFFactor> &, const List<CFFactor> & );
-
-#if ! defined(WINNT) || defined(__GNUC__)
-template CanonicalForm tmax ( const CanonicalForm &, const CanonicalForm & );
-template CanonicalForm tmin ( const CanonicalForm &, const CanonicalForm & );
-
-template Variable tmax ( const Variable &, const Variable & );
-template Variable tmin ( const Variable &, const Variable & );
-
-template int tmax ( const int &, const int & );
-template int tmin ( const int &, const int & );
-template int tabs ( const int & );
-#endif
-//}}}
-
-//
-// place here your own template stuff, not yet instantiated by factory
-//
Index: age/libs/cf/misc.pxi
===================================================================
--- sage/libs/cf/misc.pxi	(revision 294)
+++ 	(revision )
@@ -1,11 +1,0 @@
-# Unset the signal handler and create a string from the buffer,
-# then free the memory in the buffer. 
-cdef object string(char* s):
-    _sig_off
-    # Makes a python string and deletes what is pointed to by s.
-    t = str(s)
-    free(s)
-    return t
-
-_INIT = None
-
Index: sage/libs/ntl/ntl.pyx
===================================================================
--- sage/libs/ntl/ntl.pyx	(revision 3597)
+++ sage/libs/ntl/ntl.pyx	(revision 4325)
@@ -2775,7 +2775,7 @@
         Finite Field in a of size 2^8
     """
-    from sage.rings.finite_field import FiniteField_ext_pari
+    from sage.rings.finite_field import FiniteField
     f = ntl_GF2E_modulus()._sage_()
-    return FiniteField_ext_pari(int(2)**GF2E_degree(),modulus=f,name=names)
+    return FiniteField(int(2)**GF2E_degree(),modulus=f,name=names)
     
 
@@ -2905,4 +2905,12 @@
         OUTPUT:
             FiniteFieldElement over k
+
+
+        EXAMPLE:
+            sage: ntl.GF2E_modulus([1,1,0,1,1,0,0,0,1])
+            sage: e = ntl.GF2E([0,1])
+            sage: a = e._sage_(); a
+            a
+
         """
         cdef int i
@@ -2911,7 +2919,7 @@
         
         if k==None:
-            from sage.rings.finite_field import FiniteField_ext_pari
+            from sage.rings.finite_field import FiniteField
             f = ntl_GF2E_modulus()._sage_()
-            k = FiniteField_ext_pari(2**deg,modulus=f)
+            k = FiniteField(2**deg,name='a',modulus=f)
 
         if cache != None:
Index: sage/matrix/benchmark.py
===================================================================
--- sage/matrix/benchmark.py	(revision 3487)
+++ sage/matrix/benchmark.py	(revision 4336)
@@ -25,6 +25,9 @@
                 t = -timeout
             alarm(0)
-            w.append(t)
-        w.append(w[0]/w[1])
+            w.append(float(t))
+        if w[1] == 0:
+            w.append(0.0)
+        else:
+            w.append(w[0]/w[1])
         w = tuple(w)
 
@@ -515,12 +518,12 @@
         raise ValueError, 'unknown system "%s"'%system
 
-def det_GF(n=400, p=16411 ,min=1, max=100, system='sage'):
+def det_GF(n=400, p=16411 , system='sage'):
     """
     Dense integer determinant over GF.
     Given an n x n (with n=400) matrix A over GF with random entries
-    between min=1 and max=100, inclusive, compute det(A).
-    """
-    if system == 'sage':
-        A = random_matrix(GF(p), n, n, x=min, y=max+1)
+    compute det(A).
+    """
+    if system == 'sage':
+        A = random_matrix(GF(p), n, n)
         t = cputime()
         d = A.determinant()
Index: sage/matrix/constructor.py
===================================================================
--- sage/matrix/constructor.py	(revision 3187)
+++ sage/matrix/constructor.py	(revision 3973)
@@ -72,4 +72,5 @@
        ring for all the entries (using the Sequence object):
 
+        sage: x = polygen(QQ)
         sage: m = matrix([[1/3,2+x],[3,4]]); m
         [  1/3 x + 2]
Index: sage/matrix/matrix0.pyx
===================================================================
--- sage/matrix/matrix0.pyx	(revision 3543)
+++ sage/matrix/matrix0.pyx	(revision 4022)
@@ -717,5 +717,5 @@
         S = []
         for x in self.list():
-            S.append(str(x))
+            S.append(repr(x))
 
         tmp = []
Index: sage/matrix/matrix1.pyx
===================================================================
--- sage/matrix/matrix1.pyx	(revision 3477)
+++ sage/matrix/matrix1.pyx	(revision 4062)
@@ -82,5 +82,5 @@
             matrix([0,1,2],[3,4,5],[6,7,8])
             sage: a.charpoly('x').expand()
-            -x^3 + 12*x^2 + 18*x
+            -x^3+12*x^2+18*x
             sage: m.charpoly()
             x^3 - 12*x^2 - 18*x
Index: sage/matrix/matrix2.pyx
===================================================================
--- sage/matrix/matrix2.pyx	(revision 3665)
+++ sage/matrix/matrix2.pyx	(revision 4330)
@@ -18,7 +18,8 @@
 
 from   sage.structure.sequence import _combinations, Sequence
-from   sage.misc.misc import verbose, get_verbose
+from   sage.misc.misc import verbose, get_verbose, graphics_filename
 from   sage.rings.number_field.all import is_NumberField
 from   sage.rings.integer_ring import ZZ
+from   sage.rings.rational_field import QQ
 
 import sage.modules.free_module
@@ -390,5 +391,5 @@
         # TODO: find reasonable cutoff (Field specific, but seems to be quite large for Q[x])
         # if R.is_integral_domain() and R.is_exact() and algorithm == "hessenberg":
-        if  R.is_field() and algorithm == "hessenberg":
+        if  R.is_field() and R.is_exact() and algorithm == "hessenberg":
             c = self.charpoly('x')[0]
             if self._nrows % 2:
@@ -2093,5 +2094,5 @@
             if PyErr_CheckSignals(): raise KeyboardInterrupt
             for r from start_row <= r < nr:
-                if A.get_unsafe(r, c) != 0:
+                if A.get_unsafe(r, c):
                     pivots.append(c)
                     a_inverse = ~A.get_unsafe(r,c)
@@ -2100,5 +2101,5 @@
                     for i from 0 <= i < nr:
                         if i != start_row:
-                            if A.get_unsafe(i,c) != 0:
+                            if A.get_unsafe(i,c):
                                 minus_b = -A.get_unsafe(i, c)
                                 A.add_multiple_of_row(i, start_row, minus_b, c)
@@ -2307,6 +2308,116 @@
         return True
 
-    
+    def visualize_structure(self, filename=None, maxsize=512):
+        """
+        Write a PNG image to 'filename' which visualizes self by putting
+        black pixels in those positions which have nonzero entries.
+
+        White pixels are put at positions with zero entries. If 'maxsize'
+        is given, then the maximal dimension in either x or y direction is
+        set to 'maxsize' depending on which is bigger. If the image is
+        scaled, the darkness of the pixel reflects how many of the
+        represented entries are nonzero. So if e.g. one image pixel
+        actually represents a 2x2 submatrix, the dot is darker the more of
+        the four values are nonzero.
+
+        INPUT:
+            filename -- either a path or None in which case a filename in
+                        the current directory is chosen automatically
+                        (default:None)
+
+            maxsize -- maximal dimension in either x or y direction of the resulting
+                       image. If None or a maxsize larger than
+                       max(self.nrows(),self.ncols()) is given the image will have
+                       the same pixelsize as the matrix dimensions (default: 512)
+
+        """
+        import gd
+        import os
         
+        cdef int x, y, _x, _y, v, b2
+        cdef int ir,ic
+        cdef float b, fct
+
+        mr, mc = self.nrows(), self.ncols()
+
+        if maxsize is None:
+
+            ir = mc
+            ic = mr
+            b = 1.0
+
+        elif max(mr,mc) > maxsize:
+
+            maxsize = float(maxsize)
+            ir = int(mc * maxsize/max(mr,mc))
+            ic = int(mr * maxsize/max(mr,mc))
+            b = max(mr,mc)/maxsize
+
+        else:
+
+            ir = mc
+            ic = mr
+            b = 1.0
+
+        b2 = b**2
+        fct = 255.0/b2
+
+        im = gd.image((ir,ic),1)
+        white = im.colorExact((255,255,255))
+        im.fill((0,0),white)
+
+        # these speed things up a bit 
+        colorExact = im.colorExact
+        setPixel = im.setPixel
+
+        for x from 0 <= x < ic:
+            for y from 0 <= y < ir:
+                v = b2
+                for _x from 0 <= _x < b:
+                    for _y from 0 <= _y < b:
+                        if not self.get_unsafe(<int>(x*b + _x), <int>(y*b + _y)).is_zero():
+                            v-=1 #increase darkness
+
+                v = int(v*fct)
+                val = colorExact((v,v,v))
+                setPixel((y,x), val)
+
+        if filename is None:
+            filename = graphics_filename()
+
+        im.writePng(filename)
+
+    def density(self):
+        """
+        Return the density of self.
+
+        By density we understand the ration of the number of nonzero
+        positions and the self.nrows() * self.ncols(), i.e. the number
+        of possible nonzero positions.
+
+        EXAMPLE:
+        
+            First, note that the density parameter does not ensure
+            the density of a matrix, it is only an upper bound.
+
+            sage: A = random_matrix(GF(127),200,200,density=0.3)
+            sage: A.density() # somewhat random
+            643/2500 
+
+            sage: A = matrix(QQ,3,3,[0,1,2,3,0,0,6,7,8])
+            sage: A.density()
+            2/3
+        
+        """
+        cdef int x,y,k
+        k = 0
+        nr = self.nrows()
+        nc = self.ncols()
+        for x from 0 <= x < nr:
+            for y from 0 <= y < nc:
+                if not self.get_unsafe(x,y).is_zero():
+                    k+=1
+        return QQ(k)/QQ(nr*nc)
+
 
 cdef decomp_seq(v):
Index: sage/matrix/matrix_complex_double_dense.pyx
===================================================================
--- sage/matrix/matrix_complex_double_dense.pyx	(revision 3616)
+++ sage/matrix/matrix_complex_double_dense.pyx	(revision 4062)
@@ -328,4 +328,5 @@
              
         EXAMPLES:
+            sage: I = CDF.gen()
             sage: m = I*Matrix(CDF, 3, range(9))
             sage: vals, vecs = m.eigen_left()
@@ -357,5 +358,5 @@
 
         EXAMPLES:
-            sage: m = I*Matrix(CDF, 3, range(9))       
+            sage: m = CDF.gen() * matrix(CDF, 3, range(9))       
             sage: vals, vecs = m.eigen()
             sage: vecs*m                 # random lower order precision
@@ -427,4 +428,5 @@
         
         EXAMPLES:
+            sage: I = CDF.gen()
             sage: A =I*matrix(CDF, 3,3, [1,2,5,7.6,2.3,1,1,2,-1])
             sage: A   # slightly random output
@@ -471,5 +473,6 @@
         
         EXAMPLES:
-            sage: A =I*matrix(CDF, 3,3, [1,2,5,7.6,2.3,1,1,2,-1])
+            sage: I = CDF.gen()
+            sage: A = I*matrix(CDF, 3,3, [1,2,5,7.6,2.3,1,1,2,-1])
             sage: A   # slightly random output
             [1.0*I             2.0*I                5.0*I]
@@ -544,5 +547,5 @@
             [  0 1.0]
             [2.0 3.0]
-            sage: log(abs(m.determinant()))
+            sage: RDF(log(abs(m.determinant())))
             0.69314718056
             sage: m.log_determinant()
@@ -651,4 +654,5 @@
 
         EXAMPLES:
+            sage: I = CDF.gen()
             sage: m = matrix(CDF,[[1,2],[3,4]])
             sage: m = I*m
Index: sage/matrix/matrix_integer_dense.pyx
===================================================================
--- sage/matrix/matrix_integer_dense.pyx	(revision 3665)
+++ sage/matrix/matrix_integer_dense.pyx	(revision 4059)
@@ -497,5 +497,5 @@
     # def _dict(self):
 
-    def is_zero(self):
+    def __nonzero__(self):
         cdef mpz_t *a, *b
         cdef Py_ssize_t i, j
@@ -503,6 +503,6 @@
         for i from 0 <= i < self._nrows * self._ncols:
             if mpz_cmp_si(self._entries[i], 0):
-                return False
-        return True
+                return True
+        return False
 
     def _multiply_linbox(self, Matrix right):
Index: sage/matrix/matrix_mod2_dense.pyx
===================================================================
--- sage/matrix/matrix_mod2_dense.pyx	(revision 3931)
+++ sage/matrix/matrix_mod2_dense.pyx	(revision 4326)
@@ -190,4 +190,7 @@
         """
         cdef int i,j,e
+
+        if entries is None:
+            return
 
         # scalar ?  
@@ -742,5 +745,5 @@
                     k = ((random()>>16)+random())%nc # is this safe?
                     # 16-bit seems safe
-                    writePackedCell(self._entries, i, j, (random()>>16) % 2)
+                    writePackedCell(self._entries, i, k, (random()>>16) % 2)
             _sig_off
 
Index: sage/matrix/matrix_modn_sparse.pyx
===================================================================
--- sage/matrix/matrix_modn_sparse.pyx	(revision 3272)
+++ sage/matrix/matrix_modn_sparse.pyx	(revision 4329)
@@ -84,5 +84,5 @@
 from sage.rings.integer_mod cimport IntegerMod_int, IntegerMod_abstract
 
-from sage.misc.misc import verbose, get_verbose
+from sage.misc.misc import verbose, get_verbose, graphics_filename
 
 ################
@@ -344,5 +344,110 @@
         self.cache('in_echelon_form',True)
 
-
-
-
+    def visualize_structure(self, filename=None, maxsize=512):
+        """
+        Write a PNG image to 'filename' which visualizes self by putting
+        black pixels in those positions which have nonzero entries.
+
+        White pixels are put at positions with zero entries. If 'maxsize'
+        is given, then the maximal dimension in either x or y direction is
+        set to 'maxsize' depending on which is bigger. If the image is
+        scaled, the darkness of the pixel reflects how many of the
+        represented entries are nonzero. So if e.g. one image pixel
+        actually represents a 2x2 submatrix, the dot is darker the more of
+        the four values are nonzero.
+
+        INPUT:
+            filename -- either a path or None in which case a filename in
+                        the current directory is chosen automatically
+                        (default:None)
+            maxsize -- maximal dimension in either x or y direction of the resulting
+                       image. If None or a maxsize larger than
+                       max(self.nrows(),self.ncols()) is given the image will have
+                       the same pixelsize as the matrix dimensions (default: 512)
+
+        """
+        import gd
+        import os
+
+        cdef Py_ssize_t i, j, k
+        cdef float blk,invblk
+        cdef int delta
+        cdef int x,y,r,g,b
+
+        mr, mc = self.nrows(), self.ncols()
+
+        if maxsize is None:
+
+            ir = mc
+            ic = mr
+            blk = 1.0
+            invblk = 1.0
+        
+        elif max(mr,mc) > maxsize:
+
+            maxsize = float(maxsize)
+            ir = int(mc * maxsize/max(mr,mc))
+            ic = int(mr * maxsize/max(mr,mc))
+            blk = max(mr,mc)/maxsize
+            invblk = maxsize/max(mr,mc)
+
+        else:
+            
+            ir = mc
+            ic = mr
+            blk = 1.0
+            invblk = 1.0
+
+        delta = 255.0 / blk**2 
+
+        im = gd.image((ir,ic),1)
+        white = im.colorExact((255,255,255))
+        im.fill((0,0),white)
+
+        colorComponents = im.colorComponents
+        getPixel = im.getPixel
+        setPixel = im.setPixel
+        colorExact = im.colorExact
+
+        for i from 0 <= i < self._nrows:
+            for j from 0 <= j < self.rows[i].num_nonzero:
+                x = <int>(invblk * self.rows[i].positions[j])
+                y = <int>(invblk * i)
+                r,g,b = colorComponents( getPixel((x,y)))
+                setPixel( (x,y), colorExact((r-delta,g-delta,b-delta)) )
+
+        if filename is None:
+            filename = sage.misc.misc.graphics_filename()
+
+        im.writePng(filename)
+
+    def density(self):
+        """
+        Return the density of self.
+
+        By density we understand the ration of the number of nonzero
+        positions and the self.nrows() * self.ncols(), i.e. the number
+        of possible nonzero positions.
+
+
+        EXAMPLE:
+        
+            First, note that the density parameter does not ensure
+            the density of a matrix, it is only an upper bound.
+
+            sage: A = random_matrix(GF(127),200,200,density=0.3, sparse=True)
+            sage: A.density() # somewhat random
+            643/2500 
+
+            sage: A = matrix(QQ,3,3,[0,1,2,3,0,0,6,7,8],sparse=True)
+            sage: A.density()
+            2/3
+        """
+        from sage.rings.rational_field import QQ
+
+        cdef Py_ssize_t i, j, k
+        k = 0
+        for i from 0 <= i < self._nrows:
+            for j from 0 <= j < self.rows[i].num_nonzero:
+                k+=1
+        return QQ(k)/QQ(self.nrows()*self.ncols())
Index: age/matrix/matrix_rational_sparse.pxd.orig
===================================================================
--- sage/matrix/matrix_rational_sparse.pxd.orig	(revision 3111)
+++ 	(revision )
@@ -1,9 +1,0 @@
-include "../ext/cdefs.pxi"
-
-cimport matrix_sparse
-
-cdef class Matrix_rational_sparse(matrix_sparse.Matrix_sparse):
-    cdef mpq_vector* rows
-    cdef public int nr, nc
-    cdef public is_init
-    
Index: age/matrix/matrix_rational_sparse.pyx.orig
===================================================================
--- sage/matrix/matrix_rational_sparse.pyx.orig	(revision 3593)
+++ 	(revision )
@@ -1,863 +1,0 @@
-"""
-Sparse rational matrices.
-
-AUTHORS:
-    -- William Stein (2007-02-21)
-    -- Soroosh Yazdani (2007-02-21)
-
-TESTS:
-    sage: a = matrix(QQ,2,range(4), sparse=True)
-    sage: loads(dumps(a)) == a
-    True
-
-"""
-
-##############################################################################
-#       Copyright (C) 2007 William Stein <wstein@gmail.com>
-#  Distributed under the terms of the GNU General Public License (GPL)
-#  The full text of the GPL is available at:
-#                  http://www.gnu.org/licenses/
-##############################################################################
-
-include '../modules/binary_search.pxi'
-
-include '../modules/vector_integer_sparse_h.pxi'
-include '../modules/vector_integer_sparse_c.pxi'
-include '../modules/vector_rational_sparse_h.pxi'
-include '../modules/vector_rational_sparse_c.pxi'
-include '../ext/stdsage.pxi'
-
-include '../ext/interrupt.pxi'
-
-from sage.rings.rational cimport Rational
-from sage.rings.integer  cimport Integer
-from matrix cimport Matrix
-
-from sage.rings.integer_ring import ZZ
-from sage.rings.rational_field import QQ
-
-cimport sage.structure.element
-
-import sage.matrix.matrix_space
-
-from matrix_integer_sparse cimport Matrix_integer_sparse
-from matrix_rational_dense cimport Matrix_rational_dense
-
-cdef class Matrix_rational_sparse(matrix_sparse.Matrix_sparse):   
-
-    ########################################################################
-    # LEVEL 1 functionality
-    #   * __new__  
-    #   * __dealloc__   
-    #   * __init__      
-    #   * set_unsafe
-    #   * get_unsafe
-    #   * __richcmp__    -- always the same
-    #   * __hash__       -- alway simple
-    ########################################################################
-    def __new__(self, parent, entries, copy, coerce):
-        # set the parent, nrows, ncols, etc. 
-        matrix_sparse.Matrix_sparse.__init__(self, parent)
-
-        self._matrix = <mpq_vector*> sage_malloc(parent.nrows()*sizeof(mpq_vector))
-        if self._matrix == NULL:
-            raise MemoryError, "error allocating sparse matrix"
-        # initialize the rows 
-        for i from 0 <= i < parent.nrows():
-            mpq_vector_init(&self._matrix[i], self._ncols, 0)
-
-        # record that rows have been initialized
-        self._initialized = True
-
-        
-    def __dealloc__(self):
-        self._dealloc()
-
-    cdef _dealloc(self):
-        cdef Py_ssize_t i
-        if self._initialized:
-            for i from 0 <= i < self._nrows:
-                mpq_vector_clear(&self._matrix[i])
-        if self._matrix != NULL:
-            sage_free(self._matrix)
-    
-    def __init__(self, parent, entries, copy, coerce):
-        """
-        Create a sparse matrix over the rational numbers
-        
-        INPUT:
-            parent -- a matrix space
-            entries -- * a Python list of triples (i,j,x), where 0 <= i < nrows,
-                         0 <= j < ncols, and x is coercible to an int.  The i,j
-                         entry of self is set to x.  The x's can be 0.
-                       * Alternatively, entries can be a list of *all* the entries
-                         of the sparse matrix (so they would be mostly 0).
-            copy -- ignored
-            coerce -- ignored
-        """
-        cdef Py_ssize_t i, j, k
-        cdef Rational z
-        cdef void** X
-
-        # fill in entries in the dict case
-        if isinstance(entries, dict):
-            R = self.base_ring()
-            for ij, x in entries.iteritems():
-                z = R(x)
-                if z != 0:
-                    i, j = ij  # nothing better to do since this is user input, which may be bogus.
-                    if i < 0 or j < 0 or i >= self._nrows or j >= self._ncols:
-                        raise IndexError, "invalid entries list"
-                    mpq_vector_set_entry(&self._matrix[i], j, z.value)
-        elif isinstance(entries, list):
-            # Dense input format -- fill in entries
-            if len(entries) != self._nrows * self._ncols:
-                raise TypeError, "list of entries must be a dictionary of (i,j):x or a dense list of n * m elements"
-            seq = PySequence_Fast(entries,"expected a list")
-            X = PySequence_Fast_ITEMS(seq)
-            k = 0
-            R = self.base_ring()
-            # Get fast access to the entries list.
-            for i from 0 <= i < self._nrows:
-                for  j from 0 <= j < self._ncols:
-                    z = R(<object>X[k])
-                    if z != 0:
-                        mpq_vector_set_entry(&self._matrix[i], j, z.value)
-                    k = k + 1
-        else:
-            # fill in entries in the scalar case
-            z = Rational(entries)
-            if z == 0:
-                return
-            if self._nrows != self._ncols:
-                raise TypeError, "matrix must be square to initialize with a scalar."
-            for i from 0 <= i < self._nrows:
-                mpq_vector_set_entry(&self._matrix[i], i, z.value)
-            
-
-    cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, x):
-        mpq_vector_set_entry(&self._matrix[i], j, (<Rational> x).value)
-
-    cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
-        cdef Rational x
-        x = Rational()
-        mpq_vector_get_entry(&x.value, &self._matrix[i], j)
-        return x
-
-    def __richcmp__(Matrix self, right, int op):  # always need for mysterious reasons.
-        return self._richcmp(right, op)
-    def __hash__(self):
-        return self._hash()
-    
-    
-    ########################################################################
-    # LEVEL 2 functionality
-    #   * def _pickle
-    #   * def _unpickle
-    #   * cdef _add_c_impl
-    #   * cdef _sub_c_impl             
-    #   * cdef _mul_c_impl
-    #   * cdef _cmp_c_impl
-    #   * __neg__
-    #   * __invert__
-    #   * __copy__
-    #   * _multiply_classical
-    #   * _matrix_times_matrix_c_impl
-    #   * _list -- list of underlying elements (need not be a copy)
-    #   * x _dict -- sparse dictionary of underlying elements (need not be a copy)
-
-    cdef sage.structure.element.Matrix _matrix_times_matrix_c_impl(self, sage.structure.element.Matrix _right):
-        cdef Matrix_rational_sparse right, ans
-        right = _right
-
-        cdef mpq_vector* v
-
-        # Build a table that gives the nonzero positions in each column of right
-        nonzero_positions_in_columns = [set([])]*right._ncols
-        cdef Py_ssize_t i, j, k
-        for i from 0 <= i < right._nrows:
-            v = &(right._matrix[i])
-            for j from 0 <= j < right._matrix[i].num_nonzero:
-                nonzero_positions_in_columns[v.positions[j]].add(i)
-
-        ans = self.new_matrix(self._nrows, right._ncols)
-        
-        # Now do the multiplication, getting each row completely before filling it in.
-        cdef mpq_t x, y, s
-        mpq_init(x)
-        mpq_init(y)
-        mpq_init(s)
-        for i from 0 <= i < self._nrows:
-            v = &self._matrix[i]
-            for j from 0 <= j < right._ncols:
-                mpq_set_si(s, 0, 1)
-                c = nonzero_positions_in_columns[j]
-                for k from 0 <= k < v.num_nonzero:
-                    if v.positions[k] in c:
-                        mpq_vector_get_entry(&y, &right._matrix[v.positions[k]], j)
-                        mpq_mul(x, v.entries[k], y)
-                        mpq_add(s, s, x)
-                mpq_vector_set_entry(&ans._matrix[i], j, s)
-        mpq_clear(x)
-        mpq_clear(y)
-        mpq_clear(s)
-        return ans
-
-    def _matrix_times_matrix_dense(self, sage.structure.element.Matrix _right):
-        """
-        Do the sparse matrix multiply, but return a dense matrix as the result.
-        """
-        cdef Matrix_rational_sparse right
-        cdef Matrix_rational_dense ans
-        right = _right
-
-        cdef mpq_vector* v
-
-        # Build a table that gives the nonzero positions in each column of right
-        nonzero_positions_in_columns = [set([])]*right._ncols
-        cdef Py_ssize_t i, j, k
-        for i from 0 <= i < right._nrows:
-            v = &(right._matrix[i])
-            for j from 0 <= j < right._matrix[i].num_nonzero:
-                nonzero_positions_in_columns[v.positions[j]].add(i)
-
-        ans = self.new_matrix(self._nrows, right._ncols, sparse=False)
-        
-        # Now do the multiplication, getting each row completely before filling it in.
-        cdef mpq_t x, y, s
-        mpq_init(x)
-        mpq_init(y)
-        mpq_init(s)
-        for i from 0 <= i < self._nrows:
-            v = &self._matrix[i]
-            for j from 0 <= j < right._ncols:
-                mpq_set_si(s, 0, 1)
-                c = nonzero_positions_in_columns[j]
-                for k from 0 <= k < v.num_nonzero:
-                    if v.positions[k] in c:
-                        mpq_vector_get_entry(&y, &right._matrix[v.positions[k]], j)
-                        mpq_mul(x, v.entries[k], y)
-                        mpq_add(s, s, x)
-                mpq_set(ans._matrix[i][j], s)
-        mpq_clear(x)
-        mpq_clear(y)
-        mpq_clear(s)
-        return ans
-
-    
-    ########################################################################
-    # def _pickle(self):
-    # def _unpickle(self, data, int version):   # use version >= 0
-    # cdef ModuleElement _add_c_impl(self, ModuleElement right):
-    # cdef _mul_c_impl(self, Matrix right):
-    # cdef int _cmp_c_impl(self, Matrix right) except -2:
-    # def __neg__(self):
-    # def __invert__(self):
-    # def __copy__(self):
-    # def _multiply_classical(left, matrix.Matrix _right):
-    # def _list(self):
-<<<<<<< /home/was/s/devel/sage-tomorrow/sage/matrix/matrix_rational_sparse.pyx
-
-# TODO
-##     cdef ModuleElement _lmul_c_impl(self, RingElement right):
-##         """
-##         EXAMPLES:
-##             sage: a = matrix(QQ,2,range(6))
-##             sage: (3/4) * a
-##             [   0  3/4  3/2]
-##             [ 9/4    3 15/4]
-##         """
-
-    def _dict(self):
-        """
-        Unsafe version of the dict method, mainly for internal use.
-        This may return the dict of elements, but as an *unsafe*
-        reference to the underlying dict of the object.  It is might
-        be dangerous if you change entries of the returned dict.
-        """
-        d = self.fetch('dict')
-        if not d is None:
-            return d
-
-        cdef Py_ssize_t i, j, k
-        d = {}
-        for i from 0 <= i < self._nrows:
-            for j from 0 <= j < self._matrix[i].num_nonzero:
-                x = Rational()
-                mpq_set((<Rational>x).value, self._matrix[i].entries[j])
-                d[(int(i),int(self._matrix[i].positions[j]))] = x
-        self.cache('dict', d)
-        return d
-=======
-
-# TODO
-##     cdef ModuleElement _lmul_c_impl(self, RingElement right):
-##         """
-##         EXAMPLES:
-##             sage: a = matrix(QQ,2,range(6))
-##             sage: (3/4) * a
-##             [   0  3/4  3/2]
-##             [ 9/4    3 15/4]
-##         """
-
-    def _dict(self):
-        """
-        Unsafe version of the dict method, mainly for internal use.
-        This may return the dict of elements, but as an *unsafe*
-        reference to the underlying dict of the object.  It is might
-        be dangerous if you change entries of the returned dict.
-        """
-        d = self.fetch('dict')
-        if not d is None:
-            return d
-
-        cdef Py_ssize_t i, j, k
-        d = {}
-        for i from 0 <= i < self._nrows:
-            for j from 0 <= j < self._matrix[i].num_nonzero:
-                x = Integer()
-                mpz_set((<Integer>x).value, self._matrix[i].entries[j])
-                d[(int(i),int(self._matrix[i].positions[j]))] = x
-        self.cache('dict', d)
-        return d
->>>>>>> /tmp/matrix_rational_sparse.pyx~other.AytdE9
-    
-
-    ########################################################################
-    # LEVEL 3 functionality (Optional)
-    #    * cdef _sub_c_impl
-    #    * __deepcopy__
-    #    * __invert__
-    #    * Matrix windows -- only if you need strassen for that base
-    #    * Other functions (list them here):
-    ########################################################################
-
-<<<<<<< /home/was/s/devel/sage-tomorrow/sage/matrix/matrix_rational_sparse.pyx
-    def height(self):
-        """
-        Return the height of this matrix, which is the least common
-        multiple of all numerators and denominators of elements of
-        this matrix.
-
-        OUTPUT:
-            -- Integer
-
-        EXAMPLES:
-            sage: b = matrix(QQ,2,range(6), sparse=True); b[0,0]=-5007/293; b
-            [-5007/293         1         2]
-            [        3         4         5]
-            sage: b.height()
-            5007
-        """
-        cdef Integer z
-        z = PY_NEW(Integer)
-        self.mpz_height(z.value)
-        return z
-    
-    cdef int mpz_height(self, mpz_t height) except -1:
-        cdef mpz_t x, h
-        mpz_init(x)
-        mpz_init_set_si(h, 0)
-        cdef int i, j
-        _sig_on
-        for i from 0 <= i < self._nrows:
-            for j from 0 <= j < self._matrix[i].num_nonzero:
-                mpq_get_num(x, self._matrix[i].entries[j])
-                mpz_abs(x, x)
-                if mpz_cmp(h,x) < 0:
-                    mpz_set(h,x)
-                mpq_get_den(x, self._matrix[i].entries[j])
-                mpz_abs(x, x)                
-                if mpz_cmp(h,x) < 0:
-                    mpz_set(h,x)
-        _sig_off
-        mpz_set(height, h)
-        mpz_clear(h)
-        mpz_clear(x)
-        return 0
-
-    cdef int mpz_denom(self, mpz_t d) except -1:
-        mpz_set_si(d,1)
-        cdef Py_ssize_t i, j
-        cdef mpq_vector *v
-        
-        _sig_on
-        for i from 0 <= i < self._nrows:
-            for j from 0 <= j < self._matrix[i].num_nonzero:
-                mpz_lcm(d, d, mpq_denref(self._matrix[i].entries[j]))
-        _sig_off
-        return 0
-
-
-    def denominator(self):
-        """
-        Return the denominator of this matrix.
-
-        OUTPUT:
-            -- SAGE Integer
-
-        EXAMPLES:
-            sage: b = matrix(QQ,2,range(6)); b[0,0]=-5007/293; b
-            [-5007/293         1         2]
-            [        3         4         5]
-            sage: b.denominator()
-            293
-        """
-        cdef Integer z
-        z = PY_NEW(Integer)
-        self.mpz_denom(z.value)
-        return z
-
-    def _clear_denom(self):
-        """
-        INPUT:
-            self -- a matrix
-
-        OUTPUT:
-            D*self, D
-=======
-    def height(self):
-        """
-        Return the height of this matrix, which is the least common
-        multiple of all numerators and denominators of elements of
-        this matrix.
-
-        OUTPUT:
-            -- Integer
-
-        EXAMPLES:
-            sage: b = matrix(QQ,2,range(6), sparse=True); b[0,0]=-5007/293; b
-            [-5007/293         1         2]
-            [        3         4         5]
-            sage: b.height()
-            5007
-        """
-        cdef Integer z
-        z = PY_NEW(Integer)
-        self.mpz_height(z.value)
-        return z
-    
-    cdef int mpz_height(self, mpz_t height) except -1:
-        cdef mpz_t x, h
-        mpz_init(x)
-        mpz_init_set_si(h, 0)
-        cdef int i, j
-        _sig_on
-        for i from 0 <= i < self._nrows:
-            for j from 0 <= j < self._matrix[i].num_nonzero:
-                mpq_get_num(x, self._matrix[i].entries[j])
-                mpz_abs(x, x)
-                if mpz_cmp(h,x) < 0:
-                    mpz_set(h,x)
-                mpq_get_den(x, self._matrix[i].entries[j])
-                mpz_abs(x, x)                
-                if mpz_cmp(h,x) < 0:
-                    mpz_set(h,x)
-        _sig_off
-        mpz_set(height, h)
-        mpz_clear(h)
-        mpz_clear(x)
-        return 0
-
-    cdef int mpz_denom(self, mpz_t d) except -1:
-        mpz_set_si(d,1)
-        cdef Py_ssize_t i, j
-        cdef mpq_vector *v
-        
-        _sig_on
-        for i from 0 <= i < self._nrows:
-            for j from 0 <= j < self._matrix[i].num_nonzero:
-                mpz_lcm(d, d, mpq_denref(self._matrix[i].entries[j]))
-        _sig_off
-        return 0
-
-
-    def denominator(self):
-        """
-        Return the denominator of this matrix.
-
-        OUTPUT:
-            -- SAGE Integer
-
-        EXAMPLES:
-            sage: b = matrix(QQ,2,range(6)); b[0,0]=-5007/293; b
-            [-5007/293         1         2]
-            [        3         4         5]
-            sage: b.denominator()
-            293
-        """
-        cdef Integer z
-        z = PY_NEW(Integer)
-        self.mpz_denom(z.value)
-        return z
-
-    def _clear_denom(self):
-        """
-        INPUT:
-            self -- a matrix
-
-        OUTPUT:
-            D*self, D
-
-        The product D*self is a matrix over ZZ
->>>>>>> /tmp/matrix_rational_sparse.pyx~other.AytdE9
-
-<<<<<<< /home/was/s/devel/sage-tomorrow/sage/matrix/matrix_rational_sparse.pyx
-        The product D*self is a matrix over ZZ
-
-        EXAMPLES:
-            sage: a = matrix(QQ,3,[-2/7, -1/4, -2, 0, 1/7, 1, 0, 1/2, 1/5],sparse=True)
-            sage: a.denominator()
-            140
-            sage: a._clear_denom()
-            ([ -40  -35 -280]
-            [   0   20  140]
-            [   0   70   28], 140)
-        """
-        cdef Integer D
-        cdef Py_ssize_t i, j
-        cdef Matrix_integer_sparse A
-        cdef mpz_t t
-        cdef mpq_vector* v
-=======
-        EXAMPLES:
-            sage: a = matrix(QQ,3,[-2/7, -1/4, -2, 0, 1/7, 1, 0, 1/2, 1/5],sparse=True)
-            sage: a.denominator()
-            140
-            sage: a._clear_denom()
-            ([ -40  -35 -280]
-            [   0   20  140]
-            [   0   70   28], 140)
-        """
-        cdef Integer D
-        cdef Py_ssize_t i, j
-        cdef Matrix_integer_sparse A
-        cdef mpz_t t
-        cdef mpq_vector* v
->>>>>>> /tmp/matrix_rational_sparse.pyx~other.AytdE9
-
-        D = Integer()
-        self.mpz_denom(D.value)
-        
-        MZ = sage.matrix.matrix_space.MatrixSpace(ZZ, self._nrows, self._ncols, sparse=True)
-        A = MZ.zero_matrix()
-
-        mpz_init(t)
-        _sig_on
-        for i from 0 <= i < self._nrows:
-            v = &(self._matrix[i])
-            for j from 0 <= j < v.num_nonzero:
-                mpz_divexact(t, D.value, mpq_denref(v.entries[j]))
-                mpz_mul(t, t, mpq_numref(v.entries[j]))
-                mpz_vector_set_entry(&(A._matrix[i]), v.positions[j], t)
-        _sig_off
-        mpz_clear(t)
-        A._initialized = 1
-        return A, D
-    
-
-<<<<<<< /home/was/s/devel/sage-tomorrow/sage/matrix/matrix_rational_sparse.pyx
-    ################################################
-    # Echelon form
-    ################################################
-    def echelonize(self, height_guess=None, proof=True, **kwds):
-        """
-        INPUT:
-            height_guess, proof, **kwds -- all passed to the multimodular algorithm; ignored
-                                           by the p-adic algorithm.
-
-        OUTPUT:
-            matrix -- the reduced row echelon for of self.
-
-        ALGORITHM: a multimodular algorithm.
-
-        EXAMPLES:
-            sage: a = matrix(QQ, 4, range(16), sparse=True); a[0,0] = 1/19; a[0,1] = 1/5; a
-            [1/19  1/5    2    3]
-            [   4    5    6    7]
-            [   8    9   10   11]
-            [  12   13   14   15]
-            sage: a.echelonize(); a
-            [      1       0       0 -76/157]
-            [      0       1       0  -5/157]
-            [      0       0       1 238/157]
-            [      0       0       0       0]
-        """
-                 
-        x = self.fetch('in_echelon_form')
-        if not x is None: return  # already known to be in echelon form
-        self.check_mutability()
-        self.clear_cache()
-        
-        pivots = self._echelonize_multimodular(height_guess, proof, **kwds)
-
-        self.cache('in_echelon_form', True)
-        self.cache('pivots', pivots)
-        
-
-    def echelon_form(self, algorithm='default',
-                     height_guess=None, proof=True, **kwds):
-        """
-        INPUT:
-            height_guess, proof, **kwds -- all passed to the multimodular algorithm; ignored
-                                           by the p-adic algorithm.
-
-        OUTPUT:
-            self is no in reduced row echelon form.
-
-        EXAMPLES:
-            sage: a = matrix(QQ, 4, range(16), sparse=True); a[0,0] = 1/19; a[0,1] = 1/5; a
-            [1/19  1/5    2    3]
-            [   4    5    6    7]
-            [   8    9   10   11]
-            [  12   13   14   15]
-            sage: a.echelon_form()
-            [      1       0       0 -76/157]
-            [      0       1       0  -5/157]
-            [      0       0       1 238/157]
-            [      0       0       0       0]
-        """
-        label = 'echelon_form_%s'%algorithm
-        x = self.fetch(label)
-        if not x is None:
-            return x
-        if self.fetch('in_echelon_form'): return self
-        
-        E = self._echelon_form_multimodular(height_guess, proof=proof)
-
-        self.cache(label, E)
-        self.cache('pivots', E.pivots())
-        return E
-
-    # Multimodular echelonization algorithms
-    def _echelonize_multimodular(self, height_guess=None, proof=True, **kwds):
-        cdef Matrix_rational_sparse E
-        E = self._echelon_form_multimodular(height_guess, proof=proof, **kwds)
-        # Get rid of self's data
-        self._dealloc()
-        
-        # Change self's data to point to E's.
-        self._matrix = E._matrix
-
-        # Make sure that E's destructure doesn't delete self's data.
-        E._matrix = NULL
-        E._initialized = False
-        return E.pivots()
-
-
-=======
-    ################################################
-    # Echelon form
-    ################################################
-    def echelonize(self, height_guess=None, proof=True, **kwds):
-        """
-        INPUT:
-            height_guess, proof, **kwds -- all passed to the multimodular algorithm; ignored
-                                           by the p-adic algorithm.
-
-        OUTPUT:
-            matrix -- the reduced row echelon for of self.
-
-        ALGORITHM: a multimodular algorithm.
-
-        EXAMPLES:
-            sage: a = matrix(QQ, 4, range(16), sparse=True); a[0,0] = 1/19; a[0,1] = 1/5; a
-            [1/19  1/5    2    3]
-            [   4    5    6    7]
-            [   8    9   10   11]
-            [  12   13   14   15]
-            sage: a.echelonize(); a
-            [      1       0       0 -76/157]
-            [      0       1       0  -5/157]
-            [      0       0       1 238/157]
-            [      0       0       0       0]
-        """
-                 
-        x = self.fetch('in_echelon_form')
-        if not x is None: return  # already known to be in echelon form
-        self.check_mutability()
-        self.clear_cache()
-        
-        pivots = self._echelonize_multimodular(height_guess, proof, **kwds)
-
-        self.cache('in_echelon_form', True)
-        self.cache('pivots', pivots)
-        
-
-    def echelon_form(self, algorithm='default',
-                     height_guess=None, proof=True, **kwds):
-        """
-        INPUT:
-            height_guess, proof, **kwds -- all passed to the multimodular algorithm; ignored
-                                           by the p-adic algorithm.
-
-        OUTPUT:
-            self is no in reduced row echelon form.
-
-        EXAMPLES:
-            sage: a = matrix(QQ, 4, range(16), sparse=True); a[0,0] = 1/19; a[0,1] = 1/5; a
-            [1/19  1/5    2    3]
-            [   4    5    6    7]
-            [   8    9   10   11]
-            [  12   13   14   15]
-            sage: a.echelon_form()
-            [      1       0       0 -76/157]
-            [      0       1       0  -5/157]
-            [      0       0       1 238/157]
-            [      0       0       0       0]
-        """
-        label = 'echelon_form_%s'%algorithm
-        x = self.fetch(label)
-        if not x is None:
-            return x
-        if self.fetch('in_echelon_form'): return self
-        
-        E = self._echelon_form_multimodular(height_guess, proof=proof)
-
-        self.cache(label, E)
-        self.cache('pivots', E.pivots())
-        return E
-
-    # Multimodular echelonization algorithms
-    def _echelonize_multimodular(self, height_guess=None, proof=True, **kwds):
-        cdef Matrix_rational_sparse E
-        E = self._echelon_form_multimodular(height_guess, proof=proof, **kwds)
-        # Get rid of self's data
-        self._dealloc()
-        
-        # Change self's data to point to E's.
-        self._matrix = E._matrix
-
-        # Make sure that E's destructure doesn't delete self's data.
-        E._matrix = NULL
-        E._initialized = False
-
-
->>>>>>> /tmp/matrix_rational_sparse.pyx~other.AytdE9
-    def _echelon_form_multimodular(self, height_guess=None, proof=True):
-        """
-        Returns reduced row-echelon form using a multi-modular
-        algorithm.  Does not change self.
-
-        INPUT:
-            height_guess -- integer or None
-            proof -- boolean (default: True)
-        """
-        import misc
-        return misc.matrix_rational_echelon_form_multimodular(self,
-                                 height_guess=height_guess, proof=proof)
-
-
-    def set_row_to_multiple_of_row(self, i, j, s):
-        """
-        Set row i equal to s times row j.
-
-        EXAMPLES:
-            sage: a = matrix(QQ,2,3,range(6), sparse=True); a
-            [0 1 2]
-            [3 4 5]
-            sage: a.set_row_to_multiple_of_row(1,0,-3)
-            sage: a
-            [ 0  1  2]
-            [ 0 -3 -6]        
-        """
-        self.check_row_bounds_and_mutability(i, j)
-        cdef Rational _s
-        _s = Rational(s)
-        mpq_vector_scalar_multiply(&self._matrix[i], &self._matrix[j], _s.value)
-        
-    def dense_matrix(self):
-        import misc
-        return misc.matrix_rational_sparse__dense_matrix(self)
-
-##     def _set_row_to_negative_of_row_of_A_using_subset_of_columns(self, Py_ssize_t i, Matrix A,
-##                                                                  Py_ssize_t r, cols):
-##         B = self.copy()
-##         B.x_set_row_to_negative_of_row_of_A_using_subset_of_columns(i, A, r, cols)
-##         cdef Py_ssize_t l
-##         l = 0
-##         for z in range(self.ncols()):
-##             self[i,z] = 0
-##         for k in cols:
-##             self.set_unsafe(i,l,-A.get_unsafe(r,k))               #self[i,l] = -A[r,k]
-##             l += 1
-##         if self != B:
-##             print "correct =\n", self.str()
-##             print "wrong = \n", B.str()
-##             print "diff = \n", (self-B).str()
-
-    def _set_row_to_negative_of_row_of_A_using_subset_of_columns(self, Py_ssize_t i, Matrix A,
-                                                                 Py_ssize_t r, cols,
-                                                                 cols_index=None):
-        """
-        Set row i of self to -(row r of A), but where we only take the
-        given column positions in that row of A.  Note that we *DO*
-        zero out the other entries of self's row i. 
-
-        INPUT:
-            i -- integer, index into the rows of self
-            A -- a sparse matrix
-            r -- integer, index into rows of A
-            cols -- a *sorted* list of integers. 
-            cols_index -- (optional).  But set it to this to vastly speed up calls
-                       to this function:
-                               dict([(cols[i], i) for i in range(len(cols))])
-        
-        EXAMPLES:
-            sage: a = matrix(QQ,2,3,range(6), sparse=True); a
-            [0 1 2]
-            [3 4 5]
-
-        Note that the row is zeroed out before being set in the sparse case.
-            sage: a._set_row_to_negative_of_row_of_A_using_subset_of_columns(0,a,1,[1,2])
-            sage: a
-            [-4 -5  0]
-            [ 3  4  5]
-        """
-        # this function exists just because it is useful for modular symbols presentations.
-        self.check_row_bounds_and_mutability(i,i)
-        if r < 0 or r >= A.nrows():
-            raise IndexError, "invalid row"
-
-        if not A.is_sparse():
-            A = A.sparse_matrix()
-
-        if A.base_ring() != QQ:
-            A = A.change_ring(QQ)
-
-        cdef Matrix_rational_sparse _A
-        _A = A
-        
-        cdef Py_ssize_t l, n
-
-        cdef mpq_vector *v, *w
-        v = &self._matrix[i]
-        w = &_A._matrix[r]
-
-
-        if cols_index is None:
-            cols_index = dict([(cols[i], i) for i in range(len(cols))])
-            
-        _cols = set(cols)
-        pos = [i for i from 0 <= i < w.num_nonzero if w.positions[i] in _cols]
-        n = len(pos)
-
-        mpq_vector_clear(v)
-        allocate_mpq_vector(v, n)
-        v.num_nonzero = n
-        v.degree = self._ncols
-
-
-        for l from 0 <= l < n:
-            v.positions[l] = cols_index[w.positions[pos[l]]]
-            mpq_mul(v.entries[l], w.entries[pos[l]], minus_one)
-
-
-
-#########################
-
-# used for a function above
-cdef mpq_t minus_one
-mpq_init(minus_one)
-mpq_set_si(minus_one, -1,1)
-        
Index: sage/matrix/matrix_real_double_dense.pyx
===================================================================
--- sage/matrix/matrix_real_double_dense.pyx	(revision 3616)
+++ sage/matrix/matrix_real_double_dense.pyx	(revision 4003)
@@ -555,5 +555,5 @@
             [0.0 1.0]
             [2.0 3.0]
-            sage: log(abs(m.determinant()))
+            sage: RDF(log(abs(m.determinant())))
             0.69314718056
             sage: m.log_determinant()
Index: sage/matrix/misc.pyx
===================================================================
--- sage/matrix/misc.pyx	(revision 3630)
+++ sage/matrix/misc.pyx	(revision 4103)
@@ -111,5 +111,5 @@
     cdef Integer _bnd
     import math
-    _bnd = Integer(int((N//2).sqrt()))
+    _bnd = Integer(int((N//2).sqrt_approx()))
     mpz_init_set(bnd, _bnd.value)
     mpz_sub(other_bnd, N.value, bnd)
@@ -188,5 +188,5 @@
     cdef Integer _bnd
     import math
-    _bnd = Integer(int((N//2).sqrt()))
+    _bnd = Integer(int((N//2).sqrt_approx()))
     mpz_init_set(bnd, _bnd.value)
     mpz_sub(other_bnd, N.value, bnd)
Index: sage/misc/all.py
===================================================================
--- sage/misc/all.py	(revision 3704)
+++ sage/misc/all.py	(revision 4338)
@@ -7,4 +7,6 @@
                   DOT_SAGE, SAGE_ROOT, SAGE_URL, SAGE_DB, SAGE_TMP,
                   is_32_bit, is_64_bit, newton_method_sizes)
+
+from remote_file import get_remote_file
 
 from attach import attach
@@ -50,10 +52,74 @@
 from func_persist import func_persist
 
-from functional import *
+from functional import (additive_order,
+                        sqrt as numerical_sqrt,
+                        arg,
+                        base_ring,
+                        base_field,
+                        basis,
+                        category,
+                        charpoly,
+                        coerce,
+                        cyclotomic_polynomial,
+                        decomposition,
+                        denominator,
+                        derivative,
+                        det,
+                        dimension,
+                        dim,
+                        discriminant,
+                        disc,
+                        eta,
+                        exp,
+                        factor,
+                        fcp,
+                        gen,
+                        gens,
+                        hecke_operator,
+                        ideal,
+                        image,
+                        imag,
+                        imaginary,
+                        integral,
+                        integral_closure,
+                        interval,
+                        xinterval,
+                        is_commutative,
+                        is_even,
+                        is_integrally_closed,
+                        is_field,
+                        is_odd,
+                        kernel,
+                        krull_dimension,
+                        lift,
+                        minimal_polynomial,
+                        multiplicative_order,
+                        ngens,
+                        norm,
+                        numerator,
+                        objgens,
+                        objgen,
+                        one,
+                        order,
+                        rank,
+                        real,
+                        regulator,
+                        round,
+                        quotient,
+                        quo,
+                        show,
+                        isqrt,
+                        square_free_part,
+                        squarefree_part,
+                        transpose,
+                        zero,
+                        log as log_b,
+                        parent)
+
 
 from latex import latex, view, lprint, jsmath
  
 # disabled -- nobody uses mathml
-#from mathml import mathml
+#from mathml ml
 
 from trace import trace
Index: sage/misc/functional.py
===================================================================
--- sage/misc/functional.py	(revision 3713)
+++ sage/misc/functional.py	(revision 4120)
@@ -52,7 +52,7 @@
 
     EXAMPLES:
-        sage: z = 1+2*I
+        sage: z = CC(1,2)
         sage: theta = arg(z)
-        sage: cos(theta)*abs(z)   # slightly random output on cygwin
+        sage: cos(theta)*abs(z)   
         1.00000000000000
         sage: sin(theta)*abs(z)
@@ -146,9 +146,4 @@
     Return the arc cosine of x.
 
-    EXAMPLES:
-        sage: acos(0.5)
-        1.04719755119660
-        sage: acos(1 + I*1.0)
-        0.904556894302381 - 1.06127506190504*I
     """
     try: return x.acos()
@@ -159,9 +154,4 @@
     Return the arc sine of x.
 
-    EXAMPLES:
-        sage: asin(0.5)
-        0.523598775598299
-        sage: asin(1 + I*1.0)
-        0.666239432492515 + 1.06127506190504*I
     """
     try: return x.asin()
@@ -172,9 +162,4 @@
     Return the arc tangent of x.
 
-    EXAMPLES:
-        sage: atan(1/2)
-        0.463647609001
-        sage: atan(1 + I)
-        1.01722196789785 + 0.402359478108525*I
     """
     try: return x.atan()
@@ -301,5 +286,5 @@
     EXAMPLES:
         sage: eta(1+I)
-        0.742048775836565 + 0.198831370229911*I
+        0.742048775837 + 0.19883137023*I
     """
     try: return x.eta()
@@ -345,9 +330,9 @@
     except AttributeError: return factor(charpoly(x, var))
 
-def floor(x):
-    try:
-        return x.floor()
-    except AttributeError:
-        return sage.rings.all.floor(x)
+## def floor(x):
+##     try:
+##         return x.floor()
+##     except AttributeError:
+##         return sage.rings.all.floor(x)
 
 def gen(x):
@@ -423,11 +408,11 @@
         sage: z = 1+2*I
         sage: imaginary(z)
-        2.00000000000000
+        2
         sage: imag(z)
-        2.00000000000000
+        2
     """
     return imag(x)
 
-def integral(x, var=None, algorithm='maxima'):
+def integral(x, *args, **kwds):
     """
     Return an indefinite integral of an object x.
@@ -441,19 +426,18 @@
         sage: integral(f)
         1/5*x^5 - 1/4*x^4 + 1/3*x^3 - 1/2*x^2 + x
-    """
-    if var is None:
-        try:
-            return x.integral()
-        except AttributeError:
-            pass
-    import sage.interfaces.all as I
-    if var is None:
-        var = 'x'
-    if algorithm == 'maxima':
-        return I.maxima(x).integrate(var)
-    elif algorithm == 'mathematica':
-        return I.mathematica(x).Integrate(var)
+        sage: integral(sin(x),x)
+        -cos(x)
+        sage: integral(sin(x),y)
+        sin(x)*y
+        sage: integral(sin(x), x, 0, pi/2)
+        1
+        sage: sin(x).integral(x, 0,pi/2)
+        1        
+    """
+    if hasattr(x, 'integral'):
+        return x.integral(*args, **kwds)
     else:
-        raise ValueError, 'no algorithm %s'%algorithm
+        from sage.calculus.calculus import SR
+        return SR(x).integral(*args, **kwds)
         
 def integral_closure(x):
@@ -604,13 +588,4 @@
     argument.}
 
-    EXAMPLES:
-        sage: log(10,2)
-        3.32192809489
-        sage: log(8,2)
-        3.0
-        sage: log(10)
-        2.30258509299
-        sage: log(2.718)
-        0.999896315728952
     """
     if b is None:
@@ -656,4 +631,8 @@
         sage: z = 1+2*I
         sage: norm(z)
+        5
+        sage: norm(CDF(z))
+        5.0
+        sage: norm(CC(z))
         5.00000000000000
     """
@@ -739,5 +718,5 @@
 
     We compute the rank of an elliptic curve:
-        sage: E=EllipticCurve([0,0,1,-1,0])
+        sage: E = EllipticCurve([0,0,1,-1,0])
         sage: rank(E)
         1
@@ -752,5 +731,5 @@
         sage: z = 1+2*I
         sage: real(z)
-        1.00000000000000
+        1
     """
     try: return x.real()
@@ -809,8 +788,13 @@
         except AttributeError:
             pass
+    _do_show(x)
+
+def _do_show(x):
     if sage.server.support.EMBEDDED_MODE:
         print '<html><div class="math">%s</div></html>'%sage.misc.latex.latex(x)
-        return sage.misc.latex.LatexExpr('') # so not visible output
-    raise AttributeError, "object %s does not support show."%x
+        return sage.misc.latex.LatexExpr('') # so no visible output
+    from latex import view
+    view(x)
+    #raise AttributeError, "object %s does not support show."%(x, )
 
 def sqrt(x):
@@ -883,33 +867,19 @@
 squarefree_part = square_free_part
     
-def square_root(x):
-    """
-    Return a square root of x with the same parent as x, if possible,
-    otherwise raise a ValueError.
-
-    EXAMPLES:
-        sage: square_root(9)
-        3
-        sage: square_root(100)
-        10
-    """
-    try:
-        return x.square_root()
-    except AttributeError:
-        raise NotImplementedError
+## def square_root(x):
+##     """
+##     Return a square root of x with the same parent as x, if possible,
+##     otherwise raise a ValueError.
+##     EXAMPLES:
+##         sage: square_root(9)
+##         3
+##         sage: square_root(100)
+##         10
+##     """
+##     try:
+##         return x.square_root()
+##     except AttributeError:
+##         raise NotImplementedError
     
-def tan(x):
-    """
-    Return the tangent of x.
-
-    EXAMPLES:
-        sage: tan(3.1415)
-        -0.0000926535900581913
-        sage: tan(3.1415/4)
-        0.999953674278156
-    """
-    try: return x.tan()
-    except AttributeError: return RDF(x).tan()
-
 def transpose(x):
     """
Index: sage/misc/hg.py
===================================================================
--- sage/misc/hg.py	(revision 3928)
+++ sage/misc/hg.py	(revision 4041)
@@ -564,4 +564,43 @@
         self('%s --help | %s'%(cmd, pager()))
 
+    def outgoing(self, url=None, opts=''):
+        """
+        Use this to find changsets that are in your branch, but not in the
+        specified destination repository. If no destination is specified, the
+        official repository is used.
+
+        From the Mercurial documentation:
+            Show changesets not found in the specified destination repository or the
+            default push location. These are the changesets that would be pushed if
+            a push was requested.
+
+            See pull() for valid destination format details.
+
+        INPUT:
+            url:  default: self.url() -- the official repository
+                   * http://[user@]host[:port]/[path]
+                   * https://[user@]host[:port]/[path]
+                   * ssh://[user@]host[:port]/[path]
+                   * local directory (starting with a /)
+                   * name of a branch (for hg_sage); no /'s
+            options: (default: none)
+                 -M --no-merges     do not show merges
+                 -f --force         run even when remote repository is unrelated
+                 -p --patch         show patch
+                    --style         display using template map file
+                 -r --rev           a specific revision you would like to push
+                 -n --newest-first  show newest record first
+                    --template      display with template
+                 -e --ssh           specify ssh command to use
+                    --remotecmd     specify hg command to run on the remote side
+        """
+        if url is None:
+            url = self.__url
+
+        if not '/' in url:
+            url = '%s/devel/sage-%s'%(SAGE_ROOT, url)
+
+        self('outgoing %s %s | %s' % (opts, url, pager()))
+
     def pull(self, url=None, options='-u'):
         """
Index: sage/misc/interpreter.py
===================================================================
--- sage/misc/interpreter.py	(revision 3211)
+++ sage/misc/interpreter.py	(revision 4356)
@@ -226,5 +226,5 @@
             name = str(eval(line[6:]))
         except:
-            name = line[6:].strip()
+            name = str(line[6:].strip())
         try:
             F = open(name)
@@ -261,7 +261,7 @@
         # e.g., including the "from sage import *"
         try:
-            name = eval(line[5:])
+            name = str(eval(line[5:]))
         except:
-            name = line[5:].strip()
+            name = str(line[5:].strip())
         if isinstance(name, str):
             if not os.path.exists(name):
@@ -314,7 +314,7 @@
         # e.g., including the "from sage import *"
         try:
-            name = eval(line[7:])
+            name = str(eval(line[7:]))
         except:
-            name = line[7:].strip()
+            name = str(line[7:].strip())
         name = os.path.abspath(name)
         if not os.path.exists(name):
Index: sage/misc/log.py
===================================================================
--- sage/misc/log.py	(revision 1097)
+++ sage/misc/log.py	(revision 4179)
@@ -64,4 +64,6 @@
     for X in loggers:
         X._update()
+
+REFRESH = '<meta http-equiv="REFRESH" content="4">' 
 
 class Log:
Index: sage/misc/misc.py
===================================================================
--- sage/misc/misc.py	(revision 3751)
+++ sage/misc/misc.py	(revision 4331)
@@ -21,5 +21,5 @@
                "assert_attribute", "LOGFILE"]
 
-import operator, os, sys, signal, time, weakref, random
+import operator, os, socket, sys, signal, time, weakref, random, resource
 
 from banner import version, banner
@@ -27,4 +27,6 @@
 SAGE_ROOT = os.environ["SAGE_ROOT"]
 SAGE_LOCAL = SAGE_ROOT + '/local/'
+
+HOSTNAME = socket.gethostname()
 
 if not os.path.exists(SAGE_ROOT):
@@ -57,5 +59,5 @@
     else:
         print "Your home directory has a space in it.  This"
-        print "will break some functionality of SAGE.  E.g.,"
+        print "will probably break some functionality of SAGE.  E.g.,"
         print "the GAP interface will not work.  A workaround"
         print "is to set the environment variable HOME to a"
@@ -63,7 +65,14 @@
         print "permissions to before you start sage."
 
-SPYX_TMP = '%s/spyx'%DOT_SAGE
-
-SAGE_TMP='%s/tmp/%s/'%(DOT_SAGE,os.getpid())
+SPYX_TMP = '%s/spyx/%s'%(DOT_SAGE, HOSTNAME)
+
+if not os.path.exists(SPYX_TMP):
+    try:
+        os.makedirs(SPYX_TMP)
+    except OSError, msg:
+        print msg
+        raise OSError, " ** Error trying to create the SAGE tmp directory in your home directory.  A possible cause of this might be that you built or upgraded SAGE after typing 'su'.  You probably need to delete the directory $HOME/.sage."
+    
+SAGE_TMP='%s/temp/%s/%s/'%(DOT_SAGE, HOSTNAME, os.getpid())
 if not os.path.exists(SAGE_TMP):
     try:
@@ -113,4 +122,7 @@
     spent by subprocesses spawned by SAGE (e.g., Gap, Singular, etc.).
 
+    This is done via a call to resource.getrusage, so it avoids the
+    wraparound problems in time.clock() on Cygwin.
+
     INPUT:
         t -- (optional) float, time in CPU seconds
@@ -133,5 +145,6 @@
     except TypeError:
         t = 0.0
-    return time.clock() - t
+    u,s = resource.getrusage(resource.RUSAGE_SELF)[:2] 
+    return u+s - t
 
 def walltime(t=0):
@@ -452,17 +465,24 @@
         
 
-def coeff_repr(c):
-    try:
-        return c._coeff_repr()
-    except AttributeError:
-        pass
+def coeff_repr(c, is_latex=False):
+    if not is_latex:
+        try:
+            return c._coeff_repr()
+        except AttributeError:
+            pass
     if isinstance(c, (int, long, float)):
         return str(c)
-    s = str(c).replace(' ','')
+    if is_latex and hasattr(c, '_latex_'):
+        s = c._latex_()
+    else:
+        s = str(c).replace(' ','')
     if s.find("+") != -1 or s.find("-") != -1:
-        return "(%s)"%s
+        if is_latex:
+            return "\\left(%s\\right)"%s
+        else:
+            return "(%s)"%s
     return s
         
-def repr_lincomb(symbols, coeffs):
+def repr_lincomb(symbols, coeffs, is_latex=False):
     """
     Compute a string representation of a linear combination of some
@@ -497,9 +517,18 @@
     all_atomic = True
     for c in coeffs:
-        b = str(symbols[i])
-        if len(b) > 0:
-            b = "*" + b
+        if is_latex and hasattr(symbols[i], '_latex_'):
+            b = symbols[i]._latex_()
+        else:
+            b = str(symbols[i])
         if c != 0:
-            coeff = coeff_repr(c)
+            coeff = coeff_repr(c, is_latex)
+            if coeff == "1":
+                coeff = ""
+            elif coeff == "-1":
+                coeff = "-"
+            elif not is_latex and len(b) > 0:
+                b = "*" + b
+            elif len(coeff) > 0 and b == "1":
+                b = ""
             if not first:
                 coeff = " + %s"%coeff
@@ -517,4 +546,6 @@
         s = "-" + s[3:]
     s = s.replace(" 1*", " ")
+    if s == "":
+        return "1"
     return s
 
@@ -1031,5 +1062,5 @@
 def tmp_dir(name):
     r"""
-    Create and return a temporary directory in \code{\$HOME/.sage/tmp/pid/}
+    Create and return a temporary directory in \code{\$HOME/.sage/temp/hostname/pid/}
     """
     name = str(name)
@@ -1047,5 +1078,5 @@
         n = 0
         while True:
-            tmp = "/tmp/tmp_%s_%s"%(name, n)
+            tmp = "/temp/tmp_%s_%s"%(name, n)
             if not os.path.exists(tmp):
                 break
@@ -1071,4 +1102,14 @@
     return tmp
 
+def graphics_filename():
+    """
+    Return the next available canonical filename for a plot/graphics
+    file.
+    """
+    i = 0
+    while os.path.exists('sage%d.png'%i):
+        i += 1
+    filename = 'sage%d.png'%i
+    return filename
 
 #################################################################
Index: sage/misc/preparser.py
===================================================================
--- sage/misc/preparser.py	(revision 3425)
+++ sage/misc/preparser.py	(revision 4061)
@@ -8,4 +8,6 @@
                                      by digits of input (like mathematica).
     -- Joe Wetherell (2006-04-14): * added MAGMA-style constructor preparsing.
+    -- Bobby Moretti (2007-01-25): * added preliminary function assignment
+                                     notation
 
 EXAMPLES:
@@ -49,4 +51,18 @@
     SyntaxError: invalid syntax
 
+SYMBOLIC FUNCTIONAL NOTATION:
+    sage: a=10; f(theta, beta) = theta + beta; b = x^2 + theta
+    sage: f
+    (theta, beta) |--> theta + beta
+    sage: a
+    10
+    sage: b
+    x^2 + theta
+    sage: f(theta,theta)
+    2*theta
+    
+    sage: a = 5; f(x,y) = x*y*sqrt(a)
+    sage: f
+    (x, y) |--> sqrt(5)*x*y
     
 RAW LITERALS:
@@ -114,6 +130,6 @@
 #                  http://www.gnu.org/licenses/
 ###########################################################################
-
 import os
+import pdb
 
 def isalphadigit_(s):
@@ -124,8 +140,18 @@
 in_double_quote = False
 in_triple_quote = False
+
 def in_quote():
     return in_single_quote or in_double_quote or in_triple_quote
 
 def preparse(line, reset=True, do_time=False, ignore_prompts=False):
+
+    # find where the parens are for function assignment notation
+    oparen_index = -1 
+    cparen_index = -1
+
+    # for caclulus function notation:
+    paren_level = 0
+    first_eq_index = -1
+    
     global in_single_quote, in_double_quote, in_triple_quote
     line = line.rstrip()  # xreadlines leaves the '\n' at end of line
@@ -160,4 +186,7 @@
     in_number = False
     is_real = False
+
+    in_args = False
+
     if reset:
         in_single_quote = False
@@ -212,5 +241,4 @@
                 i += 1
                 continue
-
 
         # Decide if we should wrap a particular integer or real literal
@@ -241,4 +269,10 @@
                 continue
 
+        elif line[i] == ";" and not in_quote():
+            line = line[:i+1] + preparse(line[i+1:], reset, do_time, ignore_prompts)
+            i = len(line)
+            continue
+
+
         # Support for generator construction syntax:
         # "obj.<gen0,gen1,...,genN> = objConstructor(...)"
@@ -323,4 +357,98 @@
             continue
 
+        # Support for calculus-like function assignment, the line
+        # "f(x,y,z) = sin(x^3 - 4*y) + y^x"
+        # gets turnd into
+        # "f = SR(sin(x^3 - 4*y) + y^x).function(x,y,z)"
+        # AUTHORS:
+        #   - Bobby Moretti: initial version - 02/2007
+        #   - William Stein: make variables become defined if they aren't already defined.
+
+        elif (line[i] == "(") and not in_quote():
+            paren_level += 1
+            # we need to make sure that this is the first open paren we find
+            if oparen_index == -1:
+                oparen_index = i
+            i += 1
+            continue
+
+        elif (line[i] == ")") and not in_quote():
+            cparen_index = i
+            paren_level -= 1
+            i += 1
+            continue
+
+        elif (line[i] == "=") and paren_level == 0 and not in_quote():
+            if first_eq_index == -1:
+                first_eq_index = i
+            eq = i
+
+            if cparen_index == -1:
+                i += 1
+                continue
+ 
+            # make sure the '=' sign is on its own, reprsenting assignment
+            eq_chars = ["=", "!", ">", "<", "+", "-", "*", "/", "^"]
+            if line[eq-1] in eq_chars or line[eq+1] in eq_chars:
+                i += 1
+                continue
+
+            line_before = line[:oparen_index].strip()
+            if line_before == "" or not line_before.isalnum():
+                i += 1
+                continue
+
+            if eq != first_eq_index:
+                i += 1
+                continue
+
+            vars_end = cparen_index
+            vars_begin = oparen_index+1
+
+            # figure out where the line ends
+            line_after = line[vars_end+1:]
+            try:
+                a = line.index("#")
+            except ValueError:
+                a = len(line)
+
+            try:
+                b = line.index(";")
+            except ValueError:
+                b = len(line)
+
+            a =  min(a,b)
+           
+            vars = line[vars_begin:vars_end].split(",")
+            vars = [v.strip() for v in vars]
+            b = []
+
+            
+            # construct the parsed line
+            k = line[:vars_begin-1].rfind(';')
+            if k == -1:
+                k = len(line) - len(line.lstrip())
+            b.append(line[:k])
+            b.append('_=var("%s");'%(','.join(vars)))
+            b.append(line[k:vars_begin-1])
+            b.append('=')
+            b.append('symbolic_expression(')
+            b.append(line[eq+1:a].strip())
+            b.append(').function(')
+            b.append(','.join(vars))
+            b.append(')')
+            b.append(line[a:])
+
+            line =  ''.join(b)
+            
+            # i should get set to the position of the first paren after the new
+            # assignment operator
+            n = len(line_before)
+            i = line.find('=', n) + 2
+
+            continue
+        #    
+        ####### END CALCULUS ########
+
         # exponents can be either ^ or **
         elif line[i] == "^" and not in_quote():
Index: sage/misc/remote_file.py
===================================================================
--- sage/misc/remote_file.py	(revision 2831)
+++ sage/misc/remote_file.py	(revision 4338)
@@ -7,7 +7,14 @@
              "http://modular.math.washington.edu/myfile.txt"
         verbose -- whether to display download status
+
     OUTPUT:
         creates a file in the temp directory and returns the
         absolute path to that file.
+
+    EXAMPLES:
+        sage: g = get_remote_file("http://sage.math.washington.edu/home/novoselt/K3vertices", verbose=False)   # optional -- requires an internet connection
+        sage: L = lattice_polytope.read_all_polytopes(g, "K3 %4d")                    # optional
+        sage: L[0]                                                                    # optional
+        K3    0: 3-dimensional, 4 vertices.
     """
     if verbose:
Index: sage/misc/reset.pyx
===================================================================
--- sage/misc/reset.pyx	(revision 3704)
+++ sage/misc/reset.pyx	(revision 4270)
@@ -1,27 +1,90 @@
 import sys
 
-def reset():
+def reset(vars=None):
     """
     Delete all user defined variables, reset all globals variables
     back to their default state, and reset all interfaces to other
-    computer algebra systems. 
+    computer algebra systems.
+
+    If vars is specified, just restore the value of vars and leave
+    all other variables alone (i.e., call restore).
+
+    INPUT:
+        vars -- (default: None), a list, or space or comma separated
+        string.
     """
+    if not vars is None:
+        restore(vars)
+        return
     G = globals()  # this is the reason the code must be in SageX.
     T = type(sys)
     for k in G.keys():
         if k[0] != '_' and type(k) != T:
-            del G[k]
+            try:
+                del G[k]
+            except KeyError:
+                pass
     restore()
     reset_interfaces()
 
 
-def restore():
+def restore(vars=None):
     """
-    Restore all predefined global variables to their default values.
+    Restore predefined global variables to their default values.
+
+    INPUT:
+       vars -- string or list (default: None) if not None, restores
+               just the given variables to the default value.
+
+    EXAMPLES:
+        sage: x = 10; y = 15/3; QQ='red'
+        sage: QQ
+        'red'
+        sage: restore('QQ')
+        sage: QQ
+        Rational Field
+        sage: x
+        10
+        sage: restore('x  y')
+        sage: x
+        x
+        sage: y
+        y
+        sage: x = 10; y = 15/3; QQ='red'
+        sage: ww = 15
+        sage: restore()
+        sage: x,y,QQ,ww
+        (x, y, Rational Field, 15)
+        sage: restore('ww')
+        sage: ww
+        Traceback (most recent call last):
+        ...
+        NameError: name 'ww' is not defined
     """
     G = globals()  # this is the reason the code must be in SageX.
     import sage.all
-    for k, v in sage.all.__dict__.iteritems():
-        G[k] = v
+    D = sage.all.__dict__
+    _restore(G, D, vars)
+    import sage.calculus.calculus
+    _restore(sage.calculus.calculus.syms_cur, sage.calculus.calculus.syms_default, vars)
+
+def _restore(G, D, vars):
+    if vars is None:
+        for k, v in D.iteritems():
+            G[k] = v
+    else:
+        if isinstance(vars, str):
+            if ',' in vars:
+                vars = vars.split(',')
+            else:
+                vars = vars.split()
+        for k in vars:
+            if D.has_key(k):
+                G[k] = D[k]
+            else:
+                try:
+                    del G[k]      # the default value was "unset"
+                except KeyError:
+                    pass
 
 
Index: sage/modular/cusps.py
===================================================================
--- sage/modular/cusps.py	(revision 3311)
+++ sage/modular/cusps.py	(revision 4061)
@@ -102,5 +102,6 @@
             Traceback (most recent call last):
             ...
-            TypeError: Unable to coerce 1.00000000000000*I (<type 'sage.rings.complex_number.ComplexNumber'>) to Rational
+            TypeError: Unable to coerce I (<class 'sage.functions.constants.I_class'>) to Rational
+            
         """
         return Cusp(x, parent=self)
@@ -168,6 +169,6 @@
             Traceback (most recent call last):
             ...
-            TypeError: Unable to coerce 1.00000000000000*I (<type 'sage.rings.complex_number.ComplexNumber'>) to Rational
-            
+            TypeError: unable to convert I to a rational
+
             sage: a = Cusp(2,3)
             sage: loads(a.dumps()) == a
Index: sage/modular/dirichlet.py
===================================================================
--- sage/modular/dirichlet.py	(revision 3570)
+++ sage/modular/dirichlet.py	(revision 4003)
@@ -672,5 +672,5 @@
             sage: abs(e.gauss_sum_numerical())
             1.73205080756888
-            sage: sqrt(3)
+            sage: sqrt(3.0)
             1.73205080756888
             sage: e.gauss_sum_numerical(a=2)
@@ -684,5 +684,5 @@
             sage: abs(e.gauss_sum_numerical())
             3.60555127546399
-            sage: sqrt(13)
+            sage: sqrt(13.0)
             3.60555127546399
         """
Index: sage/modular/modform/element.py
===================================================================
--- sage/modular/modform/element.py	(revision 3616)
+++ sage/modular/modform/element.py	(revision 4059)
@@ -103,6 +103,6 @@
         return chi
     
-    def is_zero(self):
-        return self.element().is_zero()
+    def __nonzero__(self):
+        return not self.element().is_zero()
     
     def level(self):
Index: sage/modular/modform/numerical.py
===================================================================
--- sage/modular/modform/numerical.py	(revision 3621)
+++ sage/modular/modform/numerical.py	(revision 4249)
@@ -247,4 +247,5 @@
             [28.0, 28.0, -7.92820323028, 5.92820323028]
             sage: m = n.modular_symbols()
+            sage: x = polygen(QQ, 'x')
             sage: m.T(2).charpoly(x).factor()
             (x - 9)^2 * (x^2 - 2*x - 2)
Index: sage/modular/modsym/space.py
===================================================================
--- sage/modular/modsym/space.py	(revision 3887)
+++ sage/modular/modsym/space.py	(revision 4013)
@@ -522,4 +522,5 @@
 
         An example that (somewhat spuriously) is over a number field:
+            sage: x = polygen(QQ)
             sage: k = NumberField(x^2+1, 'a')
             sage: M = ModularSymbols(11, base_ring=k, sign=1).cuspidal_submodule()
Index: sage/modules/free_module.py
===================================================================
--- sage/modules/free_module.py	(revision 3665)
+++ sage/modules/free_module.py	(revision 4263)
@@ -107,4 +107,5 @@
 import sage.rings.principal_ideal_domain as principal_ideal_domain
 import sage.rings.field as field
+import sage.rings.finite_field as finite_field
 import sage.rings.integral_domain as integral_domain
 import sage.rings.ring as ring
@@ -2655,4 +2656,22 @@
         return self.base_ring()
 
+    def __call__(self, e, coerce=True, copy=True, check=True):
+        """
+
+        EXAMPLE:
+            sage: k.<a> = GF(3^4)
+            sage: VS = k.vector_space()
+            sage: VS(a)
+            (0, 1, 0, 0)
+            
+        """
+        try:
+            k = e.parent()
+            if finite_field.is_FiniteField(k) and k.base_ring() == self.base_ring() and k.degree() == self.degree():
+                return self(e.vector())
+        except AttributeError:
+            pass
+        return FreeModule_generic_field.__call__(self,e)
+
 
 ###############################################################################
@@ -3619,6 +3638,9 @@
         return Vector_rational_dense
     elif sage.rings.integer_mod_ring.is_IntegerModRing(R) and not is_sparse:
-        from vector_modn_dense import Vector_modn_dense
-        return Vector_modn_dense
+        from vector_modn_dense import Vector_modn_dense, MAX_MODULUS
+        if R.order() < MAX_MODULUS:
+            return Vector_modn_dense
+        else:
+            return free_module_element.FreeModuleElement_generic_dense
     else:
         if is_sparse:
Index: sage/modules/free_module_element.pyx
===================================================================
--- sage/modules/free_module_element.pyx	(revision 3887)
+++ sage/modules/free_module_element.pyx	(revision 4160)
@@ -353,7 +353,5 @@
             Ambient free module of rank 4 over the principal ideal domain Integer Ring
         """
-        return eval('self.parent()([x % p for x in self.list()], \
-                     copy=False, coerce=False, check=False)',
-                    {'self':self, 'p':p})
+        return self.parent()([x % p for x in self.list()], copy=False, coerce=False, check=False)
 
     def Mod(self, p):
@@ -406,5 +404,5 @@
         if d == 0: return "()"
         # compute column widths
-        S = eval('[str(x) for x in self.list(copy=False)]', {'self':self})
+        S = [str(x) for x in self.list(copy=False)]
         #width = max([len(x) for x in S])
         s = "("
@@ -538,12 +536,53 @@
             2
         """
-        if not isinstance(right, FreeModuleElement):
+        if not PY_TYPE_CHECK(right, FreeModuleElement):
             raise TypeError, "right must be a free module element"
-        r = right.list()
-        l = self.list()
+        r = right.list(copy=False)
+        l = self.list(copy=False)
         if len(r) != len(l):
             raise ArithmeticError, "degrees (%s and %s) must be the same"%(len(l),len(r))
-        zero = self.parent().base_ring()(0)
-        return sum(eval('[l[i]*r[i] for i in xrange(len(l))]', {'l':l,'r':r}), zero)
+        if len(r) == 0:
+            return self._parent.base_ring()(0)
+        sum = l[0] * r[0]
+        cdef Py_ssize_t i
+        for i from 1 <= i < len(l):
+            sum += l[i] * r[i]
+        return sum
+        
+    def pairwise_product(self, right):
+        """
+        Return the dot product of self and right, which is a vector of
+        of the product of the corresponding entries.
+        
+        This is a synonym for self * right.
+
+        INPUT:
+            right -- vector of the same degree as self.  it need not
+                     be in the same vector space as self, as long as
+                     the coefficients can be multiplied.
+
+        EXAMPLES:
+            sage: V = FreeModule(ZZ, 3)
+            sage: v = V([1,2,3])
+            sage: w = V([4,5,6])
+            sage: v.pairwise_product(w)
+            (4, 10, 18)
+            sage: sum(v.pairwise_product(w)) == v.dot_product(w)
+            True
+
+            sage: W = VectorSpace(GF(3),3)
+            sage: w = W([0,1,2])
+            sage: w.pairwise_product(v)
+            (0, 2, 0)
+            sage: w.pairwise_product(v).parent()
+            Vector space of dimension 3 over Finite Field of size 3
+
+        Implicit coercion is well defined (irregardless of order), so
+        we get 2 even if we do the dot product in the other order.
+        
+            sage: v.pairwise_product(w).parent()  
+            Vector space of dimension 3 over Finite Field of size 3
+        """
+        return self * right
 
     def element(self):
@@ -633,6 +672,6 @@
         z = self.base_ring()(0)
         v = self.list()
-        return eval('[i for i in xrange(self.degree()) if v[i] != z]',
-                    {'self':self, 'z':z, 'v':v})
+        cdef Py_ssize_t i
+        return [i for i from 0 <= i < self.degree() if v[i] != z]
 
     def support(self):   # do not override.
@@ -731,5 +770,5 @@
             if coerce:
                 try:
-                    entries = eval('[R(x) for x in entries]',{'R':R, 'entries':entries})
+                    entries = [R(x) for x in entries]
                 except TypeError:
                     raise TypeError, "Unable to coerce entries (=%s) to %s"%(entries, R)
@@ -880,5 +919,5 @@
     """
     x = set(v.keys()).intersection(set(w.keys()))
-    return eval('sum([v[k]*w[k] for k in x])', {'v':v, 'w':w, 'x':x})
+    return sum([v[k]*w[k] for k in x])
     
 def make_FreeModuleElement_generic_sparse(parent, entries, degree):
Index: sage/modules/real_double_vector.pyx
===================================================================
--- sage/modules/real_double_vector.pyx	(revision 3616)
+++ sage/modules/real_double_vector.pyx	(revision 4021)
@@ -333,4 +333,36 @@
         memcpy(self.v.data,p,self.v.size*sizeof(double))
 
+    #############################
+    # statistics
+    #############################
+    def mean(self):
+        return gsl_stats_mean(self.v.data, self.v.stride, self.v.size)
+
+    def variance(self):
+        return gsl_stats_variance(self.v.data, self.v.stride, self.v.size)
+
+    #def covariance(self):
+    #    return gsl_stats_covariance(self.v.data, self.v.stride, self.v.size)
+
+    def standard_deviation(self):
+        """
+        EXAMPLES:
+        sage: v = vector(RDF, 5, [1,2,3,4,5])
+        sage: v.standard_deviation()
+        1.5811388300841898
+        """
+        return gsl_stats_sd(self.v.data, self.v.stride, self.v.size)
+
+    def stats_skew(self):
+        return gsl_stats_skew(self.v.data, self.v.stride, self.v.size)
+
+    def stats_kurtosis(self):
+        return gsl_stats_kurtosis(self.v.data, self.v.stride, self.v.size)
+    
+    def stats_lag1_autocorrelation(self):
+        return gsl_stats_lag1_autocorrelation(self.v.data, self.v.stride, self.v.size)
+    
+    
+    
 def unpickle_v0(parent, entries, degree):
     # If you think you want to change this function, don't.
Index: sage/modules/vector_modn_dense.pyx
===================================================================
--- sage/modules/vector_modn_dense.pyx	(revision 3544)
+++ sage/modules/vector_modn_dense.pyx	(revision 4263)
@@ -7,4 +7,6 @@
 EXAMPLES:
     sage: v = vector(Integers(8),[1,2,3,4,5])
+    sage: type(v)
+    <type 'sage.modules.vector_modn_dense.Vector_modn_dense'>
     sage: v
     (1, 2, 3, 4, 5)
@@ -62,4 +64,6 @@
 
 cimport free_module_element
+
+MAX_MODULUS = MOD_INT_OVERFLOW
 
 cdef class Vector_modn_dense(free_module_element.FreeModuleElement):
Index: sage/monoids/free_monoid.py
===================================================================
--- sage/monoids/free_monoid.py	(revision 1840)
+++ sage/monoids/free_monoid.py	(revision 4007)
@@ -154,6 +154,8 @@
         """
         ## There should really some careful type checking here...
+        if isinstance(x, FreeMonoidElement) and x.parent() is self:
+                return x
         if isinstance(x, FreeMonoidElement) and x.parent() == self:
-            return x
+            return FreeMonoidElement(self,x._element_list,check)
         elif isinstance(x, (int, long, Integer)) and x == 1:
             return FreeMonoidElement(self, x, check) 
Index: sage/monoids/free_monoid_element.py
===================================================================
--- sage/monoids/free_monoid_element.py	(revision 1859)
+++ sage/monoids/free_monoid_element.py	(revision 4007)
@@ -67,21 +67,21 @@
             raise TypeError, "Argument x (= %s) is of the wrong type."%x
 
-    def __cmp__(left, right):
-        """
-        Compare two free monoid elements with the same parents.
-
-        The ordering is the one on the underlying sorted list of
-        (monomial,coefficients) pairs.
-
-        EXAMPLES:
-            sage: R.<x,y> = FreeMonoid(2)
-            sage: x < y
-            True
-            sage: x * y < y * x
-            True
-            sage: x * y * x^2 < x * y * x^3
-            True        
-        """
-        return cmp(left._element_list, right._element_list)
+##     def __cmp__(left, right):
+##         """
+##         Compare two free monoid elements with the same parents.
+
+##         The ordering is the one on the underlying sorted list of
+##         (monomial,coefficients) pairs.
+
+##         EXAMPLES:
+##             sage: R.<x,y> = FreeMonoid(2)
+##             sage: x < y
+##             True
+##             sage: x * y < y * x
+##             True
+##             sage: x * y * x^2 < x * y * x^3
+##             True        
+##         """
+##         return cmp(left._element_list, right._element_list)
                                         
     def _repr_(self):
@@ -254,4 +254,3 @@
                     return 1
         return 0 # x = self and y are equal
-    
-
+
Index: sage/plot/all.py
===================================================================
--- sage/plot/all.py	(revision 3581)
+++ sage/plot/all.py	(revision 4332)
@@ -4,7 +4,8 @@
                   polar_plot, contour_plot, arrow,
                   plot_vector_field, matrix_plot, bar_chart,
-                  is_Graphics)
+                  is_Graphics,
+                  show_default)
 
-from plot3d import (Graphics3d, point3d, line3d)
+from plot3d import (Graphics3d, point3d, line3d, plot3d)
 
 from plot3dsoya_wrap import plot3dsoya
Index: sage/plot/plot.py
===================================================================
--- sage/plot/plot.py	(revision 3712)
+++ sage/plot/plot.py	(revision 4330)
@@ -81,7 +81,8 @@
 see the first few zeros:
 
-    sage: p1 = plot(lambda t: arg(zeta(0.5+t*I)), 1,27,rgbcolor=(0.8,0,0))
-    sage: p2 = plot(lambda t: abs(zeta(0.5+t*I)), 1,27,rgbcolor=hue(0.7))
-    sage: p1+p2
+    sage: i = CDF.0      # define i this way for maximum speed.
+    sage: p1 = plot(lambda t: arg(zeta(0.5+t*i)), 1,27,rgbcolor=(0.8,0,0))
+    sage: p2 = plot(lambda t: abs(zeta(0.5+t*i)), 1,27,rgbcolor=hue(0.7))
+    sage: p1 + p2
     Graphics object consisting of 2 graphics primitives
     sage: (p1+p2).save()
@@ -127,4 +128,6 @@
 #*****************************************************************************
 
+import pdb
+
 from sage.structure.sage_object import SageObject
 
@@ -138,4 +141,34 @@
 EMBEDDED_MODE = False
 SHOW_DEFAULT = False
+
+def show_default(default=None):
+    """
+    Set the default for showing plots using the following commands:
+        plot, parametric_plot, polar_plot, and list_plot.
+
+    If called with no arguments, returns the current default.
+
+    EXAMPLES:
+    The default starts out as False:
+        sage: show_default()
+        False
+
+    We set it to True.  
+        sage: show_default(True)
+
+    We see that it is True.
+        sage: show_default()
+        True
+
+    Now certain plot commands will display their plots by default.
+
+    Turn of default display.
+        sage: show_default(False)
+
+    """
+    global SHOW_DEFAULT
+    if default is None:
+        return SHOW_DEFAULT
+    SHOW_DEFAULT = bool(default)
 
 do_verify = True
@@ -468,8 +501,6 @@
   
         EXAMPLES:
-            sage: h1 = lambda x : abs(sqrt(x^3  - 1))
-            sage: h2 = lambda x : -abs(sqrt(x^3  - 1))
-            sage: g1 = plot(h1, 1, 5)
-            sage: g2 = plot(h2, 1, 5)
+            sage: g1 = plot(abs(sqrt(x^3  - 1)), 1, 5)
+            sage: g2 = plot(-abs(sqrt(x^3  - 1)), 1, 5)
             sage: h = g1 + g2
             sage: h.save()
@@ -587,5 +618,5 @@
         self._extend_y_axis(ymax)
   
-    def _plot_(self, **args):
+    def plot(self, *args, **kwds):
         return self
 
@@ -690,9 +721,5 @@
         from matplotlib.figure import Figure
         if filename is None:
-            i = 0
-            while os.path.exists('sage%s.png'%i):
-                i += 1
-            filename = 'sage%s.png'%i
-
+            filename = sage.misc.misc.graphics_filename()
         try:
             ext = os.path.splitext(filename)[1].lower()
@@ -1583,5 +1610,5 @@
     def __call__(self, points, coerce=True, **kwds):
         try:
-            return points._plot_(**kwds)
+            return points.plot(**kwds)
         except AttributeError:
             pass
@@ -1894,6 +1921,5 @@
     A red, blue, and green "cool cat":
 
-        sage: ncos = lambda x: -cos(x)
-        sage: G = plot(ncos, -2, 2, thickness=5, rgbcolor=(0.5,1,0.5))
+        sage: G = plot(-cos(x), -2, 2, thickness=5, rgbcolor=(0.5,1,0.5))
         sage: P = polygon([[1,2], [5,6], [5,0]], rgbcolor=(1,0,0))
         sage: Q = polygon([(-x,y) for x,y in P[0]], rgbcolor=(0,0,1))
@@ -2165,5 +2191,5 @@
         
     where X is a SAGE object that either is callable and returns
-    numbers that can be coerced to floats, or has a _plot_ method
+    numbers that can be coerced to floats, or has a plot method
     that returns a GraphicPrimitive object.
     
@@ -2251,5 +2277,5 @@
     We can change the line style to one of '--' (dashed), '-.' (dash dot),
     '-' (solid), 'steps', ':' (dotted):
-        sage: g = plot(sin,0,10, linestyle='-.')
+        sage: g = plot(sin(x), 0, 10, linestyle='-.')
         sage: g.save('sage.png')
     """
@@ -2257,30 +2283,28 @@
         o = self.options
         o['plot_points'] = 200
-        o['plot_division'] = 1000 # is this a good value?
-        o['max_bend'] = 0.1       # is this good as well?
+        o['plot_division'] = 1000 
+        o['max_bend'] = 0.1       
+        o['rgbcolor'] = (0,0,0)   
 
     def _repr_(self):
         return "plot; type plot? for help and examples."
 
-    def __call__(self, funcs, xmin=None, xmax=None, parametric=False,
-                 polar=False, label='',
-                 show=None, **kwds):
+    def __call__(self, funcs, *args, **kwds):
+        do_show = False
+        if kwds.has_key('show') and kwds['show']:
+            do_show = True
+            del kwds['show']
+        if hasattr(funcs, 'plot'):
+            G = funcs.plot(*args, **kwds)
+        else:
+            G = self._call(funcs, *args, **kwds)
+        if do_show:
+            G.show()
+        return G
+            
+    def _call(self, funcs, xmin=None, xmax=None, parametric=False,
+              polar=False, label='', show=None, **kwds):
         if show is None:
             show = SHOW_DEFAULT
-        try:
-            G = funcs._plot_(xmin=xmin, xmax=xmax, **kwds)
-            if show:
-                G.show(**kwds)
-            return G
-        except AttributeError:
-            pass
-        try:
-            G = funcs.plot(xmin=xmin, xmax=xmax, **kwds)
-            if show:
-                G.show(**kwds)
-            return G
-        except AttributeError:
-            pass
-        
         if xmin is None:
             xmin = -1
@@ -2295,5 +2319,5 @@
             G = Graphics()
             for i in range(0, len(funcs)):
-                G += plot(funcs[i], xmin, xmax, polar=polar, **kwds)
+                G += plot(funcs[i], xmin=xmin, xmax=xmax, polar=polar, **kwds)
             if show:
                 G.show(**kwds)
@@ -2313,4 +2337,5 @@
         data = []
         dd = delta
+        exceptions = 0; msg=''
         for i in xrange(plot_points + 1):
             x = xmin + i*delta
@@ -2321,10 +2346,12 @@
             else:
                 x = xmax  # guarantee that we get the last point.
+                
             try:
                 y = f(x)
                 data.append((x, float(y)))
-            except (TypeError, ValueError), msg:
+            except (ZeroDivisionError, TypeError, ValueError), msg:
                 sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, x),1)
-                pass
+                exceptions += 1
+
         # adaptive refinement
         i, j = 0, 0
@@ -2336,12 +2363,20 @@
             if abs(data[i+1][1] - data[i][1]) > max_bend:
                 x = (data[i+1][0] + data[i][0])/2
-                y = float(f(x))
-                data.insert(i+1, (x, y))
+                try:
+                    y = float(f(x))
+                    data.insert(i+1, (x, y))
+                except (ZeroDivisionError, TypeError, ValueError), msg:
+                    sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, x),1)
+                    exceptions += 1
+                    
                 j += 1
                 if j > plot_division:
-                    #is this wrong? 
                     break
             else:
                 i += 1
+
+        if (len(data) == 0 and exceptions > 0) or exceptions > 10:
+            print "WARNING: When plotting, failed to evaluate function at %s points."%exceptions
+            print "Last error message: '%s'"%msg
         if parametric:
             data = [(fdata, g(x)) for x, fdata in data]
@@ -2424,11 +2459,11 @@
         tmin -- start value of t
         tmax -- end value of t
-        show -- whether or not to show the plot immediately (default: True)
+        show -- bool or None
+                (default: use the default as set by the show_default command)
+                 whether or not to show the plot immediately
         other options -- passed to plot.
 
     EXAMPLE:
-        sage: f = lambda t: sin(t)
-        sage: g = lambda t: sin(2*t)
-        sage: G = parametric_plot((f,g),0,2*pi,rgbcolor=hue(0.6))
+        sage: G = parametric_plot( (sin(t), sin(2*t)), 0, 2*pi, rgbcolor=hue(0.6) )
         sage: G.save()
     """
@@ -2775,7 +2810,7 @@
     Make some plots of $\sin$ functions:
     
-        sage: f = lambda x: sin(x)
-        sage: g = lambda x: sin(2*x)
-        sage: h = lambda x: sin(4*x)
+        sage: f(x) = sin(x)
+        sage: g(x) = sin(2*x)
+        sage: h(x) = sin(4*x)
         sage: p1 = plot(f,-2*pi,2*pi,rgbcolor=hue(0.5))
         sage: p2 = plot(g,-2*pi,2*pi,rgbcolor=hue(0.9))
@@ -2816,8 +2851,8 @@
     """ # TODO: figure out WTF
     from sage.rings.integer import Integer
-    from sage.rings.arith import floor
-    rr = Integer(floor(r*255)).str(base=16)
-    gg = Integer(floor(g*255)).str(base=16)
-    bb = Integer(floor(b*255)).str(base=16)
+    from math import floor
+    rr = Integer(int(floor(r*255))).str(base=16)
+    gg = Integer(int(floor(g*255))).str(base=16)
+    bb = Integer(int(floor(b*255))).str(base=16)
     rr = '0'*(2-len(rr)) + rr
     gg = '0'*(2-len(gg)) + gg
@@ -2840,5 +2875,5 @@
         ['#ff0000', '#ffda00', '#48ff00', '#00ff91', '#0091ff', '#4800ff', '#ff00da']
     """
-    from sage.rings.arith import floor
+    from math import floor
     R = []
     for i in range(n):
Index: sage/plot/plot3d.py
===================================================================
--- sage/plot/plot3d.py	(revision 2021)
+++ sage/plot/plot3d.py	(revision 4332)
@@ -293,9 +293,5 @@
 	"""
         if filename is None:
-            i = 0
-            while os.path.exists('sage%s.png'%i):
-                i += 1
-            filename = 'sage%s.png'%i
-
+            filename = sage.misc.misc.graphics_filename()
         try:
             ext = os.path.splitext(filename)[1].lower()
@@ -618,2 +614,15 @@
 # unique surface factory
 surface = SurfaceFactory()
+
+
+def plot3d(x, *args, **kwds):
+    """
+    Plot a given object in 3d.
+
+    NOTE: 3d plotting in SAGE is *not* very powerful yet.
+    """
+    if hasattr(x, 'plot3d'):
+        return x.plot3d(*args, **kwds)
+    else:
+        raise NotImplementedError, "3d Plotting of %s not yet implemented"%x
+
Index: sage/plot/tachyon.py
===================================================================
--- sage/plot/tachyon.py	(revision 3161)
+++ sage/plot/tachyon.py	(revision 4359)
@@ -1,4 +1,4 @@
 r"""
-3D Ray Tracer
+3D Plotting Using Tachyon
 
 AUTHOR:
@@ -35,5 +35,5 @@
                  antialiasing = False,
                  aspectratio = 1.0,
-                 raydepth = 12,
+                 raydepth = 5,
                  camera_center = (-3, 0, 0),
                  updir = (0, 0, 1),
@@ -164,5 +164,5 @@
                  antialiasing = False,
                  aspectratio = 1.0,
-                 raydepth = 12,
+                 raydepth = 8,
                  camera_center = (-3, 0, 0),
                  updir = (0, 0, 1),
@@ -192,4 +192,5 @@
     def save(self, filename='sage.png', verbose=0, block=True, extra_opts=''):
         """
+        INPUT:
             filename -- (default: 'sage.png')
                        output filename; the extension of
@@ -217,8 +218,5 @@
         import sage.server.support
         if sage.server.support.EMBEDDED_MODE:
-            i = 0
-            while os.path.exists('sage%s.png'%i):
-                i += 1
-            filename = 'sage%s.png'%i
+            filename = sage.misc.misc.graphics_filename()
             self.save(filename, verbose=verbose, extra_opts=extra_opts)
         else:
@@ -226,5 +224,4 @@
             self.save(filename, verbose=verbose, extra_opts=extra_opts)
             os.system('%s %s 2>/dev/null 1>/dev/null &'%(sage.misc.viewer.browser(), filename))
-
 
     def _res(self):
Index: sage/probability/random_variable.py
===================================================================
--- sage/probability/random_variable.py	(revision 2617)
+++ sage/probability/random_variable.py	(revision 4022)
@@ -2,7 +2,8 @@
 Random variables and probability spaces
 
-This introduces a class of random variables, with the focus on discrete random 
-variables (i.e. on a discrete probability space).  This avoids the problem of 
-defining a measure space and measurable functions.
+This introduces a class of random variables, with the focus on
+discrete random variables (i.e. on a discrete probability space).
+This avoids the problem of defining a measure space and measurable
+functions.
 """
 
Index: sage/quadratic_forms/binary_qf.py
===================================================================
--- sage/quadratic_forms/binary_qf.py	(revision 1894)
+++ sage/quadratic_forms/binary_qf.py	(revision 4063)
@@ -268,5 +268,5 @@
 
     ## Find the range of allowed b's
-    bmax = (-D / ZZ(3)).sqrt().ceil()
+    bmax = (-D / ZZ(3)).sqrt_approx().ceil()
     b_range = range(-bmax, bmax+1)
     
Index: sage/rings/algebraic_real.py
===================================================================
--- sage/rings/algebraic_real.py	(revision 4135)
+++ sage/rings/algebraic_real.py	(revision 4135)
@@ -0,0 +1,2169 @@
+"""
+Field of Algebraic Reals
+
+AUTHOR:
+    -- Carl Witty (2007-01-27): initial version
+
+This is an implementation of the algebraic reals (the real numbers which
+are the zero of a polynomial in ZZ[x]).  All computations are exact.
+
+As with many other implementations of the algebraic numbers, we avoid
+computing a number field and working in the number field whenever possible.
+
+Algebraic numbers exist in one of the following forms:
+
+* a rational number
+* the sum, difference, product, or quotient of algebraic numbers
+* a particular root of a polynomial, given as a polynomial with
+algebraic coefficients, an isolating interval (given as a 
+RealIntervalFieldElement) which encloses exactly one root, and
+the multiplicity of the root
+* a polynomial in a generator, where the generator is an algebraic
+number given as the root of an irreducible polynomial with integral
+coefficients and the polynomial is given as a NumberFieldElement
+
+An algebraic number can be coerced into RealIntervalField; every algebraic 
+number has a cached interval of the highest precision yet calculated.
+
+Everything is done with intervals except for comparisons.  By default,
+comparisons compute the two algebraic numbers with 128-bit precision
+intervals; if this does not suffice to prove that the numbers are different,
+then we fall back on exact computation.
+
+Note that division involves an implicit comparison of the divisor against
+zero, and may thus trigger exact computation.
+
+Also, using an algebraic number in the leading coefficient of
+a polynomial also involves an implicit comparison against zero, which
+again may trigger exact computation.
+
+Note that we work fairly hard to avoid computing new number fields;
+to halp, we keep a lattice of already-computed number fields and
+their inclusions.
+
+EXAMPLES:
+    sage: sqrt(AA(2)) > 0
+    True
+    sage: (sqrt(5 + 2*sqrt(AA(6))) - sqrt(AA(3)))**2 == 2
+    True
+
+For a monic cubic polynomial x^3 + b*x^2 + c*x + d with roots
+s1,s2,s3, the discriminant is defined as (s1-s2)^2(s1-s3)^2(s2-s3)^2
+and can be computed as b^2c^2 - 4*b^3d - 4*c^3 + 18*bcd - 27*d^2.
+We can test that these definitions do give the same result.
+
+    sage: def disc1(b, c, d):
+    ...       return b^2*c^2 - 4*b^3*d - 4*c^3 + 18*b*c*d - 27*d^2
+    sage: def disc2(s1, s2, s3):
+    ...       return ((s1-s2)*(s1-s3)*(s2-s3))^2
+    sage: x = polygen(AA)
+    sage: p = x*(x-2)*(x-4)
+    sage: cp = AA.common_polynomial(p)
+    sage: d, c, b, _ = p.list()
+    sage: s1 = AA.polynomial_root(cp, RIF(-1, 1))
+    sage: s2 = AA.polynomial_root(cp, RIF(1, 3))
+    sage: s3 = AA.polynomial_root(cp, RIF(3, 5))
+    sage: disc1(b, c, d) == disc2(s1, s2, s3)
+    True
+    sage: p = p + 1
+    sage: cp = AA.common_polynomial(p)
+    sage: d, c, b, _ = p.list()
+    sage: s1 = AA.polynomial_root(cp, RIF(-1, 1))
+    sage: s2 = AA.polynomial_root(cp, RIF(1, 3))
+    sage: s3 = AA.polynomial_root(cp, RIF(3, 5))
+    sage: disc1(b, c, d) == disc2(s1, s2, s3)
+    True
+    sage: p = (x-sqrt(AA(2)))*(x-AA(2).nth_root(3))*(x-sqrt(AA(3)))
+    sage: cp = AA.common_polynomial(p)
+    sage: d, c, b, _ = p.list()
+    sage: s1 = AA.polynomial_root(cp, RIF(1.4, 1.5))
+    sage: s2 = AA.polynomial_root(cp, RIF(1.7, 1.8))
+    sage: s3 = AA.polynomial_root(cp, RIF(1.2, 1.3))
+    sage: disc1(b, c, d) == disc2(s1, s2, s3)
+    True
+
+Some computation with radicals:
+
+    sage: phi = (1 + sqrt(AA(5))) / 2
+    sage: phi^2 == phi + 1
+    True
+    sage: tau = (1 - sqrt(AA(5))) / 2
+    sage: tau^2 == tau + 1
+    True
+    sage: phi + tau == 1
+    True
+    sage: tau < 0
+    True
+
+    sage: rt23 = sqrt(AA(2/3))
+    sage: rt35 = sqrt(AA(3/5))
+    sage: rt25 = sqrt(AA(2/5))
+    sage: rt23 * rt35 == rt25
+    True
+
+Algebraic reals which are known to be rational print as rationals; otherwise
+they print as intervals (with 53-bit precision).
+
+    sage: AA(2)/3
+    2/3
+    sage: AA(5/7)
+    5/7
+    sage: two = sqrt(AA(4)); two
+    [1.9999999999999997 .. 2.0000000000000005]
+    sage: two == 2; two
+    True
+    2
+    sage: phi
+    [1.6180339887498946 .. 1.6180339887498950]
+
+The paper _ARPREC: An Arbitrary Precision Computation Package_ discusses
+this result.  Evidently it is difficult to find, but we can easily
+verify it.
+
+    sage: alpha = AA.polynomial_root(x^10 + x^9 - x^7 - x^6 - x^5 - x^4 - x^3 + x + 1, RIF(1, 1.2))
+    sage: lhs = alpha^630 - 1
+    sage: rhs_num = (alpha^315 - 1) * (alpha^210 - 1) * (alpha^126 - 1)^2 * (alpha^90 - 1) * (alpha^3 - 1)^3 * (alpha^2 - 1)^5 * (alpha - 1)^3
+    sage: rhs_den = (alpha^35 - 1) * (alpha^15 - 1)^2 * (alpha^14 - 1)^2 * (alpha^5 - 1)^6 * alpha^68
+    sage: rhs = rhs_num / rhs_den
+    sage: lhs
+    [2.6420403358193507e44 .. 2.6420403358193520e44]
+    sage: rhs
+    [2.6420403358193507e44 .. 2.6420403358193520e44]
+    sage: lhs - rhs
+    [-62883485433074552000000000000 .. 63753912023197085000000000000]
+    sage: lhs == rhs
+    True
+    sage: lhs - rhs
+    [0.00000000000000000 .. 0.00000000000000000]
+    sage: lhs._exact_value()
+    -242494609856316402264822833062350847769474540*a^9 + 862295472068289472491654837785947906234680703*a^8 - 829559238431038252116584538075753012193290520*a^7 - 125882239615006638366472766103700441555126185*a^6 + 1399067970863104691667276008776398309383579345*a^5 - 1561176687069361567616835847286958553574223422*a^4 + 761706318888840943058230840550737823821027895*a^3 + 580740464974951394762758666210754821723780266*a^2 - 954587496403409756503464154898858512440951323*a + 546081123623099782018260884934770383777092602 where a^10 - 4*a^9 + 5*a^8 - a^7 - 6*a^6 + 9*a^5 - 6*a^4 - a^3 + 5*a^2 - 4*a + 1 = 0 and a in [0.44406334400909258 .. 0.44406334400909265]
+"""
+
+import sage.rings.ring
+from sage.structure.sage_object import SageObject
+from sage.structure.parent_gens import ParentWithGens
+from sage.rings.real_mpfr import RR
+from sage.rings.real_mpfi import RealIntervalField, RIF, RealIntervalFieldElement
+from sage.rings.polynomial_ring import PolynomialRing
+from sage.rings.integer_ring import ZZ
+from sage.rings.rational_field import QQ
+from sage.rings.number_field.number_field import NumberField
+from sage.rings.number_field.number_field_element import is_NumberFieldElement
+from sage.rings.arith import factor
+from sage.libs.pari.gen import pari
+
+# Singleton object implementation copied from integer_ring.py
+_obj = None
+class _uniq_alg(object):
+    def __new__(cls):
+        global _obj
+        if _obj is None:
+            _obj = sage.rings.ring.Field.__new__(cls)
+        return _obj
+
+class AlgebraicRealField(_uniq_alg, sage.rings.ring.Field):
+    r"""
+    The field of algebraic reals.
+
+    """
+
+    def __init__(self):
+        ParentWithGens.__init__(self, self, ('x',), normalize=False)
+        self._default_interval_field = RealIntervalField(64)
+
+    def _repr_(self):
+        return "Algebraic Field"
+
+    # Is there a standard representation for this?
+    def _latex_(self):
+        return "\\mathbf{A}"
+
+    def __call__(self, x):
+        """
+        Coerce x into the field of algebraic numbers.
+
+        """
+
+        if isinstance(x, AlgebraicRealNumber):
+            return x
+        return AlgebraicRealNumber(x)
+
+    def _coerce_impl(self, x):
+        if isinstance(x, (int, long, sage.rings.integer.Integer,
+                          sage.rings.rational.Rational)):
+            return self(x)
+        raise TypeError, 'no implicit coercion of element to the algebraic numbers'
+
+    def _is_valid_homomorphism_(self, codomain, im_gens):
+        try:
+            return im_gens[0] == codomain._coerce_(self.gen(0))
+        except TypeError:
+            return False
+
+    def default_interval_field(self):
+        return self._default_interval_field
+
+    def gens(self):
+        return (self(1), )
+
+    def gen(self, n=0):
+        if n == 0:
+            return self(1)
+        else:
+            raise IndexError, "n must be 0"
+
+    def ngens(self):
+        return 1
+
+    def is_finite(self):
+        return False
+
+    def is_atomic_repr(self):
+        return True
+
+    def characteristic(self):
+        return sage.rings.integer.Integer(0)
+
+    def order(self):
+        return infinity.infinity
+
+    def zeta(self, n=2):
+        if n == 1:
+            return self(1)
+        elif n == 2:
+            return self(-1)
+        else:
+            raise ValueError, "no n-th root of unity in algebraic reals"
+
+    def common_polynomial(self, poly):
+        """
+        Given a polynomial with algebraic coefficients, returns a
+        wrapper that caches high-precision calculations and
+        factorizations.  This wrapper can be passed to polynomial_root
+        in place of the polynomial.
+
+        Using common_polynomial makes no semantic difference, but will
+        improve efficiency if you are dealing with multiple roots
+        of a single polynomial.
+
+        EXAMPLES:
+            sage: x = polygen(AA)
+            sage: p = AA.common_polynomial(x^2 - x - 1)
+            sage: phi = AA.polynomial_root(p, RIF(0, 2))
+            sage: tau = AA.polynomial_root(p, RIF(-2, 0))
+            sage: phi + tau == 1
+            True
+            sage: phi * tau == -1
+            True
+        """
+        return AlgebraicPolynomialTracker(poly)
+
+    def polynomial_root(self, poly, interval, multiplicity=1):
+        """
+        Given a polynomial with algebraic coefficients and an interval
+        enclosing exactly one root of the polynomial, constructs
+        an algebraic real representation of that root.
+
+        The polynomial need not be irreducible, or even squarefree; but
+        if the given root is a multiple root, its multiplicity must be
+        specified.  (IMPORTANT NOTE: Currently, multiplicity-k roots
+        are handled by taking the (k-1)th derivative of the polynomial.
+        This means that the interval must enclose exactly one root
+        of this derivative.)
+
+        The conditions on the arguments (that the interval encloses exactly
+        one root, and that multiple roots match the given multiplicity)
+        are not checked; if they are not satisfied, an error may be
+        thrown (possibly later, when the algebraic number is used),
+        or wrong answers may result.
+
+        Note that if you are constructing multiple roots of a single
+        polynomial, it is better to use AA.common_polynomial
+        to get a shared polynomial.
+
+        EXAMPLES:
+            sage: x = polygen(AA)
+            sage: phi = AA.polynomial_root(x^2 - x - 1, RIF(0, 2)); phi
+            [1.6180339887498946 .. 1.6180339887498950]
+            sage: p = (x-1)^7 * (x-2)
+            sage: r = AA.polynomial_root(p, RIF(9/10, 11/10), multiplicity=7)
+            sage: r; r == 1
+            [0.99999999999999988 .. 1.0000000000000003]
+            True
+            sage: p = (x-phi)*(x-sqrt(AA(2)))
+            sage: r = AA.polynomial_root(p, RIF(1, 3/2))
+            sage: r; r == sqrt(AA(2))
+            [1.4142135623730949 .. 1.4142135623730952]
+            True
+        """
+        return AlgebraicRealNumber(AlgebraicRealNumberRoot(poly, interval, multiplicity))
+
+def is_AlgebraicRealField(F):
+    return isinstance(F, AlgebraicRealField)
+
+AA = AlgebraicRealField()
+
+def rif_seq():
+    # XXX Should do some testing to see where the efficiency breaks are
+    # in MPFR.
+    bits = 64
+    while True:
+        yield RealIntervalField(bits)
+        bits = bits * 2
+#         # XXX temporary debugging:
+#         if bits > 1024:
+#             break
+
+def clear_denominators(poly):
+    """
+    Takes a monic polynomial and rescales the variable to get a monic
+    polynomial with "integral" coefficients.  Works on any univariate
+    polynomial whose base ring has a denominator() method that returns
+    integers; for example, the base ring might be QQ or a number
+    field.
+
+    Returns the scale factor and the new polynomial.
+
+    (Inspired by Pari's primitive_pol_to_monic().)
+
+    EXAMPLES:
+        sage: from sage.rings.algebraic_real import clear_denominators
+
+        sage: _.<x> = QQ['x']
+        sage: clear_denominators(x + 3/2)
+        (2, x + 3)
+        sage: clear_denominators(x^2 + x/2 + 1/4)
+        (2, x^2 + x + 1)
+
+    """
+
+    d = poly.denominator()
+    if d == 1:
+        return d, poly
+    deg = poly.degree()
+    factors = {}
+    for i in range(deg):
+        d = poly[i].denominator()
+        df = factor(d)
+        for f, e in df:
+            oe = 0
+            if f in factors:
+                oe = factors[f]
+            min_e = (e + (deg-i) - 1) // (deg-i)
+            factors[f] = max(oe, min_e)
+    change = 1
+    for f, e in factors.iteritems():
+        change = change * f**e
+    poly = poly * (change ** deg)
+    poly = poly(poly.parent().gen() / change)
+    return change, poly
+
+def do_polred(poly):
+    """
+    Find the polynomial of lowest discriminant that generates
+    the same field as poly, out of those returned by the Pari
+    polred routine.  Returns a triple: (elt_fwd, elt_back, new_poly),
+    where new_poly is the new polynomial, elt_fwd is a polynomial
+    expression for a root of the new polynomial in terms of a root
+    of the original polynomial, and elt_back is a polynomial expression
+    for a root of the original polynomial in terms of a root of the
+    new polynomial.
+
+    EXAMPLES:
+        sage: from sage.rings.algebraic_real import do_polred
+
+        sage: _.<x> = QQ['x']
+        sage: do_polred(x^2-5)
+        (-1/2*x + 1/2, -2*x + 1, x^2 - x - 1)
+        sage: do_polred(x^2-x-11)
+        (-1/3*x + 2/3, -3*x + 2, x^2 - x - 1)
+        sage: do_polred(x^3 + 123456)
+        (-1/4*x, -4*x, x^3 - 1929)
+    """
+    degree = poly.degree()
+    pari_poly = pari(poly)
+
+    red_table = pari_poly.polred(3)
+
+    best = None
+    best_discr = None
+    
+    for i in range(red_table.nrows()):
+        red_poly = red_table[i,1]
+        if red_poly.poldegree() < degree:
+            continue
+        red_discr = red_poly.poldisc().abs()
+        if best_discr is None or red_discr < best_discr:
+            best = red_poly
+            best_discr = red_discr
+            best_elt = red_table[i,0]
+
+    assert(best is not None)
+    parent = poly.parent()
+    return parent(best_elt), parent(best_elt.Mod(pari_poly).modreverse().lift()), parent(best)
+
+def isolating_interval(intv_fn, pol):
+    """
+    intv_fn is a function that takes a RealIntervalField and returns an
+    interval containing some particular root of pol.  (It must return
+    better approximations as the RealIntervalField precision increases.)
+    pol is an irreducible polynomial with rational coefficients.
+
+    Returns an interval containing at most one root of pol.
+
+    EXAMPLES:
+        sage: from sage.rings.algebraic_real import isolating_interval
+
+        sage: _.<x> = QQ['x']
+        sage: isolating_interval(lambda rif: sqrt(rif(2)), x^2 - 2)
+        [1.41421356237309504876 .. 1.41421356237309504888]
+
+    And an example that requires more precision:
+        sage: delta = 10^(-70)
+        sage: p = (x - 1) * (x - 1 - delta) * (x - 1 + delta)
+        sage: isolating_interval(lambda rif: rif(1 + delta), p)
+        [1.00000000000000000000000000000000000000000000000000000000000000000000009999999999999999999999999999999999999999999999999999999999999999999999999999999999998 .. 1.00000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014]
+    """
+    for rif in rif_seq():
+        intv = intv_fn(rif)
+
+        # We need to verify that pol has exactly one root in the
+        # interval intv.  We know (because it is a precondition of
+        # calling this function) that it has at least one root in the
+        # interval, so we only need to verify that it has at most one
+        # root (that the interval is sufficiently narrow).
+
+        # Call the root we want alpha, and the bounding interval
+        # [bot .. top].  By Budan's theorem, if pol(x+bot)
+        # has at most one more sign change than pol(x+top),
+        # then pol has at most one root in this interval.
+        # This is true if all coefficients in pol(x+bot)
+        # except for the constant coefficient have the same
+        # sign as the corresponding coefficients in pol(x+top).
+
+        # We can check this by computing pol(x+new_intv).
+        # This gives an "interval polynomial" which represents
+        # a set of polynomials, including pol(x+bot) and
+        # pol(x+top).  If all coefficients except the constant
+        # coefficient of this interval polynomial are bounded away from
+        # zero, then pol has at most one root in intv.
+        
+        # This is a sufficient condition, but not a necessary one.
+        # It is not obvious that there always exists a bounding
+        # interval for alpha with this property.  Fortunately,
+        # in the current case with pol irreducible, such
+        # a bounding interval does exist.
+
+        # Consider the polynomial pol(x+alpha), where
+        # pol has degree n.  The coefficient of x^k in this
+        # polynomial has an exact representation as a polynomial
+        # in QQ[alpha] of degree (n-k).  If this coefficient is
+        # equal to zero, then that means that alpha is a zero
+        # of this degree (n-k) polynomial.  But if k>0, then this
+        # is impossible, since alpha is a root of an irreducible
+        # degree n polynomial.
+
+        # Thus, all coefficients of pol(x+alpha) are nonzero,
+        # except for the constant coefficient, which is zero.  We
+        # are guaranteed that if we select a sufficiently tight bounding
+        # interval around alpha, then pol(x+[bot..top])
+        # will have coefficients bounded away from zero, which proves
+        # that there is only one root within that bounding interval.
+
+        zero = rif(0)
+        rif_poly_ring = rif['x']
+
+        ip = pol(rif_poly_ring.gen() + intv)
+        coeffs = ip.list()
+        assert(zero in coeffs[0])
+
+        ok = True
+
+        for c in coeffs[1:]:
+            if zero in c:
+                ok = False
+                break
+        if ok:
+            return intv
+
+def find_zero_result(fn, l):
+    """
+    l is a list of some sort.
+    fn is a function which maps an element of l and a RealIntervalField
+    into an interval, such that for a sufficiently precise RealIntervalField,
+    exactly one element of l results in an interval containing 0.
+    Returns that one element of l.
+
+    EXAMPLES:
+        sage: from sage.rings.algebraic_real import find_zero_result
+        sage: _.<x> = QQ['x']
+        sage: delta = 10^(-70)
+        sage: p1 = x - 1
+        sage: p2 = x - 1 - delta
+        sage: p3 = x - 1 + delta
+        sage: p2 == find_zero_result(lambda p, rif: p(rif(1 + delta)), [p1, p2, p3])
+        True
+    """
+    for rif in rif_seq():
+        result = None
+        ambig = False
+        for v in l:
+            intv = fn(v, rif)
+            if 0 in intv:
+                if result is not None:
+                    ambig = True
+                    break
+                result = v
+        if ambig:
+            continue
+        if result is None:
+            raise ValueError, 'find_zero_result could not find any zeroes'
+        return result
+
+# Cache some commonly-used polynomial rings
+QQx = QQ['x']
+QQx_x = QQx.gen()
+QQy = QQ['y']
+QQy_y = QQy.gen()
+QQxy = QQ['x', 'y']
+QQxy_x = QQxy.gen(0)
+QQxy_y = QQxy.gen(1)
+
+class AlgebraicGeneratorRelation(SageObject):
+    """
+    A simple class for maintaining relations in the lattice of algebraic 
+    extensions.
+    """
+    def __init__(self, child1, child1_poly, child2, child2_poly, parent):
+        self.child1 = child1
+        self.child1_poly = child1_poly
+        self.child2 = child2
+        self.child2_poly = child2_poly
+        self.parent = parent
+
+algebraic_generator_counter = 0
+
+class AlgebraicGenerator(SageObject):
+    """
+    An AlgebraicGenerator represents both an algebraic real alpha and
+    the number field QQ[alpha].  There is a single AlgebraicGenerator
+    representing QQ (with alpha==1).
+
+    The AlgebraicGenerator class is private, and should not be used
+    directly.
+    """
+
+    def __init__(self, field, root):
+        """
+        Construct an AlgebraicGenerator object.
+
+        sage: from sage.rings.algebraic_real import AlgebraicRealNumberRoot, AlgebraicGenerator, unit_generator
+        sage: _.<y> = QQ['y']
+        sage: x = polygen(AA)
+        sage: nf = NumberField(y^2 - y - 1, name='a', check=False)
+        sage: root = AlgebraicRealNumberRoot(x^2 - x - 1, RIF(1, 2))
+        sage: x = AlgebraicGenerator(nf, root)
+        sage: x
+        Number Field in a with defining polynomial y^2 - y - 1 with a in [1.6180339887498946 .. 1.6180339887498950]
+        sage: x.field()
+        Number Field in a with defining polynomial y^2 - y - 1
+        sage: x.is_unit()
+        False
+        sage: x.union(unit_generator) is x
+        True
+        sage: unit_generator.union(x) is x
+        True
+        """
+        self._field = field
+        self._unit = (field is None)
+        self._root = root
+        self._unions = {}
+        global algebraic_generator_counter
+        self._index = algebraic_generator_counter
+        algebraic_generator_counter += 1
+
+    def __hash__(self):
+        return self._index
+
+    def __cmp__(self, other):
+        return cmp(self._index, other._index)
+
+    def _repr_(self):
+        if self._unit:
+            return 'Unit generator'
+        else:
+            return '%s with a in %s'%(self._field, self._root.interval_fast(RIF))
+
+    def is_unit(self):
+        """
+        Returns true iff this is the unit generator (alpha == 1), which
+        does not actually extend the rationals.
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import unit_generator
+            sage: unit_generator.is_unit()
+            True
+        """
+        return self._unit
+
+    def field(self):
+        return self._field
+
+    def interval_fast(self, field):
+        """
+        Returns an interval containing this generator, to the specified
+        precision.
+        """
+        return self._root.interval_fast(field)
+
+    def union(self, other):
+        """
+        Given generators alpha and beta, alpha.union(beta) gives a generator
+        for the number field QQ[alpha][beta].
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import AlgebraicRealNumberRoot, AlgebraicGenerator, unit_generator
+            sage: _.<y> = QQ['y']
+            sage: x = polygen(AA)
+            sage: nf2 = NumberField(y^2 - 2, name='a', check=False)
+            sage: root2 = AlgebraicRealNumberRoot(x^2 - 2, RIF(1, 2))
+            sage: gen2 = AlgebraicGenerator(nf2, root2)
+            sage: gen2
+            Number Field in a with defining polynomial y^2 - 2 with a in [1.4142135623730949 .. 1.4142135623730952]
+            sage: nf3 = NumberField(y^2 - 3, name='a', check=False)
+            sage: root3 = AlgebraicRealNumberRoot(x^2 - 3, RIF(1, 2))
+            sage: gen3 = AlgebraicGenerator(nf3, root3)
+            sage: gen3
+            Number Field in a with defining polynomial y^2 - 3 with a in [1.7320508075688771 .. 1.7320508075688775]
+            sage: gen2.union(unit_generator) is gen2
+            True
+            sage: unit_generator.union(gen3) is gen3
+            True
+            sage: gen2.union(gen3)
+            Number Field in a with defining polynomial y^4 - 4*y^2 + 1 with a in [0.51763809020504147 .. 0.51763809020504159]
+        """
+        if self._unit:
+            return other
+        if other._unit:
+            return self
+        if self is other:
+            return self
+        if other in self._unions:
+            return self._unions[other].parent
+        if self._field.polynomial().degree() < other._field.polynomial().degree():
+            self, other = other, self
+        sp = self._field.polynomial()
+        op = other._field.polynomial()
+        op = QQx(op)
+        # print sp
+        # print op
+        # print self._field.polynomial()
+        # print self._field.polynomial().degree()
+        pari_nf = self._field.pari_nf()
+        # print pari_nf[0]
+        factors = list(pari_nf.nffactor(op).lift())[0]
+        # print factors
+        x, y = QQxy.gens()
+        # XXX Go through strings because multivariate polynomial coercion from
+        # Pari is not implemented
+        factors_sage = [QQxy(str(p)) for p in factors]
+        # print factors_sage
+        def find_fn(p, rif):
+            rif_poly = rif['x', 'y']
+            ip = rif_poly(p)
+            return ip(other._root.interval_fast(rif), self._root.interval_fast(rif))
+        my_factor = find_zero_result(find_fn, factors_sage)
+
+        if my_factor.degree(x) == 1 and my_factor.coefficient(x) == 1:
+            value = (-my_factor + x).univariate_polynomial(QQy)
+            # print value
+            rel = AlgebraicGeneratorRelation(self, QQy_y,
+                                             other, value,
+                                             self)
+            self._unions[other] = rel
+            other._unions[self] = rel
+            return rel.parent
+
+        # XXX need more caching here
+        newpol, self_pol, k = pari_nf.rnfequation(my_factor, 1)
+        k = int(k)
+        # print newpol
+        # print self_pol
+        # print k
+
+        newpol_sage = QQx(newpol)
+        newpol_sage_y = QQy(newpol_sage)
+
+        red_elt, red_back, red_pol = do_polred(newpol_sage_y)
+
+        red_back_x = QQx(red_back)
+
+        new_nf = NumberField(red_pol, name='a', check=False)
+        
+        self_pol_sage = QQx(self_pol.lift())
+
+        new_nf_a = new_nf.gen()
+
+        def intv_fn(rif):
+            return red_elt(self._root.interval_fast(rif) * k + other._root.interval_fast(rif))
+        new_intv = isolating_interval(intv_fn, red_pol)
+
+        new_gen = AlgebraicGenerator(new_nf, AlgebraicRealNumberRoot(QQx(red_pol), new_intv))
+        rel = AlgebraicGeneratorRelation(self, self_pol_sage(red_back_x),
+                                         other, (QQx_x - k*self_pol_sage)(red_back_x),
+                                         new_gen)
+        self._unions[other] = rel
+        other._unions[self] = rel
+        return rel.parent
+    
+    def super_poly(self, super, checked=None):
+        """
+        Given a generator gen and another generator super, where super
+        is the result of a tree of union() operations where one of the
+        leaves is gen, gen.super_poly(super) returns a polynomial
+        expressing the value of gen in terms of the value of super.
+        (Except that if gen is unit_generator, super_poly() always
+        returns None.)
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import AlgebraicGenerator, AlgebraicRealNumberRoot, unit_generator
+            sage: _.<y> = QQ['y']
+            sage: x = polygen(AA)
+            sage: nf2 = NumberField(y^2 - 2, name='a', check=False)
+            sage: root2 = AlgebraicRealNumberRoot(x^2 - 2, RIF(1, 2))
+            sage: gen2 = AlgebraicGenerator(nf2, root2)
+            sage: gen2
+            Number Field in a with defining polynomial y^2 - 2 with a in [1.4142135623730949 .. 1.4142135623730952]
+            sage: nf3 = NumberField(y^2 - 3, name='a', check=False)
+            sage: root3 = AlgebraicRealNumberRoot(x^2 - 3, RIF(1, 2))
+            sage: gen3 = AlgebraicGenerator(nf3, root3)
+            sage: gen3
+            Number Field in a with defining polynomial y^2 - 3 with a in [1.7320508075688771 .. 1.7320508075688775]
+            sage: gen2_3 = gen2.union(gen3)
+            sage: gen2_3
+            Number Field in a with defining polynomial y^4 - 4*y^2 + 1 with a in [0.51763809020504147 .. 0.51763809020504159]
+            sage: unit_generator.super_poly(gen2) is None
+            True
+            sage: gen2.super_poly(gen2_3)
+            -a^3 + 3*a
+            sage: gen3.super_poly(gen2_3)
+            -a^2 + 2
+        
+        """
+        if checked is None:
+            checked = {}
+        checked[self] = True
+        if super is self:
+            return self._field.gen()
+        for u in self._unions.values():
+            # print self, u.parent
+            # print checked
+            if u.parent in checked:
+                continue
+            poly = u.parent.super_poly(super, checked)
+            # print poly, u.child1, u.child2
+            if poly is None:
+                continue
+            if self is u.child1:
+                return u.child1_poly(poly)
+            assert(self is u.child2)
+            return u.child2_poly(poly)
+        return None
+
+    def __call__(self, elt):
+        """
+        Takes an AlgebraicRealNumber which is represented as either a rational
+        or a number field element, and which is in a subfield of the
+        field generated by this generator.  Lifts the number into the
+        field of this generator, and returns either a Rational or a
+        NumberFieldElement depending on whether this is the unit generator.
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import AlgebraicRealNumberRoot, AlgebraicGenerator, AlgebraicRealNumberExtensionElement, AlgebraicRealNumberRational
+            sage: _.<y> = QQ['y']
+            sage: x = polygen(AA)
+            sage: nf2 = NumberField(y^2 - 2, name='a', check=False)
+            sage: root2 = AlgebraicRealNumberRoot(x^2 - 2, RIF(1, 2))
+            sage: gen2 = AlgebraicGenerator(nf2, root2)
+            sage: gen2
+            Number Field in a with defining polynomial y^2 - 2 with a in [1.4142135623730949 .. 1.4142135623730952]
+            sage: sqrt2 = AlgebraicRealNumberExtensionElement(gen2, nf2.gen())
+            sage: nf3 = NumberField(y^2 - 3, name='a', check=False)
+            sage: root3 = AlgebraicRealNumberRoot(x^2 - 3, RIF(1, 2))
+            sage: gen3 = AlgebraicGenerator(nf3, root3)
+            sage: gen3
+            Number Field in a with defining polynomial y^2 - 3 with a in [1.7320508075688771 .. 1.7320508075688775]
+            sage: sqrt3 = AlgebraicRealNumberExtensionElement(gen3, nf3.gen())
+            sage: gen2_3 = gen2.union(gen3)
+            sage: gen2_3
+            Number Field in a with defining polynomial y^4 - 4*y^2 + 1 with a in [0.51763809020504147 .. 0.51763809020504159]
+            sage: gen2_3(sqrt2)
+            -a^3 + 3*a
+            sage: gen2_3(AlgebraicRealNumberRational(1/7))
+            1/7
+            sage: gen2_3(sqrt3)
+            -a^2 + 2            
+        """
+        if self._unit:
+            return elt.rational_value()
+        if elt.is_rational():
+            return self._field(elt.rational_value())
+        if elt.generator() is self:
+            return elt.field_element_value()
+        gen = elt.generator()
+        sp = gen.super_poly(self)
+        # print gen
+        # print self
+        assert(not(sp is None))
+        # print sp
+        # print self._field
+        return self._field(elt.field_element_value().polynomial()(sp))
+
+class AlgebraicRealNumberDescr(SageObject):
+    """
+    An AlgebraicRealNumber is a wrapper around an AlgebraicRealNumberDescr object.
+    AlgebraicRealNumberDescr is an abstract base class, which should never
+    be directly instantiated; its concrete subclasses are
+    AlgebraicRealNumberRational, AlgebraicRealNumberExpression,
+    AlgebraicRealNumberRoot, and AlgebraicRealNumberExtensionElement.
+    AlgebraicRealNumberDescr and all of its subclasses are private, and
+    should not be used directly.    
+    """
+    def is_exact(self):
+        """
+        Returns True if self is an AlgebraicRealNumberRational or an
+        AlgebraicRealNumberExtensionElement.
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import AlgebraicRealNumberRational
+            sage: AlgebraicRealNumberRational(1/2).is_exact()
+            True
+        """
+        return False
+
+    def is_rational(self):
+        """
+        Returns True if self is an AlgebraicRealNumberRational or
+        an AlgebraicRealNumberExtensionElement which is actually rational.
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import AlgebraicRealNumberRational
+            sage: AlgebraicRealNumberRational(3/7).is_rational()
+            True
+        """
+        return False
+
+    def is_field_element(self):
+        """
+        Returns True if self is an AlgebraicRealNumberExtensionElement.
+
+            sage: from sage.rings.algebraic_real import AlgebraicRealNumberExtensionElement, AlgebraicRealNumberRoot, AlgebraicGenerator
+            sage: _.<y> = QQ['y']
+            sage: x = polygen(AA)
+            sage: nf2 = NumberField(y^2 - 2, name='a', check=False)
+            sage: root2 = AlgebraicRealNumberRoot(x^2 - 2, RIF(1, 2))
+            sage: gen2 = AlgebraicGenerator(nf2, root2)
+            sage: sqrt2 = AlgebraicRealNumberExtensionElement(gen2, nf2.gen())
+            sage: sqrt2.is_field_element()
+            True
+        """
+        return False
+
+class AlgebraicRealNumberRational(AlgebraicRealNumberDescr):
+    """
+    The subclass of AlgebraicRealNumberDescr that represents an arbitrary
+    rational.  This class is private, and should not be used directly.
+    """
+
+    def __init__(self, x):
+        if isinstance(x, (int, long, sage.rings.integer.Integer,
+                          sage.rings.rational.Rational)):
+            self._value = x
+        else:
+            raise TypeError, "Illegal initializer for algebraic number rational"
+
+    def _repr_(self):
+        return repr(self._value)
+
+    def interval_fast(self, rif):
+        return rif(self._value)
+
+    def is_rational(self):
+        return True
+
+    def rational_value(self):
+        return self._value
+
+    def exactify(self):
+        return self
+
+    def is_exact(self):
+        return True
+
+class AlgebraicRealNumberExpression(AlgebraicRealNumberDescr):
+    """
+    The subclass of AlgebraicRealNumberDescr that represents the sum,
+    difference, product, or quotient of two algebraic numbers.
+    This class is private, and should not be used directly.
+    """
+
+    def __init__(self, left, right, op):
+        """
+        op can be '+', '-', '*', or '/'.
+        left and right are algebraic numbers.
+        If op is '-', then left can be None (in which case it is taken to
+        mean 0).
+        if op is '/', then left can be None (in which case it is taken to
+        mean 1).
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import AlgebraicRealNumberExpression
+            sage: AlgebraicRealNumberExpression(AA(1/3), AA(1/2), '+')
+            [0.83333333333333325 .. 0.83333333333333338] (1/3 + 1/2)
+            sage: AlgebraicRealNumberExpression(AA(1/3), AA(1/2), '-')
+            [-0.16666666666666669 .. -0.16666666666666662] (1/3 - 1/2)
+            sage: AlgebraicRealNumberExpression(AA(1/3), AA(1/2), '*')
+            [0.16666666666666665 .. 0.16666666666666669] (1/3 * 1/2)
+            sage: AlgebraicRealNumberExpression(AA(1/3), AA(1/2), '/')
+            [0.66666666666666662 .. 0.66666666666666675] (1/3 / 1/2)
+            sage: AlgebraicRealNumberExpression(None, AA(1/2), '-')
+            [-0.50000000000000000 .. -0.50000000000000000] (None - 1/2)
+            sage: AlgebraicRealNumberExpression(None, AA(1/2), '/')
+            [2.0000000000000000 .. 2.0000000000000000] (None / 1/2)
+        """
+        self._left = left
+        self._right = right
+        self._op = op
+
+    def _repr_(self):
+        return '%s (%s %s %s)'%(self.interval_fast(RIF), self._left, self._op, self._right)
+
+    def interval_fast(self, field):
+        """
+        Returns an interval containing self with precision given by the
+        field argument (which must be a RealIntervalField).  Note that
+        the result may not be a minimal-width interval.
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import AlgebraicRealNumberExpression
+            sage: five_sixths = AlgebraicRealNumberExpression(AA(1/2), AA(1/3), '+')
+            sage: five_sixths.interval_fast(RealIntervalField(4))
+            [0.812 .. 0.875]
+            sage: five_sixths.interval_fast(RealIntervalField(70))
+            [0.83333333333333333333305 .. 0.83333333333333333333390]
+        """
+        op = self._op
+        if op == '+':
+            return self._left.interval_fast(field) + self._right.interval_fast(field)
+        if op == '-':
+            if self._left is None:
+                return -self._right.interval_fast(field)
+            else:
+                return self._left.interval_fast(field) - self._right.interval_fast(field)
+        if op == '*':
+            return self._left.interval_fast(field) * self._right.interval_fast(field)
+        if op == '/':
+            # Note: this may trigger exact computation
+            if self._right.sign() == 0:
+                raise ZeroDivisionError, 'Division by zero in algebraic number field'
+            if self._left is None:
+                return ~self._right.interval_fast(field)
+            else:
+                return self._left.interval_fast(field) / self._right.interval_fast(field)
+        raise ValueError, 'Illegal operation for AlgebraicRealNumberExpression'
+
+    def exactify(self):
+        """
+        Return a new exact AlgebraicRealNumberDescr with the same value as self.
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import AlgebraicRealNumberExpression
+            sage: five_sixths = AlgebraicRealNumberExpression(AA(1/2), AA(1/3), '+')
+            sage: five_sixths.exactify()
+            5/6
+        """
+        op = self._op
+        left = self._left
+        if left is None:
+            if op == '-':
+                left = AA(0)
+            else:
+                left = AA(1)
+        left.exactify()
+
+        right = self._right
+        right.exactify()
+        
+        gen = left._exact_field().union(right._exact_field())
+
+        # print gen
+        # print left
+        # print right
+
+        left_value = gen(left._exact_value())
+        right_value = gen(right._exact_value())
+
+        if op == '+':
+            value = left_value + right_value
+        if op == '-':
+            value = left_value - right_value
+        if op == '*':
+            value = left_value * right_value
+        if op == '/':
+            value = left_value / right_value
+
+        # print gen
+        # print left, left_value
+        # print right, right_value
+
+        if gen.is_unit():
+            return AlgebraicRealNumberRational(value)
+        else:
+            return AlgebraicRealNumberExtensionElement(gen, value)
+
+
+class AlgebraicRealNumber(sage.structure.element.FieldElement):
+    """
+    An algebraic real (a real number which is the zero of a polynomial
+    in ZZ[x]).
+
+    AlgebraicRealNumber objects can be created using AA (== AlgebraicRealNumberField());
+    either by coercing a rational, or by using the AA.polynomial_root()
+    method to construct a particular root of a polynomial with algebraic
+    coefficients.  Also, AlgebraicRealNumber is closed under addition,
+    subtraction, multiplication, division (except by 0), and rational
+    powers (including roots), except for negative numbers and powers
+    with an even denominator.
+
+    AlgebraicRealNumber objects can be approximated to any desired precision.
+    They can be compared exactly; if the two numbers are very close,
+    this may require exact computation, which can be extremely slow.
+
+    As long as exact computation is not triggered, computation with
+    algebraic reals should not be too much slower than computation with
+    intervals.  As mentioned above, exact computation is triggered
+    when comparing two algebraic reals which are very close together.
+    This can be an explicit comparison in user code, but the following
+    list of actions (not necessarily complete) can also trigger exact
+    computation:
+    Dividing by an algebraic real which is very close to 0.
+    Using an algebraic real which is very close to 0 as the leading coefficient
+    in a polynomial.
+    Taking a root of an alebraic real which is very close to 0.
+
+    The exact definition of "very close" is subject to change; currently,
+    we compute our best approximation of the two numbers using 128-bit
+    arithmetic, and see if that's sufficient to decide the comparison.
+    Note that comparing two algebraic reals which are actually equal will
+    always trigger exact computation.
+
+    EXAMPLES:
+        sage: sqrt(AA(2))
+        [1.4142135623730949 .. 1.4142135623730952]
+        sage: sqrt(AA(2))^2 == 2
+        True
+        sage: x = polygen(AA)
+        sage: phi = AA.polynomial_root(x^2 - x - 1, RIF(0, 2))
+        sage: phi
+        [1.6180339887498946 .. 1.6180339887498950]
+        sage: phi^2 == phi+1
+        True
+    """
+
+    def __init__(self, x):
+        """
+        Initialize an algebraic number.  The argument must be either
+        a rational number or a subclass of AlgebraicRealNumberDescr.
+
+        sage: from sage.rings.algebraic_real import AlgebraicRealNumberExpression
+        sage: AlgebraicRealNumber(22/7)
+        22/7
+        sage: AlgebraicRealNumber(AlgebraicRealNumberExpression(AA(1/2), AA(1/5), '+'))
+        [0.69999999999999995 .. 0.70000000000000007]
+        """
+        sage.structure.element.FieldElement.__init__(self, AA)
+        if isinstance(x, (int, long, sage.rings.integer.Integer,
+                          sage.rings.rational.Rational)):
+            self._descr = AlgebraicRealNumberRational(x)
+        elif isinstance(x, (AlgebraicRealNumberDescr)):
+            self._descr = x
+        else:
+            raise TypeError, "Illegal initializer for algebraic number"
+
+        self._value = self._descr.interval_fast(AA.default_interval_field())
+        
+    def _repr_(self):
+        if self._descr.is_rational():
+            return repr(self._descr)
+        return repr(RIF(self._value))
+
+    def _mul_(self, other):
+        sd = self._descr
+        od = other._descr
+        if sd.is_rational() and od.is_rational():
+            value = sd.rational_value() * od.rational_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberRational(value))
+        elif sd.is_field_element() and \
+                od.is_field_element() and \
+                sd.field_parent() == od.field_parent():
+            value = sd.field_element_value() * od.field_element_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberExtensionElement(sd.field_parent(), value))
+        else:
+            value = AlgebraicRealNumberExpression(self, other, '*')
+            return AlgebraicRealNumber(value)
+
+    def _div_(self, other):
+        sd = self._descr
+        od = other._descr
+        if sd.is_rational() and od.is_rational():
+            value = sd.rational_value() / od.rational_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberRational(value))
+        elif sd.is_field_element() and \
+                od.is_field_element() and \
+                sd.field_parent() == od.field_parent():
+            value = sd.field_element_value() / od.field_element_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberExtensionElement(sd.field_parent(), value))
+        else:
+            value = AlgebraicRealNumberExpression(self, other, '/')
+            return AlgebraicRealNumber(value)
+
+    def __invert__(self):
+        sd = self._descr
+        if sd.is_rational:
+            value = ~sd.rational_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberRational(value))
+        elif sd.is_field_element():
+            value = ~sd.field_element_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberExtensionElement(sd.field_parent(), value))
+        else:
+            value = AlgebraicRealNumberExpression(None, self, '/')
+            return AlgebraicRealNumber(value)
+
+    def _add_(self, other):
+        sd = self._descr
+        od = other._descr
+        if sd.is_rational() and od.is_rational():
+            value = sd.rational_value() + od.rational_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberRational(value))
+        elif sd.is_field_element() and \
+                od.is_field_element() and \
+                sd.field_parent() == od.field_parent():
+            value = sd.field_element_value() + od.field_element_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberExtensionElement(sd.field_parent(), value))
+        else:
+            value = AlgebraicRealNumberExpression(self, other, '+')
+            return AlgebraicRealNumber(value)
+
+    def _sub_(self, other):
+        sd = self._descr
+        od = other._descr
+        if sd.is_rational() and od.is_rational():
+            value = sd.rational_value() - od.rational_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberRational(value))
+        elif sd.is_field_element() and \
+                od.is_field_element() and \
+                sd.field_parent() == od.field_parent():
+            value = sd.field_element_value() - od.field_element_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberExtensionElement(sd.field_parent(), value))
+        else:
+            value = AlgebraicRealNumberExpression(self, other, '-')
+            return AlgebraicRealNumber(value)
+
+    def _neg_(self):
+        sd = self._descr
+        if sd.is_rational():
+            value = -sd.rational_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberRational(value))
+        elif sd.is_field_element():
+            value = -sd.field_element_value()
+            return AlgebraicRealNumber(AlgebraicRealNumberExtensionElement(sd.field_parent(), value))
+        else:
+            value = AlgebraicRealNumberExpression(None, self, '-')
+            return AlgebraicRealNumber(value)
+
+    def __cmp__(self, other):
+        if other._descr.is_rational() and other._descr.rational_value() == 0:
+            return self.sign()
+        elif self._descr.is_rational() and self._descr.rational_value() == 0:
+            return -other.sign()
+        else:
+            return self._sub_(other).sign()
+
+    def __pow__(self, e):
+        """
+        self^p returns the p'th power of self (where p can be an arbitrary
+        rational).
+
+        EXAMPLES:
+            sage: AA(2)^(1/2)
+            [1.4142135623730949 .. 1.4142135623730952]
+            sage: AA(8)^(2/3)
+            [3.9999999999999995 .. 4.0000000000000009]
+            sage: AA(8)^(2/3) == 4
+            True
+            sage: x = polygen(AA)
+            sage: phi = AA.polynomial_root(x^2 - x - 1, RIF(0, 2))
+            sage: tau = AA.polynomial_root(x^2 - x - 1, RIF(-2, 0))
+            sage: rt5 = AA(5)^(1/2)
+            sage: phi^10 / rt5
+            [55.003636123247410 .. 55.003636123247418]
+            sage: tau^10 / rt5
+            [0.0036361232474132654 .. 0.0036361232474132659]
+            sage: (phi^10 - tau^10) / rt5
+            [54.999999999999992 .. 55.000000000000008]
+            sage: (phi^10 - tau^10) / rt5 == fibonacci(10)
+            True
+            sage: (phi^50 - tau^50) / rt5 == fibonacci(50)
+            True
+        """
+        e = QQ._coerce_(e)
+        n = e.numerator()
+        d = e.denominator()
+        if d == 1:
+            if n == 0:
+                # implements 0^0 == 1
+                return AlgebraicRealNumber(1)
+            elif n < 0:
+                return (~self).__pow__(-n)
+            elif n == 1:
+                return self
+            else:
+                pow_n2 = self.__pow__(n//2)
+                if n % 2 == 1:
+                    return pow_n2 * pow_n2 * self
+                else:
+                    return pow_n2 * pow_n2
+        # Without this special case, we don't know the multiplicity
+        # of the desired root
+        if self.sign() == 0:
+            return AlgebriacNumber(0)
+        if d % 2 == 0:
+            if self.sign() < 0:
+                raise ValueError, 'complex algebraics not implemented'
+        pow_n = self**n
+        poly = AAPoly.gen()**d - pow_n
+        range = pow_n.interval_fast(RIF)
+        if d % 2 == 0:
+            result_min = 0
+        else:
+            result_min = min(range.lower(), -1)
+        result_max = max(range.upper(), 1)
+        return AlgebraicRealNumber(AlgebraicRealNumberRoot(poly, RIF(result_min, result_max)))
+
+    def sqrt(self):
+        return self.__pow__(~ZZ(2))
+
+    def nth_root(self, n):
+        return self.__pow__(~ZZ(n))
+
+    def exactify(self):
+        """
+        Compute an exact representation for this number.
+
+        EXAMPLES:
+            sage: two = sqrt(AA(4))            
+            sage: two
+            [1.9999999999999997 .. 2.0000000000000005]
+            sage: two.exactify()
+            sage: two
+            2
+        """
+        od = self._descr
+        self._descr = self._descr.exactify()
+        new_val = self._descr.interval_fast(self.parent().default_interval_field())
+        self._value = self._value.intersection(new_val)
+#         if self._value != self._descr.interval_fast(RIF):
+#             v1 = self._value
+#             v2 = self._descr.interval_fast(RIF)
+#             # print (v1 != v2)
+#             # print v1 - v2
+#             # print v1, v2
+#             # print 'try1', self._descr.interval_fast(RIF), 'done'
+#             global od2
+#             od2 = od
+#             # print 'a', od.interval_fast(RIF), self._value
+#             # print 'b', self._descr.interval_fast(RIF), v2
+#             # print 'try2', self._descr.interval_fast(RIF), 'done'
+#             raise ValueError
+
+    def _exact_field(self):
+        """
+        Returns a generator for a number field that includes this number
+        (not necessarily the smallest such number field).
+
+        EXAMPLES:
+            sage: AA(2)._exact_field()
+            Unit generator
+            sage: (sqrt(AA(2)) + sqrt(AA(19)))._exact_field()
+            Number Field in a with defining polynomial y^4 - 20*y^2 + 81 with a in [3.7893137826710354 .. 3.7893137826710360]
+            sage: (AA(7)^(3/5))._exact_field()
+            Number Field in a with defining polynomial y^5 - 7 with a in [1.4757731615945519 .. 1.4757731615945522]
+        """
+
+        sd = self._descr
+        if sd.is_rational():
+            return unit_generator
+        if sd.is_field_element():
+            return sd.field_parent()
+        self.exactify()
+        return self._exact_field()
+
+    def _exact_value(self):
+        """
+        Returns either an AlgebraicRealNumberRational or an
+        AlgebraicRealNumberExtensionElement representing this value.
+
+        EXAMPLES:
+            sage: AA(2)._exact_value()
+            2
+            sage: (sqrt(AA(2)) + sqrt(AA(19)))._exact_value()
+            1/9*a^3 + a^2 - 11/9*a - 10 where a^4 - 20*a^2 + 81 = 0 and a in [3.7893137826710354 .. 3.7893137826710360]
+            sage: (AA(7)^(3/5))._exact_value()
+            a^3 where a^5 - 7 = 0 and a in [1.4757731615945519 .. 1.4757731615945522]
+        """
+        sd = self._descr
+        if sd.is_exact():
+            return sd
+        self.exactify()
+        return self._exact_value()
+
+    def _more_precision(self):
+        """
+        Recompute the interval bounding this number with higher-precision
+        interval arithmetic.
+
+        EXAMPLES:
+            sage: rt2 = sqrt(AA(2))
+            sage: rt2._value
+            [1.41421356237309504876 .. 1.41421356237309504888]
+            sage: rt2._more_precision()
+            sage: rt2._value
+            [1.414213562373095048801688724209698078568 .. 1.414213562373095048801688724209698078575]
+            sage: rt2._more_precision()
+            sage: rt2._value
+            [1.414213562373095048801688724209698078569671875376948073176679737990732478462101 .. 1.414213562373095048801688724209698078569671875376948073176679737990732478462120]
+        """
+        prec = self._value.prec()
+        field = RealIntervalField(prec * 2)
+        self._value = self._descr.interval_fast(field)
+
+    def sign(self):
+        """
+        Compute the sign of this algebraic number (return -1 if negative,
+        0 if zero, or 1 if positive).
+
+        Computes an interval enclosing this number using 128-bit interval
+        arithmetic; if this interval includes 0, then fall back to
+        exact computation (which can be very slow).
+
+        EXAMPLES:
+            sage: AA(-5).nth_root(7).sign()
+            -1
+            sage: (AA(2).sqrt() - AA(2).sqrt()).sign()
+            0
+        """
+        if self._value.lower() > 0:
+            return 1
+        elif self._value.upper() < 0:
+            return -1
+        elif self._descr.is_rational():
+            val = self._descr.rational_value()
+            if val > 0:
+                return 1
+            elif val < 0:
+                return -1
+            else:
+                return 0
+        elif self._descr.is_field_element():
+            if not self._descr.is_irrational():
+                self._descr = AlgebraicRealNumberRational(self._descr.rational_value())
+                return self.sign()
+            # An irrational number must eventually be different from 0
+            self._more_precision()
+            return self.sign()
+        elif self._value.prec() < 128:
+            # OK, we'll try adding precision one more time
+            # print self._value
+            self._more_precision()
+            return self.sign()
+        else:
+            # Sigh...
+            self.exactify()
+            return self.sign()
+
+    def interval_fast(self, field):
+        """
+        Given a RealIntervalField, compute the value of this number
+        using interval arithmetic of at least the precision of the field,
+        and return the value in that field.  (More precision may be used
+        in the computation.)  The returned interval may be arbitrarily
+        imprecise, if this number is the result of a sufficiently long
+        computation chain.
+
+        EXAMPLES:
+            sage: x = AA(2).sqrt()
+            sage: x.interval_fast(RIF)
+            [1.4142135623730949 .. 1.4142135623730952]
+            sage: x.interval_fast(RealIntervalField(200))
+            [1.4142135623730950488016887242096980785696718753769480731766796 .. 1.4142135623730950488016887242096980785696718753769480731766809]
+            sage: x = AA(4).sqrt()
+            sage: (x-2).interval_fast(RIF)
+            [-1.0842021724855045e-19 .. 2.1684043449710089e-19]
+        """
+        if field.prec() == self._value.prec():
+            return self._value
+        elif field.prec() > self._value.prec():
+            self._more_precision()
+            return self.interval_fast(field)
+        else:
+            return field(self._value)
+
+    def interval_diameter(self, diam):
+        """
+        Compute an interval representation of self with diameter() at
+        most diam.  The precision of the returned value is unpredictable.
+
+        EXAMPLES:
+            sage: AA(2).sqrt().interval_diameter(1e-10)
+            [1.41421356237309504876 .. 1.41421356237309504888]
+            sage: AA(2).sqrt().interval_diameter(1e-30)
+            [1.414213562373095048801688724209698078568 .. 1.414213562373095048801688724209698078575]
+        """
+        if diam <= 0:
+            raise ValueError, 'diameter must be positive in interval_diameter'
+
+        while self._value.diameter() > diam:
+            self._more_precision()
+
+        return self._value
+
+    def interval(self, field):
+        """
+        Given a RealIntervalField of precision p, compute an interval
+        representation of self with diameter() at most 2^-p; then round
+        that representation into the given field.  Here diameter() is
+        relative diameter for intervals not containing 0, and absolute
+        diameter for intervals that do contain 0; thus, if the returned
+        interval does not contain 0, it has at least p-1 good bits.
+
+        EXAMPLES:
+            sage: RIF64 = RealIntervalField(64)
+            sage: x = AA(2).sqrt()
+            sage: y = x*x
+            sage: y = 1000 * y - 999 * y
+            sage: y.interval_fast(RIF64)
+            [1.99999999999999966693 .. 2.00000000000000033307]
+            sage: y.interval(RIF64)
+            [1.99999999999999999989 .. 2.00000000000000000022]
+        """
+        target = RR(1.0) >> field.prec()
+        val = self.interval_diameter(target)
+        return field(val)
+
+    def interval_exact(self, field):
+        """
+        Given a RealIntervalField, compute the best possible
+        approximation of this number in that field.  Note that if this
+        number is sufficiently close to some floating-point number
+        (and, in particular, if this number is exactly representable in
+        floating-point), then this will trigger exact computation, which
+        may be very slow.
+
+        EXAMPLES:
+            sage: x = AA(2).sqrt()
+            sage: y = x*x
+            sage: x.interval(RIF)
+            [1.4142135623730949 .. 1.4142135623730952]
+            sage: x.interval_exact(RIF)
+            [1.4142135623730949 .. 1.4142135623730952]
+            sage: y.interval(RIF)
+            [1.9999999999999997 .. 2.0000000000000005]
+            sage: y.interval_exact(RIF)
+            [2.0000000000000000 .. 2.0000000000000000]
+            sage: z = 1 + AA(2).sqrt() / 2^200
+            sage: z.interval(RIF)
+            [1.0000000000000000 .. 1.0000000000000003]
+            sage: z.interval_exact(RIF)
+            [1.0000000000000000 .. 1.0000000000000003]
+        """
+        for extra in (0, 40):
+            target = RR(1.0) >> field.prec()
+            # p==precise; pr==precise rounded
+            pval = self.interval_diameter(target)
+            pbot = pval.lower()
+            ptop = pval.upper()
+            val = field(pval)
+            bot = val.lower()
+            top = val.upper()
+            prbot = pbot.parent()(bot)
+            prtop = ptop.parent()(top)
+            if bot == top or (bot.nextabove() == top and
+                              prbot < pbot and ptop < prtop):
+                return val
+
+        # Even 40 extra bits of precision aren't enough to prove that
+        # self is not an exactly representable float.
+        self.exactify()
+        while True:
+            # p==precise; pr==precise rounded
+            pval = self._value
+            pbot = pval.lower()
+            ptop = pval.upper()
+            val = field(pval)
+            bot = val.lower()
+            top = val.upper()
+            prbot = pbot.parent()(bot)
+            prtop = ptop.parent()(top)
+            if bot == top or (bot.nextabove() == top and
+                              prbot < pbot and ptop < prtop):
+                return val
+
+            self._more_precision()
+
+    def real(self, field):
+        """
+        Given a RealField, compute a good approximation to self in that field.
+        The approximation will be off by at most two ulp's, except for
+        numbers which are very close to 0, which will have an absolute
+        error at most 2^(-(field.prec()-1)).  Also, the rounding mode of the
+        field is respected.
+
+        EXAMPLES:
+            sage: x = AA(2).sqrt()^2
+            sage: x.real(RR)
+            2.00000000000000
+            sage: x.real(RealField(53, rnd='RNDD'))
+            1.99999999999999
+            sage: x.real(RealField(53, rnd='RNDU'))
+            2.00000000000001
+            sage: x.real(RealField(53, rnd='RNDZ'))
+            1.99999999999999
+            sage: (-x).real(RR)
+            -2.00000000000000
+            sage: (-x).real(RealField(53, rnd='RNDD'))
+            -2.00000000000001
+            sage: (-x).real(RealField(53, rnd='RNDU'))
+            -1.99999999999999
+            sage: (-x).real(RealField(53, rnd='RNDZ'))
+            -1.99999999999999
+            sage: (x-2).real(RR)
+            5.42101086242752e-20
+            sage: (x-2).real(RealField(53, rnd='RNDD'))
+            -1.08420217248551e-19
+            sage: (x-2).real(RealField(53, rnd='RNDU'))
+            2.16840434497101e-19
+            sage: (x-2).real(RealField(53, rnd='RNDZ'))
+            0.000000000000000
+            sage: y = AA(2).sqrt()
+            sage: y.real(RR)
+            1.41421356237309
+            sage: y.real(RealField(53, rnd='RNDD'))
+            1.41421356237309
+            sage: y.real(RealField(53, rnd='RNDU'))
+            1.41421356237310
+            sage: y.real(RealField(53, rnd='RNDZ'))
+            1.41421356237309
+        """
+        v = self.interval(RealIntervalField(field.prec()))
+
+        mode = field.rounding_mode()
+        if mode == 'RNDN':
+            return v.center()
+        if mode == 'RNDD':
+            return v.lower()
+        if mode == 'RNDU':
+            return v.upper()
+        if mode == 'RNDZ':
+            if v > 0:
+                return field(v.lower())
+            elif v < 0:
+                return field(v.upper())
+            else:
+                return field(0)
+
+    def real_exact(self, field):
+        """
+        Given a RealField, compute the best possible approximation of
+        this number in that field.  Note that if this number is sufficiently
+        close to some floating-point number in the field (and, in particular,
+        if this number is exactly representable in the field), then
+        this will trigger exact computation, which may be very slow.
+
+        The rounding mode of the field is respected.
+
+        EXAMPLES:
+            sage: x = AA(2).sqrt()^2
+            sage: x.real_exact(RR)
+            2.00000000000000
+            sage: x.real_exact(RealField(53, rnd='RNDD'))
+            2.00000000000000
+            sage: x.real_exact(RealField(53, rnd='RNDU'))
+            2.00000000000000
+            sage: x.real_exact(RealField(53, rnd='RNDZ'))
+            2.00000000000000
+            sage: (-x).real_exact(RR)
+            -2.00000000000000
+            sage: (-x).real_exact(RealField(53, rnd='RNDD'))
+            -2.00000000000000
+            sage: (-x).real_exact(RealField(53, rnd='RNDU'))
+            -2.00000000000000
+            sage: (-x).real_exact(RealField(53, rnd='RNDZ'))
+            -2.00000000000000
+            sage: (x-2).real_exact(RR)
+            0.000000000000000
+            sage: (x-2).real_exact(RealField(53, rnd='RNDD'))
+            0.000000000000000
+            sage: (x-2).real_exact(RealField(53, rnd='RNDU'))
+            0.000000000000000
+            sage: (x-2).real_exact(RealField(53, rnd='RNDZ'))
+            0.000000000000000
+            sage: y = AA(2).sqrt()
+            sage: y.real_exact(RR)
+            1.41421356237310
+            sage: y.real_exact(RealField(53, rnd='RNDD'))
+            1.41421356237309
+            sage: y.real_exact(RealField(53, rnd='RNDU'))
+            1.41421356237310
+            sage: y.real_exact(RealField(53, rnd='RNDZ'))
+            1.41421356237309
+        """
+        for extra in (0, 40):
+            target = RR(1.0) >> field.prec()
+            val = self.interval_diameter(target)
+            fbot = field(val.lower())
+            ftop = field(val.upper())
+            if fbot == ftop:
+                return ftop
+
+        # Even 40 extra bits of precision aren't enough to determine the
+        # answer.
+        rifp1 = RealIntervalField(field.prec() + 1)
+        rifp2 = RealIntervalField(field.prec() + 2)
+
+        val = self.interval_exact(rifp1)
+
+        # Call the largest floating-point number <= self 'x'.  Then
+        # val may be [x .. x], [x .. x + 1/2 ulp],
+        # [x + 1/2 ulp .. x + 1/2 ulp], or [x + 1/2 ulp .. x + 1 ulp];
+        # in the second and fourth cases, the true value is not equal
+        # to either of the interval endpoints.
+
+        mid = rifp2(val).center()
+
+        # Now mid may be x, x + 1/4 ulp, x + 1/2 ulp, or x + 3/4 ulp; in
+        # the first and third cases, mid is the exact, true value of self;
+        # in the second and fourth cases, self is close to mid, and is
+        # neither x, x + 1/2 ulp, nor x + 1 ulp.
+
+        # In all of these cases, in all rounding modes, the rounded value
+        # of mid is the same as the rounded value of self.
+
+        return field(mid)
+
+def is_AlgebraicRealNumber(x):
+    return isinstance(x, AlgebraicRealNumber)
+
+AAPoly = PolynomialRing(AA, 'x')
+
+class AlgebraicPolynomialTracker(SageObject):
+    """
+    Keeps track of a polynomial used for algebraic numbers.
+
+    If multiple algebraic numbers are created as roots of a single
+    polynomial, this allows the polynomial and information about
+    the polynomial to be shared.  This reduces work if the polynomial
+    must be recomputed at higher precision, or if it must be made
+    exact.
+
+    This class is private, and should only be constructed by
+    AlgebraicRealField.common_polynomial(), and should only be used as
+    an argument to AlgebraicRealField.polynomial_root().
+
+    EXAMPLES:
+        sage: x = polygen(AA)
+        sage: P = AA.common_polynomial(x^2 - x - 1)
+        sage: P
+        x^2 - x - 1
+        sage: AA.polynomial_root(P, RIF(0, 2))
+        [1.6180339887498946 .. 1.6180339887498950]
+    """
+
+    def __init__(self, poly):
+        poly = AAPoly._coerce_(poly)
+        self._poly = poly
+        self._exact = False
+
+    def _repr_(self):
+        return repr(self._poly)
+
+    def poly(self):
+        return self._poly
+
+    def exactify(self):
+        """
+        Compute a common field that holds all of the algebraic coefficients
+        of this polynomial, then factor the polynomial over that field.
+        Store the factors for later use (ignoring multiplicity).
+        """
+        if self._exact:
+            return
+
+        self._exact = True
+
+        gen = unit_generator
+
+        for c in self._poly.list():
+            c.exactify()
+            gen = gen.union(c._exact_field())
+
+        self._gen = gen
+
+        coeffs = [gen(c._exact_value()) for c in self._poly.list()]
+
+        if gen.is_unit():
+            qp = QQy(coeffs)
+            self._factors = [fac_exp[0] for fac_exp in qp.factor()]
+        else:
+            fld = gen.field()
+            fld_poly = fld['x']
+
+            fp = fld_poly(coeffs)
+
+            self._factors = [fac_exp[0] for fac_exp in fp.factor()]
+
+    def factors(self):
+        self.exactify()
+        return self._factors
+
+    def generator(self):
+        self.exactify()
+        return self._gen
+
+class AlgebraicRealNumberRoot(AlgebraicRealNumberDescr):
+    """
+    The subclass of AlgebraicRealNumberDescr that represents a particular
+    root of a polynomial with algebraic coefficients.
+    This class is private, and should not be used directly.
+    """
+    def __init__(self, poly, interval, multiplicity=1):
+        if not isinstance(poly, AlgebraicPolynomialTracker):
+            poly = AlgebraicPolynomialTracker(poly)
+        self._poly = poly
+        # Rethink precision control...integer bitcounts vs.
+        # RealIntervalField values
+        self._multiplicity = multiplicity
+        self._interval = self.refine_interval(interval, 64)
+        
+    def _repr_(self):
+        return 'Root %s of %s'%(self._interval, self._poly)
+
+    def refine_interval(self, interval, precision):
+        """
+        Takes an interval which is assumed to enclose exactly one root
+        of the polynomial (or, with multiplicity=k, exactly one root
+        of the k-1'th derivative); and a precision, in bits.
+
+        Tries to find a narrow interval enclosing the root using
+        interval arithmetic of the given precision.  (No particular
+        number of resulting bits of precision is guaranteed.)
+
+        Uses a combination of Newton's method (adapted for interval
+        arithmetic) and bisection.  The algorithm will converge very
+        quickly if started with a sufficiently narrow interval.
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import AlgebraicRealNumberRoot
+            sage: x = polygen(AA)
+            sage: rt2 = AlgebraicRealNumberRoot(x^2 - 2, RIF(0, 2))
+            sage: rt2.refine_interval(RIF(0, 2), 75)
+            [1.41421356237309504880163 .. 1.41421356237309504880175]
+        """
+        p = self._poly.poly()
+        dp = p.derivative()
+        for i in xrange(0, self._multiplicity - 1):
+            p = dp
+            dp = p.derivative()
+
+        # Don't throw away bits in the original interval; doing so might
+        # invalidate it (include an extra root)
+        field = RealIntervalField(max(precision, interval.prec()))
+        zero = field(0)
+        interval = field(interval)
+        poly_ring = field['x']
+
+        # XXX Once this is properly integrated into SAGE,
+        # then the following should be replaced with:
+        # interval_p = poly_ring(p)
+        # (and similarly for interval_dp)
+        coeffs = [c.interval_fast(field) for c in p.list()]
+        interval_p = poly_ring(coeffs)
+
+        # This special case is important: this is the only way we could
+        # refine "infinitely deep" (we could get an interval of diameter
+        # about 2^{-2^31}, and then hit floating-point underflow); avoiding
+        # this case here means we don't have to worry about iterating too 
+        # many times later
+        if coeffs[0] == zero and zero in interval:
+            return zero
+
+        dcoeffs = [c.interval_fast(field) for c in dp.list()]
+        interval_dp = poly_ring(dcoeffs)
+        
+        linfo = {}
+        uinfo = {}
+
+        # print coeffs
+        # print p
+
+        def update_info(info, x):
+            info['endpoint'] = x
+            val = interval_p(field(x))
+            info['value'] = val
+            # sign == 1 if val is bounded greater than 0
+            # sign == -1 if val is bounded less than 0
+            # sign == 0 if val might be 0
+            if val > zero:
+                info['sign'] = 1
+            elif val < zero:
+                info['sign'] = -1
+            else:
+                info['sign'] = 0
+
+        update_info(linfo, interval.lower())
+        update_info(uinfo, interval.upper())
+
+        newton_lower = True
+
+        while True:
+            if linfo['sign'] == 0 and uinfo['sign'] == 0:
+                # We take it on faith that there is a root in interval,
+                # even though we can't prove it at the current precision.
+                # We can't do any more refining...
+                return interval
+
+            # print interval
+
+            if linfo['sign'] == uinfo['sign']:
+                # Oops...
+                print self._poly.poly()
+                print interval_p
+                print linfo['endpoint'], linfo['value'], linfo['sign']
+                print uinfo['endpoint'], uinfo['value'], uinfo['sign']
+                raise ValueError, "Refining interval that does not bound unique root!"
+
+            # Use a simple algorithm:
+            # Try an interval Newton-Raphson step.  If this does not add at
+            # least one bit of information, or if it fails (because the
+            # slope is not bounded away from zero), then try bisection.
+            # If this fails because the value at the midpoint is not
+            # bounded away from zero, then also try the 1/4 and 3/4 points.
+            # If all of these fail, then return the current interval.
+
+            slope = interval_dp(interval)
+
+            newton_success = False
+            diam = interval.diameter()
+
+            if not (zero in slope):
+                # OK, we try Newton-Raphson.
+                # I have no idea if it helps, but each time through the loop,
+                # we either do Newton-Raphson from the left endpoint or
+                # the right endpoint, alternating.
+
+                newton_lower = not newton_lower
+                if newton_lower:
+                    new_range = linfo['endpoint'] - linfo['value'] / slope
+                else:
+                    new_range = uinfo['endpoint'] - uinfo['value'] / slope
+
+                if new_range.lower() in interval:
+                    interval = field(new_range.lower(), interval.upper())
+                    update_info(linfo, interval.lower())
+                if new_range.upper() in interval:
+                    interval = field(interval.lower(), new_range.upper())
+                    update_info(uinfo, interval.upper())
+
+                new_diam = interval.diameter()
+
+                if new_diam == 0:
+                    # Wow, we managed to find the answer exactly.
+                    # (I think this can only happen with a linear polynomial,
+                    # in which case we shouldn't have been in this
+                    # function at all; but oh well.)
+                    return interval
+
+                if (new_diam << 1) <= diam:
+                    # We got at least one bit.
+                    newton_success = True
+
+            if not newton_success:
+                center = interval.center()
+
+                def try_bisection(mid):
+                    minfo = {}
+                    update_info(minfo, mid)
+                    if minfo['sign'] == 0:
+                        return interval, False
+                    # We check to make sure the new interval is actually
+                    # narrower; this might not be true if the interval
+                    # is less than 4 ulp's wide
+                    if minfo['sign'] == linfo['sign'] and mid > interval.lower():
+                        linfo['endpoint'] = minfo['endpoint']
+                        linfo['value'] = minfo['value']
+                        linfo['sign'] = minfo['sign']
+                        return field(mid, interval.upper()), True
+                    if minfo['sign'] == uinfo['sign'] and mid < interval.upper():
+                        uinfo['endpoint'] = minfo['endpoint']
+                        uinfo['value'] = minfo['value']
+                        uinfo['sign'] = minfo['sign']
+                        return field(interval.lower(), mid), True
+                    return interval, False
+
+                interval, bisect_success = try_bisection(center)
+
+                if not bisect_success:
+                    uq = (center + interval.upper()) / 2
+                    interval, bisect_success = try_bisection(uq)
+                if not bisect_success:
+                    lq = (center + interval.lower()) / 2
+                    interval, bisect_success = try_bisection(lq)
+
+                if not bisect_success:
+                    # OK, we've refined about as much as we can.
+                    # (We might be able to trim a little more off the edges,
+                    # but the interval is no more than twice as wide as the
+                    # narrowest possible.)
+                    return interval
+        
+
+    def exactify(self):
+        """
+        Returns either an AlgebraicRealNumberRational or an
+        AlgebraicRealNumberExtensionElement with the same value as this number.
+
+        EXAMPLES:
+            sage: from sage.rings.algebraic_real import AlgebraicRealNumberRoot
+            sage: x = polygen(AA)
+            sage: two = AlgebraicRealNumberRoot((x-2)*(x-sqrt(AA(2))), RIF(1.5, 3))
+            sage: two.exactify()
+            2 where a^2 - 2 = 0 and a in [1.4142135623730949 .. 1.4142135623730952]
+            sage: two.exactify().rational_value()
+            2
+            sage: strange = AlgebraicRealNumberRoot(x^2 + sqrt(AA(3))*x - sqrt(AA(2)), RIF(-1, 3))
+            sage: strange.exactify()
+            a where a^8 - 6*a^6 + 5*a^4 - 12*a^2 + 4 = 0 and a in [0.60510122651395104 .. 0.60510122651395116]
+        """
+        gen = self._poly.generator()
+
+        if gen.is_unit():
+            qpf = self._poly.factors()
+            def find_fn(factor, rif):
+                return factor(self.interval_fast(rif))
+            my_factor = find_zero_result(find_fn, qpf)
+
+            # Factoring always returns monic polynomials over the rationals
+            assert(my_factor.is_monic())
+
+            if my_factor.degree() == 1:
+                return AlgebraicRealNumberRational(-my_factor[0])
+
+            den, my_factor = clear_denominators(my_factor)
+
+            red_elt, red_back, red_pol = do_polred(my_factor)
+
+            field = NumberField(red_pol, 'a', check=False)
+            
+            def intv_fn(rif):
+                return red_elt(self.interval_fast(rif) * den)
+            new_intv = isolating_interval(intv_fn, red_pol)
+            root = AlgebraicRealNumberRoot(AAPoly(red_pol), new_intv)
+            new_gen = AlgebraicGenerator(field, root)
+            
+            return AlgebraicRealNumberExtensionElement(new_gen, red_back(field.gen())/den)
+        else:
+            fld = gen.field()
+
+            fpf = self._poly.factors()
+            # print fpf
+            def find_fn(factor, rif):
+                rif_poly = rif['x']
+                gen_val = gen.interval_fast(rif)
+                self_val = self.interval_fast(rif)
+                ip = rif_poly([c.polynomial()(gen_val) for c in factor])
+                return ip(self_val)
+            my_factor = find_zero_result(find_fn, fpf)
+
+            # print my_factor
+            assert(my_factor.is_monic())
+
+            if my_factor.degree() == 1:
+                return AlgebraicRealNumberExtensionElement(gen, -my_factor[0])
+
+            # rnfequation needs a monic polynomial with integral coefficients.
+            # We achieve this with a change of variables.
+
+            den, my_factor = clear_denominators(my_factor)
+
+            pari_nf = gen.field().pari_nf()
+            # print pari_nf[0]
+            x, y = QQxy.gens()
+            my_factor = QQxy['z']([c.polynomial()(y) for c in my_factor])(x)
+            # print my_factor
+
+            # XXX much duplicate code with AlgebraicGenerator.union()
+
+            # XXX need more caching here
+            newpol, self_pol, k = pari_nf.rnfequation(my_factor, 1)
+            k = int(k)
+            # print newpol
+            # print self_pol
+            # print k
+
+            newpol_sage = QQx(newpol)
+            newpol_sage_y = QQy(newpol_sage)
+
+            red_elt, red_back, red_pol = do_polred(newpol_sage_y)
+
+            new_nf = NumberField(red_pol, name='a', check=False)
+            
+            self_pol_sage = QQx(self_pol.lift())
+
+            new_nf_a = new_nf.gen()
+            
+            def intv_fn(rif):
+                return red_elt(gen.interval_fast(rif) * k + self.interval_fast(rif) * den)
+            new_intv = isolating_interval(intv_fn, red_pol)
+
+            root = AlgebraicRealNumberRoot(QQx(red_pol), new_intv)
+            new_gen = AlgebraicGenerator(new_nf, root)
+            red_back_a = red_back(new_nf.gen())
+            new_poly = ((QQx_x - k * self_pol_sage)(red_back_a)/den)
+            return AlgebraicRealNumberExtensionElement(new_gen, new_poly)
+        
+    def _more_precision(self):
+        """
+        Recompute the interval enclosing this root at higher
+        precision.
+        """
+        prec = self._interval.prec()
+        self._interval = self.refine_interval(self._interval, prec*2)
+
+    def interval_fast(self, field):
+        """
+        Given a RealIntervalField, compute the value of this number
+        using interval arithmetic of at least the precision of the field,
+        and return the value in that field.  (More precision may be used
+        in the computation.)
+        """
+        if field.prec() == self._interval.prec():
+            return self._interval
+        if field.prec() < self._interval.prec():
+            return field(self._interval)
+        self._more_precision()
+        return self.interval_fast(field)
+
+unit_generator = AlgebraicGenerator(None, AlgebraicRealNumberRoot(AAPoly.gen() - 1, RIF(1)))
+
+class AlgebraicRealNumberExtensionElement(AlgebraicRealNumberDescr):
+    """
+    The subclass of AlgebraicRealNumberDescr that represents a number field
+    element in terms of a specific generator.  Consists of a polynomial
+    with rational coefficients in terms of the generator, and the
+    generator itself, an AlgebraicGenerator.
+    """
+
+    # XXX Should override __new__, and return an AlgebraicRealNumberRational
+    # if the value is rational.
+
+    def __init__(self, generator, value):
+        self._generator = generator
+        self._value = value
+    
+    def _repr_(self):
+        return '%s where %s = 0 and a in %s'%(self._value,
+                                              self._generator.field().polynomial()._repr(name='a'),
+                                              self._generator.interval_fast(RIF))
+
+    def generator(self):
+        return self._generator
+
+    def is_exact(self):
+        return True
+
+    def is_field_element(self):
+        return True
+
+    def field_parent(self):
+        return self._generator
+
+    def exactify(self):
+        return self
+
+    def rational_value(self):
+        poly = self._value.polynomial()
+        assert(poly.is_constant())
+        return poly[0]
+
+    def is_irrational(self):
+        return self._value.polynomial().degree() >= 1
+
+    def field_element_value(self):
+        return self._value
+
+    def interval_fast(self, field):
+        gen_val = self._generator.interval_fast(field)
+        # XXX Coercion to field() below is necessary in case this is
+        # a constant polynomial (that is, this is a rational number).
+        # If we maintain the invariant that AlgebraicRealNumberExtensionElement
+        # values are never rational, then the coercion is redundant.
+        return field(self._value.polynomial()(gen_val))
+
+ax = AAPoly.gen()
+# def heptadecagon():
+#     # Compute the exact (x,y) coordinates of the vertices of a 34-gon.
+#     # (Take every other coordinate to get the vertices of a
+#     # heptadecagon.)
+#     # Formulas from:
+#     # Weisstein, Eric W. "Trigonometry Angles--Pi/17." From 
+#     # MathWorld--A Wolfram Web Resource. 
+#     # http://mathworld.wolfram.com/TrigonometryAnglesPi17.html 
+
+#     rt17 = AA(17).sqrt()
+#     rt2 = AA(2).sqrt()
+#     eps = (17 + rt17).sqrt()
+#     epss = (17 - rt17).sqrt()
+#     delta = rt17 - 1
+#     alpha = (34 + 6*rt17 + rt2*delta*epss - 8*rt2*eps).sqrt()
+#     beta = 2*(17 + 3*rt17 - 2*rt2*eps - rt2*epss).sqrt()
+#     x = rt2*(15 + rt17 + rt2*(alpha + epss)).sqrt()/8
+#     y = rt2*(epss**2 - rt2*(alpha + epss)).sqrt()/8
+
+#     cx, cy = 1, 0
+#     for i in range(34):
+#         cx, cy = x*cx-y*cy, x*cy+y*cx
+#     print cx, cy
+#     print cx.sign(), cy.sign()
+#     print "Yo!"
+#     print (cx-1).sign()
+#     print "OK"
+# # heptadecagon()
+
+# def heptadecagon2():
+#     # Compute the exact (x,y) coordinates of the vertices of a 34-gon.
+#     # (Take every other coordinate to get the vertices of a
+#     # heptadecagon.)
+#     # Formulas from:
+#     # Weisstein, Eric W. "Heptadecagon." From MathWorld--A Wolfram 
+#     # Web Resource. http://mathworld.wolfram.com/Heptadecagon.html 
+
+#     x = AA.polynomial_root(256*ax**8 - 128*ax**7 - 448*ax**6 + 192*ax**5 + 240*ax**4 - 80*ax**3 - 40*ax**2 + 8*ax + 1, RIF(0.9829, 0.983))
+#     y = (1-x**2).sqrt()
+
+#     cx, cy = 1, 0
+#     for i in range(34):
+#         cx, cy = x*cx-y*cy, x*cy+y*cx
+#     print cx, cy
+#     print cx.sign(), cy.sign()
+#     print (cx-1).sign()
+#     return x, y
+# # heptadecagon2()   
Index: sage/rings/all.py
===================================================================
--- sage/rings/all.py	(revision 3543)
+++ sage/rings/all.py	(revision 4255)
@@ -88,5 +88,10 @@
 
 # Quad double
-#from real_qdrf import RealQuadDoubleField, RQDF
+from real_rqdf import RealQuadDoubleField, RQDF, QuadDoubleElement
+
+# Algebraic reals (the intersection of the algebraic closure of the rationals
+# with the reals)
+from algebraic_real import (AlgebraicRealField, is_AlgebraicRealField, AA,
+                            AlgebraicRealNumber, is_AlgebraicRealNumber)
 
 # Intervals
@@ -116,5 +121,5 @@
 # Laurent series ring in one variable
 from laurent_series_ring import LaurentSeriesRing, is_LaurentSeriesRing
-from laurent_series_ring_element import LaurentSeries
+from laurent_series_ring_element import LaurentSeries, is_LaurentSeries
 
 # Float interval arithmetic
Index: sage/rings/arith.py
===================================================================
--- sage/rings/arith.py	(revision 3926)
+++ sage/rings/arith.py	(revision 4254)
@@ -62,5 +62,5 @@
 
     This example involves a complex number.
-        sage: z = (1/2)*(1 + sqrt(3) *CC.0); z
+        sage: z = (1/2)*(1 + RDF(sqrt(3)) *CC.0); z
         0.500000000000000 + 0.866025403784439*I
         sage: p = algdep(z, 6); p
@@ -422,7 +422,8 @@
 def is_prime_power(n, flag=0):
     r"""
-    Returns True if $x$ is a prime power, and False otherwise.  The result
-    is proven correct -- {\em this is NOT a pseudo-primality test!}.
-    
+    Returns True if $x$ is a prime power, and False otherwise.
+    The result is proven correct -- {\em this is NOT a
+    pseudo-primality test!}.
+
     INPUT:
         n -- an integer
@@ -432,8 +433,4 @@
                 2: certify primality using the APRCL test.
 
-    OUTPUT:
-        bool -- True or False
-
-    IMPLEMENTATION: Calls the PARI isprime and ispower functions.
 
     EXAMPLES::
@@ -454,15 +451,5 @@
     """
     Z = integer_ring.ZZ
-    n = Z(n)
-    if n == 1:
-        return True
-    if n < 1:
-        return False
-    if is_prime(n, flag):
-        return True
-    k, g = pari(n).ispower()
-    if not k:
-        return False
-    return g.isprime(flag)
+    return Z(n).is_prime_power(flag=flag)
 
 def valuation(m, p):
@@ -555,7 +542,7 @@
     """
     if stop is None:
-        start, stop = 2, start
+        start, stop = 2, int(start)
     try:
-        v = pari.primes_up_to_n(stop-1)
+        v = pari.primes_up_to_n(int(stop-1))
     except OverflowError:
         return list(primes(start, stop))  # lame but works.
@@ -567,5 +554,5 @@
     if start <= 2:
         return [Z(p) for p in v]     # this dominates runtime!
-    start = pari(start)
+    start = pari(int(start))
     return [Z(p) for p in v if p >= start]     # this dominates runtime!
 
@@ -1224,5 +1211,5 @@
         1/8
     """
-    if a == one:
+    if bool(a == one):
         return a
     if m < 0:
@@ -1483,5 +1470,5 @@
 # primes at most a given limit.
 
-def factor(n, proof=True, int_=False, algorithm='pari', verbose=0):
+def factor(n, proof=True, int_=False, algorithm='pari', verbose=0, **kwds):
     """
     Returns the factorization of the integer n as a sorted list of
@@ -1536,5 +1523,5 @@
     if not isinstance(n, (int,long, integer.Integer)):
         try:
-            return n.factor()
+            return n.factor(**kwds)
         except AttributeError:
             raise TypeError, "unable to factor n"
@@ -2260,5 +2247,5 @@
         [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1]
         sage: continued_fraction_list(sqrt(4/19))
-        [0, 2, 5, 1, 1, 2, 1, 16, 1, 2, 1, 1, 5, 4, 5, 1, 1, 2, 1, 15, 2]
+        [0, 2, 5, 1, 1, 2, 1, 16, 1, 2, 1, 1, 5, 4, 5, 1, 1, 2, 1, 18]
         sage: continued_fraction_list(RR(pi), partial_convergents=True)
         ([3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 3],
@@ -2284,6 +2271,21 @@
         [2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10, 1, 1, 12, 1, 1, 14, 1, 1, 16, 1, 1, 18, 1, 1, 20, 1, 1, 22, 1, 1, 24, 1, 1, 26, 1, 1, 28, 1, 1, 30, 1, 1, 32, 1, 1, 34, 1, 1, 36, 1, 1, 38, 1, 1]
     """
+    import sage.calculus.calculus
+    import sage.functions.constants
+    # if x is a SymbolicExpression, try coercing it to a real number
     if not bits is None:
-        x = sage.rings.real_mpfr.RealField(bits)(x)
+        try:
+            x = sage.rings.real_mpfr.RealField(bits)(x)
+        except  TypeError:
+            raise TypeError, "can only find the continued fraction of a number"
+    elif isinstance(x, float):
+        from real_double import RDF
+        x = RDF(x)
+    elif isinstance(x, (sage.calculus.calculus.SymbolicExpression,
+                        sage.functions.constants.Constant)):
+        try:
+            x = sage.rings.real_mpfr.RealField(53)(x)
+        except TypeError:
+            raise TypeError, "can only find the continued fraction of a number"
     elif not partial_convergents and \
            isinstance(x, (integer.Integer, sage.rings.rational.Rational,
@@ -2615,7 +2617,9 @@
         0.652965496420167 + 0.343065839816545*I
         sage: falling_factorial(1+I, 4)
-        2.00000000000000 + 4.00000000000000*I
+        (I - 2)*(I - 1)*I*(I + 1)
+        sage: expand(falling_factorial(1+I, 4))
+        4*I + 2
         sage: falling_factorial(I, 4)
-        -10.0000000000000
+        (I - 3)*(I - 2)*(I - 1)*I
 
         sage: M = MatrixSpace(ZZ, 4, 4)
@@ -2676,10 +2680,12 @@
         0.266816390637832 + 0.122783354006372*I
     
-        sage: rising_factorial(I, 4)
-        -10.0000000000000
+        sage: a = rising_factorial(I, 4); a
+        I*(I + 1)*(I + 2)*(I + 3)
+        sage: expand(a)
+        -10
     
     See falling_factorial(I, 4).
     
-        sage: R = ZZ['x']
+        sage: x = polygen(ZZ)
         sage: rising_factorial(x, 4)
         x^4 + 6*x^3 + 11*x^2 + 6*x 
@@ -2696,7 +2702,11 @@
 
 
-def ceil(x):
+def integer_ceil(x):
     """
     Return the ceiling of x.
+
+    EXAMPLES:
+        sage: integer_ceil(5.4)
+        6
     """
     try: 
@@ -2707,9 +2717,7 @@
         except TypeError:
             pass
-    raise NotImplementedError, "computation of floor of %s not implemented"%x
-
-ceiling = ceil
-
-def floor(x):
+    raise NotImplementedError, "computation of floor of %s not implemented"%repr(x)
+
+def integer_floor(x):
     r"""
     Return the largest integer $\leq x$.
@@ -2722,11 +2730,11 @@
 
     EXAMPLES:
-        sage: floor(5.4)
+        sage: integer_floor(5.4)
         5
-        sage: floor(float(5.4))
+        sage: integer_floor(float(5.4))
         5
-        sage: floor(-5/2)
+        sage: integer_floor(-5/2)
         -3
-        sage: floor(RDF(-5/2))
+        sage: integer_floor(RDF(-5/2))
         -3
     """
Index: sage/rings/complex_double.pyx
===================================================================
--- sage/rings/complex_double.pyx	(revision 3710)
+++ sage/rings/complex_double.pyx	(revision 4258)
@@ -82,4 +82,8 @@
 CC = complex_field.ComplexField()
 
+import real_mpfr
+RR = real_mpfr.RealField()
+
+from real_double import RealDoubleElement
 
 # PREC is the precision (in decimal digits) that all PARI computations with doubles
@@ -96,4 +100,7 @@
 
 from sage.structure.parent_gens import ParentWithGens
+
+def is_ComplexDoubleField(x):
+    return bool(PY_TYPE_CHECK(x, ComplexDoubleField_class))
 
 cdef class ComplexDoubleField_class(sage.rings.ring.Field):
@@ -229,4 +236,6 @@
                 else:
                     return t
+            elif hasattr(x, '_complex_double_'):
+                return x._complex_double_(self)
             else:
                 return ComplexDoubleElement(x, 0)
@@ -252,26 +261,12 @@
             3.4
 
-        Symbolic constants canonically coerce into the complex double field,
-        but CDF does not canonically coerce to symbolic constants:
-            sage: CDF._coerce_(pi)
-            3.14159265359
-            sage: R = parent(pi)
-            sage: R(CDF.0)
-            1.0*I
-            sage: R._coerce_(CDF.0)
-            Traceback (most recent call last):
-            ...
-            TypeError: no canonical coercion of element into self.
-
-        Thus the sum of a CDF and a symbolic constant is in CDF:
+        Thus the sum of a CDF and a symbolic object is symbolic:
             sage: a = pi + CDF.0; a
-            3.14159265359 + 1.0*I
+            1.00000000000000*I + pi
             sage: parent(a)
-            Complex Double Field        
-        """
-        import sage.functions.constants
+            Symbolic Ring
+        """
         return self._coerce_try(x, [self.real_double_field(),
-                                    sage.functions.constants.ConstantRing,
-                                    CC])
+                                    CC, RR])
 
 
@@ -661,11 +656,11 @@
             0.0
             sage: CDF(0,1).arg()
-            1.5707963267948966
+            1.57079632679
             sage: CDF(0,-1).arg()
-            -1.5707963267948966
+            -1.57079632679
             sage: CDF(-1,0).arg()
-            3.1415926535897931        
-        """
-        return gsl_complex_arg(self._complex)
+            3.14159265359
+        """
+        return RealDoubleElement(gsl_complex_arg(self._complex))
 
     def __abs__(self):
@@ -675,5 +670,5 @@
         EXAMPLES:
             sage: abs(CDF(1,2))
-            2.2360679774997898
+            2.2360679775
             sage: abs(CDF(1,0))
             1.0
@@ -681,5 +676,5 @@
             3.6055512754639891        
         """
-        return gsl_complex_abs(self._complex)
+        return RealDoubleElement(gsl_complex_abs(self._complex))
 
     def abs(self):
@@ -691,5 +686,5 @@
             3.6055512754639891        
         """
-        return gsl_complex_abs(self._complex)
+        return RealDoubleElement(gsl_complex_abs(self._complex))
     
     def abs2(self):
@@ -702,5 +697,5 @@
             13.0        
         """
-        return gsl_complex_abs2(self._complex)
+        return RealDoubleElement(gsl_complex_abs2(self._complex))
 
     def norm(self):
@@ -713,5 +708,5 @@
             13.0        
         """
-        return gsl_complex_abs2(self._complex)
+        return RealDoubleElement(gsl_complex_abs2(self._complex))
 
     def logabs(self):
@@ -725,19 +720,14 @@
 
         EXAMPLES:
-        We try it out. 
             sage: CDF(1.1,0.1).logabs()
-            0.099425429372582669
+            0.0994254293726
             sage: log(abs(CDF(1.1,0.1)))
             0.0994254293726
 
-        Which is better?  
             sage: log(abs(ComplexField(200)(1.1,0.1)))
             0.099425429372582675602989386713555936556752871164033127857198
-
-        Indeed, the logabs, wins.            
-        """
-        return gsl_complex_logabs(self._complex)
-
-    # TODO: real and imag should be elements of RealDoubleField, when that exists. 
+        """
+        return RealDoubleElement(gsl_complex_logabs(self._complex))
+
     def real(self):
         """
@@ -749,5 +739,5 @@
             3.0
         """
-        return self._complex.dat[0]
+        return RealDoubleElement(self._complex.dat[0])
 
     def imag(self):
@@ -760,5 +750,5 @@
             -2.0
         """
-        return self._complex.dat[1]
+        return RealDoubleElement(self._complex.dat[1])
 
     def parent(self):
@@ -779,9 +769,14 @@
     # Elementary Complex Functions
     #######################################################################
-    def sqrt(self):
-        r"""
-        This function returns the square root of the complex number $z$,
-        $\sqrt{z}$. The branch cut is the negative real axis. The result
-        always lies in the right half of the complex plane.
+    def sqrt(self, all=False, **kwds):
+        r"""
+        The square root function.
+        
+        INPUT:
+            all -- bool (default: False); if True, return a list
+                of all square roots.
+
+        If all is False, the branch cut is the negative real axis. The
+        result always lies in the right half of the complex plane.
 
         EXAMPLES:
@@ -798,22 +793,25 @@
             sage: a = CDF(-1)
             sage: a.sqrt()
-            1.0*I            
-        """
-        return self._new_c(gsl_complex_sqrt(self._complex))
-
-    def square_root(self):
-        r"""
-        This function returns the square root of the complex number $z$,
-        $\sqrt{z}$. The branch cut is the negative real axis. The result
-        always lies in the right half of the complex plane.
-
-        EXAMPLES:
-            sage: a = CDF(2,3)
-            sage: b = a.square_root(); b
-            1.67414922804 + 0.89597747613*I
-            sage: b^2
-            2.0 + 3.0*I
-        """
-        return self._new_c(gsl_complex_sqrt(self._complex))
+            1.0*I
+
+        We compute all square roots:
+            sage: CDF(-2).sqrt(all=True)
+            [1.41421356237*I, -1.41421356237*I]
+            sage: CDF(0).sqrt(all=True)
+            [0]
+        """
+        z = self._new_c(gsl_complex_sqrt(self._complex))
+        if all:
+             if z.is_zero():
+                 return [z]
+             else:
+                 return [z, -z]
+        return z
+        
+    def is_square(self):
+        """
+        This function always returns true as $\C$ is algebraically closed. 
+        """
+        return True
 
     def _pow_(self, ComplexDoubleElement a):
@@ -854,5 +852,11 @@
             0.5 + 0.866025403784*I
             sage: a^3                  # slightly random-ish arch dependent output
-            -1.0 + 1.22460635382e-16*I   
+            -1.0 + 1.22460635382e-16*I
+
+        We raise to symbolic powers:
+            sage: CDF(1.2)^x
+            1.20000000000000^x
+            sage: CDF(1.2)^(x^n + n^x)
+            1.20000000000000^(x^n + n^x)
         """
         try:
@@ -863,5 +867,12 @@
         except TypeError:
             # a is not a complex number
-            return z._pow_(CDF(a))
+            try:
+                return z._pow_(CDF(a))
+            except TypeError:
+                try:
+                    return a.parent()(z)**a
+                except AttributeError:
+                    raise TypeError
+                
 
     def exp(self):
@@ -1256,5 +1267,5 @@
             sage: z = CDF(1,1); z.eta()
             0.742048775837 + 0.19883137023*I
-            sage: i = CDF(0,1)
+            sage: i = CDF(0,1); pi = CDF(pi)
             sage: exp(pi * i * z / 12) * prod([1-exp(2*pi*i*n*z) for n in range(1,10)])
             0.742048775837 + 0.19883137023*I
@@ -1264,4 +1275,5 @@
             sage: z.eta(omit_frac=True)
             0.998129069926
+            sage: pi = CDF(pi)
             sage: prod([1-exp(2*pi*i*n*z) for n in range(1,10)])      # slightly random-ish arch dependent output
             0.998129069926 + 4.5908467128e-19*I  
@@ -1345,6 +1357,7 @@
         
         EXAMPLES:
-            sage: (1+I).agm(2-I)
-            1.62780548487271 + 0.136827548397369*I
+            sage: i = CDF(I)
+            sage: (1+i).agm(2-i)
+            1.62780548487 + 0.136827548397*I
         """
         cdef pari_sp sp
@@ -1434,5 +1447,5 @@
         
         EXAMPLE:
-            sage: z = (1/2)*(1 + sqrt(3) *CDF.0); z
+            sage: z = (1/2)*(1 + RDF(sqrt(3)) *CDF.0); z
             0.5 + 0.866025403784*I
             sage: p = z.algdep(5); p
Index: sage/rings/complex_field.py
===================================================================
--- sage/rings/complex_field.py	(revision 3290)
+++ sage/rings/complex_field.py	(revision 4057)
@@ -30,5 +30,5 @@
 
 cache = {}
-def ComplexField(prec=53):
+def ComplexField(prec=53, names=None):
     """
     Return the complex field with real and imaginary parts having prec
@@ -42,4 +42,7 @@
         sage: ComplexField(100).base_ring()
         Real Field with 100 bits of precision
+        sage: i = ComplexField(200).gen()
+        sage: i^2
+        -1.0000000000000000000000000000000000000000000000000000000000
     """
     global cache
@@ -99,4 +102,7 @@
         sage: loads(CC.dumps()) == CC
         True
+        sage: k = ComplexField(100)
+        sage: loads(dumps(k)) == k
+        True
 
     This illustrates basic properties of a complex field.
@@ -121,4 +127,7 @@
         self._prec = int(prec)
         ParentWithGens.__init__(self, self._real_field(), ('I',), False)
+
+    def __reduce__(self):
+        return ComplexField, (self._prec, )
 
     def is_exact(self):
Index: sage/rings/complex_number.pyx
===================================================================
--- sage/rings/complex_number.pyx	(revision 3484)
+++ sage/rings/complex_number.pyx	(revision 4258)
@@ -38,5 +38,5 @@
 
 def is_ComplexNumber(x):
-    return isinstance(x, ComplexNumber)
+    return bool(isinstance(x, ComplexNumber))
 
 cdef class ComplexNumber(sage.structure.element.FieldElement):
@@ -45,6 +45,5 @@
 
     EXAMPLES:
-        sage: C = ComplexField()
-        sage: I = C.0
+        sage: I = CC.0
         sage: b = 1.5 + 2.5*I
         sage: loads(b.dumps()) == b
@@ -117,9 +116,9 @@
 
         EXAMPLES:
-            sage: a = 1+I
+            sage: a = CC(1 + I)
             sage: loads(dumps(a)) == a
             True
         """
-        # TODO: This is potentially very slow -- make a 1 version that
+        # TODO: This is potentially slow -- make a 1 version that
         # is native and much faster -- doesn't use .real()/.imag()
         return (make_ComplexNumber0, (self._parent, self._multiplicative_order, self.real(), self.imag()))
@@ -261,5 +260,5 @@
         """
         EXAMPLES:
-            sage: C, i = ComplexField(20).objgen()
+            sage: C.<i> = ComplexField(20)
             sage: a = i^2; a
             -1.0000
@@ -279,9 +278,17 @@
         if isinstance(right, (int, long, integer.Integer)):
             return sage.rings.ring_element.RingElement.__pow__(self, right)
-        z = self._pari_()
-        P = (<ComplexNumber>self)._parent
-        w = P(right)._pari_()
-        m = z**w
-        return P(m)
+        try:
+            P = self.parent()
+            right = P(right)
+            z = self._pari_()
+            w = P(right)._pari_()
+            m = z**w
+            return P(m)
+        except TypeError:
+            try:
+                self = right.parent()(self)
+                return self**right
+            except AttributeError:
+                raise TypeError
     
     def prec(self):
@@ -348,4 +355,5 @@
 
         EXAMPLES:
+            sage: I = CC.0
             sage: a = ~(5+I)
             sage: a * (5+I)
@@ -416,5 +424,5 @@
 
         EXAMPLES:
-            sage: C, i = ComplexField().objgen()
+            sage: C.<i> = ComplexField()
             sage: i.multiplicative_order()
             4
@@ -429,5 +437,5 @@
             sage: C(2).multiplicative_order()
             +Infinity
-            sage: w = (1+sqrt(-3))/2; w
+            sage: w = (1+sqrt(-3.0))/2; w
             0.500000000000000 + 0.866025403784439*I
             sage: abs(w)
@@ -462,5 +470,5 @@
         """
         EXAMPLES:
-            sage: (1+I).acos()
+            sage: (1+CC(I)).acos()
             0.904556894302381 - 1.06127506190504*I
         """
@@ -470,5 +478,5 @@
         """
         EXAMPLES:
-            sage: (1+I).acosh()
+            sage: (1+CC(I)).acosh()
             1.06127506190504 + 0.904556894302381*I
         """
@@ -478,5 +486,5 @@
         """
         EXAMPLES:
-            sage: (1+I).asin()
+            sage: (1+CC(I)).asin()
             0.666239432492515 + 1.06127506190504*I
         """
@@ -486,5 +494,5 @@
         """
         EXAMPLES:
-            sage: (1+I).asinh()
+            sage: (1+CC(I)).asinh()
             1.06127506190504 + 0.666239432492515*I
         """
@@ -494,5 +502,5 @@
         """
         EXAMPLES:
-            sage: (1+I).atan()
+            sage: (1+CC(I)).atan()
             1.01722196789785 + 0.402359478108525*I
         """
@@ -502,13 +510,38 @@
         """
         EXAMPLES:
-            sage: (1+I).atanh()
+            sage: (1+CC(I)).atanh()
             0.402359478108525 + 1.01722196789785*I
         """
         return self._parent(self._pari_().atanh())
 
+    def coth(self):
+        """
+        EXAMPLES:
+            sage: ComplexField(100)(1,1).coth()
+            0.86801414289592494863584920892 - 0.21762156185440268136513424361*I
+        """
+        return 1/self.tanh()
+
+    def csch(self):
+        """
+        EXAMPLES:
+            sage: ComplexField(100)(1,1).csch()
+            0.30393100162842645033448560451 - 0.62151801717042842123490780586*I
+        """
+        return 1/self.sinh()
+
+    def sech(self):
+        """
+        EXAMPLES:
+            sage: ComplexField(100)(1,1).sech()
+            0.49833703055518678521380589177 - 0.59108384172104504805039169297*I            
+        """
+        return 1/self.cosh()
+    
+
     def cotan(self):
         """
         EXAMPLES:
-            sage: (1+I).cotan()
+            sage: (1+CC(I)).cotan()
             0.217621561854403 - 0.868014142895925*I
             sage: i = ComplexField(200).0
@@ -524,5 +557,5 @@
         """
         EXAMPLES:
-            sage: (1+I).cos()
+            sage: (1+CC(I)).cos()
             0.833730025131149 - 0.988897705762865*I
         """
@@ -532,5 +565,5 @@
         """
         EXAMPLES:
-            sage: (1+I).cosh()
+            sage: (1+CC(I)).cosh()
             0.833730025131149 + 0.988897705762865*I
         """
@@ -568,4 +601,5 @@
             sage: z = 1 + i; z.eta()
             0.742048775836565 + 0.198831370229911*I
+            sage: pi = CC(pi)        # otherwise we will get a symbolic result.
             sage: exp(pi * i * z / 12) * prod([1-exp(2*pi*i*n*z) for n in range(1,10)])
             0.742048775836565 + 0.198831370229911*I
@@ -590,5 +624,5 @@
 
         You can also use functional notation.
-            sage: eta(1+I)
+            sage: eta(1+CC(I))
             0.742048775836565 + 0.198831370229911*I
         """
@@ -602,5 +636,5 @@
         """
         EXAMPLES:
-            sage: (1+I).sin()
+            sage: (1+CC(I)).sin()
             1.29845758141598 + 0.634963914784736*I
         """
@@ -610,5 +644,5 @@
         """
         EXAMPLES:
-            sage: (1+I).sinh()
+            sage: (1+CC(I)).sinh()
             0.634963914784736 + 1.29845758141598*I
         """
@@ -618,5 +652,5 @@
         """
         EXAMPLES:
-            sage: (1+I).tan()
+            sage: (1+CC(I)).tan()
             0.271752585319512 + 1.08392332733869*I
         """
@@ -626,5 +660,5 @@
         """
         EXAMPLES:
-            sage: (1+I).tanh()
+            sage: (1+CC(I)).tanh()
             1.08392332733869 + 0.271752585319512*I
         """
@@ -635,5 +669,5 @@
         """
         EXAMPLES:
-            sage: (1+I).agm(2-I)
+            sage: (1+CC(I)).agm(2-I)
             1.62780548487271 + 0.136827548397369*I
         """
@@ -764,6 +798,12 @@
             return infinity.infinity
     
-    def sqrt(self):
-        """
+    def sqrt(self, all=False, **kwds):
+        """
+        The square root function.
+                
+        INPUT:
+            all -- bool (default: False); if True, return a list
+                of all square roots.
+        
         EXAMPLES:
             sage: C, i = ComplexField(30).objgen()
@@ -778,16 +818,17 @@
             0.70710678118654752440084436210484903928483593768847403658834 + 0.70710678118654752440084436210484903928483593768847403658834*I
         """
-        return self._parent(self._pari_().sqrt())
-
-    def square_root(self):
-        """
-        Return square root, which is a complex number.
-
-        EXAMPLES:
-            sage: i = ComplexField(100).0
-            sage: (-i).sqrt()
-            0.70710678118654752440084436210 - 0.70710678118654752440084436210*I
-        """
-        return self.sqrt()
+        z = self._parent(self._pari_().sqrt())
+        if all:
+            if z.is_zero():
+                return [z]
+            else:
+                return [z, -z]
+        return z
+    
+    def is_square(self):
+        """
+        This function always returns true as $\C$ is algebraically closed. 
+        """
+        return True
 
     def zeta(self):
@@ -816,5 +857,5 @@
         EXAMPLE:
             sage: C = ComplexField()
-            sage: z = (1/2)*(1 + sqrt(3) *C.0); z
+            sage: z = (1/2)*(1 + sqrt(3.0) *C.0); z
             0.500000000000000 + 0.866025403784439*I
             sage: p = z.algdep(5); p
Index: sage/rings/contfrac.py
===================================================================
--- sage/rings/contfrac.py	(revision 3538)
+++ sage/rings/contfrac.py	(revision 4257)
@@ -626,23 +626,14 @@
         return s
 
-    def square_root(self):
-        """
-        Return exact square root or raise an error if self
-        is not a perfect square. 
-        
-        EXAMPLES:
-            sage: a = CFF(4/25).square_root(); a
-            [0, 2, 2]
-            sage: a.value()
-            2/5
-        """
-        return ContinuedFraction(self.parent(),
-                                 self._rational_().square_root())
-
-    def sqrt(self):
-        """
-        Return continued fraction approximation to the
-        square root of the value of this continued fraction, if
-        it is positive.  If self is negative raise a ValueError.
+    def sqrt(self, prec=53, all=False):
+        """
+        Return continued fraction approximation to square root of the
+        value of this continued fraction.
+
+        INPUT:
+            prec -- integer (default: 53) precision of square root
+                    that is approximated
+            all -- bool (default: False); if True, return all square
+                   roots of self, instead of just one.
         
         EXAMPLES:
@@ -655,9 +646,24 @@
             sage: float(b.value()^2 - a)
             4.0935373134057017e-17
+            sage: b = a.sqrt(prec=100); b
+            [0, 2, 5, 1, 1, 2, 1, 16, 1, 2, 1, 1, 5, 4, 5, 1, 1, 2, 1, 16, 1, 2, 1, 1, 5, 4, 5, 1, 1, 2, 1, 16, 1, 2, 1, 1, 5, 5]
+            sage: b^2
+            [0, 4, 1, 3, 49545773063556658177372134479, 1, 3, 4]
+            sage: a.sqrt(all=True)
+            [[0, 2, 5, 1, 1, 2, 1, 16, 1, 2, 1, 1, 5, 4, 5, 1, 1, 2, 1, 15, 2],
+             [-1, 1, 1, 5, 1, 1, 2, 1, 16, 1, 2, 1, 1, 5, 4, 5, 1, 1, 2, 1, 15, 2]]            
+            sage: a = CFF(4/25).sqrt(); a
+            [0, 2, 2]
+            sage: a.value()
+            2/5
         """
         r = self._rational_()
         if r < 0:
             raise ValueError, "self must be positive"
-        return ContinuedFraction(self.parent(), r.sqrt())
+        X = r.sqrt(all=all, prec=prec)
+        if not all:
+            return ContinuedFraction(self.parent(), X)
+        else:
+            return [ContinuedFraction(self.parent(), x) for x in X]
 
     def list(self):
@@ -764,7 +770,7 @@
         return self._rational_().is_one()
 
-    def is_zero(self):
-        """
-        Return True if self is zero.
+    def __nonzero__(self):
+        """
+        Return False if self is zero.
         
         EXAMPLES:
@@ -774,5 +780,5 @@
             False
         """
-        return self._rational_().is_zero()
+        return not self._rational_().is_zero()
 
     def _pari_(self):
Index: sage/rings/cygwinfix.h
===================================================================
--- sage/rings/cygwinfix.h	(revision 4357)
+++ sage/rings/cygwinfix.h	(revision 4357)
@@ -0,0 +1,7 @@
+// cygwinfix.h
+// defines NAN and INFINITY on cygwin
+
+#if defined(__CYGWIN__)
+#define NAN (0.0/0.0)
+#define INFINITY HUGE_VALF
+#endif
Index: sage/rings/finite_field.py
===================================================================
--- sage/rings/finite_field.py	(revision 3125)
+++ sage/rings/finite_field.py	(revision 3991)
@@ -500,4 +500,5 @@
 
         Nonconstant polynomials do not coerce:
+            sage: x = polygen(QQ)
             sage: k(x)
             Traceback (most recent call last):
Index: sage/rings/finite_field_givaro.pyx
===================================================================
--- sage/rings/finite_field_givaro.pyx	(revision 3125)
+++ sage/rings/finite_field_givaro.pyx	(revision 4074)
@@ -762,4 +762,38 @@
         return ret
 
+    def fetch_int(FiniteField_givaro self, int n):
+        r"""
+        Given an integer $n$ return a finite field element in self
+        which equals $n$ under the condition that  self.gen() is set to
+        self.characteristic().
+
+        EXAMPLE:
+            sage: k.<a> = GF(2^8)
+            sage: k.fetch_int(8)
+            a^3
+            sage: e = k.fetch_int(151); e
+            a^7 + a^4 + a^2 + a + 1
+            sage: 2^7 + 2^4 + 2^2 + 2 + 1
+            151
+        """
+        cdef GivaroGfq *k = self.objectptr
+        cdef int ret = k.zero
+        cdef int a = k.sage_generator()
+        cdef int at = k.one
+        cdef unsigned int ch = k.characteristic()
+        cdef int _n, t, i
+
+        if n<0 or n>k.cardinality():
+            raise TypeError, "n must be between 0 and self.order()"
+
+        _n = n
+        
+        for i from 0 <= i < k.exponent():
+            t = k.initi(t, _n%ch)
+            ret = k.axpy(ret, t, at, ret)
+            at = k.mul(at,at,a)
+            _n = _n/ch
+        return make_FiniteField_givaroElement(self, ret)
+
     def polynomial(self):
         """
@@ -1191,7 +1225,7 @@
         return (<FiniteField_givaro>self._parent)
 
-    def is_zero(FiniteField_givaroElement self):
+    def __nonzero__(FiniteField_givaroElement self):
         r"""
-        Return True if \code{self == k(0)}.
+        Return True if \code{self != k(0)}.
 
         EXAMPLES:
@@ -1203,5 +1237,5 @@
             True        
         """
-        return bool((<FiniteField_givaro>self._parent).objectptr.isZero(self.element))
+        return not bool((<FiniteField_givaro>self._parent).objectptr.isZero(self.element))
         
     def is_one(FiniteField_givaroElement self):
@@ -1870,4 +1904,38 @@
         raise ValueError, "must be a perfect square."
 
+    def vector(FiniteField_givaroElement self):
+        """
+        Return a vector in self.parent().vector_space() matching self.
+
+        EXAMPLES:
+            sage: k.<a> = GF(2^4)
+            sage: e = a^2 + 1
+            sage: v = e.vector()
+            sage: v
+            (1, 0, 1, 0)
+            sage: k(v)
+            a^2 + 1
+
+            sage: k.<a> = GF(3^4)
+            sage: e = 2*a^2 + 1
+            sage: v = e.vector()
+            sage: v
+            (1, 0, 2, 0)
+            sage: k(v)
+            2*a^2 + 1
+
+        """
+        cdef FiniteField_givaro k = <FiniteField_givaro>self._parent
+        
+        quo = k.log_to_int(self.element)
+        b   = int(k.characteristic())
+
+        ret = []
+        for i in range(k.degree()):
+            coeff = quo%b
+            ret.append(coeff)
+            quo = quo/b
+        return k.vector_space()(ret)
+
     def __reduce__(FiniteField_givaroElement self):
         """
Index: sage/rings/fraction_field.py
===================================================================
--- sage/rings/fraction_field.py	(revision 2399)
+++ sage/rings/fraction_field.py	(revision 4057)
@@ -4,4 +4,40 @@
 AUTHOR: William Stein (with input from David Joyner, David Kohel, and
         Joe Wetherell)
+
+EXAMPLES:
+Quotienting is a constructor for an element of the fraction field:
+    sage: R.<x> = QQ[]
+    sage: (x^2-1)/(x+1)
+    x - 1
+    sage: parent((x^2-1)/(x+1))
+    Fraction Field of Univariate Polynomial Ring in x over Rational Field
+    
+
+The GCD is not taken (since it doesn't converge sometimes) in the inexact case.
+    sage: Z.<z> = CC[]
+    sage: I = CC.gen()
+    sage: (1+I+z)/(z+0.1*I)
+    (1.00000000000000*z + 1.00000000000000 + 1.00000000000000*I)/(1.00000000000000*z + 0.100000000000000*I)
+    sage: (1+I*z)/(z+1.1)
+    (1.00000000000000*I*z + 1.00000000000000)/(1.00000000000000*z + 1.10000000000000)
+    
+    
+TESTS:
+    sage: F = FractionField(IntegerRing())
+    sage: F == loads(dumps(F))
+    True
+    
+    sage: F = FractionField(PolynomialRing(RationalField(),'x'))
+    sage: F == loads(dumps(F))
+    True
+    
+    sage: F = FractionField(PolynomialRing(IntegerRing(),'x'))
+    sage: F == loads(dumps(F))
+    True
+
+    sage: F = FractionField(MPolynomialRing(RationalField(),2,'x'))
+    sage: F == loads(dumps(F))
+    True
+
 """
 
@@ -159,5 +195,20 @@
             R = self.ring()
             x = R(x); y = R(y)
-        return fraction_field_element.FractionFieldElement(self, x, y, coerce=False)
+        return fraction_field_element.FractionFieldElement(self, x, y,
+                                            coerce=False, reduce = self.is_exact())
+
+    def is_exact(self):
+        """
+        EXAMPLES:
+            sage: Z.<z>=CC[]
+            sage: Z.is_exact()
+            False
+        """
+        try:
+            return self.__is_exact
+        except AttributeError:
+            r = self.ring().is_exact()
+            self.__is_exact = r
+        return r
 
     def _coerce_impl(self, x):
Index: sage/rings/fraction_field_element.py
===================================================================
--- sage/rings/fraction_field_element.py	(revision 2725)
+++ sage/rings/fraction_field_element.py	(revision 4181)
@@ -57,5 +57,5 @@
             self.__numerator = numerator
             self.__denominator = denominator
-        if reduce:
+        if reduce and parent.is_exact():
             try:
                 self.reduce()
Index: sage/rings/groebner_fan.py
===================================================================
--- sage/rings/groebner_fan.py	(revision 2487)
+++ sage/rings/groebner_fan.py	(revision 4077)
@@ -42,4 +42,12 @@
     sage: g.reduced_groebner_bases()
     [[1 - y^2 + x^2], [-1 + y^2 - x^2]]
+
+TESTS:
+    sage: x,y = QQ['x,y'].gens() 
+    sage: i = ideal(x^2 - y^2 + 1)
+    sage: g = i.groebner_fan()
+    sage: g == loads(dumps(g))
+    True
+
 """
 
@@ -97,5 +105,5 @@
             sage: G = I.groebner_fan(); G
             Groebner fan of the ideal:
-            Ideal (y^2*z - x, -1*y + x*z^2, -1*z + x^2*y) of Polynomial Ring in x, y, z over Rational Field
+            Ideal (-1*z + x^2*y, y^2*z - x, -1*y + x*z^2) of Polynomial Ring in x, y, z over Rational Field
         """
         self.__is_groebner_basis = is_groebner_basis
@@ -120,4 +128,7 @@
         self.__ring = S
 
+    def __eq__(self,right):
+        return type(self) == type(right) and self.ideal() == right.ideal()
+
     def ideal(self):
         """
@@ -195,5 +206,5 @@
             sage: G = R.ideal([x^2*y - z, y^2*z - x, z^2*x - y]).groebner_fan()
             sage: G._gfan_ideal()
-            '{-1*b + a*c^2, b^2*c - a, -1*c + a^2*b}'
+            '{-1*c + a^2*b, b^2*c - a, -1*b + a*c^2}'
         """
         try:
Index: sage/rings/homset.py
===================================================================
--- sage/rings/homset.py	(revision 2369)
+++ sage/rings/homset.py	(revision 4057)
@@ -36,4 +36,24 @@
         return "Set of Homomorphisms from %s to %s"%(self.domain(), self.codomain())
 
+    def has_coerce_map_from(self, x):
+        """
+        The default for coercion maps between ring homomorphism
+        spaces is very restrictive (until more implementation work
+        is done).
+        """
+        return (x.domain() == self.domain() and x.codomain() == self.codomain())
+
+    def _coerce_impl(self, x):
+        if not isinstance(x, morphism.RingHomomorphism):
+            raise TypeError
+        if x.parent() is self:
+            return x
+        if x.parent() == self:
+            if isinstance(x, morphism.RingHomomorphism_im_gens):
+                return morphism.RingHomomorphism_im_gens(self, x.im_gens())
+            elif isinstance(x, morphism.RingHomomorphism_cover):
+                return morphism.RingHomomorphism_cover(self)
+        raise TypeError
+
     def __call__(self, im_gens, check=True):
         """
@@ -44,9 +64,20 @@
             ...
             TypeError: images do not define a valid homomorphism
+
+        TESTS:
+            sage: H = Hom(ZZ, QQ)
+            sage: H == loads(dumps(H))
+            True
         """
+        if isinstance(im_gens, (morphism.RingHomomorphism_im_gens,  morphism.RingHomomorphism_cover) ):
+            return self._coerce_impl(im_gens)
         try:
             return morphism.RingHomomorphism_im_gens(self, im_gens, check=check)
         except (NotImplementedError, ValueError), err:
-            raise TypeError, "images do not define a valid homomorphism"
+            try:
+                return self._coerce_impl(im_gens)
+            except TypeError:
+                raise TypeError, "images do not define a valid homomorphism"
+        
 
     def natural_map(self):
@@ -69,6 +100,21 @@
         sage: phi(b)
         a
+
+    TESTS:
+    We test pickling of a homset from a quotient. 
+        sage: R.<x,y> = PolynomialRing(QQ, 2)
+        sage: S.<a,b> = R.quotient(x^2 + y^2)
+        sage: H = S.Hom(R)
+        sage: H == loads(dumps(H))
+        True
+    
+    We test pickling of actual homomorphisms in a quotient:
+        sage: phi = S.hom([b,a])
+        sage: phi == loads(dumps(phi))
+        True
     """
     def __call__(self, im_gens, check=True):
+        if isinstance(im_gens, morphism.RingHomomorphism_from_quotient):
+            return morphism.RingHomomorphism_from_quotient(self, im_gens._phi())
         try:
             pi = self.domain().cover()
@@ -76,5 +122,15 @@
             return morphism.RingHomomorphism_from_quotient(self, phi)
         except (NotImplementedError, ValueError), err:
-            raise TypeError, "images do not define a valid homomorphism"
-    
-    
+            try:
+                return self._coerce_impl(im_gens)
+            except TypeError:
+                raise TypeError, "images do not define a valid homomorphism"
+
+    def _coerce_impl(self, x):
+        if not isinstance(x, morphism.RingHomomorphism_from_quotient):
+            raise TypeError
+        if x.parent() is self:
+            return x
+        if x.parent() == self:
+            return morphism.RingHomomorphism_from_quotient(self, x._phi())
+        raise TypeError
Index: sage/rings/ideal.py
===================================================================
--- sage/rings/ideal.py	(revision 3311)
+++ sage/rings/ideal.py	(revision 4077)
@@ -60,18 +60,15 @@
         sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2])
         sage: I
-        Ideal (x^2 + 1, x^2 + 3*x + 4) of Univariate Polynomial Ring in x over Integer Ring
+        Ideal (x^2 + 3*x + 4, x^2 + 1) of Univariate Polynomial Ring in x over Integer Ring
         sage: Ideal(R, [4 + 3*x + x^2, 1 + x^2])
-        Ideal (x^2 + 1, x^2 + 3*x + 4) of Univariate Polynomial Ring in x over Integer Ring
+        Ideal (x^2 + 3*x + 4, x^2 + 1) of Univariate Polynomial Ring in x over Integer Ring
         sage: Ideal((4 + 3*x + x^2, 1 + x^2))
-        Ideal (x^2 + 1, x^2 + 3*x + 4) of Univariate Polynomial Ring in x over Integer Ring
+        Ideal (x^2 + 3*x + 4, x^2 + 1) of Univariate Polynomial Ring in x over Integer Ring
         
         sage: ideal(x^2-2*x+1, x^2-1)
-        Ideal (x^2 - 2*x + 1, x^2 - 1) of Univariate Polynomial Ring in x over Integer Ring
+        Ideal (x^2 - 1, x^2 - 2*x + 1) of Univariate Polynomial Ring in x over Integer Ring
         sage: ideal([x^2-2*x+1, x^2-1])
-        Ideal (x^2 - 2*x + 1, x^2 - 1) of Univariate Polynomial Ring in x over Integer Ring
-        sage: ideal(x^2-2*x+1, x^2-1)
-        Ideal (x^2 - 2*x + 1, x^2 - 1) of Univariate Polynomial Ring in x over Integer Ring
-        sage: ideal([x^2-2*x+1, x^2-1])
-        Ideal (x^2 - 2*x + 1, x^2 - 1) of Univariate Polynomial Ring in x over Integer Ring
+        Ideal (x^2 - 1, x^2 - 2*x + 1) of Univariate Polynomial Ring in x over Integer Ring
+
 
     This example illustrates how SAGE finds a common ambient ring for the ideal, even though
@@ -80,9 +77,24 @@
         sage: i = ideal(1,t,t^2)
         sage: i
-        Ideal (1, t, t^2) of Univariate Polynomial Ring in t over Integer Ring
+        Ideal (t, 1, t^2) of Univariate Polynomial Ring in t over Integer Ring
         sage: i = ideal(1/2,t,t^2)
         Traceback (most recent call last):
         ...
         TypeError: unable to find common ring into which all ideal generators map        
+
+    TESTS:
+        sage: R, x = PolynomialRing(ZZ, 'x').objgen()
+        sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2])
+        sage: I == loads(dumps(I))
+        True
+
+        sage: I = Ideal(R, [4 + 3*x + x^2, 1 + x^2])
+        sage: I == loads(dumps(I))
+        True
+                
+        sage: I = Ideal((4 + 3*x + x^2, 1 + x^2))
+        sage: I == loads(dumps(I))
+        True
+
     """
     if isinstance(R, Ideal_generic):
@@ -123,5 +135,4 @@
 
     gens = list(set(gens))
-
     if isinstance(R, sage.rings.principal_ideal_domain.PrincipalIdealDomain):
         # Use GCD algorithm to obtain a principal ideal
@@ -130,5 +141,5 @@
             g = R.gcd(g, h)
         return Ideal_pid(R, g)
-        
+
     if len(gens) == 1:
         return Ideal_principal(R, gens[0])
@@ -150,18 +161,5 @@
         if coerce:
             gens = [ring(x) for x in gens]
-        gens = list(set(gens))
-        
-        # Regarding the "important" comment below: Otherwise the
-        # generators will be in a completely random order, given the
-        # code that comes before that line.  A basic design choice in
-        # SAGE is that as much as possible lists of objects (e.g.,
-        # list(R), where R is finite), should not be in a random
-        # order.  Feel free to add this as a comment.  It would be
-        # fine to replace the sort by something else, if it yields the
-        # same answer.  However, I don't think randomizing the orders
-        # of things, e.g., lists of generators, for no reason, is a
-        # good idea in SAGE.  This is another "rule of thumb" for the
-        # programmer's guide.
-        gens.sort()    # important!
+
         self.__gens = tuple(gens)
         MonoidElement.__init__(self, ring.ideal_monoid())
@@ -170,9 +168,13 @@
         return '(%s)'%(', '.join([str(x) for x in self.gens()]))
         
-    def _repr_(self):
+    def __repr__(self):
         return "Ideal %s of %s"%(self._repr_short(), self.ring())
 
     def __cmp__(self, other):
-        return cmp(set(self.gens()), set(other.gens()))
+        S = set(self.gens())
+        T = set(other.gens())
+        if S == T:
+            return 0
+        return cmp(self.gens(), other.gens())
 
     def __contains__(self, x):
@@ -186,6 +188,6 @@
         raise NotImplementedError
 
-    def is_zero(self):
-        return self.gens() == [self.ring()(0)]
+    def __nonzero__(self):
+        return self.gens() != [self.ring()(0)]
 
     def base_ring(self):
@@ -262,5 +264,5 @@
         Ideal_generic.__init__(self, ring, [gen])
 
-    def _repr_(self):
+    def __repr__(self):
         return "Principal ideal (%s) of %s"%(self.gen(), self.ring())
 
Index: sage/rings/ideal_monoid.py
===================================================================
--- sage/rings/ideal_monoid.py	(revision 1851)
+++ sage/rings/ideal_monoid.py	(revision 4019)
@@ -7,4 +7,5 @@
 from sage.structure.parent_gens import ParentWithGens
 import sage.rings.integer_ring
+import ideal
 
 def IdealMonoid(R):
@@ -25,7 +26,13 @@
 
     def __call__(self, x):
+        if isinstance(x, ideal.Ideal_generic):
+            x = x.gens()
         return self.__R.ideal(x)
 
     def _coerce_impl(self, x):
         R = self.__R
-        return R.ideal(R._coerce_(x))
+        if isinstance(x, ideal.Ideal_generic):
+            x = [R._coerce_impl(y) for y in x.gens()]
+            return R.ideal(x)
+        else:
+            return R.ideal(R._coerce_(x))
Index: sage/rings/infinity.py
===================================================================
--- sage/rings/infinity.py	(revision 3335)
+++ sage/rings/infinity.py	(revision 4022)
@@ -116,4 +116,14 @@
     ...
     SignError: cannot add positive finite value to negative finite value
+
+TESTS:
+    sage: P = InfinityRing
+    sage: P == loads(dumps(P))
+    True
+
+    sage: P(2) == loads(dumps(P(2)))
+    True
+
+
 """
 
@@ -261,4 +271,7 @@
     def _repr_(self):
         return "Infinity"
+
+    def _maxima_init_(self):
+        return "inf"
 
     def lcm(self, x):
@@ -468,4 +481,12 @@
         return "-Infinity"
 
+    def _maxima_init_(self):
+        """
+        EXAMPLES:
+            sage: maxima(-oo)
+            minf
+        """
+        return "minf"
+
     def _latex_(self):
         return "-\\infty"
@@ -537,4 +558,12 @@
         return "+Infinity"
 
+    def _maxima_init_(self):
+        """
+        EXAMPLES:
+            sage: maxima(oo)
+            inf
+        """
+        return "inf"
+
     def _latex_(self):
         return "+\\infty"
@@ -597,18 +626,19 @@
 infinity = InfinityRing.gen(0)
 Infinity = infinity
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+minus_infinity = InfinityRing.gen(1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: sage/rings/integer.pyx
===================================================================
--- sage/rings/integer.pyx	(revision 3927)
+++ sage/rings/integer.pyx	(revision 4260)
@@ -13,4 +13,5 @@
     -- Rishikesh (2007-02-25): changed quo_rem so that the rem is positive
     -- David Harvey, Martin Albrecht, Robert Bradshaw (2007-03-01): optimized Integer constructor and pool
+    -- Pablo De Napoli (2007-04-01): multiplicative_order should return +infinity for non zero numbers
     -- Robert Bradshaw (2007-04-12): is_perfect_power, Jacobi symbol (with Kronecker extension)
                                      Convert some methods to use GMP directly rather than pari, Integer() -> PY_NEW(Integer)
@@ -393,5 +394,4 @@
         base.
 
-
         EXAMPLES:
             sage: Integer(2^10).str(2)
@@ -655,8 +655,5 @@
             1
             sage: (-1)^(1/3)
-            Traceback (most recent call last):
-            ...
-            TypeError: exponent (=1/3) must be an integer.
-            Coerce your numbers to real or complex numbers first.
+            -1
 
         The base need not be an integer (it can be a builtin
@@ -676,4 +673,22 @@
             RuntimeError: exponent must be at most 4294967294  # 32-bit
             RuntimeError: exponent must be at most 18446744073709551614 # 64-bit
+
+        We raise 2 to various interesting exponents:
+            sage: 2^x                # symbolic x
+            2^x
+            sage: 2^1.5              # real number
+            2.82842712474619 
+            sage: 2^I                # complex number
+            2^I
+            sage: f = 2^(sin(x)-cos(x)); f
+            2^(sin(x) - cos(x))
+            sage: f(3)
+            2^(sin(3) - cos(3))
+            sage: 2^(x+y+z)
+            2^(z + y + x)
+            sage: 2^(1/2)
+            sqrt(2)
+            sage: 2^(-1/2)
+            1/sqrt(2)
         """
         cdef Integer _n
@@ -690,5 +705,9 @@
             _n = Integer(n)
         except TypeError:
-            raise TypeError, "exponent (=%s) must be an integer.\nCoerce your numbers to real or complex numbers first."%n
+            try:
+                s = n.parent()(self)
+                return s**n
+            except AttributeError:
+                raise TypeError, "exponent (=%s) must be an integer.\nCoerce your numbers to real or complex numbers first."%n
 
         if _n < 0:
@@ -759,5 +778,5 @@
         if n < 1:
             raise ValueError, "n (=%s) must be positive" % n
-        if (self < 0) and not (n & 1):
+        if (mpz_sgn(self.value) < 0) and not (n & 1):
             raise ValueError, "cannot take even root of negative number"
         cdef Integer x
@@ -806,7 +825,7 @@
 
            sage: x = 3^100000
-           sage: log(RR(x), 3)
+           sage: RR(log(RR(x), 3))
            100000.000000000
-           sage: log(RR(x + 100000), 3)
+           sage: RR(log(RR(x + 100000), 3))
            100000.000000000
 
@@ -827,5 +846,5 @@
             raise ValueError, "base of log must be an integer"
         m = _m
-        if self <= 0:
+        if mpz_sgn(self.value) <= 0:
             raise ValueError, "self must be positive"
         if m < 2:
@@ -1067,7 +1086,4 @@
         return mpz_get_pylong(self.value)
 
-    def __nonzero__(self):
-        return not self.is_zero()
-
     def __float__(self):
         return mpz_get_d(self.value)
@@ -1261,5 +1277,5 @@
             6 720        
         """
-        if self < 0:
+        if mpz_sgn(self.value) < 0:
             raise ValueError, "factorial -- self = (%s) must be nonnegative"%self
 
@@ -1318,7 +1334,7 @@
         return bool(mpz_cmp_si(self.value, 1) == 0)
 
-    def is_zero(self):
+    def __nonzero__(self):
         r"""
-        Returns \code{True} if the integers is $0$, otherwise \code{False}.
+        Returns \code{True} if the integers is not $0$, otherwise \code{False}.
 
         EXAMPLES:
@@ -1328,5 +1344,5 @@
             True
         """
-        return bool(mpz_cmp_si(self.value, 0) == 0)
+        return bool(mpz_cmp_si(self.value, 0) != 0)
 
     def is_unit(self):
@@ -1355,5 +1371,44 @@
             False
         """
+        if mpz_sgn(self.value) < 0:
+            return False
         return bool(mpz_perfect_square_p(self.value))
+
+    def is_prime_power(self, flag=0):
+        r"""
+        Returns True if $x$ is a prime power, and False otherwise.
+
+        INPUT:
+            flag (for primality testing) -- int 
+                    0 (default): use a combination of algorithms.
+                    1: certify primality using the Pocklington-Lehmer Test.
+                    2: certify primality using the APRCL test.
+
+        EXAMPLES:
+            sage: (-10).is_prime_power()
+            False
+            sage: (10).is_prime_power()
+            False
+            sage: (64).is_prime_power()
+            True
+            sage: (3^10000).is_prime_power()
+            True
+            sage: (10000).is_prime_power(flag=1)
+            False
+        """
+        if self.is_zero():
+            return False
+        elif self.is_one():
+            return True
+        elif mpz_sgn(self.value) < 0:
+            return False
+        if self.is_prime():
+            return True
+        if not self.is_perfect_power():
+            return False
+        k, g = self._pari_().ispower()
+        if not k:
+            raise RuntimeError, "inconsistent results between GMP and pari"
+        return g.isprime(flag=flag)
 
     def is_prime(self):
@@ -1403,6 +1458,6 @@
         
     def jacobi(self, b):
-        """
-        Calculate the Jacobi symbol $\left(\frac{self,b}\right)$.
+        r"""
+        Calculate the Jacobi symbol $\left(\frac{self}{b}\right)$.
 
         EXAMPLES:
@@ -1439,6 +1494,7 @@
         
     def kronecker(self, b):
-        """
-        Calculate the Jacobi symbol $\left(\frac{self,b}\right)$ with the Kronecker extension 
+        r"""
+        Calculate the Kronecker symbol
+        $\left(\frac{self}{b}\right)$ with the Kronecker extension 
         $(self/2)=(2/self)$ when self odd, or $(self/2)=0$ when $self$ even.
 
@@ -1528,6 +1584,5 @@
     def multiplicative_order(self):
         r"""
-        Return the multiplicative order of self, if self is a unit, or raise
-        \code{ArithmeticError} otherwise.
+        Return the multiplicative order of self.
 
         EXAMPLES:
@@ -1537,18 +1592,15 @@
             2
             sage: ZZ(0).multiplicative_order()
-            Traceback (most recent call last):
-            ...
-            ArithmeticError: no power of 0 is a unit
+            +Infinity
             sage: ZZ(2).multiplicative_order()
-            Traceback (most recent call last):
-            ...
-            ArithmeticError: no power of 2 is a unit
-        """
-        if mpz_cmp_si(self.value, 1) == 0:
-            return Integer(1)
+            +Infinity
+        """
+        import sage.rings.infinity
+        if  mpz_cmp_si(self.value, 1) == 0:
+                return Integer(1)
         elif mpz_cmp_si(self.value, -1) == 0:
-            return Integer(2)
+                return Integer(2)
         else:
-            raise ArithmeticError, "no power of %s is a unit"%self
+                return sage.rings.infinity.infinity
 
     def is_squarefree(self):
@@ -1615,8 +1667,8 @@
             Traceback (most recent call last):
             ...
-            ValueError: square root of negative number not defined.
-        """
-        if self < 0:
-            raise ValueError, "square root of negative number not defined."
+            ValueError: square root of negative integer not defined.
+        """
+        if mpz_sgn(self.value) < 0:
+            raise ValueError, "square root of negative integer not defined."
         cdef Integer x
         x = PY_NEW(Integer)
@@ -1628,81 +1680,97 @@
         return x
 
-    
-    def sqrt(self, bits=None):
-        r"""
-        Returns the positive square root of self, possibly as a
-        \emph{a real or complex number} if self is not a perfect
-        integer square.
-
+    def sqrt_approx(self, prec=None, all=False):
+        """
+        EXAMPLES:
+            sage: 5.sqrt_approx(prec=200)
+            2.2360679774997896964091736687312762354406183596115257242709
+            sage: 5.sqrt_approx()
+            2.23606797749979
+            sage: 4.sqrt_approx()
+            2
+        """
+        try:
+            return self.sqrt(extend=False,all=all)
+        except ValueError:
+            pass
+        if prec is None:
+            prec = max(53, 2*(mpz_sizeinbase(self.value, 2)+2))
+        return self.sqrt(prec=prec, all=all)
+
+    def sqrt(self, prec=None, extend=True, all=False):
+        """
+        The square root function.
+        
         INPUT:
-            bits -- number of bits of precision.
-                    If bits is not specified, the number of
-                    bits of precision is at least twice the
-                    number of bits of self (the precision
-                    is always at least 53 bits if not specified).
-        OUTPUT:
-            integer, real number, or complex number.
-
-        For the guaranteed integer square root of a perfect square
-        (with error checking), use \code{self.square_root()}.
-        
-        EXAMPLE:
-            sage: Z = IntegerRing()
-            sage: Z(4).sqrt()
-            2
-            sage: Z(4).sqrt(53)
-            2.00000000000000
-            sage: Z(2).sqrt(53)
-            1.41421356237310
-            sage: Z(2).sqrt(100)
+            prec -- integer (default: None): if None, returns an exact
+                 square root; otherwise returns a numerical square
+                 root if necessary, to the given bits of precision.
+            extend -- bool (default: True); if True, return a square
+                 root in an extension ring, if necessary. Otherwise,
+                 raise a ValueError if the square is not in the base
+                 ring.
+            all -- bool (default: False); if True, return all square
+                 roots of self, instead of just one.
+
+        EXAMPLES:
+            sage: Integer(144).sqrt()
+            12
+            sage: Integer(102).sqrt()
+            sqrt(102)
+
+            sage: n = 2
+            sage: n.sqrt(all=True)
+            [sqrt(2), -sqrt(2)]
+            sage: n.sqrt(prec=10)
+            1.4
+            sage: n.sqrt(prec=100)
             1.4142135623730950488016887242
-            sage: n = 39188072418583779289; n.square_root()
-            6260037733
-            sage: (100^100).sqrt()
-            10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-            sage: (-1).sqrt()
-            1.00000000000000*I
-            sage: sqrt(-2)
-            1.41421356237310*I
-            sage: sqrt(97)
-            9.84885780179610
-            sage: n = 97; n.sqrt(200)
-            9.8488578017961047217462114149176244816961362874427641717232
-        """
-        if bits is None:
-            try:
-                return self.square_root()
-            except ValueError:
-                pass
-            bits = max(53, 2*(mpz_sizeinbase(self.value, 2)+2))
-            
-        if self < 0:
-            import sage.rings.complex_field
-            x = sage.rings.complex_field.ComplexField(bits)(self)
-            return x.sqrt()
-        else:
-            import real_mpfr            
-            R = real_mpfr.RealField(bits)
-            return R(self).sqrt()
-
-    def square_root(self):
-        """
-        Return the positive integer square root of self, or raises a ValueError
-        if self is not a perfect square.
-
-        EXAMPLES:
-            sage: Integer(144).square_root()
-            12
-            sage: Integer(102).square_root()
+            sage: n.sqrt(prec=100,all=True)
+            [1.4142135623730950488016887242, -1.4142135623730950488016887242]
+            sage: n.sqrt(extend=False)
             Traceback (most recent call last):
             ...
-            ValueError: self (=102) is not a perfect square
-        """
-        n = self.isqrt()
-        if n * n == self:
-            return n
-        raise ValueError, "self (=%s) is not a perfect square"%self
-            
-
+            ValueError: square root of 2 not an integer
+            sage: Integer(0).sqrt(all=True)
+            [0]
+        """
+        if mpz_sgn(self.value) < 0:
+            if not extend:
+                raise ValueError, "square root of negative number not an integer"
+            if prec:
+                from sage.rings.complex_field import ComplexField
+                K = ComplexField(prec)
+                return K(self).sqrt(all=all)
+            from sage.calculus.calculus import sqrt
+            return sqrt(self, all=all)
+
+
+        cdef int non_square
+        cdef Integer z = PY_NEW(Integer)
+        cdef mpz_t tmp
+        _sig_on
+        mpz_init(tmp)
+        mpz_sqrtrem(z.value, tmp, self.value)
+        non_square = mpz_sgn(tmp) != 0
+        mpz_clear(tmp)
+        _sig_off
+
+        if non_square:
+            if not extend:
+                raise ValueError, "square root of %s not an integer"%self
+            if prec:
+                from sage.rings.real_mpfr import RealField
+                K = RealField(prec)
+                return K(self).sqrt(all=all)
+            from sage.calculus.calculus import sqrt
+            return sqrt(self, all=all)
+
+        if all:
+            if z.is_zero():
+                return [z]
+            else:
+                [z, -z]
+        return z
+        
     def _xgcd(self, Integer n):
         r"""
Index: sage/rings/integer_mod.pyx
===================================================================
--- sage/rings/integer_mod.pyx	(revision 3926)
+++ sage/rings/integer_mod.pyx	(revision 4291)
@@ -22,4 +22,5 @@
     -- William Stein (editing and polishing; new arith architecture)
     -- Robert Bradshaw (implement native is_square and square_root)
+    -- William Stein (sqrt)
 
 TESTS:
@@ -110,5 +111,9 @@
             if res < 0:
                 res = res + modulus.int64
-            return modulus.lookup(res)
+            a = modulus.lookup(res)
+            if (<Element>a)._parent is not parent:
+               (<Element>a)._parent = parent
+#                print (<Element>a)._parent, " is not ", parent
+            return a
     if modulus.int32 != -1:
         return IntegerMod_int(parent, value)
@@ -472,5 +477,5 @@
 
     def is_square(self):
-        """
+        r"""
         EXAMPLES:
             sage: Mod(3,17).is_square()
@@ -494,5 +499,5 @@
             
         ALGORITHM:
-            Calculate the Jacobi symbol $(self/p)$ at each prime $p dividing $n$
+            Calculate the Jacobi symbol $(self/p)$ at each prime $p$ dividing $n$
             It must be 1 or 0 for each prime, and if it is 0 mod $p$, 
             where $p^k || n$, then $ord_p(self)$ must be even or greater than $k$. 
@@ -535,65 +540,156 @@
             return 1
 
-
-    def sqrt(self):
-        """
-        Same as self.square_root().
-        """
-        return self.square_root()
-        
-
-    def square_root(self):
-        """
-        Calculates the square roots mod $p$ for each of the primes $p$ dividing 
-        the order of the ring, then lifts p-adically and uses crt to 
-        find a square root mod $n$. 
-        
-        See also \code{square_root_mod_prime_power} and \code{square_root_mod_prime}
-        (in this module) algorithms details. 
+    def sqrt(self, extend=True, all=False):
+        r"""
+        Returns square root or square roots of self modulo n.
+
+        INPUT:
+            extend -- bool (default: True); if True, return a square
+                 root in an extension ring, if necessary. Otherwise,
+                 raise a ValueError if the square is not in the base ring.
+            all -- bool (default: False); if True, return *all* square
+                   roots of self, instead of just one.
+        
+        ALGORITHM: Calculates the square roots mod $p$ for each of the
+        primes $p$ dividing the order of the ring, then lifts them
+        p-adically and uses the CRT to find a square root mod $n$.
+        
+        See also \code{square_root_mod_prime_power} and
+        \code{square_root_mod_prime} (in this module) for more
+        algorithmic details.
         
         EXAMPLES: 
-            sage: mod(-1, 17).square_root()
+            sage: mod(-1, 17).sqrt()
             4
-            sage: mod(5, 389).square_root()
+            sage: mod(5, 389).sqrt()
             86
-            sage: mod(7, 18).square_root()
+            sage: mod(7, 18).sqrt()
             5
-            sage: a = mod(14, 5^60).square_root()
+            sage: a = mod(14, 5^60).sqrt()
             sage: a*a
             14            
-            sage: mod(15, 389).square_root()
+            sage: mod(15, 389).sqrt(extend=False)
             Traceback (most recent call last):
             ...
-            ValueError: Self must be a square.
-            sage: Mod(1/9, next_prime(2^40)).square_root()^(-2)
+            ValueError: self must be a square
+            sage: Mod(1/9, next_prime(2^40)).sqrt()^(-2)
             9
-            sage: Mod(1/25, next_prime(2^90)).square_root()^(-2)
+            sage: Mod(1/25, next_prime(2^90)).sqrt()^(-2)
             25
 
-        """ 
-        if self.is_zero() or self.is_one():
-            return self
+            sage: a = Mod(3,5); a
+            3
+            sage: x = Mod(-1, 360)
+            sage: x.sqrt(extend=False)
+            Traceback (most recent call last):
+            ...
+            ValueError: self must be a square
+            sage: y = x.sqrt(); y
+            sqrt359
+            sage: y.parent()
+            Univariate Quotient Polynomial Ring in sqrt359 over Ring of integers modulo 360 with modulus x^2 + 1
+            sage: y^2
+            359
+
+        We compute all square roots in several cases:
+            sage: R = Integers(5*2^3*3^2); R
+            Ring of integers modulo 360
+            sage: R(40).sqrt(all=True)
+            [20, 160, 200, 340]
+            sage: [x for x in R if x^2 == 40]  # Brute force verification
+            [20, 160, 200, 340]
+            sage: R(1).sqrt(all=True)
+            [1, 19, 71, 89, 91, 109, 161, 179, 181, 199, 251, 269, 271, 289, 341, 359]
+
+            sage: R = Integers(5*13^2*37); R
+            Ring of integers modulo 31265
+            sage: v = R(-1).sqrt(all=True); v
+            [3817, 5507, 13252, 14942, 16323, 18013, 25758, 27448]
+            sage: [x^2 for x in v]
+            [31264, 31264, 31264, 31264, 31264, 31264, 31264, 31264]
+
+        Modulo a power of 2:
+            sage: R = Integers(2^7); R
+            Ring of integers modulo 128
+            sage: a = R(17)
+            sage: a.sqrt()
+            23
+            sage: a.sqrt(all=True)
+            [23, 41, 87, 105]
+            sage: [x for x in R if x^2==17]
+            [23, 41, 87, 105]
+        """
+        if self.is_one():
+            if all:
+                return list(self.parent().square_roots_of_one())
+            else:
+                return self
             
         if not self.is_square_c():
-            raise ValueError, "Self must be a square."
-            
-        moduli = self._parent.factored_order()
-        if len(moduli) == 1:
-            p, e = moduli[0]
+            if extend:
+                R = self.parent()['x']
+                y = 'sqrt%s'%self
+                Q = R.quotient(R.gen()**2 - R(self), names=(y,))
+                z = Q.gen()
+                if all:
+                    # TODO
+                    raise NotImplementedError
+                return z
+            raise ValueError, "self must be a square"
+            
+        F = self._parent.factored_order()
+        if len(F) == 1:
+            p, e = F[0]
+
+            if all and e > 1 and not self.is_unit():
+                # TODO -- this is the *one* and only remaining STUPID SLOW CASE.
+                v = [x for x in self.parent() if x*x == self]
+                return v
+            
             if e > 1:
                 x = square_root_mod_prime_power(mod(self, p**e), p, e)
             else:
                 x = square_root_mod_prime(self, p)
-                
-        else:
-            # return product of square roots mod each prime power
-            sqrts = [square_root_mod_prime(mod(self, p), p) for p, e in moduli if e == 1] + \
-                    [square_root_mod_prime_power(mod(self, p**e), p, e) for p, e in moduli if e != 1]
-            
-            x = sqrts.pop()
-            for y in sqrts:
-                x = x.crt(y)
-        
-        return x._balanced_abs()
+            x = x._balanced_abs()
+            
+            if not all:
+                return x
+
+            v = list(set([x*a for a in self.parent().square_roots_of_one()]))
+            v.sort()
+            return v
+        else:
+            if not all:
+                # Use CRT to combine together a square root modulo each prime power
+                sqrts = [square_root_mod_prime(mod(self, p), p) for p, e in F if e == 1] + \
+                        [square_root_mod_prime_power(mod(self, p**e), p, e) for p, e in F if e != 1]
+
+                x = sqrts.pop()
+                for y in sqrts:
+                    x = x.crt(y)
+                return x._balanced_abs()
+            else:
+                # Use CRT to combine together all square roots modulo each prime power
+                vmod = []
+                moduli = []
+                P = self.parent()
+                from integer_mod_ring import IntegerModRing
+                for p, e in F:
+                    k = p**e
+                    R = IntegerModRing(p**e)
+                    w = [P(x) for x in R(self).sqrt(all=True)]
+                    vmod.append(w)
+                    moduli.append(k)
+                # Now combine in all possible ways using the CRT
+                from arith import CRT_basis
+                basis = CRT_basis(moduli)
+                from sage.misc.mrange import cartesian_product_iterator
+                v = []
+                for x in cartesian_product_iterator(vmod):
+                    # x is a specific choice of roots modulo each prime power divisor
+                    a = sum([basis[i]*x[i] for i in range(len(x))])
+                    v.append(a)
+                v.sort()
+                return v
         
     def _balanced_abs(self):
@@ -835,7 +931,7 @@
         return bool(mpz_cmp_si(self.value, 1) == 0)
 
-    def is_zero(IntegerMod_gmp self):
-        """
-        Returns \code{True} if this is $0$, otherwise \code{False}.
+    def __nonzero__(IntegerMod_gmp self):
+        """
+        Returns \code{True} if this is not $0$, otherwise \code{False}.
 
         EXAMPLES:
@@ -845,5 +941,5 @@
             True
         """
-        return bool(mpz_cmp_si(self.value, 0) == 0)
+        return bool(mpz_cmp_si(self.value, 0) != 0)
 
     def is_unit(self):
@@ -1096,6 +1192,6 @@
             return self.__modulus.lookup(value)
         cdef IntegerMod_int x = PY_NEW(IntegerMod_int)
+        x._parent = self._parent
         x.__modulus = self.__modulus
-        x._parent = self._parent
         x.ivalue = value
         return x
@@ -1160,7 +1256,7 @@
         return bool(self.ivalue == 1)
 
-    def is_zero(IntegerMod_int self):
-        """
-        Returns \code{True} if this is $0$, otherwise \code{False}.
+    def __nonzero__(IntegerMod_int self):
+        """
+        Returns \code{True} if this is not $0$, otherwise \code{False}.
 
         EXAMPLES:
@@ -1170,5 +1266,5 @@
             True
         """
-        return bool(self.ivalue == 0)
+        return bool(self.ivalue != 0)
 
     def is_unit(IntegerMod_int self):
@@ -1671,7 +1767,7 @@
         return bool(self.ivalue == 1)
 
-    def is_zero(IntegerMod_int64 self):
-        """
-        Returns \code{True} if this is $0$, otherwise \code{False}.
+    def __nonzero__(IntegerMod_int64 self):
+        """
+        Returns \code{True} if this is not $0$, otherwise \code{False}.
 
         EXAMPLES:
@@ -1681,5 +1777,5 @@
             True
         """
-        return bool(self.ivalue == 0)
+        return bool(self.ivalue != 0)
 
     def is_unit(IntegerMod_int64 self):
@@ -2040,10 +2136,10 @@
 
 def square_root_mod_prime_power(IntegerMod_abstract a, p, e):
-    """
-    Calculates the square root of a, where a is an integer mod p^e.
+    r"""
+    Calculates the square root of $a$, where $a$ is an integer mod $p^e$.
     
     ALGORITHM: 
         Perform p-adically by stripping off even powers of $p$ to get
-        a unit and lifting $\sqrt{unit} mod p$ via newton's method.
+        a unit and lifting $\sqrt{unit} mod p$ via Newton's method.
         
     AUTHOR:
@@ -2054,5 +2150,10 @@
     
     if p == 2:
-        return a if e == 1 else self.parent()(self.pari().sqrt())  # TODO: implement directly
+        if e == 1:
+            return a
+        # TODO: implement something that isn't totally idiotic.
+        for x in a.parent():
+            if x**2 == a:
+                return x
     
     # strip off even powers of p
@@ -2068,6 +2169,6 @@
     x = unit.parent()(square_root_mod_prime(mod(unit, p), p))
 
-    # lift p-adically using newton iteration
-    # this is done to higher precision than neccisary except at the last step
+    # lift p-adically using Newton iteration
+    # this is done to higher precision than neccesary except at the last step
     one_half = ~(a._new_c_from_long(2))
     for i from 0 <= i <  ceil(log(e)/log(2)) - val/2:
@@ -2078,17 +2179,19 @@
         x *= p**(val // 2)
     return x
-    
+        
 def square_root_mod_prime(IntegerMod_abstract a, p=None):
-    """
+    r"""
     Calculates the square root of a, where a is an integer mod p. 
     
     ALGORITHM: 
         Several cases based on residue class of p mod 16.
-        
-        $p$ mod 2 = 0 \Rightarrow p = 2 so \sqrt{a} = a$.
-        $p$ mod 4 = 3 \Rightarrow \sqrt{a} = a^{(p+1)/4}$.
-        $p$ mod 8 = 5 \Rightarrow \sqrt{a} = \zeta i a$ where $\zeta = (2a)^{(p-5)/8}, i=\sqrt{-1}$.
-        $p$ mod 16 = 9$ Similar, work in a bi-quadratic extension of $\F_p$.
-        $p$ mod 16 = 1$ Variant of Cipolla\202\304\354Lehmer, using Lucas functions.
+
+    \begin{verbatim}
+        $p$ mod 2 = 0 $\Rightarrow$ p = 2 so \sqrt{a} = a$.
+        $p$ mod 4 = 3 $\Rightarrow \sqrt{a} = a^{(p+1)/4}$.
+        $p$ mod 8 = 5 $\Rightarrow \sqrt{a} = \zeta i a$ where $\zeta = (2a)^{(p-5)/8}$, $i=\sqrt{-1}$.
+        $p$ mod 16 = 9$ Similar, work in a bi-quadratic extension of $\FF_p$.
+        $p$ mod 16 = 1$ Variant of Cipolla-Lehmer, using Lucas functions.
+    \end{verbatim}
         
     REFERENCES: 
@@ -2102,5 +2205,5 @@
             
         H. Postl. 'Fast evaluation of Dickson Polynomials'
-            Contrib. to General Algebra, Vol. 6 (1988) pp. 223\202\304\354225
+            Contrib. to General Algebra, Vol. 6 (1988) pp. 223--225
         
     AUTHOR:
@@ -2109,5 +2212,5 @@
     TESTS: 
         Every case appears in the first hundred primes. 
-        sage: all([(a*a).square_root()^2 == a*a for p in prime_range(100) for a in Integers(p)])
+        sage: all([(a*a).sqrt()^2 == a*a for p in prime_range(100) for a in Integers(p)])
         True
     """
@@ -2126,22 +2229,22 @@
         
     elif p_mod_16 % 4 == 3:
-        return a ** ((p+1)/4)
+        return a ** ((p+1)//4)
         
     elif p_mod_16 % 8 == 5:
         two_a = a+a
-        zeta = two_a ** ((p-5)/8)
-        i = two_a ** ((p-1)/4)
+        zeta = two_a ** ((p-5)//8)
+        i = two_a ** ((p-1)//4)
         return zeta*a*(i-1)
         
     elif p_mod_16 == 9:
-        s = (a+a) ** ((p-1)/4)
+        s = (a+a) ** ((p-1)//4)
         if s.is_one():
             d = a._parent.quadratic_nonresidue()
             d2 = d*d
-            z = (2 * d2 * a) ** ((p-9)/16)
+            z = (2 * d2 * a) ** ((p-9)//16)
             i = 2 * d2 * z*z * a
             return z*d*a*(i-1)
         else:
-            z = (a+a) ** ((p-9)/16)
+            z = (a+a) ** ((p-9)//16)
             i = 2 * z*z * a
             return z*a*(i-1)
Index: sage/rings/integer_mod_ring.py
===================================================================
--- sage/rings/integer_mod_ring.py	(revision 3925)
+++ sage/rings/integer_mod_ring.py	(revision 4278)
@@ -32,5 +32,6 @@
     -- William Stein (initial code)
     -- David Joyner (2005-12-22): most examples
-    -- Robert Bradshaw (2006-08-24) Convert to SageX
+    -- Robert Bradshaw (2006-08-24): convert to SageX
+    -- William Stein (2007-04-29): square_roots_of_one    
 """
 
@@ -399,4 +400,14 @@
             
     def quadratic_nonresidue(self):
+        """
+        Return a quadratic non-residue in self.
+
+        EXAMPLES:
+            sage: R = Integers(17)
+            sage: R.quadratic_nonresidue()
+            3
+            sage: R(3).is_square()
+            False
+        """
         try:
             return self._nonresidue
@@ -406,4 +417,73 @@
                     self._nonresidue = a
                     return a
+
+    def square_roots_of_one(self):
+        """
+        Return all square roots of 1 in self, i.e., all solutions
+        to $x^2 - 1$.
+
+        OUTPUT:
+            tuple -- the square roots of 1 in self.
+
+        EXAMPLES:
+            sage: R = Integers(2^10)
+            sage: [x for x in R if x^2 == 1]
+            [1, 511, 513, 1023]
+            sage: R.square_roots_of_one()
+            (1, 511, 513, 1023)
+
+            sage: v = Integers(9*5).square_roots_of_one(); v
+            (1, 19, 26, 44)
+            sage: [x^2 for x in v]
+            [1, 1, 1, 1]
+            sage: v = Integers(9*5*8).square_roots_of_one(); v
+            (1, 19, 71, 89, 91, 109, 161, 179, 181, 199, 251, 269, 271, 289, 341, 359)
+            sage: [x^2 for x in v]
+            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
+        """
+        try:
+            return self.__square_roots_of_one
+        except AttributeError:
+            pass
+        n = self.__order
+        if n.is_prime_power():
+            if n % 2 == 0:
+                # power of 2
+                if n == 2:
+                    v = [self(1)]
+                elif n == 4:
+                    v = [self(1), self(3)]
+                else: # n >= 8
+                    half_ord = n//2
+                    v = [self(1), self(-1), self(half_ord-1), self(half_ord+1)]
+            else:
+                v = [self(1), self(-1)]
+        else:
+            # Reduce to the prime power case.
+            F = self.factored_order()
+            vmod = []
+            moduli = []
+            for p, e in F:
+                k = p**e
+                R = IntegerModRing(p**e)
+                w = [self(x) for x in R.square_roots_of_one()]
+                vmod.append(w)
+                moduli.append(k)
+            # Now combine in all possible ways using the CRT
+            from arith import CRT_basis
+            basis = CRT_basis(moduli)
+            from sage.misc.mrange import cartesian_product_iterator
+            v = []
+            for x in cartesian_product_iterator(vmod):
+                # x is a specific choice of roots modulo each prime power divisor
+                a = sum([basis[i]*x[i] for i in range(len(x))])
+                v.append(a)
+            #end for
+        #end if
+        
+        v.sort()
+        v = tuple(v)
+        self.__square_roots_of_one = v
+        return v
             
     def factored_order(self):
Index: sage/rings/integer_ring.pxd
===================================================================
--- sage/rings/integer_ring.pxd	(revision 3665)
+++ sage/rings/integer_ring.pxd	(revision 4057)
@@ -8,2 +8,3 @@
     cdef Integer _coerce_ZZ(self, ntl_c_ZZ *z)
     cdef int _randomize_mpz(self, mpz_t value, x, y, distribution) except -1
+    cdef object _zero
Index: sage/rings/integer_ring.pyx
===================================================================
--- sage/rings/integer_ring.pyx	(revision 3665)
+++ sage/rings/integer_ring.pyx	(revision 4010)
@@ -28,4 +28,10 @@
     sage: Z('94803849083985934859834583945394')
     94803849083985934859834583945394
+
+TESTS:
+    sage: Z = IntegerRing()
+    sage: Z == loads(dumps(Z))
+    True
+
 """
 
Index: sage/rings/laurent_series_ring.py
===================================================================
--- sage/rings/laurent_series_ring.py	(revision 3665)
+++ sage/rings/laurent_series_ring.py	(revision 4279)
@@ -100,4 +100,7 @@
         ParentWithGens.__init__(self, base_ring, name)
         self.__sparse = sparse
+        
+    def change_ring(self, R):
+        return LaurentSeriesRing(R, self.variable_name(), sparse=self.__sparse)
 
     def is_sparse(self):
Index: sage/rings/laurent_series_ring_element.pxd
===================================================================
--- sage/rings/laurent_series_ring_element.pxd	(revision 4158)
+++ sage/rings/laurent_series_ring_element.pxd	(revision 4158)
@@ -0,0 +1,5 @@
+from sage.structure.element cimport AlgebraElement
+
+cdef class LaurentSeries(AlgebraElement):
+    cdef object __u
+    cdef long __n
Index: age/rings/laurent_series_ring_element.py
===================================================================
--- sage/rings/laurent_series_ring_element.py	(revision 3919)
+++ 	(revision )
@@ -1,768 +1,0 @@
-"""
-Laurent Series
-
-EXAMPLES:
-
-    sage: R.<t> = LaurentSeriesRing(GF(7), 't'); R
-    Laurent Series Ring in t over Finite Field of size 7
-    sage: f = 1/(1-t+O(t^10)); f
-    1 + t + t^2 + t^3 + t^4 + t^5 + t^6 + t^7 + t^8 + t^9 + O(t^10)
-
-Laurent series are immutable:
-    sage: f[2]
-    1
-    sage: f[2] = 5
-    Traceback (most recent call last):
-    ...
-    IndexError: Laurent series are immutable    
-
-We compute with a Laurent series over the complex mpfr numbers. 
-    sage: K.<q> = Frac(CC[['q']])
-    sage: K
-    Laurent Series Ring in q over Complex Field with 53 bits of precision
-    sage: q
-    1.00000000000000*q
-
-Saving and loading.
-    sage: loads(q.dumps()) == q
-    True
-    sage: loads(K.dumps()) == K
-    True
-
-IMPLEMENTATION: Laurent series in SAGE are represented internally as a
-    power of the variable times the unit part (which need not be a
-    unit -- it's a polynomial with nonzero constant term).  The zero
-    Laurent series has unit part 0.
-
-
-AUTHORS:
-    -- William Stein: original version
-    -- David Joyner: added examples 2006-01-22
-"""
-
-import operator
-
-from infinity import infinity
-
-import laurent_series_ring
-import power_series_ring_element
-import power_series_ring
-import polynomial_element as polynomial
-import sage.misc.latex as latex
-import sage.rings.ring_element as ring_element
-
-class LaurentSeries(ring_element.RingElement):
-    """
-    A Laurent Series.
-    """
-    def __init__(self, parent, f, n=0):
-        r"""
-        Create the Laurent series $t^n \cdot f$.  The default is n=0.
-
-        INPUT:
-            parent -- a Laurent series ring
-            f -- a power series (or something can be coerced to one); note that
-                 f does *not* have to be a unit. 
-            n -- integer (default 0)
-
-        OUTPUT:
-            a Laurent series
-        """
-        ring_element.RingElement.__init__(self, parent)
-        if isinstance(f, LaurentSeries):
-            n += f.__n
-            f = parent.power_series_ring()(f.__u)
-        elif not isinstance(f, power_series_ring_element.PowerSeries):
-            f = parent.power_series_ring()(f)
-
-        # self is that t^n * u:
-        if f.is_zero():
-            self.__n = n
-            self.__u = f
-        else:
-            self.__n = n + f.valuation()    # power of the variable
-            self.__u = f.valuation_zero_part()        # unit part
-        
-    def is_unit(self):
-        """
-        Returns True if this is Laurent series is a unit in this ring.
-        
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(QQ)
-            sage: (2+t).is_unit()
-            True
-            sage: f = 2+t^2+O(t^10); f.is_unit()
-            True
-            sage: 1/f
-            1/2 - 1/4*t^2 + 1/8*t^4 - 1/16*t^6 + 1/32*t^8 + O(t^10)
-            sage: R(0).is_unit()
-            False
-            sage: R.<s> = LaurentSeriesRing(ZZ)
-            sage: f = 2 + s^2 + O(s^10)
-            sage: f.is_unit()
-            False
-            sage: 1/f
-            Traceback (most recent call last):
-            ...
-            ArithmeticError: division not defined
-
-        ALGORITHM: A Laurent series is a unit if and only if
-        its "unit part" is a unit.
-        """
-        return self.__u.is_unit()
-
-    def is_zero(self):
-        """
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: f = 1/x + x + x^2 + 3*x^4 + O(x^7)
-            sage: f.is_zero()
-            0
-            sage: z = 0*f
-            sage: z.is_zero()
-            1
-        """
-        return self.__u.is_zero()
-        
-    def _im_gens_(self, codomain, im_gens):
-        return codomain(self(im_gens[0]))
-
-    def __normalize(self):
-        r"""
-        A Laurent series is a pair (u(t), n), where either u=0 (to
-        some precision) or u is a unit.  This pair corresponds to
-        $t^n\cdot u(t)$.
-        """
-        if self.is_zero():
-            return
-        v = self.__u.valuation()
-        if v == 0:
-            return
-        self.__n += v
-        self.__u = self.__u.valuation_zero_part()
-        
-    def _repr_(self):
-        """
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(QQ)
-            sage: (2 + (2/3)*t^3).__repr__()
-            '2 + 2/3*t^3'
-        """
-        if self.is_zero():
-            if self.prec() == infinity:
-                return "0"
-            else:
-                return "O(%s^%s)"%(self.parent().variable_name(),self.prec())
-        s = " "
-        v = self.__u.list()
-        valuation = self.__n
-        m = len(v)
-        X = self.parent().variable_name()
-        atomic_repr = self.parent().base_ring().is_atomic_repr()
-        first = True
-        for n in xrange(m):
-            x = v[n]
-            e = n + valuation
-            if x != 0:
-                if not first:
-                    s += " + "
-                x = str(x)
-                if not atomic_repr and (x[1:].find("+") != -1 or x[1:].find("-") != -1):
-                    x = "(%s)"%x
-                if e == 1:
-                    var = "*%s"%X
-                elif e == 0:
-                    var = ""
-                else:
-                    var = "*%s^%s"%(X,e)
-                s += "%s%s"%(x,var)
-                first = False
-        if atomic_repr:
-            s = s.replace(" + -", " - ")
-        s = s.replace(" 1*"," ")
-        s = s.replace(" -1*", " -")
-        if self.prec() == 0:
-            bigoh = "O(1)"
-        elif self.prec() == 1:
-            bigoh = "O(%s)"%self.parent().variable_name()
-        else:
-            bigoh = "O(%s^%s)"%(self.parent().variable_name(),self.prec())
-        if self.prec() != infinity:
-            if s == " ":
-                return bigoh
-            s += " + %s"%bigoh
-        return s[1:]
-
-    def _latex_(self):
-        r"""
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: f = (17/2)*x^-2 + x + x^2 + 3*x^4 + O(x^7)
-            sage: latex(f)
-            \frac{\frac{17}{2}}{x^{2}} + x + x^{2} + 3x^{4} + O(\text{x}^{7})
-        """
-        if self.is_zero():
-            if self.prec() == infinity:
-                return "0"
-            else:
-                return "0 + \\cdots"
-        s = " "
-        v = self.__u.list()
-        valuation = self.__n
-        m = len(v)
-        X = self.parent().variable_name()
-        atomic_repr = self.parent().base_ring().is_atomic_repr()
-        first = True
-        for n in xrange(m):
-            x = v[n]
-            e = n + valuation
-            if x != 0:
-                if not first:
-                    s += " + "
-                x = latex.latex(x)
-                if not atomic_repr and n > 0 and (x[1:].find("+") != -1 or x[1:].find("-") != -1):
-                    x = "\\left(%s\\right)"%x
-                if e == 1:
-                    var = "|%s"%X
-                elif e == 0:
-                    var = ""
-                elif e > 0:
-                    var = "|%s^{%s}"%(X,e)
-                if e >= 0:
-                    s += "%s%s"%(x,var)
-                else: # negative e
-                    if e == -1:
-                        s += "\\frac{%s}{%s}"%(x, X)
-                    else:
-                        s += "\\frac{%s}{%s^{%s}}"%(x, X,-e)
-                first = False
-        if atomic_repr:
-            s = s.replace(" + -", " - ")
-        s = s.replace(" 1|"," ")
-        s = s.replace(" -1|", " -")
-        s = s.replace("|","")
-        pr = self.prec()
-        if pr != infinity:
-            if pr == 0:
-                bigoh = "O(1)"
-            elif pr == 1:
-                bigoh = "O(%s)"%latex.latex(self.parent().variable_name())
-            else:
-                bigoh = "O(%s^{%s})"%(latex.latex(self.parent().variable_name()),pr)
-            if s == " ":
-                return bigoh
-            s += " + %s"%bigoh
-        return s[1:]
-
-    def __getitem__(self, i):
-        """
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(QQ)
-            sage: f = -5/t^(10) + t + t^2 - 10/3*t^3; f
-            -5*t^-10 + t + t^2 - 10/3*t^3
-            sage: f[-10]
-            -5
-            sage: f[1]
-            1
-            sage: f[3]
-            -10/3
-            sage: f[-9]
-            0
-        """
-        return self.__u[i-self.__n]
-
-    def __getslice__(self, i, j):
-        """
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(QQ)
-            sage: f = -5/t^(10) + 1/3 + t + t^2 - 10/3*t^3 + O(t^5); f
-            -5*t^-10 + 1/3 + t + t^2 - 10/3*t^3 + O(t^5)
-            sage: f[-10:2]
-            -5*t^-10 + 1/3 + t + O(t^5)
-            sage: f[0:]
-            1/3 + t + t^2 - 10/3*t^3 + O(t^5)
-        """
-        f = self.__u[i-self.__n:j-self.__n]
-        return LaurentSeries(self.parent(), f, self.__n)
-
-    def __iter__(self):
-        """
-        Iterate through the coefficients from the first nonzero one to
-        the last nonzero one.
-        
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(QQ)
-            sage: f = -5/t^(2) + t + t^2 - 10/3*t^3; f
-            -5*t^-2 + t + t^2 - 10/3*t^3
-            sage: for a in f: print a
-            -5
-            0
-            0
-            1
-            1
-            -10/3
-        """
-        for i in range(self.valuation(), self.degree()+1):
-            yield self[i]
-
-    def __setitem__(self, n, value):
-        """
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(QQ)
-            sage: f = t^2 + t^3 + O(t^10)
-            sage: f[2] = 5
-            Traceback (most recent call last):
-            ...
-            IndexError: Laurent series are immutable
-        """
-        raise IndexError, "Laurent series are immutable"
-
-    def _unsafe_mutate(self, i, value):
-        """
-        SAGE assumes throughout that commutative ring elements are immutable.
-        This is relevant for caching, etc.  But sometimes you need to change
-        a Laurent series and you really know what you're doing.  That's
-        when this function is for you.
-
-        EXAMPLES:
-        
-        """
-        j = i - self.__n
-        if j >= 0:
-            self.__u._unsafe_mutate(j, value)
-        else: # off to the left
-            if value != 0:
-                self.__n = self.__n + j
-                R = self.parent().base_ring()
-                coeffs = [value] + [R(0) for _ in range(1,-j)] + self.__u.list()
-                self.__u = self.__u.parent()(coeffs)
-        self.__normalize()
-
-    def _add_(self, right):
-        """
-        Add two power series with the same parent.
-        
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(QQ)
-            sage: t + t
-            2*t
-            sage: f = 1/t + t^2 + t^3 - 17/3 * t^4 + O(t^5)
-            sage: g = 1/(1-t + O(t^7)); g
-            1 + t + t^2 + t^3 + t^4 + t^5 + t^6 + O(t^7)
-            sage: f + g
-            t^-1 + 1 + t + 2*t^2 + 2*t^3 - 14/3*t^4 + O(t^5)
-            sage: f + 0
-            t^-1 + t^2 + t^3 - 17/3*t^4 + O(t^5)
-            sage: 0 + f
-            t^-1 + t^2 + t^3 - 17/3*t^4 + O(t^5)
-            sage: R(0) + R(0)
-            0
-            sage: (t^3 + O(t^10)) + (t^-3 +O(t^9))
-            t^-3 + t^3 + O(t^9)
-            
-        ALGORITHM:
-            Multiply both Laurent series by a power of the variable to make them
-            power series, add those power series, then divide. 
-        """
-        # Add together two Laurent series over the same base ring.
-
-        # 1. Special case when one or the other is 0.
-        if right.is_zero():
-            return self.add_bigoh(right.prec())
-        if self.is_zero():
-            return right.add_bigoh(self.prec())
-
-        # 2. Find power of t that we can multiply both by to get power series.
-        m = - min(self.valuation(), right.valuation())
-        # Now t^m times each one is a polynomial.
-        # Get the polynomial indeterminate t
-        t = self.__u.parent().gen()
-        # Compute t^m times self
-        f1 = t**(self.__n + m) * self.__u
-        # Compute t^m times right
-        f2 = t**(right.__n + m) * right.__u
-        # Now add f1 and f2 as power series
-        g = f1 + f2
-        # Finally construct the Laurent series associated to the sum time t^(-m).
-        return LaurentSeries(self.parent(), g, -m)
-
-    def add_bigoh(self, prec):
-        """
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(QQ)
-            sage: f = t^2 + t^3 + O(t^10); f
-            t^2 + t^3 + O(t^10)
-            sage: f.add_bigoh(5)
-            t^2 + t^3 + O(t^5)
-        """
-        if prec == infinity or prec >= self.prec():
-            return self
-        u = self.__u.add_bigoh(prec - self.__n)
-        return LaurentSeries(self.parent(), u, self.__n)
-
-    def degree(self):
-        """
-        Return the degree of a polynomial equivalent to this power
-        series modulo big oh of the precision.
-        
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: g = x^2 - x^4 + O(x^8)
-            sage: g.degree()
-            4
-            sage: g = -10/x^5 + x^2 - x^4 + O(x^8)
-            sage: g.degree()
-            4
-        """
-        return self.__u.degree() + self.valuation()
-
-# todo:
-# I commented out the following __sub__ because it doesn't fit the new
-# arithmetic architecture rules. Perhaps a native _sub_ implementation would
-# be reasonable to have, but it seems pretty well covered by the default
-# RingElement._sub_c_impl() implementation anyway, so why bother.
-#   -- David Harvey
-#
-# BTW should mention that David Roe is working on reimplementing laurent
-# series from scratch. (hopefully!)
-#
-#    def __sub__(self, right):
-#        """
-#        EXAMPLES:
-#            sage: R = LaurentSeriesRing(ZZ, 't')
-#            sage: f = t^2 + t^3 + O(t^10)
-#            sage: g = 3/t^4 + t^3 + O(t^5)
-#            sage: f - g
-#            -3*t^-4 + t^2 + O(t^5)
-#            sage: g - f
-#            3*t^-4 - t^2 + O(t^5)
-#        """
-#        return self + right.__neg__()
-
-# ditto with __neg__:
-#
-#    def __neg__(self):
-#        """
-#        EXAMPLES:
-#            sage: R.<t> = LaurentSeriesRing(ZZ)
-#            sage: f = 3/t^2 +  t^2 + t^3 + O(t^10)
-#            sage: f.__neg__()
-#            -3*t^-2 - t^2 - t^3 + O(t^10)
-#        """
-#        return (-1)*self
-
-    def _mul_(self, right):
-        """
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: f = 1/x^3 + x + x^2 + 3*x^4 + O(x^7)
-            sage: g = 1 - x + x^2 - x^4 + O(x^8)
-            sage: f*g
-            x^-3 - x^-2 + x^-1 + 4*x^4 + O(x^5)
-        """
-        return LaurentSeries(self.parent(),
-                             self.__u * right.__u,
-                             self.__n + right.__n)
-    def __pow__(self, r):
-        """
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: f = x + x^2 + 3*x^4 + O(x^7)
-            sage: g = 1/x^10 - x + x^2 - x^4 + O(x^8)
-            sage: f^7
-            x^7 + 7*x^8 + 21*x^9 + 56*x^10 + 161*x^11 + 336*x^12 + O(x^13)
-            sage: g^7
-            x^-70 - 7*x^-59 + 7*x^-58 - 7*x^-56 + O(x^-52)
-        """
-        right=int(r)
-        if right != r:
-            raise ValueError, "exponent must be an integer"
-        return LaurentSeries(self.parent(), self.__u**right, self.__n*right)
-
-        
-    def _div_(self, right):
-        """
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: f = x + x^2 + 3*x^4 + O(x^7)
-            sage: g = 1/x^7 - x + x^2 - x^4 + O(x^8)
-            sage: f/x
-            1 + x + 3*x^3 + O(x^6)
-            sage: f/g
-            x^8 + x^9 + 3*x^11 + O(x^14)
-        """
-        if right.__u.is_zero():
-            raise ZeroDivisionError
-        try:
-            return LaurentSeries(self.parent(),
-                             self.__u / right.__u,
-                             self.__n - right.__n)
-        except TypeError, msg:
-            # todo: this could also make something in the formal fraction field.
-            raise ArithmeticError, "division not defined"
-
-
-    def common_prec(self, f):
-        r"""
-        Returns minimum precision of $f$ and self.
-
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(QQ)
-
-            sage: f = t^(-1) + t + t^2 + O(t^3)
-            sage: g = t + t^3 + t^4 + O(t^4)
-            sage: f.common_prec(g)
-            3
-            sage: g.common_prec(f)
-            3
-
-            sage: f = t + t^2 + O(t^3)
-            sage: g = t^(-3) + t^2
-            sage: f.common_prec(g)
-            3
-            sage: g.common_prec(f)
-            3
-
-            sage: f = t + t^2
-            sage: f = t^2
-            sage: f.common_prec(g)
-            +Infinity
-
-            sage: f = t^(-3) + O(t^(-2))
-            sage: g = t^(-5) + O(t^(-1))
-            sage: f.common_prec(g)
-            -2
-        """
-        if self.prec() is infinity:
-            return f.prec()
-        elif f.prec() is infinity:
-            return self.prec()
-        return min(self.prec(), f.prec())
-
-    def __cmp__(self, right):
-        r"""
-        Comparison of self and right.
-
-        We say two approximate laurent series are equal, if they agree
-        for all coefficients up to the *minimum* of the precisions of
-        each. Comparison is done in dictionary order from lowest degree to
-        highest degree coefficients (this is different than
-        polynomials).
-
-        See power_series_ring_element.__cmp__() for more information.
-        
-        EXAMPLES:
-            sage: R.<x> = LaurentSeriesRing(QQ)
-            sage: f = x^(-1) + 1 + x + O(x^2)
-            sage: g = x^(-1) + 1 + O(x)
-            sage: f == g
-            True
-
-            sage: f = x^(-1) + 1 + x + O(x^2)
-            sage: g = x^(-1) + 2 + O(x)
-            sage: f == g
-            False
-            sage: f < g
-            True
-            sage: f > g
-            False
-
-            sage: f = x^(-2) + 1 + x + O(x^2)
-            sage: g = x^(-1) + 2 + O(x)
-            sage: f == g
-            False
-            sage: f < g
-            False
-            sage: f > g
-            True
-        """
-        prec = self.common_prec(right)
-        n = min(self.__n, right.__n)
-
-        # zero pad coefficients on the left, to line them up for comparison
-        zero = self.base_ring()(0)
-        x = [zero] * (self.__n - n) + self.__u.list()
-        y = [zero] * (right.__n - n) + right.__u.list()
-
-        # zero pad on right to make the lists the same length
-        # (this is necessary since the power series list() function just
-        # returns the coefficients of the underlying polynomial, which may
-        # have zeroes in the high coefficients)
-        if len(x) < len(y):
-            x.extend([zero] * (len(y) - len(x)))
-        elif len(y) < len(x):
-            y.extend([zero] * (len(x) - len(y)))
-
-        if not (prec is infinity):
-            x = x[:(prec-n)]
-            y = y[:(prec-n)]
-
-        return cmp(x,y)
-
-    def valuation_zero_part(self):
-        """
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: f = x + x^2 + 3*x^4 + O(x^7)
-            sage: f/x
-            1 + x + 3*x^3 + O(x^6)
-            sage: f.valuation_zero_part()
-            1 + x + 3*x^3 + O(x^6)
-            sage: g = 1/x^7 - x + x^2 - x^4 + O(x^8)
-            sage: g.valuation_zero_part()
-            1 - x^8 + x^9 - x^11 + O(x^15)
-        """
-        return self.__u
-
-    def valuation(self):
-        """
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: f = 1/x + x^2 + 3*x^4 + O(x^7)
-            sage: g = 1 - x + x^2 - x^4 + O(x^8)
-            sage: f.valuation()
-            -1
-            sage: g.valuation()
-            0
-        """
-        return self.__n
-
-    def variable(self):
-        """
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: f = 1/x + x^2 + 3*x^4 + O(x^7)
-            sage: f.variable()
-            'x'
-        """
-        return self.parent().variable_name()
-
-    def prec(self):
-        """
-        This function returns the n so that the Laurent series is
-        of the form (stuff) + $O(t^n)$.  It doesn't matter how many
-        negative powers appear in the expansion.  In particular,
-        prec could be negative.
-
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: f = x^2 + 3*x^4 + O(x^7)
-            sage: f.prec()
-            7
-            sage: g = 1/x^10 - x + x^2 - x^4 + O(x^8)
-            sage: g.prec()
-            8
-        """
-        return self.__u.prec() + self.valuation()
-
-    def copy(self):
-        return LaurentSeries(self.parent(), self.__u.copy(), self.__n)
-
-    def derivative(self):
-        """
-        The formal derivative of this Laurent series.
-
-        EXAMPLES:
-            sage: x = Frac(QQ[['x']]).0
-            sage: f = x^2 + 3*x^4 + O(x^7)
-            sage: f.derivative()
-            2*x + 12*x^3 + O(x^6)
-            sage: g = 1/x^10 - x + x^2 - x^4 + O(x^8)
-            sage: g.derivative()
-            -10*x^-11 - 1 + 2*x - 4*x^3 + O(x^7)
-        """
-        if self.is_zero():
-            return LaurentSeries(self.parent(), 0, self.__u.prec() - 1)
-        n = self.__n
-        a = self.__u.list()
-        v = [(n+m)*a[m] for m in range(len(a))]
-        u = self.parent().power_series_ring()(v, self.__u.prec())
-        return LaurentSeries(self.parent(), u, n-1)
-        
-    def integral(self):
-        r"""
-        The formal integral of this Laurent series with 0 constant term.
-
-        EXAMPLES:
-        The integral may or may not be defined if the base ring
-        is not a field.
-            sage: t = LaurentSeriesRing(ZZ, 't').0
-            sage: f = 2*t^-3 + 3*t^2 + O(t^4)
-            sage: f.integral()
-            -t^-2 + t^3 + O(t^5)
-
-            sage: f = t^3
-            sage: f.integral()
-            Traceback (most recent call last):
-            ...
-            ArithmeticError: Coefficients of integral cannot be coerced into the base ring
-            
-
-        The integral of 1/t is $\log(t)$, which is not given by a Laurent series:
-        
-            sage: t = Frac(QQ[['t']]).0
-            sage: f = -1/t^3 - 31/t + O(t^3)
-            sage: f.integral()
-            Traceback (most recent call last):
-            ...
-            ArithmeticError: The integral of is not a Laurent series, since t^-1 has nonzero coefficient.
-        """
-        n = self.__n
-        a = self.__u.list()
-        if self[-1] != 0:
-            raise ArithmeticError, \
-                  "The integral of is not a Laurent series, since t^-1 has nonzero coefficient."
-
-        if n < 0:
-            v = [a[i]/(n+i+1) for i in range(-1-n)] + [0]
-        else:
-            v = []
-        v += [a[i]/(n+i+1) for i in range(max(-n,0), len(a))]
-        try:
-            u = self.parent().power_series_ring()(v, self.__u.prec())
-        except TypeError:
-            raise ArithmeticError, "Coefficients of integral cannot be coerced into the base ring"
-        return LaurentSeries(self.parent(), u, n+1)
-
-
-    def power_series(self):
-        """
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(ZZ)
-            sage: f = 1/(1-t+O(t^10)); f.parent()
-            Laurent Series Ring in t over Integer Ring
-            sage: g = f.power_series(); g
-            1 + t + t^2 + t^3 + t^4 + t^5 + t^6 + t^7 + t^8 + t^9 + O(t^10)
-            sage: parent(g)
-            Power Series Ring in t over Integer Ring
-            sage: f = 3/t^2 +  t^2 + t^3 + O(t^10)
-            sage: f.power_series()
-            Traceback (most recent call last):
-            ...
-            ArithmeticError: self is a not a power series
-        """
-        if self.__n < 0:
-            raise ArithmeticError, "self is a not a power series"
-        u = self.__u
-        t = u.parent().gen()
-        return t**(self.__n) * u
-        
-    def __call__(self, *x):
-        """
-        Compute value of this Laurent series at x.
-
-        EXAMPLES:
-            sage: R.<t> = LaurentSeriesRing(ZZ)
-            sage: f = t^(-2) + t^2 + O(t^8)
-            sage: f(2)
-            17/4
-            sage: f(-1)
-            2
-            sage: f(1/3)
-            82/9
-        """
-        if isinstance(x[0], tuple):
-            x = x[0]
-        return self.__u(x) * (x[0]**self.__n)
-
-
Index: sage/rings/laurent_series_ring_element.pyx
===================================================================
--- sage/rings/laurent_series_ring_element.pyx	(revision 4279)
+++ sage/rings/laurent_series_ring_element.pyx	(revision 4279)
@@ -0,0 +1,850 @@
+"""
+Laurent Series
+
+EXAMPLES:
+
+    sage: R.<t> = LaurentSeriesRing(GF(7), 't'); R
+    Laurent Series Ring in t over Finite Field of size 7
+    sage: f = 1/(1-t+O(t^10)); f
+    1 + t + t^2 + t^3 + t^4 + t^5 + t^6 + t^7 + t^8 + t^9 + O(t^10)
+
+Laurent series are immutable:
+    sage: f[2]
+    1
+    sage: f[2] = 5
+    Traceback (most recent call last):
+    ...
+    IndexError: Laurent series are immutable    
+
+We compute with a Laurent series over the complex mpfr numbers. 
+    sage: K.<q> = Frac(CC[['q']])
+    sage: K
+    Laurent Series Ring in q over Complex Field with 53 bits of precision
+    sage: q
+    1.00000000000000*q
+
+Saving and loading.
+    sage: loads(q.dumps()) == q
+    True
+    sage: loads(K.dumps()) == K
+    True
+
+IMPLEMENTATION: Laurent series in SAGE are represented internally as a
+    power of the variable times the unit part (which need not be a
+    unit -- it's a polynomial with nonzero constant term).  The zero
+    Laurent series has unit part 0.
+
+
+AUTHORS:
+    -- William Stein: original version
+    -- David Joyner: added examples 2006-01-22
+    -- Robert Bradshaw: optimizations, shifting 2007-04
+    -- Robert Bradshaw: SageX version
+"""
+
+import operator
+
+from infinity import infinity
+
+import laurent_series_ring
+import power_series_ring_element
+import power_series_ring
+import polynomial_element as polynomial
+import sage.misc.latex
+import sage.rings.ring_element as ring_element
+from sage.rings.integer import Integer
+
+from sage.structure.element cimport Element, ModuleElement, RingElement, AlgebraElement
+
+def is_LaurentSeries(x):
+    return isinstance(x, LaurentSeries)
+
+cdef class LaurentSeries(AlgebraElement):
+    """
+    A Laurent Series.
+    """
+        
+    def __init__(self, parent, f, n=0):
+        r"""
+        Create the Laurent series $t^n \cdot f$.  The default is n=0.
+
+        INPUT:
+            parent -- a Laurent series ring
+            f -- a power series (or something can be coerced to one); note that
+                 f does *not* have to be a unit. 
+            n -- integer (default 0)
+
+        OUTPUT:
+            a Laurent series
+        """
+        AlgebraElement.__init__(self, parent)
+        if isinstance(f, LaurentSeries):
+            n += (<LaurentSeries>f).__n
+            f = parent.power_series_ring()((<LaurentSeries>f).__u)
+        elif not isinstance(f, power_series_ring_element.PowerSeries):
+            f = parent.power_series_ring()(f)
+
+        # self is that t^n * u:
+        if f.is_zero():
+            if n == infinity:
+                self.__n = 0
+                self.__u = parent.power_series_ring()(0)
+            else:
+                self.__n = n
+                self.__u = f
+        else:
+            self.__n = n + f.valuation()    # power of the variable
+            self.__u = f.valuation_zero_part()        # unit part
+            
+    def __reduce__(self):
+        return make_element_from_parent, (self._parent, self.__u, self.__n)
+        
+    def change_ring(self, R):
+        return self.parent().change_ring(R)(self)
+        
+    def is_unit(self):
+        """
+        Returns True if this is Laurent series is a unit in this ring.
+        
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ)
+            sage: (2+t).is_unit()
+            True
+            sage: f = 2+t^2+O(t^10); f.is_unit()
+            True
+            sage: 1/f
+            1/2 - 1/4*t^2 + 1/8*t^4 - 1/16*t^6 + 1/32*t^8 + O(t^10)
+            sage: R(0).is_unit()
+            False
+            sage: R.<s> = LaurentSeriesRing(ZZ)
+            sage: f = 2 + s^2 + O(s^10)
+            sage: f.is_unit()
+            False
+            sage: 1/f
+            Traceback (most recent call last):
+            ...
+            ArithmeticError: division not defined
+
+        ALGORITHM: A Laurent series is a unit if and only if
+        its "unit part" is a unit.
+        """
+        return self.__u.is_unit()
+
+    def is_zero(self):
+        """
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: f = 1/x + x + x^2 + 3*x^4 + O(x^7)
+            sage: f.is_zero()
+            0
+            sage: z = 0*f
+            sage: z.is_zero()
+            1
+        """
+        return self.__u.is_zero()
+        
+    def _im_gens_(self, codomain, im_gens):
+        return codomain(self(im_gens[0]))
+
+    def __normalize(self):
+        r"""
+        A Laurent series is a pair (u(t), n), where either u=0 (to
+        some precision) or u is a unit.  This pair corresponds to
+        $t^n\cdot u(t)$.
+        """
+        if self.is_zero():
+            return
+        v = self.__u.valuation()
+        if v == 0:
+            return
+        self.__n += v
+        self.__u = self.__u.valuation_zero_part()
+        
+    def _repr_(self):
+        """
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ)
+            sage: (2 + (2/3)*t^3).__repr__()
+            '2 + 2/3*t^3'
+        """
+        if self.is_zero():
+            if self.prec() == infinity:
+                return "0"
+            else:
+                return "O(%s^%s)"%(self._parent.variable_name(),self.prec())
+        s = " "
+        v = self.__u.list()
+        valuation = self.__n
+        m = len(v)
+        X = self._parent.variable_name()
+        atomic_repr = self._parent.base_ring().is_atomic_repr()
+        first = True
+        for n in xrange(m):
+            x = v[n]
+            e = n + valuation
+            if x != 0:
+                if not first:
+                    s += " + "
+                x = str(x)
+                if not atomic_repr and (x[1:].find("+") != -1 or x[1:].find("-") != -1):
+                    x = "(%s)"%x
+                if e == 1:
+                    var = "*%s"%X
+                elif e == 0:
+                    var = ""
+                else:
+                    var = "*%s^%s"%(X,e)
+                s += "%s%s"%(x,var)
+                first = False
+        if atomic_repr:
+            s = s.replace(" + -", " - ")
+        s = s.replace(" 1*"," ")
+        s = s.replace(" -1*", " -")
+        if self.prec() == 0:
+            bigoh = "O(1)"
+        elif self.prec() == 1:
+            bigoh = "O(%s)"%self._parent.variable_name()
+        else:
+            bigoh = "O(%s^%s)"%(self._parent.variable_name(),self.prec())
+        if self.prec() != infinity:
+            if s == " ":
+                return bigoh
+            s += " + %s"%bigoh
+        return s[1:]
+
+    def _latex_(self):
+        r"""
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: f = (17/2)*x^-2 + x + x^2 + 3*x^4 + O(x^7)
+            sage: latex(f)
+            \frac{\frac{17}{2}}{x^{2}} + x + x^{2} + 3x^{4} + O(\text{x}^{7})
+        """
+        if self.is_zero():
+            if self.prec() == infinity:
+                return "0"
+            else:
+                return "0 + \\cdots"
+        s = " "
+        v = self.__u.list()
+        valuation = self.__n
+        m = len(v)
+        X = self._parent.variable_name()
+        atomic_repr = self._parent.base_ring().is_atomic_repr()
+        first = True
+        for n in xrange(m):
+            x = v[n]
+            e = n + valuation
+            if x != 0:
+                if not first:
+                    s += " + "
+                x = sage.misc.latex.latex(x)
+                if not atomic_repr and n > 0 and (x[1:].find("+") != -1 or x[1:].find("-") != -1):
+                    x = "\\left(%s\\right)"%x
+                if e == 1:
+                    var = "|%s"%X
+                elif e == 0:
+                    var = ""
+                elif e > 0:
+                    var = "|%s^{%s}"%(X,e)
+                if e >= 0:
+                    s += "%s%s"%(x,var)
+                else: # negative e
+                    if e == -1:
+                        s += "\\frac{%s}{%s}"%(x, X)
+                    else:
+                        s += "\\frac{%s}{%s^{%s}}"%(x, X,-e)
+                first = False
+        if atomic_repr:
+            s = s.replace(" + -", " - ")
+        s = s.replace(" 1|"," ")
+        s = s.replace(" -1|", " -")
+        s = s.replace("|","")
+        pr = self.prec()
+        if pr != infinity:
+            if pr == 0:
+                bigoh = "O(1)"
+            elif pr == 1:
+                bigoh = "O(%s)"%sage.misc.latex.latex(self._parent.variable_name())
+            else:
+                bigoh = "O(%s^{%s})"%(sage.misc.latex.latex(self._parent.variable_name()),pr)
+            if s == " ":
+                return bigoh
+            s += " + %s"%bigoh
+        return s[1:]
+
+    def __getitem__(self, i):
+        """
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ)
+            sage: f = -5/t^(10) + t + t^2 - 10/3*t^3; f
+            -5*t^-10 + t + t^2 - 10/3*t^3
+            sage: f[-10]
+            -5
+            sage: f[1]
+            1
+            sage: f[3]
+            -10/3
+            sage: f[-9]
+            0
+        """
+        return self.__u[i-self.__n]
+
+    def __getslice__(self, i, j):
+        """
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ)
+            sage: f = -5/t^(10) + 1/3 + t + t^2 - 10/3*t^3 + O(t^5); f
+            -5*t^-10 + 1/3 + t + t^2 - 10/3*t^3 + O(t^5)
+            sage: f[-10:2]
+            -5*t^-10 + 1/3 + t + O(t^5)
+            sage: f[0:]
+            1/3 + t + t^2 - 10/3*t^3 + O(t^5)
+        """
+        if j > self.__u.degree():
+            j = self.__u.degree()
+        f = self.__u[i-self.__n:j-self.__n]
+        return LaurentSeries(self._parent, f, self.__n)
+
+    def __iter__(self):
+        """
+        Iterate through the coefficients from the first nonzero one to
+        the last nonzero one.
+        
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ)
+            sage: f = -5/t^(2) + t + t^2 - 10/3*t^3; f
+            -5*t^-2 + t + t^2 - 10/3*t^3
+            sage: for a in f: print a
+            -5
+            0
+            0
+            1
+            1
+            -10/3
+        """
+        return iter(self.__u)
+        
+    def list(self):
+        return self.__u.list()
+
+    def __setitem__(self, n, value):
+        """
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ)
+            sage: f = t^2 + t^3 + O(t^10)
+            sage: f[2] = 5
+            Traceback (most recent call last):
+            ...
+            IndexError: Laurent series are immutable
+        """
+        raise IndexError, "Laurent series are immutable"
+
+    def _unsafe_mutate(self, i, value):
+        """
+        SAGE assumes throughout that commutative ring elements are immutable.
+        This is relevant for caching, etc.  But sometimes you need to change
+        a Laurent series and you really know what you're doing.  That's
+        when this function is for you.
+
+        EXAMPLES:
+        
+        """
+        j = i - self.__n
+        if j >= 0:
+            self.__u._unsafe_mutate(j, value)
+        else: # off to the left
+            if value != 0:
+                self.__n = self.__n + j
+                R = self._parent.base_ring()
+                coeffs = [value] + [R(0) for _ in range(1,-j)] + self.__u.list()
+                self.__u = self.__u._parent(coeffs)
+        self.__normalize()
+
+    cdef ModuleElement _add_c_impl(self, ModuleElement right_m):
+        """
+        Add two power series with the same parent.
+        
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ)
+            sage: t + t
+            2*t
+            sage: f = 1/t + t^2 + t^3 - 17/3 * t^4 + O(t^5)
+            sage: g = 1/(1-t + O(t^7)); g
+            1 + t + t^2 + t^3 + t^4 + t^5 + t^6 + O(t^7)
+            sage: f + g
+            t^-1 + 1 + t + 2*t^2 + 2*t^3 - 14/3*t^4 + O(t^5)
+            sage: f + 0
+            t^-1 + t^2 + t^3 - 17/3*t^4 + O(t^5)
+            sage: 0 + f
+            t^-1 + t^2 + t^3 - 17/3*t^4 + O(t^5)
+            sage: R(0) + R(0)
+            0
+            sage: (t^3 + O(t^10)) + (t^-3 +O(t^9))
+            t^-3 + t^3 + O(t^9)
+            
+        ALGORITHM:
+            Shift the unit parts to align them, then add. 
+        """
+        cdef LaurentSeries right = <LaurentSeries>right_m
+        cdef long m
+        
+        # 1. Special case when one or the other is 0.
+        if right.is_zero():
+            return self.add_bigoh(right.prec())
+        if self.is_zero():
+            return right.add_bigoh(self.prec())
+
+        # 2. Align the unit parts.
+        if self.__n < right.__n:
+            m = self.__n
+            f1 = self.__u
+            f2 = right.__u << right.__n - m
+        else:
+            m = right.__n
+            f1 = self.__u << self.__n - m
+            f2 = right.__u
+        # 3. Add
+        return LaurentSeries(self._parent, f1 + f2, m)
+
+    cdef ModuleElement _sub_c_impl(self, ModuleElement right_m):
+        """
+        Subtract two power series with the same parent.
+        
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ)
+            sage: t - t
+            0
+            sage: t^5 + 2 * t^-5
+            2*t^-5 + t^5
+            
+        ALGORITHM:
+            Shift the unit parts to align them, then subtract. 
+        """
+        cdef LaurentSeries right = <LaurentSeries>right_m
+        cdef long m
+
+        # 1. Special case when one or the other is 0.
+        if right.is_zero():
+            return self.add_bigoh(right.prec())
+        if self.is_zero():
+            return -right.add_bigoh(self.prec())
+
+        # 2. Align the unit parts.
+        if self.__n < right.__n:
+            m = self.__n
+            f1 = self.__u
+            f2 = right.__u << right.__n - m
+        else:
+            m = right.__n
+            f1 = self.__u << self.__n - m
+            f2 = right.__u
+        # 3. Subtract
+        return LaurentSeries(self._parent, f1 - f2, m)
+
+
+    def add_bigoh(self, prec):
+        """
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ)
+            sage: f = t^2 + t^3 + O(t^10); f
+            t^2 + t^3 + O(t^10)
+            sage: f.add_bigoh(5)
+            t^2 + t^3 + O(t^5)
+        """
+        if prec == infinity or prec >= self.prec():
+            return self
+        u = self.__u.add_bigoh(prec - self.__n)
+        return LaurentSeries(self._parent, u, self.__n)
+
+    def degree(self):
+        """
+        Return the degree of a polynomial equivalent to this power
+        series modulo big oh of the precision.
+        
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: g = x^2 - x^4 + O(x^8)
+            sage: g.degree()
+            4
+            sage: g = -10/x^5 + x^2 - x^4 + O(x^8)
+            sage: g.degree()
+            4
+        """
+        return self.__u.degree() + self.__n
+
+
+    def __neg__(self):
+        """
+        sage: R.<t> = LaurentSeriesRing(QQ)
+        sage: -(1+t^5)
+        -1 - t^5
+        sage: -(1/(1+t+O(t^5)))
+        -1 + t - t^2 + t^3 - t^4 + O(t^5)
+        """
+        return LaurentSeries(self._parent, -self.__u, self.__n)
+
+    cdef RingElement _mul_c_impl(self, RingElement right_r):
+        """
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: f = 1/x^3 + x + x^2 + 3*x^4 + O(x^7)
+            sage: g = 1 - x + x^2 - x^4 + O(x^8)
+            sage: f*g
+            x^-3 - x^-2 + x^-1 + 4*x^4 + O(x^5)
+        """
+        cdef LaurentSeries right = <LaurentSeries>right_r
+        return LaurentSeries(self._parent,
+                             self.__u * right.__u,
+                             self.__n + right.__n)
+                             
+    cdef ModuleElement _rmul_c_impl(self, RingElement c):
+        return LaurentSeries(self._parent, c * self.__u, self.__n)
+                             
+    cdef ModuleElement _lmul_c_impl(self, RingElement c):
+        return LaurentSeries(self._parent, self.__u * c, self.__n)
+                             
+    def __pow__(_self, r, dummy):
+        """
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: f = x + x^2 + 3*x^4 + O(x^7)
+            sage: g = 1/x^10 - x + x^2 - x^4 + O(x^8)
+            sage: f^7
+            x^7 + 7*x^8 + 21*x^9 + 56*x^10 + 161*x^11 + 336*x^12 + O(x^13)
+            sage: g^7
+            x^-70 - 7*x^-59 + 7*x^-58 - 7*x^-56 + O(x^-52)
+        """
+        cdef LaurentSeries self = _self
+        right=int(r)
+        if right != r:
+            raise ValueError, "exponent must be an integer"
+        return LaurentSeries(self._parent, self.__u**right, self.__n*right)
+        
+    def shift(self, k):
+        r"""
+        Returns this laurent series multiplied by the power $t^n$. Does not
+        change this series.
+        
+        NOTE: 
+            Despite the fact that higher order terms are printed to the
+            right in a power series, right shifting decreases the powers
+            of $t$, while left shifting increases them. This is to be 
+            consistant with polynomials, integers, etc. 
+
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ['y'])
+            sage: f = (t+t^-1)^4; f
+            t^-4 + 4*t^-2 + 6 + 4*t^2 + t^4
+            sage: f.shift(10)
+            t^6 + 4*t^8 + 6*t^10 + 4*t^12 + t^14
+            sage: f >> 10
+            t^-14 + 4*t^-12 + 6*t^-10 + 4*t^-8 + t^-6
+            sage: t << 4
+            t^5
+            sage: t + O(t^3) >> 4
+            t^-3 + O(t^-1)
+            
+        AUTHOR:
+            -- Robert Bradshaw (2007-04-18)
+        """
+        return LaurentSeries(self._parent, self.__u, self.__n + k)        
+        
+    def __lshift__(LaurentSeries self, k):
+        return LaurentSeries(self._parent, self.__u, self.__n + k)
+
+    def __rshift__(LaurentSeries self, k):
+        return LaurentSeries(self._parent, self.__u, self.__n - k)
+
+        
+    cdef RingElement _div_c_impl(self, RingElement right_r):
+        """
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: f = x + x^2 + 3*x^4 + O(x^7)
+            sage: g = 1/x^7 - x + x^2 - x^4 + O(x^8)
+            sage: f/x
+            1 + x + 3*x^3 + O(x^6)
+            sage: f/g
+            x^8 + x^9 + 3*x^11 + O(x^14)
+        """
+        cdef LaurentSeries right = <LaurentSeries>right_r
+        if right.__u.is_zero():
+            raise ZeroDivisionError
+        try:
+            return LaurentSeries(self._parent,
+                             self.__u / right.__u,
+                             self.__n - right.__n)
+        except TypeError, msg:
+            # todo: this could also make something in the formal fraction field.
+            raise ArithmeticError, "division not defined"
+
+
+    def common_prec(self, f):
+        r"""
+        Returns minimum precision of $f$ and self.
+
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(QQ)
+
+            sage: f = t^(-1) + t + t^2 + O(t^3)
+            sage: g = t + t^3 + t^4 + O(t^4)
+            sage: f.common_prec(g)
+            3
+            sage: g.common_prec(f)
+            3
+
+            sage: f = t + t^2 + O(t^3)
+            sage: g = t^(-3) + t^2
+            sage: f.common_prec(g)
+            3
+            sage: g.common_prec(f)
+            3
+
+            sage: f = t + t^2
+            sage: f = t^2
+            sage: f.common_prec(g)
+            +Infinity
+
+            sage: f = t^(-3) + O(t^(-2))
+            sage: g = t^(-5) + O(t^(-1))
+            sage: f.common_prec(g)
+            -2
+        """
+        if self.prec() is infinity:
+            return f.prec()
+        elif f.prec() is infinity:
+            return self.prec()
+        return min(self.prec(), f.prec())
+
+    cdef int _cmp_c_impl(self, Element right_r) except -2:
+        r"""
+        Comparison of self and right.
+
+        We say two approximate laurent series are equal, if they agree
+        for all coefficients up to the *minimum* of the precisions of
+        each. Comparison is done in dictionary order from lowest degree to
+        highest degree coefficients (this is different than
+        polynomials).
+
+        See power_series_ring_element.__cmp__() for more information.
+        
+        EXAMPLES:
+            sage: R.<x> = LaurentSeriesRing(QQ)
+            sage: f = x^(-1) + 1 + x + O(x^2)
+            sage: g = x^(-1) + 1 + O(x)
+            sage: f == g
+            True
+
+            sage: f = x^(-1) + 1 + x + O(x^2)
+            sage: g = x^(-1) + 2 + O(x)
+            sage: f == g
+            False
+            sage: f < g
+            True
+            sage: f > g
+            False
+
+            sage: f = x^(-2) + 1 + x + O(x^2)
+            sage: g = x^(-1) + 2 + O(x)
+            sage: f == g
+            False
+            sage: f < g
+            False
+            sage: f > g
+            True
+        """
+        cdef LaurentSeries right = <LaurentSeries>right_r
+
+        prec = self.common_prec(right)
+        n = min(self.__n, right.__n)
+
+        # zero pad coefficients on the left, to line them up for comparison
+        zero = self.base_ring()(0)
+        x = [zero] * (self.__n - n) + self.__u.list()
+        y = [zero] * (right.__n - n) + right.__u.list()
+
+        # zero pad on right to make the lists the same length
+        # (this is necessary since the power series list() function just
+        # returns the coefficients of the underlying polynomial, which may
+        # have zeroes in the high coefficients)
+        if len(x) < len(y):
+            x.extend([zero] * (len(y) - len(x)))
+        elif len(y) < len(x):
+            y.extend([zero] * (len(x) - len(y)))
+
+        if not (prec is infinity):
+            x = x[:(prec-n)]
+            y = y[:(prec-n)]
+
+        return cmp(x,y)
+
+    def valuation_zero_part(self):
+        """
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: f = x + x^2 + 3*x^4 + O(x^7)
+            sage: f/x
+            1 + x + 3*x^3 + O(x^6)
+            sage: f.valuation_zero_part()
+            1 + x + 3*x^3 + O(x^6)
+            sage: g = 1/x^7 - x + x^2 - x^4 + O(x^8)
+            sage: g.valuation_zero_part()
+            1 - x^8 + x^9 - x^11 + O(x^15)
+        """
+        return self.__u
+
+    def valuation(self):
+        """
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: f = 1/x + x^2 + 3*x^4 + O(x^7)
+            sage: g = 1 - x + x^2 - x^4 + O(x^8)
+            sage: f.valuation()
+            -1
+            sage: g.valuation()
+            0
+        """
+        return self.__n
+
+    def variable(self):
+        """
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: f = 1/x + x^2 + 3*x^4 + O(x^7)
+            sage: f.variable()
+            'x'
+        """
+        return self._parent.variable_name()
+
+    def prec(self):
+        """
+        This function returns the n so that the Laurent series is
+        of the form (stuff) + $O(t^n)$.  It doesn't matter how many
+        negative powers appear in the expansion.  In particular,
+        prec could be negative.
+
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: f = x^2 + 3*x^4 + O(x^7)
+            sage: f.prec()
+            7
+            sage: g = 1/x^10 - x + x^2 - x^4 + O(x^8)
+            sage: g.prec()
+            8
+        """
+        return self.__u.prec() + self.__n
+
+    def copy(self):
+        return LaurentSeries(self._parent, self.__u.copy(), self.__n)
+
+    def derivative(self):
+        """
+        The formal derivative of this Laurent series.
+
+        EXAMPLES:
+            sage: x = Frac(QQ[['x']]).0
+            sage: f = x^2 + 3*x^4 + O(x^7)
+            sage: f.derivative()
+            2*x + 12*x^3 + O(x^6)
+            sage: g = 1/x^10 - x + x^2 - x^4 + O(x^8)
+            sage: g.derivative()
+            -10*x^-11 - 1 + 2*x - 4*x^3 + O(x^7)
+        """
+        if self.is_zero():
+            return LaurentSeries(self._parent, 0, self.__u.prec() - 1)
+        cdef long m, n = self.__n
+        a = self.__u.list()
+        v = [(n+m)*a[m] for m from 0 <= m < len(a)]
+        u = self._parent.power_series_ring()(v, self.__u.prec())
+        return LaurentSeries(self._parent, u, n-1)
+        
+    def integral(self):
+        r"""
+        The formal integral of this Laurent series with 0 constant term.
+
+        EXAMPLES:
+        The integral may or may not be defined if the base ring
+        is not a field.
+            sage: t = LaurentSeriesRing(ZZ, 't').0
+            sage: f = 2*t^-3 + 3*t^2 + O(t^4)
+            sage: f.integral()
+            -t^-2 + t^3 + O(t^5)
+
+            sage: f = t^3
+            sage: f.integral()
+            Traceback (most recent call last):
+            ...
+            ArithmeticError: Coefficients of integral cannot be coerced into the base ring
+            
+
+        The integral of 1/t is $\log(t)$, which is not given by a Laurent series:
+        
+            sage: t = Frac(QQ[['t']]).0
+            sage: f = -1/t^3 - 31/t + O(t^3)
+            sage: f.integral()
+            Traceback (most recent call last):
+            ...
+            ArithmeticError: The integral of is not a Laurent series, since t^-1 has nonzero coefficient.
+        """
+        cdef long i, n = self.__n
+        a = self.__u.list()
+        if self[-1] != 0:
+            raise ArithmeticError, \
+                  "The integral of is not a Laurent series, since t^-1 has nonzero coefficient."
+
+        if n < 0:
+            v = [a[i]/(n+i+1) for i in range(-1-n)] + [0]
+        else:
+            v = []
+        v += [a[i]/(n+i+1) for i in range(max(-n,0), len(a))]
+        try:
+            u = self._parent.power_series_ring()(v, self.__u.prec())
+        except TypeError:
+            raise ArithmeticError, "Coefficients of integral cannot be coerced into the base ring"
+        return LaurentSeries(self._parent, u, n+1)
+
+
+    def power_series(self):
+        """
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(ZZ)
+            sage: f = 1/(1-t+O(t^10)); f.parent()
+            Laurent Series Ring in t over Integer Ring
+            sage: g = f.power_series(); g
+            1 + t + t^2 + t^3 + t^4 + t^5 + t^6 + t^7 + t^8 + t^9 + O(t^10)
+            sage: parent(g)
+            Power Series Ring in t over Integer Ring
+            sage: f = 3/t^2 +  t^2 + t^3 + O(t^10)
+            sage: f.power_series()
+            Traceback (most recent call last):
+            ...
+            ArithmeticError: self is a not a power series
+        """
+        if self.__n < 0:
+            raise ArithmeticError, "self is a not a power series"
+        u = self.__u
+        t = u.parent().gen()
+        return t**(self.__n) * u
+        
+    def __call__(self, *x):
+        """
+        Compute value of this Laurent series at x.
+
+        EXAMPLES:
+            sage: R.<t> = LaurentSeriesRing(ZZ)
+            sage: f = t^(-2) + t^2 + O(t^8)
+            sage: f(2)
+            17/4
+            sage: f(-1)
+            2
+            sage: f(1/3)
+            82/9
+        """
+        if isinstance(x[0], tuple):
+            x = x[0]
+        return self.__u(x) * (x[0]**self.__n)
+
+
+def make_element_from_parent(parent, *args):
+    return parent(*args)
Index: sage/rings/morphism.py
===================================================================
--- sage/rings/morphism.py	(revision 3354)
+++ sage/rings/morphism.py	(revision 4077)
@@ -282,4 +282,20 @@
     sage: i(beta^2 + 1)
     2.58740105196820
+
+TESTS:
+    sage: H = Hom(ZZ, QQ)
+    sage: H == loads(dumps(H))
+    True
+
+    sage: K.<zeta7> = CyclotomicField(7)
+    sage: c = K.hom([1/zeta7])
+    sage: c == loads(dumps(c))
+    True
+
+    sage: R.<t> = PowerSeriesRing(GF(5))
+    sage: f = R.hom([t^5])
+    sage: f == loads(dumps(f))
+    True
+
 """
 
@@ -329,7 +345,9 @@
         sage: S.lift()
         Set-theoretic ring morphism:
-          From: Quotient of Polynomial Ring in x, y over Rational Field by the ideal (y, y^2 + x^2)
+          From: Quotient of Polynomial Ring in x, y over Rational Field by the ideal (y^2 + x^2, y)
           To:   Polynomial Ring in x, y over Rational Field
           Defn: Choice of lifting map
+        sage: S.lift() == 0
+        False
     """
     def __init__(self, R, S):
@@ -342,4 +360,9 @@
             raise TypeError, "No natural lift map"
 
+    def __cmp__(self, other):
+        if not isinstance(other, RingMap_lift):
+            return cmp(type(self), type(other))
+        return 0
+        
     def _repr_defn(self):
         return "Choice of lifting map"
@@ -379,5 +402,8 @@
         A *ring* homomorphism is considered to be 0 if and only if
         it sends the 1 element of the domain to the 0 element of the
-        codomain.
+        codomain.  Since rings in SAGE all have a 1 element, the
+        zero homomorphism is only to a ring of order 1, where 1==0,
+        e.g., the ring \code{Integers(1)}.
+        
 
         EXAMPLES:
@@ -453,4 +479,48 @@
         return self.__im_gens
 
+    def __cmp__(self, other):
+        """
+        EXAMPLES:
+        A single variate quotient over QQ.
+            sage: R.<x> = QQ[]
+            sage: Q.<a> = R.quotient(x^2 + x + 1)
+            sage: f1 = R.hom([a])
+            sage: f2 = R.hom([a + a^2 + a + 1])
+            sage: f1 == f2
+            True
+            sage: f1 == R.hom([a^2])
+            False
+            sage: f1(x^3 + x)
+            a + 1
+            sage: f2(x^3 + x)
+            a + 1
+
+        TESTS:
+            sage: loads(dumps(f2)) == f2
+            True
+
+        EXAMPLES:
+        A multivariate quotient over a finite field.
+            sage: R.<x,y> = GF(7)[]
+            sage: Q.<a,b> = R.quotient([x^2 + x + 1, y^2 + y + 1])
+            sage: f1 = R.hom([a, b])
+            sage: f2 = R.hom([a + a^2 + a + 1, b + b^2 + b + 1])
+            sage: f1 == f2
+            True
+            sage: f1 == R.hom([b,a])
+            False
+            sage: f1(x^3 + x + y^2)
+            6*b + a
+            sage: f2(x^3 + x + y^2)
+            6*b + a
+
+        TEST:
+            sage: loads(dumps(f2)) == f2
+            True
+        """
+        if not isinstance(other, RingHomomorphism_im_gens):
+            return cmp(type(self), type(other))
+        return cmp(self.__im_gens, other.__im_gens)
+
     def _repr_defn(self):
         D = self.domain()
@@ -477,6 +547,6 @@
         b + a
     """
-    def __init__(self, ring, quotient_ring):
-        RingHomomorphism.__init__(self, ring.Hom(quotient_ring))
+    def __init__(self, parent):
+        RingHomomorphism.__init__(self, parent)
 
     def _call_(self, x):
@@ -489,4 +559,18 @@
         return self.codomain().defining_ideal()
     
+    def __cmp__(self, other):
+        """
+        EXAMPLES:
+            sage: R.<x,y> = PolynomialRing(QQ, 2)
+            sage: S.<a,b> = R.quo(x^2 + y^2)
+            sage: phi = S.cover()
+            sage: phi == loads(dumps(phi))
+            True
+            sage: phi == R.quo(x^2 + y^3).cover()
+            False
+        """
+        if not isinstance(other, RingHomomorphism_cover):
+            return cmp(type(self), type(other))
+        return 0  # since parents are the same, i.e., both cover maps with same domain and codomain
 
 class RingHomomorphism_from_quotient(RingHomomorphism):
@@ -517,5 +601,6 @@
         sage: phi(a+b+c)
         c + b + a
-        
+        sage: loads(dumps(phi)) == phi
+        True        
 
      Validity of the homomorphism is determined, when possible, and a
@@ -539,6 +624,30 @@
         self.__phi = phi
 
+    def _phi(self):
+        """
+        Underlying morphism used to define this quotient map (i.e.,
+        morphism from the cover of the domain).
+        """
+        return self.__phi
+
     def morphism_from_cover(self):
         return self.__phi
+
+    def __cmp__(self, other):
+        """
+        EXAMPLES:
+            sage: R.<x, y, z> = PolynomialRing(GF(19), 3)
+            sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3)
+            sage: phi = S.hom([b, c, a])
+            sage: psi = S.hom([c, b, a])
+            sage: f = S.hom([b, c, a + a^3 + b^3 + c^3])
+            sage: phi == psi
+            False
+            sage: phi == f
+            True
+        """
+        if not isinstance(other, RingHomomorphism_from_quotient):
+            return cmp(type(self), type(other))
+        return cmp(self.__phi, other.__phi)
 
     def _repr_defn(self):
Index: sage/rings/mpfr.pxi
===================================================================
--- sage/rings/mpfr.pxi	(revision 3927)
+++ sage/rings/mpfr.pxi	(revision 4151)
@@ -37,4 +37,6 @@
     void mpfr_clear (mpfr_t x)
 
+    mp_prec_t mpfr_get_prec (mpfr_t x)
+    
     int mpfr_set (mpfr_t rop, mpfr_t op, mp_rnd_t rnd)
     int mpfr_set_si (mpfr_t rop, long int op, mp_rnd_t rnd)
Index: sage/rings/multi_polynomial_element.py
===================================================================
--- sage/rings/multi_polynomial_element.py	(revision 4091)
+++ sage/rings/multi_polynomial_element.py	(revision 4171)
@@ -71,4 +71,66 @@
         return "%s"%self.__element
 
+    ####################
+    # Some standard conversions
+    ####################
+    def __int__(self):
+        if self.degree() == 0:
+            return int(self.constant_coefficient())
+        else:
+            raise TypeError
+        
+    def __long__(self):
+        if self.degree() == 0:
+            return long(self.constant_coefficient())
+        else:
+            raise TypeError
+
+    def __float__(self):
+        if self.degree() == 0:
+            return float(self.constant_coefficient())
+        else:
+            raise TypeError
+
+    def _mpfr_(self, R):
+        if self.degree() == 0:
+            return R(self.constant_coefficient())
+        else:
+            raise TypeError
+
+    def _complex_mpfr_field_(self, R):
+        if self.degree() == 0:
+            return R(self.constant_coefficient())
+        else:
+            raise TypeError
+
+    def _complex_double_(self, R):
+        if self.degree() == 0:
+            return R(self.constant_coefficient())
+        else:
+            raise TypeError
+
+    def _real_double_(self, R):
+        if self.degree() == 0:
+            return R(self.constant_coefficient())
+        else:
+            raise TypeError
+        
+    def _rational_(self):
+        if self.degree() == 0:
+            from rational import Rational
+            return Rational(repr(self))
+        else:
+            raise TypeError
+
+    def _integer_(self):
+        if self.degree() == 0:
+            from integer import Integer
+            return Integer(repr(self))
+        else:
+            raise TypeError
+    
+
+    ####################
+
     def __call__(self, *x):
         """
@@ -227,5 +289,5 @@
     def __pow__(self, n):
         if not isinstance(n, (int, long, integer.Integer)):
-            raise TypeError, "The exponent must be an integer."
+            n = integer.Integer(n)
         if n < 0:
             return 1/(self**(-n))
@@ -239,4 +301,7 @@
     def element(self):
         return self.__element
+        
+    def change_ring(self, R):
+        return self.parent().change_ring(R)(self)
 
 
@@ -307,5 +372,5 @@
 
         INPUT:
-            x -- multivariate polynmial (a generator of the parent of self)
+            x -- multivariate polynomial (a generator of the parent of self)
                  If x is not specified (or is None), return the total degree,
                  which is the maximum degree of any monomial.
@@ -489,6 +554,6 @@
             sage: c = f.coefficient(x*y); c
             2
-            sage: c in QQ
-            False
+            sage: c.parent()
+            Polynomial Ring in x, y over Rational Field
             sage: c in MPolynomialRing(RationalField(), 2, names = ['x','y'])
             True
@@ -973,11 +1038,11 @@
         return self._MPolynomial_element__element != right._MPolynomial_element__element
 
-    def is_zero(self):
-        """
-        Returns True if self == 0
+    def __nonzero__(self):
+        """
+        Returns True if self != 0
 
         \note{This is much faster than actually writing self == 0}
         """
-        return self._MPolynomial_element__element.dict()=={}
+        return self._MPolynomial_element__element.dict()!={}
 
     ############################################################################
@@ -1051,5 +1116,5 @@
             sage: M = f.lift(I)
             sage: M
-            [y^4 + x*y^5 + x^2*y^3 + x^3*y^4 + x^4*y^2 + x^5*y^3 + x^6*y + x^7*y^2 + x^8, y^7]
+            [y^7, y^4 + x*y^5 + x^2*y^3 + x^3*y^4 + x^4*y^2 + x^5*y^3 + x^6*y + x^7*y^2 + x^8]
             sage: sum( map( mul , zip( M, I.gens() ) ) ) == f
             True
Index: sage/rings/multi_polynomial_ideal.py
===================================================================
--- sage/rings/multi_polynomial_ideal.py	(revision 3645)
+++ sage/rings/multi_polynomial_ideal.py	(revision 4261)
@@ -61,4 +61,11 @@
     sage: 0 in j                                                # optional
     True
+
+TESTS:
+    sage: x,y,z = QQ['x,y,z'].gens()
+    sage: I = ideal(x^5 + y^4 + z^3 - 1,  x^3 + y^3 + z^2 - 1)
+    sage: I == loads(dumps(I))
+    True
+
 """
 
@@ -170,6 +177,6 @@
             sage: S = I._singular_()
             sage: S
-            y,
-            x^3+y
+            x^3+y,
+            y
         """
         if singular is None: singular = singular_default
@@ -330,8 +337,8 @@
         return self.__dimension
         
-    def _singular_groebner_basis(self, algorithm="groebner"):
+    def _groebner_basis_using_singular(self, algorithm="groebner"):
         """
         Return a Groebner basis of this ideal. If a groebner basis for
-        this ideal has been calculated before the cached groebner
+        this ideal has been calculated before the cached Groebner
         basis is returned regardless of the requested algorithm.
 
@@ -357,12 +364,6 @@
             sage: I = sage.rings.ideal.Cyclic(R,4); I
             Ideal (d + c + b + a, c*d + b*c + a*d + a*b, b*c*d + a*c*d + a*b*d + a*b*c, -1 + a*b*c*d) of Polynomial Ring in a, b, c, d over Rational Field
-            sage: I.groebner_basis()
+            sage: I._groebner_basis_using_singular()
             [1 - d^4 - c^2*d^2 + c^2*d^6, -1*d - c + c^2*d^3 + c^3*d^2, -1*d + d^5 - b + b*d^4, -1*d^2 - d^6 + c*d + c^2*d^4 - b*d^5 + b*c, d^2 + 2*b*d + b^2, d + c + b + a]
-            
-        \note{Some Groebner basis calculations crash on 64-bit
-        opterons with \SAGE's singular build, but work fine with an
-        official binary.  If you download and install a Singular
-        binary from the Singular website it will not have this problem
-        (you can use it with \SAGE by putting it in local/bin/).}
         """
         try:
@@ -387,4 +388,25 @@
         return self.__groebner_basis
 
+    def _singular_groebner_basis(self):
+        try:
+            S = self.__singular_groebner_basis
+        except AttributeError:
+            G = self.groebner_basis()
+            try:
+                return self.__singular_groebner_basis
+            except AttributeError:
+                pass
+
+        try:
+            S._check_valid()
+            return S
+        except ValueError:
+            G = self.groebner_basis()
+            S = singular(G)
+            self.__singular_groebner_basis = S
+        return S
+            
+    
+
     def genus(self):
         """
@@ -417,5 +439,5 @@
             Ideal (y^2, x*y, x^2) of Polynomial Ring in x, y over Rational Field
             sage: IJ = I*J; IJ
-            Ideal (y^3, x*y, x^2*y^2, x^3) of Polynomial Ring in x, y over Rational Field
+            Ideal (x^2*y^2, x^3, y^3, x*y) of Polynomial Ring in x, y over Rational Field
             sage: IJ == K
             False
@@ -441,5 +463,5 @@
             sage: I = (p*q^2, y-z^2)*R
             sage: I.minimal_associated_primes ()
-            [Ideal (-1*z^2 + y, 2 + z^3) of Polynomial Ring in x, y, z over Rational Field, Ideal (-1*z^2 + y, 1 + z^2) of Polynomial Ring in x, y, z over Rational Field]
+            [Ideal (2 + z^3, -1*z^2 + y) of Polynomial Ring in x, y, z over Rational Field, Ideal (1 + z^2, -1*z^2 + y) of Polynomial Ring in x, y, z over Rational Field]
         
         ALGORITHM: Uses Singular.
@@ -509,5 +531,5 @@
             sage: I = ideal([x^2,x*y^4,y^5])
             sage: I.integral_closure()
-            [x^2, y^5, x*y^3]
+            [x^2, y^5, -1*x*y^3]
 
         ALGORITHM: Use Singular
@@ -547,20 +569,31 @@
         if self.base_ring() == sage.rings.integer_ring.ZZ:
             return self._reduce_using_macaulay2(f)
-        
-        try:
-            singular = self.__singular_groebner_basis.parent()
-        except AttributeError:
-            self.groebner_basis()
-            singular = self.__singular_groebner_basis.parent()
+
+        try:
+            singular = self._singular_groebner_basis().parent()
+        except (AttributeError, RuntimeError):
+            singular = self._singular_groebner_basis().parent()
         
         f = self.ring()(f)
         g = singular(f)
         try:
-            h = g.reduce(self.__singular_groebner_basis)
+            self.ring()._singular_(singular).set_ring()            
+            h = g.reduce(self._singular_groebner_basis())
         except TypeError:
             # This is OK, since f is in the right ring -- type error
             # just means it's a rational
             return f
-        return self.ring()(h)
+        try:
+            return self.ring()(h)
+        except (TypeError, RuntimeError):
+            return self.ring()(h[1])
+            # Why the above?
+            # For mysterious reasons, sometimes Singular returns a length
+            # one vector with the reduced polynomial in it.
+            # This occurs in the following example:
+            #sage: R.<x,y> = PolynomialRing(QQ, 2)
+            #sage: S.<a,b> = R.quotient(x^2 + y^2)
+            #sage: phi = S.hom([b,a])
+            #sage: loads(dumps(phi))
 
 
@@ -809,5 +842,5 @@
             sage: R.<x,y> = PolynomialRing(IntegerRing(), 2, order='lex')
             sage: R.ideal([x, y])
-            Ideal (y, x) of Polynomial Ring in x, y over Integer Ring
+            Ideal (x, y) of Polynomial Ring in x, y over Integer Ring
             sage: R.<x0,x1> = GF(3)[]
             sage: R.ideal([x0^2, x1^3])
@@ -856,7 +889,7 @@
                 return self._macaulay2_groebner_basis()
             else:
-                return self._singular_groebner_basis("groebner")
+                return self._groebner_basis_using_singular("groebner")
         elif algorithm.startswith('singular:'):
-            return self._singular_groebner_basis(algorithm[9:])
+            return self._groebner_basis_using_singular(algorithm[9:])
         elif algorithm == 'macaulay2:gb':
             return self._macaulay2_groebner_basis()
Index: sage/rings/multi_polynomial_libsingular.pyx
===================================================================
--- sage/rings/multi_polynomial_libsingular.pyx	(revision 4365)
+++ sage/rings/multi_polynomial_libsingular.pyx	(revision 4366)
@@ -473,5 +473,5 @@
             sage: P.<x,y,z> = MPolynomialRing_libsingular(QQ,3)
             sage: sage.rings.ideal.Katsura(P)
-            Ideal (x + 2*y + 2*z - 1, 2*x*y + 2*y*z - y, x^2 + 2*y^2 + 2*z^2 - x) of Polynomial Ring in x, y, z over Rational Field
+            Ideal (x + 2*y + 2*z - 1, x^2 + 2*y^2 + 2*z^2 - x, 2*x*y + 2*y*z - y) of Polynomial Ring in x, y, z over Rational Field
 
             sage: P.ideal([x + 2*y + 2*z-1, 2*x*y + 2*y*z-y, x^2 + 2*y^2 + 2*z^2-x])
Index: sage/rings/multi_polynomial_ring.py
===================================================================
--- sage/rings/multi_polynomial_ring.py	(revision 4091)
+++ sage/rings/multi_polynomial_ring.py	(revision 4259)
@@ -85,4 +85,5 @@
 
 from multi_polynomial_ring_generic import MPolynomialRing_generic, is_MPolynomialRing
+
 
 class MPolynomialRing_macaulay2_repr:
@@ -112,4 +113,11 @@
         return self.__macaulay2
 
+    def is_exact(self):
+        return self.base_ring().is_exact()
+        
+    def change_ring(self, R):
+        from polynomial_ring_constructor import PolynomialRing
+        return PolynomialRing(R, self.variable_names(), order=self.term_order())
+
 class MPolynomialRing_polydict( MPolynomialRing_macaulay2_repr, MPolynomialRing_generic):
     """
@@ -187,9 +195,6 @@
             Polynomial Ring in x, y over Rational Field
 
-        We create an equal but not identical copy of the integer ring
-        by dumping and loading:
+        We dump and load a the polynomial ring S:
             sage: S2 = loads(dumps(S))
-            sage: S2 is S
-            False
             sage: S2 == S
             True
@@ -204,5 +209,30 @@
             sage: f = x^2 + 2/3*y^3
             sage: S(f)
-            3*b^3 + a^2        
+            3*b^3 + a^2
+
+        Coercion from symbolic variables:
+            sage: x,y,z = var('x,y,z')
+            sage: R = QQ[x,y,z]
+            sage: type(x)
+            <class 'sage.calculus.calculus.SymbolicVariable'>
+            sage: type(R(x))
+            <class 'sage.rings.multi_polynomial_element.MPolynomial_polydict'>
+            sage: f = R(x^3 + y^3 - z^3); f
+            -1*z^3 + y^3 + x^3
+            sage: type(f)
+            <class 'sage.rings.multi_polynomial_element.MPolynomial_polydict'>
+            sage: parent(f)
+            Polynomial Ring in x, y, z over Rational Field
+
+        A more complicated symbolic and computational mix.  Behind the scenes
+        Singular and Maxima are doing the real work. 
+            sage: R = QQ[x,y,z]
+            sage: f = (x^3 + y^3 - z^3)^10; f
+            (-z^3 + y^3 + x^3)^10
+            sage: g = R(f); parent(g)
+            Polynomial Ring in x, y, z over Rational Field
+            sage: (f - g).expand()
+            0
+            
         """
         if isinstance(x, multi_polynomial_element.MPolynomial_polydict):
@@ -227,4 +257,5 @@
         elif isinstance(x, polydict.PolyDict):
             return multi_polynomial_element.MPolynomial_polydict(self, x)
+        
         elif isinstance(x, fraction_field_element.FractionFieldElement) and x.parent().ring() == self:
             if x.denominator() == 1:
@@ -232,16 +263,22 @@
             else:
                 raise TypeError, "unable to coerce since the denominator is not 1"
+
         elif is_SingularElement(x) and self._has_singular:
             self._singular_().set_ring()
             try:
                 return x.sage_poly(self)
-            except:
-                raise TypeError, "Unable to coerce singular object"
+            except TypeError:
+                raise TypeError, "unable to coerce singular object"
+
+        elif hasattr(x, '_polynomial_'):
+            return x._polynomial_(self)
+        
         elif isinstance(x , str) and self._has_singular:
             self._singular_().set_ring()
             try:
                 return self._singular_().parent(x).sage_poly(self)
-            except:
-                raise TypeError,"Unable to coerce string"
+            except TypeError:
+                raise TypeError,"unable to coerce string"
+            
         elif is_Macaulay2Element(x):
             try:
@@ -257,6 +294,10 @@
                 raise TypeError, "Unable to coerce macaulay2 object"
             return multi_polynomial_element.MPolynomial_polydict(self, x)
-        c = self.base_ring()(x)
-        return multi_polynomial_element.MPolynomial_polydict(self, {self._zero_tuple:c})
+
+        if isinstance(x, dict):
+            return multi_polynomial_element.MPolynomial_polydict(self, x)
+        else:
+            c = self.base_ring()(x)
+            return multi_polynomial_element.MPolynomial_polydict(self, {self._zero_tuple:c})
 
 
Index: sage/rings/multi_polynomial_ring_generic.pyx
===================================================================
--- sage/rings/multi_polynomial_ring_generic.pyx	(revision 4091)
+++ sage/rings/multi_polynomial_ring_generic.pyx	(revision 4109)
@@ -239,6 +239,13 @@
         order = self.term_order()
         
-        return unpickle_MPolynomialRing_generic,(base_ring, n, names, order)
-
+        return unpickle_MPolynomialRing_generic_v1,(base_ring, n, names, order)
+
+
+####################
+# Leave *all* old versions!
+
+def unpickle_MPolynomialRing_generic_v1(base_ring, n, names, order):
+    from sage.rings.multi_polynomial_ring import MPolynomialRing
+    return MPolynomialRing(base_ring, n, names=names, order=order)
 
 
@@ -246,3 +253,3 @@
     from sage.rings.multi_polynomial_ring import MPolynomialRing
     
-    return MPolynomialRing(base_ring, n, names, order)
+    return MPolynomialRing(base_ring, n, names=names, order=order)
Index: sage/rings/number_field/number_field.py
===================================================================
--- sage/rings/number_field/number_field.py	(revision 3650)
+++ sage/rings/number_field/number_field.py	(revision 4058)
@@ -98,8 +98,7 @@
 
     EXAMPLES: Constructing a relative number field
-        sage: R.<x> = PolynomialRing(QQ)
         sage: K.<a> = NumberField(x^2 - 2)
-        sage: R.<t> = K['t']
-        sage: L = K.extension(t^3+t+a, 'b'); L
+        sage: R.<t> = K[]
+        sage: L = K.extension(t^3+t+a, b); L
         Extension by t^3 + t + a of the Number Field in a with defining polynomial x^2 - 2
         sage: L.absolute_field()
@@ -125,4 +124,11 @@
 
     name = sage.structure.parent_gens.normalize_names(1, name)
+    if not isinstance(polynomial, polynomial_element.Polynomial):
+        try:
+            polynomial = polynomial.polynomial(QQ)
+        except (AttributeError, TypeError):
+            raise TypeError, "polynomial (=%s) must be a polynomial."%repr(polynomial)
+
+    
     key = (polynomial, name)
     if _nf_cache.has_key(key):
@@ -179,5 +185,4 @@
     """
     EXAMPLES:
-        sage: R.<x> = PolynomialRing(QQ)    
         sage: K.<a> = NumberField(x^3 - 2); K
         Number Field in a with defining polynomial x^3 - 2
@@ -189,5 +194,5 @@
         ParentWithGens.__init__(self, QQ, name)
         if not isinstance(polynomial, polynomial_element.Polynomial):
-            raise TypeError, "polynomial (=%s) must be a polynomial"%polynomial
+            raise TypeError, "polynomial (=%s) must be a polynomial"%repr(polynomial)
         
         if check:
@@ -209,5 +214,14 @@
 
     def __reduce__(self):
-        return NumberField_generic, (self.__polynomial, self.variable_name(), self.__latex_variable_name)
+        """
+        TESTS:
+            sage: K.<w> = NumberField(Z^3 + Z + 1)
+            sage: L = loads(dumps(K))
+            sage: print L
+            Number Field in w with defining polynomial Z^3 + Z + 1
+            sage: print L == K
+            True
+        """
+        return NumberField_generic_v1, (self.__polynomial, self.variable_name(), self.__latex_variable_name)
 
     def complex_embeddings(self, prec=53):
@@ -217,4 +231,5 @@
 
         EXAMPLES:
+            sage: x = polygen(QQ)
             sage: f = x^5 + x + 17
             sage: k.<a> = NumberField(f)
@@ -242,5 +257,5 @@
             self.__latex_variable_name = name
 
-    def __repr__(self):
+    def _repr_(self):
         return "Number Field in %s with defining polynomial %s"%(
                    self.variable_name(), self.polynomial())
@@ -275,4 +290,8 @@
                               list)):
             return number_field_element.NumberFieldElement(self, x)
+        try:
+            return number_field_element.NumberFieldElement(self, x._rational_())
+        except (TypeError, AttributeError):
+            pass
         raise TypeError, "Cannot coerce %s into %s"%(x,self)
 
@@ -280,10 +299,7 @@
         if isinstance(x, (rational.Rational, integer.Integer, int, long)):
             return number_field_element.NumberFieldElement(self, x)
+        elif isinstance(x, number_field_element.NumberFieldElement) and x.parent() == self:
+            return number_field_element.NumberFieldElement(self, x.list())
         raise TypeError
-
-    def category(self):
-        from sage.categories.all import NumberFields
-        return NumberFields()
-    
 
     def category(self):
@@ -309,5 +325,4 @@
 
         EXAMPLES:
-            sage: R.<x> = PolynomialRing(QQ)
             sage: K.<a> = NumberField(x^3-2)
             sage: K.ideal([a])
@@ -451,5 +466,4 @@
 
         EXAMPLES:
-            sage: R.<x> = PolynomialRing(QQ)
             sage: K.<a> = NumberField(x^2+1)
             sage: K.elements_of_norm(3)
@@ -468,14 +482,30 @@
 
         EXAMPLES:
-            sage: R.<x> = PolynomialRing(QQ)
             sage: K.<a> = NumberField(x^3 - 2)
-            sage: t = K['x'].gen()
+            sage: R.<t> = K[]
             sage: L.<b> = K.extension(t^2 + a); L
-            Extension by x^2 + a of the Number Field in a with defining polynomial x^3 - 2
-        """
-        if not names is None: name = names
+            Extension by t^2 + a of the Number Field in a with defining polynomial x^3 - 2
+
+        We create another extension.
+            sage: k.<a> = NumberField(x^2 + 1); k
+            Number Field in a with defining polynomial x^2 + 1
+            sage: m.<b> = k.extension(y^2 + 1); m
+            Extension by y^2 + 1 of the Number Field in a with defining polynomial x^2 + 1
+            sage: b.minpoly()
+            x^4 + 10*x^2 + 9
+            
+        """
+        if not isinstance(poly, polynomial_element.Polynomial):
+            try:
+                poly = poly.polynomial(self)
+            except (AttributeError, TypeError):
+                raise TypeError, "polynomial (=%s) must be a polynomial."%repr(poly)
+        if not names is None:
+            name = names
+        if isinstance(name, tuple):
+            name = name[0]
         if name is None:
             raise TypeError, "the variable name must be specified."
-        return NumberField_extension(self, poly, name)
+        return NumberField_extension(self, poly, repr(name))
 
     def factor_integer(self, n):
@@ -488,5 +518,4 @@
         First we form a number field defined by $x^2 + 1$:
  
-            sage: R.<x> = PolynomialRing(QQ)
             sage: K.<I> = NumberField(x^2 + 1); K
             Number Field in I with defining polynomial x^2 + 1
@@ -543,6 +572,4 @@
 
         EXAMPLES:
-            sage: R.<x> = PolynomialRing(QQ)
-
             sage: NumberField(x^3-2, 'a').galois_group(pari_group=True)
             PARI group [6, -1, 2, "S3"] of degree 3
@@ -564,6 +591,5 @@
 
         EXAMPLES:
-            sage: x = polygen(QQ,'x')
-            sage: K.<a> = NumberField(x^5+10*x+1)
+            sage: K.<a> = NumberField(x^5 + 10*x + 1)
             sage: K.integral_basis()
             [1, a, a^2, a^3, a^4]
@@ -590,5 +616,4 @@
         
         EXAMPLES:
-            sage: R.<x> = PolynomialRing(QQ)
             sage: NumberField(x^3+x+9, 'a').narrow_class_group()
             Multiplicative Abelian Group isomorphic to C2
@@ -637,5 +662,4 @@
 
         EXAMPLES:
-            sage: R.<x> = PolynomialRing(QQ)
             sage: K = NumberField(x^3 + 2*x - 5, 'alpha')
             sage: K.polynomial_quotient_ring()
@@ -652,5 +676,4 @@
 
         EXAMPLES:
-            sage: R.<x> = PolynomialRing(QQ)
             sage: NumberField(x^2-2, 'a').regulator()
             0.88137358701954305
@@ -672,5 +695,4 @@
 
         EXAMPLES:
-            sage: R.<x> = PolynomialRing(QQ)
             sage: NumberField(x^2+1, 'a').signature()
             (0, 1)
@@ -689,5 +711,4 @@
 
         EXAMPLES:
-            sage: R.<x> = PolynomialRing(QQ)
             sage: K.<zeta3> = NumberField(x^2 + 3)
             sage: K.trace_pairing([1,zeta3])
@@ -815,5 +836,4 @@
     """
     EXAMPLES:
-        sage: R.<x> = PolynomialRing(QQ)
         sage: K.<a> = NumberField(x^3 - 2)
         sage: t = K['x'].gen()
@@ -830,5 +850,8 @@
             raise TypeError, "base (=%s) must be a number field"%base
         if not isinstance(polynomial, polynomial_element.Polynomial):
-            raise TypeError, "polynomial (=%s) must be a polynomial"%polynomial
+            try:
+                polynomial = polynomial.polynomial(base)
+            except (AttributeError, TypeError), msg:
+                raise TypeError, "polynomial (=%s) must be a polynomial."%repr(polynomial)
         if name == base.variable_name():
             raise ValueError, "Base field and extension cannot have the same name"
@@ -874,5 +897,19 @@
         self.__pari_bnf_certified = False
 
-    def __repr__(self):
+    def __reduce__(self):
+        """
+        TESTS:
+            sage: K.<w> = NumberField(Z^3 + Z + 1)
+            sage: L.<z> = K.extension(Z^3 + 2)
+            sage: L = loads(dumps(K))
+            sage: print L
+            Number Field in w with defining polynomial Z^3 + Z + 1
+            sage: print L == K
+            True        
+        """
+        return NumberField_extension_v1, (self.__base_field, self.polynomial(), self.variable_name(),
+                                          self.latex_variable_name())
+
+    def _repr_(self):
         return "Extension by %s of the Number Field in %s with defining polynomial %s"%(
             self.polynomial(), self.base_field().variable_name(),
@@ -1023,5 +1060,5 @@
             pbn = self._pari_base_nf()
             prp = self.pari_relative_polynomial()
-            pari_poly = str(pbn.rnfequation(prp)).replace('^', '**')
+            pari_poly = pbn.rnfequation(prp)
             R = self.base_field().polynomial().parent()
             self.__absolute_polynomial = R(pari_poly)
@@ -1185,5 +1222,17 @@
         self.__zeta_order = n
 
-    def __repr__(self):
+    def __reduce__(self):
+        """
+        TESTS:
+            sage: K.<zeta7> = CyclotomicField(7)
+            sage: L = loads(dumps(K))
+            sage: print L
+            Cyclotomic Field of order 7 and degree 6
+            sage: print L == K
+            True
+        """
+        return NumberField_cyclotomic_v1, (self.__zeta_order, self.variable_name())
+
+    def _repr_(self):
         return "Cyclotomic Field of order %s and degree %s"%(
                 self.zeta_order(), self.degree())
@@ -1491,4 +1540,15 @@
         NumberField_generic.__init__(self, polynomial, name=name, check=check)
         
+    def __reduce__(self):
+        """
+        TESTS:
+            sage: K.<z7> = QuadraticField(7)
+            sage: L = loads(dumps(K))
+            sage: print L
+            Number Field in z7 with defining polynomial x^2 - 7
+            sage: print L == K
+            True
+        """
+        return NumberField_quadratic_v1, (self.polynomial(), self.variable_name())
 
     def class_number(self, proof = True):
@@ -1565,2 +1625,19 @@
            (arith.is_squarefree(D) or \
             (d == 0 and (D//4)%4 in [2,3] and arith.is_squarefree(D//4)))
+
+
+###################
+# For pickling
+###################
+
+def NumberField_generic_v1(poly, name, latex_name):
+    return NumberField_generic(poly, name, latex_name, check=False)
+
+def NumberField_extension_v1(base_field, poly, name, latex_name):
+    return NumberField_extension(base_field, poly, name, latex_name, check=False)
+
+def NumberField_cyclotomic_v1(zeta_order, name):
+    return NumberField_cyclotomic(zeta_order, name)
+
+def NumberField_quadratic_v1(poly, name):
+    return NumberField_quadratic(poly, name, check=False)
Index: sage/rings/number_field/number_field_element.pyx
===================================================================
--- sage/rings/number_field/number_field_element.pyx	(revision 3650)
+++ sage/rings/number_field/number_field_element.pyx	(revision 4127)
@@ -233,9 +233,4 @@
         Return PARI C-library object corresponding to self.
 
-        NOTE: This is not the actual underlying object that represents
-        this element, since that is a polynomial in x (as PARI
-        polynomials are rather constrained in their possible variable
-        names, e.g., I cannot be the name of a variable).
-
         EXAMPLES:
             sage: k.<j> = QuadraticField(-1)
@@ -244,4 +239,9 @@
             sage: pari(j)
             Mod(j, j^2 + 1)
+
+            sage: y = QQ['y'].gen()
+            sage: k.<j> = NumberField(y^3 - 2)
+            sage: pari(j)
+            Mod(j, j^3 - 2)
 
         If you try do coerce a generator called I to PARI, hell may
@@ -276,8 +276,11 @@
         else:
             f = self.polynomial()._pari_()
-            g = self.parent().polynomial()._pari_()
+            gp = self.parent().polynomial()
+            g = gp._pari_()
+            gv = str(gp.parent().gen())
             if var != 'x':
                 f = f.subst("x",var)
-                g = g.subst("x",var)
+            if var != gv:
+                g = g.subst(gv, var)
         h = f.Mod(g)
         self.__pari[var] = h
Index: sage/rings/number_field/number_field_ideal.py
===================================================================
--- sage/rings/number_field/number_field_ideal.py	(revision 2725)
+++ sage/rings/number_field/number_field_ideal.py	(revision 4077)
@@ -4,4 +4,12 @@
 AUTHOR:
    -- Steven Sivek (2005-05-16)
+
+TESTS:
+    sage: K.<a> = NumberField(x^2 - 5)
+    sage: I = K.ideal(2/(5+a))
+    sage: I == loads(dumps(I))
+    True
+
+
 """
 
@@ -63,7 +71,5 @@
 
     def __cmp__(self, other):
-        if self.pari_hnf() == other.pari_hnf():
-            return 0
-        return -1
+        return cmp(self.pari_hnf(), other.pari_hnf())
 
     def _coerce_impl(self, x):
@@ -229,5 +235,5 @@
             sage: J = K.ideal([i+1, 2])
             sage: J.gens()
-            (2, i + 1)
+            (i + 1, 2)
             sage: J.gens_reduced()
             (i + 1,)
Index: sage/rings/padics/local_generic_element.py
===================================================================
--- sage/rings/padics/local_generic_element.py	(revision 3674)
+++ sage/rings/padics/local_generic_element.py	(revision 4282)
@@ -204,5 +204,5 @@
         raise NotImplementedError
 
-    def sqrt(self):
+    def sqrt(self, prec=None, extend=True, all=False):
         r"""
         Returns the square root of this local ring element
@@ -213,5 +213,15 @@
             local ring element -- the square root of self
         """
-        return self.square_root()
+        try:
+            s = self.square_root()
+            if all:
+                return [s, -s]
+            else:
+                return s
+        except ValueError:
+            if extend:
+                raise NotImplementedError
+            else:
+                raise ValueError, "self must be a square"
 
     def square_root(self):
Index: sage/rings/padics/padic_generic_element.py
===================================================================
--- sage/rings/padics/padic_generic_element.py	(revision 3804)
+++ sage/rings/padics/padic_generic_element.py	(revision 4257)
@@ -6,4 +6,5 @@
     -- Genya Zaytman: documentation
     -- David Harvey: doctests
+    -- William Stein: fixes to p-adic log in case input is not in Zp.
 """
 
@@ -497,8 +498,13 @@
             return (self.valuation() % 2 == 0) and (self.unit_part().residue(3) == 1)
         
-    def log(self, branch = None):
+    def log(self, branch=0):
         r"""
-        Compute the p-adic logarithm of any unit in $\Z_p$.
+        Compute the p-adic logarithm of any nonzero element of $\\Q_p$.
         (See below for normalization.)
+
+        INPUT:
+           branch -- (default: 0).  If self is not a $p$-adic unit, return
+                      the p-adic log of the unit part plus branch times
+                      the valuation of self.
         
         The usual power series for log with values in the additive
@@ -567,4 +573,24 @@
             ...       assert ll == full_log
             ...       assert ll.precision_absolute() == prec
+
+        We compute some logs of non-units:
+            sage: K = Qp(5,8); K
+            5-adic Field with capped relative precision 8
+            sage: a = K(-5^2*17); a
+            3*5^2 + 5^3 + 4*5^4 + 4*5^5 + 4*5^6 + 4*5^7 + 4*5^8 + 4*5^9 + O(5^10)
+            sage: u = a.unit_part(); u
+            3 + 5 + 4*5^2 + 4*5^3 + 4*5^4 + 4*5^5 + 4*5^6 + 4*5^7 + O(5^8)
+            sage: b = K(1235/5); b
+            2 + 4*5 + 4*5^2 + 5^3 + O(5^8)
+            sage: log(a)
+            5 + 3*5^2 + 3*5^3 + 4*5^4 + 4*5^5 + 5^6 + O(5^8)
+            sage: log(a*b) - log(a) - log(b)
+            O(5^8)
+            sage: c = a^b; c
+            2*5^494 + 4*5^496 + 2*5^497 + 5^499 + 3*5^500 + 5^501 + O(5^502)
+
+        Note that we can recover b:
+            sage: log(c)/log(a)
+            2 + 4*5 + 4*5^2 + 5^3 + O(5^7)
 
 
@@ -613,5 +639,5 @@
             z = self.unit_part()
             return (z**Integer(p-1)).log() // Integer(p-1)
-        elif not branch is None and self.parent().__contains__(branch):
+        elif not branch is None:
             branch = self.parent()(branch)
             return self.unit_part().log() + branch*self.valuation()
Index: sage/rings/padics/tests.py
===================================================================
--- sage/rings/padics/tests.py	(revision 4004)
+++ sage/rings/padics/tests.py	(revision 4004)
@@ -0,0 +1,36 @@
+"""
+TESTS:
+
+sage: R = Zp(5, prec=5, type='fixed-mod')
+sage: a = random_matrix(R,5)
+sage: a.determinant()                # random output
+5 + 3*5^2 + 5^3 + 4*5^4 + O(5^5)
+sage: K = Qp(3, 10,'capped-rel'); K.krull_dimension()
+0
+
+Computation of logs:
+
+    sage: Qp(5)(1).log()
+    O(5^20)
+    sage: Qp(5)(-1).log()
+    O(5^20)
+    sage: Qp(5,prec=5)(7).log()
+    4*5^2 + 4*5^3 + 3*5^4 + O(5^5)
+    sage: Qp(5,prec=10)(25*8).log(branch = 0)
+    5 + 3*5^3 + 3*5^4 + 2*5^5 + 5^6 + 2*5^7 + 3*5^8 + 3*5^9 + O(5^10)
+    sage: Zp(5,prec=10)(8).log()
+    5 + 3*5^3 + 3*5^4 + 2*5^5 + 5^6 + 2*5^7 + 3*5^8 + 3*5^9 + O(5^10)
+
+Loading and saving elements of various types:
+
+    sage: a = ZpCA(5)(-3); loads(dumps(a)) == a
+    True
+    sage: a = ZpCR(5)(-3); loads(dumps(a)) == a
+    True
+    sage: a = Zp(5)(-3); loads(dumps(a)) == a
+    True
+    sage: a = ZpFM(5)(-3); loads(dumps(a)) == a
+    True
+    sage: a = ZpL(5)(-3); loads(dumps(a)) == a
+    True
+"""
Index: sage/rings/polydict.pyx
===================================================================
--- sage/rings/polydict.pyx	(revision 2725)
+++ sage/rings/polydict.pyx	(revision 4006)
@@ -570,4 +570,11 @@
 
     def __reduce__(PolyDict self):
+        """
+        sage: from sage.rings.polydict import PolyDict        
+        sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4})
+        sage: loads(dumps(f)) == f
+        True
+        
+        """
         return make_PolyDict,(self.__repn,)
     
@@ -832,4 +839,12 @@
 
     def __reduce__(ETuple self):
+        """
+        EXAMPLES:
+            sage: from sage.rings.polydict import ETuple
+            sage: e = ETuple([1,1,0])
+            sage: bool(e == loads(dumps(e)))
+            True
+        """
+
         return make_ETuple,(self._data,self._length)
 
Index: sage/rings/polynomial_element.pxd
===================================================================
--- sage/rings/polynomial_element.pxd	(revision 3650)
+++ sage/rings/polynomial_element.pxd	(revision 4149)
@@ -5,11 +5,13 @@
 
 from sage.structure.element import Element, CommutativeAlgebraElement
-from sage.structure.element cimport Element, CommutativeAlgebraElement
+from sage.structure.element cimport Element, CommutativeAlgebraElement, ModuleElement
 
 cdef class Polynomial(CommutativeAlgebraElement):
+    cdef ModuleElement _neg_c_impl(self)
     cdef char _is_gen
 
-#cdef class Polynomial_generic_dense(Polynomial):
-#    cdef object __coeffs # a python list
+cdef class Polynomial_generic_dense(Polynomial):
+    cdef object __coeffs # a python list
+    cdef void __normalize(self)
     
 #cdef class Polynomial_generic_sparse(Polynomial):
Index: sage/rings/polynomial_element.pyx
===================================================================
--- sage/rings/polynomial_element.pyx	(revision 3925)
+++ sage/rings/polynomial_element.pyx	(revision 4277)
@@ -5,4 +5,12 @@
     -- William Stein: first version
     -- Martin Albrecht: Added singular coercion.
+    -- Robert Bradshaw: Move Polynomial_generic_dense to SageX
+
+TESTS:
+     sage: R.<x> = ZZ[]
+     sage: f = x^5 + 2*x^2 + (-1)
+     sage: f == loads(dumps(f))
+     True
+
 """
 
@@ -30,4 +38,5 @@
 import rational_field
 import complex_field
+import fraction_field_element
 #import padic_field
 from infinity import infinity
@@ -44,5 +53,5 @@
 
 from sage.structure.element import RingElement
-from sage.structure.element cimport Element
+from sage.structure.element cimport Element, RingElement, ModuleElement, MonoidElement
 
 from rational_field import QQ
@@ -66,5 +75,5 @@
         y*x
         sage: type(f)
-        <class 'sage.rings.polynomial_element_generic.Polynomial_generic_dense'>
+        <type 'sage.rings.polynomial_element.Polynomial_generic_dense'>
     """
     def __init__(self, parent, is_gen = False, construct=False): 
@@ -95,17 +104,56 @@
         self._is_gen = is_gen
 
-    def _add_(self, right):
-        if self.degree() >= right.degree():
-            x = list(self.list())
-            y = right.list()
+    cdef ModuleElement _add_c_impl(self, ModuleElement right):
+        cdef Py_ssize_t i, min
+        x = self.list()
+    cdef ModuleElement _neg_c_impl(self):
+        return self.polynomial([-x for x in self.list()])
+
+        y = right.list()
+
+        if len(x) > len(y):
+            min = len(y)
+            high = x[min:]
+        elif len(x) < len(y):
+            min = len(x)
+            high = y[min:]
         else:
-            x = list(right.list())
-            y = self.list()
+            min = len(x)
+            high = []
             
-        for i in xrange(len(y)):
-            x[i] += y[i]
-        
-        return self.polynomial(x)
+        low = [x[i] + y[i] for i from 0 <= i < min]
+        return self.polynomial(low + high)
     
+    def plot(self, xmin=0, xmax=1, *args, **kwds):
+        """
+        Return a plot of this polynomial.
+
+        INPUT:
+            xmin -- float
+            xmax -- float
+            *args, **kwds -- passed to either point or point
+            
+        OUTPUT:
+            returns a graphic object.
+
+        EXAMPLES:
+            sage: x = polygen(GF(389))
+            sage: plot(x^2 + 1, rgbcolor=(0,0,1)).save()
+            sage: x = polygen(QQ)
+            sage: plot(x^2 + 1, rgbcolor=(1,0,0)).save()
+        """
+        R = self.base_ring()
+        from sage.plot.plot import plot, point, line
+        if R.characteristic() == 0:
+            return plot(self.__call__, xmin=xmin, xmax=xmax, *args, **kwds)
+        else:
+            if R.is_finite():
+                v = list(R)
+                v.sort()
+                w = dict([(v[i],i) for i in range(len(v))])
+                z = [(i, w[self(v[i])]) for i in range(len(v))]
+                return point(z, *args, **kwds) 
+        raise NotImplementedError, "plotting of polynomials over %s not implemented"%R
+        
     def _lmul_(self, left):
         """
@@ -122,5 +170,7 @@
         # todo -- should multiply individual coefficients??
         #         that could be in derived class.
-        #         Note that we are guaranteed that right is in the base ring, so this could be fast.         
+        #         Note that we are guaranteed that right is in the base ring, so this could be fast.
+        if left == 0:
+            return self.parent()(0)
         return self.parent()(left) * self
     
@@ -140,4 +190,6 @@
         #         that could be in derived class.
         #         Note that we are guaranteed that right is in the base ring, so this could be fast. 
+        if right == 0:
+            return self.parent()(0)
         return self * self.parent()(right) 
         
@@ -388,5 +440,5 @@
         return long(self[0])
 
-    def _mul_(self, right):
+    cdef RingElement _mul_c_impl(self, RingElement right):
         """
         EXAMPLES:
@@ -465,5 +517,5 @@
         
         
-    def _pow(self, right):
+    def __pow__(self, right, dummy):
         """
         EXAMPLES:
@@ -479,5 +531,16 @@
         if right < 0:
             return (~self)**(-right)
-        if self._is_gen:   # special case x**n should be faster!
+        if (<Polynomial>self)._is_gen:   # special case x**n should be faster!
+            v = [0]*right + [1]
+            return self.parent()(v, check=True)
+        return arith.generic_power(self, right, self.parent()(1))
+        
+    def _pow(self, right):
+        # TODO: fit __pow__ into the arithmatic structure
+        if self.degree() <= 0:
+            return self.parent()(self[0]**right)
+        if right < 0:
+            return (~self)**(-right)
+        if (<Polynomial>self)._is_gen:   # special case x**n should be faster!
             v = [0]*right + [1]
             return self.parent()(v, check=True)
@@ -497,5 +560,5 @@
                 if n != m-1:
                     s += " + "
-                x = str(x)
+                x = repr(x)
                 if not atomic_repr and n > 0 and (x.find("+") != -1 or x.find("-") != -1):
                     x = "(%s)"%x
@@ -518,4 +581,5 @@
         r"""
         EXAMPLES:
+			sage: x = polygen(QQ)
             sage: f = x^3+2/3*x^2 - 5/3
             sage: f._repr_()
@@ -530,4 +594,5 @@
         r"""
         EXAMPLES:
+			sage: x = polygen(QQ)
             sage: latex(x^3+2/3*x^2 - 5/3)
              x^{3} + \frac{2}{3}x^{2} - \frac{5}{3}
@@ -600,12 +665,43 @@
         
     def _mul_generic(self, right):
-        d1 = self.degree()
-        d2 = right.degree()
-        d = d1 + d2
-        w = [sum([self[i]*right[k-i] for i in range(0,min(d1,k)+1) if \
-                  i <= d1 and k-i <= d2 and self[i]!=0 and right[k-i]!=0]) \
-                for k in range(d+1)]
-        return self.parent()(w)
-
+        if self is right:
+            return self._square_generic()
+        x = self.list()
+        y = right.list()
+        cdef Py_ssize_t i, k, start, end
+        cdef Py_ssize_t d1 = len(x)-1, d2 = len(y)-1
+        if d1 == -1:
+            return self
+        elif d2 == -1:
+            return right
+        elif d1 == 0:
+            c = x[0]
+            return self._parent([c*a for a in y])
+        elif d2 == 0:
+            c = y[0]
+            return self._parent([a*c for a in x])
+        coeffs = []
+        for k from 0 <= k <= d1+d2:
+            start = 0 if k <= d2 else k-d2 # max(0, k-d2)
+            end =   k if k <= d1 else d1    # min(k, d1)
+            sum = x[start] * y[k-start]
+            for i from start < i <= end:
+                sum += x[i] * y[k-i]
+            coeffs.append(sum)
+        return self._parent(coeffs)
+        
+    def _square_generic(self):
+        x = self.list()
+        cdef Py_ssize_t i, j
+        cdef Py_ssize_t d = len(x)-1
+        zero = self._parent.base_ring()(0)
+        two = self._parent.base_ring()(2)
+        coeffs = [zero] * (2 * d + 1)
+        for i from 0 <= i <= d:
+            coeffs[2*i] = x[i] * x[i]
+            for j from 0 <= j < i:
+                coeffs[i+j] += two * x[i] * x[j]
+        return self._parent(coeffs)
+        
     def _mul_fateman(self, right):
         r"""
@@ -739,5 +835,5 @@
            polynomial multiplication is implemented.
         """
-        return self.parent()(do_karatsuba(self.list(), right.list()))
+        return self._parent(do_karatsuba(self.list(), right.list()))
         
     def base_ring(self):
@@ -879,5 +975,11 @@
         
     def derivative(self):
-        return self.polynomial([self[n]*n for n in xrange(1,self.degree()+1)])
+        if self.is_zero():
+            return self
+        cdef Py_ssize_t n, degree = self.degree()
+        if degree == 0:
+            return self.parent()(0)
+        coeffs = self.list()
+        return self.polynomial([n*coeffs[n] for n from 1 <= n <= degree])
 
     def integral(self):
@@ -939,5 +1041,5 @@
             
         Notice that the unit factor is included when we multiply $F$ back out.
-            sage: F.mul()
+            sage: expand(F)
             2*x^10 + 2*x + 2*a
 
@@ -974,5 +1076,5 @@
             sage: F = factor(x^2-3); F
             (1.0000000000000000000000000000*x + 1.7320508075688772935274463415) * (1.0000000000000000000000000000*x - 1.7320508075688772935274463415)
-            sage: F.mul()
+            sage: expand(F)
             1.0000000000000000000000000000*x^2 - 3.0000000000000000000000000000
             sage: factor(x^2 + 1)
@@ -982,5 +1084,5 @@
             sage: F = factor(x^2+3); F
             (1.0000000000000000000000000000*x + -1.7320508075688772935274463415*I) * (1.0000000000000000000000000000*x + 1.7320508075688772935274463415*I)
-            sage: F.mul()
+            sage: expand(F)
             1.0000000000000000000000000000*x^2 + 3.0000000000000000000000000000
             sage: factor(x^2+1)
@@ -988,7 +1090,7 @@
             sage: f = C.0 * (x^2 + 1) ; f
             1.0000000000000000000000000000*I*x^2 + 1.0000000000000000000000000000*I
-            sage: F=factor(f); F
+            sage: F = factor(f); F
             (1.0000000000000000000000000000*I) * (1.0000000000000000000000000000*x + -1.0000000000000000000000000000*I) * (1.0000000000000000000000000000*x + 1.0000000000000000000000000000*I)
-            sage: F.mul()
+            sage: expand(F)
             1.0000000000000000000000000000*I*x^2 + 1.0000000000000000000000000000*I
         """
@@ -1244,7 +1346,4 @@
         return bool(self._is_gen)
 
-    def is_zero(self):
-        return bool(self.degree() == -1)
-
     def leading_coefficient(self):
         return self[self.degree()]
@@ -1355,5 +1454,5 @@
 
     def polynomial(self, *args, **kwds):
-        return self.parent()(*args, **kwds)
+        return self._parent(*args, **kwds)
 
     def newton_slopes(self, p):
@@ -1411,5 +1510,5 @@
 
     def _pari_init_(self):
-        return str(self._pari_())
+        return repr(self._pari_())
 
     def _magma_init_(self):
@@ -1456,5 +1555,5 @@
 
     def _gap_init_(self):
-        return str(self)
+        return repr(self)
 
     def _gap_(self, G):
@@ -1565,7 +1664,14 @@
 
             sage: x = CC['x'].0
-            sage: f = (x-1)*(x-I)
+            sage: i = CC.0
+            sage: f = (x - 1)*(x - i)
             sage: f.roots()
             [1.00000000000000*I, 1.00000000000000]
+
+        A purely symbolic roots example:
+            sage: f = expand((X-1)*(X-I)^3*(X^2 - sqrt(2))); f
+            X^6 - 3*I*X^5 - X^5 + 3*I*X^4 - sqrt(2)*X^4 - 3*X^4 + 3*sqrt(2)*I*X^3 + I*X^3 + sqrt(2)*X^3 + 3*X^3 - 3*sqrt(2)*I*X^2 - I*X^2 + 3*sqrt(2)*X^2 - sqrt(2)*I*X - 3*sqrt(2)*X + sqrt(2)*I
+            sage: print f.roots()
+            [(I, 3), (-2^(1/4), 1), (2^(1/4), 1), (1, 1)]
         """
         seq = []
@@ -1745,7 +1851,15 @@
             sage: p.shift(2)
              x^4 + 2*x^3 + 4*x^2
+             
+        One can also use the infix shift operator:
+            sage: f = x^3 + x
+            sage: f >> 2
+            x
+            sage: f << 2
+            x^5 + x^3
 
         AUTHOR:
             -- David Harvey (2006-08-06)
+            -- Robert Bradshaw (2007-04-18) Added support for infix operator.
         """
         if n == 0:
@@ -1760,4 +1874,11 @@
             else:
                 return self.polynomial(self.coeffs()[-int(n):], check=False)
+                
+    def __lshift__(self, k):
+        return self.shift(k)
+
+    def __rshift__(self, k):
+        return self.shift(-k)
+
 
     def truncate(self, n):
@@ -1781,5 +1902,5 @@
             3*x^3 - 4*x^2 + 4*x - 1
         """
-        return self // self.gcd(self.derivative())        
+        return self // self.gcd(self.derivative())
 
 
@@ -1788,5 +1909,5 @@
     
 
-def _karatsuba_sum(v,w):
+cdef _karatsuba_sum(v,w):
     if len(v)>=len(w):
         x = list(v)
@@ -1799,5 +1920,5 @@
     return x
     
-def _karatsuba_dif(v,w):
+cdef _karatsuba_dif(v,w):
     if len(v)>=len(w):
         x = list(v)
@@ -1810,11 +1931,13 @@
     return x
     
-def do_karatsuba(left, right):
+cdef do_karatsuba(left, right):
     if len(left) == 0 or len(right) == 0:
         return []
     if len(left) == 1:
-        return [left[0]*a for a in right]
+        c = left[0]
+        return [c*a for a in right]
     if len(right) == 1:
-        return [right[0]*a for a in left]
+        c = right[0]
+        return [c*a for a in left]
     if len(left) == 2 and len(right) == 2:
         b = left[0]
@@ -1836,2 +1959,299 @@
     t0 = bd
     return _karatsuba_sum(t0,_karatsuba_sum(t1,t2))
+
+
+
+cdef class Polynomial_generic_dense(Polynomial):
+    """
+    A generic dense polynomial.
+
+    EXAMPLES:
+        sage: R.<x> = PolynomialRing(PolynomialRing(QQ,'y'))
+        sage: f = x^3 - x + 17
+        sage: type(f)
+        <type 'sage.rings.polynomial_element.Polynomial_generic_dense'>
+        sage: loads(f.dumps()) == f
+        True
+    """
+    def __init__(self, parent, x=None, int check=1, is_gen=False, int construct=0, absprec=None):
+        Polynomial.__init__(self, parent, is_gen=is_gen)
+
+        if x is None:
+            self.__coeffs = []
+            return
+        R = parent.base_ring()
+        
+        if PY_TYPE_CHECK(x, Polynomial):
+            if (<Element>x)._parent is self._parent:
+                x = list(x.list())
+            elif (<Element>x)._parent is R or (<Element>x)._parent == R:
+                x = [x]
+            elif absprec is None:
+                x = [R(a) for a in x.list()]
+                check = 0
+            else:
+                x = [R(a, absprec = absprec) for a in x.list()]
+                check = 0
+                
+        elif PY_TYPE_CHECK(x, list):
+            pass
+            
+        elif PY_TYPE_CHECK(x, int) and x == 0:
+            self.__coeffs = []
+            return
+                
+        elif fraction_field_element.is_FractionFieldElement(x):
+            if x.denominator() != 1:
+                raise TypeError, "denominator must be 1"
+            else:
+                x = x.numerator()
+                
+        elif isinstance(x, dict):
+            zero = R(0)
+            n = max(x.keys())
+            v = [zero for _ in xrange(n+1)]
+            for i, z in x.iteritems():
+                v[i] = z
+            x = v
+        elif isinstance(x, pari_gen):
+            if absprec is None:
+                x = [R(w) for w in x.Vecrev()]
+            else:
+                x = [R(w, absprec = absprec) for w in x.Vecrev()]
+            check = True
+        elif not isinstance(x, list):
+            x = [x]   # constant polynomials
+        if check:
+            if absprec is None:
+                self.__coeffs = [R(z) for z in x]
+            else:
+                self.__coeffs = [R(z, absprec=absprec) for z in x]
+        else:
+            self.__coeffs = x
+        if check:
+            self.__normalize()
+            
+    def __reduce__(self):
+        return make_generic_polynomial, (self._parent, self.__coeffs)
+
+    def __hash__(self):
+        if self.degree() >= 1:
+            return hash(tuple(self.__coeffs))
+        else:
+            return hash(self[0])
+        
+    cdef void __normalize(self):
+        x = self.__coeffs
+        cdef Py_ssize_t n = len(x) - 1
+        while n >= 0 and x[n].is_zero():
+#        while n > 0 and x[n] == 0:
+            del x[n]
+            n -= 1
+            
+    def __richcmp__(left, right, int op):
+        return (<Element>left)._richcmp(right, op)
+        
+    def __getitem__(self, Py_ssize_t n):
+        """
+        EXAMPLES:
+            sage: R.<x> = ZZ[]
+            sage: f = (1+2*x)^5; f
+            32*x^5 + 80*x^4 + 80*x^3 + 40*x^2 + 10*x + 1
+            sage: f[-1]
+            0
+            sage: f[2]
+            40
+            sage: f[6]
+            0
+        """
+        if n < 0 or n >= len(self.__coeffs):
+            return self.base_ring()(0)
+        return self.__coeffs[n]
+
+    def __getslice__(self, Py_ssize_t i, j):
+        """
+        EXAMPLES:
+            sage: R.<x> = RDF[]
+            sage: f = (1+2*x)^5; f
+            32.0*x^5 + 80.0*x^4 + 80.0*x^3 + 40.0*x^2 + 10.0*x + 1.0
+            sage: f[:3]
+            40.0*x^2 + 10.0*x + 1.0
+            sage: f[2:5]
+            80.0*x^4 + 80.0*x^3 + 40.0*x^2
+            sage: f[2:]
+            32.0*x^5 + 80.0*x^4 + 80.0*x^3 + 40.0*x^2            
+        """
+        if i <= 0:
+            i = 0
+            zeros = []
+        elif i > 0:
+            zeros = [self._parent.base_ring()(0)] * i
+        return self._parent(zeros + self.__coeffs[i:j])
+
+    def _unsafe_mutate(self, n, value):
+        """
+        Never use this unless you really know what you are doing.
+
+        WARNING: This could easily introduce subtle bugs, since SAGE
+        assumes everywhere that polynomials are immutable.  It's OK to
+        use this if you really know what you're doing.
+
+        EXAMPLES:
+            sage: R.<x> = ZZ[]
+            sage: f = (1+2*x)^2; f
+            4*x^2 + 4*x + 1
+            sage: f._unsafe_mutate(1, -5)
+            sage: f
+            4*x^2 - 5*x + 1        
+        """
+        n = int(n)
+        value = self.base_ring()(value)
+        if n >= 0 and n < len(self.__coeffs):
+            self.__coeffs[n] = value
+            if n == len(self.__coeffs) and value == 0:
+                self.__normalize()  
+        elif n < 0:
+            raise IndexError, "polynomial coefficient index must be nonnegative"
+        elif value != 0:
+            zero = self.base_ring()(0)
+            for _ in xrange(len(self.__coeffs), n):
+                self.__coeffs.append(zero)
+            self.__coeffs.append(value)
+            
+    def __floordiv__(self, right):
+        """
+        Return the quotient upon division (no remainder).
+
+        EXAMPLES:
+            sage: R.<x> = QQ[]
+            sage: f = (1+2*x)^3 + 3*x; f
+            8*x^3 + 12*x^2 + 9*x + 1
+            sage: g = f // (1+2*x); g
+            4*x^2 + 4*x + 5/2
+            sage: f - g * (1+2*x)
+            -3/2
+            sage: f.quo_rem(1+2*x)
+            (4*x^2 + 4*x + 5/2, -3/2)        
+        """
+        if right.parent() == self.parent():
+            return Polynomial.__floordiv__(self, right)
+        d = self.parent().base_ring()(right)
+        return self.polynomial([c // d for c in self.__coeffs], check=False)
+        
+    cdef ModuleElement _add_c_impl(self, ModuleElement right):
+        cdef Py_ssize_t check=0, i, min
+        x = (<Polynomial_generic_dense>self).__coeffs
+        y = (<Polynomial_generic_dense>right).__coeffs
+        if len(x) > len(y):
+            min = len(y)
+            high = x[min:]
+        elif len(x) < len(y):
+            min = len(x)
+            high = y[min:]
+        else:
+            min = len(x)
+        low = [x[i] + y[i] for i from 0 <= i < min]
+        if len(x) == len(y):
+            res = self._parent(low, check=0)
+            (<Polynomial_generic_dense>res).__normalize()
+            return res
+        else:
+            return self._parent(low + high, check=0)
+
+    cdef ModuleElement _sub_c_impl(self, ModuleElement right):
+        cdef Py_ssize_t check=0, i, min
+        x = (<Polynomial_generic_dense>self).__coeffs
+        y = (<Polynomial_generic_dense>right).__coeffs
+        if len(x) > len(y):
+            min = len(y)
+            high = x[min:]
+        elif len(x) < len(y):
+            min = len(x)
+            high = [-y[i] for i from min <= i < len(y)]
+        else:
+            min = len(x)
+        low = [x[i] - y[i] for i from 0 <= i < min]
+        if len(x) == len(y):
+            res = self._parent(low, check=0)
+            (<Polynomial_generic_dense>res).__normalize()
+            return res
+        else:
+            return self._parent(low + high, check=0)
+        
+    def _rmul_(self, c):
+        if len(self.__coeffs) == 0:
+            return self
+        v = [c * a for a in self.__coeffs]
+        res = self._parent(v, check=0)
+        if v[len(v)-1].is_zero():
+            (<Polynomial_generic_dense>res).__normalize()
+        return res
+        
+    def _lmul_(self, c):
+        if len(self.__coeffs) == 0:
+            return self
+        v = [a * c for a in self.__coeffs]
+        res = self._parent(v, check=0)
+        if v[len(v)-1].is_zero():
+            (<Polynomial_generic_dense>res).__normalize()
+        return res
+        
+    def list(self):
+        """
+        Return a new copy of the list of the underlying
+        elements of self.
+        
+        EXAMPLES:
+            sage: R.<x> = GF(17)[]
+            sage: f = (1+2*x)^3 + 3*x; f
+            8*x^3 + 12*x^2 + 9*x + 1
+            sage: f.list()
+            [1, 9, 12, 8]        
+        """
+        return list(self.__coeffs)
+
+    def degree(self):
+        """
+        EXAMPLES:
+            sage: R.<x> = RDF[]
+            sage: f = (1+2*x^7)^5
+            sage: f.degree()
+            35
+        """
+        return len(self.__coeffs) - 1
+
+    def shift(self, Py_ssize_t n):
+        r"""
+        Returns this polynomial multiplied by the power $x^n$. If $n$
+        is negative, terms below $x^n$ will be discarded. Does not
+        change this polynomial.
+
+        EXAMPLES:
+            sage: R.<x> = PolynomialRing(PolynomialRing(QQ,'y'), 'x')
+            sage: p = x^2 + 2*x + 4
+            sage: type(p)
+            <type 'sage.rings.polynomial_element.Polynomial_generic_dense'>
+            sage: p.shift(0)
+             x^2 + 2*x + 4
+            sage: p.shift(-1)
+             x + 2
+            sage: p.shift(2)
+             x^4 + 2*x^3 + 4*x^2
+
+        AUTHOR:
+            -- David Harvey (2006-08-06)
+        """
+        if n == 0:
+            return self
+        if n > 0:
+            output = [self.base_ring()(0)] * n
+            output.extend(self.__coeffs)
+            return self.polynomial(output, check=False)
+        if n < 0:
+            if n > len(self.__coeffs) - 1:
+                return self.polynomial([])
+            else:
+                return self.polynomial(self.__coeffs[-int(n):], check=False)
+                
+def make_generic_polynomial(parent, coeffs):
+    return parent(coeffs)
Index: sage/rings/polynomial_element_generic.py
===================================================================
--- sage/rings/polynomial_element_generic.py	(revision 3681)
+++ sage/rings/polynomial_element_generic.py	(revision 4276)
@@ -28,5 +28,5 @@
 import copy
 
-from polynomial_element import Polynomial, is_Polynomial
+from polynomial_element import Polynomial, is_Polynomial, Polynomial_generic_dense
 from sage.structure.element import (IntegralDomainElement, EuclideanDomainElement,
                                     PrincipalIdealDomainElement)
@@ -49,216 +49,5 @@
 import sage.rings.polynomial_ring
 
-
-class Polynomial_generic_dense(Polynomial):
-    """
-    A generic dense polynomial.
-
-    EXAMPLES:
-        sage: R.<x> = PolynomialRing(PolynomialRing(QQ,'y'))
-        sage: f = x^3 - x + 17
-        sage: type(f)
-        <class 'sage.rings.polynomial_element_generic.Polynomial_generic_dense'>
-        sage: loads(f.dumps()) == f
-        True
-    """
-    def __init__(self, parent, x=None, check=True, is_gen=False, construct=False, absprec=None):
-        Polynomial.__init__(self, parent, is_gen=is_gen)
-        if x is None:
-            self.__coeffs = []
-            return
-        R = parent.base_ring()
-
-        if fraction_field_element.is_FractionFieldElement(x):
-            if x.denominator() != 1:
-                raise TypeError, "denominator must be 1"
-            else:
-                x = x.numerator()
                 
-        if isinstance(x, Polynomial):
-            if x.parent() == self.parent():
-                x = list(x.list())
-            elif x.parent() == R:
-                x = [x]
-            elif absprec is None:
-                x = [R(a) for a in x.list()]
-                check = False
-            else:
-                x = [R(a, absprec = absprec) for a in x.list()]
-                check = False
-        elif isinstance(x, dict):
-            zero = R(0)
-            n = max(x.keys())
-            v = [zero for _ in xrange(n+1)]
-            for i, z in x.iteritems():
-                v[i] = z
-            x = v
-        elif isinstance(x, pari_gen):
-            if absprec is None:
-                x = [R(w) for w in x.Vecrev()]
-            else:
-                x = [R(w, absprec = absprec) for w in x.Vecrev()]
-            check = True
-        elif not isinstance(x, list):
-            x = [x]   # constant polynomials
-        if check:
-            if absprec is None:
-                self.__coeffs = [R(z) for z in x]
-            else:
-                self.__coeffs = [R(z, absprec=absprec) for z in x]
-        else:
-            self.__coeffs = x
-        if check:
-            self.__normalize()
-        
-    def __normalize(self):
-        x = self.__coeffs
-        n = len(x)-1
-        while n>=0 and x[n] == 0:
-            del x[n]
-            n -= 1
-        
-    def __getitem__(self,n):
-        """
-        EXAMPLES:
-            sage: R.<x> = ZZ[]
-            sage: f = (1+2*x)^5; f
-            32*x^5 + 80*x^4 + 80*x^3 + 40*x^2 + 10*x + 1
-            sage: f[-1]
-            0
-            sage: f[2]
-            40
-            sage: f[6]
-            0
-        """
-        if n < 0 or n >= len(self.__coeffs):
-            return self.base_ring()(0)
-        return self.__coeffs[n]
-
-    def __getslice__(self, i, j):
-        """
-        EXAMPLES:
-            sage: R.<x> = RDF[]
-            sage: f = (1+2*x)^5; f
-            32.0*x^5 + 80.0*x^4 + 80.0*x^3 + 40.0*x^2 + 10.0*x + 1.0
-            sage: f[:3]
-            40.0*x^2 + 10.0*x + 1.0
-            sage: f[2:5]
-            80.0*x^4 + 80.0*x^3 + 40.0*x^2
-            sage: f[2:]
-            32.0*x^5 + 80.0*x^4 + 80.0*x^3 + 40.0*x^2            
-        """
-        if i < 0:
-            i = 0
-        P = self.parent()
-        return P([0]*int(i) + self.__coeffs[i:j])
-
-    def _unsafe_mutate(self, n, value):
-        """
-        Never use this unless you really know what you are doing.
-
-        WARNING: This could easily introduce subtle bugs, since SAGE
-        assumes everywhere that polynomials are immutable.  It's OK to
-        use this if you really know what you're doing.
-
-        EXAMPLES:
-            sage: R.<x> = ZZ[]
-            sage: f = (1+2*x)^2; f
-            4*x^2 + 4*x + 1
-            sage: f._unsafe_mutate(1, -5)
-            sage: f
-            4*x^2 - 5*x + 1        
-        """
-        n = int(n)
-        value = self.base_ring()(value)
-        if n >= 0 and n < len(self.__coeffs):
-            self.__coeffs[n] = value
-            if n == len(self.__coeffs) and value == 0:
-                self.__normalize()  
-        elif n < 0:
-            raise IndexError, "polynomial coefficient index must be nonnegative"
-        elif value != 0:
-            zero = self.base_ring()(0)
-            for _ in xrange(len(self.__coeffs), n):
-                self.__coeffs.append(zero)
-            self.__coeffs.append(value)
-            
-    def __floordiv__(self, right):
-        """
-        Return the quotient upon division (no remainder).
-
-        EXAMPLES:
-            sage: R.<x> = QQ[]
-            sage: f = (1+2*x)^3 + 3*x; f
-            8*x^3 + 12*x^2 + 9*x + 1
-            sage: g = f // (1+2*x); g
-            4*x^2 + 4*x + 5/2
-            sage: f - g * (1+2*x)
-            -3/2
-            sage: f.quo_rem(1+2*x)
-            (4*x^2 + 4*x + 5/2, -3/2)        
-        """
-        if right.parent() == self.parent():
-            return Polynomial.__floordiv__(self, right)
-        d = self.parent().base_ring()(right)
-        return self.polynomial([c // d for c in self.__coeffs], check=False)
-            
-    def list(self):
-        """
-        Return a new copy of the list of the underlying
-        elements of self.
-        
-        EXAMPLES:
-            sage: R.<x> = GF(17)[]
-            sage: f = (1+2*x)^3 + 3*x; f
-            8*x^3 + 12*x^2 + 9*x + 1
-            sage: f.list()
-            [1, 9, 12, 8]        
-        """
-        return list(self.__coeffs)
-
-    def degree(self):
-        """
-        EXAMPLES:
-            sage: R.<x> = RDF[]
-            sage: f = (1+2*x^7)^5
-            sage: f.degree()
-            35
-        """
-        return len(self.__coeffs) - 1
-
-    def shift(self, n):
-        r"""
-        Returns this polynomial multiplied by the power $x^n$. If $n$
-        is negative, terms below $x^n$ will be discarded. Does not
-        change this polynomial.
-
-        EXAMPLES:
-            sage: R.<x> = PolynomialRing(PolynomialRing(QQ,'y'), 'x')
-            sage: p = x^2 + 2*x + 4
-            sage: type(p)
-            <class 'sage.rings.polynomial_element_generic.Polynomial_generic_dense'>
-            sage: p.shift(0)
-             x^2 + 2*x + 4
-            sage: p.shift(-1)
-             x + 2
-            sage: p.shift(2)
-             x^4 + 2*x^3 + 4*x^2
-
-        AUTHOR:
-            -- David Harvey (2006-08-06)
-        """
-        if n == 0:
-            return self
-        if n > 0:
-            output = [self.base_ring()(0)] * n
-            output.extend(self.__coeffs)
-            return self.polynomial(output, check=False)
-        if n < 0:
-            if n > self.degree():
-                return self.polynomial([])
-            else:
-                return self.polynomial(self.__coeffs[-int(n):], check=False)
-
-
 class Polynomial_generic_sparse(Polynomial):
     """
@@ -380,5 +169,5 @@
         EXAMPLES:
             sage: R.<w> = PolynomialRing(CDF, sparse=True)
-            sage: f = CDF(1,2) + w^5 - pi*w + e
+            sage: f = CDF(1,2) + w^5 - CDF(pi)*w + CDF(e)
             sage: f._repr()
             '1.0*w^5 + (-3.14159265359)*w + 3.71828182846 + 2.0*I'
@@ -400,5 +189,5 @@
                 if n != m-1:
                     s += " + "
-                x = str(x)
+                x = repr(x)
                 if not atomic_repr and n > 0 and (x.find("+") != -1 or x.find("-") != -1):
                     x = "(%s)"%x
@@ -434,4 +223,5 @@
         EXAMPLES:
             sage: R.<w> = PolynomialRing(RDF, sparse=True)
+            sage: e = RDF(e)
             sage: f = sum(e^n*w^n for n in range(4)); f
             20.0855369232*w^3 + 7.38905609893*w^2 + 2.71828182846*w + 1.0
@@ -660,4 +450,5 @@
                                EuclideanDomainElement,
                                Polynomial_singular_repr):
+
     def quo_rem(self, other):
         """
@@ -738,6 +529,7 @@
 
         if fraction_field_element.is_FractionFieldElement(x):
-            if x.denominator() != 1:
-                raise TypeError, "denominator must be 1"
+            if x.denominator().degree() >= 1:
+                raise TypeError, "denominator must be constant"
+                x = x.numerator() * (~x.denominator()[0])
             else:
                 x = x.numerator()
@@ -1614,5 +1406,5 @@
                 if n != m:
                     s += " + "
-                x = str(x)
+                x = repr(x)
                 if not atomic_repr and n > 0 and (x.find("+") != -1 or x.find("-") != -1):
                     x = "(%s)"%x
@@ -1867,5 +1659,15 @@
         """
         self._ntl_set_modulus()
-        return self.parent()(self.__poly * right.__poly, construct=True)        
+        return self.parent()(self.__poly * right.__poly, construct=True)
+        
+    def _rmul_(self, c):
+        self._ntl_set_modulus()
+        return self.parent()(ZZ_pX([c]) * self.__poly, construct=True)
+        
+    def _lmul_(self, c):
+        self._ntl_set_modulus()
+        return self.parent()(ZZ_pX([c]) * self.__poly, construct=True)
+        
+
 
     def quo_rem(self, right):
Index: sage/rings/polynomial_pyx.pyx
===================================================================
--- sage/rings/polynomial_pyx.pyx	(revision 2725)
+++ sage/rings/polynomial_pyx.pyx	(revision 4059)
@@ -1144,6 +1144,6 @@
         return self.pq.degree 
 
-    def is_zero(self):
-        return self.pq.degree == -1
+    def __nonzero__(self):
+        return self.pq.degree != -1
 
     def list(self):
Index: sage/rings/polynomial_quotient_ring.py
===================================================================
--- sage/rings/polynomial_quotient_ring.py	(revision 3480)
+++ sage/rings/polynomial_quotient_ring.py	(revision 4003)
@@ -667,4 +667,5 @@
 
         EXAMPLES:
+            sage: x = polygen(QQ)
             sage: f = x^5 + x + 17
             sage: k = QQ['x'].quotient(f)
Index: sage/rings/polynomial_ring.py
===================================================================
--- sage/rings/polynomial_ring.py	(revision 3679)
+++ sage/rings/polynomial_ring.py	(revision 4149)
@@ -71,4 +71,5 @@
 import principal_ideal_domain
 import polynomial_element_generic
+import polynomial_element
 import multi_polynomial_element
 import rational_field
@@ -168,6 +169,6 @@
             except:
                 raise TypeError,"Unable to coerce string"
-        # elif isinstance(x, multi_polynomial_element.MPolynomial_polydict):
-        #    return x.univariate_polynomial(self)
+        elif hasattr(x, '_polynomial_'):
+            return x._polynomial_(self)
         elif is_MagmaElement(x):
             x = list(x.Eltseq())
@@ -309,5 +310,5 @@
             self.__polynomial_class = polynomial_element_generic.Polynomial_generic_sparse
         else:
-            self.__polynomial_class = polynomial_element_generic.Polynomial_generic_dense
+            self.__polynomial_class = polynomial_element.Polynomial_generic_dense
                 
     def base_extend(self, R):
@@ -435,4 +436,7 @@
             return True
         return False
+
+    def is_exact(self):
+        return self.base_ring().is_exact()
 
     def is_field(self):
@@ -828,4 +832,6 @@
             except:
                 raise TypeError,"Unable to coerce string"
+        elif hasattr(x, '_polynomial_'):
+            return x._polynomial_(self)
         return polynomial_element_generic.Polynomial_dense_mod_p(self, x, check, is_gen,construct=construct)
 
Index: sage/rings/polynomial_ring_constructor.py
===================================================================
--- sage/rings/polynomial_ring_constructor.py	(revision 3828)
+++ sage/rings/polynomial_ring_constructor.py	(revision 4259)
@@ -4,4 +4,5 @@
 
 from sage.structure.parent_gens import normalize_names
+from sage.structure.element import is_Element
 import ring
 import weakref
@@ -115,4 +116,10 @@
         y^2 + y
 
+    Often the quotes are not needed, because of predefined symbolic variables:
+        sage: R = GF(9,a)[x]
+        sage: R
+        Univariate Polynomial Ring in x over Finite Field in a of size 3^2
+
+
     In fact, since the diamond brackets on the left determine the variable name, you can omit the
     variable from the square brackets:
@@ -191,4 +198,10 @@
     """
     import polynomial_ring as m
+
+    if is_Element(arg1) and not isinstance(arg1, (int, long, m.integer.Integer)):
+        arg1 = repr(arg1)
+    if is_Element(arg2) and not isinstance(arg2, (int, long, m.integer.Integer)):
+        arg2 = repr(arg2)
+
     if isinstance(arg1, (int, long, m.integer.Integer)):
         arg1, arg2 = arg2, arg1
@@ -206,4 +219,8 @@
 
     R = None
+    if isinstance(arg1, (list, tuple)):
+        arg1 = [str(x) for x in arg1]
+    if isinstance(arg2, (list, tuple)):
+        arg2 = [str(x) for x in arg2]
     if isinstance(arg2, (int, long, m.integer.Integer)):
         # 3. PolynomialRing(base_ring, names, n, order='degrevlex'):
Index: sage/rings/polynomial_singular_interface.py
===================================================================
--- sage/rings/polynomial_singular_interface.py	(revision 2641)
+++ sage/rings/polynomial_singular_interface.py	(revision 4269)
@@ -4,4 +4,9 @@
 AUTHORS:
      -- Martin Albrecht <malb@informatik.uni-bremen.de> (2006-04-21)
+
+TESTS:
+    sage: R = MPolynomialRing(GF(2**8,'a'),10,'x', order='revlex')
+    sage: R == loads(dumps(R))
+    True
 
 """
@@ -30,4 +35,6 @@
 from complex_field import is_ComplexField
 from real_mpfr import is_RealField
+from complex_double import is_ComplexDoubleField
+from real_double import is_RealDoubleField
 from integer_ring import ZZ
 import sage.rings.arith
@@ -164,6 +171,6 @@
             #  size_t bits = 1 + (size_t) ((float)digits * 3.5);
             precision = self.base_ring().precision()
-            digits = sage.rings.arith.ceil((2*precision - 2)/7.0)
-            self.__singular = singular.ring("(real,%d,0)"%digits, _vars, order=order)
+            digits = sage.rings.arith.integer_ceil((2*precision - 2)/7.0)
+            self.__singular = singular.ring("(real,%d,0)"%digits, _vars, order=order, check=False)
 
         elif is_ComplexField(self.base_ring()):
@@ -171,13 +178,23 @@
             #  size_t bits = 1 + (size_t) ((float)digits * 3.5);
             precision = self.base_ring().precision()
-            digits = sage.rings.arith.ceil((2*precision - 2)/7.0)
-            self.__singular = singular.ring("(complex,%d,0,I)"%digits, _vars,  order=order)
+            digits = sage.rings.arith.integer_ceil((2*precision - 2)/7.0)
+            self.__singular = singular.ring("(complex,%d,0,I)"%digits, _vars,  order=order, check=False)
+
+        elif is_RealDoubleField(self.base_ring()):
+            # singular converts to bits from base_10 in mpr_complex.cc by:
+            #  size_t bits = 1 + (size_t) ((float)digits * 3.5);
+            self.__singular = singular.ring("(real,15,0)", _vars, order=order, check=False)
+
+        elif is_ComplexDoubleField(self.base_ring()):
+            # singular converts to bits from base_10 in mpr_complex.cc by:
+            #  size_t bits = 1 + (size_t) ((float)digits * 3.5);
+            self.__singular = singular.ring("(complex,15,0,I)", _vars,  order