Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/elliptic_curves/constructor.py
8820 views
1
"""
2
Elliptic curve constructor
3
4
AUTHORS:
5
6
- William Stein (2005): Initial version
7
8
- John Cremona (2008-01): EllipticCurve(j) fixed for all cases
9
"""
10
11
#*****************************************************************************
12
# Copyright (C) 2005 William Stein <[email protected]>
13
#
14
# Distributed under the terms of the GNU General Public License (GPL)
15
#
16
# This code is distributed in the hope that it will be useful,
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
# General Public License for more details.
20
#
21
# The full text of the GPL is available at:
22
#
23
# http://www.gnu.org/licenses/
24
#*****************************************************************************
25
26
27
import sage.rings.all as rings
28
29
from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing
30
from sage.rings.rational_field import is_RationalField
31
from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing
32
from sage.rings.finite_rings.constructor import is_FiniteField
33
from sage.rings.number_field.number_field import is_NumberField
34
from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial
35
from sage.rings.ring import is_Ring
36
from sage.rings.ring_element import is_RingElement
37
38
from sage.categories.fields import Fields
39
_Fields = Fields()
40
41
from sage.structure.sequence import Sequence
42
from sage.structure.element import parent
43
from sage.symbolic.ring import SR
44
from sage.symbolic.expression import is_SymbolicEquation
45
46
47
def EllipticCurve(x=None, y=None, j=None, minimal_twist=True):
48
r"""
49
Construct an elliptic curve.
50
51
In Sage, an elliptic curve is always specified by its a-invariants
52
53
.. math::
54
55
y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6.
56
57
INPUT:
58
59
There are several ways to construct an elliptic curve:
60
61
- ``EllipticCurve([a1,a2,a3,a4,a6])``: Elliptic curve with given
62
a-invariants. The invariants are coerced into the parent of the
63
first element. If all are integers, they are coerced into the
64
rational numbers.
65
66
- ``EllipticCurve([a4,a6])``: Same as above, but `a_1=a_2=a_3=0`.
67
68
- ``EllipticCurve(label)``: Returns the elliptic curve over Q from
69
the Cremona database with the given label. The label is a
70
string, such as ``"11a"`` or ``"37b2"``. The letters in the
71
label *must* be lower case (Cremona's new labeling).
72
73
- ``EllipticCurve(R, [a1,a2,a3,a4,a6])``: Create the elliptic
74
curve over ``R`` with given a-invariants. Here ``R`` can be an
75
arbitrary ring. Note that addition need not be defined.
76
77
- ``EllipticCurve(j=j0)`` or ``EllipticCurve_from_j(j0)``: Return
78
an elliptic curve with j-invariant ``j0``.
79
80
- ``EllipticCurve(polynomial)``: Read off the a-invariants from
81
the polynomial coefficients, see
82
:func:`EllipticCurve_from_Weierstrass_polynomial`.
83
84
In each case above where the input is a list of length 2 or 5, one
85
can instead give a 2 or 5-tuple instead.
86
87
EXAMPLES:
88
89
We illustrate creating elliptic curves::
90
91
sage: EllipticCurve([0,0,1,-1,0])
92
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
93
94
We create a curve from a Cremona label::
95
96
sage: EllipticCurve('37b2')
97
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field
98
sage: EllipticCurve('5077a')
99
Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field
100
sage: EllipticCurve('389a')
101
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
102
103
Old Cremona labels are allowed::
104
105
sage: EllipticCurve('2400FF')
106
Elliptic Curve defined by y^2 = x^3 + x^2 + 2*x + 8 over Rational Field
107
108
Unicode labels are allowed::
109
110
sage: EllipticCurve(u'389a')
111
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
112
113
We create curves over a finite field as follows::
114
115
sage: EllipticCurve([GF(5)(0),0,1,-1,0])
116
Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5
117
sage: EllipticCurve(GF(5), [0, 0,1,-1,0])
118
Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5
119
120
Elliptic curves over `\ZZ/N\ZZ` with `N` prime are of type
121
"elliptic curve over a finite field"::
122
123
sage: F = Zmod(101)
124
sage: EllipticCurve(F, [2, 3])
125
Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101
126
sage: E = EllipticCurve([F(2), F(3)])
127
sage: type(E)
128
<class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'>
129
sage: E.category()
130
Category of schemes over Ring of integers modulo 101
131
132
In contrast, elliptic curves over `\ZZ/N\ZZ` with `N` composite
133
are of type "generic elliptic curve"::
134
135
sage: F = Zmod(95)
136
sage: EllipticCurve(F, [2, 3])
137
Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95
138
sage: E = EllipticCurve([F(2), F(3)])
139
sage: type(E)
140
<class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'>
141
sage: E.category()
142
Category of schemes over Ring of integers modulo 95
143
144
The following is a curve over the complex numbers::
145
146
sage: E = EllipticCurve(CC, [0,0,1,-1,0])
147
sage: E
148
Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision
149
sage: E.j_invariant()
150
2988.97297297297
151
152
We can also create elliptic curves by giving the Weierstrass equation::
153
154
sage: x, y = var('x,y')
155
sage: EllipticCurve(y^2 + y == x^3 + x - 9)
156
Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field
157
158
sage: R.<x,y> = GF(5)[]
159
sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x)
160
Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5
161
162
We can explicitly specify the `j`-invariant::
163
164
sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.label()
165
Elliptic Curve defined by y^2 = x^3 - x over Rational Field
166
1728
167
'32a2'
168
169
sage: E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant()
170
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5
171
2
172
173
See :trac:`6657` ::
174
175
sage: EllipticCurve(GF(144169),j=1728)
176
Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169
177
178
By default, when a rational value of `j` is given, the constructed
179
curve is a minimal twist (minimal conductor for curves with that
180
`j`-invariant). This can be changed by setting the optional
181
parameter ``minimal_twist``, which is True by default, to False::
182
183
184
sage: EllipticCurve(j=100)
185
Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field
186
sage: E =EllipticCurve(j=100); E
187
Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field
188
sage: E.conductor()
189
33129800
190
sage: E.j_invariant()
191
100
192
sage: E =EllipticCurve(j=100, minimal_twist=False); E
193
Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field
194
sage: E.conductor()
195
298168200
196
sage: E.j_invariant()
197
100
198
199
Without this option, constructing the curve could take a long time
200
since both `j` and `j-1728` have to be factored to compute the
201
minimal twist (see :trac:`13100`)::
202
203
sage: E = EllipticCurve_from_j(2^256+1,minimal_twist=False)
204
sage: E.j_invariant() == 2^256+1
205
True
206
207
TESTS::
208
209
sage: R = ZZ['u', 'v']
210
sage: EllipticCurve(R, [1,1])
211
Elliptic Curve defined by y^2 = x^3 + x + 1 over Multivariate Polynomial Ring in u, v
212
over Integer Ring
213
214
We create a curve and a point over QQbar (see #6879)::
215
216
sage: E = EllipticCurve(QQbar,[0,1])
217
sage: E(0)
218
(0 : 1 : 0)
219
sage: E.base_field()
220
Algebraic Field
221
222
sage: E = EllipticCurve(RR,[1,2]); E; E.base_field()
223
Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision
224
Real Field with 53 bits of precision
225
sage: EllipticCurve(CC,[3,4]); E; E.base_field()
226
Elliptic Curve defined by y^2 = x^3 + 3.00000000000000*x + 4.00000000000000 over Complex Field with 53 bits of precision
227
Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision
228
Real Field with 53 bits of precision
229
sage: E = EllipticCurve(QQbar,[5,6]); E; E.base_field()
230
Elliptic Curve defined by y^2 = x^3 + 5*x + 6 over Algebraic Field
231
Algebraic Field
232
233
See :trac:`6657` ::
234
235
sage: EllipticCurve(3,j=1728)
236
Traceback (most recent call last):
237
...
238
ValueError: First parameter (if present) must be a ring when j is specified
239
240
sage: EllipticCurve(GF(5),j=3/5)
241
Traceback (most recent call last):
242
...
243
ValueError: First parameter must be a ring containing 3/5
244
245
If the universe of the coefficients is a general field, the object
246
constructed has type EllipticCurve_field. Otherwise it is
247
EllipticCurve_generic. See :trac:`9816` ::
248
249
sage: E = EllipticCurve([QQbar(1),3]); E
250
Elliptic Curve defined by y^2 = x^3 + x + 3 over Algebraic Field
251
sage: type(E)
252
<class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>
253
254
sage: E = EllipticCurve([RR(1),3]); E
255
Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 3.00000000000000 over Real Field with 53 bits of precision
256
sage: type(E)
257
<class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>
258
259
sage: E = EllipticCurve([i,i]); E
260
Elliptic Curve defined by y^2 = x^3 + I*x + I over Symbolic Ring
261
sage: type(E)
262
<class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>
263
sage: E.category()
264
Category of schemes over Symbolic Ring
265
sage: SR in Fields()
266
True
267
268
sage: F = FractionField(PolynomialRing(QQ,'t'))
269
sage: t = F.gen()
270
sage: E = EllipticCurve([t,0]); E
271
Elliptic Curve defined by y^2 = x^3 + t*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field
272
sage: type(E)
273
<class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>
274
sage: E.category()
275
Category of schemes over Fraction Field of Univariate Polynomial Ring in t over Rational Field
276
277
See :trac:`12517`::
278
279
sage: E = EllipticCurve([1..5])
280
sage: EllipticCurve(E.a_invariants())
281
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
282
283
See :trac:`11773`::
284
285
sage: E = EllipticCurve()
286
Traceback (most recent call last):
287
...
288
TypeError: invalid input to EllipticCurve constructor
289
290
"""
291
import ell_generic, ell_field, ell_finite_field, ell_number_field, ell_rational_field, ell_padic_field # here to avoid circular includes
292
293
if j is not None:
294
if not x is None:
295
if is_Ring(x):
296
try:
297
j = x(j)
298
except (ZeroDivisionError, ValueError, TypeError):
299
raise ValueError, "First parameter must be a ring containing %s"%j
300
else:
301
raise ValueError, "First parameter (if present) must be a ring when j is specified"
302
return EllipticCurve_from_j(j, minimal_twist)
303
304
if x is None:
305
raise TypeError, "invalid input to EllipticCurve constructor"
306
307
if is_SymbolicEquation(x):
308
x = x.lhs() - x.rhs()
309
310
if parent(x) is SR:
311
x = x._polynomial_(rings.QQ['x', 'y'])
312
313
if is_MPolynomial(x):
314
if y is None:
315
return EllipticCurve_from_Weierstrass_polynomial(x)
316
else:
317
return EllipticCurve_from_cubic(x, y, morphism=False)
318
319
if is_Ring(x):
320
if is_RationalField(x):
321
return ell_rational_field.EllipticCurve_rational_field(x, y)
322
elif is_FiniteField(x) or (is_IntegerModRing(x) and x.characteristic().is_prime()):
323
return ell_finite_field.EllipticCurve_finite_field(x, y)
324
elif rings.is_pAdicField(x):
325
return ell_padic_field.EllipticCurve_padic_field(x, y)
326
elif is_NumberField(x):
327
return ell_number_field.EllipticCurve_number_field(x, y)
328
elif x in _Fields:
329
return ell_field.EllipticCurve_field(x, y)
330
return ell_generic.EllipticCurve_generic(x, y)
331
332
if isinstance(x, unicode):
333
x = str(x)
334
335
if isinstance(x, basestring):
336
return ell_rational_field.EllipticCurve_rational_field(x)
337
338
if is_RingElement(x) and y is None:
339
raise TypeError, "invalid input to EllipticCurve constructor"
340
341
if not isinstance(x, (list, tuple)):
342
raise TypeError, "invalid input to EllipticCurve constructor"
343
344
x = Sequence(x)
345
if not (len(x) in [2,5]):
346
raise ValueError, "sequence of coefficients must have length 2 or 5"
347
R = x.universe()
348
349
if isinstance(x[0], (rings.Rational, rings.Integer, int, long)):
350
return ell_rational_field.EllipticCurve_rational_field(x, y)
351
352
elif is_NumberField(R):
353
return ell_number_field.EllipticCurve_number_field(x, y)
354
355
elif rings.is_pAdicField(R):
356
return ell_padic_field.EllipticCurve_padic_field(x, y)
357
358
elif is_FiniteField(R) or (is_IntegerModRing(R) and R.characteristic().is_prime()):
359
return ell_finite_field.EllipticCurve_finite_field(x, y)
360
361
elif R in _Fields:
362
return ell_field.EllipticCurve_field(x, y)
363
364
return ell_generic.EllipticCurve_generic(x, y)
365
366
367
368
def EllipticCurve_from_Weierstrass_polynomial(f):
369
"""
370
Return the elliptic curve defined by a cubic in (long) Weierstrass
371
form.
372
373
INPUT:
374
375
- ``f`` -- a inhomogeneous cubic polynomial in long Weierstrass
376
form.
377
378
OUTPUT:
379
380
The elliptic curve defined by it.
381
382
EXAMPLES::
383
384
sage: R.<x,y> = QQ[]
385
sage: f = y^2 + 1*x*y + 3*y - (x^3 + 2*x^2 + 4*x + 6)
386
sage: EllipticCurve(f)
387
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 6 over Rational Field
388
sage: EllipticCurve(f).a_invariants()
389
(1, 2, 3, 4, 6)
390
391
The polynomial ring may have extra variables as long as they
392
do not occur in the polynomial itself::
393
394
sage: R.<x,y,z,w> = QQ[]
395
sage: EllipticCurve(-y^2 + x^3 + 1)
396
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
397
sage: EllipticCurve(-x^2 + y^3 + 1)
398
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
399
sage: EllipticCurve(-w^2 + z^3 + 1)
400
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
401
402
TESTS::
403
404
sage: from sage.schemes.elliptic_curves.constructor import EllipticCurve_from_Weierstrass_polynomial
405
sage: EllipticCurve_from_Weierstrass_polynomial(-w^2 + z^3 + 1)
406
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
407
"""
408
R = f.parent()
409
cubic_variables = [ x for x in R.gens() if f.degree(x) == 3 ]
410
quadratic_variables = [ y for y in R.gens() if f.degree(y) == 2 ]
411
try:
412
x = cubic_variables[0]
413
y = quadratic_variables[0]
414
except IndexError:
415
raise ValueError('polynomial is not in long Weierstrass form')
416
417
a1 = a2 = a3 = a4 = a6 = 0
418
x3 = y2 = None
419
for coeff, mon in f:
420
if mon == x**3:
421
x3 = coeff
422
elif mon == x**2:
423
a2 = coeff
424
elif mon == x:
425
a4 = coeff
426
elif mon == 1:
427
a6 = coeff
428
elif mon == y**2:
429
y2 = -coeff
430
elif mon == x*y:
431
a1 = -coeff
432
elif mon == y:
433
a3 = -coeff
434
else:
435
raise ValueError('polynomial is not in long Weierstrass form')
436
437
if x3 != y2:
438
raise ValueError('the coefficient of x^3 and -y^2 must be the same')
439
elif x3 != 1:
440
a1, a2, a3, a4, a6 = a1/x3, a2/x3, a3/x3, a4/x3, a6/x3
441
return EllipticCurve([a1, a2, a3, a4, a6])
442
443
444
def EllipticCurve_from_c4c6(c4, c6):
445
"""
446
Return an elliptic curve with given `c_4` and
447
`c_6` invariants.
448
449
EXAMPLES::
450
451
sage: E = EllipticCurve_from_c4c6(17, -2005)
452
sage: E
453
Elliptic Curve defined by y^2 = x^3 - 17/48*x + 2005/864 over Rational Field
454
sage: E.c_invariants()
455
(17, -2005)
456
"""
457
try:
458
K = c4.parent()
459
except AttributeError:
460
K = rings.RationalField()
461
if K not in _Fields:
462
K = K.fraction_field()
463
return EllipticCurve([-K(c4)/K(48), -K(c6)/K(864)])
464
465
466
def EllipticCurve_from_j(j, minimal_twist=True):
467
"""
468
Return an elliptic curve with given `j`-invariant.
469
470
INPUT:
471
472
- ``j`` -- an element of some field.
473
474
- ``minimal_twist`` (boolean, default True) -- If True and ``j`` is in `\QQ`, the curve returned is a
475
minimal twist, i.e. has minimal conductor. If `j` is not in `\QQ` this parameter is ignored.
476
477
OUTPUT:
478
479
An elliptic curve with `j`-invariant `j`.
480
481
EXAMPLES::
482
483
sage: E = EllipticCurve_from_j(0); E; E.j_invariant(); E.label()
484
Elliptic Curve defined by y^2 + y = x^3 over Rational Field
485
0
486
'27a3'
487
488
sage: E = EllipticCurve_from_j(1728); E; E.j_invariant(); E.label()
489
Elliptic Curve defined by y^2 = x^3 - x over Rational Field
490
1728
491
'32a2'
492
493
sage: E = EllipticCurve_from_j(1); E; E.j_invariant()
494
Elliptic Curve defined by y^2 + x*y = x^3 + 36*x + 3455 over Rational Field
495
1
496
497
The ``minimal_twist`` parameter (ignored except over `\QQ` and
498
True by default) controls whether or not a minimal twist is
499
computed::
500
501
sage: EllipticCurve_from_j(100)
502
Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field
503
sage: _.conductor()
504
33129800
505
sage: EllipticCurve_from_j(100, minimal_twist=False)
506
Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field
507
sage: _.conductor()
508
298168200
509
510
Since computing the minimal twist requires factoring both `j` and
511
`j-1728` the following example would take a long time without
512
setting ``minimal_twist`` to False::
513
514
sage: E = EllipticCurve_from_j(2^256+1,minimal_twist=False)
515
sage: E.j_invariant() == 2^256+1
516
True
517
518
"""
519
try:
520
K = j.parent()
521
except AttributeError:
522
K = rings.RationalField()
523
if K not in _Fields:
524
K = K.fraction_field()
525
526
char=K.characteristic()
527
if char==2:
528
if j == 0:
529
return EllipticCurve(K, [ 0, 0, 1, 0, 0 ])
530
else:
531
return EllipticCurve(K, [ 1, 0, 0, 0, 1/j ])
532
if char == 3:
533
if j==0:
534
return EllipticCurve(K, [ 0, 0, 0, 1, 0 ])
535
else:
536
return EllipticCurve(K, [ 0, j, 0, 0, -j**2 ])
537
538
if K is rings.RationalField():
539
# we construct the minimal twist, i.e. the curve with minimal
540
# conductor with this j_invariant:
541
if j == 0:
542
return EllipticCurve(K, [ 0, 0, 1, 0, 0 ]) # 27a3
543
if j == 1728:
544
return EllipticCurve(K, [ 0, 0, 0, -1, 0 ]) # 32a2
545
546
if not minimal_twist:
547
k=j-1728
548
return EllipticCurve(K, [0,0,0,-3*j*k, -2*j*k**2])
549
550
n = j.numerator()
551
m = n-1728*j.denominator()
552
a4 = -3*n*m
553
a6 = -2*n*m**2
554
555
# Now E=[0,0,0,a4,a6] has j-invariant j=n/d
556
from sage.sets.set import Set
557
for p in Set(n.prime_divisors()+m.prime_divisors()):
558
e = min(a4.valuation(p)//2,a6.valuation(p)//3)
559
if e>0:
560
p = p**e
561
a4 /= p**2
562
a6 /= p**3
563
564
# Now E=[0,0,0,a4,a6] is minimal at all p != 2,3
565
tw = [-1,2,-2,3,-3,6,-6]
566
E1 = EllipticCurve([0,0,0,a4,a6])
567
Elist = [E1] + [E1.quadratic_twist(t) for t in tw]
568
crv_cmp = lambda E,F: cmp(E.conductor(),F.conductor())
569
Elist.sort(cmp=crv_cmp)
570
return Elist[0]
571
572
# defaults for all other fields:
573
if j == 0:
574
return EllipticCurve(K, [ 0, 0, 0, 0, 1 ])
575
if j == 1728:
576
return EllipticCurve(K, [ 0, 0, 0, 1, 0 ])
577
k=j-1728
578
return EllipticCurve(K, [0,0,0,-3*j*k, -2*j*k**2])
579
580
581
def EllipticCurve_from_cubic(F, P, morphism=True):
582
r"""
583
Construct an elliptic curve from a ternary cubic with a rational point.
584
585
If you just want the Weierstrass form and are not interested in
586
the morphism then it is easier to use
587
:func:`~sage.schemes.elliptic_curves.jacobian.Jacobian`
588
instead. This will construct the same elliptic curve but you don't
589
have to supply the point ``P``.
590
591
INPUT:
592
593
- ``F`` -- a homogeneous cubic in three variables with rational
594
coefficients, as a polynomial ring element, defining a smooth
595
plane cubic curve.
596
597
- ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the
598
curve `F=0`. Need not be a flex, but see caveat on output.
599
600
- ``morphism`` -- boolean (default: ``True``). Whether to return
601
the morphism or just the elliptic curve.
602
603
OUTPUT:
604
605
An elliptic curve in long Weierstrass form isomorphic to the curve
606
`F=0`.
607
608
If ``morphism=True`` is passed, then a birational equivalence
609
between F and the Weierstrass curve is returned. If the point
610
happens to be a flex, then this is an isomorphism.
611
612
EXAMPLES:
613
614
First we find that the Fermat cubic is isomorphic to the curve
615
with Cremona label 27a1::
616
617
sage: R.<x,y,z> = QQ[]
618
sage: cubic = x^3+y^3+z^3
619
sage: P = [1,-1,0]
620
sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E
621
Elliptic Curve defined by y^2 + 2*x*y + 1/3*y = x^3 - x^2 - 1/3*x - 1/27 over Rational Field
622
sage: E.cremona_label()
623
'27a1'
624
sage: EllipticCurve_from_cubic(cubic, [0,1,-1], morphism=False).cremona_label()
625
'27a1'
626
sage: EllipticCurve_from_cubic(cubic, [1,0,-1], morphism=False).cremona_label()
627
'27a1'
628
629
Next we find the minimal model and conductor of the Jacobian of the
630
Selmer curve::
631
632
sage: R.<a,b,c> = QQ[]
633
sage: cubic = a^3+b^3+60*c^3
634
sage: P = [1,-1,0]
635
sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E
636
Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field
637
sage: E.minimal_model()
638
Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field
639
sage: E.conductor()
640
24300
641
642
We can also get the birational equivalence to and from the
643
Weierstrass form. We start with an example where ``P`` is a flex
644
and the equivalence is an isomorphism::
645
646
sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True)
647
sage: f
648
Scheme morphism:
649
From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
650
a^3 + b^3 + 60*c^3
651
To: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3
652
over Rational Field
653
Defn: Defined on coordinates by sending (a : b : c) to
654
(-c : -b + c : 1/20*a + 1/20*b)
655
656
sage: finv = f.inverse(); finv
657
Scheme morphism:
658
From: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3
659
over Rational Field
660
To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
661
a^3 + b^3 + 60*c^3
662
Defn: Defined on coordinates by sending (x : y : z) to
663
(x + y + 20*z : -x - y : -x)
664
665
We verify that `f` maps the chosen point `P=(1,-1,0)` on the cubic
666
to the origin of the elliptic curve::
667
668
sage: f([1,-1,0])
669
(0 : 1 : 0)
670
sage: finv([0,1,0])
671
(-1 : 1 : 0)
672
673
To verify the output, we plug in the polynomials to check that
674
this indeed transforms the cubic into Weierstrass form::
675
676
sage: cubic(finv.defining_polynomials()) * finv.post_rescaling()
677
-x^3 + x^2*z + 2*x*y*z + y^2*z + 20*x*z^2 + 20*y*z^2 + 400/3*z^3
678
679
sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling()
680
a^3 + b^3 + 60*c^3
681
682
If the point is not a flex then the cubic can not be transformed
683
to a Weierstrass equation by a linear transformation. The general
684
birational transformation is quadratic::
685
686
sage: cubic = a^3+7*b^3+64*c^3
687
sage: P = [2,2,-1]
688
sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True)
689
sage: E = f.codomain(); E
690
Elliptic Curve defined by y^2 - 722*x*y - 21870000*y = x^3
691
+ 23579*x^2 over Rational Field
692
sage: E.minimal_model()
693
Elliptic Curve defined by y^2 + y = x^3 - 331 over Rational Field
694
695
sage: f
696
Scheme morphism:
697
From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
698
a^3 + 7*b^3 + 64*c^3
699
To: Elliptic Curve defined by y^2 - 722*x*y - 21870000*y =
700
x^3 + 23579*x^2 over Rational Field
701
Defn: Defined on coordinates by sending (a : b : c) to
702
(-5/112896*a^2 - 17/40320*a*b - 1/1280*b^2 - 29/35280*a*c
703
- 13/5040*b*c - 4/2205*c^2 :
704
-4055/112896*a^2 - 4787/40320*a*b - 91/1280*b^2 - 7769/35280*a*c
705
- 1993/5040*b*c - 724/2205*c^2 :
706
1/4572288000*a^2 + 1/326592000*a*b + 1/93312000*b^2 + 1/142884000*a*c
707
+ 1/20412000*b*c + 1/17860500*c^2)
708
709
sage: finv = f.inverse(); finv
710
Scheme morphism:
711
From: Elliptic Curve defined by y^2 - 722*x*y - 21870000*y =
712
x^3 + 23579*x^2 over Rational Field
713
To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
714
a^3 + 7*b^3 + 64*c^3
715
Defn: Defined on coordinates by sending (x : y : z) to
716
(2*x^2 + 227700*x*z - 900*y*z :
717
2*x^2 - 32940*x*z + 540*y*z :
718
-x^2 - 56520*x*z - 180*y*z)
719
720
sage: cubic(finv.defining_polynomials()) * finv.post_rescaling()
721
-x^3 - 23579*x^2*z - 722*x*y*z + y^2*z - 21870000*y*z^2
722
723
sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling()
724
a^3 + 7*b^3 + 64*c^3
725
726
TESTS::
727
728
sage: R.<x,y,z> = QQ[]
729
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
730
sage: EllipticCurve_from_cubic(cubic, [1,-1,1], morphism=False)
731
Elliptic Curve defined by y^2 - 882*x*y - 2560000*y = x^3 - 127281*x^2 over Rational Field
732
"""
733
import sage.matrix.all as matrix
734
735
# check the input
736
R = F.parent()
737
if not is_MPolynomialRing(R):
738
raise TypeError('equation must be a polynomial')
739
if R.ngens() != 3:
740
raise TypeError('equation must be a polynomial in three variables')
741
if not F.is_homogeneous():
742
raise TypeError('equation must be a homogeneous polynomial')
743
K = F.parent().base_ring()
744
try:
745
P = [K(c) for c in P]
746
except TypeError:
747
raise TypeError('cannot convert %s into %s'%(P,K))
748
if F(P) != 0:
749
raise ValueError('%s is not a point on %s'%(P,F))
750
if len(P) != 3:
751
raise TypeError('%s is not a projective point'%P)
752
x, y, z = R.gens()
753
754
# First case: if P = P2 then P is a flex
755
P2 = chord_and_tangent(F, P)
756
if are_projectively_equivalent(P, P2, base_ring=K):
757
# find the tangent to F in P
758
dx = K(F.derivative(x)(P))
759
dy = K(F.derivative(y)(P))
760
dz = K(F.derivative(z)(P))
761
# find a second point Q on the tangent line but not on the cubic
762
for tangent in [[dy, -dx, K.zero()], [dz, K.zero(), -dx], [K.zero(), -dz, dx]]:
763
tangent = projective_point(tangent)
764
Q = [tangent[0]+P[0], tangent[1]+P[1], tangent[2]+P[2]]
765
F_Q = F(Q)
766
if F_Q != 0: # At most one further point may accidentally be on the cubic
767
break
768
assert F_Q != 0
769
# pick linearly independent third point
770
for third_point in [(1,0,0), (0,1,0), (0,0,1)]:
771
M = matrix.matrix(K, [Q, P, third_point]).transpose()
772
if M.is_invertible():
773
break
774
F2 = R(M.act_on_polynomial(F))
775
# scale and dehomogenise
776
a = K(F2.coefficient(x**3))
777
F3 = F2/a
778
b = K(F3.coefficient(y*y*z))
779
S = rings.PolynomialRing(K, 'x,y,z')
780
# elliptic curve coordinates
781
X, Y, Z = S.gen(0), S.gen(1), S(-1/b)*S.gen(2)
782
F4 = F3(X, Y, Z)
783
E = EllipticCurve(F4.subs(z=1))
784
if not morphism:
785
return E
786
inv_defining_poly = [ M[i,0]*X + M[i,1]*Y + M[i,2]*Z for i in range(3) ]
787
inv_post = -1/a
788
M = M.inverse()
789
trans_x, trans_y, trans_z = [ M[i,0]*x + M[i,1]*y + M[i,2]*z for i in range(3) ]
790
fwd_defining_poly = [trans_x, trans_y, -b*trans_z]
791
fwd_post = -a
792
793
# Second case: P is not a flex, then P, P2, P3 are different
794
else:
795
P3 = chord_and_tangent(F, P2)
796
# send P, P2, P3 to (1:0:0), (0:1:0), (0:0:1) respectively
797
M = matrix.matrix(K, [P, P2, P3]).transpose()
798
F2 = M.act_on_polynomial(F)
799
# substitute x = U^2, y = V*W, z = U*W, and rename (x,y,z)=(U,V,W)
800
F3 = F2.substitute({x:x**2, y:y*z, z:x*z}) // (x**2*z)
801
# scale and dehomogenise
802
a = K(F3.coefficient(x**3))
803
F4 = F3/a
804
b = K(F4.coefficient(y*y*z))
805
# change to a polynomial in only two variables
806
S = rings.PolynomialRing(K, 'x,y,z')
807
# elliptic curve coordinates
808
X, Y, Z = S.gen(0), S.gen(1), S(-1/b)*S.gen(2)
809
F5 = F4(X, Y, Z)
810
E = EllipticCurve(F5.subs(z=1))
811
if not morphism:
812
return E
813
inv_defining_poly = [ M[i,0]*X*X + M[i,1]*Y*Z + M[i,2]*X*Z for i in range(3) ]
814
inv_post = -1/a/(X**2)/Z
815
M = M.inverse()
816
trans_x, trans_y, trans_z = [
817
(M[i,0]*x + M[i,1]*y + M[i,2]*z) for i in range(3) ]
818
fwd_defining_poly = [ trans_x*trans_z, trans_x*trans_y, -b*trans_z*trans_z ]
819
fwd_post = -a/(trans_x*trans_z*trans_z)
820
821
# Construct the morphism
822
from sage.schemes.projective.projective_space import ProjectiveSpace
823
P2 = ProjectiveSpace(2, K, names=map(str, R.gens()))
824
cubic = P2.subscheme(F)
825
from sage.schemes.elliptic_curves.weierstrass_transform import \
826
WeierstrassTransformationWithInverse
827
return WeierstrassTransformationWithInverse(
828
cubic, E, fwd_defining_poly, fwd_post, inv_defining_poly, inv_post)
829
830
831
def chord_and_tangent(F, P):
832
"""
833
Use the chord and tangent method to get another point on a cubic.
834
835
INPUT:
836
837
- ``F`` -- a homogeneous cubic in three variables with rational
838
coefficients, as a polynomial ring element, defining a smooth
839
plane cubic curve.
840
841
- ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the
842
curve `F=0`.
843
844
OUTPUT:
845
846
Another point satisfying the equation ``F``.
847
848
EXAMPLES::
849
850
sage: R.<x,y,z> = QQ[]
851
sage: from sage.schemes.elliptic_curves.constructor import chord_and_tangent
852
sage: F = x^3+y^3+60*z^3
853
sage: chord_and_tangent(F, [1,-1,0])
854
[1, -1, 0]
855
856
sage: F = x^3+7*y^3+64*z^3
857
sage: p0 = [2,2,-1]
858
sage: p1 = chord_and_tangent(F, p0); p1
859
[-5, 3, -1]
860
sage: p2 = chord_and_tangent(F, p1); p2
861
[1265, -183, -314]
862
863
TESTS::
864
865
sage: F(p2)
866
0
867
sage: map(type, p2)
868
[<type 'sage.rings.rational.Rational'>,
869
<type 'sage.rings.rational.Rational'>,
870
<type 'sage.rings.rational.Rational'>]
871
"""
872
# check the input
873
R = F.parent()
874
if not is_MPolynomialRing(R):
875
raise TypeError('equation must be a polynomial')
876
if R.ngens() != 3:
877
raise TypeError('%s is not a polynomial in three variables'%F)
878
if not F.is_homogeneous():
879
raise TypeError('%s is not a homogeneous polynomial'%F)
880
x, y, z = R.gens()
881
if len(P) != 3:
882
raise TypeError('%s is not a projective point'%P)
883
K = R.base_ring()
884
try:
885
P = [K(c) for c in P]
886
except TypeError:
887
raise TypeError('cannot coerce %s into %s'%(P,K))
888
if F(P) != 0:
889
raise ValueError('%s is not a point on %s'%(P,F))
890
891
# find the tangent to F in P
892
dx = K(F.derivative(x)(P))
893
dy = K(F.derivative(y)(P))
894
dz = K(F.derivative(z)(P))
895
# if dF/dy(P) = 0, change variables so that dF/dy != 0
896
if dy == 0:
897
if dx != 0:
898
g = F.substitute({x:y, y:x})
899
Q = [P[1], P[0], P[2]]
900
R = chord_and_tangent(g, Q)
901
return [R[1], R[0], R[2]]
902
elif dz != 0:
903
g = F.substitute({y:z, z:y})
904
Q = [P[0], P[2], P[1]]
905
R = chord_and_tangent(g, Q)
906
return [R[0], R[2], R[1]]
907
else:
908
raise ValueError('%s is singular at %s'%(F, P))
909
910
# t will be our choice of parmeter of the tangent plane
911
# dx*(x-P[0]) + dy*(y-P[1]) + dz*(z-P[2])
912
# through the point P
913
t = rings.PolynomialRing(K, 't').gen(0)
914
Ft = F(dy*t+P[0], -dx*t+P[1], P[2])
915
if Ft == 0: # (dy, -dx, 0) is projectively equivalent to P
916
# then (0, -dz, dy) is not projectively equivalent to P
917
g = F.substitute({x:z, z:x})
918
Q = [P[2], P[1], P[0]]
919
R = chord_and_tangent(g, Q)
920
return [R[2], R[1], R[0]]
921
# Ft has a double zero at t=0 by construction, which we now remove
922
Ft = Ft // t**2
923
924
# first case: the third point is at t=infinity
925
if Ft.is_constant():
926
return projective_point([dy, -dx, 0])
927
# second case: the third point is at finite t
928
else:
929
assert Ft.degree() == 1
930
t0 = Ft.roots()[0][0]
931
return projective_point([dy*t0+P[0], -dx*t0+P[1], P[2]])
932
933
934
def projective_point(p):
935
"""
936
Return equivalent point with denominators removed
937
938
INPUT:
939
940
- ``P``, ``Q`` -- list/tuple of projective coordinates.
941
942
OUTPUT:
943
944
List of projective coordinates.
945
946
EXAMPLES::
947
948
sage: from sage.schemes.elliptic_curves.constructor import projective_point
949
sage: projective_point([4/5, 6/5, 8/5])
950
[2, 3, 4]
951
sage: F = GF(11)
952
sage: projective_point([F(4), F(8), F(2)])
953
[4, 8, 2]
954
"""
955
try:
956
p_gcd = rings.integer.GCD_list([x.numerator() for x in p])
957
p_lcm = rings.integer.LCM_list([x.denominator() for x in p])
958
except AttributeError:
959
return p
960
scale = p_lcm / p_gcd
961
return [scale * x for x in p]
962
963
964
def are_projectively_equivalent(P, Q, base_ring):
965
"""
966
Test whether ``P`` and ``Q`` are projectively equivalent.
967
968
INPUT:
969
970
- ``P``, ``Q`` -- list/tuple of projective coordinates.
971
972
- ``base_ring`` -- the base ring.
973
974
OUTPUT:
975
976
Boolean.
977
978
EXAMPLES::
979
980
sage: from sage.schemes.elliptic_curves.constructor import are_projectively_equivalent
981
sage: are_projectively_equivalent([0,1,2,3], [0,1,2,2], base_ring=QQ)
982
False
983
sage: are_projectively_equivalent([0,1,2,3], [0,2,4,6], base_ring=QQ)
984
True
985
"""
986
from sage.matrix.constructor import matrix
987
return matrix(base_ring, [P, Q]).rank() < 2
988
989
990
def EllipticCurve_from_plane_curve(C, P):
991
"""
992
Deprecated way to construct an elliptic curve.
993
994
Use :meth:`~sage.schemes.elliptic_curves.jacobian.Jacobian` instead.
995
996
EXAMPLES::
997
998
sage: R.<x,y,z> = QQ[]
999
sage: C = Curve(x^3+y^3+z^3)
1000
sage: P = C(1,-1,0)
1001
sage: E = EllipticCurve_from_plane_curve(C,P); E # long time (3s on sage.math, 2013)
1002
doctest:...: DeprecationWarning: use Jacobian(C) instead
1003
See http://trac.sagemath.org/3416 for details.
1004
Elliptic Curve defined by y^2 = x^3 - 27/4 over Rational Field
1005
"""
1006
from sage.misc.superseded import deprecation
1007
deprecation(3416, 'use Jacobian(C) instead')
1008
# Note: this function never used the rational point
1009
from sage.schemes.elliptic_curves.jacobian import Jacobian
1010
return Jacobian(C)
1011
1012
1013
def EllipticCurves_with_good_reduction_outside_S(S=[], proof=None, verbose=False):
1014
r"""
1015
Returns a sorted list of all elliptic curves defined over `Q`
1016
with good reduction outside the set `S` of primes.
1017
1018
INPUT:
1019
1020
- ``S`` - list of primes (default: empty list).
1021
1022
- ``proof`` - True/False (default True): the MW basis for
1023
auxiliary curves will be computed with this proof flag.
1024
1025
- ``verbose`` - True/False (default False): if True, some details
1026
of the computation will be output.
1027
1028
.. note::
1029
1030
Proof flag: The algorithm used requires determining all
1031
S-integral points on several auxiliary curves, which in turn
1032
requires the computation of their generators. This is not
1033
always possible (even in theory) using current knowledge.
1034
1035
The value of this flag is passed to the function which
1036
computes generators of various auxiliary elliptic curves, in
1037
order to find their S-integral points. Set to False if the
1038
default (True) causes warning messages, but note that you can
1039
then not rely on the set of curves returned being
1040
complete.
1041
1042
EXAMPLES::
1043
1044
sage: EllipticCurves_with_good_reduction_outside_S([])
1045
[]
1046
sage: elist = EllipticCurves_with_good_reduction_outside_S([2])
1047
sage: elist
1048
[Elliptic Curve defined by y^2 = x^3 + 4*x over Rational Field,
1049
Elliptic Curve defined by y^2 = x^3 - x over Rational Field,
1050
...
1051
Elliptic Curve defined by y^2 = x^3 - x^2 - 13*x + 21 over Rational Field]
1052
sage: len(elist)
1053
24
1054
sage: ', '.join([e.label() for e in elist])
1055
'32a1, 32a2, 32a3, 32a4, 64a1, 64a2, 64a3, 64a4, 128a1, 128a2, 128b1, 128b2, 128c1, 128c2, 128d1, 128d2, 256a1, 256a2, 256b1, 256b2, 256c1, 256c2, 256d1, 256d2'
1056
1057
Without ``Proof=False``, this example gives two warnings::
1058
1059
sage: elist = EllipticCurves_with_good_reduction_outside_S([11],proof=False) # long time (14s on sage.math, 2011)
1060
sage: len(elist) # long time
1061
12
1062
sage: ', '.join([e.label() for e in elist]) # long time
1063
'11a1, 11a2, 11a3, 121a1, 121a2, 121b1, 121b2, 121c1, 121c2, 121d1, 121d2, 121d3'
1064
1065
sage: elist = EllipticCurves_with_good_reduction_outside_S([2,3]) # long time (26s on sage.math, 2011)
1066
sage: len(elist) # long time
1067
752
1068
sage: max([e.conductor() for e in elist]) # long time
1069
62208
1070
sage: [N.factor() for N in Set([e.conductor() for e in elist])] # long time
1071
[2^7,
1072
2^8,
1073
2^3 * 3^4,
1074
2^2 * 3^3,
1075
2^8 * 3^4,
1076
2^4 * 3^4,
1077
2^3 * 3,
1078
2^7 * 3,
1079
2^3 * 3^5,
1080
3^3,
1081
2^8 * 3,
1082
2^5 * 3^4,
1083
2^4 * 3,
1084
2 * 3^4,
1085
2^2 * 3^2,
1086
2^6 * 3^4,
1087
2^6,
1088
2^7 * 3^2,
1089
2^4 * 3^5,
1090
2^4 * 3^3,
1091
2 * 3^3,
1092
2^6 * 3^3,
1093
2^6 * 3,
1094
2^5,
1095
2^2 * 3^4,
1096
2^3 * 3^2,
1097
2^5 * 3,
1098
2^7 * 3^4,
1099
2^2 * 3^5,
1100
2^8 * 3^2,
1101
2^5 * 3^2,
1102
2^7 * 3^5,
1103
2^8 * 3^5,
1104
2^3 * 3^3,
1105
2^8 * 3^3,
1106
2^5 * 3^5,
1107
2^4 * 3^2,
1108
2 * 3^5,
1109
2^5 * 3^3,
1110
2^6 * 3^5,
1111
2^7 * 3^3,
1112
3^5,
1113
2^6 * 3^2]
1114
"""
1115
from ell_egros import (egros_from_jlist, egros_get_j)
1116
return egros_from_jlist(egros_get_j(S, proof=proof, verbose=verbose), S)
1117
1118