trace of Heegner point

691 days ago by jen

Let E be an elliptic curve, K a quadratic imaginary number field, and K[1] the Hilbert class field of K. Suppose we have computed the point y_1 \in E(K[1]) so that its coordinates are known as algebraic numbers. This algorithm computes the trace y_K = tr_{E(K[1])/E(K)} y_1 \in E(K).

def content(f): """ f: polynomial computes the content of f """ return gcd(f.coefficients()) def trace(E, y1): """ E: elliptic curve y1: Heegner point computes the trace of the Heegner point y1 """ R1 = QQ['x'] x = R1.gen() D = E.two_division_polynomial() if y1[0] == 0: A = x else: A = y1[0].minpoly() a1, a2, a3, a4, a6 = E.a_invariants() B = (2*y1[1] + a1*y1[0] + a3).polynomial('x') try: xcoord = y1[0].polynomial() except AttributeError: Pass #print "B = %s"%B #print "D = %s"%D #print "A = %s"%A if xcoord != x: q,r = B.quo_rem(xcoord) B = q*x + r if r.degree() != 0: raise ValueError,"need a different Galois conjugate" #g1monic,d = sage.schemes.elliptic_curves.heegner.make_monic(y1[0].polynomial()) #L.<a> = NumberField(g1monic) #EL = E.change_ring(L) #newpoint = EL.lift_x(a/d) #xcoord = newpoint[0].polynomial() #B = (2*newpoint[1] + a1*newpoint[0] + a3).polynomial('x') C,rr =(((B^2)-D)).quo_rem(4*A) c = content(B)/content(A) if c == 0: #then B is 0 and the point is 2-torsion return E(-a3/a1,0) A = A*c C = C/c while C.degree() < A.degree(): A_copy = A A = C C = A_copy B = -B d,r = B.quo_rem(2*A) C += d*(d*A-B) B -= 2*d*A if A.degree() == 0: return E(0,1,0) else: #print [A,B,C] x = A.constant_coefficient()/-A.leading_coefficient() return E(x, (B-a3- a1*x)/2) 
       

An example for E = 37a with K = \mathbf{Q}(\sqrt{-115}).

E = EllipticCurve('37a') P = E.heegner_point(-115) Q = P.point_exact() print "Q: ", Q print "trace of Q: ", trace(E,Q) print "2*Q: ", 2*Q print "trace of 2*Q: ",trace(E,2*Q) print trace(E,2*Q) == 2*trace(E,Q) 
       
Q:  (a : a + 8 : 1)
trace of Q:  (6 : -15 : 1)
2*Q:  (4495/27889*a - 9971/27889 : 228470/4657463*a + 2722552/4657463 :
1)
trace of 2*Q:  (1357/841 : -53277/24389 : 1)
True
Q:  (a : a + 8 : 1)
trace of Q:  (6 : -15 : 1)
2*Q:  (4495/27889*a - 9971/27889 : 228470/4657463*a + 2722552/4657463 : 1)
trace of 2*Q:  (1357/841 : -53277/24389 : 1)
True

An example for K = \mathbf{Q}(\sqrt{-47}):

E = EllipticCurve('37a') P = E.heegner_point(-47) Q = P.point_exact() print Q print "approx: ", P.numerical_approx() print "trace: ",trace(E,Q) 
       
(a : a^4 + a - 1 : 1)
approx:  (0.412950303452653 - 1.25066518004254*I : -1.28823571480978 -
1.62837695832401*I : 1.00000000000000)
trace:  (0 : -1 : 1)
(a : a^4 + a - 1 : 1)
approx:  (0.412950303452653 - 1.25066518004254*I : -1.28823571480978 - 1.62837695832401*I : 1.00000000000000)
trace:  (0 : -1 : 1)
R = E(0,0) #Mordell-Weil generator for i in range(-5,6): print i,i*R 
       
-5 (1/4 : -3/8 : 1)
-4 (2 : 2 : 1)
-3 (-1 : 0 : 1)
-2 (1 : -1 : 1)
-1 (0 : -1 : 1)
0 (0 : 1 : 0)
1 (0 : 0 : 1)
2 (1 : 0 : 1)
3 (-1 : -1 : 1)
4 (2 : -3 : 1)
5 (1/4 : -5/8 : 1)
-5 (1/4 : -3/8 : 1)
-4 (2 : 2 : 1)
-3 (-1 : 0 : 1)
-2 (1 : -1 : 1)
-1 (0 : -1 : 1)
0 (0 : 1 : 0)
1 (0 : 0 : 1)
2 (1 : 0 : 1)
3 (-1 : -1 : 1)
4 (2 : -3 : 1)
5 (1/4 : -5/8 : 1)
E.heegner_index(-47) 
       
1.00000?
1.00000?