Isomorphisms between Weierstrass models of elliptic curves¶
AUTHORS:
Robert Bradshaw (2007): initial version
John Cremona (Jan 2008): isomorphisms, automorphisms and twists in all characteristics
Lorenz Panny (2021):
EllipticCurveHom
interface
- class sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism(E=None, urst=None, F=None)[source]¶
Bases:
EllipticCurveHom
,baseWI
Class representing a Weierstrass isomorphism between two elliptic curves.
INPUT:
E
– anEllipticCurve
, orNone
(see below)urst
– a 4-tuple \((u,r,s,t)\), abaseWI
object, orNone
(see below)F
– anEllipticCurve
, orNone
(see below)
Given two Elliptic Curves
E
andF
(represented by Weierstrass models as usual), and a transformationurst
fromE
toF
, construct an isomorphism fromE
toF
. An exception is raised ifurst(E) != F
. At most one ofE
,F
,urst
can beNone
. In this case, the missing input is constructed from the others in such a way thaturst(E) == F
holds, and an exception is raised if this is impossible (typically becauseE
andF
are not isomorphic).Users will not usually need to use this class directly, but instead use methods such as
isomorphism_to()
orisomorphisms()
.Explicitly, the isomorphism defined by \((u,r,s,t)\) maps a point \((x,y)\) to the point
\[((x-r) / u^2, \; (y - s(x-r) - t) / u^3) .\]If the domain \(E\) has Weierstrass coefficients \([a_1,a_2,a_3,a_4,a_6]\), the codomain \(F\) is given by
\[\begin{split}a_1' &= (a_1 + 2s) / u \\ a_2' &= (a_2 - a_1s + 3r - s^2) / u^2 \\ a_3' &= (a_3 + a_1r + 2t) / u^3 \\ a_4' &= (a_4 + 2a_2r - a_1(rs+t) - a_3s + 3r^2 - 2st) / u^4 \\ a_6' &= (a_6 - a_1rt + a_2r^2 - a_3t + a_4r + r^3 - t^2) / u^6 .\end{split}\]EXAMPLES:
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * sage: WeierstrassIsomorphism(EllipticCurve([0,1,2,3,4]), (-1,2,3,4)) Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field To: 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) Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field To: 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 == E True
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.weierstrass_morphism import * >>> WeierstrassIsomorphism(EllipticCurve([Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)]), (-Integer(1),Integer(2),Integer(3),Integer(4))) Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field To: 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) >>> E = EllipticCurve([Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)]) >>> F = EllipticCurve(E.cremona_label()) >>> WeierstrassIsomorphism(E, None, F) Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field To: 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) >>> w = WeierstrassIsomorphism(None, (Integer(1),Integer(0),Integer(0),-Integer(1)), F) >>> w._domain == E True
from sage.schemes.elliptic_curves.weierstrass_morphism import * WeierstrassIsomorphism(EllipticCurve([0,1,2,3,4]), (-1,2,3,4)) E = EllipticCurve([0,1,2,3,4]) F = EllipticCurve(E.cremona_label()) WeierstrassIsomorphism(E, None, F) w = WeierstrassIsomorphism(None, (1,0,0,-1), F) w._domain == E
- dual()[source]¶
Return the dual isogeny of this isomorphism.
For isomorphisms, the dual is just the inverse.
EXAMPLES:
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: E = EllipticCurve(QuadraticField(-3), [0,1]) # needs sage.rings.number_field sage: w = WeierstrassIsomorphism(E, (CyclotomicField(3).gen(),0,0,0)) # needs sage.rings.number_field sage: (w.dual() * w).rational_maps() # needs sage.rings.number_field (x, y)
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism >>> E = EllipticCurve(QuadraticField(-Integer(3)), [Integer(0),Integer(1)]) # needs sage.rings.number_field >>> w = WeierstrassIsomorphism(E, (CyclotomicField(Integer(3)).gen(),Integer(0),Integer(0),Integer(0))) # needs sage.rings.number_field >>> (w.dual() * w).rational_maps() # needs sage.rings.number_field (x, y)
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism E = EllipticCurve(QuadraticField(-3), [0,1]) # needs sage.rings.number_field w = WeierstrassIsomorphism(E, (CyclotomicField(3).gen(),0,0,0)) # needs sage.rings.number_field (w.dual() * w).rational_maps() # needs sage.rings.number_field
sage: E1 = EllipticCurve([11,22,33,44,55]) sage: E2 = E1.short_weierstrass_model() sage: iso = E1.isomorphism_to(E2) sage: iso.dual() == ~iso True
>>> from sage.all import * >>> E1 = EllipticCurve([Integer(11),Integer(22),Integer(33),Integer(44),Integer(55)]) >>> E2 = E1.short_weierstrass_model() >>> iso = E1.isomorphism_to(E2) >>> iso.dual() == ~iso True
E1 = EllipticCurve([11,22,33,44,55]) E2 = E1.short_weierstrass_model() iso = E1.isomorphism_to(E2) iso.dual() == ~iso
- inseparable_degree()[source]¶
Return the inseparable degree of this Weierstrass isomorphism.
For isomorphisms, this method always returns one.
- is_identity()[source]¶
Check if this Weierstrass isomorphism is the identity.
EXAMPLES:
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: p = 97 sage: Fp = GF(p) sage: E = EllipticCurve(Fp, [1, 28]) sage: ws = WeierstrassIsomorphism(E, None, E) sage: ws.is_identity() False
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism >>> p = Integer(97) >>> Fp = GF(p) >>> E = EllipticCurve(Fp, [Integer(1), Integer(28)]) >>> ws = WeierstrassIsomorphism(E, None, E) >>> ws.is_identity() False
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism p = 97 Fp = GF(p) E = EllipticCurve(Fp, [1, 28]) ws = WeierstrassIsomorphism(E, None, E) ws.is_identity()
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: p = 97 sage: Fp = GF(p) sage: E = EllipticCurve(Fp, [1, 28]) sage: ws = WeierstrassIsomorphism(E, (1, 0, 0, 0), None) sage: ws.is_identity() True
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism >>> p = Integer(97) >>> Fp = GF(p) >>> E = EllipticCurve(Fp, [Integer(1), Integer(28)]) >>> ws = WeierstrassIsomorphism(E, (Integer(1), Integer(0), Integer(0), Integer(0)), None) >>> ws.is_identity() True
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism p = 97 Fp = GF(p) E = EllipticCurve(Fp, [1, 28]) ws = WeierstrassIsomorphism(E, (1, 0, 0, 0), None) ws.is_identity()
- kernel_polynomial()[source]¶
Return the kernel polynomial of this isomorphism.
Isomorphisms have trivial kernel by definition, hence this method always returns \(1\).
EXAMPLES:
sage: E1 = EllipticCurve([11,22,33,44,55]) sage: E2 = EllipticCurve_from_j(E1.j_invariant()) sage: iso = E1.isomorphism_to(E2) sage: iso.kernel_polynomial() 1 sage: psi = E1.isogeny(iso.kernel_polynomial(), codomain=E2); psi Isogeny of degree 1 from Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 over Rational Field sage: psi in {iso, -iso} True
>>> from sage.all import * >>> E1 = EllipticCurve([Integer(11),Integer(22),Integer(33),Integer(44),Integer(55)]) >>> E2 = EllipticCurve_from_j(E1.j_invariant()) >>> iso = E1.isomorphism_to(E2) >>> iso.kernel_polynomial() 1 >>> psi = E1.isogeny(iso.kernel_polynomial(), codomain=E2); psi Isogeny of degree 1 from Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 over Rational Field >>> psi in {iso, -iso} True
E1 = EllipticCurve([11,22,33,44,55]) E2 = EllipticCurve_from_j(E1.j_invariant()) iso = E1.isomorphism_to(E2) iso.kernel_polynomial() psi = E1.isogeny(iso.kernel_polynomial(), codomain=E2); psi psi in {iso, -iso}
- order()[source]¶
Compute the order of this Weierstrass isomorphism if it is an automorphism.
A
ValueError
is raised if the domain is not equal to the codomain.A
NotImplementedError
is raised if the order of the automorphism is not 1, 2, 3, 4 or 6.EXAMPLES:
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * sage: p = 97 sage: Fp = GF(p) sage: E = EllipticCurve(Fp, [1, 28]) sage: ws = WeierstrassIsomorphism(E, None, E) sage: ws.order() 2
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.weierstrass_morphism import * >>> p = Integer(97) >>> Fp = GF(p) >>> E = EllipticCurve(Fp, [Integer(1), Integer(28)]) >>> ws = WeierstrassIsomorphism(E, None, E) >>> ws.order() 2
from sage.schemes.elliptic_curves.weierstrass_morphism import * p = 97 Fp = GF(p) E = EllipticCurve(Fp, [1, 28]) ws = WeierstrassIsomorphism(E, None, E) ws.order()
- rational_maps()[source]¶
Return the pair of rational maps defining this isomorphism.
EXAMPLES:
sage: E1 = EllipticCurve([11,22,33,44,55]) sage: E2 = EllipticCurve_from_j(E1.j_invariant()) sage: iso = E1.isomorphism_to(E2); iso Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 over Rational Field To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 over Rational Field Via: (u,r,s,t) = (1, -17, -5, 77) sage: iso.rational_maps() (x + 17, 5*x + y + 8) sage: f = E2.defining_polynomial()(*iso.rational_maps(), 1) sage: I = E1.defining_ideal() sage: x,y,z = I.ring().gens() sage: f in I + Ideal(z-1) True
>>> from sage.all import * >>> E1 = EllipticCurve([Integer(11),Integer(22),Integer(33),Integer(44),Integer(55)]) >>> E2 = EllipticCurve_from_j(E1.j_invariant()) >>> iso = E1.isomorphism_to(E2); iso Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 over Rational Field To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 over Rational Field Via: (u,r,s,t) = (1, -17, -5, 77) >>> iso.rational_maps() (x + 17, 5*x + y + 8) >>> f = E2.defining_polynomial()(*iso.rational_maps(), Integer(1)) >>> I = E1.defining_ideal() >>> x,y,z = I.ring().gens() >>> f in I + Ideal(z-Integer(1)) True
E1 = EllipticCurve([11,22,33,44,55]) E2 = EllipticCurve_from_j(E1.j_invariant()) iso = E1.isomorphism_to(E2); iso iso.rational_maps() f = E2.defining_polynomial()(*iso.rational_maps(), 1) I = E1.defining_ideal() x,y,z = I.ring().gens() f in I + Ideal(z-1)
sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(65537), [1,1,1,1,1]) sage: w = E.isomorphism_to(E.short_weierstrass_model()) sage: f,g = w.rational_maps() sage: P = E.random_point() sage: w(P).xy() == (f(P.xy()), g(P.xy())) True
>>> from sage.all import * >>> # needs sage.rings.finite_rings >>> E = EllipticCurve(GF(Integer(65537)), [Integer(1),Integer(1),Integer(1),Integer(1),Integer(1)]) >>> w = E.isomorphism_to(E.short_weierstrass_model()) >>> f,g = w.rational_maps() >>> P = E.random_point() >>> w(P).xy() == (f(P.xy()), g(P.xy())) True
# needs sage.rings.finite_rings E = EllipticCurve(GF(65537), [1,1,1,1,1]) w = E.isomorphism_to(E.short_weierstrass_model()) f,g = w.rational_maps() P = E.random_point() w(P).xy() == (f(P.xy()), g(P.xy()))
- scaling_factor()[source]¶
Return the Weierstrass scaling factor associated to this Weierstrass isomorphism.
The scaling factor is the constant \(u\) (in the base field) such that \(\varphi^* \omega_2 = u \omega_1\), where \(\varphi: E_1\to E_2\) is this isomorphism and \(\omega_i\) are the standard Weierstrass differentials on \(E_i\) defined by \(\mathrm dx/(2y+a_1x+a_3)\).
EXAMPLES:
sage: E = EllipticCurve(QQbar, [0,1]) # needs sage.rings.number_field sage: all(f.scaling_factor() == f.formal()[1] for f in E.automorphisms()) # needs sage.rings.number_field True
>>> from sage.all import * >>> E = EllipticCurve(QQbar, [Integer(0),Integer(1)]) # needs sage.rings.number_field >>> all(f.scaling_factor() == f.formal()[Integer(1)] for f in E.automorphisms()) # needs sage.rings.number_field True
E = EllipticCurve(QQbar, [0,1]) # needs sage.rings.number_field all(f.scaling_factor() == f.formal()[1] for f in E.automorphisms()) # needs sage.rings.number_field
ALGORITHM: The scaling factor equals the \(u\) component of the tuple \((u,r,s,t)\) defining the isomorphism.
- x_rational_map()[source]¶
Return the \(x\)-coordinate rational map of this isomorphism.
EXAMPLES:
sage: E1 = EllipticCurve([11,22,33,44,55]) sage: E2 = EllipticCurve_from_j(E1.j_invariant()) sage: iso = E1.isomorphism_to(E2); iso Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 over Rational Field To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 over Rational Field Via: (u,r,s,t) = (1, -17, -5, 77) sage: iso.x_rational_map() x + 17 sage: iso.x_rational_map() == iso.rational_maps()[0] True
>>> from sage.all import * >>> E1 = EllipticCurve([Integer(11),Integer(22),Integer(33),Integer(44),Integer(55)]) >>> E2 = EllipticCurve_from_j(E1.j_invariant()) >>> iso = E1.isomorphism_to(E2); iso Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 over Rational Field To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 over Rational Field Via: (u,r,s,t) = (1, -17, -5, 77) >>> iso.x_rational_map() x + 17 >>> iso.x_rational_map() == iso.rational_maps()[Integer(0)] True
E1 = EllipticCurve([11,22,33,44,55]) E2 = EllipticCurve_from_j(E1.j_invariant()) iso = E1.isomorphism_to(E2); iso iso.x_rational_map() iso.x_rational_map() == iso.rational_maps()[0]
- class sage.schemes.elliptic_curves.weierstrass_morphism.baseWI(u=1, r=0, s=0, t=0)[source]¶
Bases:
object
This class implements the basic arithmetic of isomorphisms between Weierstrass models of elliptic curves.
These are specified by lists of the form \([u,r,s,t]\) (with \(u \neq 0\)) which specifies a transformation \((x,y) \mapsto (x',y')\) where
\((x,y) = (u^2x'+r , u^3y' + su^2x' + t).\)
INPUT:
u
,r
,s
,t
– (default: \(1\), \(0\), \(0\), \(0\)); standard parameters of an isomorphism between Weierstrass models
EXAMPLES:
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * sage: baseWI() (1, 0, 0, 0) sage: baseWI(2,3,4,5) (2, 3, 4, 5) sage: R.<u,r,s,t> = QQ[] sage: baseWI(u,r,s,t) (u, r, s, t)
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.weierstrass_morphism import * >>> baseWI() (1, 0, 0, 0) >>> baseWI(Integer(2),Integer(3),Integer(4),Integer(5)) (2, 3, 4, 5) >>> R = QQ['u, r, s, t']; (u, r, s, t,) = R._first_ngens(4) >>> baseWI(u,r,s,t) (u, r, s, t)
from sage.schemes.elliptic_curves.weierstrass_morphism import * baseWI() baseWI(2,3,4,5) R.<u,r,s,t> = QQ[] baseWI(u,r,s,t)
- is_identity()[source]¶
Return
True
if this is the identity isomorphism.EXAMPLES:
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * sage: w = baseWI(); w.is_identity() True sage: w = baseWI(2,3,4,5); w.is_identity() False
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.weierstrass_morphism import * >>> w = baseWI(); w.is_identity() True >>> w = baseWI(Integer(2),Integer(3),Integer(4),Integer(5)); w.is_identity() False
from sage.schemes.elliptic_curves.weierstrass_morphism import * w = baseWI(); w.is_identity() w = baseWI(2,3,4,5); w.is_identity()
- tuple()[source]¶
Return the parameters \(u,r,s,t\) as a tuple.
EXAMPLES:
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * sage: w = baseWI(2,3,4,5) sage: w.tuple() (2, 3, 4, 5)
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.weierstrass_morphism import * >>> w = baseWI(Integer(2),Integer(3),Integer(4),Integer(5)) >>> w.tuple() (2, 3, 4, 5)
from sage.schemes.elliptic_curves.weierstrass_morphism import * w = baseWI(2,3,4,5) w.tuple()
- sage.schemes.elliptic_curves.weierstrass_morphism.identity_morphism(E)[source]¶
Given an elliptic curve \(E\), return the identity morphism on \(E\) as a
WeierstrassIsomorphism
.EXAMPLES:
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import identity_morphism sage: E = EllipticCurve([5,6,7,8,9]) sage: id_ = identity_morphism(E) sage: id_.rational_maps() (x, y)
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.weierstrass_morphism import identity_morphism >>> E = EllipticCurve([Integer(5),Integer(6),Integer(7),Integer(8),Integer(9)]) >>> id_ = identity_morphism(E) >>> id_.rational_maps() (x, y)
from sage.schemes.elliptic_curves.weierstrass_morphism import identity_morphism E = EllipticCurve([5,6,7,8,9]) id_ = identity_morphism(E) id_.rational_maps()
- sage.schemes.elliptic_curves.weierstrass_morphism.negation_morphism(E)[source]¶
Given an elliptic curve \(E\), return the negation endomorphism \([-1]\) of \(E\) as a
WeierstrassIsomorphism
.EXAMPLES:
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import negation_morphism sage: E = EllipticCurve([5,6,7,8,9]) sage: neg = negation_morphism(E) sage: neg.rational_maps() (x, -5*x - y - 7)
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.weierstrass_morphism import negation_morphism >>> E = EllipticCurve([Integer(5),Integer(6),Integer(7),Integer(8),Integer(9)]) >>> neg = negation_morphism(E) >>> neg.rational_maps() (x, -5*x - y - 7)
from sage.schemes.elliptic_curves.weierstrass_morphism import negation_morphism E = EllipticCurve([5,6,7,8,9]) neg = negation_morphism(E) neg.rational_maps()