Path: blob/main/scripts/hmf/check_conjugates.py
1451 views
# -*- coding: utf-8 -*-1r""" Check presence of conjugates in table of Hilbert modular forms, and adds them if not present.23Assumes that the set of primes is a subset of the set of ideals.45Warning ; will not work with non-parallel weights because there is no6description of which weight corresponds to which embedding. (ordered by image of7generator in R ?)8Note that labels contain no information about weight.910Initial version (University of Warwick 2015) Aurel Page1112"""1314import sys15sys.path.append("../..")16from copy import copy17from lmfdb.WebNumberField import WebNumberField18from lmfdb.hilbert_modular_forms.hilbert_field import (findvar, niceideals,19conjideals, str2ideal, HilbertNumberField)20from sage.all import oo2122from lmfdb.base import getDBConnection23print("getting connection")24C = getDBConnection()25C['admin'].authenticate('lmfdb', 'lmfdb') ## read-only on all databases by default2627# Run the following function to authenticate on the hmfs database28# (necessary to write/delete data). This requires having the29# necessary password.yaml file.3031def authenticate():32print("authenticating on the hmfs database")33import yaml34import os35pw_dict = yaml.load(open(os.path.join(os.getcwd(), os.extsep, os.extsep, os.extsep, "passwords.yaml")))36username = pw_dict['data']['username']37password = pw_dict['data']['password']38C['hmfs'].authenticate(username, password) ## read/write on hmfs3940print("setting hmfs, fields and forms")41hmfs = C.hmfs42forms = hmfs.forms43fields = hmfs.fields44hecke = hmfs.hecke # contains eigenvalues45nfcurves = C.elliptic_curves.nfcurves4647# Cache of WebNumberField and FieldData objects to avoid re-creation48WNFs = {}49Fdata = {}505152def get_WNF(label, gen_name):53if label not in WNFs:54WNFs[label] = WebNumberField(label, gen_name=gen_name)55return WNFs[label]565758def get_Fdata(label):59if label not in Fdata:60Fdata[label] = fields.find_one({'label': label})61return Fdata[label]626364def nautos(label):65return len(get_WNF(label, 'a').K().automorphisms())666768def checkprimes(label):69Fdata = get_Fdata(label)70gen_name = findvar(Fdata['ideals'])71WebF = get_WNF(label, gen_name)72F = WebF.K()73# ideals = niceideals(F, Fdata['ideals']) # never used74primes = niceideals(F, Fdata['primes'])75F = HilbertNumberField(label)76L = []77for prhnf,prideal,prlabel in primes:78ideal = F.ideal(prlabel)79if ideal != prideal:80L.append(prlabel)81return L8283def fldlabel2conjdata(label):84data = {}85Fdata = get_Fdata(label)86gen_name = findvar(Fdata['ideals'])87WebF = get_WNF(label, gen_name)88F = WebF.K()89data['F'] = F90auts = F.automorphisms()91if len(auts) == 1: #no nontrivial automorphism, nothing to do92return None93auts = [g for g in auts if not g.is_identity()]94data['auts'] = auts95ideals = niceideals(F, Fdata['ideals'])96data['ideals'] = ideals97cideals = conjideals(ideals, auts)98data['conjideals'] = cideals99primes = niceideals(F, Fdata['primes'])100data['primes'] = primes101primeslabels = [prm[2] for prm in primes]102cprimes = conjideals(primes, auts)103cprimes = [[primeslabels.index(cprimes[(prm[2],ig)]) for prm in primes] for ig in range(len(auts))]104data['conjprimes'] = cprimes105return data106107def conjstringideal(F,stridl,g):108"""Given a string representing an ideal of F and an automorphism g of F,109return the string representing the conjugate ideal.110"""111N,n,_,gen = str2ideal(F,stridl)112return '[' + str(N) + ',' + str(n) + ',' + str(g(gen)) + ']'113114def conjform_label(f, ig, cideals):115level_label = cideals[(f['level_label'],ig)]116short_label = level_label + '-' + f['label_suffix']117return f['field_label'] + '-' + short_label118119def conjform(f, h, g, ig, cideals, cprimes, F):120"""121f is a 'short' newform from the forms collection;122h is its hecke data from the hecke collection123g is an automorphism of the base field, ig it index in auts124cideals, cprimes are the lists of conjugated ideals and primes125"""126if 'is_base_change' in f and f['is_base_change'][0:3] == 'yes':127print("This form is a base-change.")128#return None129#if the form is a base-change, but not from Q,130#we should still add its conjugate131132# first we copy / conjugate the short newform f. The keys which133# need to be changed are 'label', 'short_label', 'level_label',134# 'level_ideal':135136# first copy all fields (most of which will not be changed):137fg = copy(f)138139# but this must go:140del fg['_id']141142# and these must be changed:143fg['level_label'] = cideals[(f['level_label'],ig)]144fg['short_label'] = fg['level_label'] + '-' + fg['label_suffix']145fg['label'] = fg['field_label'] + '-' + fg['short_label']146fg['level_ideal'] = conjstringideal(F,f['level_ideal'],g)147148# Next we apply the appropriate permutation to the Hecke and149# Atkin-Lehner eigenvalues to update the fields150# 'hecke_elgenvalues', 'AL_eigenvalues' of the hecke object, as151# well as its label. The remaining key 'hecke_polynomial' is152# unchanged.153154hg = {}155hg['label'] = fg['label']156hg['hecke_polynomial'] = h['hecke_polynomial']157158if 'AL_eigenvalues' in h:159hg['AL_eigenvalues'] = [[conjstringideal(F,x[0],g),x[1]] for x in h['AL_eigenvalues']]160161H = h['hecke_eigenvalues']162naP = len(H)163Hg = [False for i in range(naP)] # just placeholders164165attained = [False for i in range(naP)]166for i in range(naP):167if cprimes[ig][i] < naP:168attained[cprimes[ig][i]] = True169170maxi = 0171while maxi < naP:172if not attained[maxi]:173break174maxi += 1175176if maxi < naP:177print("truncating list of eigenvalues (missing conjugate prime)")178del Hg[maxi:]179180for i in range(naP):181if cprimes[ig][i] < maxi:182Hg[cprimes[ig][i]] = H[i]183184hg['hecke_eigenvalues'] = Hg185186return fg, hg187188def checkadd_conj(label, min_level_norm=0, max_level_norm=None, fix=False, buildform=False):189if fix:190buildform = True191count = 0192countmiss = 0193query = {}194query['field_label'] = label195query['level_norm'] = {'$gte' : int(min_level_norm)}196if max_level_norm:197query['level_norm']['$lte'] = int(max_level_norm)198else:199max_level_norm = oo200ftoconj = forms.find(query)201print("%s forms over %s to examine of level norm between %s and %s."202% (ftoconj.count(),label,min_level_norm,max_level_norm))203if ftoconj.count() == 0:204return None205print("Ideals precomputations...")206data = fldlabel2conjdata(label)207if data is None:208print("No nontrival automorphisms!")209return210print("...done.\n")211auts = data['auts']212print("Applying %s non-trivial automorphisms..." % len(auts))213cideals = data['conjideals']214cprimes = data['conjprimes']215F = data['F']216for f in ftoconj:217#print("Testing form %s" % f['label'])218h = hecke.find_one({'label': f['label']})219for g in auts:220ig = auts.index(g)221fg_label = conjform_label(f, ig, cideals)222fgdb = forms.find_one({'label':fg_label})223if fgdb is None:224print("Testing form %s: conjugate %s not present" % (f['label'], fg_label))225countmiss += 1226if buildform:227fg, hg = conjform(f, h, g, ig, cideals, cprimes, F)228if fix:229if fg is not None: # else: is a lift (self-conjugate), should have been detected230print("adding it : " + fg['label'])231forms.insert_one(fg)232hecke.insert_one(fg)233count += 1234print("\nMissing "+str(countmiss)+" conjugate forms (possibly counted multiple times if several nontrivial automorphisms).")235print("Added "+str(count)+" new conjugate forms.")236return None237238def forms_equal(f,g):239fH = f['hecke_eigenvalues']240gH = g['hecke_eigenvalues']241for i in range(min(len(fH),len(gH))):242if fH[i] != gH[i]:243return False244return True245246def check_multiplicity_one(label):247F = HilbertNumberField(label)248count = 0249for N in F.ideals_iter():250Lf = forms.find({'field_label':label, 'level_label':N['label']})251Lf = [f for f in Lf]252n = len(Lf)253for i in range(n):254for j in range(i+1,n):255if forms_equal(Lf[i],Lf[j]):256count += 1257print("duplicates: "+Lf[i]['label']+" and "+Lf[j]['label'])258print("Found "+str(count)+" duplicate forms.")259260def fix_data_fields(min_level_norm=0, max_level_norm=None, fix=False):261r""" One-off utility to:2621. add degree and disc fields for each Hilbert newform2632. Change CM and base-change from "yes?" to "yes"264"""265count = 0266query = {}267query['level_norm'] = {'$gte' : int(min_level_norm)}268if max_level_norm:269query['level_norm']['$lte'] = int(max_level_norm)270else:271max_level_norm = oo272forms_to_fix = forms.find(query)273print("%s forms to examine of level norm between %s and %s."274% (forms_to_fix.count(),min_level_norm,max_level_norm))275if forms_to_fix.count() == 0:276return None277for f in forms_to_fix:278count = count+1279if count%100==0: print("%s: %s" % (count, f['label']))280fix_data = {}281deg, r, disc, n = f['field_label'].split('.')282fix_data['deg'] = int(deg)283fix_data['disc'] = int(disc)284if f['is_CM'] == 'yes?':285fix_data['is_CM'] = 'yes'286if f['is_base_change'] == 'yes?':287fix_data['is_base_change'] = 'yes'288#print("using fixed data %s for form %s" % (fix_data,f['label']))289if fix:290forms.update({'label': f['label']}, {"$set": fix_data}, upsert=True)291292def fix_one_label(lab, reverse=False):293r""" If lab has length 1 do nothing. If it has length 2 increment the294first letter (a to b to c to ... to z). The lengths must be at295most 2 and if =2 it must start with 'a'..'y' (these are all which296were required). If reverse==True the inverse operation is carried297out (z to y to ... to c to b to a).298"""299if len(lab)!=2:300return lab301else:302if reverse:303return chr(ord(lab[0])-int(1))+lab[1]304else:305return chr(ord(lab[0])+int(1))+lab[1]306307def fix_labels(field_label, min_level_norm=0, max_level_norm=None, fix_forms=False, fix_curves=False, reverse=False):308r""" One-off utility to correct labels 'aa'->'ba'->'ca', ..., 'az'->'bz'->'cz'309"""310from sage.databases.cremona import class_to_int311count = 0312query = {}313query['field_label'] = field_label314query['level_norm'] = {'$gte' : int(min_level_norm)}315if max_level_norm:316query['level_norm']['$lte'] = int(max_level_norm)317else:318max_level_norm = oo319forms_to_fix = forms.find(query)320print("%s forms to examine of level norm between %s and %s."321% (forms_to_fix.count(),min_level_norm,max_level_norm))322if forms_to_fix.count() == 0:323return None324for f in forms_to_fix:325count = count+1326if count%100==0: print("%s: %s" % (count, f['label']))327fix_data = {}328lab = f['label_suffix']329if len(lab)==1:330continue331if f['label'][-2:] != lab:332print("Incorrect label_suffix %s in form %s" % (lab,f['label']))333return334oldlab = lab335lab = fix_one_label(lab, reverse=reverse)336fix_data['label_suffix'] = lab337fix_data['label'] = f['label'].replace(oldlab,lab)338fix_data['short_label'] = f['short_label'].replace(oldlab,lab)339fix_data['label_nsuffix'] = class_to_int(lab)340print("using fixed data %s for form %s" % (fix_data,f['label']))341if fix_forms:342forms.update({'label': f['label']}, {"$set": fix_data}, upsert=True)343344# find associated elliptic curve and fix that too (where appropriate)345if f['deg']==2 and f['dimension']==1:346for e in nfcurves.find({'class_label':f['label']}):347fix_data = {}348fix_data['iso_label'] = lab349fix_data['label'] = e['label'].replace(oldlab,lab)350fix_data['short_label'] = e['short_label'].replace(oldlab,lab)351fix_data['class_label'] = e['class_label'].replace(oldlab,lab)352fix_data['short_class_label'] = e['short_class_label'].replace(oldlab,lab)353print("using fixed data %s for curve %s" % (fix_data,e['label']))354if fix_curves:355res = nfcurves.update_one({'_id': e['_id']}, {"$set": fix_data}, upsert=True)356assert res.matched_count==1357else:358print("No elliptic curve to fix")359360def fix_curve_labels(field_label, min_cond_norm=0, max_cond_norm=None, fix_curves=False, reverse=False):361r""" One-off utility to correct labels 'aa'->'ba'->'ca', ..., 'az'->'bz'->'cz'362"""363count = 0364query = {}365query['field_label'] = field_label366query['conductor_norm'] = {'$gte' : int(min_cond_norm)}367if max_cond_norm:368query['conductor_norm']['$lte'] = int(max_cond_norm)369else:370max_cond_norm = oo371curves_to_fix = nfcurves.find(query)372print("%s curves to examine of conductor norm between %s and %s."373% (curves_to_fix.count(),min_cond_norm,max_cond_norm))374if curves_to_fix.count() == 0:375return None376for c in curves_to_fix:377count = count+1378if count%100==0: print("%s: %s" % (count, c['label']))379lab = c['iso_label']380if len(lab)==1:381continue382if c['iso_label'][-2:] != lab:383print("Incorrect iso_label %s in curve %s" % (lab,c['label']))384return385oldlab = lab386lab = fix_one_label(lab, reverse=reverse)387fix_data = {}388fix_data['iso_label'] = lab389fix_data['label'] = c['label'].replace(oldlab,lab)390fix_data['short_label'] = c['short_label'].replace(oldlab,lab)391fix_data['class_label'] = c['class_label'].replace(oldlab,lab)392fix_data['short_class_label'] = c['short_class_label'].replace(oldlab,lab)393print("using fixed data %s for curve %s" % (fix_data,c['label']))394if fix_curves:395res = nfcurves.update_one({'_id': c['_id']}, {"$set": fix_data}, upsert=True)396assert res.matched_count==1397398def fix_one_curve_label(field_label, cond_label, old_iso_label, new_iso_label, fix_curves=False):399r""" One-off utility to correct class label400"""401query = {}402query['field_label'] = field_label403query['conductor_label'] = cond_label404query['iso_label'] = old_iso_label405curves_to_fix = nfcurves.find(query)406print("%s curves to fix" % curves_to_fix.count())407if curves_to_fix.count() == 0:408return None409for c in curves_to_fix:410oldlab = old_iso_label411lab = new_iso_label412fix_data = {}413fix_data['iso_label'] = lab414fix_data['label'] = c['label'].replace(oldlab,lab)415fix_data['short_label'] = c['short_label'].replace(oldlab,lab)416fix_data['class_label'] = c['class_label'].replace(oldlab,lab)417fix_data['short_class_label'] = c['short_class_label'].replace(oldlab,lab)418print("using fixed data %s for curve %s" % (fix_data,c['label']))419if fix_curves:420res = nfcurves.update_one({'_id': c['_id']}, {"$set": fix_data}, upsert=True)421assert res.matched_count==1422423def set_one_curve_label(id, new_iso_label, fix_curves=False):424r""" One-off utility to correct class label425"""426query = {}427query['_id'] = id428curves_to_fix = nfcurves.find(query)429print("%s curves to fix" % curves_to_fix.count())430if curves_to_fix.count() == 0:431return None432for c in curves_to_fix:433oldlab = c['iso_label']434lab = new_iso_label435fix_data = {}436fix_data['iso_label'] = lab437fix_data['label'] = c['label'].replace(oldlab,lab)438fix_data['short_label'] = c['short_label'].replace(oldlab,lab)439fix_data['class_label'] = c['class_label'].replace(oldlab,lab)440fix_data['short_class_label'] = c['short_class_label'].replace(oldlab,lab)441print("using fixed data %s for curve %s" % (fix_data,c['label']))442if fix_curves:443res = nfcurves.update_one({'_id': c['_id']}, {"$set": fix_data}, upsert=True)444assert res.matched_count==1445446def add_numeric_label_suffixes(min_level_norm=0, max_level_norm=None, fix=False):447r""" One-off utility to add a numeric conversion of the letter-coded448label suffixes 'a'->0', 'z'->25, 'ba'->26, etc. for sorting449purposes.450"""451from sage.databases.cremona import class_to_int452count = 0453query = {}454query['level_norm'] = {'$gte' : int(min_level_norm)}455if max_level_norm:456query['level_norm']['$lte'] = int(max_level_norm)457else:458max_level_norm = oo459forms_to_fix = forms.find(query)460print("%s forms to examine of level norm between %s and %s."461% (forms_to_fix.count(),min_level_norm,max_level_norm))462for f in forms_to_fix:463count = count+1464if count%100==0: print("%s: %s" % (count, f['label']))465fix_data = {}466lab = f['label_suffix']467fix_data['label_nsuffix'] = class_to_int(lab)468#print("using fixed data %s for form %s" % (fix_data,f['label']))469if fix:470forms.update({'label': f['label']}, {"$set": fix_data}, upsert=True)471472473474475