Elliptic curves over a general ring

Sage defines an elliptic curve over a ring \(R\) as a Weierstrass Model with five coefficients \([a_1,a_2,a_3,a_4,a_6]\) in \(R\) given by

\[y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6.\]

Note that the (usual) scheme-theoretic definition of an elliptic curve over \(R\) would require the discriminant to be a unit in \(R\); Sage only imposes that the discriminant is nonzero. Also note that in Magma, “Weierstrass Model” refers to a model with \(a_1=a_2=a_3=0\), which is called Short Weierstrass Model in Sage; these do not always exist in characteristics 2 and 3.

EXAMPLES:

We construct an elliptic curve over an elaborate base ring:

sage: p, a, b = 97, 1, 3
sage: R.<u> = GF(p)[]
sage: S.<v> = R[]
sage: T = S.fraction_field()
sage: E = EllipticCurve(T, [a, b]); E
Elliptic Curve defined by y^2  = x^3 + x + 3 over Fraction Field of Univariate
Polynomial Ring in v over Univariate Polynomial Ring in u over Finite Field of size 97
sage: latex(E)
y^2  = x^{3} + x + 3
>>> from sage.all import *
>>> p, a, b = Integer(97), Integer(1), Integer(3)
>>> R = GF(p)['u']; (u,) = R._first_ngens(1)
>>> S = R['v']; (v,) = S._first_ngens(1)
>>> T = S.fraction_field()
>>> E = EllipticCurve(T, [a, b]); E
Elliptic Curve defined by y^2  = x^3 + x + 3 over Fraction Field of Univariate
Polynomial Ring in v over Univariate Polynomial Ring in u over Finite Field of size 97
>>> latex(E)
y^2  = x^{3} + x + 3

AUTHORS:

  • William Stein (2005): Initial version

  • Robert Bradshaw et al….

  • John Cremona (2008-01): isomorphisms, automorphisms and twists in all characteristics

  • Julian Rueth (2014-04-11): improved caching

  • Lorenz Panny (2022-04-14): added .montgomery_model()

class sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic(K, ainvs, category=None)[source]

Bases: WithEqualityById, ProjectivePlaneCurve

Elliptic curve over a generic base ring.

EXAMPLES:

sage: E = EllipticCurve([1,2,3/4,7,19]); E
Elliptic Curve defined by y^2 + x*y + 3/4*y = x^3 + 2*x^2 + 7*x + 19 over Rational Field
sage: loads(E.dumps()) == E
True
sage: E = EllipticCurve([1,3])
sage: P = E([-1,1,1])
sage: -5*P
(179051/80089 : -91814227/22665187 : 1)
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3)/Integer(4),Integer(7),Integer(19)]); E
Elliptic Curve defined by y^2 + x*y + 3/4*y = x^3 + 2*x^2 + 7*x + 19 over Rational Field
>>> loads(E.dumps()) == E
True
>>> E = EllipticCurve([Integer(1),Integer(3)])
>>> P = E([-Integer(1),Integer(1),Integer(1)])
>>> -Integer(5)*P
(179051/80089 : -91814227/22665187 : 1)
a1()[source]

Return the \(a_1\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,6])
sage: E.a1()
1
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(6)])
>>> E.a1()
1
a2()[source]

Return the \(a_2\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,6])
sage: E.a2()
2
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(6)])
>>> E.a2()
2
a3()[source]

Return the \(a_3\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,6])
sage: E.a3()
3
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(6)])
>>> E.a3()
3
a4()[source]

Return the \(a_4\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,6])
sage: E.a4()
4
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(6)])
>>> E.a4()
4
a6()[source]

Return the \(a_6\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,6])
sage: E.a6()
6
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(6)])
>>> E.a6()
6
a_invariants()[source]

The \(a\)-invariants of this elliptic curve, as a tuple.

OUTPUT:

(tuple) - a 5-tuple of the \(a\)-invariants of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,5])
sage: E.a_invariants()
(1, 2, 3, 4, 5)

sage: E = EllipticCurve([0,1]); E
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
sage: E.a_invariants()
(0, 0, 0, 0, 1)

sage: E = EllipticCurve([GF(7)(3),5])
sage: E.a_invariants()
(0, 0, 0, 3, 5)
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E.a_invariants()
(1, 2, 3, 4, 5)

>>> E = EllipticCurve([Integer(0),Integer(1)]); E
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
>>> E.a_invariants()
(0, 0, 0, 0, 1)

>>> E = EllipticCurve([GF(Integer(7))(Integer(3)),Integer(5)])
>>> E.a_invariants()
(0, 0, 0, 3, 5)
ainvs()[source]

The \(a\)-invariants of this elliptic curve, as a tuple.

OUTPUT:

(tuple) - a 5-tuple of the \(a\)-invariants of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,5])
sage: E.a_invariants()
(1, 2, 3, 4, 5)

sage: E = EllipticCurve([0,1]); E
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
sage: E.a_invariants()
(0, 0, 0, 0, 1)

sage: E = EllipticCurve([GF(7)(3),5])
sage: E.a_invariants()
(0, 0, 0, 3, 5)
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E.a_invariants()
(1, 2, 3, 4, 5)

>>> E = EllipticCurve([Integer(0),Integer(1)]); E
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
>>> E.a_invariants()
(0, 0, 0, 0, 1)

>>> E = EllipticCurve([GF(Integer(7))(Integer(3)),Integer(5)])
>>> E.a_invariants()
(0, 0, 0, 3, 5)
automorphisms(field=None)[source]

Return the set of isomorphisms from self to itself (as a list).

The identity and negation morphisms are guaranteed to appear as the first and second entry of the returned list.

INPUT:

  • field – (default: None) a field into which the coefficients of the curve may be coerced (by default, uses the base field of the curve)

OUTPUT:

A list of WeierstrassIsomorphism objects consisting of all the isomorphisms from the curve self to itself defined over field.

EXAMPLES:

sage: E = EllipticCurve_from_j(QQ(0))  # a curve with j=0 over QQ
sage: E.automorphisms()
[Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Rational Field
   Via:  (u,r,s,t) = (1, 0, 0, 0),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Rational Field
   Via:  (u,r,s,t) = (-1, 0, 0, -1)]
>>> from sage.all import *
>>> E = EllipticCurve_from_j(QQ(Integer(0)))  # a curve with j=0 over QQ
>>> E.automorphisms()
[Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Rational Field
   Via:  (u,r,s,t) = (1, 0, 0, 0),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Rational Field
   Via:  (u,r,s,t) = (-1, 0, 0, -1)]

We can also find automorphisms defined over extension fields:

sage: x = polygen(ZZ, 'x')
sage: K.<a> = NumberField(x^2 + 3)  # adjoin roots of unity                 # needs sage.rings.number_field
sage: E.automorphisms(K)                                                    # needs sage.rings.number_field
[Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (1, 0, 0, 0),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (-1, 0, 0, -1),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (-1/2*a - 1/2, 0, 0, 0),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (1/2*a + 1/2, 0, 0, -1),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (1/2*a - 1/2, 0, 0, 0),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (-1/2*a + 1/2, 0, 0, -1)]
>>> from sage.all import *
>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(2) + Integer(3), names=('a',)); (a,) = K._first_ngens(1)# adjoin roots of unity                 # needs sage.rings.number_field
>>> E.automorphisms(K)                                                    # needs sage.rings.number_field
[Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (1, 0, 0, 0),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (-1, 0, 0, -1),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (-1/2*a - 1/2, 0, 0, 0),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (1/2*a + 1/2, 0, 0, -1),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (1/2*a - 1/2, 0, 0, 0),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Number Field in a with defining polynomial x^2 + 3
   Via:  (u,r,s,t) = (-1/2*a + 1/2, 0, 0, -1)]

sage: [len(EllipticCurve_from_j(GF(q,'a')(0)).automorphisms())              # needs sage.rings.finite_rings
....:  for q in [2,4,3,9,5,25,7,49]]
[2, 24, 2, 12, 2, 6, 6, 6]
>>> from sage.all import *
>>> [len(EllipticCurve_from_j(GF(q,'a')(Integer(0))).automorphisms())              # needs sage.rings.finite_rings
...  for q in [Integer(2),Integer(4),Integer(3),Integer(9),Integer(5),Integer(25),Integer(7),Integer(49)]]
[2, 24, 2, 12, 2, 6, 6, 6]
b2()[source]

Return the \(b_2\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,5])
sage: E.b2()
9
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E.b2()
9
b4()[source]

Return the \(b_4\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,5])
sage: E.b4()
11
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E.b4()
11
b6()[source]

Return the \(b_6\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,5])
sage: E.b6()
29
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E.b6()
29
b8()[source]

Return the \(b_8\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,5])
sage: E.b8()
35
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E.b8()
35
b_invariants()[source]

Return the \(b\)-invariants of this elliptic curve, as a tuple.

OUTPUT:

(tuple) - a 4-tuple of the \(b\)-invariants of this elliptic curve.

This method is cached.

EXAMPLES:

sage: E = EllipticCurve([0, -1, 1, -10, -20])
sage: E.b_invariants()
(-4, -20, -79, -21)

sage: E = EllipticCurve([-4,0])
sage: E.b_invariants()
(0, -8, 0, -16)

sage: E = EllipticCurve([1,2,3,4,5])
sage: E.b_invariants()
(9, 11, 29, 35)
sage: E.b2()
9
sage: E.b4()
11
sage: E.b6()
29
sage: E.b8()
35
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(10), -Integer(20)])
>>> E.b_invariants()
(-4, -20, -79, -21)

>>> E = EllipticCurve([-Integer(4),Integer(0)])
>>> E.b_invariants()
(0, -8, 0, -16)

>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E.b_invariants()
(9, 11, 29, 35)
>>> E.b2()
9
>>> E.b4()
11
>>> E.b6()
29
>>> E.b8()
35

ALGORITHM:

These are simple functions of the \(a\)-invariants.

AUTHORS:

  • William Stein (2005-04-25)

base_extend(R)[source]

Return the base extension of self to \(R\).

INPUT:

  • R – either a ring into which the \(a\)-invariants of self may be converted, or a morphism which may be applied to them.

OUTPUT:

An elliptic curve over the new ring whose \(a\)-invariants are the images of the \(a\)-invariants of self.

EXAMPLES:

sage: E = EllipticCurve(GF(5), [1,1]); E
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5
sage: E1 = E.base_extend(GF(125,'a')); E1                                   # needs sage.rings.finite_rings
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 5^3
>>> from sage.all import *
>>> E = EllipticCurve(GF(Integer(5)), [Integer(1),Integer(1)]); E
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5
>>> E1 = E.base_extend(GF(Integer(125),'a')); E1                                   # needs sage.rings.finite_rings
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 5^3
base_ring()[source]

Return the base ring of the elliptic curve.

EXAMPLES:

sage: E = EllipticCurve(GF(49, 'a'), [3,5])                                 # needs sage.rings.finite_rings
sage: E.base_ring()                                                         # needs sage.rings.finite_rings
Finite Field in a of size 7^2
>>> from sage.all import *
>>> E = EllipticCurve(GF(Integer(49), 'a'), [Integer(3),Integer(5)])                                 # needs sage.rings.finite_rings
>>> E.base_ring()                                                         # needs sage.rings.finite_rings
Finite Field in a of size 7^2

sage: E = EllipticCurve([1,1])
sage: E.base_ring()
Rational Field
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(1)])
>>> E.base_ring()
Rational Field

sage: E = EllipticCurve(ZZ, [3,5])
sage: E.base_ring()
Integer Ring
>>> from sage.all import *
>>> E = EllipticCurve(ZZ, [Integer(3),Integer(5)])
>>> E.base_ring()
Integer Ring
c4()[source]

Return the \(c_4\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([0, -1, 1, -10, -20])
sage: E.c4()
496
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(10), -Integer(20)])
>>> E.c4()
496
c6()[source]

Return the \(c_6\) invariant of this elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([0, -1, 1, -10, -20])
sage: E.c6()
20008
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(10), -Integer(20)])
>>> E.c6()
20008
c_invariants()[source]

Return the \(c\)-invariants of this elliptic curve, as a tuple.

This method is cached.

OUTPUT:

(tuple) - a 2-tuple of the \(c\)-invariants of the elliptic curve.

EXAMPLES:

sage: E = EllipticCurve([0, -1, 1, -10, -20])
sage: E.c_invariants()
(496, 20008)

sage: E = EllipticCurve([-4,0])
sage: E.c_invariants()
(192, 0)
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(10), -Integer(20)])
>>> E.c_invariants()
(496, 20008)

>>> E = EllipticCurve([-Integer(4),Integer(0)])
>>> E.c_invariants()
(192, 0)

ALGORITHM:

These are simple functions of the \(a\)-invariants.

AUTHORS:

  • William Stein (2005-04-25)

change_ring(R)[source]

Return the base change of self to \(R\).

This has the same effect as self.base_extend(R).

EXAMPLES:

