Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/elliptic_curves/ell_generic.py
8821 views
1
r"""
2
Elliptic curves over a general ring
3
4
Sage defines an elliptic curve over a ring `R` as a 'Weierstrass Model' with
5
five coefficients `[a_1,a_2,a_3,a_4,a_6]` in `R` given by
6
7
`y^2 + a_1 xy + a_3 y = x^3 +a_2 x^2 +a_4 x +a_6`.
8
9
Note that the (usual) scheme-theoretic definition of an elliptic curve over `R` would require the discriminant to be a unit in `R`, Sage only imposes that the discriminant is non-zero. Also, in Magma, 'Weierstrass Model' means a model with `a1=a2=a3=0`, which is called 'Short Weierstrass Model' in Sage; these do not always exist in characteristics 2 and 3.
10
11
EXAMPLES:
12
13
We construct an elliptic curve over an elaborate base ring::
14
15
sage: p = 97; a=1; b=3
16
sage: R, u = PolynomialRing(GF(p), 'u').objgen()
17
sage: S, v = PolynomialRing(R, 'v').objgen()
18
sage: T = S.fraction_field()
19
sage: E = EllipticCurve(T, [a, b]); E
20
Elliptic Curve defined by y^2 = x^3 + x + 3 over Fraction Field of Univariate Polynomial Ring in v over Univariate Polynomial Ring in u over Finite Field of size 97
21
sage: latex(E)
22
y^2 = x^{3} + x + 3
23
24
AUTHORS:
25
26
- William Stein (2005): Initial version
27
28
- Robert Bradshaw et al....
29
30
- John Cremona (2008-01): isomorphisms, automorphisms and twists in all characteristics
31
"""
32
33
#*****************************************************************************
34
# Copyright (C) 2005 William Stein <[email protected]>
35
#
36
# Distributed under the terms of the GNU General Public License (GPL)
37
#
38
# This code is distributed in the hope that it will be useful,
39
# but WITHOUT ANY WARRANTY; without even the implied warranty of
40
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41
# General Public License for more details.
42
#
43
# The full text of the GPL is available at:
44
#
45
# http://www.gnu.org/licenses/
46
#*****************************************************************************
47
48
import math
49
50
from sage.rings.all import PolynomialRing
51
from sage.rings.polynomial.polynomial_ring import polygen, polygens
52
import sage.groups.additive_abelian.additive_abelian_group as groups
53
import sage.groups.generic as generic
54
import sage.plot.all as plot
55
from sage.plot.plot import generate_plot_points
56
57
import sage.rings.arith as arith
58
import sage.rings.all as rings
59
from sage.rings.number_field.all import is_NumberField
60
import sage.misc.misc as misc
61
62
63
# Schemes
64
import sage.schemes.projective.projective_space as projective_space
65
from sage.schemes.projective.projective_homset import SchemeHomset_points_abelian_variety_field
66
67
import ell_point
68
import ell_torsion
69
import constructor
70
import formal_group
71
import weierstrass_morphism as wm
72
73
74
factor = arith.factor
75
sqrt = math.sqrt
76
exp = math.exp
77
mul = misc.mul
78
next_prime = arith.next_prime
79
80
oo = rings.infinity # infinity
81
O = rings.O # big oh
82
83
import sage.schemes.plane_curves.projective_curve as plane_curve
84
85
def is_EllipticCurve(x):
86
r"""
87
Utility function to test if ``x`` is an instance of an Elliptic Curve class.
88
89
EXAMPLES::
90
91
sage: from sage.schemes.elliptic_curves.ell_generic import is_EllipticCurve
92
sage: E = EllipticCurve([1,2,3/4,7,19])
93
sage: is_EllipticCurve(E)
94
True
95
sage: is_EllipticCurve(0)
96
False
97
"""
98
return isinstance(x, EllipticCurve_generic)
99
100
class EllipticCurve_generic(plane_curve.ProjectiveCurve_generic):
101
r"""
102
Elliptic curve over a generic base ring.
103
104
EXAMPLES::
105
106
sage: E = EllipticCurve([1,2,3/4,7,19]); E
107
Elliptic Curve defined by y^2 + x*y + 3/4*y = x^3 + 2*x^2 + 7*x + 19 over Rational Field
108
sage: loads(E.dumps()) == E
109
True
110
sage: E = EllipticCurve([1,3])
111
sage: P = E([-1,1,1])
112
sage: -5*P
113
(179051/80089 : -91814227/22665187 : 1)
114
"""
115
def __init__(self, ainvs, extra=None):
116
r"""
117
Constructor from `a`-invariants (long or short Weierstrass coefficients).
118
119
INPUT:
120
121
- ``ainvs`` (list) -- either `[a_1,a_2,a_3,a_4,a_6]` or
122
`[a_4,a_6]` (with `a_1=a_2=a_3=0` in the second case).
123
124
.. note::
125
126
See constructor.py for more variants.
127
128
EXAMPLES::
129
130
sage: E = EllipticCurve([1,2,3,4,5]); E
131
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
132
sage: E = EllipticCurve(GF(7),[1,2,3,4,5]); E
133
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 7
134
135
Constructor from `[a_4,a_6]` sets `a_1=a_2=a_3=0`::
136
137
sage: EllipticCurve([4,5]).ainvs()
138
(0, 0, 0, 4, 5)
139
140
The base ring need not be a field::
141
142
sage: EllipticCurve(IntegerModRing(91),[1,2,3,4,5])
143
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Ring of integers modulo 91
144
"""
145
if extra != None: # possibility of two arguments
146
K, ainvs = ainvs, extra
147
else:
148
K = ainvs[0].parent()
149
assert len(ainvs) == 2 or len(ainvs) == 5
150
self.__base_ring = K
151
ainvs = [K(x) for x in ainvs]
152
if len(ainvs) == 2:
153
ainvs = [K(0),K(0),K(0)] + ainvs
154
self.__ainvs = tuple(ainvs)
155
if self.discriminant() == 0:
156
raise ArithmeticError, \
157
"Invariants %s define a singular curve."%ainvs
158
PP = projective_space.ProjectiveSpace(2, K, names='xyz');
159
x, y, z = PP.coordinate_ring().gens()
160
a1, a2, a3, a4, a6 = ainvs
161
f = y**2*z + (a1*x + a3*z)*y*z \
162
- (x**3 + a2*x**2*z + a4*x*z**2 + a6*z**3)
163
plane_curve.ProjectiveCurve_generic.__init__(self, PP, f)
164
# TODO: cleanup, are these two point classes redundant?
165
166
# See #1975: we deliberately set the class to
167
# EllipticCurvePoint_finite_field for finite rings, so that we
168
# can do some arithmetic on points over Z/NZ, for teaching
169
# purposes.
170
from sage.rings.finite_rings.constructor import is_FiniteField
171
from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing
172
if is_FiniteField(K) or is_IntegerModRing(K):
173
self._morphism = self._point = ell_point.EllipticCurvePoint_finite_field
174
elif K.is_field():
175
if is_NumberField(K):
176
self._morphism = self._point = ell_point.EllipticCurvePoint_number_field
177
else:
178
self._morphism = self._point = ell_point.EllipticCurvePoint_field
179
else:
180
self._morphism = self._point = ell_point.EllipticCurvePoint
181
182
def _defining_params_(self):
183
r"""
184
Internal function. Returns a tuple of the base ring of this
185
elliptic curve and its `a`-invariants, from which it can be
186
reconstructed.
187
188
EXAMPLES::
189
190
sage: E=EllipticCurve(QQ,[1,1])
191
sage: E._defining_params_()
192
(Rational Field, [0, 0, 0, 1, 1])
193
sage: EllipticCurve(*E._defining_params_()) == E
194
True
195
"""
196
return (self.__base_ring, list(self.__ainvs))
197
198
def __hash__(self):
199
"""
200
TESTS::
201
202
sage: E = EllipticCurve('37a')
203
sage: hash(E)
204
-1437250549 # 32-bit
205
-2189969105152029685 # 64-bit
206
sage: hash(E) != hash(E.change_ring(GF(7)))
207
True
208
"""
209
return hash((self.__base_ring, self.__ainvs))
210
211
def _repr_(self):
212
"""
213
String representation of elliptic curve.
214
215
EXAMPLES::
216
217
sage: E=EllipticCurve([1,2,3,4,5]); E._repr_()
218
'Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field'
219
220
::
221
222
sage: R.<x> = QQ['x']
223
sage: K.<a> = NumberField(x^3-17)
224
sage: EllipticCurve([a^2-3, -2/3*a + 3])
225
Elliptic Curve defined by y^2 = x^3 + (a^2-3)*x + (-2/3*a+3) over Number Field in a
226
with defining polynomial x^3 - 17
227
"""
228
#return "Elliptic Curve with a-invariants %s over %s"%(self.ainvs(), self.base_ring())
229
b = self.ainvs()
230
#return "y^2 + %s*x*y + %s*y = x^3 + %s*x^2 + %s*x + %s"%\
231
# (a[0], a[2], a[1], a[3], a[4])
232
a = [z._coeff_repr() for z in b]
233
s = "Elliptic Curve defined by "
234
s += "y^2 "
235
if a[0] == "-1":
236
s += "- x*y "
237
elif a[0] == '1':
238
s += "+ x*y "
239
elif b[0]:
240
s += "+ %s*x*y "%a[0]
241
if a[2] == "-1":
242
s += "- y "
243
elif a[2] == '1':
244
s += "+ y "
245
elif b[2]:
246
s += "+ %s*y "%a[2]
247
s += "= x^3 "
248
if a[1] == "-1":
249
s += "- x^2 "
250
elif a[1] == '1':
251
s += "+ x^2 "
252
elif b[1]:
253
s += "+ %s*x^2 "%a[1]
254
if a[3] == "-1":
255
s += "- x "
256
elif a[3] == '1':
257
s += "+ x "
258
elif b[3]:
259
s += "+ %s*x "%a[3]
260
if a[4] == '-1':
261
s += "- 1 "
262
elif a[4] == '1':
263
s += "+ 1 "
264
elif b[4]:
265
s += "+ %s "%a[4]
266
s = s.replace("+ -","- ")
267
s += "over %s"%self.base_ring()
268
return s
269
270
def _latex_(self):
271
"""
272
Internal function. Returns a latex string for this elliptic curve.
273
274
Users will normally use latex() instead.
275
276
EXAMPLES::
277
278
sage: E = EllipticCurve(QQ, [1,1])
279
sage: E._latex_()
280
'y^2 = x^{3} + x + 1 '
281
282
sage: E = EllipticCurve(QQ, [1,2,3,4,5])
283
sage: E._latex_()
284
'y^2 + x y + 3 y = x^{3} + 2 x^{2} + 4 x + 5 '
285
286
Check that :trac:`12524` is solved::
287
288
sage: K.<phi> = NumberField(x^2-x-1)
289
sage: E = EllipticCurve([0,0,phi,27*phi-43,-80*phi+128])
290
sage: E._latex_()
291
'y^2 + \\phi y = x^{3} + \\left(27 \\phi - 43\\right) x - 80 \\phi + 128 '
292
"""
293
from sage.rings.polynomial.polynomial_ring import polygen
294
a = self.ainvs()
295
x, y = polygen(self.base_ring(), 'x, y')
296
s = "y^2"
297
if a[0] or a[2]:
298
s += " + " + (a[0]*x*y + a[2]*y)._latex_()
299
s += " = "
300
s += (x**3 + a[1]*x**2 + a[3]*x + a[4])._latex_()
301
s += " "
302
s = s.replace("+ -","- ")
303
return s
304
305
def _pari_init_(self):
306
"""
307
Internal function. Returns a string to initialize this elliptic
308
curve in the PARI system.
309
310
EXAMPLES::
311
312
sage: E=EllipticCurve(QQ,[1,1])
313
sage: E._pari_init_()
314
'ellinit([0/1,0/1,0/1,1/1,1/1])'
315
"""
316
return 'ellinit([%s])'%(','.join([x._pari_init_() for x in self.ainvs()]))
317
318
def _magma_init_(self, magma):
319
"""
320
Internal function. Returns a string to initialize this elliptic
321
curve in the Magma subsystem.
322
323
EXAMPLES::
324
325
sage: E = EllipticCurve(QQ,[1,1])
326
sage: E._magma_init_(magma) # optional - magma
327
'EllipticCurve([_sage_ref...|0/1,0/1,0/1,1/1,1/1])'
328
sage: E = EllipticCurve(GF(41),[2,5]) # optional - magma
329
sage: E._magma_init_(magma) # optional - magma
330
'EllipticCurve([_sage_ref...|GF(41)!0,GF(41)!0,GF(41)!0,GF(41)!2,GF(41)!5])'
331
sage: E = EllipticCurve(GF(25,'a'), [0,0,1,4,0])
332
sage: magma(E) # optional - magma
333
Elliptic Curve defined by y^2 + y = x^3 + 4*x over GF(5^2)
334
sage: magma(EllipticCurve([1/2,2/3,-4/5,6/7,8/9])) # optional - magma
335
Elliptic Curve defined by y^2 + 1/2*x*y - 4/5*y = x^3 + 2/3*x^2 + 6/7*x + 8/9 over Rational Field
336
sage: R.<x> = Frac(QQ['x'])
337
sage: magma(EllipticCurve([x,1+x])) # optional - magma
338
Elliptic Curve defined by y^2 = x^3 + x*x + (x + 1) over Univariate rational function field over Rational Field
339
"""
340
kmn = magma(self.base_ring())._ref()
341
return 'EllipticCurve([%s|%s])'%(kmn,','.join([x._magma_init_(magma) for x in self.ainvs()]))
342
343
344
def _symbolic_(self, SR):
345
r"""
346
Many elliptic curves can be converted into a symbolic expression
347
using the ``symbolic_expression`` command.
348
349
EXAMPLES: We find a torsion point on 11a.
350
351
::
352
353
sage: E = EllipticCurve('11a')
354
sage: E._symbolic_(SR)
355
y^2 + y == x^3 - x^2 - 10*x - 20
356
sage: E.torsion_subgroup().gens()
357
((5 : 5 : 1),)
358
359
We find the corresponding symbolic equality::
360
361
sage: eqn = symbolic_expression(E); eqn
362
y^2 + y == x^3 - x^2 - 10*x - 20
363
364
We verify that the given point is on the curve::
365
366
sage: eqn(x=5,y=5)
367
30 == 30
368
sage: bool(eqn(x=5,y=5))
369
True
370
371
We create a single expression::
372
373
sage: F = eqn.lhs() - eqn.rhs(); F
374
-x^3 + x^2 + y^2 + 10*x + y + 20
375
sage: y = var('y')
376
sage: F.solve(y)
377
[y == -1/2*sqrt(4*x^3 - 4*x^2 - 40*x - 79) - 1/2,
378
y == 1/2*sqrt(4*x^3 - 4*x^2 - 40*x - 79) - 1/2]
379
380
You can also solve for x in terms of y, but the result is
381
horrendous. Continuing with the above example, we can explicitly
382
find points over random fields by substituting in values for x::
383
384
sage: v = F.solve(y)[0].rhs(); v
385
-1/2*sqrt(4*x^3 - 4*x^2 - 40*x - 79) - 1/2
386
sage: v = v.function(x)
387
sage: v(3)
388
-1/2*sqrt(-127) - 1/2
389
sage: v(7)
390
-1/2*sqrt(817) - 1/2
391
sage: v(-7)
392
-1/2*sqrt(-1367) - 1/2
393
sage: v(sqrt(2))
394
-1/2*sqrt(-32*sqrt(2) - 87) - 1/2
395
396
We can even do arithmetic with them, as follows::
397
398
sage: E2 = E.change_ring(SR); E2
399
Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Symbolic Ring
400
sage: P = E2.point((3, v(3), 1), check=False) # the check=False option doesn't verify that y^2 = f(x)
401
sage: P
402
(3 : -1/2*sqrt(-127) - 1/2 : 1)
403
sage: P + P
404
(-756/127 : 41143/32258*sqrt(-127) - 1/2 : 1)
405
406
We can even throw in a transcendental::
407
408
sage: w = E2.point((pi,v(pi),1), check=False); w
409
(pi : -1/2*sqrt(-40*pi + 4*pi^3 - 4*pi^2 - 79) - 1/2 : 1)
410
sage: x, y, z = w; ((y^2 + y) - (x^3 - x^2 - 10*x - 20)).expand()
411
0
412
413
sage: 2*w
414
(-2*pi + (2*pi - 3*pi^2 + 10)^2/(-40*pi + 4*pi^3 - 4*pi^2 - 79) + 1 : (3*pi - (2*pi - 3*pi^2 + 10)^2/(-40*pi + 4*pi^3 - 4*pi^2 - 79) - 1)*(2*pi - 3*pi^2 + 10)/sqrt(-40*pi + 4*pi^3 - 4*pi^2 - 79) + 1/2*sqrt(-40*pi + 4*pi^3 - 4*pi^2 - 79) - 1/2 : 1)
415
416
sage: x, y, z = 2*w; temp = ((y^2 + y) - (x^3 - x^2 - 10*x - 20))
417
418
This is a point on the curve::
419
420
sage: bool(temp == 0)
421
True
422
"""
423
a = [SR(x) for x in self.a_invariants()]
424
x, y = SR.var('x, y')
425
return y**2 + a[0]*x*y + a[2]*y == x**3 + a[1]*x**2 + a[3]*x + a[4]
426
427
def __cmp__(self, other):
428
"""
429
Standard comparison function for elliptic curves, to allow sorting
430
and equality testing.
431
432
EXAMPLES::
433
434
sage: E=EllipticCurve(QQ,[1,1])
435
sage: F=EllipticCurve(QQ,[0,0,0,1,1])
436
sage: E==F
437
True
438
"""
439
if not isinstance(other, EllipticCurve_generic):
440
return -1
441
t = cmp(self.base_ring(), other.base_ring())
442
if t:
443
return t
444
return cmp(self.ainvs(), other.ainvs())
445
446
def __contains__(self, P):
447
"""
448
Returns True if and only if P is a point on the elliptic curve. P
449
just has to be something that can be coerced to a point.
450
451
EXAMPLES::
452
453
sage: E = EllipticCurve([0, 0, 1, -1, 0])
454
sage: (0,0) in E
455
True
456
sage: (1,3) in E
457
False
458
sage: E = EllipticCurve([GF(7)(0), 1])
459
sage: [0,0] in E
460
False
461
sage: [0,8] in E
462
True
463
sage: P = E(0,8)
464
sage: P
465
(0 : 1 : 1)
466
sage: P in E
467
True
468
"""
469
if not isinstance(P, ell_point.EllipticCurvePoint):
470
try:
471
P = self(P)
472
except TypeError:
473
return False
474
if P.curve() == self:
475
return True
476
x, y, a = P[0], P[1], self.ainvs()
477
return y**2 + a[0]*x*y + a[2]*y == x**3 + a[1]*x**2 + a[3]*x + a[4]
478
479
def __call__(self, *args, **kwds):
480
r"""
481
EXAMPLES::
482
483
sage: E = EllipticCurve([0, 0, 1, -1, 0])
484
485
The point at infinity, which is the 0 element of the group::
486
487
sage: E(0)
488
(0 : 1 : 0)
489
490
The origin is a point on our curve::
491
492
sage: P = E([0,0])
493
sage: P
494
(0 : 0 : 1)
495
496
The curve associated to a point::
497
498
sage: P.curve()
499
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
500
501
Points can be specified by given a 2-tuple or 3-tuple::
502
503
sage: E([0,0])
504
(0 : 0 : 1)
505
sage: E([0,1,0])
506
(0 : 1 : 0)
507
508
Over a field, points are normalized so the 3rd entry (if non-zero)
509
is 1::
510
511
sage: E(105, -69, 125)
512
(21/25 : -69/125 : 1)
513
514
We create points on an elliptic curve over a prime finite field::
515
516
sage: E = EllipticCurve([GF(7)(0), 1])
517
sage: E([2,3])
518
(2 : 3 : 1)
519
sage: E([0,0])
520
Traceback (most recent call last):
521
...
522
TypeError: Coordinates [0, 0, 1] do not define a point on Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7
523
524
We create a point on an elliptic curve over a number field::
525
526
sage: x = polygen(RationalField())
527
sage: K = NumberField(x**3 + x + 1, 'a'); a = K.gen()
528
sage: E = EllipticCurve([a,a])
529
sage: E
530
Elliptic Curve defined by y^2 = x^3 + a*x + a over Number Field in a with defining polynomial x^3 + x + 1
531
sage: E = EllipticCurve([K(1),1])
532
sage: E
533
Elliptic Curve defined by y^2 = x^3 + x + 1 over Number Field in a with defining polynomial x^3 + x + 1
534
sage: P = E([a,0,1])
535
sage: P
536
(a : 0 : 1)
537
sage: P+P
538
(0 : 1 : 0)
539
540
Another example involving p-adics::
541
542
sage: E = EllipticCurve('37a1')
543
sage: P = E([0,0]); P
544
(0 : 0 : 1)
545
sage: R = pAdicField(3,20)
546
sage: Ep = E.base_extend(R); Ep
547
Elliptic Curve defined by y^2 + (1+O(3^20))*y = x^3 + (2+2*3+2*3^2+2*3^3+2*3^4+2*3^5+2*3^6+2*3^7+2*3^8+2*3^9+2*3^10+2*3^11+2*3^12+2*3^13+2*3^14+2*3^15+2*3^16+2*3^17+2*3^18+2*3^19+O(3^20))*x over 3-adic Field with capped relative precision 20
548
sage: Ep(P)
549
(0 : 0 : 1 + O(3^20))
550
551
Constructing points from the torsion subgroup (which is an abstract
552
abelian group)::
553
554
sage: E = EllipticCurve('14a1')
555
sage: T = E.torsion_subgroup()
556
sage: [E(t) for t in T]
557
[(0 : 1 : 0),
558
(9 : 23 : 1),
559
(2 : 2 : 1),
560
(1 : -1 : 1),
561
(2 : -5 : 1),
562
(9 : -33 : 1)]
563
564
::
565
566
sage: E = EllipticCurve([0,0,0,-49,0])
567
sage: T = E.torsion_subgroup()
568
sage: [E(t) for t in T]
569
[(0 : 1 : 0), (7 : 0 : 1), (0 : 0 : 1), (-7 : 0 : 1)]
570
571
::
572
573
sage: E = EllipticCurve('37a1')
574
sage: T = E.torsion_subgroup()
575
sage: [E(t) for t in T]
576
[(0 : 1 : 0)]
577
"""
578
if len(args) == 1 and args[0] == 0:
579
R = self.base_ring()
580
return self.point([R(0),R(1),R(0)], check=False)
581
P = args[0]
582
if isinstance(P, groups.AdditiveAbelianGroupElement) and isinstance(P.parent(),ell_torsion.EllipticCurveTorsionSubgroup):
583
return self(P.element())
584
if isinstance(args[0],
585
(ell_point.EllipticCurvePoint_field, \
586
ell_point.EllipticCurvePoint_number_field, \
587
ell_point.EllipticCurvePoint)):
588
# check if denominator of the point contains a factor of the
589
# characteristic of the base ring. if so, coerce the point to
590
# infinity.
591
characteristic = self.base_ring().characteristic()
592
if characteristic != 0 and isinstance(args[0][0], rings.Rational) and isinstance(args[0][1], rings.Rational):
593
if rings.mod(args[0][0].denominator(),characteristic) == 0 or rings.mod(args[0][1].denominator(),characteristic) == 0:
594
return self._reduce_point(args[0], characteristic)
595
args = tuple(args[0])
596
597
return plane_curve.ProjectiveCurve_generic.__call__(self, *args, **kwds)
598
599
def _reduce_point(self, R, p):
600
r"""
601
Reduces a point R on an ellipitc curve to the corresponding point on
602
the elliptic curve reduced modulo p. Used to coerce points between
603
curves when p is a factor of the denominator of one of the
604
coordinates.
605
606
This functionality is used internally in the \code{call} method for
607
elliptic curves.
608
609
INPUT:
610
R -- a point on an elliptic curve
611
p -- a prime
612
613
OUTPUT:
614
S -- the corresponding point of the elliptic curve containing R, but
615
reduced modulo p
616
617
EXAMPLES:
618
Suppose we have a point with large height on a rational elliptic curve
619
whose denominator contains a factor of 11::
620
621
sage: E = EllipticCurve([1,-1,0,94,9])
622
sage: R = E([0,3]) + 5*E([8,31])
623
sage: factor(R.xy()[0].denominator())
624
2^2 * 11^2 * 1457253032371^2
625
626
Since 11 is a factor of the denominator, this point corresponds to the
627
point at infinity on the same curve but reduced modulo 11. The reduce
628
function tells us this::
629
630
sage: E11 = E.change_ring(GF(11))
631
sage: S = E11._reduce_point(R, 11)
632
sage: E11(S)
633
(0 : 1 : 0)
634
635
The 0 point reduces as expected::
636
637
sage: E11._reduce_point(E(0), 11)
638
(0 : 1 : 0)
639
640
Note that one need not explicitly call
641
\code{EllipticCurve._reduce_point}
642
"""
643
if R.is_zero():
644
return R.curve().change_ring(rings.GF(p))(0)
645
x, y = R.xy()
646
d = arith.LCM(x.denominator(), y.denominator())
647
return R.curve().change_ring(rings.GF(p))([x*d, y*d, d])
648
649
def is_x_coord(self, x):
650
r"""
651
Returns True if ``x`` is the `x`-coordinate of a point on this curve.
652
653
.. note::
654
655
See also ``lift_x()`` to find the point(s) with a given
656
`x`-coordinate. This function may be useful in cases where
657
testing an element of the base field for being a square is
658
faster than finding its square root.
659
660
EXAMPLES::
661
662
sage: E = EllipticCurve('37a'); E
663
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
664
sage: E.is_x_coord(1)
665
True
666
sage: E.is_x_coord(2)
667
True
668
669
There are no rational points with x-coordinate 3::
670
671
sage: E.is_x_coord(3)
672
False
673
674
However, there are such points in `E(\RR)`::
675
676
sage: E.change_ring(RR).is_x_coord(3)
677
True
678
679
And of course it always works in `E(\CC)`::
680
681
sage: E.change_ring(RR).is_x_coord(-3)
682
False
683
sage: E.change_ring(CC).is_x_coord(-3)
684
True
685
686
AUTHORS:
687
688
- John Cremona (2008-08-07): adapted from lift_x()
689
690
TEST::
691
692
sage: E=EllipticCurve('5077a1')
693
sage: [x for x in srange(-10,10) if E.is_x_coord (x)]
694
[-3, -2, -1, 0, 1, 2, 3, 4, 8]
695
696
::
697
698
sage: F=GF(32,'a')
699
sage: E=EllipticCurve(F,[1,0,0,0,1])
700
sage: set([P[0] for P in E.points() if P!=E(0)]) == set([x for x in F if E.is_x_coord(x)])
701
True
702
"""
703
K = self.base_ring()
704
try:
705
x = K(x)
706
except TypeError:
707
raise TypeError, 'x must be coercible into the base ring of the curve'
708
a1, a2, a3, a4, a6 = self.ainvs()
709
fx = ((x + a2) * x + a4) * x + a6
710
if a1.is_zero() and a3.is_zero():
711
return fx.is_square()
712
b = (a1*x + a3)
713
if K.characteristic() == 2:
714
R = PolynomialRing(K, 'y')
715
F = R([-fx,b,1])
716
return len(F.roots())>0
717
D = b*b + 4*fx
718
return D.is_square()
719
720
def lift_x(self, x, all=False):
721
r"""
722
Returns one or all points with given `x`-coordinate.
723
724
INPUT:
725
726
- ``x`` -- an element of the base ring of the curve.
727
728
- ``all`` (bool, default False) -- if True, return a (possibly
729
empty) list of all points; if False, return just one point,
730
or raise a ValueError if there are none.
731
732
.. note::
733
734
See also ``is_x_coord()``.
735
736
EXAMPLES::
737
738
sage: E = EllipticCurve('37a'); E
739
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
740
sage: E.lift_x(1)
741
(1 : 0 : 1)
742
sage: E.lift_x(2)
743
(2 : 2 : 1)
744
sage: E.lift_x(1/4, all=True)
745
[(1/4 : -3/8 : 1), (1/4 : -5/8 : 1)]
746
747
There are no rational points with `x`-coordinate 3::
748
749
sage: E.lift_x(3)
750
Traceback (most recent call last):
751
...
752
ValueError: No point with x-coordinate 3 on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
753
754
However, there are two such points in `E(\RR)`::
755
756
sage: E.change_ring(RR).lift_x(3, all=True)
757
[(3.00000000000000 : 4.42442890089805 : 1.00000000000000), (3.00000000000000 : -5.42442890089805 : 1.00000000000000)]
758
759
And of course it always works in `E(\CC)`::
760
761
sage: E.change_ring(RR).lift_x(.5, all=True)
762
[]
763
sage: E.change_ring(CC).lift_x(.5)
764
(0.500000000000000 : -0.500000000000000 + 0.353553390593274*I : 1.00000000000000)
765
766
We can perform these operations over finite fields too::
767
768
sage: E = E.change_ring(GF(17)); E
769
Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17
770
sage: E.lift_x(7)
771
(7 : 11 : 1)
772
sage: E.lift_x(3)
773
Traceback (most recent call last):
774
...
775
ValueError: No point with x-coordinate 3 on Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17
776
777
Note that there is only one lift with `x`-coordinate 10 in
778
`E(\GF{17})`::
779
780
sage: E.lift_x(10, all=True)
781
[(10 : 8 : 1)]
782
783
We can lift over more exotic rings too::
784
785
sage: E = EllipticCurve('37a');
786
sage: E.lift_x(pAdicField(17, 5)(6))
787
(6 + O(17^5) : 2 + 16*17 + 16*17^2 + 16*17^3 + 16*17^4 + O(17^5) : 1 + O(17^5))
788
sage: K.<t> = PowerSeriesRing(QQ, 't', 5)
789
sage: E.lift_x(1+t)
790
(1 + t : 2*t - t^2 + 5*t^3 - 21*t^4 + O(t^5) : 1)
791
sage: K.<a> = GF(16)
792
sage: E = E.change_ring(K)
793
sage: E.lift_x(a^3)
794
(a^3 : a^3 + a : 1)
795
796
AUTHOR:
797
798
- Robert Bradshaw (2007-04-24)
799
800
TEST::
801
802
sage: E = EllipticCurve('37a').short_weierstrass_model().change_ring(GF(17))
803
sage: E.lift_x(3, all=True)
804
[]
805
sage: E.lift_x(7, all=True)
806
[(7 : 3 : 1), (7 : 14 : 1)]
807
"""
808
a1, a2, a3, a4, a6 = self.ainvs()
809
f = ((x + a2) * x + a4) * x + a6
810
K = self.base_ring()
811
x += K(0)
812
one = x.parent()(1)
813
if a1.is_zero() and a3.is_zero():
814
if f.is_square():
815
if all:
816
ys = f.sqrt(all=True)
817
return [self.point([x, y, one], check=False) for y in ys]
818
else:
819
return self.point([x, f.sqrt(), one], check=False)
820
else:
821
b = (a1*x + a3)
822
D = b*b + 4*f
823
if K.characteristic() == 2:
824
R = PolynomialRing(K, 'y')
825
F = R([-f,b,1])
826
ys = F.roots(multiplicities=False)
827
if all:
828
return [self.point([x, y, one], check=False) for y in ys]
829
elif len(ys) > 0:
830
return self.point([x, ys[0], one], check=False)
831
elif D.is_square():
832
if all:
833
return [self.point([x, (-b+d)/2, one], check=False) for d in D.sqrt(all=True)]
834
else:
835
return self.point([x, (-b+D.sqrt())/2, one], check=False)
836
if all:
837
return []
838
else:
839
raise ValueError, "No point with x-coordinate %s on %s"%(x, self)
840
841
def _point_homset(self, *args, **kwds):
842
r"""
843
Internal function. Returns the (abstract) group of points on this
844
elliptic curve over a ring.
845
846
EXAMPLES::
847
848
sage: E=EllipticCurve(GF(5),[1,1])
849
sage: E._point_homset(Spec(GF(5^10,'a'),GF(5)), E)
850
Abelian group of points on Elliptic Curve defined
851
by y^2 = x^3 + x + 1 over Finite Field in a of size 5^10
852
"""
853
return SchemeHomset_points_abelian_variety_field(*args, **kwds)
854
855
def __getitem__(self, n):
856
r"""
857
Placeholder for standard indexing function.
858
859
EXAMPLES::
860
861
sage: E=EllipticCurve(QQ,[1,1])
862
sage: E[2]
863
Traceback (most recent call last):
864
...
865
NotImplementedError: not implemented.
866
"""
867
raise NotImplementedError, "not implemented."
868
869
def __is_over_RationalField(self):
870
r"""
871
Internal function. Returns true iff the base ring of this elliptic
872
curve is the field of rational numbers.
873
874
EXAMPLES::
875
876
sage: E=EllipticCurve(QQ,[1,1])
877
sage: E._EllipticCurve_generic__is_over_RationalField()
878
True
879
sage: E=EllipticCurve(GF(5),[1,1])
880
sage: E._EllipticCurve_generic__is_over_RationalField()
881
False
882
"""
883
return isinstance(self.base_ring(), rings.RationalField)
884
885
def is_on_curve(self, x, y):
886
r"""
887
Returns True if `(x,y)` is an affine point on this curve.
888
889
INPUT:
890
891
- ``x``, ``y`` - elements of the base ring of the curve.
892
893
EXAMPLES::
894
895
sage: E=EllipticCurve(QQ,[1,1])
896
sage: E.is_on_curve(0,1)
897
True
898
sage: E.is_on_curve(1,1)
899
False
900
"""
901
a = self.ainvs()
902
return y**2 +a[0]*x*y + a[2]*y == x**3 + a[1]*x**2 + a[3]*x + a[4]
903
904
def a_invariants(self):
905
r"""
906
The `a`-invariants of this elliptic curve, as a tuple.
907
908
OUTPUT:
909
910
(tuple) - a 5-tuple of the `a`-invariants of this elliptic curve.
911
912
EXAMPLES::
913
914
sage: E = EllipticCurve([1,2,3,4,5])
915
sage: E.a_invariants()
916
(1, 2, 3, 4, 5)
917
sage: E = EllipticCurve([0,1])
918
sage: E
919
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
920
sage: E.a_invariants()
921
(0, 0, 0, 0, 1)
922
sage: E = EllipticCurve([GF(7)(3),5])
923
sage: E.a_invariants()
924
(0, 0, 0, 3, 5)
925
926
::
927
928
sage: E = EllipticCurve([1,0,0,0,1])
929
sage: E.a_invariants()[0] = 100000000
930
Traceback (most recent call last):
931
...
932
TypeError: 'tuple' object does not support item assignment
933
934
"""
935
return self.__ainvs
936
937
ainvs = a_invariants
938
939
def a1(self):
940
r"""
941
Returns the `a_1` invariant of this elliptic curve.
942
943
EXAMPLES::
944
945
sage: E = EllipticCurve([1,2,3,4,6])
946
sage: E.a1()
947
1
948
"""
949
return self.__ainvs[0]
950
951
def a2(self):
952
r"""
953
Returns the `a_2` invariant of this elliptic curve.
954
955
EXAMPLES::
956
957
sage: E = EllipticCurve([1,2,3,4,6])
958
sage: E.a2()
959
2
960
"""
961
return self.__ainvs[1]
962
963
def a3(self):
964
r"""
965
Returns the `a_3` invariant of this elliptic curve.
966
967
EXAMPLES::
968
969
sage: E = EllipticCurve([1,2,3,4,6])
970
sage: E.a3()
971
3
972
"""
973
return self.__ainvs[2]
974
975
def a4(self):
976
r"""
977
Returns the `a_4` invariant of this elliptic curve.
978
979
EXAMPLES::
980
981
sage: E = EllipticCurve([1,2,3,4,6])
982
sage: E.a4()
983
4
984
"""
985
return self.__ainvs[3]
986
987
def a6(self):
988
r"""
989
Returns the `a_6` invariant of this elliptic curve.
990
991
EXAMPLES::
992
993
sage: E = EllipticCurve([1,2,3,4,6])
994
sage: E.a6()
995
6
996
"""
997
return self.__ainvs[4]
998
999
def b_invariants(self):
1000
r"""
1001
Returns the `b`-invariants of this elliptic curve, as a tuple.
1002
1003
OUTPUT:
1004
1005
(tuple) - a 4-tuple of the `b`-invariants of this elliptic curve.
1006
1007
EXAMPLES::
1008
1009
sage: E = EllipticCurve([0, -1, 1, -10, -20])
1010
sage: E.b_invariants()
1011
(-4, -20, -79, -21)
1012
sage: E = EllipticCurve([-4,0])
1013
sage: E.b_invariants()
1014
(0, -8, 0, -16)
1015
1016
::
1017
1018
sage: E = EllipticCurve([1,2,3,4,5])
1019
sage: E.b_invariants()
1020
(9, 11, 29, 35)
1021
sage: E.b2()
1022
9
1023
sage: E.b4()
1024
11
1025
sage: E.b6()
1026
29
1027
sage: E.b8()
1028
35
1029
1030
ALGORITHM:
1031
1032
These are simple functions of the `a`-invariants.
1033
1034
AUTHORS:
1035
1036
- William Stein (2005-04-25)
1037
"""
1038
try:
1039
return self.__b_invariants
1040
except AttributeError:
1041
a1,a2,a3,a4,a6 = self.ainvs()
1042
self.__b_invariants = a1*a1 + 4*a2, \
1043
a1*a3 + 2*a4, \
1044
a3**2 + 4*a6, \
1045
a1**2 * a6 + 4*a2*a6 - a1*a3*a4 + a2*a3**2 - a4**2
1046
return self.__b_invariants
1047
1048
def b2(self):
1049
r"""
1050
Returns the `b_2` invariant of this elliptic curve.
1051
1052
EXAMPLES::
1053
1054
sage: E = EllipticCurve([1,2,3,4,5])
1055
sage: E.b2()
1056
9
1057
"""
1058
try:
1059
return self.__b_invariants[0]
1060
except AttributeError:
1061
return self.b_invariants()[0]
1062
1063
def b4(self):
1064
r"""
1065
Returns the `b_4` invariant of this elliptic curve.
1066
1067
EXAMPLES::
1068
1069
sage: E = EllipticCurve([1,2,3,4,5])
1070
sage: E.b4()
1071
11
1072
"""
1073
try:
1074
return self.__b_invariants[1]
1075
except AttributeError:
1076
return self.b_invariants()[1]
1077
1078
def b6(self):
1079
r"""
1080
Returns the `b_6` invariant of this elliptic curve.
1081
1082
EXAMPLES::
1083
1084
sage: E = EllipticCurve([1,2,3,4,5])
1085
sage: E.b6()
1086
29
1087
"""
1088
try:
1089
return self.__b_invariants[2]
1090
except AttributeError:
1091
return self.b_invariants()[2]
1092
1093
def b8(self):
1094
r"""
1095
Returns the `b_8` invariant of this elliptic curve.
1096
1097
EXAMPLES::
1098
1099
sage: E = EllipticCurve([1,2,3,4,5])
1100
sage: E.b8()
1101
35
1102
"""
1103
try:
1104
return self.__b_invariants[3]
1105
except AttributeError:
1106
return self.b_invariants()[3]
1107
1108
def c_invariants(self):
1109
r"""
1110
Returns the `c`-invariants of this elliptic curve, as a tuple.
1111
1112
OUTPUT:
1113
1114
(tuple) - a 2-tuple of the `c`-invariants of the elliptic curve.
1115
1116
EXAMPLES::
1117
1118
sage: E = EllipticCurve([0, -1, 1, -10, -20])
1119
sage: E.c_invariants()
1120
(496, 20008)
1121
sage: E = EllipticCurve([-4,0])
1122
sage: E.c_invariants()
1123
(192, 0)
1124
1125
ALGORITHM:
1126
1127
These are simple functions of the `a`-invariants.
1128
1129
AUTHORS:
1130
1131
- William Stein (2005-04-25)
1132
"""
1133
try:
1134
return self.__c_invariants
1135
except AttributeError:
1136
b2,b4,b6,b8 = self.b_invariants()
1137
self.__c_invariants = b2**2 - 24*b4,\
1138
-b2**3 + 36*b2*b4 - 216*b6 # note: c6 is wrong in Silverman, but right in Cremona
1139
return self.__c_invariants
1140
1141
def c4(self):
1142
r"""
1143
Returns the `c_4` invariant of this elliptic curve.
1144
1145
EXAMPLES::
1146
1147
sage: E = EllipticCurve([0, -1, 1, -10, -20])
1148
sage: E.c4()
1149
496
1150
"""
1151
try:
1152
return self.__c_invariants[0]
1153
except AttributeError:
1154
pass
1155
return self.c_invariants()[0]
1156
1157
def c6(self):
1158
r"""
1159
Returns the `c_6` invariant of this elliptic curve.
1160
1161
EXAMPLES::
1162
1163
sage: E = EllipticCurve([0, -1, 1, -10, -20])
1164
sage: E.c6()
1165
20008
1166
"""
1167
try:
1168
return self.__c_invariants[1]
1169
except AttributeError:
1170
pass
1171
return self.c_invariants()[1]
1172
1173
def discriminant(self):
1174
r"""
1175
Returns the discriminant of this elliptic curve.
1176
1177
EXAMPLES::
1178
1179
sage: E = EllipticCurve([0,0,1,-1,0])
1180
sage: E.discriminant()
1181
37
1182
sage: E = EllipticCurve([0, -1, 1, -10, -20])
1183
sage: E.discriminant()
1184
-161051
1185
1186
::
1187
1188
sage: E = EllipticCurve([GF(7)(2),1])
1189
sage: E.discriminant()
1190
1
1191
"""
1192
try:
1193
return self.__discriminant
1194
except AttributeError:
1195
b2, b4, b6, b8 = self.b_invariants()
1196
self.__discriminant = -b2**2*b8 - 8*b4**3 - 27*b6**2 + 9*b2*b4*b6
1197
return self.__discriminant
1198
1199
def j_invariant(self):
1200
r"""
1201
Returns the `j`-invariant of this elliptic curve.
1202
1203
EXAMPLES::
1204
1205
sage: E = EllipticCurve([0,0,1,-1,0])
1206
sage: E.j_invariant()
1207
110592/37
1208
sage: E = EllipticCurve([0, -1, 1, -10, -20])
1209
sage: E.j_invariant()
1210
-122023936/161051
1211
sage: E = EllipticCurve([-4,0])
1212
sage: E.j_invariant()
1213
1728
1214
1215
::
1216
1217
sage: E = EllipticCurve([GF(7)(2),1])
1218
sage: E.j_invariant()
1219
1
1220
"""
1221
try:
1222
return self.__j_invariant
1223
except AttributeError:
1224
c4, _ = self.c_invariants()
1225
self.__j_invariant = c4**3 / self.discriminant()
1226
return self.__j_invariant
1227
1228
1229
def base_extend(self, R):
1230
r"""
1231
Returns a new curve with the same `a`-invariants but defined over a new ring.
1232
1233
INPUT:
1234
1235
- ``R`` -- either a ring into which the curve's `a`-invariants
1236
may be coerced, or a morphism which may be applied to them.
1237
1238
OUTPUT:
1239
1240
A new elliptic curve with the same `a`-invariants, defined over the new ring.
1241
1242
EXAMPLES::
1243
1244
sage: E=EllipticCurve(GF(5),[1,1]); E
1245
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5
1246
sage: E1=E.base_extend(GF(125,'a')); E1
1247
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 5^3
1248
sage: F2=GF(5^2,'a'); a=F2.gen()
1249
sage: F4=GF(5^4,'b'); b=F4.gen()
1250
sage: h=F2.hom([a.charpoly().roots(ring=F4,multiplicities=False)[0]],F4)
1251
sage: E=EllipticCurve(F2,[1,a]); E
1252
Elliptic Curve defined by y^2 = x^3 + x + a over Finite Field in a of size 5^2
1253
sage: E.base_extend(h)
1254
Elliptic Curve defined by y^2 = x^3 + x + (4*b^3+4*b^2+4*b+3) over Finite Field in b of size 5^4
1255
"""
1256
return constructor.EllipticCurve([R(a) for a in self.a_invariants()])
1257
1258
change_ring = base_extend
1259
1260
def base_ring(self):
1261
r"""
1262
Returns the base ring of the elliptic curve.
1263
1264
EXAMPLES::
1265
1266
sage: E = EllipticCurve(GF(49, 'a'), [3,5])
1267
sage: E.base_ring()
1268
Finite Field in a of size 7^2
1269
1270
::
1271
1272
sage: E = EllipticCurve([1,1])
1273
sage: E.base_ring()
1274
Rational Field
1275
1276
::
1277
1278
sage: E = EllipticCurve(ZZ, [3,5])
1279
sage: E.base_ring()
1280
Integer Ring
1281
"""
1282
return self.__base_ring
1283
1284
def gens(self):
1285
r"""
1286
Placeholder function to return generators of an elliptic curve.
1287
1288
.. note::
1289
1290
This functionality is implemented in certain derived
1291
classes, such as EllipticCurve_rational_field.
1292
1293
EXAMPLES::
1294
1295
sage: R.<a1,a2,a3,a4,a6>=QQ[]
1296
sage: E=EllipticCurve([a1,a2,a3,a4,a6])
1297
sage: E.gens()
1298
Traceback (most recent call last):
1299
...
1300
NotImplementedError: not implemented.
1301
sage: E=EllipticCurve(QQ,[1,1])
1302
sage: E.gens()
1303
[(0 : 1 : 1)]
1304
"""
1305
raise NotImplementedError, "not implemented."
1306
1307
def gen(self, i):
1308
r"""
1309
Function returning the i'th generator of this elliptic curve.
1310
1311
.. note::
1312
1313
Relies on gens() being implemented.
1314
1315
EXAMPLES::
1316
1317
sage: R.<a1,a2,a3,a4,a6>=QQ[]
1318
sage: E=EllipticCurve([a1,a2,a3,a4,a6])
1319
sage: E.gen(0)
1320
Traceback (most recent call last):
1321
...
1322
NotImplementedError: not implemented.
1323
"""
1324
return self.gens()[i]
1325
1326
def rst_transform(self, r, s, t):
1327
r"""
1328
Returns the transform of the curve by `(r,s,t)` (with `u=1`).
1329
1330
INPUT:
1331
1332
- ``r``, ``s``, ``t`` -- three elements of the base ring.
1333
1334
OUTPUT:
1335
1336
The elliptic curve obtained from self by the standard
1337
Weierstrass transformation `(u,r,s,t)` with `u=1`.
1338
1339
.. note::
1340
1341
This is just a special case of ``change_weierstrass_model()``, with `u=1`.
1342
1343
EXAMPLES::
1344
1345
sage: R.<r,s,t>=QQ[]
1346
sage: E=EllipticCurve([1,2,3,4,5])
1347
sage: E.rst_transform(r,s,t)
1348
Elliptic Curve defined by y^2 + (2*s+1)*x*y + (r+2*t+3)*y = x^3 + (-s^2+3*r-s+2)*x^2 + (3*r^2-r*s-2*s*t+4*r-3*s-t+4)*x + (r^3+2*r^2-r*t-t^2+4*r-3*t+5) over Multivariate Polynomial Ring in r, s, t over Rational Field
1349
"""
1350
return self.change_weierstrass_model(1,r,s,t)
1351
1352
def scale_curve(self, u):
1353
r"""
1354
Returns the transform of the curve by scale factor `u`.
1355
1356
INPUT:
1357
1358
- ``u`` -- an invertible element of the base ring.
1359
1360
OUTPUT:
1361
1362
The elliptic curve obtained from self by the standard
1363
Weierstrass transformation `(u,r,s,t)` with `r=s=t=0`.
1364
1365
.. note::
1366
1367
This is just a special case of ``change_weierstrass_model()``, with `r=s=t=0`.
1368
1369
EXAMPLES::
1370
1371
sage: K=Frac(PolynomialRing(QQ,'u'))
1372
sage: u=K.gen()
1373
sage: E=EllipticCurve([1,2,3,4,5])
1374
sage: E.scale_curve(u)
1375
Elliptic Curve defined by y^2 + u*x*y + 3*u^3*y = x^3 + 2*u^2*x^2 + 4*u^4*x + 5*u^6 over Fraction Field of Univariate Polynomial Ring in u over Rational Field
1376
"""
1377
if isinstance(u, (int,long)):
1378
u=self.base_ring()(u) # because otherwise 1/u would round!
1379
return self.change_weierstrass_model(1/u,0,0,0)
1380
1381
def discriminant(self):
1382
r"""
1383
Returns the discriminant of this elliptic curve.
1384
1385
EXAMPLES::
1386
1387
sage: E = EllipticCurve([0,0,1,-1,0])
1388
sage: E.discriminant()
1389
37
1390
sage: E = EllipticCurve([0, -1, 1, -10, -20])
1391
sage: E.discriminant()
1392
-161051
1393
1394
::
1395
1396
sage: E = EllipticCurve([GF(7)(2),1])
1397
sage: E.discriminant()
1398
1
1399
"""
1400
try:
1401
return self.__discriminant
1402
except AttributeError:
1403
b2, b4, b6, b8 = self.b_invariants()
1404
self.__discriminant = -b2**2*b8 - 8*b4**3 - 27*b6**2 + 9*b2*b4*b6
1405
return self.__discriminant
1406
1407
def j_invariant(self):
1408
r"""
1409
Returns the j-invariant of this elliptic curve.
1410
1411
EXAMPLES::
1412
1413
sage: E = EllipticCurve([0,0,1,-1,0])
1414
sage: E.j_invariant()
1415
110592/37
1416
sage: E = EllipticCurve([0, -1, 1, -10, -20])
1417
sage: E.j_invariant()
1418
-122023936/161051
1419
sage: E = EllipticCurve([-4,0])
1420
sage: E.j_invariant()
1421
1728
1422
1423
::
1424
1425
sage: E = EllipticCurve([GF(7)(2),1])
1426
sage: E.j_invariant()
1427
1
1428
"""
1429
try:
1430
return self.__j_invariant
1431
except AttributeError:
1432
c4, _ = self.c_invariants()
1433
self.__j_invariant = c4**3 / self.discriminant()
1434
return self.__j_invariant
1435
1436
#############################################################
1437
#
1438
# Explanation of the division (also known as torsion) polynomial
1439
# functions in Sage.
1440
#
1441
# The main user function division_polynomial() (also aliased as
1442
# torsion_polynomial()) is used to compute polynomials whose roots
1443
# determine the $m$-torsion points on the curve. Three options are
1444
# available, which effect the result when $m$ is even and also the
1445
# parent ring of the returned value. The function can return either a
1446
# polynomial or the evaluation of that polynomial at a point,
1447
# depending on the input. Values are cached.
1448
#
1449
# The options are controlled by the value of the parameter
1450
# two_torsion_multiplicity, which may be 0, 1 or 2. If it is 0 or 2,
1451
# then a univariate polynomial will be returned (or evaluated at the
1452
# parameter x if x is not None). This is the polynomial whose roots
1453
# are the values of $x(P)$ at the nonzero points $P$ where $m*P=0$
1454
# (when two_torsion_multiplicity==2), or the points where $m*P=0$ but
1455
# $2*P\not=0$ (when two_torsion_multiplicity==0).
1456
#
1457
# If two_torsion_multiplicity==1, then a bivariate polynomial is
1458
# returned, which (as a function on the curve) has a simple zero at
1459
# each nonzero point $P$ such that $m*P=0$. When $m$ is odd this is a
1460
# polynomial in $x$ alone, but is still returned as an element of a
1461
# polynomial ring in two variables; when $m$ is even it has a factor
1462
# $2y+a_1x+a_3$. In this case if the parameter x is not None then it
1463
# should be a tuple of length 2, or a point P on the curve, and the
1464
# returned value is the value of the bivariate polynomial at this
1465
# point.
1466
#
1467
# Comparison with Magma: Magma's function DivisionPolynomial(E,m)
1468
# returns a triple of univariate polynomials $f,g,h$ where $f$ is
1469
# \code{E.division_polynomial(m,two_torsion_multiplicity=2)}, $g$ is
1470
# \code{E.division_polynomial(m,two_torsion_multiplicity=0)} and $h$
1471
# is the quotient, so that $h=1$ when $m$ is odd.
1472
1473
#############################################################
1474
1475
def division_polynomial_0(self, n, x=None, cache=None):
1476
r"""
1477
Returns the `n^{th}` torsion (division) polynomial, without
1478
the 2-torsion factor if `n` is even, as a polynomial in `x`.
1479
1480
These are the polynomials `g_n` defined in Mazur/Tate
1481
("The p-adic sigma function"), but with the sign flipped for even
1482
`n`, so that the leading coefficient is always positive.
1483
1484
.. note::
1485
1486
This function is intended for internal use; users should use
1487
:meth:`.division_polynomial`.
1488
1489
.. seealso::
1490
1491
:meth:`multiple_x_numerator`
1492
:meth:`multiple_x_denominator`
1493
:meth:`division_polynomial`
1494
1495
INPUT:
1496
1497
1498
- ``n`` - positive integer, or the special values `-1`
1499
and `-2` which mean `B_6 = (2y + a_1 x + a_3)^2` and
1500
`B_6^2` respectively (in the notation of Mazur/Tate).
1501
1502
- ``x`` - optional ring element to use as the "x"
1503
variable. If x is None, then a new polynomial ring will be
1504
constructed over the base ring of the elliptic curve, and its
1505
generator will be used as x. Note that x does not need to be a
1506
generator of a polynomial ring; any ring element is ok. This
1507
permits fast calculation of the torsion polynomial *evaluated* on
1508
any element of a ring.
1509
1510
- ``cache`` - optional dictionary, with integer keys.
1511
If the key m is in cache, then cache[m] is assumed to be the value
1512
of division_polynomial_0(m) for the supplied x. New entries will
1513
be added to the cache as they are computed.
1514
1515
1516
ALGORITHM:
1517
1518
Recursion described in Mazur/Tate. The recursive
1519
formulae are evaluated `O((log n)^2)` times.
1520
1521
AUTHORS:
1522
1523
- David Harvey (2006-09-24): initial version
1524
1525
- John Cremona (2008-08-26): unified division polynomial code
1526
1527
EXAMPLES::
1528
1529
sage: E = EllipticCurve("37a")
1530
sage: E.division_polynomial_0(1)
1531
1
1532
sage: E.division_polynomial_0(2)
1533
1
1534
sage: E.division_polynomial_0(3)
1535
3*x^4 - 6*x^2 + 3*x - 1
1536
sage: E.division_polynomial_0(4)
1537
2*x^6 - 10*x^4 + 10*x^3 - 10*x^2 + 2*x + 1
1538
sage: E.division_polynomial_0(5)
1539
5*x^12 - 62*x^10 + 95*x^9 - 105*x^8 - 60*x^7 + 285*x^6 - 174*x^5 - 5*x^4 - 5*x^3 + 35*x^2 - 15*x + 2
1540
sage: E.division_polynomial_0(6)
1541
3*x^16 - 72*x^14 + 168*x^13 - 364*x^12 + 1120*x^10 - 1144*x^9 + 300*x^8 - 540*x^7 + 1120*x^6 - 588*x^5 - 133*x^4 + 252*x^3 - 114*x^2 + 22*x - 1
1542
sage: E.division_polynomial_0(7)
1543
7*x^24 - 308*x^22 + 986*x^21 - 2954*x^20 + 28*x^19 + 17171*x^18 - 23142*x^17 + 511*x^16 - 5012*x^15 + 43804*x^14 - 7140*x^13 - 96950*x^12 + 111356*x^11 - 19516*x^10 - 49707*x^9 + 40054*x^8 - 124*x^7 - 18382*x^6 + 13342*x^5 - 4816*x^4 + 1099*x^3 - 210*x^2 + 35*x - 3
1544
sage: E.division_polynomial_0(8)
1545
4*x^30 - 292*x^28 + 1252*x^27 - 5436*x^26 + 2340*x^25 + 39834*x^24 - 79560*x^23 + 51432*x^22 - 142896*x^21 + 451596*x^20 - 212040*x^19 - 1005316*x^18 + 1726416*x^17 - 671160*x^16 - 954924*x^15 + 1119552*x^14 + 313308*x^13 - 1502818*x^12 + 1189908*x^11 - 160152*x^10 - 399176*x^9 + 386142*x^8 - 220128*x^7 + 99558*x^6 - 33528*x^5 + 6042*x^4 + 310*x^3 - 406*x^2 + 78*x - 5
1546
1547
::
1548
1549
sage: E.division_polynomial_0(18) % E.division_polynomial_0(6) == 0
1550
True
1551
1552
An example to illustrate the relationship with torsion points::
1553
1554
sage: F = GF(11)
1555
sage: E = EllipticCurve(F, [0, 2]); E
1556
Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field of size 11
1557
sage: f = E.division_polynomial_0(5); f
1558
5*x^12 + x^9 + 8*x^6 + 4*x^3 + 7
1559
sage: f.factor()
1560
(5) * (x^2 + 5) * (x^2 + 2*x + 5) * (x^2 + 5*x + 7) * (x^2 + 7*x + 7) * (x^2 + 9*x + 5) * (x^2 + 10*x + 7)
1561
1562
This indicates that the x-coordinates of all the 5-torsion points
1563
of `E` are in `GF(11^2)`, and therefore the
1564
`y`-coordinates are in `\GF(11^4)`::
1565
1566
sage: K = GF(11^4, 'a')
1567
sage: X = E.change_ring(K)
1568
sage: f = X.division_polynomial_0(5)
1569
sage: x_coords = f.roots(multiplicities=False); x_coords
1570
[10*a^3 + 4*a^2 + 5*a + 6,
1571
9*a^3 + 8*a^2 + 10*a + 8,
1572
8*a^3 + a^2 + 4*a + 10,
1573
8*a^3 + a^2 + 4*a + 8,
1574
8*a^3 + a^2 + 4*a + 4,
1575
6*a^3 + 9*a^2 + 3*a + 4,
1576
5*a^3 + 2*a^2 + 8*a + 7,
1577
3*a^3 + 10*a^2 + 7*a + 8,
1578
3*a^3 + 10*a^2 + 7*a + 3,
1579
3*a^3 + 10*a^2 + 7*a + 1,
1580
2*a^3 + 3*a^2 + a + 7,
1581
a^3 + 7*a^2 + 6*a]
1582
1583
Now we check that these are exactly the `x`-coordinates of the
1584
5-torsion points of `E`::
1585
1586
sage: for x in x_coords:
1587
... assert X.lift_x(x).order() == 5
1588
1589
The roots of the polynomial are the `x`-coordinates of the points `P`
1590
such that `mP=0` but `2P\not=0`::
1591
1592
sage: E=EllipticCurve('14a1')
1593
sage: T=E.torsion_subgroup()
1594
sage: [n*T.0 for n in range(6)]
1595
[(0 : 1 : 0),
1596
(9 : 23 : 1),
1597
(2 : 2 : 1),
1598
(1 : -1 : 1),
1599
(2 : -5 : 1),
1600
(9 : -33 : 1)]
1601
sage: pol=E.division_polynomial_0(6)
1602
sage: xlist=pol.roots(multiplicities=False); xlist
1603
[9, 2, -1/3, -5]
1604
sage: [E.lift_x(x, all=True) for x in xlist]
1605
[[(9 : 23 : 1), (9 : -33 : 1)], [(2 : 2 : 1), (2 : -5 : 1)], [], []]
1606
1607
.. note::
1608
1609
The point of order 2 and the identity do not appear.
1610
The points with `x=-1/3` and `x=-5` are not rational.
1611
"""
1612
if x is None:
1613
x = rings.PolynomialRing(self.base_ring(), 'x').gen()
1614
1615
if cache is None:
1616
cache = {}
1617
else:
1618
try:
1619
return cache[(n,x)]
1620
except KeyError:
1621
pass
1622
1623
b2, b4, b6, b8 = self.b_invariants()
1624
1625
n = int(n)
1626
if n <= 4:
1627
if n == -1:
1628
answer = 4*x**3 + b2*x**2 + 2*b4*x + b6
1629
elif n == -2:
1630
answer = self.division_polynomial_0(-1, x, cache) ** 2
1631
elif n == 1 or n == 2:
1632
answer = x.parent()(1)
1633
elif n == 3:
1634
answer = 3*x**4 + b2*x**3 + 3*b4*x**2 + 3*b6*x + b8
1635
elif n == 4:
1636
answer = -self.division_polynomial_0(-2, x, cache) + \
1637
(6*x**2 + b2*x + b4) * \
1638
self.division_polynomial_0(3, x, cache)
1639
else:
1640
raise ValueError, "n must be a positive integer (or -1 or -2)"
1641
else:
1642
if n % 2 == 0:
1643
m = (n-2) // 2
1644
g_mplus3 = self.division_polynomial_0(m+3, x, cache)
1645
g_mplus2 = self.division_polynomial_0(m+2, x, cache)
1646
g_mplus1 = self.division_polynomial_0(m+1, x, cache)
1647
g_m = self.division_polynomial_0(m, x, cache)
1648
g_mless1 = self.division_polynomial_0(m-1, x, cache)
1649
answer = g_mplus1 * \
1650
(g_mplus3 * g_m**2 - g_mless1 * g_mplus2**2)
1651
else:
1652
m = (n-1) // 2
1653
g_mplus2 = self.division_polynomial_0(m+2, x, cache)
1654
g_mplus1 = self.division_polynomial_0(m+1, x, cache)
1655
g_m = self.division_polynomial_0(m, x, cache)
1656
g_mless1 = self.division_polynomial_0(m-1, x, cache)
1657
B6_sqr = self.division_polynomial_0(-2, x, cache)
1658
if m % 2 == 0:
1659
answer = B6_sqr * g_mplus2 * g_m**3 - \
1660
g_mless1 * g_mplus1**3
1661
else:
1662
answer = g_mplus2 * g_m**3 - \
1663
B6_sqr * g_mless1 * g_mplus1**3
1664
1665
cache[(n,x)] = answer
1666
return answer
1667
1668
def two_division_polynomial(self, x = None):
1669
r"""
1670
Returns the 2-division polynomial of this elliptic curve evaluated
1671
at ``x``.
1672
1673
INPUT:
1674
1675
- ``x`` - optional ring element to use as the `x` variable. If
1676
``x`` is ``None``, then a new polynomial ring will be
1677
constructed over the base ring of the elliptic curve, and
1678
its generator will be used as ``x``. Note that ``x`` does
1679
not need to be a generator of a polynomial ring; any ring
1680
element is ok. This permits fast calculation of the torsion
1681
polynomial *evaluated* on any element of a ring.
1682
1683
1684
EXAMPLES::
1685
1686
sage: E=EllipticCurve('5077a1')
1687
sage: E.two_division_polynomial()
1688
4*x^3 - 28*x + 25
1689
sage: E=EllipticCurve(GF(3^2,'a'),[1,1,1,1,1])
1690
sage: E.two_division_polynomial()
1691
x^3 + 2*x^2 + 2
1692
sage: E.two_division_polynomial().roots()
1693
[(2, 1), (2*a, 1), (a + 2, 1)]
1694
"""
1695
return self.division_polynomial_0(-1,x)
1696
1697
def division_polynomial(self, m, x=None, two_torsion_multiplicity=2):
1698
r"""
1699
Returns the `m^{th}` division polynomial of this elliptic
1700
curve evaluated at ``x``.
1701
1702
INPUT:
1703
1704
1705
- ``m`` - positive integer.
1706
1707
- ``x`` - optional ring element to use as the "x"
1708
variable. If x is None, then a new polynomial ring will be
1709
constructed over the base ring of the elliptic curve, and its
1710
generator will be used as x. Note that x does not need to be a
1711
generator of a polynomial ring; any ring element is ok. This
1712
permits fast calculation of the torsion polynomial *evaluated* on
1713
any element of a ring.
1714
1715
- ``two_torsion_multiplicity`` - 0,1 or 2
1716
1717
If 0: for even `m` when x is None, a univariate polynomial
1718
over the base ring of the curve is returned, which omits
1719
factors whose roots are the `x`-coordinates of the
1720
`2`-torsion points. Similarly when `x` is not none, the
1721
evaluation of such a polynomial at `x` is returned.
1722
1723
If 2: for even `m` when x is None, a univariate polynomial
1724
over the base ring of the curve is returned, which includes a
1725
factor of degree 3 whose roots are the `x`-coordinates of
1726
the `2`-torsion points. Similarly when `x` is not
1727
none, the evaluation of such a polynomial at `x` is
1728
returned.
1729
1730
If 1: when x is None, a bivariate polynomial over the base
1731
ring of the curve is returned, which includes a factor
1732
`2*y+a1*x+a3` which has simple zeros at the `2`-torsion
1733
points. When `x` is not none, it should be a tuple of
1734
length 2, and the evaluation of such a polynomial at `x`
1735
is returned.
1736
1737
EXAMPLES::
1738
1739
sage: E = EllipticCurve([0,0,1,-1,0])
1740
sage: E.division_polynomial(1)
1741
1
1742
sage: E.division_polynomial(2, two_torsion_multiplicity=0)
1743
1
1744
sage: E.division_polynomial(2, two_torsion_multiplicity=1)
1745
2*y + 1
1746
sage: E.division_polynomial(2, two_torsion_multiplicity=2)
1747
4*x^3 - 4*x + 1
1748
sage: E.division_polynomial(2)
1749
4*x^3 - 4*x + 1
1750
sage: [E.division_polynomial(3, two_torsion_multiplicity=i) for i in range(3)]
1751
[3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1]
1752
sage: [type(E.division_polynomial(3, two_torsion_multiplicity=i)) for i in range(3)]
1753
[<type 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>,
1754
<type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>,
1755
<type 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>]
1756
1757
::
1758
1759
sage: E = EllipticCurve([0, -1, 1, -10, -20])
1760
sage: R.<z>=PolynomialRing(QQ)
1761
sage: E.division_polynomial(4,z,0)
1762
2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821
1763
sage: E.division_polynomial(4,z)
1764
8*z^9 - 24*z^8 - 464*z^7 - 2758*z^6 + 6636*z^5 + 34356*z^4 + 53510*z^3 + 99714*z^2 + 351024*z + 459859
1765
1766
This does not work, since when two_torsion_multiplicity is 1, we
1767
compute a bivariate polynomial, and must evaluate at a tuple of
1768
length 2::
1769
1770
sage: E.division_polynomial(4,z,1)
1771
Traceback (most recent call last):
1772
...
1773
ValueError: x should be a tuple of length 2 (or None) when two_torsion_multiplicity is 1
1774
sage: R.<z,w>=PolynomialRing(QQ,2)
1775
sage: E.division_polynomial(4,(z,w),1).factor()
1776
(2*w + 1) * (2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821)
1777
1778
We can also evaluate this bivariate polynomial at a point::
1779
1780
sage: P = E(5,5)
1781
sage: E.division_polynomial(4,P,two_torsion_multiplicity=1)
1782
-1771561
1783
"""
1784
1785
if not two_torsion_multiplicity in [0,1,2]:
1786
raise ValueError, "two_torsion_multiplicity must be 0,1 or 2"
1787
1788
# Coerce the input m to be an integer
1789
m = rings.Integer(m)
1790
1791
if two_torsion_multiplicity == 0:
1792
try:
1793
return self.__divpoly0[(m,x)]
1794
except AttributeError:
1795
self.__divpoly0 = {}
1796
except KeyError:
1797
pass
1798
f = self.division_polynomial_0(m,x)
1799
self.__divpoly0[(m,x)] = f
1800
return f
1801
1802
if two_torsion_multiplicity == 1:
1803
try:
1804
return self.__divpoly1[(m,x)]
1805
except AttributeError:
1806
self.__divpoly1 = {}
1807
except KeyError:
1808
pass
1809
xy = x
1810
R, (x,y) = PolynomialRing(self.base_ring(), 2, 'x,y').objgens()
1811
a1,a2,a3,a4,a6 = self.a_invariants()
1812
f = self.division_polynomial_0(m,x)
1813
if m % 2 == 0:
1814
f *= (2*y+a1*x+a3)
1815
if xy is None:
1816
self.__divpoly1[(m,(x,y))] = f
1817
return f
1818
else:
1819
if isinstance(xy,tuple) and len(xy)==2 or isinstance(xy, ell_point.EllipticCurvePoint_field):
1820
fxy = f(xy[0],xy[1])
1821
self.__divpoly1[(m,xy)] = fxy
1822
return fxy
1823
else:
1824
raise ValueError, "x should be a tuple of length 2 (or None) when two_torsion_multiplicity is 1"
1825
1826
if two_torsion_multiplicity == 2:
1827
try:
1828
return self.__divpoly2[(m,x)]
1829
except AttributeError:
1830
self.__divpoly2 = {}
1831
except KeyError:
1832
pass
1833
f = self.division_polynomial_0(m,x)
1834
if m%2 == 0:
1835
f *= self.division_polynomial_0(-1,x)
1836
self.__divpoly2[(m,x)] = f
1837
return f
1838
1839
torsion_polynomial = division_polynomial
1840
1841
def _multiple_x_numerator(self, n, x=None, cache=None):
1842
r"""
1843
Returns the numerator of the `x`-coordinate of the `n\th` multiple of a
1844
point, using torsion polynomials (division polynomials).
1845
1846
INPUT:
1847
1848
- ``n``, ``x``, ``cache`` -- as described in ``division_polynomial_0()``.
1849
1850
The result is cached. This is so that on calling
1851
``P.division_points(n)`` for the same `n` and different
1852
points `P` (on the same curve), we do not have to recompute
1853
the polynomials.
1854
1855
.. warning::
1856
1857
There may of course be cancellation between the numerator
1858
and the denominator (_multiple_x_denominator()). Be
1859
careful. E.g. if a point on an elliptic curve with
1860
coefficients in ZZ reduces to a singular point modulo a
1861
prime, then there will be cancellation, otherwise not, see
1862
Chris Wuthrich' p-adic heights in families of elliptic
1863
curves'.
1864
1865
.. seealso::
1866
1867
:meth:`_multiple_x_denominator`
1868
1869
AUTHORS:
1870
1871
- David Harvey (2006-09-24)
1872
1873
EXAMPLES::
1874
1875
sage: E = EllipticCurve("37a")
1876
sage: P = E.gens()[0]
1877
sage: x = P[0]
1878
1879
::
1880
1881
sage: (35*P)[0]
1882
-804287518035141565236193151/1063198259901027900600665796
1883
sage: E._multiple_x_numerator(35, x)
1884
-804287518035141565236193151
1885
sage: E._multiple_x_denominator(35, x)
1886
1063198259901027900600665796
1887
1888
::
1889
1890
sage: (36*P)[0]
1891
54202648602164057575419038802/15402543997324146892198790401
1892
sage: E._multiple_x_numerator(36, x)
1893
54202648602164057575419038802
1894
sage: E._multiple_x_denominator(36, x)
1895
15402543997324146892198790401
1896
1897
An example where cancellation occurs::
1898
1899
sage: E = EllipticCurve("88a1")
1900
sage: P = E([2,2]) # fixed choice of generator
1901
sage: n = E._multiple_x_numerator(11, P[0]); n
1902
442446784738847563128068650529343492278651453440
1903
sage: d = E._multiple_x_denominator(11, P[0]); d
1904
1427247692705959881058285969449495136382746624
1905
sage: n/d
1906
310
1907
sage: 11*P
1908
(310 : -5458 : 1)
1909
"""
1910
if x is None:
1911
x = rings.PolynomialRing(self.base_ring(), 'x').gen()
1912
1913
try:
1914
return self._mul_x_num_cache[(n,x)]
1915
except AttributeError:
1916
self._mul_x_num_cache = {}
1917
except KeyError:
1918
pass
1919
1920
if cache is None:
1921
cache = {}
1922
1923
n = int(n)
1924
if n < 2:
1925
print "n must be at least 2"
1926
1927
self.division_polynomial_0( -2, x, cache)
1928
self.division_polynomial_0(n-1, x, cache)
1929
self.division_polynomial_0(n , x, cache)
1930
self.division_polynomial_0(n+1, x, cache)
1931
1932
if n % 2 == 0:
1933
self._mul_x_num_cache[(n,x)] = x * cache[(-1,x)] * cache[(n,x)]**2 - cache[(n-1,x)] * cache[(n+1,x)]
1934
else:
1935
self._mul_x_num_cache[(n,x)] = x * cache[(n,x)]**2 - cache[(-1,x)] * cache[(n-1,x)] * cache[(n+1,x)]
1936
return self._mul_x_num_cache[(n,x)]
1937
1938
1939
def _multiple_x_denominator(self, n, x=None, cache=None):
1940
r"""
1941
Returns the denominator of the x-coordinate of the nth multiple of
1942
a point, using torsion polynomials (division polynomials).
1943
1944
INPUT:
1945
1946
- ``n``, ``x``, ``cache`` -- as described in ``division_polynomial_0()``.
1947
1948
The result is cached. This is so that calling
1949
P.division_points(n) for the same n and different points P
1950
(on the same curve) does not have to recompute the
1951
polynomials.
1952
1953
.. seealso::
1954
1955
:meth:`multiple_x_numerator`
1956
1957
TODO: the numerator and denominator versions share a calculation,
1958
namely squaring `\psi_n`. Maybe would be good to offer a
1959
combined version to make this more efficient.
1960
1961
EXAMPLES::
1962
1963
sage: E = EllipticCurve("43a")
1964
sage: P = E.gens()[0]
1965
sage: x = P[0]
1966
sage: (31*P)[0]
1967
-33058398375463796474831580/154693637754223970056975321
1968
sage: E._multiple_x_numerator(31, x)
1969
-33058398375463796474831580
1970
sage: E._multiple_x_denominator(31, x)
1971
154693637754223970056975321
1972
1973
AUTHORS:
1974
1975
- David Harvey (2006-09-24)
1976
"""
1977
if x is None:
1978
x = rings.PolynomialRing(self.base_ring(), 'x').gen()
1979
1980
try:
1981
return self._mul_x_den_cache[(n,x)]
1982
except AttributeError:
1983
self._mul_x_den_cache = {}
1984
except KeyError:
1985
pass
1986
1987
if cache is None:
1988
cache = {}
1989
1990
n = int(n)
1991
if n < 2:
1992
print "n must be at least 2"
1993
1994
self.division_polynomial_0(-2, x, cache)
1995
self.division_polynomial_0(n , x, cache)
1996
1997
if n % 2 == 0:
1998
self._mul_x_den_cache[(n,x)] = cache[(-1,x)] * cache[(n,x)]**2
1999
else:
2000
self._mul_x_den_cache[(n,x)] = cache[(n,x)]**2
2001
return self._mul_x_den_cache[(n,x)]
2002
2003
2004
def multiplication_by_m(self, m, x_only=False):
2005
r"""
2006
Return the multiplication-by-`m` map from ``self`` to ``self``
2007
2008
The result is a pair of rational functions in two variables
2009
`x`, `y` (or a rational function in one variable `x` if
2010
``x_only`` is ``True``).
2011
2012
INPUT:
2013
2014
- ``m`` - a nonzero integer
2015
2016
- ``x_only`` - boolean (default: ``False``) if ``True``, return
2017
only the `x`-coordinate of the map (as a rational function
2018
in one variable).
2019
2020
OUTPUT:
2021
2022
- a pair `(f(x), g(x,y))`, where `f` and `g` are rational
2023
functions with the degree of `y` in `g(x,y)` exactly 1,
2024
2025
- or just `f(x)` if ``x_only`` is ``True``
2026
2027
.. NOTE::
2028
2029
- The result is not cached.
2030
2031
- ``m`` is allowed to be negative (but not 0).
2032
2033
EXAMPLES::
2034
2035
sage: E = EllipticCurve([-1,3])
2036
2037
We verify that multiplication by 1 is just the identity::
2038
2039
sage: E.multiplication_by_m(1)
2040
(x, y)
2041
2042
Multiplication by 2 is more complicated::
2043
2044
sage: f = E.multiplication_by_m(2)
2045
sage: f
2046
((x^4 + 2*x^2 - 24*x + 1)/(4*x^3 - 4*x + 12), (8*x^6*y - 40*x^4*y + 480*x^3*y - 40*x^2*y + 96*x*y - 568*y)/(64*x^6 - 128*x^4 + 384*x^3 + 64*x^2 - 384*x + 576))
2047
2048
Grab only the x-coordinate (less work)::
2049
2050
sage: mx = E.multiplication_by_m(2, x_only=True); mx
2051
(x^4 + 2*x^2 - 24*x + 1)/(4*x^3 - 4*x + 12)
2052
sage: mx.parent()
2053
Fraction Field of Univariate Polynomial Ring in x over Rational Field
2054
2055
We check that it works on a point::
2056
2057
sage: P = E([2,3])
2058
sage: eval = lambda f,P: [fi(P[0],P[1]) for fi in f]
2059
sage: assert E(eval(f,P)) == 2*P
2060
2061
We do the same but with multiplication by 3::
2062
2063
sage: f = E.multiplication_by_m(3)
2064
sage: assert E(eval(f,P)) == 3*P
2065
2066
And the same with multiplication by 4::
2067
2068
sage: f = E.multiplication_by_m(4)
2069
sage: assert E(eval(f,P)) == 4*P
2070
2071
And the same with multiplication by -1,-2,-3,-4::
2072
2073
sage: for m in [-1,-2,-3,-4]:
2074
....: f = E.multiplication_by_m(m)
2075
....: assert E(eval(f,P)) == m*P
2076
2077
TESTS:
2078
2079
Verify for this fairly random looking curve and point that
2080
multiplication by m returns the right result for the first 10
2081
integers::
2082
2083
sage: E = EllipticCurve([23,-105])
2084
sage: P = E([129/4, 1479/8])
2085
sage: for n in [1..10]:
2086
....: f = E.multiplication_by_m(n)
2087
....: Q = n*P
2088
....: assert Q == E(eval(f,P))
2089
....: f = E.multiplication_by_m(-n)
2090
....: Q = -n*P
2091
....: assert Q == E(eval(f,P))
2092
2093
The following test shows that :trac:`4364` is indeed fixed::
2094
2095
sage: p = next_prime(2^30-41)
2096
sage: a = GF(p)(1)
2097
sage: b = GF(p)(1)
2098
sage: E = EllipticCurve([a, b])
2099
sage: P = E.random_point()
2100
sage: my_eval = lambda f,P: [fi(P[0],P[1]) for fi in f]
2101
sage: f = E.multiplication_by_m(2)
2102
sage: assert(E(eval(f,P)) == 2*P)
2103
"""
2104
# Coerce the input m to be an integer
2105
m = rings.Integer(m)
2106
if m == 0:
2107
raise ValueError("m must be a non-zero integer")
2108
2109
if x_only:
2110
x = polygen(self.base_ring(), 'x')
2111
else:
2112
x, y = polygens(self.base_ring(), 'x,y')
2113
2114
# Special case of multiplication by 1 is easy.
2115
if m == 1:
2116
if not x_only:
2117
return (x, y)
2118
else:
2119
return x
2120
2121
# Grab curve invariants
2122
a1, a2, a3, a4, a6 = self.a_invariants()
2123
2124
if m == -1:
2125
if not x_only:
2126
return (x, -y-a1*x-a3)
2127
else:
2128
return x
2129
2130
# the x-coordinate does not depend on the sign of m. The work
2131
# here is done by functions defined earlier:
2132
2133
mx = (x.parent()(self._multiple_x_numerator(m.abs(), x))
2134
/ x.parent()(self._multiple_x_denominator(m.abs(), x)))
2135
2136
if x_only:
2137
# Return it if the optional parameter x_only is set.
2138
return mx
2139
2140
# Consideration of the invariant differential
2141
# w=dx/(2*y+a1*x+a3) shows that m*w = d(mx)/(2*my+a1*mx+a3)
2142
# and hence 2*my+a1*mx+a3 = (1/m)*(2*y+a1*x+a3)*d(mx)/dx
2143
2144
my = ((2*y+a1*x+a3)*mx.derivative(x)/m - a1*mx-a3)/2
2145
2146
return mx, my
2147
2148
def multiplication_by_m_isogeny(self, m):
2149
r"""
2150
Return the ``EllipticCurveIsogeny`` object associated to the
2151
multiplication-by-`m` map on self. The resulting isogeny will
2152
have the associated rational maps (i.e. those returned by
2153
`self.multiplication_by_m()`) already computed.
2154
2155
NOTE: This function is currently *much* slower than the
2156
result of ``self.multiplication_by_m()``, because
2157
constructing an isogeny precomputes a significant amount
2158
of information. See trac tickets #7368 and #8014 for the
2159
status of improving this situation.
2160
2161
INPUT:
2162
2163
- ``m`` - a nonzero integer
2164
2165
OUTPUT:
2166
2167
- An ``EllipticCurveIsogeny`` object associated to the
2168
multiplication-by-`m` map on self.
2169
2170
EXAMPLES::
2171
2172
sage: E = EllipticCurve('11a1')
2173
sage: E.multiplication_by_m_isogeny(7)
2174
Isogeny of degree 49 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
2175
2176
"""
2177
mx, my = self.multiplication_by_m(m)
2178
2179
torsion_poly = self.torsion_polynomial(m).monic()
2180
phi = self.isogeny(torsion_poly, codomain=self)
2181
phi._EllipticCurveIsogeny__initialize_rational_maps(precomputed_maps=(mx, my))
2182
2183
return phi
2184
2185
def isomorphism_to(self, other):
2186
"""
2187
Given another weierstrass model ``other`` of self, return an
2188
isomorphism from self to ``other``.
2189
2190
INPUT:
2191
2192
- ``other`` -- an elliptic curve isomorphic to ``self``.
2193
2194
OUTPUT:
2195
2196
(Weierstrassmorphism) An isomorphism from self to other.
2197
2198
.. note::
2199
2200
If the curves in question are not isomorphic, a ValueError is raised.
2201
2202
EXAMPLES::
2203
2204
sage: E = EllipticCurve('37a')
2205
sage: F = E.short_weierstrass_model()
2206
sage: w = E.isomorphism_to(F); w
2207
Generic morphism:
2208
From: Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
2209
To: Abelian group of points on Elliptic Curve defined by y^2 = x^3 - 16*x + 16 over Rational Field
2210
Via: (u,r,s,t) = (1/2, 0, 0, -1/2)
2211
sage: P = E(0,-1,1)
2212
sage: w(P)
2213
(0 : -4 : 1)
2214
sage: w(5*P)
2215
(1 : 1 : 1)
2216
sage: 5*w(P)
2217
(1 : 1 : 1)
2218
sage: 120*w(P) == w(120*P)
2219
True
2220
2221
We can also handle injections to different base rings::
2222
2223
sage: K.<a> = NumberField(x^3-7)
2224
sage: E.isomorphism_to(E.change_ring(K))
2225
Generic morphism:
2226
From: Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
2227
To: Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 + (-1)*x over Number Field in a with defining polynomial x^3 - 7
2228
Via: (u,r,s,t) = (1, 0, 0, 0)
2229
"""
2230
return wm.WeierstrassIsomorphism(self, None, other)
2231
2232
def automorphisms(self, field=None):
2233
"""
2234
Return the set of isomorphisms from self to itself (as a list).
2235
2236
INPUT:
2237
2238
- ``field`` (default None) -- a field into which the
2239
coefficients of the curve may be coerced (by default, uses
2240
the base field of the curve).
2241
2242
OUTPUT:
2243
2244
(list) A list of ``WeierstrassIsomorphism`` objects
2245
consisting of all the isomorphisms from the curve ``self`` to
2246
itself defined over ``field``.
2247
2248
EXAMPLES::
2249
2250
sage: E = EllipticCurve_from_j(QQ(0)) # a curve with j=0 over QQ
2251
sage: E.automorphisms();
2252
[Generic endomorphism of Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 over Rational Field
2253
Via: (u,r,s,t) = (-1, 0, 0, -1), Generic endomorphism of Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 over Rational Field
2254
Via: (u,r,s,t) = (1, 0, 0, 0)]
2255
2256
We can also find automorphisms defined over extension fields::
2257
2258
sage: K.<a> = NumberField(x^2+3) # adjoin roots of unity
2259
sage: E.automorphisms(K)
2260
[Generic endomorphism of Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 over Number Field in a with defining polynomial x^2 + 3
2261
Via: (u,r,s,t) = (-1, 0, 0, -1),
2262
...
2263
Generic endomorphism of Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 over Number Field in a with defining polynomial x^2 + 3
2264
Via: (u,r,s,t) = (1, 0, 0, 0)]
2265
2266
::
2267
2268
sage: [ len(EllipticCurve_from_j(GF(q,'a')(0)).automorphisms()) for q in [2,4,3,9,5,25,7,49]]
2269
[2, 24, 2, 12, 2, 6, 6, 6]
2270
"""
2271
if field==None:
2272
return [wm.WeierstrassIsomorphism(self, urst, self)
2273
for urst in wm.isomorphisms(self,self)]
2274
E=self.change_ring(field)
2275
return [wm.WeierstrassIsomorphism(E, urst, E)
2276
for urst in wm.isomorphisms(E,E)]
2277
2278
def isomorphisms(self, other, field=None):
2279
"""
2280
Return the set of isomorphisms from self to other (as a list).
2281
2282
INPUT:
2283
2284
- ``other`` -- another elliptic curve.
2285
2286
- ``field`` (default None) -- a field into which the
2287
coefficients of the curves may be coerced (by default, uses
2288
the base field of the curves).
2289
2290
OUTPUT:
2291
2292
(list) A list of ``WeierstrassIsomorphism`` objects consisting of all
2293
the isomorphisms from the curve ``self`` to the curve
2294
``other`` defined over ``field``.
2295
2296
EXAMPLES::
2297
2298
sage: E = EllipticCurve_from_j(QQ(0)) # a curve with j=0 over QQ
2299
sage: F = EllipticCurve('27a3') # should be the same one
2300
sage: E.isomorphisms(F);
2301
[Generic morphism:
2302
From: Abelian group of points on Elliptic Curve defined
2303
by y^2 + y = x^3 over Rational Field
2304
To: Abelian group of points on Elliptic Curve defined
2305
by y^2 + y = x^3 over Rational Field
2306
Via: (u,r,s,t) = (-1, 0, 0, -1), Generic morphism:
2307
From: Abelian group of points on Elliptic Curve defined
2308
by y^2 + y = x^3 over Rational Field
2309
To: Abelian group of points on Elliptic Curve defined
2310
by y^2 + y = x^3 over Rational Field
2311
Via: (u,r,s,t) = (1, 0, 0, 0)]
2312
2313
2314
We can also find isomorphisms defined over extension fields::
2315
2316
sage: E=EllipticCurve(GF(7),[0,0,0,1,1])
2317
sage: F=EllipticCurve(GF(7),[0,0,0,1,-1])
2318
sage: E.isomorphisms(F)
2319
[]
2320
sage: E.isomorphisms(F,GF(49,'a'))
2321
[Generic morphism:
2322
From: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 7^2
2323
To: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x + 6 over Finite Field in a of size 7^2
2324
Via: (u,r,s,t) = (a + 3, 0, 0, 0), Generic morphism:
2325
From: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 7^2
2326
To: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x + 6 over Finite Field in a of size 7^2
2327
Via: (u,r,s,t) = (6*a + 4, 0, 0, 0)]
2328
"""
2329
if field==None:
2330
return [wm.WeierstrassIsomorphism(self, urst, other)
2331
for urst in wm.isomorphisms(self,other)]
2332
E=self.change_ring(field)
2333
F=other.change_ring(field)
2334
return [wm.WeierstrassIsomorphism(E, urst, F)
2335
for urst in wm.isomorphisms(E,F)]
2336
2337
def is_isomorphic(self, other, field=None):
2338
"""
2339
Returns whether or not self is isomorphic to other.
2340
2341
INPUT:
2342
2343
- ``other`` -- another elliptic curve.
2344
2345
- ``field`` (default None) -- a field into which the
2346
coefficients of the curves may be coerced (by default, uses
2347
the base field of the curves).
2348
2349
OUTPUT:
2350
2351
(bool) True if there is an isomorphism from curve ``self`` to
2352
curve ``other`` defined over ``field``.
2353
2354
EXAMPLES::
2355
2356
sage: E = EllipticCurve('389a')
2357
sage: F = E.change_weierstrass_model([2,3,4,5]); F
2358
Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 3/2*x^2 - 13/16*x over Rational Field
2359
sage: E.is_isomorphic(F)
2360
True
2361
sage: E.is_isomorphic(F.change_ring(CC))
2362
False
2363
"""
2364
if not is_EllipticCurve(other):
2365
return False
2366
if field==None:
2367
if self.base_ring() != other.base_ring():
2368
return False
2369
elif self.j_invariant() != other.j_invariant(): # easy check
2370
return False
2371
else:
2372
return wm.isomorphisms(self,other,True) != None
2373
else:
2374
E=self.base_extend(field)
2375
F=other.base_extend(field)
2376
if E.j_invariant() != F.j_invariant(): # easy check
2377
return False
2378
else:
2379
return wm.isomorphisms(E,other,F) != None
2380
2381
def change_weierstrass_model(self, *urst):
2382
r"""
2383
Return a new Weierstrass model of self under the standard transformation `(u,r,s,t)`
2384
2385
.. math::
2386
2387
(x,y) \mapsto (x',y') = (u^2x + r , u^3y + su^2x + t).
2388
2389
2390
EXAMPLES::
2391
2392
sage: E = EllipticCurve('15a')
2393
sage: F1 = E.change_weierstrass_model([1/2,0,0,0]); F1
2394
Elliptic Curve defined by y^2 + 2*x*y + 8*y = x^3 + 4*x^2 - 160*x - 640 over Rational Field
2395
sage: F2 = E.change_weierstrass_model([7,2,1/3,5]); F2
2396
Elliptic Curve defined by y^2 + 5/21*x*y + 13/343*y = x^3 + 59/441*x^2 - 10/7203*x - 58/117649 over Rational Field
2397
sage: F1.is_isomorphic(F2)
2398
True
2399
"""
2400
if isinstance(urst[0], (tuple, list)):
2401
urst = urst[0]
2402
return constructor.EllipticCurve((wm.baseWI(*urst))(self.ainvs()))
2403
2404
def short_weierstrass_model(self, complete_cube=True):
2405
"""
2406
Returns a short Weierstrass model for self.
2407
2408
INPUT:
2409
2410
- ``complete_cube`` - bool (default: True); for
2411
meaning, see below.
2412
2413
OUTPUT:
2414
2415
An elliptic curve.
2416
2417
If ``complete_cube=True``: Return a model of the form
2418
`y^2 = x^3 + a*x + b` for this curve. The characteristic
2419
must not be 2; in characteristic 3, it is only possible if `b_2=0`.
2420
2421
If ``complete_cube=False``: Return a model of the form
2422
`y^2 = x^3 + ax^2 + bx + c` for this curve. The
2423
characteristic must not be 2.
2424
2425
EXAMPLES::
2426
2427
sage: E = EllipticCurve([1,2,3,4,5])
2428
sage: print E
2429
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
2430
sage: F = E.short_weierstrass_model()
2431
sage: print F
2432
Elliptic Curve defined by y^2 = x^3 + 4941*x + 185166 over Rational Field
2433
sage: E.is_isomorphic(F)
2434
True
2435
sage: F = E.short_weierstrass_model(complete_cube=False)
2436
sage: print F
2437
Elliptic Curve defined by y^2 = x^3 + 9*x^2 + 88*x + 464 over Rational Field
2438
sage: print E.is_isomorphic(F)
2439
True
2440
2441
::
2442
2443
sage: E = EllipticCurve(GF(3),[1,2,3,4,5])
2444
sage: E.short_weierstrass_model(complete_cube=False)
2445
Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 3
2446
2447
This used to be different see trac #3973::
2448
2449
sage: E.short_weierstrass_model()
2450
Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 3
2451
2452
More tests in characteristic 3::
2453
2454
sage: E = EllipticCurve(GF(3),[0,2,1,2,1])
2455
sage: E.short_weierstrass_model()
2456
Traceback (most recent call last):
2457
...
2458
ValueError: short_weierstrass_model(): no short model for Elliptic Curve defined by y^2 + y = x^3 + 2*x^2 + 2*x + 1 over Finite Field of size 3 (characteristic is 3)
2459
sage: E.short_weierstrass_model(complete_cube=False)
2460
Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2*x + 2 over Finite Field of size 3
2461
sage: E.short_weierstrass_model(complete_cube=False).is_isomorphic(E)
2462
True
2463
"""
2464
import constructor
2465
K = self.base_ring()
2466
2467
# any curve of the form y^2 = x^3 +.. is singular in characteristic 2
2468
if K.characteristic() == 2:
2469
raise ValueError, "short_weierstrass_model(): no short model for %s (characteristic is %s)"%(self,K.characteristic())
2470
2471
# in characteristic 3 we can complete the square but we can only complete the cube if b2 is 0
2472
if K.characteristic() == 3:
2473
b2,b4,b6,_ = self.b_invariants()
2474
if complete_cube and b2 != 0:
2475
raise ValueError, "short_weierstrass_model(): no short model for %s (characteristic is %s)"%(self,K.characteristic())
2476
else:
2477
return constructor.EllipticCurve([0,b2,0,8*b4,16*b6])
2478
2479
a1,a2,a3,_,_ = self.a_invariants()
2480
if complete_cube:
2481
if a1==0 and a2==0 and a3==0:
2482
return self
2483
else:
2484
b2,b4,b6,_ = self.b_invariants()
2485
if b2==0:
2486
return constructor.EllipticCurve([0,0,0,8*b4,16*b6])
2487
else:
2488
c4, c6 = self.c_invariants()
2489
return constructor.EllipticCurve([0,0,0,-27*c4, -54*c6])
2490
else:
2491
if a1==0 and a3==0:
2492
return self
2493
else:
2494
b2,b4,b6,_ = self.b_invariants()
2495
return constructor.EllipticCurve([0,b2,0,8*b4,16*b6])
2496
2497
2498
2499
# Plotting
2500
2501
2502
def plot(self, xmin=None, xmax=None, components='both', **args):
2503
"""
2504
Draw a graph of this elliptic curve.
2505
2506
INPUT:
2507
2508
- ``xmin, xmax`` - (optional) points will be computed at
2509
least within this range, but possibly farther.
2510
2511
- ``components`` - a string, one of the following:
2512
2513
- ``both`` -- (default), scale so that both bounded and
2514
unbounded components appear
2515
2516
- ``bounded`` -- scale the plot to show the bounded
2517
component. Raises an error if there is only one real
2518
component.
2519
2520
- ``unbounded`` -- scale the plot to show the unbounded
2521
component, including the two flex points.
2522
2523
- ``plot_points`` -- passed to
2524
:func:`sage.plot.generate_plot_points`
2525
2526
- ``adaptive_tolerance`` -- passed to
2527
:func:`sage.plot.generate_plot_points`
2528
2529
- ``adaptive_recursion`` -- passed to
2530
:func:`sage.plot.generate_plot_points`
2531
2532
- ``randomize`` -- passed to
2533
:func:`sage.plot.generate_plot_points`
2534
2535
- ``**args`` - all other options are passed to
2536
:class:`sage.plot.line.Line`
2537
2538
EXAMPLES::
2539
2540
sage: E = EllipticCurve([0,-1])
2541
sage: plot(E, rgbcolor=hue(0.7))
2542
sage: E = EllipticCurve('37a')
2543
sage: plot(E)
2544
sage: plot(E, xmin=25,xmax=26)
2545
2546
With #12766 we added the components keyword::
2547
2548
sage: E.real_components()
2549
2
2550
sage: E.plot(components='bounded')
2551
sage: E.plot(components='unbounded')
2552
2553
If there is only one component then specifying
2554
components='bounded' raises a ValueError::
2555
2556
sage: E = EllipticCurve('9990be2')
2557
sage: E.plot(components='bounded')
2558
Traceback (most recent call last):
2559
...
2560
ValueError: no bounded component for this curve
2561
"""
2562
RR = rings.RealField()
2563
K = self.base_ring()
2564
try:
2565
RR._coerce_(K(1))
2566
except TypeError:
2567
raise NotImplementedError, "Plotting of curves over %s not implemented yet"%K
2568
if components not in ['both', 'bounded', 'unbounded']:
2569
raise ValueError("component must be one of 'both', 'bounded' or 'unbounded'")
2570
2571
a1, a2, a3, a4, a6 = self.ainvs()
2572
d = self.division_polynomial(2)
2573
# Internal function for plotting first branch of the curve
2574
f1 = lambda z: (-(a1*z + a3) + sqrt(abs(d(z))))/2
2575
# Internal function for plotting second branch of the curve
2576
f2 = lambda z: (-(a1*z + a3) - sqrt(abs(d(z))))/2
2577
r = d.roots(RR, multiplicities=False)
2578
r.sort()
2579
if components == 'bounded' and len(r) == 1:
2580
raise ValueError("no bounded component for this curve")
2581
if isinstance(xmin, (tuple, list)):
2582
if xmax is not None:
2583
raise ValueError("xmax must be None if xmin is a tuple")
2584
if len(xmin) != 2:
2585
raise ValueError("if xmin is a tuple it must have length 2")
2586
xmin, xmax = xmin
2587
if xmin is None or xmax is None:
2588
xmins = []
2589
xmaxs = []
2590
if components in ['both','bounded'] and len(r) > 1:
2591
xmins.append(r[0])
2592
xmaxs.append(r[1])
2593
2594
# The following 3 is an aesthetic choice. It's possible
2595
# that we should compute both of the following when
2596
# components=='both' and len(r) > 1 and take the maximum
2597
# generated xmax.
2598
if components == 'unbounded' or components == 'both' and (len(r) == 1 or r[2] - r[1] > 3*(r[1] - r[0])):
2599
flex = self.division_polynomial(3).roots(RR, multiplicities=False)
2600
flex.sort()
2601
flex = flex[-1]
2602
xmins.append(r[-1])
2603
# The doubling here is an aesthetic choice
2604
xmaxs.append(flex + 2*(flex - r[-1]))
2605
elif components == 'both':
2606
# First the easy part.
2607
xmins.append(r[-1])
2608
# There are two components and the unbounded component
2609
# is not too far from the bounded one. We scale so
2610
# that the unbounded component is twice as tall as the
2611
# bounded component. The y values corresponding to
2612
# horizontal tangent lines are determined as follows.
2613
# We implicitly differentiate the equation for this
2614
# curve and get
2615
# 2 yy' + a1 y + a1 xy' + a3 y' = 3 x^2 + 2a2 x + a4
2616
2617
R = RR['x']
2618
x = R.gen()
2619
if a1 == 0:
2620
# a horizontal tangent line can only occur at a root of
2621
Ederiv = 3*x**2 + 2*a2*x + a4
2622
else:
2623
# y' = 0 ==> y = (3*x^2 + 2*a2*x + a4) / a1
2624
y = (3*x**2 + 2*a2*x + a4) / a1
2625
Ederiv = y**2 + a1*x*y + a3*y - (x**3 + a2*x**2 + a4*x + a6)
2626
critx = [a for a in Ederiv.roots(RR, multiplicities=False) if r[0] < a < r[1]]
2627
if len(critx) == 0:
2628
raise RuntimeError("No horizontal tangent lines on bounded component")
2629
# The 2.5 here is an aesthetic choice
2630
ymax = 2.5 * max([f1(a) for a in critx])
2631
ymin = 2.5 * min([f2(a) for a in critx])
2632
top_branch = ymax**2 + a1*x*ymax + a3*ymax - (x**3 + a2*x**2 + a4*x + a6)
2633
bottom_branch = ymin**2 + a1*x*ymin + a3*ymin - (x**3 + a2*x**2 + a4*x + a6)
2634
xmaxs.append(max(top_branch.roots(RR,multiplicities=False) + bottom_branch.roots(RR,multiplicities=False)))
2635
xmins = min(xmins)
2636
xmaxs = max(xmaxs)
2637
span = xmaxs - xmins
2638
if xmin is None:
2639
xmin = xmins - .02*span
2640
if xmax is None:
2641
xmax = xmaxs + .02*span
2642
elif xmin >= xmax:
2643
raise ValueError("xmin must be less than xmax")
2644
2645
I = []
2646
if components in ['unbounded', 'both'] and xmax > r[-1]:
2647
# one real root; 1 component
2648
if xmin <= r[-1]:
2649
I.append((r[-1],xmax,'<'))
2650
else:
2651
I.append((xmin, xmax,'='))
2652
if components in ['bounded','both'] and len(r) > 1 and (xmin < r[1] or xmax > r[0]):
2653
if xmin <= r[0]:
2654
if xmax >= r[1]:
2655
I.append((r[0],r[1],'o'))
2656
else:
2657
I.append((r[0],xmax,'<'))
2658
elif xmax >= r[1]:
2659
I.append((xmin, r[1], '>'))
2660
else:
2661
I.append((xmin, xmax, '='))
2662
2663
g = plot.Graphics()
2664
plot_points = int(args.pop('plot_points',200))
2665
adaptive_tolerance = args.pop('adaptive_tolerance',0.01)
2666
adaptive_recursion = args.pop('adaptive_recursion',5)
2667
randomize = args.pop('randomize',True)
2668
for j in range(len(I)):
2669
a,b,shape = I[j]
2670
v = generate_plot_points(f1, (a, b), plot_points, adaptive_tolerance, adaptive_recursion, randomize)
2671
w = generate_plot_points(f2, (a, b), plot_points, adaptive_tolerance, adaptive_recursion, randomize)
2672
if shape == 'o':
2673
g += plot.line(v + list(reversed(w)) + [v[0]], **args)
2674
elif shape == '<':
2675
g += plot.line(list(reversed(v)) + w, **args)
2676
elif shape == '>':
2677
g += plot.line(v + list(reversed(w)), **args)
2678
else:
2679
g += plot.line(v, **args)
2680
g += plot.line(w, **args)
2681
return g
2682
2683
def formal_group(self):
2684
r"""
2685
The formal group associated to this elliptic curve.
2686
2687
EXAMPLES::
2688
2689
sage: E = EllipticCurve("37a")
2690
sage: E.formal_group()
2691
Formal Group associated to the Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
2692
"""
2693
try:
2694
return self.__formal_group
2695
except AttributeError:
2696
self.__formal_group = formal_group.EllipticCurveFormalGroup(self)
2697
return self.__formal_group
2698
2699
formal = formal_group
2700
2701
def _p_primary_torsion_basis(self,p,m=None):
2702
r"""
2703
Find a basis for the `p`-primary part of the torsion
2704
subgroup of this elliptic curve.
2705
2706
INPUT:
2707
2708
- ``p`` (integer) -- a prime number.
2709
2710
- ``m`` (integer or None) -- if not None, the $p$-primary torsion will be assumed to have order at most $p^m$.
2711
2712
OUTPUT:
2713
2714
A list of 0, 1 or 2 pairs `[T,k]` where `T` is a generator of
2715
order `p^k`. That is, either `[]` or `[[T_1,k_1]]` or
2716
`[[T_1,k_1],[T_2,k_2]]` with `[]`, `[T_1]`, or `[T_1,T_2]` a
2717
basis and `p^{k_1} \ge p^{k_2} \ge 1` their orders.
2718
2719
.. warning::
2720
2721
1. Do not call this on a curve whose group is
2722
`p`-divisible (i.e., whose `p`-primary part
2723
is infinite)!
2724
2725
2. The code uses division polynomials and will be slow for
2726
large `p`.
2727
2728
EXAMPLES::
2729
2730
sage: E = EllipticCurve('11a1')
2731
sage: E._p_primary_torsion_basis(5)
2732
[[(5 : -6 : 1), 1]]
2733
sage: K.<t> = NumberField(x^4 + x^3 + 11*x^2 + 41*x + 101)
2734
sage: EK = E.base_extend(K)
2735
sage: EK._p_primary_torsion_basis(5) # long time (2s on sage.math, 2011)
2736
[[(16 : 60 : 1), 1], [(t : 1/11*t^3 + 6/11*t^2 + 19/11*t + 48/11 : 1), 1]]
2737
sage: EF = E.change_ring(GF(101))
2738
sage: EF._p_primary_torsion_basis(5)
2739
[[(0 : 13 : 1), 1], [(5 : 5 : 1), 1]]
2740
2741
sage: F.<z> = CyclotomicField(21)
2742
sage: E = EllipticCurve([2,-z^7,-z^7,0,0])
2743
sage: E._p_primary_torsion_basis(7,2) # long time (8s on sage.math, 2011)
2744
[[(0 : z^7 : 1), 1],
2745
[(z^7 - z^6 + z^4 - z^3 + z^2 - 1 : z^8 - 2*z^7 + z^6 + 2*z^5 - 3*z^4 + 2*z^3 - 2*z + 2 : 1), 1]]
2746
2747
TESTS:
2748
2749
This shows that the bug at trac #4937 is fixed::
2750
2751
sage: a=804515977734860566494239770982282063895480484302363715494873
2752
sage: b=584772221603632866665682322899297141793188252000674256662071
2753
sage: E = EllipticCurve(GF(10^60+3201),[0,a,0,b,0])
2754
sage: [t[1] for t in E._p_primary_torsion_basis(2)] # long time (3s on sage.math, 2011)
2755
[16, 1]
2756
"""
2757
p = rings.Integer(p)
2758
if not p.is_prime():
2759
raise ValueError("p (=%s) should be prime" % p)
2760
2761
if m is None:
2762
from sage.rings.infinity import Infinity
2763
m = Infinity
2764
2765
if m == 0:
2766
return []
2767
2768
# First find the p-torsion:
2769
Ep = self(0).division_points(p)
2770
p_rank = rings.Integer(len(Ep)).exact_log(p)
2771
assert p_rank in [0,1,2]
2772
2773
if p_rank == 0:
2774
return []
2775
2776
assert p_rank in [1,2]
2777
2778
if p_rank == 1:
2779
P = Ep[0]
2780
if P.is_zero(): P=Ep[1]
2781
k = 1
2782
if m==1:
2783
return [[P,k]]
2784
pts = P.division_points(p) # length 0 or p
2785
while len(pts)>0:
2786
k += 1
2787
P = pts[0]
2788
if m<=k:
2789
return [[P,k]]
2790
pts = P.division_points(p)
2791
# now P generates the p-power-torsion and has order p^k
2792
return [[P,k]]
2793
2794
assert p_rank == 2
2795
2796
Epi = iter(Ep) # used to iterate through Ep
2797
# Find P1,P2 which generate the p-torsion:
2798
P1 = Epi.next()
2799
while P1.is_zero(): P1 = Epi.next()
2800
P2 = Epi.next()
2801
while generic.linear_relation(P1,P2,'+')[0] != 0: P2 = Epi.next()
2802
2803
k = 1
2804
log_order = 2
2805
if m<=log_order:
2806
return [[P1,1],[P2,1]]
2807
2808
pts1 = P1.division_points(p)
2809
pts2 = P2.division_points(p)
2810
while len(pts1)>0 and len(pts2)>0:
2811
k += 1
2812
P1 = pts1[0]
2813
P2 = pts2[0]
2814
log_order += 2
2815
if m<=log_order:
2816
return [[P1,k],[P2,k]]
2817
pts1 = P1.division_points(p)
2818
pts2 = P2.division_points(p)
2819
2820
# Now P1,P2 are a basis for the p^k torsion, which is
2821
# isomorphic to (Z/p^k)^2, and k is the maximal integer for
2822
# which this is the case.
2823
2824
# We now determine whether a combination (P2 or P1+a*P2 for
2825
# some a) can be further divided for some a mod p; if so,
2826
# replace P1 by that combination, set pts to be the list of
2827
# solutions Q to p*Q=P1. If no combination can be divided,
2828
# then the structure is (p^k,p^k) and we can stop.
2829
2830
if len(pts1) > 0:
2831
pts = pts1
2832
elif len(pts2) > 0:
2833
P1, P2 = P2, P1
2834
pts = pts2
2835
else:
2836
for Q in generic.multiples(P2,p-1,P1+P2,operation='+'):
2837
# Q runs through P1+a*P2 for a=1,2,...,p-1
2838
pts = Q.division_points(p)
2839
if len(pts) > 0:
2840
P1 = Q
2841
break
2842
2843
if len(pts)==0:
2844
return [[P1,k],[P2,k]]
2845
2846
# Now the structure is (p^n,p^k) for some n>k. We need to
2847
# replace P1 by an element of maximal order p^n. So far we
2848
# have pts = list of Q satisfying p*Q=P1, and all such Q have
2849
# order p^{k+1}.
2850
2851
# We keep trying to divide P1 by p. At each step, if we
2852
# succeed, replace P1 by any of the results and increment n.
2853
# If we fails try again with P1+a*P2 for a in [1..p-1]. If any
2854
# succeed, replace P1 by one of the resulting divided points.
2855
# If all fail, the structure is (p^n,p^k) and P1,P2 are
2856
# generators.
2857
2858
n=k
2859
while True:
2860
P1=pts[0]
2861
n += 1
2862
log_order += 1
2863
if m<=log_order:
2864
return [[P1,n],[P2,k]]
2865
pts = P1.division_points(p)
2866
if len(pts)==0:
2867
for Q in generic.multiples(P2,p-1,P1+P2,operation='+'):
2868
# Q runs through P1+a*P2 for a=1,2,...,p-1
2869
pts = Q.division_points(p)
2870
if len(pts)>0:
2871
break
2872
if len(pts)==0:
2873
return [[P1,n],[P2,k]]
2874
2875
2876
def hyperelliptic_polynomials(self):
2877
r"""
2878
Returns a pair of polynomials `g(x)`, `h(x)` such that this elliptic
2879
curve can be defined by the standard hyperelliptic equation
2880
2881
.. math::
2882
2883
y^2 + h(x)y = g(x).
2884
2885
EXAMPLES::
2886
2887
sage: R.<a1,a2,a3,a4,a6>=QQ[]
2888
sage: E=EllipticCurve([a1,a2,a3,a4,a6])
2889
sage: E.hyperelliptic_polynomials()
2890
(x^3 + a2*x^2 + a4*x + a6, a1*x + a3)
2891
"""
2892
K = self.base_ring()
2893
R = PolynomialRing(K, 'x')
2894
x = R.gen(0)
2895
a1, a2, a3, a4, a6 = self.ainvs()
2896
return R([a6, a4, a2, 1]), R([a3, a1])
2897
2898
def pari_curve(self):
2899
"""
2900
Return the PARI curve corresponding to this elliptic curve.
2901
2902
The result is cached.
2903
2904
EXAMPLES::
2905
2906
sage: E = EllipticCurve([RR(0), RR(0), RR(1), RR(-1), RR(0)])
2907
sage: e = E.pari_curve()
2908
sage: type(e)
2909
<type 'sage.libs.pari.gen.gen'>
2910
sage: e.type()
2911
't_VEC'
2912
sage: e.disc()
2913
37.0000000000000
2914
2915
Over a finite field::
2916
2917
sage: EllipticCurve(GF(41),[2,5]).pari_curve()
2918
[Mod(0, 41), Mod(0, 41), Mod(0, 41), Mod(2, 41), Mod(5, 41), Mod(0, 41), Mod(4, 41), Mod(20, 41), Mod(37, 41), Mod(27, 41), Mod(26, 41), Mod(4, 41), Mod(11, 41), 0, 0, 0, 0, 0, 0]
2919
2920
Over a `p`-adic field::
2921
2922
sage: Qp = pAdicField(5, prec=3)
2923
sage: E = EllipticCurve(Qp,[3, 4])
2924
sage: E.pari_curve()
2925
[O(5^3), O(5^3), O(5^3), 3 + O(5^3), 4 + O(5^3), O(5^3), 1 + 5 + O(5^3), 1 + 3*5 + O(5^3), 1 + 3*5 + 4*5^2 + O(5^3), 1 + 5 + 4*5^2 + O(5^3), 4 + 3*5 + 5^2 + O(5^3), 2*5 + 4*5^2 + O(5^3), 3*5^-1 + O(5), [4 + 4*5 + 4*5^2 + O(5^3)], 1 + 2*5 + 4*5^2 + O(5^3), 1 + 5 + 4*5^2 + O(5^3), 2*5 + 4*5^2 + O(5^3), 3 + 3*5 + 3*5^2 + O(5^3), 0]
2926
sage: E.j_invariant()
2927
3*5^-1 + O(5)
2928
2929
The `j`-invariant must have negative `p`-adic valuation::
2930
2931
sage: E = EllipticCurve(Qp,[1, 1])
2932
sage: E.j_invariant() # the j-invariant is a p-adic integer
2933
2 + 4*5^2 + O(5^3)
2934
sage: E.pari_curve()
2935
Traceback (most recent call last):
2936
...
2937
PariError: valuation of j must be negative in p-adic ellinit
2938
"""
2939
try:
2940
return self._pari_curve
2941
except AttributeError:
2942
pass
2943
2944
from sage.libs.pari.all import pari
2945
self._pari_curve = pari(list(self.a_invariants())).ellinit()
2946
return self._pari_curve
2947
2948
# This method is defined so that pari(E) returns exactly the same
2949
# as E.pari_curve(). This works even for classes that inherit from
2950
# EllipticCurve_generic, such as EllipticCurve_rational_field.
2951
def _pari_(self):
2952
"""
2953
Return the PARI curve corresponding to this elliptic curve
2954
with the default precision of 64 bits.
2955
2956
EXAMPLES::
2957
2958
sage: E = EllipticCurve('11a1')
2959
sage: pari(E)
2960
[0, -1, 1, -10, -20, -4, -20, -79, -21, 496, 20008, -161051, -122023936/161051, [4.34630815820539, -1.67315407910270 + 1.32084892226908*I, -1.67315407910270 - 1.32084892226908*I]~, ...]
2961
sage: E.pari_curve(prec=64)
2962
[0, -1, 1, -10, -20, -4, -20, -79, -21, 496, 20008, -161051, -122023936/161051, [4.34630815820539, -1.67315407910270 + 1.32084892226908*I, -1.67315407910270 - 1.32084892226908*I]~, ...]
2963
2964
Over a finite field::
2965
2966
sage: EllipticCurve(GF(2), [0,0,1,1,1])._pari_()
2967
[Mod(0, 2), Mod(0, 2), Mod(1, 2), Mod(1, 2), Mod(1, 2), Mod(0, 2), Mod(0, 2), Mod(1, 2), Mod(1, 2), Mod(0, 2), Mod(0, 2), Mod(1, 2), Mod(0, 2), 0, 0, 0, 0, 0, 0]
2968
"""
2969
return self.pari_curve()
2970
2971