diff -r 03b9d8113657 -r b4439a628ed2 sage/functions/complex_lattice.py
--- a/sage/functions/complex_lattice.py	Thu Apr 23 15:19:33 2009 -0700
+++ b/sage/functions/complex_lattice.py	Fri Apr 24 20:58:34 2009 -0700
@@ -3,6 +3,8 @@
 import sage.matrix.matrix
 from sage.rings.all import ZZ, QQ, ComplexField
 from riemann_theta import invert
+from sage.matrix.all import matrix
+from sage.modules.all import vector
 
 class ComplexLattice:
     r"""
diff -r 03b9d8113657 -r b4439a628ed2 sage/functions/klein_p.py
--- a/sage/functions/klein_p.py	Thu Apr 23 15:19:33 2009 -0700
+++ b/sage/functions/klein_p.py	Fri Apr 24 20:58:34 2009 -0700
@@ -11,6 +11,22 @@
     import sage.symbolic.ring
     return sage.symbolic.ring.var(*args) # ignore kwds for now
 
+def symplectic_blocks(A):
+    n = A.nrows() // 2
+    Gamma = A.copy()
+    Gamma.subdivide(n, n)
+    a, b, c, d = Gamma.subdivision(0, 0), Gamma.subdivision(0, 1), Gamma.subdivision(1, 0), Gamma.subdivision(1, 1)
+    return a, b, c, d
+
+def act_on_char(v, M):
+    a, b, c, d = symplectic_blocks(M)
+    B = (ZZ(1)/2*a.transpose()*c)
+    bs = [ B[i, i] for i in range(B.nrows()) ]
+    C = (ZZ(1)/2*b.transpose()*d)
+    cs = [ C[i, i] for i in range(B.nrows()) ]
+    u = M.transpose()*vector(v) + vector(bs + cs)
+    return u
+
 class KleinPFunction:
     r"""
     EXAMPLES::
@@ -42,9 +58,7 @@
         [-88.0400127429 - 185.610596981*I  61.5755815636 - 52.9059237104*I -2.80859789488 - 5.44145586052*I]
         [-88.0400127429 - 185.610596981*I  61.5755815636 - 52.9059237104*I -2.80859789488 - 5.44145586052*I]
 
-
-
-
+        The Klein $p$-functions as theta functions:
 
         sage: Omega = matrix(ComplexField(200), 2, 4, [[ -4.7405 - 2.1033*I, -2.2680 - 0.73692*I, -1.4017 - 0.45544*I, 0.86631 + 1.1924*I], [ -4.6218 + 2.6971*I, 0.50844 - 0.69981*I, -0.82267 + 1.1323*I, -1.3311 - 0.43250*I]])
         sage: u = Omega * vector([-1/9, -1/5, 4/7, 2/3])
@@ -52,33 +66,31 @@
         sage: c = [(1/2, 0), (1/2, 0)]
         sage: T = KleinPFunction(c, Omega)
 
-        sage: siegel_theta_with_char(c, T._lattice._tau, 0)
-        sage: T._rational_function_for_derivative(0, 0)
-        
-        sage: [ T([ 1/(10*n^4), 0 ]) for n in range(1, 10, 2) ]
+        sage: w2i = sage.functions.riemann_theta.invert(T._lattice._w2)
 
-        # sage: u = 0*u
+        sage: F0 = lambda(u): (siegel_theta(T._lattice._tau, w2i*(u + T._lattice._w1*T._r + T._lattice._w2*T._s)))^2
+        sage: v0 = F0(u)
+        sage: vs0 = [ F0(u + Omega*v)/v0 for v in (QQ^4).basis() ]; vs0
+        [-16487.492394930182668277324150116927554150265718974510196455 + 479.19016920897403723210696608619729178293222907875587709466*I,
+         -75.383912252238205442425176070603448662756671505393552089737 - 199.03073804363008003970949935689460364964520370386947387148*I,
+         1.0000000000000000000000000000000000000000000000000000000000 - 6.2230152778611417071440640537801242405902521687211671331011e-59*I,
+         1.0000000000000000000000000000000000000000000000000000000000 - 3.1737377917091822706434726674278633627010286060477952378816e-59*I]
 
-        sage: w2i = sage.functions.riemann_theta.invert(T._lattice._w2)
-        sage: v0 = siegel_theta_with_char(c, T._lattice._tau, w2i*u)
-        sage: vs0 = [ siegel_theta_with_char(c, T._lattice._tau, w2i*(u + Omega*v))/v0 for v in (QQ^4).basis() ]; vs0
+        sage: F1 = lambda(u): (T(u, theta=2))
+        sage: v1 = F1(u)
+        sage: vs1 = [ F1(u + Omega*v)/v1 for v in (QQ^4).basis() ]; vs1
+        [-16488.280681303679869619898553247616018735438591661019545124 + 478.77207179245119025244691818738230399045940647557308702332*I,
+         -75.386885202833213393244288967271682030147622368988542259939 - 199.05177602257529213805043288308245086597976894487565516400*I,
+         1.0000000000000000000000000000000000000000000000000000000000,
+         1.0000000000000000000000000000000000000000000000000000000000 + 2.1780553472513995975004224188230434842065882590524084965854e-60*I]
 