sage: # needs sage.rings.finite_rings
sage: F2 = GF(5^2,'a'); a = F2.gen()
sage: F4 = GF(5^4,'b'); b = F4.gen()
sage: roots = a.charpoly().roots(ring=F4, multiplicities=False)
sage: h = F2.hom([roots[0]], F4)
sage: E = EllipticCurve(F2, [1,a]); E
Elliptic Curve defined by y^2 = x^3 + x + a
over Finite Field in a of size 5^2
sage: E.change_ring(h)
Elliptic Curve defined by y^2 = x^3 + x + (4*b^3+4*b^2+4*b+3)
over Finite Field in b of size 5^4
>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> F2 = GF(Integer(5)**Integer(2),'a'); a = F2.gen()
>>> F4 = GF(Integer(5)**Integer(4),'b'); b = F4.gen()
>>> roots = a.charpoly().roots(ring=F4, multiplicities=False)
>>> h = F2.hom([roots[Integer(0)]], F4)
>>> E = EllipticCurve(F2, [Integer(1),a]); E
Elliptic Curve defined by y^2 = x^3 + x + a
over Finite Field in a of size 5^2
>>> E.change_ring(h)
Elliptic Curve defined by y^2 = x^3 + x + (4*b^3+4*b^2+4*b+3)
over Finite Field in b of size 5^4
change_weierstrass_model(*urst)[source]

Return a new Weierstrass model of self under the standard transformation \((u,r,s,t)\).

\[(x,y) \mapsto (x',y') = (u^2x + r , u^3y + su^2x + t).\]

EXAMPLES:

sage: E = EllipticCurve('15a')
sage: F1 = E.change_weierstrass_model([1/2,0,0,0]); F1
Elliptic Curve defined by y^2 + 2*x*y + 8*y = x^3 + 4*x^2 - 160*x - 640
over Rational Field
sage: F2 = E.change_weierstrass_model([7,2,1/3,5]); F2
Elliptic Curve defined by
y^2 + 5/21*x*y + 13/343*y = x^3 + 59/441*x^2 - 10/7203*x - 58/117649
over Rational Field
sage: F1.is_isomorphic(F2)
True
>>> from sage.all import *
>>> E = EllipticCurve('15a')
>>> F1 = E.change_weierstrass_model([Integer(1)/Integer(2),Integer(0),Integer(0),Integer(0)]); F1
Elliptic Curve defined by y^2 + 2*x*y + 8*y = x^3 + 4*x^2 - 160*x - 640
over Rational Field
>>> F2 = E.change_weierstrass_model([Integer(7),Integer(2),Integer(1)/Integer(3),Integer(5)]); F2
Elliptic Curve defined by
y^2 + 5/21*x*y + 13/343*y = x^3 + 59/441*x^2 - 10/7203*x - 58/117649
over Rational Field
>>> F1.is_isomorphic(F2)
True
discriminant()[source]

Return the discriminant of this elliptic curve.

This method is cached.

EXAMPLES:

sage: E = EllipticCurve([0,0,1,-1,0])
sage: E.discriminant()
37

sage: E = EllipticCurve([0, -1, 1, -10, -20])
sage: E.discriminant()
-161051

sage: E = EllipticCurve([GF(7)(2),1])
sage: E.discriminant()
1
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(1),Integer(0)])
>>> E.discriminant()
37

>>> E = EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(10), -Integer(20)])
>>> E.discriminant()
-161051

>>> E = EllipticCurve([GF(Integer(7))(Integer(2)),Integer(1)])
>>> E.discriminant()
1
division_polynomial(m, x=None, two_torsion_multiplicity=2, force_evaluate=None)[source]

Return the \(m\)-th division polynomial of this elliptic curve evaluated at \(x\).

The division polynomial is cached if \(x\) is None.

INPUT:

  • m – positive integer

  • x – (optional) ring element to use as the \(x\) variable. If \(x\) is None (omitted), then a new polynomial ring will be constructed over the base ring of the elliptic curve, and its generator will be used as \(x\). Note that \(x\) does not need to be a generator of a polynomial ring; any ring element works. This permits fast calculation of the torsion polynomial evaluated on any element of a ring.

  • two_torsion_multiplicity – 0, 1, or 2

    If 0: For even \(m\) when \(x\) is None, a univariate polynomial over the base ring of the curve is returned, which omits factors whose roots are the \(x\)-coordinates of the \(2\)-torsion points. When \(x\) is not None, the evaluation of such a polynomial at \(x\) is returned.

    If 2: For even \(m\) when \(x\) is None, a univariate polynomial over the base ring of the curve is returned, which includes a factor of degree 3 whose roots are the \(x\)-coordinates of the \(2\)-torsion points. Similarly, when \(x\) is not None, the evaluation of such a polynomial at \(x\) is returned.

    If 1: For even \(m\) when \(x\) is None, a bivariate polynomial over the base ring of the curve is returned, which includes a factor \(2y+a_1x+a_3\) having simple zeros at the \(2\)-torsion points. When \(x\) is not None, it should be a tuple of length 2, and the evaluation of such a polynomial at \(x\) is returned.

  • force_evaluate – (optional) 0, 1, or 2

    By default, this method makes use of previously cached generic division polynomials to compute the value of the polynomial at a given element \(x\) whenever it appears beneficial to do so. Explicitly setting this flag overrides the default behavior.

    Note that the complexity of evaluating a generic division polynomial scales much worse than that of computing the value at a point directly (using the recursive formulas), hence setting this flag can be detrimental to performance.

    If 0: Do not use cached generic division polynomials.

    If 1: If the generic division polynomial for this \(m\) has been cached before, evaluate it at \(x\) to compute the result.

    If 2: Compute the value at \(x\) by evaluating the generic division polynomial. If the generic \(m\)-division polynomial has not yet been cached, compute and cache it first.

EXAMPLES:

sage: E = EllipticCurve([0,0,1,-1,0])
sage: E.division_polynomial(1)
1
sage: E.division_polynomial(2, two_torsion_multiplicity=0)
1
sage: E.division_polynomial(2, two_torsion_multiplicity=1)
2*y + 1
sage: E.division_polynomial(2, two_torsion_multiplicity=2)
4*x^3 - 4*x + 1
sage: E.division_polynomial(2)
4*x^3 - 4*x + 1
sage: [E.division_polynomial(3, two_torsion_multiplicity=i) for i in range(3)]
[3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1]
sage: [type(E.division_polynomial(3, two_torsion_multiplicity=i)) for i in range(3)]
[<... 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>,
 <... 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>,
 <... 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>]
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(1),Integer(0)])
>>> E.division_polynomial(Integer(1))
1
>>> E.division_polynomial(Integer(2), two_torsion_multiplicity=Integer(0))
1
>>> E.division_polynomial(Integer(2), two_torsion_multiplicity=Integer(1))
2*y + 1
>>> E.division_polynomial(Integer(2), two_torsion_multiplicity=Integer(2))
4*x^3 - 4*x + 1
>>> E.division_polynomial(Integer(2))
4*x^3 - 4*x + 1
>>> [E.division_polynomial(Integer(3), two_torsion_multiplicity=i) for i in range(Integer(3))]
[3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1]
>>> [type(E.division_polynomial(Integer(3), two_torsion_multiplicity=i)) for i in range(Integer(3))]
[<... 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>,
 <... 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>,
 <... 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>]

sage: E = EllipticCurve([0, -1, 1, -10, -20])
sage: R.<z> = PolynomialRing(QQ)
sage: E.division_polynomial(4, z, 0)
2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821
sage: E.division_polynomial(4, z)
8*z^9 - 24*z^8 - 464*z^7 - 2758*z^6 + 6636*z^5 + 34356*z^4
 + 53510*z^3 + 99714*z^2 + 351024*z + 459859
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(10), -Integer(20)])
>>> R = PolynomialRing(QQ, names=('z',)); (z,) = R._first_ngens(1)
>>> E.division_polynomial(Integer(4), z, Integer(0))
2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821
>>> E.division_polynomial(Integer(4), z)
8*z^9 - 24*z^8 - 464*z^7 - 2758*z^6 + 6636*z^5 + 34356*z^4
 + 53510*z^3 + 99714*z^2 + 351024*z + 459859

This does not work, since when two_torsion_multiplicity is 1, we compute a bivariate polynomial, and must evaluate at a tuple of length 2:

sage: E.division_polynomial(4,z,1)
Traceback (most recent call last):
...
ValueError: x should be a tuple of length 2 (or None)
when two_torsion_multiplicity is 1
sage: R.<z,w> = PolynomialRing(QQ, 2)
sage: E.division_polynomial(4, (z,w), 1).factor()
(2*w + 1) * (2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821)
>>> from sage.all import *
>>> E.division_polynomial(Integer(4),z,Integer(1))
Traceback (most recent call last):
...
ValueError: x should be a tuple of length 2 (or None)
when two_torsion_multiplicity is 1
>>> R = PolynomialRing(QQ, Integer(2), names=('z', 'w',)); (z, w,) = R._first_ngens(2)
>>> E.division_polynomial(Integer(4), (z,w), Integer(1)).factor()
(2*w + 1) * (2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821)

We can also evaluate this bivariate polynomial at a point:

sage: P = E(5,5)
sage: E.division_polynomial(4,P,two_torsion_multiplicity=1)
-1771561
>>> from sage.all import *
>>> P = E(Integer(5),Integer(5))
>>> E.division_polynomial(Integer(4),P,two_torsion_multiplicity=Integer(1))
-1771561
division_polynomial_0(n, x=None)[source]

Return the \(n\)-th torsion (division) polynomial, without the 2-torsion factor if \(n\) is even, as a polynomial in \(x\).

These are the polynomials \(g_n\) defined in [MT1991], but with the sign flipped for even \(n\), so that the leading coefficient is always positive.

Note

This function is intended for internal use; users should use division_polynomial().

See also

INPUT:

  • n – positive integer, or the special values -1 and -2 which mean \(B_6 = (2y + a_1 x + a_3)^2\) and \(B_6^2\) respectively (in the notation of [MT1991]), or a list of integers

  • x – a ring element to use as the “x” variable or None (default: None); if None, then a new polynomial ring will be constructed over the base ring of the elliptic curve, and its generator will be used as x. Note that x does not need to be a generator of a polynomial ring; any ring element is ok. This permits fast calculation of the torsion polynomial evaluated on any element of a ring.

ALGORITHM:

Recursion described in [MT1991]. The recursive formulae are evaluated \(O(\log^2 n)\) times.

AUTHORS:

  • David Harvey (2006-09-24): initial version

  • John Cremona (2008-08-26): unified division polynomial code

EXAMPLES:

sage: E = EllipticCurve("37a")
sage: E.division_polynomial_0(1)
1
sage: E.division_polynomial_0(2)
1
sage: E.division_polynomial_0(3)
3*x^4 - 6*x^2 + 3*x - 1
sage: E.division_polynomial_0(4)
2*x^6 - 10*x^4 + 10*x^3 - 10*x^2 + 2*x + 1
sage: E.division_polynomial_0(5)
5*x^12 - 62*x^10 + 95*x^9 - 105*x^8 - 60*x^7 + 285*x^6 - 174*x^5 - 5*x^4 - 5*x^3 + 35*x^2 - 15*x + 2
sage: E.division_polynomial_0(6)
3*x^16 - 72*x^14 + 168*x^13 - 364*x^12 + 1120*x^10 - 1144*x^9 + 300*x^8 - 540*x^7 + 1120*x^6 - 588*x^5 - 133*x^4 + 252*x^3 - 114*x^2 + 22*x - 1
sage: E.division_polynomial_0(7)
7*x^24 - 308*x^22 + 986*x^21 - 2954*x^20 + 28*x^19 + 17171*x^18 - 23142*x^17 + 511*x^16 - 5012*x^15 + 43804*x^14 - 7140*x^13 - 96950*x^12 + 111356*x^11 - 19516*x^10 - 49707*x^9 + 40054*x^8 - 124*x^7 - 18382*x^6 + 13342*x^5 - 4816*x^4 + 1099*x^3 - 210*x^2 + 35*x - 3
sage: E.division_polynomial_0(8)
4*x^30 - 292*x^28 + 1252*x^27 - 5436*x^26 + 2340*x^25 + 39834*x^24 - 79560*x^23 + 51432*x^22 - 142896*x^21 + 451596*x^20 - 212040*x^19 - 1005316*x^18 + 1726416*x^17 - 671160*x^16 - 954924*x^15 + 1119552*x^14 + 313308*x^13 - 1502818*x^12 + 1189908*x^11 - 160152*x^10 - 399176*x^9 + 386142*x^8 - 220128*x^7 + 99558*x^6 - 33528*x^5 + 6042*x^4 + 310*x^3 - 406*x^2 + 78*x - 5
>>> from sage.all import *
>>> E = EllipticCurve("37a")
>>> E.division_polynomial_0(Integer(1))
1
>>> E.division_polynomial_0(Integer(2))
1
>>> E.division_polynomial_0(Integer(3))
3*x^4 - 6*x^2 + 3*x - 1
>>> E.division_polynomial_0(Integer(4))
2*x^6 - 10*x^4 + 10*x^3 - 10*x^2 + 2*x + 1
>>> E.division_polynomial_0(Integer(5))
5*x^12 - 62*x^10 + 95*x^9 - 105*x^8 - 60*x^7 + 285*x^6 - 174*x^5 - 5*x^4 - 5*x^3 + 35*x^2 - 15*x + 2
>>> E.division_polynomial_0(Integer(6))
3*x^16 - 72*x^14 + 168*x^13 - 364*x^12 + 1120*x^10 - 1144*x^9 + 300*x^8 - 540*x^7 + 1120*x^6 - 588*x^5 - 133*x^4 + 252*x^3 - 114*x^2 + 22*x - 1
>>> E.division_polynomial_0(Integer(7))
7*x^24 - 308*x^22 + 986*x^21 - 2954*x^20 + 28*x^19 + 17171*x^18 - 23142*x^17 + 511*x^16 - 5012*x^15 + 43804*x^14 - 7140*x^13 - 96950*x^12 + 111356*x^11 - 19516*x^10 - 49707*x^9 + 40054*x^8 - 124*x^7 - 18382*x^6 + 13342*x^5 - 4816*x^4 + 1099*x^3 - 210*x^2 + 35*x - 3
>>> E.division_polynomial_0(Integer(8))
4*x^30 - 292*x^28 + 1252*x^27 - 5436*x^26 + 2340*x^25 + 39834*x^24 - 79560*x^23 + 51432*x^22 - 142896*x^21 + 451596*x^20 - 212040*x^19 - 1005316*x^18 + 1726416*x^17 - 671160*x^16 - 954924*x^15 + 1119552*x^14 + 313308*x^13 - 1502818*x^12 + 1189908*x^11 - 160152*x^10 - 399176*x^9 + 386142*x^8 - 220128*x^7 + 99558*x^6 - 33528*x^5 + 6042*x^4 + 310*x^3 - 406*x^2 + 78*x - 5

