def test_web_latex_ideal_fact(self): r""" Checking utility: web_latex_ideal_fact """ from sage.all import NumberField x = var('x') K = NumberField(x**2 - 5, 'a') a = K.gen() I = K.ideal(2 / (5 + a)).factor() self.assertEqual(web_latex_ideal_fact(I), '\\( \\left(-a\\right)^{-1} \\)') self.assertEqual(web_latex_ideal_fact(I, enclose=False), ' \\left(-a\\right)^{-1} ')
def test_web_latex_ideal_fact(self): r""" Checking utility: web_latex_ideal_fact """ from sage.all import NumberField x = var('x') K = NumberField(x**2 - 5, 'a') a = K.gen() I = K.ideal(2/(5+a)).factor() self.assertEqual(web_latex_ideal_fact(I), '\\( \\left(-a\\right)^{-1} \\)') self.assertEqual(web_latex_ideal_fact(I, enclose=False), ' \\left(-a\\right)^{-1} ')
def make_E(self): K = self.field.K() # a-invariants self.ainvs = parse_ainvs(K, self.ainvs) self.latex_ainvs = web_latex(self.ainvs) self.numb = str(self.number) # Conductor, discriminant, j-invariant N = ideal_from_string(K, self.conductor_ideal) self.cond = web_latex(N) self.cond_norm = web_latex(self.conductor_norm) local_data = self.local_data # NB badprimes is a list of primes which divide the # discriminant of this model. At most one of these might # actually be a prime of good reduction, if the curve has no # global minimal model. badprimes = [ideal_from_string(K, ld['p']) for ld in local_data] badnorms = [ZZ(ld['normp']) for ld in local_data] mindisc_ords = [ld['ord_disc'] for ld in local_data] # Assumption: the curve models stored in the database are # either global minimal models or minimal at all but one # prime, so the list here has length 0 or 1: self.non_min_primes = [ideal_from_string(K, P) for P in self.non_min_p] self.is_minimal = (len(self.non_min_primes) == 0) self.has_minimal_model = self.is_minimal disc_ords = [ld['ord_disc'] for ld in local_data] if not self.is_minimal: Pmin = self.non_min_primes[0] P_index = badprimes.index(Pmin) self.non_min_prime = web_latex(Pmin) disc_ords[P_index] += 12 if self.conductor_norm == 1: # since the factorization of (1) displays as "1" self.fact_cond = self.cond self.fact_cond_norm = self.cond else: Nfac = Factorization([(P, ld['ord_cond']) for P, ld in zip(badprimes, local_data)]) self.fact_cond = web_latex_ideal_fact(Nfac) Nnormfac = Factorization([(q, ld['ord_cond']) for q, ld in zip(badnorms, local_data)]) self.fact_cond_norm = web_latex(Nnormfac) # D is the discriminant ideal of the model D = prod([P**e for P, e in zip(badprimes, disc_ords)], K.ideal(1)) self.disc = web_latex(D) Dnorm = D.norm() self.disc_norm = web_latex(Dnorm) if Dnorm == 1: # since the factorization of (1) displays as "1" self.fact_disc = self.disc self.fact_disc_norm = self.disc else: Dfac = Factorization([(P, e) for P, e in zip(badprimes, disc_ords)]) self.fact_disc = web_latex_ideal_fact(Dfac) Dnormfac = Factorization([(q, e) for q, e in zip(badnorms, disc_ords)]) self.fact_disc_norm = web_latex(Dnormfac) if not self.is_minimal: Dmin = ideal_from_string(K, self.minD) self.mindisc = web_latex(Dmin) Dmin_norm = Dmin.norm() self.mindisc_norm = web_latex(Dmin_norm) if Dmin_norm == 1: # since the factorization of (1) displays as "1" self.fact_mindisc = self.mindisc self.fact_mindisc_norm = self.mindisc else: Dminfac = Factorization([ (P, e) for P, edd in zip(badprimes, mindisc_ords) ]) self.fact_mindisc = web_latex_ideal_fact(Dminfac) Dminnormfac = Factorization([ (q, e) for q, e in zip(badnorms, mindisc_ords) ]) self.fact_mindisc_norm = web_latex(Dminnormfac) j = self.field.parse_NFelt(self.jinv) # if j: # d = j.denominator() # n = d * j # numerator exists for quadratic fields only! # g = GCD(list(n)) # n1 = n / g # self.j = web_latex(n1) # if d != 1: # if n1 > 1: # # self.j = "("+self.j+")\(/\)"+web_latex(d) # self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d)) # else: # self.j = web_latex(d) # if g > 1: # if n1 > 1: # self.j = web_latex(g) + self.j # else: # self.j = web_latex(g) self.j = web_latex(j) self.fact_j = None # See issue 1258: some j factorizations work but take too long # (e.g. EllipticCurve/6.6.371293.1/1.1/a/1). Note that we do # store the factorization of the denominator of j and display # that, which is the most interesting part. # Images of Galois representations if not hasattr(self, 'galois_images'): #print "No Galois image data" self.galois_images = "?" self.non_surjective_primes = "?" self.galois_data = [] else: self.galois_data = [{ 'p': p, 'image': im } for p, im in zip(self.non_surjective_primes, self.galois_images)] # CM and End(E) self.cm_bool = "no" self.End = "\(\Z\)" if self.cm: self.rational_cm = K(self.cm).is_square() self.cm_sqf = ZZ(self.cm).squarefree_part() self.cm_bool = "yes (\(%s\))" % self.cm if self.cm % 4 == 0: d4 = ZZ(self.cm) // 4 self.End = "\(\Z[\sqrt{%s}]\)" % (d4) else: self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm # Galois images in CM case: if self.cm and self.galois_images != '?': self.cm_ramp = [ p for p in ZZ(self.cm).support() if not p in self.non_surjective_primes ] self.cm_nramp = len(self.cm_ramp) if self.cm_nramp == 1: self.cm_ramp = self.cm_ramp[0] else: self.cm_ramp = ", ".join([str(p) for p in self.cm_ramp]) # Sato-Tate: # The lines below will need to change once we have curves over non-quadratic fields # that contain the Hilbert class field of an imaginary quadratic field if self.cm: if self.signature == [0, 1] and ZZ( -self.abs_disc * self.cm).is_square(): self.ST = st_link_by_name(1, 2, 'U(1)') else: self.ST = st_link_by_name(1, 2, 'N(U(1))') else: self.ST = st_link_by_name(1, 2, 'SU(2)') # Q-curve / Base change self.qc = "no" try: if self.q_curve: self.qc = "yes" except AttributeError: # in case the db entry does not have this field set pass # Torsion self.ntors = web_latex(self.torsion_order) self.tr = len(self.torsion_structure) if self.tr == 0: self.tor_struct_pretty = "Trivial" if self.tr == 1: self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0] if self.tr == 2: self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple( self.torsion_structure) torsion_gens = [parse_point(K, P) for P in self.torsion_gens] self.torsion_gens = ",".join([web_point(P) for P in torsion_gens]) # Rank or bounds try: self.rk = web_latex(self.rank) except AttributeError: self.rk = "?" try: self.rk_bnds = "%s...%s" % tuple(self.rank_bounds) except AttributeError: self.rank_bounds = [0, Infinity] self.rk_bnds = "not available" # Generators try: gens = [parse_point(K, P) for P in self.gens] self.gens = ", ".join([web_point(P) for P in gens]) if self.rk == "?": self.reg = "not available" else: if gens: try: self.reg = self.reg except AttributeError: self.reg = "not available" pass # self.reg already set else: self.reg = 1 # otherwise we only get 1.00000... except AttributeError: self.gens = "not available" self.reg = "not available" try: if self.rank == 0: self.reg = 1 except AttributeError: pass # Local data for P, ld in zip(badprimes, local_data): ld['p'] = web_latex(P) ld['norm'] = P.norm() ld['kod'] = web_latex(ld['kod']).replace('$', '') # URLs of self and related objects: self.urls = {} # It's useful to be able to use this class out of context, when calling url_for will fail: try: self.urls['curve'] = url_for(".show_ecnf", nf=self.field_label, conductor_label=quote( self.conductor_label), class_label=self.iso_label, number=self.number) except RuntimeError: return self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=quote( self.conductor_label), class_label=self.iso_label) self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=quote( self.conductor_label)) self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label) # Isogeny information if self.number == 1: isogmat = self.isogeny_matrix else: isogmat = db_ecnf().find_one({ 'class_label': self.class_label, 'number': 1 })['isogeny_matrix'] self.class_deg = max([max(d) for d in isogmat]) self.one_deg = ZZ(self.class_deg).is_prime() self.ncurves = db_ecnf().count({'class_label': self.class_label}) isodegs = [str(d) for d in self.isogeny_degrees if d > 1] if len(isodegs) < 3: self.isogeny_degrees = " and ".join(isodegs) else: self.isogeny_degrees = " and ".join( [", ".join(isodegs[:-1]), isodegs[-1]]) 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) 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.friends = [] self.friends += [('Isogeny class ' + self.short_class_label, self.urls['class'])] self.friends += [('Twists', url_for('ecnf.index', field=self.field_label, jinv=rename_j(j)))] if totally_real: self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])] self.friends += [('L-function', self.urls['Lfunction'])] if imag_quadratic: #self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')] if "CM" in self.label: self.friends += [('Bianchi Modular Form is not cuspidal', '')] else: self.friends += [('Bianchi Modular Form %s' % self.bmf_label, self.bmf_url)] self.properties = [('Base field', self.field.field_pretty()), ('Label', self.label)] # Plot if K.signature()[0]: self.plot = encode_plot( EC_nf_plot(K, self.ainvs, self.field.generator_name())) self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot self.properties += [(None, self.plot_link)] self.properties += [ ('Conductor', self.cond), ('Conductor norm', self.cond_norm), # See issue #796 for why this is hidden (can be very large) # ('j-invariant', self.j), ('CM', self.cm_bool) ] if self.base_change: self.properties += [ ('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change])) ] else: self.base_change = [] # in case it was False instead of [] self.properties += [('Q-curve', self.qc)] r = self.rk if r == "?": r = self.rk_bnds self.properties += [ ('Torsion order', self.ntors), ('Rank', r), ] for E0 in self.base_change: self.friends += [('Base-change of %s /\(\Q\)' % E0, url_for("ec.by_ec_label", label=E0))] self._code = None # will be set if needed by get_code()
def make_E(self): #print("Creating ECNF object for {}".format(self.label)) #sys.stdout.flush() K = self.field.K() # a-invariants self.ainvs = parse_ainvs(K, self.ainvs) self.latex_ainvs = web_latex(self.ainvs) self.numb = str(self.number) # Conductor, discriminant, j-invariant if self.conductor_norm == 1: N = K.ideal(1) else: N = ideal_from_string(K, self.conductor_ideal) # The following can trigger expensive computations! #self.cond = web_latex(N) self.cond = pretty_ideal(N) self.cond_norm = web_latex(self.conductor_norm) local_data = self.local_data # NB badprimes is a list of primes which divide the # discriminant of this model. At most one of these might # actually be a prime of good reduction, if the curve has no # global minimal model. badprimes = [ideal_from_string(K, ld['p']) for ld in local_data] badnorms = [ZZ(ld['normp']) for ld in local_data] mindisc_ords = [ld['ord_disc'] for ld in local_data] # Assumption: the curve models stored in the database are # either global minimal models or minimal at all but one # prime, so the list here has length 0 or 1: self.non_min_primes = [ideal_from_string(K, P) for P in self.non_min_p] self.is_minimal = (len(self.non_min_primes) == 0) self.has_minimal_model = self.is_minimal disc_ords = [ld['ord_disc'] for ld in local_data] if not self.is_minimal: Pmin = self.non_min_primes[0] P_index = badprimes.index(Pmin) self.non_min_prime = pretty_ideal(Pmin) disc_ords[P_index] += 12 if self.conductor_norm == 1: # since the factorization of (1) displays as "1" self.fact_cond = self.cond self.fact_cond_norm = '1' else: Nfac = Factorization([(P, ld['ord_cond']) for P, ld in zip(badprimes, local_data)]) self.fact_cond = web_latex_ideal_fact(Nfac) Nnormfac = Factorization([(q, ld['ord_cond']) for q, ld in zip(badnorms, local_data)]) self.fact_cond_norm = web_latex(Nnormfac) # D is the discriminant ideal of the model D = prod([P**e for P, e in zip(badprimes, disc_ords)], K.ideal(1)) self.disc = pretty_ideal(D) Dnorm = D.norm() self.disc_norm = web_latex(Dnorm) if Dnorm == 1: # since the factorization of (1) displays as "1" self.fact_disc = self.disc self.fact_disc_norm = '1' else: Dfac = Factorization([(P, e) for P, e in zip(badprimes, disc_ords)]) self.fact_disc = web_latex_ideal_fact(Dfac) Dnormfac = Factorization([(q, e) for q, e in zip(badnorms, disc_ords)]) self.fact_disc_norm = web_latex(Dnormfac) if not self.is_minimal: Dmin = ideal_from_string(K, self.minD) self.mindisc = pretty_ideal(Dmin) Dmin_norm = Dmin.norm() self.mindisc_norm = web_latex(Dmin_norm) if Dmin_norm == 1: # since the factorization of (1) displays as "1" self.fact_mindisc = self.mindisc self.fact_mindisc_norm = self.mindisc_norm else: Dminfac = Factorization(list(zip(badprimes, mindisc_ords))) self.fact_mindisc = web_latex_ideal_fact(Dminfac) Dminnormfac = Factorization(list(zip(badnorms, mindisc_ords))) self.fact_mindisc_norm = web_latex(Dminnormfac) j = self.field.parse_NFelt(self.jinv) # if j: # d = j.denominator() # n = d * j # numerator exists for quadratic fields only! # g = GCD(list(n)) # n1 = n / g # self.j = web_latex(n1) # if d != 1: # if n1 > 1: # # self.j = "("+self.j+")\(/\)"+web_latex(d) # self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d)) # else: # self.j = web_latex(d) # if g > 1: # if n1 > 1: # self.j = web_latex(g) + self.j # else: # self.j = web_latex(g) self.j = web_latex(j) self.fact_j = None # See issue 1258: some j factorizations work but take too long # (e.g. EllipticCurve/6.6.371293.1/1.1/a/1). Note that we do # store the factorization of the denominator of j and display # that, which is the most interesting part. # The equation is stored in the database as a latex string. # Some of these have extraneous double quotes at beginning and # end, shich we fix here. We also strip out initial \( and \) # (if present) which are added in the template. self.equation = self.equation.replace('"', '').replace('\\(', '').replace( '\\)', '') # Images of Galois representations if not hasattr(self, 'galois_images'): #print "No Galois image data" self.galois_images = "?" self.non_surjective_primes = "?" self.galois_data = [] else: self.galois_data = [{ 'p': p, 'image': im } for p, im in zip(self.non_surjective_primes, self.galois_images)] # CM and End(E) self.cm_bool = "no" self.End = r"\(\Z\)" if self.cm: # When we switch to storing rational cm by having |D| in # the column, change the following lines: if self.cm > 0: self.rational_cm = True self.cm = -self.cm else: self.rational_cm = K(self.cm).is_square() self.cm_sqf = ZZ(self.cm).squarefree_part() self.cm_bool = r"yes (\(%s\))" % self.cm if self.cm % 4 == 0: d4 = ZZ(self.cm) // 4 self.End = r"\(\Z[\sqrt{%s}]\)" % (d4) else: self.End = r"\(\Z[(1+\sqrt{%s})/2]\)" % self.cm # Galois images in CM case: if self.cm and self.galois_images != '?': self.cm_ramp = [ p for p in ZZ(self.cm).support() if not p in self.non_surjective_primes ] self.cm_nramp = len(self.cm_ramp) if self.cm_nramp == 1: self.cm_ramp = self.cm_ramp[0] else: self.cm_ramp = ", ".join([str(p) for p in self.cm_ramp]) # Sato-Tate: # The lines below will need to change once we have curves over non-quadratic fields # that contain the Hilbert class field of an imaginary quadratic field if self.cm: if self.signature == [0, 1] and ZZ( -self.abs_disc * self.cm).is_square(): self.ST = st_link_by_name(1, 2, 'U(1)') else: self.ST = st_link_by_name(1, 2, 'N(U(1))') else: self.ST = st_link_by_name(1, 2, 'SU(2)') # Q-curve / Base change try: qc = self.q_curve if qc is True: self.qc = "yes" elif qc is False: self.qc = "no" else: # just in case self.qc = "not determined" except AttributeError: self.qc = "not determined" # Torsion self.ntors = web_latex(self.torsion_order) self.tr = len(self.torsion_structure) if self.tr == 0: self.tor_struct_pretty = "trivial" if self.tr == 1: self.tor_struct_pretty = r"\(\Z/%s\Z\)" % self.torsion_structure[0] if self.tr == 2: self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple( self.torsion_structure) self.torsion_gens = [ web_point(parse_point(K, P)) for P in self.torsion_gens ] # BSD data # # We divide into 3 cases, based on rank_bounds [lb,ub], # analytic_rank ar, (lb=ngens always). The flag # self.bsd_status is set to one of the following: # # "unconditional" # lb=ar=ub: we always have reg but in some cases over sextic fields we do not have omega, Lvalue, sha. # i.e. [lb,ar,ub] = [r,r,r] # # "conditional" # lb=ar<ub: we always have reg but in some cases over sextic fields we do not have omega, Lvalue, sha. # e.g. [lb,ar,ub] = [0,0,2], [1,1,3] # # "missing_gens" # lb<ar<=ub # e.g. [lb,ar,ub] = [0,1,1], [0,2,2], [1,2,2], [0,1,3] # # "incomplete" # ar not computed. (We can always set lb=0, ub=Infinity.) # Rank and bounds try: self.rk = web_latex(self.rank) except AttributeError: self.rank = None self.rk = "not available" try: self.rk_lb, self.rk_ub = self.rank_bounds except AttributeError: self.rk_lb = 0 self.rk_ub = Infinity self.rank_bounds = "not available" # Analytic rank try: self.ar = web_latex(self.analytic_rank) except AttributeError: self.analytic_rank = None self.ar = "not available" # for debugging: assert self.rk == "not available" or (self.rk_lb == self.rank and self.rank == self.rk_ub) assert self.ar == "not available" or (self.rk_lb <= self.analytic_rank and self.analytic_rank <= self.rk_ub) self.bsd_status = "incomplete" if self.analytic_rank != None: if self.rk_lb == self.rk_ub: self.bsd_status = "unconditional" elif self.rk_lb == self.analytic_rank: self.bsd_status = "conditional" else: self.bsd_status = "missing_gens" # Regulator only in conditional/unconditional cases, or when we know the rank: if self.bsd_status in ["conditional", "unconditional"]: if self.ar == 0: self.reg = web_latex(1) # otherwise we only get 1.00000... else: try: self.reg = web_latex(self.reg) except AttributeError: self.reg = "not available" elif self.rk != "not available": self.reg = web_latex(self.reg) if self.rank else web_latex(1) else: self.reg = "not available" # Generators try: self.gens = [web_point(parse_point(K, P)) for P in self.gens] except AttributeError: self.gens = [] # Global period try: self.omega = web_latex(self.omega) except AttributeError: self.omega = "not available" # L-value try: r = int(self.analytic_rank) # lhs = "L(E,1) = " if r==0 else "L'(E,1) = " if r==1 else "L^{{({})}}(E,1)/{}! = ".format(r,r) self.Lvalue = "\\(" + str(self.Lvalue) + "\\)" except (TypeError, AttributeError): self.Lvalue = "not available" # Tamagawa product tamagawa_numbers = [ZZ(_ld['cp']) for _ld in self.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 ] if len(cp_fac) > 1: self.tamagawa_factors = r'\cdot'.join(cp_fac) else: self.tamagawa_factors = None self.tamagawa_product = web_latex(prod(tamagawa_numbers, 1)) # Analytic Sha try: self.sha = web_latex(self.sha) + " (rounded)" except AttributeError: self.sha = "not available" # Local data # Fix for Kodaira symbols, which in the database start and end # with \( and \) and may have multiple backslashes. Note that # to put a single backslash into a python string you have to # use '\\' which will display as '\\' but only counts as one # character in the string. which are added in the template. def tidy_kod(kod): while '\\\\' in kod: kod = kod.replace('\\\\', '\\') kod = kod.replace('\\(', '').replace('\\)', '') return kod for P, ld in zip(badprimes, local_data): ld['p'] = web_latex(P) ld['norm'] = P.norm() ld['kod'] = tidy_kod(ld['kod']) # URLs of self and related objects: self.urls = {} # It's useful to be able to use this class out of context, when calling url_for will fail: try: self.urls['curve'] = url_for(".show_ecnf", nf=self.field_label, conductor_label=quote( self.conductor_label), class_label=self.iso_label, number=self.number) except RuntimeError: return self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=quote( self.conductor_label), class_label=self.iso_label) self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=quote( self.conductor_label)) self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label) # Isogeny information self.one_deg = ZZ(self.class_deg).is_prime() isodegs = [str(d) for d in self.isodeg if d > 1] if len(isodegs) < 3: self.isodeg = " and ".join(isodegs) else: self.isodeg = " and ".join([", ".join(isodegs[:-1]), isodegs[-1]]) 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 < 70000: # 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 isog_class.py # and should be refactored self.friends = [] self.friends += [('Isogeny class ' + self.short_class_label, self.urls['class'])] self.friends += [('Twists', url_for('ecnf.index', field=self.field_label, jinv=rename_j(j)))] if totally_real and not 'Lfunction' 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 not 'Lfunction' 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, '') ] self.properties = [('Label', self.label)] # Plot if K.signature()[0]: self.plot = encode_plot( EC_nf_plot(K, self.ainvs, self.field.generator_name())) self.plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format( self.plot) self.properties += [(None, self.plot_link)] self.properties += [('Base field', self.field.field_pretty())] self.properties += [ ('Conductor', self.cond), ('Conductor norm', self.cond_norm), # See issue #796 for why this is hidden (can be very large) # ('j-invariant', self.j), ('CM', self.cm_bool) ] if self.base_change: self.properties += [ ('Base change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change])) ] else: self.base_change = [] # in case it was False instead of [] self.properties += [('Base change', 'no')] self.properties += [('Q-curve', self.qc)] r = self.rk if r == "?": r = self.rk_bnds self.properties += [ ('Torsion order', self.ntors), ('Rank', r), ] for E0 in self.base_change: self.friends += [(r'Base change of %s /\(\Q\)' % E0, url_for("ec.by_ec_label", label=E0))] self._code = None # will be set if needed by get_code() self.downloads = [('All stored data to text', url_for(".download_ECNF_all", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number))] for lang in [["Magma", "magma"], ["SageMath", "sage"], ["GP", "gp"]]: self.downloads.append( ('Code to {}'.format(lang[0]), url_for(".ecnf_code_download", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number, download_type=lang[1]))) if 'Lfunction' in self.urls: Lfun = get_lfunction_by_url( self.urls['Lfunction'].lstrip('/L').rstrip('/'), projection=['degree', 'trace_hash', 'Lhash']) if Lfun is None: self.friends += [('L-function not available', "")] else: 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] } self.friends += names_and_urls(instances, exclude=exclude) self.friends += [('L-function', self.urls['Lfunction'])] else: self.friends += [('L-function not available', "")]
def render_bmf_space_webpage(field_label, level_label): info = {} t = "Bianchi Modular Forms of Level %s over %s" % (level_label, field_label) credit = bianchi_credit bread = [('Modular Forms', url_for('mf.modular_form_main_page')), ('Bianchi Modular Forms', url_for(".index")), (field_pretty(field_label), url_for(".render_bmf_field_dim_table_gl2", field_label=field_label)), (level_label, '')] friends = [] properties2 = [] if not field_label_regex.match(field_label): info['err'] = "%s is not a valid label for an imaginary quadratic field" % field_label else: pretty_field_label = field_pretty(field_label) if not db_dims().find({'field_label': field_label}): info['err'] = "no dimension information exists in the database for field %s" % pretty_field_label else: t = "Bianchi Modular Forms of level %s over %s" % (level_label, pretty_field_label) data = db_dims().find({'field_label': field_label, 'level_label': level_label}) nres = data.count() if nres==0: info['err'] = "no dimension information exists in the database for level %s and field %s" % (level_label, pretty_field_label) else: data = data.next() info['label'] = data['label'] info['nf'] = nf = WebNumberField(field_label) info['field_label'] = field_label info['pretty_field_label'] = pretty_field_label info['level_label'] = level_label info['level_norm'] = data['level_norm'] info['field_poly'] = teXify_pol(str(nf.poly())) info['field_knowl'] = nf_display_knowl(field_label, getDBConnection(), pretty_field_label) w = 'i' if nf.disc()==-4 else 'a' L = nf.K().change_names(w) alpha = L.gen() info['field_gen'] = latex(alpha) I = ideal_from_label(L,level_label) info['level_gen'] = latex(I.gens_reduced()[0]) info['level_fact'] = web_latex_ideal_fact(I.factor(), enclose=False) dim_data = data['gl2_dims'] weights = dim_data.keys() weights.sort(key=lambda w: int(w)) for w in weights: dim_data[w]['dim']=dim_data[w]['cuspidal_dim'] info['dim_data'] = dim_data info['weights'] = weights info['nweights'] = len(weights) newdim = data['gl2_dims']['2']['new_dim'] newforms = db_forms().find({'field_label':field_label, 'level_label':level_label}).sort('label_suffix', ASCENDING) info['nfdata'] = [{ 'label': f['short_label'], 'url': url_for(".render_bmf_webpage",field_label=f['field_label'], level_label=f['level_label'], label_suffix=f['label_suffix']), 'wt': f['weight'], 'dim': f['dimension'], 'sfe': "+1" if f['sfe']==1 else "-1", 'bc': bc_info(f['bc']), 'cm': cm_info(f['CM']), } for f in newforms] info['nnewforms'] = len(info['nfdata']) properties2 = [('Base field', pretty_field_label), ('Level',info['level_label']), ('Norm',str(info['level_norm'])), ('New dimension',str(newdim))] friends = [('Newform {}'.format(f['label']), f['url']) for f in info['nfdata'] ] return render_template("bmf-space.html", info=info, credit=credit, title=t, bread=bread, properties2=properties2, friends=friends)
def make_E(self): coeffs = self.ainvs # list of 5 lists of d strings self.ainvs = [self.field.parse_NFelt(x) for x in coeffs] self.latex_ainvs = web_latex(self.ainvs) from sage.schemes.elliptic_curves.all import EllipticCurve self.E = E = EllipticCurve(self.ainvs) self.equn = web_latex(E) self.numb = str(self.number) # Conductor, discriminant, j-invariant N = E.conductor() self.cond = web_latex(N) self.cond_norm = web_latex(N.norm()) if N.norm()==1: # since the factorization of (1) displays as "1" self.fact_cond = self.cond else: self.fact_cond = web_latex_ideal_fact(N.factor()) self.fact_cond_norm = web_latex(N.norm().factor()) D = self.field.K().ideal(E.discriminant()) self.disc = web_latex(D) self.disc_norm = web_latex(D.norm()) if D.norm()==1: # since the factorization of (1) displays as "1" self.fact_disc = self.disc else: self.fact_disc = web_latex_ideal_fact(D.factor()) self.fact_disc_norm = web_latex(D.norm().factor()) # Minimal model? # # All curves in the database should be given # by models which are globally minimal if possible, else # minimal at all but one prime. But we do not rely on this # here, and the display should be correct if either (1) there # exists a global minimal model but this model is not; or (2) # this model is non-minimal at more than one prime. # self.non_min_primes = non_minimal_primes(E) self.is_minimal = (len(self.non_min_primes)==0) self.has_minimal_model = True if not self.is_minimal: self.non_min_prime = ','.join([web_latex(P) for P in self.non_min_primes]) self.has_minimal_model = has_global_minimal_model(E) if not self.is_minimal: Dmin = minimal_discriminant_ideal(E) self.mindisc = web_latex(Dmin) self.mindisc_norm = web_latex(Dmin.norm()) if Dmin.norm()==1: # since the factorization of (1) displays as "1" self.fact_mindisc = self.mindisc else: self.fact_mindisc = web_latex_ideal_fact(Dmin.factor()) self.fact_mindisc_norm = web_latex(Dmin.norm().factor()) j = E.j_invariant() if j: d = j.denominator() n = d*j # numerator exists for quadratic fields only! g = GCD(list(n)) n1 = n/g self.j = web_latex(n1) if d!=1: if n1>1: #self.j = "("+self.j+")\(/\)"+web_latex(d) self.j = web_latex(r"\frac{%s}{%s}" % (self.j,d)) else: self.j = web_latex(d) if g>1: if n1>1: self.j = web_latex(g) + self.j else: self.j = web_latex(g) self.j = web_latex(j) self.fact_j = None if j.is_zero(): self.fact_j = web_latex(j) else: try: self.fact_j = web_latex(j.factor()) except (ArithmeticError,ValueError): # if not all prime ideal factors principal pass # CM and End(E) self.cm_bool = "no" self.End = "\(\Z\)" if self.cm: self.cm_bool = "yes (\(%s\))" % self.cm if self.cm%4==0: d4 = ZZ(self.cm)//4 self.End = "\(\Z[\sqrt{%s}]\)"%(d4) else: self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm # Q-curve / Base change self.qc = "no" try: if self.q_curve: self.qc = "yes" except AttributeError: # in case the db entry does not have this field set pass # Torsion self.ntors = web_latex(self.torsion_order) self.tr = len(self.torsion_structure) if self.tr==0: self.tor_struct_pretty = "Trivial" if self.tr==1: self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0] if self.tr==2: self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(self.torsion_structure) torsion_gens = [E([self.field.parse_NFelt(x) for x in P]) for P in self.torsion_gens] self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens]) # Rank etc try: self.rk = web_latex(self.rank) except AttributeError: self.rk = "not recorded" # if rank in self: # self.r = web_latex(self.rank) # Local data self.local_data = [] for p in N.prime_factors(): self.local_info = E.local_data(p, algorithm="generic") self.local_data.append({'p': web_latex(p), 'norm': web_latex(p.norm().factor()), 'tamagawa_number': self.local_info.tamagawa_number(), 'kodaira_symbol': web_latex(self.local_info.kodaira_symbol()).replace('$', ''), 'reduction_type': self.local_info.bad_reduction_type(), 'ord_den_j': max(0,-E.j_invariant().valuation(p)), 'ord_mindisc': self.local_info.discriminant_valuation() }) # URLs of self and related objects: self.urls = {} self.urls['curve'] = url_for(".show_ecnf", nf = self.field_label, conductor_label=self.conductor_label, class_label = self.iso_label, number = self.number) 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) if self.field.is_real_quadratic(): 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 self.field.is_imag_quadratic(): self.bmf_label = "-".join([self.field.label,self.conductor_label,self.iso_label]) self.friends = [] self.friends += [('Isogeny class '+self.short_class_label, self.urls['class'])] self.friends += [('Twists',url_for('ecnf.index',field_label=self.field_label,jinv=self.jinv))] if self.field.is_real_quadratic(): self.friends += [('Hilbert Modular Form '+self.hmf_label, self.urls['hmf'])] if self.field.is_imag_quadratic(): self.friends += [('Bianchi Modular Form %s not yet available' % self.bmf_label, '')] self.properties = [ ('Base field', self.field.field_pretty()), ('Label' , self.label)] # Plot if E.base_field().signature()[0]: self.plot = encode_plot(EC_nf_plot(E,self.field.generator_name())) self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot self.properties += [(None, self.plot_link)] self.properties += [ ('Conductor' , self.cond), ('Conductor norm' , self.cond_norm), ('j-invariant' , self.j), ('CM' , self.cm_bool)] if self.base_change: self.properties += [('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))] else: self.base_change = [] # in case it was False instead of [] self.properties += [('Q-curve' , self.qc)] self.properties += [ ('Torsion order' , self.ntors), ('Rank' , self.rk), ] for E0 in self.base_change: self.friends += [('Base-change of %s /\(\Q\)' % E0 , url_for("ec.by_ec_label", label=E0))]
def make_E(self): coeffs = self.ainvs # list of 5 lists of d strings self.ainvs = [self.field.parse_NFelt(x) for x in coeffs] self.latex_ainvs = web_latex(self.ainvs) from sage.schemes.elliptic_curves.all import EllipticCurve self.E = E = EllipticCurve(self.ainvs) self.equn = web_latex(E) self.numb = str(self.number) # Conductor, discriminant, j-invariant N = E.conductor() self.cond = web_latex(N) self.cond_norm = web_latex(N.norm()) if N.norm() == 1: # since the factorization of (1) displays as "1" self.fact_cond = self.cond else: self.fact_cond = web_latex_ideal_fact(N.factor()) self.fact_cond_norm = web_latex(N.norm().factor()) D = self.field.K().ideal(E.discriminant()) self.disc = web_latex(D) self.disc_norm = web_latex(D.norm()) if D.norm() == 1: # since the factorization of (1) displays as "1" self.fact_disc = self.disc else: self.fact_disc = web_latex_ideal_fact(D.factor()) self.fact_disc_norm = web_latex(D.norm().factor()) # Minimal model? # # All curves in the database should be given # by models which are globally minimal if possible, else # minimal at all but one prime. But we do not rely on this # here, and the display should be correct if either (1) there # exists a global minimal model but this model is not; or (2) # this model is non-minimal at more than one prime. # self.non_min_primes = non_minimal_primes(E) self.is_minimal = (len(self.non_min_primes) == 0) self.has_minimal_model = True if not self.is_minimal: self.non_min_prime = ','.join( [web_latex(P) for P in self.non_min_primes]) self.has_minimal_model = has_global_minimal_model(E) if not self.is_minimal: Dmin = minimal_discriminant_ideal(E) self.mindisc = web_latex(Dmin) self.mindisc_norm = web_latex(Dmin.norm()) if Dmin.norm( ) == 1: # since the factorization of (1) displays as "1" self.fact_mindisc = self.mindisc else: self.fact_mindisc = web_latex_ideal_fact(Dmin.factor()) self.fact_mindisc_norm = web_latex(Dmin.norm().factor()) j = E.j_invariant() if j: d = j.denominator() n = d * j # numerator exists for quadratic fields only! g = GCD(list(n)) n1 = n / g self.j = web_latex(n1) if d != 1: if n1 > 1: #self.j = "("+self.j+")\(/\)"+web_latex(d) self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d)) else: self.j = web_latex(d) if g > 1: if n1 > 1: self.j = web_latex(g) + self.j else: self.j = web_latex(g) self.j = web_latex(j) self.fact_j = None if j.is_zero(): self.fact_j = web_latex(j) else: try: self.fact_j = web_latex(j.factor()) except (ArithmeticError, ValueError): # if not all prime ideal factors principal pass # CM and End(E) self.cm_bool = "no" self.End = "\(\Z\)" if self.cm: self.cm_bool = "yes (\(%s\))" % self.cm if self.cm % 4 == 0: d4 = ZZ(self.cm) // 4 self.End = "\(\Z[\sqrt{%s}]\)" % (d4) else: self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm # Q-curve / Base change self.qc = "no" try: if self.q_curve: self.qc = "yes" except AttributeError: # in case the db entry does not have this field set pass # Torsion self.ntors = web_latex(self.torsion_order) self.tr = len(self.torsion_structure) if self.tr == 0: self.tor_struct_pretty = "Trivial" if self.tr == 1: self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0] if self.tr == 2: self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple( self.torsion_structure) torsion_gens = [ E([self.field.parse_NFelt(x) for x in P]) for P in self.torsion_gens ] self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens]) # Rank etc try: self.rk = web_latex(self.rank) except AttributeError: self.rk = "not recorded" # if rank in self: # self.r = web_latex(self.rank) # Local data self.local_data = [] for p in N.prime_factors(): self.local_info = E.local_data(p, algorithm="generic") self.local_data.append({ 'p': web_latex(p), 'norm': web_latex(p.norm().factor()), 'tamagawa_number': self.local_info.tamagawa_number(), 'kodaira_symbol': web_latex(self.local_info.kodaira_symbol()).replace('$', ''), 'reduction_type': self.local_info.bad_reduction_type(), 'ord_den_j': max(0, E.j_invariant().valuation(p)), 'ord_mindisc': self.local_info.discriminant_valuation() }) # URLs of self and related objects: self.urls = {} self.urls['curve'] = url_for(".show_ecnf", nf=self.field_label, conductor_label=self.conductor_label, class_label=self.iso_label, number=self.number) 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) if self.field.is_real_quadratic(): 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 self.field.is_imag_quadratic(): self.bmf_label = "-".join( [self.field.label, self.conductor_label, self.iso_label]) self.friends = [] self.friends += [('Isogeny class ' + self.short_class_label, self.urls['class'])] if self.field.is_real_quadratic(): self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])] if self.field.is_imag_quadratic(): self.friends += [ ('Bianchi Modular Form %s not yet available' % self.bmf_label, '') ] self.properties = [('Base field', self.field.field_pretty()), ('Label', self.label)] # Plot n1 = len(E.base_field().embeddings(RR)) if (n1): self.plot = encode_plot(EC_nf_plot(E, self.field.generator_name())) self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot self.properties += [(None, self.plot_link)] self.properties += [('Conductor', self.cond), ('Conductor norm', self.cond_norm), ('j-invariant', self.j), ('CM', self.cm_bool)] if self.base_change: self.properties += [ ('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change])) ] else: self.base_change = [] # in case it was False instead of [] self.properties += [('Q-curve', self.qc)] self.properties += [ ('Torsion order', self.ntors), ('Rank', self.rk), ] for E0 in self.base_change: self.friends += [('Base-change of %s /\(\Q\)' % E0, url_for("ec.by_ec_label", label=E0))]
def render_bmf_space_webpage(field_label, level_label): info = {} t = "Bianchi Modular Forms of Level %s over %s" % (level_label, field_label) credit = bianchi_credit bread = [('Modular Forms', url_for('mf.modular_form_main_page')), ('Bianchi Modular Forms', url_for(".index")), (field_pretty(field_label), url_for(".render_bmf_field_dim_table_gl2", field_label=field_label)), (level_label, '')] friends = [] properties2 = [] if not field_label_regex.match(field_label): info['err'] = "%s is not a valid label for an imaginary quadratic field" % field_label else: pretty_field_label = field_pretty(field_label) if not db.bmf_dims.exists({'field_label': field_label}): info['err'] = "no dimension information exists in the database for field %s" % pretty_field_label else: t = "Bianchi Modular Forms of level %s over %s" % (level_label, pretty_field_label) data = db.bmf_dims.lucky({'field_label': field_label, 'level_label': level_label}) if not data: info['err'] = "no dimension information exists in the database for level %s and field %s" % (level_label, pretty_field_label) else: info['label'] = data['label'] info['nf'] = nf = WebNumberField(field_label) info['field_label'] = field_label info['pretty_field_label'] = pretty_field_label info['level_label'] = level_label info['level_norm'] = data['level_norm'] info['field_poly'] = teXify_pol(str(nf.poly())) info['field_knowl'] = nf_display_knowl(field_label, pretty_field_label) w = 'i' if nf.disc()==-4 else 'a' L = nf.K().change_names(w) alpha = L.gen() info['field_gen'] = latex(alpha) I = ideal_from_label(L,level_label) info['level_gen'] = latex(I.gens_reduced()[0]) info['level_fact'] = web_latex_ideal_fact(I.factor(), enclose=False) dim_data = data['gl2_dims'] weights = dim_data.keys() weights.sort(key=lambda w: int(w)) for w in weights: dim_data[w]['dim']=dim_data[w]['cuspidal_dim'] info['dim_data'] = dim_data info['weights'] = weights info['nweights'] = len(weights) newdim = data['gl2_dims']['2']['new_dim'] newforms = db.bmf_forms.search({'field_label':field_label, 'level_label':level_label}) info['nfdata'] = [{ 'label': f['short_label'], 'url': url_for(".render_bmf_webpage",field_label=f['field_label'], level_label=f['level_label'], label_suffix=f['label_suffix']), 'wt': f['weight'], 'dim': f['dimension'], 'sfe': "+1" if f.get('sfe',None)==1 else "-1" if f.get('sfe',None)==-1 else "?", 'bc': bc_info(f['bc']), 'cm': cm_info(f.get('CM','?')), } for f in newforms] info['nnewforms'] = len(info['nfdata']) properties2 = [('Base field', pretty_field_label), ('Level',info['level_label']), ('Norm',str(info['level_norm'])), ('New dimension',str(newdim))] friends = [('Newform {}'.format(f['label']), f['url']) for f in info['nfdata'] ] return render_template("bmf-space.html", info=info, credit=credit, title=t, bread=bread, properties2=properties2, friends=friends)
def make_E(self): K = self.field.K() # a-invariants self.ainvs = parse_ainvs(K,self.ainvs) self.latex_ainvs = web_latex(self.ainvs) self.numb = str(self.number) # Conductor, discriminant, j-invariant N = ideal_from_string(K,self.conductor_ideal) self.cond = web_latex(N) self.cond_norm = web_latex(self.conductor_norm) local_data = self.local_data # NB badprimes is a list of primes which divide the # discriminant of this model. At most one of these might # actually be a prime of good reduction, if the curve has no # global minimal model. badprimes = [ideal_from_string(K,ld['p']) for ld in local_data] badnorms = [ZZ(ld['normp']) for ld in local_data] mindisc_ords = [ld['ord_disc'] for ld in local_data] # Assumption: the curve models stored in the database are # either global minimal models or minimal at all but one # prime, so the list here has length 0 or 1: self.non_min_primes = [ideal_from_string(K,P) for P in self.non_min_p] self.is_minimal = (len(self.non_min_primes) == 0) self.has_minimal_model = self.is_minimal disc_ords = [ld['ord_disc'] for ld in local_data] if not self.is_minimal: Pmin = self.non_min_primes[0] P_index = badprimes.index(Pmin) self.non_min_prime = web_latex(Pmin) disc_ords[P_index] += 12 if self.conductor_norm == 1: # since the factorization of (1) displays as "1" self.fact_cond = self.cond self.fact_cond_norm = self.cond else: Nfac = Factorization([(P,ld['ord_cond']) for P,ld in zip(badprimes,local_data)]) self.fact_cond = web_latex_ideal_fact(Nfac) Nnormfac = Factorization([(q,ld['ord_cond']) for q,ld in zip(badnorms,local_data)]) self.fact_cond_norm = web_latex(Nnormfac) # D is the discriminant ideal of the model D = prod([P**e for P,e in zip(badprimes,disc_ords)], K.ideal(1)) self.disc = web_latex(D) Dnorm = D.norm() self.disc_norm = web_latex(Dnorm) if Dnorm == 1: # since the factorization of (1) displays as "1" self.fact_disc = self.disc self.fact_disc_norm = self.disc else: Dfac = Factorization([(P,e) for P,e in zip(badprimes,disc_ords)]) self.fact_disc = web_latex_ideal_fact(Dfac) Dnormfac = Factorization([(q,e) for q,e in zip(badnorms,disc_ords)]) self.fact_disc_norm = web_latex(Dnormfac) if not self.is_minimal: Dmin = ideal_from_string(K,self.minD) self.mindisc = web_latex(Dmin) Dmin_norm = Dmin.norm() self.mindisc_norm = web_latex(Dmin_norm) if Dmin_norm == 1: # since the factorization of (1) displays as "1" self.fact_mindisc = self.mindisc self.fact_mindisc_norm = self.mindisc else: Dminfac = Factorization([(P,e) for P,edd in zip(badprimes,mindisc_ords)]) self.fact_mindisc = web_latex_ideal_fact(Dminfac) Dminnormfac = Factorization([(q,e) for q,e in zip(badnorms,mindisc_ords)]) self.fact_mindisc_norm = web_latex(Dminnormfac) j = self.field.parse_NFelt(self.jinv) # if j: # d = j.denominator() # n = d * j # numerator exists for quadratic fields only! # g = GCD(list(n)) # n1 = n / g # self.j = web_latex(n1) # if d != 1: # if n1 > 1: # # self.j = "("+self.j+")\(/\)"+web_latex(d) # self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d)) # else: # self.j = web_latex(d) # if g > 1: # if n1 > 1: # self.j = web_latex(g) + self.j # else: # self.j = web_latex(g) self.j = web_latex(j) self.fact_j = None # See issue 1258: some j factorizations work but take too long # (e.g. EllipticCurve/6.6.371293.1/1.1/a/1). Note that we do # store the factorization of the denominator of j and display # that, which is the most interesting part. # CM and End(E) self.cm_bool = "no" self.End = "\(\Z\)" if self.cm: self.cm_bool = "yes (\(%s\))" % self.cm if self.cm % 4 == 0: d4 = ZZ(self.cm) // 4 self.End = "\(\Z[\sqrt{%s}]\)" % (d4) else: self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm # The line below will need to change once we have curves over non-quadratic fields # that contain the Hilbert class field of an imaginary quadratic field if self.signature == [0,1] and ZZ(-self.abs_disc*self.cm).is_square(): self.ST = st_link_by_name(1,2,'U(1)') else: self.ST = st_link_by_name(1,2,'N(U(1))') else: self.ST = st_link_by_name(1,2,'SU(2)') # Q-curve / Base change self.qc = "no" try: if self.q_curve: self.qc = "yes" except AttributeError: # in case the db entry does not have this field set pass # Torsion self.ntors = web_latex(self.torsion_order) self.tr = len(self.torsion_structure) if self.tr == 0: self.tor_struct_pretty = "Trivial" if self.tr == 1: self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0] if self.tr == 2: self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(self.torsion_structure) torsion_gens = [parse_point(K,P) for P in self.torsion_gens] self.torsion_gens = ",".join([web_point(P) for P in torsion_gens]) # Rank or bounds try: self.rk = web_latex(self.rank) except AttributeError: self.rk = "?" try: self.rk_bnds = "%s...%s" % tuple(self.rank_bounds) except AttributeError: self.rank_bounds = [0, Infinity] self.rk_bnds = "not available" # Generators try: gens = [parse_point(K,P) for P in self.gens] self.gens = ", ".join([web_point(P) for P in gens]) if self.rk == "?": self.reg = "not available" else: if gens: try: self.reg = self.reg except AttributeError: self.reg = "not available" pass # self.reg already set else: self.reg = 1 # otherwise we only get 1.00000... except AttributeError: self.gens = "not available" self.reg = "not available" try: if self.rank == 0: self.reg = 1 except AttributeError: pass # Local data for P,ld in zip(badprimes,local_data): ld['p'] = web_latex(P) ld['norm'] = P.norm() ld['kod'] = web_latex(ld['kod']).replace('$', '') # URLs of self and related objects: self.urls = {} # It's useful to be able to use this class out of context, when calling url_for will fail: try: self.urls['curve'] = url_for(".show_ecnf", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number) except RuntimeError: return self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label) self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=quote(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) 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.friends = [] self.friends += [('Isogeny class ' + self.short_class_label, self.urls['class'])] self.friends += [('Twists', url_for('ecnf.index', field=self.field_label, jinv=rename_j(j)))] if totally_real: self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])] self.friends += [('L-function', self.urls['Lfunction'])] if imag_quadratic: self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')] self.properties = [ ('Base field', self.field.field_pretty()), ('Label', self.label)] # Plot if K.signature()[0]: self.plot = encode_plot(EC_nf_plot(K,self.ainvs, self.field.generator_name())) self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot self.properties += [(None, self.plot_link)] self.properties += [ ('Conductor', self.cond), ('Conductor norm', self.cond_norm), # See issue #796 for why this is hidden (can be very large) # ('j-invariant', self.j), ('CM', self.cm_bool)] if self.base_change: self.properties += [('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))] else: self.base_change = [] # in case it was False instead of [] self.properties += [('Q-curve', self.qc)] r = self.rk if r == "?": r = self.rk_bnds self.properties += [ ('Torsion order', self.ntors), ('Rank', r), ] for E0 in self.base_change: self.friends += [('Base-change of %s /\(\Q\)' % E0, url_for("ec.by_ec_label", label=E0))] self._code = None # will be set if needed by get_code()
def render_bmf_space_webpage(field_label, level_label): info = {} t = "Bianchi modular forms of level %s over %s" % (level_label, field_label) bread = get_bread([ (field_pretty(field_label), url_for(".render_bmf_field_dim_table_gl2", field_label=field_label)), (level_label, '')]) friends = [] properties = [] if not field_label_regex.match(field_label): info['err'] = "%s is not a valid label for an imaginary quadratic field" % field_label else: pretty_field_label = field_pretty(field_label) if not db.bmf_dims.exists({'field_label': field_label}): info['err'] = "no dimension information exists in the database for field %s" % pretty_field_label else: t = "Bianchi modular forms of level %s over %s" % (level_label, pretty_field_label) data = db.bmf_dims.lucky({'field_label': field_label, 'level_label': level_label}) if not data: info['err'] = "no dimension information exists in the database for level %s and field %s" % (level_label, pretty_field_label) else: info['label'] = data['label'] info['nf'] = nf = WebNumberField(field_label) info['field_label'] = field_label info['pretty_field_label'] = pretty_field_label info['level_label'] = level_label info['level_norm'] = data['level_norm'] info['field_poly'] = teXify_pol(str(nf.poly())) info['field_knowl'] = nf_display_knowl(field_label, pretty_field_label) w = 'i' if nf.disc()==-4 else 'a' L = nf.K().change_names(w) alpha = L.gen() info['field_gen'] = latex(alpha) I = ideal_from_label(L,level_label) info['level_gen'] = latex(I.gens_reduced()[0]) info['level_fact'] = web_latex_ideal_fact(I.factor(), enclose=False) dim_data = data['gl2_dims'] weights = list(dim_data) weights.sort(key=int) for w in weights: dim_data[w]['dim']=dim_data[w]['cuspidal_dim'] info['dim_data'] = dim_data info['weights'] = weights info['nweights'] = len(weights) newdim = data['gl2_dims']['2']['new_dim'] newforms = db.bmf_forms.search({'field_label':field_label, 'level_label':level_label}) info['nfdata'] = [{ 'label': f['short_label'], 'url': url_for(".render_bmf_webpage",field_label=f['field_label'], level_label=f['level_label'], label_suffix=f['label_suffix']), 'wt': f['weight'], 'dim': f['dimension'], 'sfe': "+1" if f.get('sfe',None)==1 else "-1" if f.get('sfe',None)==-1 else "?", 'bc': bc_info(f['bc']), 'cm': cm_info(f.get('CM','?')), } for f in newforms] info['nnewforms'] = len(info['nfdata']) # currently we have newforms of dimension 1 and 2 only (mostly dimension 1) info['nnf1'] = sum(1 for f in info['nfdata'] if f['dim']==1) info['nnf2'] = sum(1 for f in info['nfdata'] if f['dim']==2) info['nnf_missing'] = dim_data['2']['new_dim'] - info['nnf1'] - 2*info['nnf2'] properties = [('Base field', pretty_field_label), ('Level',info['level_label']), ('Norm',str(info['level_norm'])), ('New dimension',str(newdim))] friends = [('Newform {}'.format(f['label']), f['url']) for f in info['nfdata'] ] return render_template("bmf-space.html", info=info, title=t, bread=bread, properties=properties, friends=friends, learnmore=learnmore_list())
def make_E(self): coeffs = self.ainvs # list of 5 lists of d strings self.ainvs = [self.field.parse_NFelt(x) for x in coeffs] self.latex_ainvs = web_latex(self.ainvs) from sage.schemes.elliptic_curves.all import EllipticCurve self.E = E = EllipticCurve(self.ainvs) self.equn = web_latex(E) self.numb = str(self.number) # Conductor, discriminant, j-invariant N = E.conductor() self.cond = web_latex(N) self.cond_norm = web_latex(N.norm()) if N.norm() == 1: # since the factorization of (1) displays as "1" self.fact_cond = self.cond else: self.fact_cond = web_latex_ideal_fact(N.factor()) self.fact_cond_norm = web_latex(N.norm().factor()) D = self.field.K().ideal(E.discriminant()) self.disc = web_latex(D) self.disc_norm = web_latex(D.norm()) if D.norm() == 1: # since the factorization of (1) displays as "1" self.fact_disc = self.disc else: self.fact_disc = web_latex_ideal_fact(D.factor()) self.fact_disc_norm = web_latex(D.norm().factor()) # Minimal model? # # All curves in the database should be given # by models which are globally minimal if possible, else # minimal at all but one prime. But we do not rely on this # here, and the display should be correct if either (1) there # exists a global minimal model but this model is not; or (2) # this model is non-minimal at more than one prime. # self.non_min_primes = non_minimal_primes(E) self.is_minimal = (len(self.non_min_primes) == 0) self.has_minimal_model = True if not self.is_minimal: self.non_min_prime = ','.join( [web_latex(P) for P in self.non_min_primes]) self.has_minimal_model = has_global_minimal_model(E) if not self.is_minimal: Dmin = minimal_discriminant_ideal(E) self.mindisc = web_latex(Dmin) self.mindisc_norm = web_latex(Dmin.norm()) if Dmin.norm( ) == 1: # since the factorization of (1) displays as "1" self.fact_mindisc = self.mindisc else: self.fact_mindisc = web_latex_ideal_fact(Dmin.factor()) self.fact_mindisc_norm = web_latex(Dmin.norm().factor()) j = E.j_invariant() if j: d = j.denominator() n = d * j # numerator exists for quadratic fields only! g = GCD(list(n)) n1 = n / g self.j = web_latex(n1) if d != 1: if n1 > 1: # self.j = "("+self.j+")\(/\)"+web_latex(d) self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d)) else: self.j = web_latex(d) if g > 1: if n1 > 1: self.j = web_latex(g) + self.j else: self.j = web_latex(g) self.j = web_latex(j) self.fact_j = None # See issue 1258: some j factorizations work bu take too long (e.g. EllipticCurve/6.6.371293.1/1.1/a/1) # If these are really wanted, they could be precomputed and stored in the db if j.is_zero(): self.fact_j = web_latex(j) else: if self.field.K().degree( ) < 3: #j.numerator_ideal().norm()<1000000000000: try: self.fact_j = web_latex(j.factor()) except (ArithmeticError, ValueError ): # if not all prime ideal factors principal pass # CM and End(E) self.cm_bool = "no" self.End = "\(\Z\)" if self.cm: self.cm_bool = "yes (\(%s\))" % self.cm if self.cm % 4 == 0: d4 = ZZ(self.cm) // 4 self.End = "\(\Z[\sqrt{%s}]\)" % (d4) else: self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm # The line below will need to change once we have curves over non-quadratic fields # that contain the Hilbert class field of an imaginary quadratic field if self.signature == [0, 1] and ZZ( -self.abs_disc * self.cm).is_square(): self.ST = '<a href="%s">$%s$</a>' % (url_for( 'st.by_label', label='1.2.U(1)'), '\\mathrm{U}(1)') else: self.ST = '<a href="%s">$%s$</a>' % (url_for( 'st.by_label', label='1.2.N(U(1))'), 'N(\\mathrm{U}(1))') else: self.ST = '<a href="%s">$%s$</a>' % (url_for( 'st.by_label', label='1.2.SU(2)'), '\\mathrm{SU}(2)') # Q-curve / Base change self.qc = "no" try: if self.q_curve: self.qc = "yes" except AttributeError: # in case the db entry does not have this field set pass # Torsion self.ntors = web_latex(self.torsion_order) self.tr = len(self.torsion_structure) if self.tr == 0: self.tor_struct_pretty = "Trivial" if self.tr == 1: self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0] if self.tr == 2: self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple( self.torsion_structure) torsion_gens = [ E([self.field.parse_NFelt(x) for x in P]) for P in self.torsion_gens ] self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens]) # Rank or bounds try: self.rk = web_latex(self.rank) except AttributeError: self.rk = "?" try: self.rk_bnds = "%s...%s" % tuple(self.rank_bounds) except AttributeError: self.rank_bounds = [0, Infinity] self.rk_bnds = "not available" # Generators try: gens = [ E([self.field.parse_NFelt(x) for x in P]) for P in self.gens ] self.gens = ", ".join([web_latex(P) for P in gens]) if self.rk == "?": self.reg = "not available" else: if gens: self.reg = E.regulator_of_points(gens) else: self.reg = 1 # otherwise we only get 1.00000... except AttributeError: self.gens = "not available" self.reg = "not available" try: if self.rank == 0: self.reg = 1 except AttributeError: pass # Local data self.local_data = [] for p in N.prime_factors(): self.local_info = E.local_data(p, algorithm="generic") self.local_data.append({ 'p': web_latex(p), 'norm': web_latex(p.norm().factor()), 'tamagawa_number': self.local_info.tamagawa_number(), 'kodaira_symbol': web_latex(self.local_info.kodaira_symbol()).replace('$', ''), 'reduction_type': self.local_info.bad_reduction_type(), 'ord_den_j': max(0, -E.j_invariant().valuation(p)), 'ord_mindisc': self.local_info.discriminant_valuation(), 'ord_cond': self.local_info.conductor_valuation() }) # URLs of self and related objects: self.urls = {} # It's useful to be able to use this class out of context, when calling url_for will fail: try: self.urls['curve'] = url_for(".show_ecnf", nf=self.field_label, conductor_label=quote( self.conductor_label), class_label=self.iso_label, number=self.number) except RuntimeError: return self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=quote( self.conductor_label), class_label=self.iso_label) self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=quote( self.conductor_label)) self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label) sig = self.signature real_quadratic = sig == [2, 0] 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) 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.friends = [] self.friends += [('Isogeny class ' + self.short_class_label, self.urls['class'])] self.friends += [('Twists', url_for('ecnf.index', field_label=self.field_label, jinv=self.jinv))] if totally_real: self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])] self.friends += [('L-function', self.urls['Lfunction'])] if imag_quadratic: self.friends += [ ('Bianchi Modular Form %s not available' % self.bmf_label, '') ] self.properties = [('Base field', self.field.field_pretty()), ('Label', self.label)] # Plot if E.base_field().signature()[0]: self.plot = encode_plot(EC_nf_plot(E, self.field.generator_name())) self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot self.properties += [(None, self.plot_link)] self.properties += [ ('Conductor', self.cond), ('Conductor norm', self.cond_norm), # See issue #796 for why this is hidden # ('j-invariant', self.j), ('CM', self.cm_bool) ] if self.base_change: self.properties += [ ('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change])) ] else: self.base_change = [] # in case it was False instead of [] self.properties += [('Q-curve', self.qc)] r = self.rk if r == "?": r = self.rk_bnds self.properties += [ ('Torsion order', self.ntors), ('Rank', r), ] for E0 in self.base_change: self.friends += [('Base-change of %s /\(\Q\)' % E0, url_for("ec.by_ec_label", label=E0))] self._code = None # will be set if needed by get_code()
def make_E(self): coeffs = self.ainvs # list of 5 lists of d strings self.ainvs = [self.field.parse_NFelt(x) for x in coeffs] self.latex_ainvs = web_latex(self.ainvs) from sage.schemes.elliptic_curves.all import EllipticCurve self.E = E = EllipticCurve(self.ainvs) self.equn = web_latex(E) self.numb = str(self.number) # Conductor, discriminant, j-invariant N = E.conductor() self.cond = web_latex(N) self.cond_norm = web_latex(N.norm()) if N.norm() == 1: # since the factorization of (1) displays as "1" self.fact_cond = self.cond else: self.fact_cond = web_latex_ideal_fact(N.factor()) self.fact_cond_norm = web_latex(N.norm().factor()) D = self.field.K().ideal(E.discriminant()) self.disc = web_latex(D) self.disc_norm = web_latex(D.norm()) if D.norm() == 1: # since the factorization of (1) displays as "1" self.fact_disc = self.disc else: self.fact_disc = web_latex_ideal_fact(D.factor()) self.fact_disc_norm = web_latex(D.norm().factor()) # Minimal model? # # All curves in the database should be given # by models which are globally minimal if possible, else # minimal at all but one prime. But we do not rely on this # here, and the display should be correct if either (1) there # exists a global minimal model but this model is not; or (2) # this model is non-minimal at more than one prime. # self.non_min_primes = non_minimal_primes(E) self.is_minimal = (len(self.non_min_primes) == 0) self.has_minimal_model = True if not self.is_minimal: self.non_min_prime = ','.join([web_latex(P) for P in self.non_min_primes]) self.has_minimal_model = has_global_minimal_model(E) if not self.is_minimal: Dmin = minimal_discriminant_ideal(E) self.mindisc = web_latex(Dmin) self.mindisc_norm = web_latex(Dmin.norm()) if Dmin.norm() == 1: # since the factorization of (1) displays as "1" self.fact_mindisc = self.mindisc else: self.fact_mindisc = web_latex_ideal_fact(Dmin.factor()) self.fact_mindisc_norm = web_latex(Dmin.norm().factor()) j = E.j_invariant() if j: d = j.denominator() n = d * j # numerator exists for quadratic fields only! g = GCD(list(n)) n1 = n / g self.j = web_latex(n1) if d != 1: if n1 > 1: # self.j = "("+self.j+")\(/\)"+web_latex(d) self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d)) else: self.j = web_latex(d) if g > 1: if n1 > 1: self.j = web_latex(g) + self.j else: self.j = web_latex(g) self.j = web_latex(j) self.fact_j = None # See issue 1258: some j factorizations work bu take too long (e.g. EllipticCurve/6.6.371293.1/1.1/a/1) # If these are really wanted, they could be precomputed and stored in the db if j.is_zero(): self.fact_j = web_latex(j) else: if self.field.K().degree() < 3: #j.numerator_ideal().norm()<1000000000000: try: self.fact_j = web_latex(j.factor()) except (ArithmeticError, ValueError): # if not all prime ideal factors principal pass # CM and End(E) self.cm_bool = "no" self.End = "\(\Z\)" if self.cm: self.cm_bool = "yes (\(%s\))" % self.cm if self.cm % 4 == 0: d4 = ZZ(self.cm) // 4 self.End = "\(\Z[\sqrt{%s}]\)" % (d4) else: self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm # The line below will need to change once we have curves over non-quadratic fields # that contain the Hilbert class field of an imaginary quadratic field if self.signature == [0,1] and ZZ(-self.abs_disc*self.cm).is_square(): self.ST = '<a href="%s">$%s$</a>' % (url_for('st.by_label', label='1.2.U(1)'),'\\mathrm{U}(1)') else: self.ST = '<a href="%s">$%s$</a>' % (url_for('st.by_label', label='1.2.N(U(1))'),'N(\\mathrm{U}(1))') else: self.ST = '<a href="%s">$%s$</a>' % (url_for('st.by_label', label='1.2.SU(2)'),'\\mathrm{SU}(2)') # Q-curve / Base change self.qc = "no" try: if self.q_curve: self.qc = "yes" except AttributeError: # in case the db entry does not have this field set pass # Torsion self.ntors = web_latex(self.torsion_order) self.tr = len(self.torsion_structure) if self.tr == 0: self.tor_struct_pretty = "Trivial" if self.tr == 1: self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0] if self.tr == 2: self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(self.torsion_structure) torsion_gens = [E([self.field.parse_NFelt(x) for x in P]) for P in self.torsion_gens] self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens]) # Rank or bounds try: self.rk = web_latex(self.rank) except AttributeError: self.rk = "?" try: self.rk_bnds = "%s...%s" % tuple(self.rank_bounds) except AttributeError: self.rank_bounds = [0, Infinity] self.rk_bnds = "not available" # Generators try: gens = [E([self.field.parse_NFelt(x) for x in P]) for P in self.gens] self.gens = ", ".join([web_latex(P) for P in gens]) if self.rk == "?": self.reg = "not available" else: if gens: self.reg = E.regulator_of_points(gens) else: self.reg = 1 # otherwise we only get 1.00000... except AttributeError: self.gens = "not available" self.reg = "not available" try: if self.rank == 0: self.reg = 1 except AttributeError: pass # Local data self.local_data = [] for p in N.prime_factors(): self.local_info = E.local_data(p, algorithm="generic") self.local_data.append({'p': web_latex(p), 'norm': web_latex(p.norm().factor()), 'tamagawa_number': self.local_info.tamagawa_number(), 'kodaira_symbol': web_latex(self.local_info.kodaira_symbol()).replace('$', ''), 'reduction_type': self.local_info.bad_reduction_type(), 'ord_den_j': max(0, -E.j_invariant().valuation(p)), 'ord_mindisc': self.local_info.discriminant_valuation(), 'ord_cond': self.local_info.conductor_valuation() }) # URLs of self and related objects: self.urls = {} # It's useful to be able to use this class out of context, when calling url_for will fail: try: self.urls['curve'] = url_for(".show_ecnf", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number) except RuntimeError: return self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label) self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=quote(self.conductor_label)) self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label) sig = self.signature real_quadratic = sig == [2,0] 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) 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.friends = [] self.friends += [('Isogeny class ' + self.short_class_label, self.urls['class'])] self.friends += [('Twists', url_for('ecnf.index', field_label=self.field_label, jinv=self.jinv))] if totally_real: self.friends += [('Hilbert Modular Form ' + self.hmf_label, self.urls['hmf'])] self.friends += [('L-function', self.urls['Lfunction'])] if imag_quadratic: self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')] self.properties = [ ('Base field', self.field.field_pretty()), ('Label', self.label)] # Plot if E.base_field().signature()[0]: self.plot = encode_plot(EC_nf_plot(E, self.field.generator_name())) self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot self.properties += [(None, self.plot_link)] self.properties += [ ('Conductor', self.cond), ('Conductor norm', self.cond_norm), # See issue #796 for why this is hidden # ('j-invariant', self.j), ('CM', self.cm_bool)] if self.base_change: self.properties += [('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))] else: self.base_change = [] # in case it was False instead of [] self.properties += [('Q-curve', self.qc)] r = self.rk if r == "?": r = self.rk_bnds self.properties += [ ('Torsion order', self.ntors), ('Rank', r), ] for E0 in self.base_change: self.friends += [('Base-change of %s /\(\Q\)' % E0, url_for("ec.by_ec_label", label=E0))] self._code = None # will be set if needed by get_code()
def make_E(self): coeffs = self.ainvs # list of 5 lists of d strings self.ainvs = [self.field.parse_NFelt(x) for x in coeffs] self.latex_ainvs = web_latex(self.ainvs) from sage.schemes.elliptic_curves.all import EllipticCurve self.E = E = EllipticCurve(self.ainvs) self.equn = web_latex(E) self.numb = str(self.number) # Conductor, discriminant, j-invariant N = E.conductor() self.cond = web_latex(N) self.cond_norm = web_latex(N.norm()) if N.norm() == 1: # since the factorization of (1) displays as "1" self.fact_cond = self.cond else: self.fact_cond = web_latex_ideal_fact(N.factor()) self.fact_cond_norm = web_latex(N.norm().factor()) D = self.field.K().ideal(E.discriminant()) self.disc = web_latex(D) self.disc_norm = web_latex(D.norm()) if D.norm() == 1: # since the factorization of (1) displays as "1" self.fact_disc = self.disc else: self.fact_disc = web_latex_ideal_fact(D.factor()) self.fact_disc_norm = web_latex(D.norm().factor()) # Minimal model? # # All curves in the database should be given # by models which are globally minimal if possible, else # minimal at all but one prime. But we do not rely on this # here, and the display should be correct if either (1) there # exists a global minimal model but this model is not; or (2) # this model is non-minimal at more than one prime. # self.non_min_primes = non_minimal_primes(E) self.is_minimal = len(self.non_min_primes) == 0 self.has_minimal_model = True if not self.is_minimal: self.non_min_prime = ",".join([web_latex(P) for P in self.non_min_primes]) self.has_minimal_model = has_global_minimal_model(E) if not self.is_minimal: Dmin = minimal_discriminant_ideal(E) self.mindisc = web_latex(Dmin) self.mindisc_norm = web_latex(Dmin.norm()) if Dmin.norm() == 1: # since the factorization of (1) displays as "1" self.fact_mindisc = self.mindisc else: self.fact_mindisc = web_latex_ideal_fact(Dmin.factor()) self.fact_mindisc_norm = web_latex(Dmin.norm().factor()) j = E.j_invariant() if j: d = j.denominator() n = d * j # numerator exists for quadratic fields only! g = GCD(list(n)) n1 = n / g self.j = web_latex(n1) if d != 1: if n1 > 1: # self.j = "("+self.j+")\(/\)"+web_latex(d) self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d)) else: self.j = web_latex(d) if g > 1: if n1 > 1: self.j = web_latex(g) + self.j else: self.j = web_latex(g) self.j = web_latex(j) self.fact_j = None if j.is_zero(): self.fact_j = web_latex(j) else: try: self.fact_j = web_latex(j.factor()) except (ArithmeticError, ValueError): # if not all prime ideal factors principal pass # CM and End(E) self.cm_bool = "no" self.End = "\(\Z\)" if self.cm: self.cm_bool = "yes (\(%s\))" % self.cm if self.cm % 4 == 0: d4 = ZZ(self.cm) // 4 self.End = "\(\Z[\sqrt{%s}]\)" % (d4) else: self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm # Q-curve / Base change self.qc = "no" try: if self.q_curve: self.qc = "yes" except AttributeError: # in case the db entry does not have this field set pass # Torsion self.ntors = web_latex(self.torsion_order) self.tr = len(self.torsion_structure) if self.tr == 0: self.tor_struct_pretty = "Trivial" if self.tr == 1: self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0] if self.tr == 2: self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(self.torsion_structure) torsion_gens = [E([self.field.parse_NFelt(x) for x in P]) for P in self.torsion_gens] self.torsion_gens = ",".join([web_latex(P) for P in torsion_gens]) # Rank or bounds try: self.rk = web_latex(self.rank) except AttributeError: self.rk = "?" try: self.rk_bnds = "%s...%s" % tuple(self.rank_bounds) except AttributeError: self.rank_bounds = [0, Infinity] self.rk_bnds = "not recorded" # Generators try: gens = [E([self.field.parse_NFelt(x) for x in P]) for P in self.gens] self.gens = ", ".join([web_latex(P) for P in gens]) if self.rk == "?": self.reg = "unknown" else: if gens: self.reg = E.regulator_of_points(gens) else: self.reg = 1 # otherwise we only get 1.00000... except AttributeError: self.gens = "not recorded" self.reg = "unknown" try: if self.rank == 0: self.reg = 1 except AttributeError: pass # Local data self.local_data = [] for p in N.prime_factors(): self.local_info = E.local_data(p, algorithm="generic") self.local_data.append( { "p": web_latex(p), "norm": web_latex(p.norm().factor()), "tamagawa_number": self.local_info.tamagawa_number(), "kodaira_symbol": web_latex(self.local_info.kodaira_symbol()).replace("$", ""), "reduction_type": self.local_info.bad_reduction_type(), "ord_den_j": max(0, -E.j_invariant().valuation(p)), "ord_mindisc": self.local_info.discriminant_valuation(), "ord_cond": self.local_info.conductor_valuation(), } ) # URLs of self and related objects: self.urls = {} # It's useful to be able to use this class out of context, when calling url_for will fail: try: self.urls["curve"] = url_for( ".show_ecnf", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number, ) except RuntimeError: return self.urls["class"] = url_for( ".show_ecnf_isoclass", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, ) self.urls["conductor"] = url_for( ".show_ecnf_conductor", nf=self.field_label, conductor_label=quote(self.conductor_label) ) self.urls["field"] = url_for(".show_ecnf1", nf=self.field_label) sig = self.signature real_quadratic = sig == [2, 0] 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) 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.friends = [] self.friends += [("Isogeny class " + self.short_class_label, self.urls["class"])] self.friends += [("Twists", url_for("ecnf.index", field_label=self.field_label, jinv=self.jinv))] if totally_real: self.friends += [("Hilbert Modular Form " + self.hmf_label, self.urls["hmf"])] self.friends += [("L-function", self.urls["Lfunction"])] if imag_quadratic: self.friends += [("Bianchi Modular Form %s not yet available" % self.bmf_label, "")] self.properties = [("Base field", self.field.field_pretty()), ("Label", self.label)] # Plot if E.base_field().signature()[0]: self.plot = encode_plot(EC_nf_plot(E, self.field.generator_name())) self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot self.properties += [(None, self.plot_link)] self.properties += [ ("Conductor", self.cond), ("Conductor norm", self.cond_norm), # See issue #796 for why this is hidden # ('j-invariant', self.j), ("CM", self.cm_bool), ] if self.base_change: self.properties += [("base-change", "yes: %s" % ",".join([str(lab) for lab in self.base_change]))] else: self.base_change = [] # in case it was False instead of [] self.properties += [("Q-curve", self.qc)] r = self.rk if r == "?": r = self.rk_bnds self.properties += [("Torsion order", self.ntors), ("Rank", r)] for E0 in self.base_change: self.friends += [("Base-change of %s /\(\Q\)" % E0, url_for("ec.by_ec_label", label=E0))] self.make_code_snippets()
def make_E(self): #print("Creating ECNF object for {}".format(self.label)) #sys.stdout.flush() K = self.field.K() # a-invariants self.ainvs = parse_ainvs(K,self.ainvs) self.latex_ainvs = web_latex(self.ainvs) self.numb = str(self.number) # Conductor, discriminant, j-invariant if self.conductor_norm==1: N = K.ideal(1) else: N = ideal_from_string(K,self.conductor_ideal) # The following can trigger expensive computations! #self.cond = web_latex(N) self.cond = pretty_ideal(N) self.cond_norm = web_latex(self.conductor_norm) local_data = self.local_data # NB badprimes is a list of primes which divide the # discriminant of this model. At most one of these might # actually be a prime of good reduction, if the curve has no # global minimal model. badprimes = [ideal_from_string(K,ld['p']) for ld in local_data] badnorms = [ZZ(ld['normp']) for ld in local_data] mindisc_ords = [ld['ord_disc'] for ld in local_data] # Assumption: the curve models stored in the database are # either global minimal models or minimal at all but one # prime, so the list here has length 0 or 1: self.non_min_primes = [ideal_from_string(K,P) for P in self.non_min_p] self.is_minimal = (len(self.non_min_primes) == 0) self.has_minimal_model = self.is_minimal disc_ords = [ld['ord_disc'] for ld in local_data] if not self.is_minimal: Pmin = self.non_min_primes[0] P_index = badprimes.index(Pmin) self.non_min_prime = pretty_ideal(Pmin) disc_ords[P_index] += 12 if self.conductor_norm == 1: # since the factorization of (1) displays as "1" self.fact_cond = self.cond self.fact_cond_norm = '1' else: Nfac = Factorization([(P,ld['ord_cond']) for P,ld in zip(badprimes,local_data)]) self.fact_cond = web_latex_ideal_fact(Nfac) Nnormfac = Factorization([(q,ld['ord_cond']) for q,ld in zip(badnorms,local_data)]) self.fact_cond_norm = web_latex(Nnormfac) # D is the discriminant ideal of the model D = prod([P**e for P,e in zip(badprimes,disc_ords)], K.ideal(1)) self.disc = pretty_ideal(D) Dnorm = D.norm() self.disc_norm = web_latex(Dnorm) if Dnorm == 1: # since the factorization of (1) displays as "1" self.fact_disc = self.disc self.fact_disc_norm = '1' else: Dfac = Factorization([(P,e) for P,e in zip(badprimes,disc_ords)]) self.fact_disc = web_latex_ideal_fact(Dfac) Dnormfac = Factorization([(q,e) for q,e in zip(badnorms,disc_ords)]) self.fact_disc_norm = web_latex(Dnormfac) if not self.is_minimal: Dmin = ideal_from_string(K,self.minD) self.mindisc = pretty_ideal(Dmin) Dmin_norm = Dmin.norm() self.mindisc_norm = web_latex(Dmin_norm) if Dmin_norm == 1: # since the factorization of (1) displays as "1" self.fact_mindisc = self.mindisc self.fact_mindisc_norm = self.mindisc else: Dminfac = Factorization([(P,e) for P,edd in zip(badprimes,mindisc_ords)]) self.fact_mindisc = web_latex_ideal_fact(Dminfac) Dminnormfac = Factorization([(q,e) for q,e in zip(badnorms,mindisc_ords)]) self.fact_mindisc_norm = web_latex(Dminnormfac) j = self.field.parse_NFelt(self.jinv) # if j: # d = j.denominator() # n = d * j # numerator exists for quadratic fields only! # g = GCD(list(n)) # n1 = n / g # self.j = web_latex(n1) # if d != 1: # if n1 > 1: # # self.j = "("+self.j+")\(/\)"+web_latex(d) # self.j = web_latex(r"\frac{%s}{%s}" % (self.j, d)) # else: # self.j = web_latex(d) # if g > 1: # if n1 > 1: # self.j = web_latex(g) + self.j # else: # self.j = web_latex(g) self.j = web_latex(j) self.fact_j = None # See issue 1258: some j factorizations work but take too long # (e.g. EllipticCurve/6.6.371293.1/1.1/a/1). Note that we do # store the factorization of the denominator of j and display # that, which is the most interesting part. # Images of Galois representations if not hasattr(self,'galois_images'): #print "No Galois image data" self.galois_images = "?" self.non_surjective_primes = "?" self.galois_data = [] else: self.galois_data = [{'p': p,'image': im } for p,im in zip(self.non_surjective_primes, self.galois_images)] # CM and End(E) self.cm_bool = "no" self.End = "\(\Z\)" if self.cm: self.rational_cm = K(self.cm).is_square() self.cm_sqf = ZZ(self.cm).squarefree_part() self.cm_bool = "yes (\(%s\))" % self.cm if self.cm % 4 == 0: d4 = ZZ(self.cm) // 4 self.End = "\(\Z[\sqrt{%s}]\)" % (d4) else: self.End = "\(\Z[(1+\sqrt{%s})/2]\)" % self.cm # Galois images in CM case: if self.cm and self.galois_images != '?': self.cm_ramp = [p for p in ZZ(self.cm).support() if not p in self.non_surjective_primes] self.cm_nramp = len(self.cm_ramp) if self.cm_nramp==1: self.cm_ramp = self.cm_ramp[0] else: self.cm_ramp = ", ".join([str(p) for p in self.cm_ramp]) # Sato-Tate: # The lines below will need to change once we have curves over non-quadratic fields # that contain the Hilbert class field of an imaginary quadratic field if self.cm: if self.signature == [0,1] and ZZ(-self.abs_disc*self.cm).is_square(): self.ST = st_link_by_name(1,2,'U(1)') else: self.ST = st_link_by_name(1,2,'N(U(1))') else: self.ST = st_link_by_name(1,2,'SU(2)') # Q-curve / Base change self.qc = self.q_curve if self.qc == "?": self.qc = "not determined" elif self.qc == True: self.qc = "yes" elif self.qc == False: self.qc = "no" else: # just in case self.qc = "not determined" # Torsion self.ntors = web_latex(self.torsion_order) self.tr = len(self.torsion_structure) if self.tr == 0: self.tor_struct_pretty = "Trivial" if self.tr == 1: self.tor_struct_pretty = "\(\Z/%s\Z\)" % self.torsion_structure[0] if self.tr == 2: self.tor_struct_pretty = r"\(\Z/%s\Z\times\Z/%s\Z\)" % tuple(self.torsion_structure) torsion_gens = [parse_point(K,P) for P in self.torsion_gens] self.torsion_gens = ",".join([web_point(P) for P in torsion_gens]) # Rank or bounds try: self.rk = web_latex(self.rank) except AttributeError: self.rk = "?" try: self.rk_bnds = "%s...%s" % tuple(self.rank_bounds) except AttributeError: self.rank_bounds = [0, Infinity] self.rk_bnds = "not available" # Generators try: gens = [parse_point(K,P) for P in self.gens] self.gens = ", ".join([web_point(P) for P in gens]) if self.rk == "?": self.reg = "not available" else: if gens: try: self.reg = self.reg except AttributeError: self.reg = "not available" pass # self.reg already set else: self.reg = 1 # otherwise we only get 1.00000... except AttributeError: self.gens = "not available" self.reg = "not available" try: if self.rank == 0: self.reg = 1 except AttributeError: pass # Local data for P,ld in zip(badprimes,local_data): ld['p'] = web_latex(P) ld['norm'] = P.norm() ld['kod'] = ld['kod'].replace('\\\\', '\\') ld['kod'] = web_latex(ld['kod']).replace('$', '') # URLs of self and related objects: self.urls = {} # It's useful to be able to use this class out of context, when calling url_for will fail: try: self.urls['curve'] = url_for(".show_ecnf", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number) except RuntimeError: return self.urls['class'] = url_for(".show_ecnf_isoclass", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label) self.urls['conductor'] = url_for(".show_ecnf_conductor", nf=self.field_label, conductor_label=quote(self.conductor_label)) self.urls['field'] = url_for(".show_ecnf1", nf=self.field_label) # Isogeny information self.one_deg = ZZ(self.class_deg).is_prime() isodegs = [str(d) for d in self.isogeny_degrees if d>1] if len(isodegs)<3: self.isogeny_degrees = " and ".join(isodegs) else: self.isogeny_degrees = " and ".join([", ".join(isodegs[:-1]),isodegs[-1]]) 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 < 70000: # 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 = [] self.friends += [('Isogeny class ' + self.short_class_label, self.urls['class'])] self.friends += [('Twists', url_for('ecnf.index', field=self.field_label, jinv=rename_j(j)))] if totally_real: 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', '')] else: 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: self.friends += [('L-function', self.urls['Lfunction'])] else: self.friends += [('L-function not available', "")] self.properties = [ ('Base field', self.field.field_pretty()), ('Label', self.label)] # Plot if K.signature()[0]: self.plot = encode_plot(EC_nf_plot(K,self.ainvs, self.field.generator_name())) self.plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format(self.plot) self.properties += [(None, self.plot_link)] self.properties += [ ('Conductor', self.cond), ('Conductor norm', self.cond_norm), # See issue #796 for why this is hidden (can be very large) # ('j-invariant', self.j), ('CM', self.cm_bool)] if self.base_change: self.properties += [('base-change', 'yes: %s' % ','.join([str(lab) for lab in self.base_change]))] else: self.base_change = [] # in case it was False instead of [] self.properties += [('base-change', 'no')] self.properties += [('Q-curve', self.qc)] r = self.rk if r == "?": r = self.rk_bnds self.properties += [ ('Torsion order', self.ntors), ('Rank', r), ] for E0 in self.base_change: self.friends += [('Base-change of %s /\(\Q\)' % E0, url_for("ec.by_ec_label", label=E0))] self._code = None # will be set if needed by get_code() self.downloads = [('Download all stored data', url_for(".download_ECNF_all", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number))] for lang in [["Magma","magma"], ["SageMath","sage"], ["GP", "gp"]]: self.downloads.append(('Download {} code'.format(lang[0]), url_for(".ecnf_code_download", nf=self.field_label, conductor_label=quote(self.conductor_label), class_label=self.iso_label, number=self.number, download_type=lang[1])))