-        sage: T(u, theta=True)
-        sage: T(u) * siegel_theta_with_char(c, T._lattice._tau, w2i*u)^2
-
-        sage: v1 = T(u, theta=True); v1
-        sage: T._last_subs_dict['X']
-        4.7152730063487808517364990257033652942008921406590784528275e-6 - 3.1990704034116803052447891933386212484433501980263454265724e-6*I
-        sage: siegel_theta(T._lattice._tau, w2i*u + T._z*T._r + T._s)
-        4.7152730063487808517364990257033652942008921406590784528275e-6 - 3.1990704034116803052447891933386212484433501980263454265724e-6*I
-
-        sage: vs1 = [ T((u + Omega*v), theta=True)/v1 for v in (QQ^4).basis() ]; vs1
-
-        sage: 2
+        sage: v1
+        -3.6933728385553929818733586359883313386820842853086473298038 + 2.7371941934098641999889606670061469307324921624281306538397*I
     """
     def __init__(self, rs, lattice):
         self._lattice = ComplexLattice(lattice)
         self._z = self._lattice._tau
+        self._g = self._z.nrows() # XXX only works for g = 2 anyways!
         self._R = self._z.base_ring()
         II = self._R.gen()
         PI = self._R.pi()
@@ -96,7 +108,6 @@
         import sage.symbolic.function
         self._func = sage.symbolic.function.function('theta')
         self._theta = self._func(*v)
-        self._total = -1 * (self._theta.log() + self._scale)
         self._RT = RiemannTheta(self._z)
 
         # cache with memory one
@@ -107,6 +118,16 @@
     def __repr__(self):
         return "phi[...]( _, \n%s" % self._lattice._Omega.change_ring(ComplexField(10))
 
+    def reduced(self):
+        return KleinPFunction((self._r, self._s), self._lattice.reduced())
+
+    def acted_on_by(self, G):
+        d = act_on_char(vector(list(self._r) + list(self._s)), G)
+        Omega = self._lattice._Omega * G.transpose()
+        r = d[:self._g]
+        s = d[self._g:]
+        return KleinPFunction((r, s), Omega)
+
     def _derivs_upto(self, N):
         r"""
         EXAMPLES::
@@ -131,21 +152,38 @@
                 L.append(vector(xs))
         return L
 
-    @cached_method
-    def _rational_function_for_derivative(self, *derivs):
+    def _rational_function_for_derivative(self, derivs, theta=0):
         r"""
         Calculate the rational function giving $p_{derivs}$ in terms of theta
         derivatives.
+
+        sage: tau = matrix(CDF, 2, 2, [I, 0, 0, I])
+        sage: T = KleinPFunction([(1/2, 0), (1/2, 0)], tau)
+        sage: T._rational_function_for_derivative((0, 0))
+        (((-3.14159265359)*X^2 + X_0^2 - X*X_00)/X^2, {(0,): 'X_0', (0, 0): 'X_00'})
+        sage: T._rational_function_for_derivative((0, 1))
+        ((-X*X_01 + X_0*X_1)/X^2, {(0, 1): 'X_01', (0,): 'X_0', (1,): 'X_1'})
+        sage: T._rational_function_for_derivative((1, 1, 1))
+        (((-2.0)*X_1^3 + 3.0*X*X_1*X_11 - X^2*X_111)/X^3, {(1, 1, 1): 'X_111', (1, 1): 'X_11', (1,): 'X_1'})
+
+        The theta options works:
+
+        sage: T._rational_function_for_derivative((0, 0), theta=0)
+        (((-3.14159265359)*X^2 + X_0^2 - X*X_00)/X^2, {(0,): 'X_0', (0, 0): 'X_00'})
+        sage: T._rational_function_for_derivative((0, 0), theta=1)
+        (((-3.14159265359)*X^2 + X_0^2 - X*X_00)/X, {(0,): 'X_0', (0, 0): 'X_00'})
+        sage: T._rational_function_for_derivative((0, 0), theta=2)
+        ((-3.14159265359)*X^2 + X_0^2 - X*X_00, {(0,): 'X_0', (0, 0): 'X_00'})
+        sage: T._rational_function_for_derivative((0, 0), theta=3)
+        ((-3.14159265359)*X^3 + X*X_0^2 - X^2*X_00, {(0,): 'X_0', (0, 0): 'X_00'})
         """
         assert len(derivs) >= 2
 
         u0, u1 = myvar('u0, u1', ns=1)
         u = vector([u0, u1])
         v = u * invert(self._lattice._w2).transpose()
-        func = self._func
-        theta = self._theta
 
-        total_symb = self._total
+        total_symb = -1 * (self._theta.log() + self._scale)
         for deriv in derivs:
             total_symb = total_symb.derivative(u[deriv])
 
