Elliptic curve constructor¶
AUTHORS:
William Stein (2005): Initial version
John Cremona (2008-01): EllipticCurve(j) fixed for all cases
- class sage.schemes.elliptic_curves.constructor.EllipticCurveFactory[source]¶
Bases:
UniqueFactory
Construct an elliptic curve.
In Sage, an elliptic curve is always specified by (the coefficients of) a long Weierstrass equation
\[y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6.\]INPUT:
There are several ways to construct an elliptic curve:
EllipticCurve([a1,a2,a3,a4,a6])
: Elliptic curve with given \(a\)-invariants. The invariants are coerced into a common parent. If all are integers, they are coerced into the rational numbers.EllipticCurve([a4,a6])
: Same as above, but \(a_1=a_2=a_3=0\).EllipticCurve(label)
: Returns the elliptic curve over \(\QQ\) from the Cremona database with the given label. The label is a string, such as'11a'
or'37b2'
. The letters in the label must be lower case (Cremona’s new labeling).EllipticCurve(R, [a1,a2,a3,a4,a6])
: Create the elliptic curve over \(R\) with given \(a\)-invariants. Here \(R\) can be an arbitrary commutative ring, although most functionality is only implemented over fields.EllipticCurve(j=j0)
orEllipticCurve_from_j(j0)
: Return an elliptic curve with \(j\)-invariantj0
.EllipticCurve(polynomial)
: Read off the \(a\)-invariants from the polynomial coefficients, seeEllipticCurve_from_Weierstrass_polynomial()
.EllipticCurve(cubic, point)
: The elliptic curve defined by a plane cubic (homogeneous polynomial in three variables), with a rational point.
Instead of giving the coefficients as a list of length 2 or 5, one can also give a tuple.
EXAMPLES:
We illustrate creating elliptic curves:
sage: EllipticCurve([0,0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
>>> from sage.all import * >>> EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(1),Integer(0)]) Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
EllipticCurve([0,0,1,-1,0])
We create a curve from a Cremona label:
sage: EllipticCurve('37b2') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field sage: EllipticCurve('5077a') Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field sage: EllipticCurve('389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
>>> from sage.all import * >>> EllipticCurve('37b2') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field >>> EllipticCurve('5077a') Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field >>> EllipticCurve('389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
EllipticCurve('37b2') EllipticCurve('5077a') EllipticCurve('389a')
Old Cremona labels are allowed:
sage: EllipticCurve('2400FF') Elliptic Curve defined by y^2 = x^3 + x^2 + 2*x + 8 over Rational Field
>>> from sage.all import * >>> EllipticCurve('2400FF') Elliptic Curve defined by y^2 = x^3 + x^2 + 2*x + 8 over Rational Field
EllipticCurve('2400FF')
Unicode labels are allowed:
sage: EllipticCurve(u'389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
>>> from sage.all import * >>> EllipticCurve(u'389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
EllipticCurve(u'389a')
We create curves over a finite field as follows:
sage: EllipticCurve([GF(5)(0),0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 sage: EllipticCurve(GF(5), [0, 0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5
>>> from sage.all import * >>> EllipticCurve([GF(Integer(5))(Integer(0)),Integer(0),Integer(1),-Integer(1),Integer(0)]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 >>> EllipticCurve(GF(Integer(5)), [Integer(0), Integer(0),Integer(1),-Integer(1),Integer(0)]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5
EllipticCurve([GF(5)(0),0,1,-1,0]) EllipticCurve(GF(5), [0, 0,1,-1,0])
Elliptic curves over \(\ZZ/N\ZZ\) with \(N\) prime are of type “elliptic curve over a finite field”:
sage: F = Zmod(101) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'> sage: E.category() Category of abelian varieties over Ring of integers modulo 101
>>> from sage.all import * >>> F = Zmod(Integer(101)) >>> EllipticCurve(F, [Integer(2), Integer(3)]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101 >>> E = EllipticCurve([F(Integer(2)), F(Integer(3))]) >>> type(E) <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'> >>> E.category() Category of abelian varieties over Ring of integers modulo 101
F = Zmod(101) EllipticCurve(F, [2, 3]) E = EllipticCurve([F(2), F(3)]) type(E) E.category()
In contrast, elliptic curves over \(\ZZ/N\ZZ\) with \(N\) composite are of type “generic elliptic curve”:
sage: F = Zmod(95) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'> sage: E.category() Category of schemes over Ring of integers modulo 95
>>> from sage.all import * >>> F = Zmod(Integer(95)) >>> EllipticCurve(F, [Integer(2), Integer(3)]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95 >>> E = EllipticCurve([F(Integer(2)), F(Integer(3))]) >>> type(E) <class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'> >>> E.category() Category of schemes over Ring of integers modulo 95
F = Zmod(95) EllipticCurve(F, [2, 3]) E = EllipticCurve([F(2), F(3)]) type(E) E.category()
The following is a curve over the complex numbers:
sage: E = EllipticCurve(CC, [0,0,1,-1,0]) sage: E Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision sage: E.j_invariant() 2988.97297297297
>>> from sage.all import * >>> E = EllipticCurve(CC, [Integer(0),Integer(0),Integer(1),-Integer(1),Integer(0)]) >>> E Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision >>> E.j_invariant() 2988.97297297297
E = EllipticCurve(CC, [0,0,1,-1,0]) E E.j_invariant()
We can also create elliptic curves by giving the Weierstrass equation:
sage: R2.<x,y> = PolynomialRing(QQ,2) sage: EllipticCurve(y^2 + y - ( x^3 + x - 9 )) Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field sage: R.<x,y> = GF(5)[] sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x) Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5
>>> from sage.all import * >>> R2 = PolynomialRing(QQ,Integer(2), names=('x', 'y',)); (x, y,) = R2._first_ngens(2) >>> EllipticCurve(y**Integer(2) + y - ( x**Integer(3) + x - Integer(9) )) Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field >>> R = GF(Integer(5))['x, y']; (x, y,) = R._first_ngens(2) >>> EllipticCurve(x**Integer(3) + x**Integer(2) + Integer(2) - y**Integer(2) - y*x) Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5
R2.<x,y> = PolynomialRing(QQ,2) EllipticCurve(y^2 + y - ( x^3 + x - 9 )) R.<x,y> = GF(5)[] EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x)
We can also create elliptic curves by giving a smooth plane cubic with a rational point:
sage: R3.<x,y,z> = PolynomialRing(QQ,3) sage: F = x^3 + y^3 + 30*z^3 sage: P = [1,-1,0] sage: EllipticCurve(F,P) Elliptic Curve defined by y^2 - 270*y = x^3 - 24300 over Rational Field
>>> from sage.all import * >>> R3 = PolynomialRing(QQ,Integer(3), names=('x', 'y', 'z',)); (x, y, z,) = R3._first_ngens(3) >>> F = x**Integer(3) + y**Integer(3) + Integer(30)*z**Integer(3) >>> P = [Integer(1),-Integer(1),Integer(0)] >>> EllipticCurve(F,P) Elliptic Curve defined by y^2 - 270*y = x^3 - 24300 over Rational Field
R3.<x,y,z> = PolynomialRing(QQ,3) F = x^3 + y^3 + 30*z^3 P = [1,-1,0] EllipticCurve(F,P)
We can explicitly specify the \(j\)-invariant:
sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 = x^3 - x over Rational Field 1728 '32a2' sage: E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant() Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 2
>>> from sage.all import * >>> E = EllipticCurve(j=Integer(1728)); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 = x^3 - x over Rational Field 1728 '32a2' >>> E = EllipticCurve(j=GF(Integer(5))(Integer(2))); E; E.j_invariant() Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 2
E = EllipticCurve(j=1728); E; E.j_invariant(); E.label() E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant()
See Issue #6657
sage: EllipticCurve(GF(144169), j=1728) # needs sage.rings.finite_rings Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169
>>> from sage.all import * >>> EllipticCurve(GF(Integer(144169)), j=Integer(1728)) # needs sage.rings.finite_rings Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169
EllipticCurve(GF(144169), j=1728) # needs sage.rings.finite_rings
Elliptic curves over the same ring with the same Weierstrass coefficients are identical, even when they are constructed in different ways (see Issue #11474):
sage: EllipticCurve('11a3') is EllipticCurve(QQ, [0, -1, 1, 0, 0]) True
>>> from sage.all import * >>> EllipticCurve('11a3') is EllipticCurve(QQ, [Integer(0), -Integer(1), Integer(1), Integer(0), Integer(0)]) True
EllipticCurve('11a3') is EllipticCurve(QQ, [0, -1, 1, 0, 0])
By default, when a rational value of \(j\) is given, the constructed curve is a minimal twist (minimal conductor for curves with that \(j\)-invariant). This can be changed by setting the optional parameter
minimal_twist
, which isTrue
by default, toFalse
:sage: EllipticCurve(j=100) Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field sage: E =EllipticCurve(j=100); E Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field sage: E.conductor() 33129800 sage: E.j_invariant() 100 sage: E =EllipticCurve(j=100, minimal_twist=False); E Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field sage: E.conductor() 298168200 sage: E.j_invariant() 100
>>> from sage.all import * >>> EllipticCurve(j=Integer(100)) Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field >>> E =EllipticCurve(j=Integer(100)); E Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field >>> E.conductor() 33129800 >>> E.j_invariant() 100 >>> E =EllipticCurve(j=Integer(100), minimal_twist=False); E Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field >>> E.conductor() 298168200 >>> E.j_invariant() 100
EllipticCurve(j=100) E =EllipticCurve(j=100); E E.conductor() E.j_invariant() E =EllipticCurve(j=100, minimal_twist=False); E E.conductor() E.j_invariant()
Without this option, constructing the curve could take a long time since both \(j\) and \(j-1728\) have to be factored to compute the minimal twist (see Issue #13100):
sage: E = EllipticCurve_from_j(2^256+1, minimal_twist=False) sage: E.j_invariant() == 2^256+1 True
>>> from sage.all import * >>> E = EllipticCurve_from_j(Integer(2)**Integer(256)+Integer(1), minimal_twist=False) >>> E.j_invariant() == Integer(2)**Integer(256)+Integer(1) True
E = EllipticCurve_from_j(2^256+1, minimal_twist=False) E.j_invariant() == 2^256+1
- create_key_and_extra_args(x=None, y=None, j=None, minimal_twist=True, **kwds)[source]¶
Return a
UniqueFactory
key and possibly extra parameters.INPUT: See the documentation for
EllipticCurveFactory
.OUTPUT:
A pair
(key, extra_args)
:key
has the form \((R, (a_1, a_2, a_3, a_4, a_6))\), representing a ring and the Weierstrass coefficients of an elliptic curve over that ring;extra_args
is a dictionary containing additional data to be inserted into the elliptic curve structure.
EXAMPLES:
sage: EllipticCurve.create_key_and_extra_args(j=8000) ((Rational Field, (0, 1, 0, -3, 1)), {})
>>> from sage.all import * >>> EllipticCurve.create_key_and_extra_args(j=Integer(8000)) ((Rational Field, (0, 1, 0, -3, 1)), {})
EllipticCurve.create_key_and_extra_args(j=8000)
When constructing a curve over \(\QQ\) from a Cremona or LMFDB label, the invariants from the database are returned as
extra_args
:sage: key, data = EllipticCurve.create_key_and_extra_args('389.a1') sage: key (Rational Field, (0, 1, 1, -2, 0)) sage: data['conductor'] 389 sage: data['cremona_label'] '389a1' sage: data['lmfdb_label'] '389.a1' sage: data['rank'] 2 sage: data['torsion_order'] 1
>>> from sage.all import * >>> key, data = EllipticCurve.create_key_and_extra_args('389.a1') >>> key (Rational Field, (0, 1, 1, -2, 0)) >>> data['conductor'] 389 >>> data['cremona_label'] '389a1' >>> data['lmfdb_label'] '389.a1' >>> data['rank'] 2 >>> data['torsion_order'] 1
key, data = EllipticCurve.create_key_and_extra_args('389.a1') key data['conductor'] data['cremona_label'] data['lmfdb_label'] data['rank'] data['torsion_order']
User-specified keywords are also included in
extra_args
:sage: key, data = EllipticCurve.create_key_and_extra_args((0, 0, 1, -23737, 960366), rank=4) sage: data['rank'] 4
>>> from sage.all import * >>> key, data = EllipticCurve.create_key_and_extra_args((Integer(0), Integer(0), Integer(1), -Integer(23737), Integer(960366)), rank=Integer(4)) >>> data['rank'] 4
key, data = EllipticCurve.create_key_and_extra_args((0, 0, 1, -23737, 960366), rank=4) data['rank']
Furthermore, keywords takes precedence over data from the database, which can be used to specify an alternative set of generators for the Mordell-Weil group:
sage: key, data = EllipticCurve.create_key_and_extra_args('5077a1', gens=[[1, -1], [-2, 3], [4, -7]]) sage: data['gens'] [[1, -1], [-2, 3], [4, -7]] sage: E = EllipticCurve.create_object(0, key, **data) sage: E.gens() [(-2 : 3 : 1), (1 : -1 : 1), (4 : -7 : 1)]
>>> from sage.all import * >>> key, data = EllipticCurve.create_key_and_extra_args('5077a1', gens=[[Integer(1), -Integer(1)], [-Integer(2), Integer(3)], [Integer(4), -Integer(7)]]) >>> data['gens'] [[1, -1], [-2, 3], [4, -7]] >>> E = EllipticCurve.create_object(Integer(0), key, **data) >>> E.gens() [(-2 : 3 : 1), (1 : -1 : 1), (4 : -7 : 1)]
key, data = EllipticCurve.create_key_and_extra_args('5077a1', gens=[[1, -1], [-2, 3], [4, -7]]) data['gens'] E = EllipticCurve.create_object(0, key, **data) E.gens()
Note that elliptic curves are equal if and only they have the same base ring and Weierstrass equation; the data in
extra_args
do not influence comparison of elliptic curves. A consequence of this is that passing keyword arguments only works when constructing an elliptic curve the first time:sage: E = EllipticCurve('433a1', gens=[[-1, 1], [3, 4]]) sage: E.gens() [(-1 : 1 : 1), (3 : 4 : 1)] sage: E = EllipticCurve('433a1', gens=[[-1, 0], [0, 1]]) sage: E.gens() [(-1 : 1 : 1), (3 : 4 : 1)]
>>> from sage.all import * >>> E = EllipticCurve('433a1', gens=[[-Integer(1), Integer(1)], [Integer(3), Integer(4)]]) >>> E.gens() [(-1 : 1 : 1), (3 : 4 : 1)] >>> E = EllipticCurve('433a1', gens=[[-Integer(1), Integer(0)], [Integer(0), Integer(1)]]) >>> E.gens() [(-1 : 1 : 1), (3 : 4 : 1)]
E = EllipticCurve('433a1', gens=[[-1, 1], [3, 4]]) E.gens() E = EllipticCurve('433a1', gens=[[-1, 0], [0, 1]]) E.gens()
Warning
Manually specifying extra data is almost never necessary and is not guaranteed to have any effect, as the above example shows. Almost no checking is done, so specifying incorrect data may lead to wrong results of computations instead of errors or warnings.
- create_object(version, key, names, **kwds)[source]¶
Create an object from a
UniqueFactory
key.EXAMPLES:
sage: E = EllipticCurve.create_object(0, (GF(3), (1, 2, 0, 1, 2))) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'>
>>> from sage.all import * >>> E = EllipticCurve.create_object(Integer(0), (GF(Integer(3)), (Integer(1), Integer(2), Integer(0), Integer(1), Integer(2)))) >>> type(E) <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'>
E = EllipticCurve.create_object(0, (GF(3), (1, 2, 0, 1, 2))) type(E)
names
is ignored at the moment, however it is used to support a convenient way to get a generator:sage: E.<P> = EllipticCurve(QQ, [1, 3]) sage: P (-1 : 1 : 1) sage: E.<P> = EllipticCurve(GF(5), [1, 3]) sage: P (4 : 1 : 1)
>>> from sage.all import * >>> E = EllipticCurve(QQ, [Integer(1), Integer(3)], names=('P',)); (P,) = E._first_ngens(1) >>> P (-1 : 1 : 1) >>> E = EllipticCurve(GF(Integer(5)), [Integer(1), Integer(3)], names=('P',)); (P,) = E._first_ngens(1) >>> P (4 : 1 : 1)
E.<P> = EllipticCurve(QQ, [1, 3]) P E.<P> = EllipticCurve(GF(5), [1, 3]) P
Note
Keyword arguments are currently only passed to the constructor for elliptic curves over \(\QQ\); elliptic curves over other fields do not support them.
- sage.schemes.elliptic_curves.constructor.EllipticCurve_from_Weierstrass_polynomial(f)[source]¶
Return the elliptic curve defined by a cubic in (long) Weierstrass form.
INPUT:
f
– a inhomogeneous cubic polynomial in long Weierstrass form
OUTPUT: the elliptic curve defined by it
EXAMPLES:
sage: R.<x,y> = QQ[] sage: f = y^2 + 1*x*y + 3*y - (x^3 + 2*x^2 + 4*x + 6) sage: EllipticCurve(f) Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 6 over Rational Field sage: EllipticCurve(f).a_invariants() (1, 2, 3, 4, 6)
>>> from sage.all import * >>> R = QQ['x, y']; (x, y,) = R._first_ngens(2) >>> f = y**Integer(2) + Integer(1)*x*y + Integer(3)*y - (x**Integer(3) + Integer(2)*x**Integer(2) + Integer(4)*x + Integer(6)) >>> EllipticCurve(f) Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 6 over Rational Field >>> EllipticCurve(f).a_invariants() (1, 2, 3, 4, 6)
R.<x,y> = QQ[] f = y^2 + 1*x*y + 3*y - (x^3 + 2*x^2 + 4*x + 6) EllipticCurve(f) EllipticCurve(f).a_invariants()
The polynomial ring may have extra variables as long as they do not occur in the polynomial itself:
sage: R.<x,y,z,w> = QQ[] sage: EllipticCurve(-y^2 + x^3 + 1) Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field sage: EllipticCurve(-x^2 + y^3 + 1) Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field sage: EllipticCurve(-w^2 + z^3 + 1) Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
>>> from sage.all import * >>> R = QQ['x, y, z, w']; (x, y, z, w,) = R._first_ngens(4) >>> EllipticCurve(-y**Integer(2) + x**Integer(3) + Integer(1)) Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field >>> EllipticCurve(-x**Integer(2) + y**Integer(3) + Integer(1)) Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field >>> EllipticCurve(-w**Integer(2) + z**Integer(3) + Integer(1)) Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
R.<x,y,z,w> = QQ[] EllipticCurve(-y^2 + x^3 + 1) EllipticCurve(-x^2 + y^3 + 1) EllipticCurve(-w^2 + z^3 + 1)
- sage.schemes.elliptic_curves.constructor.EllipticCurve_from_c4c6(c4, c6)[source]¶
Return an elliptic curve with given \(c_4\) and \(c_6\) invariants.
EXAMPLES:
sage: E = EllipticCurve_from_c4c6(17, -2005) sage: E Elliptic Curve defined by y^2 = x^3 - 17/48*x + 2005/864 over Rational Field sage: E.c_invariants() (17, -2005)
>>> from sage.all import * >>> E = EllipticCurve_from_c4c6(Integer(17), -Integer(2005)) >>> E Elliptic Curve defined by y^2 = x^3 - 17/48*x + 2005/864 over Rational Field >>> E.c_invariants() (17, -2005)
E = EllipticCurve_from_c4c6(17, -2005) E E.c_invariants()
- sage.schemes.elliptic_curves.constructor.EllipticCurve_from_cubic(F, P=None, morphism=True)[source]¶
Construct an elliptic curve from a ternary cubic with a rational point.
If you just want the Weierstrass form and are not interested in the morphism then it is easier to use the function
Jacobian()
instead. If there is a rational point on the given cubic, this function will construct the same elliptic curve but you do not have to supply the pointP
.INPUT:
F
– a homogeneous cubic in three variables with rational coefficients, as a polynomial ring element, defining a smooth plane cubic curve \(C\)P
– a 3-tuple \((x,y,z)\) defining a projective point on \(C\), orNone
. IfNone
then a rational flex will be used as a base point if one exists, otherwise an error will be raised.morphism
– boolean (default:True
); ifTrue
returns a birational isomorphism from \(C\) to a Weierstrass elliptic curve \(E\), otherwise just returns \(E\)
OUTPUT:
Either (when
morphism``=``False
) an elliptic curve \(E\) in long Weierstrass form isomorphic to the plane cubic curve \(C\) defined by the equation \(F=0\).Or (when
morphism=True
), a birational isomorphism from \(C\) to the elliptic curve \(E\). If the given point is a flex, this is a linear isomorphism.Note
The function
Jacobian()
may be used instead. It constructs the same elliptic curve (which is in all cases the Jacobian of \((F=0)\)) and needs no base point to be provided, but also returns no isomorphism since in general there is none: the plane cubic is only isomorphic to its Jacobian when it has a rational point.Note
When
morphism=True
, a birational isomorphism between the curve \(F=0\) and the Weierstrass curve is returned. If the point happens to be a flex, then this is a linear isomorphism. The morphism does not necessarily take the given point \(P\) to the point at infinity on \(E\), since we always use a rational flex on \(C\) as base-point when one exists.EXAMPLES:
First we find that the Fermat cubic is isomorphic to the curve with Cremona label 27a1:
sage: R.<x,y,z> = QQ[] sage: cubic = x^3 + y^3 + z^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 - 9*y = x^3 - 27 over Rational Field sage: E.cremona_label() '27a1' sage: EllipticCurve_from_cubic(cubic, [0,1,-1], morphism=False).cremona_label() '27a1' sage: EllipticCurve_from_cubic(cubic, [1,0,-1], morphism=False).cremona_label() '27a1'
>>> from sage.all import * >>> R = QQ['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> cubic = x**Integer(3) + y**Integer(3) + z**Integer(3) >>> P = [Integer(1),-Integer(1),Integer(0)] >>> E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 - 9*y = x^3 - 27 over Rational Field >>> E.cremona_label() '27a1' >>> EllipticCurve_from_cubic(cubic, [Integer(0),Integer(1),-Integer(1)], morphism=False).cremona_label() '27a1' >>> EllipticCurve_from_cubic(cubic, [Integer(1),Integer(0),-Integer(1)], morphism=False).cremona_label() '27a1'
R.<x,y,z> = QQ[] cubic = x^3 + y^3 + z^3 P = [1,-1,0] E = EllipticCurve_from_cubic(cubic, P, morphism=False); E E.cremona_label() EllipticCurve_from_cubic(cubic, [0,1,-1], morphism=False).cremona_label() EllipticCurve_from_cubic(cubic, [1,0,-1], morphism=False).cremona_label()
Next we find the minimal model and conductor of the Jacobian of the Selmer curve:
sage: R.<a,b,c> = QQ[] sage: cubic = a^3 + b^3 + 60*c^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 - 540*y = x^3 - 97200 over Rational Field sage: E.minimal_model() Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field sage: E.conductor() 24300
>>> from sage.all import * >>> R = QQ['a, b, c']; (a, b, c,) = R._first_ngens(3) >>> cubic = a**Integer(3) + b**Integer(3) + Integer(60)*c**Integer(3) >>> P = [Integer(1),-Integer(1),Integer(0)] >>> E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 - 540*y = x^3 - 97200 over Rational Field >>> E.minimal_model() Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field >>> E.conductor() 24300
R.<a,b,c> = QQ[] cubic = a^3 + b^3 + 60*c^3 P = [1,-1,0] E = EllipticCurve_from_cubic(cubic, P, morphism=False); E E.minimal_model() E.conductor()
We can also get the birational isomorphism to and from the Weierstrass form. We start with an example where
P
is a flex and the equivalence is a linear isomorphism:sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: f Scheme morphism: From: Projective Plane Curve over Rational Field defined by a^3 + b^3 + 60*c^3 To: Elliptic Curve defined by y^2 - 540*y = x^3 - 97200 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (-c : 3*a : 1/180*a + 1/180*b) sage: finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 - 540*y = x^3 - 97200 over Rational Field To: Projective Plane Curve over Rational Field defined by a^3 + b^3 + 60*c^3 Defn: Defined on coordinates by sending (x : y : z) to (1/3*y : -1/3*y + 180*z : -x) Scheme morphism: From: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + b^3 + 60*c^3 Defn: Defined on coordinates by sending (x : y : z) to (x + y + 20*z : -x - y : -x)
>>> from sage.all import * >>> f = EllipticCurve_from_cubic(cubic, P, morphism=True) >>> f Scheme morphism: From: Projective Plane Curve over Rational Field defined by a^3 + b^3 + 60*c^3 To: Elliptic Curve defined by y^2 - 540*y = x^3 - 97200 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (-c : 3*a : 1/180*a + 1/180*b) >>> finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 - 540*y = x^3 - 97200 over Rational Field To: Projective Plane Curve over Rational Field defined by a^3 + b^3 + 60*c^3 Defn: Defined on coordinates by sending (x : y : z) to (1/3*y : -1/3*y + 180*z : -x) Scheme morphism: From: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + b^3 + 60*c^3 Defn: Defined on coordinates by sending (x : y : z) to (x + y + 20*z : -x - y : -x)
f = EllipticCurve_from_cubic(cubic, P, morphism=True) f finv = f.inverse(); finv
We verify that \(f\) maps the chosen point \(P=(1,-1,0)\) on the cubic to the origin of the elliptic curve:
sage: f([1,-1,0]) (0 : 1 : 0) sage: finv([0,1,0]) (-1 : 1 : 0)
>>> from sage.all import * >>> f([Integer(1),-Integer(1),Integer(0)]) (0 : 1 : 0) >>> finv([Integer(0),Integer(1),Integer(0)]) (-1 : 1 : 0)
f([1,-1,0]) finv([0,1,0])
To verify the output, we plug in the polynomials to check that this indeed transforms the cubic into Weierstrass form:
sage: cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 + y^2*z - 540*y*z^2 + 97200*z^3 sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + b^3 + 60*c^3
>>> from sage.all import * >>> cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 + y^2*z - 540*y*z^2 + 97200*z^3 >>> E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + b^3 + 60*c^3
cubic(finv.defining_polynomials()) * finv.post_rescaling() E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling()
If the given point is not a flex and the cubic has no rational flexes, then the cubic can not be transformed to a Weierstrass equation by a linear transformation. The general birational transformation is still a birational isomorphism, but is quadratic:
sage: R.<x,y,z> = QQ[] sage: cubic = x^2*y + 4*x*y^2 + x^2*z + 8*x*y*z + 4*y^2*z + 9*x*z^2 + 9*y*z^2 sage: f = EllipticCurve_from_cubic(cubic, [1,-1,1], morphism=True); f Scheme morphism: From: Projective Plane Curve over Rational Field defined by x^2*y + 4*x*y^2 + x^2*z + 8*x*y*z + 4*y^2*z + 9*x*z^2 + 9*y*z^2 To: Elliptic Curve defined by y^2 + 7560/19*x*y + 552960000000/2352637*y = x^3 - 3445200/133*x^2 over Rational Field Defn: Defined on coordinates by sending (x : y : z) to (2527/17280*x^2 + 133/2160*x*y + 133/108000*y^2 + 133/2880*x*z + 931/18000*y*z - 3857/48000*z^2 : -6859/288*x^2 + 323/36*x*y + 359/1800*y^2 + 551/48*x*z + 2813/300*y*z + 24389/800*z^2 : -2352637/99532800000*x^2 - 2352637/124416000000*x*y - 2352637/622080000000*y^2 + 2352637/82944000000*x*z + 2352637/207360000000*y*z - 2352637/276480000000*z^2)
>>> from sage.all import * >>> R = QQ['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> cubic = x**Integer(2)*y + Integer(4)*x*y**Integer(2) + x**Integer(2)*z + Integer(8)*x*y*z + Integer(4)*y**Integer(2)*z + Integer(9)*x*z**Integer(2) + Integer(9)*y*z**Integer(2) >>> f = EllipticCurve_from_cubic(cubic, [Integer(1),-Integer(1),Integer(1)], morphism=True); f Scheme morphism: From: Projective Plane Curve over Rational Field defined by x^2*y + 4*x*y^2 + x^2*z + 8*x*y*z + 4*y^2*z + 9*x*z^2 + 9*y*z^2 To: Elliptic Curve defined by y^2 + 7560/19*x*y + 552960000000/2352637*y = x^3 - 3445200/133*x^2 over Rational Field Defn: Defined on coordinates by sending (x : y : z) to (2527/17280*x^2 + 133/2160*x*y + 133/108000*y^2 + 133/2880*x*z + 931/18000*y*z - 3857/48000*z^2 : -6859/288*x^2 + 323/36*x*y + 359/1800*y^2 + 551/48*x*z + 2813/300*y*z + 24389/800*z^2 : -2352637/99532800000*x^2 - 2352637/124416000000*x*y - 2352637/622080000000*y^2 + 2352637/82944000000*x*z + 2352637/207360000000*y*z - 2352637/276480000000*z^2)
R.<x,y,z> = QQ[] cubic = x^2*y + 4*x*y^2 + x^2*z + 8*x*y*z + 4*y^2*z + 9*x*z^2 + 9*y*z^2 f = EllipticCurve_from_cubic(cubic, [1,-1,1], morphism=True); f
Note that the morphism returned cannot be evaluated directly at the given point
P=(1:-1:1)
since the polynomials defining it all vanish there:sage: f([1,-1,1]) Traceback (most recent call last): ... ValueError: [0, 0, 0] does not define a valid projective point since all entries are zero
>>> from sage.all import * >>> f([Integer(1),-Integer(1),Integer(1)]) Traceback (most recent call last): ... ValueError: [0, 0, 0] does not define a valid projective point since all entries are zero
f([1,-1,1])
Using the group law on the codomain elliptic curve, which has rank 1 and full 2-torsion, and the inverse morphism, we can find many points on the cubic. First we find the preimages of multiples of the generator:
sage: E = f.codomain() sage: E.label() '720e2' sage: E.rank() 1 sage: R = E.gens()[0]; R (-17280000/2527 : 9331200000/6859 : 1) sage: finv = f.inverse() sage: [finv(k*R) for k in range(1,10)] [(-4 : 1 : 0), (-1 : 4 : 1), (-20 : -55/76 : 1), (319/399 : -11339/7539 : 1), (159919/14360 : -4078139/1327840 : 1), (-27809119/63578639 : 1856146436/3425378659 : 1), (-510646582340/56909753439 : 424000923715/30153806197284 : 1), (-56686114363679/4050436059492161 : -2433034816977728281/1072927821085503881 : 1), (650589589099815846721/72056273157352822480 : -347376189546061993109881/194127383495944026752320 : 1)]
>>> from sage.all import * >>> E = f.codomain() >>> E.label() '720e2' >>> E.rank() 1 >>> R = E.gens()[Integer(0)]; R (-17280000/2527 : 9331200000/6859 : 1) >>> finv = f.inverse() >>> [finv(k*R) for k in range(Integer(1),Integer(10))] [(-4 : 1 : 0), (-1 : 4 : 1), (-20 : -55/76 : 1), (319/399 : -11339/7539 : 1), (159919/14360 : -4078139/1327840 : 1), (-27809119/63578639 : 1856146436/3425378659 : 1), (-510646582340/56909753439 : 424000923715/30153806197284 : 1), (-56686114363679/4050436059492161 : -2433034816977728281/1072927821085503881 : 1), (650589589099815846721/72056273157352822480 : -347376189546061993109881/194127383495944026752320 : 1)]
E = f.codomain() E.label() E.rank() R = E.gens()[0]; R finv = f.inverse() [finv(k*R) for k in range(1,10)]
The elliptic curve also has torsion, which we can map back:
sage: E.torsion_points() [(0 : 1 : 0), (-144000000/17689 : 3533760000000/2352637 : 1), (-92160000/17689 : 2162073600000/2352637 : 1), (-5760000/17689 : -124070400000/2352637 : 1)] sage: [finv(Q) for Q in E.torsion_points() if Q] [(9 : -9/4 : 1), (-9 : 0 : 1), (0 : 1 : 0)]
>>> from sage.all import * >>> E.torsion_points() [(0 : 1 : 0), (-144000000/17689 : 3533760000000/2352637 : 1), (-92160000/17689 : 2162073600000/2352637 : 1), (-5760000/17689 : -124070400000/2352637 : 1)] >>> [finv(Q) for Q in E.torsion_points() if Q] [(9 : -9/4 : 1), (-9 : 0 : 1), (0 : 1 : 0)]
E.torsion_points() [finv(Q) for Q in E.torsion_points() if Q]
In this example, the given point
P
is not a flex but the cubic does have a rational flex,(-4:0:1)
. We return a linear isomorphism which maps this flex to the point at infinity on the Weierstrass model:sage: R.<a,b,c> = QQ[] sage: cubic = a^3 + 7*b^3 + 64*c^3 sage: P = [2,2,-1] sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: E = f.codomain(); E Elliptic Curve defined by y^2 - 258048*y = x^3 - 22196256768 over Rational Field sage: E.minimal_model() Elliptic Curve defined by y^2 + y = x^3 - 331 over Rational Field sage: f Scheme morphism: From: Projective Plane Curve over Rational Field defined by a^3 + 7*b^3 + 64*c^3 To: Elliptic Curve defined by y^2 - 258048*y = x^3 - 22196256768 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (b : -48*a : -1/5376*a - 1/1344*c) sage: finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 - 258048*y = x^3 - 22196256768 over Rational Field To: Projective Plane Curve over Rational Field defined by a^3 + 7*b^3 + 64*c^3 Defn: Defined on coordinates by sending (x : y : z) to (-1/48*y : x : 1/192*y - 1344*z) sage: cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 + y^2*z - 258048*y*z^2 + 22196256768*z^3 sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + 7*b^3 + 64*c^3 sage: f(P) (5376 : -258048 : 1) sage: f([-4,0,1]) (0 : 1 : 0)
>>> from sage.all import * >>> R = QQ['a, b, c']; (a, b, c,) = R._first_ngens(3) >>> cubic = a**Integer(3) + Integer(7)*b**Integer(3) + Integer(64)*c**Integer(3) >>> P = [Integer(2),Integer(2),-Integer(1)] >>> f = EllipticCurve_from_cubic(cubic, P, morphism=True) >>> E = f.codomain(); E Elliptic Curve defined by y^2 - 258048*y = x^3 - 22196256768 over Rational Field >>> E.minimal_model() Elliptic Curve defined by y^2 + y = x^3 - 331 over Rational Field >>> f Scheme morphism: From: Projective Plane Curve over Rational Field defined by a^3 + 7*b^3 + 64*c^3 To: Elliptic Curve defined by y^2 - 258048*y = x^3 - 22196256768 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (b : -48*a : -1/5376*a - 1/1344*c) >>> finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 - 258048*y = x^3 - 22196256768 over Rational Field To: Projective Plane Curve over Rational Field defined by a^3 + 7*b^3 + 64*c^3 Defn: Defined on coordinates by sending (x : y : z) to (-1/48*y : x : 1/192*y - 1344*z) >>> cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 + y^2*z - 258048*y*z^2 + 22196256768*z^3 >>> E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + 7*b^3 + 64*c^3 >>> f(P) (5376 : -258048 : 1) >>> f([-Integer(4),Integer(0),Integer(1)]) (0 : 1 : 0)
R.<a,b,c> = QQ[] cubic = a^3 + 7*b^3 + 64*c^3 P = [2,2,-1] f = EllipticCurve_from_cubic(cubic, P, morphism=True) E = f.codomain(); E E.minimal_model() f finv = f.inverse(); finv cubic(finv.defining_polynomials()) * finv.post_rescaling() E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() f(P) f([-4,0,1])
It is possible to not provide a base point
P
provided that the cubic has a rational flex. In this case the flexes will be found and one will be used as a base point:sage: R.<x,y,z> = QQ[] sage: cubic = x^3 + y^3 + z^3 sage: f = EllipticCurve_from_cubic(cubic, morphism=True) sage: f Scheme morphism: From: Projective Plane Curve over Rational Field defined by x^3 + y^3 + z^3 To: Elliptic Curve defined by y^2 - 9*y = x^3 - 27 over Rational Field Defn: Defined on coordinates by sending (x : y : z) to (y : -3*x : -1/3*x - 1/3*z)
>>> from sage.all import * >>> R = QQ['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> cubic = x**Integer(3) + y**Integer(3) + z**Integer(3) >>> f = EllipticCurve_from_cubic(cubic, morphism=True) >>> f Scheme morphism: From: Projective Plane Curve over Rational Field defined by x^3 + y^3 + z^3 To: Elliptic Curve defined by y^2 - 9*y = x^3 - 27 over Rational Field Defn: Defined on coordinates by sending (x : y : z) to (y : -3*x : -1/3*x - 1/3*z)
R.<x,y,z> = QQ[] cubic = x^3 + y^3 + z^3 f = EllipticCurve_from_cubic(cubic, morphism=True) f
An error will be raised if no point is given and there are no rational flexes:
sage: R.<x,y,z> = QQ[] sage: cubic = 3*x^3 + 4*y^3 + 5*z^3 sage: EllipticCurve_from_cubic(cubic) Traceback (most recent call last): ... ValueError: A point must be given when the cubic has no rational flexes
>>> from sage.all import * >>> R = QQ['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> cubic = Integer(3)*x**Integer(3) + Integer(4)*y**Integer(3) + Integer(5)*z**Integer(3) >>> EllipticCurve_from_cubic(cubic) Traceback (most recent call last): ... ValueError: A point must be given when the cubic has no rational flexes
R.<x,y,z> = QQ[] cubic = 3*x^3 + 4*y^3 + 5*z^3 EllipticCurve_from_cubic(cubic)
An example over a finite field, using a flex:
sage: K = GF(17) sage: R.<x,y,z> = K[] sage: cubic = 2*x^3 + 3*y^3 + 4*z^3 sage: EllipticCurve_from_cubic(cubic, [0,3,1]) Scheme morphism: From: Projective Plane Curve over Finite Field of size 17 defined by 2*x^3 + 3*y^3 + 4*z^3 To: Elliptic Curve defined by y^2 + 16*y = x^3 + 11 over Finite Field of size 17 Defn: Defined on coordinates by sending (x : y : z) to (-x : 4*y : 4*y + 5*z)
>>> from sage.all import * >>> K = GF(Integer(17)) >>> R = K['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> cubic = Integer(2)*x**Integer(3) + Integer(3)*y**Integer(3) + Integer(4)*z**Integer(3) >>> EllipticCurve_from_cubic(cubic, [Integer(0),Integer(3),Integer(1)]) Scheme morphism: From: Projective Plane Curve over Finite Field of size 17 defined by 2*x^3 + 3*y^3 + 4*z^3 To: Elliptic Curve defined by y^2 + 16*y = x^3 + 11 over Finite Field of size 17 Defn: Defined on coordinates by sending (x : y : z) to (-x : 4*y : 4*y + 5*z)
K = GF(17) R.<x,y,z> = K[] cubic = 2*x^3 + 3*y^3 + 4*z^3 EllipticCurve_from_cubic(cubic, [0,3,1])
An example in characteristic 3:
sage: K = GF(3) sage: R.<x,y,z> = K[] sage: cubic = x^3 + y^3 + z^3 + x*y*z sage: EllipticCurve_from_cubic(cubic, [0,1,-1]) Scheme morphism: From: Projective Plane Curve over Finite Field of size 3 defined by x^3 + y^3 + x*y*z + z^3 To: Elliptic Curve defined by y^2 + x*y = x^3 + 1 over Finite Field of size 3 Defn: Defined on coordinates by sending (x : y : z) to (y + z : -y : x)
>>> from sage.all import * >>> K = GF(Integer(3)) >>> R = K['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> cubic = x**Integer(3) + y**Integer(3) + z**Integer(3) + x*y*z >>> EllipticCurve_from_cubic(cubic, [Integer(0),Integer(1),-Integer(1)]) Scheme morphism: From: Projective Plane Curve over Finite Field of size 3 defined by x^3 + y^3 + x*y*z + z^3 To: Elliptic Curve defined by y^2 + x*y = x^3 + 1 over Finite Field of size 3 Defn: Defined on coordinates by sending (x : y : z) to (y + z : -y : x)
K = GF(3) R.<x,y,z> = K[] cubic = x^3 + y^3 + z^3 + x*y*z EllipticCurve_from_cubic(cubic, [0,1,-1])
An example over a number field, using a non-flex and where there are no rational flexes:
sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-3) sage: R.<x,y,z> = K[] sage: cubic = 2*x^3 + 3*y^3 + 5*z^3 sage: EllipticCurve_from_cubic(cubic, [1,1,-1]) Scheme morphism: From: Projective Plane Curve over Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I defined by 2*x^3 + 3*y^3 + 5*z^3 To: Elliptic Curve defined by y^2 + 1754460/2053*x*y + 5226454388736000/8653002877*y = x^3 + (-652253285700/4214809)*x^2 over Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I Defn: Defined on coordinates by sending (x : y : z) to (-16424/127575*x^2 - 231989/680400*x*y - 14371/64800*y^2 - 26689/81648*x*z - 10265/27216*y*z - 2053/163296*z^2 : 24496/315*x^2 + 119243/840*x*y + 4837/80*y^2 + 67259/504*x*z + 25507/168*y*z + 5135/1008*z^2 : 8653002877/2099914709760000*x^2 + 8653002877/699971569920000*x*y + 8653002877/933295426560000*y^2 + 8653002877/419982941952000*x*z + 8653002877/279988627968000*y*z + 8653002877/335986353561600*z^2)
>>> from sage.all import * >>> # needs sage.rings.number_field >>> K = QuadraticField(-Integer(3), names=('a',)); (a,) = K._first_ngens(1) >>> R = K['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> cubic = Integer(2)*x**Integer(3) + Integer(3)*y**Integer(3) + Integer(5)*z**Integer(3) >>> EllipticCurve_from_cubic(cubic, [Integer(1),Integer(1),-Integer(1)]) Scheme morphism: From: Projective Plane Curve over Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I defined by 2*x^3 + 3*y^3 + 5*z^3 To: Elliptic Curve defined by y^2 + 1754460/2053*x*y + 5226454388736000/8653002877*y = x^3 + (-652253285700/4214809)*x^2 over Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I Defn: Defined on coordinates by sending (x : y : z) to (-16424/127575*x^2 - 231989/680400*x*y - 14371/64800*y^2 - 26689/81648*x*z - 10265/27216*y*z - 2053/163296*z^2 : 24496/315*x^2 + 119243/840*x*y + 4837/80*y^2 + 67259/504*x*z + 25507/168*y*z + 5135/1008*z^2 : 8653002877/2099914709760000*x^2 + 8653002877/699971569920000*x*y + 8653002877/933295426560000*y^2 + 8653002877/419982941952000*x*z + 8653002877/279988627968000*y*z + 8653002877/335986353561600*z^2)
# needs sage.rings.number_field K.<a> = QuadraticField(-3) R.<x,y,z> = K[] cubic = 2*x^3 + 3*y^3 + 5*z^3 EllipticCurve_from_cubic(cubic, [1,1,-1])
An example over a function field, using a non-flex:
sage: K.<t> = FunctionField(QQ) sage: R.<x,y,z> = K[] sage: cubic = x^3 + t*y^3 + (1+t)*z^3 sage: EllipticCurve_from_cubic(cubic, [1,1,-1], morphism=False) # needs sage.libs.singular Elliptic Curve defined by y^2 + ((162*t^6+486*t^5+810*t^4+810*t^3+486*t^2+162*t)/(t^6+12*t^5-3*t^4-20*t^3-3*t^2+12*t+1))*x*y + ((314928*t^14+4094064*t^13+23462136*t^12+78102144*t^11+167561379*t^10+243026001*t^9+243026001*t^8+167561379*t^7+78102144*t^6+23462136*t^5+4094064*t^4+314928*t^3)/(t^14+40*t^13+577*t^12+3524*t^11+8075*t^10+5288*t^9-8661*t^8-17688*t^7-8661*t^6+5288*t^5+8075*t^4+3524*t^3+577*t^2+40*t+1))*y = x^3 + ((2187*t^12+13122*t^11-17496*t^10-207765*t^9-516132*t^8-673596*t^7-516132*t^6-207765*t^5-17496*t^4+13122*t^3+2187*t^2)/(t^12+24*t^11+138*t^10-112*t^9-477*t^8+72*t^7+708*t^6+72*t^5-477*t^4-112*t^3+138*t^2+24*t+1))*x^2 over Rational function field in t over Rational Field
>>> from sage.all import * >>> K = FunctionField(QQ, names=('t',)); (t,) = K._first_ngens(1) >>> R = K['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> cubic = x**Integer(3) + t*y**Integer(3) + (Integer(1)+t)*z**Integer(3) >>> EllipticCurve_from_cubic(cubic, [Integer(1),Integer(1),-Integer(1)], morphism=False) # needs sage.libs.singular Elliptic Curve defined by y^2 + ((162*t^6+486*t^5+810*t^4+810*t^3+486*t^2+162*t)/(t^6+12*t^5-3*t^4-20*t^3-3*t^2+12*t+1))*x*y + ((314928*t^14+4094064*t^13+23462136*t^12+78102144*t^11+167561379*t^10+243026001*t^9+243026001*t^8+167561379*t^7+78102144*t^6+23462136*t^5+4094064*t^4+314928*t^3)/(t^14+40*t^13+577*t^12+3524*t^11+8075*t^10+5288*t^9-8661*t^8-17688*t^7-8661*t^6+5288*t^5+8075*t^4+3524*t^3+577*t^2+40*t+1))*y = x^3 + ((2187*t^12+13122*t^11-17496*t^10-207765*t^9-516132*t^8-673596*t^7-516132*t^6-207765*t^5-17496*t^4+13122*t^3+2187*t^2)/(t^12+24*t^11+138*t^10-112*t^9-477*t^8+72*t^7+708*t^6+72*t^5-477*t^4-112*t^3+138*t^2+24*t+1))*x^2 over Rational function field in t over Rational Field
K.<t> = FunctionField(QQ) R.<x,y,z> = K[] cubic = x^3 + t*y^3 + (1+t)*z^3 EllipticCurve_from_cubic(cubic, [1,1,-1], morphism=False) # needs sage.libs.singular
- sage.schemes.elliptic_curves.constructor.EllipticCurve_from_j(j, minimal_twist=True)[source]¶
Return an elliptic curve with given \(j\)-invariant.
INPUT:
j
– an element of some fieldminimal_twist
– boolean (default:True
); ifTrue
andj
is in \(\QQ\), the curve returned is a minimal twist, i.e. has minimal conductor; when there is more than one curve with minimal conductor, the curve returned is the one whose label comes first if the curves are in the CremonaDatabase, otherwise the one whose minimal a-invariants are first lexicographically. If \(j\) is not in \(\QQ\) this parameter is ignored.
OUTPUT: an elliptic curve with \(j\)-invariant \(j\)
EXAMPLES:
sage: E = EllipticCurve_from_j(0); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 + y = x^3 over Rational Field 0 '27a3' sage: E = EllipticCurve_from_j(1728); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 = x^3 - x over Rational Field 1728 '32a2' sage: E = EllipticCurve_from_j(1); E; E.j_invariant() Elliptic Curve defined by y^2 + x*y = x^3 + 36*x + 3455 over Rational Field 1
>>> from sage.all import * >>> E = EllipticCurve_from_j(Integer(0)); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 + y = x^3 over Rational Field 0 '27a3' >>> E = EllipticCurve_from_j(Integer(1728)); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 = x^3 - x over Rational Field 1728 '32a2' >>> E = EllipticCurve_from_j(Integer(1)); E; E.j_invariant() Elliptic Curve defined by y^2 + x*y = x^3 + 36*x + 3455 over Rational Field 1
E = EllipticCurve_from_j(0); E; E.j_invariant(); E.label() E = EllipticCurve_from_j(1728); E; E.j_invariant(); E.label() E = EllipticCurve_from_j(1); E; E.j_invariant()
The
minimal_twist
parameter (ignored except over \(\QQ\) andTrue
by default) controls whether or not a minimal twist is computed:sage: EllipticCurve_from_j(100) Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field sage: _.conductor() 33129800 sage: EllipticCurve_from_j(100, minimal_twist=False) Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field sage: _.conductor() 298168200
>>> from sage.all import * >>> EllipticCurve_from_j(Integer(100)) Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field >>> _.conductor() 33129800 >>> EllipticCurve_from_j(Integer(100), minimal_twist=False) Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field >>> _.conductor() 298168200
EllipticCurve_from_j(100) _.conductor() EllipticCurve_from_j(100, minimal_twist=False) _.conductor()
Since computing the minimal twist requires factoring both \(j\) and \(j-1728\) the following example would take a long time without setting
minimal_twist
to False:sage: E = EllipticCurve_from_j(2^256+1, minimal_twist=False) sage: E.j_invariant() == 2^256+1 True
>>> from sage.all import * >>> E = EllipticCurve_from_j(Integer(2)**Integer(256)+Integer(1), minimal_twist=False) >>> E.j_invariant() == Integer(2)**Integer(256)+Integer(1) True
E = EllipticCurve_from_j(2^256+1, minimal_twist=False) E.j_invariant() == 2^256+1
- sage.schemes.elliptic_curves.constructor.EllipticCurves_with_good_reduction_outside_S(S=[], proof=None, verbose=False)[source]¶
Return a sorted list of all elliptic curves defined over \(\QQ\) with good reduction outside the set \(S\) of primes.
INPUT:
S
– list of primes (default: empty list)proof
– boolean (default:True
); the MW basis for auxiliary curves will be computed with this proof flagverbose
– boolean (default:False
); ifTrue
, some details of the computation will be output
Note
Proof flag: The algorithm used requires determining all S-integral points on several auxiliary curves, which in turn requires the computation of their generators. This is not always possible (even in theory) using current knowledge.
The value of this flag is passed to the function which computes generators of various auxiliary elliptic curves, in order to find their S-integral points. Set to
False
if the default (True
) causes warning messages, but note that you can then not rely on the set of curves returned being complete.EXAMPLES:
sage: EllipticCurves_with_good_reduction_outside_S([]) [] sage: elist = EllipticCurves_with_good_reduction_outside_S([2]) sage: elist [Elliptic Curve defined by y^2 = x^3 + 4*x over Rational Field, Elliptic Curve defined by y^2 = x^3 - x over Rational Field, ... Elliptic Curve defined by y^2 = x^3 - x^2 - 13*x + 21 over Rational Field] sage: len(elist) 24 sage: ', '.join(e.label() for e in elist) '32a1, 32a2, 32a3, 32a4, 64a1, 64a2, 64a3, 64a4, 128a1, 128a2, 128b1, 128b2, 128c1, 128c2, 128d1, 128d2, 256a1, 256a2, 256b1, 256b2, 256c1, 256c2, 256d1, 256d2'
>>> from sage.all import * >>> EllipticCurves_with_good_reduction_outside_S([]) [] >>> elist = EllipticCurves_with_good_reduction_outside_S([Integer(2)]) >>> elist [Elliptic Curve defined by y^2 = x^3 + 4*x over Rational Field, Elliptic Curve defined by y^2 = x^3 - x over Rational Field, ... Elliptic Curve defined by y^2 = x^3 - x^2 - 13*x + 21 over Rational Field] >>> len(elist) 24 >>> ', '.join(e.label() for e in elist) '32a1, 32a2, 32a3, 32a4, 64a1, 64a2, 64a3, 64a4, 128a1, 128a2, 128b1, 128b2, 128c1, 128c2, 128d1, 128d2, 256a1, 256a2, 256b1, 256b2, 256c1, 256c2, 256d1, 256d2'
EllipticCurves_with_good_reduction_outside_S([]) elist = EllipticCurves_with_good_reduction_outside_S([2]) elist len(elist) ', '.join(e.label() for e in elist)
Without
Proof=False
, this example gives two warnings:sage: elist = EllipticCurves_with_good_reduction_outside_S([11], proof=False) # long time (14s on sage.math, 2011) sage: len(elist) # long time 12 sage: ', '.join(e.label() for e in elist) # long time '11a1, 11a2, 11a3, 121a1, 121a2, 121b1, 121b2, 121c1, 121c2, 121d1, 121d2, 121d3' sage: # long time sage: elist = EllipticCurves_with_good_reduction_outside_S([2,3]) # long time (26s on sage.math, 2011) sage: len(elist) 752 sage: conds = sorted(set([e.conductor() for e in elist])) sage: max(conds) 62208 sage: [N.factor() for N in conds] [2^3 * 3, 3^3, 2^5, 2^2 * 3^2, 2^4 * 3, 2 * 3^3, 2^6, 2^3 * 3^2, 2^5 * 3, 2^2 * 3^3, 2^7, 2^4 * 3^2, 2 * 3^4, 2^6 * 3, 2^3 * 3^3, 3^5, 2^8, 2^5 * 3^2, 2^2 * 3^4, 2^7 * 3, 2^4 * 3^3, 2 * 3^5, 2^6 * 3^2, 2^3 * 3^4, 2^8 * 3, 2^5 * 3^3, 2^2 * 3^5, 2^7 * 3^2, 2^4 * 3^4, 2^6 * 3^3, 2^3 * 3^5, 2^8 * 3^2, 2^5 * 3^4, 2^7 * 3^3, 2^4 * 3^5, 2^6 * 3^4, 2^8 * 3^3, 2^5 * 3^5, 2^7 * 3^4, 2^6 * 3^5, 2^8 * 3^4, 2^7 * 3^5, 2^8 * 3^5]
>>> from sage.all import * >>> elist = EllipticCurves_with_good_reduction_outside_S([Integer(11)], proof=False) # long time (14s on sage.math, 2011) >>> len(elist) # long time 12 >>> ', '.join(e.label() for e in elist) # long time '11a1, 11a2, 11a3, 121a1, 121a2, 121b1, 121b2, 121c1, 121c2, 121d1, 121d2, 121d3' >>> # long time >>> elist = EllipticCurves_with_good_reduction_outside_S([Integer(2),Integer(3)]) # long time (26s on sage.math, 2011) >>> len(elist) 752 >>> conds = sorted(set([e.conductor() for e in elist])) >>> max(conds) 62208 >>> [N.factor() for N in conds] [2^3 * 3, 3^3, 2^5, 2^2 * 3^2, 2^4 * 3, 2 * 3^3, 2^6, 2^3 * 3^2, 2^5 * 3, 2^2 * 3^3, 2^7, 2^4 * 3^2, 2 * 3^4, 2^6 * 3, 2^3 * 3^3, 3^5, 2^8, 2^5 * 3^2, 2^2 * 3^4, 2^7 * 3, 2^4 * 3^3, 2 * 3^5, 2^6 * 3^2, 2^3 * 3^4, 2^8 * 3, 2^5 * 3^3, 2^2 * 3^5, 2^7 * 3^2, 2^4 * 3^4, 2^6 * 3^3, 2^3 * 3^5, 2^8 * 3^2, 2^5 * 3^4, 2^7 * 3^3, 2^4 * 3^5, 2^6 * 3^4, 2^8 * 3^3, 2^5 * 3^5, 2^7 * 3^4, 2^6 * 3^5, 2^8 * 3^4, 2^7 * 3^5, 2^8 * 3^5]
elist = EllipticCurves_with_good_reduction_outside_S([11], proof=False) # long time (14s on sage.math, 2011) len(elist) # long time ', '.join(e.label() for e in elist) # long time # long time elist = EllipticCurves_with_good_reduction_outside_S([2,3]) # long time (26s on sage.math, 2011) len(elist) conds = sorted(set([e.conductor() for e in elist])) max(conds) [N.factor() for N in conds]
- sage.schemes.elliptic_curves.constructor.are_projectively_equivalent(P, Q, base_ring)[source]¶
Test whether
P
andQ
are projectively equivalent.INPUT:
P
,Q
– list/tuple of projective coordinatesbase_ring
– the base ring
OUTPUT: boolean
EXAMPLES:
sage: from sage.schemes.elliptic_curves.constructor import are_projectively_equivalent sage: are_projectively_equivalent([0,1,2,3], [0,1,2,2], base_ring=QQ) False sage: are_projectively_equivalent([0,1,2,3], [0,2,4,6], base_ring=QQ) True
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.constructor import are_projectively_equivalent >>> are_projectively_equivalent([Integer(0),Integer(1),Integer(2),Integer(3)], [Integer(0),Integer(1),Integer(2),Integer(2)], base_ring=QQ) False >>> are_projectively_equivalent([Integer(0),Integer(1),Integer(2),Integer(3)], [Integer(0),Integer(2),Integer(4),Integer(6)], base_ring=QQ) True
from sage.schemes.elliptic_curves.constructor import are_projectively_equivalent are_projectively_equivalent([0,1,2,3], [0,1,2,2], base_ring=QQ) are_projectively_equivalent([0,1,2,3], [0,2,4,6], base_ring=QQ)
- sage.schemes.elliptic_curves.constructor.chord_and_tangent(F, P)[source]¶
Return the third point of intersection of a cubic with the tangent at one point.
INPUT:
F
– a homogeneous cubic in three variables with rational coefficients, as a polynomial ring element, defining a smooth plane cubic curve.P
– a 3-tuple \((x,y,z)\) defining a projective point on the curve \(F=0\)
OUTPUT:
A point
Q
such thatF(Q)=0
, namely the third point of intersection of the tangent atP
with the curveF=0
, soQ=P
if and only ifP
is a flex.EXAMPLES:
sage: R.<x,y,z> = QQ[] sage: from sage.schemes.elliptic_curves.constructor import chord_and_tangent sage: F = x^3 + y^3 + 60*z^3 sage: chord_and_tangent(F, [1,-1,0]) (-1 : 1 : 0) sage: F = x^3 + 7*y^3 + 64*z^3 sage: p0 = [2,2,-1] sage: p1 = chord_and_tangent(F, p0); p1 (5 : -3 : 1) sage: p2 = chord_and_tangent(F, p1); p2 (-1265/314 : 183/314 : 1)
>>> from sage.all import * >>> R = QQ['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> from sage.schemes.elliptic_curves.constructor import chord_and_tangent >>> F = x**Integer(3) + y**Integer(3) + Integer(60)*z**Integer(3) >>> chord_and_tangent(F, [Integer(1),-Integer(1),Integer(0)]) (-1 : 1 : 0) >>> F = x**Integer(3) + Integer(7)*y**Integer(3) + Integer(64)*z**Integer(3) >>> p0 = [Integer(2),Integer(2),-Integer(1)] >>> p1 = chord_and_tangent(F, p0); p1 (5 : -3 : 1) >>> p2 = chord_and_tangent(F, p1); p2 (-1265/314 : 183/314 : 1)
R.<x,y,z> = QQ[] from sage.schemes.elliptic_curves.constructor import chord_and_tangent F = x^3 + y^3 + 60*z^3 chord_and_tangent(F, [1,-1,0]) F = x^3 + 7*y^3 + 64*z^3 p0 = [2,2,-1] p1 = chord_and_tangent(F, p0); p1 p2 = chord_and_tangent(F, p1); p2
- sage.schemes.elliptic_curves.constructor.coefficients_from_Weierstrass_polynomial(f)[source]¶
Return the coefficients \([a_1, a_2, a_3, a_4, a_6]\) of a cubic in Weierstrass form.
EXAMPLES:
sage: from sage.schemes.elliptic_curves.constructor import coefficients_from_Weierstrass_polynomial sage: R.<w,z> = QQ[] sage: coefficients_from_Weierstrass_polynomial(-w^2 + z^3 + 1) [0, 0, 0, 0, 1]
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.constructor import coefficients_from_Weierstrass_polynomial >>> R = QQ['w, z']; (w, z,) = R._first_ngens(2) >>> coefficients_from_Weierstrass_polynomial(-w**Integer(2) + z**Integer(3) + Integer(1)) [0, 0, 0, 0, 1]
from sage.schemes.elliptic_curves.constructor import coefficients_from_Weierstrass_polynomial R.<w,z> = QQ[] coefficients_from_Weierstrass_polynomial(-w^2 + z^3 + 1)
- sage.schemes.elliptic_curves.constructor.coefficients_from_j(j, minimal_twist=True)[source]¶
Return Weierstrass coefficients \((a_1, a_2, a_3, a_4, a_6)\) for an elliptic curve with given \(j\)-invariant.
INPUT: See
EllipticCurve_from_j()
.EXAMPLES:
sage: from sage.schemes.elliptic_curves.constructor import coefficients_from_j sage: coefficients_from_j(0) [0, 0, 1, 0, 0] sage: coefficients_from_j(1728) [0, 0, 0, -1, 0] sage: coefficients_from_j(1) [1, 0, 0, 36, 3455]
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.constructor import coefficients_from_j >>> coefficients_from_j(Integer(0)) [0, 0, 1, 0, 0] >>> coefficients_from_j(Integer(1728)) [0, 0, 0, -1, 0] >>> coefficients_from_j(Integer(1)) [1, 0, 0, 36, 3455]
from sage.schemes.elliptic_curves.constructor import coefficients_from_j coefficients_from_j(0) coefficients_from_j(1728) coefficients_from_j(1)
The
minimal_twist
parameter (ignored except over \(\QQ\) andTrue
by default) controls whether or not a minimal twist is computed:sage: coefficients_from_j(100) [0, 1, 0, 3392, 307888] sage: coefficients_from_j(100, minimal_twist=False) [0, 0, 0, 488400, -530076800]
>>> from sage.all import * >>> coefficients_from_j(Integer(100)) [0, 1, 0, 3392, 307888] >>> coefficients_from_j(Integer(100), minimal_twist=False) [0, 0, 0, 488400, -530076800]
coefficients_from_j(100) coefficients_from_j(100, minimal_twist=False)
- sage.schemes.elliptic_curves.constructor.projective_point(p)[source]¶
Return equivalent point with denominators removed.
INPUT:
P
,Q
– list/tuple of projective coordinates
OUTPUT: list of projective coordinates
EXAMPLES:
sage: from sage.schemes.elliptic_curves.constructor import projective_point sage: projective_point([4/5, 6/5, 8/5]) [2, 3, 4] sage: F = GF(11) sage: projective_point([F(4), F(8), F(2)]) [4, 8, 2]
>>> from sage.all import * >>> from sage.schemes.elliptic_curves.constructor import projective_point >>> projective_point([Integer(4)/Integer(5), Integer(6)/Integer(5), Integer(8)/Integer(5)]) [2, 3, 4] >>> F = GF(Integer(11)) >>> projective_point([F(Integer(4)), F(Integer(8)), F(Integer(2))]) [4, 8, 2]
from sage.schemes.elliptic_curves.constructor import projective_point projective_point([4/5, 6/5, 8/5]) F = GF(11) projective_point([F(4), F(8), F(2)])
- sage.schemes.elliptic_curves.constructor.tangent_at_smooth_point(C, P)[source]¶
Return the tangent at the smooth point \(P\) of projective curve \(C\).
INPUT:
C
– a projective plane curveP
– a 3-tuple \((x,y,z)\) defining a projective point on \(C\)
OUTPUT: the linear form defining the tangent at \(P\) to \(C\)
EXAMPLES:
sage: R.<x,y,z> = QQ[] sage: from sage.schemes.elliptic_curves.constructor import tangent_at_smooth_point sage: C = Curve(x^3 + y^3 + 60*z^3) sage: tangent_at_smooth_point(C, [1,-1,0]) x + y sage: K.<t> = FunctionField(QQ) sage: R.<x,y,z> = K[] sage: C = Curve(x^3 + 2*y^3 + 3*z^3) sage: from sage.schemes.elliptic_curves.constructor import tangent_at_smooth_point sage: tangent_at_smooth_point(C,[1,1,-1]) 3*x + 6*y + 9*z
>>> from sage.all import * >>> R = QQ['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> from sage.schemes.elliptic_curves.constructor import tangent_at_smooth_point >>> C = Curve(x**Integer(3) + y**Integer(3) + Integer(60)*z**Integer(3)) >>> tangent_at_smooth_point(C, [Integer(1),-Integer(1),Integer(0)]) x + y >>> K = FunctionField(QQ, names=('t',)); (t,) = K._first_ngens(1) >>> R = K['x, y, z']; (x, y, z,) = R._first_ngens(3) >>> C = Curve(x**Integer(3) + Integer(2)*y**Integer(3) + Integer(3)*z**Integer(3)) >>> from sage.schemes.elliptic_curves.constructor import tangent_at_smooth_point >>> tangent_at_smooth_point(C,[Integer(1),Integer(1),-Integer(1)]) 3*x + 6*y + 9*z
R.<x,y,z> = QQ[] from sage.schemes.elliptic_curves.constructor import tangent_at_smooth_point C = Curve(x^3 + y^3 + 60*z^3) tangent_at_smooth_point(C, [1,-1,0]) K.<t> = FunctionField(QQ) R.<x,y,z> = K[] C = Curve(x^3 + 2*y^3 + 3*z^3) from sage.schemes.elliptic_curves.constructor import tangent_at_smooth_point tangent_at_smooth_point(C,[1,1,-1])