Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/elliptic_curves/ell_rational_field.py
8820 views
1
# -*- coding: utf-8 -*-
2
"""
3
Elliptic curves over the rational numbers
4
5
AUTHORS:
6
7
- William Stein (2005): first version
8
9
- William Stein (2006-02-26): fixed Lseries_extended which didn't work
10
because of changes elsewhere in Sage.
11
12
- David Harvey (2006-09): Added padic_E2, padic_sigma, padic_height,
13
padic_regulator methods.
14
15
- David Harvey (2007-02): reworked padic-height related code
16
17
- Christian Wuthrich (2007): added padic sha computation
18
19
- David Roe (2007-09): moved sha, l-series and p-adic functionality to
20
separate files.
21
22
- John Cremona (2008-01)
23
24
- Tobias Nagel and Michael Mardaus (2008-07): added integral_points
25
26
- John Cremona (2008-07): further work on integral_points
27
28
- Christian Wuthrich (2010-01): moved Galois reps and modular
29
parametrization in a separate file
30
31
- Simon Spicer (2013-03): Added code for modular degrees and congruence
32
numbers of higher level
33
34
"""
35
36
##############################################################################
37
# Copyright (C) 2005,2006,2007 William Stein <[email protected]>
38
#
39
# Distributed under the terms of the GNU General Public License (GPL)
40
#
41
# This code is distributed in the hope that it will be useful,
42
# but WITHOUT ANY WARRANTY; without even the implied warranty of
43
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44
# General Public License for more details.
45
#
46
# The full text of the GPL is available at:
47
#
48
# http://www.gnu.org/licenses/
49
##############################################################################
50
51
import constructor
52
import BSD
53
from ell_generic import is_EllipticCurve
54
import ell_modular_symbols
55
from ell_number_field import EllipticCurve_number_field
56
import ell_point
57
import ell_tate_curve
58
import ell_torsion
59
import heegner
60
from gp_simon import simon_two_descent
61
from lseries_ell import Lseries_ell
62
import mod5family
63
from modular_parametrization import ModularParameterization
64
import padic_lseries
65
import padics
66
67
from sage.modular.modsym.modsym import ModularSymbols
68
69
import sage.modular.modform.constructor
70
import sage.modular.modform.element
71
import sage.libs.mwrank.all as mwrank
72
import sage.databases.cremona
73
74
import sage.rings.arith as arith
75
import sage.rings.all as rings
76
from sage.rings.all import (
77
PowerSeriesRing,
78
infinity as oo,
79
ZZ, QQ,
80
Integer,
81
IntegerRing, RealField,
82
ComplexField, RationalField)
83
84
import sage.misc.misc as misc
85
from sage.misc.all import verbose
86
87
from sage.misc.functional import log
88
89
import sage.matrix.all as matrix
90
from sage.libs.pari.all import pari, PariError
91
from sage.functions.other import gamma_inc
92
from math import sqrt
93
from sage.interfaces.all import gp
94
from sage.misc.cachefunc import cached_method
95
from copy import copy
96
97
Q = RationalField()
98
C = ComplexField()
99
R = RealField()
100
Z = IntegerRing()
101
IR = rings.RealIntervalField(20)
102
103
_MAX_HEIGHT=21
104
105
# complex multiplication dictionary:
106
# CMJ is a dict of pairs (j,D) where j is a rational CM j-invariant
107
# and D is the corresponding quadratic discriminant
108
109
CMJ={ 0: -3, 54000: -12, -12288000: -27, 1728: -4, 287496: -16,
110
-3375: -7, 16581375: -28, 8000: -8, -32768: -11, -884736: -19,
111
-884736000: -43, -147197952000: -67, -262537412640768000: -163}
112
113
114
class EllipticCurve_rational_field(EllipticCurve_number_field):
115
r"""
116
Elliptic curve over the Rational Field.
117
118
INPUT:
119
120
- ``ainvs`` (list or string) -- either `[a_1,a_2,a_3,a_4,a_6]` or
121
`[a_4,a_6]` (with `a_1=a_2=a_3=0`) or a valid label from the
122
database.
123
124
.. note::
125
126
See constructor.py for more variants.
127
128
EXAMPLES:
129
130
Construction from Weierstrass coefficients (`a`-invariants), long form::
131
132
sage: E = EllipticCurve([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 Rational Field
134
135
Construction from Weierstrass coefficients (`a`-invariants),
136
short form (sets `a_1=a_2=a_3=0`)::
137
138
sage: EllipticCurve([4,5]).ainvs()
139
(0, 0, 0, 4, 5)
140
141
Construction from a database label::
142
143
sage: EllipticCurve('389a1')
144
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
145
146
"""
147
def __init__(self, ainvs, extra=None):
148
r"""
149
Constructor for the EllipticCurve_rational_field class.
150
151
INPUT:
152
153
- ``ainvs`` (list or string) -- either `[a_1,a_2,a_3,a_4,a_6]`
154
or `[a_4,a_6]` (with `a_1=a_2=a_3=0`) or a valid label from
155
the database.
156
157
.. note::
158
159
See constructor.py for more variants.
160
161
EXAMPLES::
162
163
sage: E = EllipticCurve([1,2,3,4,5]); E
164
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
165
166
Constructor from `[a_4,a_6]` sets `a_1=a_2=a_3=0`::
167
168
sage: EllipticCurve([4,5]).ainvs()
169
(0, 0, 0, 4, 5)
170
171
Constructor from a Cremona label::
172
173
sage: EllipticCurve('389a1')
174
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
175
176
Constructor from an LMFDB label::
177
178
sage: EllipticCurve('462.f3')
179
Elliptic Curve defined by y^2 + x*y = x^3 - 363*x + 1305 over Rational Field
180
181
TESTS:
182
183
When constructing a curve from the large database using a
184
label, we must be careful that the copied generators have the
185
right curve (see #10999: the following used not to work when
186
the large database was installed)::
187
188
sage: E=EllipticCurve('389a1')
189
sage: [P.curve() is E for P in E.gens()]
190
[True, True]
191
192
"""
193
if extra != None: # possibility of two arguments (the first would be the field)
194
ainvs = extra
195
self.__np = {}
196
self.__gens = {}
197
self.__rank = {}
198
self.__regulator = {}
199
self.__generalized_modular_degree = {}
200
self.__generalized_congruence_number = {}
201
self._isoclass = {}
202
if isinstance(ainvs, str):
203
label = ainvs
204
X = sage.databases.cremona.CremonaDatabase()[label]
205
EllipticCurve_number_field.__init__(self, Q, list(X.a_invariants()))
206
for attr in ['rank', 'torsion_order', 'cremona_label', 'conductor',
207
'modular_degree', 'gens', 'regulator']:
208
s = "_EllipticCurve_rational_field__"+attr
209
if hasattr(X,s):
210
if attr == 'gens': # see #10999
211
gens_dict = getattr(X, s)
212
for boo in gens_dict.keys():
213
gens_dict[boo] = [self(P) for P in gens_dict[boo]]
214
setattr(self, s, gens_dict)
215
else:
216
setattr(self, s, getattr(X, s))
217
if hasattr(X,'_lmfdb_label'):
218
self._lmfdb_label = X._lmfdb_label
219
return
220
EllipticCurve_number_field.__init__(self, Q, ainvs)
221
if self.base_ring() != Q:
222
raise TypeError, "Base field (=%s) must be the Rational Field."%self.base_ring()
223
224
def _set_rank(self, r):
225
"""
226
Internal function to set the cached rank of this elliptic curve to
227
r.
228
229
.. warning::
230
231
No checking is done! Not intended for use by users.
232
233
EXAMPLES::
234
235
sage: E = EllipticCurve('37a1')
236
sage: E._set_rank(99) # bogus value -- not checked
237
sage: E.rank() # returns bogus cached value
238
99
239
sage: E._EllipticCurve_rational_field__rank={} # undo the damage
240
sage: E.rank() # the correct rank
241
1
242
"""
243
self.__rank = {}
244
self.__rank[True] = Integer(r)
245
246
def _set_torsion_order(self, t):
247
"""
248
Internal function to set the cached torsion order of this elliptic
249
curve to t.
250
251
.. warning::
252
253
No checking is done! Not intended for use by users.
254
255
EXAMPLES::
256
257
sage: E=EllipticCurve('37a1')
258
sage: E._set_torsion_order(99) # bogus value -- not checked
259
sage: E.torsion_order() # returns bogus cached value
260
99
261
sage: T = E.torsion_subgroup() # causes actual torsion to be computed
262
sage: E.torsion_order() # the correct value
263
1
264
"""
265
self.__torsion_order = Integer(t)
266
267
def _set_cremona_label(self, L):
268
"""
269
Internal function to set the cached label of this elliptic curve to
270
L.
271
272
.. warning::
273
274
No checking is done! Not intended for use by users.
275
276
EXAMPLES::
277
278
sage: E=EllipticCurve('37a1')
279
sage: E._set_cremona_label('bogus')
280
sage: E.label()
281
'bogus'
282
sage: E.database_curve().label()
283
'37a1'
284
sage: E.label() # no change
285
'bogus'
286
sage: E._set_cremona_label(E.database_curve().label())
287
sage: E.label() # now it is correct
288
'37a1'
289
"""
290
self.__cremona_label = L
291
292
def _set_conductor(self, N):
293
"""
294
Internal function to set the cached conductor of this elliptic
295
curve to N.
296
297
.. warning::
298
299
No checking is done! Not intended for use by users.
300
Setting to the wrong value will cause strange problems (see
301
examples).
302
303
EXAMPLES::
304
305
sage: E=EllipticCurve('37a1')
306
sage: E._set_conductor(99) # bogus value -- not checked
307
sage: E.conductor() # returns bogus cached value
308
99
309
"""
310
self.__conductor_pari = Integer(N)
311
312
def _set_modular_degree(self, deg):
313
"""
314
Internal function to set the cached modular degree of this elliptic
315
curve to deg.
316
317
.. warning::
318
319
No checking is done!
320
321
EXAMPLES::
322
323
sage: E=EllipticCurve('5077a1')
324
sage: E.modular_degree()
325
1984
326
sage: E._set_modular_degree(123456789)
327
sage: E.modular_degree()
328
123456789
329
sage: E._set_modular_degree(E.database_curve().modular_degree())
330
sage: E.modular_degree()
331
1984
332
"""
333
self.__modular_degree = Integer(deg)
334
335
def _set_gens(self, gens):
336
"""
337
Internal function to set the cached generators of this elliptic
338
curve to gens.
339
340
.. warning::
341
342
No checking is done!
343
344
EXAMPLES::
345
346
sage: E=EllipticCurve('5077a1')
347
sage: E.rank()
348
3
349
sage: E.gens() # random
350
[(-2 : 3 : 1), (-7/4 : 25/8 : 1), (1 : -1 : 1)]
351
sage: E._set_gens([]) # bogus list
352
sage: E.rank() # unchanged
353
3
354
sage: E._set_gens([E(-2,3), E(-1,3), E(0,2)])
355
sage: E.gens()
356
[(-2 : 3 : 1), (-1 : 3 : 1), (0 : 2 : 1)]
357
"""
358
self.__gens = {}
359
self.__gens[True] = [self.point(x, check=True) for x in gens]
360
self.__gens[True].sort()
361
362
363
def is_p_integral(self, p):
364
r"""
365
Returns True if this elliptic curve has `p`-integral
366
coefficients.
367
368
INPUT:
369
370
371
- ``p`` - a prime integer
372
373
374
EXAMPLES::
375
376
sage: E=EllipticCurve(QQ,[1,1]); E
377
Elliptic Curve defined by y^2 = x^3 + x + 1 over Rational Field
378
sage: E.is_p_integral(2)
379
True
380
sage: E2=E.change_weierstrass_model(2,0,0,0); E2
381
Elliptic Curve defined by y^2 = x^3 + 1/16*x + 1/64 over Rational Field
382
sage: E2.is_p_integral(2)
383
False
384
sage: E2.is_p_integral(3)
385
True
386
"""
387
if not arith.is_prime(p):
388
raise ArithmeticError, "p must be prime"
389
if self.is_integral():
390
return True
391
return bool(misc.mul([x.valuation(p) >= 0 for x in self.ainvs()]))
392
393
def is_integral(self):
394
"""
395
Returns True if this elliptic curve has integral coefficients (in
396
Z)
397
398
EXAMPLES::
399
400
sage: E=EllipticCurve(QQ,[1,1]); E
401
Elliptic Curve defined by y^2 = x^3 + x + 1 over Rational Field
402
sage: E.is_integral()
403
True
404
sage: E2=E.change_weierstrass_model(2,0,0,0); E2
405
Elliptic Curve defined by y^2 = x^3 + 1/16*x + 1/64 over Rational Field
406
sage: E2.is_integral()
407
False
408
"""
409
try:
410
return self.__is_integral
411
except AttributeError:
412
one = Integer(1)
413
self.__is_integral = bool(misc.mul([x.denominator() == 1 for x in self.ainvs()]))
414
return self.__is_integral
415
416
417
def mwrank(self, options=''):
418
r"""
419
Run Cremona's mwrank program on this elliptic curve and return the
420
result as a string.
421
422
INPUT:
423
424
425
- ``options`` (string) -- run-time options passed when starting mwrank.
426
The format is as follows (see below for examples of usage):
427
428
- ``-v n`` (verbosity level) sets verbosity to n (default=1)
429
- ``-o`` (PARI/GP style output flag) turns ON extra PARI/GP short output (default is OFF)
430
- ``-p n`` (precision) sets precision to `n` decimals (default=15)
431
- ``-b n`` (quartic bound) bound on quartic point search (default=10)
432
- ``-x n`` (n_aux) number of aux primes used for sieving (default=6)
433
- ``-l`` (generator list flag) turns ON listing of points (default ON unless v=0)
434
- ``-s`` (selmer_only flag) if set, computes Selmer rank only (default: not set)
435
- ``-d`` (skip_2nd_descent flag) if set, skips the second descent for curves with 2-torsion (default: not set)
436
- ``-S n`` (sat_bd) upper bound on saturation primes (default=100, -1 for automatic)
437
438
OUTPUT:
439
440
- ``string`` - output of mwrank on this curve
441
442
443
.. note::
444
445
The output is a raw string and completely illegible using
446
automatic display, so it is recommended to use print for
447
legible output.
448
449
EXAMPLES::
450
451
sage: E = EllipticCurve('37a1')
452
sage: E.mwrank() #random
453
...
454
sage: print E.mwrank()
455
Curve [0,0,1,-1,0] : Basic pair: I=48, J=-432
456
disc=255744
457
...
458
Generator 1 is [0:-1:1]; height 0.05111...
459
460
Regulator = 0.05111...
461
462
The rank and full Mordell-Weil basis have been determined unconditionally.
463
...
464
465
Options to mwrank can be passed::
466
467
sage: E = EllipticCurve([0,0,0,877,0])
468
469
Run mwrank with 'verbose' flag set to 0 but list generators if
470
found
471
472
::
473
474
sage: print E.mwrank('-v0 -l')
475
Curve [0,0,0,877,0] : 0 <= rank <= 1
476
Regulator = 1
477
478
Run mwrank again, this time with a higher bound for point searching
479
on homogeneous spaces::
480
481
sage: print E.mwrank('-v0 -l -b11')
482
Curve [0,0,0,877,0] : Rank = 1
483
Generator 1 is [29604565304828237474403861024284371796799791624792913256602210:-256256267988926809388776834045513089648669153204356603464786949:490078023219787588959802933995928925096061616470779979261000]; height 95.980371987964
484
Regulator = 95.980371987964
485
"""
486
if options == "":
487
from sage.interfaces.all import mwrank
488
else:
489
from sage.interfaces.all import Mwrank
490
mwrank = Mwrank(options=options)
491
return mwrank(list(self.a_invariants()))
492
493
def conductor(self, algorithm="pari"):
494
"""
495
Returns the conductor of the elliptic curve.
496
497
INPUT:
498
499
500
- ``algorithm`` - str, (default: "pari")
501
502
- ``"pari"`` - use the PARI C-library ellglobalred
503
implementation of Tate's algorithm
504
505
- ``"mwrank"`` - use Cremona's mwrank implementation
506
of Tate's algorithm; can be faster if the curve has integer
507
coefficients (TODO: limited to small conductor until mwrank gets
508
integer factorization)
509
510
- ``"gp"`` - use the GP interpreter.
511
512
- ``"generic"`` - use the general number field
513
implementation
514
515
- ``"all"`` - use all four implementations, verify
516
that the results are the same (or raise an error), and output the
517
common value.
518
519
520
EXAMPLE::
521
522
sage: E = EllipticCurve([1, -1, 1, -29372, -1932937])
523
sage: E.conductor(algorithm="pari")
524
3006
525
sage: E.conductor(algorithm="mwrank")
526
3006
527
sage: E.conductor(algorithm="gp")
528
3006
529
sage: E.conductor(algorithm="generic")
530
3006
531
sage: E.conductor(algorithm="all")
532
3006
533
534
.. note::
535
536
The conductor computed using each algorithm is cached
537
separately. Thus calling ``E.conductor('pari')``, then
538
``E.conductor('mwrank')`` and getting the same result
539
checks that both systems compute the same answer.
540
"""
541
542
if algorithm == "pari":
543
try:
544
return self.__conductor_pari
545
except AttributeError:
546
self.__conductor_pari = Integer(self.pari_mincurve().ellglobalred()[0])
547
return self.__conductor_pari
548
549
elif algorithm == "gp":
550
try:
551
return self.__conductor_gp
552
except AttributeError:
553
self.__conductor_gp = Integer(gp.eval('ellglobalred(ellinit(%s,0))[1]'%list(self.a_invariants())))
554
return self.__conductor_gp
555
556
elif algorithm == "mwrank":
557
try:
558
return self.__conductor_mwrank
559
except AttributeError:
560
if self.is_integral():
561
self.__conductor_mwrank = Integer(self.mwrank_curve().conductor())
562
else:
563
self.__conductor_mwrank = Integer(self.minimal_model().mwrank_curve().conductor())
564
return self.__conductor_mwrank
565
566
elif algorithm == "generic":
567
try:
568
return self.__conductor_generic
569
except AttributeError:
570
self.__conductor_generic = sage.schemes.elliptic_curves.ell_number_field.EllipticCurve_number_field.conductor(self).gen()
571
return self.__conductor_generic
572
573
elif algorithm == "all":
574
N1 = self.conductor("pari")
575
N2 = self.conductor("mwrank")
576
N3 = self.conductor("gp")
577
N4 = self.conductor("generic")
578
if N1 != N2 or N2 != N3 or N2 != N4:
579
raise ArithmeticError, "PARI, mwrank, gp and Sage compute different conductors (%s,%s,%s,%3) for %s"%(
580
N1, N2, N3, N4, self)
581
return N1
582
else:
583
raise RuntimeError, "algorithm '%s' is not known."%algorithm
584
585
####################################################################
586
# Access to PARI curves related to this curve.
587
####################################################################
588
589
def pari_curve(self, prec=None, factor=1):
590
"""
591
Return the PARI curve corresponding to this elliptic curve.
592
593
INPUT:
594
595
596
- ``prec`` - The precision of quantities calculated for the
597
returned curve, in bits. If None, defaults to factor
598
multiplied by the precision of the largest cached curve (or
599
a small default precision depending on the curve if none yet
600
computed).
601
602
- ``factor`` - The factor by which to increase the
603
precision over the maximum previously computed precision. Only used
604
if prec (which gives an explicit precision) is None.
605
606
607
EXAMPLES::
608
609
sage: E = EllipticCurve([0, 0, 1, -1, 0])
610
sage: e = E.pari_curve()
611
sage: type(e)
612
<type 'sage.libs.pari.gen.gen'>
613
sage: e.type()
614
't_VEC'
615
sage: e.ellan(10)
616
[1, -2, -3, 2, -2, 6, -1, 0, 6, 4]
617
618
::
619
620
sage: E = EllipticCurve(RationalField(), ['1/3', '2/3'])
621
sage: e = E.pari_curve(prec=100)
622
sage: E._pari_curve.has_key(100)
623
True
624
sage: e.type()
625
't_VEC'
626
sage: e[:5]
627
[0, 0, 0, 1/3, 2/3]
628
629
This shows that the bug uncovered by trac:`3954` is fixed::
630
631
sage: E._pari_curve.has_key(100)
632
True
633
634
::
635
636
sage: E = EllipticCurve('37a1')
637
sage: Epari = E.pari_curve()
638
sage: Epari[14].python().prec()
639
64
640
sage: [a.precision() for a in Epari]
641
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4] # 32-bit
642
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3] # 64-bit
643
sage: Epari = E.pari_curve(factor=2)
644
sage: Epari[14].python().prec()
645
128
646
647
This shows that the bug uncovered by trac`4715` is fixed::
648
649
sage: Ep = EllipticCurve('903b3').pari_curve()
650
651
When the curve coefficients are large, a larger precision is
652
required (see :trac:`13163`)::
653
654
sage: E = EllipticCurve([4382696457564794691603442338788106497, 28, 3992, 16777216, 298])
655
sage: E.pari_curve(prec=64)
656
Traceback (most recent call last):
657
...
658
PariError: precision too low in ellinit
659
sage: E.pari_curve() # automatically choose the right precision
660
[4382696457564794691603442338788106497, 28, 3992, 16777216, 298, ...]
661
sage: E.minimal_model()
662
Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 7686423934083797390675981169229171907674183588326184511391146727143672423167091484392497987721106542488224058921302964259990799229848935835464702*x + 8202280443553761483773108648734271851215988504820214784899752662100459663011709992446860978259617135893103951840830254045837355547141096270521198994389833928471736723050112419004202643591202131091441454709193394358885 over Rational Field
663
"""
664
try:
665
# if the PARI curve has already been computed to this
666
# precision, returned the cached copy
667
return self._pari_curve[prec]
668
except AttributeError:
669
self._pari_curve = {}
670
except KeyError:
671
pass
672
673
# Double the precision if needed?
674
retry_prec = False
675
676
if prec is None:
677
if len(self._pari_curve) == 0:
678
# No curves computed yet
679
prec = 64
680
retry_prec = True
681
else:
682
# Take largest cached precision
683
prec = max(self._pari_curve.keys())
684
if factor == 1:
685
return self._pari_curve[prec]
686
prec = int(prec * factor)
687
688
pari_invariants = pari(self.a_invariants())
689
while True:
690
try:
691
self._pari_curve[prec] = pari_invariants.ellinit(precision=prec)
692
return self._pari_curve[prec]
693
except PariError as e:
694
if retry_prec and 'precision too low' in str(e):
695
# Retry with double precision
696
prec *= 2
697
else:
698
raise
699
700
def pari_mincurve(self, prec=None, factor=1):
701
"""
702
Return the PARI curve corresponding to a minimal model for this
703
elliptic curve.
704
705
INPUT:
706
707
708
- ``prec`` - The precision of quantities calculated for the
709
returned curve, in bits. If None, defaults to factor
710
multiplied by the precision of the largest cached curve (or
711
the default real precision if none yet computed).
712
713
- ``factor`` - The factor by which to increase the
714
precision over the maximum previously computed precision. Only used
715
if prec (which gives an explicit precision) is None.
716
717
718
EXAMPLES::
719
720
sage: E = EllipticCurve(RationalField(), ['1/3', '2/3'])
721
sage: e = E.pari_mincurve()
722
sage: e[:5]
723
[0, 0, 0, 27, 486]
724
sage: E.conductor()
725
47232
726
sage: e.ellglobalred()
727
[47232, [1, 0, 0, 0], 2]
728
"""
729
try:
730
# if the PARI curve has already been computed to this
731
# precision, returned the cached copy
732
return self._pari_mincurve[prec]
733
except AttributeError:
734
# no PARI curves have been computed for this elliptic curve
735
self._pari_mincurve = {}
736
except KeyError:
737
# PARI curves are cached for this elliptic curve, but they
738
# are not of the requested precision (or prec = None)
739
if prec is None:
740
L = self._pari_mincurve.keys()
741
L.sort()
742
if factor == 1:
743
return self._pari_mincurve[L[-1]]
744
else:
745
prec = int(factor * L[-1])
746
e = self.pari_curve(prec)
747
mc, change = e.ellminimalmodel()
748
self._pari_mincurve[prec] = mc
749
# self.__min_transform = change
750
return mc
751
752
def database_curve(self):
753
"""
754
Return the curve in the elliptic curve database isomorphic to this
755
curve, if possible. Otherwise raise a RuntimeError exception.
756
757
EXAMPLES::
758
759
sage: E = EllipticCurve([0,1,2,3,4])
760
sage: E.database_curve()
761
Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 5 over Rational Field
762
763
.. note::
764
765
The model of the curve in the database can be different
766
from the Weierstrass model for this curve, e.g., database
767
models are always minimal.
768
"""
769
try:
770
return self.__database_curve
771
except AttributeError:
772
misc.verbose("Looking up %s in the database."%self)
773
D = sage.databases.cremona.CremonaDatabase()
774
ainvs = list(self.minimal_model().ainvs())
775
try:
776
self.__database_curve = D.elliptic_curve_from_ainvs(ainvs)
777
except RuntimeError:
778
raise RuntimeError, "Elliptic curve %s not in the database."%self
779
return self.__database_curve
780
781
782
def Np(self, p):
783
r"""
784
The number of points on `E` modulo `p`.
785
786
INPUT:
787
788
- ``p`` (int) -- a prime, not necessarily of good reduction.
789
790
791
OUTPUT:
792
793
(int) The number ofpoints on the reduction of `E` modulo `p`
794
(including the singular point when `p` is a prime of bad
795
reduction).
796
797
EXAMPLES::
798
799
sage: E = EllipticCurve([0, -1, 1, -10, -20])
800
sage: E.Np(2)
801
5
802
sage: E.Np(3)
803
5
804
sage: E.conductor()
805
11
806
sage: E.Np(11)
807
11
808
809
This even works when the prime is large::
810
811
sage: E = EllipticCurve('37a')
812
sage: E.Np(next_prime(10^30))
813
1000000000000001426441464441649
814
"""
815
if self.conductor() % p == 0:
816
return p + 1 - self.ap(p)
817
return p+1 - self.ap(p)
818
819
#def __pari_double_prec(self):
820
# EllipticCurve_number_field._EllipticCurve__pari_double_prec(self)
821
# try:
822
# del self._pari_mincurve
823
# except AttributeError:
824
# pass
825
826
####################################################################
827
# Access to mwrank
828
####################################################################
829
def mwrank_curve(self, verbose=False):
830
"""
831
Construct an mwrank_EllipticCurve from this elliptic curve
832
833
The resulting mwrank_EllipticCurve has available methods from John
834
Cremona's eclib library.
835
836
EXAMPLES::
837
838
sage: E=EllipticCurve('11a1')
839
sage: EE=E.mwrank_curve()
840
sage: EE
841
y^2+ y = x^3 - x^2 - 10*x - 20
842
sage: type(EE)
843
<class 'sage.libs.mwrank.interface.mwrank_EllipticCurve'>
844
sage: EE.isogeny_class()
845
([[0, -1, 1, -10, -20], [0, -1, 1, -7820, -263580], [0, -1, 1, 0, 0]],
846
[[0, 5, 5], [5, 0, 0], [5, 0, 0]])
847
"""
848
try:
849
return self.__mwrank_curve
850
except AttributeError:
851
pass
852
self.__mwrank_curve = mwrank.mwrank_EllipticCurve(
853
list(self.ainvs()), verbose=verbose)
854
return self.__mwrank_curve
855
856
def two_descent(self, verbose=True,
857
selmer_only = False,
858
first_limit = 20,
859
second_limit = 8,
860
n_aux = -1,
861
second_descent = 1):
862
"""
863
Compute 2-descent data for this curve.
864
865
INPUT:
866
867
868
- ``verbose`` - (default: True) print what mwrank is
869
doing. If False, **no output** is printed.
870
871
- ``selmer_only`` - (default: False) selmer_only
872
switch
873
874
- ``first_limit`` - (default: 20) firstlim is bound
875
on x+z second_limit- (default: 8) secondlim is bound on log max
876
x,z , i.e. logarithmic
877
878
- ``n_aux`` - (default: -1) n_aux only relevant for
879
general 2-descent when 2-torsion trivial; n_aux=-1 causes default
880
to be used (depends on method)
881
882
- ``second_descent`` - (default: True)
883
second_descent only relevant for descent via 2-isogeny
884
885
886
OUTPUT:
887
888
Returns ``True`` if the descent succeeded, i.e. if the lower bound and
889
the upper bound for the rank are the same. In this case, generators and
890
the rank are cached. A return value of ``False`` indicates that either
891
rational points were not found, or that Sha[2] is nontrivial and mwrank
892
was unable to determine this for sure.
893
894
EXAMPLES::
895
896
sage: E=EllipticCurve('37a1')
897
sage: E.two_descent(verbose=False)
898
True
899
900
"""
901
misc.verbose("Calling mwrank C++ library.")
902
C = self.mwrank_curve()
903
C.two_descent(verbose, selmer_only,
904
first_limit, second_limit,
905
n_aux, second_descent)
906
if C.certain():
907
self.__gens[True] = [self.point(x, check=True) for x in C.gens()]
908
self.__gens[True].sort()
909
self.__rank[True] = len(self.__gens[True])
910
return C.certain()
911
912
####################################################################
913
# Etc.
914
####################################################################
915
916
def aplist(self, n, python_ints=False):
917
r"""
918
The Fourier coefficients `a_p` of the modular form
919
attached to this elliptic curve, for all primes `p\leq n`.
920
921
INPUT:
922
923
924
- ``n`` - integer
925
926
- ``python_ints`` - bool (default: False); if True
927
return a list of Python ints instead of Sage integers.
928
929
930
OUTPUT: list of integers
931
932
EXAMPLES::
933
934
sage: e = EllipticCurve('37a')
935
sage: e.aplist(1)
936
[]
937
sage: e.aplist(2)
938
[-2]
939
sage: e.aplist(10)
940
[-2, -3, -2, -1]
941
sage: v = e.aplist(13); v
942
[-2, -3, -2, -1, -5, -2]
943
sage: type(v[0])
944
<type 'sage.rings.integer.Integer'>
945
sage: type(e.aplist(13, python_ints=True)[0])
946
<type 'int'>
947
"""
948
e = self.pari_mincurve()
949
v = e.ellaplist(n, python_ints=True)
950
if python_ints:
951
return v
952
else:
953
return [Integer(a) for a in v]
954
955
956
957
def anlist(self, n, python_ints=False):
958
"""
959
The Fourier coefficients up to and including `a_n` of the
960
modular form attached to this elliptic curve. The i-th element of
961
the return list is a[i].
962
963
INPUT:
964
965
966
- ``n`` - integer
967
968
- ``python_ints`` - bool (default: False); if True
969
return a list of Python ints instead of Sage integers.
970
971
972
OUTPUT: list of integers
973
974
EXAMPLES::
975
976
sage: E = EllipticCurve([0, -1, 1, -10, -20])
977
sage: E.anlist(3)
978
[0, 1, -2, -1]
979
980
::
981
982
sage: E = EllipticCurve([0,1])
983
sage: E.anlist(20)
984
[0, 1, 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 8, 0]
985
"""
986
n = int(n)
987
e = self.pari_mincurve()
988
if n >= 2147483648:
989
raise RuntimeError, "anlist: n (=%s) must be < 2147483648."%n
990
991
v = [0] + e.ellan(n, python_ints=True)
992
if not python_ints:
993
v = [Integer(x) for x in v]
994
return v
995
996
997
# There is some overheard associated with coercing the PARI
998
# list back to Python, but it's not bad. It's better to do it
999
# this way instead of trying to eval the whole list, since the
1000
# int conversion is done very sensibly. NOTE: This would fail
1001
# if a_n won't fit in a C int, i.e., is bigger than
1002
# 2147483648; however, we wouldn't realistically compute
1003
# anlist for n that large anyway.
1004
#
1005
# Some relevant timings:
1006
#
1007
# E <--> [0, 1, 1, -2, 0] 389A
1008
# E = EllipticCurve([0, 1, 1, -2, 0]); // Sage or MAGMA
1009
# e = E.pari_mincurve()
1010
# f = ellinit([0,1,1,-2,0]);
1011
#
1012
# Computation Time (1.6Ghz Pentium-4m laptop)
1013
# time v:=TracesOfFrobenius(E,10000); // MAGMA 0.120
1014
# gettime;v=ellan(f,10000);gettime/1000 0.046
1015
# time v=e.ellan (10000) 0.04
1016
# time v=E.anlist(10000) 0.07
1017
1018
# time v:=TracesOfFrobenius(E,100000); // MAGMA 1.620
1019
# gettime;v=ellan(f,100000);gettime/1000 0.676
1020
# time v=e.ellan (100000) 0.7
1021
# time v=E.anlist(100000) 0.83
1022
1023
# time v:=TracesOfFrobenius(E,1000000); // MAGMA 20.850
1024
# gettime;v=ellan(f,1000000);gettime/1000 9.238
1025
# time v=e.ellan (1000000) 9.61
1026
# time v=E.anlist(1000000) 10.95 (13.171 in cygwin vmware)
1027
1028
# time v:=TracesOfFrobenius(E,10000000); //MAGMA 257.850
1029
# gettime;v=ellan(f,10000000);gettime/1000 FAILS no matter how many allocatemem()'s!!
1030
# time v=e.ellan (10000000) 139.37
1031
# time v=E.anlist(10000000) 136.32
1032
#
1033
# The last Sage comp retries with stack size 40MB,
1034
# 80MB, 160MB, and succeeds last time. It's very interesting that this
1035
# last computation is *not* possible in GP, but works in py_pari!
1036
#
1037
1038
def q_expansion(self, prec):
1039
r"""
1040
Return the `q`-expansion to precision prec of the newform
1041
attached to this elliptic curve.
1042
1043
INPUT:
1044
1045
1046
- ``prec`` - an integer
1047
1048
1049
OUTPUT:
1050
1051
a power series (in the variable 'q')
1052
1053
.. note::
1054
1055
If you want the output to be a modular form and not just a
1056
`q`-expansion, use :meth:`.modular_form`.
1057
1058
EXAMPLES::
1059
1060
sage: E=EllipticCurve('37a1')
1061
sage: E.q_expansion(20)
1062
q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + 6*q^6 - q^7 + 6*q^9 + 4*q^10 - 5*q^11 - 6*q^12 - 2*q^13 + 2*q^14 + 6*q^15 - 4*q^16 - 12*q^18 + O(q^20)
1063
"""
1064
return PowerSeriesRing(Q, 'q')(self.anlist(prec), prec, check=True)
1065
1066
def modular_form(self):
1067
r"""
1068
Return the cuspidal modular form associated to this elliptic
1069
curve.
1070
1071
EXAMPLES::
1072
1073
sage: E = EllipticCurve('37a')
1074
sage: f = E.modular_form()
1075
sage: f
1076
q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + O(q^6)
1077
1078
If you need to see more terms in the `q`-expansion::
1079
1080
sage: f.q_expansion(20)
1081
q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + 6*q^6 - q^7 + 6*q^9 + 4*q^10 - 5*q^11 - 6*q^12 - 2*q^13 + 2*q^14 + 6*q^15 - 4*q^16 - 12*q^18 + O(q^20)
1082
1083
.. note::
1084
1085
If you just want the `q`-expansion, use
1086
:meth:`.q_expansion`.
1087
"""
1088
try:
1089
return self.__modular_form
1090
except AttributeError:
1091
M = sage.modular.modform.constructor.ModularForms(self.conductor(),weight=2)
1092
f = sage.modular.modform.element.ModularFormElement_elliptic_curve(M, self)
1093
self.__modular_form = f
1094
return f
1095
1096
def modular_symbol_space(self, sign=1, base_ring=Q, bound=None):
1097
r"""
1098
Return the space of cuspidal modular symbols associated to this
1099
elliptic curve, with given sign and base ring.
1100
1101
INPUT:
1102
1103
1104
- ``sign`` - 0, -1, or 1
1105
1106
- ``base_ring`` - a ring
1107
1108
1109
EXAMPLES::
1110
1111
sage: f = EllipticCurve('37b')
1112
sage: f.modular_symbol_space()
1113
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(37) of weight 2 with sign 1 over Rational Field
1114
sage: f.modular_symbol_space(-1)
1115
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 for Gamma_0(37) of weight 2 with sign -1 over Rational Field
1116
sage: f.modular_symbol_space(0, bound=3)
1117
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(37) of weight 2 with sign 0 over Rational Field
1118
1119
.. note::
1120
1121
If you just want the `q`-expansion, use
1122
:meth:`.q_expansion`.
1123
"""
1124
typ = (sign, base_ring)
1125
try:
1126
return self.__modular_symbol_space[typ]
1127
except AttributeError:
1128
self.__modular_symbol_space = {}
1129
except KeyError:
1130
pass
1131
M = ell_modular_symbols.modular_symbol_space(self, sign, base_ring, bound=bound)
1132
self.__modular_symbol_space[typ] = M
1133
return M
1134
1135
def modular_symbol(self, sign=1, use_eclib = False, normalize = "L_ratio"):
1136
r"""
1137
Return the modular symbol associated to this elliptic curve,
1138
with given sign and base ring. This is the map that sends `r/s`
1139
to a fixed multiple of the integral of `2 \pi i f(z) dz`
1140
from `\infty` to `r/s`, normalized so that all values of this map take
1141
values in `\QQ`.
1142
1143
The normalization is such that for sign +1,
1144
the value at the cusp 0 is equal to the quotient of `L(E,1)`
1145
by the least positive period of `E` (unlike in ``L_ratio``
1146
of ``lseries()``, where the value is also divided by the
1147
number of connected components of `E(\RR)`). In particular the
1148
modular symbol depends on `E` and not only the isogeny class of `E`.
1149
1150
INPUT:
1151
1152
- ``sign`` - 1 (default) or -1
1153
1154
- ``use_eclib`` - (default: False); if True the computation is
1155
done with John Cremona's implementation of modular
1156
symbols in ``eclib``
1157
1158
- ``normalize`` - (default: 'L_ratio'); either 'L_ratio',
1159
'period', or 'none';
1160
For 'L_ratio', the modular symbol tries to normalized correctly
1161
as explained above by comparing it to ``L_ratio`` for the
1162
curve and some small twists.
1163
The normalization 'period' is only available if
1164
``use_eclib=False``. It uses the ``integral_period_map`` for modular
1165
symbols and is known to be equal to the above normalization
1166
up to the sign and a possible power of 2.
1167
For 'none', the modular symbol is almost certainly
1168
not correctly normalized, i.e. all values will be a
1169
fixed scalar multiple of what they should be. But
1170
the initial computation of the modular symbol is
1171
much faster if ``use_eclib=False``, though evaluation of
1172
it after computing it won't be any faster.
1173
1174
EXAMPLES::
1175
1176
sage: E=EllipticCurve('37a1')
1177
sage: M=E.modular_symbol(); M
1178
Modular symbol with sign 1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
1179
sage: M(1/2)
1180
0
1181
sage: M(1/5)
1182
1
1183
1184
::
1185
1186
sage: E=EllipticCurve('121b1')
1187
sage: M=E.modular_symbol()
1188
Warning : Could not normalize the modular symbols, maybe all further results will be multiplied by -1, 2 or -2.
1189
sage: M(1/7)
1190
-1/2
1191
1192
::
1193
1194
sage: E=EllipticCurve('11a1')
1195
sage: E.modular_symbol()(0)
1196
1/5
1197
sage: E=EllipticCurve('11a2')
1198
sage: E.modular_symbol()(0)
1199
1
1200
sage: E=EllipticCurve('11a3')
1201
sage: E.modular_symbol()(0)
1202
1/25
1203
1204
::
1205
1206
sage: E=EllipticCurve('11a2')
1207
sage: E.modular_symbol(use_eclib=True, normalize='L_ratio')(0)
1208
1
1209
sage: E.modular_symbol(use_eclib=True, normalize='none')(0)
1210
2/5
1211
sage: E.modular_symbol(use_eclib=True, normalize='period')(0)
1212
Traceback (most recent call last):
1213
...
1214
ValueError: no normalization 'period' known for modular symbols using John Cremona's eclib
1215
sage: E.modular_symbol(use_eclib=False, normalize='L_ratio')(0)
1216
1
1217
sage: E.modular_symbol(use_eclib=False, normalize='none')(0)
1218
1
1219
sage: E.modular_symbol(use_eclib=False, normalize='period')(0)
1220
1
1221
1222
::
1223
1224
sage: E=EllipticCurve('11a3')
1225
sage: E.modular_symbol(use_eclib=True, normalize='L_ratio')(0)
1226
1/25
1227
sage: E.modular_symbol(use_eclib=True, normalize='none')(0)
1228
2/5
1229
sage: E.modular_symbol(use_eclib=True, normalize='period')(0)
1230
Traceback (most recent call last):
1231
...
1232
ValueError: no normalization 'period' known for modular symbols using John Cremona's eclib
1233
sage: E.modular_symbol(use_eclib=False, normalize='L_ratio')(0)
1234
1/25
1235
sage: E.modular_symbol(use_eclib=False, normalize='none')(0)
1236
1
1237
sage: E.modular_symbol(use_eclib=False, normalize='period')(0)
1238
1/25
1239
1240
"""
1241
typ = (sign, normalize, use_eclib)
1242
try:
1243
return self.__modular_symbol[typ]
1244
except AttributeError:
1245
self.__modular_symbol = {}
1246
except KeyError:
1247
pass
1248
if use_eclib :
1249
M = ell_modular_symbols.ModularSymbolECLIB(self, sign, normalize=normalize)
1250
else :
1251
M = ell_modular_symbols.ModularSymbolSage(self, sign, normalize=normalize)
1252
self.__modular_symbol[typ] = M
1253
return M
1254
1255
padic_lseries = padics.padic_lseries
1256
1257
def newform(self):
1258
r"""
1259
Same as ``self.modular_form()``.
1260
1261
EXAMPLES::
1262
1263
sage: E=EllipticCurve('37a1')
1264
sage: E.newform()
1265
q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + O(q^6)
1266
sage: E.newform() == E.modular_form()
1267
True
1268
"""
1269
return self.modular_form()
1270
1271
def q_eigenform(self, prec):
1272
r"""
1273
Synonym for ``self.q_expansion(prec)``.
1274
1275
EXAMPLES::
1276
1277
sage: E=EllipticCurve('37a1')
1278
sage: E.q_eigenform(10)
1279
q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + 6*q^6 - q^7 + 6*q^9 + O(q^10)
1280
sage: E.q_eigenform(10) == E.q_expansion(10)
1281
True
1282
"""
1283
return self.q_expansion(prec)
1284
1285
def analytic_rank(self, algorithm="pari", leading_coefficient=False):
1286
r"""
1287
Return an integer that is *probably* the analytic rank of this
1288
elliptic curve. If leading_coefficient is ``True`` (only implemented
1289
for PARI), return a tuple `(rank, lead)` where `lead` is the value of
1290
the first non-zero derivative of the L-function of the elliptic
1291
curve.
1292
1293
INPUT:
1294
1295
- algorithm -
1296
1297
- 'pari' (default) - use the PARI library function.
1298
1299
- 'sympow' -use Watkins's program sympow
1300
1301
- 'rubinstein' - use Rubinstein's L-function C++ program lcalc.
1302
1303
- 'magma' - use MAGMA
1304
1305
- 'all' - compute with all other free algorithms, check that
1306
the answers agree, and return the common answer.
1307
1308
.. note::
1309
1310
If the curve is loaded from the large Cremona database,
1311
then the modular degree is taken from the database.
1312
1313
Of the three above, probably Rubinstein's is the most
1314
efficient (in some limited testing I've done).
1315
1316
.. note::
1317
1318
It is an open problem to *prove* that *any* particular
1319
elliptic curve has analytic rank `\geq 4`.
1320
1321
EXAMPLES::
1322
1323
sage: E = EllipticCurve('389a')
1324
sage: E.analytic_rank(algorithm='pari')
1325
2
1326
sage: E.analytic_rank(algorithm='rubinstein')
1327
2
1328
sage: E.analytic_rank(algorithm='sympow')
1329
2
1330
sage: E.analytic_rank(algorithm='magma') # optional - magma
1331
2
1332
sage: E.analytic_rank(algorithm='all')
1333
2
1334
1335
With the optional parameter leading_coefficient set to ``True``, a
1336
tuple of both the analytic rank and the leading term of the
1337
L-series at `s = 1` is returned::
1338
1339
sage: EllipticCurve([0,-1,1,-10,-20]).analytic_rank(leading_coefficient=True)
1340
(0, 0.25384186085591068...)
1341
sage: EllipticCurve([0,0,1,-1,0]).analytic_rank(leading_coefficient=True)
1342
(1, 0.30599977383405230...)
1343
sage: EllipticCurve([0,1,1,-2,0]).analytic_rank(leading_coefficient=True)
1344
(2, 1.518633000576853...)
1345
sage: EllipticCurve([0,0,1,-7,6]).analytic_rank(leading_coefficient=True)
1346
(3, 10.39109940071580...)
1347
sage: EllipticCurve([0,0,1,-7,36]).analytic_rank(leading_coefficient=True)
1348
(4, 196.170903794579...)
1349
1350
TESTS:
1351
1352
When the input is horrendous, some of the algorithms just bomb out with a RuntimeError::
1353
1354
sage: EllipticCurve([1234567,89101112]).analytic_rank(algorithm='rubinstein')
1355
Traceback (most recent call last):
1356
...
1357
RuntimeError: unable to compute analytic rank using rubinstein algorithm ('unable to convert x (= 6.19283e+19 and is too large) to an integer')
1358
sage: EllipticCurve([1234567,89101112]).analytic_rank(algorithm='sympow')
1359
Traceback (most recent call last):
1360
...
1361
RuntimeError: failed to compute analytic rank
1362
"""
1363
if algorithm == 'pari':
1364
rank_lead = self.pari_curve().ellanalyticrank()
1365
if leading_coefficient:
1366
return (rings.Integer(rank_lead[0]), rank_lead[1].python())
1367
else:
1368
return rings.Integer(self.pari_curve().ellanalyticrank()[0])
1369
elif algorithm == 'rubinstein':
1370
if leading_coefficient:
1371
raise NotImplementedError, "Cannot compute leading coefficient using rubinstein algorithm"
1372
try:
1373
from sage.lfunctions.lcalc import lcalc
1374
return lcalc.analytic_rank(L=self)
1375
except TypeError,msg:
1376
raise RuntimeError, "unable to compute analytic rank using rubinstein algorithm ('%s')"%msg
1377
elif algorithm == 'sympow':
1378
if leading_coefficient:
1379
raise NotImplementedError, "Cannot compute leading coefficient using sympow"
1380
from sage.lfunctions.sympow import sympow
1381
return sympow.analytic_rank(self)[0]
1382
elif algorithm == 'magma':
1383
if leading_coefficient:
1384
raise NotImplementedError, "Cannot compute leading coefficient using magma"
1385
from sage.interfaces.all import magma
1386
return rings.Integer(magma(self).AnalyticRank())
1387
elif algorithm == 'all':
1388
if leading_coefficient:
1389
S = set([self.analytic_rank('pari', True)])
1390
else:
1391
S = set([self.analytic_rank('pari'),
1392
self.analytic_rank('rubinstein'), self.analytic_rank('sympow')])
1393
if len(S) != 1:
1394
raise RuntimeError, "Bug in analytic_rank; algorithms don't agree! (E=%s)"%self
1395
return list(S)[0]
1396
else:
1397
raise ValueError, "algorithm %s not defined"%algorithm
1398
1399
1400
def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=10, maxprob=20, limbigprime=30):
1401
r"""
1402
Computes a lower bound for the rank of the Mordell-Weil group `E(Q)`,
1403
the rank of the 2-Selmer group, and a list of points of infinite order on
1404
`E(Q)`.
1405
1406
INPUT:
1407
1408
1409
- ``verbose`` - integer, 0,1,2,3; (default: 0), the
1410
verbosity level
1411
1412
- ``lim1`` - (default: 5) limite des points triviaux
1413
sur les quartiques
1414
1415
- ``lim3`` - (default: 50) limite des points sur les
1416
quartiques ELS
1417
1418
- ``limtriv`` - (default: 10) limite des points
1419
triviaux sur la courbe elliptique
1420
1421
- ``maxprob`` - (default: 20)
1422
1423
- ``limbigprime`` - (default: 30) to distinguish
1424
between small and large prime numbers. Use probabilistic tests for
1425
large primes. If 0, don't any probabilistic tests.
1426
1427
1428
OUTPUT:
1429
1430
1431
- ``integer`` - lower bound on the rank of self
1432
1433
- ``integer`` - the dimension of the 2-Selmer group.
1434
This is an upper bound to the rank, but it is not sharp in general.
1435
1436
- ``list`` - list of points of infinite order in `E(Q)`.
1437
1438
To obtain a list of generators, use E.gens().
1439
1440
1441
IMPLEMENTATION: Uses Denis Simon's PARI/GP scripts from
1442
http://www.math.unicaen.fr/~simon/
1443
1444
EXAMPLES: These computations use pseudo-random numbers, so we set
1445
the seed for reproducible testing.
1446
1447
We compute the ranks of the curves of lowest known conductor up to
1448
rank `8`. Amazingly, each of these computations finishes
1449
almost instantly!
1450
1451
::
1452
1453
sage: E = EllipticCurve('11a1')
1454
sage: set_random_seed(0)
1455
sage: E.simon_two_descent()
1456
(0, 0, [])
1457
sage: E = EllipticCurve('37a1')
1458
sage: set_random_seed(0)
1459
sage: E.simon_two_descent()
1460
(1, 1, [(0 : 0 : 1)])
1461
sage: E = EllipticCurve('389a1')
1462
sage: set_random_seed(0)
1463
sage: E.simon_two_descent()
1464
(2, 2, [(1 : 0 : 1), (-11/9 : -55/27 : 1)])
1465
sage: E = EllipticCurve('5077a1')
1466
sage: set_random_seed(0)
1467
sage: E.simon_two_descent()
1468
(3, 3, [(1 : -1 : 1), (2 : 0 : 1), (0 : 2 : 1)])
1469
1470
In this example Simon's program does not find any points, though it
1471
does correctly compute the rank of the 2-Selmer group.
1472
1473
::
1474
1475
sage: E = EllipticCurve([1, -1, 0, -751055859, -7922219731979])
1476
sage: set_random_seed(0)
1477
sage: E.simon_two_descent()
1478
(1, 1, [])
1479
1480
The rest of these entries were taken from Tom Womack's page
1481
http://tom.womack.net/maths/conductors.htm
1482
1483
::
1484
1485
sage: E = EllipticCurve([1, -1, 0, -79, 289])
1486
sage: set_random_seed(0)
1487
sage: E.simon_two_descent()
1488
(4, 4, [(4 : 3 : 1), (5 : -2 : 1), (6 : -1 : 1), (8 : 7 : 1)])
1489
sage: E = EllipticCurve([0, 0, 1, -79, 342])
1490
sage: set_random_seed(0)
1491
sage: E.simon_two_descent() # long time (9s on sage.math, 2011)
1492
(5, 5, [(5 : 8 : 1), (4 : 9 : 1), (3 : 11 : 1), (-1 : 20 : 1), (-6 : -25 : 1)])
1493
sage: E = EllipticCurve([1, 1, 0, -2582, 48720])
1494
sage: set_random_seed(0)
1495
sage: r, s, G = E.simon_two_descent(); r,s
1496
(6, 6)
1497
sage: E = EllipticCurve([0, 0, 0, -10012, 346900])
1498
sage: set_random_seed(0)
1499
sage: r, s, G = E.simon_two_descent(); r,s
1500
(7, 7)
1501
sage: E = EllipticCurve([0, 0, 1, -23737, 960366])
1502
sage: set_random_seed(0)
1503
sage: r, s, G = E.simon_two_descent(); r,s
1504
(8, 8)
1505
1506
Example from :trac: `10832`::
1507
1508
sage: E = EllipticCurve([1,0,0,-6664,86543])
1509
sage: E.simon_two_descent()
1510
(2, 3, [(-73 : -394 : 1), (323/4 : 1891/8 : 1)])
1511
sage: E.rank()
1512
2
1513
sage: E.gens()
1514
[(-73 : -394 : 1), (323/4 : 1891/8 : 1)]
1515
1516
Example where the lower bound is known to be 1
1517
despite that the algorithm has not found any
1518
points of infinite order ::
1519
1520
sage: E = EllipticCurve([1, 1, 0, -23611790086, 1396491910863060])
1521
sage: E.simon_two_descent()
1522
(1, 2, [])
1523
sage: E.rank()
1524
1
1525
sage: E.gens() # uses mwrank
1526
[(4311692542083/48594841 : -13035144436525227/338754636611 : 1)]
1527
1528
Example for :trac: `5153`::
1529
1530
sage: E = EllipticCurve([3,0])
1531
sage: E.simon_two_descent()
1532
(1, 2, [(3 : 6 : 1)])
1533
1534
"""
1535
verbose = int(verbose)
1536
t = simon_two_descent(self, verbose=verbose, lim1=lim1, lim3=lim3, limtriv=limtriv,
1537
maxprob=maxprob, limbigprime=limbigprime)
1538
if t=='fail':
1539
raise RuntimeError, 'Run-time error in simon_two_descent.'
1540
if verbose>0:
1541
print "simon_two_descent returns", t
1542
rank_low_bd = rings.Integer(t[0])
1543
two_selmer_rank = rings.Integer(t[1])
1544
pts = [self(P) for P in t[2]]
1545
pts = [P for P in pts if P.has_infinite_order()]
1546
if rank_low_bd == two_selmer_rank - self.two_torsion_rank():
1547
if verbose>0:
1548
print "Rank determined successfully, saturating..."
1549
gens = self.saturation(pts)[0]
1550
if len(gens) == rank_low_bd:
1551
self.__gens[True] = gens
1552
self.__gens[True].sort()
1553
self.__rank[True] = rank_low_bd
1554
1555
return rank_low_bd, two_selmer_rank, pts
1556
1557
two_descent_simon = simon_two_descent
1558
1559
def three_selmer_rank(self, algorithm='UseSUnits'):
1560
r"""
1561
Return the 3-selmer rank of this elliptic curve, computed using
1562
Magma.
1563
1564
INPUT:
1565
1566
1567
- ``algorithm`` - 'Heuristic' (which is usually much
1568
faster in large examples), 'FindCubeRoots', or 'UseSUnits'
1569
(default)
1570
1571
1572
OUTPUT: nonnegative integer
1573
1574
EXAMPLES: A rank 0 curve::
1575
1576
sage: EllipticCurve('11a').three_selmer_rank() # optional - magma
1577
0
1578
1579
A rank 0 curve with rational 3-isogeny but no 3-torsion
1580
1581
::
1582
1583
sage: EllipticCurve('14a3').three_selmer_rank() # optional - magma
1584
0
1585
1586
A rank 0 curve with rational 3-torsion::
1587
1588
sage: EllipticCurve('14a1').three_selmer_rank() # optional - magma
1589
1
1590
1591
A rank 1 curve with rational 3-isogeny::
1592
1593
sage: EllipticCurve('91b').three_selmer_rank() # optional - magma
1594
2
1595
1596
A rank 0 curve with nontrivial 3-Sha. The Heuristic option makes
1597
this about twice as fast as without it.
1598
1599
::
1600
1601
sage: EllipticCurve('681b').three_selmer_rank(algorithm='Heuristic') # long time (10 seconds); optional - magma
1602
2
1603
"""
1604
from sage.interfaces.all import magma
1605
E = magma(self)
1606
return Integer(E.ThreeSelmerGroup(MethodForFinalStep = magma('"%s"'%algorithm)).Ngens())
1607
1608
def rank(self, use_database=False, verbose=False,
1609
only_use_mwrank=True,
1610
algorithm='mwrank_lib',
1611
proof=None):
1612
"""
1613
Return the rank of this elliptic curve, assuming no conjectures.
1614
1615
If we fail to provably compute the rank, raises a RuntimeError
1616
exception.
1617
1618
INPUT:
1619
1620
1621
- ``use_database (bool)`` - (default: False), if
1622
True, try to look up the regulator in the Cremona database.
1623
1624
- ``verbose`` - (default: None), if specified changes
1625
the verbosity of mwrank computations. algorithm -
1626
1627
- ``- 'mwrank_shell'`` - call mwrank shell command
1628
1629
- ``- 'mwrank_lib'`` - call mwrank c library
1630
1631
- ``only_use_mwrank`` - (default: True) if False try
1632
using analytic rank methods first.
1633
1634
- ``proof`` - bool or None (default: None, see
1635
proof.elliptic_curve or sage.structure.proof). Note that results
1636
obtained from databases are considered proof = True
1637
1638
1639
OUTPUT:
1640
1641
1642
- ``rank (int)`` - the rank of the elliptic curve.
1643
1644
1645
IMPLEMENTATION: Uses L-functions, mwrank, and databases.
1646
1647
EXAMPLES::
1648
1649
sage: EllipticCurve('11a').rank()
1650
0
1651
sage: EllipticCurve('37a').rank()
1652
1
1653
sage: EllipticCurve('389a').rank()
1654
2
1655
sage: EllipticCurve('5077a').rank()
1656
3
1657
sage: EllipticCurve([1, -1, 0, -79, 289]).rank() # This will use the default proof behavior of True
1658
4
1659
sage: EllipticCurve([0, 0, 1, -79, 342]).rank(proof=False)
1660
5
1661
sage: EllipticCurve([0, 0, 1, -79, 342]).simon_two_descent()[0] # long time (7s on sage.math, 2012)
1662
5
1663
1664
Examples with denominators in defining equations::
1665
1666
sage: E = EllipticCurve([0, 0, 0, 0, -675/4])
1667
sage: E.rank()
1668
0
1669
sage: E = EllipticCurve([0, 0, 1/2, 0, -1/5])
1670
sage: E.rank()
1671
1
1672
sage: E.minimal_model().rank()
1673
1
1674
1675
A large example where mwrank doesn't determine the result with certainty::
1676
1677
sage: EllipticCurve([1,0,0,0,37455]).rank(proof=False)
1678
0
1679
sage: EllipticCurve([1,0,0,0,37455]).rank(proof=True)
1680
Traceback (most recent call last):
1681
...
1682
RuntimeError: Rank not provably correct.
1683
"""
1684
if proof is None:
1685
from sage.structure.proof.proof import get_flag
1686
proof = get_flag(proof, "elliptic_curve")
1687
else:
1688
proof = bool(proof)
1689
try:
1690
return self.__rank[proof]
1691
except KeyError:
1692
if proof is False and self.__rank.has_key(True):
1693
return self.__rank[True]
1694
if use_database:
1695
try:
1696
self.__rank[True] = self.database_curve().rank()
1697
return self.__rank[True]
1698
except (AttributeError, RuntimeError):
1699
pass
1700
if not only_use_mwrank:
1701
N = self.conductor()
1702
prec = int(4*float(sqrt(N))) + 10
1703
if self.root_number() == 1:
1704
L, err = self.lseries().at1(prec)
1705
if abs(L) > err + R(0.0001): # definitely doesn't vanish
1706
misc.verbose("rank 0 because L(E,1)=%s"%L)
1707
self.__rank[proof] = 0
1708
return self.__rank[proof]
1709
else:
1710
Lprime, err = self.lseries().deriv_at1(prec)
1711
if abs(Lprime) > err + R(0.0001): # definitely doesn't vanish
1712
misc.verbose("rank 1 because L'(E,1)=%s"%Lprime)
1713
self.__rank[proof] = 1
1714
return self.__rank[proof]
1715
1716
if algorithm == 'mwrank_lib':
1717
misc.verbose("using mwrank lib")
1718
if self.is_integral(): E = self
1719
else: E = self.integral_model()
1720
C = E.mwrank_curve()
1721
C.set_verbose(verbose)
1722
r = C.rank()
1723
if C.certain():
1724
proof = True
1725
else:
1726
if proof:
1727
print "Unable to compute the rank with certainty (lower bound=%s)."%C.rank()
1728
print "This could be because Sha(E/Q)[2] is nontrivial."
1729
print "Try calling something like two_descent(second_limit=13) on the"
1730
print "curve then trying this command again. You could also try rank"
1731
print "with only_use_mwrank=False."
1732
del E.__mwrank_curve
1733
raise RuntimeError, 'Rank not provably correct.'
1734
else:
1735
misc.verbose("Warning -- rank not proven correct", level=1)
1736
self.__rank[proof] = r
1737
elif algorithm == 'mwrank_shell':
1738
misc.verbose("using mwrank shell")
1739
X = self.mwrank()
1740
if 'determined unconditionally' not in X or 'only a lower bound of' in X:
1741
if proof:
1742
X= "".join(X.split("\n")[-4:-2])
1743
print X
1744
raise RuntimeError, 'Rank not provably correct.'
1745
else:
1746
misc.verbose("Warning -- rank not proven correct", level=1)
1747
1748
s = "lower bound of"
1749
X = X[X.rfind(s)+len(s)+1:]
1750
r = Integer(X.split()[0])
1751
else:
1752
if proof is False:
1753
proof = True #since we actually provably found the rank
1754
match = 'Rank ='
1755
i = X.find(match)
1756
if i == -1:
1757
match = 'found points of rank'
1758
i = X.find(match)
1759
if i == -1:
1760
raise RuntimeError, "%s\nbug -- tried to find 'Rank =' or 'found points of rank' in mwrank output but couldn't."%X
1761
j = i + X[i:].find('\n')
1762
r = Integer(X[i+len(match)+1:j])
1763
self.__rank[proof] = r
1764
1765
return self.__rank[proof]
1766
1767
def gens(self, verbose=False, rank1_search=10,
1768
algorithm='mwrank_lib',
1769
only_use_mwrank=True,
1770
proof = None,
1771
use_database = True,
1772
descent_second_limit=12,
1773
sat_bound = 1000):
1774
"""
1775
Compute and return generators for the Mordell-Weil group E(Q)
1776
*modulo* torsion.
1777
1778
.. warning::
1779
1780
If the program fails to give a provably correct result, it
1781
prints a warning message, but does not raise an
1782
exception. Use the gens_certain command to find out if this
1783
warning message was printed.
1784
1785
INPUT:
1786
1787
1788
- ``verbose`` - (default: None), if specified changes
1789
the verbosity of mwrank computations.
1790
1791
- ``rank1_search`` - (default: 10), if the curve has
1792
analytic rank 1, try to find a generator by a direct search up to
1793
this logarithmic height. If this fails the usual mwrank procedure
1794
is called. algorithm -
1795
1796
- ``- 'mwrank_shell' (default)`` - call mwrank shell
1797
command
1798
1799
- ``- 'mwrank_lib'`` - call mwrank c library
1800
1801
- ``only_use_mwrank`` - bool (default True) if
1802
False, attempts to first use more naive, natively implemented
1803
methods.
1804
1805
- ``proof`` - bool or None (default None, see
1806
proof.elliptic_curve or sage.structure.proof).
1807
1808
- ``use_database`` - bool (default True) if True,
1809
attempts to find curve and gens in the (optional) database
1810
1811
- ``descent_second_limit`` - (default: 12)- used in 2-descent
1812
1813
- ``sat_bound`` - (default: 1000) - bound on primes used in
1814
saturation. If the computed bound on the index of the
1815
points found by two-descent in the Mordell-Weil group is
1816
greater than this, a warning message will be displayed.
1817
1818
OUTPUT:
1819
1820
1821
- ``generators`` - List of generators for the
1822
Mordell-Weil group modulo torsion.
1823
1824
1825
IMPLEMENTATION: Uses Cremona's mwrank C library.
1826
1827
EXAMPLES::
1828
1829
sage: E = EllipticCurve('389a')
1830
sage: E.gens() # random output
1831
[(-1 : 1 : 1), (0 : 0 : 1)]
1832
1833
A non-integral example::
1834
1835
sage: E = EllipticCurve([-3/8,-2/3])
1836
sage: E.gens() # random (up to sign)
1837
[(10/9 : 29/54 : 1)]
1838
1839
A non-minimal example::
1840
1841
sage: E = EllipticCurve('389a1')
1842
sage: E1 = E.change_weierstrass_model([1/20,0,0,0]); E1
1843
Elliptic Curve defined by y^2 + 8000*y = x^3 + 400*x^2 - 320000*x over Rational Field
1844
sage: E1.gens() # random (if database not used)
1845
[(-400 : 8000 : 1), (0 : -8000 : 1)]
1846
"""
1847
if proof is None:
1848
from sage.structure.proof.proof import get_flag
1849
proof = get_flag(proof, "elliptic_curve")
1850
else:
1851
proof = bool(proof)
1852
1853
# If the gens are already cached, return them:
1854
try:
1855
return list(self.__gens[proof]) # return copy so not changed
1856
except AttributeError:
1857
pass
1858
except KeyError:
1859
if proof is False and self.__gens.has_key(True):
1860
return self.__gens[True]
1861
1862
# At this point, either self.__gens does not exist, or
1863
# self.__gens[False] exists but not self.__gens[True], and
1864
# proof is True
1865
1866
# If the optional extended database is installed and an
1867
# isomorphic curve is in the database then its gens will be
1868
# known; if only the default database is installed, the rank
1869
# will be known but not the gens.
1870
1871
if use_database:
1872
try:
1873
E = self.database_curve()
1874
iso = E.isomorphism_to(self)
1875
try:
1876
self.__gens[True] = [iso(P) for P in E.__gens[True]]
1877
return self.__gens[True]
1878
except (KeyError,AttributeError): # database curve does not have the gens
1879
pass
1880
except (RuntimeError, KeyError): # curve or gens not in database
1881
pass
1882
1883
if self.conductor() > 10**7:
1884
only_use_mwrank = True
1885
1886
if not only_use_mwrank:
1887
try:
1888
misc.verbose("Trying to compute rank.")
1889
r = self.rank(only_use_mwrank = False)
1890
misc.verbose("Got r = %s."%r)
1891
if r == 0:
1892
misc.verbose("Rank = 0, so done.")
1893
self.__gens[True] = []
1894
return self.__gens[True]
1895
if r == 1 and rank1_search:
1896
misc.verbose("Rank = 1, so using direct search.")
1897
h = 6
1898
while h <= rank1_search:
1899
misc.verbose("Trying direct search up to height %s"%h)
1900
G = self.point_search(h, verbose)
1901
G = [P for P in G if P.order() == oo]
1902
if len(G) > 0:
1903
misc.verbose("Direct search succeeded.")
1904
G, _, _ = self.saturation(G, verbose=verbose)
1905
misc.verbose("Computed saturation.")
1906
self.__gens[True] = G
1907
return self.__gens[True]
1908
h += 2
1909
misc.verbose("Direct search FAILED.")
1910
except RuntimeError:
1911
pass
1912
# end if (not_use_mwrank)
1913
if algorithm == "mwrank_lib":
1914
misc.verbose("Calling mwrank C++ library.")
1915
if not self.is_integral():
1916
xterm = 1; yterm = 1
1917
ai = self.a_invariants()
1918
for a in ai:
1919
if not a.is_integral():
1920
for p, _ in a.denom().factor():
1921
e = min([(ai[i].valuation(p)/[1,2,3,4,6][i]) for i in range(5)]).floor()
1922
ai = [ai[i]/p**(e*[1,2,3,4,6][i]) for i in range(5)]
1923
xterm *= p**(2*e)
1924
yterm *= p**(3*e)
1925
E = constructor.EllipticCurve(list(ai))
1926
else:
1927
E = self; xterm = 1; yterm = 1
1928
C = E.mwrank_curve(verbose)
1929
if not (verbose is None):
1930
C.set_verbose(verbose)
1931
C.two_descent(verbose=verbose, second_limit=descent_second_limit)
1932
C.saturate(bound=sat_bound)
1933
G = C.gens()
1934
if proof is True and C.certain() is False:
1935
del self.__mwrank_curve
1936
raise RuntimeError, "Unable to compute the rank, hence generators, with certainty (lower bound=%s, generators found=%s). This could be because Sha(E/Q)[2] is nontrivial."%(C.rank(),G) + \
1937
"\nTry increasing descent_second_limit then trying this command again."
1938
else:
1939
proof = C.certain()
1940
G = [[x*xterm,y*yterm,z] for x,y,z in G]
1941
else:
1942
# when gens() calls mwrank it passes the command-line
1943
# parameter "-p 100" which helps curves with large
1944
# coefficients and 2-torsion and is otherwise harmless.
1945
# This is pending a more intelligent handling of mwrank
1946
# options in gens() (which is nontrivial since gens() needs
1947
# to parse the output from mwrank and this is seriously
1948
# affected by what parameters the user passes!).
1949
# In fact it would be much better to avoid the mwrank console at
1950
# all for gens() and just use the library. This is in
1951
# progress (see trac #1949).
1952
X = self.mwrank('-p 100 -S '+str(sat_bound))
1953
misc.verbose("Calling mwrank shell.")
1954
if not 'The rank and full Mordell-Weil basis have been determined unconditionally' in X:
1955
msg = 'Generators not provably computed.'
1956
if proof:
1957
raise RuntimeError, '%s\n%s'%(X,msg)
1958
else:
1959
misc.verbose("Warning -- %s"%msg, level=1)
1960
elif proof is False:
1961
proof = True
1962
G = []
1963
i = X.find('Generator ')
1964
while i != -1:
1965
j = i + X[i:].find(';')
1966
k = i + X[i:].find('[')
1967
G.append(eval(X[k:j].replace(':',',')))
1968
X = X[j:]
1969
i = X.find('Generator ')
1970
####
1971
self.__gens[proof] = [self.point(x, check=True) for x in G]
1972
self.__gens[proof].sort()
1973
self.__rank[proof] = len(self.__gens[proof])
1974
return self.__gens[proof]
1975
1976
def gens_certain(self):
1977
"""
1978
Return True if the generators have been proven correct.
1979
1980
EXAMPLES::
1981
1982
sage: E=EllipticCurve('37a1')
1983
sage: E.gens() # random (up to sign)
1984
[(0 : -1 : 1)]
1985
sage: E.gens_certain()
1986
True
1987
"""
1988
return self.__gens.has_key(True)
1989
1990
def ngens(self, proof = None):
1991
"""
1992
Return the number of generators of this elliptic curve.
1993
1994
.. note::
1995
1996
See :meth:'.gens' for further documentation. The function
1997
:meth:`.ngens` calls :meth:`.gens` if not already done, but
1998
only with default parameters. Better results may be
1999
obtained by calling ``mwrank()`` with carefully chosen
2000
parameters.
2001
2002
EXAMPLES::
2003
2004
sage: E=EllipticCurve('37a1')
2005
sage: E.ngens()
2006
1
2007
2008
TO DO: This example should not cause a run-time error.
2009
2010
::
2011
2012
sage: E=EllipticCurve([0,0,0,877,0])
2013
sage: # E.ngens() ######## causes run-time error
2014
2015
::
2016
2017
sage: print E.mwrank('-v0 -b12 -l')
2018
Curve [0,0,0,877,0] : Rank = 1
2019
Generator 1 is [29604565304828237474403861024284371796799791624792913256602210:-256256267988926809388776834045513089648669153204356603464786949:490078023219787588959802933995928925096061616470779979261000]; height 95.980371987964
2020
Regulator = 95.980...
2021
"""
2022
return len(self.gens(proof = proof))
2023
2024
def regulator(self, use_database=True, proof=None, precision=None,
2025
descent_second_limit=12, verbose=False):
2026
"""
2027
Returns the regulator of this curve, which must be defined over Q.
2028
2029
INPUT:
2030
2031
2032
- ``use_database`` - bool (default: False), if True,
2033
try to look up the generators in the Cremona database.
2034
2035
- ``proof`` - bool or None (default: None, see
2036
proof.[tab] or sage.structure.proof). Note that results from
2037
databases are considered proof = True
2038
2039
- ``precision`` - int or None (default: None): the
2040
precision in bits of the result (default real precision if None)
2041
2042
- ``descent_second_limit`` - (default: 12)- used in 2-descent
2043
2044
- ``verbose`` - whether to print mwrank's verbose output
2045
2046
EXAMPLES::
2047
2048
sage: E = EllipticCurve([0, 0, 1, -1, 0])
2049
sage: E.regulator()
2050
0.0511114082399688
2051
sage: EllipticCurve('11a').regulator()
2052
1.00000000000000
2053
sage: EllipticCurve('37a').regulator()
2054
0.0511114082399688
2055
sage: EllipticCurve('389a').regulator()
2056
0.152460177943144
2057
sage: EllipticCurve('5077a').regulator()
2058
0.41714355875838...
2059
sage: EllipticCurve([1, -1, 0, -79, 289]).regulator()
2060
1.50434488827528
2061
sage: EllipticCurve([0, 0, 1, -79, 342]).regulator(proof=False) # long time (6s on sage.math, 2011)
2062
14.790527570131...
2063
"""
2064
if precision is None:
2065
RR = rings.RealField()
2066
precision = RR.precision()
2067
else:
2068
RR = rings.RealField(precision)
2069
2070
if proof is None:
2071
from sage.structure.proof.proof import get_flag
2072
proof = get_flag(proof, "elliptic_curve")
2073
else:
2074
proof = bool(proof)
2075
2076
# We return a cached value if it exists and has sufficient precision:
2077
try:
2078
reg = self.__regulator[proof]
2079
if reg.parent().precision() >= precision:
2080
return RR(reg)
2081
else: # Found regulator value but precision is too low
2082
pass
2083
except KeyError:
2084
if proof is False and self.__regulator.has_key(True):
2085
reg = self.__regulator[True]
2086
if reg.parent().precision() >= precision:
2087
return RR(reg)
2088
else: # Found regulator value but precision is too low
2089
pass
2090
2091
# Next we find the gens, taking them from the database if they
2092
# are there and use_database is True, else computing them:
2093
2094
G = self.gens(proof=proof, use_database=use_database, descent_second_limit=descent_second_limit, verbose=verbose)
2095
2096
# Finally compute the regulator of the generators found:
2097
2098
self.__regulator[proof] = self.regulator_of_points(G,precision=precision)
2099
return self.__regulator[proof]
2100
2101
def saturation(self, points, verbose=False, max_prime=0, odd_primes_only=False):
2102
"""
2103
Given a list of rational points on E, compute the saturation in
2104
E(Q) of the subgroup they generate.
2105
2106
INPUT:
2107
2108
2109
- ``points (list)`` - list of points on E
2110
2111
- ``verbose (bool)`` - (default: False), if True, give
2112
verbose output
2113
2114
- ``max_prime (int)`` - (default: 0), saturation is
2115
performed for all primes up to max_prime. If max_prime==0,
2116
perform saturation at *all* primes, i.e., compute the true
2117
saturation.
2118
2119
- ``odd_primes_only (bool)`` - only do saturation at
2120
odd primes
2121
2122
2123
OUTPUT:
2124
2125
2126
- ``saturation (list)`` - points that form a basis for
2127
the saturation
2128
2129
- ``index (int)`` - the index of the group generated
2130
by points in their saturation
2131
2132
- ``regulator (real with default precision)`` -
2133
regulator of saturated points.
2134
2135
2136
ALGORITHM: Uses Cremona's ``mwrank`` package. With ``max_prime=0``,
2137
we call ``mwrank`` with successively larger prime bounds until the full
2138
saturation is provably found. The results of saturation at the
2139
previous primes is stored in each case, so this should be
2140
reasonably fast.
2141
2142
EXAMPLES::
2143
2144
sage: E=EllipticCurve('37a1')
2145
sage: P=E(0,0)
2146
sage: Q=5*P; Q
2147
(1/4 : -5/8 : 1)
2148
sage: E.saturation([Q])
2149
([(0 : 0 : 1)], 5, 0.0511114082399688)
2150
2151
TESTS:
2152
2153
See :trac:`10590`. This example would loop forever at default precision::
2154
2155
sage: E = EllipticCurve([1, 0, 1, -977842, -372252745])
2156
sage: P = E([-192128125858676194585718821667542660822323528626273/336995568430319276695106602174283479617040716649, 70208213492933395764907328787228427430477177498927549075405076353624188436/195630373799784831667835900062564586429333568841391304129067339731164107, 1])
2157
sage: P.height()
2158
113.302910926080
2159
sage: E.saturation([P])
2160
([(-192128125858676194585718821667542660822323528626273/336995568430319276695106602174283479617040716649 : 70208213492933395764907328787228427430477177498927549075405076353624188436/195630373799784831667835900062564586429333568841391304129067339731164107 : 1)], 1, 113.302910926080)
2161
sage: (Q,), ind, reg = E.saturation([2*P]) # needs higher precision, handled by eclib
2162
sage: 2*Q == 2*P
2163
True
2164
sage: ind
2165
2
2166
sage: reg
2167
113.302910926080
2168
2169
See :trac:`10840`. This used to cause eclib to crash since the
2170
curve is non-minimal at 2::
2171
2172
sage: E = EllipticCurve([0,0,0,-13711473216,0])
2173
sage: P = E([-19992,16313472])
2174
sage: Q = E([-24108,-17791704])
2175
sage: R = E([-97104,-20391840])
2176
sage: S = E([-113288,-9969344])
2177
sage: E.saturation([P,Q,R,S])
2178
([(-19992 : 16313472 : 1), (-24108 : -17791704 : 1), (-97104 : -20391840 : 1), (-113288 : -9969344 : 1)], 1, 172.792031341679)
2179
2180
"""
2181
if not isinstance(points, list):
2182
raise TypeError, "points (=%s) must be a list."%points
2183
if len(points) == 0:
2184
return [], None, R(1)
2185
2186
v = []
2187
for P in points:
2188
if not isinstance(P, ell_point.EllipticCurvePoint_field):
2189
P = self(P)
2190
elif P.curve() != self:
2191
raise ArithmeticError, "point (=%s) must be %s."%(P,self)
2192
2193
minimal = True
2194
if not self.is_minimal():
2195
minimal = False
2196
Emin = self.minimal_model()
2197
phi = self.isomorphism_to(Emin)
2198
points = [phi(P) for P in points]
2199
else:
2200
Emin = self
2201
2202
for P in points:
2203
x, y = P.xy()
2204
d = x.denominator().lcm(y.denominator())
2205
v.append((x*d, y*d, d))
2206
2207
c = Emin.mwrank_curve()
2208
mw = mwrank.mwrank_MordellWeil(c, verbose)
2209
mw.process(v)
2210
repeat_until_saturated = False
2211
if max_prime == 0:
2212
repeat_until_saturated = True
2213
max_prime = 9973
2214
from sage.libs.all import mwrank_get_precision, mwrank_set_precision
2215
prec0 = mwrank_get_precision()
2216
prec = 100
2217
if prec0<prec:
2218
mwrank_set_precision(prec)
2219
else:
2220
prec = prec0
2221
while True:
2222
ok, index, unsat = mw.saturate(max_prime=max_prime, odd_primes_only = odd_primes_only)
2223
reg = mw.regulator()
2224
if ok or not repeat_until_saturated: break
2225
max_prime = arith.next_prime(max_prime + 1000)
2226
prec += 50
2227
#print "Increasing precision to ",prec," and max_prime to ",max_prime
2228
mwrank_set_precision(prec)
2229
if prec!=prec0: mwrank_set_precision(prec0)
2230
#print "precision was originally ",prec0," and is now ",mwrank_get_precision()
2231
sat = mw.points()
2232
sat = [Emin(P) for P in sat]
2233
if not minimal:
2234
phi_inv = ~phi
2235
sat = [phi_inv(P) for P in sat]
2236
reg = self.regulator_of_points(sat)
2237
return sat, index, R(reg)
2238
2239
2240
def CPS_height_bound(self):
2241
r"""
2242
Return the Cremona-Prickett-Siksek height bound. This is a
2243
floating point number B such that if P is a rational point on
2244
the curve, then `h(P) \le \hat{h}(P) + B`, where `h(P)` is
2245
the naive logarithmic height of `P` and `\hat{h}(P)` is the
2246
canonical height.
2247
2248
SEE ALSO: silverman_height_bound for a bound that also works for
2249
points over number fields.
2250
2251
EXAMPLES::
2252
2253
sage: E = EllipticCurve("11a")
2254
sage: E.CPS_height_bound()
2255
2.8774743273580445
2256
sage: E = EllipticCurve("5077a")
2257
sage: E.CPS_height_bound()
2258
0.0
2259
sage: E = EllipticCurve([1,2,3,4,1])
2260
sage: E.CPS_height_bound()
2261
Traceback (most recent call last):
2262
...
2263
RuntimeError: curve must be minimal.
2264
sage: F = E.quadratic_twist(-19)
2265
sage: F
2266
Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 + 1376*x - 130 over Rational Field
2267
sage: F.CPS_height_bound()
2268
0.6555158376972852
2269
2270
IMPLEMENTATION:
2271
Call the corresponding mwrank C++ library function. Note that
2272
the formula in the [CPS] paper is given for number fields. It's
2273
only the implementation in Sage that restricts to the rational
2274
field.
2275
"""
2276
if not self.is_minimal():
2277
raise RuntimeError, "curve must be minimal."
2278
return self.mwrank_curve().CPS_height_bound()
2279
2280
2281
def silverman_height_bound(self, algorithm='default'):
2282
r"""
2283
Return the Silverman height bound. This is a positive real
2284
(floating point) number B such that for all points `P` on the
2285
curve over any number field, `|h(P) - \hat{h}(P)| \leq B`,
2286
where `h(P)` is the naive logarithmic height of `P` and
2287
`\hat{h}(P)` is the canonical height.
2288
2289
INPUT:
2290
2291
- ``algorithm`` --
2292
2293
- 'default' (default) -- compute using a Python
2294
implementation in Sage
2295
2296
- 'mwrank' -- use a C++ implementation in the mwrank
2297
library
2298
2299
NOTES:
2300
2301
- The CPS_height_bound is often better (i.e. smaller) than
2302
the Silverman bound, but it only applies for points over
2303
the base field, whereas the Silverman bound works over
2304
all number fields.
2305
2306
- The Silverman bound is also fairly straightforward to
2307
compute over number fields, but isn't implemented here.
2308
2309
- Silverman's paper is 'The Difference Between the Weil
2310
Height and the Canonical Height on Elliptic Curves',
2311
Math. Comp., Volume 55, Number 192, pages 723-743. We
2312
use a correction by Bremner with 0.973 replaced by 0.961,
2313
as explained in the source code to mwrank (htconst.cc).
2314
2315
EXAMPLES::
2316
2317
sage: E=EllipticCurve('37a1')
2318
sage: E.silverman_height_bound()
2319
4.825400758180918
2320
sage: E.silverman_height_bound(algorithm='mwrank')
2321
4.825400758180918
2322
sage: E.CPS_height_bound()
2323
0.16397076103046915
2324
"""
2325
if algorithm == 'default':
2326
Delta = self.discriminant()
2327
j = self.j_invariant()
2328
b2 = self.b2()
2329
twostar = 2 if b2 else 1
2330
from math import log
2331
def h(x):
2332
return log(max(abs(x.numerator()), abs(x.denominator())))
2333
def h_oo(x):
2334
return log(max(abs(x),1))
2335
mu = h(Delta)/12 + h_oo(j)/12 + h_oo(b2/12)/2 + log(twostar)/2
2336
lower = 2*(-h(j)/24 - mu - 0.961)
2337
upper = 2*(mu + 1.07)
2338
return max(abs(lower), abs(upper))
2339
elif algorithm == 'mwrank':
2340
return self.mwrank_curve().silverman_bound()
2341
else:
2342
raise ValueError, "unknown algorithm '%s'"%algorithm
2343
2344
2345
2346
def point_search(self, height_limit, verbose=False, rank_bound=None):
2347
"""
2348
Search for points on a curve up to an input bound on the naive
2349
logarithmic height.
2350
2351
INPUT:
2352
2353
2354
- ``height_limit (float)`` - bound on naive height
2355
2356
- ``verbose (bool)`` - (default: False)
2357
2358
If True, report on each point as found together with linear
2359
relations between the points found and the saturation process.
2360
2361
If False, just return the result.
2362
2363
- ``rank_bound (bool)`` - (default: None)
2364
2365
If provided, stop searching for points once we find this many
2366
independent nontorsion points.
2367
2368
OUTPUT: points (list) - list of independent points which generate
2369
the subgroup of the Mordell-Weil group generated by the points
2370
found and then saturated.
2371
2372
.. warning::
2373
2374
height_limit is logarithmic, so increasing by 1 will cause
2375
the running time to increase by a factor of approximately
2376
4.5 (=exp(1.5)).
2377
2378
IMPLEMENTATION: Uses Michael Stoll's ratpoints library.
2379
2380
EXAMPLES::
2381
2382
sage: E=EllipticCurve('389a1')
2383
sage: E.point_search(5, verbose=False)
2384
[(-1 : 1 : 1), (-3/4 : 7/8 : 1)]
2385
2386
Increasing the height_limit takes longer, but finds no more
2387
points::
2388
2389
sage: E.point_search(10, verbose=False)
2390
[(-1 : 1 : 1), (-3/4 : 7/8 : 1)]
2391
2392
In fact this curve has rank 2 so no more than 2 points will ever be
2393
output, but we are not using this fact.
2394
2395
::
2396
2397
sage: E.saturation(_)
2398
([(-1 : 1 : 1), (-3/4 : 7/8 : 1)], 1, 0.152460177943144)
2399
2400
What this shows is that if the rank is 2 then the points listed do
2401
generate the Mordell-Weil group (mod torsion). Finally,
2402
2403
::
2404
2405
sage: E.rank()
2406
2
2407
2408
If we only need one independent generator::
2409
2410
sage: E.point_search(5, verbose=False, rank_bound=1)
2411
[(-2 : 0 : 1)]
2412
2413
"""
2414
from sage.libs.ratpoints import ratpoints
2415
from sage.functions.all import exp
2416
from sage.rings.arith import GCD
2417
H = exp(float(height_limit)) # max(|p|,|q|) <= H, if x = p/q coprime
2418
coeffs = [16*self.b6(), 8*self.b4(), self.b2(), 1]
2419
points = []
2420
a1 = self.a1()
2421
a3 = self.a3()
2422
new_H = H*2 # since we change the x-coord by 2 below
2423
for X,Y,Z in ratpoints(coeffs, new_H, verbose):
2424
if Z == 0: continue
2425
z = 2*Z
2426
x = X/2
2427
y = (Y/z - a1*x - a3*z)/2
2428
d = GCD((x,y,z))
2429
x = x/d
2430
if max(x.numerator().abs(), x.denominator().abs()) <= H:
2431
y = y/d
2432
z = z/d
2433
points.append(self((x,y,z)))
2434
if rank_bound is not None:
2435
points = self.saturation(points, verbose=verbose)[0]
2436
if len(points) == rank_bound:
2437
break
2438
if rank_bound is None:
2439
points = self.saturation(points, verbose=verbose)[0]
2440
return points
2441
2442
2443
def selmer_rank(self):
2444
"""
2445
The rank of the 2-Selmer group of the curve.
2446
2447
EXAMPLE: The following is the curve 960D1, which has rank 0, but
2448
Sha of order 4.
2449
2450
::
2451
2452
sage: E = EllipticCurve([0, -1, 0, -900, -10098])
2453
sage: E.selmer_rank()
2454
3
2455
2456
Here the Selmer rank is equal to the 2-torsion rank (=1) plus
2457
the 2-rank of Sha (=2), and the rank itself is zero::
2458
2459
sage: E.rank()
2460
0
2461
2462
In contrast, for the curve 571A, also with rank 0 and Sha of
2463
order 4, we get a worse bound::
2464
2465
sage: E = EllipticCurve([0, -1, 1, -929, -10595])
2466
sage: E.selmer_rank()
2467
2
2468
sage: E.rank_bound()
2469
2
2470
2471
To establish that the rank is in fact 0 in this case, we would
2472
need to carry out a higher descent::
2473
2474
sage: E.three_selmer_rank() # optional: magma
2475
0
2476
2477
Or use the L-function to compute the analytic rank::
2478
2479
sage: E.rank(only_use_mwrank=False)
2480
0
2481
2482
"""
2483
try:
2484
return self.__selmer_rank
2485
except AttributeError:
2486
C = self.mwrank_curve()
2487
self.__selmer_rank = C.selmer_rank()
2488
return self.__selmer_rank
2489
2490
2491
def rank_bound(self):
2492
"""
2493
Upper bound on the rank of the curve, computed using
2494
2-descent. In many cases, this is the actual rank of the
2495
curve. If the curve has no 2-torsion it is the same as the
2496
2-selmer rank.
2497
2498
EXAMPLE: The following is the curve 960D1, which has rank 0, but
2499
Sha of order 4.
2500
2501
::
2502
2503
sage: E = EllipticCurve([0, -1, 0, -900, -10098])
2504
sage: E.rank_bound()
2505
0
2506
2507
It gives 0 instead of 2, because it knows Sha is nontrivial. In
2508
contrast, for the curve 571A, also with rank 0 and Sha of order 4,
2509
we get a worse bound::
2510
2511
sage: E = EllipticCurve([0, -1, 1, -929, -10595])
2512
sage: E.rank_bound()
2513
2
2514
sage: E.rank(only_use_mwrank=False) # uses L-function
2515
0
2516
2517
"""
2518
try:
2519
return self.__rank_bound
2520
except AttributeError:
2521
C = self.mwrank_curve()
2522
self.__rank_bound = C.rank_bound()
2523
return self.__rank_bound
2524
2525
2526
def an(self, n):
2527
"""
2528
The n-th Fourier coefficient of the modular form corresponding to
2529
this elliptic curve, where n is a positive integer.
2530
2531
EXAMPLES::
2532
2533
sage: E=EllipticCurve('37a1')
2534
sage: [E.an(n) for n in range(20) if n>0]
2535
[1, -2, -3, 2, -2, 6, -1, 0, 6, 4, -5, -6, -2, 2, 6, -4, 0, -12, 0]
2536
"""
2537
return Integer(self.pari_mincurve().ellak(n))
2538
2539
def ap(self, p):
2540
"""
2541
The p-th Fourier coefficient of the modular form corresponding to
2542
this elliptic curve, where p is prime.
2543
2544
EXAMPLES::
2545
2546
sage: E=EllipticCurve('37a1')
2547
sage: [E.ap(p) for p in prime_range(50)]
2548
[-2, -3, -2, -1, -5, -2, 0, 0, 2, 6, -4, -1, -9, 2, -9]
2549
"""
2550
if not arith.is_prime(p):
2551
raise ArithmeticError, "p must be prime"
2552
return Integer(self.pari_mincurve().ellap(p))
2553
2554
def quadratic_twist(self, D):
2555
"""
2556
Return the quadratic twist of this elliptic curve by D.
2557
2558
D must be a nonzero rational number.
2559
2560
.. note::
2561
2562
This function overrides the generic ``quadratic_twist()``
2563
function for elliptic curves, returning a minimal model.
2564
2565
EXAMPLES::
2566
2567
sage: E=EllipticCurve('37a1')
2568
sage: E2=E.quadratic_twist(2); E2
2569
Elliptic Curve defined by y^2 = x^3 - 4*x + 2 over Rational Field
2570
sage: E2.conductor()
2571
2368
2572
sage: E2.quadratic_twist(2) == E
2573
True
2574
"""
2575
return EllipticCurve_number_field.quadratic_twist(self, D).minimal_model()
2576
2577
def minimal_model(self):
2578
r"""
2579
Return the unique minimal Weierstrass equation for this elliptic
2580
curve. This is the model with minimal discriminant and
2581
`a_1,a_2,a_3 \in \{0,\pm 1\}`.
2582
2583
EXAMPLES::
2584
2585
sage: E=EllipticCurve([10,100,1000,10000,1000000])
2586
sage: E.minimal_model()
2587
Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Rational Field
2588
"""
2589
try:
2590
return self.__minimal_model
2591
except AttributeError:
2592
F = self.pari_mincurve()
2593
self.__minimal_model = EllipticCurve_rational_field([Q(F[i]) for i in range(5)])
2594
return self.__minimal_model
2595
2596
def is_minimal(self):
2597
r"""
2598
Return True iff this elliptic curve is a reduced minimal model.
2599
2600
The unique minimal Weierstrass equation for this elliptic curve.
2601
This is the model with minimal discriminant and
2602
`a_1,a_2,a_3 \in \{0,\pm 1\}`.
2603
2604
TO DO: This is not very efficient since it just computes the
2605
minimal model and compares. A better implementation using the Kraus
2606
conditions would be preferable.
2607
2608
EXAMPLES::
2609
2610
sage: E=EllipticCurve([10,100,1000,10000,1000000])
2611
sage: E.is_minimal()
2612
False
2613
sage: E=E.minimal_model()
2614
sage: E.is_minimal()
2615
True
2616
"""
2617
return self.ainvs() == self.minimal_model().ainvs()
2618
2619
def is_p_minimal(self, p):
2620
"""
2621
Tests if curve is p-minimal at a given prime p.
2622
2623
INPUT: p - a primeOUTPUT: True - if curve is p-minimal
2624
2625
2626
- ``False`` - if curve isn't p-minimal
2627
2628
2629
EXAMPLES::
2630
2631
sage: E = EllipticCurve('441a2')
2632
sage: E.is_p_minimal(7)
2633
True
2634
2635
::
2636
2637
sage: E = EllipticCurve([0,0,0,0,(2*5*11)**10])
2638
sage: [E.is_p_minimal(p) for p in prime_range(2,24)]
2639
[False, True, False, True, False, True, True, True, True]
2640
"""
2641
if not p.is_prime():
2642
raise ValueError,"p must be prime"
2643
if not self.is_p_integral(p):
2644
return False
2645
if p > 3:
2646
return ((self.discriminant().valuation(p) < 12) or (self.c4().valuation(p) < 4))
2647
# else p = 2,3
2648
Emin = self.minimal_model()
2649
return self.discriminant().valuation(p) == Emin.discriminant().valuation(p)
2650
2651
# Duplicate!
2652
#
2653
# def is_integral(self):
2654
# for n in self.ainvs():
2655
# if n.denominator() != 1:
2656
# return False
2657
# return True
2658
2659
def kodaira_type(self, p):
2660
"""
2661
Local Kodaira type of the elliptic curve at `p`.
2662
2663
INPUT:
2664
2665
- p, an integral prime
2666
2667
2668
OUTPUT:
2669
2670
2671
- the Kodaira type of this elliptic curve at p,
2672
as a KodairaSymbol.
2673
2674
2675
EXAMPLES::
2676
2677
sage: E = EllipticCurve('124a')
2678
sage: E.kodaira_type(2)
2679
IV
2680
"""
2681
return self.local_data(p).kodaira_symbol()
2682
2683
kodaira_symbol = kodaira_type
2684
2685
def kodaira_type_old(self, p):
2686
"""
2687
Local Kodaira type of the elliptic curve at `p`.
2688
2689
INPUT:
2690
2691
2692
- p, an integral prime
2693
2694
2695
OUTPUT:
2696
2697
- the kodaira type of this elliptic curve at p,
2698
as a KodairaSymbol.
2699
2700
EXAMPLES::
2701
2702
sage: E = EllipticCurve('124a')
2703
sage: E.kodaira_type_old(2)
2704
IV
2705
"""
2706
if not arith.is_prime(p):
2707
raise ArithmeticError, "p must be prime"
2708
try:
2709
self.__kodaira_type
2710
except AttributeError:
2711
self.__kodaira_type = {}
2712
self.__tamagawa_number = {}
2713
if not self.__kodaira_type.has_key(p):
2714
v = self.pari_mincurve().elllocalred(p)
2715
from kodaira_symbol import KodairaSymbol
2716
self.__kodaira_type[p] = KodairaSymbol(v[1])
2717
self.__tamagawa_number[p] = Integer(v[3])
2718
return self.__kodaira_type[p]
2719
2720
def tamagawa_number(self, p):
2721
r"""
2722
The Tamagawa number of the elliptic curve at `p`.
2723
2724
This is the order of the component group
2725
`E(\QQ_p)/E^0(\QQ_p)`.
2726
2727
EXAMPLES::
2728
2729
sage: E = EllipticCurve('11a')
2730
sage: E.tamagawa_number(11)
2731
5
2732
sage: E = EllipticCurve('37b')
2733
sage: E.tamagawa_number(37)
2734
3
2735
"""
2736
return self.local_data(p).tamagawa_number()
2737
2738
def tamagawa_number_old(self, p):
2739
r"""
2740
The Tamagawa number of the elliptic curve at `p`.
2741
2742
This is the order of the component group
2743
`E(\QQ_p)/E^0(\QQ_p)`.
2744
2745
EXAMPLES::
2746
2747
sage: E = EllipticCurve('11a')
2748
sage: E.tamagawa_number_old(11)
2749
5
2750
sage: E = EllipticCurve('37b')
2751
sage: E.tamagawa_number_old(37)
2752
3
2753
"""
2754
if not arith.is_prime(p):
2755
raise ArithmeticError, "p must be prime"
2756
try:
2757
return self.__tamagawa_number[p]
2758
except (AttributeError, KeyError):
2759
self.kodaira_type_old(p)
2760
return self.__tamagawa_number[p]
2761
2762
def tamagawa_exponent(self, p):
2763
"""
2764
The Tamagawa index of the elliptic curve at `p`.
2765
2766
This is the index of the component group
2767
`E(\QQ_p)/E^0(\QQ_p)`. It equals the
2768
Tamagawa number (as the component group is cyclic) except for types
2769
`I_m^*` (`m` even) when the group can be
2770
`C_2 \times C_2`.
2771
2772
EXAMPLES::
2773
2774
sage: E = EllipticCurve('816a1')
2775
sage: E.tamagawa_number(2)
2776
4
2777
sage: E.tamagawa_exponent(2)
2778
2
2779
sage: E.kodaira_symbol(2)
2780
I2*
2781
2782
::
2783
2784
sage: E = EllipticCurve('200c4')
2785
sage: E.kodaira_symbol(5)
2786
I4*
2787
sage: E.tamagawa_number(5)
2788
4
2789
sage: E.tamagawa_exponent(5)
2790
2
2791
2792
See #4715::
2793
2794
sage: E=EllipticCurve('117a3')
2795
sage: E.tamagawa_exponent(13)
2796
4
2797
"""
2798
if not arith.is_prime(p):
2799
raise ArithmeticError, "p must be prime"
2800
cp = self.tamagawa_number(p)
2801
if not cp==4:
2802
return cp
2803
ks = self.kodaira_type(p)
2804
if ks._roman==1 and ks._n%2==0 and ks._starred:
2805
return 2
2806
return 4
2807
2808
def tamagawa_product(self):
2809
"""
2810
Returns the product of the Tamagawa numbers.
2811
2812
EXAMPLES::
2813
2814
sage: E = EllipticCurve('54a')
2815
sage: E.tamagawa_product ()
2816
3
2817
"""
2818
try:
2819
return self.__tamagawa_product
2820
except AttributeError:
2821
self.__tamagawa_product = Integer(self.pari_mincurve().ellglobalred()[2].python())
2822
return self.__tamagawa_product
2823
2824
def real_components(self):
2825
"""
2826
Returns 1 if there is 1 real component and 2 if there are 2.
2827
2828
EXAMPLES::
2829
2830
sage: E = EllipticCurve('37a')
2831
sage: E.real_components ()
2832
2
2833
sage: E = EllipticCurve('37b')
2834
sage: E.real_components ()
2835
2
2836
sage: E = EllipticCurve('11a')
2837
sage: E.real_components ()
2838
1
2839
"""
2840
invs = self.short_weierstrass_model().ainvs()
2841
x = rings.polygen(self.base_ring())
2842
f = x**3 + invs[3]*x + invs[4]
2843
if f.discriminant() > 0:
2844
return 2
2845
else:
2846
return 1
2847
2848
def has_good_reduction_outside_S(self,S=[]):
2849
r"""
2850
Tests if this elliptic curve has good reduction outside `S`.
2851
2852
INPUT:
2853
2854
- S - list of primes (default: empty list).
2855
2856
.. note::
2857
2858
Primality of elements of S is not checked, and the output
2859
is undefined if S is not a list or contains non-primes.
2860
2861
This only tests the given model, so should only be applied to
2862
minimal models.
2863
2864
EXAMPLES::
2865
2866
sage: EllipticCurve('11a1').has_good_reduction_outside_S([11])
2867
True
2868
sage: EllipticCurve('11a1').has_good_reduction_outside_S([2])
2869
False
2870
sage: EllipticCurve('2310a1').has_good_reduction_outside_S([2,3,5,7])
2871
False
2872
sage: EllipticCurve('2310a1').has_good_reduction_outside_S([2,3,5,7,11])
2873
True
2874
"""
2875
return self.discriminant().is_S_unit(S)
2876
2877
def period_lattice(self, embedding=None):
2878
r"""
2879
Returns the period lattice of the elliptic curve with respect to
2880
the differential `dx/(2y + a_1x + a_3)`.
2881
2882
INPUT:
2883
2884
- ``embedding`` - ignored (for compatibility with the
2885
period_lattice function for elliptic_curve_number_field)
2886
2887
OUTPUT:
2888
2889
(period lattice) The PeriodLattice_ell object associated to
2890
this elliptic curve (with respect to the natural embedding of
2891
`\QQ` into `\RR`).
2892
2893
EXAMPLES::
2894
2895
sage: E = EllipticCurve('37a')
2896
sage: E.period_lattice()
2897
Period lattice associated to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
2898
"""
2899
try:
2900
return self._period_lattice
2901
except AttributeError:
2902
from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell
2903
self._period_lattice = PeriodLattice_ell(self)
2904
return self._period_lattice
2905
2906
def elliptic_exponential(self, z, embedding=None):
2907
r"""
2908
Computes the elliptic exponential of a complex number with respect to the elliptic curve.
2909
2910
INPUT:
2911
2912
- ``z`` (complex) -- a complex number
2913
2914
- ``embedding`` - ignored (for compatibility with the
2915
period_lattice function for elliptic_curve_number_field)
2916
2917
OUTPUT:
2918
2919
The image of `z` modulo `L` under the Weierstrass parametrization
2920
`\CC/L \to E(\CC)`.
2921
2922
.. note::
2923
2924
The precision is that of the input ``z``, or the default
2925
precision of 53 bits if ``z`` is exact.
2926
2927
EXAMPLES::
2928
2929
sage: E = EllipticCurve([1,1,1,-8,6])
2930
sage: P = E([1,-2])
2931
sage: z = P.elliptic_logarithm() # default precision is 100 here
2932
sage: E.elliptic_exponential(z)
2933
(1.0000000000000000000000000000 : -2.0000000000000000000000000000 : 1.0000000000000000000000000000)
2934
sage: z = E([1,-2]).elliptic_logarithm(precision=201)
2935
sage: E.elliptic_exponential(z)
2936
(1.00000000000000000000000000000000000000000000000000000000000 : -2.00000000000000000000000000000000000000000000000000000000000 : 1.00000000000000000000000000000000000000000000000000000000000)
2937
2938
::
2939
2940
sage: E = EllipticCurve('389a')
2941
sage: Q = E([3,5])
2942
sage: E.elliptic_exponential(Q.elliptic_logarithm())
2943
(3.0000000000000000000000000000 : 5.0000000000000000000000000000 : 1.0000000000000000000000000000)
2944
sage: P = E([-1,1])
2945
sage: P.elliptic_logarithm()
2946
0.47934825019021931612953301006 + 0.98586885077582410221120384908*I
2947
sage: E.elliptic_exponential(P.elliptic_logarithm())
2948
(-1.0000000000000000000000000000 : 1.0000000000000000000000000000 : 1.0000000000000000000000000000)
2949
2950
2951
Some torsion examples::
2952
2953
sage: w1,w2 = E.period_lattice().basis()
2954
sage: E.two_division_polynomial().roots(CC,multiplicities=False)
2955
[-2.0403022002854..., 0.13540924022175..., 0.90489296006371...]
2956
sage: [E.elliptic_exponential((a*w1+b*w2)/2)[0] for a,b in [(0,1),(1,1),(1,0)]]
2957
[-2.0403022002854..., 0.13540924022175..., 0.90489296006371...]
2958
2959
sage: E.division_polynomial(3).roots(CC,multiplicities=False)
2960
[-2.88288879135...,
2961
1.39292799513...,
2962
0.078313731444316... - 0.492840991709...*I,
2963
0.078313731444316... + 0.492840991709...*I]
2964
sage: [E.elliptic_exponential((a*w1+b*w2)/3)[0] for a,b in [(0,1),(1,0),(1,1),(2,1)]]
2965
[-2.8828887913533..., 1.39292799513138,
2966
0.0783137314443... - 0.492840991709...*I,
2967
0.0783137314443... + 0.492840991709...*I]
2968
2969
Observe that this is a group homomorphism (modulo rounding error)::
2970
2971
sage: z = CC.random_element()
2972
sage: 2 * E.elliptic_exponential(z)
2973
(-1.52184235874404 - 0.0581413944316544*I : 0.948655866506124 - 0.0381469928565030*I : 1.00000000000000)
2974
sage: E.elliptic_exponential(2 * z)
2975
(-1.52184235874404 - 0.0581413944316562*I : 0.948655866506128 - 0.0381469928565034*I : 1.00000000000000)
2976
"""
2977
return self.period_lattice().elliptic_exponential(z)
2978
2979
def lseries(self):
2980
"""
2981
Returns the L-series of this elliptic curve.
2982
2983
Further documentation is available for the functions which apply to
2984
the L-series.
2985
2986
EXAMPLES::
2987
2988
sage: E=EllipticCurve('37a1')
2989
sage: E.lseries()
2990
Complex L-series of the Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
2991
"""
2992
try:
2993
return self.__lseries
2994
except AttributeError:
2995
from lseries_ell import Lseries_ell
2996
self.__lseries = Lseries_ell(self)
2997
return self.__lseries
2998
2999
def Lambda(self, s, prec):
3000
r"""
3001
Returns the value of the Lambda-series of the elliptic curve E at
3002
s, where s can be any complex number.
3003
3004
IMPLEMENTATION: Fairly *slow* computation using the definitions
3005
and implemented in Python.
3006
3007
Uses prec terms of the power series.
3008
3009
EXAMPLES::
3010
3011
sage: E = EllipticCurve('389a')
3012
sage: E.Lambda(1.4+0.5*I, 50)
3013
-0.354172680517... + 0.874518681720...*I
3014
"""
3015
from sage.all import pi
3016
3017
s = C(s)
3018
N = self.conductor()
3019
pi = R(pi)
3020
a = self.anlist(prec)
3021
eps = self.root_number()
3022
sqrtN = float(N.sqrt())
3023
def _F(n, t):
3024
return gamma_inc(t+1, 2*pi*n/sqrtN) * C(sqrtN/(2*pi*n))**(t+1)
3025
return sum([a[n]*(_F(n,s-1) + eps*_F(n,1-s)) for n in xrange(1,prec+1)])
3026
3027
def is_local_integral_model(self,*p):
3028
r"""
3029
Tests if self is integral at the prime `p`, or at all the
3030
primes if `p` is a list or tuple of primes
3031
3032
EXAMPLES::
3033
3034
sage: E=EllipticCurve([1/2,1/5,1/5,1/5,1/5])
3035
sage: [E.is_local_integral_model(p) for p in (2,3,5)]
3036
[False, True, False]
3037
sage: E.is_local_integral_model(2,3,5)
3038
False
3039
sage: Eint2=E.local_integral_model(2)
3040
sage: Eint2.is_local_integral_model(2)
3041
True
3042
"""
3043
if len(p)==1: p=p[0]
3044
if isinstance(p,(tuple,list)):
3045
return misc.forall(p, lambda x : self.is_local_integral_model(x))[0]
3046
assert p.is_prime(), "p must be prime in is_local_integral_model()"
3047
return misc.forall(self.ainvs(), lambda x : x.valuation(p) >= 0)[0]
3048
3049
def local_integral_model(self,p):
3050
r"""
3051
Return a model of self which is integral at the prime `p`.
3052
3053
EXAMPLES::
3054
3055
sage: E=EllipticCurve([0, 0, 1/216, -7/1296, 1/7776])
3056
sage: E.local_integral_model(2)
3057
Elliptic Curve defined by y^2 + 1/27*y = x^3 - 7/81*x + 2/243 over Rational Field
3058
sage: E.local_integral_model(3)
3059
Elliptic Curve defined by y^2 + 1/8*y = x^3 - 7/16*x + 3/32 over Rational Field
3060
sage: E.local_integral_model(2).local_integral_model(3) == EllipticCurve('5077a1')
3061
True
3062
"""
3063
assert p.is_prime(), "p must be prime in local_integral_model()"
3064
ai = self.a_invariants()
3065
e = min([(ai[i].valuation(p)/[1,2,3,4,6][i]) for i in range(5)]).floor()
3066
return constructor.EllipticCurve([ai[i]/p**(e*[1,2,3,4,6][i]) for i in range(5)])
3067
3068
def is_global_integral_model(self):
3069
r"""
3070
Return true iff self is integral at all primes.
3071
3072
EXAMPLES::
3073
3074
sage: E=EllipticCurve([1/2,1/5,1/5,1/5,1/5])
3075
sage: E.is_global_integral_model()
3076
False
3077
sage: Emin=E.global_integral_model()
3078
sage: Emin.is_global_integral_model()
3079
True
3080
"""
3081
return self.is_integral()
3082
3083
def global_integral_model(self):
3084
r"""
3085
Return a model of self which is integral at all primes.
3086
3087
EXAMPLES::
3088
3089
sage: E = EllipticCurve([0, 0, 1/216, -7/1296, 1/7776])
3090
sage: F = E.global_integral_model(); F
3091
Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field
3092
sage: F == EllipticCurve('5077a1')
3093
True
3094
"""
3095
ai = self.a_invariants()
3096
for a in ai:
3097
if not a.is_integral():
3098
for p, _ in a.denom().factor():
3099
e = min([(ai[i].valuation(p)/[1,2,3,4,6][i]) for i in range(5)]).floor()
3100
ai = [ai[i]/p**(e*[1,2,3,4,6][i]) for i in range(5)]
3101
for z in ai:
3102
assert z.denominator() == 1, "bug in global_integral_model: %s" % ai
3103
return constructor.EllipticCurve(list(ai))
3104
3105
integral_model = global_integral_model
3106
3107
def integral_short_weierstrass_model(self):
3108
r"""
3109
Return a model of the form `y^2 = x^3 + ax + b` for this
3110
curve with `a,b\in\ZZ`.
3111
3112
EXAMPLES::
3113
3114
sage: E = EllipticCurve('17a1')
3115
sage: E.integral_short_weierstrass_model()
3116
Elliptic Curve defined by y^2 = x^3 - 11*x - 890 over Rational Field
3117
"""
3118
F = self.minimal_model().short_weierstrass_model()
3119
_,_,_,A,B = F.ainvs()
3120
for p in [2,3]:
3121
e=min(A.valuation(p)/4,B.valuation(p)/6).floor()
3122
A /= Integer(p**(4*e))
3123
B /= Integer(p**(6*e))
3124
return constructor.EllipticCurve([A,B])
3125
3126
# deprecated function replaced by integral_short_weierstrass_model, see trac 3974.
3127
def integral_weierstrass_model(self):
3128
r"""
3129
Return a model of the form `y^2 = x^3 + ax + b` for this
3130
curve with `a,b\in\ZZ`.
3131
3132
Note that this function is deprecated, and that you should use
3133
integral_short_weierstrass_model instead as this will be
3134
disappearing in the near future.
3135
3136
EXAMPLES::
3137
3138
sage: E = EllipticCurve('17a1')
3139
sage: E.integral_weierstrass_model() #random
3140
doctest:1: DeprecationWarning: integral_weierstrass_model is deprecated, use integral_short_weierstrass_model instead!
3141
Elliptic Curve defined by y^2 = x^3 - 11*x - 890 over Rational Field
3142
"""
3143
from sage.misc.superseded import deprecation
3144
deprecation(3974, "integral_weierstrass_model is deprecated, use integral_short_weierstrass_model instead!")
3145
return self.integral_short_weierstrass_model()
3146
3147
3148
def _generalized_congmod_numbers(self, M, invariant="both"):
3149
"""
3150
Internal method to compute the generalized modular degree and congruence number
3151
at level `MN`, where `N` is the conductor of `E`.
3152
Values obtained are cached.
3153
3154
This function is called by self.modular_degree() and self.congruence_number() when
3155
`M>1`. Since so much of the computation of the two values is shared, this method
3156
by default computes and caches both.
3157
3158
INPUT:
3159
3160
- ``M`` - Non-negative integer; this function is only ever called on M>1, although
3161
the algorithm works fine for the case `M==1`
3162
3163
- ``invariant`` - String; default "both". Options are:
3164
3165
- "both" - Both modular degree and congruence number at level `MN` are computed
3166
3167
- "moddeg" - Only modular degree is computed
3168
3169
- "congnum" - Only congruence number is computed
3170
3171
OUTPUT:
3172
3173
- A dictionary containing either the modular degree (a positive integer) at index "moddeg",
3174
or the congruence number (a positive integer) at index "congnum", or both.
3175
3176
As far as we know there is no other implementation for this algorithm, so as yet
3177
there is nothing to check the below examples against.
3178
3179
EXAMPLES::
3180
3181
sage: E = EllipticCurve('37a')
3182
sage: for M in range(2,8): print(M,E.modular_degree(M=M),E.congruence_number(M=M)) # long time (22s on 2009 MBP)
3183
(2, 5, 20)
3184
(3, 7, 28)
3185
(4, 50, 400)
3186
(5, 32, 128)
3187
(6, 1225, 19600)
3188
(7, 63, 252)
3189
"""
3190
# Check invariant specification before we get going
3191
if invariant not in ["moddeg", "congnum", "both"]:
3192
raise ValueError("Invalid invariant specification")
3193
3194
# Cuspidal space at level MN
3195
N = self.conductor()
3196
S = ModularSymbols(N*M,sign=1).cuspidal_subspace()
3197
3198
# Cut out the subspace by hitting it with T_p for enough p
3199
A = S
3200
d = self.dimension()*arith.sigma(M,0)
3201
p = 2
3202
while A.dimension() > d:
3203
while N*M % p == 0:
3204
p = arith.next_prime(p)
3205
Tp = A.hecke_operator(p)
3206
A = (Tp - self.ap(p)).kernel()
3207
p = arith.next_prime(p)
3208
B = A.complement().cuspidal_submodule()
3209
3210
L = {}
3211
if invariant in ["moddeg", "both"]:
3212
V = A.integral_structure()
3213
W = B.integral_structure()
3214
moddeg = (V + W).index_in(S.integral_structure())
3215
L["moddeg"] = moddeg
3216
self.__generalized_modular_degree[M] = moddeg
3217
3218
if invariant in ["congnum", "both"]:
3219
congnum = A.congruence_number(B)
3220
L["congnum"] = congnum
3221
self.__generalized_congruence_number[M] = congnum
3222
3223
return L
3224
3225
3226
def modular_degree(self, algorithm='sympow', M=1):
3227
r"""
3228
Return the modular degree at level `MN` of this elliptic curve. The case
3229
`M==1` corresponds to the classical definition of modular degree.
3230
3231
When `M>1`, the function returns the degree of the map from `X_0(MN) \to A`, where
3232
A is the abelian variety generated by embeddings of `E` into `J_0(MN)`.
3233
3234
The result is cached. Subsequent calls, even with a different
3235
algorithm, just returned the cached result. The algorithm argument is ignored
3236
when `M>1`.
3237
3238
INPUT:
3239
3240
- ``algorithm`` - string:
3241
3242
- ``'sympow'`` - (default) use Mark Watkin's (newer) C
3243
program sympow
3244
3245
- ``'magma'`` - requires that MAGMA be installed (also
3246
implemented by Mark Watkins)
3247
3248
- ``M`` - Non-negative integer; the modular degree at level `MN` is returned
3249
(see above)
3250
3251
.. note::
3252
3253
On 64-bit computers ec does not work, so Sage uses sympow
3254
even if ec is selected on a 64-bit computer.
3255
3256
The correctness of this function when called with algorithm "sympow"
3257
is subject to the following three hypothesis:
3258
3259
3260
- Manin's conjecture: the Manin constant is 1
3261
3262
- Steven's conjecture: the `X_1(N)`-optimal quotient is
3263
the curve with minimal Faltings height. (This is proved in most
3264
cases.)
3265
3266
- The modular degree fits in a machine double, so it better be
3267
less than about 50-some bits. (If you use sympow this constraint
3268
does not apply.)
3269
3270
3271
Moreover for all algorithms, computing a certain value of an
3272
`L`-function 'uses a heuristic method that discerns when
3273
the real-number approximation to the modular degree is within
3274
epsilon [=0.01 for algorithm='sympow'] of the same integer for 3
3275
consecutive trials (which occur maybe every 25000 coefficients or
3276
so). Probably it could just round at some point. For rigour, you
3277
would need to bound the tail by assuming (essentially) that all the
3278
`a_n` are as large as possible, but in practice they
3279
exhibit significant (square root) cancellation. One difficulty is
3280
that it doesn't do the sum in 1-2-3-4 order; it uses
3281
1-2-4-8--3-6-12-24-9-18- (Euler product style) instead, and so you
3282
have to guess ahead of time at what point to curtail this
3283
expansion.' (Quote from an email of Mark Watkins.)
3284
3285
.. note::
3286
3287
If the curve is loaded from the large Cremona database,
3288
then the modular degree is taken from the database.
3289
3290
EXAMPLES::
3291
3292
sage: E = EllipticCurve([0, -1, 1, -10, -20])
3293
sage: E
3294
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
3295
sage: E.modular_degree()
3296
1
3297
sage: E = EllipticCurve('5077a')
3298
sage: E.modular_degree()
3299
1984
3300
sage: factor(1984)
3301
2^6 * 31
3302
3303
::
3304
3305
sage: EllipticCurve([0, 0, 1, -7, 6]).modular_degree()
3306
1984
3307
sage: EllipticCurve([0, 0, 1, -7, 6]).modular_degree(algorithm='sympow')
3308
1984
3309
sage: EllipticCurve([0, 0, 1, -7, 6]).modular_degree(algorithm='magma') # optional - magma
3310
1984
3311
3312
We compute the modular degree of the curve with rank 4 having
3313
smallest (known) conductor::
3314
3315
sage: E = EllipticCurve([1, -1, 0, -79, 289])
3316
sage: factor(E.conductor()) # conductor is 234446
3317
2 * 117223
3318
sage: factor(E.modular_degree())
3319
2^7 * 2617
3320
3321
Higher level cases::
3322
3323
sage: E = EllipticCurve('11a')
3324
sage: for M in range(1,11): print(E.modular_degree(M=M)) # long time (20s on 2009 MBP)
3325
1
3326
1
3327
3
3328
2
3329
7
3330
45
3331
12
3332
16
3333
54
3334
245
3335
"""
3336
# Case 1: standard modular degree
3337
if M==1:
3338
try:
3339
return self.__modular_degree
3340
3341
except AttributeError:
3342
if algorithm == 'sympow':
3343
from sage.lfunctions.all import sympow
3344
m = sympow.modular_degree(self)
3345
elif algorithm == 'magma':
3346
from sage.interfaces.all import magma
3347
m = rings.Integer(magma(self).ModularDegree())
3348
else:
3349
raise ValueError, "unknown algorithm %s"%algorithm
3350
self.__modular_degree = m
3351
return m
3352
3353
# Case 2: M > 1
3354
else:
3355
try:
3356
return self.__generalized_modular_degree[M]
3357
except KeyError:
3358
# self._generalized_congmod_numbers() also populates cache
3359
return self._generalized_congmod_numbers(M)["moddeg"]
3360
3361
3362
def modular_parametrization(self):
3363
r"""
3364
Returns the modular parametrization of this elliptic curve, which is
3365
a map from `X_0(N)` to self, where `N` is the conductor of self.
3366
3367
EXAMPLES::
3368
3369
sage: E = EllipticCurve('15a')
3370
sage: phi = E.modular_parametrization(); phi
3371
Modular parameterization from the upper half plane to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field
3372
sage: z = 0.1 + 0.2j
3373
sage: phi(z)
3374
(8.20822465478531 - 13.1562816054682*I : -8.79855099049364 + 69.4006129342200*I : 1.00000000000000)
3375
3376
This map is actually a map on `X_0(N)`, so equivalent representatives
3377
in the upper half plane map to the same point::
3378
3379
sage: phi((-7*z-1)/(15*z+2))
3380
(8.20822465478524 - 13.1562816054681*I : -8.79855099049... + 69.4006129342...*I : 1.00000000000000)
3381
3382
We can also get a series expansion of this modular parameterization::
3383
3384
sage: E=EllipticCurve('389a1')
3385
sage: X,Y=E.modular_parametrization().power_series()
3386
sage: X
3387
q^-2 + 2*q^-1 + 4 + 7*q + 13*q^2 + 18*q^3 + 31*q^4 + 49*q^5 + 74*q^6 + 111*q^7 + 173*q^8 + 251*q^9 + 379*q^10 + 560*q^11 + 824*q^12 + 1199*q^13 + 1773*q^14 + 2548*q^15 + 3722*q^16 + 5374*q^17 + O(q^18)
3388
sage: Y
3389
-q^-3 - 3*q^-2 - 8*q^-1 - 17 - 33*q - 61*q^2 - 110*q^3 - 186*q^4 - 320*q^5 - 528*q^6 - 861*q^7 - 1383*q^8 - 2218*q^9 - 3472*q^10 - 5451*q^11 - 8447*q^12 - 13020*q^13 - 19923*q^14 - 30403*q^15 - 46003*q^16 + O(q^17)
3390
3391
The following should give 0, but only approximately::
3392
3393
sage: q = X.parent().gen()
3394
sage: E.defining_polynomial()(X,Y,1) + O(q^11) == 0
3395
True
3396
"""
3397
return ModularParameterization(self)
3398
3399
def congruence_number(self, M=1):
3400
r"""
3401
The case `M==1` corresponds to the classical definition of congruence number:
3402
Let `X` be the subspace of `S_2(\Gamma_0(N))` spanned by the newform
3403
associated with this elliptic curve, and `Y` be orthogonal compliment
3404
of `X` under the Petersson inner product. Let `S_X` and `S_Y` be the
3405
intersections of `X` and `Y` with `S_2(\Gamma_0(N), \ZZ)`. The congruence
3406
number is defined to be `[S_X \oplus S_Y : S_2(\Gamma_0(N),\ZZ)]`.
3407
It measures congruences between `f` and elements of `S_2(\Gamma_0(N),\ZZ)`
3408
orthogonal to `f`.
3409
3410
The congruence number for higher levels, when M>1, is defined as above, but
3411
instead considers `X` to be the subspace of `S_2(\Gamma_0(MN))` spanned by
3412
embeddings into `S_2(\Gamma_0(MN))` of the newform associated with this
3413
elliptic curve; this subspace has dimension `\sigma_0(M)`, i.e. the number
3414
of divisors of `M`. Let `Y` be the orthogonal complement in `S_2(\Gamma_0(MN))`
3415
of `X` under the Petersson inner product, and `S_X` and `S_Y` the intersections
3416
of `X` and `Y` with `S_2(\Gamma_0(MN), \ZZ)` respectively. Then the congruence
3417
number at level `MN` is `[S_X \oplus S_Y : S_2(\Gamma_0(MN),\ZZ)]`.
3418
3419
INPUT:
3420
3421
- ``M`` - Non-negative integer; congruence number is computed at level `MN`,
3422
where `N` is the conductor of self.
3423
3424
EXAMPLES::
3425
3426
sage: E = EllipticCurve('37a')
3427
sage: E.congruence_number()
3428
2
3429
sage: E.congruence_number()
3430
2
3431
sage: E = EllipticCurve('54b')
3432
sage: E.congruence_number()
3433
6
3434
sage: E.modular_degree()
3435
2
3436
sage: E = EllipticCurve('242a1')
3437
sage: E.modular_degree()
3438
16
3439
sage: E.congruence_number() # long time (4s on sage.math, 2011)
3440
176
3441
3442
Higher level cases::
3443
3444
sage: E = EllipticCurve('11a')
3445
sage: for M in range(1,11): print(E.congruence_number(M)) # long time (20s on 2009 MBP)
3446
1
3447
1
3448
3
3449
2
3450
7
3451
45
3452
12
3453
4
3454
18
3455
245
3456
3457
It is a theorem of Ribet that the congruence number (at level `N`) is equal
3458
to the modular degree in the case of square free conductor. It is a conjecture
3459
of Agashe, Ribet, and Stein that `ord_p(c_f/m_f) \le ord_p(N)/2`.
3460
3461
TESTS::
3462
3463
sage: E = EllipticCurve('11a')
3464
sage: E.congruence_number()
3465
1
3466
"""
3467
# Case 1: M==1
3468
if M==1:
3469
try:
3470
return self.__congruence_number
3471
except AttributeError:
3472
pass
3473
# Currently this is *much* faster to compute
3474
m = self.modular_degree()
3475
if self.conductor().is_squarefree():
3476
self.__congruence_number = m
3477
else:
3478
W = self.modular_symbol_space(sign=1)
3479
V = W.complement().cuspidal_subspace()
3480
self.__congruence_number = W.congruence_number(V)
3481
if not m.divides(self.__congruence_number):
3482
# We should never get here
3483
raise ValueError, "BUG in modular degree or congruence number computation of: %s" % self
3484
return self.__congruence_number
3485
3486
# Case 2: M > 1
3487
else:
3488
try:
3489
return self.__generalized_congruence_number[M]
3490
except KeyError:
3491
# self._generalized_congmod_numbers() also populates cache
3492
return self._generalized_congmod_numbers(M)["congnum"]
3493
3494
3495
def cremona_label(self, space=False):
3496
"""
3497
Return the Cremona label associated to (the minimal model) of this
3498
curve, if it is known. If not, raise a RuntimeError exception.
3499
3500
EXAMPLES::
3501
3502
sage: E=EllipticCurve('389a1')
3503
sage: E.cremona_label()
3504
'389a1'
3505
3506
The default database only contains conductors up to 10000, so any
3507
curve with conductor greater than that will cause an error to be
3508
raised. The optional package ``database_cremona_ellcurve``
3509
contains many more curves.
3510
3511
::
3512
3513
sage: E = EllipticCurve([1, -1, 0, -79, 289])
3514
sage: E.conductor()
3515
234446
3516
sage: E.cremona_label() # optional - database_cremona_ellcurve
3517
'234446a1'
3518
sage: E = EllipticCurve((0, 0, 1, -79, 342))
3519
sage: E.conductor()
3520
19047851
3521
sage: E.cremona_label()
3522
Traceback (most recent call last):
3523
...
3524
RuntimeError: Cremona label not known for Elliptic Curve defined by y^2 + y = x^3 - 79*x + 342 over Rational Field.
3525
"""
3526
try:
3527
if not space:
3528
return self.__cremona_label.replace(' ','')
3529
return self.__cremona_label
3530
except AttributeError:
3531
try:
3532
X = self.database_curve()
3533
except RuntimeError:
3534
raise RuntimeError, "Cremona label not known for %s."%self
3535
self.__cremona_label = X.__cremona_label
3536
return self.cremona_label(space)
3537
3538
label = cremona_label
3539
3540
def reduction(self,p):
3541
"""
3542
Return the reduction of the elliptic curve at a prime of good
3543
reduction.
3544
3545
.. note::
3546
3547
The actual reduction is done in ``self.change_ring(GF(p))``;
3548
the reduction is performed after changing to a model which
3549
is minimal at p.
3550
3551
INPUT:
3552
3553
- ``p`` - a (positive) prime number
3554
3555
3556
OUTPUT: an elliptic curve over the finite field GF(p)
3557
3558
EXAMPLES::
3559
3560
sage: E = EllipticCurve('389a1')
3561
sage: E.reduction(2)
3562
Elliptic Curve defined by y^2 + y = x^3 + x^2 over Finite Field of size 2
3563
sage: E.reduction(3)
3564
Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 3
3565
sage: E.reduction(5)
3566
Elliptic Curve defined by y^2 + y = x^3 + x^2 + 3*x over Finite Field of size 5
3567
sage: E.reduction(38)
3568
Traceback (most recent call last):
3569
...
3570
AttributeError: p must be prime.
3571
sage: E.reduction(389)
3572
Traceback (most recent call last):
3573
...
3574
AttributeError: The curve must have good reduction at p.
3575
sage: E=EllipticCurve([5^4,5^6])
3576
sage: E.reduction(5)
3577
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5
3578
"""
3579
p = rings.Integer(p)
3580
if not p.is_prime():
3581
raise AttributeError, "p must be prime."
3582
disc = self.discriminant()
3583
if not disc.valuation(p) == 0:
3584
local_data=self.local_data(p)
3585
if local_data.has_good_reduction():
3586
return local_data.minimal_model().change_ring(rings.GF(p))
3587
raise AttributeError, "The curve must have good reduction at p."
3588
return self.change_ring(rings.GF(p))
3589
3590
def torsion_order(self):
3591
"""
3592
Return the order of the torsion subgroup.
3593
3594
EXAMPLES::
3595
3596
sage: e = EllipticCurve('11a')
3597
sage: e.torsion_order()
3598
5
3599
sage: type(e.torsion_order())
3600
<type 'sage.rings.integer.Integer'>
3601
sage: e = EllipticCurve([1,2,3,4,5])
3602
sage: e.torsion_order()
3603
1
3604
sage: type(e.torsion_order())
3605
<type 'sage.rings.integer.Integer'>
3606
"""
3607
try:
3608
return self.__torsion_order
3609
except AttributeError:
3610
self.__torsion_order = self.torsion_subgroup().order()
3611
return self.__torsion_order
3612
3613
def _torsion_bound(self,number_of_places = 20):
3614
r"""
3615
Computes an upper bound on the order of the torsion group of the
3616
elliptic curve by counting points modulo several primes of good
3617
reduction. Note that the upper bound returned by this function is a
3618
multiple of the order of the torsion group.
3619
3620
INPUT:
3621
3622
3623
- ``number_of_places (default = 20)`` - the number
3624
of places that will be used to find the bound
3625
3626
3627
OUTPUT:
3628
3629
3630
- ``integer`` - the upper bound
3631
3632
3633
EXAMPLES:
3634
"""
3635
E = self
3636
bound = Integer(0)
3637
k = 0
3638
p = Integer(2) # will run through odd primes
3639
while k < number_of_places :
3640
p = p.next_prime()
3641
# check if the formal group at the place is torsion-free
3642
# if so the torsion injects into the reduction
3643
while not E.is_local_integral_model(p) or not E.is_good(p): p = p.next_prime()
3644
bound = arith.gcd(bound,E.reduction(p).cardinality())
3645
if bound == 1:
3646
return bound
3647
k += 1
3648
return bound
3649
3650
3651
def torsion_subgroup(self, algorithm="pari"):
3652
"""
3653
Returns the torsion subgroup of this elliptic curve.
3654
3655
INPUT:
3656
3657
3658
- ``algorithm`` - string:
3659
3660
- ``"pari"`` - (default) use the PARI library
3661
3662
- ``"doud"`` - use Doud's algorithm
3663
3664
- ``"lutz_nagell"`` - use the Lutz-Nagell theorem
3665
3666
3667
OUTPUT: The EllipticCurveTorsionSubgroup instance associated to
3668
this elliptic curve.
3669
3670
.. note::
3671
3672
To see the torsion points as a list, use :meth:`.torsion_points`.
3673
3674
EXAMPLES::
3675
3676
sage: EllipticCurve('11a').torsion_subgroup()
3677
Torsion Subgroup isomorphic to Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
3678
sage: EllipticCurve('37b').torsion_subgroup()
3679
Torsion Subgroup isomorphic to Z/3 associated to the Elliptic Curve defined by y^2 + y = x^3 + x^2 - 23*x - 50 over Rational Field
3680
3681
::
3682
3683
sage: e = EllipticCurve([-1386747,368636886]);e
3684
Elliptic Curve defined by y^2 = x^3 - 1386747*x + 368636886 over Rational Field
3685
sage: G = e.torsion_subgroup(); G
3686
Torsion Subgroup isomorphic to Z/2 + Z/8 associated to the Elliptic
3687
Curve defined by y^2 = x^3 - 1386747*x + 368636886 over
3688
Rational Field
3689
sage: G.0
3690
(1227 : 22680 : 1)
3691
sage: G.1
3692
(282 : 0 : 1)
3693
sage: list(G)
3694
[(0 : 1 : 0), (1227 : 22680 : 1), (2307 : -97200 : 1), (8787 : 816480 : 1), (1011 : 0 : 1), (8787 : -816480 : 1), (2307 : 97200 : 1), (1227 : -22680 : 1), (282 : 0 : 1), (-933 : 29160 : 1), (-285 : -27216 : 1), (147 : 12960 : 1), (-1293 : 0 : 1), (147 : -12960 : 1), (-285 : 27216 : 1), (-933 : -29160 : 1)]
3695
"""
3696
try:
3697
return self.__torsion_subgroup
3698
except AttributeError:
3699
self.__torsion_subgroup = ell_torsion.EllipticCurveTorsionSubgroup(self, algorithm)
3700
self.__torsion_order = self.__torsion_subgroup.order()
3701
return self.__torsion_subgroup
3702
3703
def torsion_points(self, algorithm="pari"):
3704
"""
3705
Returns the torsion points of this elliptic curve as a sorted
3706
list.
3707
3708
INPUT:
3709
3710
3711
- ``algorithm`` - string:
3712
3713
- "pari" - (default) use the PARI library
3714
3715
- "doud" - use Doud's algorithm
3716
3717
- "lutz_nagell" - use the Lutz-Nagell theorem
3718
3719
3720
OUTPUT: A list of all the torsion points on this elliptic curve.
3721
3722
EXAMPLES::
3723
3724
sage: EllipticCurve('11a').torsion_points()
3725
[(0 : 1 : 0), (5 : -6 : 1), (5 : 5 : 1), (16 : -61 : 1), (16 : 60 : 1)]
3726
sage: EllipticCurve('37b').torsion_points()
3727
[(0 : 1 : 0), (8 : -19 : 1), (8 : 18 : 1)]
3728
3729
::
3730
3731
sage: E=EllipticCurve([-1386747,368636886])
3732
sage: T=E.torsion_subgroup(); T
3733
Torsion Subgroup isomorphic to Z/2 + Z/8 associated to the Elliptic Curve defined by y^2 = x^3 - 1386747*x + 368636886 over Rational Field
3734
sage: T == E.torsion_subgroup(algorithm="doud")
3735
True
3736
sage: T == E.torsion_subgroup(algorithm="lutz_nagell")
3737
True
3738
sage: E.torsion_points()
3739
[(-1293 : 0 : 1),
3740
(-933 : -29160 : 1),
3741
(-933 : 29160 : 1),
3742
(-285 : -27216 : 1),
3743
(-285 : 27216 : 1),
3744
(0 : 1 : 0),
3745
(147 : -12960 : 1),
3746
(147 : 12960 : 1),
3747
(282 : 0 : 1),
3748
(1011 : 0 : 1),
3749
(1227 : -22680 : 1),
3750
(1227 : 22680 : 1),
3751
(2307 : -97200 : 1),
3752
(2307 : 97200 : 1),
3753
(8787 : -816480 : 1),
3754
(8787 : 816480 : 1)]
3755
"""
3756
return sorted(self.torsion_subgroup(algorithm).points())
3757
3758
## def newform_eval(self, z, prec):
3759
## """
3760
## The value of the newform attached to this elliptic curve at
3761
## the point z in the complex upper half plane, computed using
3762
## prec terms of the power series expansion. Note that the power
3763
## series need not converge well near the real axis.
3764
## """
3765
## raise NotImplementedError
3766
3767
@cached_method
3768
def root_number(self, p=None):
3769
"""
3770
Returns the root number of this elliptic curve.
3771
3772
This is 1 if the order of vanishing of the L-function L(E,s) at 1
3773
is even, and -1 if it is odd.
3774
3775
INPUT::
3776
3777
- `p` -- optional, default (None); if given, return the local
3778
root number at `p`
3779
3780
EXAMPLES::
3781
3782
sage: EllipticCurve('11a1').root_number()
3783
1
3784
sage: EllipticCurve('37a1').root_number()
3785
-1
3786
sage: EllipticCurve('389a1').root_number()
3787
1
3788
sage: type(EllipticCurve('389a1').root_number())
3789
<type 'sage.rings.integer.Integer'>
3790
3791
sage: E = EllipticCurve('100a1')
3792
sage: E.root_number(2)
3793
-1
3794
sage: E.root_number(5)
3795
1
3796
sage: E.root_number(7)
3797
1
3798
3799
The root number is cached::
3800
3801
sage: E.root_number(2) is E.root_number(2)
3802
True
3803
sage: E.root_number()
3804
1
3805
"""
3806
e = self.pari_mincurve()
3807
if p is None:
3808
return Integer(e.ellrootno())
3809
else:
3810
return Integer(e.ellrootno(p))
3811
3812
def has_cm(self):
3813
"""
3814
Returns True iff this elliptic curve has Complex Multiplication.
3815
3816
EXAMPLES::
3817
3818
sage: E=EllipticCurve('37a1')
3819
sage: E.has_cm()
3820
False
3821
sage: E=EllipticCurve('32a1')
3822
sage: E.has_cm()
3823
True
3824
sage: E.j_invariant()
3825
1728
3826
"""
3827
3828
return CMJ.has_key(self.j_invariant())
3829
3830
def cm_discriminant(self):
3831
"""
3832
Returns the associated quadratic discriminant if this elliptic
3833
curve has Complex Multiplication.
3834
3835
A ValueError is raised if the curve does not have CM (see the
3836
function has_cm()).
3837
3838
EXAMPLES::
3839
3840
sage: E=EllipticCurve('32a1')
3841
sage: E.cm_discriminant()
3842
-4
3843
sage: E=EllipticCurve('121b1')
3844
sage: E.cm_discriminant()
3845
-11
3846
sage: E=EllipticCurve('37a1')
3847
sage: E.cm_discriminant()
3848
Traceback (most recent call last):
3849
...
3850
ValueError: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field does not have CM
3851
"""
3852
3853
try:
3854
return CMJ[self.j_invariant()]
3855
except KeyError:
3856
raise ValueError, "%s does not have CM"%self
3857
3858
3859
def quadratic_twist(self, D):
3860
"""
3861
Return the global minimal model of the quadratic twist of this
3862
curve by D.
3863
3864
EXAMPLES::
3865
3866
sage: E=EllipticCurve('37a1')
3867
sage: E7=E.quadratic_twist(7); E7
3868
Elliptic Curve defined by y^2 = x^3 - 784*x + 5488 over Rational Field
3869
sage: E7.conductor()
3870
29008
3871
sage: E7.quadratic_twist(7) == E
3872
True
3873
"""
3874
return EllipticCurve_number_field.quadratic_twist(self, D).minimal_model()
3875
3876
def minimal_quadratic_twist(self):
3877
r"""
3878
Determines a quadratic twist with minimal conductor. Returns a
3879
global minimal model of the twist and the fundamental
3880
discriminant of the quadratic field over which they are
3881
isomorphic.
3882
3883
.. note::
3884
3885
If there is more than one curve with minimal conductor, the
3886
one returned is the one with smallest label (if in the
3887
database), or the one with minimal `a`-invariant list
3888
(otherwise).
3889
3890
.. note::
3891
3892
For curves with `j`-invariant 0 or 1728 the curve returned
3893
is the minimal quadratic twist, not necessarily the minimal
3894
twist (which would have conductor 27 or 32 respectively).
3895
3896
EXAMPLES::
3897
3898
sage: E = EllipticCurve('121d1')
3899
sage: E.minimal_quadratic_twist()
3900
(Elliptic Curve defined by y^2 + y = x^3 - x^2 over Rational Field, -11)
3901
sage: Et, D = EllipticCurve('32a1').minimal_quadratic_twist()
3902
sage: D
3903
1
3904
3905
sage: E = EllipticCurve('11a1')
3906
sage: Et, D = E.quadratic_twist(-24).minimal_quadratic_twist()
3907
sage: E == Et
3908
True
3909
sage: D
3910
-24
3911
3912
sage: E = EllipticCurve([0,0,0,0,1000])
3913
sage: E.minimal_quadratic_twist()
3914
(Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field, 40)
3915
sage: E = EllipticCurve([0,0,0,1600,0])
3916
sage: E.minimal_quadratic_twist()
3917
(Elliptic Curve defined by y^2 = x^3 + 4*x over Rational Field, 5)
3918
3919
If the curve has square-free conductor then it is already minimal (see :trac:`14060`)::
3920
3921
sage: E = cremona_optimal_curves([2*3*5*7*11]).next()
3922
sage: (E, 1) == E.minimal_quadratic_twist()
3923
True
3924
3925
An example where the minimal quadratic twist is not the
3926
minimal twist (which has conductor 27)::
3927
3928
sage: E = EllipticCurve([0,0,0,0,7])
3929
sage: E.j_invariant()
3930
0
3931
sage: E.minimal_quadratic_twist()[0].conductor()
3932
5292
3933
"""
3934
if self.conductor().is_squarefree():
3935
return self, Integer(1)
3936
j = self.j_invariant()
3937
if j!=0 and j!=1728:
3938
# the constructor from j will give the minimal twist
3939
Et = constructor.EllipticCurve_from_j(j)
3940
else:
3941
if j==0: # divide c6 by largest cube
3942
c = -2*self.c6()
3943
for p in c.support():
3944
e = c.valuation(p)//3
3945
c /= p**(3*e)
3946
E1 = constructor.EllipticCurve([0,0,0,0,c])
3947
elif j==1728: # divide c4 by largest square
3948
c = -3*self.c4()
3949
for p in c.support():
3950
e = c.valuation(p)//2
3951
c /= p**(2*e)
3952
E1 = constructor.EllipticCurve([0,0,0,c,0])
3953
tw = [-1,2,-2,3,-3,6,-6]
3954
Elist = [E1] + [E1.quadratic_twist(t) for t in tw]
3955
crv_cmp = lambda E,F: cmp(E.conductor(),F.conductor())
3956
Elist.sort(cmp=crv_cmp)
3957
Et = Elist[0]
3958
3959
Et = Et.minimal_model()
3960
3961
D = self.is_quadratic_twist(Et) # 1 or square-free
3962
if D % 4 != 1:
3963
D *= 4
3964
3965
return Et, D
3966
3967
3968
##########################################################
3969
# Isogeny class
3970
##########################################################
3971
def isogeny_class(self, algorithm="sage", order=None):
3972
r"""
3973
Returns the `\QQ`-isogeny class of this elliptic curve.
3974
3975
INPUT:
3976
3977
- ``algorithm`` - string: one of the following:
3978
3979
- "database" - use the Cremona database (only works if
3980
curve is isomorphic to a curve in the database)
3981
3982
- "sage" (default) - use the native Sage implementation.
3983
3984
- ``order`` -- None, string, or list of curves (default:
3985
None): If not None then the curves in the class are
3986
reordered after being computed. Note that if the order is
3987
None then the resulting order will depend on the algorithm.
3988
3989
- if ``order`` is "database" or "sage", then the reordering
3990
is so that the order of curves matches the order produced
3991
by that algorithm.
3992
3993
- if ``order`` is "lmfdb" then the curves are sorted
3994
lexicographically by a-invariants, in the LMFDB database.
3995
3996
- if ``order`` is a list of curves, then the curves in the
3997
class are reordered to be isomorphic with the specified
3998
list of curves.
3999
4000
OUTPUT:
4001
4002
An instance of the class
4003
:class:`sage.schemes.elliptic_curves.isogeny_class.IsogenyClass_EC_Rational`.
4004
This object models a list of minimal models (with containment,
4005
index, etc based on isomorphism classes). It also has methods
4006
for computing the isogeny matrix and the list of isogenies
4007
between curves in this class.
4008
4009
.. note::
4010
4011
The curves in the isogeny class will all be standard
4012
minimal models.
4013
4014
EXAMPLES::
4015
4016
sage: isocls = EllipticCurve('37b').isogeny_class(order="lmfdb")
4017
sage: isocls
4018
Elliptic curve isogeny class 37b
4019
sage: isocls.curves
4020
(Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field,
4021
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 23*x - 50 over Rational Field,
4022
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 3*x + 1 over Rational Field)
4023
sage: isocls.matrix()
4024
[1 3 9]
4025
[3 1 3]
4026
[9 3 1]
4027
4028
::
4029
4030
sage: isocls = EllipticCurve('37b').isogeny_class('database', order="lmfdb"); isocls.curves
4031
(Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field,
4032
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 23*x - 50 over Rational Field,
4033
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 3*x + 1 over Rational Field)
4034
4035
This is an example of a curve with a `37`-isogeny::
4036
4037
sage: E = EllipticCurve([1,1,1,-8,6])
4038
sage: isocls = E.isogeny_class(); isocls
4039
Isogeny class of Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 8*x + 6 over Rational Field
4040
sage: isocls.matrix()
4041
[ 1 37]
4042
[37 1]
4043
sage: print "\n".join([repr(E) for E in isocls.curves])
4044
Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 8*x + 6 over Rational Field
4045
Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 208083*x - 36621194 over Rational Field
4046
4047
This curve had numerous `2`-isogenies::
4048
4049
sage: e=EllipticCurve([1,0,0,-39,90])
4050
sage: isocls = e.isogeny_class(); isocls.matrix()
4051
[1 2 4 4 8 8]
4052
[2 1 2 2 4 4]
4053
[4 2 1 4 8 8]
4054
[4 2 4 1 2 2]
4055
[8 4 8 2 1 4]
4056
[8 4 8 2 4 1]
4057
4058
See http://math.harvard.edu/~elkies/nature.html for more
4059
interesting examples of isogeny structures.
4060
4061
::
4062
4063
sage: E = EllipticCurve(j = -262537412640768000)
4064
sage: isocls = E.isogeny_class(); isocls.matrix()
4065
[ 1 163]
4066
[163 1]
4067
sage: print "\n".join([repr(C) for C in isocls.curves])
4068
Elliptic Curve defined by y^2 + y = x^3 - 2174420*x + 1234136692 over Rational Field
4069
Elliptic Curve defined by y^2 + y = x^3 - 57772164980*x - 5344733777551611 over Rational Field
4070
4071
4072
The degrees of isogenies are invariant under twists::
4073
4074
sage: E = EllipticCurve(j = -262537412640768000)
4075
sage: E1 = E.quadratic_twist(6584935282)
4076
sage: isocls = E1.isogeny_class(); isocls.matrix()
4077
[ 1 163]
4078
[163 1]
4079
sage: E1.conductor()
4080
18433092966712063653330496
4081
4082
::
4083
4084
sage: E = EllipticCurve('14a1')
4085
sage: isocls = E.isogeny_class(); isocls.matrix()
4086
[ 1 2 3 3 6 6]
4087
[ 2 1 6 6 3 3]
4088
[ 3 6 1 9 2 18]
4089
[ 3 6 9 1 18 2]
4090
[ 6 3 2 18 1 9]
4091
[ 6 3 18 2 9 1]
4092
sage: print "\n".join([repr(C) for C in isocls.curves])
4093
Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field
4094
Elliptic Curve defined by y^2 + x*y + y = x^3 - 36*x - 70 over Rational Field
4095
Elliptic Curve defined by y^2 + x*y + y = x^3 - x over Rational Field
4096
Elliptic Curve defined by y^2 + x*y + y = x^3 - 171*x - 874 over Rational Field
4097
Elliptic Curve defined by y^2 + x*y + y = x^3 - 11*x + 12 over Rational Field
4098
Elliptic Curve defined by y^2 + x*y + y = x^3 - 2731*x - 55146 over Rational Field
4099
sage: isocls2 = isocls.reorder('lmfdb'); isocls2.matrix()
4100
[ 1 2 3 9 18 6]
4101
[ 2 1 6 18 9 3]
4102
[ 3 6 1 3 6 2]
4103
[ 9 18 3 1 2 6]
4104
[18 9 6 2 1 3]
4105
[ 6 3 2 6 3 1]
4106
sage: print "\n".join([repr(C) for C in isocls2.curves])
4107
Elliptic Curve defined by y^2 + x*y + y = x^3 - 2731*x - 55146 over Rational Field
4108
Elliptic Curve defined by y^2 + x*y + y = x^3 - 171*x - 874 over Rational Field
4109
Elliptic Curve defined by y^2 + x*y + y = x^3 - 36*x - 70 over Rational Field
4110
Elliptic Curve defined by y^2 + x*y + y = x^3 - 11*x + 12 over Rational Field
4111
Elliptic Curve defined by y^2 + x*y + y = x^3 - x over Rational Field
4112
Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field
4113
4114
::
4115
4116
sage: E = EllipticCurve('11a1')
4117
sage: isocls = E.isogeny_class(); isocls.matrix()
4118
[ 1 5 5]
4119
[ 5 1 25]
4120
[ 5 25 1]
4121
sage: f = isocls.isogenies()[0][1]; f.kernel_polynomial()
4122
x^2 + x - 29/5
4123
"""
4124
try:
4125
isoclass = self._isoclass[algorithm]
4126
except KeyError:
4127
from sage.schemes.elliptic_curves.isogeny_class import IsogenyClass_EC_Rational
4128
if hasattr(self, "_lmfdb_label") and self._lmfdb_label:
4129
label = self._lmfdb_label[:-1]
4130
elif hasattr(self, "_EllipticCurve_rational_field__cremona_label") and self.__cremona_label:
4131
label = self.__cremona_label[:-1]
4132
else:
4133
label = None
4134
4135
isoclass = IsogenyClass_EC_Rational(self, algorithm, label)
4136
self._isoclass[algorithm] = isoclass
4137
4138
if order:
4139
isoclass = isoclass.reorder(order)
4140
4141
return isoclass
4142
4143
def isogenies_prime_degree(self, l=None):
4144
r"""
4145
Returns a list of `\ell`-isogenies from self, where `\ell` is a
4146
prime.
4147
4148
INPUT:
4149
4150
- ``l`` -- either None or a prime or a list of primes.
4151
4152
OUTPUT:
4153
4154
(list) `\ell`-isogenies for the given `\ell` or if `\ell` is None, all
4155
`\ell`-isogenies.
4156
4157
.. note::
4158
4159
The codomains of the isogenies returned are standard
4160
minimal models. This is because the functions
4161
:meth:`isogenies_prime_degree_genus_0()` and
4162
:meth:`isogenies_sporadic_Q()` are implemented that way for
4163
curves defined over `\QQ`.
4164
4165
EXAMPLES::
4166
4167
sage: E = EllipticCurve([45,32])
4168
sage: E.isogenies_prime_degree()
4169
[]
4170
sage: E = EllipticCurve(j = -262537412640768000)
4171
sage: E.isogenies_prime_degree()
4172
[Isogeny of degree 163 from Elliptic Curve defined by y^2 + y = x^3 - 2174420*x + 1234136692 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - 57772164980*x - 5344733777551611 over Rational Field]
4173
sage: E1 = E.quadratic_twist(6584935282)
4174
sage: E1.isogenies_prime_degree()
4175
[Isogeny of degree 163 from Elliptic Curve defined by y^2 = x^3 - 94285835957031797981376080*x + 352385311612420041387338054224547830898 over Rational Field to Elliptic Curve defined by y^2 = x^3 - 2505080375542377840567181069520*x - 1526091631109553256978090116318797845018020806 over Rational Field]
4176
4177
sage: E = EllipticCurve('14a1')
4178
sage: E.isogenies_prime_degree(2)
4179
[Isogeny of degree 2 from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - 36*x - 70 over Rational Field]
4180
sage: E.isogenies_prime_degree(3)
4181
[Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - x over Rational Field, Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - 171*x - 874 over Rational Field]
4182
sage: E.isogenies_prime_degree(5)
4183
[]
4184
sage: E.isogenies_prime_degree(11)
4185
[]
4186
sage: E.isogenies_prime_degree(29)
4187
[]
4188
sage: E.isogenies_prime_degree(4)
4189
Traceback (most recent call last):
4190
...
4191
ValueError: 4 is not prime.
4192
4193
"""
4194
from isogeny_small_degree import isogenies_prime_degree_genus_0, isogenies_sporadic_Q
4195
4196
if l in [2, 3, 5, 7, 13]:
4197
return isogenies_prime_degree_genus_0(self, l)
4198
elif l != None and type(l) != list:
4199
try:
4200
if l.is_prime(proof=False):
4201
return isogenies_sporadic_Q(self, l)
4202
else:
4203
raise ValueError("%s is not prime."%l)
4204
except AttributeError:
4205
raise ValueError("%s is not prime."%l)
4206
if l == None:
4207
isogs = isogenies_prime_degree_genus_0(self)
4208
if isogs != []:
4209
return isogs
4210
else:
4211
return isogenies_sporadic_Q(self)
4212
if type(l) == list:
4213
isogs = []
4214
i = 0
4215
while i<len(l):
4216
isogenies = [f for f in self.isogenies_prime_degree(l[i]) if not f in isogs]
4217
isogs.extend(isogenies)
4218
i = i+1
4219
return isogs
4220
4221
def is_isogenous(self, other, proof=True, maxp=200):
4222
"""
4223
Returns whether or not self is isogenous to other.
4224
4225
INPUT:
4226
4227
- ``other`` -- another elliptic curve.
4228
4229
- ``proof`` (default True) -- If ``False``, the function will
4230
return ``True`` whenever the two curves have the same
4231
conductor and are isogenous modulo `p` for `p` up to ``maxp``.
4232
If ``True``, this test is followed by a rigorous test (which
4233
may be more time-consuming).
4234
4235
- ``maxp`` (int, default 200) -- The maximum prime `p` for
4236
which isogeny modulo `p` will be checked.
4237
4238
OUTPUT:
4239
4240
(bool) True if there is an isogeny from curve ``self`` to
4241
curve ``other``.
4242
4243
METHOD:
4244
4245
First the conductors are compared as well as the Traces of
4246
Frobenius for good primes up to ``maxp``. If any of these
4247
tests fail, ``False`` is returned. If they all pass and
4248
``proof`` is ``False`` then ``True`` is returned, otherwise a
4249
complete set of curves isogenous to ``self`` is computed and
4250
``other`` is checked for isomorphism with any of these,
4251
4252
EXAMPLES::
4253
4254
sage: E1 = EllipticCurve('14a1')
4255
sage: E6 = EllipticCurve('14a6')
4256
sage: E1.is_isogenous(E6)
4257
True
4258
sage: E1.is_isogenous(EllipticCurve('11a1'))
4259
False
4260
4261
::
4262
4263
sage: EllipticCurve('37a1').is_isogenous(EllipticCurve('37b1'))
4264
False
4265
4266
::
4267
4268
sage: E = EllipticCurve([2, 16])
4269
sage: EE = EllipticCurve([87, 45])
4270
sage: E.is_isogenous(EE)
4271
False
4272
"""
4273
if not is_EllipticCurve(other):
4274
raise ValueError, "Second argument is not an Elliptic Curve."
4275
if not other.base_field() is QQ:
4276
raise ValueError, "If first argument is an elliptic curve over QQ then the second argument must be also."
4277
4278
if self.is_isomorphic(other):
4279
return True
4280
4281
E1 = self.minimal_model()
4282
E2 = other.minimal_model()
4283
D1 = E1.discriminant()
4284
D2 = E2.discriminant()
4285
4286
if any([E1.change_ring(rings.GF(p)).cardinality() != E2.change_ring(rings.GF(p)).cardinality() for p in [p for p in rings.prime_range(2,maxp) if D1.valuation(p) == 0 and D2.valuation(p) == 0]]):
4287
return False
4288
4289
if E1.conductor() != E2.conductor():
4290
return False
4291
4292
if not proof:
4293
return True
4294
else:
4295
return E2 in E1.isogeny_class().curves
4296
4297
def isogeny_degree(self, other):
4298
"""
4299
Returns the minimal degree of an isogeny between self and
4300
other.
4301
4302
INPUT:
4303
4304
- ``other`` -- another elliptic curve.
4305
4306
OUTPUT:
4307
4308
(int) The minimal degree of an isogeny from ``self`` to
4309
``other``, or 0 if the curves are not isogenous.
4310
4311
EXAMPLES::
4312
4313
sage: E = EllipticCurve([-1056, 13552])
4314
sage: E2 = EllipticCurve([-127776, -18037712])
4315
sage: E.isogeny_degree(E2)
4316
11
4317
4318
::
4319
4320
sage: E1 = EllipticCurve('14a1')
4321
sage: E2 = EllipticCurve('14a2')
4322
sage: E3 = EllipticCurve('14a3')
4323
sage: E4 = EllipticCurve('14a4')
4324
sage: E5 = EllipticCurve('14a5')
4325
sage: E6 = EllipticCurve('14a6')
4326
sage: E3.isogeny_degree(E1)
4327
3
4328
sage: E3.isogeny_degree(E2)
4329
6
4330
sage: E3.isogeny_degree(E3)
4331
1
4332
sage: E3.isogeny_degree(E4)
4333
9
4334
sage: E3.isogeny_degree(E5)
4335
2
4336
sage: E3.isogeny_degree(E6)
4337
18
4338
4339
::
4340
4341
sage: E1 = EllipticCurve('30a1')
4342
sage: E2 = EllipticCurve('30a2')
4343
sage: E3 = EllipticCurve('30a3')
4344
sage: E4 = EllipticCurve('30a4')
4345
sage: E5 = EllipticCurve('30a5')
4346
sage: E6 = EllipticCurve('30a6')
4347
sage: E7 = EllipticCurve('30a7')
4348
sage: E8 = EllipticCurve('30a8')
4349
sage: E1.isogeny_degree(E1)
4350
1
4351
sage: E1.isogeny_degree(E2)
4352
2
4353
sage: E1.isogeny_degree(E3)
4354
3
4355
sage: E1.isogeny_degree(E4)
4356
4
4357
sage: E1.isogeny_degree(E5)
4358
4
4359
sage: E1.isogeny_degree(E6)
4360
6
4361
sage: E1.isogeny_degree(E7)
4362
12
4363
sage: E1.isogeny_degree(E8)
4364
12
4365
4366
::
4367
4368
sage: E1 = EllipticCurve('15a1')
4369
sage: E2 = EllipticCurve('15a2')
4370
sage: E3 = EllipticCurve('15a3')
4371
sage: E4 = EllipticCurve('15a4')
4372
sage: E5 = EllipticCurve('15a5')
4373
sage: E6 = EllipticCurve('15a6')
4374
sage: E7 = EllipticCurve('15a7')
4375
sage: E8 = EllipticCurve('15a8')
4376
sage: E1.isogeny_degree(E1)
4377
1
4378
sage: E7.isogeny_degree(E2)
4379
8
4380
sage: E7.isogeny_degree(E3)
4381
2
4382
sage: E7.isogeny_degree(E4)
4383
8
4384
sage: E7.isogeny_degree(E5)
4385
16
4386
sage: E7.isogeny_degree(E6)
4387
16
4388
sage: E7.isogeny_degree(E8)
4389
4
4390
4391
0 is returned when the curves are not isogenous::
4392
4393
sage: A = EllipticCurve('37a1')
4394
sage: B = EllipticCurve('37b1')
4395
sage: A.isogeny_degree(B)
4396
0
4397
sage: A.is_isogenous(B)
4398
False
4399
"""
4400
E1 = self.minimal_model()
4401
E2 = other.minimal_model()
4402
4403
if not E1.is_isogenous(E2, proof=False):
4404
return Integer(0)
4405
4406
isocls = E1.isogeny_class()
4407
try:
4408
return isocls.matrix(fill=True)[0,isocls.index(E2)]
4409
except ValueError:
4410
return Integer(0)
4411
4412
#
4413
# The following function can be implemented once composition of
4414
# isogenies has been implemented.
4415
#
4416
# def contruct_isogeny(self, other):
4417
# """
4418
# Returns an isogeny from self to other if the two curves are in
4419
# the same isogeny class.
4420
# """
4421
4422
4423
def optimal_curve(self):
4424
"""
4425
Given an elliptic curve that is in the installed Cremona
4426
database, return the optimal curve isogenous to it.
4427
4428
EXAMPLES:
4429
4430
The following curve is not optimal::
4431
4432
sage: E = EllipticCurve('11a2'); E
4433
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field
4434
sage: E.optimal_curve()
4435
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
4436
sage: E.optimal_curve().cremona_label()
4437
'11a1'
4438
4439
Note that 990h is the special case where the optimal curve
4440
isn't the first in the Cremona labeling::
4441
4442
sage: E = EllipticCurve('990h4'); E
4443
Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 + 6112*x - 41533 over Rational Field
4444
sage: F = E.optimal_curve(); F
4445
Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 1568*x - 4669 over Rational Field
4446
sage: F.cremona_label()
4447
'990h3'
4448
sage: EllipticCurve('990a1').optimal_curve().cremona_label() # a isn't h.
4449
'990a1'
4450
4451
If the input curve is optimal, this function returns that
4452
curve (not just a copy of it or a curve isomorphic to it!)::
4453
4454
sage: E = EllipticCurve('37a1')
4455
sage: E.optimal_curve() is E
4456
True
4457
4458
Also, if this curve is optimal but not given by a minimal
4459
model, this curve will still be returned, so this function
4460
need not return a minimal model in general.
4461
4462
::
4463
4464
sage: F = E.short_weierstrass_model(); F
4465
Elliptic Curve defined by y^2 = x^3 - 16*x + 16 over Rational Field
4466
sage: F.optimal_curve()
4467
Elliptic Curve defined by y^2 = x^3 - 16*x + 16 over Rational Field
4468
"""
4469
label = self.cremona_label()
4470
N, isogeny, number = sage.databases.cremona.parse_cremona_label(label)
4471
if N == 990 and isogeny == 'h':
4472
optimal_label = '990h3'
4473
else:
4474
optimal_label = '%s%s1'%(N,isogeny)
4475
if optimal_label == label: return self
4476
return constructor.EllipticCurve(optimal_label)
4477
4478
def isogeny_graph(self, order=None):
4479
r"""
4480
Return a graph representing the isogeny class of this elliptic
4481
curve, where the vertices are isogenous curves over
4482
`\QQ` and the edges are prime degree isogenies.
4483
4484
.. note:
4485
4486
The vertices are labeled 1 to n rather than 0 to n-1 to
4487
correspond to LMFDB and Cremona labels.
4488
4489
EXAMPLES::
4490
4491
sage: LL = []
4492
sage: for e in cremona_optimal_curves(range(1, 38)): # long time
4493
....: G = e.isogeny_graph()
4494
....: already = False
4495
....: for H in LL:
4496
....: if G.is_isomorphic(H):
4497
....: already = True
4498
....: break
4499
....: if not already:
4500
....: LL.append(G)
4501
sage: graphs_list.show_graphs(LL) # long time
4502
4503
::
4504
4505
sage: E = EllipticCurve('195a')
4506
sage: G = E.isogeny_graph()
4507
sage: for v in G: print v, G.get_vertex(v)
4508
...
4509
1 Elliptic Curve defined by y^2 + x*y = x^3 - 110*x + 435 over Rational Field
4510
2 Elliptic Curve defined by y^2 + x*y = x^3 - 115*x + 392 over Rational Field
4511
3 Elliptic Curve defined by y^2 + x*y = x^3 + 210*x + 2277 over Rational Field
4512
4 Elliptic Curve defined by y^2 + x*y = x^3 - 520*x - 4225 over Rational Field
4513
5 Elliptic Curve defined by y^2 + x*y = x^3 + 605*x - 19750 over Rational Field
4514
6 Elliptic Curve defined by y^2 + x*y = x^3 - 8125*x - 282568 over Rational Field
4515
7 Elliptic Curve defined by y^2 + x*y = x^3 - 7930*x - 296725 over Rational Field
4516
8 Elliptic Curve defined by y^2 + x*y = x^3 - 130000*x - 18051943 over Rational Field
4517
sage: G.plot(edge_labels=True)
4518
"""
4519
return self.isogeny_class(order=order).graph()
4520
4521
def manin_constant(self):
4522
r"""
4523
Return the Manin constant of this elliptic curve. If `\phi: X_0(N) \to E` is the modular
4524
parametrization of minimal degree, then the Manin constant `c` is defined to be the rational
4525
number `c` such that `\phi^*(\omega_E) = c\cdot \omega_f` where `\omega_E` is a Neron differential and `\omega_f = f(q) dq/q` is the differential on `X_0(N)` corresponding to the
4526
newform `f` attached to the isogeny class of `E`.
4527
4528
It is known that the Manin constant is an integer. It is conjectured that in each class there is at least one, more precisely the so-called strong Weil curve or `X_0(N)`-optimal curve, that has Manin constant `1`.
4529
4530
OUTPUT:
4531
4532
an integer
4533
4534
This function only works if the curve is in the installed
4535
Cremona database. Sage includes by default a small databases;
4536
for the full database you have to install an optional package.
4537
4538
EXAMPLES::
4539
4540
sage: EllipticCurve('11a1').manin_constant()
4541
1
4542
sage: EllipticCurve('11a2').manin_constant()
4543
1
4544
sage: EllipticCurve('11a3').manin_constant()
4545
5
4546
4547
Check that it works even if the curve is non-minimal::
4548
4549
sage: EllipticCurve('11a3').change_weierstrass_model([1/35,0,0,0]).manin_constant()
4550
5
4551
4552
Rather complicated examples (see #12080) ::
4553
4554
sage: [ EllipticCurve('27a%s'%i).manin_constant() for i in [1,2,3,4]]
4555
[1, 1, 3, 3]
4556
sage: [ EllipticCurve('80b%s'%i).manin_constant() for i in [1,2,3,4]]
4557
[1, 2, 1, 2]
4558
4559
"""
4560
from sage.databases.cremona import CremonaDatabase
4561
4562
if self.conductor() > CremonaDatabase().largest_conductor():
4563
raise NotImplementedError, "The Manin constant can only be evaluated for curves in Cremona's tables. If you have not done so, you may wish to install the optional large database."
4564
4565
E = self.minimal_model()
4566
C = self.optimal_curve()
4567
m = C.isogeny_class().matrix()
4568
ma = max(max(x) for x in m)
4569
OmC = C.period_lattice().basis()
4570
OmE = E.period_lattice().basis()
4571
q_plus = QQ(gp.bestappr(OmE[0]/OmC[0],ma+1) )
4572
n_plus = q_plus.numerator()
4573
4574
cinf_E = E.real_components()
4575
cinf_C = C.real_components()
4576
OmC_minus = OmC[1].imag()
4577
if cinf_C == 1:
4578
OmC_minus *= 2
4579
OmE_minus = OmE[1].imag()
4580
if cinf_E == 1:
4581
OmE_minus *= 2
4582
q_minus = QQ(gp.bestappr(OmE_minus/OmC_minus, ma+1))
4583
n_minus = q_minus.numerator()
4584
n = ZZ(n_minus * n_plus)
4585
4586
if cinf_C == cinf_E:
4587
return n
4588
# otherwise they have different number of connected component and we have to adjust for this
4589
elif cinf_C > cinf_E:
4590
if ZZ(n_plus) % 2 == 0 and ZZ(n_minus) % 2 == 0:
4591
return n // 2
4592
else:
4593
return n
4594
else: #if cinf_C < cinf_E:
4595
if q_plus.denominator() % 2 == 0 and q_minus.denominator() % 2 == 0:
4596
return n
4597
else:
4598
return n*2
4599
4600
def _shortest_paths(self):
4601
r"""
4602
Technical internal function that returns the list of isogenies
4603
curves and corresponding dictionary of shortest isogeny paths
4604
from self to each other curve in the isogeny class.
4605
4606
OUTPUT:
4607
4608
list, dict
4609
4610
EXAMPLES::
4611
4612
sage: EllipticCurve('11a1')._shortest_paths()
4613
((Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field,
4614
Elliptic Curve defined by y^2 + y = x^3 - x^2 over Rational Field,
4615
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field),
4616
{0: 0, 1: 5, 2: 5})
4617
sage: EllipticCurve('11a2')._shortest_paths()
4618
((Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field,
4619
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field,
4620
Elliptic Curve defined by y^2 + y = x^3 - x^2 over Rational Field),
4621
{0: 0, 1: 5, 2: 25})
4622
"""
4623
from sage.graphs.graph import Graph
4624
isocls = self.isogeny_class()
4625
M = isocls.matrix(fill=True).change_ring(rings.RR)
4626
# see trac #4889 for nebulous M.list() --> M.entries() change...
4627
# Take logs here since shortest path minimizes the *sum* of the weights -- not the product.
4628
M = M.parent()([a.log() if a else 0 for a in M.list()])
4629
G = Graph(M, format='weighted_adjacency_matrix')
4630
G.set_vertices(dict([(v,isocls[v]) for v in G.vertices()]))
4631
v = G.shortest_path_lengths(0, by_weight=True, weight_sums=True)
4632
# Now exponentiate and round to get degrees of isogenies
4633
v = dict([(i, j.exp().round() if j else 0) for i,j in v.iteritems()])
4634
return isocls.curves, v
4635
4636
def _multiple_of_degree_of_isogeny_to_optimal_curve(self):
4637
r"""
4638
Internal function returning an integer m such that the degree of
4639
the isogeny between this curve and the optimal curve in its
4640
isogeny class is a divisor of m.
4641
4642
.. warning::
4643
4644
The result is *not* provably correct, in the
4645
sense that when the numbers are huge isogenies could be
4646
missed because of precision issues.
4647
4648
EXAMPLES::
4649
4650
sage: E = EllipticCurve('11a1')
4651
sage: E._multiple_of_degree_of_isogeny_to_optimal_curve()
4652
5
4653
sage: E = EllipticCurve('11a2')
4654
sage: E._multiple_of_degree_of_isogeny_to_optimal_curve()
4655
25
4656
sage: E = EllipticCurve('11a3')
4657
sage: E._multiple_of_degree_of_isogeny_to_optimal_curve()
4658
25
4659
"""
4660
_, v = self._shortest_paths()
4661
# Compute the degree of an isogeny from self to anything else
4662
# in the isogeny class of self. Assuming the isogeny
4663
# enumeration is complete (which need not be the case a priori!), the LCM
4664
# of these numbers is a multiple of the degree of the isogeny
4665
# to the optimal curve.
4666
v = [deg for num, deg in v.iteritems() if deg] # get just the degrees
4667
return arith.LCM(v)
4668
4669
##########################################################
4670
# Galois Representations
4671
##########################################################
4672
4673
def galois_representation(self):
4674
r"""
4675
The compatible family of the Galois representation
4676
attached to this elliptic curve.
4677
4678
Given an elliptic curve `E` over `\QQ`
4679
and a rational prime number `p`, the `p^n`-torsion
4680
`E[p^n]` points of `E` is a representation of the
4681
absolute Galois group of `\QQ`. As `n` varies
4682
we obtain the Tate module `T_p E` which is a
4683
a representation of `G_K` on a free `\ZZ_p`-module
4684
of rank `2`. As `p` varies the representations
4685
are compatible.
4686
4687
EXAMPLES::
4688
4689
sage: rho = EllipticCurve('11a1').galois_representation()
4690
sage: rho
4691
Compatible family of Galois representations associated to the Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
4692
sage: rho.is_irreducible(7)
4693
True
4694
sage: rho.is_irreducible(5)
4695
False
4696
sage: rho.is_surjective(11)
4697
True
4698
sage: rho.non_surjective()
4699
[5]
4700
sage: rho = EllipticCurve('37a1').galois_representation()
4701
sage: rho.non_surjective()
4702
[]
4703
sage: rho = EllipticCurve('27a1').galois_representation()
4704
sage: rho.is_irreducible(7)
4705
True
4706
sage: rho.non_surjective() # cm-curve
4707
[0]
4708
4709
"""
4710
try:
4711
return self.__rho
4712
except AttributeError:
4713
from gal_reps import GaloisRepresentation
4714
self.__rho = GaloisRepresentation(self)
4715
return self.__rho
4716
4717
# deprecated as it should be the is_reducible for a scheme (and hence return False always).
4718
def is_reducible(self, p):
4719
"""
4720
Return True if the mod-p representation attached to E is
4721
reducible.
4722
4723
Note that this function is deprecated, and that you should use
4724
galois_representation().is_reducible(p) instead as this will be
4725
disappearing in the near future.
4726
4727
EXAMPLES::
4728
4729
sage: EllipticCurve('20a1').is_reducible(3) #random
4730
doctest:1: DeprecationWarning: is_reducible is deprecated, use galois_representation().is_reducible(p) instead!
4731
True
4732
4733
"""
4734
from sage.misc.superseded import deprecation
4735
deprecation(8118, "is_reducible is deprecated, use galois_representation().is_reducible(p) instead!")
4736
return self.galois_representation().is_reducible(p)
4737
4738
# deprecated as it should be the is_irreducible for a scheme (and hence return True always).
4739
def is_irreducible(self, p):
4740
"""
4741
Return True if the mod p representation is irreducible.
4742
4743
Note that this function is deprecated, and that you should use
4744
galois_representation().is_irreducible(p) instead as this will be
4745
disappearing in the near future.
4746
4747
EXAMPLES::
4748
4749
sage: EllipticCurve('20a1').is_irreducible(7) #random
4750
doctest:1: DeprecationWarning: is_irreducible is deprecated, use galois_representation().is_irreducible(p) instead!
4751
True
4752
4753
"""
4754
from sage.misc.superseded import deprecation
4755
deprecation(8118, "is_irreducible is deprecated, use galois_representation().is_irreducible(p) instead!")
4756
return self.galois_representation().is_irreducible(p)
4757
4758
# deprecated
4759
def is_surjective(self, p, A=1000):
4760
r"""
4761
Returns true if the mod p representation is surjective
4762
4763
Note that this function is deprecated, and that you should use
4764
galois_representation().is_surjective(p) instead as this will be
4765
disappearing in the near future.
4766
4767
EXAMPLES::
4768
4769
sage: EllipticCurve('20a1').is_surjective(7) #random
4770
doctest:1: DeprecationWarning: is_surjective is deprecated, use galois_representation().is_surjective(p) instead!
4771
True
4772
4773
"""
4774
from sage.misc.superseded import deprecation
4775
deprecation(8118, "is_surjective is deprecated, use galois_representation().is_surjective(p) instead!")
4776
return self.galois_representation().is_surjective(p,A)
4777
4778
# deprecated
4779
def reducible_primes(self):
4780
r"""
4781
Returns a list of reducible primes.
4782
4783
Note that this function is deprecated, and that you should use
4784
galois_representation().reducible_primes() instead as this will be
4785
disappearing in the near future.
4786
4787
EXAMPLES::
4788
4789
sage: EllipticCurve('20a1').reducible_primes() #random
4790
doctest:1: DeprecationWarning: reducible_primes is deprecated, use galois_representation().reducible_primes() instead!
4791
[2,3]
4792
4793
"""
4794
from sage.misc.superseded import deprecation
4795
deprecation(8118, "reducible_primes is deprecated, use galois_representation().reducible_primes() instead!")
4796
return self.galois_representation().reducible_primes()
4797
4798
# deprecated
4799
def non_surjective(self, A=1000):
4800
r"""
4801
Returns a list of primes p for which the Galois representation mod p is not surjective.
4802
4803
Note that this function is deprecated, and that you should use
4804
galois_representation().non_surjective() instead as this will be
4805
disappearing in the near future.
4806
4807
EXAMPLES::
4808
4809
sage: EllipticCurve('20a1').non_surjective() #random
4810
doctest:1: DeprecationWarning: non_surjective is deprecated, use galois_representation().non_surjective() instead!
4811
[2,3]
4812
4813
"""
4814
from sage.misc.superseded import deprecation
4815
deprecation(8118, "non_surjective is deprecated, use galois_representation().non_surjective() instead!")
4816
return self.galois_representation().non_surjective()
4817
4818
def is_semistable(self):
4819
"""
4820
Return True iff this elliptic curve is semi-stable at all primes.
4821
4822
EXAMPLES::
4823
4824
sage: E=EllipticCurve('37a1')
4825
sage: E.is_semistable()
4826
True
4827
sage: E=EllipticCurve('90a1')
4828
sage: E.is_semistable()
4829
False
4830
"""
4831
return self.conductor().is_squarefree()
4832
4833
def is_ordinary(self, p, ell=None):
4834
"""
4835
Return True precisely when the mod-p representation attached to
4836
this elliptic curve is ordinary at ell.
4837
4838
INPUT:
4839
4840
- ``p`` - a prime ell - a prime (default: p)
4841
4842
OUTPUT: bool
4843
4844
EXAMPLES::
4845
4846
sage: E=EllipticCurve('37a1')
4847
sage: E.is_ordinary(37)
4848
True
4849
sage: E=EllipticCurve('32a1')
4850
sage: E.is_ordinary(2)
4851
False
4852
sage: [p for p in prime_range(50) if E.is_ordinary(p)]
4853
[5, 13, 17, 29, 37, 41]
4854
4855
"""
4856
if ell is None:
4857
ell = p
4858
return self.ap(ell) % p != 0
4859
4860
def is_good(self, p, check=True):
4861
"""
4862
Return True if `p` is a prime of good reduction for
4863
`E`.
4864
4865
INPUT:
4866
4867
- ``p`` - a prime
4868
4869
OUTPUT: bool
4870
4871
EXAMPLES::
4872
4873
sage: e = EllipticCurve('11a')
4874
sage: e.is_good(-8)
4875
Traceback (most recent call last):
4876
...
4877
ValueError: p must be prime
4878
sage: e.is_good(-8, check=False)
4879
True
4880
4881
"""
4882
if check:
4883
if not arith.is_prime(p):
4884
raise ValueError, "p must be prime"
4885
return self.conductor() % p != 0
4886
4887
4888
def is_supersingular(self, p, ell=None):
4889
"""
4890
Return True precisely when p is a prime of good reduction and the
4891
mod-p representation attached to this elliptic curve is
4892
supersingular at ell.
4893
4894
INPUT:
4895
4896
- ``p`` - a prime ell - a prime (default: p)
4897
4898
OUTPUT: bool
4899
4900
EXAMPLES::
4901
4902
sage: E=EllipticCurve('37a1')
4903
sage: E.is_supersingular(37)
4904
False
4905
sage: E=EllipticCurve('32a1')
4906
sage: E.is_supersingular(2)
4907
False
4908
sage: E.is_supersingular(7)
4909
True
4910
sage: [p for p in prime_range(50) if E.is_supersingular(p)]
4911
[3, 7, 11, 19, 23, 31, 43, 47]
4912
4913
"""
4914
if ell is None:
4915
ell = p
4916
return self.is_good(p) and not self.is_ordinary(p, ell)
4917
4918
def supersingular_primes(self, B):
4919
"""
4920
Return a list of all supersingular primes for this elliptic curve
4921
up to and possibly including B.
4922
4923
EXAMPLES::
4924
4925
sage: e = EllipticCurve('11a')
4926
sage: e.aplist(20)
4927
[-2, -1, 1, -2, 1, 4, -2, 0]
4928
sage: e.supersingular_primes(1000)
4929
[2, 19, 29, 199, 569, 809]
4930
4931
::
4932
4933
sage: e = EllipticCurve('27a')
4934
sage: e.aplist(20)
4935
[0, 0, 0, -1, 0, 5, 0, -7]
4936
sage: e.supersingular_primes(97)
4937
[2, 5, 11, 17, 23, 29, 41, 47, 53, 59, 71, 83, 89]
4938
sage: e.ordinary_primes(97)
4939
[7, 13, 19, 31, 37, 43, 61, 67, 73, 79, 97]
4940
sage: e.supersingular_primes(3)
4941
[2]
4942
sage: e.supersingular_primes(2)
4943
[2]
4944
sage: e.supersingular_primes(1)
4945
[]
4946
"""
4947
v = self.aplist(max(B, 3))
4948
P = rings.prime_range(max(B,3)+1)
4949
N = self.conductor()
4950
return [P[i] for i in [0,1] if P[i] <= B and v[i]%P[i]==0 and N%P[i] != 0] + \
4951
[P[i] for i in range(2,len(v)) if v[i] == 0 and N%P[i] != 0]
4952
4953
def ordinary_primes(self, B):
4954
"""
4955
Return a list of all ordinary primes for this elliptic curve up to
4956
and possibly including B.
4957
4958
EXAMPLES::
4959
4960
sage: e = EllipticCurve('11a')
4961
sage: e.aplist(20)
4962
[-2, -1, 1, -2, 1, 4, -2, 0]
4963
sage: e.ordinary_primes(97)
4964
[3, 5, 7, 11, 13, 17, 23, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
4965
sage: e = EllipticCurve('49a')
4966
sage: e.aplist(20)
4967
[1, 0, 0, 0, 4, 0, 0, 0]
4968
sage: e.supersingular_primes(97)
4969
[3, 5, 13, 17, 19, 31, 41, 47, 59, 61, 73, 83, 89, 97]
4970
sage: e.ordinary_primes(97)
4971
[2, 11, 23, 29, 37, 43, 53, 67, 71, 79]
4972
sage: e.ordinary_primes(3)
4973
[2]
4974
sage: e.ordinary_primes(2)
4975
[2]
4976
sage: e.ordinary_primes(1)
4977
[]
4978
"""
4979
v = self.aplist(max(B, 3) )
4980
P = rings.prime_range(max(B,3) +1)
4981
return [P[i] for i in [0,1] if P[i] <= B and v[i]%P[i]!=0] +\
4982
[P[i] for i in range(2,len(v)) if v[i] != 0]
4983
4984
def eval_modular_form(self, points, prec):
4985
"""
4986
Evaluate the modular form of this elliptic curve at points in CC
4987
4988
INPUT:
4989
4990
4991
- ``points`` - a list of points in the half-plane of
4992
convergence
4993
4994
- ``prec`` - precision
4995
4996
4997
OUTPUT: A list of values L(E,s) for s in points
4998
4999
.. note::
5000
5001
Better examples are welcome.
5002
5003
EXAMPLES::
5004
5005
sage: E=EllipticCurve('37a1')
5006
sage: E.eval_modular_form([1.5+I,2.0+I,2.5+I],0.000001)
5007
[0, 0, 0]
5008
"""
5009
if not isinstance(points, (list,xrange)):
5010
try:
5011
points = list(points)
5012
except TypeError:
5013
return self.eval_modular_form([points],prec)
5014
an = self.pari_mincurve().ellan(prec)
5015
s = 0
5016
c = pari('2 * Pi * I')
5017
ans = []
5018
for z in points:
5019
s = pari(0)
5020
r0 = (c*z).exp()
5021
r = r0
5022
for n in xrange(1,prec):
5023
s += an[n-1]*r
5024
r *= r0
5025
ans.append(s.python())
5026
return ans
5027
5028
5029
########################################################################
5030
# The Tate-Shafarevich group
5031
########################################################################
5032
5033
def sha(self):
5034
"""
5035
Return an object of class
5036
'sage.schemes.elliptic_curves.sha_tate.Sha' attached to this
5037
elliptic curve.
5038
5039
This can be used in functions related to bounding the order of Sha
5040
(The Tate-Shafarevich group of the curve).
5041
5042
EXAMPLES::
5043
5044
sage: E=EllipticCurve('37a1')
5045
sage: S=E.sha()
5046
sage: S
5047
Tate-Shafarevich group for the Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
5048
sage: S.bound_kolyvagin()
5049
([2], 1)
5050
"""
5051
try:
5052
return self.__sha
5053
except AttributeError:
5054
from sha_tate import Sha
5055
self.__sha = Sha(self)
5056
return self.__sha
5057
5058
#################################################################################
5059
# Functions related to Heegner points#################################################################################
5060
heegner_point = heegner.ell_heegner_point
5061
kolyvagin_point = heegner.kolyvagin_point
5062
5063
heegner_discriminants = heegner.ell_heegner_discriminants
5064
heegner_discriminants_list = heegner.ell_heegner_discriminants_list
5065
satisfies_heegner_hypothesis = heegner.satisfies_heegner_hypothesis
5066
5067
heegner_point_height = heegner.heegner_point_height
5068
5069
heegner_index = heegner.heegner_index
5070
_adjust_heegner_index = heegner._adjust_heegner_index
5071
heegner_index_bound = heegner.heegner_index_bound
5072
_heegner_index_in_EK = heegner._heegner_index_in_EK
5073
5074
heegner_sha_an = heegner.heegner_sha_an
5075
5076
_heegner_forms_list = heegner._heegner_forms_list
5077
_heegner_best_tau = heegner._heegner_best_tau
5078
5079
#################################################################################
5080
# p-adic functions
5081
#################################################################################
5082
5083
padic_regulator = padics.padic_regulator
5084
5085
padic_height_pairing_matrix = padics.padic_height_pairing_matrix
5086
5087
padic_height = padics.padic_height
5088
padic_height_via_multiply = padics.padic_height_via_multiply
5089
5090
padic_sigma = padics.padic_sigma
5091
padic_sigma_truncated = padics.padic_sigma_truncated
5092
5093
padic_E2 = padics.padic_E2
5094
5095
matrix_of_frobenius = padics.matrix_of_frobenius
5096
5097
# def weierstrass_p(self):
5098
# # TODO: add allowing negative valuations for power series
5099
# return 1/t**2 + a1/t + rings.frac(1,12)*(a1-8*a2) -a3*t \
5100
# - (a4+a1*a3)*t**2 + O(t**3)
5101
5102
5103
def mod5family(self):
5104
"""
5105
Return the family of all elliptic curves with the same mod-5
5106
representation as self.
5107
5108
EXAMPLES::
5109
5110
sage: E=EllipticCurve('32a1')
5111
sage: E.mod5family()
5112
Elliptic Curve defined by y^2 = x^3 + 4*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field
5113
"""
5114
E = self.short_weierstrass_model()
5115
a = E.a4()
5116
b = E.a6()
5117
return mod5family.mod5family(a,b)
5118
5119
def tate_curve(self, p):
5120
r"""
5121
Creates the Tate Curve over the `p`-adics associated to
5122
this elliptic curves.
5123
5124
This Tate curve a `p`-adic curve with split multiplicative
5125
reduction of the form `y^2+xy=x^3+s_4 x+s_6` which is
5126
isomorphic to the given curve over the algebraic closure of
5127
`\QQ_p`. Its points over `\QQ_p`
5128
are isomorphic to `\QQ_p^{\times}/q^{\ZZ}`
5129
for a certain parameter `q\in\ZZ_p`.
5130
5131
INPUT:
5132
5133
p - a prime where the curve has multiplicative reduction.
5134
5135
EXAMPLES::
5136
5137
sage: e = EllipticCurve('130a1')
5138
sage: e.tate_curve(2)
5139
2-adic Tate curve associated to the Elliptic Curve defined by y^2 + x*y + y = x^3 - 33*x + 68 over Rational Field
5140
5141
The input curve must have multiplicative reduction at the prime.
5142
5143
::
5144
5145
sage: e.tate_curve(3)
5146
Traceback (most recent call last):
5147
...
5148
ValueError: The elliptic curve must have multiplicative reduction at 3
5149
5150
We compute with `p=5`::
5151
5152
sage: T = e.tate_curve(5); T
5153
5-adic Tate curve associated to the Elliptic Curve defined by y^2 + x*y + y = x^3 - 33*x + 68 over Rational Field
5154
5155
We find the Tate parameter `q`::
5156
5157
sage: T.parameter(prec=5)
5158
3*5^3 + 3*5^4 + 2*5^5 + 2*5^6 + 3*5^7 + O(5^8)
5159
5160
We compute the `\mathcal{L}`-invariant of the curve::
5161
5162
sage: T.L_invariant(prec=10)
5163
5^3 + 4*5^4 + 2*5^5 + 2*5^6 + 2*5^7 + 3*5^8 + 5^9 + O(5^10)
5164
"""
5165
try:
5166
return self._tate_curve[p]
5167
except AttributeError:
5168
self._tate_curve = {}
5169
except KeyError:
5170
pass
5171
5172
Eq = ell_tate_curve.TateCurve(self,p)
5173
self._tate_curve[p] = Eq
5174
return Eq
5175
5176
def height(self, precision=None):
5177
"""
5178
Returns the real height of this elliptic curve. This is used in
5179
integral_points()
5180
5181
INPUT:
5182
5183
5184
- ``precision`` - desired real precision of the result
5185
(default real precision if None)
5186
5187
5188
EXAMPLES::
5189
5190
sage: E=EllipticCurve('5077a1')
5191
sage: E.height()
5192
17.4513334798896
5193
sage: E.height(100)
5194
17.451333479889612702508579399
5195
sage: E=EllipticCurve([0,0,0,0,1])
5196
sage: E.height()
5197
1.38629436111989
5198
sage: E=EllipticCurve([0,0,0,1,0])
5199
sage: E.height()
5200
7.45471994936400
5201
"""
5202
if precision is None:
5203
precision = RealField().precision()
5204
R = RealField(precision)
5205
c4 = self.c4()
5206
c6 = self.c6()
5207
j = self.j_invariant()
5208
log_g2 = R((c4/12)).abs().log()
5209
log_g3 = R((c6/216)).abs().log()
5210
5211
if j == 0:
5212
h_j = R(1)
5213
else:
5214
h_j = max(log(R(abs(j.numerator()))), log(R(abs(j.denominator()))))
5215
if (self.c4() != 0) and (self.c6() != 0):
5216
h_gs = max(1, log_g2, log_g3)
5217
elif c4 == 0:
5218
if c6 == 0:
5219
return max(1,h_j)
5220
h_gs = max(1, log_g3)
5221
else:
5222
h_gs = max(1, log_g2)
5223
return max(R(1),h_j, h_gs)
5224
5225
def antilogarithm(self, z, max_denominator=None):
5226
r"""
5227
Returns the rational point (if any) associated to this complex
5228
number; the inverse of the elliptic logarithm function.
5229
5230
INPUT:
5231
5232
- ``z`` -- a complex number representing an element of
5233
`\CC/L` where `L` is the period lattice of the elliptic curve
5234
5235
- ``max_denominator`` (int or None) -- parameter controlling
5236
the attempted conversion of real numbers to rationals. If
5237
None, ``simplest_rational()`` will be used; otherwise,
5238
``nearby_rational()`` will be used with this value of
5239
``max_denominator``.
5240
5241
OUTPUT:
5242
5243
- point on the curve: the rational point which is the
5244
image of `z` under the Weierstrass parametrization, if it
5245
exists and can be determined from `z` and the given value
5246
of max_denominator (if any); otherwise a ValueError exception
5247
is raised.
5248
5249
EXAMPLES::
5250
5251
sage: E = EllipticCurve('389a')
5252
sage: P = E(-1,1)
5253
sage: z = P.elliptic_logarithm()
5254
sage: E.antilogarithm(z)
5255
(-1 : 1 : 1)
5256
sage: Q = E(0,-1)
5257
sage: z = Q.elliptic_logarithm()
5258
sage: E.antilogarithm(z)
5259
Traceback (most recent call last):
5260
...
5261
ValueError: approximated point not on the curve
5262
sage: E.antilogarithm(z, max_denominator=10)
5263
(0 : -1 : 1)
5264
5265
sage: E = EllipticCurve('11a1')
5266
sage: w1,w2 = E.period_lattice().basis()
5267
sage: [E.antilogarithm(a*w1/5,1) for a in range(5)]
5268
[(0 : 1 : 0), (16 : -61 : 1), (5 : -6 : 1), (5 : 5 : 1), (16 : 60 : 1)]
5269
"""
5270
if z.is_zero():
5271
return self(0)
5272
expZ = self.elliptic_exponential(z)
5273
xy = [t.real() for t in expZ[:2]]
5274
if max_denominator is None:
5275
xy = [t.simplest_rational() for t in xy]
5276
else:
5277
xy = [t.nearby_rational(max_denominator=max_denominator) for t in xy]
5278
try:
5279
return self(xy)
5280
except TypeError:
5281
raise ValueError, "approximated point not on the curve"
5282
5283
def integral_x_coords_in_interval(self,xmin,xmax):
5284
r"""
5285
Returns the set of integers `x` with `xmin\le x\le xmax` which are
5286
`x`-coordinates of rational points on this curve.
5287
5288
INPUT:
5289
5290
- ``xmin``, ``xmax`` (integers) -- two integers.
5291
5292
OUTPUT:
5293
5294
(set) The set of integers `x` with `xmin\le x\le xmax` which
5295
are `x`-coordinates of rational points on the elliptic curve.
5296
5297
EXAMPLES::
5298
5299
sage: E = EllipticCurve([0, 0, 1, -7, 6])
5300
sage: xset = E.integral_x_coords_in_interval(-100,100)
5301
sage: xlist = list(xset); xlist.sort(); xlist
5302
[-3, -2, -1, 0, 1, 2, 3, 4, 8, 11, 14, 21, 37, 52, 93]
5303
"""
5304
from sage.libs.ratpoints import ratpoints
5305
xmin=Integer(xmin)
5306
xmax=Integer(xmax)
5307
coeffs = self.division_polynomial(2).coeffs()
5308
H = max(xmin.abs(), xmax.abs())
5309
return set([x for x,y,z in ratpoints(coeffs, H, max_x_denom=1, intervals=[[xmin,xmax]]) if z])
5310
5311
prove_BSD = BSD.prove_BSD
5312
5313
def integral_points(self, mw_base='auto', both_signs=False, verbose=False):
5314
"""
5315
Computes all integral points (up to sign) on this elliptic curve.
5316
5317
INPUT:
5318
5319
5320
- ``mw_base`` - list of EllipticCurvePoint generating
5321
the Mordell-Weil group of E (default: 'auto' - calls self.gens())
5322
5323
- ``both_signs`` - True/False (default False): if
5324
True the output contains both P and -P, otherwise only one of each
5325
pair.
5326
5327
- ``verbose`` - True/False (default False): if True,
5328
some details of the computation are output
5329
5330
5331
OUTPUT: A sorted list of all the integral points on E (up to sign
5332
unless both_signs is True)
5333
5334
.. note::
5335
5336
The complexity increases exponentially in the rank of curve
5337
E. The computation time (but not the output!) depends on
5338
the Mordell-Weil basis. If mw_base is given but is not a
5339
basis for the Mordell-Weil group (modulo torsion), integral
5340
points which are not in the subgroup generated by the given
5341
points will almost certainly not be listed.
5342
5343
EXAMPLES: A curve of rank 3 with no torsion points
5344
5345
::
5346
5347
sage: E=EllipticCurve([0,0,1,-7,6])
5348
sage: P1=E.point((2,0)); P2=E.point((-1,3)); P3=E.point((4,6))
5349
sage: a=E.integral_points([P1,P2,P3]); a
5350
[(-3 : 0 : 1), (-2 : 3 : 1), (-1 : 3 : 1), (0 : 2 : 1), (1 : 0 : 1), (2 : 0 : 1), (3 : 3 : 1), (4 : 6 : 1), (8 : 21 : 1), (11 : 35 : 1), (14 : 51 : 1), (21 : 95 : 1), (37 : 224 : 1), (52 : 374 : 1), (93 : 896 : 1), (342 : 6324 : 1), (406 : 8180 : 1), (816 : 23309 : 1)]
5351
5352
::
5353
5354
sage: a = E.integral_points([P1,P2,P3], verbose=True)
5355
Using mw_basis [(2 : 0 : 1), (3 : -4 : 1), (8 : -22 : 1)]
5356
e1,e2,e3: -3.0124303725933... 1.0658205476962... 1.94660982489710
5357
Minimal eigenvalue of height pairing matrix: 0.63792081458500...
5358
x-coords of points on compact component with -3 <=x<= 1
5359
[-3, -2, -1, 0, 1]
5360
x-coords of points on non-compact component with 2 <=x<= 6
5361
[2, 3, 4]
5362
starting search of remaining points using coefficient bound 5
5363
x-coords of extra integral points:
5364
[2, 3, 4, 8, 11, 14, 21, 37, 52, 93, 342, 406, 816]
5365
Total number of integral points: 18
5366
5367
It is not necessary to specify mw_base; if it is not provided,
5368
then the Mordell-Weil basis must be computed, which may take
5369
much longer.
5370
5371
::
5372
5373
sage: E=EllipticCurve([0,0,1,-7,6])
5374
sage: a=E.integral_points(both_signs=True); a
5375
[(-3 : -1 : 1), (-3 : 0 : 1), (-2 : -4 : 1), (-2 : 3 : 1), (-1 : -4 : 1), (-1 : 3 : 1), (0 : -3 : 1), (0 : 2 : 1), (1 : -1 : 1), (1 : 0 : 1), (2 : -1 : 1), (2 : 0 : 1), (3 : -4 : 1), (3 : 3 : 1), (4 : -7 : 1), (4 : 6 : 1), (8 : -22 : 1), (8 : 21 : 1), (11 : -36 : 1), (11 : 35 : 1), (14 : -52 : 1), (14 : 51 : 1), (21 : -96 : 1), (21 : 95 : 1), (37 : -225 : 1), (37 : 224 : 1), (52 : -375 : 1), (52 : 374 : 1), (93 : -897 : 1), (93 : 896 : 1), (342 : -6325 : 1), (342 : 6324 : 1), (406 : -8181 : 1), (406 : 8180 : 1), (816 : -23310 : 1), (816 : 23309 : 1)]
5376
5377
An example with negative discriminant::
5378
5379
sage: EllipticCurve('900d1').integral_points()
5380
[(-11 : 27 : 1), (-4 : 34 : 1), (4 : 18 : 1), (16 : 54 : 1)]
5381
5382
Another example with rank 5 and no torsion points::
5383
5384
sage: E=EllipticCurve([-879984,319138704])
5385
sage: P1=E.point((540,1188)); P2=E.point((576,1836))
5386
sage: P3=E.point((468,3132)); P4=E.point((612,3132))
5387
sage: P5=E.point((432,4428))
5388
sage: a=E.integral_points([P1,P2,P3,P4,P5]); len(a) # long time (18s on sage.math, 2011)
5389
54
5390
5391
TESTS:
5392
5393
The bug reported on trac #4525 is now fixed::
5394
5395
sage: EllipticCurve('91b1').integral_points()
5396
[(-1 : 3 : 1), (1 : 0 : 1), (3 : 4 : 1)]
5397
5398
::
5399
5400
sage: [len(e.integral_points(both_signs=False)) for e in cremona_curves([11..100])] # long time (15s on sage.math, 2011)
5401
[2, 0, 2, 3, 2, 1, 3, 0, 2, 4, 2, 4, 3, 0, 0, 1, 2, 1, 2, 0, 2, 1, 0, 1, 3, 3, 1, 1, 4, 2, 3, 2, 0, 0, 5, 3, 2, 2, 1, 1, 1, 0, 1, 3, 0, 1, 0, 1, 1, 3, 6, 1, 2, 2, 2, 0, 0, 2, 3, 1, 2, 2, 1, 1, 0, 3, 2, 1, 0, 1, 0, 1, 3, 3, 1, 1, 5, 1, 0, 1, 1, 0, 1, 2, 0, 2, 0, 1, 1, 3, 1, 2, 2, 4, 4, 2, 1, 0, 0, 5, 1, 0, 1, 2, 0, 2, 2, 0, 0, 0, 1, 0, 3, 1, 5, 1, 2, 4, 1, 0, 1, 0, 1, 0, 1, 0, 2, 2, 0, 0, 1, 0, 1, 1, 4, 1, 0, 1, 1, 0, 4, 2, 0, 1, 1, 2, 3, 1, 1, 1, 1, 6, 2, 1, 1, 0, 2, 0, 6, 2, 0, 4, 2, 2, 0, 0, 1, 2, 0, 2, 1, 0, 3, 1, 2, 1, 4, 6, 3, 2, 1, 0, 2, 2, 0, 0, 5, 4, 1, 0, 0, 1, 0, 2, 2, 0, 0, 2, 3, 1, 3, 1, 1, 0, 1, 0, 0, 1, 2, 2, 0, 2, 0, 0, 1, 2, 0, 0, 4, 1, 0, 1, 1, 0, 1, 2, 0, 1, 4, 3, 1, 2, 2, 1, 1, 1, 1, 6, 3, 3, 3, 3, 1, 1, 1, 1, 1, 0, 7, 3, 0, 1, 3, 2, 1, 0, 3, 2, 1, 0, 2, 2, 6, 0, 0, 6, 2, 2, 3, 3, 5, 5, 1, 0, 6, 1, 0, 3, 1, 1, 2, 3, 1, 2, 1, 1, 0, 1, 0, 1, 0, 5, 5, 2, 2, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1]
5402
5403
The bug reported at #4897 is now fixed::
5404
5405
sage: [P[0] for P in EllipticCurve([0,0,0,-468,2592]).integral_points()]
5406
[-24, -18, -14, -6, -3, 4, 6, 18, 21, 24, 36, 46, 102, 168, 186, 381, 1476, 2034, 67246]
5407
5408
.. note::
5409
5410
This function uses the algorithm given in [Co1].
5411
5412
REFERENCES:
5413
5414
- [Co1] Cohen H., Number Theory Vol I: Tools and Diophantine
5415
Equations GTM 239, Springer 2007
5416
5417
AUTHORS:
5418
5419
- Michael Mardaus (2008-07)
5420
5421
- Tobias Nagel (2008-07)
5422
5423
- John Cremona (2008-07)
5424
"""
5425
#####################################################################
5426
# INPUT CHECK #######################################################
5427
if not self.is_integral():
5428
raise ValueError, "integral_points() can only be called on an integral model"
5429
5430
if mw_base=='auto':
5431
mw_base = self.gens()
5432
r = len(mw_base)
5433
else:
5434
try:
5435
r = len(mw_base)
5436
except TypeError:
5437
raise TypeError, 'mw_base must be a list'
5438
if not all([P.curve() is self for P in mw_base]):
5439
raise ValueError, "points are not on the correct curve"
5440
5441
tors_points = self.torsion_points()
5442
5443
# END INPUT-CHECK####################################################
5444
#####################################################################
5445
5446
#####################################################################
5447
# INTERNAL FUNCTIONS ################################################
5448
5449
############################## begin ################################
5450
def point_preprocessing(free,tor):
5451
r"""
5452
Transforms the mw_basis ``free`` into a `\ZZ`-basis for
5453
`E(\QQ)\cap E^0(`\RR)`. If there is a torsion point on the
5454
"egg" we add it to any of the gens on the egg; otherwise
5455
we replace the free generators with generators of a
5456
subgroup of index 2.
5457
"""
5458
r = len(free)
5459
newfree = [Q for Q in free] # copy
5460
tor_egg = [T for T in tor if not T.is_on_identity_component()]
5461
free_id = [P.is_on_identity_component() for P in free]
5462
if any(tor_egg):
5463
T = tor_egg[0]
5464
for i in range(r):
5465
if not free_id[i]:
5466
newfree[i] += T
5467
else:
5468
if not all(free_id):
5469
i0 = free_id.index(False)
5470
P = free[i0]
5471
for i in range(r):
5472
if not free_id[i]:
5473
if i==i0:
5474
newfree[i] = 2*newfree[i]
5475
else:
5476
newfree[i] += P
5477
return newfree
5478
############################## end ################################
5479
5480
# END Internal functions #############################################
5481
######################################################################
5482
5483
if (r == 0):
5484
int_points = [P for P in tors_points if not P.is_zero()]
5485
int_points = [P for P in int_points if P[0].is_integral()]
5486
if not both_signs:
5487
xlist = set([P[0] for P in int_points])
5488
int_points = [self.lift_x(x) for x in xlist]
5489
int_points.sort()
5490
if verbose:
5491
print 'Total number of integral points:',len(int_points)
5492
return int_points
5493
5494
if verbose:
5495
import sys # so we can flush stdout for debugging
5496
5497
g2 = self.c4()/12
5498
g3 = self.c6()/216
5499
disc = self.discriminant()
5500
j = self.j_invariant()
5501
b2 = self.b2()
5502
5503
Qx = rings.PolynomialRing(RationalField(),'x')
5504
pol = Qx([-self.c6()/216,-self.c4()/12,0,4])
5505
if disc > 0: # two real component -> 3 roots in RR
5506
#on curve 897e4, only one root is found with default precision!
5507
RR = R
5508
prec = RR.precision()
5509
ei = pol.roots(RR,multiplicities=False)
5510
while len(ei)<3:
5511
prec*=2
5512
RR=RealField(prec)
5513
ei = pol.roots(RR,multiplicities=False)
5514
e1,e2,e3 = ei
5515
if r >= 1: #preprocessing of mw_base only necessary if rank > 0
5516
mw_base = point_preprocessing(mw_base, tors_points)
5517
#at most one point in E^{egg}
5518
5519
elif disc < 0: # one real component => 1 root in RR (=: e3),
5520
# 2 roots in C (e1,e2)
5521
roots = pol.roots(C,multiplicities=False)
5522
e3 = pol.roots(R,multiplicities=False)[0]
5523
roots.remove(e3)
5524
e1,e2 = roots
5525
5526
from sage.all import pi
5527
e = R(1).exp()
5528
pi = R(pi)
5529
5530
M = self.height_pairing_matrix(mw_base)
5531
mw_base, U = self.lll_reduce(mw_base,M)
5532
M = U.transpose()*M*U
5533
5534
if verbose:
5535
print "Using mw_basis ",mw_base
5536
print "e1,e2,e3: ",e1,e2,e3
5537
sys.stdout.flush()
5538
5539
# Algorithm presented in [Co1]
5540
h_E = self.height()
5541
w1, w2 = self.period_lattice().basis()
5542
mu = R(disc).abs().log() / 6
5543
if j!=0:
5544
mu += max(R(1),R(j).abs().log()) / 6
5545
if b2!=0:
5546
mu += max(R(1),R(b2).abs().log())
5547
mu += log(R(2))
5548
else:
5549
mu += 1
5550
5551
c1 = (mu + 2.14).exp()
5552
c2 = min(M.charpoly ().roots(multiplicities=False))
5553
if verbose:
5554
print "Minimal eigenvalue of height pairing matrix: ", c2
5555
sys.stdout.flush()
5556
5557
c3 = (w1**2)*R(b2).abs()/48 + 8
5558
c5 = (c1*c3).sqrt()
5559
c7 = abs((3*pi)/((w1**2) * (w1/w2).imag()))
5560
5561
mw_base_log = [] #contains \Phi(Q_i)
5562
mod_h_list = [] #contains h_m(Q_i)
5563
c9_help_list = []
5564
for i in range(0,r):
5565
mw_base_log.append(mw_base[i].elliptic_logarithm().abs())
5566
mod_h_list.append(max(mw_base[i].height(),h_E,c7*mw_base_log[i]**2))
5567
c9_help_list.append((mod_h_list[i]).sqrt()/mw_base_log[i])
5568
c8 = max(e*h_E,max(mod_h_list))
5569
c9 = e/c7.sqrt() * min(c9_help_list)
5570
n=r+1
5571
c10 = R(2 * 10**(8+7*n) * R((2/e)**(2 * n**2)) * (n+1)**(4 * n**2 + 10 * n) * log(c9)**(-2*n - 1) * misc.prod(mod_h_list))
5572
5573
top = Z(128) #arbitrary first upper bound
5574
bottom = Z(0)
5575
log_c9=log(c9); log_c5=log(c5)
5576
log_r_top = log(R(r*(10**top)))
5577
# if verbose:
5578
# print "[bottom,top] = ",[bottom,top]
5579
5580
while R(c10*(log_r_top+log_c9)*(log(log_r_top)+h_E+log_c9)**(n+1)) > R(c2/2 * (10**top)**2 - log_c5):
5581
#initial bound 'top' too small, upshift of search interval
5582
bottom = top
5583
top = 2*top
5584
while top >= bottom: #binary-search like search for fitting exponent (bound)
5585
# if verbose:
5586
# print "[bottom,top] = ",[bottom,top]
5587
bound = (bottom + (top - bottom)/2).floor()
5588
log_r_bound = log(R(r*(10**bound)))
5589
if R(c10*(log_r_bound+log_c9)*(log(log_r_bound)+h_E+log_c9)**(n+1)) > R(c2/2 * (10**bound)**2 - log_c5):
5590
bottom = bound + 1
5591
else:
5592
top = bound - 1
5593
5594
H_q = R(10)**bound
5595
break_cond = 0 #at least one reduction step
5596
#reduction via LLL
5597
M = matrix.MatrixSpace(Z,n)
5598
while break_cond < 0.9: #as long as the improvement of the new bound in comparison to the old is greater than 10%
5599
c = R((H_q**n)*10) #c has to be greater than H_q^n
5600
m = copy(M.identity_matrix())
5601
for i in range(r):
5602
m[i, r] = R(c*mw_base_log[i]).round()
5603
m[r,r] = max(Z(1),R(c*w1).round()) #ensures that m isn't singular
5604
5605
#LLL - implemented in sage - operates on rows not on columns
5606
m_LLL = m.LLL()
5607
m_gram = m_LLL.gram_schmidt()[0]
5608
b1_norm = R(m_LLL.row(0).norm())
5609
5610
#compute constant c1 ~ c1_LLL of Corollary 2.3.17 and hence d(L,0)^2 ~ d_L_0
5611
c1_LLL = -1
5612
for i in range(n):
5613
tmp = R(b1_norm/(m_gram.row(i).norm()))
5614
if tmp > c1_LLL:
5615
c1_LLL = tmp
5616
5617
if c1_LLL < 0:
5618
raise RuntimeError, 'Unexpected intermediate result. Please try another Mordell-Weil base'
5619
5620
d_L_0 = R(b1_norm**2 / c1_LLL)
5621
5622
#Reducing of upper bound
5623
Q = r * H_q**2
5624
T = (1 + (3/2*r*H_q))/2
5625
if d_L_0 < R(T**2+Q):
5626
d_L_0 = 10*(T**2*Q)
5627
low_bound = R(((d_L_0 - Q).sqrt() - T)/c)
5628
5629
#new bound according to low_bound and upper bound
5630
#[c_5 exp((-c_2*H_q^2)/2)] provided by Corollary 8.7.3
5631
if low_bound != 0:
5632
H_q_new = R((log(low_bound/c5)/(-c2/2))).sqrt()
5633
H_q_new = H_q_new.ceil()
5634
if H_q_new == 1:
5635
break_cond = 1 # stops reduction
5636
else:
5637
break_cond = R(H_q_new/H_q)
5638
H_q = H_q_new
5639
else:
5640
break_cond = 1 # stops reduction, so using last H_q > 0
5641
#END LLL-Reduction loop
5642
5643
b2_12 = b2/12
5644
if disc > 0:
5645
##Points in egg have X(P) between e1 and e2 [X(P)=x(P)+b2/12]:
5646
x_int_points = self.integral_x_coords_in_interval((e1-b2_12).ceil(), (e2-b2_12).floor())
5647
if verbose:
5648
print 'x-coords of points on compact component with ',(e1-b2_12).ceil(),'<=x<=',(e2-b2_12).floor()
5649
L = list(x_int_points) # to have the order
5650
L.sort() # deterministic for doctests!
5651
print L
5652
sys.stdout.flush()
5653
else:
5654
x_int_points = set()
5655
5656
##Points in noncompact component with X(P)< 2*max(|e1|,|e2|,|e3|) , espec. X(P)>=e3
5657
x0 = (e3-b2_12).ceil()
5658
x1 = (2*max(abs(e1),abs(e2),abs(e3)) - b2_12).ceil()
5659
x_int_points2 = self.integral_x_coords_in_interval(x0, x1)
5660
x_int_points = x_int_points.union(x_int_points2)
5661
if verbose:
5662
print 'x-coords of points on non-compact component with ',x0,'<=x<=',x1-1
5663
L = list(x_int_points2)
5664
L.sort()
5665
print L
5666
sys.stdout.flush()
5667
5668
if verbose:
5669
print 'starting search of remaining points using coefficient bound ',H_q
5670
sys.stdout.flush()
5671
x_int_points3 = integral_points_with_bounded_mw_coeffs(self,mw_base,H_q)
5672
x_int_points = x_int_points.union(x_int_points3)
5673
if verbose:
5674
print 'x-coords of extra integral points:'
5675
L = list(x_int_points3)
5676
L.sort()
5677
print L
5678
sys.stdout.flush()
5679
5680
if len(tors_points)>1:
5681
x_int_points_t = set()
5682
for x in x_int_points:
5683
P = self.lift_x(x)
5684
for T in tors_points:
5685
Q = P+T
5686
if not Q.is_zero() and Q[0].is_integral():
5687
x_int_points_t = x_int_points_t.union([Q[0]])
5688
x_int_points = x_int_points.union(x_int_points_t)
5689
5690
# Now we have all the x-coordinates of integral points, and we
5691
# construct the points, depending on the parameter both_signs:
5692
if both_signs:
5693
int_points = sum([self.lift_x(x,all=True) for x in x_int_points],[])
5694
else:
5695
int_points = [self.lift_x(x) for x in x_int_points]
5696
int_points.sort()
5697
if verbose:
5698
print 'Total number of integral points:',len(int_points)
5699
return int_points
5700
5701
def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, proof=None):
5702
"""
5703
Computes all S-integral points (up to sign) on this elliptic curve.
5704
5705
INPUT:
5706
5707
- ``S`` - list of primes
5708
5709
- ``mw_base`` - list of EllipticCurvePoint generating the
5710
Mordell-Weil group of E (default: 'auto' - calls
5711
:meth:`.gens`)
5712
5713
- ``both_signs`` - True/False (default False): if True the
5714
output contains both P and -P, otherwise only one of each
5715
pair.
5716
5717
- ``verbose`` - True/False (default False): if True, some
5718
details of the computation are output.
5719
5720
- ``proof`` - True/False (default True): if True ALL
5721
S-integral points will be returned. If False, the MW basis
5722
will be computed with the proof=False flag, and also the
5723
time-consuming final call to
5724
S_integral_x_coords_with_abs_bounded_by(abs_bound) is
5725
omitted. Use this only if the computation takes too long,
5726
but be warned that then it cannot be guaranteed that all
5727
S-integral points will be found.
5728
5729
OUTPUT:
5730
5731
A sorted list of all the S-integral points on E (up to sign
5732
unless both_signs is True)
5733
5734
.. note::
5735
5736
The complexity increases exponentially in the rank of curve
5737
E and in the length of S. The computation time (but not
5738
the output!) depends on the Mordell-Weil basis. If mw_base
5739
is given but is not a basis for the Mordell-Weil group
5740
(modulo torsion), S-integral points which are not in the
5741
subgroup generated by the given points will almost
5742
certainly not be listed.
5743
5744
EXAMPLES:
5745
5746
A curve of rank 3 with no torsion points::
5747
5748
sage: E=EllipticCurve([0,0,1,-7,6])
5749
sage: P1=E.point((2,0)); P2=E.point((-1,3)); P3=E.point((4,6))
5750
sage: a=E.S_integral_points(S=[2,3], mw_base=[P1,P2,P3], verbose=True);a
5751
max_S: 3 len_S: 3 len_tors: 1
5752
lambda 0.485997517468...
5753
k1,k2,k3,k4 6.68597129142710e234 1.31952866480763 3.31908110593519e9 2.42767548272846e17
5754
p= 2 : trying with p_prec = 30
5755
mw_base_p_log_val = [2, 2, 1]
5756
min_psi = 2 + 2^3 + 2^6 + 2^7 + 2^8 + 2^9 + 2^11 + 2^12 + 2^13 + 2^16 + 2^17 + 2^19 + 2^20 + 2^21 + 2^23 + 2^24 + 2^28 + O(2^30)
5757
p= 3 : trying with p_prec = 30
5758
mw_base_p_log_val = [1, 2, 1]
5759
min_psi = 3 + 3^2 + 2*3^3 + 3^6 + 2*3^7 + 2*3^8 + 3^9 + 2*3^11 + 2*3^12 + 2*3^13 + 3^15 + 2*3^16 + 3^18 + 2*3^19 + 2*3^22 + 2*3^23 + 2*3^24 + 2*3^27 + 3^28 + 3^29 + O(3^30)
5760
mw_base [(1 : -1 : 1), (2 : 0 : 1), (0 : -3 : 1)]
5761
mw_base_log [0.667789378224099, 0.552642660712417, 0.818477222895703]
5762
mp [5, 7]
5763
mw_base_p_log [[2^2 + 2^3 + 2^6 + 2^7 + 2^8 + 2^9 + 2^14 + 2^15 + 2^18 + 2^19 + 2^24 + 2^29 + O(2^30), 2^2 + 2^3 + 2^5 + 2^6 + 2^9 + 2^11 + 2^12 + 2^14 + 2^15 + 2^16 + 2^18 + 2^20 + 2^22 + 2^23 + 2^26 + 2^27 + 2^29 + O(2^30), 2 + 2^3 + 2^6 + 2^7 + 2^8 + 2^9 + 2^11 + 2^12 + 2^13 + 2^16 + 2^17 + 2^19 + 2^20 + 2^21 + 2^23 + 2^24 + 2^28 + O(2^30)], [2*3^2 + 2*3^5 + 2*3^6 + 2*3^7 + 3^8 + 3^9 + 2*3^10 + 3^12 + 2*3^14 + 3^15 + 3^17 + 2*3^19 + 2*3^23 + 3^25 + 3^28 + O(3^30), 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^6 + 2*3^7 + 2*3^8 + 3^10 + 2*3^12 + 3^13 + 2*3^14 + 3^15 + 3^18 + 3^22 + 3^25 + 2*3^26 + 3^27 + 3^28 + O(3^30), 3 + 3^2 + 2*3^3 + 3^6 + 2*3^7 + 2*3^8 + 3^9 + 2*3^11 + 2*3^12 + 2*3^13 + 3^15 + 2*3^16 + 3^18 + 2*3^19 + 2*3^22 + 2*3^23 + 2*3^24 + 2*3^27 + 3^28 + 3^29 + O(3^30)]]
5764
k5,k6,k7 0.321154513240... 1.55246328915... 0.161999172489...
5765
initial bound 2.6227097483365...e117
5766
bound_list [58, 58, 58]
5767
bound_list [8, 9, 9]
5768
bound_list [8, 7, 7]
5769
bound_list [8, 7, 7]
5770
starting search of points using coefficient bound 8
5771
x-coords of S-integral points via linear combination of mw_base and torsion:
5772
[-3, -26/9, -8159/2916, -2759/1024, -151/64, -1343/576, -2, -7/4, -1, -47/256, 0, 1/4, 4/9, 9/16, 58/81, 7/9, 6169/6561, 1, 17/16, 2, 33/16, 172/81, 9/4, 25/9, 3, 31/9, 4, 25/4, 1793/256, 8, 625/64, 11, 14, 21, 37, 52, 6142/81, 93, 4537/36, 342, 406, 816, 207331217/4096]
5773
starting search of extra S-integer points with absolute value bounded by 3.89321964979420
5774
x-coords of points with bounded absolute value
5775
[-3, -2, -1, 0, 1, 2]
5776
Total number of S-integral points: 43
5777
[(-3 : 0 : 1), (-26/9 : 28/27 : 1), (-8159/2916 : 233461/157464 : 1), (-2759/1024 : 60819/32768 : 1), (-151/64 : 1333/512 : 1), (-1343/576 : 36575/13824 : 1), (-2 : 3 : 1), (-7/4 : 25/8 : 1), (-1 : 3 : 1), (-47/256 : 9191/4096 : 1), (0 : 2 : 1), (1/4 : 13/8 : 1), (4/9 : 35/27 : 1), (9/16 : 69/64 : 1), (58/81 : 559/729 : 1), (7/9 : 17/27 : 1), (6169/6561 : 109871/531441 : 1), (1 : 0 : 1), (17/16 : -25/64 : 1), (2 : 0 : 1), (33/16 : 17/64 : 1), (172/81 : 350/729 : 1), (9/4 : 7/8 : 1), (25/9 : 64/27 : 1), (3 : 3 : 1), (31/9 : 116/27 : 1), (4 : 6 : 1), (25/4 : 111/8 : 1), (1793/256 : 68991/4096 : 1), (8 : 21 : 1), (625/64 : 14839/512 : 1), (11 : 35 : 1), (14 : 51 : 1), (21 : 95 : 1), (37 : 224 : 1), (52 : 374 : 1), (6142/81 : 480700/729 : 1), (93 : 896 : 1), (4537/36 : 305425/216 : 1), (342 : 6324 : 1), (406 : 8180 : 1), (816 : 23309 : 1), (207331217/4096 : 2985362173625/262144 : 1)]
5778
5779
It is not necessary to specify mw_base; if it is not provided,
5780
then the Mordell-Weil basis must be computed, which may take
5781
much longer.
5782
5783
::
5784
5785
sage: a = E.S_integral_points([2,3])
5786
sage: len(a)
5787
43
5788
5789
An example with negative discriminant::
5790
5791
sage: EllipticCurve('900d1').S_integral_points([17], both_signs=True)
5792
[(-11 : -27 : 1), (-11 : 27 : 1), (-4 : -34 : 1), (-4 : 34 : 1), (4 : -18 : 1), (4 : 18 : 1), (2636/289 : -98786/4913 : 1), (2636/289 : 98786/4913 : 1), (16 : -54 : 1), (16 : 54 : 1)]
5793
5794
Output checked with Magma (corrected in 3 cases)::
5795
5796
sage: [len(e.S_integral_points([2], both_signs=False)) for e in cremona_curves([11..100])] # long time (17s on sage.math, 2011)
5797
[2, 0, 2, 3, 3, 1, 3, 1, 3, 5, 3, 5, 4, 1, 1, 2, 2, 2, 3, 1, 2, 1, 0, 1, 3, 3, 1, 1, 5, 3, 4, 2, 1, 1, 5, 3, 2, 2, 1, 1, 1, 0, 1, 3, 0, 1, 0, 1, 1, 3, 7, 1, 3, 3, 3, 1, 1, 2, 3, 1, 2, 3, 1, 2, 1, 3, 3, 1, 1, 1, 0, 1, 3, 3, 1, 1, 7, 1, 0, 1, 1, 0, 1, 2, 0, 3, 1, 2, 1, 3, 1, 2, 2, 4, 5, 3, 2, 1, 1, 6, 1, 0, 1, 3, 1, 3, 3, 1, 1, 1, 1, 1, 3, 1, 5, 1, 2, 4, 1, 1, 1, 1, 1, 0, 1, 0, 2, 2, 0, 0, 1, 0, 1, 1, 6, 1, 0, 1, 1, 0, 4, 3, 1, 2, 1, 2, 3, 1, 1, 1, 1, 8, 3, 1, 2, 1, 2, 0, 8, 2, 0, 6, 2, 3, 1, 1, 1, 3, 1, 3, 2, 1, 3, 1, 2, 1, 6, 9, 3, 3, 1, 1, 2, 3, 1, 1, 5, 5, 1, 1, 0, 1, 1, 2, 3, 1, 1, 2, 3, 1, 3, 1, 1, 1, 1, 0, 0, 1, 3, 3, 1, 3, 1, 1, 2, 2, 0, 0, 6, 1, 0, 1, 1, 1, 1, 3, 1, 2, 6, 3, 1, 2, 2, 1, 1, 1, 1, 7, 5, 4, 3, 3, 1, 1, 1, 1, 1, 1, 8, 5, 1, 1, 3, 3, 1, 1, 3, 3, 1, 1, 2, 3, 6, 1, 1, 7, 3, 3, 4, 5, 9, 6, 1, 0, 7, 1, 1, 3, 1, 1, 2, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 7, 8, 2, 3, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1]
5798
5799
An example from [PZGH]::
5800
5801
sage: E = EllipticCurve([0,0,0,-172,505])
5802
sage: E.rank(), len(E.S_integral_points([3,5,7])) # long time (5s on sage.math, 2011)
5803
(4, 72)
5804
5805
This is curve "7690e1" which failed until \#4805 was fixed::
5806
5807
sage: EllipticCurve([1,1,1,-301,-1821]).S_integral_points([13,2])
5808
[(-13 : 16 : 1),
5809
(-9 : 20 : 1),
5810
(-7 : 4 : 1),
5811
(21 : 30 : 1),
5812
(23 : 52 : 1),
5813
(63 : 452 : 1),
5814
(71 : 548 : 1),
5815
(87 : 756 : 1),
5816
(2711 : 139828 : 1),
5817
(7323 : 623052 : 1),
5818
(17687 : 2343476 : 1)]
5819
5820
REFERENCES:
5821
5822
- [PZGH] Petho A., Zimmer H.G., Gebel J. and Herrmann E.,
5823
Computing all S-integral points on elliptic curves
5824
Math. Proc. Camb. Phil. Soc. (1999), 127, 383-402
5825
5826
- Some parts of this implementation are partially based on the
5827
function integral_points()
5828
5829
AUTHORS:
5830
5831
- Tobias Nagel (2008-12)
5832
5833
- Michael Mardaus (2008-12)
5834
5835
- John Cremona (2008-12)
5836
"""
5837
# INPUT CHECK #######################################################
5838
5839
if proof is None:
5840
from sage.structure.proof.proof import get_flag
5841
proof = get_flag(proof, "elliptic_curve")
5842
else:
5843
proof = bool(proof)
5844
5845
5846
if not self.is_integral():
5847
raise ValueError, "S_integral_points() can only be called on an integral model"
5848
if not all([self.is_p_minimal(s) for s in S]):
5849
raise ValueError, "%s must be p-minimal for all primes in S"%self
5850
5851
try:
5852
len_S = len(S)
5853
if len_S == 0:
5854
return self.integral_points(mw_base, both_signs, verbose)
5855
if not all([s.is_prime() for s in S]):
5856
raise ValueError, "All elements of S must be prime"
5857
S.sort()
5858
except TypeError:
5859
raise TypeError, 'S must be a list of primes'
5860
except AttributeError:#catches: <tuple>.sort(), <!ZZ>.is_prime()
5861
raise AttributeError,'S must be a list of primes'
5862
5863
if mw_base=='auto':
5864
if verbose:
5865
print "Starting computation of MW basis"
5866
mw_base = self.gens(proof=proof)
5867
r = len(mw_base)
5868
if verbose:
5869
print "Finished computation of MW basis; rank is ",r
5870
else:
5871
try:
5872
r = len(mw_base)
5873
except TypeError:
5874
raise TypeError, 'mw_base must be a list'
5875
if not all([P.curve() is self for P in mw_base]):
5876
raise ValueError, "mw_base-points are not on the correct curve"
5877
5878
#End Input-Check ######################################################
5879
5880
#Internal functions ###################################################
5881
def reduction_at(p):
5882
r"""
5883
Reducing the bound `H_q` at the finite place p in S via LLL
5884
"""
5885
indexp = S.index(p)
5886
pc = Z(p**(R(c.log()/log(p,e)).ceil()))
5887
m = copy(M.identity_matrix())
5888
for i in range(r):
5889
try:
5890
m[i, r] = Z((beta[indexp][i])%pc)
5891
except ZeroDivisionError: #If Inverse doesn't exist, change denominator (which is only approx)
5892
val_nu = (beta[indexp][i]).numerator()
5893
val_de = (beta[indexp][i]).denominator()
5894
m[i, r] = Z((val_nu/(val_de+1))%pc)
5895
m[r,r] = max(Z(1), pc)
5896
5897
#LLL - implemented in sage - operates on rows not on columns
5898
m_LLL = m.LLL()
5899
m_gram = m_LLL.gram_schmidt()[0]
5900
b1_norm = R(m_LLL.row(0).norm())
5901
5902
c1_LLL = -1
5903
for i in range(n):
5904
tmp = R(b1_norm/(m_gram.row(i).norm()))
5905
if tmp > c1_LLL:
5906
c1_LLL = tmp
5907
if c1_LLL < 0:
5908
raise RuntimeError, 'Unexpected intermediate result. Please try another Mordell-Weil base'
5909
d_L_0 = R(b1_norm**2 / c1_LLL)
5910
5911
#Reducing of upper bound
5912
Q = r * H_q**2
5913
T = (1 + (3/2*r*H_q))/2
5914
if d_L_0 < R(T**2+Q):
5915
d_L_0 = 10*(T**2*Q)
5916
low_bound = R(((d_L_0 - Q).sqrt() - T)/c)
5917
5918
##new bound according to low_bound and upper bound
5919
##[k5*k6 exp(-k7**H_q^2)]
5920
if low_bound != 0:
5921
H_q_infinity = R(((low_bound/(k6)).log()/(-k7)).sqrt())
5922
return (H_q_infinity.ceil())
5923
else:
5924
return (H_q)
5925
#<-------------------------------------------------------------------------
5926
#>-------------------------------------------------------------------------
5927
def S_integral_points_with_bounded_mw_coeffs():
5928
r"""
5929
Returns the set of S-integers x which are x-coordinates of
5930
points on the curve which are linear combinations of the
5931
generators (basis and torsion points) with coefficients
5932
bounded by `H_q`. The bound `H_q` will be computed at
5933
runtime.
5934
(Modified version of integral_points_with_bounded_mw_coeffs() in
5935
integral_points() )
5936
5937
TODO: Make this more efficient. In the case ``S=[]`` we
5938
worked over the reals and only computed a combination
5939
exactly if the real coordinates were approximately
5940
integral. We need a version of this which works for
5941
S-integral points, probably by finding a bound on the
5942
denominator.
5943
"""
5944
from sage.groups.generic import multiples
5945
xs=set()
5946
N=H_q
5947
5948
def test(P):
5949
"""
5950
Record x-coord of a point if S-integral.
5951
"""
5952
if not P.is_zero():
5953
xP = P[0]
5954
if xP.is_S_integral(S):
5955
xs.add(xP)
5956
5957
def test_with_T(R):
5958
"""
5959
Record x-coords of a 'point+torsion' if S-integral.
5960
"""
5961
for T in tors_points:
5962
test(R+T)
5963
5964
# For small rank and small H_q perform simple search
5965
if r==1 and N<=10:
5966
for P in multiples(mw_base[0],N+1):
5967
test_with_T(P)
5968
return xs
5969
5970
# explicit computation and testing linear combinations
5971
# ni loops through all tuples (n_1,...,n_r) with |n_i| <= N
5972
# stops when (0,0,...,0) is reached because after that, only inverse points of
5973
# previously tested points would be tested
5974
5975
E0=E(0)
5976
ni = [-N for i in range(r)]
5977
mw_baseN = [-N*P for P in mw_base]
5978
Pi = [0 for j in range(r)]
5979
Pi[0] = mw_baseN[0]
5980
for i in range(1,r):
5981
Pi[i] = Pi[i-1] + mw_baseN[i]
5982
5983
while True:
5984
if all([n==0 for n in ni]):
5985
test_with_T(E0)
5986
break
5987
5988
# test the ni-combination which is Pi[r-1]
5989
test_with_T(Pi[r-1])
5990
5991
# increment indices and stored points
5992
i0 = r-1
5993
while ni[i0]==N:
5994
ni[i0] = -N
5995
i0 -= 1
5996
ni[i0] += 1
5997
if all([n==0 for n in ni[0:i0+1]]):
5998
Pi[i0] = E0
5999
else:
6000
Pi[i0] += mw_base[i0]
6001
for i in range(i0+1,r):
6002
Pi[i] = Pi[i-1] + mw_baseN[i]
6003
6004
return xs
6005
#<-------------------------------------------------------------------------
6006
#>-------------------------------------------------------------------------
6007
def S_integral_x_coords_with_abs_bounded_by(abs_bound):
6008
r"""
6009
Extra search of points with `|x|< ` abs_bound, assuming
6010
that `x` is `S`-integral and `|x|\ge|x|_q` for all primes
6011
`q` in `S`. (Such points are not covered by the main part
6012
of the code). We know
6013
6014
.. math::
6015
6016
x=\frac{\xi}{\p_1^{\alpha_1} \cdot \dots \cdot \p_s^{\alpha_s}},\ (gcd(\xi,\p_i)=1),\ p_i \in S
6017
6018
so a bound of `\alpha_i` can be found in terms of
6019
abs_bound. Additionally each `\alpha` must be even, giving
6020
another restriction. This gives a finite list of
6021
denominators to test, and for each, a range of numerators.
6022
All candidates for `x` resulting from this theory are then
6023
tested, and a list of the ones which are `x`-coordinates
6024
of (`S`-integral) points is returned.
6025
6026
TODO: Make this more efficient. If we had an efficient
6027
function for searching for integral points (for example,
6028
by wrapping Stoll's ratpoint program) then it should be
6029
better to scale the equation by the maximum denominator
6030
and search for integral points on the scaled model.
6031
6032
"""
6033
x_min = min(self.two_division_polynomial().roots(R,multiplicities=False))
6034
x_min_neg = bool(x_min<0)
6035
x_min_pos = not x_min_neg
6036
log_ab = R(abs_bound.log())
6037
alpha = [(log_ab/R(log(p,e))).floor() for p in S]
6038
if all([alpha_i <= 1 for alpha_i in alpha]): # so alpha_i must be 0 to satisfy that denominator is a square
6039
return set([x for x in range(-abs_bound,abs_bound) if E.is_x_coord(x)])
6040
else:
6041
xs = []
6042
alpha_max_even = [y-y%2 for y in alpha]
6043
p_pow_alpha = []
6044
list_alpha = []
6045
for i in range(len_S-1):
6046
list_alpha.append(range(0,alpha_max_even[i]+2,2))
6047
p_pow_alpha.append([S[i]**list_alpha[i][j] for j in range(len(list_alpha[i]))])
6048
if verbose:
6049
print list_alpha, p_pow_alpha
6050
# denom_maxpa is a list of pairs (d,q) where d runs
6051
# through possible denominators, and q=p^a is the
6052
# maximum prime power divisor of d:
6053
denom_maxpa = [(misc.prod(tmp),max(tmp)) for tmp in cartesian_product_iterator(p_pow_alpha)]
6054
# The maximum denominator is this (not used):
6055
# denom = [misc.prod([pp[-1] for pp in p_pow_alpha],1)]
6056
for de,maxpa in denom_maxpa:
6057
n_max = (abs_bound*de).ceil()
6058
n_min = maxpa*de
6059
if x_min_pos:
6060
pos_n_only = True
6061
if x_min > maxpa:
6062
n_min = (x_min*de).floor()
6063
else:
6064
pos_n_only = False
6065
neg_n_max = (x_min.abs()*de).ceil()
6066
6067
# if verbose:
6068
# print "testing denominator ",de
6069
# print "numerator bounds = ",(n_min,n_max)
6070
6071
for n in misc.xsrange(n_min,n_max+1):
6072
tmp = n/de # to save time, do not check de is the exact denominator
6073
if E.is_x_coord(tmp):
6074
xs+=[tmp]
6075
if not pos_n_only:
6076
if n <= neg_n_max:
6077
if E.is_x_coord(-tmp):
6078
xs+=[-tmp]
6079
6080
return set(xs)
6081
#<-------------------------------------------------------------------------
6082
#End internal functions ###############################################
6083
from sage.misc.all import cartesian_product_iterator
6084
6085
E = self
6086
tors_points = E.torsion_points()
6087
6088
if (r==0):#only Torsionpoints to consider
6089
int_points = [P for P in tors_points if not P.is_zero()]
6090
int_points = [P for P in int_points if P[0].is_S_integral(S)]
6091
if not both_signs:
6092
xlist = set([P[0] for P in int_points])
6093
int_points = [E.lift_x(x) for x in xlist]
6094
int_points.sort()
6095
if verbose:
6096
print 'Total number of S-integral points:',len(int_points)
6097
return int_points
6098
6099
if verbose:
6100
import sys # so we can flush stdout for debugging
6101
6102
e = R(1).exp()
6103
a1, a2, a3, a4, a6 = E.a_invariants()
6104
b2, b4, b6, b8 = E.b_invariants()
6105
c4, c6 = E.c_invariants()
6106
disc = E.discriminant()
6107
#internal function is doing only a comparison of E and E.short_weierstass_model() so the following is easier
6108
if a1 == a2 == a3 == 0:
6109
is_short = True
6110
else:
6111
is_short = False
6112
6113
w1, w2 = E.period_lattice().basis()
6114
6115
Qx = rings.PolynomialRing(RationalField(),'x')
6116
pol = Qx([-54*c6,-27*c4,0,1])
6117
if disc > 0: # two real component -> 3 roots in RR
6118
# it is possible that only one root is found with default precision! (see integral_points())
6119
RR = R
6120
prec = RR.precision()
6121
ei = pol.roots(RR,multiplicities=False)
6122
while len(ei)<3:
6123
prec*=2
6124
RR=RealField(prec)
6125
ei = pol.roots(RR,multiplicities=False)
6126
e1,e2,e3 = ei
6127
elif disc < 0: # one real component => 1 root in RR (=: e3),
6128
# 2 roots in C (e1,e2)
6129
roots = pol.roots(C,multiplicities=False)
6130
e3 = pol.roots(R,multiplicities=False)[0]
6131
roots.remove(e3)
6132
e1,e2 = roots
6133
6134
len_tors = len(tors_points)
6135
n = r + 1
6136
6137
M = E.height_pairing_matrix(mw_base)
6138
mw_base, U = E.lll_reduce(mw_base,M)
6139
M = U.transpose()*M*U
6140
6141
# NB "lambda" is a reserved word in Python!
6142
lamda = min(M.charpoly(algorithm="hessenberg").roots(multiplicities = False))
6143
max_S = max(S)
6144
len_S += 1 #Counting infinity (always "included" in S)
6145
if verbose:
6146
print 'max_S:',max_S,'len_S:',len_S,'len_tors:',len_tors
6147
print 'lambda',lamda
6148
sys.stdout.flush()
6149
6150
if is_short:
6151
disc_0_abs = R((4*a4**3 + 27*a6**2).abs())
6152
k4 = R(10**4 * max(16*a4**2, 256*disc_0_abs.sqrt()**3))
6153
k3 = R(32/3 * disc_0_abs.sqrt() * (8 + 0.5*disc_0_abs.log())**4)
6154
else:
6155
disc_sh = R(E.short_weierstrass_model().discriminant()) #computes y^2=x^3 -27c4x -54c6
6156
k4 = R(20**4 * max(3**6 * c4**2, 16*(disc_sh.abs().sqrt())**3))
6157
k3 = R(32/3 * disc_sh.abs().sqrt() * (8 + 0.5*disc_sh.abs().log())**4)
6158
6159
6160
k2 = max(R(b2.abs()), R(b4.abs().sqrt()), R(b6.abs()**(1/3)), R(b8.abs()**(1/4))).log()
6161
k1 = R(7 * 10**(38*len_S+49)) * R(len_S**(20*len_S+15)) * max_S**24 * R(max(1,log(max_S, e))**(4*len_S - 2)) * k3 * k3.log()**2 * ((20*len_S - 19)*k3 + (e*k4).log()) + 2*R(2*b2.abs()+6).log()
6162
6163
if verbose:
6164
print 'k1,k2,k3,k4',k1,k2,k3,k4
6165
sys.stdout.flush()
6166
#H_q -> [PZGH]:N_0 (due to consistency to integral_points())
6167
H_q = R(((k1/2+k2)/lamda).sqrt())
6168
6169
#computation of logs
6170
mw_base_log = [(pts.elliptic_logarithm().abs())*(len_tors/w1) for pts in mw_base]
6171
mw_base_p_log = []
6172
beta = []
6173
mp=[]
6174
tmp = 0
6175
for p in S:
6176
Np = E.Np(p)
6177
cp = E.tamagawa_exponent(p)
6178
mp_temp = Z(len_tors).lcm(cp*Np)
6179
mp.append(mp_temp) #only necessary because of verbose below
6180
p_prec=30+E.discriminant().valuation(p)
6181
p_prec_ok=False
6182
while not p_prec_ok:
6183
if verbose:
6184
print "p=",p,": trying with p_prec = ",p_prec
6185
try:
6186
mw_base_p_log.append([mp_temp*(pts.padic_elliptic_logarithm(p,absprec=p_prec)) for pts in mw_base])
6187
p_prec_ok=True
6188
except ValueError:
6189
p_prec *= 2
6190
#reorder mw_base_p: last value has minimal valuation at p
6191
mw_base_p_log_val = [mw_base_p_log[tmp][i].valuation() for i in range(r)]
6192
if verbose:
6193
print "mw_base_p_log_val = ",mw_base_p_log_val
6194
min_index = mw_base_p_log_val.index(min(mw_base_p_log_val))
6195
min_psi = mw_base_p_log[tmp][min_index]
6196
if verbose:
6197
print "min_psi = ",min_psi
6198
mw_base_p_log[tmp].remove(min_psi)
6199
mw_base_p_log[tmp].append(min_psi)
6200
#beta needed for reduction at p later on
6201
try:
6202
beta.append([-mw_base_p_log[tmp][j]/min_psi for j in range(r)])
6203
except ValueError:
6204
# e.g. mw_base_p_log[tmp]==[0]: can occur e.g. [?]'172c6, S=[2]
6205
beta.append([0] for j in range(r))
6206
tmp +=1
6207
6208
if verbose:
6209
print 'mw_base',mw_base
6210
print 'mw_base_log', mw_base_log
6211
print 'mp', mp
6212
print 'mw_base_p_log',mw_base_p_log
6213
#print 'beta', beta
6214
sys.stdout.flush()
6215
6216
#constants in reduction (not needed to be computed every reduction step)
6217
k5 = R((2*len_tors)/(3*w1))
6218
k6 = R((k2/len_S).exp())
6219
k7 = R(lamda/len_S)
6220
6221
if verbose:
6222
print 'k5,k6,k7',k5,k6,k7
6223
sys.stdout.flush()
6224
6225
break_cond = 0
6226
M = matrix.MatrixSpace(Z,n)
6227
#Reduction of initial bound
6228
if verbose:
6229
print 'initial bound',H_q
6230
sys.stdout.flush()
6231
6232
while break_cond < 0.9:
6233
#reduction at infinity
6234
bound_list=[]
6235
c = R((H_q**n)*100)
6236
m = copy(M.identity_matrix())
6237
for i in range(r):
6238
m[i, r] = R(c*mw_base_log[i]).round()
6239
m[r,r] = max(Z(1), R(c*w1).round())
6240
#LLL - implemented in sage - operates on rows not on columns
6241
m_LLL = m.LLL()
6242
m_gram = m_LLL.gram_schmidt()[0]
6243
b1_norm = R(m_LLL.row(0).norm())
6244
6245
#compute constant c1_LLL (cf. integral_points())
6246
c1_LLL = -1
6247
for i in range(n):
6248
tmp = R(b1_norm/(m_gram.row(i).norm()))
6249
if tmp > c1_LLL:
6250
c1_LLL = tmp
6251
if c1_LLL < 0:
6252
raise RuntimeError, 'Unexpected intermediate result. Please try another Mordell-Weil base'
6253
d_L_0 = R(b1_norm**2 / c1_LLL)
6254
6255
#Reducing of upper bound
6256
Q = r * H_q**2
6257
T = (1 + (3/2*r*H_q))/2
6258
if d_L_0 < R(T**2+Q):
6259
d_L_0 = 10*(T**2*Q)
6260
low_bound = R(((d_L_0 - Q).sqrt() - T)/c)
6261
6262
##new bound according to low_bound and upper bound
6263
##[k5*k6 exp(-k7**H_q^2)]
6264
if low_bound != 0:
6265
H_q_infinity = R(((low_bound/(k5*k6)).log()/(-k7)).abs().sqrt())
6266
bound_list.append(H_q_infinity.ceil())
6267
else:
6268
bound_list.append(H_q)
6269
6270
##reduction for finite places in S
6271
for p in S:
6272
bound_list.append(reduction_at(p))
6273
6274
if verbose:
6275
print 'bound_list',bound_list
6276
sys.stdout.flush()
6277
6278
H_q_new = max(bound_list)
6279
if (H_q_new > H_q): #no improvement
6280
break_cond = 1 #stop reduction
6281
elif (H_q_new == 1): #best possible H_q
6282
H_q = H_q_new
6283
break_cond = 1 #stop
6284
else:
6285
break_cond = R(H_q_new/H_q)
6286
H_q = H_q_new
6287
#end of reductions
6288
6289
#search of S-integral points
6290
#step1: via linear combination and H_q
6291
x_S_int_points = set()
6292
if verbose:
6293
print 'starting search of points using coefficient bound ',H_q
6294
sys.stdout.flush()
6295
x_S_int_points1 = S_integral_points_with_bounded_mw_coeffs()
6296
x_S_int_points = x_S_int_points.union(x_S_int_points1)
6297
if verbose:
6298
print 'x-coords of S-integral points via linear combination of mw_base and torsion:'
6299
L = list(x_S_int_points1)
6300
L.sort()
6301
print L
6302
sys.stdout.flush()
6303
6304
#step 2: Extra search
6305
if e3 < 0:
6306
M = R( max((27*c4).abs().sqrt(), R((54*c6).abs()**(1/3)) / R(2**(1/3))-1) )
6307
else:
6308
M = R(0)
6309
e0 = max(e1+e2, 2*e3) + M
6310
abs_bound = R((max(0,e0)+6*b2.abs())/36)
6311
6312
if proof:
6313
if verbose:
6314
print 'starting search of extra S-integer points with absolute value bounded by',abs_bound
6315
sys.stdout.flush()
6316
if abs_bound != 0:
6317
x_S_int_points2 = S_integral_x_coords_with_abs_bounded_by(abs_bound)
6318
x_S_int_points = x_S_int_points.union(x_S_int_points2)
6319
if verbose:
6320
print 'x-coords of points with bounded absolute value'
6321
L = list(x_S_int_points2)
6322
L.sort()
6323
print L
6324
sys.stdout.flush()
6325
6326
if len(tors_points)>1:
6327
x_S_int_points_t = set()
6328
for x in x_S_int_points:
6329
P = E.lift_x(x)
6330
for T in tors_points:
6331
Q = P+T
6332
if not Q.is_zero() and Q[0].is_S_integral(S):
6333
x_S_int_points_t = x_S_int_points_t.union([Q[0]])
6334
x_S_int_points = x_S_int_points.union(x_S_int_points_t)
6335
6336
# All x values collected, now considering "both_signs"
6337
if both_signs:
6338
S_int_points = sum([self.lift_x(x,all=True) for x in x_S_int_points],[])
6339
else:
6340
S_int_points = [self.lift_x(x) for x in x_S_int_points]
6341
S_int_points.sort()
6342
if verbose:
6343
print 'Total number of S-integral points:',len(S_int_points)
6344
return S_int_points
6345
6346
6347
def cremona_curves(conductors):
6348
"""
6349
Return iterator over all known curves (in database) with conductor
6350
in the list of conductors.
6351
6352
EXAMPLES::
6353
6354
sage: [(E.label(), E.rank()) for E in cremona_curves(srange(35,40))]
6355
[('35a1', 0),
6356
('35a2', 0),
6357
('35a3', 0),
6358
('36a1', 0),
6359
('36a2', 0),
6360
('36a3', 0),
6361
('36a4', 0),
6362
('37a1', 1),
6363
('37b1', 0),
6364
('37b2', 0),
6365
('37b3', 0),
6366
('38a1', 0),
6367
('38a2', 0),
6368
('38a3', 0),
6369
('38b1', 0),
6370
('38b2', 0),
6371
('39a1', 0),
6372
('39a2', 0),
6373
('39a3', 0),
6374
('39a4', 0)]
6375
"""
6376
if isinstance(conductors, (int,long, rings.RingElement)):
6377
conductors = [conductors]
6378
return sage.databases.cremona.CremonaDatabase().iter(conductors)
6379
6380
def cremona_optimal_curves(conductors):
6381
"""
6382
Return iterator over all known optimal curves (in database) with
6383
conductor in the list of conductors.
6384
6385
EXAMPLES::
6386
6387
sage: [(E.label(), E.rank()) for E in cremona_optimal_curves(srange(35,40))]
6388
[('35a1', 0),
6389
('36a1', 0),
6390
('37a1', 1),
6391
('37b1', 0),
6392
('38a1', 0),
6393
('38b1', 0),
6394
('39a1', 0)]
6395
6396
There is one case -- 990h3 -- when the optimal curve isn't labeled with a 1::
6397
6398
sage: [e.cremona_label() for e in cremona_optimal_curves([990])]
6399
['990a1', '990b1', '990c1', '990d1', '990e1', '990f1', '990g1', '990h3', '990i1', '990j1', '990k1', '990l1']
6400
6401
"""
6402
if isinstance(conductors, (int,long,rings.RingElement)):
6403
conductors = [conductors]
6404
return sage.databases.cremona.CremonaDatabase().iter_optimal(conductors)
6405
6406
def integral_points_with_bounded_mw_coeffs(E, mw_base, N):
6407
r"""
6408
Returns the set of integers `x` which are
6409
`x`-coordinates of points on the curve `E` which
6410
are linear combinations of the generators (basis and torsion
6411
points) with coefficients bounded by `N`.
6412
"""
6413
from sage.groups.generic import multiples
6414
xs=set()
6415
tors_points = E.torsion_points()
6416
r = len(mw_base)
6417
6418
def use(P):
6419
"""
6420
Helper function to record x-coord of a point if integral.
6421
"""
6422
if not P.is_zero():
6423
xP = P[0]
6424
if xP.is_integral():
6425
xs.add(xP)
6426
6427
def use_t(R):
6428
"""
6429
Helper function to record x-coords of a point +torsion if
6430
integral.
6431
"""
6432
for T in tors_points:
6433
use(R+T)
6434
6435
# We use a naive method when the number of possibilities is small:
6436
6437
if r==1 and N<=10:
6438
for P in multiples(mw_base[0],N+1):
6439
use_t(P)
6440
return xs
6441
6442
# Otherwise it is very very much faster to first compute
6443
# the linear combinations over RR, and only compute them as
6444
# rational points if they are approximately integral.
6445
6446
# Note: making eps larger here will dramatically increase
6447
# the running time. If evidence arises that integral
6448
# points are being missed, it would be better to increase
6449
# the real precision than to increase eps.
6450
6451
def is_approx_integral(P):
6452
r"""
6453
Local function, returns True if the real point `P` is approximately integral.
6454
"""
6455
eps = 0.0001
6456
return (abs(P[0]-P[0].round()))<eps and (abs(P[1]-P[1].round()))<eps
6457
6458
RR = RealField(100) #(100)
6459
ER = E.change_ring(RR)
6460
ER0 = ER(0)
6461
6462
# Note: doing [ER(P) for P in mw_base] sometimes fails. The
6463
# following way is harder, since we have to make sure we don't use
6464
# -P instead of P, but is safer.
6465
6466
Rgens = [ER.lift_x(P[0]) for P in mw_base]
6467
for i in range(r):
6468
if abs(Rgens[i][1]-mw_base[i][1])>abs((-Rgens[i])[1]-mw_base[i][1]):
6469
Rgens[i] = -Rgens[i]
6470
6471
# the ni loop through all tuples (a1,a2,...,ar) with
6472
# |ai|<=N, but we stop immediately after using the tuple
6473
# (0,0,...,0).
6474
6475
# Initialization:
6476
ni = [-N for i in range(r)]
6477
RgensN = [-N*P for P in Rgens]
6478
# RPi[i] = -N*(Rgens[0]+...+Rgens[i])
6479
RPi = [0 for j in range(r)]
6480
RPi[0] = RgensN[0]
6481
for i in range(1,r):
6482
RPi[i] = RPi[i-1] + RgensN[i]
6483
6484
tors_points_R = map(ER, tors_points)
6485
while True:
6486
if all([n==0 for n in ni]):
6487
use_t(E(0))
6488
break
6489
6490
# test the ni-combination which is RPi[r-1]
6491
RP = RPi[r-1]
6492
6493
for T, TR in zip(tors_points, tors_points_R):
6494
if is_approx_integral(RP + TR):
6495
P = sum([ni[i]*mw_base[i] for i in range(r)],T)
6496
use(P)
6497
6498
# increment indices and stored points
6499
i0 = r-1
6500
while ni[i0]==N:
6501
ni[i0] = -N
6502
i0 -= 1
6503
ni[i0] += 1
6504
# The next lines are to prevent rounding error: (-P)+P behaves
6505
# badly for real points!
6506
if all([n==0 for n in ni[0:i0+1]]):
6507
RPi[i0] = ER0
6508
else:
6509
RPi[i0] += Rgens[i0]
6510
for i in range(i0+1,r):
6511
RPi[i] = RPi[i-1] + RgensN[i]
6512
6513
return xs
6514
6515
6516