def name_and_object_from_url(url): url_split = url.split("/") name = None obj_exists = False if url_split[0] == "EllipticCurve": if url_split[1] == 'Q': # EllipticCurve/Q/341641/a label_isogeny_class = ".".join(url_split[-2:]) # count doesn't honor limit! obj_exists = db.ec_curves.exists( {"lmfdb_iso": label_isogeny_class}) else: # EllipticCurve/2.2.140.1/14.1/a label_isogeny_class = "-".join(url_split[-3:]) obj_exists = db.ec_nfcurves.exists( {"class_label": label_isogeny_class}) name = 'Isogeny class ' + label_isogeny_class elif url_split[0] == "ModularForm": if url_split[1] == 'GL2': if url_split[2] == 'Q' and url_split[3] == 'holomorphic': # ModularForm/GL2/Q/holomorphic/14/2/1/a full_label = ".".join(url_split[-4:]) name = 'Modular form ' + full_label obj_exists = is_newform_in_db(full_label) elif url_split[2] == 'TotallyReal': # ModularForm/GL2/TotallyReal/2.2.140.1/holomorphic/2.2.140.1-14.1-a label = url_split[-1] name = 'Hilbert modular form ' + label obj_exists = is_hmf_in_db(label) elif url_split[2] == 'ImaginaryQuadratic': # ModularForm/GL2/ImaginaryQuadratic/2.0.4.1/98.1/a label = '-'.join(url_split[-3:]) name = 'Bianchi modular form ' + label obj_exists = is_bmf_in_db(label) return name, obj_exists
def name_and_object_from_url(url): url_split = url.split("/"); name = None; obj_exists = False; if url_split[0] == "EllipticCurve": if url_split[1] == 'Q': # EllipticCurve/Q/341641/a label_isogeny_class = ".".join(url_split[-2:]); # count doesn't honor limit! obj_exists = db.ec_curves.exists({"lmfdb_iso" : label_isogeny_class}) else: # EllipticCurve/2.2.140.1/14.1/a label_isogeny_class = "-".join(url_split[-3:]); obj_exists = db.ec_nfcurves.exists({"class_label" : label_isogeny_class}) name = 'Isogeny class ' + label_isogeny_class; elif url_split[0] == "ModularForm": if url_split[1] == 'GL2': if url_split[2] == 'Q' and url_split[3] == 'holomorphic': # ModularForm/GL2/Q/holomorphic/14/2/1/a full_label = ".".join(url_split[-4:]) name = 'Modular form ' + full_label; obj_exists = is_newform_in_db(full_label); elif url_split[2] == 'TotallyReal': # ModularForm/GL2/TotallyReal/2.2.140.1/holomorphic/2.2.140.1-14.1-a label = url_split[-1]; name = 'Hilbert modular form ' + label; obj_exists = is_hmf_in_db(label); elif url_split[2] == 'ImaginaryQuadratic': # ModularForm/GL2/ImaginaryQuadratic/2.0.4.1/98.1/a label = '-'.join(url_split[-3:]) name = 'Bianchi modular form ' + label; obj_exists = is_bmf_in_db(label); return name, obj_exists
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 make_class(self): self.CM = self.cm N, iso, number = split_lmfdb_label(self.lmfdb_iso) # Extract the size of the isogeny class from the database ncurves = self.class_size # Create a list of the curves in the class from the database self.curves = [db_ec().find_one({'iso':self.iso, 'lmfdb_number': i+1}) for i in range(ncurves)] # Set optimality flags. The optimal curve is number 1 except # in one case which is labeled differently in the Cremona tables for c in self.curves: c['optimal'] = (c['number']==(3 if self.label == '990h' else 1)) c['ai'] = parse_ainvs(c['xainvs']) c['url'] = url_for(".by_triple_label", conductor=N, iso_label=iso, number=c['lmfdb_number']) from sage.matrix.all import Matrix self.isogeny_matrix = Matrix(self.isogeny_matrix) self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix)) # Create isogeny graph: self.graph = make_graph(self.isogeny_matrix) P = self.graph.plot(edge_labels=True) self.graph_img = encode_plot(P) self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img self.newform = web_latex(PowerSeriesRing(QQ, 'q')(self.anlist, 20, check=True)) self.newform_label = newform_label(N,2,1,iso) self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=1, label=iso) self.newform_exists_in_db = is_newform_in_db(self.newform_label) self.lfunction_link = url_for("l_functions.l_function_ec_page", conductor_label = N, isogeny_class_label = iso) self.friends = [('L-function', self.lfunction_link)] if not self.CM: self.CM = "no" if int(N)<=300: self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', conductor = N, isogeny = iso))] if int(N)<=50: self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', conductor = N, isogeny = iso))] if self.newform_exists_in_db: self.friends += [('Modular form ' + self.newform_label, self.newform_link)] self.properties = [('Label', self.lmfdb_iso), ('Number of curves', str(ncurves)), ('Conductor', '\(%s\)' % N), ('CM', '%s' % self.CM), ('Rank', '\(%s\)' % self.rank), ('Graph', ''),(None, self.graph_link) ] self.downloads = [('Download coefficients of newform', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=1000)), ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))] if self.lmfdb_iso == self.iso: self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso else: self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso) self.bread = [('Elliptic Curves', url_for("ecnf.index")), ('$\Q$', url_for(".rational_elliptic_curves")), ('%s' % N, url_for(".by_conductor", conductor=N)), ('%s' % iso, ' ')] self.code = {} self.code['show'] = {'sage':''} # use default show names self.code['class'] = {'sage':'E = EllipticCurve("%s1")\n'%(self.lmfdb_iso) + 'E.isogeny_class()\n'} self.code['curves'] = {'sage':'E.isogeny_class().curves'} self.code['rank'] = {'sage':'E.rank()'} self.code['q_eigenform'] = {'sage':'E.q_eigenform(10)'} self.code['matrix'] = {'sage':'E.isogeny_class().matrix()'} self.code['plot'] = {'sage':'E.isogeny_graph().plot(edge_labels=True)'}
def make_form(self): # To start with the data fields of self are just those from # the database. We need to reformat these and compute some # further (easy) data about it. # from lmfdb.ecnf.WebEllipticCurve import FIELD self.field = FIELD(self.field_label) pretty_field = field_pretty(self.field_label) self.field_knowl = nf_display_knowl(self.field_label, pretty_field) try: dims = db.bmf_dims.lucky( { 'field_label': self.field_label, 'level_label': self.level_label }, projection='gl2_dims') self.newspace_dimension = dims[str(self.weight)]['new_dim'] except TypeError: self.newspace_dimension = 'not available' self.newspace_label = "-".join([self.field_label, self.level_label]) self.newspace_url = url_for(".render_bmf_space_webpage", field_label=self.field_label, level_label=self.level_label) K = self.field.K() if self.dimension > 1: Qx = PolynomialRing(QQ, 'x') self.hecke_poly = Qx(str(self.hecke_poly)) F = NumberField(self.hecke_poly, 'z') self.hecke_poly = web_latex(self.hecke_poly) def conv(ap): if '?' in ap: return 'not known' else: return F(str(ap)) self.hecke_eigs = [conv(str(ap)) for ap in self.hecke_eigs] self.nap = len(self.hecke_eigs) self.nap0 = min(50, self.nap) self.hecke_table = [[ web_latex(p.norm()), ideal_label(p), web_latex(p.gens_reduced()[0]), web_latex(ap) ] for p, ap in zip(primes_iter(K), self.hecke_eigs[:self.nap0])] level = ideal_from_label(K, self.level_label) self.level_ideal2 = web_latex(level) badp = level.prime_factors() self.have_AL = self.AL_eigs[0] != '?' if self.have_AL: self.AL_table = [[ web_latex(p.norm()), ideal_label(p), web_latex(p.gens_reduced()[0]), web_latex(ap) ] for p, ap in zip(badp, self.AL_eigs)] self.sign = 'not determined' if self.sfe == 1: self.sign = "+1" elif self.sfe == -1: self.sign = "-1" if self.Lratio == '?': self.Lratio = "not determined" self.anrank = "not determined" else: self.Lratio = QQ(self.Lratio) self.anrank = "\(0\)" if self.Lratio != 0 else "odd" if self.sfe == -1 else "\(\ge2\), even" self.properties2 = [('Base field', pretty_field), ('Weight', str(self.weight)), ('Level norm', str(self.level_norm)), ('Level', self.level_ideal2), ('Label', self.label), ('Dimension', str(self.dimension))] if self.CM == '?': self.CM = 'not determined' elif self.CM == 0: self.CM = 'no' self.properties2.append(('CM', str(self.CM))) self.bc_extra = '' self.bcd = 0 self.bct = self.bc != '?' and self.bc != 0 if self.bc == '?': self.bc = 'not determined' elif self.bc == 0: self.bc = 'no' elif self.bc == 1: self.bcd = self.bc self.bc = 'yes' elif self.bc > 1: self.bcd = self.bc self.bc = 'yes' self.bc_extra = ', of a form over \(\mathbb{Q}\) with coefficients in \(\mathbb{Q}(\sqrt{' + str( self.bcd) + '})\)' elif self.bc == -1: self.bc = 'no' self.bc_extra = ', but is a twist of the base-change of a form over \(\mathbb{Q}\)' elif self.bc < -1: self.bcd = -self.bc self.bc = 'no' self.bc_extra = ', but is a twist of the base-change of a form over \(\mathbb{Q}\) with coefficients in \(\mathbb{Q}(\sqrt{' + str( self.bcd) + '})\)' self.properties2.append(('Base-change', str(self.bc))) curve_bc = db.ec_nfcurves.lucky({'class_label': self.label}, projection="base_change") if curve_bc is not None: self.ec_status = 'exists' self.ec_url = url_for("ecnf.show_ecnf_isoclass", nf=self.field_label, conductor_label=self.level_label, class_label=self.label_suffix) curve_bc_parts = [split_lmfdb_label(lab) for lab in curve_bc] bc_urls = [ url_for("emf.render_elliptic_modular_forms", level=cond, weight=2, character=1, label=iso) for cond, iso, num in curve_bc_parts ] bc_labels = [ newform_label(cond, 2, 1, iso) for cond, iso, num in curve_bc_parts ] bc_exists = [is_newform_in_db(lab) for lab in bc_labels] self.bc_forms = [{ 'exists': ex, 'label': lab, 'url': url } for ex, lab, url in zip(bc_exists, bc_labels, bc_urls)] else: self.bc_forms = [] if self.bct: self.ec_status = 'none' else: self.ec_status = 'missing' self.properties2.append(('Sign', self.sign)) self.properties2.append(('Analytic rank', self.anrank)) self.friends = [] if self.dimension == 1: if self.ec_status == 'exists': self.friends += [ ('Elliptic curve isogeny class {}'.format(self.label), self.ec_url) ] elif self.ec_status == 'missing': self.friends += [ ('Elliptic curve {} missing'.format(self.label), "") ] else: self.friends += [('No elliptic curve', "")] self.friends += [('Newspace {}'.format(self.newspace_label), self.newspace_url)] self.friends += [('L-function not available', '')]
def make_form(self): # To start with the data fields of self are just those from # the database. We need to reformat these and compute some # further (easy) data about it. # from lmfdb.ecnf.WebEllipticCurve import FIELD self.field = FIELD(self.field_label) pretty_field = field_pretty(self.field_label) self.field_knowl = nf_display_knowl(self.field_label, getDBConnection(), pretty_field) try: dims = db_dims().find_one({'field_label':self.field_label, 'level_label':self.level_label})['gl2_dims'] self.newspace_dimension = dims[str(self.weight)]['new_dim'] except TypeError: self.newspace_dimension = 'not available' self.newspace_label = "-".join([self.field_label,self.level_label]) self.newspace_url = url_for(".render_bmf_space_webpage", field_label=self.field_label, level_label=self.level_label) K = self.field.K() if self.dimension>1: Qx = PolynomialRing(QQ,'x') self.hecke_poly = Qx(str(self.hecke_poly)) F = NumberField(self.hecke_poly,'z') self.hecke_poly = web_latex(self.hecke_poly) def conv(ap): if '?' in ap: return 'not known' else: return F(str(ap)) self.hecke_eigs = [conv(str(ap)) for ap in self.hecke_eigs] self.nap = len(self.hecke_eigs) self.nap0 = min(50, self.nap) self.hecke_table = [[web_latex(p.norm()), ideal_label(p), web_latex(p.gens_reduced()[0]), web_latex(ap)] for p,ap in zip(primes_iter(K), self.hecke_eigs[:self.nap0])] level = ideal_from_label(K,self.level_label) self.level_ideal2 = web_latex(level) badp = level.prime_factors() self.have_AL = self.AL_eigs[0]!='?' if self.have_AL: self.AL_table = [[web_latex(p.norm()), ideal_label(p), web_latex(p.gens_reduced()[0]), web_latex(ap)] for p,ap in zip(badp, self.AL_eigs)] self.sign = 'not determined' if self.sfe == 1: self.sign = "+1" elif self.sfe == -1: self.sign = "-1" if self.Lratio == '?': self.Lratio = "not determined" self.anrank = "not determined" else: self.Lratio = QQ(self.Lratio) self.anrank = "\(0\)" if self.Lratio!=0 else "odd" if self.sfe==-1 else "\(\ge2\), even" self.properties2 = [('Base field', pretty_field), ('Weight', str(self.weight)), ('Level norm', str(self.level_norm)), ('Level', self.level_ideal2), ('Label', self.label), ('Dimension', str(self.dimension)) ] if self.CM == '?': self.CM = 'not determined' elif self.CM == 0: self.CM = 'no' self.properties2.append(('CM', str(self.CM))) self.bc_extra = '' self.bcd = 0 self.bct = self.bc!='?' and self.bc!=0 if self.bc == '?': self.bc = 'not determined' elif self.bc == 0: self.bc = 'no' elif self.bc == 1: self.bcd = self.bc self.bc = 'yes' elif self.bc >1: self.bcd = self.bc self.bc = 'yes' self.bc_extra = ', of a form over \(\mathbb{Q}\) with coefficients in \(\mathbb{Q}(\sqrt{'+str(self.bcd)+'})\)' elif self.bc == -1: self.bc = 'no' self.bc_extra = ', but is a twist of the base-change of a form over \(\mathbb{Q}\)' elif self.bc < -1: self.bcd = -self.bc self.bc = 'no' self.bc_extra = ', but is a twist of the base-change of a form over \(\mathbb{Q}\) with coefficients in \(\mathbb{Q}(\sqrt{'+str(self.bcd)+'})\)' self.properties2.append(('Base-change', str(self.bc))) curve = db_ecnf().find_one({'class_label':self.label}) if curve: self.ec_status = 'exists' self.ec_url = url_for("ecnf.show_ecnf_isoclass", nf=self.field_label, conductor_label=self.level_label, class_label=self.label_suffix) curve_bc = curve['base_change'] curve_bc_parts = [split_lmfdb_label(lab) for lab in curve_bc] bc_urls = [url_for("emf.render_elliptic_modular_forms", level=cond, weight=2, character=1, label=iso) for cond, iso, num in curve_bc_parts] bc_labels = [newform_label(cond,2,1,iso) for cond,iso,num in curve_bc_parts] bc_exists = [is_newform_in_db(lab) for lab in bc_labels] self.bc_forms = [{'exists':ex, 'label':lab, 'url':url} for ex,lab,url in zip(bc_exists, bc_labels, bc_urls)] else: self.bc_forms = [] if self.bct: self.ec_status = 'none' else: self.ec_status = 'missing' self.properties2.append(('Sign', self.sign)) self.properties2.append(('Analytic rank', self.anrank)) self.friends = [] if self.dimension==1: if self.ec_status == 'exists': self.friends += [('Elliptic curve isogeny class {}'.format(self.label), self.ec_url)] elif self.ec_status == 'missing': self.friends += [('Elliptic curve {} missing'.format(self.label), "")] else: self.friends += [('No elliptic curve', "")] self.friends += [ ('Newspace {}'.format(self.newspace_label),self.newspace_url)] self.friends += [ ('L-function not available','')]
def make_class(self): self.ainvs_str = self.ainvs self.ainvs = [int(a) for a in self.ainvs_str] self.E = EllipticCurve(self.ainvs) self.CM = self.E.has_cm() try: # Extract the isogeny degree matrix from the database size = len(self.isogeny_matrix) from sage.matrix.all import Matrix self.isogeny_matrix = Matrix(self.isogeny_matrix) except AttributeError: # Failsafe: construct it from scratch self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix() size = self.isogeny_matrix.nrows() self.ncurves = size # Create isogeny graph: self.graph = make_graph(self.isogeny_matrix) P = self.graph.plot(edge_labels=True) self.graph_img = encode_plot(P) self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img # Create a list of the curves in the class from the database self.db_curves = [self.E] self.optimal_flags = [False] * size self.degrees = [0] * size if self.degree: self.degrees[0] = self.degree else: try: self.degrees[0] = self.E.modular_degree() except RuntimeError: pass # Fill in the curves in the class by looking each one up in the db: self.cremona_labels = [self.label] + [0] * (size - 1) if self.number == 1: self.optimal_flags[0] = True for i in range(2, size + 1): Edata = db_ec().find_one({'lmfdb_label': self.lmfdb_iso + str(i)}) Ei = EllipticCurve([int(a) for a in Edata['ainvs']]) self.cremona_labels[i - 1] = Edata['label'] if Edata['number'] == 1: self.optimal_flags[i - 1] = True if 'degree' in Edata: self.degrees[i - 1] = Edata['degree'] else: try: self.degrees[i - 1] = Ei.modular_degree() except RuntimeError: pass self.db_curves.append(Ei) if self.iso == '990h': # this isogeny class is labeled wrong in Cremona's tables self.optimal_flags = [False, False, True, False] self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix)) N, iso, number = split_lmfdb_label(self.lmfdb_iso) self.newform = web_latex(self.E.q_eigenform(10)) self.newform_label = newform_label(N, 2, 1, iso) self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=1, label=iso) newform_exists_in_db = is_newform_in_db(self.newform_label) self.lfunction_link = url_for("l_functions.l_function_ec_page", label=self.lmfdb_iso) self.curves = [ dict([('label', self.lmfdb_iso + str(i + 1)), ('url', url_for(".by_triple_label", conductor=N, iso_label=iso, number=i + 1)), ('cremona_label', self.cremona_labels[i]), ('ainvs', str(list(c.ainvs()))), ('torsion', c.torsion_order()), ('degree', self.degrees[i]), ('optimal', self.optimal_flags[i])]) for i, c in enumerate(self.db_curves) ] self.friends = [('L-function', self.lfunction_link)] if not self.CM: if int(N) <= 300: self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso))] if int(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.properties = [('Label', self.lmfdb_iso), ('Number of curves', str(self.ncurves)), ('Conductor', '\(%s\)' % N), ('CM', '%s' % self.CM), ('Rank', '\(%s\)' % self.rank), ('Graph', ''), (None, self.graph_link)] self.downloads = [('Download coefficients of newform', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=100)), ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))] if self.lmfdb_iso == self.iso: self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso else: self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % ( self.lmfdb_iso, self.iso) self.bread = [('Elliptic Curves', url_for("ecnf.index")), ('$\Q$', url_for(".rational_elliptic_curves")), ('%s' % N, url_for(".by_conductor", conductor=N)), ('%s' % iso, ' ')]
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 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 = {} data['ainvs'] = 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']) # extract data about MW rank, generators, heights and torsion: self.make_mw() # get more data from the database entry 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_curves.lucky({'label': minq_label}, 'lmfdb_label') data['minq_info'] = '(itself)' if minqD == 1 else '(by %s)' % minqD if self.degree is None: data['degree'] = 0 # invalid, but will be displayed nicely else: data['degree'] = self.degree if self.number == 1: data['an'] = self.anlist data['ap'] = self.aplist else: r = db.ec_curves.lucky({'lmfdb_iso': self.lmfdb_iso, 'number': 1}) data['an'] = r['anlist'] data['ap'] = r['aplist'] 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['galois_images'] = [ trim_galois_image_code(s) for s in self.mod_p_images ] data['non_maximal_primes'] = self.non_maximal_primes data['galois_data'] = [{ 'p': p, 'image': im } for p, im in zip(data['non_maximal_primes'], data['galois_images'])] data['CMD'] = self.cm data['CM'] = "no" data['EndE'] = "\(\Z\)" if self.cm: data['cm_ramp'] = [ p for p in ZZ(self.cm).support() if not p in self.non_maximal_primes ] data['cm_nramp'] = len(data['cm_ramp']) if data['cm_nramp'] == 1: data['cm_ramp'] = data['cm_ramp'][0] else: data['cm_ramp'] = ", ".join([str(p) for p in data['cm_ramp']]) data['cm_sqf'] = ZZ(self.cm).squarefree_part() 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 ] cond, iso, num = split_lmfdb_label(self.lmfdb_label) self.class_url = url_for(".by_double_iso_label", conductor=N, iso_label=iso) self.one_deg = ZZ(self.class_deg).is_prime() self.ncurves = db.ec_curves.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 & other BSD data self.make_bsd() # 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'] = db.ec_padic.exists( {'lmfdb_iso': self.lmfdb_iso}) # Iwasawa data (where present) self.make_iwasawa() # Torsion growth data (where present) self.make_torsion_growth() 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", conductor_label=N, isogeny_class_label=iso))] if not self.cm: if N <= 300: self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', conductor=N, isogeny=iso))] if N <= 50: self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', conductor=N, isogeny=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 SageMath 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 = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format( 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\)' % self.mw['rank']), ('Torsion Structure', '\(%s\)' % self.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_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: 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['galois_images'] = [ trim_galois_image_code(s) for s in self.mod_p_images ] data['non_maximal_primes'] = self.non_maximal_primes data['galois_data'] = [{ 'p': p, 'image': im } for p, im in zip(data['non_maximal_primes'], data['galois_images'])] data['CMD'] = self.cm data['CM'] = "no" data['EndE'] = "\(\Z\)" if self.cm: data['cm_ramp'] = [ p for p in ZZ(self.cm).support() if not p in self.non_surjective_primes ] data['cm_nramp'] = len(data['cm_ramp']) if data['cm_nramp'] == 1: data['cm_ramp'] = data['cm_ramp'][0] else: data['cm_ramp'] = ", ".join([str(p) for p in data['cm_ramp']]) data['cm_sqf'] = ZZ(self.cm).squarefree_part() 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 ] cond, iso, num = split_lmfdb_label(self.lmfdb_label) self.class_url = url_for(".by_double_iso_label", conductor=N, iso_label=iso) self.one_deg = ZZ(self.class_deg).is_prime() 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 data['iwdata'] = [] try: pp = [int(p) for p in self.iwdata] badp = [l['p'] for l in self.local_data] rtypes = [l['red'] for l in self.local_data] data[ 'iw_missing_flag'] = False # flags that there is at least one "?" in the table data[ 'additive_shown'] = False # flags that there is at least one additive prime in table for p in sorted(pp): rtype = "" if p in badp: red = rtypes[badp.index(p)] # Additive primes are excluded from the table # if red==0: # continue #rtype = ["nsmult","add", "smult"][1+red] rtype = ["nonsplit", "add", "split"][1 + red] p = str(p) pdata = self.iwdata[p] if isinstance(pdata, type(u'?')): if not rtype: rtype = "ordinary" if pdata == "o?" else "ss" if rtype == "add": data['iwdata'] += [[p, rtype, "-", "-"]] data['additive_shown'] = True else: data['iwdata'] += [[p, rtype, "?", "?"]] data['iw_missing_flag'] = True else: if len(pdata) == 2: if not rtype: rtype = "ordinary" lambdas = str(pdata[0]) mus = str(pdata[1]) else: rtype = "ss" lambdas = ",".join([str(pdata[0]), str(pdata[1])]) mus = str(pdata[2]) mus = ",".join([mus, mus]) data['iwdata'] += [[p, rtype, lambdas, mus]] except AttributeError: # For curves with no Iwasawa data pass 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) # Torsion growth data data['torsion_growth_data_exists'] = False try: tg = self.tor_gro data['torsion_growth_data_exists'] = True data['tgx'] = tgextra = [] # find all base-changes of this curve in the database, if any bcs = [ res['label'] for res in getDBConnection().elliptic_curves.nfcurves.find( {'base_change': self.lmfdb_label}, projection={ 'label': True, '_id': False }) ] bcfs = [lab.split("-")[0] for lab in bcs] for F, T in tg.items(): tg1 = {} tg1['bc'] = "Not in database" if ":" in F: F = F.replace(":", ".") field_data = nf_display_knowl(F, getDBConnection(), field_pretty(F)) deg = int(F.split(".")[0]) bcc = [x for x, y in zip(bcs, bcfs) if y == F] if bcc: from lmfdb.ecnf.main import split_full_label F, NN, I, C = split_full_label(bcc[0]) tg1['bc'] = bcc[0] tg1['bc_url'] = url_for('ecnf.show_ecnf', nf=F, conductor_label=NN, class_label=I, number=C) else: field_data = web_latex_split_on_pm( coeff_to_poly(string2list(F))) deg = F.count(",") tg1['d'] = deg tg1['f'] = field_data tg1['t'] = '\(' + ' \\times '.join( ['\Z/{}\Z'.format(n) for n in T.split(",")]) + '\)' tg1['m'] = 0 tgextra.append(tg1) tgextra.sort(key=lambda x: x['d']) data['ntgx'] = len(tgextra) lastd = 1 for tg in tgextra: d = tg['d'] if d != lastd: tg['m'] = len([x for x in tgextra if x['d'] == d]) lastd = d data['tg_maxd'] = max(db_ecstats().find_one( {'_id': 'torsion_growth'})['degrees']) except AttributeError: pass # we have no torsion growth data 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", conductor_label=N, isogeny_class_label=iso))] if not self.cm: if N <= 300: self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', conductor=N, isogeny=iso))] if N <= 50: self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', conductor=N, isogeny=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 = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format( 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_class(self): self.ainvs_str = self.ainvs self.ainvs = [int(a) for a in self.ainvs_str] self.E = EllipticCurve(self.ainvs) self.CM = self.E.has_cm() try: # Extract the isogeny degree matrix from the database size = len(self.isogeny_matrix) from sage.matrix.all import Matrix self.isogeny_matrix = Matrix(self.isogeny_matrix) except AttributeError: # Failsafe: construct it from scratch self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix() size = self.isogeny_matrix.nrows() self.ncurves = size # Create isogeny graph: self.graph = make_graph(self.isogeny_matrix) P = self.graph.plot(edge_labels=True) self.graph_img = encode_plot(P) self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img # Create a list of the curves in the class from the database self.db_curves = [self.E] self.optimal_flags = [False] * size self.degrees = [0] * size if self.degree: self.degrees[0] = self.degree else: try: self.degrees[0] = self.E.modular_degree() except RuntimeError: pass # Fill in the curves in the class by looking each one up in the db: self.cremona_labels = [self.label] + [0] * (size - 1) if self.number == 1: self.optimal_flags[0] = True for i in range(2, size + 1): Edata = db_ec().find_one({'lmfdb_label': self.lmfdb_iso + str(i)}) Ei = EllipticCurve([int(a) for a in Edata['ainvs']]) self.cremona_labels[i - 1] = Edata['label'] if Edata['number'] == 1: self.optimal_flags[i - 1] = True if 'degree' in Edata: self.degrees[i - 1] = Edata['degree'] else: try: self.degrees[i - 1] = Ei.modular_degree() except RuntimeError: pass self.db_curves.append(Ei) if self.iso == '990h': # this isogeny class is labeled wrong in Cremona's tables self.optimal_flags = [False, False, True, False] self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix)) N, iso, number = split_lmfdb_label(self.lmfdb_iso) self.newform = web_latex(self.E.q_eigenform(10)) self.newform_label = newform_label(N,2,1,iso) self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=1, label=iso) self.newform_exists_in_db = is_newform_in_db(self.newform_label) self.lfunction_link = url_for("l_functions.l_function_ec_page", label=self.lmfdb_iso) self.curves = [dict([('label',self.lmfdb_iso + str(i + 1)), ('url',url_for(".by_triple_label", conductor=N, iso_label=iso, number=i+1)), ('cremona_label',self.cremona_labels[i]), ('ainvs',str(list(c.ainvs()))), ('torsion',c.torsion_order()), ('degree',self.degrees[i]), ('optimal',self.optimal_flags[i])]) for i, c in enumerate(self.db_curves)] self.friends = [('L-function', self.lfunction_link)] if not self.CM: if int(N)<=300: self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso))] if int(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.properties = [('Label', self.lmfdb_iso), ('Number of curves', str(self.ncurves)), ('Conductor', '\(%s\)' % N), ('CM', '%s' % self.CM), ('Rank', '\(%s\)' % self.rank), ('Graph', ''),(None, self.graph_link) ] self.downloads = [('Download coefficients of newform', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=1000)), ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))] if self.lmfdb_iso == self.iso: self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso else: self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso) self.bread = [('Elliptic Curves', url_for("ecnf.index")), ('$\Q$', url_for(".rational_elliptic_curves")), ('%s' % N, url_for(".by_conductor", conductor=N)), ('%s' % iso, ' ')] self.code = {} self.code['show'] = {'sage':''} # use default show names self.code['class'] = {'sage':'E = EllipticCurve("%s1")\n'%(self.lmfdb_iso) + 'E.isogeny_class()\n'} self.code['curves'] = {'sage':'E.isogeny_class().curves'} self.code['rank'] = {'sage':'E.rank()'} self.code['q_eigenform'] = {'sage':'E.q_eigenform(10)'} self.code['matrix'] = {'sage':'E.isogeny_class().matrix()'} self.code['plot'] = {'sage':'E.isogeny_graph().plot(edge_labels=True)'}
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 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 = {} data['ainvs'] = 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']) # extract data about MW rank, generators, heights and torsion: self.make_mw() # get more data from the database entry 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_curves.lucky({'label':minq_label}, 'lmfdb_label') data['minq_info'] = '(itself)' if minqD==1 else '(by %s)' % minqD if self.degree is None: data['degree'] = 0 # invalid, but will be displayed nicely else: data['degree'] = self.degree if self.number == 1: data['an'] = self.anlist data['ap'] = self.aplist else: r = db.ec_curves.lucky({'lmfdb_iso':self.lmfdb_iso, 'number':1}) data['an'] = r['anlist'] data['ap'] = r['aplist'] 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['galois_images'] = [trim_galois_image_code(s) for s in self.mod_p_images] data['non_maximal_primes'] = self.non_maximal_primes data['galois_data'] = [{'p': p,'image': im } for p,im in zip(data['non_maximal_primes'], data['galois_images'])] data['CMD'] = self.cm data['CM'] = "no" data['EndE'] = "\(\Z\)" if self.cm: data['cm_ramp'] = [p for p in ZZ(self.cm).support() if not p in self.non_maximal_primes] data['cm_nramp'] = len(data['cm_ramp']) if data['cm_nramp']==1: data['cm_ramp'] = data['cm_ramp'][0] else: data['cm_ramp'] = ", ".join([str(p) for p in data['cm_ramp']]) data['cm_sqf'] = ZZ(self.cm).squarefree_part() 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] cond, iso, num = split_lmfdb_label(self.lmfdb_label) self.class_url = url_for(".by_double_iso_label", conductor=N, iso_label=iso) self.one_deg = ZZ(self.class_deg).is_prime() self.ncurves = db.ec_curves.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 & other BSD data self.make_bsd() # 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'] = db.ec_padic.exists({'lmfdb_iso': self.lmfdb_iso}) # Iwasawa data (where present) self.make_iwasawa() # Torsion growth data (where present) self.make_torsion_growth() 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", conductor_label = N, isogeny_class_label = iso))] if not self.cm: if N<=300: self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', conductor = N, isogeny = iso))] if N<=50: self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', conductor = N, isogeny = 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 SageMath 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 = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format(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\)' % self.mw['rank']), ('Torsion Structure', '\(%s\)' % self.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_class(self): self.ainvs_str = self.ainvs self.ainvs = [int(a) for a in self.ainvs_str] self.E = EllipticCurve(self.ainvs) self.CM = self.E.has_cm() try: # Extract the isogeny degree matrix from the database size = len(self.isogeny_matrix) from sage.matrix.all import Matrix self.isogeny_matrix = Matrix(self.isogeny_matrix) except AttributeError: # Failsafe: construct it from scratch self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix() size = self.isogeny_matrix.nrows() self.ncurves = size # Create isogeny graph: self.graph = make_graph(self.isogeny_matrix) P = self.graph.plot(edge_labels=True) self.graph_img = encode_plot(P) self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img # Create a list of the curves in the class from the database self.db_curves = [self.E] self.optimal_flags = [False] * size self.degrees = [0] * size if self.degree: self.degrees[0] = self.degree else: try: self.degrees[0] = self.E.modular_degree() except RuntimeError: pass # Fill in the curves in the class by looking each one up in the db: self.cremona_labels = [self.label] + [0] * (size - 1) if self.number == 1: self.optimal_flags[0] = True for i in range(2, size + 1): Edata = db_ec().find_one({"lmfdb_label": self.lmfdb_iso + str(i)}) Ei = EllipticCurve([int(a) for a in Edata["ainvs"]]) self.cremona_labels[i - 1] = Edata["label"] if Edata["number"] == 1: self.optimal_flags[i - 1] = True if "degree" in Edata: self.degrees[i - 1] = Edata["degree"] else: try: self.degrees[i - 1] = Ei.modular_degree() except RuntimeError: pass self.db_curves.append(Ei) if self.iso == "990h": # this isogeny class is labeled wrong in Cremona's tables self.optimal_flags = [False, False, True, False] self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix)) N, iso, number = split_lmfdb_label(self.lmfdb_iso) self.newform = web_latex(self.E.q_eigenform(10)) self.newform_label = newform_label(N, 2, 1, iso) self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=1, label=iso) newform_exists_in_db = is_newform_in_db(self.newform_label) self.lfunction_link = url_for("l_functions.l_function_ec_page", label=self.lmfdb_iso) self.curves = [ dict( [ ("label", self.lmfdb_iso + str(i + 1)), ("url", url_for(".by_triple_label", conductor=N, iso_label=iso, number=i + 1)), ("cremona_label", self.cremona_labels[i]), ("ainvs", str(list(c.ainvs()))), ("torsion", c.torsion_order()), ("degree", self.degrees[i]), ("optimal", self.optimal_flags[i]), ] ) for i, c in enumerate(self.db_curves) ] self.friends = [("L-function", self.lfunction_link)] if not self.CM: self.friends += [ ( "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), ), ] if newform_exists_in_db: self.friends += [("Modular form " + self.newform_label, self.newform_link)] self.properties = [ ("Label", self.lmfdb_iso), ("Number of curves", str(self.ncurves)), ("Conductor", "\(%s\)" % N), ("CM", "%s" % self.CM), ("Rank", "\(%s\)" % self.rank), ("Graph", ""), (None, self.graph_link), ] self.downloads = [ ("Download coefficients of newform", url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=100)), ("Download stored data for all curves", url_for(".download_EC_all", label=self.lmfdb_iso)), ] if self.lmfdb_iso == self.iso: self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso else: self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso) self.bread = [ ("Elliptic Curves", url_for("ecnf.index")), ("$\Q$", url_for(".rational_elliptic_curves")), ("%s" % N, url_for(".by_conductor", conductor=N)), ("%s" % iso, " "), ]
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 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({'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,' ')]