def render_group_webpage(args): data = None info = {} if 'label' in args: label = clean_input(args['label']) label = label.replace('t', 'T') C = base.getDBConnection() data = C.transitivegroups.groups.find_one({'label': label}) if data is None: bread = get_bread([("Search error", url_for('.search'))]) info['err'] = "Group " + label + " was not found in the database." info['label'] = label return search_input_error(info, bread) title = 'Galois Group:' + label n = data['n'] t = data['t'] data['yesno'] = yesno order = data['order'] data['orderfac'] = latex(ZZ(order).factor()) orderfac = latex(ZZ(order).factor()) data['ordermsg'] = "$%s=%s$" % (order, latex(orderfac)) if ZZ(order) == 1: data['ordermsg'] = "$1$" if ZZ(order).is_prime(): data['ordermsg'] = "$%s$ (is prime)" % order pgroup = len(ZZ(order).prime_factors()) < 2 if n == 1: G = gap.SmallGroup(n, t) else: G = gap.TransitiveGroup(n, t) if ZZ(order) < ZZ('10000000000'): ctable = chartable(n, t) else: ctable = 'Group too large' data['gens'] = generators(n, t) if n == 1 and t == 1: data['gens'] = 'None needed' data['chartable'] = ctable data['parity'] = "$%s$" % data['parity'] data['cclasses'] = conjclasses(G, n) data['subinfo'] = subfield_display(C, n, data['subs']) data['resolve'] = resolve_display(C, data['resolve']) # if len(data['resolve']) == 0: data['resolve'] = 'None' data['otherreps'] = otherrep_display(n, t, C, data['repns']) prop2 = [ ('Order:', '\(%s\)' % order), ('n:', '\(%s\)' % data['n']), ('Cyclic:', yesno(data['cyc'])), ('Abelian:', yesno(data['ab'])), ('Solvable:', yesno(data['solv'])), ('Primitive:', yesno(data['prim'])), ('$p$-group:', yesno(pgroup)), ('Name:', group_display_short(n, t, C)), ] info.update(data) bread = get_bread([(label, ' ')]) return render_template("gg-show-group.html", credit=GG_credit, title=title, bread=bread, info=info, properties2=prop2)
def splitint(a,p): if a==1: return ' ' j = valuation(a,p) if j==0: return str(a) a = a/p**j if a==1: return latex(ZZ(p**j).factor()) return str(a)+r'\cdot'+latex(ZZ(p**j).factor())
def safe_reduce(f): if not m: return latex(f) try: if f in sam.field(): return latex(redc(f)) else: return latex(redp(f)) except ZeroDivisionError: return '\\textrm{Unable to reduce} \\bmod\\mathfrak{m}'
def make_map_latex(map_str): # FIXME: Get rid of nu when map is defined over QQ if "nu" not in map_str: R0 = QQ else: R0 = PolynomialRing(QQ,'nu') R = PolynomialRing(R0,2,'x,y') F = FractionField(R) phi = F(map_str) num = phi.numerator() den = phi.denominator() c_num = num.denominator() c_den = den.denominator() lc = c_den/c_num # rescale coeffs to make them integral. then try to factor out gcds # numerator num_new = c_num*num num_cs = num_new.coefficients() if R0 == QQ: num_cs_ZZ = num_cs else: num_cs_ZZ = [] for el in num_cs: num_cs_ZZ = num_cs_ZZ + el.coefficients() num_gcd = gcd(num_cs_ZZ) # denominator den_new = c_den*den den_cs = den_new.coefficients() if R0 == QQ: den_cs_ZZ = den_cs else: den_cs_ZZ = [] for el in den_cs: den_cs_ZZ = den_cs_ZZ + el.coefficients() den_gcd = gcd(den_cs_ZZ) lc = lc*(num_gcd/den_gcd) num_new = num_new/num_gcd den_new = den_new/den_gcd # make strings for lc, num, and den num_str = latex(num_new) den_str = latex(den_new) if lc==1: lc_str="" else: lc_str = latex(lc) if den_new==1: if lc ==1: phi_str = num_str else: phi_str = lc_str+"("+num_str+")" else: phi_str = lc_str+"\\frac{"+num_str+"}"+"{"+den_str+"}" return phi_str
def _latex_using_dpd_depth1(self, dpd_dct): names = [dpd_dct[c] for c in self._consts] _gcd = QQ(gcd(self._coeffs)) coeffs = [c / _gcd for c in self._coeffs] coeffs_names = [(c, n) for c, n in zip(coeffs, names) if c != 0] tail_terms = ["%s %s %s" % ("+" if c > 0 else "", c, n) for c, n in coeffs_names[1:]] c0, n0 = coeffs_names[0] head_term = str(c0) + " " + str(n0) return r"\frac{{{pol_num}}}{{{pol_dnm}}} \left({terms}\right)".format( pol_dnm=latex(_gcd.denominator() * self._scalar_const._polynomial_expr()), pol_num=latex(_gcd.numerator()), terms=" ".join([head_term] + tail_terms), )
def make_curve_latex(crv_str): # FIXME: Get rid of nu when map is defined over QQ if "nu" not in crv_str: R0 = QQ else: R0 = PolynomialRing(QQ,'nu') R = PolynomialRing(R0,2,'x,y') F = FractionField(R) sides = crv_str.split("=") lhs = latex(F(sides[0])) rhs = latex(F(sides[1])) eqn_str = lhs + '=' + rhs return eqn_str
def latex(self, prec=None, name=None, keepzeta=False): """ Change the name of the variable in a polynomial. If keepzeta, then don't change the name of zetaN in the defining polynomial of a cyclotomic field. (keepzeta not implemented yet) """ if prec is None: qe = self.value() else: qe = self.value() if not qe is None: qe = qe.truncate_powerseries(prec) wl = web_latex_split_on_re(qe) if name is not None and self.value().base_ring().absolute_degree()>1: oldname = latex(self.value().base_ring().gen()) subfrom = oldname.strip() subfrom = subfrom.replace("\\","\\\\") subfrom = subfrom.replace("{","\\{") # because x_{0} means something in a regular expression if subfrom[0].isalpha(): subfrom = "\\b" + subfrom subto = name.replace("\\","\\\\") + " " if keepzeta and "zeta" in subfrom: pass # keep the variable as-is else: wl = re.sub(subfrom, subto, wl) return wl else: return wl
def eigs_as_seqseq_to_qexp(self, prec_max): # Takes a sequence of sequence of integers and returns a string for the corresponding q expansion # For example, eigs_as_seqseq_to_qexp([[0,0],[1,3]]) returns "\((1+3\beta_{1})q\)\(+O(q^2)\)" prec = min(self.qexp_prec, prec_max) if prec == 0: return 'O(1)' eigseq = self.qexp[:prec] d = self.dim Rgens = self._get_Rgens() s = '' for j in range(len(eigseq)): term = sum([Rgens[i]*eigseq[j][i] for i in range(d)]) if term != 0: latexterm = latex(term) if term.number_of_terms() > 1: latexterm = r"\left(" + latexterm + r"\right)" if j > 0: if term == 1: latexterm = '' elif term == -1: latexterm = '-' if j == 1: latexterm += ' q' else: latexterm += ' q^{%d}' % j #print latexterm if s != '' and latexterm[0] != '-': latexterm = '+' + latexterm s += '\(' + latexterm + '\) ' # Work around bug in Sage's latex s = s.replace('betaq', 'beta q') return s + '\(+O(q^{%d})\)' % prec
def eigs_as_seqseq_to_qexp(self, prec_max): # Takes a sequence of sequence of integers (or pairs of integers in the hecke_ring_cyclotomic_generator != 0 case) and returns a string for the corresponding q expansion # For example, eigs_as_seqseq_to_qexp([[0,0],[1,3]]) returns "\((1+3\beta_{1})q\)\(+O(q^2)\)" prec = min(self.qexp_prec, prec_max) if prec == 0: return 'O(1)' eigseq = self.qexp[:prec] use_knowl = too_big(eigseq, 10**24) s = '' for j in range(len(eigseq)): term = self._elt(eigseq[j]) if term != 0: latexterm = latex(term) if use_knowl: latexterm = make_bigint(latexterm) if term.number_of_terms() > 1: latexterm = r"(" + latexterm + r")" if j > 0: if term == 1: latexterm = '' elif term == -1: latexterm = '-' if j == 1: latexterm += ' q' else: latexterm += ' q^{%d}' % j if s != '' and latexterm[0] != '-': latexterm = '+' + latexterm s += '\(' + latexterm + '\) ' # Work around bug in Sage's latex s = s.replace('betaq', 'beta q') return s + '\(+O(q^{%d})\)' % prec
def disc_factored_latex(self): D = self.disc() s = '' if D < 0: D = -D s = r'-\,' return s + latex(D.factor())
def web_latex_split_on_pm(x): on = ['+', '-'] # A = "\( %s \)" % latex(x) try: A = "\(" + x + "\)" # assume we are given LaTeX to split on except: A = "\( %s \)" % latex(x) # need a more clever split_on_pm that inserts left and right properly A = A.replace("\\left","") A = A.replace("\\right","") for s in on: # A = A.replace(s, '\) ' + s + ' \( ') # A = A.replace(s, '\) ' + ' \( \mathstrut ' + s ) A = A.replace(s, '\)' + ' \(\mathstrut ' + s + '\mathstrut ') # the above will be re-done using a more sophisticated method involving # regular expressions. Below fixes bad spacing when the current approach # encounters terms like (-3+x) for s in on: A = A.replace('(\) \(\mathstrut '+s,'(' + s) A = A.replace('( {}','(') A = A.replace('(\) \(','(') A = A.replace('\(+','\(\mathstrut+') A = A.replace('\(-','\(\mathstrut-') A = A.replace('( ','(') A = A.replace('( ','(') return A
def web_latex_split_on_re(x, r = '(q[^+-]*[+-])'): def insert_latex(s): return s.group(1) + '\) \(' if isinstance(x, (str, unicode)): return x else: A = "\( %s \)" % latex(x) c = re.compile(r) A = A.replace('+', '\) \( {}+ ') A = A.replace('-', '\) \( {}- ') # A = A.replace('\left(','\left( {}\\right.') # parantheses needs to be balanced # A = A.replace('\\right)','\left.\\right)') A = A.replace('\left(','\\bigl(') A = A.replace('\\right)','\\bigr)') A = c.sub(insert_latex, A) # the above will be re-done using a more sophisticated method involving # regular expressions. Below fixes bad spacing when the current approach # encounters terms like (-3+x) A = A.replace('( {}','(') A = A.replace('(\) \(','(') A = A.replace('\(+','\(\mathstrut+') A = A.replace('\(-','\(\mathstrut-') A = A.replace('( ','(') A = A.replace('( ','(') A = A.replace('+\) \(O','+O') return A
def get_local_algebra(self, p): local_algebra_dict = self._data.get('loc_algebras', None) if local_algebra_dict is None: return None if str(p) in local_algebra_dict: R = PolynomialRing(QQ, 'x') palg = local_algebra_dict[str(p)] palgs = [R(str(s)) for s in palg.split(',')] try: palgstr = [ list2string([int(c) for c in pol.coefficients(sparse=False)]) for pol in palgs] palgrec = [db.lf_fields.lucky({'p': p, 'coeffs': map(int, c.split(','))}) for c in palgstr] return [ [ LF['label'], latex(f), int(LF['e']), int(LF['f']), int(LF['c']), group_display_knowl(LF['n'], LF['galT']), LF['t'], LF['u'], LF['slopes'] ] for LF, f in zip(palgrec, palgs) ] except: # we were unable to find the local fields in the database return None
def nf_knowl_guts(label): out = '' wnf = WebNumberField(label) if wnf.is_null(): return 'Cannot find global number field %s' % label out += "Global number field %s" % label out += '<div>' out += 'Defining polynomial: ' out += "\(%s\)" % latex(wnf.poly()) D = wnf.disc() Dfact = wnf.disc_factored_latex() if D.abs().is_prime() or D == 1: Dfact = "\(%s\)" % str(D) else: Dfact = '%s = \(%s\)' % (str(D),Dfact) out += '<br>Discriminant: ' out += Dfact out += '<br>Signature: ' out += str(wnf.signature()) out += '<br>Galois group: '+group_pretty_and_nTj(wnf.degree(),wnf.galois_t(), True) out += '<br>Class number: %s ' % str(wnf.class_number_latex()) if wnf.can_class_number(): out += wnf.short_grh_string() out += '</div>' out += '<div align="right">' out += '<a href="%s">%s home page</a>' % (str(url_for("number_fields.number_field_render_webpage", natural=label)),label) out += '</div>' return out
def web_latex_split_on(x, on=['+', '-']): if isinstance(x, (str, unicode)): return x else: A = "\( %s \)" % latex(x) for s in on: A = A.replace(s, '\) ' + s + ' \( ') return A
def render_hgm_webpage(args): data = None info = {} if 'label' in args: label = clean_input(args['label']) C = base.getDBConnection() data = C.hgm.motives.find_one({'label': label}) if data is None: bread = get_bread([("Search error", url_for('.search'))]) info['err'] = "Motive " + label + " was not found in the database." info['label'] = label return search_input_error(info, bread) title = 'Hypergeometric Motive:' + label A = data['A'] B = data['B'] tn,td = data['t'] t = latex(QQ(str(tn)+'/'+str(td))) primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71] locinfo = data['locinfo'] for j in range(len(locinfo)): locinfo[j] = [primes[j]] + locinfo[j] locinfo[j][2] = poly_with_factored_coeffs(locinfo[j][2], primes[j]) hodge = data['hodge'] prop2 = [ ('Degree', '\(%s\)' % data['degree']), ('Weight', '\(%s\)' % data['weight']), ('Conductor', '\(%s\)' % data['cond']), ] # Now add factorization of conductor Cond = ZZ(data['cond']) if not (Cond.abs().is_prime() or Cond == 1): data['cond'] = "%s=%s" % (str(Cond), factorint(data['cond'])) info.update({ 'A': A, 'B': B, 't': t, 'degree': data['degree'], 'weight': data['weight'], 'sign': data['sign'], 'sig': data['sig'], 'hodge': hodge, 'cond': data['cond'], 'req': data['req'], 'locinfo': locinfo }) AB_data, t_data = data["label"].split("_t") #AB_data = data["label"].split("_t")[0] friends = [("Motive family "+AB_data.replace("_"," "), url_for(".by_family_label", label = AB_data))] friends.append(('L-function', url_for("l_functions.l_function_hgm_page", label=AB_data, t='t'+t_data))) # if rffriend != '': # friends.append(('Discriminant root field', rffriend)) bread = get_bread([(label, ' ')]) return render_template("hgm-show-motive.html", credit=HGM_credit, title=title, bread=bread, info=info, properties2=prop2, friends=friends)
def latex(self, prec=None, name=None): if prec is None: qe = self.value() else: qe = self.value().truncate_powerseries(prec) wl = web_latex_split_on_re(qe) if name is not None and self.value().base_ring().degree()>1: return wl.replace(latex(self.value().base_ring().gen()), name) else: return wl
def web_latex_poly(pol, name='x', keepzeta=False): """ Change the name of the variable in a polynomial. If keepzeta, then don't change the name of zetaN in the defining polynomial of a cyclotomic field. (keepzeta not implemented yet) """ # the next few lines were adapted from the lines after line 117 of web_newforms.py oldname = latex(pol.parent().gen()) subfrom = oldname.strip() subfrom = subfrom.replace("\\","\\\\") subfrom = subfrom.replace("{","\\{") # because x_{0} means somethgn in a regular expression if subfrom[0].isalpha(): subfrom = "\\b" + subfrom subto = name.replace("\\","\\\\") subto += " " # print "converting from",subfrom,"to", subto, "of", latex(pol) newpol = re.sub(subfrom, subto, latex(pol)) # print "result is",newpol return web_latex_split_on_pm(newpol)
def formatfield(coef): coef = string2list(coef) thefield = WebNumberField.from_coeffs(coef) if thefield._data is None: deg = len(coef) - 1 mypol = latex(coeff_to_poly(coef)) mypol = mypol.replace(' ','').replace('+','%2B').replace('{', '%7B').replace('}','%7d') mypol = '<a title = "Field missing" knowl="nf.field.missing" kwargs="poly=%s">Deg %d</a>' % (mypol,deg) return mypol return nf_display_knowl(thefield.get_label(),thefield.field_pretty())
def myhelper(self, coefmult): coef = string2list(coefmult[0]) subfield = self.from_coeffs(coef) if subfield._data is None: deg = len(coef) - 1 mypol = latex(coeff_to_poly(coef)) mypol = mypol.replace(' ','').replace('+','%2B').replace('{', '%7B').replace('}','%7d') mypol = '<a title = "Field missing" knowl="nf.field.missing" kwargs="poly=%s">Deg %d</a>' % (mypol,deg) return [mypol, coefmult[1]] return [nf_display_knowl(subfield.get_label(),subfield.field_pretty()), coefmult[1]]
def web_latex(x, enclose=True): """ Convert input to latex string unless it's a string or unicode. The key word argument `enclose` indicates whether to surround the string with `\(` and `\)` to tag it as an equation in html. Note: if input is a factored ideal, use web_latex_ideal_fact instead. Example: >>> x = var('x') >>> web_latex(x**23 + 2*x + 1) '\\( x^{23} + 2 \\, x + 1 \\)' """ if isinstance(x, (str, unicode)): return x if enclose == True: return "\( %s \)" % latex(x) return " %s " % latex(x)
def make_bsd(self): bsd = self.bsd = {} r = self.rank if r >= 2: bsd['lder_name'] = "L^{(%s)}(E,1)/%s!" % (r,r) elif r: bsd['lder_name'] = "L'(E,1)" else: bsd['lder_name'] = "L(E,1)" bsd['reg'] = self.regulator bsd['omega'] = self.real_period bsd['sha'] = self.sha bsd['lder'] = self.special_value 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] bsd['tamagawa_factors'] = r'\cdot'.join(cp_fac) bsd['tamagawa_product'] = prod(tamagawa_numbers)
def list_factored_to_factored_poly_otherorder(sfacts_fc_list, galois=False, vari='T', p=None): """ Either return the polynomial in a nice factored form, or return a pair, with first entry the factored polynomial and the second entry a list describing the Galois groups of the factors. vari allows to choose the variable of the polynomial to be returned. """ gal_list = [] order = TermOrder('M(0,-1,0,-1)') ZZpT = PolynomialRing(ZZ, ['p', vari], order=order) ZZT = PolynomialRing(ZZ, vari) outstr = '' for g, e in sfacts_fc_list: if galois: # hack because currently sage only handles monic polynomials: this_poly = ZZT(list(reversed(g))) this_degree = this_poly.degree() this_number_field = NumberField(this_poly, "a") this_gal = this_number_field.galois_group(type='pari') this_t_number = this_gal.group().__pari__()[2].sage() gal_list.append([this_degree, this_t_number]) # casting from ZZT -> ZZpT if p is None: gtoprint = {(0, i): gi for i, gi in enumerate(g)} else: gtoprint = {} for i, elt in enumerate(g): if elt != 0: val = ZZ(elt).valuation(p) gtoprint[(val, i)] = elt / p**val glatex = latex(ZZpT(gtoprint)) if e > 1: outstr += '( %s )^{%d}' % (glatex, e) elif len(sfacts_fc_list) > 1: outstr += '( %s )' % (glatex, ) else: outstr += glatex if galois: # 2 factors of degree 2 if len(sfacts_fc_list) == 2: if len(sfacts_fc_list[0][0]) == 3 and len( sfacts_fc_list[1][0]) == 3: troubletest = ZZT(sfacts_fc_list[0][0]).disc() * ZZT( sfacts_fc_list[1][0]).disc() if troubletest.is_square(): gal_list = [[2, 1]] return outstr, gal_list return outstr
def display_character_values(self): Rgens = self._get_Rgens() d = self.dim gens = [r' <td class="dark border-right border-bottom">\(n\)</td>'] vals = [r' <td class="dark border-right">\(\chi(n)\)</td>'] for j, (g, chi_g) in enumerate(self.hecke_ring_character_values): term = sum(Rgens[i]*chi_g[i] for i in range(d)) latexterm = latex(term) color = "dark" if j%2 else "light" gens.append(r' <td class="%s border-bottom">\(%s\)</td>'%(color, g)) vals.append(r' <td class="%s">\(%s\)</td>'%(color, latexterm)) return ' <tr>\n%s </tr>\n <tr>\n%s </tr>'%('\n'.join(gens), '\n'.join(vals))
def make_class(self): self.ECNF = ECNF.by_label(self.label) # Create a list of the curves in the class from the database self.db_curves = [ECNF(c) for c in db_ec().find( {'field_label' : self.field_label, 'conductor_label' : self.conductor_label, 'iso_label' : self.iso_label}).sort('number')] size = len(self.db_curves) # Extract the isogeny degree matrix from the database if possible, else create it if hasattr(self,'isogeny_matrix'): from sage.matrix.all import Matrix self.isogeny_matrix = Matrix(self.isogeny_matrix) else: self.isogeny_matrix = make_iso_matrix(self.db_curves) # 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.curves = [[c.short_label, c.urls['curve'], c.latex_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.ECNF.field_label) self.field = self.ECNF.field 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 = [] 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 = [('Label', self.ECNF.label), (None, self.graph_link), ('Conductor', '%s' % self.ECNF.cond) ] self.bread = [('Elliptic Curves ', url_for(".index")), (self.ECNF.field_label, self.urls['field']), (self.ECNF.conductor_label, self.urls['conductor']), ('isogeny class %s' % self.ECNF.short_label, self.urls['class'])]
def ll_raw(*stuff): """For each argument, generate a latex representation, unless the argument is already a string. Superfluous curly braces and \\left or \\right commands are removed. Moreover, the variable la is replaced by lambda.""" result = "" for s in stuff: if isinstance(s, basestring): result += s else: result += latex_strip(latex(s)) return result
def formatfield(coef): coef = string2list(coef) thefield = WebNumberField.from_coeffs(coef) if thefield._data is None: deg = len(coef) - 1 mypol = latex(coeff_to_poly(coef)) mypol = mypol.replace(' ', '').replace('+', '%2B').replace( '{', '%7B').replace('}', '%7d') mypol = '<a title = "Field missing" knowl="nf.field.missing" kwargs="poly=%s">Deg %d</a>' % ( mypol, deg) return mypol return nf_display_knowl(thefield.get_label(), thefield.field_pretty())
def specialValueString(L, s, sLatex, normalization="analytic"): ''' Returns the LaTex to dislpay for L(s) Will eventually be replaced by specialValueTriple. ''' number_of_decimals = 10 val = None if hasattr(L, "lfunc_data"): s_alg = s + p2sage(L.lfunc_data['analytic_normalization']) for x in p2sage(L.lfunc_data['values']): # the numbers here are always half integers # so this comparison is exact if x[0] == s_alg: val = x[1] break if val is None: if L.fromDB: val = "not computed" else: val = L.sageLfunction.value(s) if normalization == "arithmetic": lfunction_value_tex = L.texname_arithmetic.replace('s)', sLatex + ')') else: lfunction_value_tex = L.texname.replace('(s', '(' + sLatex) # We must test for NaN first, since it would show as zero otherwise # Try "RR(NaN) < float(1e-10)" in sage -- GT if CC(val).real().is_NaN(): return "\\[{0}=\\infty\\]".format(lfunction_value_tex) elif val.abs() < 1e-10: return "\\[{0}=0\\]".format(lfunction_value_tex) elif normalization == "arithmetic": return (lfunction_value_tex, latex( round(val.real(), number_of_decimals) + round(val.imag(), number_of_decimals) * I)) else: return "\\[{0} \\approx {1}\\]".format( lfunction_value_tex, latex( round(val.real(), number_of_decimals) + round(val.imag(), number_of_decimals) * I))
def print_list_of_coefficients(info): r""" Print a table of Fourier coefficients in the requested format """ level = my_get(info, "level", -1, int) weight = my_get(info, "weight", -1, int) bitprec = my_get(info, "bitprec", 12, int) # number of digits character = my_get(info, "character", "", str) # int(info.get('weight',0)) fmt = info.get("format", "q_expansion") if character == "": character = "1" label = info.get("label", "") if character.isalnum(): character = int(character) else: return "The character '{0}' is not well-defined!".format(character) print "--------------" if label == "" or level == -1 or weight == -1: return "Need to specify a modular form completely!!" number = int(info["number"]) + 1 if "number" in info else 20 emf_logger.debug("number = {}".format(number)) F = WebNewForm(level=level, weight=weight, character=character, label=label, prec=number) if not F.has_updated(): return "" if not "number" in info: F.prec = number = max(F.parent.sturm_bound + 1, 20) F.update_from_db() shead = "Cusp forms of weight " + str(weight) + "on \(" + latex(F.parent.group) + "\)" s = "" if (character is not None) and (character > 0): shead = shead + " and character \( \chi_{" + str(character) + "}\)" # s="<table><tr><td>" coefs = "" if fmt == "sage": res = [] if number > F.max_available_prec(): raise IndexError, "The database does not contain this many ({0}) coefficients for this modular form! We only have {1}".format( number, F.max_available_prec() ) if fmt == "sage": qe = F.coefficients(range(number)) res.append(qe) else: coefs += print_coefficients_for_one_form(F, number, info["format"], bitprec=bitprec) if not fmt == "sage": return s + "\n" + coefs else: if len(res) == 1: res = res[0] # print "res=",res return dumps(res)
def number_field_jump(info): query = {'label_orig': info['jump']} try: parse_nf_string(info, query, 'jump', name="Label", qfield='label') # we end up parsing the string twice, but that is okay F1, _, _ = input_string_to_poly(info['jump']) if F1 and F1.list() != db.nf_fields.lookup(query['label'], 'coeffs'): flash_info( r"The requested field $\Q[{}]/\langle {}\rangle$ is isomorphic to the field below, but uses a different defining polynomial." .format(str(F1.parent().gen()), latex(F1))) return redirect(url_for(".by_label", label=query['label'])) except ValueError: return redirect(url_for(".number_field_render_webpage"))
def render_hgm_webpage(args): data = None info = {} if 'label' in args: label = clean_input(args['label']) C = base.getDBConnection() data = C.hgm.motives.find_one({'label': label}) if data is None: bread = get_bread([("Search error", url_for('.search'))]) info['err'] = "Motive " + label + " was not found in the database." info['label'] = label return search_input_error(info, bread) title = 'Hypergeometric Motive:' + label A = data['A'] B = data['B'] tn = data['t']['n'] td = data['t']['d'] t = latex(QQ(str(tn)+'/'+str(td))) primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71] locinfo = data['locinfo'] for j in range(len(locinfo)): locinfo[j] = [primes[j]] + locinfo[j] locinfo[j][2] = poly_with_factored_coeffs(locinfo[j][2], primes[j]) hodge = data['hodge'] prop2 = [ ('Degree', '\(%s\)' % data['degree']), ('Weight', '\(%s\)' % data['weight']), ('Conductor', '\(%s\)' % data['cond']), ] info.update({ 'A': A, 'B': B, 't': t, 'degree': data['degree'], 'weight': data['weight'], 'sign': data['sign'], 'sig': data['sig'], 'hodge': hodge, 'cond': data['cond'], 'req': data['req'], 'locinfo': locinfo }) friends = [] # friends = [('Galois group', "/GaloisGroup/%dT%d" % (gn, gt))] # if unramfriend != '': # friends.append(('Unramified subfield', unramfriend)) # if rffriend != '': # friends.append(('Discriminant root field', rffriend)) bread = get_bread([(label, ' ')]) return render_template("hgm-show-motive.html", credit=HGM_credit, title=title, bread=bread, info=info, properties2=prop2, friends=friends)
def render_isogeny_class(iso_class): info = {} credit = 'John Cremona' label = iso_class C = base.getDBConnection() data = C.ellcurves.isogeny.find_one({'label': label}) if data is None: return "No such isogeny class" ainvs = [int(a) for a in data['ainvs_for_optimal_curve']] E = EllipticCurve(ainvs) info = {'label': label} info['optimal_ainvs'] = ainvs if 'imag' in data: info['imag'] = data['imag'] if 'real' in data: info['real'] = data['real'] info['rank'] = data['rank'] info['isogeny_matrix'] = latex(matrix(eval(data['isogeny_matrix']))) info['modular_degree'] = data['degree'] #info['f'] = ajax_more(E.q_eigenform, 10, 20, 50, 100, 250) info['f'] = web_latex(E.q_eigenform(10)) G = E.isogeny_graph() n = G.num_verts() G.relabel(range(1, n + 1)) # proper cremona labels... info['graph_img'] = image_src(G.plot(edge_labels=True)) curves = data['label_of_curves_in_the_class'] info['curves'] = list(curves) info['download_qexp_url'] = url_for('download_qexp', limit=100, ainvs=','.join([str(a) for a in ainvs])) info['download_all_url'] = url_for('download_all', label=str(label)) friends = [('Elliptic Curve %s' % l, "/EllipticCurve/Q/%s" % l) for l in data['label_of_curves_in_the_class']] friends.append(('Quadratic Twist', "/quadratic_twists/%s" % (label))) friends.append(('Modular Form', url_for("emf.render_classical_modular_form_from_label", label="%s" % (label)))) info['friends'] = friends t = "Elliptic Curve Isogeny Class %s" % info['label'] bread = [('Elliptic Curves ', url_for("rational_elliptic_curves")), ('isogeny class %s' % info['label'], ' ')] return render_template("elliptic_curve/iso_class.html", info=info, bread=bread, credit=credit, title=t)
def print_geometric_data_Gamma0N(N): r""" Print data about Gamma0(N). """ G = Gamma0(N) s = "" s = "<table>" s += "<tr><td>index:</td><td>%s</td></tr>" % G.index() s += "<tr><td>genus:</td><td>%s</td></tr>" % G.genus() s += "<tr><td>Cusps:</td><td>\(%s\)</td></tr>" % latex(G.cusps()) s += "<tr><td colspan=\"2\">Number of elliptic fixed points</td></tr>" s += "<tr><td>order 2:</td><td>%s</td></tr>" % G.nu2() s += "<tr><td>order 3:</td><td>%s</td></tr>" % G.nu3() s += "</table>" return s
def make_curve_latex(crv_str, nu=None): if "nu" not in crv_str: R0 = QQ else: R0 = PolynomialRing(QQ, "nu") R = PolynomialRing(R0, 2, "x,y") #F = FractionField(R) sides = crv_str.split("=") lhs = R(sides[0]) rhs = R(sides[1]) if nu and ("nu" in crv_str): S = PolynomialRing(CC, 2, 'x,y') # evaluate at nu, if given new_lhs = dict() new_rhs = dict() for m, c in lhs.dict().items(): new_lhs[m] = c.subs(nu=nu) for m, c in rhs.dict().items(): new_rhs[m] = c.subs(nu=nu) lhs = S(new_lhs) # R, or something else, like CC[]? rhs = S(new_rhs) eqn_str = latex(lhs) + "=" + latex(rhs) return eqn_str
def display_hecke_cutters(self): polynomials = [] truncated = False for p,F in self.hecke_cutters: cut = len(F) - 1 count = 0 while cut >= 0 and count < 8: if F[cut]: count += 1 cut -= 1 if count < 8 or cut == 0 and abs(F[0]) < 100: F = latex(coeff_to_poly(F, 'T%s'%p)) else: # truncate to the first 8 nonzero coefficients F = [0]*(cut+1) + F[cut+1:] F = latex(coeff_to_poly(F, 'T%s'%p)) + r' + \cdots' truncated = True polynomials.append(web_latex_split_on_pm(F)) title = 'linear operator' if len(polynomials) > 1: title += 's' knowl = display_knowl('mf.elliptic.hecke_cutter', title=title) desc = "<p>This newform can be constructed as the " if truncated or len(polynomials) > 1: if len(polynomials) > 1: desc += "intersection of the kernels " else: desc += "kernel " desc += "of the following %s acting on %s:</p>\n<table>" desc = desc % (knowl, self.display_newspace()) desc += "\n".join("<tr><td>%s</td></tr>" % F for F in polynomials) + "\n</table>" elif len(polynomials) == 1: desc += "kernel of the %s %s acting on %s." desc = desc % (knowl, polynomials[0], self.display_newspace()) else: desc = r"<p>There are no other newforms in %s.</p>"%(self.display_newspace()) return desc
def specialValueString(L, s, sLatex, normalization="analytic"): ''' Returns the LaTex to dislpay for L(s) Will eventually be replaced by specialValueTriple. ''' number_of_decimals = 10 val = None if hasattr(L,"lfunc_data"): s_alg = s+p2sage(L.lfunc_data['analytic_normalization']) for x in p2sage(L.lfunc_data['values']): # the numbers here are always half integers # so this comparison is exact if x[0] == s_alg: val = x[1] break if val is None: if L.fromDB: val = "not computed" else: val = L.sageLfunction.value(s) if normalization == "arithmetic": lfunction_value_tex = L.texname_arithmetic.replace('s)', sLatex + ')') else: lfunction_value_tex = L.texname.replace('(s', '(' + sLatex) # We must test for NaN first, since it would show as zero otherwise # Try "RR(NaN) < float(1e-10)" in sage -- GT if CC(val).real().is_NaN(): return "\\[{0}=\\infty\\]".format(lfunction_value_tex) elif val.abs() < 1e-10: return "\\[{0}=0\\]".format(lfunction_value_tex) elif normalization == "arithmetic": return(lfunction_value_tex, latex(round(val.real(), number_of_decimals) + round(val.imag(), number_of_decimals) * I)) else: return "\\[{0} \\approx {1}\\]".format(lfunction_value_tex, latex(round(val.real(), number_of_decimals) + round(val.imag(), number_of_decimals) * I))
def jacobi_sum(self, val): mod, num = self.modulus, self.number val = int(val[0]) psi = self.H[val] chi = self.chi.sage_character() psi = psi.sage_character() jacobi_sum = chi.jacobi_sum(psi) chitex = self.char2tex(mod, num, tag=False) psitex = self.char2tex(mod, val, tag=False) Gtex = '\Z/%s\Z' % mod chitexr = self.char2tex(mod, num, 'r', tag=False) psitex1r = self.char2tex(mod, val, '1-r', tag=False) deftex = r'\sum_{r\in %s} %s %s'%(Gtex,chitexr,psitex1r) from sage.all import latex return r"\( \displaystyle J(%s,%s) = %s = %s.\)" % (chitex, psitex, deftex, latex(jacobi_sum))
def myhelper(self, coefmult): coef = string2list(coefmult[0]) subfield = self.from_coeffs(coef) if subfield._data is None: deg = len(coef) - 1 mypol = latex(coeff_to_poly(coef)) mypol = mypol.replace(' ', '').replace('+', '%2B').replace( '{', '%7B').replace('}', '%7d') mypol = '<a title = "Field missing" knowl="nf.field.missing" kwargs="poly=%s">Deg %d</a>' % ( mypol, deg) return [mypol, coefmult[1]] return [ nf_display_knowl(subfield.get_label(), subfield.field_pretty()), coefmult[1] ]
def get_local_algebra(self, p): local_algebra_dict = self._data.get('loc_algebras', None) if local_algebra_dict is None: return None if str(p) in local_algebra_dict: R = PolynomialRing(QQ, 'x') palg = local_algebra_dict[str(p)] palgs = [R(str(s)) for s in palg.split(',')] palgs = [list2string([int(c) for c in pol.coefficients(sparse=False)]) for pol in palgs] palgs = [lfdb().find_one({'p': p, 'coeffs': c}) for c in palgs] return [[f['label'], latex(R(string2list(f['coeffs']))), int(f['e']), int(f['f']),int(f['c']), group_display_knowl(f['gal'][0], f['gal'][1], db()), f['t'],f['u'],f['slopes']] for f in palgs] return None
def web_latex_split_on(x, on=['+', '-']): r""" Convert input into a latex string. A different latex surround `\(` `\)` is used, with splits occuring at `on` (+ - by default). Example: >>> x = var('x') >>> web_latex_split_on(x**2 + 1) '\\( x^{2} \\) + \\( 1 \\)' """ if isinstance(x, string_types): return x else: A = r"\( %s \)" % latex(x) for s in on: A = A.replace(s, r'\) ' + s + r' \( ') return A
def bigpoly_knowl(f, nterms_cutoff=8, bigint_cutoff=12, var='x'): lng = web_latex(coeff_to_poly(f, var)) if bigint_cutoff: lng = make_bigint(lng, bigint_cutoff, max_width=70).replace('"',"'") if len([c for c in f if c != 0]) > nterms_cutoff: short = "%s^{%s}" % (latex(coeff_to_poly([0,1], var)), len(f) - 1) i = len(f) - 2 while i >= 0 and f[i] == 0: i -= 1 if i >= 0: # nonzero terms if f[i] > 0: short += r" + \cdots" else: short += r" - \cdots" return r'<a title="[poly]" knowl="dynamic_show" kwargs="%s">\(%s\)</a>'%(lng, short) else: return lng
def specialValueTriple(L, s, sLatex_analytic, sLatex_arithmetic): ''' Returns [L_arithmetic, L_analytic, L_val] Currently only used for genus 2 curves and Dirichlet characters. Eventually want to use for all L-functions. ''' number_of_decimals = 10 val = None if hasattr(L, "lfunc_data"): s_alg = s + p2sage(L.lfunc_data['analytic_normalization']) if 'values' in L.lfunc_data.keys(): for x in p2sage(L.lfunc_data['values']): # the numbers here are always half integers # so this comparison is exact if x[0] == s_alg: val = x[1] break if val is None: if L.fromDB: val = "not computed" else: val = L.sageLfunction.value(s) # We must test for NaN first, since it would show as zero otherwise # Try "RR(NaN) < float(1e-10)" in sage -- GT lfunction_value_tex_arithmetic = L.texname_arithmetic.replace( 's)', sLatex_arithmetic + ')') lfunction_value_tex_analytic = L.texname.replace('(s', '(' + sLatex_analytic) try: if CC(val).real().is_NaN(): Lval = "\\infty" elif val.abs() < 1e-10: Lval = "0" else: Lval = latex( round(val.real(), number_of_decimals) + round(val.imag(), number_of_decimals) * I) except (TypeError, NameError): Lval = val # if val is text return [lfunction_value_tex_analytic, lfunction_value_tex_arithmetic, Lval]
def raw_typeset(raw, typeset='', extra='', compressed=False): r""" Return a span with typeset material which will toggle to raw material when an icon is clicked on. The raw version can be a string, or a sage object which will stringify properly. If the typeset version can be gotten by just applying latex to the raw version, the typeset version can be omitted. If there is a string to appear between the toggled text and the icon, it can be given in the argument extra If one of these appear on a page, then the icon to toggle all of them on the page will appear in the upper right corner of the body of the page. """ if not typeset: typeset = r'\({}\)'.format(latex(raw)) typeset = f'<span class="tset-container">{typeset}</span>' # clean white space raw = re.sub(r'\s+', ' ', str(raw).strip()) raw = f'<textarea rows="1" cols="{len(raw)}" class="raw-container">{raw}</textarea>' # the doublesclick behavior is set on load in javascript out = f""" <span class="raw-tset-container tset {"compressed" if compressed else ""}"> {typeset} {raw} {extra} <span class="raw-tset-copy-btn" onclick="copyrawcontainer(this)"> <img alt="Copy content" class="tset-icon"> </span> <span class="raw-tset-toggle" onclick="iconrawtset(this)"> <img alt="Toggle raw display" class="tset-icon" </span> </span>""" return out
def web_latex_split_on_re(x, r = '(q[^+-]*[+-])'): r""" Convert input into a latex string, with splits into separate latex strings occurring on given regex `r`. CAUTION: this gives a different result than web_latex_split_on_pm Example: >>> x = var('x') >>> web_latex_split_on_re(x**2 + 1) '\\(x^{2} \\) \\(\\mathstrut+ 1 \\)' """ def insert_latex(s): return s.group(1) + r'\) \(' if isinstance(x, string_types): return x else: A = r"\( %s \)" % latex(x) c = re.compile(r) A = A.replace(r'+', r'\) \( {}+ ') A = A.replace(r'-', r'\) \( {}- ') # A = A.replace('\left(','\left( {}\\right.') # parantheses needs to be balanced # A = A.replace('\\right)','\left.\\right)') A = A.replace(r'\left(',r'\bigl(') A = A.replace(r'\right)',r'\bigr)') A = c.sub(insert_latex, A) # the above will be re-done using a more sophisticated method involving # regular expressions. Below fixes bad spacing when the current approach # encounters terms like (-3+x) A = A.replace(r'( {}', r'(') A = A.replace(r'(\) \(', r'(') A = A.replace(r'\(+', r'\(\mathstrut+') A = A.replace(r'\(-', r'\(\mathstrut-') A = A.replace(r'( ', r'(') A = A.replace(r'( ', r'(') A = A.replace(r'+\) \(O', r'+O') return A
def jacobi_sum(self, val): mod, num = self.modulus, self.number try: val = int(val) except ValueError: raise Warning ("n must be a positive integer coprime to the modulus {} and no greater than it".format(mod)) if gcd(mod, val) > 1: raise Warning ("n must be coprime to the modulus : %s"%mod) if val > mod: raise Warning ("n must be less than the modulus : %s"%mod) if val < 0: raise Warning ("n must be positive") chi_values_data = db.char_dir_values.lookup( "{}.{}".format(mod, num) ) chi_valuepairs = chi_values_data['values_gens'] chi_genvalues = [int(v) for g, v in chi_valuepairs] chi = self.chi.sage_character(self.order, chi_genvalues) psi = ConreyCharacter(self.modulus, val) psi_values_data = db.char_dir_values.lookup( "{}.{}".format(self.modulus, val) ) psi_valuepairs = psi_values_data['values_gens'] psi_genvalues = [int(v) for g, v in psi_valuepairs] psi = psi.sage_character(self.order, psi_genvalues) jacobi_sum = chi.jacobi_sum(psi) chitex = self.char2tex(mod, num, tag=False) psitex = self.char2tex(mod, val, tag=False) Gtex = r'\Z/%s\Z' % mod chitexr = self.char2tex(mod, num, 'r', tag=False) psitex1r = self.char2tex(mod, val, '1-r', tag=False) deftex = r'\sum_{r\in %s} %s %s'%(Gtex,chitexr,psitex1r) return r"\( \displaystyle J(%s,%s) = %s = %s \)" % (chitex, psitex, deftex, latex(jacobi_sum))
def _latex_(self): r""" Returns LaTeX string representation of self. EXAMPLES:: sage: WR=WeilRepDiscriminantForm(2,dual=False) sage: latex(WR) Weil representation of the discriminant form given by $\mathbb{Z}/4\mathbb{Z}$ with quadratic form $Q(x)=2\,x^{2} \mathrm{mod} 1$. """ s="\\begin{verbatim}\\end{verbatim}" if self._is_dual_rep: s+="Dual of " else: s+="" # s+="Weil representation of the discriminant form given by $\\mathbb{Z}/"+str(2*self._N)+"\\mathbb{Z}$ \\text{ with quadratic form } Q(x)="+latex(self._N)+"\\,x^{2}\\, \\mathrm{mod}\\, 1$ .\end{verbatim}}" s+="Weil representation of the discriminant form given by $\\mathbb{Z}/"+str(2*self._N)+"\\mathbb{Z}$" s+=" with quadratic form $Q(x)="+latex(self._N)+"\\,x^{2}\\, \\mathrm{mod}\\, 1$." return s
def web_latex_split_on_pm(x): r""" Convert input into a latex string, with specific handling of expressions including `+` and `-`. Example: >>> x = var('x') >>> web_latex_split_on_pm(x**2 + 1) '\\(x^{2} \\) \\(\\mathstrut +\\mathstrut 1 \\)' """ on = ['+', '-'] # A = "\( %s \)" % latex(x) try: A = r"\(" + x + r"\)" # assume we are given LaTeX to split on except: A = r"\( %s \)" % latex(x) # need a more clever split_on_pm that inserts left and right properly A = A.replace(r"\left","") A = A.replace(r"\right","") for s in on: # A = A.replace(s, r'\) ' + s + r' \( ') # A = A.replace(s, r'\) ' + r' \( \mathstrut ' + s ) A = A.replace(s, r'\)' + r' \(\mathstrut ' + s + r'\mathstrut ') # the above will be re-done using a more sophisticated method involving # regular expressions. Below fixes bad spacing when the current approach # encounters terms like (-3+x) for s in on: A = A.replace(r'(\) \(\mathstrut ' + s, '(' + s) A = A.replace(r'( {}', r'(') A = A.replace(r'(\) \(', r'(') A = A.replace(r'\(+', r'\(\mathstrut+') A = A.replace(r'\(-', r'\(\mathstrut-') A = A.replace(r'( ', r'(') A = A.replace(r'( ', r'(') return A
def render_hecke_algebras_webpage_l_adic(**args): data = None if 'orbit_label' in args and 'prime' in args: lab = clean_input(args.get('orbit_label')) if lab != args.get('orbit_label'): base_lab = ".".join([split(lab)[i] for i in [0, 1, 2]]) return redirect( url_for('.render_hecke_algebras_webpage', label=base_lab), 301) try: ell = int(args.get('prime')) except ValueError: base_lab = ".".join([split(lab)[i] for i in [0, 1, 2]]) return redirect( url_for('.render_hecke_algebras_webpage', label=base_lab), 301) data = db.hecke_ladic.lucky({'orbit_label': lab, 'ell': ell}) if data is None: t = "Hecke algebra search error" bread = [('HeckeAlgebra', url_for(".hecke_algebras_render_webpage"))] flash_error( "%s is not a valid label for the ℓ-adic information for an Hecke algebra orbit in the database.", lab) return render_template("hecke_algebras-error.html", title=t, properties=[], bread=bread, learnmore=learnmore_list()) info = {} info.update(data) proj = [ 'index', 'orbit_label', 'ell', 'idempotent', 'field', 'structure', 'properties', 'operators' ] res = list( db.hecke_ladic.search( { 'level': data['level'], 'weight': data['weight'], 'orbit_label': data['orbit_label'], 'ell': data['ell'] }, proj)) for f in res: if f['idempotent'] != "": dim = len(sage_eval(f['idempotent'])) l_max = sage_eval(f['idempotent'])[0][0].ndigits() if dim > 4 or l_max > 5: f['idempotent_display'] = [] elif dim == 1: f['idempotent_display'] = sage_eval(f['idempotent'])[0][0] else: f['idempotent_display'] = latex( matrix(sage_eval(f['idempotent']))) else: f['idempotent_display'] = latex(matrix([[1]])) del f['idempotent'] f['download_id'] = [ (i, url_for(".render_hecke_algebras_webpage_ell_download", orbit_label=f['orbit_label'], index=f['index'], prime=f['ell'], lang=i, obj='idempotents')) for i in ['magma', 'sage'] ] # for 'gp' the code does not work, since p-adics are not implemented field = f.pop('field') if field is not None: f['deg'] = field[1] f['field_poly'] = field[2] structure = f.pop('structure') if structure is not None: f['dim'] = structure[0] f['num_gen'] = structure[1] s2 = sage_eval(structure[2]) f['gens'] = [[int(s2.index(i) + 1), str(i)] for i in s2] f['rel'] = sage_eval(structure[3]) properties = f.pop('properties') if properties is not None: f['grading'] = properties[0] f['gorenstein_def'] = properties[1] f['gorenstein'] = "yes" if properties[1] == 0 else "no" operators = f.pop('operators') if operators is not None: f['operators_mod_l'] = operators f['num_hecke_op'] = len(operators) f['size_op'] = size = sqrt(len(operators[0])) if size > 4: f['operators_mod_l_display'] = [] elif size == 1: f['operators_mod_l_display'] = [[i + 1, operators[i][0]] for i in range(10)] else: f['operators_mod_l_display'] = [[ i + 1, latex(matrix(size, size, operators[i])) ] for i in range(5)] f['download_op'] = [ (lang, url_for(".render_hecke_algebras_webpage_ell_download", orbit_label=f['orbit_label'], index=f['index'], prime=f['ell'], lang=lang, obj='operators')) for lang in ['magma', 'sage'] ] # for 'gp' the code does not work info['num_l_adic_orbits'] = len(res) info['l_adic_orbits'] = res info['level'] = int(data['level']) info['weight'] = int(data['weight']) info['base_lab'] = ".".join( [split(data['orbit_label'])[i] for i in [0, 1, 2]]) info['orbit_label'] = str(data['orbit_label']) info['ell'] = int(data['ell']) bread = [('HeckeAlgebra', url_for(".hecke_algebras_render_webpage")), ('%s' % info['base_lab'], url_for('.render_hecke_algebras_webpage', label=info['base_lab'])), ('%s' % info['ell'], ' ')] credit = hecke_algebras_credit info['properties'] = [('Level', '%s' % info['level']), ('Weight', '%s' % info['weight']), ('Characteristic', '%s' % info['ell']), ('Orbit label', '%s' % info['orbit_label'])] info['friends'] = [('Modular form ' + info['base_lab'], url_for("cmf.by_url_space_label", level=info['level'], weight=info['weight'], char_orbit_label='a'))] t = "%s-adic and mod %s data for the Hecke algebra orbit %s" % ( info['ell'], info['ell'], info['orbit_label']) return render_template("hecke_algebras_l_adic-single.html", info=info, credit=credit, title=t, bread=bread, properties=info['properties'], learnmore=learnmore_list(), friends=info['friends'], KNOWL_ID='hecke_algebra_l_adic.%s' % (info['orbit_label']))
def render_hecke_algebras_webpage(**args): data = None if 'label' in args: lab = clean_input(args.get('label')) if lab != args.get('label'): return redirect( url_for('.render_hecke_algebras_webpage', label=lab), 301) data = db.hecke_algebras.lookup(lab) if data is None: t = "Hecke algebra search error" bread = [('HeckeAlgebra', url_for(".hecke_algebras_render_webpage"))] flash_error( "%s is not a valid label for a Hecke algebra in the database.", lab) return render_template("hecke_algebras-error.html", title=t, properties=[], bread=bread, learnmore=learnmore_list()) info = {} info.update(data) bread = [('HeckeAlgebra', url_for(".hecke_algebras_render_webpage")), ('%s' % data['label'], ' ')] credit = hecke_algebras_credit info['level'] = int(data['level']) info['weight'] = int(data['weight']) info['num_orbits'] = int(data['num_orbits']) dim_count = "not available" proj = [ 'orbit_label', 'hecke_op', 'num_hecke_op', 'Zbasis', 'discriminant', 'disc_fac', 'Qbasis', 'Qalg_gen' ] orb = list(db.hecke_orbits.search({'parent_label': data['label']}, proj)) if orb: #consistency check if len(orb) != int(data['num_orbits']): return search_input_error(info) dim_count = 0 for v in orb: ops = sage_eval(v['hecke_op']) dim = int(matrix(ops[0]).nrows()) dim_count += dim if dim > 4: v['hecke_op_display'] = [] elif dim == 1: v['hecke_op_display'] = [[i + 1, ops[i][0][0]] for i in range(10)] else: v['hecke_op_display'] = [[i + 1, latex(matrix(ops[i]))] for i in range(5)] v['download_op'] = [ (lang, url_for(".render_hecke_algebras_webpage_download", orbit_label=v['orbit_label'], lang=lang, obj='operators')) for lang in ['gp', 'magma', 'sage'] ] if v['Zbasis'] is None: for key in [ 'Zbasis', 'discriminant', 'disc_fac', 'Qbasis', 'Qalg_gen' ]: del v[key] else: v['Zbasis'] = [[int(i) for i in j] for j in v['Zbasis']] v['disc_fac'] = [[int(i) for i in j] for j in v['disc_fac']] if dim > 4: v['gen_display'] = [] elif dim == 1: v['gen_display'] = [v['Zbasis'][0][0]] else: v['gen_display'] = [ latex(matrix(dim, dim, v['Zbasis'][i])) for i in range(dim) ] v['inner_twists'] = "not available" # not yet in the database v['download_gen'] = [ (lang, url_for(".render_hecke_algebras_webpage_download", orbit_label=v['orbit_label'], lang=lang, obj='gen')) for lang in ['gp', 'magma', 'sage'] ] info['orbits'] = orb info['dim_alg'] = dim_count info['l_adic'] = l_range info['properties'] = [('Label', '%s' % info['label']), ('Level', '%s' % info['level']), ('Weight', '%s' % info['weight'])] if info['num_orbits'] != 0: info['friends'] = [('Newforms space ' + info['label'], url_for("cmf.by_url_space_label", level=info['level'], weight=info['weight'], char_orbit_label='a'))] else: info['friends'] = [] t = "Hecke algebra %s" % info['label'] return render_template("hecke_algebras-single.html", info=info, credit=credit, title=t, bread=bread, properties=info['properties'], learnmore=learnmore_list(), friends=info['friends'], KNOWL_ID='hecke_algebra.%s' % (info['label']))
def make_mwbsd(self): mwbsd = self.mwbsd = db.ec_mwbsd.lookup(self.lmfdb_label) # Some components are in the main table: mwbsd['analytic_rank'] = r = self.analytic_rank mwbsd['torsion'] = self.torsion tamagawa_numbers = [ld['tamagawa_number'] for ld in self.local_data] mwbsd['tamagawa_product'] = prod(tamagawa_numbers) if mwbsd['tamagawa_product'] > 1: cp_fac = [ZZ(cp).factor() for cp in tamagawa_numbers] cp_fac = [ latex(cp) if len(cp) < 2 else '(' + latex(cp) + ')' for cp in cp_fac ] mwbsd['tamagawa_factors'] = r'\cdot'.join(cp_fac) else: mwbsd['tamagawa_factors'] = None try: mwbsd['rank'] = self.rank mwbsd['reg'] = self.regulator mwbsd['sha'] = self.sha mwbsd['sha2'] = latex_sha(self.sha) except AttributeError: mwbsd['rank'] = '?' mwbsd['reg'] = '?' mwbsd['sha'] = '?' mwbsd['sha2'] = '?' mwbsd['regsha'] = (mwbsd['special_value'] * self.torsion**2) / ( mwbsd['tamagawa_product'] * mwbsd['real_period']) if r <= 1: mwbsd['rank'] = r # Integral points xintcoords = mwbsd['xcoord_integral_points'] a1, _, a3, _, _ = ainvs = self.ainvs if a1 or a3: int_pts = sum([[(x, y) for y in make_y_coords(ainvs, x)] for x in xintcoords], []) mwbsd['int_points'] = raw_typeset( ', '.join(str(P) for P in int_pts), ', '.join(web_latex(P) for P in int_pts)) else: int_pts = [(x, make_y_coords(ainvs, x)[0]) for x in xintcoords] raw_form = sum([[P, (P[0], -P[1])] if P[1] else [P] for P in int_pts], []) raw_form = ', '.join(str(P) for P in raw_form) mwbsd['int_points'] = raw_typeset( raw_form, ', '.join(pm_pt(P) for P in int_pts)) # Generators (mod torsion) and heights: mwbsd['generators'] = [ raw_typeset(weighted_proj_to_affine_point(P)) for P in mwbsd['gens'] ] if mwbsd['ngens'] else '' # Torsion structure and generators: if mwbsd['torsion'] == 1: mwbsd['tor_struct'] = '' mwbsd['tor_gens'] = '' else: mwbsd['tor_struct'] = r' \times '.join( r'\Z/{%s}\Z' % n for n in self.torsion_structure) tor_gens_tmp = [ weighted_proj_to_affine_point(P) for P in mwbsd['torsion_generators'] ] mwbsd['tor_gens'] = raw_typeset( ', '.join(str(P) for P in tor_gens_tmp), ', '.join(web_latex(P) for P in tor_gens_tmp)) # BSD invariants if r >= 2: mwbsd['lder_name'] = "L^{(%s)}(E,1)/%s!" % (r, r) elif r: mwbsd['lder_name'] = "L'(E,1)" else: mwbsd['lder_name'] = "L(E,1)"
def make_curve(self): data = self.data = {} lmfdb_label = self.lmfdb_label # Some data fields of self are just those from the database. # These only need some reformatting. data['ainvs'] = self.ainvs data['conductor'] = N = self.conductor data['j_invariant'] = QQ(tuple(self.jinv)) data['j_inv_factor'] = latex(0) if data['j_invariant']: # don't factor 0 data['j_inv_factor'] = latex(data['j_invariant'].factor()) data['j_inv_latex'] = web_latex(data['j_invariant']) # retrieve local reduction data from table ec_localdata: self.local_data = local_data = list( db.ec_localdata.search({"lmfdb_label": lmfdb_label})) for ld in local_data: if ld['kodaira_symbol'] <= -14: # Work around bug in Sage's latex ld['kod'] = 'I_{%s}^{*}' % (-ld['kodaira_symbol'] - 4) else: ld['kod'] = latex(KodairaSymbol(ld['kodaira_symbol'])) Nfac = Factorization([(ZZ(ld['prime']), ld['conductor_valuation']) for ld in local_data]) Dfac = Factorization([(ZZ(ld['prime']), ld['discriminant_valuation']) for ld in local_data], unit=ZZ(self.signD)) data['disc_factor'] = latex(Dfac) data['disc'] = D = Dfac.value() data['cond_factor'] = latex(Nfac) data['disc_latex'] = web_latex(D) data['cond_latex'] = web_latex(N) # retrieve data about MW rank, generators, heights and # torsion, leading term of L-function & other BSD data from # table ec_mwbsd: self.make_mwbsd() # latex equation: latexeqn = latex_equation(self.ainvs) data['equation'] = raw_typeset(unlatex(latexeqn), latexeqn) # minimal quadratic twist: data['minq_D'] = minqD = self.min_quad_twist_disc data['minq_label'] = db.ec_curvedata.lucky( {'ainvs': self.min_quad_twist_ainvs}, projection='lmfdb_label' if self.label_type == 'LMFDB' else 'Clabel') data['minq_info'] = '(itself)' if minqD == 1 else '(by {})'.format( minqD) # modular degree: try: data['degree'] = ZZ(self.degree) # convert None to 0 except AttributeError: # if not computed, db has Null and the attribute is missing data['degree'] = 0 # invalid, but will be displayed nicely # coefficients of modular form / L-series: classdata = db.ec_classdata.lookup(self.lmfdb_iso) data['an'] = classdata['anlist'] data['ap'] = classdata['aplist'] # mod-p Galois images: data['galois_data'] = list( db.ec_galrep.search({'lmfdb_label': lmfdb_label})) for gd in data[ 'galois_data']: # remove the prime prefix from each image code gd['image'] = trim_galois_image_code(gd['image']) # CM and Endo ring: data['CMD'] = self.cm data['CM'] = "no" data['EndE'] = r"\(\Z\)" if self.cm: data['cm_ramp'] = [ p for p in ZZ(self.cm).support() if not p in self.nonmax_primes ] data['cm_nramp'] = len(data['cm_ramp']) if data['cm_nramp'] == 1: data['cm_ramp'] = data['cm_ramp'][0] else: data['cm_ramp'] = ", ".join(str(p) for p in data['cm_ramp']) data['cm_sqf'] = ZZ(self.cm).squarefree_part() data['CM'] = r"yes (\(D=%s\))" % data['CMD'] if data['CMD'] % 4 == 0: d4 = ZZ(data['CMD']) // 4 data['EndE'] = r"\(\Z[\sqrt{%s}]\)" % d4 else: data['EndE'] = r"\(\Z[(1+\sqrt{%s})/2]\)" % data['CMD'] data['ST'] = st_link_by_name(1, 2, 'N(U(1))') else: data['ST'] = st_link_by_name(1, 2, 'SU(2)') # Isogeny degrees: cond, iso, num = split_lmfdb_label(lmfdb_label) self.class_deg = classdata['class_deg'] 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: data['isogeny_degrees'] = " and ".join(isodegs) else: data['isogeny_degrees'] = " and ".join( [", ".join(isodegs[:-1]), isodegs[-1]]) self.make_twoadic_data() # Optimality # The optimal curve in the class is the curve whose Cremona # label ends in '1' except for '990h' which was labelled # wrongly long ago. This is proved for N up to # OPTIMALITY_BOUND (and when there is only one curve in an # isogeny class, obviously) and expected for all N. # Column 'optimality' is 1 for certainly optimal curves, 0 for # certainly non-optimal curves, and is n>1 if the curve is one # of n in the isogeny class which may be optimal given current # knowledge. # Column "manin_constant' is the correct Manin constant # assuming that the optimal curve in the class is known, or # otherwise if it is the curve with (Cremona) number 1. # The code here allows us to update the display correctly by # changing one line in this file (defining OPTIMALITY_BOUND) # without changing the data. data['optimality_bound'] = OPTIMALITY_BOUND self.cremona_bound = CREMONA_BOUND if N < CREMONA_BOUND: data[ 'manin_constant'] = self.manin_constant # (conditional on data['optimality_known']) else: data['manin_constant'] = 0 # (meaning not available) if N < OPTIMALITY_BOUND: data['optimality_code'] = int( self.Cnumber == (3 if self.Ciso == '990h' else 1)) data['optimality_known'] = True data['manin_known'] = True if self.label_type == 'Cremona': data[ 'optimal_label'] = '990h3' if self.Ciso == '990h' else self.Ciso + '1' else: data[ 'optimal_label'] = '990.i3' if self.lmfdb_iso == '990.i' else self.lmfdb_iso + '1' elif N < CREMONA_BOUND: data['optimality_code'] = self.optimality data['optimality_known'] = (self.optimality < 2) if self.optimality == 1: data['manin_known'] = True data[ 'optimal_label'] = self.Clabel if self.label_type == 'Cremona' else self.lmfdb_label else: if self.Cnumber == 1: data['manin_known'] = False data[ 'optimal_label'] = self.Clabel if self.label_type == 'Cremona' else self.lmfdb_label else: # find curve #1 in this class and its optimailty code: opt_curve = db.ec_curvedata.lucky( { 'Ciso': self.Ciso, 'Cnumber': 1 }, projection=['Clabel', 'lmfdb_label', 'optimality']) data['manin_known'] = (opt_curve['optimality'] == 1) data['optimal_label'] = opt_curve[ 'Clabel' if self.label_type == 'Cremona' else 'lmfdb_label'] else: data['optimality_code'] = None data['optimality_known'] = False data['manin_known'] = False data['optimal_label'] = '' # p-adic data: data['p_adic_primes'] = [ p for i, p in enumerate(prime_range(5, 100)) if (N * data['ap'][i]) % p != 0 ] data['p_adic_data_exists'] = False if data['optimality_code'] == 1: data['p_adic_data_exists'] = db.ec_padic.exists( {'lmfdb_iso': self.lmfdb_iso}) # Iwasawa data (where present) self.make_iwasawa() # Torsion growth data (where present) self.make_torsion_growth() # Newform rawnewform = str(PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True)) data['newform'] = raw_typeset( rawnewform, web_latex(PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True))) data['newform_label'] = self.newform_label = ".".join( [str(cond), str(2), 'a', iso]) self.newform_link = url_for("cmf.by_url_newform_label", level=cond, weight=2, char_orbit_label='a', hecke_orbit=iso) self.newform_exists_in_db = db.mf_newforms.label_exists( self.newform_label) self._code = None if self.label_type == 'Cremona': self.class_url = url_for(".by_ec_label", label=self.Ciso) self.class_name = self.Ciso else: self.class_url = url_for(".by_ec_label", label=self.lmfdb_iso) self.class_name = self.lmfdb_iso data['class_name'] = self.class_name data['Cnumber'] = self.Cnumber if N < CREMONA_BOUND else None self.friends = [('Isogeny class ' + self.class_name, self.class_url), ('Minimal quadratic twist %s %s' % (data['minq_info'], data['minq_label']), url_for(".by_ec_label", label=data['minq_label'])), ('All twists ', url_for(".rational_elliptic_curves", jinv=data['j_invariant']))] lfun_url = url_for("l_functions.l_function_ec_page", conductor_label=N, isogeny_class_label=iso) origin_url = lfun_url.lstrip('/L/').rstrip('/') if db.lfunc_instances.exists({'url': origin_url}): self.friends += [('L-function', lfun_url)] else: self.friends += [('L-function not available', "")] if not self.cm: if N <= 300: self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', conductor=N, isogeny=iso))] if N <= 50: self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', conductor=N, isogeny=iso))] if self.newform_exists_in_db: self.friends += [('Modular form ' + self.newform_label, self.newform_link)] self.downloads = [('q-expansion to text', url_for(".download_EC_qexp", label=self.lmfdb_label, limit=1000)), ('All stored data to text', url_for(".download_EC_all", label=self.lmfdb_label)), ('Code to Magma', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='magma')), ('Code to SageMath', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='sage')), ('Code to GP', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='gp'))] try: self.plot = encode_plot(self.E.plot()) except AttributeError: self.plot = encode_plot(EllipticCurve(data['ainvs']).plot()) self.plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format( self.plot) self.properties = [ ('Label', self.Clabel if self.label_type == 'Cremona' else self.lmfdb_label), (None, self.plot_link), ('Conductor', prop_int_pretty(data['conductor'])), ('Discriminant', prop_int_pretty(data['disc'])), ('j-invariant', '%s' % data['j_inv_latex']), ('CM', '%s' % data['CM']), ('Rank', 'unknown' if self.mwbsd['rank'] == '?' else prop_int_pretty(self.mwbsd['rank'])), ('Torsion structure', (r'\(%s\)' % self.mwbsd['tor_struct']) if self.mwbsd['tor_struct'] else 'trivial'), ] if self.label_type == 'Cremona': self.title = "Elliptic curve with Cremona label {} (LMFDB label {})".format( self.Clabel, self.lmfdb_label) elif N < CREMONA_BOUND: self.title = "Elliptic curve with LMFDB label {} (Cremona label {})".format( self.lmfdb_label, self.Clabel) else: self.title = "Elliptic curve with LMFDB label {}".format( self.lmfdb_label) self.bread = [('Elliptic curves', url_for("ecnf.index")), (r'$\Q$', url_for(".rational_elliptic_curves")), ('%s' % N, url_for(".by_conductor", conductor=N)), ('%s' % iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)), ('%s' % num, ' ')]
def make_passport_object(self, passport): from lmfdb.belyi.main import url_for_belyi_galmap_label # all information about the map goes in the data dictionary # most of the data from the database gets polished/formatted before we put it in the data dictionary data = self.data = {} for elt in ('plabel', 'abc', 'num_orbits', 'g', 'abc', 'deg', 'maxdegbf'): data[elt] = passport[elt] nt = passport['group'].split('T') data['group'] = group_display_knowl(int(nt[0]), int(nt[1]), getDBConnection()) data['geomtype'] = geomtypelet_to_geomtypename_dict[ passport['geomtype']] data['lambdas'] = [str(c)[1:-1] for c in passport['lambdas']] data['pass_size'] = passport['pass_size'] # Permutation triples galmaps_for_plabel = belyi_db_galmaps().find({ "plabel": passport['plabel'] }).sort([('label_index', ASCENDING)]) galmapdata = [] for galmap in galmaps_for_plabel: # wrap number field nonsense F = belyi_base_field(galmap) # inLMFDB = False; field = {} if F._data == None: field['in_LMFDB'] = False fld_coeffs = galmap['base_field'] pol = PolynomialRing(QQ, 'x')(fld_coeffs) field['base_field'] = latex(pol) field['isQQ'] = False else: field['in_LMFDB'] = True if F.poly().degree() == 1: field['isQQ'] = True F.latex_poly = web_latex(F.poly()) field['base_field'] = F galmapdatum = [ galmap['label'].split('-')[-1], url_for_belyi_galmap_label(galmap['label']), galmap['orbit_size'], field, galmap['triples_cyc'][0][0], galmap['triples_cyc'][0][1], galmap['triples_cyc'][0][2], ] galmapdata.append(galmapdatum) data['galmapdata'] = galmapdata # Properties properties = [('Label', passport['plabel']), ('Group', str(passport['group'])), ('Orders', str(passport['abc'])), ('Genus', str(passport['g'])), ('Size', str(passport['pass_size'])), ('Galois orbits', str(passport['num_orbits']))] self.properties = properties # Friends self.friends = [] # Breadcrumbs groupstr, abcstr, sigma0, sigma1, sigmaoo, gstr = data['plabel'].split( "-") lambdasstr = '%s-%s-%s' % (sigma0, sigma1, sigmaoo) lambdasgstr = lambdasstr + "-" + gstr self.bread = [('Belyi Maps', url_for(".index")), (groupstr, url_for(".by_url_belyi_search_group", group=groupstr)), (abcstr, url_for(".by_url_belyi_search_group_triple", group=groupstr, abc=abcstr)), (lambdasgstr, url_for(".by_url_belyi_passport_label", group=groupstr, abc=abcstr, sigma0=sigma0, sigma1=sigma1, sigmaoo=sigmaoo, g=gstr))] # Title self.title = "Passport " + data['plabel'] # Code snippets (only for curves) self.code = {} return
def make_galmap_object(self, galmap): from lmfdb.belyi.main import url_for_belyi_passport_label # all information about the map goes in the data dictionary # most of the data from the database gets polished/formatted before we put it in the data dictionary data = self.data = {} # the stuff that does not need to be polished for elt in ('label', 'plabel', 'triples_cyc', 'orbit_size', 'g', 'abc', 'deg'): data[elt] = galmap[elt] nt = galmap['group'].split('T') data['group'] = group_display_knowl(int(nt[0]), int(nt[1]), getDBConnection()) data['geomtype'] = geomtypelet_to_geomtypename_dict[galmap['geomtype']] data['lambdas'] = [str(c)[1:-1] for c in galmap['lambdas']] data['isQQ'] = False data['in_LMFDB'] = False F = belyi_base_field(galmap) if F._data == None: fld_coeffs = galmap['base_field'] pol = PolynomialRing(QQ, 'x')(fld_coeffs) data['base_field'] = latex(pol) else: data['in_LMFDB'] = True if F.poly().degree() == 1: data['isQQ'] = True F.latex_poly = web_latex(F.poly()) data['base_field'] = F crv_str = galmap['curve'] if crv_str == 'PP1': data['curve'] = '\mathbb{P}^1' else: data['curve'] = make_curve_latex(crv_str) # change pairs of floats to complex numbers embeds = galmap['embeddings'] embed_strs = [] for el in embeds: if el[1] < 0: el_str = str(el[0]) + str(el[1]) + "\sqrt{-1}" else: el_str = str(el[0]) + "+" + str(el[1]) + "\sqrt{-1}" embed_strs.append(el_str) data['map'] = make_map_latex(galmap['map']) data['embeddings_and_triples'] = [] if data['isQQ']: for i in range(0, len(data['triples_cyc'])): triple_cyc = data['triples_cyc'][i] data['embeddings_and_triples'].append([ "\\text{not applicable (over $\mathbb{Q}$)}", triple_cyc[0], triple_cyc[1], triple_cyc[2] ]) else: for i in range(0, len(data['triples_cyc'])): triple_cyc = data['triples_cyc'][i] data['embeddings_and_triples'].append([ embed_strs[i], triple_cyc[0], triple_cyc[1], triple_cyc[2] ]) data['lambdas'] = [str(c)[1:-1] for c in galmap['lambdas']] # Properties properties = [ ('Label', galmap['label']), ('Group', str(galmap['group'])), ('Orders', str(galmap['abc'])), ('Genus', str(galmap['g'])), ('Size', str(galmap['orbit_size'])), ] self.properties = properties # Friends self.friends = [('Passport', url_for_belyi_passport_label(galmap['plabel']))] # Breadcrumbs groupstr, abcstr, sigma0, sigma1, sigmaoo, gstr, letnum = data[ 'label'].split("-") lambdasstr = '%s-%s-%s' % (sigma0, sigma1, sigmaoo) lambdasgstr = lambdasstr + "-" + gstr self.bread = [ ('Belyi Maps', url_for(".index")), (groupstr, url_for(".by_url_belyi_search_group", group=groupstr)), (abcstr, url_for(".by_url_belyi_search_group_triple", group=groupstr, abc=abcstr)), (lambdasgstr, url_for(".by_url_belyi_passport_label", group=groupstr, abc=abcstr, sigma0=sigma0, sigma1=sigma1, sigmaoo=sigmaoo, g=gstr)), (letnum, url_for(".by_url_belyi_galmap_label", group=groupstr, abc=abcstr, sigma0=sigma0, sigma1=sigma1, sigmaoo=sigmaoo, g=gstr, letnum=letnum)), ] # Title self.title = "Belyi map " + data['label'] # Code snippets (only for curves) self.code = {} return
def make_curve(self): # To start with the data fields of self are just those from # the database. We need to reformat these. # Old version: required constructing the actual elliptic curve # E, and computing some further data about it. # New version (May 2016): extra data fields now in the # database so we do not have to construct the curve or do any # computation with it on the fly. As a failsafe the old way # is still included. data = self.data = {} data['ainvs'] = [ZZ(ai) for ai in self.ainvs] data['conductor'] = N = ZZ(self.conductor) data['j_invariant'] = QQ(str(self.jinv)) data['j_inv_factor'] = latex(0) if data['j_invariant']: # don't factor 0 data['j_inv_factor'] = latex(data['j_invariant'].factor()) data['j_inv_str'] = unicode(str(data['j_invariant'])) data['j_inv_latex'] = web_latex(data['j_invariant']) # extract data about MW rank, generators, heights and torsion: self.make_mw() # get more data from the database entry data['equation'] = self.equation local_data = self.local_data D = self.signD * prod([ld['p']**ld['ord_disc'] for ld in local_data]) for ld in local_data: ld['kod'] = ld['kod'].replace("\\\\", "\\") data['disc'] = D Nfac = Factorization([(ZZ(ld['p']), ld['ord_cond']) for ld in local_data]) Dfac = Factorization([(ZZ(ld['p']), ld['ord_disc']) for ld in local_data], unit=ZZ(self.signD)) data['minq_D'] = minqD = self.min_quad_twist['disc'] data['minq_label'] = self.min_quad_twist[ 'lmfdb_label'] if self.label_type == 'LMFDB' else self.min_quad_twist[ 'label'] data['minq_info'] = '(itself)' if minqD == 1 else '(by {})'.format( minqD) if self.degree is None: data['degree'] = 0 # invalid, but will be displayed nicely else: data['degree'] = self.degree try: data['an'] = self.anlist data['ap'] = self.aplist except AttributeError: r = db.ec_curves.lucky({'lmfdb_iso': self.lmfdb_iso, 'number': 1}) data['an'] = r['anlist'] data['ap'] = r['aplist'] data['disc_factor'] = latex(Dfac) data['cond_factor'] = latex(Nfac) data['disc_latex'] = web_latex(D) data['cond_latex'] = web_latex(N) data['galois_images'] = [ trim_galois_image_code(s) for s in self.mod_p_images ] data['non_maximal_primes'] = self.non_maximal_primes data['galois_data'] = [{ 'p': p, 'image': im } for p, im in zip(data['non_maximal_primes'], data['galois_images'])] data['CMD'] = self.cm data['CM'] = "no" data['EndE'] = "\(\Z\)" if self.cm: data['cm_ramp'] = [ p for p in ZZ(self.cm).support() if not p in self.non_maximal_primes ] data['cm_nramp'] = len(data['cm_ramp']) if data['cm_nramp'] == 1: data['cm_ramp'] = data['cm_ramp'][0] else: data['cm_ramp'] = ", ".join([str(p) for p in data['cm_ramp']]) data['cm_sqf'] = ZZ(self.cm).squarefree_part() data['CM'] = "yes (\(D=%s\))" % data['CMD'] if data['CMD'] % 4 == 0: d4 = ZZ(data['CMD']) // 4 data['EndE'] = "\(\Z[\sqrt{%s}]\)" % d4 else: data['EndE'] = "\(\Z[(1+\sqrt{%s})/2]\)" % data['CMD'] data['ST'] = st_link_by_name(1, 2, 'N(U(1))') else: data['ST'] = st_link_by_name(1, 2, 'SU(2)') data['p_adic_primes'] = [ p for i, p in enumerate(prime_range(5, 100)) if (N * data['ap'][i]) % p != 0 ] cond, iso, num = split_lmfdb_label(self.lmfdb_label) self.one_deg = ZZ(self.class_deg).is_prime() isodegs = [str(d) for d in self.isogeny_degrees if d > 1] if len(isodegs) < 3: data['isogeny_degrees'] = " and ".join(isodegs) else: data['isogeny_degrees'] = " and ".join( [", ".join(isodegs[:-1]), isodegs[-1]]) if self.twoadic_gens: from sage.matrix.all import Matrix data['twoadic_gen_matrices'] = ','.join( [latex(Matrix(2, 2, M)) for M in self.twoadic_gens]) data[ 'twoadic_rouse_url'] = ROUSE_URL_PREFIX + self.twoadic_label + ".html" # Leading term of L-function & other BSD data self.make_bsd() # Optimality (the optimal curve in the class is the curve # whose Cremona label ends in '1' except for '990h' which was # labelled wrongly long ago): this is proved for N up to # OPTIMALITY_BOUND (and when there is only one curve in an # isogeny class, obviously) and expected for all N. # Column 'optimality' is 1 for certainly optimal curves, 0 for # certainly non-optimal curves, and is n>1 if the curve is one # of n in the isogeny class which may be optimal given current # knowledge. # Column "manin_constant' is the correct Manin constant # assuming that the optimal curve in the class is known, or # otherwise if it is the curve with (Cremona) number 1. # The code here allows us to update the display correctly by # changing one line in this file (defining OPTIMALITY_BOUND) # without changing the data. data['optimality_bound'] = OPTIMALITY_BOUND data[ 'manin_constant'] = self.manin_constant # (conditional on data['optimality_known']) if N < OPTIMALITY_BOUND: data['optimality_code'] = int( self.number == (3 if self.iso == '990h' else 1)) data['optimality_known'] = True data['manin_known'] = True if self.label_type == 'Cremona': data[ 'optimal_label'] = '990h3' if self.iso == '990h' else self.iso + '1' else: data[ 'optimal_label'] = '990.i3' if self.lmfdb_iso == '990.i' else self.lmfdb_iso + '1' else: data['optimality_code'] = self.optimality data['optimality_known'] = (self.optimality < 2) if self.optimality == 1: data['manin_known'] = True data[ 'optimal_label'] = self.label if self.label_type == 'Cremona' else self.lmfdb_label else: if self.number == 1: data['manin_known'] = False data[ 'optimal_label'] = self.label if self.label_type == 'Cremona' else self.lmfdb_label else: # find curve #1 in this class and its optimailty code: opt_curve = db.ec_curves.lucky( { 'iso': self.iso, 'number': 1 }, projection=['label', 'lmfdb_label', 'optimality']) data['manin_known'] = (opt_curve['optimality'] == 1) data['optimal_label'] = opt_curve[ 'label' if self.label_type == 'Cremona' else 'lmfdb_label'] data['p_adic_data_exists'] = False if data['optimality_code'] == 1: data['p_adic_data_exists'] = db.ec_padic.exists( {'lmfdb_iso': self.lmfdb_iso}) # Iwasawa data (where present) self.make_iwasawa() # Torsion growth data (where present) self.make_torsion_growth() data['newform'] = web_latex( PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True)) data['newform_label'] = self.newform_label = ".".join( [str(cond), str(2), 'a', iso]) self.newform_link = url_for("cmf.by_url_newform_label", level=cond, weight=2, char_orbit_label='a', hecke_orbit=iso) self.newform_exists_in_db = db.mf_newforms.label_exists( self.newform_label) self._code = None if self.label_type == 'Cremona': self.class_url = url_for(".by_ec_label", label=self.iso) self.class_name = self.iso else: self.class_url = url_for(".by_double_iso_label", conductor=N, iso_label=iso) self.class_name = self.lmfdb_iso data['class_name'] = self.class_name data['number'] = self.number self.friends = [('Isogeny class ' + self.class_name, self.class_url), ('Minimal quadratic twist %s %s' % (data['minq_info'], data['minq_label']), url_for(".by_ec_label", label=data['minq_label'])), ('All twists ', url_for(".rational_elliptic_curves", jinv=self.jinv))] lfun_url = url_for("l_functions.l_function_ec_page", conductor_label=N, isogeny_class_label=iso) origin_url = lfun_url.lstrip('/L/').rstrip('/') if db.lfunc_instances.exists({'url': origin_url}): self.friends += [('L-function', lfun_url)] else: self.friends += [('L-function not available', "")] if not self.cm: if N <= 300: self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', conductor=N, isogeny=iso))] if N <= 50: self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', conductor=N, isogeny=iso))] if self.newform_exists_in_db: self.friends += [('Modular form ' + self.newform_label, self.newform_link)] self.downloads = [('q-expansion to text', url_for(".download_EC_qexp", label=self.lmfdb_label, limit=1000)), ('All stored data to text', url_for(".download_EC_all", label=self.lmfdb_label)), ('Code to Magma', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='magma')), ('Code to SageMath', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='sage')), ('Code to GP', url_for(".ec_code_download", conductor=cond, iso=iso, number=num, label=self.lmfdb_label, download_type='gp'))] try: self.plot = encode_plot(self.E.plot()) except AttributeError: self.plot = encode_plot(EllipticCurve(data['ainvs']).plot()) self.plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format( self.plot) self.properties = [ ('Label', self.label if self.label_type == 'Cremona' else self.lmfdb_label), (None, self.plot_link), ('Conductor', '%s' % data['conductor']), ('Discriminant', '%s' % data['disc']), ('j-invariant', '%s' % data['j_inv_latex']), ('CM', '%s' % data['CM']), ('Rank', '%s' % self.mw['rank']), ('Torsion Structure', '\(%s\)' % self.mw['tor_struct']) ] if self.label_type == 'Cremona': self.title = "Elliptic Curve with Cremona label {} (LMFDB label {})".format( self.label, self.lmfdb_label) else: self.title = "Elliptic Curve with LMFDB label {} (Cremona label {})".format( self.lmfdb_label, self.label) self.bread = [('Elliptic Curves', url_for("ecnf.index")), ('$\Q$', url_for(".rational_elliptic_curves")), ('%s' % N, url_for(".by_conductor", conductor=N)), ('%s' % iso, url_for(".by_double_iso_label", conductor=N, iso_label=iso)), ('%s' % num, ' ')]
def render_isogeny_class(iso_class): info = {} credit = 'John Cremona' lmfdb_iso = iso_class # e.g. '11.a' N, iso, number = lmfdb_label_regex.match(lmfdb_iso).groups() CDB = lmfdb.base.getDBConnection().elliptic_curves.curves E1data = CDB.find_one({'lmfdb_label': lmfdb_iso + '1'}) if E1data is None: return elliptic_curve_jump_error(lmfdb_iso, {}) cremona_iso = E1data['iso'] ainvs = [int(a) for a in E1data['ainvs']] E1 = EllipticCurve(ainvs) ver = sage.version.version.split('.') # e.g. "6.1.beta2" ma = int(ver[0]) mi = int(ver[1]) if ma > 6 or ma == 6 and mi > 1: # Code for Sage 6.2 and later: isogeny_class = E1.isogeny_class() curves = isogeny_class.curves mat = isogeny_class.matrix() else: # Code for Sage 6.1 and before: curves, mat = E1.isogeny_class() size = len(curves) # Create a list of the curves in the class from the database, so # they are in the correct order! db_curves = [E1] optimal_flags = [False] * size degrees = [0] * size if 'degree' in E1data: degrees[0] = E1data['degree'] else: try: degrees[0] = E1.modular_degree() except RuntimeError: pass cremona_labels = [E1data['label']] + [0] * (size - 1) if E1data['number'] == 1: optimal_flags[0] = True for i in range(2, size + 1): Edata = CDB.find_one({'lmfdb_label': lmfdb_iso + str(i)}) E = EllipticCurve([int(a) for a in Edata['ainvs']]) cremona_labels[i - 1] = Edata['label'] if Edata['number'] == 1: optimal_flags[i - 1] = True if 'degree' in Edata: degrees[i - 1] = Edata['degree'] else: try: degrees[i - 1] = E.modular_degree() except RuntimeError: pass db_curves.append(E) if cremona_iso == '990h': # this isogeny class is labeled wrong in Cremona's tables optimal_flags = [False, False, True, False] # Now work out the permutation needed to match the two lists of curves: perm = [db_curves.index(E) for E in curves] # Apply the same permutation to the isogeny matrix: mat = [[mat[perm[i], perm[j]] for j in range(size)] for i in range(size)] info = {'label': lmfdb_iso} info['optimal_ainvs'] = ainvs info['rank'] = E1data['rank'] info['isogeny_matrix'] = latex(matrix(mat)) # info['f'] = ajax_more(E.q_eigenform, 10, 20, 50, 100, 250) info['f'] = web_latex(E.q_eigenform(10)) info['graph_img'] = url_for('.plot_iso_graph', label=lmfdb_iso) info['curves'] = [[ lmfdb_iso + str(i + 1), cremona_labels[i], str(list(c.ainvs())), c.torsion_order(), degrees[i], optimal_flags[i] ] for i, c in enumerate(db_curves)] friends = [] # friends.append(('Quadratic Twist', "/quadratic_twists/%s" % (lmfdb_iso))) friends.append(('L-function', url_for("l_functions.l_function_ec_page", label=lmfdb_iso))) friends.append(('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=lmfdb_iso))) friends.append(('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=lmfdb_iso))) # render_one_elliptic_modular_form(level,weight,character,label,**kwds) friends.append(('Modular form ' + lmfdb_iso.replace('.', '.2'), url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=0, label=iso))) info['friends'] = friends info['downloads'] = [('Download coeffients of q-expansion', url_for(".download_EC_qexp", label=lmfdb_iso, limit=100)), ('Download stored data for curves in this class', url_for(".download_EC_all", label=lmfdb_iso))] if lmfdb_iso == cremona_iso: t = "Elliptic Curve Isogeny Class %s" % lmfdb_iso else: t = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % ( lmfdb_iso, cremona_iso) bread = [('Elliptic Curves ', url_for(".rational_elliptic_curves")), ('isogeny class %s' % lmfdb_iso, ' ')] return render_template("iso_class.html", info=info, bread=bread, credit=credit, title=t, friends=info['friends'], downloads=info['downloads'])
def render_curve_webpage_by_label(label): C = lmfdb.base.getDBConnection() data = C.elliptic_curves.curves.find_one({'lmfdb_label': label}) if data is None: return elliptic_curve_jump_error(label, {}) info = {} ainvs = [int(a) for a in data['ainvs']] E = EllipticCurve(ainvs) cremona_label = data['label'] lmfdb_label = data['lmfdb_label'] N = ZZ(data['conductor']) cremona_iso_class = data['iso'] # eg '37a' lmfdb_iso_class = data['lmfdb_iso'] # eg '37.a' rank = data['rank'] try: j_invariant = QQ(str(data['jinv'])) except KeyError: j_invariant = E.j_invariant() if j_invariant == 0: j_inv_factored = latex(0) else: j_inv_factored = latex(j_invariant.factor()) jinv = unicode(str(j_invariant)) CMD = 0 CM = "no" EndE = "\(\Z\)" if E.has_cm(): CMD = E.cm_discriminant() CM = "yes (\(%s\))" % CMD if CMD % 4 == 0: d4 = ZZ(CMD) // 4 # r = d4.squarefree_part() # f = (d4//r).isqrt() # f="" if f==1 else str(f) # EndE = "\(\Z[%s\sqrt{%s}]\)"%(f,r) EndE = "\(\Z[\sqrt{%s}]\)" % (d4) else: EndE = "\(\Z[(1+\sqrt{%s})/2]\)" % CMD # plot=E.plot() discriminant = E.discriminant() xintpoints_projective = [ E.lift_x(x) for x in xintegral_point(data['x-coordinates_of_integral_points']) ] xintpoints = proj_to_aff(xintpoints_projective) if 'degree' in data: modular_degree = data['degree'] else: try: modular_degree = E.modular_degree() except RuntimeError: modular_degree = 0 # invalid, will be displayed nicely G = E.torsion_subgroup().gens() E_pari = E.pari_curve(prec=200) from sage.libs.pari.all import PariError try: minq = E.minimal_quadratic_twist()[0] except PariError: # this does occur with 164411a1 print "PariError computing minimal quadratic twist of elliptic curve %s" % lmfdb_label minq = E if E == minq: minq_label = lmfdb_label else: minq_ainvs = [str(c) for c in minq.ainvs()] minq_label = C.elliptic_curves.curves.find_one({'ainvs': minq_ainvs })['lmfdb_label'] # We do not just do the following, as Sage's installed database # might not have all the curves in the LMFDB database. # minq_label = E.minimal_quadratic_twist()[0].label() if 'gens' in data: generator = parse_gens(data['gens']) if len(G) == 0: tor_struct = '\mathrm{Trivial}' tor_group = '\mathrm{Trivial}' else: tor_group = ' \\times '.join(['\Z/{%s}\Z' % a.order() for a in G]) if 'torsion_structure' in data: info['tor_structure'] = ' \\times '.join( ['\Z/{%s}\Z' % int(a) for a in data['torsion_structure']]) else: info['tor_structure'] = tor_group def trim_galois_image_code(s): return s[2:] if s[1].isdigit() else s[1:] if 'galois_images' in data: galois_images = data['galois_images'] galois_images = [trim_galois_image_code(s) for s in galois_images] non_surjective_primes = data['non-surjective_primes'] galois_data = [{ 'p': p, 'image': im } for p, im in zip(non_surjective_primes, galois_images)] info.update(data) if rank >= 2: lder_tex = "L%s(E,1)" % ("^{(" + str(rank) + ")}") elif rank == 1: lder_tex = "L%s(E,1)" % ("'" * rank) else: assert rank == 0 lder_tex = "L(E,1)" info['Gamma0optimal'] = (cremona_label[-1] == '1' if cremona_iso_class != '990h' else cremona_label[-1] == '3') info['modular_degree'] = modular_degree p_adic_data_exists = (C.elliptic_curves.padic_db.find({ 'lmfdb_iso': lmfdb_iso_class }).count()) > 0 and info['Gamma0optimal'] # Local data local_data = [] for p in N.prime_factors(): local_info = E.local_data(p, algorithm="generic") local_data.append({ 'p': p, 'tamagawa_number': local_info.tamagawa_number(), 'kodaira_symbol': web_latex(local_info.kodaira_symbol()).replace('$', ''), 'reduction_type': local_info.bad_reduction_type() }) mod_form_iso = lmfdb_label_regex.match(lmfdb_iso_class).groups()[1] tamagawa_numbers = [ E.local_data(p, algorithm="generic").tamagawa_number() for p in N.prime_factors() ] # if we use E.tamagawa_numbers() it calls E.local_data(p) which # crashes on some curves e.g. 164411a1 info.update({ 'conductor': N, 'disc_factor': latex(discriminant.factor()), 'j_invar_factor': j_inv_factored, 'label': lmfdb_label, 'cremona_label': cremona_label, 'iso_class': lmfdb_iso_class, 'cremona_iso_class': cremona_iso_class, 'equation': web_latex(E), #'f': ajax_more(E.q_eigenform, 10, 20, 50, 100, 250), 'f': web_latex(E.q_eigenform(10)), 'generators': ', '.join(web_latex(g) for g in generator) if 'gens' in data else ' ', 'lder': lder_tex, 'p_adic_primes': [ p for p in sage.all.prime_range(5, 100) if E.is_ordinary(p) and not p.divides(N) ], 'p_adic_data_exists': p_adic_data_exists, 'ainvs': format_ainvs(data['ainvs']), 'CM': CM, 'CMD': CMD, 'EndE': EndE, 'tamagawa_numbers': r' \cdot '.join(str(sage.all.factor(c)) for c in tamagawa_numbers), 'local_data': local_data, 'cond_factor': latex(N.factor()), 'galois_data': galois_data, 'xintegral_points': ', '.join(web_latex(P) for P in xintpoints), 'tor_gens': ', '.join(web_latex(eval(g)) for g in data['torsion_generators']) if False else ', '.join( web_latex(P.element().xy()) for P in list(G)) }) info['friends'] = [('Isogeny class ' + lmfdb_iso_class, url_for(".by_ec_label", label=lmfdb_iso_class)), ('Minimal quadratic twist ' + minq_label, url_for(".by_ec_label", label=minq_label)), ('All twists ', url_for(".rational_elliptic_curves", jinv=jinv)), ('L-function', url_for("l_functions.l_function_ec_page", label=lmfdb_label)), ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=lmfdb_iso_class)), ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=lmfdb_iso_class))] info['friends'].append( ('Modular form ' + lmfdb_iso_class.replace('.', '.2'), url_for("emf.render_elliptic_modular_forms", level=int(N), weight=2, character=0, label=mod_form_iso))) info['downloads'] = [('Download coeffients of q-expansion', url_for(".download_EC_qexp", label=lmfdb_label, limit=100)), ('Download all stored data', url_for(".download_EC_all", label=lmfdb_label))] # info['learnmore'] = [('Elliptic Curves', url_for(".not_yet_implemented"))] # info['plot'] = image_src(plot) info['plot'] = url_for('.plot_ec', label=lmfdb_label) properties2 = [('Label', '%s' % lmfdb_label), (None, '<img src="%s" width="200" height="150"/>' % url_for('.plot_ec', label=lmfdb_label)), ('Conductor', '\(%s\)' % N), ('Discriminant', '\(%s\)' % discriminant), ('j-invariant', '%s' % web_latex(j_invariant)), ('CM', '%s' % CM), ('Rank', '\(%s\)' % rank), ('Torsion Structure', '\(%s\)' % tor_group)] # properties.extend([ "prop %s = %s<br/>" % (_,_*1923) for _ in range(12) ]) credit = 'John Cremona and Andrew Sutherland' if info['label'] == info['cremona_label']: t = "Elliptic Curve %s" % info['label'] else: t = "Elliptic Curve %s (Cremona label %s)" % (info['label'], info['cremona_label']) bread = [('Elliptic Curves ', url_for(".rational_elliptic_curves")), ('Elliptic curves %s' % lmfdb_label, ' ')] return render_template("curve.html", properties2=properties2, credit=credit, bread=bread, title=t, info=info, friends=info['friends'], downloads=info['downloads'])