def __init__(self, E=None, urst=None, F=None): r""" Constructor for WeierstrassIsomorphism class, INPUT: - ``E`` -- an EllipticCurve, or None (see below). - ``urst`` -- a 4-tuple `(u,r,s,t)`, or None (see below). - ``F`` -- an EllipticCurve, or None (see below). Given two Elliptic Curves ``E`` and ``F`` (represented by Weierstrass models as usual), and a transformation ``urst`` from ``E`` to ``F``, construct an isomorphism from ``E`` to ``F``. An exception is raised if ``urst(E)!=F``. At most one of ``E``, ``F``, ``urst`` can be None. If ``F==None`` then ``F`` is constructed as ``urst(E)``. If ``E==None`` then ``E`` is constructed as ``urst^-1(F)``. If ``urst==None`` then an isomorphism from ``E`` to ``F`` is constructed if possible, and an exception is raised if they are not isomorphic. Otherwise ``urst`` can be a tuple of length 4 or a object of type ``baseWI``. Users will not usually need to use this class directly, but instead use methods such as ``isomorphism`` of elliptic curves. EXAMPLES:: sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * sage: WeierstrassIsomorphism(EllipticCurve([0,1,2,3,4]),(-1,2,3,4)) Generic morphism: From: Abelian group of points on Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field To: 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 Field Via: (u,r,s,t) = (-1, 2, 3, 4) sage: E=EllipticCurve([0,1,2,3,4]) sage: F=EllipticCurve(E.cremona_label()) sage: WeierstrassIsomorphism(E,None,F) Generic morphism: From: Abelian group of points on Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field To: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 5 over Rational Field Via: (u,r,s,t) = (1, 0, 0, -1) sage: w=WeierstrassIsomorphism(None,(1,0,0,-1),F) sage: w._domain_curve==E True """ from ell_generic import is_EllipticCurve if E != None: if not is_EllipticCurve(E): raise ValueError, "First argument must be an elliptic curve or None" if F != None: if not is_EllipticCurve(F): raise ValueError, "Third argument must be an elliptic curve or None" if urst != None: if len(urst) != 4: raise ValueError, "Second argument must be [u,r,s,t] or None" if len([par for par in [E, urst, F] if par != None]) < 2: raise ValueError, "At most 1 argument can be None" if F == None: # easy case baseWI.__init__(self, *urst) F = EllipticCurve(baseWI.__call__(self, list(E.a_invariants()))) Morphism.__init__(self, Hom(E(0).parent(), F(0).parent())) self._domain_curve = E self._codomain_curve = F return if E == None: # easy case in reverse baseWI.__init__(self, *urst) inv_urst = baseWI.__invert__(self) E = EllipticCurve(baseWI.__call__(inv_urst, list(F.a_invariants()))) Morphism.__init__(self, Hom(E(0).parent(), F(0).parent())) self._domain_curve = E self._codomain_curve = F return if urst == None: # try to construct the morphism urst = isomorphisms(E, F, True) if urst == None: raise ValueError, "Elliptic curves not isomorphic." baseWI.__init__(self, *urst) Morphism.__init__(self, Hom(E(0).parent(), F(0).parent())) self._domain_curve = E self._codomain_curve = F return # none of the parameters is None: baseWI.__init__(self, *urst) if F != EllipticCurve(baseWI.__call__(self, list(E.a_invariants()))): raise ValueError, "second argument is not an isomorphism from first argument to third argument" else: Morphism.__init__(self, Hom(E(0).parent(), F(0).parent())) self._domain_curve = E self._codomain_curve = F return
def __init__(self, E=None, urst=None, F=None): r""" Constructor for WeierstrassIsomorphism class, INPUT: - ``E`` -- an EllipticCurve, or None (see below). - ``urst`` -- a 4-tuple `(u,r,s,t)`, or None (see below). - ``F`` -- an EllipticCurve, or None (see below). Given two Elliptic Curves ``E`` and ``F`` (represented by Weierstrass models as usual), and a transformation ``urst`` from ``E`` to ``F``, construct an isomorphism from ``E`` to ``F``. An exception is raised if ``urst(E)!=F``. At most one of ``E``, ``F``, ``urst`` can be None. If ``F==None`` then ``F`` is constructed as ``urst(E)``. If ``E==None`` then ``E`` is constructed as ``urst^-1(F)``. If ``urst==None`` then an isomorphism from ``E`` to ``F`` is constructed if possible, and an exception is raised if they are not isomorphic. Otherwise ``urst`` can be a tuple of length 4 or a object of type ``baseWI``. Users will not usually need to use this class directly, but instead use methods such as ``isomorphism`` of elliptic curves. EXAMPLES:: sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * sage: WeierstrassIsomorphism(EllipticCurve([0,1,2,3,4]),(-1,2,3,4)) Generic morphism: From: Abelian group of points on Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field To: 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 Field Via: (u,r,s,t) = (-1, 2, 3, 4) sage: E=EllipticCurve([0,1,2,3,4]) sage: F=EllipticCurve(E.cremona_label()) sage: WeierstrassIsomorphism(E,None,F) Generic morphism: From: Abelian group of points on Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field To: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 5 over Rational Field Via: (u,r,s,t) = (1, 0, 0, -1) sage: w=WeierstrassIsomorphism(None,(1,0,0,-1),F) sage: w._domain_curve==E True """ from ell_generic import is_EllipticCurve if E!=None: if not is_EllipticCurve(E): raise ValueError("First argument must be an elliptic curve or None") if F!=None: if not is_EllipticCurve(F): raise ValueError("Third argument must be an elliptic curve or None") if urst!=None: if len(urst)!=4: raise ValueError("Second argument must be [u,r,s,t] or None") if len([par for par in [E,urst,F] if par!=None])<2: raise ValueError("At most 1 argument can be None") if F==None: # easy case baseWI.__init__(self,*urst) F=EllipticCurve(baseWI.__call__(self,list(E.a_invariants()))) Morphism.__init__(self, Hom(E(0).parent(), F(0).parent())) self._domain_curve = E self._codomain_curve = F return if E==None: # easy case in reverse baseWI.__init__(self,*urst) inv_urst=baseWI.__invert__(self) E=EllipticCurve(baseWI.__call__(inv_urst,list(F.a_invariants()))) Morphism.__init__(self, Hom(E(0).parent(), F(0).parent())) self._domain_curve = E self._codomain_curve = F return if urst==None: # try to construct the morphism urst=isomorphisms(E,F,True) if urst==None: raise ValueError("Elliptic curves not isomorphic.") baseWI.__init__(self, *urst) Morphism.__init__(self, Hom(E(0).parent(), F(0).parent())) self._domain_curve = E self._codomain_curve = F return # none of the parameters is None: baseWI.__init__(self,*urst) if F!=EllipticCurve(baseWI.__call__(self,list(E.a_invariants()))): raise ValueError("second argument is not an isomorphism from first argument to third argument") else: Morphism.__init__(self, Hom(E(0).parent(), F(0).parent())) self._domain_curve = E self._codomain_curve = F return
def isomorphisms(E, F, JustOne=False): r""" Returns one or all isomorphisms between two elliptic curves. INPUT: - ``E``, ``F`` (EllipticCurve) -- Two elliptic curves. - ``JustOne`` (bool) If True, returns one isomorphism, or None if the curves are not isomorphic. If False, returns a (possibly empty) list of isomorphisms. OUTPUT: Either None, or a 4-tuple `(u,r,s,t)` representing an isomorphism, or a list of these. .. note:: This function is not intended for users, who should use the interface provided by ``ell_generic``. EXAMPLES:: sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a3')) [(-1, 0, 0, -1), (1, 0, 0, 0)] sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a3'),JustOne=True) (1, 0, 0, 0) sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a1')) [] sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a1'),JustOne=True) """ from ell_generic import is_EllipticCurve if not is_EllipticCurve(E) or not is_EllipticCurve(F): raise ValueError, "arguments are not elliptic curves" K = E.base_ring() # if not K == F.base_ring(): return [] j = E.j_invariant() if j != F.j_invariant(): if JustOne: return None return [] from sage.rings.all import PolynomialRing x = PolynomialRing(K, 'x').gen() a1E, a2E, a3E, a4E, a6E = E.ainvs() a1F, a2F, a3F, a4F, a6F = F.ainvs() char = K.characteristic() if char == 2: if j == 0: ulist = (x**3 - (a3E / a3F)).roots(multiplicities=False) ans = [] for u in ulist: slist = (x**4 + a3E * x + (a2F**2 + a4F) * u**4 + a2E**2 + a4E).roots(multiplicities=False) for s in slist: r = s**2 + a2E + a2F * u**2 tlist = (x**2 + a3E * x + r**3 + a2E * r**2 + a4E * r + a6E + a6F * u**6).roots(multiplicities=False) for t in tlist: if JustOne: return (u, r, s, t) ans.append((u, r, s, t)) if JustOne: return None ans.sort() return ans else: ans = [] u = a1E / a1F r = (a3E + a3F * u**3) / a1E slist = [ s[0] for s in (x**2 + a1E * x + (r + a2E + a2F * u**2)).roots() ] for s in slist: t = (a4E + a4F * u**4 + s * a3E + r * s * a1E + r**2) if JustOne: return (u, r, s, t) ans.append((u, r, s, t)) if JustOne: return None ans.sort() return ans b2E, b4E, b6E, b8E = E.b_invariants() b2F, b4F, b6F, b8F = F.b_invariants() if char == 3: if j == 0: ulist = (x**4 - (b4E / b4F)).roots(multiplicities=False) ans = [] for u in ulist: s = a1E - a1F * u t = a3E - a3F * u**3 rlist = (x**3 - b4E * x + (b6E - b6F * u**6)).roots(multiplicities=False) for r in rlist: if JustOne: return (u, r, s, t + r * a1E) ans.append((u, r, s, t + r * a1E)) if JustOne: return None ans.sort() return ans else: ulist = (x**2 - (b2E / b2F)).roots(multiplicities=False) ans = [] for u in ulist: r = (b4F * u**4 - b4E) / b2E s = (a1E - a1F * u) t = (a3E - a3F * u**3 + a1E * r) if JustOne: return (u, r, s, t) ans.append((u, r, s, t)) if JustOne: return None ans.sort() return ans # now char!=2,3: c4E, c6E = E.c_invariants() c4F, c6F = F.c_invariants() if j == 0: m, um = 6, c6E / c6F elif j == 1728: m, um = 4, c4E / c4F else: m, um = 2, (c6E * c4F) / (c6F * c4E) ulist = (x**m - um).roots(multiplicities=False) ans = [] for u in ulist: s = (a1F * u - a1E) / 2 r = (a2F * u**2 + a1E * s + s**2 - a2E) / 3 t = (a3F * u**3 - a1E * r - a3E) / 2 if JustOne: return (u, r, s, t) ans.append((u, r, s, t)) if JustOne: return None ans.sort() return ans
def isomorphisms(E,F,JustOne=False): r""" Returns one or all isomorphisms between two elliptic curves. INPUT: - ``E``, ``F`` (EllipticCurve) -- Two elliptic curves. - ``JustOne`` (bool) If True, returns one isomorphism, or None if the curves are not isomorphic. If False, returns a (possibly empty) list of isomorphisms. OUTPUT: Either None, or a 4-tuple `(u,r,s,t)` representing an isomorphism, or a list of these. .. note:: This function is not intended for users, who should use the interface provided by ``ell_generic``. EXAMPLES:: sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a3')) [(-1, 0, 0, -1), (1, 0, 0, 0)] sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a3'),JustOne=True) (1, 0, 0, 0) sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a1')) [] sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a1'),JustOne=True) """ from ell_generic import is_EllipticCurve if not is_EllipticCurve(E) or not is_EllipticCurve(F): raise ValueError("arguments are not elliptic curves") K = E.base_ring() # if not K == F.base_ring(): return [] j=E.j_invariant() if j != F.j_invariant(): if JustOne: return None return [] from sage.rings.all import PolynomialRing x=PolynomialRing(K,'x').gen() a1E, a2E, a3E, a4E, a6E = E.ainvs() a1F, a2F, a3F, a4F, a6F = F.ainvs() char=K.characteristic() if char==2: if j==0: ulist=(x**3-(a3E/a3F)).roots(multiplicities=False) ans=[] for u in ulist: slist=(x**4+a3E*x+(a2F**2+a4F)*u**4+a2E**2+a4E).roots(multiplicities=False) for s in slist: r=s**2+a2E+a2F*u**2 tlist= (x**2 + a3E*x + r**3 + a2E*r**2 + a4E*r + a6E + a6F*u**6).roots(multiplicities=False) for t in tlist: if JustOne: return (u,r,s,t) ans.append((u,r,s,t)) if JustOne: return None ans.sort() return ans else: ans=[] u=a1E/a1F r=(a3E+a3F*u**3)/a1E slist=[s[0] for s in (x**2+a1E*x+(r+a2E+a2F*u**2)).roots()] for s in slist: t = (a4E+a4F*u**4 + s*a3E + r*s*a1E + r**2) if JustOne: return (u,r,s,t) ans.append((u,r,s,t)) if JustOne: return None ans.sort() return ans b2E, b4E, b6E, b8E = E.b_invariants() b2F, b4F, b6F, b8F = F.b_invariants() if char==3: if j==0: ulist=(x**4-(b4E/b4F)).roots(multiplicities=False) ans=[] for u in ulist: s=a1E-a1F*u t=a3E-a3F*u**3 rlist=(x**3-b4E*x+(b6E-b6F*u**6)).roots(multiplicities=False) for r in rlist: if JustOne: return (u,r,s,t+r*a1E) ans.append((u,r,s,t+r*a1E)) if JustOne: return None ans.sort() return ans else: ulist=(x**2-(b2E/b2F)).roots(multiplicities=False) ans=[] for u in ulist: r = (b4F*u**4 -b4E)/b2E s = (a1E-a1F*u) t = (a3E-a3F*u**3 + a1E*r) if JustOne: return (u,r,s,t) ans.append((u,r,s,t)) if JustOne: return None ans.sort() return ans # now char!=2,3: c4E,c6E = E.c_invariants() c4F,c6F = F.c_invariants() if j==0: m,um = 6,c6E/c6F elif j==1728: m,um=4,c4E/c4F else: m,um=2,(c6E*c4F)/(c6F*c4E) ulist=(x**m-um).roots(multiplicities=False) ans=[] for u in ulist: s = (a1F*u - a1E)/2 r = (a2F*u**2 + a1E*s + s**2 - a2E)/3 t = (a3F*u**3 - a1E*r - a3E)/2 if JustOne: return (u,r,s,t) ans.append((u,r,s,t)) if JustOne: return None ans.sort() return ans