def fix1_qcurve_flag(ec, verbose=False): """ Update ec structure (from nfcurves collection) with the correct q_curves flag. For degree >2 at present we only do trivial tests here which do not require any computation. """ if ec['q_curve']: # keep old True values return ec # Easy sufficient tests in all degrees qc = False if ec['cm']: qc = True elif all(c == '0' for c in ec['jinv'].split(",")[1:]): qc = True if qc: # then we have just set it to True if ec['q_curve'] != qc: if verbose: print("{}: changing q_curve flag from {} to {}".format( ec['label'], ec['q_curve'], qc)) ec['q_curve'] = qc return ec # else if degree != 2 just replace possibly false negatives with '?' if ec['degree'] > 2: qc = '?' # if ec['q_curve'] != qc: # print("{}: changing q_curve flag from {} to {}".format(ec['label'],ec['q_curve'],qc)) ec['q_curve'] = qc return ec # else (degree 2 only for now) do the work (knowing that E does # not have CM and j(E) is not in Q) K = FIELD(ec['field_label']) sigma = K.K().galois_group()[1] # Compute the Q-curve flag from scratch N = ideal_from_string(K.K(), ec['conductor_ideal']) if sigma(N) != N: qc = False else: # construct and check the curve ainvsK = parse_ainvs(K.K(), ec['ainvs']) E = EllipticCurve(ainvsK) qc = is_Q_curve(E) if ec['q_curve'] != qc: if verbose: print("{}: changing q_curve flag from {} to {}".format( ec['label'], ec['q_curve'], qc)) ec['q_curve'] = qc return ec
def make_isoclass_line(ec): r""" for ec a curve object from the database, create a line of text to match the corresponding raw input line from an isoclass file. ec should be a dict with these fields: 'field_label', 'conductor_label', 'iso_label', 'number' and optionally: 'isogeny_matrix' Output line fields (15): field_label conductor_label iso_label number isogeny_matrix Sample output line: 2.0.4.1 65.18.1 a 1 [[1,6,3,18,9,2],[6,1,2,3,6,3],[3,2,1,6,3,6],[18,3,6,1,2,9],[9,6,3,2,1,18],[2,3,6,9,18,1]] """ mat = '' if 'isogeny_matrix' in ec: mat = str(ec['isogeny_matrix']).replace(' ', '') else: print("Making isogeny matrix for class %s" % ec['label']) from lmfdb.ecnf.isog_class import permute_mat from lmfdb.ecnf.WebEllipticCurve import FIELD K = FIELD(ec['field_label']) curves = nfcurves.find({ 'field_label': ec['field_label'], 'conductor_label': ec['conductor_label'], 'iso_label': ec['iso_label'] }).sort('number') Elist = [ EllipticCurve([K.parse_NFelt(x) for x in c['ainvs']]) for c in curves ] cl = Elist[0].isogeny_class() perm = dict([(i, cl.index(E)) for i, E in enumerate(Elist)]) mat = permute_mat(cl.matrix(), perm, True) mat = str([list(ri) for ri in mat.rows()]).replace(" ", "") output_fields = [ ec['field_label'], ec['conductor_label'], ec['iso_label'], str(ec['number']), mat ] return " ".join(output_fields)
def make_isoclass_line(ec): r""" for ec a curve object from the database, create a line of text to match the corresponding raw input line from an isoclass file. ec should be a dict with these fields: 'field_label', 'conductor_label', 'iso_label', 'number' and optionally: 'isogeny_matrix' Output line fields (15): field_label conductor_label iso_label number isogeny_matrix Sample output line: 2.0.4.1 65.18.1 a 1 [[1,6,3,18,9,2],[6,1,2,3,6,3],[3,2,1,6,3,6],[18,3,6,1,2,9],[9,6,3,2,1,18],[2,3,6,9,18,1]] """ mat = '' if 'isogeny_matrix' in ec: mat = str(ec['isogeny_matrix']).replace(' ', '') else: print("Making isogeny matrix for class %s" % ec['label']) from lmfdb.ecnf.isog_class import permute_mat from lmfdb.ecnf.WebEllipticCurve import FIELD K = FIELD(ec['field_label']) curves = nfcurves.find({'field_label': ec['field_label'], 'conductor_label': ec['conductor_label'], 'iso_label': ec['iso_label']}).sort('number') Elist = [EllipticCurve([K.parse_NFelt(x) for x in c['ainvs']]) for c in curves] cl = Elist[0].isogeny_class() perm = dict([(i, cl.index(E)) for i, E in enumerate(Elist)]) mat = permute_mat(cl.matrix(), perm, True) mat = str([list(ri) for ri in mat.rows()]).replace(" ", "") output_fields = [ec['field_label'], ec['conductor_label'], ec['iso_label'], str(ec['number']), mat] return " ".join(output_fields)
def check_Q_curves(field_label='2.2.5.1', min_norm=0, max_norm=None, fix=False, verbose=False): """Given a (quadratic) field label test all curves E over that field for being Q-curves. """ query = {} query['field_label'] = field_label query['conductor_norm'] = {'$gte': int(min_norm)} if max_norm: query['conductor_norm']['$lte'] = int(max_norm) else: max_norm = 'infinity' cursor = nfcurves.find(query) # keep the curves and re-find them, else the cursor times out. curves = [ec['label'] for ec in cursor] ncurves = len(curves) print("Checking {} curves over field {}".format(ncurves, field_label)) K = FIELD(field_label) sigma = K.K().galois_group()[1] bad1 = [] bad2 = [] count = 0 for label in curves: count += 1 if count % 1000 == 0: print("checked {} curves ({}%)".format(count, 100.0 * count / ncurves)) ec = nfcurves.find_one({'label': label}) assert label == ec['label'] method = None # first check that j(E) is rational (no computation needed) jinv = ec['jinv'] if all(c == '0' for c in jinv.split(",")[1:]): if verbose: print("{}: j in QQ".format(label)) qc = True method = "j in Q" elif ec['cm']: if verbose: print("{}: CM".format(label)) qc = True method = "CM" else: # construct and check the conductor if verbose: print("{}: checking conductor".format(label)) N = ideal_from_string(K.K(), ec['conductor_ideal']) if sigma(N) != N: qc = False method = "conductor" else: # construct and check the curve if verbose: print("{}: checking isogenies".format(label)) ainvsK = parse_ainvs(K.K(), ec['ainvs']) E = EllipticCurve(ainvsK) qc = is_Q_curve(E) method = "isogenies" db_qc = ec['q_curve'] if qc and not db_qc: print("Curve {} is a Q-curve (using {}) but database thinks not". format(label, method)) bad1 += [label] elif db_qc and not qc: print( "Curve {} is not a Q-curve (using {}) but database thinks it is" .format(label, method)) bad2 += [label] else: if verbose: print("Curve {} OK (using {})".format(label, method)) print( "{} curves in the database are incorrectly labelled as being Q-curves". format(len(bad2))) print( "{} curves in the database are incorrectly labelled as NOT being Q-curves" .format(len(bad1))) return bad1, bad2
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_class(self): # Create a list of the curves in the class from the database self.db_curves = list(db.ec_nfcurves.search( {'field_label': self.field_label, 'conductor_norm': self.conductor_norm, 'conductor_label': self.conductor_label, 'iso_nlabel': self.iso_nlabel})) # Rank or bounds try: self.rk = web_latex(self.db_curves[0]['rank']) except KeyError: self.rk = "?" try: self.rk_bnds = "%s...%s" % tuple(self.db_curves[0]['rank_bounds']) except KeyError: self.rank_bounds = [0, Infinity] self.rk_bnds = "not recorded" # Extract the isogeny degree matrix from the database if not hasattr(self, 'isogeny_matrix'): # this would happen if the class is initiated with a curve # which is not #1 in its class: self.isogeny_matrix = self.db_curves[0].isogeny_matrix self.isogeny_matrix = Matrix(self.isogeny_matrix) self.one_deg = ZZ(self.class_deg).is_prime() # 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.isogeny_matrix_str = latex(Matrix(self.isogeny_matrix)) self.field = FIELD(self.field_label) self.field_name = field_pretty(self.field_label) self.field_knowl = nf_display_knowl(self.field_label, self.field_name) def curve_url(c): return url_for(".show_ecnf", nf=c['field_label'], conductor_label=c['conductor_label'], class_label=c['iso_label'], number=c['number']) self.curves = [[c['short_label'], curve_url(c), web_ainvs(self.field_label,c['ainvs'])] for c in self.db_curves] self.urls = {} self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=self.conductor_label, class_label=self.iso_label) self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=self.conductor_label) self.urls['field'] = url_for('.show_ecnf1', nf=self.field_label) sig = self.signature totally_real = sig[1] == 0 imag_quadratic = sig == [0,1] if totally_real: self.hmf_label = "-".join([self.field_label, self.conductor_label, self.iso_label]) self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field_label, label=self.hmf_label) lfun_url = url_for("l_functions.l_function_ecnf_page", field_label=self.field_label, conductor_label=self.conductor_label, isogeny_class_label=self.iso_label) origin_url = lfun_url.lstrip('/L/').rstrip('/') if sig[0] <= 2 and db.lfunc_instances.exists({'url': origin_url}): self.urls['Lfunction'] = lfun_url elif self.abs_disc ** 2 * self.conductor_norm < 40000: # we shouldn't trust the Lfun computed on the fly for large conductor self.urls['Lfunction'] = url_for("l_functions.l_function_hmf_page", field=self.field_label, label=self.hmf_label, character='0', number='0') if imag_quadratic: self.bmf_label = "-".join([self.field_label, self.conductor_label, self.iso_label]) self.bmf_url = url_for('bmf.render_bmf_webpage', field_label=self.field_label, level_label=self.conductor_label, label_suffix=self.iso_label) lfun_url = url_for("l_functions.l_function_ecnf_page", field_label=self.field_label, conductor_label=self.conductor_label, isogeny_class_label=self.iso_label) origin_url = lfun_url.lstrip('/L/').rstrip('/') if db.lfunc_instances.exists({'url':origin_url}): self.urls['Lfunction'] = lfun_url # most of this code is repeated in WebEllipticCurve.py # and should be refactored self.friends = [] if totally_real and 'Lfunction' not in self.urls: self.friends += [('Hilbert modular form ' + self.hmf_label, self.urls['hmf'])] if imag_quadratic: if "CM" in self.label: self.friends += [('Bianchi modular form is not cuspidal', '')] elif 'Lfunction' not in self.urls: if db.bmf_forms.label_exists(self.bmf_label): self.friends += [('Bianchi modular form %s' % self.bmf_label, self.bmf_url)] else: self.friends += [('(Bianchi modular form %s)' % self.bmf_label, '')] if 'Lfunction' in self.urls: Lfun = get_lfunction_by_url(self.urls['Lfunction'].lstrip('/L').rstrip('/'), projection=['degree', 'trace_hash', 'Lhash']) instances = get_instances_by_Lhash_and_trace_hash( Lfun['Lhash'], Lfun['degree'], Lfun.get('trace_hash')) exclude={elt[1].rstrip('/').lstrip('/') for elt in self.friends if elt[1]} exclude.add(lfun_url.lstrip('/L/').rstrip('/')) self.friends += names_and_urls(instances, exclude=exclude) self.friends += [('L-function', self.urls['Lfunction'])] else: self.friends += [('L-function not available', "")] self.properties = [('Base field', self.field_name), ('Label', self.class_label), (None, self.graph_link), ('Conductor', '%s' % self.conductor_label) ] if self.rk != '?': self.properties += [('Rank', '%s' % self.rk)] else: if self.rk_bnds == 'not recorded': self.properties += [('Rank', '%s' % self.rk_bnds)] else: self.properties += [('Rank bounds', '%s' % self.rk_bnds)] self.bread = [('Elliptic curves ', url_for(".index")), (self.field_label, self.urls['field']), (self.conductor_label, self.urls['conductor']), ('isogeny class %s' % self.short_label, self.urls['class'])]
class WebBMF(object): """ Class for an Bianchi Newform """ def __init__(self, dbdata): """Arguments: - dbdata: the data from the database dbdata is expected to be a database entry from which the class is initialised. """ logger.debug("Constructing an instance of WebBMF class from database") self.__dict__.update(dbdata) # All other fields are handled here self.make_form() @staticmethod def by_label(label): """ Searches for a specific Hilbert newform in the forms collection by its label. """ data = db_forms().find_one({"label": label}) if data: return WebBMF(data) raise ValueError("Bianchi newform %s not found" % label) # caller must catch this and raise an error 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_form(self, nap0=50): # 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() # 'hecke_poly_obj' is the non-LaTeX version of hecke_poly self.hecke_poly_obj = self.hecke_poly 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.level = ideal_from_label(K, self.level_label) self.level_ideal2 = web_latex(self.level) badp = self.level.prime_factors() self.nap = len(self.hecke_eigs) self.nap0 = min(nap0, self.nap) self.neigs = self.nap0 + len(badp) 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.neigs]) if not p in badp] 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)] # The following helps to create Sage download data self.AL_table_data = [[p.gens_reduced(), ap] for p, ap in zip(badp, self.AL_eigs)] self.sign = 'not determined' try: if self.sfe == 1: self.sign = "$+1$" elif self.sfe == -1: self.sign = "$-1$" except AttributeError: self.sfe = '?' if self.Lratio == '?': self.Lratio = "not determined" self.anrank = "not determined" else: self.Lratio = QQ(self.Lratio) self.anrank = r"\(0\)" if self.Lratio != 0 else "odd" if self.sfe == -1 else r"\(\ge2\), even" self.properties = [('Label', self.label), ('Base field', pretty_field), ('Weight', prop_int_pretty(self.weight)), ('Level norm', prop_int_pretty(self.level_norm)), ('Level', self.level_ideal2), ('Dimension', prop_int_pretty(self.dimension))] try: if self.CM == '?': self.CM = 'not determined' elif self.CM == 0: self.CM = 'no' else: if int(self.CM) % 4 in [2, 3]: self.CM = 4 * int(self.CM) self.CM = "$%s$" % self.CM except AttributeError: self.CM = 'not determined' self.properties.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 = r', of a form over \(\mathbb{Q}\) with coefficients in \(\mathbb{Q}(\sqrt{' + str( self.bcd) + r'})\)' elif self.bc == -1: self.bc = 'no' self.bc_extra = r', 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 = r', but is a twist of the base change of a form over \(\mathbb{Q}\) with coefficients in \(\mathbb{Q}(\sqrt{' + str( self.bcd) + r'})\)' self.properties.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: if curve_bc and "." not in curve_bc[0]: curve_bc = [ cremona_label_to_lmfdb_label(lab) for lab in curve_bc ] 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("cmf.by_url_newform_label", level=cond, weight=2, char_orbit_label='a', hecke_orbit=iso) for cond, iso, num in curve_bc_parts ] bc_labels = [ ".".join([str(cond), str(2), 'a', iso]) for cond, iso, _ in curve_bc_parts ] bc_exists = [db.mf_newforms.label_exists(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 or self.label in bmfs_with_no_curve: self.ec_status = 'none' else: self.ec_status = 'missing' self.properties.append(('Sign', self.sign)) self.properties.append(('Analytic rank', self.anrank)) self.friends = [] self.friends += [('Newspace {}'.format(self.newspace_label), self.newspace_url)] url = 'ModularForm/GL2/ImaginaryQuadratic/{}'.format( self.label.replace('-', '/')) Lfun = get_lfunction_by_url(url) if Lfun: instances = get_instances_by_Lhash_and_trace_hash( Lfun['Lhash'], Lfun['degree'], Lfun['trace_hash']) # This will also add the EC/G2C, as this how the Lfun was computed # and not add itself self.friends = names_and_urls(instances, exclude={url}) self.friends.append(('L-function', '/L/' + url)) else: # old code if self.dimension == 1: if self.ec_status == 'exists': self.friends += [('Isogeny class {}'.format(self.label), self.ec_url)] elif self.ec_status == 'missing': self.friends += [ ('Isogeny class {} missing'.format(self.label), "") ] else: self.friends += [('No elliptic curve', "")] self.friends += [('L-function not available', '')]
class WebBMF(object): """ Class for an Bianchi Newform """ def __init__(self, dbdata): """Arguments: - dbdata: the data from the database dbdata is expected to be a database entry from which the class is initialised. """ logger.debug("Constructing an instance of WebBMF class from database") self.__dict__.update(dbdata) # All other fields are handled here self.make_form() @staticmethod def by_label(label): """ Searches for a specific Hilbert newform in the forms collection by its label. """ data = db.bmf_forms.lookup(label) if data: return WebBMF(data) raise ValueError("Bianchi newform %s not found" % label) # caller must catch this and raise an error 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' try: if self.sfe == 1: self.sign = "+1" elif self.sfe == -1: self.sign = "-1" except AttributeError: self.sfe = '?' 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))] try: if self.CM == '?': self.CM = 'not determined' elif self.CM == 0: self.CM = 'no' else: if self.CM % 4 in [2, 3]: self.CM = 4 * self.CM except AttributeError: self.CM = 'not determined' 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("cmf.by_url_newform_label", level=cond, weight=2, char_orbit_label='a', hecke_orbit=iso) for cond, iso, num in curve_bc_parts ] bc_labels = [ ".".join([str(cond), str(2), 'a', iso]) for cond, iso, _ in curve_bc_parts ] bc_exists = [db.mf_newforms.label_exists(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 or self.label in bmfs_with_no_curve: self.ec_status = 'none' else: self.ec_status = 'missing' self.properties2.append(('Sign', self.sign)) self.properties2.append(('Analytic rank', self.anrank)) self.friends = [] self.friends += [('Newspace {}'.format(self.newspace_label), self.newspace_url)] url = 'ModularForm/GL2/ImaginaryQuadratic/{}'.format( self.label.replace('-', '/')) Lfun = get_lfunction_by_url(url) if Lfun: instances = get_instances_by_Lhash_and_trace_hash( Lfun['Lhash'], Lfun['degree'], Lfun['trace_hash']) # This will also add the EC/G2C, as this how the Lfun was computed # and not add itself self.friends = names_and_urls(instances, exclude={url}) self.friends.append(('L-function', '/L/' + url)) else: # old code if self.dimension == 1: if self.ec_status == 'exists': self.friends += [('Isogeny class {}'.format(self.label), self.ec_url)] elif self.ec_status == 'missing': self.friends += [ ('Isogeny class {} missing'.format(self.label), "") ] else: self.friends += [('No elliptic curve', "")] self.friends += [('L-function not available', '')]
def make_class(self): # Create a list of the curves in the class from the database self.db_curves = [ c for c in db_ecnf().find({ 'field_label': self.field_label, 'conductor_norm': self.conductor_norm, 'conductor_label': self.conductor_label, 'iso_nlabel': self.iso_nlabel }).sort('number') ] # Rank or bounds try: self.rk = web_latex(self.db_curves[0]['rank']) except KeyError: self.rk = "?" try: self.rk_bnds = "%s...%s" % tuple(self.db_curves[0]['rank_bounds']) except KeyError: self.rank_bounds = [0, Infinity] self.rk_bnds = "not recorded" # Extract the isogeny degree matrix from the database if not hasattr(self, 'isogeny_matrix'): # this would happen if the class is initiated with a curve # which is not #1 in its class: self.isogeny_matrix = self.db_curves[0].isogeny_matrix self.isogeny_matrix = Matrix(self.isogeny_matrix) self.one_deg = ZZ(self.class_deg).is_prime() # 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.isogeny_matrix_str = latex(Matrix(self.isogeny_matrix)) self.field = FIELD(self.field_label) self.field_name = field_pretty(self.field_label) self.field_knowl = nf_display_knowl(self.field_label, lmfdb.base.getDBConnection(), self.field_name) def curve_url(c): return url_for(".show_ecnf", nf=c['field_label'], conductor_label=c['conductor_label'], class_label=c['iso_label'], number=c['number']) self.curves = [[ c['short_label'], curve_url(c), web_ainvs(self.field_label, c['ainvs']) ] for c in self.db_curves] self.urls = {} self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=self.conductor_label, class_label=self.iso_label) self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=self.conductor_label) self.urls['field'] = url_for('.show_ecnf1', nf=self.field_label) sig = self.signature totally_real = sig[1] == 0 imag_quadratic = sig == [0, 1] if totally_real: self.hmf_label = "-".join( [self.field_label, self.conductor_label, self.iso_label]) self.urls['hmf'] = url_for('hmf.render_hmf_webpage', field_label=self.field_label, label=self.hmf_label) if sig[0] <= 2: self.urls['Lfunction'] = url_for( "l_functions.l_function_ecnf_page", field_label=self.field_label, conductor_label=self.conductor_label, isogeny_class_label=self.iso_label) elif self.abs_disc**2 * self.conductor_norm < 40000: # we shouldn't trust the Lfun computed on the fly for large conductor self.urls['Lfunction'] = url_for( "l_functions.l_function_hmf_page", field=self.field_label, label=self.hmf_label, character='0', number='0') if imag_quadratic: self.bmf_label = "-".join( [self.field_label, self.conductor_label, self.iso_label]) self.bmf_url = url_for('bmf.render_bmf_webpage', field_label=self.field_label, level_label=self.conductor_label, label_suffix=self.iso_label) self.urls['Lfunction'] = url_for( "l_functions.l_function_ecnf_page", field_label=self.field_label, conductor_label=self.conductor_label, isogeny_class_label=self.iso_label) self.friends = [] if totally_real: self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])] if imag_quadratic: #self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')] self.friends += [('Bianchi Modular Form %s' % self.bmf_label, self.bmf_url)] if 'Lfunction' in self.urls: self.friends += [('L-function', self.urls['Lfunction'])] else: self.friends += [('L-function not available', "")] self.properties = [('Base field', self.field_name), ('Label', self.class_label), (None, self.graph_link), ('Conductor', '%s' % self.conductor_label)] if self.rk != '?': self.properties += [('Rank', '%s' % self.rk)] else: if self.rk_bnds == 'not recorded': self.properties += [('Rank', '%s' % self.rk_bnds)] else: self.properties += [('Rank bounds', '%s' % self.rk_bnds)] self.bread = [('Elliptic Curves ', url_for(".index")), (self.field_label, self.urls['field']), (self.conductor_label, self.urls['conductor']), ('isogeny class %s' % self.short_label, self.urls['class'])]