sage: E.division_polynomial_0(18) % E.division_polynomial_0(6) == 0
True
>>> from sage.all import *
>>> E.division_polynomial_0(Integer(18)) % E.division_polynomial_0(Integer(6)) == Integer(0)
True

An example to illustrate the relationship with torsion points:

sage: F = GF(11)
sage: E = EllipticCurve(F, [0, 2]); E
Elliptic Curve defined by y^2  = x^3 + 2 over Finite Field of size 11
sage: f = E.division_polynomial_0(5); f
5*x^12 + x^9 + 8*x^6 + 4*x^3 + 7
sage: f.factor()
(5) * (x^2 + 5) * (x^2 + 2*x + 5) * (x^2 + 5*x + 7)
 * (x^2 + 7*x + 7) * (x^2 + 9*x + 5) * (x^2 + 10*x + 7)
>>> from sage.all import *
>>> F = GF(Integer(11))
>>> E = EllipticCurve(F, [Integer(0), Integer(2)]); E
Elliptic Curve defined by y^2  = x^3 + 2 over Finite Field of size 11
>>> f = E.division_polynomial_0(Integer(5)); f
5*x^12 + x^9 + 8*x^6 + 4*x^3 + 7
>>> f.factor()
(5) * (x^2 + 5) * (x^2 + 2*x + 5) * (x^2 + 5*x + 7)
 * (x^2 + 7*x + 7) * (x^2 + 9*x + 5) * (x^2 + 10*x + 7)

This indicates that the \(x\)-coordinates of all the 5-torsion points of \(E\) are in \(\GF{11^2}\), and therefore the \(y\)-coordinates are in \(\GF{11^4}\):

sage: # needs sage.rings.finite_rings
sage: K = GF(11^4, 'a')
sage: X = E.change_ring(K)
sage: f = X.division_polynomial_0(5)
sage: x_coords = f.roots(multiplicities=False); x_coords
[10*a^3 + 4*a^2 + 5*a + 6,
 9*a^3 + 8*a^2 + 10*a + 8,
 8*a^3 + a^2 + 4*a + 10,
 8*a^3 + a^2 + 4*a + 8,
 8*a^3 + a^2 + 4*a + 4,
 6*a^3 + 9*a^2 + 3*a + 4,
 5*a^3 + 2*a^2 + 8*a + 7,
 3*a^3 + 10*a^2 + 7*a + 8,
 3*a^3 + 10*a^2 + 7*a + 3,
 3*a^3 + 10*a^2 + 7*a + 1,
 2*a^3 + 3*a^2 + a + 7,
 a^3 + 7*a^2 + 6*a]
>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> K = GF(Integer(11)**Integer(4), 'a')
>>> X = E.change_ring(K)
>>> f = X.division_polynomial_0(Integer(5))
>>> x_coords = f.roots(multiplicities=False); x_coords
[10*a^3 + 4*a^2 + 5*a + 6,
 9*a^3 + 8*a^2 + 10*a + 8,
 8*a^3 + a^2 + 4*a + 10,
 8*a^3 + a^2 + 4*a + 8,
 8*a^3 + a^2 + 4*a + 4,
 6*a^3 + 9*a^2 + 3*a + 4,
 5*a^3 + 2*a^2 + 8*a + 7,
 3*a^3 + 10*a^2 + 7*a + 8,
 3*a^3 + 10*a^2 + 7*a + 3,
 3*a^3 + 10*a^2 + 7*a + 1,
 2*a^3 + 3*a^2 + a + 7,
 a^3 + 7*a^2 + 6*a]

Now we check that these are exactly the \(x\)-coordinates of the 5-torsion points of \(E\):

sage: for x in x_coords:                                                    # needs sage.rings.finite_rings
....:     assert X.lift_x(x).order() == 5
>>> from sage.all import *
>>> for x in x_coords:                                                    # needs sage.rings.finite_rings
...     assert X.lift_x(x).order() == Integer(5)

The roots of the polynomial are the \(x\)-coordinates of the points \(P\) such that \(mP=0\) but \(2P\not=0\):

sage: E = EllipticCurve('14a1')
sage: T = E.torsion_subgroup()
sage: [n*T.0 for n in range(6)]
[(0 : 1 : 0),
(9 : 23 : 1),
(2 : 2 : 1),
(1 : -1 : 1),
(2 : -5 : 1),
(9 : -33 : 1)]
sage: pol = E.division_polynomial_0(6)
sage: xlist = pol.roots(multiplicities=False); xlist
[9, 2, -1/3, -5]
sage: [E.lift_x(x, all=True) for x in xlist]
[[(9 : -33 : 1), (9 : 23 : 1)], [(2 : -5 : 1), (2 : 2 : 1)], [], []]
>>> from sage.all import *
>>> E = EllipticCurve('14a1')
>>> T = E.torsion_subgroup()
>>> [n*T.gen(0) for n in range(Integer(6))]
[(0 : 1 : 0),
(9 : 23 : 1),
(2 : 2 : 1),
(1 : -1 : 1),
(2 : -5 : 1),
(9 : -33 : 1)]
>>> pol = E.division_polynomial_0(Integer(6))
>>> xlist = pol.roots(multiplicities=False); xlist
[9, 2, -1/3, -5]
>>> [E.lift_x(x, all=True) for x in xlist]
[[(9 : -33 : 1), (9 : 23 : 1)], [(2 : -5 : 1), (2 : 2 : 1)], [], []]

Note

The point of order 2 and the identity do not appear. The points with \(x=-1/3\) and \(x=-5\) are not rational.

formal()[source]

Return the formal group associated to this elliptic curve.

This method is cached.

EXAMPLES:

sage: E = EllipticCurve("37a")
sage: E.formal_group()
Formal Group associated to the Elliptic Curve
defined by y^2 + y = x^3 - x over Rational Field
>>> from sage.all import *
>>> E = EllipticCurve("37a")
>>> E.formal_group()
Formal Group associated to the Elliptic Curve
defined by y^2 + y = x^3 - x over Rational Field
formal_group()[source]

Return the formal group associated to this elliptic curve.

This method is cached.

EXAMPLES:

sage: E = EllipticCurve("37a")
sage: E.formal_group()
Formal Group associated to the Elliptic Curve
defined by y^2 + y = x^3 - x over Rational Field
>>> from sage.all import *
>>> E = EllipticCurve("37a")
>>> E.formal_group()
Formal Group associated to the Elliptic Curve
defined by y^2 + y = x^3 - x over Rational Field
frobenius_isogeny(n=1)[source]

Return the \(n\)-power Frobenius isogeny from this curve to its Galois conjugate.

The Frobenius endomorphism is the special case where \(n\) is divisible by the degree of the base ring of the curve.

EXAMPLES:

sage: # needs sage.rings.finite_rings
sage: z3, = GF(13^3).gens()
sage: E = EllipticCurve([z3, z3^2])
sage: E.frobenius_isogeny()
Frobenius isogeny of degree 13:
  From: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2
         over Finite Field in z3 of size 13^3
  To:   Elliptic Curve defined by y^2 = x^3 + (5*z3^2+7*z3+11)*x + (5*z3^2+12*z3+1)
         over Finite Field in z3 of size 13^3
sage: E.frobenius_isogeny(3)
Frobenius endomorphism of degree 2197 = 13^3:
  From: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2
         over Finite Field in z3 of size 13^3
  To:   Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2
         over Finite Field in z3 of size 13^3
>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> z3, = GF(Integer(13)**Integer(3)).gens()
>>> E = EllipticCurve([z3, z3**Integer(2)])
>>> E.frobenius_isogeny()
Frobenius isogeny of degree 13:
  From: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2
         over Finite Field in z3 of size 13^3
  To:   Elliptic Curve defined by y^2 = x^3 + (5*z3^2+7*z3+11)*x + (5*z3^2+12*z3+1)
         over Finite Field in z3 of size 13^3
>>> E.frobenius_isogeny(Integer(3))
Frobenius endomorphism of degree 2197 = 13^3:
  From: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2
         over Finite Field in z3 of size 13^3
  To:   Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2
         over Finite Field in z3 of size 13^3
gen(i)[source]

Function returning the i’th generator of this elliptic curve.

Note

Relies on gens() being implemented.

EXAMPLES:

sage: R.<a1,a2,a3,a4,a6> = QQ[]
sage: E = EllipticCurve([a1,a2,a3,a4,a6])
sage: E.gen(0)
Traceback (most recent call last):
...
NotImplementedError: not implemented.
>>> from sage.all import *
>>> R = QQ['a1, a2, a3, a4, a6']; (a1, a2, a3, a4, a6,) = R._first_ngens(5)
>>> E = EllipticCurve([a1,a2,a3,a4,a6])
>>> E.gen(Integer(0))
Traceback (most recent call last):
...
NotImplementedError: not implemented.
gens()[source]

Placeholder function to return generators of an elliptic curve.

Note

This functionality is implemented in certain derived classes, such as EllipticCurve_rational_field.

EXAMPLES:

sage: R.<a1,a2,a3,a4,a6> = QQ[]
sage: E = EllipticCurve([a1,a2,a3,a4,a6])
sage: E.gens()
Traceback (most recent call last):
...
NotImplementedError: not implemented.
sage: E = EllipticCurve(QQ, [1,1])
sage: E.gens()
[(0 : 1 : 1)]
>>> from sage.all import *
>>> R = QQ['a1, a2, a3, a4, a6']; (a1, a2, a3, a4, a6,) = R._first_ngens(5)
>>> E = EllipticCurve([a1,a2,a3,a4,a6])
>>> E.gens()
Traceback (most recent call last):
...
NotImplementedError: not implemented.
>>> E = EllipticCurve(QQ, [Integer(1),Integer(1)])
>>> E.gens()
[(0 : 1 : 1)]
hyperelliptic_polynomials()[source]

Return a pair of polynomials \(g(x)\), \(h(x)\) such that this elliptic curve can be defined by the standard hyperelliptic equation

\[y^2 + h(x)y = g(x).\]

EXAMPLES:

sage: R.<a1,a2,a3,a4,a6>=QQ[]
sage: E = EllipticCurve([a1,a2,a3,a4,a6])
sage: E.hyperelliptic_polynomials()
(x^3 + a2*x^2 + a4*x + a6, a1*x + a3)
>>> from sage.all import *
>>> R = QQ['a1, a2, a3, a4, a6']; (a1, a2, a3, a4, a6,) = R._first_ngens(5)
>>> E = EllipticCurve([a1,a2,a3,a4,a6])
>>> E.hyperelliptic_polynomials()
(x^3 + a2*x^2 + a4*x + a6, a1*x + a3)
identity_morphism()[source]

Return the identity endomorphism of this elliptic curve as an EllipticCurveHom object.

EXAMPLES:

sage: E = EllipticCurve(j=42)
sage: E.identity_morphism()
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + 5901*x + 1105454 over Rational Field
  Via:  (u,r,s,t) = (1, 0, 0, 0)
sage: E.identity_morphism() == E.scalar_multiplication(1)
True
>>> from sage.all import *
>>> E = EllipticCurve(j=Integer(42))
>>> E.identity_morphism()
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + 5901*x + 1105454 over Rational Field
  Via:  (u,r,s,t) = (1, 0, 0, 0)
