Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/databases/cremona.py
8814 views
1
"""
2
Cremona's tables of elliptic curves
3
4
Sage includes John Cremona's tables of elliptic curves in an
5
easy-to-use format. An instance of the class CremonaDatabase()
6
gives access to the database.
7
8
If the optional full CremonaDatabase is not installed, a mini-version
9
is included by default with Sage. It contains Weierstrass equations,
10
rank, and torsion for curves up to conductor 10000.
11
12
The large database includes all curves in John Cremona's tables. It
13
also includes data related to the BSD conjecture and modular degrees
14
for all of these curves, and generators for the Mordell-Weil
15
groups. To install it type the following in Sage::
16
17
!sage -i database_cremona_ellcurve
18
19
This causes the latest version of the database to be downloaded from
20
the internet.
21
22
Both the mini and full versions of John Cremona's tables are stored in
23
SAGE_SHARE/cremona as SQLite databases. The mini version has the layout::
24
25
CREATE TABLE t_class(conductor INTEGER, class TEXT PRIMARY KEY, rank INTEGER);
26
CREATE TABLE t_curve(class TEXT, curve TEXT PRIMARY KEY, eqn TEXT UNIQUE, tors INTEGER);
27
CREATE INDEX i_t_class_conductor ON t_class(conductor);
28
CREATE INDEX i_t_curve_class ON t_curve(class);
29
30
while the full version has the layout::
31
32
CREATE TABLE t_class(conductor INTEGER, class TEXT PRIMARY KEY, rank INTEGER, L REAL, deg INTEGER);
33
CREATE TABLE t_curve(class TEXT, curve TEXT PRIMARY KEY, eqn TEXT UNIQUE, gens TEXT, tors INTEGER, cp INTEGER, om REAL, reg REAL, sha);
34
CREATE INDEX i_t_class_conductor ON t_class(conductor);
35
CREATE INDEX i_t_curve_class ON t_curve(class);
36
"""
37
#*****************************************************************************
38
# Copyright (C) 2011 R. Andrew Ohana <[email protected]>
39
# Copyright (C) 2005 William Stein <[email protected]>
40
#
41
# Distributed under the terms of the GNU General Public License (GPL)
42
# as published by the Free Software Foundation; either version 2 of
43
# the License, or (at your option) any later version.
44
# http://www.gnu.org/licenses/
45
#*****************************************************************************
46
47
from __future__ import print_function
48
49
import os
50
from sage.misc.prandom import randint
51
52
import sage.schemes.elliptic_curves.constructor as elliptic
53
from sql_db import SQLDatabase, verify_column
54
from sage.misc.package import is_package_installed
55
from sage.misc.misc import SAGE_SHARE, walltime
56
57
import re
58
import string
59
60
_cremonaSkeleton = {
61
't_class': {
62
'conductor': {'sql':'INTEGER', 'index':True},
63
'class': {'sql':'TEXT', 'primary_key':True},
64
'rank': {'sql':'INTEGER'},
65
'L': {'sql':'REAL'},
66
'deg': {'sql':'INTEGER'}
67
},
68
't_curve': {
69
'class': {'sql':'TEXT', 'index':True},
70
'curve': {'sql':'TEXT', 'primary_key':True},
71
'eqn': {'sql':'TEXT', 'unique':True},
72
'gens': {'sql':'TEXT'},
73
'tors': {'sql':'INTEGER'},
74
'cp': {'sql':'INTEGER'},
75
'om': {'sql':'REAL'},
76
'reg': {'sql':'REAL'},
77
'sha': {'sql':'NOTYPE'}
78
}
79
}
80
_miniCremonaSkeleton = {
81
't_class': {
82
'conductor': {'sql':'INTEGER', 'index':True},
83
'class': {'sql':'TEXT', 'primary_key':True},
84
'rank': {'sql':'INTEGER'}
85
},
86
't_curve': {
87
'class': {'sql':'TEXT', 'index':True},
88
'curve': {'sql':'TEXT', 'primary_key':True},
89
'eqn': {'sql':'TEXT', 'unique':True},
90
'tors': {'sql':'INTEGER'}
91
}
92
}
93
94
for t in _cremonaSkeleton:
95
for c in _cremonaSkeleton[t]:
96
_cremonaSkeleton[t][c] = verify_column(_cremonaSkeleton[t][c])
97
for c in _miniCremonaSkeleton[t]:
98
_miniCremonaSkeleton[t][c] = verify_column(_miniCremonaSkeleton[t][c])
99
100
def build(name, data_tgz, largest_conductor=0, mini=False, decompress=True):
101
"""
102
Build the CremonaDatabase with given name from scratch
103
using the data_tgz tarball.
104
105
... note::
106
107
For data up to level 240000, this function takes about 3
108
minutes on a AMD Opteron(tm) Processor 6174. The resulting database
109
occupies 309MB disk space.
110
111
To create the large Cremona database from Cremona's data_tgz tarball,
112
run the following command::
113
114
sage: d = sage.databases.cremona.build('cremona','ecdata.tgz') # not tested
115
"""
116
db_path = os.path.join(SAGE_SHARE,'cremona',name.replace(' ','_')+'.db')
117
if os.path.exists(db_path):
118
raise RuntimeError('Please (re)move %s before building '%db_path \
119
+ 'database')
120
if not os.path.exists(data_tgz):
121
raise IOError("The data file is not at %s"%data_tgz)
122
t = walltime()
123
124
if decompress:
125
cmd = "tar zxvf %s"%data_tgz
126
n = os.system(cmd)
127
if n:
128
raise RuntimeError("Error extracting tarball.")
129
if mini:
130
c = MiniCremonaDatabase(name,False,True)
131
else:
132
c = LargeCremonaDatabase(name,False,True)
133
c._init_from_ftpdata('ecdata', largest_conductor)
134
print("Total time: ", walltime(t))
135
136
def is_optimal_id(id):
137
"""
138
Returns true if the Cremona id refers to an optimal curve, and
139
false otherwise. The curve is optimal if the id, which is of the
140
form [letter code][number] has number 1.
141
142
.. note::
143
144
990h3 is the optimal curve in that class, so doesn't obey
145
this rule.
146
147
INPUT:
148
149
- ``id`` - str of form letter code followed by an
150
integer, e.g., a3, bb5, etc.
151
152
OUTPUT: bool
153
154
EXAMPLES::
155
156
sage: from sage.databases.cremona import is_optimal_id
157
sage: is_optimal_id('b1')
158
True
159
sage: is_optimal_id('bb1')
160
True
161
sage: is_optimal_id('c1')
162
True
163
sage: is_optimal_id('c2')
164
False
165
"""
166
return id[-1] == '1' and not id[-2].isdigit()
167
168
def cremona_letter_code(n):
169
"""
170
Returns the Cremona letter code corresponding to an integer. For
171
example, 0 - a 25 - z 26 - ba 51 - bz 52 - ca 53 - cb etc.
172
173
.. note::
174
175
This is just the base 26 representation of n, where a=0, b=1,
176
..., z=25. This extends the old Cremona notation (counting from
177
0) for the first 26 classes, and is different for classes above
178
26.
179
180
INPUT:
181
182
- ``n`` (int) -- a non-negative integer
183
184
OUTPUT: str
185
186
EXAMPLES::
187
188
sage: from sage.databases.cremona import cremona_letter_code
189
sage: cremona_letter_code(0)
190
'a'
191
sage: cremona_letter_code(26)
192
'ba'
193
sage: cremona_letter_code(27)
194
'bb'
195
sage: cremona_letter_code(521)
196
'ub'
197
sage: cremona_letter_code(53)
198
'cb'
199
sage: cremona_letter_code(2005)
200
'czd'
201
202
TESTS::
203
204
sage: cremona_letter_code(QQ)
205
Traceback (most recent call last):
206
...
207
ValueError: Cremona letter codes are only defined for non-negative integers
208
sage: cremona_letter_code(x)
209
Traceback (most recent call last):
210
...
211
ValueError: Cremona letter codes are only defined for non-negative integers
212
sage: cremona_letter_code(-1)
213
Traceback (most recent call last):
214
...
215
ValueError: Cremona letter codes are only defined for non-negative integers
216
sage: cremona_letter_code(3.14159)
217
Traceback (most recent call last):
218
...
219
ValueError: Cremona letter codes are only defined for non-negative integers
220
"""
221
try:
222
m = int(n)
223
if n == m:
224
n = m
225
else:
226
n = -1
227
except (ValueError, TypeError):
228
n = -1
229
230
if n<0:
231
raise ValueError("Cremona letter codes are only defined for non-negative integers")
232
233
if n == 0:
234
return "a"
235
s = ""
236
while n != 0:
237
s = chr(n%26+97) + s
238
n //= 26
239
return s
240
241
def old_cremona_letter_code(n):
242
r"""
243
Returns the *old* Cremona letter code corresponding to an integer.
244
integer.
245
246
For example::
247
248
1 --> A
249
26 --> Z
250
27 --> AA
251
52 --> ZZ
252
53 --> AAA
253
etc.
254
255
INPUT:
256
257
- ``n`` - int
258
259
OUTPUT: str
260
261
EXAMPLES::
262
263
sage: from sage.databases.cremona import old_cremona_letter_code
264
sage: old_cremona_letter_code(1)
265
'A'
266
sage: old_cremona_letter_code(26)
267
'Z'
268
sage: old_cremona_letter_code(27)
269
'AA'
270
sage: old_cremona_letter_code(521)
271
'AAAAAAAAAAAAAAAAAAAAA'
272
sage: old_cremona_letter_code(53)
273
'AAA'
274
sage: old_cremona_letter_code(2005)
275
'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC'
276
"""
277
n -= 1
278
k = n%26 + 65
279
label = chr(k)*int(n//26 + 1)
280
return label
281
282
old_cremona_label_regex = re.compile(r'(\d+)([A-Z]*)(\d*)$')
283
cremona_label_regex = re.compile(r'(\d+)([a-z]*)(\d*)$')
284
lmfdb_label_regex = re.compile(r'(\d+)\.([a-z]+)(\d*)$')
285
286
def parse_cremona_label(label):
287
"""
288
Given a Cremona label that defines an elliptic
289
curve, e.g., 11a1 or 37b3, parse the label and return the
290
conductor, isogeny class label, and number.
291
292
For this function, the curve number may be omitted, in which case
293
it defaults to 1. If the curve number and isogeny class are both
294
omitted (label is just a string representing a conductor), then
295
the isogeny class defaults to 'a' and the number to 1. Valid
296
labels consist of one or more digits, followed by zero or more
297
letters (either all in upper case for an old Cremona label, or all
298
in lower case), followed by zero or more digits.
299
300
INPUT:
301
302
- ``label`` - str
303
304
OUTPUT:
305
306
- ``int`` - the conductor
307
- ``str`` - the isogeny class label
308
- ``int`` - the number
309
310
EXAMPLES::
311
312
sage: from sage.databases.cremona import parse_cremona_label
313
sage: parse_cremona_label('37a2')
314
(37, 'a', 2)
315
sage: parse_cremona_label('37b1')
316
(37, 'b', 1)
317
sage: parse_cremona_label('10bb2')
318
(10, 'bb', 2)
319
sage: parse_cremona_label('11a')
320
(11, 'a', 1)
321
sage: parse_cremona_label('11')
322
(11, 'a', 1)
323
324
Valid old Cremona labels are allowed::
325
326
sage: parse_cremona_label('17CCCC')
327
(17, 'dc', 1)
328
sage: parse_cremona_label('5AB2')
329
Traceback (most recent call last):
330
...
331
ValueError: 5AB2 is not a valid Cremona label
332
333
TESTS::
334
335
sage: from sage.databases.cremona import parse_cremona_label
336
sage: parse_cremona_label('x11')
337
Traceback (most recent call last):
338
...
339
ValueError: x11 is not a valid Cremona label
340
"""
341
m = cremona_label_regex.match(str(label))
342
if m is None:
343
m = old_cremona_label_regex.match(str(label))
344
if m is None:
345
raise ValueError(label + " is not a valid Cremona label")
346
347
conductor, iso, num = m.groups()
348
if len(iso) == 0:
349
iso = "a"
350
if len(num) == 0:
351
num = "1"
352
353
# convert old cremona labels to new ones
354
if iso.upper() == iso and iso[0]*len(iso) == iso:
355
iso = cremona_letter_code((len(iso)-1)*26+ord(iso[0])-ord('A'))
356
357
# verify cremona label is valid
358
if iso.lower() != iso:
359
raise ValueError('%s is not a valid Cremona label'%label)
360
361
return int(conductor), iso, int(num)
362
363
def parse_lmfdb_label(label):
364
"""
365
Given an LMFDB label that defines an elliptic curve, e.g., 11.a1
366
or 37.b3, parse the label and return the conductor, isogeny class
367
label, and number.
368
369
The LMFDB label (named after the L-functions and modular forms
370
database), is determined by the following two orders:
371
372
- Isogeny classes with the same conductor are ordered
373
lexicographically by the coefficients in the q-expansion of the
374
associated modular form.
375
376
- Curves within the same isogeny class are ordered
377
lexicographically by the a-invariants of the minimal model.
378
379
The format is <conductor>.<iso><curve>, where the isogeny class is
380
encoded using the same base-26 encoding into letters used in
381
Cremona's labels. For example, 990.h3 is the same as Cremona's 990j1
382
383
For this function, the curve number may be omitted, in which case
384
it defaults to 1. If the curve number and isogeny class are both
385
omitted (label is just a string representing a conductor), then
386
the isogeny class defaults to 'a' and the number to 1.
387
388
INPUT:
389
390
- ``label`` - str
391
392
OUTPUT:
393
394
- ``int`` - the conductor
395
- ``str`` - the isogeny class label
396
- ``int`` - the number
397
398
EXAMPLES::
399
400
sage: from sage.databases.cremona import parse_lmfdb_label
401
sage: parse_lmfdb_label('37.a2')
402
(37, 'a', 2)
403
sage: parse_lmfdb_label('37.b')
404
(37, 'b', 1)
405
sage: parse_lmfdb_label('10.bb2')
406
(10, 'bb', 2)
407
"""
408
m = lmfdb_label_regex.match(str(label).lower())
409
if m is None:
410
raise ValueError(label + " is not a valid LMFDB label")
411
conductor, iso, num = m.groups()
412
if len(iso) == 0:
413
iso = "a"
414
if len(num) == 0:
415
num = "1"
416
return int(conductor), iso, int(num)
417
418
def split_code(key):
419
"""
420
Splits class+curve id string into its two parts.
421
422
EXAMPLES::
423
424
sage: import sage.databases.cremona as cremona
425
sage: cremona.split_code('ba2')
426
('ba', '2')
427
"""
428
cu = re.split("[a-z]*",key)[1]
429
cl = re.split("[0-9]*",key)[0]
430
return (cl,cu)
431
432
def class_to_int(k):
433
"""
434
Converts class id string into an integer. Note that this is the
435
inverse of cremona_letter_code.
436
437
EXAMPLES::
438
439
sage: import sage.databases.cremona as cremona
440
sage: cremona.class_to_int('ba')
441
26
442
sage: cremona.class_to_int('cremona')
443
821863562
444
sage: cremona.cremona_letter_code(821863562)
445
'cremona'
446
"""
447
kk = [string.ascii_lowercase.index(ch) for ch in list(k)]
448
kk.reverse()
449
return sum([kk[i]*26**i for i in range(len(kk))])
450
451
def cmp_code(key1,key2):
452
"""
453
Comparison function for curve id strings.
454
455
.. note::
456
457
Not the same as standard lexicographic order!
458
459
EXAMPLES::
460
461
sage: import sage.databases.cremona as cremona
462
sage: cremona.cmp_code('ba1','z1')
463
1
464
465
By contrast::
466
467
sage: cmp('ba1','z1')
468
-1
469
"""
470
cl1,cu1 = split_code(key1)
471
cl2,cu2 = split_code(key2)
472
d = class_to_int(cl1)-class_to_int(cl2)
473
if d!=0: return d
474
return cmp(cu1,cu2)
475
476
def cremona_to_lmfdb(cremona_label, CDB=None):
477
"""
478
Converts a Cremona label into an LMFDB label.
479
480
See :func:`parse_lmfdb_label` for an explanation of LMFDB labels.
481
482
INPUT:
483
484
- ``cremona_label`` -- a string, the Cremona label of a curve.
485
This can be the label of a curve (e.g. '990j1') or of an isogeny
486
class (e.g. '990j')
487
- ``CDB`` -- the Cremona database in which to look up the isogeny
488
classes of the same conductor.
489
490
OUTPUT:
491
492
- ``lmfdb_label`` -- a string, the corresponding LMFDB label.
493
494
EXAMPLES::
495
496
sage: from sage.databases.cremona import cremona_to_lmfdb, lmfdb_to_cremona
497
sage: cremona_to_lmfdb('990j1')
498
'990.h3'
499
sage: lmfdb_to_cremona('990.h3')
500
'990j1'
501
502
TESTS::
503
504
sage: for label in ['5077a1','66a3','102b','420c2']:
505
... assert(lmfdb_to_cremona(cremona_to_lmfdb(label)) == label)
506
sage: for label in ['438.c2','306.b','462.f3']:
507
... assert(cremona_to_lmfdb(lmfdb_to_cremona(label)) == label)
508
"""
509
from sage.libs.pari.all import pari
510
m = cremona_label_regex.match(cremona_label)
511
if m is None:
512
raise ValueError("Invalid Cremona label")
513
N, cremona_iso, cremona_number = m.groups()
514
if CDB is None:
515
CDB = CremonaDatabase()
516
classes = CDB.isogeny_classes(N)
517
ft = int(53)
518
tff = int(255) # This should be enough to distinguish between curves (using heuristics from Sato-Tate for example)
519
isos = []
520
for i, iso in enumerate(classes):
521
alist = iso[0][0]
522
E = pari(alist).ellinit(precision=ft)
523
isos.append((E.ellan(tff, python_ints=True), cremona_letter_code(i)))
524
isos.sort()
525
sorted_letters = [iso[1] for iso in isos]
526
lmfdb_iso = cremona_letter_code(sorted_letters.index(cremona_iso))
527
if len(cremona_number) > 0:
528
iso_class = sorted([(curve[0],str(i+1)) for i,curve in enumerate(classes[class_to_int(cremona_iso)])])
529
sorted_numbers = [curve[1] for curve in iso_class]
530
lmfdb_number = str(sorted_numbers.index(cremona_number)+1)
531
return N + '.' + lmfdb_iso + lmfdb_number
532
else:
533
return N + '.' + lmfdb_iso
534
535
def lmfdb_to_cremona(lmfdb_label, CDB=None):
536
"""
537
Converts an LMFDB labe into a Cremona label.
538
539
See :func:`parse_lmfdb_label` for an explanation of LMFDB labels.
540
541
INPUT:
542
543
- ``lmfdb_label`` -- a string, the LMFDB label of a curve.
544
This can be the label of a curve (e.g. '990.j1') or of an isogeny
545
class (e.g. '990.j')
546
- ``CDB`` -- the Cremona database in which to look up the isogeny
547
classes of the same conductor.
548
549
OUTPUT:
550
551
- ``cremona_label`` -- a string, the corresponding Cremona label.
552
553
EXAMPLES::
554
555
sage: from sage.databases.cremona import cremona_to_lmfdb, lmfdb_to_cremona
556
sage: lmfdb_to_cremona('990.h3')
557
'990j1'
558
sage: cremona_to_lmfdb('990j1')
559
'990.h3'
560
"""
561
from sage.libs.pari.all import pari
562
m = lmfdb_label_regex.match(lmfdb_label)
563
if m is None:
564
raise ValueError("Invalid LMFDB label")
565
N, lmfdb_iso, lmfdb_number = m.groups()
566
if CDB is None:
567
CDB = CremonaDatabase()
568
classes = CDB.isogeny_classes(N)
569
ft = int(53)
570
tff = int(255) # This should be enough to distinguish between curves (using heuristics from Sato-Tate for example)
571
isos = []
572
for i, iso in enumerate(classes):
573
alist = iso[0][0]
574
E = pari(alist).ellinit(precision=ft)
575
isos.append((E.ellan(tff, python_ints=True), cremona_letter_code(i)))
576
isos.sort()
577
cremona_iso = isos[class_to_int(lmfdb_iso)][1]
578
if len(lmfdb_number) > 0:
579
iso_class = sorted([(curve[0],i+1) for i,curve in enumerate(classes[class_to_int(cremona_iso)])])
580
cremona_number = str(iso_class[int(lmfdb_number)-1][1])
581
return N + cremona_iso + cremona_number
582
else:
583
return N + cremona_iso
584
585
class MiniCremonaDatabase(SQLDatabase):
586
"""
587
The Cremona database of elliptic curves.
588
589
EXAMPLES::
590
591
sage: c = CremonaDatabase()
592
sage: c.allcurves(11)
593
{'a1': [[0, -1, 1, -10, -20], 0, 5], 'a3': [[0, -1, 1, 0, 0], 0, 5],
594
'a2': [[0, -1, 1, -7820, -263580], 0, 1]}
595
"""
596
def __init__(self, name, read_only=True, build=False):
597
"""
598
Initialize the database.
599
600
TESTS::
601
602
sage: c = CremonaDatabase('cremona mini')
603
sage: c.name
604
'cremona mini'
605
"""
606
self.name = name
607
name = name.replace(' ','_')
608
db_path = os.path.join(SAGE_SHARE, 'cremona', name+'.db')
609
if build:
610
if name is None:
611
raise RuntimeError('The database must have a name.')
612
if read_only:
613
raise RuntimeError('The database must not be read_only.')
614
SQLDatabase.__init__(self, db_path, read_only=read_only, \
615
skeleton=_miniCremonaSkeleton)
616
return
617
if not os.path.isfile(db_path):
618
raise ValueError("Desired database (='%s') does not "%self.name \
619
+ "exist")
620
SQLDatabase.__init__(self, db_path, read_only=read_only)
621
if self.get_skeleton() != _miniCremonaSkeleton:
622
raise RuntimeError('Database at %s does '%(self.__dblocation__) \
623
+ 'not appear to be a valid SQL Cremona database.')
624
625
def __iter__(self):
626
"""
627
Returns an iterator through all EllipticCurve objects in the
628
Cremona database.
629
630
TESTS::
631
632
sage: it = CremonaDatabase().__iter__()
633
sage: it.next().label()
634
'11a1'
635
sage: it.next().label()
636
'11a2'
637
sage: it.next().label()
638
'11a3'
639
sage: it.next().label()
640
'14a1'
641
sage: skip = [it.next() for _ in range(100)]
642
sage: it.next().label()
643
'45a3'
644
"""
645
query = "SELECT curve FROM t_curve,t_class USING(class) ORDER BY conductor"
646
for c in self.__connection__.cursor().execute(query):
647
yield self.elliptic_curve(c[0])
648
649
def __getitem__(self, N):
650
"""
651
If N is an integer, return all data about level N in the database.
652
If N is a string it must be a Cremona label, in which case return
653
the corresponding elliptic curve, if it is in the database.
654
655
INPUT:
656
657
- ``N`` - int or str
658
659
OUTPUT: dict (if N is an int) or EllipticCurve (if N is a str)
660
661
TESTS::
662
663
sage: c = CremonaDatabase()
664
sage: c[11]['allcurves']['a2']
665
[[0, -1, 1, -7820, -263580], 0, 1]
666
sage: c['11a2']
667
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field
668
"""
669
if isinstance(N, str):
670
return self.elliptic_curve(N)
671
672
try:
673
N = int(N)
674
except ValueError:
675
raise KeyError("N (=%s) must be a string or positive integer."%N)
676
677
if N <= 0:
678
raise KeyError("N (=%s) must be a string or positive integer."%N)
679
680
ret = {'allcurves': self.allcurves(N)}
681
if hasattr(self, 'allbsd'):
682
ret['allbsd'] = self.allbsd(N)
683
if hasattr(self, 'degphi'):
684
ret['degphi'] = self.degphi(N)
685
if hasattr(self, 'allgens'):
686
ret['allgens'] = self.allgens(N)
687
return ret
688
689
def __repr__(self):
690
"""
691
String representation of this database.
692
693
TESTS::
694
695
sage: c = CremonaDatabase('cremona mini')
696
sage: c.__repr__()
697
"Cremona's database of elliptic curves with conductor at most 9999"
698
"""
699
return "Cremona's database of elliptic curves with conductor at most "\
700
+ str(self.largest_conductor())
701
702
def allcurves(self, N):
703
"""
704
Returns the allcurves table of curves of conductor N.
705
706
INPUT:
707
708
- ``N`` - int, the conductor
709
710
OUTPUT:
711
712
- ``dict`` - id:[ainvs, rank, tor], ...
713
714
EXAMPLES::
715
716
sage: c = CremonaDatabase()
717
sage: c.allcurves(11)['a3']
718
[[0, -1, 1, 0, 0], 0, 5]
719
sage: c.allcurves(12)
720
{}
721
sage: c.allcurves(12001)['a1'] # optional - database_cremona_ellcurve
722
[[1, 0, 0, -101, 382], 1, 1]
723
"""
724
ret = {}
725
for c in self.__connection__.cursor().execute('SELECT curve,eqn,' \
726
+ 'rank,tors FROM t_curve,t_class USING(class) WHERE ' \
727
+ 'conductor=?',(int(N),)):
728
N,iso,num = parse_cremona_label(c[0])
729
ret[iso+str(num)] = [eval(c[1]),c[2],c[3]]
730
return ret
731
732
def curves(self, N):
733
"""
734
Returns the curves table of all *optimal* curves of conductor N.
735
736
INPUT:
737
738
- ``N`` - int, the conductor
739
740
OUTPUT:
741
742
- ``dict`` - id:[ainvs, rank, tor], ...
743
744
EXAMPLES:
745
746
Optimal curves of conductor 37::
747
748
sage: CremonaDatabase().curves(37)
749
{'a1': [[0, 0, 1, -1, 0], 1, 1], 'b1': [[0, 1, 1, -23, -50], 0, 3]}
750
751
Note the 'h3', which is the unique case in the tables where
752
the optimal curve doesn't have label ending in 1::
753
754
sage: list(sorted(CremonaDatabase().curves(990).keys()))
755
['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h3', 'i1', 'j1', 'k1', 'l1']
756
757
TESTS::
758
759
sage: c = CremonaDatabase()
760
sage: c.curves(12001)['a1'] # optional - database_cremona_ellcurve
761
[[1, 0, 0, -101, 382], 1, 1]
762
"""
763
ret = {}
764
for c in self.__connection__.cursor().execute('SELECT curve,eqn,' \
765
+ 'rank,tors FROM t_curve,t_class USING(class) WHERE ' \
766
+ 'curve=class||1 AND conductor=?',(int(N),)):
767
N,iso,num = parse_cremona_label(c[0])
768
ret[iso+str(num)] = [eval(c[1]),c[2],c[3]]
769
if N == 990:
770
del ret['h1']
771
ret['h3'] = [[1,-1,1,-1568,-4669],int(1),int(6)]
772
return ret
773
774
def elliptic_curve_from_ainvs(self, ainvs):
775
"""
776
Returns the elliptic curve in the database of with minimal
777
ainvs, if it exists, or raises a RuntimeError exception
778
otherwise.
779
780
INPUT:
781
782
- ``ainvs`` - list (5-tuple of int's); the minimal
783
Weierstrass model for an elliptic curve
784
785
OUTPUT: EllipticCurve
786
787
EXAMPLES::
788
789
sage: c = CremonaDatabase()
790
sage: c.elliptic_curve_from_ainvs([0, -1, 1, -10, -20])
791
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
792
sage: c.elliptic_curve_from_ainvs([1, 0, 0, -101, 382]) # optional - database_cremona_ellcurve
793
Elliptic Curve defined by y^2 + x*y = x^3 - 101*x + 382 over Rational Field
794
795
Old (pre-2006) Cremona labels are also allowed::
796
797
sage: c.elliptic_curve('9450KKKK1')
798
Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 5*x + 7 over Rational Field
799
800
Make sure :trac:`12565` is fixed::
801
802
sage: c.elliptic_curve('10a1')
803
Traceback (most recent call last):
804
...
805
ValueError: There is no elliptic curve with label 10a1 in the database
806
"""
807
q = self.__connection__.cursor().execute("SELECT curve FROM t_curve " \
808
+ "WHERE eqn=?",(str(ainvs).replace(' ',''),))
809
try:
810
return self.elliptic_curve(q.next()[0])
811
except StopIteration:
812
raise RuntimeError("No elliptic curve with ainvs (=%s) "%ainvs \
813
+ "in the database.")
814
815
def elliptic_curve(self, label):
816
"""
817
Return an elliptic curve with given label with some data about it
818
from the database pre-filled in.
819
820
INPUT:
821
822
- ``label`` - str (Cremona or LMFDB label)
823
824
OUTPUT:
825
826
- an :class:`sage.schemes.elliptic_curves.ell_rational_field.EllipticCurve_rational_field`
827
828
.. note::
829
830
For more details on LMFDB labels see :func:`parse_lmfdb_label`.
831
832
EXAMPLES::
833
834
sage: c = CremonaDatabase()
835
sage: c.elliptic_curve('11a1')
836
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
837
sage: c.elliptic_curve('12001a1') # optional - database_cremona_ellcurve
838
Elliptic Curve defined by y^2 + x*y = x^3 - 101*x + 382 over Rational Field
839
sage: c.elliptic_curve('48c1')
840
Traceback (most recent call last):
841
...
842
ValueError: There is no elliptic curve with label 48c1 in the database
843
844
You can also use LMFDB labels::
845
846
sage: c.elliptic_curve('462.f3')
847
Elliptic Curve defined by y^2 + x*y = x^3 - 363*x + 1305 over Rational Field
848
"""
849
# There are two possible strings: the Cremona label and the LMFDB label.
850
# They are distinguished by the presence of a period.
851
if label.find('.') == -1:
852
cremona_label = label
853
lmfdb_label = None
854
else:
855
cremona_label = lmfdb_to_cremona(label)
856
lmfdb_label = label
857
858
N, iso, num = parse_cremona_label(cremona_label)
859
label = str(N)+iso+str(num)
860
if self.get_skeleton() == _miniCremonaSkeleton:
861
q = self.__connection__.cursor().execute("SELECT eqn,rank,tors " \
862
+ 'FROM t_curve,t_class USING(class) WHERE curve=?', (label,))
863
else:
864
q = self.__connection__.cursor().execute("SELECT eqn,rank,tors," \
865
+ "deg,gens,cp,om,L,reg,sha FROM t_curve,t_class " \
866
+ "USING(class) WHERE curve=?",(label,))
867
try:
868
c = q.next()
869
F = elliptic.EllipticCurve(eval(c[0]))
870
F._set_cremona_label(label)
871
F._set_rank(c[1])
872
F._set_torsion_order(c[2])
873
F._set_conductor(N)
874
if lmfdb_label:
875
F._lmfdb_label = lmfdb_label
876
if len(c) > 3:
877
if num == 1:
878
F._set_modular_degree(c[3])
879
F._set_gens(eval(c[4]))
880
F.db_extra = list(c[5:])
881
elif c[1] == 0:
882
# we know the rank is 0, so the gens are empty
883
F._set_gens([])
884
return F
885
except StopIteration:
886
if N < self.largest_conductor():
887
message = "There is no elliptic curve with label " + label \
888
+ " in the database"
889
elif is_package_installed('database_cremona_ellcurve'):
890
message = "There is no elliptic curve with label " + label \
891
+ " in the currently available databases"
892
else:
893
message = "There is no elliptic curve with label " \
894
+ label + " in the default database; try installing " \
895
+ "the optional package database_cremona_ellcurve which " \
896
+ "contains the complete Cremona database"
897
raise ValueError(message)
898
899
def iter(self, conductors):
900
"""
901
Return an iterator through all curves in the database with given
902
conductors.
903
904
INPUT:
905
906
- ``conductors`` - list or generator of ints
907
908
OUTPUT: generator that iterates over EllipticCurve objects.
909
910
EXAMPLES::
911
912
sage: [e.cremona_label() for e in CremonaDatabase().iter([11..15])]
913
['11a1', '11a2', '11a3', '14a1', '14a2', '14a3', '14a4', '14a5',
914
'14a6', '15a1', '15a2', '15a3', '15a4', '15a5', '15a6', '15a7', '15a8']
915
"""
916
for N in conductors:
917
for c in self.__connection__.cursor().execute('SELECT curve ' \
918
+ 'FROM t_curve,t_class USING(class) WHERE conductor=?', \
919
(int(N),)):
920
yield self.elliptic_curve(c[0])
921
922
def isogeny_classes(self, conductor):
923
"""
924
Return the allcurves data (ainvariants, rank and torsion) for the
925
elliptic curves in the database of given conductor as a list of
926
lists, one for each isogeny class. The curve with number 1 is
927
always listed first.
928
929
EXAMPLES::
930
931
sage: c = CremonaDatabase()
932
sage: c.isogeny_classes(11)
933
[[[[0, -1, 1, -10, -20], 0, 5],
934
[[0, -1, 1, -7820, -263580], 0, 1],
935
[[0, -1, 1, 0, 0], 0, 5]]]
936
sage: c.isogeny_classes(12001) # optional - database_cremona_ellcurve
937
[[[[1, 0, 0, -101, 382], 1, 1]],
938
[[[0, 0, 1, -247, 1494], 1, 1]],
939
[[[0, 0, 1, -4, -18], 1, 1]],
940
[[[0, 1, 1, -10, 18], 1, 1]]]
941
"""
942
conductor=int(conductor)
943
classes = []
944
A = self.allcurves(conductor)
945
K = A.keys()
946
K.sort(cmp_code)
947
for k in K:
948
v = A[k]
949
# test if not first curve in class
950
if not (k[-1] == '1' and k[-2].isalpha()):
951
classes[len(classes)-1].append(v)
952
else:
953
classes.append([v])
954
return classes
955
956
def isogeny_class(self, label):
957
"""
958
Returns the isogeny class of elliptic curves that are
959
isogenous to the curve with given Cremona label.
960
961
INPUT:
962
963
- ``label`` - string
964
965
OUTPUT:
966
967
- ``list`` - list of EllipticCurve objects.
968
969
EXAMPLES::
970
971
sage: c = CremonaDatabase()
972
sage: c.isogeny_class('11a1')
973
[Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field,
974
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field,
975
Elliptic Curve defined by y^2 + y = x^3 - x^2 over Rational Field]
976
sage: c.isogeny_class('12001a1') # optional - database_cremona_ellcurve
977
[Elliptic Curve defined by y^2 + x*y = x^3 - 101*x + 382 over Rational Field]
978
"""
979
conductor,iso,num=parse_cremona_label(label)
980
q = self.__connection__.cursor().execute("SELECT curve FROM t_curve " \
981
+ "WHERE class=?",(str(conductor)+iso,))
982
return [self.elliptic_curve(c[0]) for c in q]
983
984
def iter_optimal(self, conductors):
985
"""
986
Return an iterator through all optimal curves in the database with given conductors.
987
988
INPUT:
989
990
- ``conductors`` - list or generator of ints
991
992
OUTPUT:
993
994
generator that iterates over EllipticCurve objects.
995
996
EXAMPLES:
997
998
We list optimal curves with conductor up to 20::
999
1000
sage: [e.cremona_label() for e in CremonaDatabase().iter_optimal([11..20])]
1001
['11a1', '14a1', '15a1', '17a1', '19a1', '20a1']
1002
1003
Note the unfortunate 990h3 special case::
1004
1005
sage: [e.cremona_label() for e in CremonaDatabase().iter_optimal([990])]
1006
['990a1', '990b1', '990c1', '990d1', '990e1', '990f1', '990g1', '990h3', '990i1', '990j1', '990k1', '990l1']
1007
"""
1008
for N in conductors:
1009
if N == 990:
1010
for c in self.__connection__.cursor().execute('SELECT class ' \
1011
+ 'FROM t_class WHERE conductor=990'):
1012
if c[0][-1] == u'h':
1013
yield self.elliptic_curve(c[0]+u'3')
1014
else:
1015
yield self.elliptic_curve(c[0]+u'1')
1016
continue
1017
for c in self.__connection__.cursor().execute('SELECT curve ' \
1018
+ 'FROM t_curve,t_class USING(class) WHERE curve=class||1 ' \
1019
+ 'AND conductor=?',(int(N),)):
1020
yield self.elliptic_curve(c[0])
1021
1022
def list(self, conductors):
1023
"""
1024
Returns a list of all curves with given conductors.
1025
1026
INPUT:
1027
1028
- ``conductors`` - list or generator of ints
1029
1030
OUTPUT:
1031
1032
- list of EllipticCurve objects.
1033
1034
EXAMPLES::
1035
1036
sage: CremonaDatabase().list([37])
1037
[Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field,
1038
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 23*x - 50 over Rational Field,
1039
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field,
1040
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 3*x + 1 over Rational Field]
1041
"""
1042
return list(self.iter(conductors))
1043
1044
def list_optimal(self, conductors):
1045
"""
1046
Returns a list of all optimal curves with given conductors.
1047
1048
INPUT:
1049
1050
- ``conductors`` - list or generator of ints
1051
list of EllipticCurve objects.
1052
1053
OUTPUT:
1054
1055
list of EllipticCurve objects.
1056
1057
EXAMPLES::
1058
1059
sage: CremonaDatabase().list_optimal([37])
1060
[Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field,
1061
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 23*x - 50 over Rational Field]
1062
"""
1063
return list(self.iter_optimal(conductors))
1064
1065
def largest_conductor(self):
1066
"""
1067
The largest conductor for which the database is complete.
1068
1069
OUTPUT:
1070
1071
- ``int`` - largest conductor
1072
1073
EXAMPLES::
1074
1075
sage: c = CremonaDatabase('cremona mini')
1076
sage: c.largest_conductor()
1077
9999
1078
"""
1079
if hasattr(self, '__largest_conductor__'):
1080
return self.__largest_conductor__
1081
#print "Computing largest conductor."
1082
q = self.__connection__.cursor().execute('SELECT conductor FROM ' \
1083
+ 't_class ORDER BY conductor DESC LIMIT 1')
1084
self.__largest_conductor__ = q.next()[0]
1085
return self.__largest_conductor__
1086
1087
def smallest_conductor(self):
1088
"""
1089
The smallest conductor for which the database is complete: always 1.
1090
1091
OUTPUT:
1092
1093
- ``int`` - smallest conductor
1094
1095
.. note::
1096
1097
This always returns the integer 1, since that is the
1098
smallest conductor for which the database is complete,
1099
although there are no elliptic curves of conductor 1. The
1100
smallest conductor of a curve in the database is 11.
1101
1102
EXAMPLES::
1103
1104
sage: CremonaDatabase().smallest_conductor()
1105
1
1106
"""
1107
return 1
1108
1109
def conductor_range(self):
1110
"""
1111
Return the range of conductors that are covered by the database.
1112
1113
OUTPUT: tuple of ints (N1,N2+1) where N1 is the smallest and
1114
N2 the largest conductor for which the database is complete.
1115
1116
EXAMPLES::
1117
1118
sage: c = CremonaDatabase('cremona mini')
1119
sage: c.conductor_range()
1120
(1, 10000)
1121
"""
1122
return 1, self.largest_conductor()+1
1123
1124
def number_of_curves(self, N=0, i=0):
1125
"""
1126
Returns the number of curves stored in the database with conductor
1127
N. If N = 0, returns the total number of curves in the database.
1128
1129
If i is nonzero, returns the number of curves in the i-th isogeny
1130
class. If i is a Cremona letter code, e.g., 'a' or 'bc', it is
1131
converted to the corresponding number.
1132
1133
INPUT:
1134
1135
- ``N`` - int
1136
- ``i`` - int or str
1137
1138
OUTPUT: int
1139
1140
EXAMPLES::
1141
1142
sage: c = CremonaDatabase()
1143
sage: c.number_of_curves(11)
1144
3
1145
sage: c.number_of_curves(37)
1146
4
1147
sage: c.number_of_curves(990)
1148
42
1149
sage: num = c.number_of_curves()
1150
"""
1151
if N == 0:
1152
if hasattr(self, '__number_of_curves__'):
1153
return self.__number_of_curves__
1154
q = self.__connection__.cursor().execute('SELECT COUNT(curve) ' \
1155
+ 'FROM t_curve')
1156
self.__number_of_curves__ = q.next()[0]
1157
return self.__number_of_curves__
1158
if i == 0:
1159
q = self.__connection__.cursor().execute('SELECT COUNT(curve) ' \
1160
+ 'FROM t_curve,t_class USING(class) WHERE conductor=?', \
1161
(int(N),))
1162
return q.next()[0]
1163
if not isinstance(i, str):
1164
i = cremona_letter_code(i)
1165
q = self.__connection__.cursor().execute('SELECT COUNT(curve) FROM ' \
1166
+ 't_curve WHERE class=?',(str(N)+i,))
1167
return q.next()[0]
1168
1169
def number_of_isogeny_classes(self, N=0):
1170
"""
1171
Returns the number of isogeny classes of curves in the database of
1172
conductor N. If N is 0, return the total number of isogeny classes
1173
of curves in the database.
1174
1175
INPUT:
1176
1177
- ``N`` - int
1178
1179
OUTPUT: int
1180
1181
EXAMPLES::
1182
1183
sage: c = CremonaDatabase()
1184
sage: c.number_of_isogeny_classes(11)
1185
1
1186
sage: c.number_of_isogeny_classes(37)
1187
2
1188
sage: num = c.number_of_isogeny_classes()
1189
"""
1190
if N == 0:
1191
if hasattr(self, '__number_of_isogeny_classes__'):
1192
return self.__number_of_isogeny_classes__
1193
q = self.__connection__.cursor().execute('SELECT COUNT(class) ' \
1194
+ 'FROM t_class')
1195
self.__number_of_isogeny_classes__ = q.next()[0]
1196
return self.__number_of_isogeny_classes__
1197
q = self.__connection__.cursor().execute('SELECT COUNT(class) FROM ' \
1198
+ 't_class WHERE conductor=?',(int(N),))
1199
return q.next()[0]
1200
1201
def random(self):
1202
"""
1203
Returns a random curve from the database.
1204
1205
EXAMPLES::
1206
1207
sage: CremonaDatabase().random() # random -- depends on database installed
1208
Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 224*x + 3072 over Rational Field
1209
"""
1210
N = randint(11, self.largest_conductor())
1211
q = self.__connection__.cursor().execute('SELECT conductor FROM ' \
1212
+ 't_class WHERE conductor>=? ORDER BY conductor',(int(N),))
1213
try:
1214
N = q.next()[0]
1215
except StopIteration:
1216
N = 11
1217
iso = randint(0, self.number_of_isogeny_classes(N)-1)
1218
iso = cremona_letter_code(iso)
1219
num = randint(1, self.number_of_curves(N,iso))
1220
return self.elliptic_curve(str(N)+iso+str(num))
1221
1222
###############################################################################
1223
# Functions for loading data from Cremona's ftpdata directory.
1224
###############################################################################
1225
def _init_from_ftpdata(self, ftpdata, largest_conductor=0):
1226
"""
1227
Create the SQL Cremona Database from the Cremona data directory,
1228
which is available from Cremona's website. I.e., just wget
1229
Cremona's database to a local directory.
1230
1231
To create the large database from Cremona's text files, see
1232
sage.databases.cremona.build, do NOT run this method directly.
1233
1234
EXAMPLES::
1235
1236
sage: d = sage.databases.cremona.MiniCremonaDatabase(name='cremona', read_only=False, rebuild=True) # not tested
1237
sage: d._init_from_ftpdata('.') # not tested
1238
"""
1239
if self.__read_only__:
1240
raise RuntimeError("The database must not be read_only.")
1241
1242
if not os.path.exists(ftpdata):
1243
raise RuntimeError("The cremona ftpdata directory '" + ftpdata \
1244
+ "' does not exist.")
1245
1246
if largest_conductor:
1247
print("largest conductor =", largest_conductor)
1248
self.__largest_conductor__ = largest_conductor
1249
1250
num_curves, num_iso_classes = self._init_allcurves(ftpdata, largest_conductor)
1251
self.__number_of_curves__ = num_curves
1252
self.__number_of_isogeny_classes__ = num_iso_classes
1253
if hasattr(self, 'degphi'):
1254
self._init_degphi(ftpdata, largest_conductor)
1255
if hasattr(self, 'allbsd'):
1256
self._init_allbsd(ftpdata, largest_conductor)
1257
if hasattr(self, 'allgens'):
1258
self._init_allgens(ftpdata, largest_conductor)
1259
self.vacuum()
1260
1261
def _init_allcurves(self, ftpdata, largest_conductor=0):
1262
"""
1263
Initialize the allcurves table by reading the corresponding ftpdata
1264
files and importing them into the database.
1265
1266
To create the large database from Cremona's text files, see
1267
sage.databases.cremona.build, do NOT run this method directly.
1268
1269
INPUT:
1270
1271
- ``largest_conductor`` - int (default: 0), if 0,
1272
then only include data up to that conductor.
1273
1274
OUTPUT:
1275
1276
- ``int`` - number_of_curves
1277
- ``int`` - number_of_isogeny_classes
1278
1279
EXAMPLES::
1280
1281
sage: d = sage.databases.cremona.MiniCremonaDatabase(name='cremona', read_only=False, rebuild=True) # not tested
1282
sage: d._init_allcurves('.', 11) # not tested
1283
(3, 1)
1284
"""
1285
if self.__read_only__:
1286
raise RuntimeError("The database must not be read_only.")
1287
files = sorted(os.listdir(ftpdata))
1288
name = 'allcurves'
1289
num_curves = 0
1290
num_iso_classes = 0
1291
con = self.get_connection()
1292
for F in files:
1293
if not F[:len(name)] == name:
1294
continue
1295
print("Inserting", F)
1296
class_data = []
1297
curve_data = []
1298
for L in file(ftpdata + "/" + F).readlines():
1299
N, iso, num, ainvs, r, tor = L.split()
1300
if largest_conductor and int(N) > largest_conductor: break
1301
cls = N+iso
1302
cur = cls+num
1303
if num == "1":
1304
class_data.append((N,cls,r))
1305
num_iso_classes += 1
1306
curve_data.append((cur,cls,ainvs,tor))
1307
num_curves += 1
1308
con.executemany('INSERT INTO t_class (conductor,class,rank) ' \
1309
+ 'VALUES (?,?,?)', class_data)
1310
con.executemany('INSERT INTO t_curve (curve,class,eqn,tors) ' \
1311
+ 'VALUES (?,?,?,?)', curve_data)
1312
print("Committing...")
1313
print("num_iso_classes =", num_iso_classes)
1314
self.commit()
1315
if largest_conductor and int(N) > largest_conductor: break
1316
return num_curves, num_iso_classes
1317
1318
class LargeCremonaDatabase(MiniCremonaDatabase):
1319
"""
1320
The Cremona database of elliptic curves.
1321
1322
EXAMPLES::
1323
1324
sage: c = CremonaDatabase('cremona') # optional - database_cremona_ellcurve
1325
sage: c.allcurves(11) # optional - database_cremona_ellcurve
1326
{'a1': [[0, -1, 1, -10, -20], 0, 5], 'a3': [[0, -1, 1, 0, 0], 0, 5],
1327
'a2': [[0, -1, 1, -7820, -263580], 0, 1]}
1328
"""
1329
def __init__(self, name, read_only=True, build=False):
1330
"""
1331
Initialize the database.
1332
1333
TESTS::
1334
1335
sage: c = CremonaDatabase('cremona') # optional - database_cremona_ellcurve
1336
sage: c.name # optional - database_cremona_ellcurve
1337
'cremona'
1338
"""
1339
self.name = name
1340
name = name.replace(' ','_')
1341
db_path = os.path.join(SAGE_SHARE, 'cremona', name+'.db')
1342
if build:
1343
if name is None:
1344
raise RuntimeError('The database must have a name.')
1345
if read_only:
1346
raise RuntimeError('The database must not be read_only.')
1347
SQLDatabase.__init__(self, db_path, read_only=read_only, \
1348
skeleton=_cremonaSkeleton)
1349
return
1350
if not os.path.isfile(db_path):
1351
raise ValueError("Desired database (='%s') does not "%self.name \
1352
+ "exist")
1353
SQLDatabase.__init__(self, db_path, read_only=read_only)
1354
if self.get_skeleton() != _cremonaSkeleton:
1355
raise RuntimeError('Database at %s does '%(self.__dblocation__) \
1356
+ 'not appear to be a valid SQL Cremona database.')
1357
1358
def allbsd(self, N):
1359
r"""
1360
Return the allbsd table for conductor N. The entries are::
1361
1362
[id, tamagawa_product, Omega_E, L, Reg_E, Sha_an(E)]
1363
1364
where id is the isogeny class (letter) followed by a number, e.g.,
1365
b3, and L is `L^r(E,1)/r!`, where E has rank r.
1366
1367
INPUT:
1368
1369
- ``N`` - int, the conductor
1370
1371
OUTPUT: dict containing the allbsd table for each isogeny class
1372
in conductor N
1373
1374
EXAMPLES::
1375
1376
sage: c = CremonaDatabase()
1377
sage: c.allbsd(12) # optional - database_cremona_ellcurve
1378
{}
1379
sage: c.allbsd(19)['a3'] # optional - database_cremona_ellcurve
1380
[1, 4.07927920046493, 0.453253244496104, 1.0, 1]
1381
sage: c.allbsd(12001)['a1'] # optional - database_cremona_ellcurve
1382
[2, 3.27608135248722, 1.54910143090506, 0.236425971187952, 1.0]
1383
"""
1384
ret = {}
1385
for c in self.__connection__.cursor().execute('SELECT curve,cp,om,L,' \
1386
+ 'reg,sha FROM t_curve,t_class USING(class) WHERE conductor=?', \
1387
(int(N),)):
1388
N,iso,num = parse_cremona_label(c[0])
1389
ret[iso+str(num)] = list(c[1:])
1390
return ret
1391
1392
def allgens(self, N):
1393
"""
1394
Return the allgens table for conductor N.
1395
1396
INPUT:
1397
1398
- ``N`` - int, the conductor
1399
1400
OUTPUT:
1401
1402
- ``dict`` - id:[points, ...], ...
1403
1404
EXAMPLES::
1405
1406
sage: c = CremonaDatabase()
1407
sage: c.allgens(12) # optional - database_cremona_ellcurve
1408
{}
1409
sage: c.allgens(1001)['a1'] # optional - database_cremona_ellcurve
1410
[[61, 181, 1]]
1411
sage: c.allgens(12001)['a1'] # optional - database_cremona_ellcurve
1412
[[7, 2, 1]]
1413
"""
1414
ret = {}
1415
for c in self.__connection__.cursor().execute('SELECT curve,gens ' \
1416
+ 'FROM t_curve,t_class USING(class) WHERE conductor=?',(int(N),)):
1417
N,iso,num = parse_cremona_label(c[0])
1418
ret[iso+str(num)] = eval(c[1])
1419
return ret
1420
1421
def degphi(self, N):
1422
"""
1423
Return the degphi table for conductor N.
1424
1425
INPUT:
1426
1427
- ``N`` - int, the conductor
1428
1429
OUTPUT:
1430
1431
- ``dict`` - id:degphi, ...
1432
1433
EXAMPLES::
1434
1435
sage: c = CremonaDatabase()
1436
sage: c.degphi(11) # optional - database_cremona_ellcurve
1437
{'a1': 1}
1438
sage: c.degphi(12001)['c1'] # optional - database_cremona_ellcurve
1439
1640
1440
"""
1441
ret = {}
1442
for c in self.__connection__.cursor().execute('SELECT curve,deg FROM' \
1443
+ ' t_curve,t_class USING(class) WHERE curve=class||1 AND ' \
1444
+ 'conductor=?', (int(N),)):
1445
N,iso,num = parse_cremona_label(c[0])
1446
ret[iso+str(num)] = c[1]
1447
return ret
1448
1449
def _init_degphi(self, ftpdata, largest_conductor=0):
1450
"""
1451
Initialize the degphi table by reading the corresponding ftpdata
1452
files and importing them into the database.
1453
1454
To create the large database from Cremona's text files, see
1455
sage.databases.cremona.build, do NOT run this method directly.
1456
1457
EXAMPLES::
1458
1459
sage: d = sage.databases.cremona.LargeCremonaDatabase(name='cremona', read_only=False, rebuild=True) # not tested
1460
sage: d._init_degphi('.') # not tested
1461
"""
1462
if self.__read_only__:
1463
raise RuntimeError("The database must not be read_only.")
1464
files = sorted(os.listdir(ftpdata))
1465
name = "degphi"
1466
con = self.get_connection()
1467
for F in files:
1468
if not F[:len(name)] == name:
1469
continue
1470
print("Inserting", F)
1471
class_data = []
1472
for L in file(ftpdata + "/" + F).readlines():
1473
N, iso, num, degree, primes, curve = L.split()
1474
if largest_conductor and int(N) > largest_conductor: break
1475
class_data.append((degree,N+iso))
1476
con.executemany('UPDATE t_class SET deg=? WHERE class=?', \
1477
class_data)
1478
print("Committing...")
1479
self.commit()
1480
if largest_conductor and int(N) > largest_conductor: break
1481
1482
def _init_allbsd(self, ftpdata, largest_conductor=0):
1483
"""
1484
Initialize the allbsd table by reading the corresponding ftpdata
1485
files and importing them into the database.
1486
1487
To create the large database from Cremona's text files, see
1488
sage.databases.cremona.build, do NOT run this method directly.
1489
1490
EXAMPLES::
1491
1492
sage: d = sage.databases.cremona.LargeCremonaDatabase(name='cremona', read_only=False, rebuild=True) # not tested
1493
sage: d._init_allbsd('.') # not tested
1494
"""
1495
if self.__read_only__:
1496
raise RuntimeError("The database must not be read_only.")
1497
files = sorted(os.listdir(ftpdata))
1498
name = "allbsd"
1499
con = self.get_connection()
1500
for F in files:
1501
if not F[:len(name)] == name:
1502
continue
1503
print("Inserting", F)
1504
curve_data = []
1505
class_data = []
1506
for L in file(ftpdata + "/" + F).readlines():
1507
N, iso, num, eqn, rank, tor, cp, om, L, reg, sha = L.split()
1508
if largest_conductor and int(N) > largest_conductor: break
1509
cls = N+iso
1510
if num == "1":
1511
class_data.append((L,cls))
1512
curve_data.append((cp,om,reg,eval(sha),cls+num))
1513
con.executemany("UPDATE t_class SET L=? WHERE class=?", class_data)
1514
con.executemany("UPDATE t_curve SET cp=?,om=?,reg=?,sha=? WHERE " \
1515
+ "curve=?", curve_data)
1516
print("Committing...")
1517
self.commit()
1518
if largest_conductor and int(N) > largest_conductor: break
1519
1520
def _init_allgens(self, ftpdata, largest_conductor=0):
1521
"""
1522
Initialize the allgens table by reading the corresponding ftpdata
1523
files and importing them into the database.
1524
1525
To create the large database from Cremona's text files, see
1526
sage.databases.cremona.build, do NOT run this method directly.
1527
1528
EXAMPLES::
1529
1530
sage: d = sage.databases.cremona.LargeCremonaDatabase(name='cremona', read_only=False, rebuild=True) # not tested
1531
sage: d._init_allgens('.') # not tested
1532
"""
1533
if self.__read_only__:
1534
raise RuntimeError("The database must not be read_only.")
1535
files = sorted(os.listdir(ftpdata))
1536
name = "allgens"
1537
con = self.get_connection()
1538
for F in files:
1539
if not F[:len(name)] == name:
1540
continue
1541
print("Inserting", F)
1542
curve_data = []
1543
for L in file(ftpdata + "/" + F).readlines():
1544
v = L.split()
1545
if largest_conductor and int(v[0]) > largest_conductor: break
1546
gens = '['+','.join(v[6:6+int(v[4])]).replace(':',',')+']'
1547
curve_data.append((gens,''.join(v[:3])))
1548
con.executemany("UPDATE t_curve SET gens=? WHERE curve=?", \
1549
curve_data)
1550
print("Committing...")
1551
if largest_conductor and int(v[0]) > largest_conductor: break
1552
1553
_db = None
1554
def CremonaDatabase(name=None,mini=None,set_global=None):
1555
"""
1556
Initializes the Cremona database with name ``name``. If ``name`` is
1557
``None`` it instead initializes large Cremona database (named 'cremona'),
1558
if available or default mini Cremona database (named 'cremona mini').
1559
1560
If the Cremona database in question is in the format of the mini database,
1561
you must set ``mini=True``, otherwise it must be set to ``False``.
1562
1563
If you would like other components of Sage to use this database, mark
1564
``set_global=True``.
1565
1566
TESTS::
1567
1568
sage: c = CremonaDatabase()
1569
sage: isinstance(c, sage.databases.cremona.MiniCremonaDatabase)
1570
True
1571
sage: isinstance(c, sage.databases.cremona.LargeCremonaDatabase) # optional - database_cremona_ellcurve
1572
True
1573
1574
Verify that :trac:`12341` has been resolved::
1575
1576
sage: c = CremonaDatabase('should not exist',mini=True)
1577
Traceback (most recent call last):
1578
...
1579
ValueError: Desired database (='should not exist') does not exist
1580
sage: c = CremonaDatabase('should not exist',mini=False)
1581
Traceback (most recent call last):
1582
...
1583
ValueError: Desired database (='should not exist') does not exist
1584
sage: from sage.misc.misc import SAGE_SHARE
1585
sage: os.path.isfile(os.path.join(SAGE_SHARE,'cremona','should_not_exist.db'))
1586
False
1587
"""
1588
global _db
1589
if set_global is None:
1590
set_global = _db is None and name is None
1591
if name is None and not set_global:
1592
return _db
1593
if set_global and name is None:
1594
if is_package_installed('database_cremona_ellcurve'):
1595
name = 'cremona'
1596
else:
1597
name = 'cremona mini'
1598
if name == 'cremona':
1599
mini = False
1600
elif name == 'cremona mini':
1601
mini = True
1602
if mini is None:
1603
raise ValueError('mini must be set as either True or False')
1604
if set_global:
1605
if mini:
1606
_db = MiniCremonaDatabase(name)
1607
else:
1608
_db = LargeCremonaDatabase(name)
1609
return _db
1610
if mini:
1611
return MiniCremonaDatabase(name)
1612
return LargeCremonaDatabase(name)
1613
1614