Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/libs/mwrank/mwrank.pyx
8815 views
1
"""
2
Cython interface to Cremona's ``eclib`` library (also known as ``mwrank``)
3
4
EXAMPLES::
5
6
sage: from sage.libs.mwrank.mwrank import _Curvedata, _mw
7
sage: c = _Curvedata(1,2,3,4,5)
8
9
sage: print c
10
[1,2,3,4,5]
11
b2 = 9 b4 = 11 b6 = 29 b8 = 35
12
c4 = -183 c6 = -3429
13
disc = -10351 (# real components = 1)
14
#torsion not yet computed
15
16
sage: t= _mw(c)
17
sage: t.search(10)
18
sage: t
19
[[1:2:1]]
20
"""
21
22
import os
23
import sys
24
25
include 'sage/ext/interrupt.pxi'
26
include 'sage/ext/stdsage.pxi'
27
28
# Need to permit tabs in order to doctest verbose output.
29
"""
30
SAGE_DOCTEST_ALLOW_TABS
31
"""
32
33
cdef extern from "wrap.h":
34
### misc functions ###
35
long mwrank_get_precision()
36
void mwrank_set_precision(long n)
37
void mwrank_initprimes(char* pfilename, int verb)
38
39
40
### bigint ###
41
struct bigint
42
bigint* new_bigint()
43
void del_bigint(bigint* x)
44
bigint* str_to_bigint(char* s)
45
char* bigint_to_str(bigint* x)
46
47
### Curvedata ###
48
struct Curvedata
49
Curvedata* Curvedata_new(bigint* a1, bigint* a2,
50
bigint* a3, bigint* a4,
51
bigint* a6, int min_on_init)
52
void Curvedata_del(Curvedata* curve)
53
char* Curvedata_repr(Curvedata* curve)
54
double Curvedata_silverman_bound(Curvedata* curve)
55
double Curvedata_cps_bound(Curvedata* curve)
56
double Curvedata_height_constant(Curvedata* curve)
57
char* Curvedata_getdiscr(Curvedata* curve)
58
char* Curvedata_conductor(Curvedata* m)
59
char* Curvedata_isogeny_class(Curvedata* E, int verbose)
60
61
## mw ##
62
struct mw
63
mw* mw_new(Curvedata* curve, int verb, int pp, int maxr)
64
void mw_del(mw* m)
65
int mw_process(Curvedata* curve, mw* m,
66
bigint* x, bigint* y,
67
bigint* z, int sat)
68
char* mw_getbasis(mw* m)
69
char* mw_regulator(mw* m)
70
int mw_rank(mw* m)
71
int mw_saturate(mw* m, bigint* index, char** unsat,
72
long sat_bd, int odd_primes_only)
73
void mw_search(mw* m, char* h_lim, int moduli_option, int verb)
74
75
### two_descent ###
76
struct two_descent
77
two_descent* two_descent_new(Curvedata* curve,
78
int verb, int sel,
79
long firstlim, long secondlim,
80
long n_aux, int second_descent)
81
82
void two_descent_del(two_descent* t)
83
int two_descent_ok(two_descent* t)
84
long two_descent_get_certain(two_descent* t)
85
char* two_descent_get_basis(two_descent* t)
86
char* two_descent_regulator(two_descent* t)
87
long two_descent_get_rank(two_descent* t)
88
long two_descent_get_rank_bound(two_descent* t)
89
long two_descent_get_selmer_rank(two_descent* t)
90
void two_descent_saturate(two_descent* t, long sat_bd)
91
92
93
94
cdef object string_sigoff(char* s):
95
sig_off()
96
# Makes a python string and deletes what is pointed to by s.
97
t = str(s)
98
sage_free(s)
99
return t
100
101
class __init:
102
pass
103
104
_INIT = __init()
105
# set the default
106
mwrank_set_precision(50)
107
108
def get_precision():
109
"""
110
Returns the working floating point precision of mwrank.
111
112
OUTPUT:
113
114
(int) The current precision in decimal digits.
115
116
EXAMPLE::
117
118
sage: from sage.libs.mwrank.mwrank import get_precision
119
sage: get_precision()
120
50
121
"""
122
return mwrank_get_precision()
123
124
def set_precision(n):
125
"""
126
Sets the working floating point precision of mwrank.
127
128
INPUT:
129
130
- ``n`` (int) -- a positive integer: the number of decimal digits.
131
132
OUTPUT:
133
134
None.
135
136
EXAMPLE::
137
138
sage: from sage.libs.mwrank.mwrank import set_precision
139
sage: set_precision(50)
140
141
"""
142
mwrank_set_precision(n)
143
144
def initprimes(filename, verb=False):
145
"""
146
Initialises mwrank/eclib's internal prime list.
147
148
INPUT:
149
150
- ``filename`` (string) -- the name of a file of primes.
151
152
- ``verb`` (bool: default ``False``) -- verbose or not?
153
154
EXAMPLES::
155
156
sage: file = os.path.join(SAGE_TMP, 'PRIMES')
157
sage: open(file,'w').write(' '.join([str(p) for p in prime_range(10^7,10^7+20)]))
158
sage: mwrank_initprimes(file, verb=True)
159
Computed 78519 primes, largest is 1000253
160
reading primes from file ...
161
read extra prime 10000019
162
finished reading primes from file ...
163
Extra primes in list: 10000019
164
165
sage: mwrank_initprimes("x" + file, True)
166
Traceback (most recent call last):
167
...
168
IOError: No such file or directory: ...
169
"""
170
if not os.path.exists(filename):
171
raise IOError, 'No such file or directory: %s'%filename
172
mwrank_initprimes(filename, verb)
173
if verb:
174
sys.stdout.flush()
175
sys.stderr.flush()
176
177
############# bigint ###########################################
178
#
179
# In mwrank (and eclib) bigint is synonymous with NTL's ZZ class.
180
#
181
################################################################
182
183
cdef class _bigint:
184
"""
185
Cython class wrapping eclib's bigint class.
186
"""
187
cdef bigint* x
188
189
def __init__(self, x="0"):
190
"""
191
Constructor for bigint class.
192
193
INPUT:
194
195
- ``x`` -- string or int: a string representing a decimal
196
integer, or a Sage integer
197
198
EXAMPLES::
199
200
sage: from sage.libs.mwrank.mwrank import _bigint
201
sage: _bigint(123)
202
123
203
sage: _bigint('123')
204
123
205
sage: type(_bigint(123))
206
<type 'sage.libs.mwrank.mwrank._bigint'>
207
"""
208
if not (x is _INIT):
209
s = str(x)
210
if s.isdigit() or s[0] == "-" and s[1:].isdigit():
211
self.x = str_to_bigint(s)
212
else:
213
raise ValueError, "invalid _bigint: %s"%x
214
215
def __dealloc__(self):
216
"""
217
Destructor for bigint class (releases memory).
218
"""
219
del_bigint(self.x)
220
221
def __repr__(self):
222
"""
223
String representation of bigint.
224
225
OUTPUT:
226
227
(string) the bigint as a string (decimal)
228
229
EXAMPLES::
230
231
sage: from sage.libs.mwrank.mwrank import _bigint
232
sage: a = _bigint('123')
233
sage: a.__repr__()
234
'123'
235
sage: a = _bigint('-456')
236
sage: a.__repr__()
237
'-456'
238
"""
239
sig_on()
240
return string_sigoff(bigint_to_str(self.x))
241
242
243
cdef make_bigint(bigint* x):
244
cdef _bigint y
245
sig_off()
246
y = _bigint(_INIT)
247
y.x = x
248
return y
249
250
############# Curvedata #################
251
252
cdef class _Curvedata: # cython class wrapping eclib's Curvedata class
253
cdef Curvedata* x
254
255
def __init__(self, a1, a2, a3,
256
a4, a6, min_on_init=0):
257
"""
258
Constructor for Curvedata class.
259
260
INPUT:
261
262
- ``a1``,``a2``,``a3``,``a4``,``a6`` (int) -- integer
263
coefficients of a Weierstrass equation (must be
264
nonsingular).
265
266
- ``min_on_init`` (int, default 0) -- flag controlling whether
267
the constructed curve is replaced by a global minimal model.
268
If nonzero then this minimisation does take place.
269
270
EXAMPLES::
271
272
sage: from sage.libs.mwrank.mwrank import _Curvedata
273
sage: _Curvedata(1,2,3,4,5)
274
[1,2,3,4,5]
275
b2 = 9 b4 = 11 b6 = 29 b8 = 35
276
c4 = -183 c6 = -3429
277
disc = -10351 (# real components = 1)
278
#torsion not yet computed
279
280
A non-minimal example::
281
282
sage: _Curvedata(0,0,0,0,64)
283
[0,0,0,0,64]
284
b2 = 0 b4 = 0 b6 = 256 b8 = 0
285
c4 = 0 c6 = -55296
286
disc = -1769472 (# real components = 1)
287
#torsion not yet computed
288
289
sage: _Curvedata(0,0,0,0,64,min_on_init=1)
290
[0,0,0,0,1] (reduced minimal model)
291
b2 = 0 b4 = 0 b6 = 4 b8 = 0
292
c4 = 0 c6 = -864
293
disc = -432 (# real components = 1)
294
#torsion not yet computed
295
"""
296
cdef _bigint _a1, _a2, _a3, _a4, _a6
297
_a1 = _bigint(a1)
298
_a2 = _bigint(a2)
299
_a3 = _bigint(a3)
300
_a4 = _bigint(a4)
301
_a6 = _bigint(a6)
302
self.x = Curvedata_new(_a1.x, _a2.x, _a3.x, _a4.x, _a6.x, min_on_init)
303
if self.discriminant() == 0:
304
raise ArithmeticError, "Invariants (= %s) do not describe an elliptic curve."%([a1,a2,a3,a4,a6])
305
306
def __dealloc__(self):
307
"""
308
Destructor for Curvedata class.
309
"""
310
Curvedata_del(self.x)
311
312
def __repr__(self):
313
"""
314
String representation of Curvedata
315
316
OUTPUT:
317
318
(string) the Curvedata as a string
319
320
EXAMPLES::
321
322
sage: from sage.libs.mwrank.mwrank import _Curvedata
323
sage: E = _Curvedata(1,2,3,4,5)
324
sage: E.__repr__()
325
'[1,2,3,4,5]\nb2 = 9\t b4 = 11\t b6 = 29\t b8 = 35\nc4 = -183\t\tc6 = -3429\ndisc = -10351\t(# real components = 1)\n#torsion not yet computed'
326
sage: E
327
[1,2,3,4,5]
328
b2 = 9 b4 = 11 b6 = 29 b8 = 35
329
c4 = -183 c6 = -3429
330
disc = -10351 (# real components = 1)
331
#torsion not yet computed
332
"""
333
sig_on()
334
return string_sigoff(Curvedata_repr(self.x))[:-1]
335
336
def silverman_bound(self):
337
"""
338
The Silverman height bound for this elliptic curve.
339
340
OUTPUT:
341
342
(float) A non-negative real number `B` such that for every
343
rational point on this elliptic curve `E`, `h(P)\le\hat{h}(P)
344
+ B`, where `h(P)` is the naive height and `\hat{h}(P)` the
345
canonical height.
346
347
TODO:
348
349
Since eclib can compute this to arbitrary precision it would
350
make sense to return a Sage real.
351
352
EXAMPLES::
353
354
sage: from sage.libs.mwrank.mwrank import _Curvedata
355
sage: E = _Curvedata(1,2,3,4,5)
356
sage: E.silverman_bound()
357
6.52226179519101...
358
sage: type(E.silverman_bound())
359
<type 'float'>
360
"""
361
return Curvedata_silverman_bound(self.x)
362
363
def cps_bound(self):
364
"""
365
The Cremona-Prickett-Siksek height bound for this elliptic curve.
366
367
OUTPUT:
368
369
(float) A non-negative real number `B` such that for every
370
rational point on this elliptic curve `E`, `h(P)\le\hat{h}(P)
371
+ B`, where `h(P)` is the naive height and `\hat{h}(P)` the
372
canonical height.
373
374
TODO:
375
376
Since eclib can compute this to arbitrary precision it would
377
make sense to return a Sage real.
378
379
EXAMPLES::
380
381
sage: from sage.libs.mwrank.mwrank import _Curvedata
382
sage: E = _Curvedata(1,2,3,4,5)
383
sage: E.cps_bound()
384
0.11912451909250982
385
386
Note that this is a better bound than Silverman's in this case::
387
388
sage: E.silverman_bound()
389
6.52226179519101...
390
"""
391
cdef double x
392
# We declare x so there are *no* Python library
393
# calls within the sig_on()/sig_off().
394
sig_on()
395
x = Curvedata_cps_bound(self.x)
396
sig_off()
397
return x
398
399
def height_constant(self):
400
"""
401
A height bound for this elliptic curve.
402
403
OUTPUT:
404
405
(float) A non-negative real number `B` such that for every
406
rational point on this elliptic curve `E`, `h(P)\le\hat{h}(P)
407
+ B`, where `h(P)` is the naive height and `\hat{h}(P)` the
408
canonical height. This is the minimum of the Silverman and
409
Cremona_Prickett-Siksek height bounds.
410
411
TODO:
412
413
Since eclib can compute this to arbitrary precision it would
414
make sense to return a Sage real.
415
416
EXAMPLES::
417
418
sage: from sage.libs.mwrank.mwrank import _Curvedata
419
sage: E = _Curvedata(1,2,3,4,5)
420
sage: E.height_constant()
421
0.11912451909250982
422
"""
423
return Curvedata_height_constant(self.x)
424
425
def discriminant(self):
426
"""
427
The discriminant of this elliptic curve.
428
429
OUTPUT:
430
431
(Integer) The discriminant.
432
433
EXAMPLES::
434
435
sage: from sage.libs.mwrank.mwrank import _Curvedata
436
sage: E = _Curvedata(1,2,3,4,5)
437
sage: E.discriminant()
438
-10351
439
sage: E = _Curvedata(100,200,300,400,500)
440
sage: E.discriminant()
441
-1269581104000000
442
sage: ZZ(E.discriminant())
443
-1269581104000000
444
"""
445
sig_on()
446
from sage.rings.all import Integer
447
return Integer(string_sigoff(Curvedata_getdiscr(self.x)))
448
449
def conductor(self):
450
"""
451
The conductor of this elliptic curve.
452
453
OUTPUT:
454
455
(Integer) The conductor.
456
457
458
EXAMPLES::
459
460
sage: from sage.libs.mwrank.mwrank import _Curvedata
461
sage: E = _Curvedata(1,2,3,4,5)
462
sage: E.discriminant()
463
-10351
464
sage: E = _Curvedata(100,200,300,400,500)
465
sage: E.conductor()
466
126958110400
467
"""
468
sig_on()
469
from sage.rings.all import Integer
470
return Integer(string_sigoff(Curvedata_conductor(self.x)))
471
472
def isogeny_class(self, verbose=False):
473
"""
474
The isogeny class of this elliptic curve.
475
476
OUTPUT:
477
478
(tuple) A tuple consisting of (1) a list of the curves in the
479
isogeny class, each as a list of its Weierstrass coefficients;
480
(2) a matrix of the degrees of the isogenies between the
481
curves in the class (prime degrees only).
482
483
.. warning::
484
485
The list may not be complete, if the precision is too low.
486
Use ``mwrank_set_precision()`` to increase the precision.
487
488
EXAMPLES::
489
490
sage: from sage.libs.mwrank.mwrank import _Curvedata
491
sage: E = _Curvedata(1,0,1,4,-6)
492
sage: E.conductor()
493
14
494
sage: E.isogeny_class()
495
([[1, 0, 1, 4, -6], [1, 0, 1, -36, -70], [1, 0, 1, -1, 0], [1, 0, 1, -171, -874], [1, 0, 1, -11, 12], [1, 0, 1, -2731, -55146]], [[0, 2, 3, 3, 0, 0], [2, 0, 0, 0, 3, 3], [3, 0, 0, 0, 2, 0], [3, 0, 0, 0, 0, 2], [0, 3, 2, 0, 0, 0], [0, 3, 0, 2, 0, 0]])
496
497
"""
498
sig_on()
499
s = string_sigoff(Curvedata_isogeny_class(self.x, verbose))
500
if verbose:
501
sys.stdout.flush()
502
sys.stderr.flush()
503
from sage.misc.all import preparse
504
from sage.rings.all import Integer
505
return eval(s)
506
507
508
############# _mw #################
509
510
cdef class _mw:
511
"""
512
Cython class wrapping eclib's mw class.
513
"""
514
cdef mw* x
515
cdef Curvedata* curve
516
cdef int verb
517
518
def __init__(self, _Curvedata curve, verb=False, pp=1, maxr=999):
519
"""
520
Constructor for mw class.
521
522
INPUT:
523
524
- ``curve`` (_Curvedata) -- an elliptic curve
525
526
- ``verb`` (bool, default False) -- verbosity flag (controls
527
amount of output produced in point searches)
528
529
- ``pp`` (int, default 1) -- process points flag (if nonzero,
530
the points found are processed, so that at all times only a
531
`\ZZ`-basis for the subgroup generated by the points found
532
so far is stored; if zero, no processing is done and all
533
points found are stored).
534
535
- ``maxr`` (int, default 999) -- maximum rank (quit point
536
searching once the points found generate a subgroup of this
537
rank; useful if an upper bound for the rank is already
538
known).
539
540
EXAMPLE::
541
542
sage: from sage.libs.mwrank.mwrank import _mw
543
sage: from sage.libs.mwrank.mwrank import _Curvedata
544
sage: E = _Curvedata(1,0,1,4,-6)
545
sage: EQ = _mw(E)
546
sage: EQ
547
[]
548
sage: type(EQ)
549
<type 'sage.libs.mwrank.mwrank._mw'>
550
551
sage: E = _Curvedata(0,0,1,-7,6)
552
sage: EQ = _mw(E)
553
sage: EQ.search(2)
554
sage: EQ
555
[[1:-1:1], [-2:3:1], [-14:25:8]]
556
557
Example to illustrate the verbose parameter::
558
559
sage: from sage.libs.mwrank.mwrank import _mw
560
sage: from sage.libs.mwrank.mwrank import _Curvedata
561
sage: E = _Curvedata(0,0,1,-7,6)
562
sage: EQ = _mw(E, verb=False)
563
sage: EQ.search(1)
564
sage: EQ = _mw(E, verb=True)
565
sage: EQ.search(1)
566
P1 = [0:1:0] is torsion point, order 1
567
P1 = [-3:0:1] is generator number 1
568
...
569
P4 = [12:35:27] = 1*P1 + -1*P2 + -1*P3 (mod torsion)
570
571
The previous command produces the following output::
572
573
P1 = [0:1:0] is torsion point, order 1
574
P1 = [-3:0:1] is generator number 1
575
saturating up to 20...Checking 2-saturation
576
Points have successfully been 2-saturated (max q used = 7)
577
Checking 3-saturation
578
Points have successfully been 3-saturated (max q used = 7)
579
Checking 5-saturation
580
Points have successfully been 5-saturated (max q used = 23)
581
Checking 7-saturation
582
Points have successfully been 7-saturated (max q used = 41)
583
Checking 11-saturation
584
Points have successfully been 11-saturated (max q used = 17)
585
Checking 13-saturation
586
Points have successfully been 13-saturated (max q used = 43)
587
Checking 17-saturation
588
Points have successfully been 17-saturated (max q used = 31)
589
Checking 19-saturation
590
Points have successfully been 19-saturated (max q used = 37)
591
done
592
P2 = [-2:3:1] is generator number 2
593
saturating up to 20...Checking 2-saturation
594
possible kernel vector = [1,1]
595
This point may be in 2E(Q): [14:-52:1]
596
...and it is!
597
Replacing old generator #1 with new generator [1:-1:1]
598
Points have successfully been 2-saturated (max q used = 7)
599
Index gain = 2^1
600
Checking 3-saturation
601
Points have successfully been 3-saturated (max q used = 13)
602
Checking 5-saturation
603
Points have successfully been 5-saturated (max q used = 67)
604
Checking 7-saturation
605
Points have successfully been 7-saturated (max q used = 53)
606
Checking 11-saturation
607
Points have successfully been 11-saturated (max q used = 73)
608
Checking 13-saturation
609
Points have successfully been 13-saturated (max q used = 103)
610
Checking 17-saturation
611
Points have successfully been 17-saturated (max q used = 113)
612
Checking 19-saturation
613
Points have successfully been 19-saturated (max q used = 47)
614
done (index = 2).
615
Gained index 2, new generators = [ [1:-1:1] [-2:3:1] ]
616
P3 = [-14:25:8] is generator number 3
617
saturating up to 20...Checking 2-saturation
618
Points have successfully been 2-saturated (max q used = 11)
619
Checking 3-saturation
620
Points have successfully been 3-saturated (max q used = 13)
621
Checking 5-saturation
622
Points have successfully been 5-saturated (max q used = 71)
623
Checking 7-saturation
624
Points have successfully been 7-saturated (max q used = 101)
625
Checking 11-saturation
626
Points have successfully been 11-saturated (max q used = 127)
627
Checking 13-saturation
628
Points have successfully been 13-saturated (max q used = 151)
629
Checking 17-saturation
630
Points have successfully been 17-saturated (max q used = 139)
631
Checking 19-saturation
632
Points have successfully been 19-saturated (max q used = 179)
633
done (index = 1).
634
P4 = [-1:3:1] = -1*P1 + -1*P2 + -1*P3 (mod torsion)
635
P4 = [0:2:1] = 2*P1 + 0*P2 + 1*P3 (mod torsion)
636
P4 = [2:13:8] = -3*P1 + 1*P2 + -1*P3 (mod torsion)
637
P4 = [1:0:1] = -1*P1 + 0*P2 + 0*P3 (mod torsion)
638
P4 = [2:0:1] = -1*P1 + 1*P2 + 0*P3 (mod torsion)
639
P4 = [18:7:8] = -2*P1 + -1*P2 + -1*P3 (mod torsion)
640
P4 = [3:3:1] = 1*P1 + 0*P2 + 1*P3 (mod torsion)
641
P4 = [4:6:1] = 0*P1 + -1*P2 + -1*P3 (mod torsion)
642
P4 = [36:69:64] = 1*P1 + -2*P2 + 0*P3 (mod torsion)
643
P4 = [68:-25:64] = -2*P1 + -1*P2 + -2*P3 (mod torsion)
644
P4 = [12:35:27] = 1*P1 + -1*P2 + -1*P3 (mod torsion)
645
sage: EQ
646
[[1:-1:1], [-2:3:1], [-14:25:8]]
647
648
Example to illustrate the process points ``pp`` parameter::
649
650
sage: from sage.libs.mwrank.mwrank import _mw
651
sage: from sage.libs.mwrank.mwrank import _Curvedata
652
sage: E = _Curvedata(0,0,1,-7,6)
653
sage: EQ = _mw(E, pp=1)
654
sage: EQ.search(1); EQ
655
[[1:-1:1], [-2:3:1], [-14:25:8]]
656
sage: EQ = _mw(E, pp=0)
657
sage: EQ.search(1); EQ
658
[[-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]]
659
660
"""
661
self.curve = curve.x
662
self.x = mw_new(curve.x, verb, pp, maxr)
663
self.verb = verb
664
665
def __dealloc__(self):
666
"""
667
Destructor for mw class.
668
"""
669
mw_del(self.x)
670
671
def __repr__(self):
672
"""
673
String representation of the current basis of this mw group.
674
675
OUTPUT:
676
677
(string) the current basis of this mw as a string
678
679
EXAMPLES::
680
681
sage: from sage.libs.mwrank.mwrank import _Curvedata
682
sage: from sage.libs.mwrank.mwrank import _mw
683
sage: E = _Curvedata(0,0,1,-7,6)
684
sage: EQ = _mw(E)
685
sage: EQ # indirect doctest
686
[]
687
sage: EQ.search(2)
688
sage: EQ
689
[[1:-1:1], [-2:3:1], [-14:25:8]]
690
"""
691
sig_on()
692
return string_sigoff(mw_getbasis(self.x))
693
694
695
def process(self, point, sat=0):
696
"""
697
Processes the given point, adding it to the mw group.
698
699
INPUT:
700
701
- ``point`` (tuple or list) -- tuple or list of 3 integers.
702
An ``ArithmeticError`` is raised if the point is not on the
703
curve.
704
705
- ``sat`` (int, default 0) --saturate at primes up to ``sat``.
706
No saturation is done if ``sat=0``. (Note that it is more
707
efficient to add several points at once and then saturate
708
just once at the end).
709
710
.. note::
711
712
The eclib function which implements this only carries out
713
any saturation if the rank of the points increases upon
714
adding the new point. This is because it is assumed that
715
one saturates as ones goes along.
716
717
EXAMPLES::
718
719
sage: from sage.libs.mwrank.mwrank import _Curvedata
720
sage: from sage.libs.mwrank.mwrank import _mw
721
sage: E = _Curvedata(0,1,1,-2,0)
722
sage: EQ = _mw(E)
723
724
Initially the list of gens is empty::
725
726
sage: EQ
727
[]
728
729
We process a point of infinite order::
730
731
sage: EQ.process([-1,1,1])
732
sage: EQ
733
[[-1:1:1]]
734
735
And another independent one::
736
737
sage: EQ.process([0,-1,1])
738
sage: EQ
739
[[-1:1:1], [0:-1:1]]
740
741
Processing a point dependent on the current basis will not
742
change the basis::
743
744
sage: EQ.process([4,8,1])
745
sage: EQ
746
[[-1:1:1], [0:-1:1]]
747
748
"""
749
if not isinstance(point, (tuple, list)) and len(point) == 3:
750
raise TypeError, "point must be a list or tuple of length 3."
751
cdef _bigint x,y,z
752
sig_on()
753
x,y,z = _bigint(point[0]), _bigint(point[1]), _bigint(point[2])
754
r = mw_process(self.curve, self.x, x.x, y.x, z.x, sat)
755
sig_off()
756
if r != 0:
757
raise ArithmeticError, "point (=%s) not on curve."%point
758
759
def getbasis(self):
760
"""
761
Returns the current basis of the mw structure.
762
763
OUTPUT:
764
765
(string) String representation of the points in the basis of
766
the mw group.
767
768
EXAMPLES::
769
770
sage: from sage.libs.mwrank.mwrank import _Curvedata
771
sage: from sage.libs.mwrank.mwrank import _mw
772
sage: E = _Curvedata(0,1,1,-2,0)
773
sage: EQ = _mw(E)
774
sage: EQ.search(3)
775
sage: EQ.getbasis()
776
'[[0:-1:1], [-1:1:1]]'
777
sage: EQ.rank()
778
2
779
"""
780
sig_on()
781
s = string_sigoff(mw_getbasis(self.x))
782
return s
783
784
def regulator(self):
785
"""
786
Returns the regulator of the current basis of the mw group.
787
788
OUTPUT:
789
790
(float) The current regulator.
791
792
TODO:
793
794
``eclib`` computes the regulator to arbitrary precision, and
795
the full precision value should be returned.
796
797
EXAMPLES::
798
799
sage: from sage.libs.mwrank.mwrank import _Curvedata
800
sage: from sage.libs.mwrank.mwrank import _mw
801
sage: E = _Curvedata(0,1,1,-2,0)
802
sage: EQ = _mw(E)
803
sage: EQ.search(3)
804
sage: EQ.getbasis()
805
'[[0:-1:1], [-1:1:1]]'
806
sage: EQ.rank()
807
2
808
sage: EQ.regulator()
809
0.15246017277240753
810
"""
811
cdef float f
812
sig_on()
813
f = float(string_sigoff(mw_regulator(self.x)))
814
return f
815
816
def rank(self):
817
"""
818
Returns the rank of the current basis of the mw group.
819
820
OUTPUT:
821
822
(Integer) The current rank.
823
824
EXAMPLES::
825
826
sage: from sage.libs.mwrank.mwrank import _Curvedata
827
sage: from sage.libs.mwrank.mwrank import _mw
828
sage: E = _Curvedata(0,1,1,-2,0)
829
sage: EQ = _mw(E)
830
sage: EQ.search(3)
831
sage: EQ.getbasis()
832
'[[0:-1:1], [-1:1:1]]'
833
sage: EQ.rank()
834
2
835
"""
836
sig_on()
837
r = mw_rank(self.x)
838
sig_off()
839
from sage.rings.all import Integer
840
return Integer(r)
841
842
def saturate(self, int sat_bd=-1, int odd_primes_only=0):
843
"""
844
Saturates the current subgroup of the mw group.
845
846
INPUT:
847
848
- ``sat_bnd`` (int, default -1) -- bound on primes at which to
849
saturate. If -1 (default), compute a bound for the primes
850
which may not be saturated, and use that.
851
852
- ``odd_primes_only`` (bool, default False) -- only do
853
saturation at odd primes. (If the points have been found
854
via 2-descent they should already be 2-saturated.)
855
856
OUTPUT:
857
858
(tuple) (success flag, index, list) The success flag will be 1
859
unless something failed (usually an indication that the points
860
were not saturated but the precision is not high enough to
861
divide out successfully). The index is the index of the mw
862
group before saturation in the mw group after. The list is a
863
string representation of the primes at which saturation was
864
not proved or achieved.
865
866
EXAMPLES::
867
868
sage: from sage.libs.mwrank.mwrank import _Curvedata
869
sage: from sage.libs.mwrank.mwrank import _mw
870
sage: E = _Curvedata(0,1,1,-2,0)
871
sage: EQ = _mw(E)
872
sage: EQ.process([494, -5720, 6859]) # 3 times another point
873
sage: EQ
874
[[494:-5720:6859]]
875
sage: EQ.saturate()
876
(1, 3, '[ ]')
877
sage: EQ
878
[[-1:1:1]]
879
880
If we set the saturation bound at 2, then saturation will fail::
881
882
sage: EQ = _mw(E)
883
sage: EQ.process([494, -5720, 6859]) # 3 times another point
884
sage: EQ.saturate(sat_bd=2)
885
Saturation index bound = 10
886
WARNING: saturation at primes p > 2 will not be done;
887
points may be unsaturated at primes between 2 and index bound
888
Failed to saturate MW basis at primes [ ]
889
(0, 1, '[ ]')
890
sage: EQ
891
[[494:-5720:6859]]
892
893
The following output is also seen in the preceding example::
894
895
Saturation index bound = 10
896
WARNING: saturation at primes p > 2 will not be done;
897
points may be unsaturated at primes between 2 and index bound
898
Failed to saturate MW basis at primes [ ]
899
900
901
"""
902
cdef _bigint index
903
cdef char* s
904
cdef int ok
905
sig_on()
906
index = _bigint()
907
ok = mw_saturate(self.x, index.x, &s, sat_bd, odd_primes_only)
908
unsat = string_sigoff(s)
909
return ok, index, unsat
910
911
def search(self, h_lim, int moduli_option=0, int verb=0):
912
"""
913
Search for points in the mw group.
914
915
INPUT:
916
917
- ``h_lim`` (int) -- bound on logarithmic naive height of points
918
919
- ``moduli_option`` (int, default 0) -- option for sieving
920
strategy. The default (0) uses an adapted version of
921
Stoll's ratpoints code and is recommended.
922
923
- ``verb`` (int, default 0) -- level of verbosity. If 0, no
924
output. If positive, the points are output as found and
925
some details of the processing, finding linear relations,
926
and partial saturation are output.
927
928
.. note::
929
930
The effect of the search is also governed by the class
931
options, notably whether the points found are processed:
932
meaning that linear relations are found and saturation is
933
carried out, with the result that the list of generators
934
will always contain a `\ZZ`-span of the saturation of the
935
points found, modulo torsion.
936
937
OUTPUT:
938
939
None. The effect of the search is to update the list of
940
generators.
941
942
EXAMPLE::
943
944
sage: from sage.libs.mwrank.mwrank import _Curvedata
945
sage: from sage.libs.mwrank.mwrank import _mw
946
sage: E = _Curvedata(0,0,1,-19569,-4064513) # 873c1
947
sage: EQ = _mw(E)
948
sage: EQ = _mw(E)
949
sage: for i in [1..11]: print i, EQ.search(i), EQ
950
1 None []
951
2 None []
952
3 None []
953
4 None []
954
5 None []
955
6 None []
956
7 None []
957
8 None []
958
9 None []
959
10 None []
960
11 None [[3639568:106817593:4096]]
961
"""
962
cdef char* _h_lim
963
964
h_lim = str(h_lim)
965
_h_lim = h_lim
966
967
sig_on()
968
mw_search(self.x, _h_lim, moduli_option, verb)
969
if verb:
970
sys.stdout.flush()
971
sys.stderr.flush()
972
sig_off()
973
974
975
############# two_descent #################
976
cdef class _two_descent:
977
"""
978
Cython class wrapping eclib's two_descent class.
979
"""
980
cdef two_descent* x
981
982
def __init__(self):
983
"""
984
Constructor for two_descent class.
985
986
EXAMPLES::
987
988
sage: from sage.libs.mwrank.mwrank import _two_descent
989
sage: D2 = _two_descent()
990
"""
991
self.x = <two_descent*> 0
992
993
def __dealloc__(self):
994
"""
995
Destructor for two_descent class.
996
"""
997
if self.x:
998
two_descent_del(self.x)
999
1000
def do_descent(self, _Curvedata curve,
1001
int verb = 1,
1002
int sel = 0,
1003
int firstlim = 20,
1004
int secondlim = 8,
1005
int n_aux = -1,
1006
int second_descent = 1):
1007
"""
1008
Carry out a 2-descent.
1009
1010
INPUT:
1011
1012
- ``curvedata`` (_Curvedata) -- the curve on which to do descent.
1013
1014
- ``verb`` (int, default 1) -- verbosity level.
1015
1016
- ``sel`` (int, default 0) -- Selmer-only flag. If 1, only
1017
the 2-Selmer group will be computed, with no rational
1018
points. Useful as a faster way of getting an upper bound on
1019
the rank.
1020
1021
- ``firstlim`` (int, default 20) -- naive height bound on
1022
first point search on quartic homogeneous spaces (before
1023
testing local solubility; very simple search with no
1024
overheads).
1025
1026
- ``secondlim`` (int, default 8) -- naive height bound on
1027
second point search on quartic homogeneous spaces (after
1028
testing local solubility; sieve-assisted search)
1029
1030
- ``n_aux`` (int, default -1) -- If positive, the number of
1031
auxiliary primes used in sieve-assisted search for quartics.
1032
If -1 (the default) use a default value (set in the eclib
1033
code in ``src/qrank/mrank1.cc`` in DEFAULT_NAUX: currently 8).
1034
Only relevant for curves with no 2-torsion, where full
1035
2-descent is carried out. Worth increasing for curves
1036
expected to be of of rank>6 to one or two more than the
1037
expected rank.
1038
1039
- ``second_descent`` (int, default 1) -- flag specifying
1040
whether or not a second descent will be carried out (yes if
1041
1, the default; no if 0). Only relevant for curves with
1042
2-torsion. Recommended left as the default except for
1043
experts interested in details of Selmer groups.
1044
1045
OUTPUT:
1046
1047
None
1048
1049
EXAMPLES::
1050
1051
sage: from sage.libs.mwrank.mwrank import _Curvedata
1052
sage: CD = _Curvedata(0,0,1,-7,6)
1053
sage: from sage.libs.mwrank.mwrank import _two_descent
1054
sage: D2 = _two_descent()
1055
sage: D2.do_descent(CD)
1056
Basic pair: I=336, J=-10800
1057
disc=35092224
1058
...
1059
Mordell rank contribution from B=im(eps) = 3
1060
Selmer rank contribution from B=im(eps) = 3
1061
Sha rank contribution from B=im(eps) = 0
1062
Mordell rank contribution from A=ker(eps) = 0
1063
Selmer rank contribution from A=ker(eps) = 0
1064
Sha rank contribution from A=ker(eps) = 0
1065
sage: D2.getrank()
1066
3
1067
sage: D2.getcertain()
1068
1
1069
sage: D2.ok()
1070
1
1071
"""
1072
sig_on()
1073
self.x = two_descent_new(curve.x, verb, sel, firstlim, secondlim, n_aux, second_descent)
1074
if verb:
1075
sys.stdout.flush()
1076
sys.stderr.flush()
1077
sig_off()
1078
1079
def getrank(self):
1080
"""
1081
Returns the rank (after doing a 2-descent).
1082
1083
OUTPUT:
1084
1085
(Integer) the rank (or an upper bound).
1086
1087
EXAMPLES::
1088
1089
sage: from sage.libs.mwrank.mwrank import _Curvedata
1090
sage: CD = _Curvedata(0,0,1,-7,6)
1091
sage: from sage.libs.mwrank.mwrank import _two_descent
1092
sage: D2 = _two_descent()
1093
sage: D2.do_descent(CD)
1094
Basic pair: I=336, J=-10800
1095
disc=35092224
1096
...
1097
Mordell rank contribution from B=im(eps) = 3
1098
Selmer rank contribution from B=im(eps) = 3
1099
Sha rank contribution from B=im(eps) = 0
1100
Mordell rank contribution from A=ker(eps) = 0
1101
Selmer rank contribution from A=ker(eps) = 0
1102
Sha rank contribution from A=ker(eps) = 0
1103
sage: D2.getrank()
1104
3
1105
"""
1106
cdef int r
1107
sig_on()
1108
r = two_descent_get_rank(self.x)
1109
sig_off()
1110
from sage.rings.all import Integer
1111
return Integer(r)
1112
1113
def getrankbound(self):
1114
"""
1115
Returns the rank upper bound (after doing a 2-descent).
1116
1117
OUTPUT:
1118
1119
(Integer) an upper bound on the rank.
1120
1121
EXAMPLES::
1122
1123
sage: from sage.libs.mwrank.mwrank import _Curvedata
1124
sage: CD = _Curvedata(0,0,1,-7,6)
1125
sage: from sage.libs.mwrank.mwrank import _two_descent
1126
sage: D2 = _two_descent()
1127
sage: D2.do_descent(CD)
1128
Basic pair: I=336, J=-10800
1129
disc=35092224
1130
...
1131
Mordell rank contribution from B=im(eps) = 3
1132
Selmer rank contribution from B=im(eps) = 3
1133
Sha rank contribution from B=im(eps) = 0
1134
Mordell rank contribution from A=ker(eps) = 0
1135
Selmer rank contribution from A=ker(eps) = 0
1136
Sha rank contribution from A=ker(eps) = 0
1137
sage: D2.getrankbound()
1138
3
1139
"""
1140
cdef int r
1141
sig_on()
1142
r = two_descent_get_rank_bound(self.x)
1143
sig_off()
1144
from sage.rings.all import Integer
1145
return Integer(r)
1146
1147
def getselmer(self):
1148
"""
1149
Returns the 2-Selmer rank (after doing a 2-descent).
1150
1151
OUTPUT:
1152
1153
(Integer) The 2-Selmer rank.
1154
1155
EXAMPLES::
1156
1157
sage: from sage.libs.mwrank.mwrank import _Curvedata
1158
sage: CD = _Curvedata(0,0,1,-7,6)
1159
sage: from sage.libs.mwrank.mwrank import _two_descent
1160
sage: D2 = _two_descent()
1161
sage: D2.do_descent(CD)
1162
Basic pair: I=336, J=-10800
1163
disc=35092224
1164
...
1165
Mordell rank contribution from B=im(eps) = 3
1166
Selmer rank contribution from B=im(eps) = 3
1167
Sha rank contribution from B=im(eps) = 0
1168
Mordell rank contribution from A=ker(eps) = 0
1169
Selmer rank contribution from A=ker(eps) = 0
1170
Sha rank contribution from A=ker(eps) = 0
1171
sage: D2.getselmer()
1172
3
1173
"""
1174
sig_on()
1175
r = two_descent_get_selmer_rank(self.x)
1176
sig_off()
1177
from sage.rings.all import Integer
1178
return Integer(r)
1179
1180
def ok(self):
1181
"""
1182
Returns the success flag (after doing a 2-descent).
1183
1184
OUTPUT:
1185
1186
(bool) Flag indicating whether or not 2-descent was successful.
1187
1188
EXAMPLES::
1189
1190
sage: from sage.libs.mwrank.mwrank import _Curvedata
1191
sage: CD = _Curvedata(0,0,1,-7,6)
1192
sage: from sage.libs.mwrank.mwrank import _two_descent
1193
sage: D2 = _two_descent()
1194
sage: D2.do_descent(CD)
1195
Basic pair: I=336, J=-10800
1196
disc=35092224
1197
...
1198
Mordell rank contribution from B=im(eps) = 3
1199
Selmer rank contribution from B=im(eps) = 3
1200
Sha rank contribution from B=im(eps) = 0
1201
Mordell rank contribution from A=ker(eps) = 0
1202
Selmer rank contribution from A=ker(eps) = 0
1203
Sha rank contribution from A=ker(eps) = 0
1204
sage: D2.ok()
1205
1
1206
"""
1207
return two_descent_ok(self.x)
1208
1209
def getcertain(self):
1210
"""
1211
Returns the certainty flag (after doing a 2-descent).
1212
1213
OUTPUT:
1214
1215
(bool) True if the rank upper and lower bounds are equal.
1216
1217
EXAMPLES::
1218
1219
sage: from sage.libs.mwrank.mwrank import _Curvedata
1220
sage: CD = _Curvedata(0,0,1,-7,6)
1221
sage: from sage.libs.mwrank.mwrank import _two_descent
1222
sage: D2 = _two_descent()
1223
sage: D2.do_descent(CD)
1224
Basic pair: I=336, J=-10800
1225
disc=35092224
1226
...
1227
Mordell rank contribution from B=im(eps) = 3
1228
Selmer rank contribution from B=im(eps) = 3
1229
Sha rank contribution from B=im(eps) = 0
1230
Mordell rank contribution from A=ker(eps) = 0
1231
Selmer rank contribution from A=ker(eps) = 0
1232
Sha rank contribution from A=ker(eps) = 0
1233
sage: D2.getcertain()
1234
1
1235
"""
1236
return two_descent_get_certain(self.x)
1237
1238
def saturate(self, saturation_bound=0):
1239
"""
1240
Carries out saturation of the points found by a 2-descent.
1241
1242
OUTPUT:
1243
1244
None.
1245
1246
EXAMPLES::
1247
1248
sage: from sage.libs.mwrank.mwrank import _Curvedata
1249
sage: CD = _Curvedata(0,0,1,-7,6)
1250
sage: from sage.libs.mwrank.mwrank import _two_descent
1251
sage: D2 = _two_descent()
1252
sage: D2.do_descent(CD)
1253
Basic pair: I=336, J=-10800
1254
disc=35092224
1255
...
1256
Mordell rank contribution from B=im(eps) = 3
1257
Selmer rank contribution from B=im(eps) = 3
1258
Sha rank contribution from B=im(eps) = 0
1259
Mordell rank contribution from A=ker(eps) = 0
1260
Selmer rank contribution from A=ker(eps) = 0
1261
Sha rank contribution from A=ker(eps) = 0
1262
sage: D2.saturate()
1263
Searching for points (bound = 8)...done:
1264
found points which generate a subgroup of rank 3
1265
and regulator 0.417143558758383969817119544618093396749810106098479
1266
Processing points found during 2-descent...done:
1267
now regulator = 0.417143558758383969817119544618093396749810106098479
1268
No saturation being done
1269
sage: D2.getbasis()
1270
'[[1:-1:1], [-2:3:1], [-14:25:8]]'
1271
"""
1272
sig_on()
1273
two_descent_saturate(self.x, saturation_bound)
1274
sig_off()
1275
1276
def getbasis(self):
1277
"""
1278
Returns the basis of points found by doing a 2-descent.
1279
1280
If the success and certain flags are 1, this will be a
1281
`\ZZ/2\ZZ`-basis for `E(\QQ)/2E(\QQ)` (modulo torsion),
1282
otherwise possibly only for a proper subgroup.
1283
1284
.. note::
1285
1286
You must call ``saturate()`` first, or a RunTimeError will be raised.
1287
1288
OUTPUT:
1289
1290
(string) String representation of the list of points after
1291
saturation.
1292
1293
EXAMPLES::
1294
1295
sage: from sage.libs.mwrank.mwrank import _Curvedata
1296
sage: CD = _Curvedata(0,0,1,-7,6)
1297
sage: from sage.libs.mwrank.mwrank import _two_descent
1298
sage: D2 = _two_descent()
1299
sage: D2.do_descent(CD)
1300
Basic pair: I=336, J=-10800
1301
disc=35092224
1302
...
1303
Mordell rank contribution from B=im(eps) = 3
1304
Selmer rank contribution from B=im(eps) = 3
1305
Sha rank contribution from B=im(eps) = 0
1306
Mordell rank contribution from A=ker(eps) = 0
1307
Selmer rank contribution from A=ker(eps) = 0
1308
Sha rank contribution from A=ker(eps) = 0
1309
sage: D2.saturate()
1310
Searching for points (bound = 8)...done:
1311
found points which generate a subgroup of rank 3
1312
and regulator 0.417143558758383969817119544618093396749810106098479
1313
Processing points found during 2-descent...done:
1314
now regulator = 0.417143558758383969817119544618093396749810106098479
1315
No saturation being done
1316
sage: D2.getbasis()
1317
'[[1:-1:1], [-2:3:1], [-14:25:8]]'
1318
"""
1319
sig_on()
1320
return string_sigoff(two_descent_get_basis(self.x))
1321
1322
def regulator(self):
1323
"""
1324
Returns the regulator of the points found by doing a 2-descent.
1325
1326
OUTPUT:
1327
1328
(float) The regulator (of the subgroup found by 2-descent).
1329
1330
EXAMPLES::
1331
1332
sage: from sage.libs.mwrank.mwrank import _Curvedata
1333
sage: CD = _Curvedata(0,0,1,-7,6)
1334
sage: from sage.libs.mwrank.mwrank import _two_descent
1335
sage: D2 = _two_descent()
1336
sage: D2.do_descent(CD)
1337
Basic pair: I=336, J=-10800
1338
disc=35092224
1339
...
1340
Mordell rank contribution from B=im(eps) = 3
1341
Selmer rank contribution from B=im(eps) = 3
1342
Sha rank contribution from B=im(eps) = 0
1343
Mordell rank contribution from A=ker(eps) = 0
1344
Selmer rank contribution from A=ker(eps) = 0
1345
Sha rank contribution from A=ker(eps) = 0
1346
1347
If called before calling ``saturate()``, a bogus value of 1.0
1348
is returned::
1349
1350
sage: D2.regulator()
1351
1.0
1352
1353
After saturation, both ``getbasis()`` and ``regulator()``
1354
return the basis and regulator of the subgroup found by
1355
2-descent::
1356
1357
sage: D2.saturate()
1358
Searching for points (bound = 8)...done:
1359
found points which generate a subgroup of rank 3
1360
and regulator 0.417143558758383969817119544618093396749810106098479
1361
Processing points found during 2-descent...done:
1362
now regulator = 0.417143558758383969817119544618093396749810106098479
1363
No saturation being done
1364
sage: D2.getbasis()
1365
'[[1:-1:1], [-2:3:1], [-14:25:8]]'
1366
sage: D2.regulator()
1367
0.417143558758384
1368
"""
1369
sig_on()
1370
return float(string_sigoff(two_descent_regulator(self.x)))
1371
1372