>>> E.identity_morphism() == E.scalar_multiplication(Integer(1))
True
is_isomorphic(other, field=None)[source]

Return whether or not self is isomorphic to other.

INPUT:

  • other – another elliptic curve

  • field – (default: None) a field into which the coefficients of the curves may be coerced (by default, uses the base field of the curves).

OUTPUT:

boolean; True if there is an isomorphism from curve self to curve other defined over field.

EXAMPLES:

sage: E = EllipticCurve('389a')
sage: F = E.change_weierstrass_model([2,3,4,5]); F
Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 3/2*x^2 - 13/16*x
over Rational Field
sage: E.is_isomorphic(F)
True
sage: E.is_isomorphic(F.change_ring(CC))
False
>>> from sage.all import *
>>> E = EllipticCurve('389a')
>>> F = E.change_weierstrass_model([Integer(2),Integer(3),Integer(4),Integer(5)]); F
Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 3/2*x^2 - 13/16*x
over Rational Field
>>> E.is_isomorphic(F)
True
>>> E.is_isomorphic(F.change_ring(CC))
False
is_on_curve(x, y)[source]

Return True if \((x,y)\) is an affine point on this curve.

INPUT:

  • x, y – elements of the base ring of the curve

EXAMPLES:

sage: E = EllipticCurve(QQ,[1,1])
sage: E.is_on_curve(0,1)
True
sage: E.is_on_curve(1,1)
False
>>> from sage.all import *
>>> E = EllipticCurve(QQ,[Integer(1),Integer(1)])
>>> E.is_on_curve(Integer(0),Integer(1))
True
>>> E.is_on_curve(Integer(1),Integer(1))
False
is_x_coord(x)[source]

Return True if x is the \(x\)-coordinate of a point on this curve.

Note

See also lift_x() to find the point(s) with a given \(x\)-coordinate. This function may be useful in cases where testing an element of the base field for being a square is faster than finding its square root.

EXAMPLES:

sage: E = EllipticCurve('37a'); E
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
sage: E.is_x_coord(1)
True
sage: E.is_x_coord(2)
True
>>> from sage.all import *
>>> E = EllipticCurve('37a'); E
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
>>> E.is_x_coord(Integer(1))
True
>>> E.is_x_coord(Integer(2))
True

There are no rational points with x-coordinate 3:

sage: E.is_x_coord(3)
False
>>> from sage.all import *
>>> E.is_x_coord(Integer(3))
False

However, there are such points in \(E(\RR)\):

sage: E.change_ring(RR).is_x_coord(3)
True
>>> from sage.all import *
>>> E.change_ring(RR).is_x_coord(Integer(3))
True

And of course it always works in \(E(\CC)\):

sage: E.change_ring(RR).is_x_coord(-3)
False
sage: E.change_ring(CC).is_x_coord(-3)
True
>>> from sage.all import *
>>> E.change_ring(RR).is_x_coord(-Integer(3))
False
>>> E.change_ring(CC).is_x_coord(-Integer(3))
True

AUTHORS:

  • John Cremona (2008-08-07): adapted from lift_x()

isomorphism(u, r, s=0, t=0, is_codomain=0)[source]

Given four values \(u,r,s,t\) in the base ring of this curve, return the WeierstrassIsomorphism defined by \(u,r,s,t\) with this curve as its codomain. (The value \(u\) must be a unit; the values \(r,s,t\) default to zero.)

Optionally, if the keyword argument is_codomain is set to True, return the isomorphism defined by \(u,r,s,t\) with this curve as its codomain.

EXAMPLES:

sage: E = EllipticCurve([1, 2, 3, 4, 5])
sage: iso = E.isomorphism(6); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  To:   Elliptic Curve defined by y^2 + 1/6*x*y + 1/72*y = x^3 + 1/18*x^2 + 1/324*x + 5/46656 over Rational Field
  Via:  (u,r,s,t) = (6, 0, 0, 0)
sage: iso.domain() == E
True
sage: iso.codomain() == E.scale_curve(1 / 6)
True

sage: iso = E.isomorphism(1, 7, 8, 9); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  To:   Elliptic Curve defined by y^2 + 17*x*y + 28*y = x^3 - 49*x^2 - 54*x + 303 over Rational Field
  Via:  (u,r,s,t) = (1, 7, 8, 9)
sage: iso.domain() == E
True
sage: iso.codomain() == E.rst_transform(7, 8, 9)
True

sage: iso = E.isomorphism(6, 7, 8, 9); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  To:   Elliptic Curve defined by y^2 + 17/6*x*y + 7/54*y = x^3 - 49/36*x^2 - 1/24*x + 101/15552 over Rational Field
  Via:  (u,r,s,t) = (6, 7, 8, 9)
sage: iso.domain() == E
True
sage: iso.codomain() == E.rst_transform(7, 8, 9).scale_curve(1 / 6)
True
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1), Integer(2), Integer(3), Integer(4), Integer(5)])
>>> iso = E.isomorphism(Integer(6)); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  To:   Elliptic Curve defined by y^2 + 1/6*x*y + 1/72*y = x^3 + 1/18*x^2 + 1/324*x + 5/46656 over Rational Field
  Via:  (u,r,s,t) = (6, 0, 0, 0)
>>> iso.domain() == E
True
>>> iso.codomain() == E.scale_curve(Integer(1) / Integer(6))
True

>>> iso = E.isomorphism(Integer(1), Integer(7), Integer(8), Integer(9)); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  To:   Elliptic Curve defined by y^2 + 17*x*y + 28*y = x^3 - 49*x^2 - 54*x + 303 over Rational Field
  Via:  (u,r,s,t) = (1, 7, 8, 9)
>>> iso.domain() == E
True
>>> iso.codomain() == E.rst_transform(Integer(7), Integer(8), Integer(9))
True

>>> iso = E.isomorphism(Integer(6), Integer(7), Integer(8), Integer(9)); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  To:   Elliptic Curve defined by y^2 + 17/6*x*y + 7/54*y = x^3 - 49/36*x^2 - 1/24*x + 101/15552 over Rational Field
  Via:  (u,r,s,t) = (6, 7, 8, 9)
>>> iso.domain() == E
True
>>> iso.codomain() == E.rst_transform(Integer(7), Integer(8), Integer(9)).scale_curve(Integer(1) / Integer(6))
True

The is_codomain argument reverses the role of domain and codomain:

sage: E = EllipticCurve([1, 2, 3, 4, 5])
sage: iso = E.isomorphism(6, is_codomain=True); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + 6*x*y + 648*y = x^3 + 72*x^2 + 5184*x + 233280 over Rational Field
  To:   Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  Via:  (u,r,s,t) = (6, 0, 0, 0)
sage: iso.domain() == E.scale_curve(6)
True
sage: iso.codomain() == E
True

sage: iso = E.isomorphism(1, 7, 8, 9, is_codomain=True); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 - 15*x*y + 90*y = x^3 - 75*x^2 + 796*x - 2289 over Rational Field
  To:   Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  Via:  (u,r,s,t) = (1, 7, 8, 9)
sage: iso.domain().rst_transform(7, 8, 9) == E
True
sage: iso.codomain() == E
True

sage: iso = E.isomorphism(6, 7, 8, 9, is_codomain=True); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 - 10*x*y + 700*y = x^3 + 35*x^2 + 9641*x + 169486 over Rational Field
  To:   Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  Via:  (u,r,s,t) = (6, 7, 8, 9)
sage: iso.domain().rst_transform(7, 8, 9) == E.scale_curve(6)
True
sage: iso.codomain() == E
True
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1), Integer(2), Integer(3), Integer(4), Integer(5)])
>>> iso = E.isomorphism(Integer(6), is_codomain=True); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + 6*x*y + 648*y = x^3 + 72*x^2 + 5184*x + 233280 over Rational Field
  To:   Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  Via:  (u,r,s,t) = (6, 0, 0, 0)
>>> iso.domain() == E.scale_curve(Integer(6))
True
>>> iso.codomain() == E
True

>>> iso = E.isomorphism(Integer(1), Integer(7), Integer(8), Integer(9), is_codomain=True); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 - 15*x*y + 90*y = x^3 - 75*x^2 + 796*x - 2289 over Rational Field
  To:   Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  Via:  (u,r,s,t) = (1, 7, 8, 9)
>>> iso.domain().rst_transform(Integer(7), Integer(8), Integer(9)) == E
True
>>> iso.codomain() == E
True

>>> iso = E.isomorphism(Integer(6), Integer(7), Integer(8), Integer(9), is_codomain=True); iso
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 - 10*x*y + 700*y = x^3 + 35*x^2 + 9641*x + 169486 over Rational Field
  To:   Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
  Via:  (u,r,s,t) = (6, 7, 8, 9)
>>> iso.domain().rst_transform(Integer(7), Integer(8), Integer(9)) == E.scale_curve(Integer(6))
True
>>> iso.codomain() == E
True
isomorphism_to(other)[source]

Given another weierstrass model other of self, return an isomorphism from self to other.

INPUT:

  • other – an elliptic curve isomorphic to self

OUTPUT:

(Weierstrassmorphism) An isomorphism from self to other.

Note

If the curves in question are not isomorphic, a ValueError is raised.

EXAMPLES:

sage: E = EllipticCurve('37a')
sage: F = E.short_weierstrass_model()
sage: w = E.isomorphism_to(F); w
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
  To:   Elliptic Curve defined by y^2  = x^3 - 16*x + 16 over Rational Field
  Via:  (u,r,s,t) = (1/2, 0, 0, -1/2)
sage: P = E(0,-1,1)
sage: w(P)
(0 : -4 : 1)
sage: w(5*P)
(1 : 1 : 1)
sage: 5*w(P)
(1 : 1 : 1)
sage: 120*w(P) == w(120*P)
True
>>> from sage.all import *
>>> E = EllipticCurve('37a')
>>> F = E.short_weierstrass_model()
>>> w = E.isomorphism_to(F); w
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
  To:   Elliptic Curve defined by y^2  = x^3 - 16*x + 16 over Rational Field
  Via:  (u,r,s,t) = (1/2, 0, 0, -1/2)
>>> P = E(Integer(0),-Integer(1),Integer(1))
>>> w(P)
(0 : -4 : 1)
>>> w(Integer(5)*P)
(1 : 1 : 1)
>>> Integer(5)*w(P)
(1 : 1 : 1)
>>> Integer(120)*w(P) == w(Integer(120)*P)
True

We can also handle injections to different base rings:

sage: x = polygen(ZZ, 'x')
sage: K.<a> = NumberField(x^3 - 7)                                          # needs sage.rings.number_field
sage: E.isomorphism_to(E.change_ring(K))                                    # needs sage.rings.number_field
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
  To:   Elliptic Curve defined by y^2 + y = x^3 + (-1)*x
         over Number Field in a with defining polynomial x^3 - 7
  Via:  (u,r,s,t) = (1, 0, 0, 0)
>>> from sage.all import *
>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(3) - Integer(7), names=('a',)); (a,) = K._first_ngens(1)# needs sage.rings.number_field
>>> E.isomorphism_to(E.change_ring(K))                                    # needs sage.rings.number_field
Elliptic-curve morphism:
  From: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
  To:   Elliptic Curve defined by y^2 + y = x^3 + (-1)*x
         over Number Field in a with defining polynomial x^3 - 7
  Via:  (u,r,s,t) = (1, 0, 0, 0)
isomorphisms(other, field=None)[source]

Return the set of isomorphisms from self to other (as a list).

INPUT:

  • other – another elliptic curve

  • field – (default: None) a field into which the coefficients of the curves may be coerced (by default, uses the base field of the curves)

OUTPUT:

A list of WeierstrassIsomorphism objects consisting of all the isomorphisms from the curve self to the curve other defined over field.

EXAMPLES:

sage: E = EllipticCurve_from_j(QQ(0)) # a curve with j=0 over QQ
sage: F = EllipticCurve('27a3') # should be the same one
sage: E.isomorphisms(F)
[Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Rational Field
   Via:  (u,r,s,t) = (1, 0, 0, 0),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Rational Field
   Via:  (u,r,s,t) = (-1, 0, 0, -1)]
>>> from sage.all import *
>>> E = EllipticCurve_from_j(QQ(Integer(0))) # a curve with j=0 over QQ
>>> F = EllipticCurve('27a3') # should be the same one
>>> E.isomorphisms(F)
[Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Rational Field
   Via:  (u,r,s,t) = (1, 0, 0, 0),
 Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
  over Rational Field
   Via:  (u,r,s,t) = (-1, 0, 0, -1)]

We can also find isomorphisms defined over extension fields:

sage: # needs sage.rings.finite_rings
sage: E = EllipticCurve(GF(7), [0,0,0,1,1])
sage: F = EllipticCurve(GF(7), [0,0,0,1,-1])
sage: E.isomorphisms(F)
[]
sage: E.isomorphisms(F, GF(49,'a'))
[Elliptic-curve morphism:
   From: Elliptic Curve defined by y^2 = x^3 + x + 1
         over Finite Field in a of size 7^2
   To:   Elliptic Curve defined by y^2 = x^3 + x + 6
         over Finite Field in a of size 7^2
   Via:  (u,r,s,t) = (a + 3, 0, 0, 0),
 Elliptic-curve morphism:
   From: Elliptic Curve defined by y^2 = x^3 + x + 1
         over Finite Field in a of size 7^2
   To:   Elliptic Curve defined by y^2 = x^3 + x + 6
         over Finite Field in a of size 7^2
   Via:  (u,r,s,t) = (6*a + 4, 0, 0, 0)]
