def as_polynomial_in_E4_and_E6(self,insert_in_db=True): r""" If self is on the full modular group writes self as a polynomial in E_4 and E_6. OUTPUT: -''X'' -- vector (x_1,...,x_n) with f = Sum_{i=0}^{k/6} x_(n-i) E_6^i * E_4^{k/4-i} i.e. x_i is the coefficient of E_6^(k/6-i)* """ if(self.level() != 1): raise NotImplementedError("Only implemented for SL(2,Z). Need more generators in general.") if(self._as_polynomial_in_E4_and_E6 is not None and self._as_polynomial_in_E4_and_E6 != ''): return self._as_polynomial_in_E4_and_E6 d = self._parent.dimension_modular_forms() # dimension of space of modular forms k = self.weight() K = self.base_ring() l = list() # for n in range(d+1): # l.append(self._f.q_expansion(d+2)[n]) # v=vector(l) # (self._f.coefficients(d+1)) v = vector(self.coefficients(range(d),insert_in_db=insert_in_db)) d = dimension_modular_forms(1, k) lv = len(v) if(lv < d): raise ArithmeticError("not enough Fourier coeffs") e4 = EisensteinForms(1, 4).basis()[0].q_expansion(lv + 2) e6 = EisensteinForms(1, 6).basis()[0].q_expansion(lv + 2) m = Matrix(K, lv, d) lima = floor(k / 6) # lima=k\6; if((lima - (k / 2)) % 2 == 1): lima = lima - 1 poldeg = lima col = 0 monomials = dict() while(lima >= 0): deg6 = ZZ(lima) deg4 = (ZZ((ZZ(k / 2) - 3 * lima) / 2)) e6p = (e6 ** deg6) e4p = (e4 ** deg4) monomials[col] = [deg4, deg6] eis = e6p * e4p for i in range(1, lv + 1): m[i - 1, col] = eis.coefficients()[i - 1] lima = lima - 2 col = col + 1 if (col != d): raise ArithmeticError("bug dimension") # return [m,v] if self._verbose > 0: wmf_logger.debug("m={0}".format(m, type(m))) wmf_logger.debug("v={0}".format(v, type(v))) try: X = m.solve_right(v) except: return "" self._as_polynomial_in_E4_and_E6 = [poldeg, monomials, X] return [poldeg, monomials, X]
def __init__(self, N=1, k=2, chi=1, label='', prec=10, bitprec=53, display_bprec=26,parent=None, data=None,compute=False, verbose=-1,get_from_db=True): r""" Init self as form with given label in S_k(N,chi) """ super(WebNewForm_computing_class,self).__init__(N,k,chi,label,prec,bitprec,display_bprec,get_from_db=False) print "d=",self.__dict__ wmf_logger.debug("WebNewForm with N,k,chi,label={0}".format( (N,k,chi,label))) self._as_factor = None self._prec_needed_for_lfunctions = None self.set_parent() self.set_newform_number() self.compute_additional_properties()
def _get_newform(N, k, chi, fi=None): r""" Get an element of the space of newforms, incuding some error handling. INPUT: - ''k'' -- positive integer : the weight - ''N'' -- positive integer (default 1) : level - ''chi'' -- non-neg. integer (default 0) use character nr. chi - ''fi'' -- integer (default 0) We want to use the element nr. fi f=Newforms(N,k)[fi]. fi=-1 returns the whole list - ''prec'' -- integer (the number of coefficients to get) OUTPUT: -''t'' -- bool, returning True if we succesfully created the space and picked the wanted f -''f'' -- equals f if t=True, otherwise contains an error message. EXAMPLES:: sage: _get_newform(16,10,1) (False, 'Could not construct space $S^{new}_{16}(10)$') sage: _get_newform(10,16,1) (True, q - 68*q^3 + 1510*q^5 + O(q^6)) sage: _get_newform(10,16,3) (True, q + 156*q^3 + 870*q^5 + O(q^6)) sage: _get_newform(10,16,4) (False, '') """ t = False try: if(chi == 0): wmf_logger.debug("EXPLICITLY CALLING NEWFORMS!") S = Newforms(N, k, names='x') else: S = Newforms(DirichletGroup(N)[chi], k, names='x') if(fi >= 0 and fi < len(S)): f = S[fi] t = True elif(fi == -1 or fi is None): t = True return (t, S) else: f = "" except RuntimeError: if(chi == 0): f = "Could not construct space $S^{new}_{%s}(%s)$" % (k, N) else: f = "Could not construct space $S^{new}_{%s}(%s,\chi_{%s})$" % (k, N, chi) return (t, f)
def WebNewForm_computing(N=1, k=2, chi=1, label='', prec=10, bitprec=53, display_bprec=26, parent=None, data=None, compute=False, verbose=-1,get_from_db=True): r""" Constructor for WebNewForms with added 'nicer' error message. """ ## First check if chi == 1: if k % 2 == 1: wmf_logger.debug("Only zero function here with N,k,chi,label={0}.".format( (N,k,chi,label))) return 0 if data is None: data = {} wmf_logger.debug("incoming data in construction : {0}".format(data.get('N'),data.get('k'),data.get('chi'))) try: F = WebNewForm_computing_class(N=N, k=k, chi=chi, label=label, prec=prec, bitprec = bitprec, display_bprec=display_bprec, parent = parent, data = data, compute = compute, verbose = verbose,get_from_db = get_from_db) except ArithmeticError as e:#Exception as e: wmf_logger.critical("Could not construct WebNewForm with N,k,chi,label={0}. Error: {1}".format( (N,k,chi,label),e)) raise IndexError,"We are very sorry. The sought function could not be found in the database." return F
def get_modular_symbols(self): r""" Get Modular Symbols from database they exist. """ if not self._modular_symbols is None: return modular_symbols = connect_to_modularforms_db('Modular_symbols.files') key = {'k': int(self._k), 'N': int(self._N), 'cchi': int(self._chi)} modular_symbols_from_db = modular_symbols.find_one(key) wmf_logger.debug("found ms={0}".format(modular_symbols_from_db)) if modular_symbols_from_db is None: ms = None else: id = modular_symbols_from_db['_id'] fs = get_files_from_gridfs('Modular_symbols') ms = loads(fs.get(id).read()) self._id = id self._modular_symbols = ms
def twist_by(self, x): r""" twist self by a primitive Dirichlet character x """ # xx = x.primitive() assert x.is_primitive() q = x.conductor() # what level will the twist live on? level = self.level() qq = self.character().conductor() new_level = lcm(self.level(), lcm(q * q, q * qq)) D = DirichletGroup(new_level) new_x = D(self.character()) * D(x) * D(x) ix = D.list().index(new_x) # the correct space NS = WebModFormSpace(self._k, new_level, ix, self._prec) # have to find whih form wee want NS.galois_decomposition() M = NS.sturm_bound() + len(divisors(new_level)) C = self.coefficients(range(M)) for label in NS._galois_orbits_labels: wmf_logger.debug("label={0}".format(label)) FT = NS.f(label) CT = FT.f.coefficients(M) wmf_logger.debug("{0}".format(CT)) K = FT.f.hecke_eigenvalue_field() try: for n in range(2, M): if(new_level % n + 1 == 0): continue wmf_logger.debug("n={0}".format(n)) ct = CT[n] c = K(x(n)) * K(C[n]) wmf_logger.debug("{0} {1}".format(ct, c)) if ct != c: raise StopIteration() except StopIteration: pass else: wmf_logger.debug("Twist of f={0}".format(FT)) return FT
def __init__(self, N=1, k=2, chi=1, cuspidal=1, prec=10, bitprec=53, data=None, verbose=0,get_from_db=True): r""" Init self. INPUT: - 'k' -- weight - 'N' -- level - 'chi' -- character - 'cuspidal' -- 1 if space of cuspforms, 0 if all modforms """ wmf_logger.debug("WebModFormSpace with k,N,chi={0}".format( (k,N,chi))) super(WebModFormSpace_computing_class,self).__init__(N,k,chi,cuspidal,prec,bitprec,data, verbose,get_from_db=False) ## In this subclass we add properties which are not ## supposed to be used on the web or stored in the database self._dimension = None self._dimension_oldspace = None self._newforms = None self._modular_symbols = None self.compute_additional_properties() self.insert_into_db()
def insert_into_db(self): r""" Insert a dictionary of data for self into the database collection WebNewforms.files """ wmf_logger.debug("inserting self into db! name={0}".format(self._name)) C = connect_to_modularforms_db('WebNewforms.files') fs = get_files_from_gridfs('WebNewforms') s = {'name':self._name,'version':float(self._version)} rec = C.find_one(s) if rec: id = rec.get('_id') else: id = None if id<>None: wmf_logger.debug("Removing self from db with id={0}".format(id)) fs.delete(id) fname = "webnewform-{0:0>5}-{1:0>3}-{2:0>3}-{3}".format(self._N,self._k,self._chi,self._label) d = self.to_dict() d.pop('_ap',None) d.pop('_character',None) d.pop('_as_factor',None) id = fs.put(dumps(d),filename=fname,N=int(self._N),k=int(self._k),chi=int(self._chi),label=self._label,name=self._name,version=float(self._version)) wmf_logger.debug("inserted :{0}".format(id))
def _get_aps(self, prec=-1): r""" Get aps from database if they exist. """ ap_files = connect_to_modularforms_db('ap.files') key = {'k': int(self._k), 'N': int(self._N), 'cchi': int(self._chi)} key['prec'] = {"$gt": int(prec - 1)} ap_from_db = ap_files.find(key).sort("prec") wmf_logger.debug("finds={0}".format(ap_from_db)) wmf_logger.debug("finds.count()={0}".format(ap_from_db.count())) fs = get_files_from_gridfs('ap') aplist = {} for i in range(len(self.labels())): aplist[self.labels()[i]]={} for rec in ap_from_db: wmf_logger.debug("rec={0}".format(rec)) ni = rec.get('newform') if ni is None: for a in self.labels(): aplist[a][prec]=None return aplist a = self.labels()[ni] cur_prec = rec['prec'] if aplist.get(a,{}).get(cur_prec,None) is None: aplist[a][prec]=loads(fs.get(rec['_id']).read()) if cur_prec > prec and prec>0: # We are happy with these coefficients. return aplist return aplist
def get_newform_factors(self): r""" Get New form factors from database they exist. """ if not self._newforms is None and self._newforms == []: return factors = connect_to_modularforms_db('Newform_factors.files') key = {'k': int(self._k), 'N': int(self._N), 'cchi': int(self._chi),} factors_from_db = factors.find(key).sort('newform',int(1)) wmf_logger.debug("found factors={0}".format(factors_from_db)) self._newforms = {} if factors_from_db.count()==0: raise ValueError,"Space is not in database!" else: facts = [] self._labels = [] fs = get_files_from_gridfs('Newform_factors') for rec in factors_from_db: factor = loads(fs.get(rec['_id']).read()) label = orbit_label(rec['newform']) self._galois_orbits_labels.append(label) self._newforms[label] = factor
def break_line_at(s, brpt=20): r""" Breaks a line containing math 'smartly' at brpt characters. With smartly we mean that we break at + or - but keep brackets together """ sl = list() stmp = '' left_par = 0 #wmf_logger.debug('Break at line, Input ={0}'.format(s)) for i in range(len(s)): if s[i] == '(': # go to the matching case left_par = 1 elif s[i] == ')' and left_par == 1: left_par = 0 if left_par == 0 and (s[i] == '+' or s[i] == '-'): sl.append(stmp) stmp = '' stmp = stmp + s[i] if i == len(s) - 1: sl.append(stmp) wmf_logger.debug('sl={0}'.format(sl)) # sl now contains a split e.g. into terms in the q-expansion # we now have to join as many as fits on the line res = list() stmp = '' for j in range(len(sl)): l = len_as_printed(stmp) + len_as_printed(sl[j]) #wmf_logger.debug("l={0}".format(l)) if l < brpt: stmp = join([stmp, sl[j]]) else: res.append(stmp) stmp = sl[j] if j == len(sl) - 1: res.append(stmp) return res
def set_q_expansion_embeddings(self, prec=10, bitprec=53,format='numeric',display_bprec=26,insert_in_db=True): r""" Compute all embeddings of self into C which are in the same space as self. Return 0 if we didn't compute anything new, otherwise return 1. """ wmf_logger.debug("computing embeddings of q-expansions : has {0} embedded coeffs. Want : {1} with bitprec={2}".format(len(self._embeddings),prec,bitprec)) if display_bprec > bitprec: display_bprec = bitprec ## First check if we have sufficient data if self._embeddings['prec'] >= prec or self._embeddings['bitprec'] >= bitprec: return 0 ## We should already have sufficient data. ## Else we compute new embeddings. CF = ComplexField(bitprec) # First wee if we need higher precision, in which case we reset all coefficients: if self._embeddings['bitprec'] < bitprec: self._embeddings['values']=[] self._embeddings['latex']=[] self._embeddings['prec']=0 # See if we have need of more coefficients nstart = len(self._embeddings) wmf_logger.debug("Should have {0} embeddings".format(self._embeddings['prec'])) wmf_logger.debug("Computing new stuff !") for n in range(self._embeddings['prec'],prec): try: cn = self.coefficient(n) except IndexError: break if hasattr(cn, 'complex_embeddings'): cn_emb = cn.complex_embeddings(bitprec) else: cn_emb = [ CF(cn) for i in range(deg) ] self._embeddings['values'].append(cn_emb) self._embeddings['prec'] = len(self._embeddings['values']) # See if we also need to recompute the latex strings if display_bprec > self._embeddings['bitprec']: self._embeddings['latex'] = [] ## Have to redo these numc = len(self._embeddings['latex']) for n in range(numc,prec): cn_emb = [] for x in self._embeddings['values'][n]: t = my_complex_latex(x,display_bprec) cn_emb_latex.append(t) self._embeddidngs['latex'].append(cn_emb) wmf_logger.debug("has embeddings_latex:{0}".format(nstart)) return 1
def galois_decomposition(self): r""" We compose the new subspace into galois orbits of new cusp forms. """ from sage.monoids.all import AlphabeticStrings if(len(self._galois_decomposition) != 0): return self._galois_decomposition if '_HeckeModule_free_module__decomposition' in self._newspace.__dict__: L = self._newspace.decomposition() else: decomp = self.newform_factors() if len(decomp)>0: L = filter(lambda x: x.is_new() and x.is_cuspidal(), decomp) wmf_logger.debug("found L:{0}".format(L)) elif self._computation_too_hard(): L = [] raise IndexError,"No decomposition was found in the database!" wmf_logger.debug("no decomp in database!") else: # compute L = self._newspace.decomposition() wmf_logger.debug("newspace :".format(self._newspace)) wmf_logger.debug("computed L:".format(L)) self._galois_decomposition = L # we also label the compnents x = AlphabeticStrings().gens() for j in range(len(L)): if(j < 26): label = str(x[j]).lower() else: j1 = j % 26 j2 = floor(QQ(j) / QQ(26)) label = str(x[j1]).lower() label = label + str(j2) if label not in self._galois_orbits_labels: self._galois_orbits_labels.append(label) return L
def get_from_db(self): r""" Fetch dictionary data from the database. """ db = connect_to_modularforms_db('WebModformspace.files') s = {'name':self._name,'version':emf_version} wmf_logger.debug("Looking in DB for rec={0}".format(s)) f = db.find_one(s) wmf_logger.debug("Found rec={0}".format(f)) if f<>None: id = f.get('_id') fs = get_files_from_gridfs('WebModformspace') f = fs.get(id) wmf_logger.debug("Getting rec={0}".format(f)) d = loads(f.read()) return d return {}
def insert_into_db(self): r""" Insert a dictionary of data for self into the collection WebModularforms.files """ wmf_logger.debug("inserting self into db! name={0}".format(self._name)) db = connect_to_modularforms_db('WebModformspace.files') fs = get_files_from_gridfs('WebModformspace') s = {'name':self._name,'version':emf_version} rec = db.find_one(s) if rec: id = rec.get('_id') else: id = None if id<>None: wmf_logger.debug("Removing self from db with id={0}".format(id)) fs.delete(id) fname = "webmodformspace-{0:0>5}-{1:0>3}-{2:0>3}".format(self._N,self._k,self._chi) d = self.to_dict() d.pop('_ap',None) # Since the ap's are already in the database we don't need them here id = fs.put(dumps(d),filename=fname,N=int(self._N),k=int(self._k),chi=int(self._chi),name=self._name,version=emf_version) wmf_logger.debug("inserted :{0}".format(id))
def set_oldspace_decomposition(self): r""" Get decomposition of the oldspace in self into submodules. """ if not (self._oldspace_decomposition is None or self._oldspace_decomposition == []): return N = self._N k = self._k M = self._modular_symbols.cuspidal_submodule() L = list() L = [] check_dim = self.dimension_newspace() if(check_dim == self.dimension()): return L if(self._verbose > 1): wmf_logger.debug("check_dim:={0}".format(check_dim)) for d in divisors(N): if(d == 1): continue q = N.divide_knowing_divisible_by(d) if(self._verbose > 1): wmf_logger.debug("d={0}".format(d)) # since there is a bug in the current version of sage # we have to try this... try: O = M.old_submodule(d) except AttributeError: O = M.zero_submodule() Od = O.dimension() if(self._verbose > 1): wmf_logger.debug("O={0}".format(O)) wmf_logger.debug("Od={0}".format(Od)) if(d == N and k == 2 or Od == 0): continue if self.character().is_trivial(): # S=ModularSymbols(ZZ(N/d),k,sign=1).cuspidal_submodule().new_submodule(); Sd=S.dimension() wmf_logger.debug("q={0},{1}".format(q, type(q))) wmf_logger.debug("k={0},{1}".format(k, type(k))) Sd = dimension_new_cusp_forms(q, k) if(self._verbose > 1): wmf_logger.debug("Sd={0}".format(Sd)) if Sd > 0: mult = len(divisors(ZZ(d))) check_dim = check_dim + mult * Sd L.append((q, 0, mult, Sd)) else: xd = self.character().decomposition() for xx in xd: if xx.modulus() == q: Sd = dimension_new_cusp_forms(xx, k) if Sd > 0: # identify this character for internal storage... should be optimized x_k = self.conrey_character(xx).number() mult = len(divisors(ZZ(d))) check_dim = check_dim + mult * Sd L.append((q, x_k, mult, Sd)) if(self._verbose > 1): wmf_logger.debug("mult={0},N/d={1},Sd={2}".format(mult, ZZ(N / d), Sd)) wmf_logger.debug("check_dim={0}".format(check_dim)) check_dim = check_dim - M.dimension() if(check_dim != 0): raise ArithmeticError("Something wrong! check_dim=%s" % check_dim) self._oldspace_decomposition = L
def compute_satake_parameters_numeric(self, prec=10, bits=53,insert_in_db=True): r""" Compute the Satake parameters and return an html-table. We only do satake parameters for primes p primitive to the level. By defintion the S. parameters are given as the roots of X^2 - c(p)X + chi(p)*p^(k-1) if (p,N)=1 INPUT: -''prec'' -- compute parameters for p <=prec -''bits'' -- do real embedings intoi field of bits precision """ if self.character().order()>2: ## We only implement this for trival or quadratic characters. ## Otherwise there is difficulty to figure out what the embeddings mean... return K = self.coefficient_field() degree = self.degree() RF = RealField(bits) CF = ComplexField(bits) ps = prime_range(prec) self._satake['ps'] = [] alphas = dict() thetas = dict() aps = list() tps = list() k = self.weight() for j in range(degree): alphas[j] = dict() thetas[j] = dict() for j in xrange(len(ps)): p = ps[j] try: ap = self.coefficient(p) except IndexError: break # Remove bad primes if p.divides(self.level()): continue self._satake['ps'].append(p) chip = self.character().value(p) wmf_logger.debug("p={0}".format(p)) wmf_logger.debug("chip={0} of type={1}".format(chip,type(chip))) if hasattr(chip,'complex_embeddings'): wmf_logger.debug("embeddings(chip)={0}".format(chip.complex_embeddings())) wmf_logger.debug("ap={0}".format(ap)) wmf_logger.debug("K={0}".format(K)) # ap=self._f.coefficients(ZZ(prec))[p] if K.absolute_degree()==1: f1 = QQ(4 * chip * p ** (k - 1) - ap ** 2) alpha_p = (QQ(ap) + I * f1.sqrt()) / QQ(2) ab = RF(p ** ((k - 1) / 2)) norm_alpha = alpha_p / ab t_p = CF(norm_alpha).argument() thetas[0][p] = t_p alphas[0][p] = (alpha_p / ab).n(bits) else: for jj in range(degree): app = ap.complex_embeddings(bits)[jj] wmf_logger.debug("chip={0}".format(chip)) wmf_logger.debug("app={0}".format(app)) wmf_logger.debug("jj={0}".format(jj)) if not hasattr(chip,'complex_embeddings'): f1 = (4 * CF(chip) * p ** (k - 1) - app ** 2) else: f1 = (4 * chip.complex_embeddings(bits)[jj] * p ** (k - 1) - app ** 2) alpha_p = (app + I * abs(f1).sqrt()) # ab=RF(/RF(2))) # alpha_p=alpha_p/RealField(bits)(2) wmf_logger.debug("f1={0}".format(f1)) alpha_p = alpha_p / RF(2) wmf_logger.debug("alpha_p={0}".format(alpha_p)) t_p = CF(alpha_p).argument() # tps.append(t_p) # aps.append(alpha_p) alphas[jj][p] = alpha_p thetas[jj][p] = t_p self._satake['alphas'] = alphas self._satake['thetas'] = thetas self._satake['alphas_latex'] = dict() self._satake['thetas_latex'] = dict() for j in self._satake['alphas'].keys(): self._satake['alphas_latex'][j] = dict() for p in self._satake['alphas'][j].keys(): s = latex(self._satake['alphas'][j][p]) self._satake['alphas_latex'][j][p] = s for j in self._satake['thetas'].keys(): self._satake['thetas_latex'][j] = dict() for p in self._satake['thetas'][j].keys(): s = latex(self._satake['thetas'][j][p]) self._satake['thetas_latex'][j][p] = s wmf_logger.debug("satake=".format(self._satake)) return self._satake
def compute_cm_values_numeric(self,digits=12,insert_in_db=True): r""" Compute CM-values numerically. """ if isinstance(self._cm_values,dict) and self._cm_values <> {}: return self._cm_values # the points we want are i and rho. More can be added later... bits = ceil(int(digits) * int(4)) CF = ComplexField(bits) RF = ComplexField(bits) eps = RF(10 ** - (digits + 1)) if(self._verbose > 1): wmf_logger.debug("eps={0}".format(eps)) K = self.base_ring() # recall that degree = self.degree() cm_vals = dict() rho = CyclotomicField(3).gen() zi = CyclotomicField(4).gen() points = [rho, zi] maxprec = 1000 # max size of q-expansion minprec = 10 # max size of q-expansion for tau in points: q = CF(exp(2 * pi * I * tau)) fexp = dict() cm_vals[tau] = dict() if(tau == I and self.level() == -1): # cv= #"Exact(soon...)" #_cohen_exact_formula(k) for h in range(degree): cm_vals[tau][h] = cv continue if K.absolute_degree()==1: v1 = CF(0) v2 = CF(1) try: for prec in range(minprec, maxprec, 10): if(self._verbose > 1): wmf_logger.debug("prec={0}".format(prec)) v2 = self.as_factor().q_eigenform(prec).truncate(prec)(q) err = abs(v2 - v1) if(self._verbose > 1): wmf_logger.debug("err={0}".format(err)) if(err < eps): raise StopIteration() v1 = v2 cm_vals[tau][0] = None except StopIteration: cm_vals[tau][0] = v2 else: v1 = dict() v2 = dict() err = dict() for h in range(degree): v1[h] = 1 v2[h] = 0 try: for prec in range(minprec, maxprec, 10): if(self._verbose > 1): wmf_logger.debug("prec={0}".format(prec)) c = self.coefficients(range(prec),insert_in_db=insert_in_db) for h in range(degree): fexp[h] = list() v2[h] = 0 for n in range(prec): cn = c[n] if hasattr(cn, 'complex_embeddings'): cc = cn.complex_embeddings(CF.prec())[h] else: cc = CF(cn) v2[h] = v2[h] + cc * q ** n err[h] = abs(v2[h] - v1[h]) if(self._verbose > 1): wmf_logger.debug("v1[{0}]={1}".format(h,v1[h])) wmf_logger.debug("v2[{0}]={1}".format(h,v2[h])) wmf_logger.debug("err[{0}]={2}".format(h,err[h])) if(max(err.values()) < eps): raise StopIteration() v1[h] = v2[h] except StopIteration: pass for h in range(degree): if(err[h] < eps): cm_vals[tau][h] = v2[h] else: cm_vals[tau][h] = None self._cm_values = cm_vals
def compute_additional_properties(self): r""" Compute everything we need. """ wmf_logger.debug("Update ap's") self._get_aps() wmf_logger.debug("compute q-expansion") prec = self._prec_needed_for_lfunctions() self.set_q_expansion_embeddings(prec=prec) wmf_logger.debug("as polynomial") if self._N == 1: self.as_polynomial_in_E4_and_E6() wmf_logger.debug("compute twist info") self.twist_info() wmf_logger.debug("compute CM-values") self.compute_cm_values_numeric() wmf_logger.debug("Get Atkin-Lehner evs") self.get_atkin_lehner_eigenvalues() wmf_logger.debug("compute Satake parameters") self.set_is_CM() wmf_logger.debug("compute Satake parameters") self.compute_satake_parameters_numeric() self.set_dimensions() self.coefficient_field() self.get_base_ring() #c = self.coefficients(self.prec(),insert_in_db=False) self.insert_into_db()
def set_twist_info(self, prec=10,insert_in_db=True): r""" Try to find forms of lower level which get twisted into self. OUTPUT: -''[t,l]'' -- tuple of a Bool t and a list l. The list l contains all tuples of forms which twists to the given form. The actual minimal one is the first element of this list. t is set to True if self is minimal and False otherwise EXAMPLES:: """ if(len(self._twist_info) > 0): return self._twist_info N = self.level() k = self.weight() if(is_squarefree(ZZ(N))): self._twist_info = [True, None ] return [True, None] # We need to check all square factors of N twist_candidates = list() KF = self.base_ring() # check how many Hecke eigenvalues we need to check max_nump = self._number_of_hecke_eigenvalues_to_check() maxp = max(primes_first_n(max_nump)) for d in divisors(N): if(d == 1): continue # we look at all d such that d^2 divdes N if(not ZZ(d ** 2).divides(ZZ(N))): continue D = DirichletGroup(d) # check possible candidates to twist into f # g in S_k(M,chi) wit M=N/d^2 M = ZZ(N / d ** 2) if(self._verbose > 0): wmf_logger.debug("Checking level {0}".format(M)) for xig in range(euler_phi(M)): (t, glist) = _get_newform(M,k, xig) if(not t): return glist for g in glist: if(self._verbose > 1): wmf_logger.debug("Comparing to function {0}".format(g)) KG = g.base_ring() # we now see if twisting of g by xi in D gives us f for xi in D: try: for p in primes_first_n(max_nump): if(ZZ(p).divides(ZZ(N))): continue bf = self.as_factor().q_eigenform(maxp + 1, names='x')[p] bg = g.q_expansion(maxp + 1)[p] if(bf == 0 and bg == 0): continue elif(bf == 0 and bg != 0 or bg == 0 and bf != 0): raise StopIteration() if(ZZ(p).divides(xi.conductor())): raise ArithmeticError("") xip = xi(p) # make a preliminary check that the base rings match with respect to being # real or not try: QQ(xip) XF = QQ if(KF != QQ or KG != QQ): raise StopIteration except TypeError: # we have a non-rational (i.e. complex) value of the character XF = xip.parent() if((KF.absolute_degree() == 1 or KF.is_totally_real()) and (KG.absolute_degre() == 1 or KG.is_totally_real())): raise StopIteration ## it is diffcult to compare elements from diferent rings in general but we make some checcks # is it possible to see if there is a larger ring which everything can be # coerced into? ok = False try: a = KF(bg / xip) b = KF(bf) ok = True if(a != b): raise StopIteration() except TypeError: pass try: a = KG(bg) b = KG(xip * bf) ok = True if(a != b): raise StopIteration() except TypeError: pass if(not ok): # we could coerce and the coefficients were equal return "Could not compare against possible candidates!" # otherwise if we are here we are ok and found a candidate twist_candidates.append([M, g.q_expansion(prec), xi]) except StopIteration: # they are not equal pass wmf_logger.debug("Candidates=v{0}".format(twist_candidates)) self._twist_info = (False, twist_candidates) if(len(twist_candidates) == 0): self._twist_info = [True, None] else: self._twist_info = [False, twist_candidates] return self._twist_info