Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
AndrewVSutherland
GitHub Repository: AndrewVSutherland/lmfdb
Path: blob/main/scripts/ecnf/hmf_check_find.py
1128 views
1
# -*- coding: utf-8 -*-
2
r""" Functions to check consistency of data between elliptic curves and
3
Hilbert Modular Forms databases: """
4
5
6
# 2018-12-14: converted to work with the postgres database (JEC)
7
8
import sys
9
from sage.all import EllipticCurve, Magma, srange
10
from lmfdb import db
11
12
print("setting nfcurves")
13
nfcurves = db.ec_nfcurves
14
15
print("setting hmfs, forms, fields")
16
forms = db.hmf_forms
17
fields = db.hmf_fields
18
hecke = db.hmf_hecke # contains eigenvalues
19
20
flabels = fields.distinct('label')
21
flab2 = [fld for fld in flabels if '2.2.' in fld]
22
flab3 = [fld for fld in flabels if '3.3.' in fld]
23
flab4 = [fld for fld in flabels if '4.4.' in fld]
24
flab5 = [fld for fld in flabels if '5.5.' in fld]
25
flab6 = [fld for fld in flabels if '6.6.' in fld]
26
fld=None # else after re-reading this file fld gets left set to 6.6.905177.1
27
#
28
#
29
# Code to check conductor labels agree with Hilbert Modular Form level
30
# labels for a real quadratic field. So far run on all curves over
31
# Q(sqrt(5)).
32
#
33
#
34
35
from lmfdb.hilbert_modular_forms.hilbert_field import HilbertNumberField, str2ideal
36
from lmfdb.hilbert_modular_forms.hilbert_modular_form import get_hmf
37
from scripts.ecnf.import_utils import make_curves_line
38
from lmfdb.ecnf.WebEllipticCurve import parse_ainvs
39
40
def make_conductor(ecnfdata, hfield):
41
_, _, I, _ = str2ideal(hfield.K(), ecnfdata['conductor_ideal'])
42
return I
43
44
def check_ideal_labels(field_label='2.2.5.1', min_norm=0, max_norm=None, fix=False, verbose=False):
45
r""" Go through all curves with the given field label, assumed totally
46
real, check whether the ideal label agrees with the level_label of
47
the associated Hilbert Modular Form.
48
"""
49
query = {}
50
query['field_label'] = field_label
51
query['conductor_norm'] = {'$gte': int(min_norm)}
52
if max_norm:
53
query['conductor_norm']['$lte'] = int(max_norm)
54
else:
55
max_norm = 'infinity'
56
cursor = nfcurves.search(query)
57
K = HilbertNumberField(field_label)
58
# NB We used to have 20 in the next line but that is insufficient
59
# to distinguish the a_p for forms 2.2.12.1-150.1-a and
60
# 2.2.12.1-150.1-b !
61
remap = {} # remap[old_label] = new_label
62
63
for ec in cursor:
64
fix_needed = False
65
cond_label = ec['conductor_label']
66
if cond_label in remap:
67
new_cond_label = remap[cond_label]
68
fix_needed = (cond_label != new_cond_label)
69
if not fix_needed:
70
if verbose:
71
print("conductor label %s ok" % cond_label)
72
else:
73
conductor = make_conductor(ec, K)
74
new_cond_label = K.ideal_label(conductor)
75
remap[cond_label] = new_cond_label
76
fix_needed = (cond_label != new_cond_label)
77
78
if fix_needed:
79
print("conductor label for curve %s is wrong, should be %s not %s" % (ec['label'], new_cond_label, cond_label))
80
if fix:
81
iso = ec['iso_label']
82
num = str(ec['number'])
83
newlabeldata = {}
84
newlabeldata['conductor_label'] = new_cond_label
85
newlabeldata['short_class_label'] = '-'.join([new_cond_label, iso])
86
newlabeldata['short_label'] = ''.join([newlabeldata['short_class_label'], num])
87
newlabeldata['class_label'] = '-'.join([field_label,
88
newlabeldata['short_class_label']])
89
newlabeldata['label'] = '-'.join([field_label,
90
newlabeldata['short_label']])
91
nfcurves.update({'_id': ec['_id']}, {"$set": newlabeldata}, upsert=True)
92
else:
93
if verbose:
94
print("conductor label %s ok" % cond_label)
95
96
return dict([(k, remap[k]) for k in remap if not k == remap[k]])
97
98
#
99
#
100
# Code to check isogeny class labels agree with Hilbert Modular Form
101
# labels of each level, for a real quadratic field. Tested on all
102
# curves over Q(sqrt(5)).
103
#
104
#
105
106
def check_curve_labels(field_label='2.2.5.1', min_norm=0, max_norm=None, fix=False, verbose=False):
107
r""" Go through all curves with the given field label, assumed totally
108
real, test whether a Hilbert Modular Form exists with the same
109
label.
110
"""
111
query = {}
112
query['field_label'] = field_label
113
query['number'] = 1 # only look at first curve in each isogeny class
114
query['conductor_norm'] = {'$gte': int(min_norm)}
115
if max_norm:
116
query['conductor_norm']['$lte'] = int(max_norm)
117
else:
118
max_norm = 'infinity'
119
cursor = nfcurves.search(query)
120
nfound = 0
121
nnotfound = 0
122
nok = 0
123
bad_curves = []
124
K = HilbertNumberField(field_label)
125
primes = [P['ideal'] for P in K.primes_iter(30)]
126
curve_ap = {} # curve_ap[conductor_label] will be a dict iso -> ap
127
form_ap = {} # form_ap[conductor_label] will be a dict iso -> ap
128
129
# Step 1: look at all curves (one per isogeny class), check that
130
# there is a Hilbert newform of the same label, and if so compare
131
# ap-lists. The dicts curve_ap and form_ap store these when
132
# there is disagreement:
133
# e.g. curve_ap[conductor_label][iso_label] = aplist.
134
135
for ec in cursor:
136
hmf_label = "-".join([ec['field_label'], ec['conductor_label'], ec['iso_label']])
137
f = get_hmf(hmf_label)
138
if f:
139
if verbose:
140
print("hmf with label %s found" % hmf_label)
141
nfound += 1
142
ainvsK = parse_ainvs(K.K(), ec['ainvs'])
143
E = EllipticCurve(ainvsK)
144
good_flags = [E.has_good_reduction(P) for P in primes]
145
good_primes = [P for (P, flag) in zip(primes, good_flags) if flag]
146
aplist = [E.reduction(P).trace_of_frobenius() for P in good_primes[:10]]
147
f_hecke = hecke.lucky({'label': hmf_label}, projection=['hecke_eigenvalues'])
148
f_aplist = [int(a) for a in f_hecke['hecke_eigenvalues'][:30]]
149
f_aplist = [ap for ap, flag in zip(f_aplist, good_flags) if flag][:10]
150
if aplist == f_aplist:
151
nok += 1
152
if verbose:
153
print("Curve %s and newform agree!" % ec['short_label'])
154
else:
155
bad_curves.append(ec['short_label'])
156
print("Curve %s does NOT agree with newform" % ec['short_label'])
157
if verbose:
158
print("ap from curve: %s" % aplist)
159
print("ap from form: %s" % f_aplist)
160
if not ec['conductor_label'] in curve_ap:
161
curve_ap[ec['conductor_label']] = {}
162
form_ap[ec['conductor_label']] = {}
163
curve_ap[ec['conductor_label']][ec['iso_label']] = aplist
164
form_ap[ec['conductor_label']][f['label_suffix']] = f_aplist
165
else:
166
if verbose:
167
print("No hmf with label %s found!" % hmf_label)
168
nnotfound += 1
169
170
# Report progress:
171
172
n = nfound + nnotfound
173
if nnotfound:
174
print("Out of %s forms, %s were found and %s were not found" % (n, nfound, nnotfound))
175
else:
176
print("Out of %s classes of curve, all %s had newforms with the same label" % (n, nfound))
177
if nfound == nok:
178
print("All curves agree with matching newforms")
179
else:
180
print("%s curves agree with matching newforms, %s do not" % (nok, nfound - nok))
181
# print("Bad curves: %s" % bad_curves)
182
183
# Step 2: for each conductor_label for which there was a
184
# discrepancy, create a dict giving the permutation curve -->
185
# newform, so remap[conductor_label][iso_label] = form_label
186
187
remap = {}
188
for level in curve_ap.keys():
189
remap[level] = {}
190
c_dat = curve_ap[level]
191
f_dat = form_ap[level]
192
for a in c_dat.keys():
193
aplist = c_dat[a]
194
for b in f_dat.keys():
195
if aplist == f_dat[b]:
196
remap[level][a] = b
197
break
198
if verbose:
199
print("remap: %s" % remap)
200
201
# Step 3, for through all curves with these bad conductors and
202
# create new labels for them, update the database with these (if
203
# fix==True)
204
205
for level in remap.keys():
206
perm = remap[level]
207
print("Fixing iso labels for conductor %s using map %s" % (level, perm))
208
query = {}
209
query['field_label'] = field_label
210
query['conductor_label'] = level
211
cursor = nfcurves.search(query)
212
for ec in cursor:
213
iso = ec['iso_label']
214
if iso in perm:
215
new_iso = perm[iso]
216
if verbose:
217
print("--mapping class %s to class %s" % (iso, new_iso))
218
num = str(ec['number'])
219
newlabeldata = {}
220
newlabeldata['iso_label'] = new_iso
221
newlabeldata['short_class_label'] = '-'.join([level, new_iso])
222
newlabeldata['class_label'] = '-'.join([field_label,
223
newlabeldata['short_class_label']])
224
newlabeldata['short_label'] = ''.join([newlabeldata['short_class_label'], num])
225
newlabeldata['label'] = '-'.join([field_label,
226
newlabeldata['short_label']])
227
if verbose:
228
print("new data fields: %s" % newlabeldata)
229
if fix:
230
nfcurves.update({'_id': ec['_id']}, {"$set": newlabeldata}, upsert=True)
231
232
#
233
#
234
# Code to go through HMF database to find newforms which should have
235
# associated curves, look to see if a suitable curve exists, and if
236
# not to create a Magma script to search for one.
237
#
238
# NB the first version find_curve_labels() just outputs a Magma
239
# script; after running Magma, use export_magma_output() to produce a
240
# file of curves. Or (simpler when Magma is available on the same
241
# machine) use the second version, find_curves(), which runs Magma
242
# itself and outputs the resulting curves.
243
244
245
def output_magma_field(field_label, K, Plist, outfilename=None, verbose=False):
246
r"""
247
Writes Magma code to a file to define a number field and list of primes.
248
249
INPUT:
250
251
- ``field_label`` (str) -- a number field label
252
253
- ``K`` -- a number field.
254
255
- ``Plist`` -- a list of prime ideals of `K`.
256
257
- ``outfilename`` (string, default ``None``) -- name of file for output.
258
259
- ``verbose`` (boolean, default ``False``) -- verbosity flag. If
260
True, all output written to stdout.
261
262
NOTE:
263
264
Does not assumes the primes are principal.
265
266
OUTPUT:
267
268
(To file and/or screen, nothing is returned): Magma commands to
269
define the field `K` and the list `Plist` of primes.
270
"""
271
if outfilename:
272
outfile = open(outfilename, mode="w")
273
name = K.gen()
274
pol = K.defining_polynomial()
275
276
def output(L):
277
if outfilename:
278
outfile.write(L)
279
if verbose:
280
sys.stdout.write(L)
281
output('print "Field %s";\n' % field_label)
282
output("Qx<x> := PolynomialRing(RationalField());\n")
283
output("K<%s> := NumberField(%s);\n" % (name, pol))
284
output("OK := Integers(K);\n")
285
output("Plist := [];\n")
286
for P in Plist:
287
Pgens = P.gens_reduced()
288
Pmagma = "(%s)*OK" % Pgens[0]
289
if len(Pgens) > 1:
290
Pmagma += "+(%s)*OK" % Pgens[1]
291
output("Append(~Plist,%s);\n" % Pmagma)
292
# output("Append(~Plist,(%s)*OK);\n" % P.gens_reduced()[0])
293
# output definition of search function:
294
output('\n')
295
output('ECSearch := procedure(class_label, N, aplist,effort);\n')
296
output('print "Isogeny class ", class_label;\n')
297
output('goodP := [P: P in Plist | Valuation(N,P) eq 0];\n')
298
output('nap :=Min(#aplist,#goodP);\n')
299
output('goodP := [goodP[i]: i in [1..nap]];\n')
300
output('aplist := [aplist[i]: i in [1..nap]];\n')
301
output('print "... searching with effort", effort, " using ", nap, " primes...";\n')
302
output('curves := EllipticCurveSearch(N,effort : Primes:=goodP, Traces:=aplist);\n')
303
output('curves := [E: E in curves | &and[TraceOfFrobenius(E,goodP[i]) eq aplist[i] : i in [1..nap]]];\n')
304
output('if #curves eq 0 then print "No curve found"; end if;\n')
305
output('for E in curves do;\n ')
306
output('a1,a2,a3,a4,a6:=Explode(aInvariants(E));\n ')
307
output('printf "Curve [%o,%o,%o,%o,%o]\\n",a1,a2,a3,a4,a6;\n ')
308
output('end for;\n')
309
output('end procedure;\n\n')
310
output('SetColumns(0);\n')
311
if outfilename:
312
output("\n")
313
outfile.close()
314
315
316
def output_magma_curve_search(HMF, form, outfilename=None, verbose=False, effort=1000):
317
r""" Outputs Magma script to search for an curve to match the newform
318
with given label.
319
320
INPUT:
321
322
- ``HMF`` -- a HilbertModularField
323
324
- ``form`` -- a rational Hilbert newform from the database
325
326
- ``outfilename`` (string, default ``None``) -- name of output file
327
328
- ``verbose`` (boolean, default ``False``) -- verbosity flag.
329
330
OUTPUT:
331
332
(To file and/or screen, nothing is returned): Magma commands to
333
search for curves given their conductors and Traces of Frobenius,
334
as determined by the level and (rational) Hecke eigenvalues of a
335
Hilbert Modular Newform. The output will be appended to the file
336
whoswe name is provided, so that the field definition can be
337
output there first using the output_magma_field() function.
338
"""
339
def output(L):
340
if outfilename:
341
outfile.write(L)
342
if verbose:
343
sys.stdout.write(L)
344
if outfilename:
345
outfile = open(outfilename, mode="a")
346
347
N = HMF.ideal(form['level_label'])
348
conductor_ideal = form['level_ideal'].replace(" ","")
349
neigs = len(form['hecke_eigenvalues'])
350
Plist = [P['ideal'] for P in HMF.primes_iter(neigs)]
351
goodP = [(i, P) for i, P in enumerate(Plist) if not P.divides(N)]
352
label = form['short_label']
353
if verbose:
354
print("Missing curve %s" % label)
355
aplist = [int(form['hecke_eigenvalues'][i]) for i, P in goodP]
356
Ngens = N.gens_reduced()
357
Nmagma = "(%s)*OK" % Ngens[0]
358
if len(Ngens) > 1:
359
Nmagma += "+(%s)*OK" % Ngens[1]
360
output('print "Conductor %s";\n' % conductor_ideal)
361
output("ECSearch(\"%s\",%s,%s,%s);\n" % (label, Nmagma, aplist,effort))
362
# output("ECSearch(\"%s\",(%s)*OK,%s);\n" % (label,N.gens_reduced()[0],aplist))
363
364
if outfilename:
365
outfile.close()
366
367
368
def find_curve_labels(field_label='2.2.5.1', min_norm=0, max_norm=None, outfilename=None, verbose=False, effort=1000):
369
r""" Go through all Hilbert Modular Forms with the given field label,
370
assumed totally real, for level norms in the given range, test
371
whether an elliptic curve exists with the same label.
372
"""
373
query = {}
374
query['field_label'] = field_label
375
if fields.search({'label': field_label}).count() == 0:
376
if verbose:
377
print("No HMF data for field %s" % field_label)
378
return None
379
380
query['dimension'] = 1 # only look at rational newforms
381
query['level_norm'] = {'$gte': int(min_norm)}
382
if max_norm:
383
query['level_norm']['$lte'] = int(max_norm)
384
else:
385
max_norm = 'infinity'
386
cursor = forms.search(query, sort=['level_norm'])
387
labels = [f['label'] for f in cursor]
388
nfound = 0
389
nnotfound = 0
390
nok = 0
391
missing_curves = []
392
K = HilbertNumberField(field_label)
393
primes = [P['ideal'] for P in K.primes_iter()]
394
curve_ap = {} # curve_ap[conductor_label] will be a dict iso -> ap
395
form_ap = {} # form_ap[conductor_label] will be a dict iso -> ap
396
397
# Step 1: look at all newforms, check that there is an elliptic
398
# curve of the same label, and if so compare ap-lists. The
399
# dicts curve_ap and form_ap store these when there is
400
# disagreement: e.g. curve_ap[conductor_label][iso_label] =
401
# aplist.
402
403
for curve_label in labels:
404
# We find the forms again since otherwise the cursor might timeout during the loop.
405
f = get_hmf(curve_label)
406
ec = nfcurves.lucky({'field_label': field_label, 'class_label': curve_label, 'number': 1})
407
if ec:
408
if verbose:
409
print("curve with label %s found" % curve_label)
410
nfound += 1
411
ainvsK = parse_ainvs(K.K(), ec['ainvs'])
412
E = EllipticCurve(ainvsK)
413
good_flags = [E.has_good_reduction(P) for P in primes]
414
good_primes = [P for (P, flag) in zip(primes, good_flags) if flag]
415
aplist = [E.reduction(P).trace_of_frobenius() for P in good_primes[:30]]
416
f_aplist = [int(a) for a in f['hecke_eigenvalues'][:40]]
417
f_aplist = [ap for ap, flag in zip(f_aplist, good_flags) if flag][:30]
418
if aplist == f_aplist:
419
nok += 1
420
if verbose:
421
print("Curve %s and newform agree!" % ec['short_label'])
422
else:
423
print("Curve %s does NOT agree with newform" % ec['short_label'])
424
if verbose:
425
print("ap from curve: %s" % aplist)
426
print("ap from form: %s" % f_aplist)
427
if not ec['conductor_label'] in curve_ap:
428
curve_ap[ec['conductor_label']] = {}
429
form_ap[ec['conductor_label']] = {}
430
curve_ap[ec['conductor_label']][ec['iso_label']] = aplist
431
form_ap[ec['conductor_label']][f['label_suffix']] = f_aplist
432
else:
433
if verbose:
434
print("No curve with label %s found!" % curve_label)
435
missing_curves.append(f['short_label'])
436
nnotfound += 1
437
438
# Report progress:
439
440
n = nfound + nnotfound
441
if nnotfound:
442
print("Out of %s newforms, %s curves were found and %s were not found" % (n, nfound, nnotfound))
443
else:
444
print("Out of %s newforms, all %s had curves with the same label and ap" % (n, nfound))
445
if nfound == nok:
446
print("All curves agree with matching newforms")
447
else:
448
print("%s curves agree with matching newforms, %s do not" % (nok, nfound - nok))
449
if nnotfound:
450
print("Missing curves: %s" % missing_curves)
451
else:
452
return
453
454
if outfilename is None:
455
return
456
457
# Step 2: for each newform for which there was no curve, create a
458
# Magma file containing code to search for such a curve.
459
460
# First output Magma code to define the field and primes:
461
output_magma_field(field_label, K.K(), primes, outfilename)
462
if verbose:
463
print("...output definition of field and primes finished")
464
465
for nf_label in missing_curves:
466
if verbose:
467
print("Curve %s is missing..." % nf_label)
468
form = forms.lucky({'field_label': field_label, 'short_label': nf_label})
469
if not form:
470
print("... form %s not found!" % nf_label)
471
else:
472
if verbose:
473
print("... found form, outputting Magma search code")
474
output_magma_curve_search(K, form, outfilename, verbose=verbose, effort=effort)
475
476
# Use the following by preference, assuming that Magma is available.
477
# If outfilename=None (the default) then no searching is done and no
478
# output file produced, but this can be used to check that curves
479
# matching newforms do exist. By default all newforms (with dimension
480
# 1) for the given field are processed; one can also specify a range
481
# of level norms, or an individual newform label (without the field
482
# prefix).
483
484
def find_curves(field_label='2.2.5.1', min_norm=0, max_norm=None, label=None, outfilename=None, verbose=False, effort=500):
485
r""" Go through all Hilbert Modular Forms with the given field label,
486
assumed totally real, for level norms in the given range, test
487
whether an elliptic curve exists with the same label; if not, find
488
the curves using Magma; output these to a file.
489
"""
490
print("Checking forms over {}, norms from {} to {}".format(field_label,min_norm,max_norm))
491
if outfilename:
492
print("Output of curves found to {}".format(outfilename))
493
else:
494
print("No curve search or output, just checking")
495
query = {}
496
query['field_label'] = field_label
497
if not fields.exists({'label': field_label}):
498
if verbose:
499
print("No HMF data for field %s" % field_label)
500
return None
501
502
query['dimension'] = 1 # only look at rational newforms
503
if label:
504
print("looking for {} only".format(label))
505
query['short_label'] = label # e.g. '91.1-a'
506
else:
507
query['level_norm'] = {'$gte': int(min_norm)}
508
if max_norm:
509
query['level_norm']['$lte'] = int(max_norm)
510
cursor = forms.search(query, sort=['level_norm'])
511
labels = [f['label'] for f in cursor]
512
nfound = 0
513
nnotfound = 0
514
nok = 0
515
missing_curves = []
516
K = HilbertNumberField(field_label)
517
primes = [P['ideal'] for P in K.primes_iter(1000)]
518
curve_ap = {} # curve_ap[conductor_label] will be a dict iso -> ap
519
form_ap = {} # form_ap[conductor_label] will be a dict iso -> ap
520
521
# Step 1: look at all newforms, check that there is an elliptic
522
# curve of the same label, and if so compare ap-lists. The
523
# dicts curve_ap and form_ap store these when there is
524
# disagreement: e.g. curve_ap[conductor_label][iso_label] =
525
# aplist.
526
527
print("looping through {} forms".format(len(labels)))
528
for curve_label in labels:
529
# We find the forms again since otherwise the cursor might timeout during the loop.
530
f = get_hmf(curve_label)
531
ec = nfcurves.lucky({'field_label': field_label, 'class_label': curve_label, 'number': 1})
532
if ec:
533
if verbose:
534
print("curve with label %s found in the database" % curve_label)
535
nfound += 1
536
ainvsK = parse_ainvs(K.K(), ec['ainvs'])
537
E = EllipticCurve(ainvsK)
538
if verbose:
539
print("constructed elliptic curve {}".format(E.ainvs()))
540
good_flags = [E.has_good_reduction(P) for P in primes]
541
good_primes = [P for (P, flag) in zip(primes, good_flags) if flag]
542
aplist = [E.reduction(P).trace_of_frobenius() for P in good_primes]
543
if verbose:
544
print("computed ap from elliptic curve")
545
f_aplist = [int(a) for a in f['hecke_eigenvalues']]
546
f_aplist = [ap for ap, flag in zip(f_aplist, good_flags) if flag]
547
if verbose:
548
print("recovered ap from HMF")
549
nap = min(len(aplist), len(f_aplist))
550
if aplist[:nap] == f_aplist[:nap]:
551
nok += 1
552
if verbose:
553
print("Curve {} and newform agree! (checked {} ap)".format(ec['short_label'],nap))
554
else:
555
print("Curve {} does NOT agree with newform".format(ec['short_label']))
556
if verbose:
557
for P,aPf,aPc in zip(good_primes[:nap], f_aplist[:nap], aplist[:nap]):
558
if aPf!=aPc:
559
print("P = {} with norm {}".format(P,P.norm().factor()))
560
print("ap from curve: %s" % aPc)
561
print("ap from form: %s" % aPf)
562
if not ec['conductor_label'] in curve_ap:
563
curve_ap[ec['conductor_label']] = {}
564
form_ap[ec['conductor_label']] = {}
565
curve_ap[ec['conductor_label']][ec['iso_label']] = aplist
566
form_ap[ec['conductor_label']][f['label_suffix']] = f_aplist
567
else:
568
if verbose:
569
print("No curve with label %s found in the database!" % curve_label)
570
missing_curves.append(f['short_label'])
571
nnotfound += 1
572
573
# Report progress:
574
575
n = nfound + nnotfound
576
if nnotfound:
577
print("Out of %s newforms, %s curves were found in the database and %s were not found" % (n, nfound, nnotfound))
578
else:
579
print("Out of %s newforms, all %s had curves with the same label and ap" % (n, nfound))
580
if nfound == nok:
581
print("All curves agree with matching newforms")
582
else:
583
print("%s curves agree with matching newforms, %s do not" % (nok, nfound - nok))
584
if nnotfound:
585
print("%s missing curves" % len(missing_curves))
586
else:
587
return
588
589
# Step 2: for each newform for which there was no curve, call interface to Magma's EllipticCurveSearch()
590
# (unless outfilename is None in which case just dump the missing labels to a file)
591
592
if outfilename:
593
outfile = open(outfilename, mode="w")
594
else:
595
t = open("curves_missing.{}".format(field_label), mode="w")
596
for c in missing_curves:
597
t.write(c)
598
t.write("\n")
599
t.close()
600
return
601
602
def output(L):
603
if outfilename:
604
outfile.write(L)
605
if verbose:
606
sys.stdout.write(L)
607
608
bad_p = []
609
#if field_label=='4.4.1600.1': bad_p = [7**2,13**2,29**2]
610
if field_label=='4.4.2304.1': bad_p = [19**2,29**2]
611
if field_label=='4.4.4225.1': bad_p = [17**2,23**2]
612
if field_label=='4.4.7056.1': bad_p = [29**2,31**2]
613
if field_label=='4.4.7168.1': bad_p = [29**2]
614
if field_label=='4.4.9248.1': bad_p = [23**2]
615
if field_label=='4.4.11025.1': bad_p = [17**2,37**2,43**2]
616
if field_label=='4.4.13824.1': bad_p = [19**2]
617
if field_label=='4.4.12400.1': bad_p = [23**2]
618
if field_label=='4.4.180769.1': bad_p = [23**2]
619
if field_label=='6.6.905177.1': bad_p = [2**3]
620
bad_p = []
621
622
effort0 = effort
623
for nf_label in missing_curves:
624
if verbose:
625
print("Curve %s is missing from the database..." % nf_label)
626
form_label = field_label+"-"+nf_label
627
form = get_hmf(form_label)
628
if not form:
629
print("... form %s not found!" % nf_label)
630
else:
631
if verbose:
632
print("... found form, calling Magma search")
633
634
print("Conductor = %s" % form['level_ideal'].replace(" ",""))
635
N = K.ideal(form['level_label'])
636
neigs = len(f['hecke_eigenvalues'])
637
Plist = [P['ideal'] for P in K.primes_iter(neigs)]
638
goodP = [(i, P) for i, P in enumerate(Plist)
639
if not P.divides(N)
640
and not P.norm() in bad_p
641
and P.residue_class_degree()==1]
642
aplist = [int(f['hecke_eigenvalues'][i]) for i, P in goodP]
643
Plist = [P for i,P in goodP]
644
nap = len(Plist)
645
neigs0 = min(nap,100)
646
effort=effort0
647
if verbose:
648
print("Using %s ap from Hilbert newform and effort %s" % (neigs0,effort))
649
if bad_p:
650
print("( excluding primes with norms {})".format(bad_p))
651
#inds = list(set([randint(0,nap-1) for _ in range(neigs0)]))
652
inds = range(neigs0)
653
Plist0 = [Plist[i] for i in inds]
654
aplist0 = [aplist[i] for i in inds]
655
curves = EllipticCurveSearch(K.K(), Plist0, N, aplist0, effort)
656
# rep = 0
657
allrep=0
658
while not curves and allrep<10:
659
allrep += 1
660
effort*=2
661
# if rep<2:
662
# rep += 1
663
# else:
664
# rep = 1
665
# effort *=2
666
if verbose:
667
print("No curves found by Magma, trying again with effort %s..." % effort)
668
curves = EllipticCurveSearch(K.K(), Plist0, N, aplist0, effort)
669
if verbose:
670
if curves:
671
print("Success!")
672
else:
673
print("Still no success")
674
E = None
675
if curves:
676
E = curves[0]
677
print("%s curves for %s found, first is %s" % (len(curves),nf_label,E.ainvs()))
678
else:
679
print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
680
print("!!! No curves for %s found (using %s ap) !!!" % (nf_label,len(aplist)))
681
print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
682
683
if E is not None:
684
ec = {}
685
ec['field_label'] = field_label
686
ec['conductor_label'] = form['level_label']
687
ec['iso_label'] = form['label_suffix']
688
ec['number'] = int(1)
689
ec['conductor_ideal'] = form['level_ideal'].replace(" ","")
690
ec['conductor_norm'] = form['level_norm']
691
ai = E.ainvs()
692
ec['ainvs'] = ";".join([",".join([str(c) for c in list(a)]) for a in ai])
693
ec['cm'] = '?'
694
ec['base_change'] = []
695
output(make_curves_line(ec) + "\n")
696
if outfilename:
697
outfile.flush()
698
699
def EllipticCurveSearch(K, Plist, N, aplist, effort=1000):
700
r""" Call Magma's own EllipticCurveSearch() function to find and
701
elliptic curve E defined over K with conductor N and ap as in the
702
list.
703
704
INPUT:
705
706
- `K` (number field) -- the base field
707
- `Plist` (list) -- a list of primes of K
708
- `N` (ideal) -- an integral ideal of K
709
- `aplist` (list) -- a list of integers a(P) indexed by the P in Plist not dividing N
710
711
OUTPUT:
712
713
A list (possibly empty) of elliptic curves defined over K with
714
conductor N and traces of Frobenius given by the a(P).
715
"""
716
# Create a new magma instance for each search:
717
mag = Magma()
718
# Define the number field in Magma and the list of primes
719
mag.eval("Qx<x> := PolynomialRing(RationalField());\n")
720
name = K.gen()
721
pol = K.defining_polynomial()
722
mag.eval("Qx<x> := PolynomialRing(RationalField());\n")
723
mag.eval("K<%s> := NumberField(%s);\n" % (name, pol))
724
mag.eval("OK := Integers(K);\n")
725
mag.eval("Plist := [];\n")
726
for P in Plist:
727
Pgens = P.gens_reduced()
728
Pmagma = "(%s)*OK" % Pgens[0]
729
if len(Pgens) > 1:
730
Pmagma += "+(%s)*OK" % Pgens[1]
731
mag.eval("Append(~Plist,%s);\n" % Pmagma)
732
733
mag.eval('SetColumns(0);\n')
734
mag.eval('effort := %s;\n' % effort)
735
736
Ngens = N.gens_reduced()
737
Nmagma = "(%s)*OK" % Ngens[0]
738
if len(Ngens) > 1:
739
Nmagma += "+(%s)*OK" % Ngens[1]
740
mag.eval('N := %s;' % Nmagma)
741
mag.eval('aplist := %s;' % aplist)
742
mag.eval('goodP := [P: P in Plist | Valuation(N,P) eq 0];\n')
743
mag.eval('goodP := [goodP[i]: i in [1..#(aplist)]];\n')
744
try:
745
mag.eval('curves := EllipticCurveSearch(N,effort : Primes:=goodP, Traces:=aplist);\n')
746
mag.eval('curves := [E: E in curves | &and[TraceOfFrobenius(E,goodP[i]) eq aplist[i] : i in [1..#(aplist)]]];\n')
747
mag.eval('ncurves := #curves;')
748
ncurves = mag('ncurves;').sage()
749
except RuntimeError as arg:
750
print("RuntimError in Magma: {}".format(arg))
751
return []
752
if ncurves==0:
753
return []
754
Elist = [0 for i in range(ncurves)]
755
for i in range(ncurves):
756
mag.eval('E := curves[%s];\n' % (i+1))
757
Elist[i] = EllipticCurve(mag('aInvariants(E);\n').sage())
758
mag.quit()
759
return Elist
760
761
762
def magma_output_iter(infilename):
763
r"""
764
Read Magma search output, as an iterator yielding the curves found.
765
766
INPUT:
767
768
- ``infilename`` (string) -- name of file containing Magma output
769
"""
770
infile = open(infilename)
771
772
while True:
773
try:
774
L = next(infile)
775
except StopIteration:
776
raise StopIteration
777
778
if 'Field' in L:
779
field_label = L.split()[1]
780
K = HilbertNumberField(field_label)
781
KK = K.K()
782
783
if 'Isogeny class' in L:
784
class_label = L.split()[2]
785
cond_label, iso_label = class_label.split("-")
786
num = 0
787
788
if 'Conductor' in L:
789
cond_ideal = L.replace("Conductor ","")
790
791
if 'Curve' in L:
792
ai = [KK(a.encode()) for a in L[7:-2].split(",")]
793
num += 1
794
yield field_label, cond_label, iso_label, num, cond_ideal, ai
795
796
infile.close()
797
798
799
def export_magma_output(infilename, outfilename=None, verbose=False):
800
r"""
801
Convert Magma search output to a curves file.
802
803
INPUT:
804
805
- ``infilename`` (string) -- name of file containing Magma output
806
807
- ``outfilename`` (string, default ``None``) -- name of output file
808
809
- ``verbose`` (boolean, default ``False``) -- verbosity flag.
810
"""
811
if outfilename:
812
outfile = open(outfilename, mode="w")
813
814
def output(L):
815
if outfilename:
816
outfile.write(L)
817
if verbose:
818
sys.stdout.write(L)
819
820
K = None
821
822
for field_label, cond_label, iso_label, num, cond_ideal, ai in magma_output_iter(infilename):
823
ec = {}
824
ec['field_label'] = field_label
825
if not K:
826
K = HilbertNumberField(field_label)
827
ec['conductor_label'] = cond_label
828
ec['iso_label'] = iso_label
829
ec['number'] = num
830
N = K.ideal(cond_label)
831
norm = N.norm()
832
hnf = N.pari_hnf()
833
ec['conductor_ideal'] = cond_ideal
834
ec['conductor_ideal'] = "[%i,%s,%s]" % (norm, hnf[1][0], hnf[1][1])
835
ec['conductor_norm'] = norm
836
ec['ainvs'] = [[str(c) for c in list(a)] for a in ai]
837
ec['cm'] = '?'
838
ec['base_change'] = []
839
output(make_curves_line(ec) + "\n")
840
841
842
def rqf_iterator(d1, d2):
843
from lmfdb.WebNumberField import is_fundamental_discriminant
844
for d in srange(d1, d2 + 1):
845
if is_fundamental_discriminant(d):
846
yield d, '2.2.%s.1' % d
847
848