>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> E = EllipticCurve(GF(Integer(7)), [Integer(0),Integer(0),Integer(0),Integer(1),Integer(1)])
>>> F = EllipticCurve(GF(Integer(7)), [Integer(0),Integer(0),Integer(0),Integer(1),-Integer(1)])
>>> E.isomorphisms(F)
[]
>>> E.isomorphisms(F, GF(Integer(49),'a'))
[Elliptic-curve morphism:
   From: Elliptic Curve defined by y^2 = x^3 + x + 1
         over Finite Field in a of size 7^2
   To:   Elliptic Curve defined by y^2 = x^3 + x + 6
         over Finite Field in a of size 7^2
   Via:  (u,r,s,t) = (a + 3, 0, 0, 0),
 Elliptic-curve morphism:
   From: Elliptic Curve defined by y^2 = x^3 + x + 1
         over Finite Field in a of size 7^2
   To:   Elliptic Curve defined by y^2 = x^3 + x + 6
         over Finite Field in a of size 7^2
   Via:  (u,r,s,t) = (6*a + 4, 0, 0, 0)]
j_invariant()[source]

Return the \(j\)-invariant of this elliptic curve.

This method is cached.

EXAMPLES:

sage: E = EllipticCurve([0,0,1,-1,0])
sage: E.j_invariant()
110592/37

sage: E = EllipticCurve([0, -1, 1, -10, -20])
sage: E.j_invariant()
-122023936/161051

sage: E = EllipticCurve([-4,0])
sage: E.j_invariant()
1728

sage: E = EllipticCurve([GF(7)(2),1])
sage: E.j_invariant()
1
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(1),Integer(0)])
>>> E.j_invariant()
110592/37

>>> E = EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(10), -Integer(20)])
>>> E.j_invariant()
-122023936/161051

>>> E = EllipticCurve([-Integer(4),Integer(0)])
>>> E.j_invariant()
1728

>>> E = EllipticCurve([GF(Integer(7))(Integer(2)),Integer(1)])
>>> E.j_invariant()
1
lift_x(x, all=False, extend=False)[source]

Return one or all points with given \(x\)-coordinate.

This method is deterministic: It returns the same data each time when called again with the same \(x\).

INPUT:

  • x – an element of the base ring of the curve, or of an extension

  • all – boolean (default: False); if True, return a (possibly empty) list of all points; if False, return just one point, or raise a ValueError if there are none.

  • extend – boolean (default: False);

    • if False, extend the base if necessary and possible to include \(x\), and only return point(s) defined over this ring, or raise an error when there are none with this \(x\)-coordinate;

    • If True, the base ring will be extended if necessary to contain the \(y\)-coordinates of the point(s) with this \(x\)-coordinate, in addition to a possible base change to include \(x\).

OUTPUT:

A point or list of up to 2 points on this curve, or a base-change of this curve to a larger ring.

See also

is_x_coord()

EXAMPLES:

sage: E = EllipticCurve('37a'); E
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
sage: E.lift_x(1)
(1 : -1 : 1)
sage: E.lift_x(2)
(2 : -3 : 1)
sage: E.lift_x(1/4, all=True)
[(1/4 : -5/8 : 1), (1/4 : -3/8 : 1)]
>>> from sage.all import *
>>> E = EllipticCurve('37a'); E
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
>>> E.lift_x(Integer(1))
(1 : -1 : 1)
>>> E.lift_x(Integer(2))
(2 : -3 : 1)
>>> E.lift_x(Integer(1)/Integer(4), all=True)
[(1/4 : -5/8 : 1), (1/4 : -3/8 : 1)]

There are no rational points with \(x\)-coordinate 3:

sage: E.lift_x(3)
Traceback (most recent call last):
...
ValueError: No point with x-coordinate 3
on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
>>> from sage.all import *
>>> E.lift_x(Integer(3))
Traceback (most recent call last):
...
ValueError: No point with x-coordinate 3
on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field

We can use the extend parameter to make the necessary quadratic extension. Note that in such cases the returned point is a point on a new curve object, the result of changing the base ring to the parent of \(x\):

sage: P = E.lift_x(3, extend=True); P                                       # needs sage.rings.number_field
(3 : -y - 1 : 1)
sage: P.curve()                                                             # needs sage.rings.number_field
Elliptic Curve defined by y^2 + y = x^3 + (-1)*x
over Number Field in y with defining polynomial y^2 + y - 24
>>> from sage.all import *
>>> P = E.lift_x(Integer(3), extend=True); P                                       # needs sage.rings.number_field
(3 : -y - 1 : 1)
>>> P.curve()                                                             # needs sage.rings.number_field
Elliptic Curve defined by y^2 + y = x^3 + (-1)*x
over Number Field in y with defining polynomial y^2 + y - 24

Or we can extend scalars. There are two such points in \(E(\RR)\):

sage: E.change_ring(RR).lift_x(3, all=True)
[(3.00000000000000 : -5.42442890089805 : 1.00000000000000),
 (3.00000000000000 : 4.42442890089805 : 1.00000000000000)]
>>> from sage.all import *
>>> E.change_ring(RR).lift_x(Integer(3), all=True)
[(3.00000000000000 : -5.42442890089805 : 1.00000000000000),
 (3.00000000000000 : 4.42442890089805 : 1.00000000000000)]

And of course it always works in \(E(\CC)\):

sage: E.change_ring(RR).lift_x(.5, all=True)
[]
sage: E.change_ring(CC).lift_x(.5)
(0.500000000000000 : -0.500000000000000 - 0.353553390593274*I : 1.00000000000000)
>>> from sage.all import *
>>> E.change_ring(RR).lift_x(RealNumber('.5'), all=True)
[]
>>> E.change_ring(CC).lift_x(RealNumber('.5'))
(0.500000000000000 : -0.500000000000000 - 0.353553390593274*I : 1.00000000000000)

In this example we start with a curve defined over \(\QQ\) which has no rational points with \(x=0\), but using extend = True we can construct such a point over a quadratic field:

sage: E = EllipticCurve([0,0,0,0,2]); E
Elliptic Curve defined by y^2 = x^3 + 2 over Rational Field
sage: P = E.lift_x(0, extend=True); P                                       # needs sage.rings.number_field
(0 : -y : 1)
sage: P.curve()                                                             # needs sage.rings.number_field
Elliptic Curve defined by y^2 = x^3 + 2
over Number Field in y with defining polynomial y^2 - 2
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0),Integer(0),Integer(0),Integer(0),Integer(2)]); E
Elliptic Curve defined by y^2 = x^3 + 2 over Rational Field
>>> P = E.lift_x(Integer(0), extend=True); P                                       # needs sage.rings.number_field
(0 : -y : 1)
>>> P.curve()                                                             # needs sage.rings.number_field
Elliptic Curve defined by y^2 = x^3 + 2
over Number Field in y with defining polynomial y^2 - 2

We can perform these operations over finite fields too:

sage: E = EllipticCurve('37a').change_ring(GF(17)); E
Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17
sage: E.lift_x(7)
(7 : 5 : 1)
sage: E.lift_x(3)
Traceback (most recent call last):
...
ValueError: No point with x-coordinate 3 on
Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17
>>> from sage.all import *
>>> E = EllipticCurve('37a').change_ring(GF(Integer(17))); E
Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17
>>> E.lift_x(Integer(7))
(7 : 5 : 1)
>>> E.lift_x(Integer(3))
Traceback (most recent call last):
...
ValueError: No point with x-coordinate 3 on
Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17

Note that there is only one lift with \(x\)-coordinate 10 in \(E(\GF{17})\):

sage: E.lift_x(10, all=True)
[(10 : 8 : 1)]
>>> from sage.all import *
>>> E.lift_x(Integer(10), all=True)
[(10 : 8 : 1)]

We can lift over more exotic rings too. If the supplied x value is in an extension of the base, note that the point returned is on the base-extended curve:

sage: E = EllipticCurve('37a')
sage: P = E.lift_x(pAdicField(17, 5)(6)); P                                 # needs sage.rings.padics
(6 + O(17^5) : 14 + O(17^5) : 1 + O(17^5))
sage: P.curve()                                                             # needs sage.rings.padics
Elliptic Curve defined by
y^2 + (1+O(17^5))*y = x^3 + (16+16*17+16*17^2+16*17^3+16*17^4+O(17^5))*x
over 17-adic Field with capped relative precision 5
sage: K.<t> = PowerSeriesRing(QQ, 't', 5)
sage: P = E.lift_x(1 + t); P
(1 + t : -1 - 2*t + t^2 - 5*t^3 + 21*t^4 + O(t^5) : 1)
sage: K.<a> = GF(16)                                                        # needs sage.rings.finite_rings
sage: P = E.change_ring(K).lift_x(a^3); P                                   # needs sage.rings.finite_rings
(a^3 : a^3 + a : 1)
sage: P.curve()                                                             # needs sage.rings.finite_rings
Elliptic Curve defined by y^2 + y = x^3 + x over Finite Field in a of size 2^4
>>> from sage.all import *
>>> E = EllipticCurve('37a')
>>> P = E.lift_x(pAdicField(Integer(17), Integer(5))(Integer(6))); P                                 # needs sage.rings.padics
(6 + O(17^5) : 14 + O(17^5) : 1 + O(17^5))
>>> P.curve()                                                             # needs sage.rings.padics
Elliptic Curve defined by
y^2 + (1+O(17^5))*y = x^3 + (16+16*17+16*17^2+16*17^3+16*17^4+O(17^5))*x
over 17-adic Field with capped relative precision 5
>>> K = PowerSeriesRing(QQ, 't', Integer(5), names=('t',)); (t,) = K._first_ngens(1)
>>> P = E.lift_x(Integer(1) + t); P
(1 + t : -1 - 2*t + t^2 - 5*t^3 + 21*t^4 + O(t^5) : 1)
>>> K = GF(Integer(16), names=('a',)); (a,) = K._first_ngens(1)# needs sage.rings.finite_rings
>>> P = E.change_ring(K).lift_x(a**Integer(3)); P                                   # needs sage.rings.finite_rings
(a^3 : a^3 + a : 1)
>>> P.curve()                                                             # needs sage.rings.finite_rings
Elliptic Curve defined by y^2 + y = x^3 + x over Finite Field in a of size 2^4

We can extend the base field to include the associated \(y\) value(s):

sage: E = EllipticCurve([0,0,0,0,2]); E
Elliptic Curve defined by y^2 = x^3 + 2 over Rational Field
sage: x = polygen(QQ)
sage: P = E.lift_x(x, extend=True); P
(x : -y : 1)
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0),Integer(0),Integer(0),Integer(0),Integer(2)]); E
Elliptic Curve defined by y^2 = x^3 + 2 over Rational Field
>>> x = polygen(QQ)
>>> P = E.lift_x(x, extend=True); P
(x : -y : 1)

This point is a generic point on E:

sage: P.curve()
Elliptic Curve defined by y^2 = x^3 + 2
over Univariate Quotient Polynomial Ring in y
over Fraction Field of Univariate Polynomial Ring in x over Rational Field
with modulus y^2 - x^3 - 2
sage: -P
(x : y : 1)
sage: 2*P
((1/4*x^4 - 4*x)/(x^3 + 2) : ((-1/8*x^6 - 5*x^3 + 4)/(x^6 + 4*x^3 + 4))*y : 1)
>>> from sage.all import *
>>> P.curve()
Elliptic Curve defined by y^2 = x^3 + 2
over Univariate Quotient Polynomial Ring in y
over Fraction Field of Univariate Polynomial Ring in x over Rational Field
with modulus y^2 - x^3 - 2
>>> -P
(x : y : 1)
>>> Integer(2)*P
((1/4*x^4 - 4*x)/(x^3 + 2) : ((-1/8*x^6 - 5*x^3 + 4)/(x^6 + 4*x^3 + 4))*y : 1)

Check that Issue #30297 is fixed:

sage: K = Qp(5)                                                             # needs sage.rings.padics
sage: E = EllipticCurve([K(0), K(1)])                                       # needs sage.rings.padics
sage: E.lift_x(1, extend=True)                                              # needs sage.rings.padics
(1 + O(5^20) : y + O(5^20) : 1 + O(5^20))
>>> from sage.all import *
>>> K = Qp(Integer(5))                                                             # needs sage.rings.padics
>>> E = EllipticCurve([K(Integer(0)), K(Integer(1))])                                       # needs sage.rings.padics
>>> E.lift_x(Integer(1), extend=True)                                              # needs sage.rings.padics
(1 + O(5^20) : y + O(5^20) : 1 + O(5^20))

AUTHORS:

  • Robert Bradshaw (2007-04-24)

  • John Cremona (2017-11-10)