@@ -158,7 +196,7 @@
 
         empty_subs_dict = {}
         for deriv in self._derivs_upto(len(derivs)):
-            f = func(u0, u1)
+            f = self._func(u0, u1)
             for ind in deriv:
                 f = f.derivative(u[ind])
             f = patch_up(f) # very important!
@@ -172,8 +210,8 @@
 
         # these ones are always present
         X = myvar('X', ns=1)
-        total_symb = total_symb.subs(theta.log() == myvar('logX', ns=1)) # important that log is substitutated
-        total_symb = total_symb.subs(theta == X) # before the value
+        total_symb = total_symb.subs(self._theta.log() == myvar('logX', ns=1)) # important that log is substitutated
+        total_symb = total_symb.subs(self._theta == X) # before the value
         total_symb = total_symb.subs(u[0] == myvar('u0', ns=1))
         total_symb = total_symb.subs(u[1] == myvar('u1', ns=1))
 
@@ -182,9 +220,18 @@
         names = ['X'] + names # make 'X' first name
 
         S = PolynomialRing(self._R, len(names), names=names) # self._R[*names]
+        XinS = S.gen(0)
         # one last bit of hijinks, to avoid computing GCDs over inexact rings
-        total_symb = (X**len(derivs) * total_symb).expand()
-        total_poly = (total_symb)._polynomial_(S) / S.gen(0)**len(derivs)
+
+        # usually we scale numerater and denominator by X**(len(derivs))
+        total_symb = (X**len(derivs) * total_symb)
+        total_poly = (total_symb.expand())._polynomial_(S)
+        if len(derivs) - theta < 0:
+            total_poly *= XinS**( theta - len(derivs) )
+        elif len(derivs) - theta > 0:
+            total_poly /= XinS**( len(derivs) - theta )
+
+        assert total_poly in S.fraction_field()
         return (total_poly, empty_subs_dict)
 
     def _subs_dict_for(self, empty_subs_dict, u, rs_diff=None):
@@ -223,7 +270,7 @@
         self._last_subs_dict = subs_dict
         return subs_dict
 
-    def values_at_point(self, u, list_of_derivs, rs_diff=None, theta=False):
+    def values_at_point(self, u, list_of_derivs, rs_diff=None, theta=0):
         r"""
         EXAMPLES::
             sage: tau = matrix(CDF, 2, 2, [I, 1, 1, 2*I])
@@ -254,9 +301,7 @@
         empty_subs_items = []
         polys = []
         for deriv in list_of_derivs:
-            poly, esd = self._rational_function_for_derivative(*tuple(deriv))
-            if theta:
-                poly = poly.numerator()
+            poly, esd = self._rational_function_for_derivative(tuple(deriv), theta=theta)
             polys.append(poly)
             empty_subs_items += esd.items() # merge all dicts
         empty_subs_dict = dict(empty_subs_items)
@@ -265,7 +310,7 @@
         vals = [ self._R(poly.subs(**subs_dict)) for poly in polys ]
         return vector(vals)
 
-    def __call__(self, u, derivs=[0, 0], rs_diff=None, theta=False):
+    def __call__(self, u, derivs=[0, 0], rs_diff=None, theta=0):
         vals = self.values_at_point(u, [derivs], rs_diff=rs_diff, theta=theta)
         return vals[0]
 
@@ -295,22 +340,6 @@
     # assert all(is_symplectic(G) for G in Gs)
     return Gs
 
-def symplectic_blocks(A):
-    n = A.nrows() // 2
-    Gamma = A.copy()
-    Gamma.subdivide(n, n)
-    a, b, c, d = Gamma.subdivision(0, 0), Gamma.subdivision(0, 1), Gamma.subdivision(1, 0), Gamma.subdivision(1, 1)
-    return a, b, c, d
-
-def act_on_char(v, M):
-    a, b, c, d = symplectic_blocks(M)
-    B = (ZZ(1)/2*a.transpose()*c)
-    bs = [ B[i, i] for i in range(B.nrows()) ]
-    C = (ZZ(1)/2*b.transpose()*d)
-    cs = [ C[i, i] for i in range(B.nrows()) ]
-    u = M.transpose()*vector(v) + vector(bs + cs)
-    return u
-
 def assert_klein_p_automorphy(n=5):
     r"""
     sage: from sage.functions.klein_p import assert_klein_p_automorphy
@@ -340,10 +369,7 @@
 
         failed = False
         for G in generators_of_SP4Z(scale=1):
-            d = act_on_char(vector(flatten(c)), G)
-            Omega_ = T._lattice._Omega * G.transpose()
-            d1, d2, d3, d4 = d
-            T2 = KleinPFunction([(d1, d2), (d3, d4)], Omega_)
+            T2 = T.acted_on_by(G)
             v2 = T2.values_at_point(u, list_of_derivs) # , rs_diff=rs_diff)
 
             e2 = (v1 - v2).norm() < 1e-6
