Path: blob/main/scripts/elliptic_curves/import_ec_lfunction_data.py
1128 views
# -*- coding: utf-8 -*-1r""" Import L-function data (as computed from Cremona tables by Andy Booker).23Initial version (Bristol March 2016)45NB This script has NOT been adapted to work with postgres67For the format of the collections Lfunctions and Instances in the8database Lfunctions, see9https://github.com/LMFDB/lmfdb-inventory/blob/master/db-Lfunctions.md.10These are duplicated here for convenience but the inventory takes11precedence in case of any discrepancy.1213In general "number" means an int or double or string representing a number (e.g. '1/2').1415(1) fields which are the same for every elliptic curve over Q:1617- 'algebraic' (bool), whether the L-function is algebraic: True1819- 'analytic_normalization' (number), translation needed to obtain20the analytic normalization: 0.52122- 'coefficient_field' (string), label of the coefficient field Q: '1.1.1.1'23- 'degree' (int), degree of the L-function: 224- 'gamma_factors' (list of length 2 of lists of numbers), encoding of Gamma factors: [[],[0]]25- 'motivic_weight' (int), motivic weight: 126- 'primitive' (bool), wheher this L-function is primitive: True27- 'self_dual' (bool), wheher this L-function is self-dual: True28- 'load_key' (string), person who uploaded the data29- 'type' (string), "ECQ"3031(2) fields which depend on the curve (isogeny class)3233- '_id': internal mogodb identifier34- 'Lhash' (string)35- 'conductor' (int) conductor, e.g. 122536- 'url' (string): the URL of the object from which this37L-function originated, e.g. 'EllipticCurve/Q/11/a'38- 'instances' (list of strings): list of URLs of objects with this L-function, e.g. ['EllipticCurve/Q/11/a']39- 'order_of_vanishing': (int) order of vanishing at critical point, e.g. 040- 'bad_lfactors' (list of lists) list of pairs [p,coeffs] where p41is a bad prime and coeffs is a list of 1 or 2 numbers,42coefficients of the bad Euler factor at p,43e.g. [[2,[1]],[3,[1,1]],[5,[1,-1]]]44- 'euler_factors' (list of lists of 3 ints): list of lists [1] or45[1,1] or [1,-1] or[1,-ap,p] of coefficients of the p'th Euler46factor for the first 100 primes (including any bad primes).47- 'A2',...,'A10' (int): first few (integral) Dirichlet coefficients, arithmetic normalization48- 'a2',...,'a10' (list of 2 floats): first few (complex) Dirichlet coefficients, analytic normalization49- 'central_character' (string): label of associated central character, '%s.1' % conductor50- 'root_number' (int): sign of the functional equation: 1 or -151- 'leading_term' (number): value of L^{r}(1)/r! where r=order_of_vanishing, e.g. 0.25384186085652- 'st_group' (string): Sato-Tate group, either 'SU(2)' if not CM or 'N(U(1))' if CM53- 'positive_zeros' (list of strings): list of strings representing strictly positive54imaginary parts of zeros between 0 and 20.55- 'z1', 'z2', 'z3' (numbers): the first three positive zeros56- 'plot_delta' (number): x-increment for plot values57- 'plot_values' (list of numbers): list of y-coordinates of points on the plot5859"""6061import os62from sage.all import ZZ, primes, sqrt, EllipticCurve, prime_pi6364from lmfdb.base import getDBConnection65print("getting connection")66C= getDBConnection()67print("authenticating on the elliptic_curves database")68import yaml69pw_dict = yaml.load(open(os.path.join(os.getcwd(), os.extsep, os.extsep, os.extsep, "passwords.yaml")))70username = pw_dict['data']['username']71password = pw_dict['data']['password']72C['elliptic_curves'].authenticate(username, password)73print("setting curves")74curves = C.elliptic_curves.curves7576print("authenticating on the Lfunctions database")77C['Lfunctions'].authenticate(username, password)78Lfunctions = C.Lfunctions.Lfunctions79#Lfunctions = C.Lfunctions.LfunctionsECtest80Instances = C.Lfunctions.instances81#Instances = C.Lfunctions.instancesECtest8283def constant_data():84r"""85Returns a dict containing the L-function data which is the same for all curves:8687- 'algebraic', whether the L-function is algebraic: True88- 'analytic_normalization', translation needed to obtain the analytic normalization: 0.589- 'coefficient_field', label of the coefficient field Q: '1.1.1.1'90- 'degree', degree of the L-function: 291- 'gamma_factors', encoding of Gamma factors: [[],[0]]92- 'motivic_weight', motivic weight: 193- 'primitive', wheher this L-function is primitive: True94- 'self_dual', wheher this L-function is self-dual: True95- 'load_key', person who uploaded the data9697"""98return {99'algebraic': True,100'analytic_normalization': 0.5,101'coefficient_field': '1.1.1.1',102'degree': 2,103'gamma_factors': [[],[0]],104'motivic_weight': 1,105'primitive': True,106'self_dual': True,107'load_key': "Cremona"108}109110def make_one_euler_factor(E, p):111r"""112Returns the Euler factor at p from a Sage elliptic curve E.113"""114ap = int(E.ap(p))115e = E.conductor().valuation(p)116if e==0:117return [1,-ap,int(p)]118if e==1:119return [1,-ap]120return [1]121122def make_one_euler_factor_db(E, p):123r"""124Returns the Euler factor at p from a database elliptic curve E.125"""126ld = [ld for ld in E['local_data'] if ld['p']==p]127if ld: # p is bad, we get ap from the stored local data:128ap = ld[0]['red']129if ap:130return [1,-ap]131else:132return [1]133134# Now p is good and < 100 so we retrieve ap from the stored aplist:135136ap = E['aplist'][prime_pi(p)-1] # rebase count from 1 to 0137return [1,-ap,int(p)]138139def make_euler_factors(E, maxp=100):140r"""141Returns a list of the Euler factors for all primes up to max_p,142given a Sage elliptic curve E.143"""144return [make_one_euler_factor(E, p) for p in primes(maxp)]145146def make_euler_factors_db(E):147r"""148Returns a list of the Euler factors for all primes up to 100,149given a database elliptic curve E (which has this many ap stored)150"""151return [make_one_euler_factor_db(E, p) for p in primes(100)]152153def make_bad_lfactors(E):154r"""155Returns a list of the bad Euler factors, given a Sage elliptic curve E,156"""157return [[int(p),make_one_euler_factor(E, p)] for p in E.conductor().support()]158159def make_bad_lfactors_db(E):160r"""161Returns a list of the bad Euler factors, given a database elliptic curve E,162"""163return [[p,make_one_euler_factor_db(E, p)] for p in [ld['p'] for ld in E['local_data']]]164165def read_line(line):166r""" Parses one line from input file. Returns the hash and a dict167containing fields with keys as above. This version expects 9168fields on each line, separated by a colon:1691700. hash1711. label1722. root number1733. (not used)1744. [a(n) for n in [2..10]1755. Special value L^(r)(1)/r!1766. zeros1777. plot spacing1788. plot data179180181"""182fields = line.split(":")183if len(fields)==6:184return read_line_old(line)185assert len(fields)==9186label = fields[1]187# get a curve from the database in this isogeny class. It must188# have number 1 since only those have the ap and an stored.189E = curves.find_one({'iso': label, 'number':1})190191data = constant_data()192instances = {}193194# Set the fields in the Instances collection:195196cond = data['conductor'] = int(E['conductor'])197iso = E['lmfdb_iso'].split('.')[1]198instances['url'] = 'EllipticCurve/Q/%s/%s' % (cond,iso)199instances['Lhash'] = Lhash = fields[0]200instances['type'] = 'ECQ'201202# Set the fields in the Lfunctions collection:203204data['Lhash'] = Lhash205data['root_number'] = int(fields[2])206data['order_of_vanishing'] = int(E['rank'])207data['central_character'] = '%s.1' % cond208data['st_group'] = 'N(U(1))' if E['cm'] else 'SU(2)'209data['leading_term'] = lt = float(fields[5])210#211lt_db = float(E['special_value'])212dif = abs(lt-lt_db)213eps = 1e-14214if dif > eps:215print("{}: special value in db = {}, in input file = {}, difference = {}".format(label,lt_db,lt,dif))216217# Zeros218219zeros = fields[6][1:-1].split(",")220# omit negative ones and 0, using only string tests:221data['positive_zeros'] = [y for y in zeros if y!='0' and y[0]!='-']222data['z1'] = data['positive_zeros'][0]223data['z2'] = data['positive_zeros'][1]224data['z3'] = data['positive_zeros'][2]225226# plot data227228# constant difference in x-coordinate sequence:229data['plot_delta'] = float(fields[7])230# list of y coordinates for x>0:231data['plot_values'] = [float(y) for y in fields[8][1:-2].split(",")]232233# Euler factors:234235data['bad_lfactors'] = make_bad_lfactors_db(E)236data['euler_factors'] = make_euler_factors_db(E)237238# Dirichlet coefficients239240an = E['anlist'] # list indexed from 0 to 10 inclusive241input_an = [int(a) for a in fields[4][1:-1].split(",")]242assert an[2:11]==input_an243for n in range(2,11):244data['A%s' % n] = str(an[n])245data['a%s' % n] = [an[n]/sqrt(float(n)),0]246247return Lhash, data, instances248249def read_line_old(line):250r""" Parses one line from input file. Returns the hash and a dict251containing fields with keys as above. This original version252expects 6 fields on each line, separated by a colon:2532540. hash2551. label2562. root number2573. (not used)2584. zeros2595. plot data260261"""262fields = line.split(":")263assert len(fields)==6264label = fields[1] # use this isogeny class label to get info about the curve265E = curves.find_one({'iso': label})266267data = constant_data()268instances = {}269270# Set the fields in the Instances collection:271272cond = data['conductor'] = int(E['conductor'])273iso = E['lmfdb_iso'].split('.')[1]274instances['url'] = 'EllipticCurve/Q/%s/%s' % (cond,iso)275instances['Lhash'] = Lhash = fields[0]276instances['type'] = 'ECQ'277278# Set the fields in the Lfunctions collection:279280data['Lhash'] = Lhash281data['root_number'] = int(fields[2])282data['order_of_vanishing'] = int(E['rank'])283data['central_character'] = '%s.1' % cond284data['st_group'] = 'N(U(1))' if E['cm'] else 'SU(2)'285data['leading_term'] = float(E['special_value'])286287# Zeros288289zeros = fields[4][1:-1].split(",")290# omit negative ones and 0, using only string tests:291data['positive_zeros'] = [y for y in zeros if y!='0' and y[0]!='-']292data['z1'] = data['positive_zeros'][0]293data['z2'] = data['positive_zeros'][1]294data['z3'] = data['positive_zeros'][2]295296# plot data297298plot_xy = [[float(v) for v in vv.split(",")] for vv in fields[5][2:-3].split("],[")]299# constant difference in x-coordinate sequence:300data['plot_delta'] = plot_xy[1][0]-plot_xy[0][0]301# list of y coordinates for x>0:302data['plot_values'] = [y for x,y in plot_xy if x>=0]303304# Euler factors: we need the ap which are currently not in the305# database so we call Sage. It might be a good idea to store in306# the ec database (1) all ap for p<100; (2) all ap for bad p.307Esage = EllipticCurve([ZZ(a) for a in E['ainvs']])308data['bad_lfactors'] = make_bad_lfactors(Esage)309data['euler_factors'] = make_euler_factors(Esage)310311# Dirichlet coefficients312313an = Esage.anlist(10)314for n in range(2,11):315data['A%s' % n] = str(an[n])316data['a%s' % n] = [an[n]/sqrt(float(n)),0]317318return Lhash, data, instances319320321# To run this go into the top-level lmfdb directory, run sage and give322# the command323# %runfile lmfdb/elliptic_curves/import_ec_lfunction_data.py324#325# and then run the following function.326# Unless you set test=False it will not actually upload any data.327328def upload_to_db(base_path, f, test=True):329f = os.path.join(base_path, f)330h = open(f)331print("opened %s" % f)332333data_to_insert = {} # will hold all the data to be inserted334instances_to_insert = {} # will hold all the data to be inserted335count = 0336337for line in h.readlines():338count += 1339if count%1000==0:340print("read %s lines" % count)341Lhash, data, instance = read_line(line)342if Lhash not in data_to_insert:343data_to_insert[Lhash] = data344instances_to_insert[Lhash] = instance345346print("finished reading %s lines from file" % count)347vals = data_to_insert.values()348349print("Number of records to insert = %s" % len(vals))350count = 0351352if test:353print("Not inserting any records as in test mode")354print("First record is %s" % vals[0])355return356357for val in vals:358#print val359Lfunctions.update_one({'Lhash': val['Lhash']}, {"$set": val}, upsert=True)360Instances.update_one({'Lhash': val['Lhash']}, {"$set": instances_to_insert[val['Lhash']]}, upsert=True)361count += 1362if count % 1000 == 0:363print("inserted %s items" % count)364365366