def make_extra_data(label, number, ainvs, gens): """Given a curve label (and number, as some data is only stored wih curve number 1 in each class) and its ainvs and gens, returns a dict with which to update the entry. Extra items computed here: 'equation': latex string of curve's equation 'signD': sign of discriminant 'local_data': list of dicts, one item for each bad prime 'min_quad_twist': dict holding curve's min quadratic twist and the twisting discriminant 'heights': list of heights of gens and for curve #1 in a class only: 'aplist': list of a_p for p<100 'anlist': list of a_n for n<=20 """ E = EllipticCurve(parse_ainvs(ainvs)) data = {} # convert from a list of strings to a single string, e.g. from ['0','0','0','1','1'] to '[0,0,0,1,1]' data['equation'] = web_latex(E) data['signD'] = int(E.discriminant().sign()) data['local_data'] = [{ 'p': int(ld.prime().gen()), 'ord_cond': int(ld.conductor_valuation()), 'ord_disc': int(ld.discriminant_valuation()), 'ord_den_j': int(max(0, -(E.j_invariant().valuation(ld.prime().gen())))), 'red': int(ld.bad_reduction_type()), 'rootno': int(E.root_number(ld.prime().gen())), 'kod': web_latex(ld.kodaira_symbol()).replace('$', ''), 'cp': int(ld.tamagawa_number()) } for ld in E.local_data()] Etw, Dtw = E.minimal_quadratic_twist() if Etw.conductor() == E.conductor(): data['min_quad_twist'] = {'label': label, 'disc': int(1)} else: minq_ainvs = ''.join(['['] + [str(c) for c in Etw.ainvs()] + [']']) r = curves.find_one({ 'jinv': str(E.j_invariant()), 'ainvs': minq_ainvs }) minq_label = "" if r is None else r['label'] data['min_quad_twist'] = {'label': minq_label, 'disc': int(Dtw)} from lmfdb.elliptic_curves.web_ec import parse_points gens = [E(g) for g in parse_points(gens)] data['heights'] = [float(P.height()) for P in gens] if number == 1: data['aplist'] = E.aplist(100, python_ints=True) data['anlist'] = E.anlist(20, python_ints=True) return data
def download_qexp(): ainvs = request.args.get('ainvs') E = EllipticCurve([int(a) for a in ainvs.split(',')]) response = make_response('\n'.join( str(an) for an in E.anlist(int(request.args.get('limit', 100)), python_ints=True))) response.headers['Content-type'] = 'text/plain' return response
def download_EC_qexp(label, limit): N, iso, number = split_lmfdb_label(label) if number: ainvs = db.ec_curves.lookup(label, 'ainvs', 'lmfdb_label') else: ainvs = db.ec_curves.lookup(label, 'ainvs', 'lmfdb_iso') E = EllipticCurve(ainvs) response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True))) response.headers['Content-type'] = 'text/plain' return response
def download_EC_qexp(label, limit): N, iso, number = split_lmfdb_label(label) if number: ainvs = db.ec_curves.lookup(label, 'ainvs', 'lmfdb_label') else: ainvs = db.ec_curves.lookup(label, 'ainvs', 'lmfdb_iso') E = EllipticCurve(ainvs) response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True))) response.headers['Content-type'] = 'text/plain' return response
def download_EC_qexp(label, limit): CDB = db_ec() N, iso, number = split_lmfdb_label(label) if number: data = CDB.find_one({'lmfdb_label': label}) else: data = CDB.find_one({'lmfdb_iso': label}) E = EllipticCurve(parse_ainvs(data['ainvs'])) response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True))) response.headers['Content-type'] = 'text/plain' return response
def download_EC_qexp(label, limit): CDB = db_ec() N, iso, number = split_lmfdb_label(label) if number: data = CDB.find_one({'lmfdb_label': label}) else: data = CDB.find_one({'lmfdb_iso': label}) E = EllipticCurve(parse_ainvs(data['ainvs'])) response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True))) response.headers['Content-type'] = 'text/plain' return response
def download_EC_qexp(label, limit): logger.debug(label) CDB = lmfdb.base.getDBConnection().elliptic_curves.curves N, iso, number = lmfdb_label_regex.match(label).groups() if number: data = CDB.find_one({"lmfdb_label": label}) else: data = CDB.find_one({"lmfdb_iso": label}) ainvs = data["ainvs"] logger.debug(ainvs) E = EllipticCurve([int(a) for a in ainvs]) response = make_response(",".join(str(an) for an in E.anlist(int(limit), python_ints=True))) response.headers["Content-type"] = "text/plain" return response
def download_EC_qexp(label, limit): ec_logger.debug(label) CDB = lmfdb.base.getDBConnection().elliptic_curves.curves N, iso, number = split_lmfdb_label(label) if number: data = CDB.find_one({'lmfdb_label': label}) else: data = CDB.find_one({'lmfdb_iso': label}) ainvs = data['ainvs'] ec_logger.debug(ainvs) E = EllipticCurve([int(a) for a in ainvs]) response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True))) response.headers['Content-type'] = 'text/plain' return response
def download_EC_qexp(label, limit): ec_logger.debug(label) CDB = lmfdb.base.getDBConnection().elliptic_curves.curves N, iso, number = split_lmfdb_label(label) if number: data = CDB.find_one({'lmfdb_label': label}) else: data = CDB.find_one({'lmfdb_iso': label}) ainvs = data['ainvs'] ec_logger.debug(ainvs) E = EllipticCurve([int(a) for a in ainvs]) response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True))) response.headers['Content-type'] = 'text/plain' return response
def make_extra_data(label, number, ainvs, gens): """ C is a database elliptic curve entry. Returns a dict with which to update the entry. Data fields needed in C already: 'ainvs', 'lmfdb_label', 'gens', 'number' """ E = EllipticCurve([int(a) for a in ainvs]) data = {} # convert from a list of strings to a single string, e.g. from ['0','0','0','1','1'] to '[0,0,0,1,1]' data['xainvs'] = ''.join(['[', ','.join(ainvs), ']']) data['equation'] = web_latex(E) data['signD'] = int(E.discriminant().sign()) data['local_data'] = [{ 'p': int(ld.prime().gen()), 'ord_cond': int(ld.conductor_valuation()), 'ord_disc': int(ld.discriminant_valuation()), 'ord_den_j': int(max(0, -(E.j_invariant().valuation(ld.prime().gen())))), 'red': int(ld.bad_reduction_type()), 'rootno': int(E.root_number(ld.prime().gen())), 'kod': web_latex(ld.kodaira_symbol()).replace('$', ''), 'cp': int(ld.tamagawa_number()) } for ld in E.local_data()] Etw, Dtw = E.minimal_quadratic_twist() if Etw.conductor() == E.conductor(): data['min_quad_twist'] = {'label': label, 'disc': int(1)} else: # Later this should be changed to look for xainvs but now all curves have ainvs minq_ainvs = [str(c) for c in Etw.ainvs()] r = curves.find_one({ 'jinv': str(E.j_invariant()), 'ainvs': minq_ainvs }) minq_label = "" if r is None else r['label'] data['min_quad_twist'] = {'label': minq_label, 'disc': int(Dtw)} from lmfdb.elliptic_curves.web_ec import parse_points gens = [E(g) for g in parse_points(gens)] data['heights'] = [float(P.height()) for P in gens] if number == 1: data['aplist'] = E.aplist(100, python_ints=True) data['anlist'] = E.anlist(20, python_ints=True) return data
def _test_an_dict_over_Q(ainvs, B=100): """ Test that the an_dict function works and gives the correct answer for an elliptic curve defined over QQ, by computing using the generic code in this file, and comparing with the output of Sage's anlist function for rational elliptic curves. """ from sage.all import polygen, QQ, NumberField, EllipticCurve x = polygen(QQ,'x') F = NumberField(x - 1,'a'); a = F.gen() E = EllipticCurve(F, ainvs) EQ = EllipticCurve(QQ, ainvs) v = EQ.anlist(B) an = an_dict(E, B) for i, j in an.iteritems(): assert j == v[i[0]]
def make_extra_data(label,number,ainvs,gens): """Given a curve label (and number, as some data is only stored wih curve number 1 in each class) and its ainvs and gens, returns a dict with which to update the entry. Extra items computed here: 'equation': latex string of curve's equation 'signD': sign of discriminant 'local_data': list of dicts, one item for each bad prime 'min_quad_twist': dict holding curve's min quadratic twist and the twisting discriminant 'heights': list of heights of gens and for curve #1 in a class only: 'aplist': list of a_p for p<100 'anlist': list of a_n for n<=20 """ E = EllipticCurve(parse_ainvs(ainvs)) data = {} # convert from a list of strings to a single string, e.g. from ['0','0','0','1','1'] to '[0,0,0,1,1]' data['equation'] = web_latex(E) data['signD'] = int(E.discriminant().sign()) data['local_data'] = [{'p': int(ld.prime().gen()), 'ord_cond':int(ld.conductor_valuation()), 'ord_disc':int(ld.discriminant_valuation()), 'ord_den_j':int(max(0,-(E.j_invariant().valuation(ld.prime().gen())))), 'red':int(ld.bad_reduction_type()), 'rootno':int(E.root_number(ld.prime().gen())), 'kod':web_latex(ld.kodaira_symbol()).replace('$',''), 'cp':int(ld.tamagawa_number())} for ld in E.local_data()] Etw, Dtw = E.minimal_quadratic_twist() if Etw.conductor()==E.conductor(): data['min_quad_twist'] = {'label':label, 'disc':int(1)} else: minq_ainvs = ''.join(['['] + [str(c) for c in Etw.ainvs()] + [']']) r = curves.find_one({'jinv':str(E.j_invariant()), 'ainvs':minq_ainvs}) minq_label = "" if r is None else r['label'] data['min_quad_twist'] = {'label':minq_label, 'disc':int(Dtw)} from lmfdb.elliptic_curves.web_ec import parse_points gens = [E(g) for g in parse_points(gens)] data['heights'] = [float(P.height()) for P in gens] if number==1: data['aplist'] = E.aplist(100,python_ints=True) data['anlist'] = E.anlist(20,python_ints=True) return data
def download_EC_qexp(label, limit): try: N, iso, number = split_lmfdb_label(label) except (ValueError,AttributeError): return elliptic_curve_jump_error(label, {}) if number: ainvs = db.ec_curvedata.lookup(label, 'ainvs', 'lmfdb_label') else: ainvs = db.ec_curvedata.lookup(label, 'ainvs', 'lmfdb_iso') if ainvs is None: return elliptic_curve_jump_error(label, {}) if limit > 100000: return redirect(url_for('.download_EC_qexp',label=label,limit=10000), 301) E = EllipticCurve(ainvs) response = make_response(','.join(str(an) for an in E.anlist(int(limit), python_ints=True))) response.headers['Content-type'] = 'text/plain' return response
def make_extra_data(label,number,ainvs,gens): """ C is a database elliptic curve entry. Returns a dict with which to update the entry. Data fields needed in C already: 'ainvs', 'lmfdb_label', 'gens', 'number' """ E = EllipticCurve([int(a) for a in ainvs]) data = {} # convert from a list of strings to a single string, e.g. from ['0','0','0','1','1'] to '[0,0,0,1,1]' data['xainvs'] = ''.join(['[',','.join(ainvs),']']) data['equation'] = web_latex(E) data['signD'] = int(E.discriminant().sign()) data['local_data'] = [{'p': int(ld.prime().gen()), 'ord_cond':int(ld.conductor_valuation()), 'ord_disc':int(ld.discriminant_valuation()), 'ord_den_j':int(max(0,-(E.j_invariant().valuation(ld.prime().gen())))), 'red':int(ld.bad_reduction_type()), 'rootno':int(E.root_number(ld.prime().gen())), 'kod':web_latex(ld.kodaira_symbol()).replace('$',''), 'cp':int(ld.tamagawa_number())} for ld in E.local_data()] Etw, Dtw = E.minimal_quadratic_twist() if Etw.conductor()==E.conductor(): data['min_quad_twist'] = {'label':label, 'disc':int(1)} else: # Later this should be changed to look for xainvs but now all curves have ainvs minq_ainvs = [str(c) for c in Etw.ainvs()] r = curves.find_one({'jinv':str(E.j_invariant()), 'ainvs':minq_ainvs}) minq_label = "" if r is None else r['label'] data['min_quad_twist'] = {'label':minq_label, 'disc':int(Dtw)} from lmfdb.elliptic_curves.web_ec import parse_points gens = [E(g) for g in parse_points(gens)] data['heights'] = [float(P.height()) for P in gens] if number==1: data['aplist'] = E.aplist(100,python_ints=True) data['anlist'] = E.anlist(20,python_ints=True) return data
class WebEC(object): """ Class for an elliptic curve over Q """ def __init__(self, dbdata): """ Arguments: - dbdata: the data from the database """ logger.debug("Constructing an instance of WebEC") self.__dict__.update(dbdata) # Next lines because the hyphens make trouble self.xintcoords = split_list( dbdata['x-coordinates_of_integral_points']) self.non_surjective_primes = dbdata['non-surjective_primes'] # Next lines because the python identifiers cannot start with 2 self.twoadic_index = dbdata['2adic_index'] self.twoadic_log_level = dbdata['2adic_log_level'] self.twoadic_gens = dbdata['2adic_gens'] self.twoadic_label = dbdata['2adic_label'] # All other fields are handled here self.make_curve() @staticmethod def by_label(label): """ Searches for a specific elliptic curve in the curves collection by its label, which can be either in LMFDB or Cremona format. """ try: N, iso, number = split_lmfdb_label(label) data = db_ec().find_one({"lmfdb_label": label}) except AttributeError: try: N, iso, number = split_cremona_label(label) data = db_ec().find_one({"label": label}) except AttributeError: return "Invalid label" # caller must catch this and raise an error if data: return WebEC(data) return "Curve not found" # caller must catch this and raise an error def make_curve(self): # To start with the data fields of self are just those from # the database. We need to reformat these. # Old version: required constructing the actual elliptic curve # E, and computing some further data about it. # New version (May 2016): extra data fields now in the # database so we do not have to construct the curve or do any # computation with it on the fly. As a failsafe the old way # is still included. data = self.data = {} try: data['ainvs'] = [int(c) for c in self.xainvs[1:-1].split(',')] except AttributeError: data['ainvs'] = [int(ai) for ai in self.ainvs] data['conductor'] = N = ZZ(self.conductor) data['j_invariant'] = QQ(str(self.jinv)) data['j_inv_factor'] = latex(0) if data['j_invariant']: # don't factor 0 data['j_inv_factor'] = latex(data['j_invariant'].factor()) data['j_inv_str'] = unicode(str(data['j_invariant'])) data['j_inv_latex'] = web_latex(data['j_invariant']) mw = self.mw = {} mw['rank'] = self.rank mw['int_points'] = '' if self.xintcoords: a1, a2, a3, a4, a6 = [ZZ(a) for a in data['ainvs']] def lift_x(x): f = ((x + a2) * x + a4) * x + a6 b = (a1 * x + a3) d = (b * b + 4 * f).sqrt() return (x, (-b + d) / 2) mw['int_points'] = ', '.join( web_latex(lift_x(x)) for x in self.xintcoords) mw['generators'] = '' mw['heights'] = [] if self.gens: mw['generators'] = [ web_latex(tuple(P)) for P in parse_points(self.gens) ] mw['tor_order'] = self.torsion tor_struct = [int(c) for c in self.torsion_structure] if mw['tor_order'] == 1: mw['tor_struct'] = '\mathrm{Trivial}' mw['tor_gens'] = '' else: mw['tor_struct'] = ' \\times '.join( ['\Z/{%s}\Z' % n for n in tor_struct]) mw['tor_gens'] = ', '.join( web_latex(tuple(P)) for P in parse_points(self.torsion_generators)) # try to get all the data we need from the database entry (now in self) try: data['equation'] = self.equation local_data = self.local_data D = self.signD * prod( [ld['p']**ld['ord_disc'] for ld in local_data]) data['disc'] = D Nfac = Factorization([(ZZ(ld['p']), ld['ord_cond']) for ld in local_data]) Dfac = Factorization([(ZZ(ld['p']), ld['ord_disc']) for ld in local_data], unit=ZZ(self.signD)) data['minq_D'] = minqD = self.min_quad_twist['disc'] minq_label = self.min_quad_twist['label'] data['minq_label'] = db_ec().find_one( {'label': minq_label}, ['lmfdb_label'])['lmfdb_label'] data['minq_info'] = '(itself)' if minqD == 1 else '(by %s)' % minqD try: data['degree'] = self.degree except AttributeError: data['degree'] = 0 # invalid, but will be displayed nicely mw['heights'] = self.heights if self.number == 1: data['an'] = self.anlist data['ap'] = self.aplist else: r = db_ec().find_one({ 'lmfdb_iso': self.lmfdb_iso, 'number': 1 }, ['anlist', 'aplist']) data['an'] = r['anlist'] data['ap'] = r['aplist'] # otherwise fall back to computing it from the curve except AttributeError: print("Falling back to constructing E") self.E = EllipticCurve(data['ainvs']) data['equation'] = web_latex(self.E) data['disc'] = D = self.E.discriminant() Nfac = N.factor() Dfac = D.factor() bad_primes = [p for p, e in Nfac] try: data['degree'] = self.degree except AttributeError: try: data['degree'] = self.E.modular_degree() except RuntimeError: data['degree'] = 0 # invalid, but will be displayed nicely minq, minqD = self.E.minimal_quadratic_twist() data['minq_D'] = minqD if minqD == 1: data['minq_label'] = self.lmfdb_label data['minq_info'] = '(itself)' else: # This relies on the minimal twist being in the # database, which is true when the database only # contains the Cremona database. It would be a good # idea if, when the database is extended, we ensured # that for any curve included, all twists of smaller # conductor are also included. minq_ainvs = [str(c) for c in minq.ainvs()] data['minq_label'] = db_ec().find_one( { 'jinv': str(self.E.j_invariant()), 'ainvs': minq_ainvs }, ['lmfdb_label'])['lmfdb_label'] data['minq_info'] = '(by %s)' % minqD if self.gens: self.generators = [self.E(g) for g in parse_points(self.gens)] mw['heights'] = [P.height() for P in self.generators] data['an'] = self.E.anlist(20, python_ints=True) data['ap'] = self.E.aplist(100, python_ints=True) self.local_data = local_data = [] for p in bad_primes: ld = self.E.local_data(p, algorithm="generic") local_data_p = {} local_data_p['p'] = p local_data_p['cp'] = ld.tamagawa_number() local_data_p['kod'] = web_latex(ld.kodaira_symbol()).replace( '$', '') local_data_p['red'] = ld.bad_reduction_type() rootno = -ld.bad_reduction_type() if rootno == 0: rootno = self.E.root_number(p) local_data_p['rootno'] = rootno local_data_p['ord_cond'] = ld.conductor_valuation() local_data_p['ord_disc'] = ld.discriminant_valuation() local_data_p['ord_den_j'] = max( 0, -self.E.j_invariant().valuation(p)) local_data.append(local_data_p) # If we got the data from the database, the root numbers may # not have been stored there, so we have to compute them. If # there are additive primes this means constructing the curve. for ld in self.local_data: if not 'rootno' in ld: rootno = -ld['red'] if rootno == 0: try: E = self.E except AttributeError: self.E = E = EllipticCurve(data['ainvs']) rootno = E.root_number(ld['p']) ld['rootno'] = rootno minq_N, minq_iso, minq_number = split_lmfdb_label(data['minq_label']) data['disc_factor'] = latex(Dfac) data['cond_factor'] = latex(Nfac) data['disc_latex'] = web_latex(D) data['cond_latex'] = web_latex(N) data['CMD'] = self.cm data['CM'] = "no" data['EndE'] = "\(\Z\)" if self.cm: data['CM'] = "yes (\(D=%s\))" % data['CMD'] if data['CMD'] % 4 == 0: d4 = ZZ(data['CMD']) // 4 data['EndE'] = "\(\Z[\sqrt{%s}]\)" % d4 else: data['EndE'] = "\(\Z[(1+\sqrt{%s})/2]\)" % data['CMD'] data['ST'] = st_link_by_name(1, 2, 'N(U(1))') else: data['ST'] = st_link_by_name(1, 2, 'SU(2)') data['p_adic_primes'] = [ p for i, p in enumerate(prime_range(5, 100)) if (N * data['ap'][i]) % p != 0 ] try: data['galois_images'] = [ trim_galois_image_code(s) for s in self.galois_images ] data['non_surjective_primes'] = self.non_surjective_primes except AttributeError: #print "No Galois image data" data['galois_images'] = [] data['non_surjective_primes'] = [] data['galois_data'] = [{ 'p': p, 'image': im } for p, im in zip(data['non_surjective_primes'], data['galois_images'])] cond, iso, num = split_lmfdb_label(self.lmfdb_label) self.class_url = url_for(".by_double_iso_label", conductor=N, iso_label=iso) self.ncurves = db_ec().count({'lmfdb_iso': self.lmfdb_iso}) isodegs = [str(d) for d in self.isogeny_degrees if d > 1] if len(isodegs) < 3: data['isogeny_degrees'] = " and ".join(isodegs) else: data['isogeny_degrees'] = " and ".join( [", ".join(isodegs[:-1]), isodegs[-1]]) if self.twoadic_gens: from sage.matrix.all import Matrix data['twoadic_gen_matrices'] = ','.join( [latex(Matrix(2, 2, M)) for M in self.twoadic_gens]) data[ 'twoadic_rouse_url'] = ROUSE_URL_PREFIX + self.twoadic_label + ".html" # Leading term of L-function & BSD data bsd = self.bsd = {} r = self.rank if r >= 2: bsd['lder_name'] = "L^{(%s)}(E,1)/%s!" % (r, r) elif r: bsd['lder_name'] = "L'(E,1)" else: bsd['lder_name'] = "L(E,1)" bsd['reg'] = self.regulator bsd['omega'] = self.real_period bsd['sha'] = int(0.1 + self.sha_an) bsd['lder'] = self.special_value # Optimality (the optimal curve in the class is the curve # whose Cremona label ends in '1' except for '990h' which was # labelled wrongly long ago) if self.iso == '990h': data['Gamma0optimal'] = bool(self.number == 3) else: data['Gamma0optimal'] = bool(self.number == 1) data['p_adic_data_exists'] = False if data['Gamma0optimal']: data['p_adic_data_exists'] = (padic_db().find({ 'lmfdb_iso': self.lmfdb_iso }).count()) > 0 tamagawa_numbers = [ZZ(ld['cp']) for ld in local_data] cp_fac = [cp.factor() for cp in tamagawa_numbers] cp_fac = [ latex(cp) if len(cp) < 2 else '(' + latex(cp) + ')' for cp in cp_fac ] bsd['tamagawa_factors'] = r'\cdot'.join(cp_fac) bsd['tamagawa_product'] = prod(tamagawa_numbers) data['newform'] = web_latex( PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True)) data['newform_label'] = self.newform_label = newform_label( cond, 2, 1, iso) self.newform_link = url_for("emf.render_elliptic_modular_forms", level=cond, weight=2, character=1, label=iso) self.newform_exists_in_db = is_newform_in_db(self.newform_label) self._code = None self.class_url = url_for(".by_double_iso_label", conductor=N, iso_label=iso) self.friends = [('Isogeny class ' + self.lmfdb_iso, self.class_url), ('Minimal quadratic twist %s %s' % (data['minq_info'], data['minq_label']), url_for(".by_triple_label", conductor=minq_N, iso_label=minq_iso, number=minq_number)), ('All twists ', url_for(".rational_elliptic_curves", jinv=self.jinv)), ('L-function', url_for("l_functions.l_function_ec_page", label=self.lmfdb_label))] if not self.cm: if N <= 300: self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso))] if N <= 50: self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', label=self.lmfdb_iso))] if self.newform_exists_in_db: self.friends += [('Modular form ' + self.newform_label, self.newform_link)] self.downloads = [('Download coefficients of q-expansion', url_for(".download_EC_qexp", label=self.lmfdb_label, limit=1000)), ('Download all stored data', url_for(".download_EC_all", label=self.lmfdb_label)), ('Download Magma code', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='magma')), ('Download Sage code', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='sage')), ('Download GP code', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='gp'))] try: self.plot = encode_plot(self.E.plot()) except AttributeError: self.plot = encode_plot(EllipticCurve(data['ainvs']).plot()) self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot self.properties = [('Label', self.lmfdb_label), (None, self.plot_link), ('Conductor', '\(%s\)' % data['conductor']), ('Discriminant', '\(%s\)' % data['disc']), ('j-invariant', '%s' % data['j_inv_latex']), ('CM', '%s' % data['CM']), ('Rank', '\(%s\)' % mw['rank']), ('Torsion Structure', '\(%s\)' % mw['tor_struct'])] self.title = "Elliptic Curve %s (Cremona label %s)" % ( self.lmfdb_label, self.label) self.bread = [('Elliptic Curves', url_for("ecnf.index")), ('$\Q$', url_for(".rational_elliptic_curves")), ('%s' % N, url_for(".by_conductor", conductor=N)), ('%s' % iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)), ('%s' % num, ' ')] def code(self): if self._code == None: self.make_code_snippets() return self._code def make_code_snippets(self): # read in code.yaml from current directory: _curdir = os.path.dirname(os.path.abspath(__file__)) self._code = yaml.load(open(os.path.join(_curdir, "code.yaml"))) # Fill in placeholders for this specific curve: for lang in ['sage', 'pari', 'magma']: self._code['curve'][lang] = self._code['curve'][lang] % ( self.data['ainvs'], self.label) return for k in self._code: if k != 'prompt': for lang in self._code[k]: self._code[k][lang] = self._code[k][lang].split("\n") # remove final empty line if len(self._code[k][lang][-1]) == 0: self._code[k][lang] = self._code[k][lang][:-1]
def download_qexp(): ainvs = request.args.get('ainvs') E = EllipticCurve([int(a) for a in ainvs.split(',')]) response = make_response('\n'.join(str(an) for an in E.anlist(int(request.args.get('limit', 100)), python_ints=True))) response.headers['Content-type'] = 'text/plain' return response
def read_line_old(line): r""" Parses one line from input file. Returns the hash and a dict containing fields with keys as above. This original version expects 6 fields on each line, separated by a colon: 0. hash 1. label 2. root number 3. (not used) 4. zeros 5. plot data """ fields = line.split(":") assert len(fields)==6 label = fields[1] # use this isogeny class label to get info about the curve E = curves.find_one({'iso': label}) data = constant_data() instances = {} # Set the fields in the Instances collection: cond = data['conductor'] = int(E['conductor']) iso = E['lmfdb_iso'].split('.')[1] instances['url'] = 'EllipticCurve/Q/%s/%s' % (cond,iso) instances['Lhash'] = Lhash = fields[0] instances['type'] = 'ECQ' # Set the fields in the Lfunctions collection: data['Lhash'] = Lhash data['root_number'] = int(fields[2]) data['order_of_vanishing'] = int(E['rank']) data['central_character'] = '%s.1' % cond data['st_group'] = 'N(U(1))' if E['cm'] else 'SU(2)' data['leading_term'] = float(E['special_value']) # Zeros zeros = fields[4][1:-1].split(",") # omit negative ones and 0, using only string tests: data['positive_zeros'] = [y for y in zeros if y!='0' and y[0]!='-'] data['z1'] = data['positive_zeros'][0] data['z2'] = data['positive_zeros'][1] data['z3'] = data['positive_zeros'][2] # plot data plot_xy = [[float(v) for v in vv.split(",")] for vv in fields[5][2:-3].split("],[")] # constant difference in x-coordinate sequence: data['plot_delta'] = plot_xy[1][0]-plot_xy[0][0] # list of y coordinates for x>0: data['plot_values'] = [y for x,y in plot_xy if x>=0] # Euler factors: we need the ap which are currently not in the # database so we call Sage. It might be a good idea to store in # the ec database (1) all ap for p<100; (2) all ap for bad p. Esage = EllipticCurve([ZZ(a) for a in E['ainvs']]) data['bad_lfactors'] = make_bad_lfactors(Esage) data['euler_factors'] = make_euler_factors(Esage) # Dirichlet coefficients an = Esage.anlist(10) for n in range(2,11): data['A%s' % n] = str(an[n]) data['a%s' % n] = [an[n]/sqrt(float(n)),0] return Lhash, data, instances
def allgens(line): r""" Parses one line from an allgens file. Returns the label and a dict containing fields with keys 'conductor', 'iso', 'number', 'ainvs', 'jinv', 'cm', 'rank', 'gens', 'torsion_order', 'torsion_structure', 'torsion_generators', all values being strings or ints, and more. Input line fields: conductor iso number ainvs rank torsion_structure gens torsion_gens Sample input line: 20202 i 2 [1,0,0,-298389,54947169] 1 [2,4] [-570:6603:1] [-622:311:1] [834:19239:1] """ global lmfdb_label_to_label global label_to_lmfdb_label data = split(line) iso = data[0] + data[1] label = iso + data[2] try: lmfdb_label = label_to_lmfdb_label[label] except AttributeError: print("Label {} not found in label_to_lmfdb_label dict!".format(label)) lmfdb_label = "" global nallgens nallgens += 1 if nallgens % 100 == 0: print("processing allgens for {} (#{})".format(label, nallgens)) rank = int(data[4]) t = data[5] tor_struct = [] if t == '[]' else t[1:-1].split(",") torsion = int(prod([int(ti) for ti in tor_struct], 1)) ainvs = parse_ainvs(data[3]) E = EllipticCurve(ainvs) jinv = text_type(E.j_invariant()) if E.has_cm(): cm = int(E.cm_discriminant()) else: cm = int(0) N = E.conductor() bad_p = N.prime_factors() # will be sorted num_bad_p = len(bad_p) local_data = [{ 'p': int(ld.prime().gen()), 'ord_cond': int(ld.conductor_valuation()), 'ord_disc': int(ld.discriminant_valuation()), 'ord_den_j': int(max(0, -(E.j_invariant().valuation(ld.prime().gen())))), 'red': int(ld.bad_reduction_type()), 'rootno': int(E.root_number(ld.prime().gen())), 'kod': web_latex(ld.kodaira_symbol()).replace('$', ''), 'cp': int(ld.tamagawa_number()) } for ld in E.local_data()] semistable = all([ld['ord_cond'] == 1 for ld in local_data]) gens = [ gen.replace("[", "(").replace("]", ")") for gen in data[6:6 + rank] ] tor_gens = ["%s" % parse_tgens(tgens[1:-1]) for tgens in data[6 + rank:]] from lmfdb.elliptic_curves.web_ec import parse_points heights = [float(E(P).height()) for P in parse_points(gens)] Etw, Dtw = E.minimal_quadratic_twist() if Etw.conductor() == N: min_quad_twist = { 'label': label, 'lmfdb_label': lmfdb_label, 'disc': int(1) } else: minq_ainvs = Etw.ainvs() r = curves.lucky({ 'jinv': str(E.j_invariant()), 'ainvs': minq_ainvs }, projection=['label', 'lmfdb_label']) min_quad_twist = { 'label': r['label'], 'lmfdb_label': r['lmfdb_label'], 'disc': int(Dtw) } trace_hash = TraceHashClass(iso, E) return label, { 'conductor': int(data[0]), 'iso': iso, 'number': int(data[2]), 'ainvs': ainvs, 'jinv': jinv, 'cm': cm, 'rank': rank, 'gens': gens, 'torsion': torsion, 'torsion_structure': tor_struct, 'torsion_generators': tor_gens, 'trace_hash': trace_hash, 'equation': web_latex(E), 'bad_primes': bad_p, 'num_bad_primes': num_bad_p, 'local_data': local_data, 'semistable': semistable, 'signD': int(E.discriminant().sign()), 'heights': heights, 'aplist': E.aplist(100, python_ints=True), 'anlist': E.anlist(20, python_ints=True), 'min_quad_twist': min_quad_twist, }
class WebEC(object): """ Class for an elliptic curve over Q """ def __init__(self, dbdata): """ Arguments: - dbdata: the data from the database """ logger.debug("Constructing an instance of ECisog_class") self.__dict__.update(dbdata) # Next lines because the hyphens make trouble self.xintcoords = split_list(dbdata['x-coordinates_of_integral_points']) self.non_surjective_primes = dbdata['non-surjective_primes'] # Next lines because the python identifiers cannot start with 2 self.twoadic_index = dbdata['2adic_index'] self.twoadic_log_level = dbdata['2adic_log_level'] self.twoadic_gens = dbdata['2adic_gens'] self.twoadic_label = dbdata['2adic_label'] # All other fields are handled here self.make_curve() @staticmethod def by_label(label): """ Searches for a specific elliptic curve in the curves collection by its label, which can be either in LMFDB or Cremona format. """ try: N, iso, number = split_lmfdb_label(label) data = db_ec().find_one({"lmfdb_label" : label}) except AttributeError: try: N, iso, number = split_cremona_label(label) data = db_ec().find_one({"label" : label}) except AttributeError: return "Invalid label" # caller must catch this and raise an error if data: return WebEC(data) return "Curve not found" # caller must catch this and raise an error def make_curve(self): # To start with the data fields of self are just those from # the database. We need to reformat these. # Old version: required constructing the actual elliptic curve # E, and computing some further data about it. # New version (May 2016): extra data fields now in the # database so we do not have to construct the curve or do any # computation with it on the fly. As a failsafe the old way # is still included. data = self.data = {} try: data['ainvs'] = [int(c) for c in self.xainvs[1:-1].split(',')] except AttributeError: data['ainvs'] = [int(ai) for ai in self.ainvs] data['conductor'] = N = ZZ(self.conductor) data['j_invariant'] = QQ(str(self.jinv)) data['j_inv_factor'] = latex(0) if data['j_invariant']: # don't factor 0 data['j_inv_factor'] = latex(data['j_invariant'].factor()) data['j_inv_str'] = unicode(str(data['j_invariant'])) data['j_inv_latex'] = web_latex(data['j_invariant']) mw = self.mw = {} mw['rank'] = self.rank mw['int_points'] = '' if self.xintcoords: a1, a2, a3, a4, a6 = [ZZ(a) for a in data['ainvs']] def lift_x(x): f = ((x + a2) * x + a4) * x + a6 b = (a1*x + a3) d = (b*b + 4*f).sqrt() return (x, (-b+d)/2) mw['int_points'] = ', '.join(web_latex(lift_x(x)) for x in self.xintcoords) mw['generators'] = '' mw['heights'] = [] if self.gens: mw['generators'] = [web_latex(tuple(P)) for P in parse_points(self.gens)] mw['tor_order'] = self.torsion tor_struct = [int(c) for c in self.torsion_structure] if mw['tor_order'] == 1: mw['tor_struct'] = '\mathrm{Trivial}' mw['tor_gens'] = '' else: mw['tor_struct'] = ' \\times '.join(['\Z/{%s}\Z' % n for n in tor_struct]) mw['tor_gens'] = ', '.join(web_latex(tuple(P)) for P in parse_points(self.torsion_generators)) # try to get all the data we need from the database entry (now in self) try: data['equation'] = self.equation local_data = self.local_data badprimes = [ZZ(ld['p']) for ld in local_data] D = self.signD * prod([ld['p']**ld['ord_disc'] for ld in local_data]) data['disc'] = D Nfac = Factorization([(ZZ(ld['p']),ld['ord_cond']) for ld in local_data]) Dfac = Factorization([(ZZ(ld['p']),ld['ord_disc']) for ld in local_data], unit=ZZ(self.signD)) data['minq_D'] = minqD = self.min_quad_twist['disc'] minq_label = self.min_quad_twist['label'] data['minq_label'] = db_ec().find_one({'label':minq_label}, ['lmfdb_label'])['lmfdb_label'] data['minq_info'] = '(itself)' if minqD==1 else '(by %s)' % minqD try: data['degree'] = self.degree except AttributeError: data['degree'] =0 # invalid, but will be displayed nicely mw['heights'] = self.heights if self.number == 1: data['an'] = self.anlist data['ap'] = self.aplist else: r = db_ec().find_one({'lmfdb_iso':self.lmfdb_iso, 'number':1}, ['anlist','aplist']) data['an'] = r['anlist'] data['ap'] = r['aplist'] # otherwise fall back to computing it from the curve except AttributeError: print("Falling back to constructing E") self.E = EllipticCurve(data['ainvs']) data['equation'] = web_latex(self.E) data['disc'] = D = self.E.discriminant() Nfac = N.factor() Dfac = D.factor() bad_primes = [p for p,e in Nfac] try: data['degree'] = self.degree except AttributeError: try: data['degree'] = self.E.modular_degree() except RuntimeError: data['degree'] = 0 # invalid, but will be displayed nicely minq, minqD = self.E.minimal_quadratic_twist() data['minq_D'] = minqD if minqD == 1: data['minq_label'] = self.lmfdb_label data['minq_info'] = '(itself)' else: # This relies on the minimal twist being in the # database, which is true when the database only # contains the Cremona database. It would be a good # idea if, when the database is extended, we ensured # that for any curve included, all twists of smaller # conductor are also included. minq_ainvs = [str(c) for c in minq.ainvs()] data['minq_label'] = db_ec().find_one({'jinv':str(self.E.j_invariant()), 'ainvs': minq_ainvs},['lmfdb_label'])['lmfdb_label'] data['minq_info'] = '(by %s)' % minqD if self.gens: self.generators = [self.E(g) for g in parse_points(self.gens)] mw['heights'] = [P.height() for P in self.generators] data['an'] = self.E.anlist(20,python_ints=True) data['ap'] = self.E.aplist(100,python_ints=True) self.local_data = local_data = [] for p in bad_primes: ld = self.E.local_data(p, algorithm="generic") local_data_p = {} local_data_p['p'] = p local_data_p['cp'] = ld.tamagawa_number() local_data_p['kod'] = web_latex(ld.kodaira_symbol()).replace('$', '') local_data_p['red'] = ld.bad_reduction_type() local_data_p['ord_cond'] = ld.conductor_valuation() local_data_p['ord_disc'] = ld.discriminant_valuation() local_data_p['ord_den_j'] = max(0,-self.E.j_invariant().valuation(p)) local_data.append(local_data_p) jfac = Factorization([(ZZ(ld['p']),ld['ord_den_j']) for ld in local_data]) minq_N, minq_iso, minq_number = split_lmfdb_label(data['minq_label']) data['disc_factor'] = latex(Dfac) data['cond_factor'] =latex(Nfac) data['disc_latex'] = web_latex(D) data['cond_latex'] = web_latex(N) data['CMD'] = self.cm data['CM'] = "no" data['EndE'] = "\(\Z\)" if self.cm: data['CM'] = "yes (\(D=%s\))" % data['CMD'] if data['CMD']%4==0: d4 = ZZ(data['CMD'])//4 data['EndE'] = "\(\Z[\sqrt{%s}]\)" % d4 else: data['EndE'] = "\(\Z[(1+\sqrt{%s})/2]\)" % data['CMD'] data['ST'] = '<a href="%s">$%s$</a>' % (url_for('st.by_label', label='1.2.N(U(1))'),'N(\\mathrm{U}(1))') else: data['ST'] = '<a href="%s">$%s$</a>' % (url_for('st.by_label', label='1.2.SU(2)'),'\\mathrm{SU}(2)') data['p_adic_primes'] = [p for i,p in enumerate(sage.all.prime_range(5, 100)) if (N*data['ap'][i]) %p !=0] try: data['galois_images'] = [trim_galois_image_code(s) for s in self.galois_images] data['non_surjective_primes'] = self.non_surjective_primes except AttributeError: #print "No Galois image data" data['galois_images'] = [] data['non_surjective_primes'] = [] data['galois_data'] = [{'p': p,'image': im } for p,im in zip(data['non_surjective_primes'], data['galois_images'])] if self.twoadic_gens: from sage.matrix.all import Matrix data['twoadic_gen_matrices'] = ','.join([latex(Matrix(2,2,M)) for M in self.twoadic_gens]) data['twoadic_rouse_url'] = ROUSE_URL_PREFIX + self.twoadic_label + ".html" # Leading term of L-function & BSD data bsd = self.bsd = {} r = self.rank if r >= 2: bsd['lder_name'] = "L^{(%s)}(E,1)/%s!" % (r,r) elif r: bsd['lder_name'] = "L'(E,1)" else: bsd['lder_name'] = "L(E,1)" bsd['reg'] = self.regulator bsd['omega'] = self.real_period bsd['sha'] = int(0.1+self.sha_an) bsd['lder'] = self.special_value # Optimality (the optimal curve in the class is the curve # whose Cremona label ends in '1' except for '990h' which was # labelled wrongly long ago) if self.iso == '990h': data['Gamma0optimal'] = bool(self.number == 3) else: data['Gamma0optimal'] = bool(self.number == 1) data['p_adic_data_exists'] = False if data['Gamma0optimal']: data['p_adic_data_exists'] = (padic_db().find({'lmfdb_iso': self.lmfdb_iso}).count()) > 0 tamagawa_numbers = [ZZ(ld['cp']) for ld in local_data] cp_fac = [cp.factor() for cp in tamagawa_numbers] cp_fac = [latex(cp) if len(cp)<2 else '('+latex(cp)+')' for cp in cp_fac] bsd['tamagawa_factors'] = r'\cdot'.join(cp_fac) bsd['tamagawa_product'] = sage.misc.all.prod(tamagawa_numbers) cond, iso, num = split_lmfdb_label(self.lmfdb_label) data['newform'] = web_latex(PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True)) data['newform_label'] = self.newform_label = newform_label(cond,2,1,iso) self.newform_link = url_for("emf.render_elliptic_modular_forms", level=cond, weight=2, character=1, label=iso) self.newform_exists_in_db = is_newform_in_db(self.newform_label) self._code = None self.friends = [ ('Isogeny class ' + self.lmfdb_iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)), ('Minimal quadratic twist %s %s' % (data['minq_info'], data['minq_label']), url_for(".by_triple_label", conductor=minq_N, iso_label=minq_iso, number=minq_number)), ('All twists ', url_for(".rational_elliptic_curves", jinv=self.jinv)), ('L-function', url_for("l_functions.l_function_ec_page", label=self.lmfdb_label))] if not self.cm: if N<=300: self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso))] if N<=50: self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', label=self.lmfdb_iso))] if self.newform_exists_in_db: self.friends += [('Modular form ' + self.newform_label, self.newform_link)] self.downloads = [('Download coefficients of q-expansion', url_for(".download_EC_qexp", label=self.lmfdb_label, limit=1000)), ('Download all stored data', url_for(".download_EC_all", label=self.lmfdb_label)), ('Download Magma code', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='magma')), ('Download Sage code', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='sage')), ('Download GP code', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='gp')) ] try: self.plot = encode_plot(self.E.plot()) except AttributeError: self.plot = encode_plot(EllipticCurve(data['ainvs']).plot()) self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot self.properties = [('Label', self.lmfdb_label), (None, self.plot_link), ('Conductor', '\(%s\)' % data['conductor']), ('Discriminant', '\(%s\)' % data['disc']), ('j-invariant', '%s' % data['j_inv_latex']), ('CM', '%s' % data['CM']), ('Rank', '\(%s\)' % mw['rank']), ('Torsion Structure', '\(%s\)' % mw['tor_struct']) ] self.title = "Elliptic Curve %s (Cremona label %s)" % (self.lmfdb_label, self.label) self.bread = [('Elliptic Curves', url_for("ecnf.index")), ('$\Q$', url_for(".rational_elliptic_curves")), ('%s' % N, url_for(".by_conductor", conductor=N)), ('%s' % iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)), ('%s' % num,' ')] def code(self): if self._code == None: self.make_code_snippets() return self._code def make_code_snippets(self): # read in code.yaml from current directory: _curdir = os.path.dirname(os.path.abspath(__file__)) self._code = yaml.load(open(os.path.join(_curdir, "code.yaml"))) # Fill in placeholders for this specific curve: for lang in ['sage', 'pari', 'magma']: self._code['curve'][lang] = self._code['curve'][lang] % (self.data['ainvs'],self.label) return for k in self._code: if k != 'prompt': for lang in self._code[k]: self._code[k][lang] = self._code[k][lang].split("\n") # remove final empty line if len(self._code[k][lang][-1])==0: self._code[k][lang] = self._code[k][lang][:-1]