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 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 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 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 render_curve_webpage_by_label(label): C = lmfdb.base.getDBConnection() data = C.elliptic_curves.curves.find_one({'lmfdb_label': label}) if data is None: return elliptic_curve_jump_error(label, {}) info = {} ainvs = [int(a) for a in data['ainvs']] E = EllipticCurve(ainvs) cremona_label = data['label'] lmfdb_label = data['lmfdb_label'] N = ZZ(data['conductor']) cremona_iso_class = data['iso'] # eg '37a' lmfdb_iso_class = data['lmfdb_iso'] # eg '37.a' rank = data['rank'] try: j_invariant = QQ(str(data['jinv'])) except KeyError: j_invariant = E.j_invariant() if j_invariant == 0: j_inv_factored = latex(0) else: j_inv_factored = latex(j_invariant.factor()) jinv = unicode(str(j_invariant)) CMD = 0 CM = "no" EndE = "\(\Z\)" if E.has_cm(): CMD = E.cm_discriminant() CM = "yes (\(%s\))" % CMD if CMD % 4 == 0: d4 = ZZ(CMD) // 4 # r = d4.squarefree_part() # f = (d4//r).isqrt() # f="" if f==1 else str(f) # EndE = "\(\Z[%s\sqrt{%s}]\)"%(f,r) EndE = "\(\Z[\sqrt{%s}]\)" % (d4) else: EndE = "\(\Z[(1+\sqrt{%s})/2]\)" % CMD # plot=E.plot() discriminant = E.discriminant() xintpoints_projective = [ E.lift_x(x) for x in xintegral_point(data['x-coordinates_of_integral_points']) ] xintpoints = proj_to_aff(xintpoints_projective) if 'degree' in data: modular_degree = data['degree'] else: try: modular_degree = E.modular_degree() except RuntimeError: modular_degree = 0 # invalid, will be displayed nicely G = E.torsion_subgroup().gens() E_pari = E.pari_curve(prec=200) from sage.libs.pari.all import PariError try: minq = E.minimal_quadratic_twist()[0] except PariError: # this does occur with 164411a1 print "PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label minq = E if E == minq: minq_label = lmfdb_label else: minq_ainvs = [str(c) for c in minq.ainvs()] minq_label = C.elliptic_curves.curves.find_one({'ainvs': minq_ainvs })['lmfdb_label'] # We do not just do the following, as Sage's installed database # might not have all the curves in the LMFDB database. # minq_label = E.minimal_quadratic_twist()[0].label() if 'gens' in data: generator = parse_gens(data['gens']) if len(G) == 0: tor_struct = '\mathrm{Trivial}' tor_group = '\mathrm{Trivial}' else: tor_group = ' \\times '.join(['\Z/{%s}\Z' % a.order() for a in G]) if 'torsion_structure' in data: info['tor_structure'] = ' \\times '.join( ['\Z/{%s}\Z' % int(a) for a in data['torsion_structure']]) else: info['tor_structure'] = tor_group def trim_galois_image_code(s): return s[2:] if s[1].isdigit() else s[1:] if 'galois_images' in data: galois_images = data['galois_images'] galois_images = [trim_galois_image_code(s) for s in galois_images] non_surjective_primes = data['non-surjective_primes'] galois_data = [{ 'p': p, 'image': im } for p, im in zip(non_surjective_primes, galois_images)] info.update(data) if rank >= 2: lder_tex = "L%s(E,1)" % ("^{(" + str(rank) + ")}") elif rank == 1: lder_tex = "L%s(E,1)" % ("'" * rank) else: assert rank == 0 lder_tex = "L(E,1)" info['Gamma0optimal'] = (cremona_label[-1] == '1' if cremona_iso_class != '990h' else cremona_label[-1] == '3') info['modular_degree'] = modular_degree p_adic_data_exists = (C.elliptic_curves.padic_db.find({ 'lmfdb_iso': lmfdb_iso_class }).count()) > 0 and info['Gamma0optimal'] # Local data local_data = [] for p in N.prime_factors(): local_info = E.local_data(p, algorithm="generic") local_data.append({ 'p': p, 'tamagawa_number': local_info.tamagawa_number(), 'kodaira_symbol': web_latex(local_info.kodaira_symbol()).replace('$', ''), 'reduction_type': local_info.bad_reduction_type() }) mod_form_iso = lmfdb_label_regex.match(lmfdb_iso_class).groups()[1] tamagawa_numbers = [ E.local_data(p, algorithm="generic").tamagawa_number() for p in N.prime_factors() ] # if we use E.tamagawa_numbers() it calls E.local_data(p) which # crashes on some curves e.g. 164411a1 info.update({ 'conductor': N, 'disc_factor': latex(discriminant.factor()), 'j_invar_factor': j_inv_factored, 'label': lmfdb_label, 'cremona_label': cremona_label, 'iso_class': lmfdb_iso_class, 'cremona_iso_class': cremona_iso_class, 'equation': web_latex(E), #'f': ajax_more(E.q_eigenform, 10, 20, 50, 100, 250), 'f': web_latex(E.q_eigenform(10)), 'generators': ', '.join(web_latex(g) for g in generator) if 'gens' in data else ' ', 'lder': lder_tex, 'p_adic_primes': [ p for p in sage.all.prime_range(5, 100) if E.is_ordinary(p) and not p.divides(N) ], 'p_adic_data_exists': p_adic_data_exists, 'ainvs': format_ainvs(data['ainvs']), 'CM': CM, 'CMD': CMD, 'EndE': EndE, 'tamagawa_numbers': r' \cdot '.join(str(sage.all.factor(c)) for c in tamagawa_numbers), 'local_data': local_data, 'cond_factor': latex(N.factor()), 'galois_data': galois_data, 'xintegral_points': ', '.join(web_latex(P) for P in xintpoints), 'tor_gens': ', '.join(web_latex(eval(g)) for g in data['torsion_generators']) if False else ', '.join( web_latex(P.element().xy()) for P in list(G)) }) info['friends'] = [('Isogeny class ' + lmfdb_iso_class, url_for(".by_ec_label", label=lmfdb_iso_class)), ('Minimal quadratic twist ' + minq_label, url_for(".by_ec_label", label=minq_label)), ('All twists ', url_for(".rational_elliptic_curves", jinv=jinv)), ('L-function', url_for("l_functions.l_function_ec_page", label=lmfdb_label)), ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=lmfdb_iso_class)), ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=lmfdb_iso_class))] info['friends'].append( ('Modular form ' + lmfdb_iso_class.replace('.', '.2'), url_for("emf.render_elliptic_modular_forms", level=int(N), weight=2, character=0, label=mod_form_iso))) info['downloads'] = [('Download coeffients of q-expansion', url_for(".download_EC_qexp", label=lmfdb_label, limit=100)), ('Download all stored data', url_for(".download_EC_all", label=lmfdb_label))] # info['learnmore'] = [('Elliptic Curves', url_for(".not_yet_implemented"))] # info['plot'] = image_src(plot) info['plot'] = url_for('.plot_ec', label=lmfdb_label) properties2 = [('Label', '%s' % lmfdb_label), (None, '<img src="%s" width="200" height="150"/>' % url_for('.plot_ec', label=lmfdb_label)), ('Conductor', '\(%s\)' % N), ('Discriminant', '\(%s\)' % discriminant), ('j-invariant', '%s' % web_latex(j_invariant)), ('CM', '%s' % CM), ('Rank', '\(%s\)' % rank), ('Torsion Structure', '\(%s\)' % tor_group)] # properties.extend([ "prop %s = %s<br/>" % (_,_*1923) for _ in range(12) ]) credit = 'John Cremona and Andrew Sutherland' if info['label'] == info['cremona_label']: t = "Elliptic Curve %s" % info['label'] else: t = "Elliptic Curve %s (Cremona label %s)" % (info['label'], info['cremona_label']) bread = [('Elliptic Curves ', url_for(".rational_elliptic_curves")), ('Elliptic curves %s' % lmfdb_label, ' ')] return render_template("curve.html", properties2=properties2, credit=credit, bread=bread, title=t, info=info, friends=info['friends'], downloads=info['downloads'])
def curves(line, verbose=False): r""" Parses one line from a curves file. Returns the label and a dict containing fields with keys 'field_label', 'degree', 'signature', 'abs_disc', 'label', 'short_label', conductor_label', 'conductor_ideal', 'conductor_norm', 'iso_label', 'iso_nlabel', 'number', 'ainvs', 'jinv', 'cm', 'q_curve', 'base_change', 'torsion_order', 'torsion_structure', 'torsion_gens'; and (added May 2016): 'equation', 'local_data', 'non_min_p', 'minD' Input line fields (13): field_label conductor_label iso_label number conductor_ideal conductor_norm a1 a2 a3 a4 a6 cm base_change Sample input line: 2.0.4.1 65.18.1 a 1 [65,18,1] 65 1,1 1,1 0,1 -1,1 -1,0 0 0 """ # Parse the line and form the full label: data = split(line) if len(data) != 13: print "line %s does not have 13 fields, skipping" % line field_label = data[0] # string IQF_flag = field_label.split(".")[:2] == ['2', '0'] K = nf_lookup(field_label) if IQF_flag else None conductor_label = data[1] # string # convert label (does nothing except for imaginary quadratic) conductor_label = convert_conductor_label(field_label, conductor_label) iso_label = data[2] # string iso_nlabel = numerify_iso_label(iso_label) # int number = int(data[3]) # int short_class_label = "%s-%s" % (conductor_label, iso_label) short_label = "%s%s" % (short_class_label, str(number)) class_label = "%s-%s" % (field_label, short_class_label) label = "%s-%s" % (field_label, short_label) conductor_ideal = data[4] # string conductor_norm = int(data[5]) # int ainvs = ";".join(data[6:11]) # one string joining 5 NFelt strings cm = data[11] # int or '?' if cm != '?': cm = int(cm) # Create the field and curve to compute the j-invariant: dummy, deg, sig, abs_disc = field_data(field_label) K = nf_lookup(field_label) #print("Field %s created, gen_name = %s" % (field_label,str(K.gen()))) ainvsK = parse_ainvs(K, ainvs) # list of K-elements E = EllipticCurve(ainvsK) #print("{} created with disc = {}, N(disc)={}".format(E,K.ideal(E.discriminant()).factor(),E.discriminant().norm().factor())) j = E.j_invariant() jinv = NFelt(j) if cm == '?': cm = get_cm(j) if cm: print "cm=%s for j=%s" % (cm, j) q_curve = data[12] # 0, 1 or ?. If unknown we'll determine this below. if q_curve in ['0', '1']: # already set -- easy q_curve = bool(int(q_curve)) else: try: q_curve = is_Q_curve(E) except NotImplementedError: q_curve = '?' # Here we should check that the conductor of the constructed curve # agrees with the input conductor. N = ideal_from_string(K, conductor_ideal) NE = E.conductor() if N == "wrong" or N != NE: print( "Wrong conductor ideal {} for label {}, using actual conductor {} instead" .format(conductor_ideal, label, NE)) conductor_ideal = ideal_to_string(NE) N = NE # get torsion order, structure and generators: torgroup = E.torsion_subgroup() ntors = int(torgroup.order()) torstruct = [int(n) for n in list(torgroup.invariants())] torgens = [point_string(P.element()) for P in torgroup.gens()] # get label of elliptic curve over Q for base_change cases (a # subset of Q-curves) if True: # q_curve: now we have not precomputed Q-curve status # but still want to test for base change! if verbose: print("testing {} for base-change...".format(label)) E1list = E.descend_to(QQ) if len(E1list): base_change = [cremona_to_lmfdb(E1.label()) for E1 in E1list] if verbose: print "%s is base change of %s" % (label, base_change) else: base_change = [] # print "%s is a Q-curve, but not base-change..." % label else: base_change = [] # NB if this is not a global minimal model then local_data may # include a prime at which we have good reduction. This causes no # problems except that the bad_reduction_type is then None which # cannot be converted to an integer. The bad reduction types are # coded as (Sage) integers in {-1,0,1}. local_data = [{ 'p': ideal_to_string(ld.prime()), 'normp': str(ld.prime().norm()), 'ord_cond': int(ld.conductor_valuation()), 'ord_disc': int(ld.discriminant_valuation()), 'ord_den_j': int(max(0, -(E.j_invariant().valuation(ld.prime())))), 'red': None if ld.bad_reduction_type() == None else int(ld.bad_reduction_type()), 'kod': web_latex(ld.kodaira_symbol()).replace('$', ''), 'cp': int(ld.tamagawa_number()) } for ld in E.local_data()] non_minimal_primes = [ideal_to_string(P) for P in E.non_minimal_primes()] minD = ideal_to_string(E.minimal_discriminant_ideal()) edata = { 'field_label': field_label, 'degree': deg, 'signature': sig, 'abs_disc': abs_disc, 'class_label': class_label, 'short_class_label': short_class_label, 'label': label, 'short_label': short_label, 'conductor_label': conductor_label, 'conductor_ideal': conductor_ideal, 'conductor_norm': conductor_norm, 'iso_label': iso_label, 'iso_nlabel': iso_nlabel, 'number': number, 'ainvs': ainvs, 'jinv': jinv, 'cm': cm, 'q_curve': q_curve, 'base_change': base_change, 'torsion_order': ntors, 'torsion_structure': torstruct, 'torsion_gens': torgens, 'equation': web_latex(E), 'local_data': local_data, 'minD': minD, 'non_min_p': non_minimal_primes, } return label, edata
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 = parse_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, construct the # actual elliptic curve E, and compute some further (easy) # data about it. # # Weierstrass equation data = self.data = {} data['ainvs'] = [int(ai) for ai in self.ainvs] self.E = EllipticCurve(data['ainvs']) data['equation'] = web_latex(self.E) # conductor, j-invariant and discriminant data['conductor'] = N = ZZ(self.conductor) bad_primes = N.prime_factors() try: data['j_invariant'] = QQ(str(self.jinv)) except KeyError: data['j_invariant'] = self.E.j_invariant() data['j_inv_factor'] = latex(0) if data['j_invariant']: 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']) data['disc'] = D = self.E.discriminant() data['disc_latex'] = web_latex(data['disc']) data['disc_factor'] = latex(data['disc'].factor()) data['cond_factor'] =latex(N.factor()) data['cond_latex'] = web_latex(N) # CM and endomorphism ring 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'] # modular degree try: data['degree'] = self.degree except AttributeError: try: data['degree'] = self.E.modular_degree() except RuntimeError: data['degree'] # invalid, but will be displayed nicely # Minimal quadratic twist E_pari = self.E.pari_curve() from sage.libs.pari.all import PariError try: minq, minqD = self.E.minimal_quadratic_twist() except PariError: # this does occur with 164411a1 ec.debug("PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label) minq = self.E minqD = 1 data['minq_D'] = minqD if self.E == minq: data['minq_label'] = self.lmfdb_label data['minq_info'] = '(itself)' else: minq_ainvs = [str(c) for c in minq.ainvs()] data['minq_label'] = db_ec().find_one({'ainvs': minq_ainvs})['lmfdb_label'] data['minq_info'] = '(by %s)' % minqD minq_N, minq_iso, minq_number = split_lmfdb_label(data['minq_label']) # rational and integral points mw = self.mw = {} xintpoints_projective = [self.E.lift_x(x) for x in self.xintcoords] xintpoints = [P.xy() for P in xintpoints_projective] mw['int_points'] = ', '.join(web_latex(P) for P in xintpoints) # Generators of infinite order mw['rank'] = self.rank try: self.generators = [self.E(g) for g in parse_points(self.gens)] mw['generators'] = [web_latex(P.xy()) for P in self.generators] mw['heights'] = [P.height() for P in self.generators] except AttributeError: mw['generators'] = '' mw['heights'] = [] # Torsion subgroup: order, structure, generators 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(self.E(g).xy()) for g in parse_points(self.torsion_generators)) # Images of Galois representations 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 data['p_adic_primes'] = [p for p in sage.all.prime_range(5, 100) if self.E.is_ordinary(p) and not p.divides(N)] # Local data local_data = self.local_data = [] # if we use E.tamagawa_numbers() it calls E.local_data(p) which # used to crash on some curves e.g. 164411a1 tamagawa_numbers = [] for p in bad_primes: local_info = self.E.local_data(p, algorithm="generic") local_data_p = {} local_data_p['p'] = p local_data_p['tamagawa_number'] = local_info.tamagawa_number() tamagawa_numbers.append(ZZ(local_info.tamagawa_number())) local_data_p['kodaira_symbol'] = web_latex(local_info.kodaira_symbol()).replace('$', '') local_data_p['reduction_type'] = local_info.bad_reduction_type() local_data_p['ord_cond'] = local_info.conductor_valuation() local_data_p['ord_disc'] = local_info.discriminant_valuation() local_data_p['ord_den_j'] = max(0,-self.E.j_invariant().valuation(p)) local_data.append(local_data_p) if len(bad_primes)>1: bsd['tamagawa_factors'] = r' \cdot '.join(str(c.factor()) for c in tamagawa_numbers) else: bsd['tamagawa_factors'] = '' bsd['tamagawa_product'] = sage.misc.all.prod(tamagawa_numbers) cond, iso, num = split_lmfdb_label(self.lmfdb_label) data['newform'] = web_latex(self.E.q_eigenform(10)) self.make_code_snippets() 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)), ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso)), ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=self.lmfdb_iso)), ('Modular form ' + self.lmfdb_iso.replace('.', '.2'), url_for("emf.render_elliptic_modular_forms", level=int(N), weight=2, character=0, label=iso))] self.downloads = [('Download coeffients of q-expansion', url_for(".download_EC_qexp", label=self.lmfdb_label, limit=100)), ('Download all stored data', url_for(".download_EC_all", label=self.lmfdb_label))] self.plot = encode_plot(self.E.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 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) 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]
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]
class WebEC(object): """ Class for an elliptic curve over Q """ def __init__(self, dbdata): """ Arguments: - dbdata: the data from the database """ logger.info("Constructing an instance of ECisog_class") self.__dict__.update(dbdata) # Next lines because the hyphens make trouble self.xintcoords = parse_list(dbdata['x-coordinates_of_integral_points']) self.non_surjective_primes = dbdata['non-surjective_primes'] 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. """ print "curve label = %s" % label try: N, iso, number = lmfdb_label_regex.match(label).groups() data = db_ec().find_one({"lmfdb_label" : label}) except AttributeError: try: N, iso, number = cremona_label_regex.match(label).groups() 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, construct the # actual elliptic curve E, and compute some further (easy) # data about it. # # Weierstrass equation data = self.data = {} data['ainvs'] = [int(ai) for ai in self.ainvs] self.E = EllipticCurve(data['ainvs']) data['equation'] = web_latex(self.E) # conductor, j-invariant and discriminant data['conductor'] = N = ZZ(self.conductor) bad_primes = N.prime_factors() try: data['j_invariant'] = QQ(str(self.jinv)) except KeyError: data['j_invariant'] = self.E.j_invariant() data['j_inv_factor'] = latex(0) if data['j_invariant']: 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']) data['disc'] = self.E.discriminant() data['disc_latex'] = web_latex(data['disc']) data['disc_factor'] = latex(data['disc'].factor()) data['cond_factor'] =latex(N.factor()) data['cond_latex'] = web_latex(N) # CM and endomorphism ring data['CMD'] = 0 data['CM'] = "no" data['EndE'] = "\(\Z\)" if self.E.has_cm(): data['CMD'] = self.E.cm_discriminant() 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'] # modular degree try: data['degree'] = self.degree except AttributeError: try: data['degree'] = self.E.modular_degree() except RuntimeError: data['degree'] # invalid, but will be displayed nicely # Minimal quadratic twist E_pari = self.E.pari_curve(prec=200) from sage.libs.pari.all import PariError try: minq = self.E.minimal_quadratic_twist()[0] except PariError: # this does occur with 164411a1 ec.debug("PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label) minq = self.E if self.E == minq: data['minq_label'] = self.lmfdb_label else: minq_ainvs = [str(c) for c in minq.ainvs()] data['minq_label'] = db_ec().find_one({'ainvs': minq_ainvs})['lmfdb_label'] # rational and integral points mw = self.mw = {} xintpoints_projective = [self.E.lift_x(x) for x in self.xintcoords] xintpoints = [P.xy() for P in xintpoints_projective] mw['int_points'] = ', '.join(web_latex(P) for P in xintpoints) # Generators of infinite order mw['rank'] = self.rank try: mw['generators'] = ', '.join(web_latex(self.E(g).xy()) for g in parse_points(self.gens)) except AttributeError: mw['generators'] = '' # Torsion subgroup: order, structure, generators 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(self.E(g).xy()) for g in parse_points(self.torsion_generators)) # Images of Galois representations 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'])] # Leading term of L-function & BSD data bsd = self.bsd = {} if mw['rank'] >= 2: bsd['lder_name'] = "L^{(%s)}(E,1)" % mw['rank'] elif mw['rank']: 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 data['p_adic_primes'] = [p for p in sage.all.prime_range(5, 100) if self.E.is_ordinary(p) and not p.divides(N)] # Local data local_data = self.local_data = [] # if we use E.tamagawa_numbers() it calls E.local_data(p) which # crashes on some curves e.g. 164411a1 tamagawa_numbers = [] for p in bad_primes: local_info = self.E.local_data(p, algorithm="generic") local_data_p = {} local_data_p['p'] = p local_data_p['tamagawa_number'] = local_info.tamagawa_number() tamagawa_numbers.append(ZZ(local_info.tamagawa_number())) local_data_p['kodaira_symbol'] = web_latex(local_info.kodaira_symbol()).replace('$', '') local_data_p['reduction_type'] = local_info.bad_reduction_type() local_data.append(local_data_p) bsd['tamagawa_factors'] = r' \cdot '.join(str(c.factor()) for c in tamagawa_numbers) bsd['tamagawa_product'] = sage.misc.all.prod(tamagawa_numbers) mod_form_iso = lmfdb_label_regex.match(self.lmfdb_iso).groups()[1] data['newform'] = web_latex(self.E.q_eigenform(10)) self.friends = [ ('Isogeny class ' + self.lmfdb_iso, url_for(".by_ec_label", label=self.lmfdb_iso)), ('Minimal quadratic twist ' + data['minq_label'], url_for(".by_ec_label", label=data['minq_label'])), ('All twists ', url_for(".rational_elliptic_curves", jinv=self.jinv)), ('L-function', url_for("l_functions.l_function_ec_page", label=self.lmfdb_label)), ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso)), ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=self.lmfdb_iso)), ('Modular form ' + self.lmfdb_iso.replace('.', '.2'), url_for("emf.render_elliptic_modular_forms", level=int(N), weight=2, character=0, label=mod_form_iso))] self.downloads = [('Download coeffients of q-expansion', url_for(".download_EC_qexp", label=self.lmfdb_label, limit=100)), ('Download all stored data', url_for(".download_EC_all", label=self.lmfdb_label))] self.plot = encode_plot(self.E.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']) ] if self.lmfdb_iso == self.iso: self.title = "Elliptic Curve %s" % self.lmfdb_label else: self.title = "Elliptic Curve %s (Cremona label %s)" % (self.lmfdb_label, self.label) self.bread = [('Elliptic Curves ', url_for(".rational_elliptic_curves")), ('isogeny class %s' % self.lmfdb_iso, ' ')]
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, construct the # actual elliptic curve E, and compute some further (easy) # data about it. # # Weierstrass equation data = self.data = {} data["ainvs"] = [int(ai) for ai in self.ainvs] self.E = EllipticCurve(data["ainvs"]) data["equation"] = web_latex(self.E) # conductor, j-invariant and discriminant data["conductor"] = N = ZZ(self.conductor) bad_primes = N.prime_factors() try: data["j_invariant"] = QQ(str(self.jinv)) except KeyError: data["j_invariant"] = self.E.j_invariant() data["j_inv_factor"] = latex(0) if data["j_invariant"]: 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"]) data["disc"] = D = self.E.discriminant() data["disc_latex"] = web_latex(data["disc"]) data["disc_factor"] = latex(data["disc"].factor()) data["cond_factor"] = latex(N.factor()) data["cond_latex"] = web_latex(N) # CM and endomorphism ring 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)") # modular degree try: data["degree"] = self.degree except AttributeError: try: data["degree"] = self.E.modular_degree() except RuntimeError: data["degree"] # invalid, but will be displayed nicely # Minimal quadratic twist E_pari = self.E.pari_curve() from sage.libs.pari.all import PariError try: minq, minqD = self.E.minimal_quadratic_twist() except PariError: # this does occur with 164411a1 ec.debug("PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label) minq = self.E minqD = 1 data["minq_D"] = minqD if self.E == minq: data["minq_label"] = self.lmfdb_label data["minq_info"] = "(itself)" else: 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" ] data["minq_info"] = "(by %s)" % minqD minq_N, minq_iso, minq_number = split_lmfdb_label(data["minq_label"]) # rational and integral points mw = self.mw = {} xintpoints_projective = [self.E.lift_x(x) for x in self.xintcoords] xintpoints = [P.xy() for P in xintpoints_projective] mw["int_points"] = ", ".join(web_latex(P) for P in xintpoints) # Generators of infinite order mw["rank"] = self.rank try: self.generators = [self.E(g) for g in parse_points(self.gens)] mw["generators"] = [web_latex(P.xy()) for P in self.generators] mw["heights"] = [P.height() for P in self.generators] except AttributeError: mw["generators"] = "" mw["heights"] = [] # Torsion subgroup: order, structure, generators 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(self.E(g).xy()) for g in parse_points(self.torsion_generators)) # Images of Galois representations 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 data["p_adic_primes"] = [p for p in sage.all.prime_range(5, 100) if self.E.is_ordinary(p) and not p.divides(N)] # Local data local_data = self.local_data = [] # if we use E.tamagawa_numbers() it calls E.local_data(p) which # used to crash on some curves e.g. 164411a1 tamagawa_numbers = [] for p in bad_primes: local_info = self.E.local_data(p, algorithm="generic") local_data_p = {} local_data_p["p"] = p local_data_p["tamagawa_number"] = local_info.tamagawa_number() tamagawa_numbers.append(ZZ(local_info.tamagawa_number())) local_data_p["kodaira_symbol"] = web_latex(local_info.kodaira_symbol()).replace("$", "") local_data_p["reduction_type"] = local_info.bad_reduction_type() local_data_p["ord_cond"] = local_info.conductor_valuation() local_data_p["ord_disc"] = local_info.discriminant_valuation() local_data_p["ord_den_j"] = max(0, -self.E.j_invariant().valuation(p)) local_data.append(local_data_p) 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(self.E.q_eigenform(10)) 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) 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 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=100)), ("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" ), ), ] self.plot = encode_plot(self.E.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) 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 curves(line, verbose=False): r""" Parses one line from a curves file. Returns the label and a dict containing fields with keys 'field_label', 'degree', 'signature', 'abs_disc', 'label', 'short_label', conductor_label', 'conductor_ideal', 'conductor_norm', 'iso_label', 'iso_nlabel', 'number', 'ainvs', 'jinv', 'cm', 'q_curve', 'base_change', 'torsion_order', 'torsion_structure', 'torsion_gens'; and (added May 2016): 'equation', 'local_data', 'non_min_p', 'minD' Input line fields (13): field_label conductor_label iso_label number conductor_ideal conductor_norm a1 a2 a3 a4 a6 cm base_change Sample input line: 2.0.4.1 65.18.1 a 1 [65,18,1] 65 1,1 1,1 0,1 -1,1 -1,0 0 0 """ # Parse the line and form the full label: data = split(line) if len(data) != 13: print "line %s does not have 13 fields, skipping" % line field_label = data[0] # string IQF_flag = field_label.split(".")[:2] == ['2','0'] K = nf_lookup(field_label) if IQF_flag else None conductor_label = data[1] # string # convert label (does nothing except for imaginary quadratic) conductor_label = convert_conductor_label(field_label, conductor_label) iso_label = data[2] # string iso_nlabel = numerify_iso_label(iso_label) # int number = int(data[3]) # int short_class_label = "%s-%s" % (conductor_label, iso_label) short_label = "%s%s" % (short_class_label, str(number)) class_label = "%s-%s" % (field_label, short_class_label) label = "%s-%s" % (field_label, short_label) conductor_ideal = data[4] # string conductor_norm = int(data[5]) # int ainvs = ";".join(data[6:11]) # one string joining 5 NFelt strings cm = data[11] # int or '?' if cm != '?': cm = int(cm) q_curve = (data[12] == '1') # bool # Create the field and curve to compute the j-invariant: dummy, deg, sig, abs_disc = field_data(field_label) K = nf_lookup(field_label) #print("Field %s created, gen_name = %s" % (field_label,str(K.gen()))) ainvsK = parse_ainvs(K,ainvs) # list of K-elements E = EllipticCurve(ainvsK) #print("{} created with disc = {}, N(disc)={}".format(E,K.ideal(E.discriminant()).factor(),E.discriminant().norm().factor())) j = E.j_invariant() jinv = NFelt(j) if cm == '?': cm = get_cm(j) if cm: print "cm=%s for j=%s" % (cm, j) # Here we should check that the conductor of the constructed curve # agrees with the input conductor. N = ideal_from_string(K,conductor_ideal) NE = E.conductor() if N=="wrong" or N!=NE: print("Wrong conductor ideal {} for label {}, using actual conductor {} instead".format(conductor_ideal,label,NE)) conductor_ideal = ideal_to_string(NE) N = NE # get torsion order, structure and generators: torgroup = E.torsion_subgroup() ntors = int(torgroup.order()) torstruct = [int(n) for n in list(torgroup.invariants())] torgens = [point_string(P.element()) for P in torgroup.gens()] # get label of elliptic curve over Q for base_change cases (a # subset of Q-curves) if True: # q_curve: now we have not precomputed Q-curve status # but still want to test for base change! if verbose: print("testing {} for base-change...".format(label)) E1list = E.descend_to(QQ) if len(E1list): base_change = [cremona_to_lmfdb(E1.label()) for E1 in E1list] if verbose: print "%s is base change of %s" % (label, base_change) else: base_change = [] # print "%s is a Q-curve, but not base-change..." % label else: base_change = [] # NB if this is not a global minimal model then local_data may # include a prime at which we have good reduction. This causes no # problems except that the bad_reduction_type is then None which # cannot be converted to an integer. The bad reduction types are # coded as (Sage) integers in {-1,0,1}. local_data = [{'p': ideal_to_string(ld.prime()), 'normp': str(ld.prime().norm()), 'ord_cond':int(ld.conductor_valuation()), 'ord_disc':int(ld.discriminant_valuation()), 'ord_den_j':int(max(0,-(E.j_invariant().valuation(ld.prime())))), 'red':None if ld.bad_reduction_type()==None else int(ld.bad_reduction_type()), 'kod':web_latex(ld.kodaira_symbol()).replace('$',''), 'cp':int(ld.tamagawa_number())} for ld in E.local_data()] non_minimal_primes = [ideal_to_string(P) for P in E.non_minimal_primes()] minD = ideal_to_string(E.minimal_discriminant_ideal()) edata = { 'field_label': field_label, 'degree': deg, 'signature': sig, 'abs_disc': abs_disc, 'class_label': class_label, 'short_class_label': short_class_label, 'label': label, 'short_label': short_label, 'conductor_label': conductor_label, 'conductor_ideal': conductor_ideal, 'conductor_norm': conductor_norm, 'iso_label': iso_label, 'iso_nlabel': iso_nlabel, 'number': number, 'ainvs': ainvs, 'jinv': jinv, 'cm': cm, 'q_curve': q_curve, 'base_change': base_change, 'torsion_order': ntors, 'torsion_structure': torstruct, 'torsion_gens': torgens, 'equation': web_latex(E), 'local_data': local_data, 'minD': minD, 'non_min_p': non_minimal_primes, } return label, edata
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 = parse_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, construct the # actual elliptic curve E, and compute some further (easy) # data about it. # # Weierstrass equation data = self.data = {} data['ainvs'] = [int(ai) for ai in self.ainvs] self.E = EllipticCurve(data['ainvs']) data['equation'] = web_latex(self.E) # conductor, j-invariant and discriminant data['conductor'] = N = ZZ(self.conductor) bad_primes = N.prime_factors() try: data['j_invariant'] = QQ(str(self.jinv)) except KeyError: data['j_invariant'] = self.E.j_invariant() data['j_inv_factor'] = latex(0) if data['j_invariant']: 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']) data['disc'] = D = self.E.discriminant() data['disc_latex'] = web_latex(data['disc']) data['disc_factor'] = latex(data['disc'].factor()) data['cond_factor'] = latex(N.factor()) data['cond_latex'] = web_latex(N) # CM and endomorphism ring 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'] # modular degree try: data['degree'] = self.degree except AttributeError: try: data['degree'] = self.E.modular_degree() except RuntimeError: data['degree'] # invalid, but will be displayed nicely # Minimal quadratic twist E_pari = self.E.pari_curve() from sage.libs.pari.all import PariError try: minq, minqD = self.E.minimal_quadratic_twist() except PariError: # this does occur with 164411a1 ec.debug( "PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label) minq = self.E minqD = 1 data['minq_D'] = minqD if self.E == minq: data['minq_label'] = self.lmfdb_label data['minq_info'] = '(itself)' else: minq_ainvs = [str(c) for c in minq.ainvs()] data['minq_label'] = db_ec().find_one({'ainvs': minq_ainvs})['lmfdb_label'] data['minq_info'] = '(by %s)' % minqD minq_N, minq_iso, minq_number = split_lmfdb_label(data['minq_label']) # rational and integral points mw = self.mw = {} xintpoints_projective = [self.E.lift_x(x) for x in self.xintcoords] xintpoints = [P.xy() for P in xintpoints_projective] mw['int_points'] = ', '.join(web_latex(P) for P in xintpoints) # Generators of infinite order mw['rank'] = self.rank try: self.generators = [self.E(g) for g in parse_points(self.gens)] mw['generators'] = [web_latex(P.xy()) for P in self.generators] mw['heights'] = [P.height() for P in self.generators] except AttributeError: mw['generators'] = '' mw['heights'] = [] # Torsion subgroup: order, structure, generators 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(self.E(g).xy()) for g in parse_points(self.torsion_generators)) # Images of Galois representations 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 data['p_adic_primes'] = [ p for p in sage.all.prime_range(5, 100) if self.E.is_ordinary(p) and not p.divides(N) ] # Local data local_data = self.local_data = [] # if we use E.tamagawa_numbers() it calls E.local_data(p) which # used to crash on some curves e.g. 164411a1 tamagawa_numbers = [] for p in bad_primes: local_info = self.E.local_data(p, algorithm="generic") local_data_p = {} local_data_p['p'] = p local_data_p['tamagawa_number'] = local_info.tamagawa_number() tamagawa_numbers.append(ZZ(local_info.tamagawa_number())) local_data_p['kodaira_symbol'] = web_latex( local_info.kodaira_symbol()).replace('$', '') local_data_p['reduction_type'] = local_info.bad_reduction_type() local_data_p['ord_cond'] = local_info.conductor_valuation() local_data_p['ord_disc'] = local_info.discriminant_valuation() local_data_p['ord_den_j'] = max(0, -self.E.j_invariant().valuation(p)) local_data.append(local_data_p) 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(self.E.q_eigenform(10)) self.make_code_snippets() 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)), ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso)), ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=self.lmfdb_iso)), ('Modular form ' + self.lmfdb_iso.replace('.', '.2'), url_for("emf.render_elliptic_modular_forms", level=int(N), weight=2, character=1, label=iso))] self.downloads = [('Download coefficients of q-expansion', url_for(".download_EC_qexp", label=self.lmfdb_label, limit=100)), ('Download all stored data', url_for(".download_EC_all", label=self.lmfdb_label))] self.plot = encode_plot(self.E.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 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) 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]
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]
def render_curve_webpage_by_label(label): C = lmfdb.base.getDBConnection() data = C.elliptic_curves.curves.find_one({'lmfdb_label': label}) if data is None: return elliptic_curve_jump_error(label, {}) info = {} ainvs = [int(a) for a in data['ainvs']] E = EllipticCurve(ainvs) cremona_label = data['label'] lmfdb_label = data['lmfdb_label'] N = ZZ(data['conductor']) cremona_iso_class = data['iso'] # eg '37a' lmfdb_iso_class = data['lmfdb_iso'] # eg '37.a' rank = data['rank'] try: j_invariant = QQ(str(data['jinv'])) except KeyError: j_invariant = E.j_invariant() if j_invariant == 0: j_inv_factored = latex(0) else: j_inv_factored = latex(j_invariant.factor()) jinv = unicode(str(j_invariant)) CMD = 0 CM = "no" EndE = "\(\Z\)" if E.has_cm(): CMD = E.cm_discriminant() CM = "yes (\(%s\))"%CMD if CMD%4==0: d4 = ZZ(CMD)//4 # r = d4.squarefree_part() # f = (d4//r).isqrt() # f="" if f==1 else str(f) # EndE = "\(\Z[%s\sqrt{%s}]\)"%(f,r) EndE = "\(\Z[\sqrt{%s}]\)"%(d4) else: EndE = "\(\Z[(1+\sqrt{%s})/2]\)"%CMD # plot=E.plot() discriminant = E.discriminant() xintpoints_projective = [E.lift_x(x) for x in xintegral_point(data['x-coordinates_of_integral_points'])] xintpoints = proj_to_aff(xintpoints_projective) if 'degree' in data: modular_degree = data['degree'] else: try: modular_degree = E.modular_degree() except RuntimeError: modular_degree = 0 # invalid, will be displayed nicely G = E.torsion_subgroup().gens() minq = E.minimal_quadratic_twist()[0] if E == minq: minq_label = lmfdb_label else: minq_ainvs = [str(c) for c in minq.ainvs()] minq_label = C.elliptic_curves.curves.find_one({'ainvs': minq_ainvs})['lmfdb_label'] # We do not just do the following, as Sage's installed database # might not have all the curves in the LMFDB database. # minq_label = E.minimal_quadratic_twist()[0].label() if 'gens' in data: generator = parse_gens(data['gens']) if len(G) == 0: tor_struct = '\mathrm{Trivial}' tor_group = '\mathrm{Trivial}' else: tor_group = ' \\times '.join(['\Z/{%s}\Z' % a.order() for a in G]) if 'torsion_structure' in data: info['tor_structure'] = ' \\times '.join(['\Z/{%s}\Z' % int(a) for a in data['torsion_structure']]) else: info['tor_structure'] = tor_group info.update(data) if rank >= 2: lder_tex = "L%s(E,1)" % ("^{(" + str(rank) + ")}") elif rank == 1: lder_tex = "L%s(E,1)" % ("'" * rank) else: assert rank == 0 lder_tex = "L(E,1)" info['Gamma0optimal'] = ( cremona_label[-1] == '1' if cremona_iso_class != '990h' else cremona_label[-1] == '3') info['modular_degree'] = modular_degree p_adic_data_exists = (C.elliptic_curves.padic_db.find( {'lmfdb_iso': lmfdb_iso_class}).count()) > 0 and info['Gamma0optimal'] # Local data local_data = [] for p in N.prime_factors(): local_info = E.local_data(p) local_data.append({'p': p, 'tamagawa_number': local_info.tamagawa_number(), 'kodaira_symbol': web_latex(local_info.kodaira_symbol()).replace('$', ''), 'reduction_type': local_info.bad_reduction_type() }) mod_form_iso = lmfdb_label_regex.match(lmfdb_iso_class).groups()[1] info.update({ 'conductor': N, 'disc_factor': latex(discriminant.factor()), 'j_invar_factor': j_inv_factored, 'label': lmfdb_label, 'cremona_label': cremona_label, 'iso_class': lmfdb_iso_class, 'cremona_iso_class': cremona_iso_class, 'equation': web_latex(E), #'f': ajax_more(E.q_eigenform, 10, 20, 50, 100, 250), 'f': web_latex(E.q_eigenform(10)), 'generators': ', '.join(web_latex(g) for g in generator) if 'gens' in data else ' ', 'lder': lder_tex, 'p_adic_primes': [p for p in sage.all.prime_range(5, 100) if E.is_ordinary(p) and not p.divides(N)], 'p_adic_data_exists': p_adic_data_exists, 'ainvs': format_ainvs(data['ainvs']), 'CM': CM, 'CMD': CMD, 'EndE': EndE, 'tamagawa_numbers': r' \cdot '.join(str(sage.all.factor(c)) for c in E.tamagawa_numbers()), 'local_data': local_data, 'cond_factor': latex(N.factor()), 'xintegral_points': ', '.join(web_latex(P) for P in xintpoints), 'tor_gens': ', '.join(web_latex(eval(g)) for g in data['torsion_generators']) if False else ', '.join(web_latex(P.element().xy()) for P in list(G)) }) info['friends'] = [ ('Isogeny class ' + lmfdb_iso_class, "/EllipticCurve/Q/%s" % lmfdb_iso_class), ('Minimal quadratic twist ' + minq_label, "/EllipticCurve/Q/%s" % minq_label), ('All twists ', url_for("rational_elliptic_curves", jinv=jinv)), ('L-function', url_for("l_functions.l_function_ec_page", label=lmfdb_label)), ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=lmfdb_iso_class)), ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=lmfdb_iso_class))] info['friends'].append(('Modular form ' + lmfdb_iso_class.replace('.', '.2'), url_for( "emf.render_elliptic_modular_forms", level=int(N), weight=2, character=0, label=mod_form_iso))) info['downloads'] = [('Download coeffients of q-expansion', url_for("download_EC_qexp", label=lmfdb_label, limit=100)), ('Download all stored data', url_for("download_EC_all", label=lmfdb_label))] # info['learnmore'] = [('Elliptic Curves', url_for("not_yet_implemented"))] # info['plot'] = image_src(plot) info['plot'] = url_for('plot_ec', label=lmfdb_label) properties2 = [('Label', '%s' % lmfdb_label), (None, '<img src="%s" width="200" height="150"/>' % url_for( 'plot_ec', label=lmfdb_label)), ('Conductor', '\(%s\)' % N), ('Discriminant', '\(%s\)' % discriminant), ('j-invariant', '%s' % web_latex(j_invariant)), ('CM', '%s' % CM), ('Rank', '\(%s\)' % rank), ('Torsion Structure', '\(%s\)' % tor_group) ] # properties.extend([ "prop %s = %s<br/>" % (_,_*1923) for _ in range(12) ]) credit = 'John Cremona' if info['label'] == info['cremona_label']: t = "Elliptic Curve %s" % info['label'] else: t = "Elliptic Curve %s (Cremona label %s)" % (info['label'], info['cremona_label']) bread = [('Elliptic Curves ', url_for("rational_elliptic_curves")), ('Elliptic curves %s' % lmfdb_label, ' ')] return render_template("elliptic_curve/elliptic_curve.html", properties2=properties2, credit=credit, bread=bread, title=t, info=info, friends=info['friends'], downloads=info['downloads'])
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, }
def render_curve_webpage_by_label(label): C = lmfdb.base.getDBConnection() data = C.elliptic_curves.curves.find_one({"lmfdb_label": label}) if data is None: return elliptic_curve_jump_error(label, {}) info = {} ainvs = [int(a) for a in data["ainvs"]] E = EllipticCurve(ainvs) cremona_label = data["label"] lmfdb_label = data["lmfdb_label"] N = ZZ(data["conductor"]) cremona_iso_class = data["iso"] # eg '37a' lmfdb_iso_class = data["lmfdb_iso"] # eg '37.a' rank = data["rank"] try: j_invariant = QQ(str(data["jinv"])) except KeyError: j_invariant = E.j_invariant() if j_invariant == 0: j_inv_factored = latex(0) else: j_inv_factored = latex(j_invariant.factor()) jinv = unicode(str(j_invariant)) CMD = 0 CM = "no" EndE = "\(\Z\)" if E.has_cm(): CMD = E.cm_discriminant() CM = "yes (\(%s\))" % CMD if CMD % 4 == 0: d4 = ZZ(CMD) // 4 # r = d4.squarefree_part() # f = (d4//r).isqrt() # f="" if f==1 else str(f) # EndE = "\(\Z[%s\sqrt{%s}]\)"%(f,r) EndE = "\(\Z[\sqrt{%s}]\)" % (d4) else: EndE = "\(\Z[(1+\sqrt{%s})/2]\)" % CMD # plot=E.plot() discriminant = E.discriminant() xintpoints_projective = [E.lift_x(x) for x in xintegral_point(data["x-coordinates_of_integral_points"])] xintpoints = proj_to_aff(xintpoints_projective) if "degree" in data: modular_degree = data["degree"] else: try: modular_degree = E.modular_degree() except RuntimeError: modular_degree = 0 # invalid, will be displayed nicely G = E.torsion_subgroup().gens() E_pari = E.pari_curve(prec=200) from sage.libs.pari.all import PariError try: minq = E.minimal_quadratic_twist()[0] except PariError: # this does occur with 164411a1 print "PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label minq = E if E == minq: minq_label = lmfdb_label else: minq_ainvs = [str(c) for c in minq.ainvs()] minq_label = C.elliptic_curves.curves.find_one({"ainvs": minq_ainvs})["lmfdb_label"] # We do not just do the following, as Sage's installed database # might not have all the curves in the LMFDB database. # minq_label = E.minimal_quadratic_twist()[0].label() if "gens" in data: generator = parse_gens(data["gens"]) if len(G) == 0: tor_struct = "\mathrm{Trivial}" tor_group = "\mathrm{Trivial}" else: tor_group = " \\times ".join(["\Z/{%s}\Z" % a.order() for a in G]) if "torsion_structure" in data: info["tor_structure"] = " \\times ".join(["\Z/{%s}\Z" % int(a) for a in data["torsion_structure"]]) else: info["tor_structure"] = tor_group info.update(data) if rank >= 2: lder_tex = "L%s(E,1)" % ("^{(" + str(rank) + ")}") elif rank == 1: lder_tex = "L%s(E,1)" % ("'" * rank) else: assert rank == 0 lder_tex = "L(E,1)" info["Gamma0optimal"] = cremona_label[-1] == "1" if cremona_iso_class != "990h" else cremona_label[-1] == "3" info["modular_degree"] = modular_degree p_adic_data_exists = (C.elliptic_curves.padic_db.find({"lmfdb_iso": lmfdb_iso_class}).count()) > 0 and info[ "Gamma0optimal" ] # Local data local_data = [] for p in N.prime_factors(): local_info = E.local_data(p, algorithm="generic") local_data.append( { "p": p, "tamagawa_number": local_info.tamagawa_number(), "kodaira_symbol": web_latex(local_info.kodaira_symbol()).replace("$", ""), "reduction_type": local_info.bad_reduction_type(), } ) mod_form_iso = lmfdb_label_regex.match(lmfdb_iso_class).groups()[1] tamagawa_numbers = [E.local_data(p, algorithm="generic").tamagawa_number() for p in N.prime_factors()] # if we use E.tamagawa_numbers() it calls E.local_data(p) which # crashes on some curves e.g. 164411a1 info.update( { "conductor": N, "disc_factor": latex(discriminant.factor()), "j_invar_factor": j_inv_factored, "label": lmfdb_label, "cremona_label": cremona_label, "iso_class": lmfdb_iso_class, "cremona_iso_class": cremona_iso_class, "equation": web_latex(E), #'f': ajax_more(E.q_eigenform, 10, 20, 50, 100, 250), "f": web_latex(E.q_eigenform(10)), "generators": ", ".join(web_latex(g) for g in generator) if "gens" in data else " ", "lder": lder_tex, "p_adic_primes": [p for p in sage.all.prime_range(5, 100) if E.is_ordinary(p) and not p.divides(N)], "p_adic_data_exists": p_adic_data_exists, "ainvs": format_ainvs(data["ainvs"]), "CM": CM, "CMD": CMD, "EndE": EndE, "tamagawa_numbers": r" \cdot ".join(str(sage.all.factor(c)) for c in tamagawa_numbers), "local_data": local_data, "cond_factor": latex(N.factor()), "xintegral_points": ", ".join(web_latex(P) for P in xintpoints), "tor_gens": ", ".join(web_latex(eval(g)) for g in data["torsion_generators"]) if False else ", ".join(web_latex(P.element().xy()) for P in list(G)), } ) info["friends"] = [ ("Isogeny class " + lmfdb_iso_class, "/EllipticCurve/Q/%s" % lmfdb_iso_class), ("Minimal quadratic twist " + minq_label, "/EllipticCurve/Q/%s" % minq_label), ("All twists ", url_for("rational_elliptic_curves", jinv=jinv)), ("L-function", url_for("l_functions.l_function_ec_page", label=lmfdb_label)), ( "Symmetric square L-function", url_for("l_functions.l_function_ec_sym_page", power="2", label=lmfdb_iso_class), ), ( "Symmetric 4th power L-function", url_for("l_functions.l_function_ec_sym_page", power="4", label=lmfdb_iso_class), ), ] info["friends"].append( ( "Modular form " + lmfdb_iso_class.replace(".", ".2"), url_for("emf.render_elliptic_modular_forms", level=int(N), weight=2, character=0, label=mod_form_iso), ) ) info["downloads"] = [ ("Download coeffients of q-expansion", url_for("download_EC_qexp", label=lmfdb_label, limit=100)), ("Download all stored data", url_for("download_EC_all", label=lmfdb_label)), ] # info['learnmore'] = [('Elliptic Curves', url_for("not_yet_implemented"))] # info['plot'] = image_src(plot) info["plot"] = url_for("plot_ec", label=lmfdb_label) properties2 = [ ("Label", "%s" % lmfdb_label), (None, '<img src="%s" width="200" height="150"/>' % url_for("plot_ec", label=lmfdb_label)), ("Conductor", "\(%s\)" % N), ("Discriminant", "\(%s\)" % discriminant), ("j-invariant", "%s" % web_latex(j_invariant)), ("CM", "%s" % CM), ("Rank", "\(%s\)" % rank), ("Torsion Structure", "\(%s\)" % tor_group), ] # properties.extend([ "prop %s = %s<br/>" % (_,_*1923) for _ in range(12) ]) credit = "John Cremona" if info["label"] == info["cremona_label"]: t = "Elliptic Curve %s" % info["label"] else: t = "Elliptic Curve %s (Cremona label %s)" % (info["label"], info["cremona_label"]) bread = [("Elliptic Curves ", url_for("rational_elliptic_curves")), ("Elliptic curves %s" % lmfdb_label, " ")] return render_template( "elliptic_curve/elliptic_curve.html", properties2=properties2, credit=credit, bread=bread, title=t, info=info, friends=info["friends"], downloads=info["downloads"], )