montgomery_model(twisted=False, morphism=False)[source]

Return a (twisted or untwisted) Montgomery model for this elliptic curve, if possible.

A Montgomery curve is a smooth projective curve of the form

\[BY^2 = X^3 + AX^2 + X.\]

The Montgomery curve is called untwisted if \(B=1\).

INPUT:

  • twisted – boolean (default: False); allow \(B \neq 1\)

  • morphism – boolean (default: False); also return an isomorphism from this curve to the computed Montgomery model

OUTPUT:

If twisted is False (the default), an EllipticCurve_generic object encapsulating an untwisted Montgomery curve. Otherwise, a ProjectivePlaneCurve object encapsulating a (potentially twisted) Montgomery curve.

If morphism is True, this method returns a tuple consisting of such a curve together with an isomorphism of suitable type (either WeierstrassIsomorphism or WeierstrassTransformationWithInverse) from this curve to the Montgomery model.

EXAMPLES:

sage: E = EllipticCurve(QQbar, '11a1')                                      # needs sage.rings.number_field
sage: E.montgomery_model()                                                  # needs sage.rings.number_field
Elliptic Curve defined by y^2 = x^3 + (-1.953522420987248?)*x^2 + x
over Algebraic Field
>>> from sage.all import *
>>> E = EllipticCurve(QQbar, '11a1')                                      # needs sage.rings.number_field
>>> E.montgomery_model()                                                  # needs sage.rings.number_field
Elliptic Curve defined by y^2 = x^3 + (-1.953522420987248?)*x^2 + x
over Algebraic Field

sage: E = EllipticCurve(GF(431^2), [7,7])                                   # needs sage.rings.finite_rings
sage: E.montgomery_model()                                                  # needs sage.rings.finite_rings
Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x
over Finite Field in z2 of size 431^2
>>> from sage.all import *
>>> E = EllipticCurve(GF(Integer(431)**Integer(2)), [Integer(7),Integer(7)])                                   # needs sage.rings.finite_rings
>>> E.montgomery_model()                                                  # needs sage.rings.finite_rings
Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x
over Finite Field in z2 of size 431^2

An isomorphism between the Montgomery and Weierstrass form can be obtained using the morphism parameter:

sage: E.montgomery_model(morphism=True)                                     # needs sage.rings.finite_rings
(Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x
  over Finite Field in z2 of size 431^2,
 Elliptic-curve morphism:
   From: Elliptic Curve defined by y^2 = x^3 + 7*x + 7
         over Finite Field in z2 of size 431^2
   To:   Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x
         over Finite Field in z2 of size 431^2
   Via:  (u,r,s,t) = (64*z2 + 407, 159, 0, 0))
>>> from sage.all import *
>>> E.montgomery_model(morphism=True)                                     # needs sage.rings.finite_rings
(Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x
  over Finite Field in z2 of size 431^2,
 Elliptic-curve morphism:
   From: Elliptic Curve defined by y^2 = x^3 + 7*x + 7
         over Finite Field in z2 of size 431^2
   To:   Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x
         over Finite Field in z2 of size 431^2
   Via:  (u,r,s,t) = (64*z2 + 407, 159, 0, 0))

Not all elliptic curves have a Montgomery model over their field of definition:

sage: E = EllipticCurve(GF(257), [1,1])
sage: E.montgomery_model()
Traceback (most recent call last):
...
ValueError: Elliptic Curve defined by y^2 = x^3 + x + 1
over Finite Field of size 257 has no Montgomery model
>>> from sage.all import *
>>> E = EllipticCurve(GF(Integer(257)), [Integer(1),Integer(1)])
>>> E.montgomery_model()
Traceback (most recent call last):
...
ValueError: Elliptic Curve defined by y^2 = x^3 + x + 1
over Finite Field of size 257 has no Montgomery model

sage: E = EllipticCurve(GF(257), [10,10])
sage: E.montgomery_model()
Traceback (most recent call last):
...
ValueError: Elliptic Curve defined by y^2 = x^3 + 10*x + 10
over Finite Field of size 257 has no untwisted Montgomery model
>>> from sage.all import *
>>> E = EllipticCurve(GF(Integer(257)), [Integer(10),Integer(10)])
>>> E.montgomery_model()
Traceback (most recent call last):
...
ValueError: Elliptic Curve defined by y^2 = x^3 + 10*x + 10
over Finite Field of size 257 has no untwisted Montgomery model

However, as hinted by the error message, the latter curve does admit a twisted Montgomery model, which can be computed by passing twisted=True:

sage: E.montgomery_model(twisted=True)
Projective Plane Curve over Finite Field of size 257
defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2
>>> from sage.all import *
>>> E.montgomery_model(twisted=True)
Projective Plane Curve over Finite Field of size 257
defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2

Since Sage internally represents elliptic curves as (long) Weierstrass curves, which do not feature the Montgomery \(B\) coefficient, the returned curve in this case is merely a ProjectivePlaneCurve rather than the usual EllipticCurve_generic.

Arithmetic on curves of this type is not implemented natively, but can easily be emulated by mapping back and forth to the corresponding Weierstrass curve:

sage: C, f = E.montgomery_model(twisted=True, morphism=True)
sage: f
Scheme morphism:
  From: Elliptic Curve defined by y^2 = x^3 + 10*x + 10
        over Finite Field of size 257
  To:   Projective Plane Curve over Finite Field of size 257
        defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2
  Defn: Defined on coordinates by sending (x : y : z) to
        (x + 116*z : -y : -85*z)
sage: g = f.inverse(); g
Scheme morphism:
  From: Projective Plane Curve over Finite Field of size 257
        defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2
  To:   Elliptic Curve defined by y^2 = x^3 + 10*x + 10
        over Finite Field of size 257
  Defn: Defined on coordinates by sending (x : y : z) to
        (-85*x - 116*z : 85*y : z)
sage: P = C(70, 8)
sage: Q = C(17, 17)
sage: P + Q             # this doesn't work...
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for +: ...
sage: f(g(P) + g(Q))    # ...but this does
(107 : 168 : 1)
>>> from sage.all import *
>>> C, f = E.montgomery_model(twisted=True, morphism=True)
>>> f
Scheme morphism:
  From: Elliptic Curve defined by y^2 = x^3 + 10*x + 10
        over Finite Field of size 257
  To:   Projective Plane Curve over Finite Field of size 257
        defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2
  Defn: Defined on coordinates by sending (x : y : z) to
        (x + 116*z : -y : -85*z)
>>> g = f.inverse(); g
Scheme morphism:
  From: Projective Plane Curve over Finite Field of size 257
        defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2
  To:   Elliptic Curve defined by y^2 = x^3 + 10*x + 10
        over Finite Field of size 257
  Defn: Defined on coordinates by sending (x : y : z) to
        (-85*x - 116*z : 85*y : z)
>>> P = C(Integer(70), Integer(8))
>>> Q = C(Integer(17), Integer(17))
>>> P + Q             # this doesn't work...
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for +: ...
>>> f(g(P) + g(Q))    # ...but this does
(107 : 168 : 1)

Using the fact that the Weil pairing satisfies \(e(\psi(P),\psi(Q)) = e(P,Q)^{\deg\psi}\), even pairings can be emulated in this way (note that isomorphisms have degree \(1\)):

sage: # needs sage.rings.finite_rings
sage: F.<z2> = GF(257^2)
sage: C_ = C.change_ring(F)
sage: g_ = g.change_ring(F)
sage: g_(P).order()
12
sage: T = C_(-7 * z2 - 57, 31 * z2 - 52, 1)
sage: g_(T).order()
12
sage: g_(P).weil_pairing(g_(T), 12)
15*z2 + 204
>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> F = GF(Integer(257)**Integer(2), names=('z2',)); (z2,) = F._first_ngens(1)
>>> C_ = C.change_ring(F)
>>> g_ = g.change_ring(F)
>>> g_(P).order()
12
>>> T = C_(-Integer(7) * z2 - Integer(57), Integer(31) * z2 - Integer(52), Integer(1))
>>> g_(T).order()
12
>>> g_(P).weil_pairing(g_(T), Integer(12))
15*z2 + 204

Another alternative is to simply extend the base field enough for the curve to have an untwisted Montgomery model:

sage: C_ = E.change_ring(F).montgomery_model(); C_                          # needs sage.rings.finite_rings
Elliptic Curve defined by y^2 = x^3 + 249*x^2 + x
over Finite Field in z2 of size 257^2
sage: h = C.defining_polynomial().change_ring(F); h                         # needs sage.rings.finite_rings
-x^3 + 8*x^2*z - 127*y^2*z - x*z^2
sage: C_.is_isomorphic(EllipticCurve_from_cubic(h).codomain())              # needs sage.rings.finite_rings
True
>>> from sage.all import *
>>> C_ = E.change_ring(F).montgomery_model(); C_                          # needs sage.rings.finite_rings
Elliptic Curve defined by y^2 = x^3 + 249*x^2 + x
over Finite Field in z2 of size 257^2
>>> h = C.defining_polynomial().change_ring(F); h                         # needs sage.rings.finite_rings
-x^3 + 8*x^2*z - 127*y^2*z - x*z^2
>>> C_.is_isomorphic(EllipticCurve_from_cubic(h).codomain())              # needs sage.rings.finite_rings
True

See also

The inverse conversion — computing a Weierstrass model for a given Montgomery curve — can be performed using EllipticCurve_from_cubic().

ALGORITHM: [CS2018], §2.4

REFERENCES:

multiplication_by_m(m, x_only=False)[source]

Return the multiplication-by-\(m\) map from self to self.

The result is a pair of rational functions in two variables \(x\), \(y\) (or a rational function in one variable \(x\) if x_only is True).

INPUT:

  • m – nonzero integer

  • x_only – boolean (default: False); if True, return only the \(x\)-coordinate of the map (as a rational function in one variable)

OUTPUT:

  • a pair \((f(x), g(x,y))\), where \(f\) and \(g\) are rational functions with the degree of \(y\) in \(g(x,y)\) exactly 1,

  • or just \(f(x)\) if x_only is True

Note

  • The result is not cached.

  • m is allowed to be negative (but not 0).

EXAMPLES:

sage: E = EllipticCurve([-1,3])
>>> from sage.all import *
>>> E = EllipticCurve([-Integer(1),Integer(3)])

We verify that multiplication by 1 is just the identity:

sage: E.multiplication_by_m(1)
(x, y)
>>> from sage.all import *
>>> E.multiplication_by_m(Integer(1))
(x, y)

Multiplication by 2 is more complicated:

sage: f = E.multiplication_by_m(2)
sage: f
((x^4 + 2*x^2 - 24*x + 1)/(4*x^3 - 4*x + 12),
 (8*x^6*y - 40*x^4*y + 480*x^3*y - 40*x^2*y + 96*x*y - 568*y)/(64*x^6 - 128*x^4 + 384*x^3 + 64*x^2 - 384*x + 576))
>>> from sage.all import *
>>> f = E.multiplication_by_m(Integer(2))
>>> f
((x^4 + 2*x^2 - 24*x + 1)/(4*x^3 - 4*x + 12),
 (8*x^6*y - 40*x^4*y + 480*x^3*y - 40*x^2*y + 96*x*y - 568*y)/(64*x^6 - 128*x^4 + 384*x^3 + 64*x^2 - 384*x + 576))

Grab only the x-coordinate (less work):

sage: mx = E.multiplication_by_m(2, x_only=True); mx
(1/4*x^4 + 1/2*x^2 - 6*x + 1/4)/(x^3 - x + 3)
sage: mx.parent()
Fraction Field of Univariate Polynomial Ring in x over Rational Field
>>> from sage.all import *
>>> mx = E.multiplication_by_m(Integer(2), x_only=True); mx
(1/4*x^4 + 1/2*x^2 - 6*x + 1/4)/(x^3 - x + 3)
>>> mx.parent()
Fraction Field of Univariate Polynomial Ring in x over Rational Field

We check that it works on a point:

sage: P = E([2,3])
sage: eval = lambda f,P: [fi(P[0],P[1]) for fi in f]
sage: assert E(eval(f,P)) == 2*P
>>> from sage.all import *
>>> P = E([Integer(2),Integer(3)])
>>> eval = lambda f,P: [fi(P[Integer(0)],P[Integer(1)]) for fi in f]
>>> assert E(eval(f,P)) == Integer(2)*P

We do the same but with multiplication by 3:

sage: f = E.multiplication_by_m(3)
sage: assert E(eval(f,P)) == 3*P
>>> from sage.all import *
>>> f = E.multiplication_by_m(Integer(3))
>>> assert E(eval(f,P)) == Integer(3)*P

And the same with multiplication by 4:

sage: f = E.multiplication_by_m(4)
sage: assert E(eval(f,P)) == 4*P
>>> from sage.all import *
>>> f = E.multiplication_by_m(Integer(4))
>>> assert E(eval(f,P)) == Integer(4)*P

And the same with multiplication by -1,-2,-3,-4:

