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