Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
AndrewVSutherland
GitHub Repository: AndrewVSutherland/lmfdb
Path: blob/main/scripts/ecnf/bmf_check.py
1128 views
1
# -*- coding: utf-8 -*-
2
r""" Functions to check consistency of data between elliptic curves and
3
Bianchi Modular Forms databases: """
4
5
6
# 2020-04-15: first version by JEC
7
8
from sage.all import EllipticCurve, polygen, QQ, NumberField
9
from lmfdb import db
10
from lmfdb.nfutils.psort import primes_iter
11
from lmfdb.ecnf.WebEllipticCurve import parse_ainvs
12
13
print("setting nfcurves")
14
nfcurves = db.ec_nfcurves
15
16
print("setting bmf forms")
17
forms = db.bmf_forms
18
19
abs_discs = [4,8,3,7,11,18,43,67,163,23,31,47, 59, 71, 79, 83, 20, 24, 15, 35, 52,
20
40, 51, 88, 84, 91, 56, 55, 68, 39, 87,95]
21
fields = ['2.0.{}.1'.format(d) for d in abs_discs]
22
23
x = polygen(QQ)
24
def poly(d):
25
return x**2+(d//4) if d%4==0 else x**2-x+(d+1)//4
26
27
polys = dict([(field,poly(d)) for field,d in zip(fields, abs_discs)])
28
29
def gen_name(d):
30
return 'i' if d==4 else 't' if d==8 else 'w' if d==3 else 'a'
31
32
gen_names = dict([(field,gen_name(d)) for field,d in zip(fields, abs_discs)])
33
34
false_curves = {'2.0.4.1': ['34225.7-a', '34225.7-b', '34225.3-a', '34225.3-b'],
35
36
'2.0.8.1': ['5625.1-b', '5625.3-b', '6561.5-a', '6561.5-d',
37
'21609.1-b', '21609.1-c', '21609.3-b', '21609.3-c'],
38
39
'2.0.3.1': ['67081.3-a', '67081.3-b', '67081.7-a', '67081.7-b', '61009.1-a',
40
'61009.1-b', '61009.9-a', '61009.9-b', '123201.1-b', '123201.1-c',
41
'123201.3-b', '123201.3-c', '5625.1-a', '6561.1-b', '30625.1-a',
42
'30625.3-a', '50625.1-c', '50625.1-d', '65536.1-b', '65536.1-e', '104976.1-a'],
43
44
'2.0.7.1': ['10000.1-b', '10000.5-b', '30625.1-c', '30625.1-e', '30625.1-d',
45
'40000.1-b', '40000.7-b'],
46
47
'2.0.11.1': [] }
48
49
for fld in fields:
50
if fld not in false_curves:
51
false_curves[fld] = []
52
53
def field_from_label(lab):
54
r"""
55
Returns a number field from its LMFDB label. IQF only.
56
57
INPUT:
58
59
- ``s`` (string)-- an LMFDB field label of the form 2.0.d.1
60
61
OUTPUT:
62
63
A number field, Q(sqrt(-d)) with standard defining polynomial
64
"""
65
K = NumberField(polys[lab], gen_names[lab])
66
print("Created field from label {}: {}".format(lab,K))
67
return K
68
69
# check_curves() is adapted from the hmf_check_find function
70
# find_curves(). For IQ fields it does no curve searching but does
71
# check whether there is a curve matching each Bianchi newform in the
72
# database. Here 'matching' means same label, conductor=label and ap
73
# agree. This must allow for the valid non-existence of curves for
74
# some newforms.
75
76
def check_curves(field_label='2.0.4.1', min_norm=0, max_norm=None, label=None, check_ap = False, verbose=False):
77
r"""Go through all Bianchi Modular Forms with the given field label,
78
assumed imaginary quadratic (i.e. '2.0.d.1' with d in
79
{4,8,3,7,11}), check whether an elliptic curve exists with the
80
same label. If so, and if check_ap is True, check that the a_P agree.
81
82
"""
83
if field_label not in fields:
84
print("No BMF data available for field {}".format(field_label))
85
return
86
else:
87
K = field_from_label(field_label)
88
print("Checking forms over {}, norms from {} to {}".format(field_label,min_norm,max_norm))
89
query = {}
90
query['field_label'] = field_label
91
query['dimension'] = 1 # only look at rational newforms
92
if label:
93
print("looking for {} only".format(label))
94
query['short_label'] = label # e.g. '91.1-a'
95
else:
96
query['level_norm'] = {'$gte': int(min_norm)}
97
if max_norm:
98
query['level_norm']['$lte'] = int(max_norm)
99
cursor = forms.search(query, sort=['level_norm'])
100
labels = [f['short_label'] for f in cursor]
101
nforms = len(labels)
102
print("found {} newforms".format(nforms))
103
labels = [lab for lab in labels if lab not in false_curves[field_label]]
104
nforms = len(labels)
105
print(" of which {} should have associated curves (not false ones)".format(nforms))
106
nfound = 0
107
nnotfound = 0
108
nok = 0
109
missing_curves = []
110
mismatches = []
111
112
primes = list(primes_iter(K,maxnorm=1000)) if check_ap else []
113
curve_ap = {} # curve_ap[conductor_label] will be a dict iso -> ap
114
form_ap = {} # form_ap[conductor_label] will be a dict iso -> ap
115
116
# Now look at all newforms, check that there is an elliptic
117
# curve of the same label, and if so compare ap-lists. The
118
# dicts curve_ap and form_ap store these when there is
119
# disagreement: e.g. curve_ap[conductor_label][iso_label] =
120
# aplist.
121
122
print("checking {} newforms".format(nforms))
123
n = 0
124
for curve_label in labels:
125
n += 1
126
if n%100==0:
127
perc = 100.0*n/nforms
128
print("{} forms checked ({}%)".format(n,perc))
129
# We find the forms again since otherwise the cursor might timeout during the loop.
130
label = "-".join([field_label,curve_label])
131
if verbose:
132
print("newform and isogeny class label {}".format(label))
133
f = forms.lucky({'label':label})
134
if f:
135
if verbose:
136
print("found newform with label {}".format(label))
137
else:
138
print("no newform in database has label {}!".format(label))
139
continue
140
ec = nfcurves.lucky({'class_label': label, 'number': 1})
141
if ec:
142
if verbose:
143
print("curve with label %s found in the database" % curve_label)
144
nfound += 1
145
if not check_ap:
146
continue
147
ainvsK = parse_ainvs(K, ec['ainvs'])
148
if verbose:
149
print("E = {}".format(ainvsK))
150
E = EllipticCurve(ainvsK)
151
if verbose:
152
print("constructed elliptic curve {}".format(E.ainvs()))
153
good_flags = [E.has_good_reduction(P) for P in primes]
154
good_primes = [P for (P, flag) in zip(primes, good_flags) if flag]
155
if verbose:
156
print("{} good primes".format(len(good_primes)))
157
f_aplist = f['hecke_eigs']
158
f_aplist = [ap for ap, flag in zip(f_aplist, good_flags) if flag]
159
nap = len(f_aplist)
160
if verbose:
161
print("recovered {} ap from BMF".format(nap))
162
aplist = [E.reduction(P).trace_of_frobenius() for P in good_primes[:nap]]
163
if verbose:
164
print("computed {} ap from elliptic curve".format(nap))
165
if aplist[:nap] == f_aplist[:nap]:
166
nok += 1
167
if verbose:
168
print("Curve {} and newform agree! (checked {} ap)".format(ec['short_label'],nap))
169
else:
170
print("Curve {} does NOT agree with newform".format(ec['short_label']))
171
mismatches.append(label)
172
if verbose:
173
for P,aPf,aPc in zip(good_primes[:nap], f_aplist[:nap], aplist[:nap]):
174
if aPf!=aPc:
175
print("P = {} with norm {}".format(P,P.norm().factor()))
176
print("ap from curve: %s" % aPc)
177
print("ap from form: %s" % aPf)
178
if not ec['conductor_label'] in curve_ap:
179
curve_ap[ec['conductor_label']] = {}
180
form_ap[ec['conductor_label']] = {}
181
curve_ap[ec['conductor_label']][ec['iso_label']] = aplist
182
form_ap[ec['conductor_label']][f['label_suffix']] = f_aplist
183
else:
184
if verbose:
185
print("No curve with label %s found in the database!" % curve_label)
186
missing_curves.append(f['short_label'])
187
nnotfound += 1
188
189
# Report progress:
190
191
n = nfound + nnotfound
192
if nnotfound:
193
print("Out of %s newforms, %s curves were found in the database and %s were not found" % (n, nfound, nnotfound))
194
else:
195
print("Out of %s newforms, all %s had curves with the same label and ap" % (n, nfound))
196
if nfound == nok:
197
print("All curves agree with matching newforms")
198
else:
199
print("%s curves agree with matching newforms, %s do not" % (nok, nfound - nok))
200
if nnotfound:
201
print("%s missing curves" % len(missing_curves))
202
else:
203
pass
204
if mismatches:
205
print("{} form-curve pairs had inconsistent ap:".format(len(mismatches)))
206
print(mismatches)
207
208
209
210