# Ticket #9095: 9095-ec-ff-heights.patch

File 9095-ec-ff-heights.patch, 20.5 KB (added by robertwb, 12 years ago)

heights, apply on top of previous

• ## sage/schemes/elliptic_curves/ell_function_field.py

```# HG changeset patch
# User Robert Bradshaw <robertwb@math.washington.edu>
# Date 1275214680 25200
# Node ID e87c430ad87447090cee6de6560ac0fa6a7a119b
# Parent  095509ccfbde30e933ea9acafd1920d303f59d9c
#9095 - heights on elliptic curves over function fields

diff -r 095509ccfbde -r e87c430ad874 sage/schemes/elliptic_curves/ell_function_field.py```
 a The Legendre curve:: sage: K. = FunctionField(GF(5)) sage: E = EllipticCurve(K, [0, t^2+t, 0, t^3, 0]); E sage: Ell = EllipticCurve(K, [0, t^2+t, 0, t^3, 0]); Ell Elliptic Curve defined by y^2 = x^3 + (t^2+t)*x^2 + t^3*x over Rational function field in t over Finite Field of size 5 A rank 2 twist:: sage: E = E.quadratic_twist(t+1).short_weierstrass_model() sage: E = Ell.quadratic_twist(t+1).short_weierstrass_model() sage: P = E.lift_x(3*t^3 + t^2 - t) sage: Q = E.lift_x(3*t^3 + 2*t^2 + 3*t) sage: M = matrix(QQ, 2, [E.height_pairing(a,b) for a in [P,Q] for b in [P,Q]]) sage: M [3/2 1/2] [1/2   1] sage: M.det() 5/4 """ ###################################################################### #  Copyright (C) 2010 Robert Bradshaw #  Copyright (C) 2010 Thomas Occhipinti ###################################################################### from sage.structure.element import parent from sage.misc.all import cached_method from sage.functions.all import ceil from sage.rings.all import ZZ, Integer, unsigned_infinity as infinity, factor, gcd from ell_field import EllipticCurve_field import ell_point from sage.rings.function_field.all import is_FunctionField def minimalE(E): #this cleans up to minimal Weierstrass model, given a short W model #This only works if char = 0 or char > 3 #To Do: deal with the a4 or a6 = 0 case #Okay, so these aren't really a4 or a6, they are a4 and a6 in a "short" W model a4=E.a4() a6=E.a6() conv=1 for v,e in factor(a4.denominator()): r = a4.denominator().valuation(v) a4=a4*v ** (4*ceil(r/Integer(4))) a6=a6*v ** (6*ceil(r/Integer(4))) conv=conv*v ** ceil(r/Integer(4)) for v,e in factor(a6.denominator()): r = a6.denominator().valuation(v) a4=a4*v ** (4*ceil(r/Integer(6))) a6=a6*v ** (6*ceil(r/Integer(6))) conv=conv*v ** ceil(r/Integer(6)) for v,e in factor(gcd(a4.numerator(),a6.numerator())): while a4.numerator().valuation(v) > 3 and a6.numerator().valuation(v) > 5: a4=a4/v ** 4 a6=a6/v ** 6 conv=conv/v #this does not deal with minimality at infinity, which is dealt with elsewhere from constructor import EllipticCurve return EllipticCurve(E.base_ring(), [a4,a6]), conv def kodaira_type(v,vdisc,j,b): #if the reduction is multiplicative, we're done if b.numerator().valuation(v)==0: return "I_"+str(vdisc) if vdisc>10 or vdisc==6 or vdisc==7: return "Istar_"+str(vdisc-6) if vdisc==2: return "II" if vdisc==3: return "III" if vdisc==4: return "IV" #if we aren't done yet we need to know a bit about the j-invariant jmodv=1; if j.denominator().valuation(v)>0: jmodv=infinity if j.numerator().valuation(v)>0: jmodv=0 if vdisc==8: if jmodv==0: return "IVstar" return "Istar_2" if vdisc==9: if jmodv==infinity: return "Istar_3" return "IIIstar" if vdisc==10: if jmodv==0: return "IIstar" return "Istar_4" #all cases should be covered at this point raise RuntimeError, "Invalid discriminant valuation: %s" % vdisc def contrv(Ktype,i,j): #Computes the correction factor for points passing through the ith and jth component #of a fiber of type Ktype.  Note this is depedent on numbering the components correctly #This code is based on a table in Shioda's "Elliptic Surfaces" if i*j==0: return 0 if Ktype=="II" or Ktype=="IIstar" or Ktype=="I_1" or Ktype=="I_0": return 0 if Ktype=="IIIstar": return 3/Integer(2) if Ktype=="III": return 1/Integer(2) if Ktype=="IV": if i==j: return 2/Integer(3) return 1/Integer(3) if Ktype=="IVstar": if i==j: return 4/Integer(3) return 2/Integer(3) if Ktype=="Istar_0": if i==j: return 1 return 1/Integer(2) if Ktype[0:6]=="Istar_": if j 1/t. EXAMPLES:: sage: from sage.schemes.elliptic_curves.ell_function_field import invert_generator sage: K. = FunctionField(QQ) sage: invert_generator(t) 1/t sage: a = (t+2/t^2)^3; a (t^9 + 6*t^6 + 12*t^3 + 8)/t^6 sage: K.hom([1/t])(a) (8*t^9 + 12*t^6 + 6*t^3 + 1)/t^3 sage: invert_generator(a) (8*t^9 + 12*t^6 + 6*t^3 + 1)/t^3 sage: K. = FunctionField(GF(5)) sage: a = K.random_element(10) sage: K.hom([1/t])(a) == invert_generator(a) True """ K = a.parent() t = K.gen() numer, denom = a.numerator(), a.denominator() return K(numer.reverse() / denom.reverse()) * t**(denom.degree() - numer.degree()) class EllipticCurve_function_field(EllipticCurve_field): def __init__(self, K, ainvs): EllipticCurve_field.__init__(self, [K(x) for x in ainvs]) self._point_class = EllipticCurvePoint_function_field @cached_method def minimal_model_maps(self): """ Returns the minimal model of self away from and at infinity. EXAMPLES:: sage: K. = FunctionField(GF(5)) sage: E = EllipticCurve(K, [2,t]) sage: E.minimal_model_maps() (Generic morphism: From: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 2*x + t over Rational function field in t over Finite Field of size 5 To:   Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 2*x + t over Rational function field in t over Finite Field of size 5 Via:  (u,r,s,t) = (1, 0, 0, 0), Generic morphism: From: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 2*x + 1/t over Rational function field in t over Finite Field of size 5 To:   Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 2*t^4*x + t^5 over Rational function field in t over Finite Field of size 5 Via:  (u,r,s,t) = (1/t, 0, 0, 0)) sage: EllipticCurve(K, [1,t,t^2,0,1]).minimal_model_maps() (Generic morphism: From: Abelian group of points on Elliptic Curve defined by y^2 + x*y + t^2*y = x^3 + t*x^2 + 1 over Rational function field in t over Finite Field of size 5 To:   Abelian group of points on Elliptic Curve defined by y^2 = x^3 + (t^2+4*t+3)*x + (4*t^4+3*t^2+3*t) over Rational function field in t over Finite Field of size 5 Via:  (u,r,s,t) = (1, 3*t + 2, 2, 2*t^2 + t + 4), Generic morphism: From: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + ((3*t^2+4*t+1)/t^2)*x + ((3*t^3+3*t^2+4)/t^4) over Rational function field in t over Finite Field of size 5 To:   Abelian group of points on Elliptic Curve defined by y^2 = x^3 + (3*t^4+4*t^3+t^2)*x + (3*t^5+3*t^4+4*t^2) over Rational function field in t over Finite Field of size 5 Via:  (u,r,s,t) = (1/t, 0, 0, 0)) """ Ews = self.short_weierstrass_model() Emin, conv = minimalE(Ews) self._is_minimal = self == Emin K = self.base_ring() from constructor import EllipticCurve Einf = EllipticCurve(K, [invert_generator(Ews.a4()), invert_generator(Ews.a6())]) return self.isomorphism_to(Emin), Einf.isomorphism_to(minimalE(Einf)[0]) @cached_method def reduction_data(self): """ EXAMPLES:: sage: K. = FunctionField(GF(19)) sage: E = EllipticCurve(K, [t^2, (17*t+1)*t^2]) sage: E.reduction_data() {Infinity: 'Istar_0', t + 15: 'I_1', t: 'IV', t + 1: 'I_1'} """ if self.base_ring().degree() > 1: raise NotImplementedError to_min, to_inf = self.minimal_model_maps() if not self._is_minimal: Emin = to_min.codomain().codomain() reduction_data = Emin.reduction_data() self._euler_characteristic = Emin._euler_characteristic self._reduction_types = Emin._reduction_types return reduction_data Einf = to_inf.codomain().codomain() a4, a6 = self.a4(), self.a6() j = self.j_invariant() disc = self.discriminant().numerator() self._reduction_types = {} for v, e in disc.factor(): self._reduction_types[v]=kodaira_type(v, e, j, a6) idisc = Einf.discriminant().numerator() tinf = idisc.parent().gen() if idisc.valuation(tinf) > 0: self._reduction_types[infinity] = kodaira_type(tinf, idisc.valuation(tinf), Einf.j_invariant(), Einf.a6()) degj = max(j.numerator().degree(), j.denominator().degree()) localparts = 0 typedict = self._reduction_types for v in self._reduction_types: if v == infinity: if typedict[v]=="II": localparts=localparts+2 elif typedict[v]=="IIstar": localparts=localparts+10 elif typedict[v]=="III": localparts=localparts+3 elif typedict[v]=="IIIstar": localparts=localparts+9 elif typedict[v]=="IV": localparts=localparts+4 elif typedict[v]=="IVstar": localparts=localparts+8 elif typedict[v][0:6]=="Istar_": localparts=localparts+6 else: if typedict[v]=="II": localparts=localparts+2*v.degree() elif typedict[v]=="IIstar": localparts=localparts+10*v.degree() elif typedict[v]=="III": localparts=localparts+3*v.degree() elif typedict[v]=="IIIstar": localparts=localparts+9*v.degree() elif typedict[v]=="IV": localparts=localparts+4*v.degree() elif typedict[v]=="IVstar": localparts=localparts+8*v.degree() elif typedict[v][0:6]=="Istar_": localparts=localparts+6*v.degree() self._euler_characteristic = (degj+localparts) / ZZ(12) return typedict def euler_characteristic(self): self.reduction_data() return self._euler_characteristic def intersection_pairing(self, P, Q): if P == Q: return -self.euler_characteristic() diff = P - Q diff_min = diff.minimal_point() diff_inf = diff.minimal_point(True) tinf = diff_inf[0].parent().gen().numerator() return 1/Integer(2) * (diff_min[0].denominator().degree() + diff_inf[0].denominator().valuation(tinf)) def height_pairing(self, P, Q): """ EXAMPLES:: sage: K. = FunctionField(GF(19)) sage: E = EllipticCurve(K, [t^2, (17*t+1)*t^2]) sage: P = E((t,t)) sage: E.height_pairing(P, -P) -1/3 sage: K. = FunctionField(GF(5)) sage: E = EllipticCurve(K, [0, t^2+t, 0, t^3, 0]) sage: E = E.quadratic_twist(t+1).short_weierstrass_model() sage: P = E.lift_x(3*t^3 + t^2 - t) sage: Q = E.lift_x(3*t^3 + 2*t^2 + 3*t) sage: E.height_pairing(P, Q) 1/2 sage: P.height() + Q.height() + 2*E.height_pairing(P, Q) 7/2 sage: (P+Q).height() 7/2 """ O = self(0) res = (self.euler_characteristic() + self.intersection_pairing(P, O) + self.intersection_pairing(Q, O) - self.intersection_pairing(P, Q)) reduction_data = self.reduction_data() for v in reduction_data: if v == infinity: res -= contrv(reduction_data[v], P.component(v), Q.component(v)) else: res -= v.degree() * contrv(reduction_data[v], P.component(v), Q.component(v)) return res class EllipticCurvePoint_function_field(ell_point.EllipticCurvePoint_field): pass @cached_method def minimal_point(self, infinite=False): E = self.curve() to_min, to_inf = E.minimal_model_maps() if infinite: K = self.curve().base_ring() x,y = self.xy() return to_inf(to_inf.domain()((invert_generator(x), invert_generator(y)))) elif E._is_minimal: return self else: return to_min(self) @cached_method def component(self, v=None): """ EXAMPLES:: sage: K. = FunctionField(GF(19)) sage: E = EllipticCurve(K, [t^2, (17*t+1)*t^2]) sage: P = E((t,t)) sage: P.component(t) 1 sage: P.component() {t + 1: 0, t + 15: 0, t: 1, Infinity: 1} """ E = self.curve() reduction_data = E.reduction_data() if v is None: return dict((v, self.component(v)) for v in reduction_data) # First, we move to a new curve if necessary. if v == infinity: return self.minimal_point(True).component(E.base_ring().gen().element().numer()) elif not E._is_minimal: return self.minimal_point().component(v) else: # Here we are looking at a non-infinite place on the minimal model. def constant_part(rat): return rat.numerator().constant_coefficient()/rat.denominator().constant_coefficient() a = E.a4() b = E.a6() x, y = self.xy() if is_FunctionField(parent(v)): assert v.denominator() == 1 v = v.numerator() try: Ktype = reduction_data[v] except KeyError: return 0 #return the component of the fiber at v through which the point passes. #0 is the identity component #if the type is II or IIstar, the identity component is the only possibility if Ktype=="II" or Ktype=="IIstar" or Ktype=="I_1": return 0 #check if the point lies on the identity component if (3*x**2+a).numerator().valuation(v)==0: return 0 #if the type is III or IIIstar then there is only one non-identity component #We call that component 1 if Ktype=="III" or Ktype=="IIIstar" or Ktype=="I_2": return 1 #if the type is IV or IVstar then there are two non-identity components, which we #will arbitrarily call 1 and 2 if Ktype=="IV": ydivv=y/v y0=constant_part(ydivv) #this less than uses the lexicographic ordering of Fq to label the components if y0 < -y0: return 1 return 2 if Ktype=="IVstar": ydivv=y/v**2 y0=constant_part(ydivv) #this less than uses the lexicographic ordering of Fq to label the components if y0 < -y0: return 1 return 2 #Istar0 fibers have three non-zero components, which correspond to the roots of a #certain cubic polynomial. if Ktype=="Istar_0": r=a/v**2 r0=constant_part(r) s=b/v**3 s0=constant_part(s) x1=constant_part(x/v) X = E.base_ring().constant_field()['X'].gen() roots = (X**3 + r0*X + s0).roots() roots.sort() if x1==roots[0][0]: return 1 elif x1==roots[1][0]: return 2 return 3 if Ktype[0:2]=="I_": #call the number of components b n=int(Ktype[2:]) k=y.numerator().valuation(v) if 2*k > n-1: return n/Integer(2) c=constant_part((3*x**2+a)/v**k) yk=constant_part(y/v**k) if yk/c > -yk/c: return k return n-k if Ktype[0:6]=="Istar_": #In this case we label our mult 1 components 0, 1, 2, 3 #Following Shioda, 1 is the "near" component and 2, 3 are the "far" components n=int(Ktype[6:]) r=a/v**2 s=b/v**3 r0=constant_part(r) s0=constant_part(s) x0=constant_part(x/v) X = E.base_ring().constant_field()['X'].gen() roots = (X**3 + r0*X + s0).roots() coxa = next(item[0] for item in roots if item[1] == 2) if x0==-2*coxa: return 1 #in this case we must break into separate cases for b even and odd if n%2==0: t = E.base_ring().gen() sing0=constant_part((3*x**2+a)/(t**((n+4)/2))) if sing0 > -sing0: return 2 return 3 if n%2==1: y0=constant_part(y/v**((b+3)/2)) if y0 > -y0: return 2 return 3 raise RuntimeError, "Bad reduction type: %s" % Ktype def height(self): """ EXAMPLES:: sage: K. = FunctionField(GF(19)) sage: E = EllipticCurve(K, [t^2, (17*t+1)*t^2]) sage: P = E((t,t)) sage: P.height() 1/3 """ E = self.curve() height = 2 * E.euler_characteristic() + 2 * E.intersection_pairing(self, E(0)) reduction_data = E.reduction_data() for v in reduction_data: componentv = self.component(v) if v == infinity: height -= contrv(reduction_data[v], componentv, componentv) else: height -= v.degree() * contrv(reduction_data[v], componentv, componentv) return height def naive_height(self): """ sage: K. = FunctionField(GF(19)) sage: E = EllipticCurve(K, [t^2, (17*t+1)*t^2]) sage: P = E((t,t)) sage: P.height() 1/3 sage: P.naive_height() 1 sage: (3*P).naive_height() / 9 1/3 """ x = self.minimal_point()[0] return max(x.denominator().degree(), x.numerator().degree())