def embedding(self, m, n=None, prec=6, format='embed'): """ Return the value of the ``m``th embedding on a specified input. Should only be used when all of the entries in this column are either real or imaginary. INPUT: - ``m`` -- an integer, specifying which embedding to use. - ``n`` -- a positive integer, specifying which a_n. If None, returns the image of the generator of the field (i.e. the root corresponding to this embedding). - ``prec`` -- the precision to display floating point values - ``format`` -- either ``embed`` or ``analytic_embed``. In the second case, divide by n^((k-1)/2). """ if n is None: x = self.cc_data[m].get('embedding_root_real', None) y = self.cc_data[m].get('embedding_root_imag', None) if x is None or y is None: return '?' # we should never see this if we have an exact qexp else: x, y = self.cc_data[m]['an'][n] if format == 'analytic_embed': x *= self.analytic_shift[n] y *= self.analytic_shift[n] if self.cc_data[m]['real']: return display_float(x, prec) else: return display_complex(x, y, prec)
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 L.fromDB: #getattr(L, 'fromDB', False): s_alg = s + L.analytic_normalization for x in L.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) logger.warning( "a value of an L-function has been computed on the fly") if sLatex_arithmetic: lfunction_value_tex_arithmetic = L.texname_arithmetic.replace( 's)', sLatex_arithmetic + ')') else: lfunction_value_tex_arithmetic = '' if sLatex_analytic: lfunction_value_tex_analytic = L.texname.replace( '(s', '(' + sLatex_analytic) else: lfunction_value_tex_analytic = '' if isinstance(val, string_types): Lval = val else: ccval = CDF(val) # We must test for NaN first, since it would show as zero otherwise # Try "RR(NaN) < float(1e-10)" in sage -- GT if ccval.real().is_NaN(): Lval = r"$\infty$" else: Lval = display_complex(ccval.real(), ccval.imag(), number_of_decimals) return [lfunction_value_tex_analytic, lfunction_value_tex_arithmetic, Lval]
def satake(self, m, p, i, prec=6, format='satake'): """ Return a Satake parameter. INPUT: - ``m`` -- an integer, specifying which embedding to use. - ``p`` -- a prime, specifying which a_p. - ``i`` -- either 0 or 1, indicating which root of the quadratic. - ``prec`` -- the precision to display floating point values - ``format`` -- either ``satake`` or ``satake_angle``. In the second case, give the argument of the Satake parameter """ if format == 'satake': alpha = self._get_alpha(m, p, i) return display_complex(alpha.real(), alpha.imag(), prec) else: return self.satake_angle(m, p, i, prec)
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 L.fromDB: #getattr(L, 'fromDB', False): s_alg = s + L.analytic_normalization for x in L.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) logger.warning("a value of an L-function has been computed on the fly") if sLatex_arithmetic: lfunction_value_tex_arithmetic = L.texname_arithmetic.replace('s)', sLatex_arithmetic + ')') else: lfunction_value_tex_arithmetic = '' if sLatex_analytic: lfunction_value_tex_analytic = L.texname.replace('(s', '(' + sLatex_analytic) else: lfunction_value_tex_analytic = '' if isinstance(val, basestring): Lval = val else: ccval = CDF(val) # We must test for NaN first, since it would show as zero otherwise # Try "RR(NaN) < float(1e-10)" in sage -- GT if ccval.real().is_NaN(): Lval = "$\\infty$" else: Lval = display_complex(ccval.real(), ccval.imag(), number_of_decimals) return [lfunction_value_tex_analytic, lfunction_value_tex_arithmetic, Lval]
def pretty_coeff(c, prec=9): ''' Format the complex coefficient `c` for display on the website. ''' if isinstance(c, complex): x = c.real y = c.imag else: x = real_part(c) y = imag_part(c) # the number of digits to display 'prec' digits after the . digits = lambda z: len(str(abs(z)).split('.')[0].lstrip('0')) + prec res = display_complex(x, y, digits=max(map(digits, [x, y]))) if res == '0': return ' 0' else: return res
def pretty_coeff(c, prec=9): ''' Format the complex coefficient `c` for display on the website. ''' if isinstance(c, complex): x = c.real y = c.imag else: x = real_part(c) y = imag_part(c) # the number of digits to display 'prec' digits after the . digits = lambda z: len(str(abs(z)).split('.')[0].lstrip('0')) + prec res = display_complex(x, y, digits = max(map(digits, [x, y]))) if res == '0': return ' 0' else: return res
def q_expansion_cc(self, prec_max): eigseq = self.cc_data[self.embedding_m]['an_normalized'] prec = min(max(eigseq.keys()) + 1, prec_max) if prec == 0: return 'O(1)' s = '\(q\)' for j in range(2, prec): term = eigseq[j] latexterm = display_complex(term[0]*self.analytic_shift[j], term[1]*self.analytic_shift[j], 6, method = "round", parenthesis = True, try_halfinteger=False) if latexterm != '0': if latexterm == '1': latexterm = '' elif latexterm == '-1': latexterm = '-' 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 lfuncFEtex(L, fmt): """ Returns the LaTex for displaying the Functional equation of the L-function L. fmt could be any of the values: "analytic", "selberg" """ if fmt == "arithmetic": mu_list = [mu - L.motivic_weight/2 for mu in L.mu_fe] nu_list = [nu - L.motivic_weight/2 for nu in L.nu_fe] mu_list.sort() nu_list.sort() texname = L.texname_arithmetic try: tex_name_s = L.texnamecompleteds_arithmetic tex_name_1ms = L.texnamecompleted1ms_arithmetic except AttributeError: tex_name_s = L.texnamecompleteds tex_name_1ms = L.texnamecompleted1ms else: mu_list = L.mu_fe[:] nu_list = L.nu_fe[:] texname = L.texname tex_name_s = L.texnamecompleteds tex_name_1ms = L.texnamecompleted1ms ans = "" if fmt == "arithmetic" or fmt == "analytic": ans = "\\begin{align}\n" + tex_name_s + "=\\mathstrut &" if L.level > 1: if L.level >= 10**8 and not is_prime(int(L.level)): ans += r"\left(%s\right)^{s/2}" % latex(L.level_factored) else: ans += latex(L.level) + "^{s/2}" ans += " \\, " def munu_str(factors_list, field): assert field in ['\R','\C'] # set up to accommodate multiplicity of Gamma factors old = "" res = "" curr_exp = 0 for elt in factors_list: if elt == old: curr_exp += 1 else: old = elt if curr_exp > 1: res += "^{" + str(curr_exp) + "}" if curr_exp > 0: res += " \\, " curr_exp = 1 res += "\Gamma_{" + field + "}(s" + seriescoeff(elt, 0, "signed", "", 3) + ")" if curr_exp > 1: res += "^{" + str(curr_exp) + "}" if res != "": res += " \\, " return res ans += munu_str(mu_list, '\R') ans += munu_str(nu_list, '\C') ans += texname + "\\cr\n" ans += "=\\mathstrut & " if L.sign == 0: ans += "\epsilon \cdot " else: ans += seriescoeff(L.sign, 0, "factor", "", 3) + "\\," ans += tex_name_1ms if L.sign == 0 and L.degree == 1: ans += "\quad (\\text{with }\epsilon \\text{ not computed})" if L.sign == 0 and L.degree > 1: ans += "\quad (\\text{with }\epsilon \\text{ unknown})" ans += "\n\\end{align}\n" elif fmt == "selberg": ans += "(" + str(int(L.degree)) + ",\\ " if L.level >= 10**8 and not is_prime(int(L.level)): ans += latex(L.level_factored) else: ans += str(int(L.level)) ans += ",\\ " ans += "(" # this is mostly a hack for GL2 Maass forms def real_digits(x): return len(str(x).replace('.','').lstrip('-').lstrip('0')) def mu_fe_prec(x): if L._Ltype == 'maass': return real_digits(imag_part(x)) else: return 3 if L.mu_fe != []: mus = [ display_complex(CDF(mu).real(), CDF(mu).imag(), mu_fe_prec(mu), method="round" ) for mu in L.mu_fe ] if len(mus) >= 6 and mus == [mus[0]]*len(mus): ans += '[%s]^{%d}' % (mus[0], len(mus)) else: ans += ", ".join(mus) else: ans += "\\ " ans += ":" if L.nu_fe != []: if len(L.nu_fe) >= 6 and L.nu_fe == [L.nu_fe[0]]*len(L.nu_fe): ans += '[%s]^{%d}' % (L.nu_fe[0], len(L.nu_fe)) else: ans += ", ".join(map(str, L.nu_fe)) else: ans += "\\ " ans += "),\\ " ans += seriescoeff(L.sign, 0, "literal", "", 3) ans += ")" return(ans)
def seriescoeff(coeff, index, seriescoefftype, seriestype, digits): # seriescoefftype can be: series, serieshtml, signed, literal, factor try: if isinstance(coeff,str) or isinstance(coeff,unicode): if coeff == "I": rp = 0 ip = 1 elif coeff == "-I": rp = 0 ip = -1 else: coeff = string2number(coeff) if type(coeff) == complex: rp = coeff.real ip = coeff.imag else: rp = real_part(coeff) ip = imag_part(coeff) except TypeError: # mostly a hack for Dirichlet L-functions if seriescoefftype == "serieshtml": return " +" + coeff + "·" + seriesvar(index, seriestype) else: return coeff ans = "" if seriescoefftype in ["series", "serieshtml", "signed", "factor"]: parenthesis = True else: parenthesis = False coeff_display = display_complex(rp, ip, digits, method="truncate", parenthesis=parenthesis) # deal with the zero case if coeff_display == "0": if seriescoefftype=="literal": return "0" else: return "" if seriescoefftype=="literal": return coeff_display if seriescoefftype == "factor": if coeff_display == "1": return "" elif coeff_display == "-1": return "-" #add signs and fix spacing if seriescoefftype in ["series", "serieshtml"]: if coeff_display == "1": coeff_display = " + " elif coeff_display == "-1": coeff_display = " - " # purely real or complex number that starts with - elif coeff_display[0] == '-': # add spacings around the minus coeff_display = coeff_display.replace('-',' - ') else: ans += " + " elif seriescoefftype == 'signed' and coeff_display[0] != '-': # add the plus without the spaces ans += "+" ans += coeff_display if seriescoefftype == "serieshtml": ans = ans.replace('i',"<em>i</em>").replace('-',"−") if coeff_display[-1] not in [')', ' ']: ans += "·" if seriescoefftype in ["series", "serieshtml", "signed"]: ans += seriesvar(index, seriestype) return ans
def seriescoeff(coeff, index, seriescoefftype, seriestype, digits): # seriescoefftype can be: series, serieshtml, signed, literal, factor try: if isinstance(coeff, string_types): if coeff == "I": rp = 0 ip = 1 coeff = CDF(I) elif coeff == "-I": rp = 0 ip = -1 coeff = CDF(-I) else: coeff = string2number(coeff) if type(coeff) == complex: rp = coeff.real ip = coeff.imag else: rp = real_part(coeff) ip = imag_part(coeff) except TypeError: # mostly a hack for Dirichlet L-functions if seriescoefftype == "serieshtml": return " +" + coeff + "·" + seriesvar(index, seriestype) else: return coeff ans = "" if seriescoefftype in ["series", "serieshtml", "signed", "factor"]: parenthesis = True else: parenthesis = False coeff_display = display_complex(rp, ip, digits, method="truncate", parenthesis=parenthesis) # deal with the zero case if coeff_display == "0": if seriescoefftype=="literal": return "0" else: return "" if seriescoefftype=="literal": return coeff_display if seriescoefftype == "factor": if coeff_display == "1": return "" elif coeff_display == "-1": return "-" #add signs and fix spacing if seriescoefftype in ["series", "serieshtml"]: if coeff_display == "1": coeff_display = " + " elif coeff_display == "-1": coeff_display = " - " # purely real or complex number that starts with - elif coeff_display[0] == '-': # add spacings around the minus coeff_display = coeff_display.replace('-',' - ') else: ans += " + " elif seriescoefftype == 'signed' and coeff_display[0] != '-': # add the plus without the spaces ans += "+" ans += coeff_display if seriescoefftype == "serieshtml": ans = ans.replace('i',"<em>i</em>").replace('-',"−") if coeff_display[-1] not in [')', ' ']: ans += "·" if seriescoefftype in ["series", "serieshtml", "signed"]: ans += seriesvar(index, seriestype) return ans
def lfuncFEtex(L, fmt): """ Returns the LaTex for displaying the Functional equation of the L-function L. fmt could be any of the values: "analytic", "selberg" """ if fmt == "arithmetic": mu_list = [mu - L.motivic_weight/2 for mu in L.mu_fe] nu_list = [nu - L.motivic_weight/2 for nu in L.nu_fe] mu_list.sort() nu_list.sort() texname = L.texname_arithmetic try: tex_name_s = L.texnamecompleteds_arithmetic tex_name_1ms = L.texnamecompleted1ms_arithmetic except AttributeError: tex_name_s = L.texnamecompleteds tex_name_1ms = L.texnamecompleted1ms else: mu_list = L.mu_fe[:] nu_list = L.nu_fe[:] texname = L.texname tex_name_s = L.texnamecompleteds tex_name_1ms = L.texnamecompleted1ms ans = "" if fmt == "arithmetic" or fmt == "analytic": ans = r"\begin{aligned}" + "\n" + tex_name_s + r"=\mathstrut &" if L.level > 1: if L.level >= 10**8 and not is_prime(int(L.level)): ans += r"\left(%s\right)^{s/2}" % latex(L.level_factored) else: ans += latex(L.level) + "^{s/2}" ans += r" \, " def munu_str(factors_list, field): assert field in [r'\R',r'\C'] # set up to accommodate multiplicity of Gamma factors old = "" res = "" curr_exp = 0 for elt in factors_list: if elt == old: curr_exp += 1 else: old = elt if curr_exp > 1: res += "^{" + str(curr_exp) + "}" if curr_exp > 0: res += r" \, " curr_exp = 1 res += r"\Gamma_{" + field + "}(s" + seriescoeff(elt, 0, "signed", "", 3) + ")" if curr_exp > 1: res += "^{" + str(curr_exp) + "}" if res != "": res += r" \, " return res ans += munu_str(mu_list, r'\R') ans += munu_str(nu_list, r'\C') ans += texname + r"\cr" + "\n" ans += r"=\mathstrut & " if L.sign == 0: ans += r"\epsilon \cdot " else: ans += seriescoeff(L.sign, 0, "factor", "", 3) + r"\," ans += tex_name_1ms if L.sign == 0 and L.degree == 1: ans += r"\quad (\text{with }\epsilon \text{ not computed})" if L.sign == 0 and L.degree > 1: ans += r"\quad (\text{with }\epsilon \text{ unknown})" ans += "\n" + r"\end{aligned}\n" elif fmt == "selberg": ans += "(" + str(int(L.degree)) + r",\ " if L.level >= 10**8 and not is_prime(int(L.level)): ans += latex(L.level_factored) else: ans += str(int(L.level)) ans += r",\ " ans += "(" # this is mostly a hack for GL2 Maass forms def real_digits(x): return len(str(x).replace('.','').lstrip('-').lstrip('0')) def mu_fe_prec(x): if L._Ltype == 'maass': return real_digits(imag_part(x)) else: return 3 if L.mu_fe != []: mus = [ display_complex(CDF(mu).real(), CDF(mu).imag(), mu_fe_prec(mu), method="round" ) for mu in L.mu_fe ] if len(mus) >= 6 and mus == [mus[0]]*len(mus): ans += '[%s]^{%d}' % (mus[0], len(mus)) else: ans += ", ".join(mus) else: ans += r"\ " ans += ":" if L.nu_fe != []: if len(L.nu_fe) >= 6 and L.nu_fe == [L.nu_fe[0]]*len(L.nu_fe): ans += '[%s]^{%d}' % (L.nu_fe[0], len(L.nu_fe)) else: ans += ", ".join(map(str, L.nu_fe)) else: ans += r"\ " ans += r"),\ " ans += seriescoeff(L.sign, 0, "literal", "", 3) ans += ")" return(ans)
def setup_cc_data(self, info): """ INPUT: - ``info`` -- a dictionary with keys - ``m`` -- a string describing the embedding indexes desired - ``n`` -- a string describing the a_n desired - ``CC_m`` -- a list of embedding indexes - ``CC_n`` -- a list of desired a_n - ``format`` -- one of 'embed', 'analytic_embed', 'satake', or 'satake_angle' """ an_formats = ['embed','analytic_embed', None] angles_formats = ['satake','satake_angle', None] analytic_shift_formats = ['embed', None] cc_proj = ['conrey_index','embedding_index','embedding_m','embedding_root_real','embedding_root_imag'] format = info.get('format') query = {'hecke_orbit_code':self.hecke_orbit_code} # deal with m if self.embedding_label is None: m = info.get('m','1-%s'%(min(self.dim,20))) if '.' in m: m = re.sub(r'\d+\.\d+', self.embedding_from_embedding_label, m) CC_m = info['CC_m'] if 'CC_m' in info else integer_options(m) CC_m = sorted(set(CC_m)) # if it is a range if len(CC_m) - 1 == CC_m[-1] - CC_m[0]: query['embedding_m'] = {'$gte':CC_m[0], '$lte':CC_m[-1]} else: query['embedding_m'] = {'$in': CC_m} self.embedding_m = None else: self.embedding_m = int(info['CC_m'][0]) cc_proj.extend(['dual_conrey_index', 'dual_embedding_index']) query = {'label' : self.label + '.' + self.embedding_label} if format is None and 'CC_n' not in info: # for download CC_n = (1, self.an_cc_bound) else: n = info.get('n','1-10') CC_n = info['CC_n'] if 'CC_n' in info else integer_options(n) # convert CC_n to an interval in [1,an_bound] CC_n = ( max(1, min(CC_n)), min(self.an_cc_bound, max(CC_n)) ) an_keys = (CC_n[0]-1, CC_n[1]) # extra 5 primes in case we hit too many bad primes angles_keys = ( bisect.bisect_left(primes_for_angles, CC_n[0]), min(bisect.bisect_right(primes_for_angles, CC_n[1]) + 5, self.primes_cc_bound) ) an_projection = 'an_normalized[%d:%d]' % an_keys angles_projection = 'angles[%d:%d]' % angles_keys if format in an_formats: cc_proj.append(an_projection) if format in angles_formats: cc_proj.append(angles_projection) cc_data= list(db.mf_hecke_cc.search(query, projection = cc_proj)) if not cc_data: self.has_complex_qexp = False else: self.has_complex_qexp = True self.cc_data = {} for embedded_mf in cc_data: if format in an_formats: an_normalized = embedded_mf.pop(an_projection) # we don't store a_0, thus the +1 embedded_mf['an_normalized'] = {i: [float(x), float(y)] for i, (x, y) in enumerate(an_normalized, an_keys[0] + 1)} if format in angles_formats: embedded_mf['angles'] = {primes_for_angles[i]: theta for i, theta in enumerate(embedded_mf.pop(angles_projection), angles_keys[0])} self.cc_data[embedded_mf.pop('embedding_m')] = embedded_mf if format in analytic_shift_formats: self.analytic_shift = {i : RR(i)**((ZZ(self.weight)-1)/2) for i in self.cc_data.values()[0]['an_normalized'].keys()} if format in angles_formats: self.character_values = defaultdict(list) G = DirichletGroup_conrey(self.level) chars = [DirichletCharacter_conrey(G, char) for char in self.conrey_indexes] for p in self.cc_data.values()[0]['angles'].keys(): if p.divides(self.level): self.character_values[p] = None continue for chi in chars: c = chi.logvalue(p) * self.char_order angle = float(c / self.char_order) value = CDF(0,2*CDF.pi()*angle).exp() self.character_values[p].append((angle, value)) if self.embedding_m is not None: m = self.embedding_m dci = self.cc_data[m].get('dual_conrey_index') dei = self.cc_data[m].get('dual_embedding_index') self.dual_label = "%s.%s" % (dci, dei) x = self.cc_data[m].get('embedding_root_real') y = self.cc_data[m].get('embedding_root_imag') if x is None or y is None: self.embedding_root = None else: self.embedding_root = display_complex(x, y, 6, method='round', try_halfinteger=False)