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