Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
AndrewVSutherland
GitHub Repository: AndrewVSutherland/lmfdb
Path: blob/main/scripts/hmf/check_conjugates.py
1451 views
1
# -*- coding: utf-8 -*-
2
r""" Check presence of conjugates in table of Hilbert modular forms, and adds them if not present.
3
4
Assumes that the set of primes is a subset of the set of ideals.
5
6
Warning ; will not work with non-parallel weights because there is no
7
description of which weight corresponds to which embedding. (ordered by image of
8
generator in R ?)
9
Note that labels contain no information about weight.
10
11
Initial version (University of Warwick 2015) Aurel Page
12
13
"""
14
15
import sys
16
sys.path.append("../..")
17
from copy import copy
18
from lmfdb.WebNumberField import WebNumberField
19
from lmfdb.hilbert_modular_forms.hilbert_field import (findvar, niceideals,
20
conjideals, str2ideal, HilbertNumberField)
21
from sage.all import oo
22
23
from lmfdb.base import getDBConnection
24
print("getting connection")
25
C = getDBConnection()
26
C['admin'].authenticate('lmfdb', 'lmfdb') ## read-only on all databases by default
27
28
# Run the following function to authenticate on the hmfs database
29
# (necessary to write/delete data). This requires having the
30
# necessary password.yaml file.
31
32
def authenticate():
33
print("authenticating on the hmfs database")
34
import yaml
35
import os
36
pw_dict = yaml.load(open(os.path.join(os.getcwd(), os.extsep, os.extsep, os.extsep, "passwords.yaml")))
37
username = pw_dict['data']['username']
38
password = pw_dict['data']['password']
39
C['hmfs'].authenticate(username, password) ## read/write on hmfs
40
41
print("setting hmfs, fields and forms")
42
hmfs = C.hmfs
43
forms = hmfs.forms
44
fields = hmfs.fields
45
hecke = hmfs.hecke # contains eigenvalues
46
nfcurves = C.elliptic_curves.nfcurves
47
48
# Cache of WebNumberField and FieldData objects to avoid re-creation
49
WNFs = {}
50
Fdata = {}
51
52
53
def get_WNF(label, gen_name):
54
if label not in WNFs:
55
WNFs[label] = WebNumberField(label, gen_name=gen_name)
56
return WNFs[label]
57
58
59
def get_Fdata(label):
60
if label not in Fdata:
61
Fdata[label] = fields.find_one({'label': label})
62
return Fdata[label]
63
64
65
def nautos(label):
66
return len(get_WNF(label, 'a').K().automorphisms())
67
68
69
def checkprimes(label):
70
Fdata = get_Fdata(label)
71
gen_name = findvar(Fdata['ideals'])
72
WebF = get_WNF(label, gen_name)
73
F = WebF.K()
74
# ideals = niceideals(F, Fdata['ideals']) # never used
75
primes = niceideals(F, Fdata['primes'])
76
F = HilbertNumberField(label)
77
L = []
78
for prhnf,prideal,prlabel in primes:
79
ideal = F.ideal(prlabel)
80
if ideal != prideal:
81
L.append(prlabel)
82
return L
83
84
def fldlabel2conjdata(label):
85
data = {}
86
Fdata = get_Fdata(label)
87
gen_name = findvar(Fdata['ideals'])
88
WebF = get_WNF(label, gen_name)
89
F = WebF.K()
90
data['F'] = F
91
auts = F.automorphisms()
92
if len(auts) == 1: #no nontrivial automorphism, nothing to do
93
return None
94
auts = [g for g in auts if not g.is_identity()]
95
data['auts'] = auts
96
ideals = niceideals(F, Fdata['ideals'])
97
data['ideals'] = ideals
98
cideals = conjideals(ideals, auts)
99
data['conjideals'] = cideals
100
primes = niceideals(F, Fdata['primes'])
101
data['primes'] = primes
102
primeslabels = [prm[2] for prm in primes]
103
cprimes = conjideals(primes, auts)
104
cprimes = [[primeslabels.index(cprimes[(prm[2],ig)]) for prm in primes] for ig in range(len(auts))]
105
data['conjprimes'] = cprimes
106
return data
107
108
def conjstringideal(F,stridl,g):
109
"""Given a string representing an ideal of F and an automorphism g of F,
110
return the string representing the conjugate ideal.
111
"""
112
N,n,_,gen = str2ideal(F,stridl)
113
return '[' + str(N) + ',' + str(n) + ',' + str(g(gen)) + ']'
114
115
def conjform_label(f, ig, cideals):
116
level_label = cideals[(f['level_label'],ig)]
117
short_label = level_label + '-' + f['label_suffix']
118
return f['field_label'] + '-' + short_label
119
120
def conjform(f, h, g, ig, cideals, cprimes, F):
121
"""
122
f is a 'short' newform from the forms collection;
123
h is its hecke data from the hecke collection
124
g is an automorphism of the base field, ig it index in auts
125
cideals, cprimes are the lists of conjugated ideals and primes
126
"""
127
if 'is_base_change' in f and f['is_base_change'][0:3] == 'yes':
128
print("This form is a base-change.")
129
#return None
130
#if the form is a base-change, but not from Q,
131
#we should still add its conjugate
132
133
# first we copy / conjugate the short newform f. The keys which
134
# need to be changed are 'label', 'short_label', 'level_label',
135
# 'level_ideal':
136
137
# first copy all fields (most of which will not be changed):
138
fg = copy(f)
139
140
# but this must go:
141
del fg['_id']
142
143
# and these must be changed:
144
fg['level_label'] = cideals[(f['level_label'],ig)]
145
fg['short_label'] = fg['level_label'] + '-' + fg['label_suffix']
146
fg['label'] = fg['field_label'] + '-' + fg['short_label']
147
fg['level_ideal'] = conjstringideal(F,f['level_ideal'],g)
148
149
# Next we apply the appropriate permutation to the Hecke and
150
# Atkin-Lehner eigenvalues to update the fields
151
# 'hecke_elgenvalues', 'AL_eigenvalues' of the hecke object, as
152
# well as its label. The remaining key 'hecke_polynomial' is
153
# unchanged.
154
155
hg = {}
156
hg['label'] = fg['label']
157
hg['hecke_polynomial'] = h['hecke_polynomial']
158
159
if 'AL_eigenvalues' in h:
160
hg['AL_eigenvalues'] = [[conjstringideal(F,x[0],g),x[1]] for x in h['AL_eigenvalues']]
161
162
H = h['hecke_eigenvalues']
163
naP = len(H)
164
Hg = [False for i in range(naP)] # just placeholders
165
166
attained = [False for i in range(naP)]
167
for i in range(naP):
168
if cprimes[ig][i] < naP:
169
attained[cprimes[ig][i]] = True
170
171
maxi = 0
172
while maxi < naP:
173
if not attained[maxi]:
174
break
175
maxi += 1
176
177
if maxi < naP:
178
print("truncating list of eigenvalues (missing conjugate prime)")
179
del Hg[maxi:]
180
181
for i in range(naP):
182
if cprimes[ig][i] < maxi:
183
Hg[cprimes[ig][i]] = H[i]
184
185
hg['hecke_eigenvalues'] = Hg
186
187
return fg, hg
188
189
def checkadd_conj(label, min_level_norm=0, max_level_norm=None, fix=False, buildform=False):
190
if fix:
191
buildform = True
192
count = 0
193
countmiss = 0
194
query = {}
195
query['field_label'] = label
196
query['level_norm'] = {'$gte' : int(min_level_norm)}
197
if max_level_norm:
198
query['level_norm']['$lte'] = int(max_level_norm)
199
else:
200
max_level_norm = oo
201
ftoconj = forms.find(query)
202
print("%s forms over %s to examine of level norm between %s and %s."
203
% (ftoconj.count(),label,min_level_norm,max_level_norm))
204
if ftoconj.count() == 0:
205
return None
206
print("Ideals precomputations...")
207
data = fldlabel2conjdata(label)
208
if data is None:
209
print("No nontrival automorphisms!")
210
return
211
print("...done.\n")
212
auts = data['auts']
213
print("Applying %s non-trivial automorphisms..." % len(auts))
214
cideals = data['conjideals']
215
cprimes = data['conjprimes']
216
F = data['F']
217
for f in ftoconj:
218
#print("Testing form %s" % f['label'])
219
h = hecke.find_one({'label': f['label']})
220
for g in auts:
221
ig = auts.index(g)
222
fg_label = conjform_label(f, ig, cideals)
223
fgdb = forms.find_one({'label':fg_label})
224
if fgdb is None:
225
print("Testing form %s: conjugate %s not present" % (f['label'], fg_label))
226
countmiss += 1
227
if buildform:
228
fg, hg = conjform(f, h, g, ig, cideals, cprimes, F)
229
if fix:
230
if fg is not None: # else: is a lift (self-conjugate), should have been detected
231
print("adding it : " + fg['label'])
232
forms.insert_one(fg)
233
hecke.insert_one(fg)
234
count += 1
235
print("\nMissing "+str(countmiss)+" conjugate forms (possibly counted multiple times if several nontrivial automorphisms).")
236
print("Added "+str(count)+" new conjugate forms.")
237
return None
238
239
def forms_equal(f,g):
240
fH = f['hecke_eigenvalues']
241
gH = g['hecke_eigenvalues']
242
for i in range(min(len(fH),len(gH))):
243
if fH[i] != gH[i]:
244
return False
245
return True
246
247
def check_multiplicity_one(label):
248
F = HilbertNumberField(label)
249
count = 0
250
for N in F.ideals_iter():
251
Lf = forms.find({'field_label':label, 'level_label':N['label']})
252
Lf = [f for f in Lf]
253
n = len(Lf)
254
for i in range(n):
255
for j in range(i+1,n):
256
if forms_equal(Lf[i],Lf[j]):
257
count += 1
258
print("duplicates: "+Lf[i]['label']+" and "+Lf[j]['label'])
259
print("Found "+str(count)+" duplicate forms.")
260
261
def fix_data_fields(min_level_norm=0, max_level_norm=None, fix=False):
262
r""" One-off utility to:
263
1. add degree and disc fields for each Hilbert newform
264
2. Change CM and base-change from "yes?" to "yes"
265
"""
266
count = 0
267
query = {}
268
query['level_norm'] = {'$gte' : int(min_level_norm)}
269
if max_level_norm:
270
query['level_norm']['$lte'] = int(max_level_norm)
271
else:
272
max_level_norm = oo
273
forms_to_fix = forms.find(query)
274
print("%s forms to examine of level norm between %s and %s."
275
% (forms_to_fix.count(),min_level_norm,max_level_norm))
276
if forms_to_fix.count() == 0:
277
return None
278
for f in forms_to_fix:
279
count = count+1
280
if count%100==0: print("%s: %s" % (count, f['label']))
281
fix_data = {}
282
deg, r, disc, n = f['field_label'].split('.')
283
fix_data['deg'] = int(deg)
284
fix_data['disc'] = int(disc)
285
if f['is_CM'] == 'yes?':
286
fix_data['is_CM'] = 'yes'
287
if f['is_base_change'] == 'yes?':
288
fix_data['is_base_change'] = 'yes'
289
#print("using fixed data %s for form %s" % (fix_data,f['label']))
290
if fix:
291
forms.update({'label': f['label']}, {"$set": fix_data}, upsert=True)
292
293
def fix_one_label(lab, reverse=False):
294
r""" If lab has length 1 do nothing. If it has length 2 increment the
295
first letter (a to b to c to ... to z). The lengths must be at
296
most 2 and if =2 it must start with 'a'..'y' (these are all which
297
were required). If reverse==True the inverse operation is carried
298
out (z to y to ... to c to b to a).
299
"""
300
if len(lab)!=2:
301
return lab
302
else:
303
if reverse:
304
return chr(ord(lab[0])-int(1))+lab[1]
305
else:
306
return chr(ord(lab[0])+int(1))+lab[1]
307
308
def fix_labels(field_label, min_level_norm=0, max_level_norm=None, fix_forms=False, fix_curves=False, reverse=False):
309
r""" One-off utility to correct labels 'aa'->'ba'->'ca', ..., 'az'->'bz'->'cz'
310
"""
311
from sage.databases.cremona import class_to_int
312
count = 0
313
query = {}
314
query['field_label'] = field_label
315
query['level_norm'] = {'$gte' : int(min_level_norm)}
316
if max_level_norm:
317
query['level_norm']['$lte'] = int(max_level_norm)
318
else:
319
max_level_norm = oo
320
forms_to_fix = forms.find(query)
321
print("%s forms to examine of level norm between %s and %s."
322
% (forms_to_fix.count(),min_level_norm,max_level_norm))
323
if forms_to_fix.count() == 0:
324
return None
325
for f in forms_to_fix:
326
count = count+1
327
if count%100==0: print("%s: %s" % (count, f['label']))
328
fix_data = {}
329
lab = f['label_suffix']
330
if len(lab)==1:
331
continue
332
if f['label'][-2:] != lab:
333
print("Incorrect label_suffix %s in form %s" % (lab,f['label']))
334
return
335
oldlab = lab
336
lab = fix_one_label(lab, reverse=reverse)
337
fix_data['label_suffix'] = lab
338
fix_data['label'] = f['label'].replace(oldlab,lab)
339
fix_data['short_label'] = f['short_label'].replace(oldlab,lab)
340
fix_data['label_nsuffix'] = class_to_int(lab)
341
print("using fixed data %s for form %s" % (fix_data,f['label']))
342
if fix_forms:
343
forms.update({'label': f['label']}, {"$set": fix_data}, upsert=True)
344
345
# find associated elliptic curve and fix that too (where appropriate)
346
if f['deg']==2 and f['dimension']==1:
347
for e in nfcurves.find({'class_label':f['label']}):
348
fix_data = {}
349
fix_data['iso_label'] = lab
350
fix_data['label'] = e['label'].replace(oldlab,lab)
351
fix_data['short_label'] = e['short_label'].replace(oldlab,lab)
352
fix_data['class_label'] = e['class_label'].replace(oldlab,lab)
353
fix_data['short_class_label'] = e['short_class_label'].replace(oldlab,lab)
354
print("using fixed data %s for curve %s" % (fix_data,e['label']))
355
if fix_curves:
356
res = nfcurves.update_one({'_id': e['_id']}, {"$set": fix_data}, upsert=True)
357
assert res.matched_count==1
358
else:
359
print("No elliptic curve to fix")
360
361
def fix_curve_labels(field_label, min_cond_norm=0, max_cond_norm=None, fix_curves=False, reverse=False):
362
r""" One-off utility to correct labels 'aa'->'ba'->'ca', ..., 'az'->'bz'->'cz'
363
"""
364
count = 0
365
query = {}
366
query['field_label'] = field_label
367
query['conductor_norm'] = {'$gte' : int(min_cond_norm)}
368
if max_cond_norm:
369
query['conductor_norm']['$lte'] = int(max_cond_norm)
370
else:
371
max_cond_norm = oo
372
curves_to_fix = nfcurves.find(query)
373
print("%s curves to examine of conductor norm between %s and %s."
374
% (curves_to_fix.count(),min_cond_norm,max_cond_norm))
375
if curves_to_fix.count() == 0:
376
return None
377
for c in curves_to_fix:
378
count = count+1
379
if count%100==0: print("%s: %s" % (count, c['label']))
380
lab = c['iso_label']
381
if len(lab)==1:
382
continue
383
if c['iso_label'][-2:] != lab:
384
print("Incorrect iso_label %s in curve %s" % (lab,c['label']))
385
return
386
oldlab = lab
387
lab = fix_one_label(lab, reverse=reverse)
388
fix_data = {}
389
fix_data['iso_label'] = lab
390
fix_data['label'] = c['label'].replace(oldlab,lab)
391
fix_data['short_label'] = c['short_label'].replace(oldlab,lab)
392
fix_data['class_label'] = c['class_label'].replace(oldlab,lab)
393
fix_data['short_class_label'] = c['short_class_label'].replace(oldlab,lab)
394
print("using fixed data %s for curve %s" % (fix_data,c['label']))
395
if fix_curves:
396
res = nfcurves.update_one({'_id': c['_id']}, {"$set": fix_data}, upsert=True)
397
assert res.matched_count==1
398
399
def fix_one_curve_label(field_label, cond_label, old_iso_label, new_iso_label, fix_curves=False):
400
r""" One-off utility to correct class label
401
"""
402
query = {}
403
query['field_label'] = field_label
404
query['conductor_label'] = cond_label
405
query['iso_label'] = old_iso_label
406
curves_to_fix = nfcurves.find(query)
407
print("%s curves to fix" % curves_to_fix.count())
408
if curves_to_fix.count() == 0:
409
return None
410
for c in curves_to_fix:
411
oldlab = old_iso_label
412
lab = new_iso_label
413
fix_data = {}
414
fix_data['iso_label'] = lab
415
fix_data['label'] = c['label'].replace(oldlab,lab)
416
fix_data['short_label'] = c['short_label'].replace(oldlab,lab)
417
fix_data['class_label'] = c['class_label'].replace(oldlab,lab)
418
fix_data['short_class_label'] = c['short_class_label'].replace(oldlab,lab)
419
print("using fixed data %s for curve %s" % (fix_data,c['label']))
420
if fix_curves:
421
res = nfcurves.update_one({'_id': c['_id']}, {"$set": fix_data}, upsert=True)
422
assert res.matched_count==1
423
424
def set_one_curve_label(id, new_iso_label, fix_curves=False):
425
r""" One-off utility to correct class label
426
"""
427
query = {}
428
query['_id'] = id
429
curves_to_fix = nfcurves.find(query)
430
print("%s curves to fix" % curves_to_fix.count())
431
if curves_to_fix.count() == 0:
432
return None
433
for c in curves_to_fix:
434
oldlab = c['iso_label']
435
lab = new_iso_label
436
fix_data = {}
437
fix_data['iso_label'] = lab
438
fix_data['label'] = c['label'].replace(oldlab,lab)
439
fix_data['short_label'] = c['short_label'].replace(oldlab,lab)
440
fix_data['class_label'] = c['class_label'].replace(oldlab,lab)
441
fix_data['short_class_label'] = c['short_class_label'].replace(oldlab,lab)
442
print("using fixed data %s for curve %s" % (fix_data,c['label']))
443
if fix_curves:
444
res = nfcurves.update_one({'_id': c['_id']}, {"$set": fix_data}, upsert=True)
445
assert res.matched_count==1
446
447
def add_numeric_label_suffixes(min_level_norm=0, max_level_norm=None, fix=False):
448
r""" One-off utility to add a numeric conversion of the letter-coded
449
label suffixes 'a'->0', 'z'->25, 'ba'->26, etc. for sorting
450
purposes.
451
"""
452
from sage.databases.cremona import class_to_int
453
count = 0
454
query = {}
455
query['level_norm'] = {'$gte' : int(min_level_norm)}
456
if max_level_norm:
457
query['level_norm']['$lte'] = int(max_level_norm)
458
else:
459
max_level_norm = oo
460
forms_to_fix = forms.find(query)
461
print("%s forms to examine of level norm between %s and %s."
462
% (forms_to_fix.count(),min_level_norm,max_level_norm))
463
for f in forms_to_fix:
464
count = count+1
465
if count%100==0: print("%s: %s" % (count, f['label']))
466
fix_data = {}
467
lab = f['label_suffix']
468
fix_data['label_nsuffix'] = class_to_int(lab)
469
#print("using fixed data %s for form %s" % (fix_data,f['label']))
470
if fix:
471
forms.update({'label': f['label']}, {"$set": fix_data}, upsert=True)
472
473
474
475