sage: for m in [-1,-2,-3,-4]:
....:     f = E.multiplication_by_m(m)
....:     assert E(eval(f,P)) == m*P
>>> from sage.all import *
>>> for m in [-Integer(1),-Integer(2),-Integer(3),-Integer(4)]:
...     f = E.multiplication_by_m(m)
...     assert E(eval(f,P)) == m*P
pari_curve()[source]

Return the PARI curve corresponding to this elliptic curve.

The result is cached.

EXAMPLES:

sage: # needs sage.libs.pari
sage: E = EllipticCurve([RR(0), RR(0), RR(1), RR(-1), RR(0)])
sage: e = E.pari_curve()
sage: type(e)
<... 'cypari2.gen.Gen'>
sage: e.type()
't_VEC'
sage: e.disc()
37.0000000000000
>>> from sage.all import *
>>> # needs sage.libs.pari
>>> E = EllipticCurve([RR(Integer(0)), RR(Integer(0)), RR(Integer(1)), RR(-Integer(1)), RR(Integer(0))])
>>> e = E.pari_curve()
>>> type(e)
<... 'cypari2.gen.Gen'>
>>> e.type()
't_VEC'
>>> e.disc()
37.0000000000000

Over a finite field:

sage: EllipticCurve(GF(41), [2,5]).pari_curve()                             # needs sage.libs.pari
[Mod(0, 41), Mod(0, 41), Mod(0, 41), Mod(2, 41), Mod(5, 41),
 Mod(0, 41), Mod(4, 41), Mod(20, 41), Mod(37, 41), Mod(27, 41),
 Mod(26, 41), Mod(4, 41), Mod(11, 41),
 Vecsmall([3]),
 [41, [9, 31, [6, 0, 0, 0]]], [0, 0, 0, 0]]
>>> from sage.all import *
>>> EllipticCurve(GF(Integer(41)), [Integer(2),Integer(5)]).pari_curve()                             # needs sage.libs.pari
[Mod(0, 41), Mod(0, 41), Mod(0, 41), Mod(2, 41), Mod(5, 41),
 Mod(0, 41), Mod(4, 41), Mod(20, 41), Mod(37, 41), Mod(27, 41),
 Mod(26, 41), Mod(4, 41), Mod(11, 41),
 Vecsmall([3]),
 [41, [9, 31, [6, 0, 0, 0]]], [0, 0, 0, 0]]

Over a \(p\)-adic field:

sage: # needs sage.libs.pari sage.rings.padics
sage: Qp = pAdicField(5, prec=3)
sage: E = EllipticCurve(Qp, [3, 4])
sage: E.pari_curve()
[0, 0, 0, 3, 4, 0, 6, 16, -9, -144, -3456, -8640, 1728/5,
 Vecsmall([2]), [O(5^3)], [0, 0]]
sage: E.j_invariant()
3*5^-1 + O(5)
>>> from sage.all import *
>>> # needs sage.libs.pari sage.rings.padics
>>> Qp = pAdicField(Integer(5), prec=Integer(3))
>>> E = EllipticCurve(Qp, [Integer(3), Integer(4)])
>>> E.pari_curve()
[0, 0, 0, 3, 4, 0, 6, 16, -9, -144, -3456, -8640, 1728/5,
 Vecsmall([2]), [O(5^3)], [0, 0]]
>>> E.j_invariant()
3*5^-1 + O(5)

Over a number field:

sage: K.<a> = QuadraticField(2)                                             # needs sage.libs.pari sage.rings.number_field
sage: E = EllipticCurve([1,a])                                              # needs sage.libs.pari sage.rings.number_field
sage: E.pari_curve()                                                        # needs sage.libs.pari sage.rings.number_field
[0, 0, 0, Mod(1, y^2 - 2),
 Mod(y, y^2 - 2), 0, Mod(2, y^2 - 2), Mod(4*y, y^2 - 2),
 Mod(-1, y^2 - 2), Mod(-48, y^2 - 2), Mod(-864*y, y^2 - 2),
 Mod(-928, y^2 - 2), Mod(3456/29, y^2 - 2),
 Vecsmall([5]),
 [[y^2 - 2, [2, 0], 8, 1, [[1, -1.41421356237310; 1, 1.41421356237310],
 [1, -1.41421356237310; 1, 1.41421356237310],
 [16, -23; 16, 23], [2, 0; 0, 4], [4, 0; 0, 2], [2, 0; 0, 1],
 [2, [0, 2; 1, 0]], [2]], [-1.41421356237310, 1.41421356237310],
 [1, y], [1, 0; 0, 1], [1, 0, 0, 2; 0, 1, 1, 0]]], [0, 0, 0, 0, 0]]
>>> from sage.all import *
>>> K = QuadraticField(Integer(2), names=('a',)); (a,) = K._first_ngens(1)# needs sage.libs.pari sage.rings.number_field
>>> E = EllipticCurve([Integer(1),a])                                              # needs sage.libs.pari sage.rings.number_field
>>> E.pari_curve()                                                        # needs sage.libs.pari sage.rings.number_field
[0, 0, 0, Mod(1, y^2 - 2),
 Mod(y, y^2 - 2), 0, Mod(2, y^2 - 2), Mod(4*y, y^2 - 2),
 Mod(-1, y^2 - 2), Mod(-48, y^2 - 2), Mod(-864*y, y^2 - 2),
 Mod(-928, y^2 - 2), Mod(3456/29, y^2 - 2),
 Vecsmall([5]),
 [[y^2 - 2, [2, 0], 8, 1, [[1, -1.41421356237310; 1, 1.41421356237310],
 [1, -1.41421356237310; 1, 1.41421356237310],
 [16, -23; 16, 23], [2, 0; 0, 4], [4, 0; 0, 2], [2, 0; 0, 1],
 [2, [0, 2; 1, 0]], [2]], [-1.41421356237310, 1.41421356237310],
 [1, y], [1, 0; 0, 1], [1, 0, 0, 2; 0, 1, 1, 0]]], [0, 0, 0, 0, 0]]

PARI no longer requires that the \(j\)-invariant has negative \(p\)-adic valuation:

sage: E = EllipticCurve(Qp,[1, 1])                                          # needs sage.libs.pari sage.rings.padics
sage: E.j_invariant()  # the j-invariant is a p-adic integer                # needs sage.libs.pari sage.rings.padics
2 + 4*5^2 + O(5^3)
sage: E.pari_curve()                                                        # needs sage.libs.pari sage.rings.padics
[0, 0, 0, 1, 1, 0, 2, 4, -1, -48, -864, -496, 6912/31,
 Vecsmall([2]), [O(5^3)], [0, 0]]
>>> from sage.all import *
>>> E = EllipticCurve(Qp,[Integer(1), Integer(1)])                                          # needs sage.libs.pari sage.rings.padics
>>> E.j_invariant()  # the j-invariant is a p-adic integer                # needs sage.libs.pari sage.rings.padics
2 + 4*5^2 + O(5^3)
>>> E.pari_curve()                                                        # needs sage.libs.pari sage.rings.padics
[0, 0, 0, 1, 1, 0, 2, 4, -1, -48, -864, -496, 6912/31,
 Vecsmall([2]), [O(5^3)], [0, 0]]
plot(xmin=None, xmax=None, components='both', **args)[source]

Draw a graph of this elliptic curve.

The plot method is only implemented when there is a natural coercion from the base ring of self to RR. In this case, self is plotted as if it was defined over RR.

INPUT:

  • xmin, xmax – (optional) points will be computed at least within this range, but possibly farther

  • components – string; one of the following:

    • both – (default), scale so that both bounded and unbounded components appear

    • bounded – scale the plot to show the bounded component. Raises an error if there is only one real component.

    • unbounded – scale the plot to show the unbounded component, including the two flex points

  • plot_points – passed to sage.plot.generate_plot_points()

  • adaptive_tolerance – passed to sage.plot.generate_plot_points()

  • adaptive_recursion – passed to sage.plot.generate_plot_points()

  • randomize – passed to sage.plot.generate_plot_points()

  • **args – all other options are passed to sage.plot.line.Line

EXAMPLES:

sage: E = EllipticCurve([0, -1])
sage: plot(E, rgbcolor=hue(0.7))                                            # needs sage.plot
Graphics object consisting of 1 graphics primitive
sage: E = EllipticCurve('37a')
sage: plot(E)                                                               # needs sage.plot
Graphics object consisting of 2 graphics primitives
sage: plot(E, xmin=25, xmax=26)                                             # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0), -Integer(1)])
>>> plot(E, rgbcolor=hue(RealNumber('0.7')))                                            # needs sage.plot
Graphics object consisting of 1 graphics primitive
>>> E = EllipticCurve('37a')
>>> plot(E)                                                               # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> plot(E, xmin=Integer(25), xmax=Integer(26))                                             # needs sage.plot
Graphics object consisting of 2 graphics primitives

With Issue #12766 we added the components keyword:

sage: E.real_components()
2
sage: E.plot(components='bounded')                                          # needs sage.plot
Graphics object consisting of 1 graphics primitive
sage: E.plot(components='unbounded')                                        # needs sage.plot
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> E.real_components()
2
>>> E.plot(components='bounded')                                          # needs sage.plot
Graphics object consisting of 1 graphics primitive
>>> E.plot(components='unbounded')                                        # needs sage.plot
Graphics object consisting of 1 graphics primitive

If there is only one component then specifying components=’bounded’ raises a ValueError:

sage: E = EllipticCurve('9990be2')
sage: E.plot(components='bounded')                                          # needs sage.plot
Traceback (most recent call last):
...
ValueError: no bounded component for this curve
>>> from sage.all import *
>>> E = EllipticCurve('9990be2')
>>> E.plot(components='bounded')                                          # needs sage.plot
Traceback (most recent call last):
...
ValueError: no bounded component for this curve

An elliptic curve defined over the Complex Field can not be plotted:

sage: E = EllipticCurve(CC, [0,0,1,-1,0])
sage: E.plot()                                                              # needs sage.plot
Traceback (most recent call last):
...
NotImplementedError: plotting of curves over Complex Field
with 53 bits of precision is not implemented yet
>>> from sage.all import *
>>> E = EllipticCurve(CC, [Integer(0),Integer(0),Integer(1),-Integer(1),Integer(0)])
>>> E.plot()                                                              # needs sage.plot
Traceback (most recent call last):
...
NotImplementedError: plotting of curves over Complex Field
with 53 bits of precision is not implemented yet
rst_transform(r, s, t)[source]

Return the transform of the curve by \((r,s,t)\) (with \(u=1\)).

INPUT:

  • r, s, t – three elements of the base ring

OUTPUT:

The elliptic curve obtained from self by the standard Weierstrass transformation \((u,r,s,t)\) with \(u=1\).

Note

This is just a special case of change_weierstrass_model(), with \(u=1\).

EXAMPLES:

sage: R.<r,s,t> = QQ[]
sage: E = EllipticCurve([1,2,3,4,5])
sage: E.rst_transform(r, s, t)
Elliptic Curve defined by y^2 + (2*s+1)*x*y + (r+2*t+3)*y
= x^3 + (-s^2+3*r-s+2)*x^2 + (3*r^2-r*s-2*s*t+4*r-3*s-t+4)*x
  + (r^3+2*r^2-r*t-t^2+4*r-3*t+5)
over Multivariate Polynomial Ring in r, s, t over Rational Field
>>> from sage.all import *
>>> R = QQ['r, s, t']; (r, s, t,) = R._first_ngens(3)
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E.rst_transform(r, s, t)
Elliptic Curve defined by y^2 + (2*s+1)*x*y + (r+2*t+3)*y
= x^3 + (-s^2+3*r-s+2)*x^2 + (3*r^2-r*s-2*s*t+4*r-3*s-t+4)*x
  + (r^3+2*r^2-r*t-t^2+4*r-3*t+5)
over Multivariate Polynomial Ring in r, s, t over Rational Field
scalar_multiplication(m)[source]

Return the scalar-multiplication map \([m]\) on this elliptic curve as a sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar object.

EXAMPLES:

sage: E = EllipticCurve('77a1')
sage: m = E.scalar_multiplication(-7); m
Scalar-multiplication endomorphism [-7]
 of Elliptic Curve defined by y^2 + y = x^3 + 2*x over Rational Field
sage: m.degree()
49
sage: P = E(2,3)
sage: m(P)
(-26/225 : -2132/3375 : 1)
sage: m.rational_maps() == E.multiplication_by_m(-7)
True
>>> from sage.all import *
>>> E = EllipticCurve('77a1')
>>> m = E.scalar_multiplication(-Integer(7)); m
Scalar-multiplication endomorphism [-7]
 of Elliptic Curve defined by y^2 + y = x^3 + 2*x over Rational Field
>>> m.degree()
49
>>> P = E(Integer(2),Integer(3))
>>> m(P)
(-26/225 : -2132/3375 : 1)
>>> m.rational_maps() == E.multiplication_by_m(-Integer(7))
True

sage: E = EllipticCurve('11a1')
sage: E.scalar_multiplication(7)
Scalar-multiplication endomorphism [7]
 of Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
>>> from sage.all import *
>>> E = EllipticCurve('11a1')
>>> E.scalar_multiplication(Integer(7))
Scalar-multiplication endomorphism [7]
 of Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
