Path: blob/master/sage/schemes/elliptic_curves/weierstrass_morphism.py
4126 views
r"""1Isomorphisms between Weierstrass models of elliptic curves23AUTHORS:45- Robert Bradshaw (2007): initial version6- John Cremona (Jan 2008): isomorphisms, automorphisms and twists7in all characteristics8"""910#*****************************************************************************11# Copyright (C) 2007 Robert Bradshaw <[email protected]>12#13# Distributed under the terms of the GNU General Public License (GPL)14#15# This code is distributed in the hope that it will be useful,16# but WITHOUT ANY WARRANTY; without even the implied warranty of17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU18# General Public License for more details.19#20# The full text of the GPL is available at:21#22# http://www.gnu.org/licenses/23#*****************************************************************************242526from sage.categories.morphism import Morphism27from constructor import EllipticCurve28from sage.categories.homset import Hom2930class baseWI:31r"""32This class implements the basic arithmetic of isomorphisms between33Weierstrass models of elliptic curves. These are specified by34lists of the form `[u,r,s,t]` (with `u\not=0`) which specifies a35transformation `(x,y) \mapsto (x',y')` where3637`(x,y) = (u^2x'+r , u^3y' + su^2x' + t).`3839INPUT:4041- ``u,r,s,t`` (default (1,0,0,0)) -- standard parameters of an isomorphism between Weierstrass models.4243EXAMPLES::4445sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *46sage: baseWI()47(1, 0, 0, 0)48sage: baseWI(2,3,4,5)49(2, 3, 4, 5)50sage: R.<u,r,s,t>=QQ[]; baseWI(u,r,s,t)51(u, r, s, t)52"""5354def __init__(self, u=1, r=0, s=0, t=0):55r"""56Constructor: check for valid parameters (defaults to identity)5758INPUT:5960- ``u,r,s,t`` (default (1,0,0,0)) -- standard parameters of an isomorphism between Weierstrass models.6162EXAMPLES::6364sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *65sage: baseWI()66(1, 0, 0, 0)67sage: baseWI(2,3,4,5)68(2, 3, 4, 5)69sage: R.<u,r,s,t>=QQ[]; baseWI(u,r,s,t)70(u, r, s, t)71"""72if u==0:73raise ValueError, "u!=0 required for baseWI"74self.u=u; self.r=r; self.s=s; self.t=t7576def __cmp__(self, other):77"""78Standard comparison function.7980The ordering is just lexicographic on the tuple `(u,r,s,t)`.8182.. note::8384In a list of automorphisms, there is no guarantee that the85identity will be first!8687EXAMPLE::8889sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *90sage: baseWI(1,2,3,4)==baseWI(1,2,3,4)91True92sage: baseWI(1,2,3,4)<baseWI(1,2,3,5)93True94sage: baseWI(1,2,3,4)>baseWI(1,2,3,4)95False9697::9899It will never return equality if other is of another type:100sage: baseWI() == 1101False102103"""104if not isinstance(other, baseWI):105return cmp(type(self), type(other))106return cmp(self.tuple(), other.tuple())107108def tuple(self):109r"""110Returns the parameters `u,r,s,t` as a tuple.111112EXAMPLES::113114sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *115sage: u,r,s,t=baseWI(2,3,4,5).tuple()116sage: w=baseWI(2,3,4,5)117sage: u,r,s,t=w.tuple()118sage: u1192120"""121return (self.u,self.r,self.s,self.t)122123def __mul__(self, other):124r"""125Returns the Composition of this isomorphism and another.126127EXAMPLES::128129sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *130sage: baseWI(1,2,3,4)*baseWI(5,6,7,8)131(5, 56, 22, 858)132sage: baseWI()*baseWI(1,2,3,4)*baseWI()133(1, 2, 3, 4)134"""135u1,r1,s1,t1=other.tuple()136u2,r2,s2,t2=self.tuple()137return baseWI(u1*u2,(u1**2)*r2+r1,u1*s2+s1,(u1**3)*t2+s1*(u1**2)*r2+t1)138139def __invert__(self):140r"""141Returns the inverse of this isomorphism.142143EXAMPLES::144145sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *146sage: w=baseWI(2,3,4,5)147sage: ~w148(1/2, -3/4, -2, 7/8)149sage: w*~w150(1, 0, 0, 0)151sage: ~w*w152(1, 0, 0, 0)153sage: R.<u,r,s,t>=QQ[]; w=baseWI(u,r,s,t)154sage: ~w155(1/u, (-r)/u^2, (-s)/u, (r*s - t)/u^3)156sage: ~w*w157(1, 0, 0, 0)158"""159u,r,s,t=self.tuple()160return baseWI(1/u,-r/(u**2),-s/u,(r*s-t)/(u**3))161162def __repr__(self):163r"""164Returns the string representation of this isomorphism.165166EXAMPLES::167168sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *169sage: baseWI(2,3,4,5)170(2, 3, 4, 5)171"""172return self.tuple().__repr__()173174def is_identity(self):175r"""176Returns True if this is the identity isomorphism.177178EXAMPLES::179180sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *181sage: w=baseWI(); w.is_identity()182True183sage: w=baseWI(2,3,4,5); w.is_identity()184False185"""186return self.tuple()==(1,0,0,0)187188def __call__(self, EorP):189r"""190Base application of isomorphisms to curves and points: a191baseWI `w` may be applied to a list `[a1,a2,a3,a4,a6]`192representing the `a`-invariants of an elliptic curve `E`,193returning the `a`-invariants of `w(E)`; or to `P=[x,y]` or194`P=[x,y,z]` representing a point in `\mathbb{A}^2` or195`\mathbb{P}^2`, returning the transformed point.196197INPUT:198199- ``EorP`` -- either an elliptic curve, or a point on an elliptic curve.200201OUTPUT:202203The transformed curve or point.204205EXAMPLES::206207sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *208sage: E=EllipticCurve([0,0,1,-7,6])209sage: w=baseWI(2,3,4,5);210sage: w(E.ainvs())211[4, -7/4, 11/8, -3/2, -9/32]212sage: P=E(-2,3)213sage: w(P.xy())214[-5/4, 9/4]215sage: EllipticCurve(w(E.ainvs()))(w(P.xy()))216(-5/4 : 9/4 : 1)217"""218u,r,s,t=self.tuple()219if len(EorP)==5:220a1,a2,a3,a4,a6=EorP221a6 += r*(a4 + r*(a2 + r)) - t*(a3 + r*a1 + t);222a4 += -s*a3 + 2*r*a2 - (t + r*s)*a1 + 3*r*r - 2*s*t;223a3 += r*a1 +t+t;224a2 += -s*a1 + 3*r - s*s;225a1 += 2*s;226return [a1/u,a2/u**2,a3/u**3,a4/u**4,a6/u**6]227if len(EorP)==2:228x,y=EorP229x-=r230y-=(s*x+t)231return [x/u**2,y/u**3]232if len(EorP)==3:233x,y,z=EorP234x-=r*z235y-=(s*x+t*z)236return [x/u**2,y/u**3,z]237raise ValueError, "baseWI(a) only for a=(x,y), (x:y:z) or (a1,a2,a3,a4,a6)"238239def isomorphisms(E,F,JustOne=False):240r"""241Returns one or all isomorphisms between two elliptic curves.242243INPUT:244245- ``E``, ``F`` (EllipticCurve) -- Two elliptic curves.246247- ``JustOne`` (bool) If True, returns one isomorphism, or None if248the curves are not isomorphic. If False, returns a (possibly249empty) list of isomorphisms.250251OUTPUT:252253Either None, or a 4-tuple `(u,r,s,t)` representing an isomorphism,254or a list of these.255256.. note::257258This function is not intended for users, who should use the259interface provided by ``ell_generic``.260261EXAMPLES::262263sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *264sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a3'))265[(-1, 0, 0, -1), (1, 0, 0, 0)]266sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a3'),JustOne=True)267(1, 0, 0, 0)268sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a1'))269[]270sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a1'),JustOne=True)271"""272from ell_generic import is_EllipticCurve273if not is_EllipticCurve(E) or not is_EllipticCurve(F):274raise ValueError, "arguments are not elliptic curves"275K = E.base_ring()276# if not K == F.base_ring(): return []277j=E.j_invariant()278if j != F.j_invariant():279if JustOne: return None280return []281282from sage.rings.all import PolynomialRing283x=PolynomialRing(K,'x').gen()284285a1E, a2E, a3E, a4E, a6E = E.ainvs()286a1F, a2F, a3F, a4F, a6F = F.ainvs()287288char=K.characteristic()289290if char==2:291if j==0:292ulist=(x**3-(a3E/a3F)).roots(multiplicities=False)293ans=[]294for u in ulist:295slist=(x**4+a3E*x+(a2F**2+a4F)*u**4+a2E**2+a4E).roots(multiplicities=False)296for s in slist:297r=s**2+a2E+a2F*u**2298tlist= (x**2 + a3E*x + r**3 + a2E*r**2 + a4E*r + a6E + a6F*u**6).roots(multiplicities=False)299for t in tlist:300if JustOne: return (u,r,s,t)301ans.append((u,r,s,t))302if JustOne: return None303ans.sort()304return ans305else:306ans=[]307u=a1E/a1F308r=(a3E+a3F*u**3)/a1E309slist=[s[0] for s in (x**2+a1E*x+(r+a2E+a2F*u**2)).roots()]310for s in slist:311t = (a4E+a4F*u**4 + s*a3E + r*s*a1E + r**2)312if JustOne: return (u,r,s,t)313ans.append((u,r,s,t))314if JustOne: return None315ans.sort()316return ans317318b2E, b4E, b6E, b8E = E.b_invariants()319b2F, b4F, b6F, b8F = F.b_invariants()320321if char==3:322if j==0:323ulist=(x**4-(b4E/b4F)).roots(multiplicities=False)324ans=[]325for u in ulist:326s=a1E-a1F*u327t=a3E-a3F*u**3328rlist=(x**3-b4E*x+(b6E-b6F*u**6)).roots(multiplicities=False)329for r in rlist:330if JustOne: return (u,r,s,t+r*a1E)331ans.append((u,r,s,t+r*a1E))332if JustOne: return None333ans.sort()334return ans335else:336ulist=(x**2-(b2E/b2F)).roots(multiplicities=False)337ans=[]338for u in ulist:339r = (b4F*u**4 -b4E)/b2E340s = (a1E-a1F*u)341t = (a3E-a3F*u**3 + a1E*r)342if JustOne: return (u,r,s,t)343ans.append((u,r,s,t))344if JustOne: return None345ans.sort()346return ans347348# now char!=2,3:349c4E,c6E = E.c_invariants()350c4F,c6F = F.c_invariants()351352if j==0:353m,um = 6,c6E/c6F354elif j==1728:355m,um=4,c4E/c4F356else:357m,um=2,(c6E*c4F)/(c6F*c4E)358ulist=(x**m-um).roots(multiplicities=False)359ans=[]360for u in ulist:361s = (a1F*u - a1E)/2362r = (a2F*u**2 + a1E*s + s**2 - a2E)/3363t = (a3F*u**3 - a1E*r - a3E)/2364if JustOne: return (u,r,s,t)365ans.append((u,r,s,t))366if JustOne: return None367ans.sort()368return ans369370class WeierstrassIsomorphism(baseWI,Morphism):371r"""372Class representing a Weierstrass isomorphism between two elliptic curves.373"""374def __init__(self, E=None, urst=None, F=None):375r"""376Constructor for WeierstrassIsomorphism class,377378INPUT:379380- ``E`` -- an EllipticCurve, or None (see below).381382- ``urst`` -- a 4-tuple `(u,r,s,t)`, or None (see below).383384- ``F`` -- an EllipticCurve, or None (see below).385386Given two Elliptic Curves ``E`` and ``F`` (represented by387Weierstrass models as usual), and a transformation ``urst``388from ``E`` to ``F``, construct an isomorphism from ``E`` to389``F``. An exception is raised if ``urst(E)!=F``. At most one390of ``E``, ``F``, ``urst`` can be None. If ``F==None`` then391``F`` is constructed as ``urst(E)``. If ``E==None`` then392``E`` is constructed as ``urst^-1(F)``. If ``urst==None``393then an isomorphism from ``E`` to ``F`` is constructed if394possible, and an exception is raised if they are not395isomorphic. Otherwise ``urst`` can be a tuple of length 4 or396a object of type ``baseWI``.397398Users will not usually need to use this class directly, but instead use399methods such as ``isomorphism`` of elliptic curves.400401EXAMPLES::402403sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *404sage: WeierstrassIsomorphism(EllipticCurve([0,1,2,3,4]),(-1,2,3,4))405Generic morphism:406From: Abelian group of points on Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field407To: Abelian group of points on Elliptic Curve defined by y^2 - 6*x*y - 10*y = x^3 - 2*x^2 - 11*x - 2 over Rational Field408Via: (u,r,s,t) = (-1, 2, 3, 4)409sage: E=EllipticCurve([0,1,2,3,4])410sage: F=EllipticCurve(E.cremona_label())411sage: WeierstrassIsomorphism(E,None,F)412Generic morphism:413From: Abelian group of points on Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field414To: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 5 over Rational Field415Via: (u,r,s,t) = (1, 0, 0, -1)416sage: w=WeierstrassIsomorphism(None,(1,0,0,-1),F)417sage: w._domain_curve==E418True419"""420from ell_generic import is_EllipticCurve421422if E!=None:423if not is_EllipticCurve(E):424raise ValueError, "First argument must be an elliptic curve or None"425if F!=None:426if not is_EllipticCurve(F):427raise ValueError, "Third argument must be an elliptic curve or None"428if urst!=None:429if len(urst)!=4:430raise ValueError, "Second argument must be [u,r,s,t] or None"431if len([par for par in [E,urst,F] if par!=None])<2:432raise ValueError, "At most 1 argument can be None"433434if F==None: # easy case435baseWI.__init__(self,*urst)436F=EllipticCurve(baseWI.__call__(self,list(E.a_invariants())))437Morphism.__init__(self, Hom(E(0).parent(), F(0).parent()))438self._domain_curve = E439self._codomain_curve = F440return441442if E==None: # easy case in reverse443baseWI.__init__(self,*urst)444inv_urst=baseWI.__invert__(self)445E=EllipticCurve(baseWI.__call__(inv_urst,list(F.a_invariants())))446Morphism.__init__(self, Hom(E(0).parent(), F(0).parent()))447self._domain_curve = E448self._codomain_curve = F449return450451if urst==None: # try to construct the morphism452urst=isomorphisms(E,F,True)453if urst==None:454raise ValueError, "Elliptic curves not isomorphic."455baseWI.__init__(self, *urst)456Morphism.__init__(self, Hom(E(0).parent(), F(0).parent()))457self._domain_curve = E458self._codomain_curve = F459return460461462# none of the parameters is None:463baseWI.__init__(self,*urst)464if F!=EllipticCurve(baseWI.__call__(self,list(E.a_invariants()))):465raise ValueError, "second argument is not an isomorphism from first argument to third argument"466else:467Morphism.__init__(self, Hom(E(0).parent(), F(0).parent()))468self._domain_curve = E469self._codomain_curve = F470return471472def __cmp__(self, other):473r"""474Standard comparison function for the WeierstrassIsomorphism class.475476EXAMPLE::477478sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *479sage: E=EllipticCurve('389a1')480sage: F=E.change_weierstrass_model(1,2,3,4)481sage: w1=E.isomorphism_to(F)482sage: w1==w1483True484sage: w2 = F.automorphisms()[0] *w1485sage: w1==w2486False487488::489490sage: E=EllipticCurve_from_j(GF(7)(0))491sage: F=E.change_weierstrass_model(2,3,4,5)492sage: a=E.isomorphisms(F)493sage: b=[w*a[0] for w in F.automorphisms()]494sage: b.sort()495sage: a==b496True497sage: c=[a[0]*w for w in E.automorphisms()]498sage: c.sort()499sage: a==c500True501"""502if not isinstance(other, WeierstrassIsomorphism):503return cmp(type(self), type(other))504t = cmp(self._domain_curve, other._domain_curve)505if t: return t506t = cmp(self._codomain_curve, other._codomain_curve)507if t: return t508return baseWI.__cmp__(self,other)509510def __call__(self, P):511r"""512Call function for WeierstrassIsomorphism class.513514INPUT:515516- ``P`` (Point) -- a point on the domain curve.517518OUTPUT:519520(Point) the transformed point on the codomain curve.521522EXAMPLES::523524sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *525sage: E=EllipticCurve('37a1')526sage: w=WeierstrassIsomorphism(E,(2,3,4,5))527sage: P=E(0,-1)528sage: w(P)529(-3/4 : 3/4 : 1)530sage: w(P).curve()==E.change_weierstrass_model((2,3,4,5))531True532"""533if P[2] == 0:534return self._codomain_curve(0)535else:536return self._codomain_curve.point(baseWI.__call__(self,tuple(P._coords)), check=False)537538def __invert__(self):539r"""540Returns the inverse of this WeierstrassIsomorphism.541542EXAMPLES::543544sage: E = EllipticCurve('5077')545sage: F = E.change_weierstrass_model([2,3,4,5]); F546Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 7/4*x^2 - 3/2*x - 9/32 over Rational Field547sage: w = E.isomorphism_to(F)548sage: P = E(-2,3,1)549sage: w(P)550(-5/4 : 9/4 : 1)551sage: ~w552Generic morphism:553From: Abelian group of points on Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 7/4*x^2 - 3/2*x - 9/32 over Rational Field554To: Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field555Via: (u,r,s,t) = (1/2, -3/4, -2, 7/8)556sage: Q = w(P); Q557(-5/4 : 9/4 : 1)558sage: (~w)(Q)559(-2 : 3 : 1)560"""561winv=baseWI.__invert__(self).tuple()562return WeierstrassIsomorphism(self._codomain_curve, winv, self._domain_curve)563564def __mul__(self,other):565r"""566Returns the composition of this WeierstrassIsomorphism and the other,567568WeierstrassMorphisms can be composed using ``*`` if the569codomain & domain match: `(w1*w2)(X)=w1(w2(X))`, so we require570``w1.domain()==w2.codomain()``.571572EXAMPLES::573574sage: E1 = EllipticCurve('5077')575sage: E2 = E1.change_weierstrass_model([2,3,4,5])576sage: w1 = E1.isomorphism_to(E2)577sage: E3 = E2.change_weierstrass_model([6,7,8,9])578sage: w2 = E2.isomorphism_to(E3)579sage: P = E1(-2,3,1)580sage: (w2*w1)(P)==w2(w1(P))581True582"""583if self._domain_curve==other._codomain_curve:584w=baseWI.__mul__(self,other)585return WeierstrassIsomorphism(other._domain_curve, w.tuple(), self._codomain_curve)586else:587raise ValueError, "Domain of first argument must equal codomain of second"588589def __repr__(self):590r"""591Returns the string representation of this WeierstrassIsomorphism.592593OUTPUT:594595(string) The underlying morphism, together with an extra line596showing the `(u,r,s,t)` parameters.597598EXAMPLES::599600sage: E1 = EllipticCurve('5077')601sage: E2 = E1.change_weierstrass_model([2,3,4,5])602sage: E1.isomorphism_to(E2)603Generic morphism:604From: Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field605To: Abelian group of points on Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 7/4*x^2 - 3/2*x - 9/32 over Rational Field606Via: (u,r,s,t) = (2, 3, 4, 5)607"""608return Morphism.__repr__(self)+"\n Via: (u,r,s,t) = "+baseWI.__repr__(self)609610611612613