def atkin_lehner_eigenvalues_for_all_cusps(self): r""" """ self._atkin_lehner_eigenvalues_at_cusps = {} G = Gamma0(self.level) for c in Gamma0(self.level).cusps(): aev = self.atkin_lehner_eigenvalues() if aev is None: self._atkin_lehner_eigenvalues_at_cusps = None else: for Q, ev in aev.items(): if G.are_equivalent(c, Q / self.level): self._atkin_lehner_eigenvalues_at_cusps[c] = Q, ev return self._atkin_lehner_eigenvalues_at_cusps
def get_shift_and_width_for_coset(self, n): r""" Compute the shift and width of coset nr. n. """ if self._shift.has_key(n) and self._width.has_key(n): return self._shift[n], self._width[n] if not is_squarefree(self._level): raise NotImplementedError, "Only square-free levels implemented" G = Gamma0(self._level) A = self.coset_rep(n) a = A[0, 0] c = A[1, 0] width = G.cusp_width(Cusp(a, c)) if self._verbose > 0: print "width=", width Amat = Matrix(ZZ, 2, 2, A.matrix().list()) h = -1 for j in range(width): Th = Matrix(ZZ, 2, 2, [width, -j, 0, 1]) W = Amat * Th if self._verbose > 1: print "W=", W if self.is_involution(W): h = j break if h < 0: raise ArithmeticError, "Could not find shift!" self._shift[n] = h self._width[n] = width return h, width
def congruence_groups_between_gamma0_and_gamma1(N): """ INPUT: - N - an integer OUTPUT: - The set of all congruence subgroups contained in Gamma0(N) that contain Gamma1(N) EXAMPLES:: sage: from mdsage import * sage: congruence_groups_between_gamma0_and_gamma1(1) {Modular Group SL(2,Z)} sage: congruence_groups_between_gamma0_and_gamma1(15) {Congruence Subgroup Gamma_H(15) with H generated by [14], Congruence Subgroup Gamma_H(15) with H generated by [4, 11, 14], Congruence Subgroup Gamma0(15)} """ if N == 1: return set([Gamma0(1)]) level_N_modular_groups = set([]) for gens in generators_of_subgroups_of_unit_group(Integers(N)): gens = gens+[-1] H = sage.modular.arithgroup.congroup_gammaH._list_subgroup(N,gens) G = GammaH(N,H) level_N_modular_groups.add(G) return level_N_modular_groups
def get_geometric_data_Gamma0N(N): res = dict() G = Gamma0(N) res['index'] = G.index() res['genus'] = G.genus() res['cusps'] = G.cusps() res['nu2'] = G.nu2() res['nu3'] = G.nu3() return res
def __init__(self, A, B, r, s, k=None, number=0, ch=None, dual=False, version=1, **kwargs): r""" Initialize the Eta multiplier system: $\nu_{\eta}^{2(k+r)}$. INPUT: - G -- Group - ch -- character - dual -- if we have the dual (in this case conjugate) - weight -- Weight (recall that eta has weight 1/2 and eta**2k has weight k. If weight<>k we adjust the power accordingly. - number -- we consider eta^power (here power should be an integer so as not to change the weight...) EXAMPLE: """ self._level = lcm(A, B) G = Gamma0(self._level) if k == None: k = (QQ(r) - QQ(s)) / QQ(2) self._weight = QQ(k) if floor(self._weight - QQ(1) / QQ(2)) == ceil(self._weight - QQ(1) / QQ(2)): self._half_integral_weight = 1 else: self._half_integral_weight = 0 MultiplierSystem.__init__(self, G, dimension=1, character=ch, dual=dual) number = number % 12 if not is_even(number): raise ValueError("Need to have v_eta^(2(k+r)) with r even!") self._arg_num = A self._arg_den = B self._exp_num = r self._exp_den = s self._pow = QQ((self._weight + number)) ## k+r self._k_den = self._pow.denominator() self._k_num = self._pow.numerator() self._K = CyclotomicField(12 * self._k_den) self._z = self._K.gen()**self._k_num self._i = CyclotomicField(4).gen() self._fak = CyclotomicField(2 * self._k_den).gen()**-self._k_num self._version = version self.is_consistent(k) # test consistency
def _set_coset_reps(self): if is_prime(self._level): self._coset_reps[0] = SL2Z([1, 0, 0, 1]) for n in range(self._level): self._coset_reps[n + 1] = SL2Z([0, -1, 1, n]) else: G = Gamma0(self._level) n = 0 for A in G.coset_reps(): self._coset_reps[n] = A n += 1
def atkin_lehner(self, n): r""" Compute the Atkin-Lehner eigenvalue at the cusp of coset nr. n. """ if not self._atkin_lehner.has_key(n): A = self.coset_rep(n) c = Cusp(A[0, 0], A[1, 0]) G = Gamma0(self._level) for Q in divisors(self._level): cQ = Cusp(Q, self._level) if G.are_equivalent(c, cQ): self._atkin_lehner[n] = self._f.atkin_lehner_eigenvalue(Q) break return self._atkin_lehner[n]
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 get_geometric_data(N, group=0): res = dict() if group == 0: G = Gamma0(N) elif group == 1: G = Gamma1(N) else: return None res['index'] = G.index() res['genus'] = G.genus() res['cusps'] = G.cusps() res['nu2'] = G.nu2() res['nu3'] = G.nu3() return res
def _get_coset_n(self, A): r""" Find n s.t. A in Gamma_0(N)A_n """ G = Gamma0(self._level) if A in G: return 0 ## Always use 0 for the trivial coset else: n = 0 for n in range(self._dim): An = self.coset_rep(n) if A * An**-1 in G: return n n += 1 raise ArithmeticError, "Can not find coset of A={0}".format(A)
def __init__(self, args=[1], exponents=[1], ch=None, dual=False, version=1, **kwargs): r""" Initialize the Eta multiplier system: $\nu_{\eta}^{2(k+r)}$. INPUT: - G -- Group - ch -- character - dual -- if we have the dual (in this case conjugate) - weight -- Weight (recall that eta has weight 1/2 and eta**2k has weight k. If weight<>k we adjust the power accordingly. - number -- we consider eta^power (here power should be an integer so as not to change the weight...) EXAMPLE: """ assert len(args) == len(exponents) self._level = lcm(args) G = Gamma0(self._level) k = sum([QQ(x) * QQ(1) / QQ(2) for x in exponents]) self._weight = QQ(k) if floor(self._weight - QQ(1) / QQ(2)) == ceil(self._weight - QQ(1) / QQ(2)): self._half_integral_weight = 1 else: self._half_integral_weight = 0 MultiplierSystem.__init__(self, G, dimension=1, character=ch, dual=dual) self._arguments = args self._exponents = exponents self._pow = QQ((self._weight)) ## k+r self._k_den = self._weight.denominator() self._k_num = self._weight.numerator() self._K = CyclotomicField(12 * self._k_den) self._z = self._K.gen()**self._k_num self._i = CyclotomicField(4).gen() self._fak = CyclotomicField(2 * self._k_den).gen()**-self._k_num self._version = version self.is_consistent(k) # test consistency
def is_formal_immersion(d, p): """This funtion returns an integer n such that we have a formall immersion in characteristic q != 2,p if and only if q does not divide n. """ G = Gamma0(p) M = ModularSymbols(G, 2) S = M.cuspidal_subspace() I2 = M.hecke_operator(2) - 3 if I2.matrix().rank() != S.dimension(): raise RuntimeError(f"Formall immersion for d={d} p={p} failed" "because I2 is not of the expected rank.") Te = R_dp(G.sturm_bound(), p).row_module() R = (R_dp(d, p).restrict_codomain(Te)).change_ring(ZZ) if R.rank() < d: return 0 D = R.elementary_divisors() if D and D[-1]: return D[-1].prime_to_m_part(2) return 0
def R_dp(d, p): """Return the formal immersion matrix Args: d ([int]): degree of number field p ([prime]): prime whose formal immersion properties we'd like to check Returns: [Matrix]: The Matrix whose rows are (T_2-3)*T_i e for i <= d. This is for verifying the linear independance in Corollary 6.4 of Derickx-Kamienny-Stein-Stoll. """ M = ModularSymbols(Gamma0(p), 2) S = M.cuspidal_subspace() S_int = S.integral_structure() e = M([0, oo]) I2 = M.hecke_operator(2) - 3 def get_row(i): return S_int.coordinate_vector( S_int(M.coordinate_vector(I2(M.hecke_operator(i)(e))))) return Matrix([get_row(i) for i in range(1, d + 1)]).change_ring(ZZ)
def is_involution(self, W, verbose=0): r""" Explicit test if W is an involution of Gamma0(self._level) """ G = Gamma0(self._level) for g in G.gens(): gg = Matrix(ZZ, 2, 2, g.matrix().list()) g1 = W * gg * W**-1 if verbose > 0: print "WgW^-1=", g1 if g1 not in G: return False W2 = W * W c = gcd(W2.list()) if c > 1: W2 = W2 / c if verbose > 0: print "W^2=", W2 if W2 not in G: return False return True
def __init__(self, p, congruence_type=1, sign=1, algorithm="custom", verbose=False, dump_dir=None): """ Create a Kamienny criterion object. INPUT: - `p` -- prime -- verify that there is no order p torsion over a degree `d` field - `sign` -- 1 (default),-1 or 0 -- the sign of the modular symbols space to use - ``algorithm`` -- "default" or "custom" whether to use a custom (faster) integral structure algorithm or to use the sage builtin algortihm - ``verbose`` -- bool; whether to print extra stuff while running. EXAMPLES:: sage: from mdsage import * sage: C = KamiennyCriterion(29, algorithm="custom", verbose=False); C Kamienny's Criterion for p=29 sage: C.use_custom_algorithm True sage: C.p 29 sage: C.verbose False """ self.verbose = verbose self.dump_dir = dump_dir if self.verbose: tm = cputime(); mem = get_memory_usage(); print("init") assert congruence_type == 0 or congruence_type == 1 self.congruence_type=congruence_type try: p = ZZ(p) if congruence_type==0: self.congruence_group = Gamma0(p) if congruence_type==1: self.congruence_group = GammaH(p,[-1]) except TypeError: self.congruence_group = GammaH(p.level(),[-1]+p._generators_for_H()) self.congruence_type = ("H",self.congruence_group._list_of_elements_in_H()) self.p = self.congruence_group.level() self.algorithm=algorithm self.sign=sign self.M = ModularSymbols(self.congruence_group, sign=sign) if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "modsym") self.S = self.M.cuspidal_submodule() if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "cuspsub") self.use_custom_algorithm = False if algorithm=="custom": self.use_custom_algorithm = True if self.use_custom_algorithm: int_struct = self.integral_cuspidal_subspace() if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "custom int_struct") else: int_struct = self.S.integral_structure() if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "sage int_struct") self.S_integral = int_struct v = VectorSpace(GF(2), self.S.dimension()).random_element() self.v=v if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "rand_vect") if dump_dir: v.dump(dump_dir+"/vector%s_%s" % (p,congruence_type)) if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "dump")
def sturm_bound0(level, weight): return floor(weight * Gamma0(level).index() / 12)
def init_dynamic_properties(self): if self.character.is_trivial(): self.group = Gamma0(self.level) else: self.group = Gamma1(self.level)
def __init__(self, db, maassid, **kwds): r""" Setup a Maass form from maassid in the database db of the type MaassDB. OPTIONAL parameters: - dirichlet_c_only = 0 or 1 -fnr = get the Dirichlet series coefficients of this function in self only - get_coeffs = False if we do not compute or fetch coefficients """ mwf_logger.debug( "calling WebMaassform with DB={0} and maassid={1}, kwds={2}".format(db, maassid, kwds)) self._db = db self.R = None self.symmetry = -1 self.weight = 0 self.character = 0 self.level = 1 self.table = {} self.coeffs = {} if not isinstance(maassid, (bson.objectid.ObjectId, str)): ids = db.find_Maass_form_id(id=maassid) if len(ids) == 0: raise KeyError("maassid %s not found in database"%maassid) mwf_logger.debug("maassid is not an objectid! {0}".format(maassid)) maassid = ids[0] self._maassid = bson.objectid.ObjectId(maassid) mwf_logger.debug("_id={0}".format(self._maassid)) ff = db.get_Maass_forms(id=self._maassid) # print "ff=",ff if len(ff) == 0: raise KeyError("massid %s not found in database"%maassid) f = ff[0] # print "f here=",f self.dim = f.get('Dim', 1) if self.dim == 0: self.dim = 1 self.R = f.get('Eigenvalue', None) self.symmetry = f.get('Symmetry', -1) self.weight = f.get('Weight', 0) self.character = f.get('Character', 0) self.cusp_evs = f.get('Cusp_evs', []) self._fricke = f.get('Fricke', 0) self.error = f.get('Error', 0) self.level = f.get('Level', None) ## Contributor key self.contr = f.get('Contributor', '') md = db._mongo_db['metadata'].find_one({'c_name': self.contr}) ## Contributor full name try: self.contributor_name = md.get('contributor', self.contr) except: self.contributor_name = self.contr self.num_coeff = f.get('Numc', 0) if self.R is None or self.level is None: return ## As default we assume we just have c(0)=1 and c(1)=1 self._get_dirichlet_c_only = kwds.get('get_dirichlet_c_only', False) self._num_coeff0 = kwds.get('num_coeffs', self.num_coeff) self._get_coeffs = kwds.get('get_coeffs', True) self._fnr = kwds.get('fnr', 0) if self._get_coeffs: self.coeffs = f.get('Coefficient', [0, 1, 0, 0, 0]) if self.coeffs != [0,1,0,0,0]: self.num_coeff = len(self.coeffs) if self._get_dirichlet_c_only: # if self.coeffs!=[0,1,0,0,0]: if len(self.coeffs) == 1: self.coeffs = self.coeffs[0] else: res = {} for n in range(len(self.coeffs)): res[n] = self.coeffs[n] self.coeffs = res self.coeffs = {0: {0: self.coeffs}} else: self.coeffs = {} coeff_id = f.get('coeff_id', None) nc = Gamma0(self.level).ncusps() self.M0 = f.get('M0', nc) mwf_logger.debug("coeffid={0}, get_coeffs={1}".format(coeff_id, self._get_coeffs)) if coeff_id and self._get_coeffs: # self.coeffs==[] and coeff_id: ## Let's see if we have coefficients stored C = self._db.get_coefficients({"_id": self._maassid}) if len(C) >= 1: C = C[0] if self._get_dirichlet_c_only: mwf_logger.debug("setting Dirichlet C!") if self._fnr > len(C): self._fnr = 0 if self._num_coeff0 > len(C[self._fnr][0]) - 1: self._num_coeff0 = len(C[self._fnr][0]) - 1 self.coeffs = [] for j in range(1, self._num_coeff0 + 1): self.coeffs.append(C[self._fnr][0][j]) else: mwf_logger.debug("setting C!") self.coeffs = C ## Make sure that self.coeffs is only the current coefficients if self._get_coeffs and isinstance(self.coeffs, dict) and not self._get_dirichlet_c_only: if not isinstance(self.coeffs, dict): mwf_logger.warning("Coefficients s not a dict. Got:{0}".format(type(self.coeffs))) else: n1 = len(self.coeffs.keys()) mwf_logger.debug("|coeff.keys()|:{0}".format(n1)) if n1 != self.dim: mwf_logger.warning("Got coefficient dict of wrong format!:dim={0} and len(c.keys())={1}".format(self.dim, n1)) if n1 > 0: for j in range(self.dim): n2 = len(self.coeffs.get(j, {}).keys()) mwf_logger.debug("|coeff[{0}].keys()|:{1}".format(j, n2)) if n2 != nc: mwf_logger.warning("Got coefficient dict of wrong format!:num cusps={0} and len(c[0].keys())={1}".format(nc, n2)) self.nc = 1 # len(self.coeffs.keys()) if not self._get_dirichlet_c_only: pass # self.set_table() else: self.table = {}
def __init__(self, maass_id, **kwds): r""" Setup a Maass form from maass_id in the database db of the type MaassDB. OPTIONAL parameters: - dirichlet_c_only = 0 or 1 -fnr = get the Dirichlet series coefficients of this function in self only - get_coeffs = False if we do not compute or fetch coefficients """ self.R = None self.symmetry = -1 self.weight = 0 self.character = 0 self.level = 1 self.table = {} self.coeffs = {} self._maass_id = maass_id f = maass_db.lucky({'maass_id': maass_id}) if f is None: raise KeyError("massid %s not found in database" % maass_id) # print "f here=",f self.dim = f.get('Dim', 1) if self.dim == 0: self.dim = 1 self.R = f.get('Eigenvalue', None) self.symmetry = f.get('Symmetry', -1) self.weight = f.get('Weight', 0) self.character = f.get('Character', 0) self.cusp_evs = f.get('Cusp_evs', []) self._fricke = f.get('Fricke', 0) self.error = f.get('Error', 0) self.level = f.get('Level', None) ## Contributor key self.contr = f.get('Contributor', '') if self.contr == 'FS': self.contributor_name = 'Fredrik Stroemberg' elif self.contr == 'HT': self.contributor_name = 'Holger Then' else: self.contributor_name = self.contr self.num_coeff = f.get('Numc', 0) if self.R is None or self.level is None: return ## As default we assume we just have c(0)=1 and c(1)=1 self._get_dirichlet_c_only = kwds.get('get_dirichlet_c_only', False) self._num_coeff0 = kwds.get('num_coeffs', self.num_coeff) self._get_coeffs = kwds.get('get_coeffs', True) self._fnr = kwds.get('fnr', 0) if self._get_coeffs: self.coeffs = f.get('Coefficient', [0, 1, 0, 0, 0]) if self.coeffs != [0, 1, 0, 0, 0]: self.num_coeff = len(self.coeffs) if self._get_dirichlet_c_only: # if self.coeffs!=[0,1,0,0,0]: if len(self.coeffs) == 1: self.coeffs = self.coeffs[0] else: res = {} for n in range(len(self.coeffs)): res[n] = self.coeffs[n] self.coeffs = res self.coeffs = {0: {0: self.coeffs}} else: self.coeffs = {} nc = Gamma0(self.level).ncusps() self.M0 = f.get('M0', nc) mwf_logger.debug("maass_id={0}, get_coeffs={1}".format( maass_id, self._get_coeffs)) if self._get_coeffs: # self.coeffs==[] and maass_id: ## Let's see if we have coefficients stored C = maass_db.get_coefficients({"maass_id": self._maass_id}) if C is not None: if self._get_dirichlet_c_only: mwf_logger.debug("setting Dirichlet C!") if self._fnr > len(C): self._fnr = 0 if self._num_coeff0 > len(C[self._fnr][0]) - 1: self._num_coeff0 = len(C[self._fnr][0]) - 1 self.coeffs = [] for j in range(1, self._num_coeff0 + 1): self.coeffs.append(C[self._fnr][0][j]) else: mwf_logger.debug("setting C!") self.coeffs = C ## Make sure that self.coeffs is only the current coefficients if self._get_coeffs and isinstance( self.coeffs, dict) and not self._get_dirichlet_c_only: if not isinstance(self.coeffs, dict): mwf_logger.warning("Coefficients s not a dict. Got:{0}".format( type(self.coeffs))) else: n1 = len(self.coeffs.keys()) mwf_logger.debug("|coeff.keys()|:{0}".format(n1)) if n1 != self.dim: mwf_logger.warning( "Got coefficient dict of wrong format!:dim={0} and len(c.keys())={1}" .format(self.dim, n1)) if n1 > 0: for j in range(self.dim): n2 = len(self.coeffs.get(j, {}).keys()) mwf_logger.debug("|coeff[{0}].keys()|:{1}".format( j, n2)) if n2 != nc: mwf_logger.warning( "Got coefficient dict of wrong format!:num cusps={0} and len(c[0].keys())={1}" .format(nc, n2)) self.nc = 1 # len(self.coeffs.keys()) if not self._get_dirichlet_c_only: pass # self.set_table() else: self.table = {}
def draw_fundamental_domain(N, group='Gamma0', model="H", axes=None, filename=None, **kwds): r""" Draw fundamental domain INPUT: - ''model'' -- (default ''H'') = ''H'' -- Upper halfplane = ''D'' -- Disk model - ''filename''-- filename to print to - ''**kwds''-- additional arguments to matplotlib - ''axes'' -- set geometry of output =[x0,x1,y0,y1] -- restrict figure to [x0,x1]x[y0,y1] EXAMPLES:: sage: G=MySubgroup(Gamma0(3)) sage: G.draw_fundamental_domain() """ if group.strip() == 'Gamma0': G = Gamma0(N) elif group.strip() == 'Gamma1': G = Gamma1(N) elif group.strip() == 'Gamma': G = Gamma(N) else: raise ValueError('group must be one of: "Gamma0", "Gamma1", "Gamma"') s = "$" + latex(G) + "$" s = s.replace("mbox", "mathrm") s = s.replace("Bold", "mathbb") name = s # name ="$\mbox{SL}_{2}(\mathbb{Z})$" # need a "nice" set of coset representatives to draw a connected # fundamental domain. Only implemented for Gamma_0(N) coset_reps = nice_coset_reps(G) # if(group=='Gamma0'): # else: # coset_reps = list(G.coset_reps()) from matplotlib.backends.backend_agg import FigureCanvasAgg if (model == "D"): g = _draw_funddom_d(coset_reps, format, I) else: g = _draw_funddom(coset_reps, format) if (axes is not None): [x0, x1, y0, y1] = axes elif (model == "D"): x0 = -1 x1 = 1 y0 = -1.1 y1 = 1 else: # find the width of the fundamental domain # w = 0 # self.cusp_width(Cusp(Infinity)) FIXME: w is never used wmin = 0 wmax = 1 max_x = RR(0.55) rho = CC(exp(2 * pi * I / 3)) for V in coset_reps: ## we also compare the real parts of where rho and infinity are mapped r1 = (V.acton(rho)).real() if (V[1, 0] != 0): inf1 = RR(V[0, 0] / V[1, 0]) else: inf1 = 0 if (V[1, 0] == 0 and V[0, 0] == 1): if (V[0, 1] > wmax): wmax = V[0, 1] if (V[0, 1] < wmin): wmin = V[0, 1] if (max(r1, inf1) > max_x): max_x = max(r1, inf1) logging.debug("wmin,wmax=%s,%s" % (wmin, wmax)) # x0=-1; x1=1; y0=-0.2; y1=1.5 x0 = RR(-max_x) x1 = RR(max_x) y0 = RR(-0.15) y1 = RR(1.5) ## Draw the axes manually (since can't figure out how to do it automatically) ax = line([[x0, 0.0], [x1, 0.0]], color='black') # ax = ax + line([[0.0,y0],[0.0,y1]],color='black') ## ticks ax = ax + line([[-0.5, -0.01], [-0.5, 0.01]], color='black') ax = ax + line([[0.5, -0.01], [0.5, 0.01]], color='black') g = g + ax if model == "H": t = text(name, (0, -0.1), fontsize=16, color='black') t = t + text( "$ -\\frac{1}{2} $", (-0.5, -0.1), fontsize=12, color='black') t = t + text( "$ \\frac{1}{2} $", (0.5, -0.1), fontsize=12, color='black') else: t = text(name, (0, -1.1), fontsize=16, color='black') g = g + t g.set_aspect_ratio(1) g.set_axes_range(x0, x1, y0, y1) g.axes(False) if (filename is not None): fig = g.matplotlib() fig.set_canvas(FigureCanvasAgg(fig)) axes = fig.get_axes()[0] axes.minorticks_off() axes.set_yticks([]) fig.savefig(filename, **kwds) else: return g
def __init__(self, WR, weight=QQ(1) / QQ(2), use_symmetry=True, group=SL2Z, dual=False, **kwargs): r""" WR should be a Weil representation. INPUT: - weight -- weight (should be consistent with the signature of self) - use_symmetry -- if False we do not symmetrize the functions with respect to Z -- if True we need a compatible weight - 'group' -- Group to act on. """ if isinstance(WR, (Integer, int)): #self.WR=WeilRepDiscriminantForm(WR) #self.WR=WeilModule(WR) self._weil_module = WeilModule(WR) elif hasattr(WR, "signature"): self._weil_module = WR else: raise ValueError("{0} is not a Weil module!".format(WR)) self._sym_type = 0 if group.level() != 1: raise NotImplementedError( "Only Weil representations of SL2Z implemented!") self._group = MySubgroup(Gamma0(1)) self._dual = int(dual) self._sgn = (-1)**self._dual self.Qv = [] self._weight = weight self._use_symmetry = use_symmetry self._kwargs = kwargs self._sgn = (-1)**int(dual) half = QQ(1) / QQ(2) threehalf = QQ(3) / QQ(2) if use_symmetry: ## First find weight mod 2: twok = QQ(2) * QQ(weight) if not twok.is_integral(): raise ValueError( "Only integral or half-integral weights implemented!") kmod2 = QQ(twok % 4) / QQ(2) if dual: sig_mod_4 = -self._weil_module.signature() % 4 else: sig_mod_4 = self._weil_module.signature() % 4 sym_type = 0 if (kmod2, sig_mod_4) in [(half, 1), (threehalf, 3), (0, 0), (1, 2)]: sym_type = 1 elif (kmod2, sig_mod_4) in [(half, 3), (threehalf, 1), (0, 2), (1, 0)]: sym_type = -1 else: raise ValueError( "The Weil module with signature {0} is incompatible with the weight {1}!" .format(self._weil_module.signature(), weight)) ## Deven and Dodd contains the indices for the even and odd basis Deven = [] Dodd = [] if sym_type == 1: self._D = self._weil_module.even_submodule(indices=1) else: #sym_type==-1: self._D = self._weil_module.odd_submodule(indices=1) self._sym_type = sym_type dim = len(self._D) #Dfinish-Dstart+1 else: dim = len(self._weil_module.finite_quadratic_module().list()) self._D = list(range(dim)) self._sym_type = 0 if hasattr(self._weil_module, "finite_quadratic_module"): # for x in list(self._weil_module.finite_quadratic_module()): for x in self._weil_module.finite_quadratic_module(): self.Qv.append( self._weil_module.finite_quadratic_module().Q(x)) else: self.Qv = self._weil_module.Qv ambient_rank = self._weil_module.rank() MultiplierSystem.__init__(self, self._group, dual=dual, dimension=dim, ambient_rank=ambient_rank)
def __init__(self, G, v=None, **kwargs): r""" G should be a subgroup of PSL(2,Z). EXAMPLE:: sage: te=TestMultiplier(Gamma0(2),weight=1/2) sage: r=InducedRepresentation(Gamma0(2),v=te) """ dim = len(list(G.coset_reps())) MultiplierSystem.__init__(self, Gamma0(1), dimension=dim) self._induced_from = G # setup the action on S and T (should be faster...) self.v = v if v != None: k = v.order() if k > 2: K = CyclotomicField(k) else: K = ZZ self.S = matrix(K, dim, dim) self.T = matrix(K, dim, dim) else: self.S = matrix(dim, dim) self.T = matrix(dim, dim) S, T = SL2Z.gens() if hasattr(G, "coset_reps"): if isinstance(G.coset_reps(), list): Vl = G.coset_reps() else: Vl = list(G.coset_reps()) elif hasattr(G, "_G"): Vl = list(G._G.coset_reps()) else: raise ValueError( "Could not get coset representatives from {0}!".format(G)) self.repsT = dict() self.repsS = dict() for i in range(dim): Vi = Vl[i] for j in range(dim): Vj = Vl[j] BS = Vi * S * Vj**-1 BT = Vi * T * Vj**-1 #print "i,j #print "ViSVj^-1=",BS #print "ViTVj^-1=",BT if BS in G: if v != None: vS = v(BS) else: vS = 1 self.S[i, j] = vS self.repsS[(i, j)] = BS if BT in G: if v != None: vT = v(BT) else: vT = 1 self.T[i, j] = vT self.repsT[(i, j)] = BT
def sturm_bound0(level, weight): return (weight * Gamma0(level).index()) // 12
def __init__(self, f, prec=53, verbose=0, data={}): r""" Initialize the period polynomial of f. INPUT: - `f` -- Newform - `` EXAMPLES: # First elliptic curve sage: f=Newforms(11,2)[0] sage: pp=PeriodPolynomial(f,prec=103) sage: L=f.cuspform_lseries() sage: pp.petersson_norm() 0.00390834565612459898524738548154 - 5.53300833748482053164300189100e-35*I sage: pp.special_value(1) 0.253841860855910684337758923267 sage: L(1) 0.253841860855911 # We can also study rationality of the coefficients of the sage: pp.test_rationality() P(f 0)^+/omega_+=1.00000000000000000000000000000 P(f 0)^-/omega_-=0 P(f 1)^+/omega_+=-1.00000000000000000000000000000 P(f 1)^-/omega_-=0 P(f 2)^+/omega_+=0 P(f 2)^-/omega_-=1.27412157006452456511355616309e-31 + 1.01489446868406102099789763444e-28*I P(f 3)^+/omega_+=-5.00000000000000000000000000133 P(f 3)^-/omega_-=-1.16793587723237638257725820700e-60 + 8.24993716616779655911027615609e-29*I P(f 4)^+/omega_+=-2.50000000000000000000000000073 P(f 4)^-/omega_-=-3.39765752017206550696948310188e-32 + 2.39999999999999999999999999940*I P(f 5)^+/omega_+=2.50000000000000000000000000073 P(f 5)^-/omega_-=-3.39765752017206550696948310188e-32 + 2.39999999999999999999999999940*I P(f 6)^+/omega_+=5.00000000000000000000000000133 P(f 6)^-/omega_-=1.16793587723237638257725820700e-60 - 8.24993716616779655911027615609e-29*I P(f 7)^+/omega_+=5.00000000000000000000000000133 P(f 7)^-/omega_-=-1.16793587723237638257725820700e-60 + 8.24993716616779655911027615609e-29*I P(f 8)^+/omega_+=2.50000000000000000000000000073 P(f 8)^-/omega_-=3.39765752017206550696948310188e-32 - 2.39999999999999999999999999940*I P(f 9)^+/omega_+=-2.50000000000000000000000000073 P(f 9)^-/omega_-=3.39765752017206550696948310188e-32 - 2.39999999999999999999999999940*I P(f10)^+/omega_+=-5.00000000000000000000000000133 P(f10)^-/omega_-=1.16793587723237638257725820700e-60 - 8.24993716616779655911027615609e-29*I P(f11)^+/omega_+=0 P(f11)^-/omega_-=-1.27412157006452456511355616309e-31 - 1.01489446868406102099789763444e-28*I o1= 0.0404001869188632792144191985239*I o2= -1.36955018267536771772869542629e-33 - 0.0967407815209822856536332369020*I sage: f=Newforms(5,8,names='a')[0];f q - 14*q^2 - 48*q^3 + 68*q^4 + 125*q^5 + O(q^6) sage: L=f.cuspform_lseries() sage: pp=PeriodPolynomial(f,prec=103) sage: pp.special_value(4) -3.34183629241748201816194829811e-29 + 8.45531852674217908762910051272e-60*I sage: pp.special_value(3) -0.729970592499451187790964533256 + 2.56020879251697431818575640846e-31*I sage: L(3) -0.729970592499451 sage: L(4) 0.000000000000000 """ self._f = f self._level = None if data <> {}: self.init_from_dict(data) if self._level == None: self._level = f.level() self._k = f.weight() self._w = self._k - 2 self._verbose = verbose self._polynomials = {} self._prec = prec self._rks = {} self._coset_reps = {} self._dim = Gamma0(self._level).index() self._coefficients_at_coset = {} self._base_coeffs = [] self._base_coeffs_embedding = [] self._M = {} self._M0 = 0 self._width = {} self._shift = {} self._atkin_lehner = {} self._integrals = {} self._pplus = {} self._pminus = {} self._peterson_norm = 0 self._canonical_periods = [] # Check assert is_squarefree(self._level) ## Some numerical definitions self._RF = RealField(prec) self._eps = self._RF(2)**-self._RF(prec) self._pi = self._RF.pi()