scale_curve(u)[source]

Return the transform of the curve by scale factor \(u\).

INPUT:

  • u – an invertible element of the base ring

OUTPUT:

The elliptic curve obtained from self by the standard Weierstrass transformation \((u,r,s,t)\) with \(r=s=t=0\).

Note

This is just a special case of change_weierstrass_model(), with \(r=s=t=0\).

EXAMPLES:

sage: K = Frac(PolynomialRing(QQ, 'u'))
sage: u = K.gen()
sage: E = EllipticCurve([1,2,3,4,5])
sage: E.scale_curve(u)
Elliptic Curve defined by
y^2 + u*x*y + 3*u^3*y = x^3 + 2*u^2*x^2 + 4*u^4*x + 5*u^6
over Fraction Field of Univariate Polynomial Ring in u over Rational Field
>>> from sage.all import *
>>> K = Frac(PolynomialRing(QQ, 'u'))
>>> u = K.gen()
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E.scale_curve(u)
Elliptic Curve defined by
y^2 + u*x*y + 3*u^3*y = x^3 + 2*u^2*x^2 + 4*u^4*x + 5*u^6
over Fraction Field of Univariate Polynomial Ring in u over Rational Field
short_weierstrass_model(complete_cube=True)[source]

Return a short Weierstrass model for self.

INPUT:

  • complete_cube – boolean (default: True); for meaning, see below

OUTPUT: an elliptic curve

If complete_cube=True: Return a model of the form \(y^2 = x^3 + a*x + b\) for this curve. The characteristic must not be 2; in characteristic 3, it is only possible if \(b_2=0\).

If complete_cube=False: Return a model of the form \(y^2 = x^3 + ax^2 + bx + c\) for this curve. The characteristic must not be 2.

EXAMPLES:

sage: E = EllipticCurve([1,2,3,4,5])
sage: E
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
sage: F = E.short_weierstrass_model()
sage: F
Elliptic Curve defined by y^2  = x^3 + 4941*x + 185166 over Rational Field
sage: E.is_isomorphic(F)
True
sage: F = E.short_weierstrass_model(complete_cube=False)
sage: F
Elliptic Curve defined by y^2  = x^3 + 9*x^2 + 88*x + 464 over Rational Field
sage: E.is_isomorphic(F)
True
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
>>> F = E.short_weierstrass_model()
>>> F
Elliptic Curve defined by y^2  = x^3 + 4941*x + 185166 over Rational Field
>>> E.is_isomorphic(F)
True
>>> F = E.short_weierstrass_model(complete_cube=False)
>>> F
Elliptic Curve defined by y^2  = x^3 + 9*x^2 + 88*x + 464 over Rational Field
>>> E.is_isomorphic(F)
True

sage: E = EllipticCurve(GF(3), [1,2,3,4,5])
sage: E.short_weierstrass_model(complete_cube=False)
Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 3
>>> from sage.all import *
>>> E = EllipticCurve(GF(Integer(3)), [Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> E.short_weierstrass_model(complete_cube=False)
Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 3

This used to be different see Issue #3973:

sage: E.short_weierstrass_model()
Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 3
>>> from sage.all import *
>>> E.short_weierstrass_model()
Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 3

More tests in characteristic 3:

sage: E = EllipticCurve(GF(3), [0,2,1,2,1])
sage: E.short_weierstrass_model()
Traceback (most recent call last):
...
ValueError: short_weierstrass_model(): no short model for Elliptic Curve
defined by y^2 + y = x^3 + 2*x^2 + 2*x + 1 over Finite Field of size 3
(characteristic is 3)
sage: E.short_weierstrass_model(complete_cube=False)
Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2*x + 2
over Finite Field of size 3
sage: E.short_weierstrass_model(complete_cube=False).is_isomorphic(E)
True
>>> from sage.all import *
>>> E = EllipticCurve(GF(Integer(3)), [Integer(0),Integer(2),Integer(1),Integer(2),Integer(1)])
>>> E.short_weierstrass_model()
Traceback (most recent call last):
...
ValueError: short_weierstrass_model(): no short model for Elliptic Curve
defined by y^2 + y = x^3 + 2*x^2 + 2*x + 1 over Finite Field of size 3
(characteristic is 3)
>>> E.short_weierstrass_model(complete_cube=False)
Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2*x + 2
over Finite Field of size 3
>>> E.short_weierstrass_model(complete_cube=False).is_isomorphic(E)
True
torsion_polynomial(m, x=None, two_torsion_multiplicity=2, force_evaluate=None)[source]

Return the \(m\)-th division polynomial of this elliptic curve evaluated at \(x\).

The division polynomial is cached if \(x\) is None.

INPUT:

  • m – positive integer

  • x – (optional) ring element to use as the \(x\) variable. If \(x\) is None (omitted), then a new polynomial ring will be constructed over the base ring of the elliptic curve, and its generator will be used as \(x\). Note that \(x\) does not need to be a generator of a polynomial ring; any ring element works. This permits fast calculation of the torsion polynomial evaluated on any element of a ring.

  • two_torsion_multiplicity – 0, 1, or 2

    If 0: For even \(m\) when \(x\) is None, a univariate polynomial over the base ring of the curve is returned, which omits factors whose roots are the \(x\)-coordinates of the \(2\)-torsion points. When \(x\) is not None, the evaluation of such a polynomial at \(x\) is returned.

    If 2: For even \(m\) when \(x\) is None, a univariate polynomial over the base ring of the curve is returned, which includes a factor of degree 3 whose roots are the \(x\)-coordinates of the \(2\)-torsion points. Similarly, when \(x\) is not None, the evaluation of such a polynomial at \(x\) is returned.

    If 1: For even \(m\) when \(x\) is None, a bivariate polynomial over the base ring of the curve is returned, which includes a factor \(2y+a_1x+a_3\) having simple zeros at the \(2\)-torsion points. When \(x\) is not None, it should be a tuple of length 2, and the evaluation of such a polynomial at \(x\) is returned.

  • force_evaluate – (optional) 0, 1, or 2

    By default, this method makes use of previously cached generic division polynomials to compute the value of the polynomial at a given element \(x\) whenever it appears beneficial to do so. Explicitly setting this flag overrides the default behavior.

    Note that the complexity of evaluating a generic division polynomial scales much worse than that of computing the value at a point directly (using the recursive formulas), hence setting this flag can be detrimental to performance.

    If 0: Do not use cached generic division polynomials.

    If 1: If the generic division polynomial for this \(m\) has been cached before, evaluate it at \(x\) to compute the result.

    If 2: Compute the value at \(x\) by evaluating the generic division polynomial. If the generic \(m\)-division polynomial has not yet been cached, compute and cache it first.

EXAMPLES:

sage: E = EllipticCurve([0,0,1,-1,0])
sage: E.division_polynomial(1)
1
sage: E.division_polynomial(2, two_torsion_multiplicity=0)
1
sage: E.division_polynomial(2, two_torsion_multiplicity=1)
2*y + 1
sage: E.division_polynomial(2, two_torsion_multiplicity=2)
4*x^3 - 4*x + 1
sage: E.division_polynomial(2)
4*x^3 - 4*x + 1
sage: [E.division_polynomial(3, two_torsion_multiplicity=i) for i in range(3)]
[3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1]
sage: [type(E.division_polynomial(3, two_torsion_multiplicity=i)) for i in range(3)]
[<... 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>,
 <... 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>,
 <... 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>]
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(1),Integer(0)])
>>> E.division_polynomial(Integer(1))
1
>>> E.division_polynomial(Integer(2), two_torsion_multiplicity=Integer(0))
1
>>> E.division_polynomial(Integer(2), two_torsion_multiplicity=Integer(1))
2*y + 1
>>> E.division_polynomial(Integer(2), two_torsion_multiplicity=Integer(2))
4*x^3 - 4*x + 1
>>> E.division_polynomial(Integer(2))
4*x^3 - 4*x + 1
>>> [E.division_polynomial(Integer(3), two_torsion_multiplicity=i) for i in range(Integer(3))]
[3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1]
>>> [type(E.division_polynomial(Integer(3), two_torsion_multiplicity=i)) for i in range(Integer(3))]
[<... 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>,
 <... 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>,
 <... 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>]

sage: E = EllipticCurve([0, -1, 1, -10, -20])
sage: R.<z> = PolynomialRing(QQ)
sage: E.division_polynomial(4, z, 0)
2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821
sage: E.division_polynomial(4, z)
8*z^9 - 24*z^8 - 464*z^7 - 2758*z^6 + 6636*z^5 + 34356*z^4
 + 53510*z^3 + 99714*z^2 + 351024*z + 459859
>>> from sage.all import *
>>> E = EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(10), -Integer(20)])
>>> R = PolynomialRing(QQ, names=('z',)); (z,) = R._first_ngens(1)
>>> E.division_polynomial(Integer(4), z, Integer(0))
2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821
>>> E.division_polynomial(Integer(4), z)
8*z^9 - 24*z^8 - 464*z^7 - 2758*z^6 + 6636*z^5 + 34356*z^4
 + 53510*z^3 + 99714*z^2 + 351024*z + 459859

This does not work, since when two_torsion_multiplicity is 1, we compute a bivariate polynomial, and must evaluate at a tuple of length 2:

sage: E.division_polynomial(4,z,1)
Traceback (most recent call last):
...
ValueError: x should be a tuple of length 2 (or None)
when two_torsion_multiplicity is 1
sage: R.<z,w> = PolynomialRing(QQ, 2)
sage: E.division_polynomial(4, (z,w), 1).factor()
(2*w + 1) * (2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821)
>>> from sage.all import *
>>> E.division_polynomial(Integer(4),z,Integer(1))
Traceback (most recent call last):
...
ValueError: x should be a tuple of length 2 (or None)
when two_torsion_multiplicity is 1
>>> R = PolynomialRing(QQ, Integer(2), names=('z', 'w',)); (z, w,) = R._first_ngens(2)
>>> E.division_polynomial(Integer(4), (z,w), Integer(1)).factor()
(2*w + 1) * (2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821)

We can also evaluate this bivariate polynomial at a point:

sage: P = E(5,5)
sage: E.division_polynomial(4,P,two_torsion_multiplicity=1)
-1771561
>>> from sage.all import *
>>> P = E(Integer(5),Integer(5))
>>> E.division_polynomial(Integer(4),P,two_torsion_multiplicity=Integer(1))
-1771561
two_division_polynomial(x=None)[source]

Return the 2-division polynomial of this elliptic curve evaluated at x.

INPUT:

  • x – (optional) ring element to use as the \(x\) variable. If x is None, then a new polynomial ring will be constructed over the base ring of the elliptic curve, and its generator will be used as x. Note that x does not need to be a generator of a polynomial ring; any ring element is acceptable. This permits fast calculation of the torsion polynomial evaluated on any element of a ring.

EXAMPLES:

sage: E = EllipticCurve('5077a1')
sage: E.two_division_polynomial()
4*x^3 - 28*x + 25
sage: E = EllipticCurve(GF(3^2,'a'), [1,1,1,1,1])                           # needs sage.rings.finite_rings
sage: E.two_division_polynomial()                                           # needs sage.rings.finite_rings
x^3 + 2*x^2 + 2
sage: E.two_division_polynomial().roots()                                   # needs sage.rings.finite_rings
[(2, 1), (2*a, 1), (a + 2, 1)]
>>> from sage.all import *
>>> E = EllipticCurve('5077a1')
>>> E.two_division_polynomial()
4*x^3 - 28*x + 25
>>> E = EllipticCurve(GF(Integer(3)**Integer(2),'a'), [Integer(1),Integer(1),Integer(1),Integer(1),Integer(1)])                           # needs sage.rings.finite_rings
>>> E.two_division_polynomial()                                           # needs sage.rings.finite_rings
x^3 + 2*x^2 + 2
>>> E.two_division_polynomial().roots()                                   # needs sage.rings.finite_rings
[(2, 1), (2*a, 1), (a + 2, 1)]
sage.schemes.elliptic_curves.ell_generic.is_EllipticCurve(x)[source]

Utility function to test if x is an instance of an Elliptic Curve class.

EXAMPLES:

sage: from sage.schemes.elliptic_curves.ell_generic import is_EllipticCurve
sage: E = EllipticCurve([1,2,3/4,7,19])
sage: is_EllipticCurve(E)
doctest:warning...
DeprecationWarning: The function is_EllipticCurve is deprecated; use 'isinstance(..., EllipticCurve_generic)' instead.
See https://github.com/sagemath/sage/issues/38022 for details.
True
sage: is_EllipticCurve(0)
False
>>> from sage.all import *
>>> from sage.schemes.elliptic_curves.ell_generic import is_EllipticCurve
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3)/Integer(4),Integer(7),Integer(19)])
>>> is_EllipticCurve(E)
doctest:warning...
DeprecationWarning: The function is_EllipticCurve is deprecated; use 'isinstance(..., EllipticCurve_generic)' instead.
See https://github.com/sagemath/sage/issues/38022 for details.
True
>>> is_EllipticCurve(Integer(0))
False