Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/libs/mwrank/interface.py
4046 views
1
r"""
2
Sage interface to Cremona's eclib library (also known as mwrank)
3
4
This is the Sage interface to John Cremona's ``eclib`` C++ library for
5
arithmetic on elliptic curves. The classes defined in this module
6
give Sage interpreter-level access to some of the functionality of
7
``eclib``. For most purposes, it is not necessary to directly use these
8
classes. Instead, one can create an
9
:class:`EllipticCurve <sage.schemes.elliptic_curves.constructor.EllipticCurve>`
10
and call methods that are implemented using this module.
11
12
.. note::
13
14
This interface is a direct library-level interface to ``eclib``,
15
including the 2-descent program ``mwrank``.
16
"""
17
18
from sage.structure.sage_object import SageObject
19
from sage.rings.integer_ring import IntegerRing
20
21
# Need to permit tabs in order to doctest verbose output.
22
"""
23
SAGE_DOCTEST_ALLOW_TABS
24
"""
25
26
def get_precision():
27
r"""
28
Return the global NTL real number precision.
29
30
See also :meth:`set_precision`.
31
32
.. warning::
33
34
The internal precision is binary. This function multiplies the
35
binary precision by 0.3 (`=\log_2(10)` approximately) and
36
truncates.
37
38
OUTPUT:
39
40
(int) The current decimal precision.
41
42
EXAMPLES::
43
44
sage: mwrank_get_precision()
45
50
46
"""
47
# don't want to load mwrank every time Sage starts up, so we do
48
# the import here.
49
from sage.libs.mwrank.mwrank import get_precision
50
return get_precision()
51
52
def set_precision(n):
53
r"""
54
Set the global NTL real number precision. This has a massive
55
effect on the speed of mwrank calculations. The default (used if
56
this function is not called) is ``n=50``, but it might have to be
57
increased if a computation fails. See also :meth:`get_precision`.
58
59
INPUT:
60
61
- ``n`` (long) -- real precision used for floating point
62
computations in the library, in decimal digits.
63
64
.. warning::
65
66
This change is global and affects *all* future calls of eclib
67
functions by Sage.
68
69
EXAMPLES::
70
71
sage: mwrank_set_precision(20)
72
"""
73
# don't want to load mwrank every time Sage starts up, so we do
74
# the import here.
75
from sage.libs.mwrank.mwrank import set_precision
76
set_precision(n)
77
78
class mwrank_EllipticCurve(SageObject):
79
r"""
80
The :class:`mwrank_EllipticCurve` class represents an elliptic
81
curve using the ``Curvedata`` class from ``eclib``, called here an 'mwrank
82
elliptic curve'.
83
84
Create the mwrank elliptic curve with invariants
85
``ainvs``, which is a list of 5 or less *integers* `a_1`,
86
`a_2`, `a_3`, `a_4`, and `a_5`.
87
88
If strictly less than 5 invariants are given, then the *first*
89
ones are set to 0, so, e.g., ``[3,4]`` means `a_1=a_2=a_3=0` and
90
`a_4=3`, `a_5=4`.
91
92
INPUT:
93
94
- ``ainvs`` (list or tuple) -- a list of 5 or less integers, the
95
coefficients of a nonsingular Weierstrass equation.
96
97
- ``verbose`` (bool, default ``False``) -- verbosity flag. If ``True``,
98
then all Selmer group computations will be verbose.
99
100
EXAMPLES:
101
102
We create the elliptic curve `y^2 + y = x^3 + x^2 - 2x`::
103
104
sage: e = mwrank_EllipticCurve([0, 1, 1, -2, 0])
105
sage: e.ainvs()
106
[0, 1, 1, -2, 0]
107
108
This example illustrates that omitted `a`-invariants default to `0`::
109
110
sage: e = mwrank_EllipticCurve([3, -4])
111
sage: e
112
y^2 = x^3 + 3*x - 4
113
sage: e.ainvs()
114
[0, 0, 0, 3, -4]
115
116
The entries of the input list are coerced to :class:`int`.
117
If this is impossible, then an error is raised::
118
119
sage: e = mwrank_EllipticCurve([3, -4.8]); e
120
Traceback (most recent call last):
121
...
122
TypeError: ainvs must be a list or tuple of integers.
123
124
When you enter a singular model you get an exception::
125
126
sage: e = mwrank_EllipticCurve([0, 0])
127
Traceback (most recent call last):
128
...
129
ArithmeticError: Invariants (= [0, 0, 0, 0, 0]) do not describe an elliptic curve.
130
"""
131
132
def __init__(self, ainvs, verbose=False):
133
r"""
134
Create the mwrank elliptic curve with invariants
135
``ainvs``, which is a list of 5 or less *integers* `a_1`,
136
`a_2`, `a_3`, `a_4`, and `a_5`.
137
138
See the docstring of this class for full documentation.
139
140
EXAMPLES:
141
142
We create the elliptic curve `y^2 + y = x^3 + x^2 - 2x`::
143
144
sage: e = mwrank_EllipticCurve([0, 1, 1, -2, 0])
145
sage: e.ainvs()
146
[0, 1, 1, -2, 0]
147
"""
148
# import here to save time during startup (mwrank takes a while to init)
149
150
from sage.libs.mwrank.mwrank import _Curvedata
151
152
# if not isinstance(ainvs, list) and len(ainvs) <= 5:
153
if not isinstance(ainvs, (list,tuple)) or not len(ainvs) <= 5:
154
raise TypeError, "ainvs must be a list or tuple of length at most 5."
155
156
# Pad ainvs on the beginning by 0's, so e.g.
157
# [a4,a5] works.
158
ainvs = [0]*(5-len(ainvs)) + ainvs
159
160
# Convert each entry to an int
161
try:
162
a_int = [IntegerRing()(x) for x in ainvs]
163
except (TypeError, ValueError):
164
raise TypeError, "ainvs must be a list or tuple of integers."
165
self.__ainvs = a_int
166
self.__curve = _Curvedata(a_int[0], a_int[1], a_int[2],
167
a_int[3], a_int[4])
168
169
if verbose:
170
self.__verbose = True
171
else:
172
self.__verbose = False
173
174
# place holders
175
self.__saturate = -2 # not yet saturated
176
177
def __reduce__(self):
178
r"""
179
Standard Python function used in pickling.
180
181
EXAMPLES::
182
183
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
184
sage: E.__reduce__()
185
(<class 'sage.libs.mwrank.interface.mwrank_EllipticCurve'>, ([0, 0, 1, -7, 6], False))
186
187
188
"""
189
return mwrank_EllipticCurve, (self.__ainvs, self.__verbose)
190
191
192
def set_verbose(self, verbose):
193
"""
194
Set the verbosity of printing of output by the :meth:`two_descent()` and
195
other functions.
196
197
INPUT:
198
199
- ``verbose`` (int) -- if positive, print lots of output when
200
doing 2-descent.
201
202
EXAMPLES::
203
204
sage: E = mwrank_EllipticCurve([0, 0, 1, -1, 0])
205
sage: E.saturate() # no output
206
sage: E.gens()
207
[[0, -1, 1]]
208
209
sage: E = mwrank_EllipticCurve([0, 0, 1, -1, 0])
210
sage: E.set_verbose(1)
211
sage: E.saturate() # produces the following output
212
213
::
214
215
Basic pair: I=48, J=-432
216
disc=255744
217
2-adic index bound = 2
218
By Lemma 5.1(a), 2-adic index = 1
219
2-adic index = 1
220
One (I,J) pair
221
Looking for quartics with I = 48, J = -432
222
Looking for Type 2 quartics:
223
Trying positive a from 1 up to 1 (square a first...)
224
(1,0,-6,4,1) --trivial
225
Trying positive a from 1 up to 1 (...then non-square a)
226
Finished looking for Type 2 quartics.
227
Looking for Type 1 quartics:
228
Trying positive a from 1 up to 2 (square a first...)
229
(1,0,0,4,4) --nontrivial...(x:y:z) = (1 : 1 : 0)
230
Point = [0:0:1]
231
height = 0.051111408239968840235886099756942021609538202280854
232
Rank of B=im(eps) increases to 1 (The previous point is on the egg)
233
Exiting search for Type 1 quartics after finding one which is globally soluble.
234
Mordell rank contribution from B=im(eps) = 1
235
Selmer rank contribution from B=im(eps) = 1
236
Sha rank contribution from B=im(eps) = 0
237
Mordell rank contribution from A=ker(eps) = 0
238
Selmer rank contribution from A=ker(eps) = 0
239
Sha rank contribution from A=ker(eps) = 0
240
Searching for points (bound = 8)...done:
241
found points of rank 1
242
and regulator 0.051111408239968840235886099756942021609538202280854
243
Processing points found during 2-descent...done:
244
now regulator = 0.051111408239968840235886099756942021609538202280854
245
Saturating (bound = -1)...done:
246
points were already saturated.
247
"""
248
self.__verbose = verbose
249
250
251
def _curve_data(self):
252
r"""
253
Returns the underlying :class:`_Curvedata` class for this mwrank elliptic curve.
254
255
EXAMPLES::
256
257
sage: E = mwrank_EllipticCurve([0,0,1,-1,0])
258
sage: E._curve_data()
259
[0,0,1,-1,0]
260
b2 = 0 b4 = -2 b6 = 1 b8 = -1
261
c4 = 48 c6 = -216
262
disc = 37 (# real components = 2)
263
#torsion not yet computed
264
"""
265
return self.__curve
266
267
def ainvs(self):
268
r"""
269
Returns the `a`-invariants of this mwrank elliptic curve.
270
271
EXAMPLES::
272
273
sage: E = mwrank_EllipticCurve([0,0,1,-1,0])
274
sage: E.ainvs()
275
[0, 0, 1, -1, 0]
276
"""
277
return self.__ainvs
278
279
def isogeny_class(self, verbose=False):
280
r"""
281
Returns the isogeny class of this mwrank elliptic curve.
282
283
EXAMPLES::
284
285
sage: E = mwrank_EllipticCurve([0,-1,1,0,0])
286
sage: E.isogeny_class()
287
([[0, -1, 1, 0, 0], [0, -1, 1, -10, -20], [0, -1, 1, -7820, -263580]], [[0, 5, 0], [5, 0, 5], [0, 5, 0]])
288
"""
289
return self.__curve.isogeny_class(verbose)
290
291
def __repr__(self):
292
r"""
293
Returns the string representation of this mwrank elliptic curve.
294
295
EXAMPLES::
296
297
sage: E = mwrank_EllipticCurve([0,-1,1,0,0])
298
sage: E.__repr__()
299
'y^2+ y = x^3 - x^2 '
300
"""
301
# TODO: Is the use (or omission) of spaces here intentional?
302
a = self.ainvs()
303
s = "y^2"
304
if a[0] == -1:
305
s += "- x*y "
306
elif a[0] == 1:
307
s += "+ x*y "
308
elif a[0] != 0:
309
s += "+ %s*x*y "%a[0]
310
if a[2] == -1:
311
s += " - y"
312
elif a[2] == 1:
313
s += "+ y"
314
elif a[2] != 0:
315
s += "+ %s*y"%a[2]
316
s += " = x^3 "
317
if a[1] == -1:
318
s += "- x^2 "
319
elif a[1] == 1:
320
s += "+ x^2 "
321
elif a[1] != 0:
322
s += "+ %s*x^2 "%a[1]
323
if a[3] == -1:
324
s += "- x "
325
elif a[3] == 1:
326
s += "+ x "
327
elif a[3] != 0:
328
s += "+ %s*x "%a[3]
329
if a[4] == -1:
330
s += "-1"
331
elif a[4] == 1:
332
s += "+1"
333
elif a[4] != 0:
334
s += "+ %s"%a[4]
335
s = s.replace("+ -","- ")
336
return s
337
338
339
def two_descent(self,
340
verbose = True,
341
selmer_only = False,
342
first_limit = 20,
343
second_limit = 8,
344
n_aux = -1,
345
second_descent = True):
346
"""
347
Compute 2-descent data for this curve.
348
349
INPUT:
350
351
- ``verbose`` (bool, default ``True``) -- print what mwrank is doing.
352
353
- ``selmer_only`` (bool, default ``False``) -- ``selmer_only`` switch.
354
355
- ``first_limit`` (int, default 20) -- bound on `|x|+|z|` in
356
quartic point search.
357
358
- ``second_limit`` (int, default 8) -- bound on
359
`\log \max(|x|,|z|)`, i.e. logarithmic.
360
361
- ``n_aux`` (int, default -1) -- (only relevant for general
362
2-descent when 2-torsion trivial) number of primes used for
363
quartic search. ``n_aux=-1`` causes default (8) to be used.
364
Increase for curves of higher rank.
365
366
- ``second_descent`` (bool, default ``True``) -- (only relevant
367
for curves with 2-torsion, where mwrank uses descent via
368
2-isogeny) flag determining whether or not to do second
369
descent. *Default strongly recommended.*
370
371
372
OUTPUT:
373
374
Nothing -- nothing is returned.
375
376
TESTS (see #7992)::
377
378
sage: EllipticCurve([0, prod(prime_range(10))]).mwrank_curve().two_descent()
379
sage: EllipticCurve([0, prod(prime_range(100))]).mwrank_curve().two_descent()
380
Traceback (most recent call last):
381
...
382
RuntimeError: Aborted
383
384
385
"""
386
from sage.libs.mwrank.mwrank import _two_descent # import here to save time
387
first_limit = int(first_limit)
388
second_limit = int(second_limit)
389
n_aux = int(n_aux)
390
second_descent = int(second_descent) # convert from bool to (int) 0 or 1
391
# TODO: Don't allow limits above some value...???
392
# (since otherwise mwrank just sets limit tiny)
393
self.__descent = _two_descent()
394
self.__descent.do_descent(self.__curve,
395
verbose,
396
selmer_only,
397
first_limit,
398
second_limit,
399
n_aux,
400
second_descent)
401
if not self.__two_descent_data().ok():
402
raise RuntimeError, "A 2-descent did not complete successfully."
403
404
def __two_descent_data(self):
405
r"""
406
Returns the 2-descent data for this elliptic curve.
407
408
EXAMPLES::
409
410
sage: E = mwrank_EllipticCurve([0,-1,1,0,0])
411
sage: E._mwrank_EllipticCurve__two_descent_data()
412
<sage.libs.mwrank.mwrank._two_descent object at ...>
413
"""
414
try:
415
return self.__descent
416
except AttributeError:
417
self.two_descent(self.__verbose)
418
return self.__descent
419
420
def conductor(self):
421
"""
422
Return the conductor of this curve, computed using Cremona's
423
implementation of Tate's algorithm.
424
425
.. note::
426
427
This is independent of PARI's.
428
429
EXAMPLES::
430
431
sage: E = mwrank_EllipticCurve([1, 1, 0, -6958, -224588])
432
sage: E.conductor()
433
2310
434
"""
435
return self.__curve.conductor()
436
437
def rank(self):
438
"""
439
Returns the rank of this curve, computed using :meth:`two_descent()`.
440
441
In general this may only be a lower bound for the rank; an
442
upper bound may be obtained using the function :meth:`rank_bound()`.
443
To test whether the value has been proved to be correct, use
444
the method :meth:`certain()`.
445
446
EXAMPLES::
447
448
sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098])
449
sage: E.rank()
450
0
451
sage: E.certain()
452
True
453
454
::
455
456
sage: E = mwrank_EllipticCurve([0, -1, 1, -929, -10595])
457
sage: E.rank()
458
0
459
sage: E.certain()
460
False
461
462
"""
463
return self.__two_descent_data().getrank()
464
465
def rank_bound(self):
466
"""
467
Returns an upper bound for the rank of this curve, computed
468
using :meth:`two_descent()`.
469
470
If the curve has no 2-torsion, this is equal to the 2-Selmer
471
rank. If the curve has 2-torsion, the upper bound may be
472
smaller than the bound obtained from the 2-Selmer rank minus
473
the 2-rank of the torsion, since more information is gained
474
from the 2-isogenous curve or curves.
475
476
EXAMPLES:
477
478
The following is the curve 960D1, which has rank 0,
479
but Sha of order 4::
480
481
sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098])
482
sage: E.rank_bound()
483
0
484
sage: E.rank()
485
0
486
487
In this case the rank was computed using a second descent,
488
which is able to determine (by considering a 2-isogenous
489
curve) that Sha is nontrivial. If we deliberately stop the
490
second descent, the rank bound is larger::
491
492
sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098])
493
sage: E.two_descent(second_descent = False, verbose=False)
494
sage: E.rank_bound()
495
2
496
497
In contrast, for the curve 571A, also with rank 0 and Sha
498
of order 4, we only obtain an upper bound of 2::
499
500
sage: E = mwrank_EllipticCurve([0, -1, 1, -929, -10595])
501
sage: E.rank_bound()
502
2
503
504
In this case the value returned by :meth:`rank()` is only a
505
lower bound in general (though this is correct)::
506
507
sage: E.rank()
508
0
509
sage: E.certain()
510
False
511
512
"""
513
return self.__two_descent_data().getrankbound()
514
515
def selmer_rank(self):
516
r"""
517
Returns the rank of the 2-Selmer group of the curve.
518
519
EXAMPLES:
520
521
The following is the curve 960D1, which has rank 0, but Sha of
522
order 4. The 2-torsion has rank 2, and the Selmer rank is 3::
523
524
sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098])
525
sage: E.selmer_rank()
526
3
527
528
Nevertheless, we can obtain a tight upper bound on the rank
529
since a second descent is performed which establishes the
530
2-rank of Sha::
531
532
sage: E.rank_bound()
533
0
534
535
To show that this was resolved using a second descent, we do
536
the computation again but turn off ``second_descent``::
537
538
sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098])
539
sage: E.two_descent(second_descent = False, verbose=False)
540
sage: E.rank_bound()
541
2
542
543
For the curve 571A, also with rank 0 and Sha of order 4,
544
but with no 2-torsion, the Selmer rank is strictly greater
545
than the rank::
546
547
sage: E = mwrank_EllipticCurve([0, -1, 1, -929, -10595])
548
sage: E.selmer_rank()
549
2
550
sage: E.rank_bound()
551
2
552
553
In cases like this with no 2-torsion, the rank upper bound is
554
always equal to the 2-Selmer rank. If we ask for the rank,
555
all we get is a lower bound::
556
557
sage: E.rank()
558
0
559
sage: E.certain()
560
False
561
562
"""
563
return self.__two_descent_data().getselmer()
564
565
def regulator(self):
566
r"""
567
Return the regulator of the saturated Mordell-Weil group.
568
569
EXAMPLES::
570
571
sage: E = mwrank_EllipticCurve([0, 0, 1, -1, 0])
572
sage: E.regulator()
573
0.05111140823996884
574
"""
575
self.saturate()
576
if not self.certain():
577
raise RuntimeError, "Unable to saturate Mordell-Weil group."
578
R = self.__two_descent_data().regulator()
579
return float(R)
580
581
def saturate(self, bound=-1):
582
"""
583
Compute the saturation of the Mordell-Weil group at all
584
primes up to ``bound``.
585
586
INPUT:
587
588
- ``bound`` (int, default -1) -- Use `-1` (the default) to
589
saturate at *all* primes, `0` for no saturation, or `n` (a
590
positive integer) to saturate at all primes up to `n`.
591
592
EXAMPLES:
593
594
Since the 2-descent automatically saturates at primes up to
595
20, it is not easy to come up with an example where saturation
596
has any effect::
597
598
sage: E = mwrank_EllipticCurve([0, 0, 0, -1002231243161, 0])
599
sage: E.gens()
600
[[-1001107, -4004428, 1]]
601
sage: E.saturate()
602
sage: E.gens()
603
[[-1001107, -4004428, 1]]
604
605
"""
606
bound = int(bound)
607
if self.__saturate < bound:
608
self.__two_descent_data().saturate(bound)
609
self.__saturate = bound
610
611
def gens(self):
612
"""
613
Return a list of the generators for the Mordell-Weil group.
614
615
EXAMPLES::
616
617
sage: E = mwrank_EllipticCurve([0, 0, 1, -1, 0])
618
sage: E.gens()
619
[[0, -1, 1]]
620
"""
621
self.saturate()
622
from sage.misc.all import preparse
623
from sage.rings.all import Integer
624
return eval(preparse(self.__two_descent_data().getbasis().replace(":",",")))
625
626
def certain(self):
627
r"""
628
Returns ``True`` if the last :meth:`two_descent()` call provably correctly
629
computed the rank. If :meth:`two_descent()` hasn't been
630
called, then it is first called by :meth:`certain()`
631
using the default parameters.
632
633
The result is ``True`` if and only if the results of the methods
634
:meth:`rank()` and :meth:`rank_bound()` are equal.
635
636
EXAMPLES:
637
638
A 2-descent does not determine `E(\QQ)` with certainty
639
for the curve `y^2 + y = x^3 - x^2 - 120x - 2183`::
640
641
sage: E = mwrank_EllipticCurve([0, -1, 1, -120, -2183])
642
sage: E.two_descent(False)
643
...
644
sage: E.certain()
645
False
646
sage: E.rank()
647
0
648
649
The previous value is only a lower bound; the upper bound is greater::
650
651
sage: E.rank_bound()
652
2
653
654
In fact the rank of `E` is actually 0 (as one could see by
655
computing the `L`-function), but Sha has order 4 and the
656
2-torsion is trivial, so mwrank cannot conclusively
657
determine the rank in this case.
658
"""
659
return bool(self.__two_descent_data().getcertain())
660
661
#def fullmw(self):
662
# return self.__two_descent_data().getfullmw()
663
664
def CPS_height_bound(self):
665
r"""
666
Return the Cremona-Prickett-Siksek height bound. This is a
667
floating point number `B` such that if `P` is a point on the
668
curve, then the naive logarithmic height `h(P)` is less than
669
`B+\hat{h}(P)`, where `\hat{h}(P)` is the canonical height of
670
`P`.
671
672
.. warning::
673
674
We assume the model is minimal!
675
676
EXAMPLES::
677
678
sage: E = mwrank_EllipticCurve([0, 0, 0, -1002231243161, 0])
679
sage: E.CPS_height_bound()
680
14.163198527061496
681
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
682
sage: E.CPS_height_bound()
683
0.0
684
"""
685
return self.__curve.cps_bound()
686
687
def silverman_bound(self):
688
r"""
689
Return the Silverman height bound. This is a floating point
690
number `B` such that if `P` is a point on the curve, then the
691
naive logarithmic height `h(P)` is less than `B+\hat{h}(P)`,
692
where `\hat{h}(P)` is the canonical height of `P`.
693
694
.. warning::
695
696
We assume the model is minimal!
697
698
EXAMPLES::
699
700
sage: E = mwrank_EllipticCurve([0, 0, 0, -1002231243161, 0])
701
sage: E.silverman_bound()
702
18.29545210468247
703
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
704
sage: E.silverman_bound()
705
6.284833369972403
706
"""
707
return self.__curve.silverman_bound()
708
709
710
class mwrank_MordellWeil(SageObject):
711
r"""
712
The :class:`mwrank_MordellWeil` class represents a subgroup of a
713
Mordell-Weil group. Use this class to saturate a specified list
714
of points on an :class:`mwrank_EllipticCurve`, or to search for
715
points up to some bound.
716
717
INPUT:
718
719
- ``curve`` (:class:`mwrank_EllipticCurve`) -- the underlying
720
elliptic curve.
721
722
- ``verbose`` (bool, default ``False``) -- verbosity flag (controls
723
amount of output produced in point searches).
724
725
- ``pp`` (int, default 1) -- process points flag (if nonzero,
726
the points found are processed, so that at all times only a
727
`\ZZ`-basis for the subgroup generated by the points found
728
so far is stored; if zero, no processing is done and all
729
points found are stored).
730
731
- ``maxr`` (int, default 999) -- maximum rank (quit point
732
searching once the points found generate a subgroup of this
733
rank; useful if an upper bound for the rank is already
734
known).
735
736
EXAMPLE::
737
738
sage: E = mwrank_EllipticCurve([1,0,1,4,-6])
739
sage: EQ = mwrank_MordellWeil(E)
740
sage: EQ
741
Subgroup of Mordell-Weil group: []
742
sage: EQ.search(2) # output below
743
744
The previous command produces the following output::
745
746
P1 = [0:1:0] is torsion point, order 1
747
P1 = [1:-1:1] is torsion point, order 2
748
P1 = [2:2:1] is torsion point, order 3
749
P1 = [9:23:1] is torsion point, order 6
750
751
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
752
sage: EQ = mwrank_MordellWeil(E)
753
sage: EQ.search(2)
754
sage: EQ
755
Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
756
757
Example to illustrate the verbose parameter::
758
759
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
760
sage: EQ = mwrank_MordellWeil(E, verbose=False)
761
sage: EQ.search(1) # no output
762
sage: EQ
763
Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
764
765
sage: EQ = mwrank_MordellWeil(E, verbose=True)
766
sage: EQ.search(1) # output below
767
768
The previous command produces the following output::
769
770
P1 = [0:1:0] is torsion point, order 1
771
P1 = [-3:0:1] is generator number 1
772
saturating up to 20...Checking 2-saturation
773
Points have successfully been 2-saturated (max q used = 7)
774
Checking 3-saturation
775
Points have successfully been 3-saturated (max q used = 7)
776
Checking 5-saturation
777
Points have successfully been 5-saturated (max q used = 23)
778
Checking 7-saturation
779
Points have successfully been 7-saturated (max q used = 41)
780
Checking 11-saturation
781
Points have successfully been 11-saturated (max q used = 17)
782
Checking 13-saturation
783
Points have successfully been 13-saturated (max q used = 43)
784
Checking 17-saturation
785
Points have successfully been 17-saturated (max q used = 31)
786
Checking 19-saturation
787
Points have successfully been 19-saturated (max q used = 37)
788
done
789
P2 = [-2:3:1] is generator number 2
790
saturating up to 20...Checking 2-saturation
791
possible kernel vector = [1,1]
792
This point may be in 2E(Q): [14:-52:1]
793
...and it is!
794
Replacing old generator #1 with new generator [1:-1:1]
795
Points have successfully been 2-saturated (max q used = 7)
796
Index gain = 2^1
797
Checking 3-saturation
798
Points have successfully been 3-saturated (max q used = 13)
799
Checking 5-saturation
800
Points have successfully been 5-saturated (max q used = 67)
801
Checking 7-saturation
802
Points have successfully been 7-saturated (max q used = 53)
803
Checking 11-saturation
804
Points have successfully been 11-saturated (max q used = 73)
805
Checking 13-saturation
806
Points have successfully been 13-saturated (max q used = 103)
807
Checking 17-saturation
808
Points have successfully been 17-saturated (max q used = 113)
809
Checking 19-saturation
810
Points have successfully been 19-saturated (max q used = 47)
811
done (index = 2).
812
Gained index 2, new generators = [ [1:-1:1] [-2:3:1] ]
813
P3 = [-14:25:8] is generator number 3
814
saturating up to 20...Checking 2-saturation
815
Points have successfully been 2-saturated (max q used = 11)
816
Checking 3-saturation
817
Points have successfully been 3-saturated (max q used = 13)
818
Checking 5-saturation
819
Points have successfully been 5-saturated (max q used = 71)
820
Checking 7-saturation
821
Points have successfully been 7-saturated (max q used = 101)
822
Checking 11-saturation
823
Points have successfully been 11-saturated (max q used = 127)
824
Checking 13-saturation
825
Points have successfully been 13-saturated (max q used = 151)
826
Checking 17-saturation
827
Points have successfully been 17-saturated (max q used = 139)
828
Checking 19-saturation
829
Points have successfully been 19-saturated (max q used = 179)
830
done (index = 1).
831
P4 = [-1:3:1] = -1*P1 + -1*P2 + -1*P3 (mod torsion)
832
P4 = [0:2:1] = 2*P1 + 0*P2 + 1*P3 (mod torsion)
833
P4 = [2:13:8] = -3*P1 + 1*P2 + -1*P3 (mod torsion)
834
P4 = [1:0:1] = -1*P1 + 0*P2 + 0*P3 (mod torsion)
835
P4 = [2:0:1] = -1*P1 + 1*P2 + 0*P3 (mod torsion)
836
P4 = [18:7:8] = -2*P1 + -1*P2 + -1*P3 (mod torsion)
837
P4 = [3:3:1] = 1*P1 + 0*P2 + 1*P3 (mod torsion)
838
P4 = [4:6:1] = 0*P1 + -1*P2 + -1*P3 (mod torsion)
839
P4 = [36:69:64] = 1*P1 + -2*P2 + 0*P3 (mod torsion)
840
P4 = [68:-25:64] = -2*P1 + -1*P2 + -2*P3 (mod torsion)
841
P4 = [12:35:27] = 1*P1 + -1*P2 + -1*P3 (mod torsion)
842
sage: EQ
843
Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
844
845
Example to illustrate the process points (``pp``) parameter::
846
847
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
848
sage: EQ = mwrank_MordellWeil(E, verbose=False, pp=1)
849
sage: EQ.search(1); EQ # generators only
850
Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
851
sage: EQ = mwrank_MordellWeil(E, verbose=False, pp=0)
852
sage: EQ.search(1); EQ # all points found
853
Subgroup of Mordell-Weil group: [[-3:0:1], [-2:3:1], [-14:25:8], [-1:3:1], [0:2:1], [2:13:8], [1:0:1], [2:0:1], [18:7:8], [3:3:1], [4:6:1], [36:69:64], [68:-25:64], [12:35:27]]
854
"""
855
856
def __init__(self, curve, verbose=True, pp=1, maxr=999):
857
r"""
858
Constructor for the :class:`mwrank_MordellWeil` class.
859
860
See the docstring of this class for full documentation.
861
862
EXAMPLE::
863
864
sage: E = mwrank_EllipticCurve([1,0,1,4,-6])
865
sage: EQ = mwrank_MordellWeil(E)
866
sage: EQ
867
Subgroup of Mordell-Weil group: []
868
"""
869
if not isinstance(curve, mwrank_EllipticCurve):
870
raise TypeError, "curve (=%s) must be an mwrank_EllipticCurve"%curve
871
self.__curve = curve
872
self.__verbose = verbose
873
self.__pp = pp
874
self.__maxr = maxr
875
if verbose:
876
verb = 1
877
else:
878
verb = 0
879
from sage.libs.mwrank.mwrank import _mw # import here to save time
880
self.__mw = _mw(curve._curve_data(), verb, pp, maxr)
881
882
def __reduce__(self):
883
r"""
884
Standard Python function used in pickling.
885
886
EXAMPLES::
887
888
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
889
sage: EQ = mwrank_MordellWeil(E)
890
sage: EQ.__reduce__()
891
(<class 'sage.libs.mwrank.interface.mwrank_MordellWeil'>, (y^2+ y = x^3 - 7*x + 6, True, 1, 999))
892
"""
893
return mwrank_MordellWeil, (self.__curve, self.__verbose, self.__pp, self.__maxr)
894
895
def __repr__(self):
896
r"""
897
String representation of this Mordell-Weil subgroup.
898
899
OUTPUT:
900
901
(string) String representation of this Mordell-Weil subgroup.
902
903
EXAMPLE::
904
905
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
906
sage: EQ = mwrank_MordellWeil(E, verbose=False)
907
sage: EQ.__repr__()
908
'Subgroup of Mordell-Weil group: []'
909
sage: EQ.search(1)
910
sage: EQ.__repr__()
911
'Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]'
912
"""
913
# FIXED: Changing "Mordell Weil" to "Mordell-Weil" did break doctests...
914
return "Subgroup of Mordell-Weil group: %s"%self.__mw
915
916
def process(self, v, sat=0):
917
"""
918
This function allows one to add points to a :class:`mwrank_MordellWeil` object.
919
920
Process points in the list ``v``, with saturation at primes up to
921
``sat``. If ``sat`` is zero (the default), do no saturation.
922
923
INPUT:
924
925
- ``v`` (list of 3-tuples or lists of ints or Integers) -- a
926
list of triples of integers, which define points on the
927
curve.
928
929
- ``sat`` (int, default 0) -- saturate at primes up to ``sat``, or at
930
*all* primes if ``sat`` is zero.
931
932
OUTPUT:
933
934
None. But note that if the ``verbose`` flag is set, then there
935
will be some output as a side-effect.
936
937
EXAMPLES::
938
939
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
940
sage: E.gens()
941
[[1, -1, 1], [-2, 3, 1], [-14, 25, 8]]
942
sage: EQ = mwrank_MordellWeil(E)
943
sage: EQ.process([[1, -1, 1], [-2, 3, 1], [-14, 25, 8]])
944
945
Output of previous command::
946
947
P1 = [1:-1:1] is generator number 1
948
P2 = [-2:3:1] is generator number 2
949
P3 = [-14:25:8] is generator number 3
950
951
::
952
953
sage: EQ.points()
954
[[1, -1, 1], [-2, 3, 1], [-14, 25, 8]]
955
956
Example to illustrate the saturation parameter ``sat``::
957
958
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
959
sage: EQ = mwrank_MordellWeil(E)
960
sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], sat=20)
961
sage: EQ.points()
962
[[-2, 3, 1], [-14, 25, 8], [1, -1, 1]]
963
964
Here the processing was followed by saturation at primes up to
965
20. Now we prevent this initial saturation::
966
967
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
968
sage: EQ = mwrank_MordellWeil(E)
969
sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], sat=0)
970
sage: EQ.points()
971
[[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]]
972
sage: EQ.regulator()
973
375.42919921875
974
sage: EQ.saturate(2) # points were not 2-saturated
975
(False, 2, '[ ]')
976
sage: EQ.points()
977
[[-2, 3, 1], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]]
978
sage: EQ.regulator()
979
93.8572998046875
980
sage: EQ.saturate(3) # points were not 3-saturated
981
(False, 3, '[ ]')
982
sage: EQ.points()
983
[[-2, 3, 1], [-14, 25, 8], [-13422227300, -49322830557, 12167000000]]
984
sage: EQ.regulator()
985
10.4285888671875
986
sage: EQ.saturate(5) # points were not 5-saturated
987
(False, 5, '[ ]')
988
sage: EQ.points()
989
[[-2, 3, 1], [-14, 25, 8], [1, -1, 1]]
990
sage: EQ.regulator()
991
0.4171435534954071
992
sage: EQ.saturate() # points are now saturated
993
(True, 1, '[ ]')
994
"""
995
if not isinstance(v, list):
996
raise TypeError, "v (=%s) must be a list"%v
997
sat = int(sat)
998
for P in v:
999
if not isinstance(P, (list,tuple)) or len(P) != 3:
1000
raise TypeError, "v (=%s) must be a list of 3-tuples (or 3-element lists) of ints"%v
1001
self.__mw.process(P, sat)
1002
1003
def regulator(self):
1004
"""
1005
Return the regulator of the points in this subgroup of
1006
the Mordell-Weil group.
1007
1008
.. note::
1009
1010
``eclib`` can compute the regulator to arbitrary precision,
1011
but the interface currently returns the output as a ``float``.
1012
1013
OUTPUT:
1014
1015
(float) The regulator of the points in this subgroup.
1016
1017
EXAMPLES::
1018
1019
sage: E = mwrank_EllipticCurve([0,-1,1,0,0])
1020
sage: E.regulator()
1021
1.0
1022
1023
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
1024
sage: E.regulator()
1025
0.417143558758384
1026
"""
1027
return self.__mw.regulator()
1028
1029
def rank(self):
1030
"""
1031
Return the rank of this subgroup of the Mordell-Weil group.
1032
1033
OUTPUT:
1034
1035
(int) The rank of this subgroup of the Mordell-Weil group.
1036
1037
EXAMPLES::
1038
1039
sage: E = mwrank_EllipticCurve([0,-1,1,0,0])
1040
sage: E.rank()
1041
0
1042
1043
A rank 3 example::
1044
1045
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
1046
sage: EQ = mwrank_MordellWeil(E)
1047
sage: EQ.rank()
1048
0
1049
sage: EQ.regulator()
1050
1.0
1051
1052
The preceding output is correct, since we have not yet tried
1053
to find any points on the curve either by searching or
1054
2-descent::
1055
1056
sage: EQ
1057
Subgroup of Mordell-Weil group: []
1058
1059
Now we do a very small search::
1060
1061
sage: EQ.search(1)
1062
sage: EQ
1063
Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
1064
sage: EQ.rank()
1065
3
1066
sage: EQ.regulator()
1067
0.4171435534954071
1068
1069
We do in fact now have a full Mordell-Weil basis.
1070
1071
"""
1072
return self.__mw.rank()
1073
1074
def saturate(self, max_prime=-1, odd_primes_only=False):
1075
r"""
1076
Saturate this subgroup of the Mordell-Weil group.
1077
1078
INPUT:
1079
1080
- ``max_prime`` (int, default -1) -- saturation is performed for
1081
all primes up to ``max_prime``. If `-1` (the default), an
1082
upper bound is computed for the primes at which the subgroup
1083
may not be saturated, and this is used; however, if the
1084
computed bound is greater than a value set by the ``eclib``
1085
library (currently 97) then no saturation will be attempted
1086
at primes above this.
1087
1088
- ``odd_primes_only`` (bool, default ``False``) -- only do
1089
saturation at odd primes. (If the points have been found
1090
via :meth:``two_descent()`` they should already be 2-saturated.)
1091
1092
OUTPUT:
1093
1094
(3-tuple) (``ok``, ``index``, ``unsatlist``) where:
1095
1096
- ``ok`` (bool) -- ``True`` if and only if the saturation was
1097
provably successful at all primes attempted. If the default
1098
was used for ``max_prime`` and no warning was output about
1099
the computed saturation bound being too high, then ``True``
1100
indicates that the subgroup is saturated at *all*
1101
primes.
1102
1103
- ``index`` (int) -- the index of the group generated by the
1104
original points in their saturation.
1105
1106
- ``unsatlist`` (list of ints) -- list of primes at which
1107
saturation could not be proved or achieved. Increasing the
1108
decimal precision should correct this, since it happens when
1109
a linear combination of the points appears to be a multiple
1110
of `p` but cannot be divided by `p`. (Note that ``eclib``
1111
uses floating point methods based on elliptic logarithms to
1112
divide points.)
1113
1114
.. note::
1115
1116
We emphasize that if this function returns ``True`` as the
1117
first return argument (``ok``), and if the default was used for the
1118
parameter ``max_prime``, then the points in the basis after
1119
calling this function are saturated at *all* primes,
1120
i.e., saturating at the primes up to ``max_prime`` are
1121
sufficient to saturate at all primes. Note that the
1122
function might not have needed to saturate at all primes up
1123
to ``max_prime``. It has worked out what prime you need to
1124
saturate up to, and that prime might be smaller than ``max_prime``.
1125
1126
.. note::
1127
1128
Currently (May 2010), this does not remember the result of
1129
calling :meth:`search()`. So calling :meth:`search()` up
1130
to height 20 then calling :meth:`saturate()` results in
1131
another search up to height 18.
1132
1133
EXAMPLES::
1134
1135
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
1136
sage: EQ = mwrank_MordellWeil(E)
1137
1138
We initialise with three points which happen to be 2, 3 and 5
1139
times the generators of this rank 3 curve. To prevent
1140
automatic saturation at this stage we set the parameter
1141
``sat`` to 0 (which is in fact the default)::
1142
1143
sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], sat=0)
1144
sage: EQ
1145
Subgroup of Mordell-Weil group: [[1547:-2967:343], [2707496766203306:864581029138191:2969715140223272], [-13422227300:-49322830557:12167000000]]
1146
sage: EQ.regulator()
1147
375.42919921875
1148
1149
Now we saturate at `p=2`, and gain index 2::
1150
1151
sage: EQ.saturate(2) # points were not 2-saturated
1152
(False, 2, '[ ]')
1153
sage: EQ
1154
Subgroup of Mordell-Weil group: [[-2:3:1], [2707496766203306:864581029138191:2969715140223272], [-13422227300:-49322830557:12167000000]]
1155
sage: EQ.regulator()
1156
93.8572998046875
1157
1158
Now we saturate at `p=3`, and gain index 3::
1159
1160
sage: EQ.saturate(3) # points were not 3-saturated
1161
(False, 3, '[ ]')
1162
sage: EQ
1163
Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [-13422227300:-49322830557:12167000000]]
1164
sage: EQ.regulator()
1165
10.4285888671875
1166
1167
Now we saturate at `p=5`, and gain index 5::
1168
1169
sage: EQ.saturate(5) # points were not 5-saturated
1170
(False, 5, '[ ]')
1171
sage: EQ
1172
Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [1:-1:1]]
1173
sage: EQ.regulator()
1174
0.4171435534954071
1175
1176
Finally we finish the saturation. The output here shows that
1177
the points are now provably saturated at all primes::
1178
1179
sage: EQ.saturate() # points are now saturated
1180
(True, 1, '[ ]')
1181
1182
Of course, the :meth:`process()` function would have done all this
1183
automatically for us::
1184
1185
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
1186
sage: EQ = mwrank_MordellWeil(E)
1187
sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], sat=5)
1188
sage: EQ
1189
Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [1:-1:1]]
1190
sage: EQ.regulator()
1191
0.4171435534954071
1192
1193
But we would still need to use the :meth:`saturate()` function to
1194
verify that full saturation has been done::
1195
1196
sage: EQ.saturate()
1197
(True, 1, '[ ]')
1198
1199
The preceding command produces the following output as a
1200
side-effect. It proves that the index of the points in their
1201
saturation is at most 3, then proves saturation at 2 and at 3,
1202
by reducing the points modulo all primes of good reduction up
1203
to 11, respectively 13::
1204
1205
saturating basis...Saturation index bound = 3
1206
Checking saturation at [ 2 3 ]
1207
Checking 2-saturation
1208
Points were proved 2-saturated (max q used = 11)
1209
Checking 3-saturation
1210
Points were proved 3-saturated (max q used = 13)
1211
done
1212
"""
1213
ok, index, unsat = self.__mw.saturate(int(max_prime), odd_primes_only)
1214
return bool(ok), int(str(index)), unsat
1215
1216
def search(self, height_limit=18, verbose=False):
1217
r"""
1218
Search for new points, and add them to this subgroup of the
1219
Mordell-Weil group.
1220
1221
INPUT:
1222
1223
- ``height_limit`` (float, default: 18) -- search up to this
1224
logarithmic height.
1225
1226
.. note::
1227
1228
On 32-bit machines, this *must* be < 21.48 else
1229
`\exp(h_{\text{lim}}) > 2^{31}` and overflows. On 64-bit machines, it
1230
must be *at most* 43.668. However, this bound is a logarithmic
1231
bound and increasing it by just 1 increases the running time
1232
by (roughly) `\exp(1.5)=4.5`, so searching up to even 20
1233
takes a very long time.
1234
1235
.. note::
1236
1237
The search is carried out with a quadratic sieve, using
1238
code adapted from a version of Michael Stoll's
1239
``ratpoints`` program. It would be preferable to use a
1240
newer version of ``ratpoints``.
1241
1242
- ``verbose`` (bool, default ``False``) -- turn verbose operation on
1243
or off.
1244
1245
EXAMPLES:
1246
1247
A rank 3 example, where a very small search is sufficient to
1248
find a Mordell-Weil basis::
1249
1250
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
1251
sage: EQ = mwrank_MordellWeil(E)
1252
sage: EQ.search(1)
1253
sage: EQ
1254
Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
1255
1256
In the next example, a search bound of 12 is needed to find a
1257
non-torsion point::
1258
1259
sage: E = mwrank_EllipticCurve([0, -1, 0, -18392, -1186248]) #1056g4
1260
sage: EQ = mwrank_MordellWeil(E)
1261
sage: EQ.search(11); EQ
1262
Subgroup of Mordell-Weil group: []
1263
sage: EQ.search(12); EQ
1264
Subgroup of Mordell-Weil group: [[4413270:10381877:27000]]
1265
"""
1266
height_limit = float(height_limit)
1267
if height_limit >= 21.4: # TODO: docstring says 21.48 (for 32-bit machines; what about 64-bit...?)
1268
raise ValueError, "The height limit must be < 21.4."
1269
1270
moduli_option = 0 # Use Stoll's sieving program... see strategies in ratpoints-1.4.c
1271
1272
## moduli_option -- int (default: 0); if > 0; a flag used to determine
1273
## the moduli that are used in sieving
1274
## 1 -- first 10 odd primes; the first one you
1275
## would think of.
1276
## 2 -- three composites; $2^6\cdot 3^4$, ... TODO
1277
## (from German mathematician J. Gebel;
1278
## personal conversation about SIMATH)
1279
## 3 -- nine prime powers; $2^5, \ldots$;
1280
## like 1 but includes powers of small primes
1281
## TODO: Extract the meaning from mwprocs.cc; line 776 etc.
1282
1283
verbose = bool(verbose)
1284
self.__mw.search(height_limit, moduli_option, verbose)
1285
1286
def points(self):
1287
"""
1288
Return a list of the generating points in this Mordell-Weil
1289
group.
1290
1291
OUTPUT:
1292
1293
(list) A list of lists of length 3, each holding the
1294
primitive integer coordinates `[x,y,z]` of a generating
1295
point.
1296
1297
EXAMPLES::
1298
1299
sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
1300
sage: EQ = mwrank_MordellWeil(E)
1301
sage: EQ.search(1)
1302
sage: EQ.points()
1303
[[1, -1, 1], [-2, 3, 1], [-14, 25, 8]]
1304
1305
"""
1306
from sage.misc.all import preparse
1307
from sage.rings.all import Integer
1308
return eval(preparse(self.__mw.getbasis().replace(":",",")))
1309
1310
1311
1312