class PSModularSymbolSpace(Module): r""" A class for spaces of modular symbols that use Glenn Stevens' conventions. This class should not be instantiated directly by the user: this is handled by the factory object ``PSModularSymbols``. INPUT: - ``group`` -- congruence subgroup - ``coefficients`` -- a coefficient module - ``sign`` -- (default: 0); 0, -1, or 1 EXAMPLES:: sage: D = Distributions(2, 11) sage: M = PSModularSymbols(Gamma0(2), coefficients=D); M.sign() 0 sage: M = PSModularSymbols(Gamma0(2), coefficients=D, sign=-1); M.sign() -1 sage: M = PSModularSymbols(Gamma0(2), coefficients=D, sign=1); M.sign() 1 """ def __init__(self, group, coefficients, sign=0): r""" INPUT: See :class:`PSModularSymbolSpace` EXAMPLES:: sage: D = Distributions(2, 11) sage: M = PSModularSymbols(Gamma0(11), coefficients=D) sage: type(M) <class 'sage.modular.pollack_stevens.space.PSModularSymbolSpace_with_category'> sage: TestSuite(M).run() """ Module.__init__(self, coefficients.base_ring()) if sign not in [0,-1,1]: # sign must be be 0, -1 or 1 raise ValueError, "sign must be 0, -1, or 1" self._group = group self._coefficients = coefficients if coefficients.is_symk(): self.Element = PSModularSymbolElement_symk else: self.Element = PSModularSymbolElement_dist self._sign = sign # should distingish between Gamma0 and Gamma1... self._source = ManinRelations(group.level()) # Register the action of 2x2 matrices on self. if coefficients.is_symk(): action = PSModSymAction(Sigma0(1), self) else: action = PSModSymAction(Sigma0(self.prime()), self) self._populate_coercion_lists_(action_list=[action]) def _element_constructor_(self, data): r""" Construct an element of self from data. """ if isinstance(data, PSModularSymbolElement): data = data._map elif isinstance(data, ManinMap): pass else: # a dict, or a single distribution specifying a constant symbol, etc data = ManinMap(self._coefficients, self._source, data) if data._codomain != self._coefficients: data = data.extend_codomain(self._coefficients) return self.element_class(data, self, construct=True) def _coerce_map_from_(self, other): r""" Used for comparison and coercion. EXAMPLE:: sage: M1 = PSModularSymbols(Gamma0(11), coefficients=Symk(3)) sage: M2 = PSModularSymbols(Gamma0(11), coefficients=Symk(3,Qp(11))) sage: M3 = PSModularSymbols(Gamma0(11), coefficients=Symk(4)) sage: M4 = PSModularSymbols(Gamma0(11), coefficients=Distributions(3, 11, 10)) sage: M1.has_coerce_map_from(M2) False sage: M2.has_coerce_map_from(M1) True sage: M1.has_coerce_map_from(M3) False sage: M1.has_coerce_map_from(M4) False sage: M2.has_coerce_map_from(M4) True """ if isinstance(other, PSModularSymbolSpace): if other.group() == self.group() \ and self.coefficient_module().has_coerce_map_from(other.coefficient_module()): return True else: return False def _repr_(self): r""" Returns print representation. EXAMPLES:: sage: D = Distributions(2, 11) sage: M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M._repr_() 'Space of overconvergent modular symbols for Congruence Subgroup Gamma0(2) with sign 0 and values in Space of 11-adic distributions with k=2 action and precision cap 20' """ if self.coefficient_module().is_symk(): s = "Space of modular symbols for " else: s = "Space of overconvergent modular symbols for " s += "%s with sign %s and values in %s"%(self.group(), self.sign(), self.coefficient_module()) return s def source(self): r""" Return the domain of the modular symbols in this space. OUTPUT: A :class:`sage.modular.pollack_stevens.fund_domain.PSModularSymbolsDomain` EXAMPLES:: sage: D = Distributions(2, 11); M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.source() Manin Relations of level 2 """ return self._source def coefficient_module(self): r""" Return the coefficient module of this space. EXAMPLES:: sage: D = Distributions(2, 11); M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.coefficient_module() Space of 11-adic distributions with k=2 action and precision cap 20 sage: M.coefficient_module() is D True """ return self._coefficients def group(self): r""" Return the congruence subgroup of this space. EXAMPLES:: sage: D = Distributions(2, 5) sage: G = Gamma0(23) sage: M = PSModularSymbols(G, coefficients=D) sage: M.group() Congruence Subgroup Gamma0(23) sage: D = Symk(4) sage: G = Gamma1(11) sage: M = PSModularSymbols(G, coefficients=D) sage: M.group() Congruence Subgroup Gamma1(11) """ return self._group def sign(self): r""" Return the sign of this space. EXAMPLES:: sage: D = Distributions(3, 17) sage: M = PSModularSymbols(Gamma(5), coefficients=D) sage: M.sign() 0 sage: D = Symk(4) sage: M = PSModularSymbols(Gamma1(8), coefficients=D, sign=-1) sage: M.sign() -1 """ return self._sign def ngens(self): r""" Returns the number of generators defining this space. EXAMPLES:: sage: D = Distributions(4, 29) sage: M = PSModularSymbols(Gamma1(12), coefficients=D) sage: M.ngens() 5 sage: D = Symk(2) sage: M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.ngens() 2 """ return len(self._source.indices()) def ncoset_reps(self): r""" Returns the number of coset representatives defining the domain of the modular symbols in this space. OUTPUT: The number of coset representatives stored in the manin relations. (Just the size of P^1(Z/NZ)) EXAMPLES:: sage: D = Symk(2) sage: M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.ncoset_reps() 3 """ return len(self._source.reps()) def level(self): r""" Returns the level `N`, where this space is of level `\Gamma_0(N)`. EXAMPLES:: sage: D = Distributions(7, 11) sage: M = PSModularSymbols(Gamma1(14), coefficients=D) sage: M.level() 14 """ return self._source.level() def _grab_relations(self): r""" This is used internally as part of a consistency check. EXAMPLES:: sage: D = Distributions(4, 3) sage: M = PSModularSymbols(Gamma1(13), coefficients=D) sage: M._grab_relations() [[(1, [1 0] [0 1], 0)], [(-1, [-1 -1] [ 0 -1], 0)], [(1, [1 0] [0 1], 2)], [(1, [1 0] [0 1], 3)], [(1, [1 0] [0 1], 4)], [(1, [1 0] [0 1], 5)]] """ S0N = Sigma0(self._source._N) v = [] for r in range(len(self._source.gens())): for j in range(len(self._source.reps())): R = self._source.relations(j) if len(R) == 1 and R[0][2] == self._source.indices(r): if R[0][0] != -1 or R[0][1] != S0N(1): v = v + [R] return v def precision_cap(self): r""" Returns the number of moments of each element of this space. EXAMPLES:: sage: D = Distributions(2, 5) sage: M = PSModularSymbols(Gamma1(13), coefficients=D) sage: M.precision_cap() 20 sage: D = Distributions(3, 7, prec_cap=10) sage: M = PSModularSymbols(Gamma0(7), coefficients=D) sage: M.precision_cap() 10 """ ### WARNING -- IF YOU ARE WORKING IN SYM^K(Q^2) THIS WILL JUST RETURN K-1. NOT GOOD return self.coefficient_module()._prec_cap def weight(self): r""" Returns the weight of this space. .. WARNING:: We emphasize that in the Pollack-Stevens notation, this is the usual weight minus 2, so a classical weight 2 modular form corresponds to a modular symbol of "weight 0". EXAMPLES:: sage: D = Symk(5) sage: M = PSModularSymbols(Gamma1(7), coefficients=D) sage: M.weight() 5 """ return self.coefficient_module()._k def prime(self): r""" Returns the prime of this space. EXAMPLES: sage: D = Distributions(2, 11) sage: M = PSModularSymbols(Gamma(2), coefficients=D) sage: M.prime() 11 """ return self.coefficient_module()._p def _p_stabilize_parent_space(self, p, new_base_ring): r""" Returns the space of Pollack-Stevens modular symbols of level ``p * N``, with changed base ring. This is used internally when constructing the p-stabilization of a modular symbol. INPUT: - ``p`` -- prime number - ``new_base_ring`` -- the base ring of the result OUTPUT: The space of modular symbols of level ``p * N``, where N is the level of this space. EXAMPLES:: sage: D = Distributions(2, 7); M = PSModularSymbols(Gamma(13), coefficients=D) sage: M._p_stabilize_parent_space(7, M.base_ring()) Space of overconvergent modular symbols for Congruence Subgroup Gamma(91) with sign 0 and values in Space of 7-adic distributions with k=2 action and precision cap 20 sage: D = Distributions(4, 17); M = PSModularSymbols(Gamma1(3), coefficients=D) sage: M._p_stabilize_parent_space(17, Qp(17)) Space of overconvergent modular symbols for Congruence Subgroup Gamma1(51) with sign 0 and values in Space of 17-adic distributions with k=4 action and precision cap 20 """ N = self.level() if N % p == 0: raise ValueError("the level isn't prime to p") from sage.modular.arithgroup.all import Gamma, is_Gamma, Gamma0, is_Gamma0, Gamma1, is_Gamma1 G = self.group() if is_Gamma0(G): G = Gamma0(N*p) elif is_Gamma1(G): G = Gamma1(N*p) elif is_Gamma(G): G = Gamma(N*p) else: raise NotImplementedError return PSModularSymbols(G, coefficients=self.coefficient_module().change_ring(new_base_ring), sign=self.sign()) def _specialize_parent_space(self, new_base_ring): r""" Internal function that is used by the specialize method on elements. It returns a space with same parameters as this one, but over ``new_base_ring``. INPUT: - ``new_base_ring`` -- a ring OUTPUT: A space of modular symbols to which our space specializes. EXAMPLES:: sage: D = Distributions(7, 5); M = PSModularSymbols(Gamma0(2), coefficients=D); M Space of overconvergent modular symbols for Congruence Subgroup Gamma0(2) with sign 0 and values in Space of 5-adic distributions with k=7 action and precision cap 20 sage: M._specialize_parent_space(QQ) Space of modular symbols for Congruence Subgroup Gamma0(2) with sign 0 and values in Sym^7 Q^2 sage: M.base_ring() 5-adic Ring with capped absolute precision 20 sage: M._specialize_parent_space(QQ).base_ring() Rational Field """ return PSModularSymbols(self.group(), coefficients=self.coefficient_module().specialize(new_base_ring), sign=self.sign()) def _lift_parent_space(self, p, M, new_base_ring): r""" Used internally to lift a space of modular symbols to space of overconvergent modular symbols. INPUT: - ``p`` -- prime - ``M`` -- precision cap - ``new_base_ring`` -- ring OUTPUT: A space of distribution valued modular symbols. EXAMPLES:: sage: D = Distributions(4, 17, 2); M = PSModularSymbols(Gamma1(3), coefficients=D) sage: D.is_symk() False sage: M._lift_parent_space(17, 10, Qp(17)) Traceback (most recent call last): ... TypeError: Coefficient module must be a Symk sage: PSModularSymbols(Gamma1(3), weight=1)._lift_parent_space(17,10,Qp(17)) Space of overconvergent modular symbols for Congruence Subgroup Gamma1(3) with sign 0 and values in Space of 17-adic distributions with k=1 action and precision cap 10 """ if self.coefficient_module().is_symk(): return PSModularSymbols(self.group(), coefficients=self.coefficient_module().lift(p, M, new_base_ring), sign=self.sign()) else: raise TypeError("Coefficient module must be a Symk") def change_ring(self, new_base_ring): r""" Changes the base ring of this space to ``new_base_ring``. INPUT: - ``new_base_ring`` -- a ring OUTPUT: A space of modular symbols over the specified base. EXAMPLES:: sage: from sage.modular.pollack_stevens.distributions import Symk sage: D = Symk(4) sage: M = PSModularSymbols(Gamma(6), coefficients=D); M Space of modular symbols for Congruence Subgroup Gamma(6) with sign 0 and values in Sym^4 Q^2 sage: M.change_ring(Qp(5,8)) Space of modular symbols for Congruence Subgroup Gamma(6) with sign 0 and values in Sym^4 Q_5^2 """ return PSModularSymbols(self.group(), coefficients=self.coefficient_module().change_ring(new_base_ring), sign=self.sign()) def _an_element_(self): # WARNING -- THIS ISN'T REALLY AN ELEMENT OF THE SPACE BECAUSE IT DOESN'T # SATISFY THE MANIN RELATIONS r""" Returns the cusps associated to an element of a congruence subgroup. OUTPUT: An element of the modular symbol space. Returns a "typical" element of this space; in this case the constant map sending every element to an element of the coefficient module. EXAMPLES:: sage: D = Symk(4) sage: M = PSModularSymbols(Gamma(6), coefficients=D) sage: x = M.an_element(); x # indirect doctest Modular symbol of level 6 with values in Sym^4 Q^2 sage: x.values() [(0, 1, 2, 3, 4), (0, 1, 2, 3, 4), (0, 1, 2, 3, 4)] sage: D = Symk(2, Qp(11)); M = PSModularSymbols(Gamma0(2), coefficients=D) sage: x = M.an_element(); x.values() [(0, 1 + O(11^20), 2 + O(11^20)), (0, 1 + O(11^20), 2 + O(11^20))] sage: x in M True """ return self(self.coefficient_module().an_element()) def random_element(self,M=None): r""" Returns a random OMS in this space with M moments INPUT: - ``M`` -- positive integer OUTPUT: An element of the modular symbol space with ``M`` moments Returns a random element in this space by randomly choosing values of distributions on all but one divisor, and solves the difference equation to determine the value on the last divisor. """ if (M == None) and (not self.coefficient_module().is_symk()): M = self.coefficient_module().precision_cap() k = self.coefficient_module()._k p = self.prime() manin = self.source() # ## There must be a problem here with that +1 -- should be variable depending on a c of some matrix # ## We'll need to divide by some power of p and so we add extra accuracy here. # if k != 0: # MM = M + valuation(k,p) + 1 + M.exact_log(p) # else: # MM = M + M.exact_log(p) + 1 ## this loop runs thru all of the generators (except (0)-(infty)) and randomly chooses a distribution ## to assign to this generator (in the 2,3-torsion cases care is taken to satisfy the relevant relation) D = {} for g in manin.gens(): D[g] = self.coefficient_module().random_element(M) # print "pre:",D[g] if g in manin.reps_with_two_torsion() and g in manin.reps_with_three_torsion: raise ValueError("Level 1 not implemented") if g in manin.reps_with_two_torsion(): gamg = manin.two_torsion_matrix(g) D[g] = D[g] - D[g] * gamg else: if g in manin.reps_with_three_torsion(): gamg = manin.three_torsion_matrix(g) D[g] = 2*D[g] - D[g] * gamg - D[g] * gamg**2 # print "post:",D[g] ## now we compute nu_infty of Prop 5.1 of [PS1] t = self.coefficient_module().zero_element() for g in manin.gens()[1:]: if (not g in manin.reps_with_two_torsion()) and (not g in manin.reps_with_three_torsion()): # print "g:", g # print "D[g]:",D[g] # print "manin",manin.gammas[g] # print "D*m:",D[g] * manin.gammas[g] # print "-------" t += D[g] * manin.gammas[g] - D[g] else: if g in MR.reps_with_two_torsion(): t -= D[g] else: t -= D[g] ## If k = 0, then t has total measure zero. However, this is not true when k != 0 ## (unlike Prop 5.1 of [PS1] this is not a lift of classical symbol). ## So instead we simply add (const)*mu_1 to some (non-torsion) v[j] to fix this ## here since (mu_1 |_k ([a,b,c,d]-1))(trival char) = chi(a) k a^{k-1} c , ## we take the constant to be minus the total measure of t divided by (chi(a) k a^{k-1} c) if k != 0: j = 1 g = manin.gens()[j] while (g in manin.reps_with_two_torsion()) or (g in manin.reps_with_three_torsion()) and (j < len(manin.gens())): j = j + 1 g = manin.gens()[j] if j == len(manin.gens()): raise ValueError("everything is 2 or 3 torsion! NOT YET IMPLEMENTED IN THIS CASE") gam = manin.gammas[g] a = gam.matrix()[0,0] c = gam.matrix()[1,0] if self.coefficient_module()._character != None: chara = self.coefficient_module()._character(a) else: chara = 1 err = -t.moment(0)/(chara*k*a**(k-1)*c) v = [0 for j in range(M)] v[1] = 1 mu_1 = err * self.coefficient_module()(v) D[g] += mu_1 # print "Modifying: ",D[g] t = t + mu_1 * gam - mu_1 Id = manin.gens()[0] if not self.coefficient_module().is_symk(): mu = t.solve_diff_eqn() D[Id] = -mu # print "Last:",D[Id] else: if self.coefficient_module()._k == 0: D[Id] = self.coefficient_module().random_element() else: raise ValueError("Not implemented for symk with k>0 yet") return self(D)
class PSModularSymbolSpace(Module): r""" A class for spaces of modular symbols that use Glenn Stevens' conventions. This class should not be instantiated directly by the user: this is handled by the factory object ``PSModularSymbols``. INPUT: - ``group`` -- congruence subgroup - ``coefficients`` -- a coefficient module - ``sign`` -- (default: 0); 0, -1, or 1 EXAMPLES:: sage: D = Distributions(2, 11) sage: M = PSModularSymbols(Gamma0(2), coefficients=D); M.sign() 0 sage: M = PSModularSymbols(Gamma0(2), coefficients=D, sign=-1); M.sign() -1 sage: M = PSModularSymbols(Gamma0(2), coefficients=D, sign=1); M.sign() 1 """ def __init__(self, group, coefficients, sign=0): r""" INPUT: See :class:`PSModularSymbolSpace` EXAMPLES:: sage: D = Distributions(2, 11) sage: M = PSModularSymbols(Gamma0(2), coefficients=D) sage: type(M) <class 'sage.modular.pollack_stevens.space.PSModularSymbolSpace_with_category'> sage: TestSuite(M).run() """ Module.__init__(self, coefficients.base_ring()) if sign not in [0,-1,1]: # sign must be be 0, -1 or 1 raise ValueError, "sign must be 0, -1, or 1" self._group = group self._coefficients = coefficients if coefficients.is_symk(): self.Element = PSModularSymbolElement_symk else: self.Element = PSModularSymbolElement_dist self._sign = sign # should distingish between Gamma0 and Gamma1... self._source = ManinRelations(group.level()) # We have to include the first action so that scaling by Z doesn't try to pass through matrices actions = [PSModSymAction(ZZ, self), PSModSymAction(M2ZSpace, self)] self._populate_coercion_lists_(action_list=actions) def _repr_(self): r""" Returns print representation. EXAMPLES:: sage: D = Distributions(2, 11) sage: M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M._repr_() 'Space of overconvergent modular symbols for Congruence Subgroup Gamma0(2) with sign 0 and values in Space of 11-adic distributions with k=2 action and precision cap 20' """ if self.coefficient_module().is_symk(): s = "Space of modular symbols for " else: s = "Space of overconvergent modular symbols for " s += "%s with sign %s and values in %s"%(self.group(), self.sign(), self.coefficient_module()) return s def source(self): r""" Return the domain of the modular symbols in this space. OUTPUT: A :class:`sage.modular.pollack_stevens.fund_domain.PSModularSymbolsDomain` EXAMPLES:: sage: D = Distributions(2, 11); M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.source() Manin Relations of level 2 """ return self._source def coefficient_module(self): r""" Return the coefficient module of this space. EXAMPLES:: sage: D = Distributions(2, 11); M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.coefficient_module() Space of 11-adic distributions with k=2 action and precision cap 20 sage: M.coefficient_module() is D True """ return self._coefficients def group(self): r""" Return the congruence subgroup of this space. EXAMPLES:: sage: D = Distributions(2, 5) sage: G = Gamma0(23) sage: M = PSModularSymbols(G, coefficients=D) sage: M.group() Congruence Subgroup Gamma0(23) sage: D = Symk(4) sage: G = Gamma1(11) sage: M = PSModularSymbols(G, coefficients=D) sage: M.group() Congruence Subgroup Gamma1(11) """ return self._group def sign(self): r""" Return the sign of this space. EXAMPLES:: sage: D = Distributions(3, 17) sage: M = PSModularSymbols(Gamma(5), coefficients=D) sage: M.sign() 0 sage: D = Symk(4) sage: M = PSModularSymbols(Gamma1(8), coefficients=D, sign=-1) sage: M.sign() -1 """ return self._sign def ngens(self): r""" Returns the number of generators defining this space. EXAMPLES:: sage: D = Distributions(4, 29) sage: M = PSModularSymbols(Gamma1(12), coefficients=D) sage: M.ngens() 5 sage: D = Symk(2) sage: M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.ngens() 2 """ return len(self._source.indices()) def ncoset_reps(self): r""" Returns the number of coset representatives defining the domain of the modular symbols in this space. OUTPUT: The number of coset representatives stored in the manin relations. (Just the size of P^1(Z/NZ)) EXAMPLES:: sage: D = Symk(2) sage: M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.ncoset_reps() 3 """ return len(self._source.reps()) def level(self): r""" Returns the level `N`, where this space is of level `\Gamma_0(N)`. EXAMPLES:: sage: D = Distributions(7, 11) sage: M = PSModularSymbols(Gamma1(14), coefficients=D) sage: M.level() 14 """ return self._source.level() def _grab_relations(self): r""" This is used internally as part of a consistency check. EXAMPLES:: sage: D = Distributions(4, 3) sage: M = PSModularSymbols(Gamma1(13), coefficients=D) sage: M._grab_relations() [[(1, [1 0] [0 1], 0)], [(-1, [-1 -1] [ 0 -1], 0)], [(1, [1 0] [0 1], 2)], [(1, [1 0] [0 1], 3)], [(1, [1 0] [0 1], 4)], [(1, [1 0] [0 1], 5)]] """ v = [] for r in range(len(self._source.gens())): for j in range(len(self._source.reps())): R = self._source.relations(j) if len(R) == 1 and R[0][2] == self._source.indices(r): if R[0][0] != -1 or R[0][1] != M2ZSpace.one(): v = v + [R] return v def precision_cap(self): r""" Returns the number of moments of each element of this space. EXAMPLES:: sage: D = Distributions(2, 5) sage: M = PSModularSymbols(Gamma1(13), coefficients=D) sage: M.precision_cap() 20 sage: D = Distributions(3, 7, prec_cap=10) sage: M = PSModularSymbols(Gamma0(7), coefficients=D) sage: M.precision_cap() 10 """ ### WARNING -- IF YOU ARE WORKING IN SYM^K(Q^2) THIS WILL JUST RETURN K-1. NOT GOOD return self.coefficient_module()._prec_cap def weight(self): r""" Returns the weight of this space. .. WARNING:: We emphasize that in the Pollack-Stevens notation, this is the usual weight minus 2, so a classical weight 2 modular form corresponds to a modular symbol of "weight 0". EXAMPLES:: sage: D = Symk(5) sage: M = PSModularSymbols(Gamma1(7), coefficients=D) sage: M.weight() 5 """ return self.coefficient_module()._k def prime(self): r""" Returns the prime of this space. EXAMPLES: sage: D = Distributions(2, 11) sage: M = PSModularSymbols(Gamma(2), coefficients=D) sage: M.prime() 11 """ return self.coefficient_module()._p def _p_stabilize_parent_space(self, p, new_base_ring): r""" Returns the space of Pollack-Stevens modular symbols of level ``p * N``, with changed base ring. This is used internally when constructing the p-stabilization of a modular symbol. INPUT: - ``p`` -- prime number - ``new_base_ring`` -- the base ring of the result OUTPUT: The space of modular symbols of level ``p * N``, where N is the level of this space. EXAMPLES:: sage: D = Distributions(2, 7); M = PSModularSymbols(Gamma(13), coefficients=D) sage: M._p_stabilize_parent_space(7, M.base_ring()) Space of overconvergent modular symbols for Congruence Subgroup Gamma(91) with sign 0 and values in Space of 7-adic distributions with k=2 action and precision cap 20 sage: D = Distributions(4, 17); M = PSModularSymbols(Gamma1(3), coefficients=D) sage: M._p_stabilize_parent_space(17, Qp(17)) Space of overconvergent modular symbols for Congruence Subgroup Gamma1(51) with sign 0 and values in Space of 17-adic distributions with k=4 action and precision cap 20 """ N = self.level() if N % p == 0: raise ValueError("the level isn't prime to p") from sage.modular.arithgroup.all import Gamma, is_Gamma, Gamma0, is_Gamma0, Gamma1, is_Gamma1 G = self.group() if is_Gamma0(G): G = Gamma0(N*p) elif is_Gamma1(G): G = Gamma1(N*p) elif is_Gamma(G): G = Gamma(N*p) else: raise NotImplementedError return PSModularSymbols(G, coefficients=self.coefficient_module().change_ring(new_base_ring), sign=self.sign()) def _specialize_parent_space(self, new_base_ring): r""" Internal function that is used by the specialize method on elements. It returns a space with same parameters as this one, but over ``new_base_ring``. INPUT: - ``new_base_ring`` -- a ring OUTPUT: A space of modular symbols to which our space specializes. EXAMPLES:: sage: D = Distributions(7, 5); M = PSModularSymbols(Gamma0(2), coefficients=D); M Space of overconvergent modular symbols for Congruence Subgroup Gamma0(2) with sign 0 and values in Space of 5-adic distributions with k=7 action and precision cap 20 sage: M._specialize_parent_space(QQ) Space of modular symbols for Congruence Subgroup Gamma0(2) with sign 0 and values in Sym^7 Q^2 sage: M.base_ring() 5-adic Ring with capped absolute precision 20 sage: M._specialize_parent_space(QQ).base_ring() Rational Field """ return PSModularSymbols(self.group(), coefficients=self.coefficient_module().specialize(new_base_ring), sign=self.sign()) def _lift_parent_space(self, p, M, new_base_ring): r""" Used internally to lift a space of modular symbols to space of overconvergent modular symbols. INPUT: - ``p`` -- prime - ``M`` -- precision cap - ``new_base_ring`` -- ring OUTPUT: A space of distribution valued modular symbols. EXAMPLES:: sage: D = Distributions(4, 17, 2); M = PSModularSymbols(Gamma1(3), coefficients=D) sage: D.is_symk() False sage: M._lift_parent_space(17, 10, Qp(17)) Traceback (most recent call last): ... TypeError: Coefficient module must be a Symk sage: PSModularSymbols(Gamma1(3), weight=3)._lift_parent_space(17,10,Qp(17)) Space of overconvergent modular symbols for Congruence Subgroup Gamma1(3) with sign 0 and values in Space of 17-adic distributions with k=1 action and precision cap 10 """ if self.coefficient_module().is_symk(): return PSModularSymbols(self.group(), coefficients=self.coefficient_module().lift(p, M, new_base_ring), sign=self.sign()) else: raise TypeError("Coefficient module must be a Symk") def change_ring(self, new_base_ring): r""" Changes the base ring of this space to ``new_base_ring``. INPUT: - ``new_base_ring`` -- a ring OUTPUT: A space of modular symbols over the specified base. EXAMPLES:: sage: from sage.modular.pollack_stevens.distributions import Symk sage: D = Symk(4) sage: M = PSModularSymbols(Gamma(6), coefficients=D); M Space of modular symbols for Congruence Subgroup Gamma(6) with sign 0 and values in Sym^4 Q^2 sage: M.change_ring(Qp(5,8)) Space of modular symbols for Congruence Subgroup Gamma(6) with sign 0 and values in Sym^4 Q_5^2 """ return PSModularSymbols(self.group(), coefficients=self.coefficient_module().change_ring(new_base_ring), sign=self.sign()) def _an_element_(self): r""" Returns the cusps associated to an element of a congruence subgroup. OUTPUT: An element of the modular symbol space. Returns a "typical" element of this space; in this case the constant map sending every element to an element of the coefficient module. EXAMPLES:: sage: D = Symk(4) sage: M = PSModularSymbols(Gamma(6), coefficients=D) sage: x = M.an_element(); x # indirect doctest Modular symbol with values in Sym^4 Q^2 sage: x.values() [(0, 1, 2, 3, 4), (0, 1, 2, 3, 4), (0, 1, 2, 3, 4)] sage: D = Symk(2, Qp(11)); M = PSModularSymbols(Gamma0(2), coefficients=D) sage: x = M.an_element(); x.values() [(0, 1 + O(11^20), 2 + O(11^20)), (0, 1 + O(11^20), 2 + O(11^20))] sage: x in M True """ return self(self.coefficient_module().an_element())
class ModularSymbolSpace_generic(Module): """ This is the parent class for the generic category of modular symbol spaces. A class for spaces of modular symbols that use Glenn Stevens' conventions. There are two main differences between the modular symbols in this directory and the ones in sage.modular.modsym. - There is a shift in the weight: weight `k=0` here corresponds to weight `k=2` there. - There is a duality: these modular symbols are functions from `Div^0(P^1(\QQ))`, the others are formal linear combinations of such elements. INPUT: - ``V`` -- the coefficient module, which should have a right action of `M_2(\ZZ)` - ``domain`` -- a set or None, giving the domain """ def __init__(self, group, coefficients, sign=0): """ INPUT: - ``group`` -- congruence subgroup - ``coefficients`` -- a coefficient module - ``sign`` -- (default: 0); 0, -1, 1 EXAMPLES:: sage: D = Distributions(2, 11); M = PSModularSymbols(Gamma0(2), coefficients=D) sage: type(M) <class 'sage.modular.pollack_stevens.space.PSModularSymbolSpace_with_category'> sage: M.sign() 0 sage: M = PSModularSymbols(Gamma0(2), coefficients=D, sign=-1); M.sign() -1 sage: M = PSModularSymbols(Gamma0(2), coefficients=D, sign=1); M.sign() 1 """ #NEW R = coefficients.base_ring() Parent.__init__(self, base = R, category = ModularSymbolSpaces(R)) #NEW if sign not in [0,-1,1]: # sign must be be 0, -1 or 1 raise ValueError, "sign must be 0, -1, or 1" self._group = group self._coefficients = coefficients if coefficients.is_symk(): self.Element = SymkModSymElement else: self.Element = OverconvergentModSymElement self._sign = sign # should distingish between Gamma0 and Gamma1... self._source = ManinRelations(group.level()) # We have to include the first action so that scaling by Z doesn't try to pass through matrices actions = [PSModSymAction(ZZ, self), PSModSymAction(M2ZSpace, self)] self._populate_coercion_lists_(action_list=actions) def _repr_(self): r""" Returns print representation. EXAMPLES:: sage: D = Distributions(2, 11); M = PSModularSymbols(Gamma0(2), coefficients=D); M._repr_() 'Space of overconvergent modular symbols for Congruence Subgroup Gamma0(2) with sign 0 and values in Space of 11-adic distributions with k=2 action and precision cap 20' """ if self.coefficient_module().is_symk(): s = "Space of modular symbols for " else: s = "Space of overconvergent modular symbols for " s += "%s with sign %s and values in %s"%(self.group(), self.sign(), self.coefficient_module()) return s def source(self): """ Return object that represents the domain of the modular symbol elements. OUTPUT: - object of type fund_domain.PSModularSymbolsDomain EXAMPLES:: sage: D = Distributions(2, 11); M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.source() Manin Relations of level 2 """ return self._source def coefficient_module(self): r""" Returns the coefficient module of self. OUTPUT: - module EXAMPLES:: sage: D = Distributions(2, 11); M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.coefficient_module() Space of 11-adic distributions with k=2 action and precision cap 20 sage: M.coefficient_module() == D True sage: M.coefficient_module() is D True """ return self._coefficients def group(self): r""" Returns the congruence subgroup of self. EXAMPLES:: sage: D = Distributions(2, 5) sage: G = Gamma0(23) sage: M = PSModularSymbols(G, coefficients=D) sage: M.group() Congruence Subgroup Gamma0(23) sage: D = Symk(4) sage: G = Gamma1(11) sage: M = PSModularSymbols(G, coefficients=D) sage: M.group() Congruence Subgroup Gamma1(11) """ return self._group def sign(self): r""" Returns the sign of self. EXAMPLES:: sage: D = Distributions(3, 17) sage: M = PSModularSymbols(Gamma(5), coefficients=D) sage: M.sign() 0 sage: D = Symk(4) sage: M = PSModularSymbols(Gamma1(8), coefficients=D, sign=-1) sage: M.sign() -1 """ return self._sign def ngens(self): r""" Returns the number of generators defining self. EXAMPLES:: sage: D = Distributions(4, 29) sage: M = PSModularSymbols(Gamma1(12), coefficients=D) sage: M.ngens() 5 sage: D = Symk(2) sage: M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.ngens() 2 """ return len(self._source.indices()) def ncoset_reps(self): r""" Returns the number of coset representatives defining the full_data of self. OUTPUT: - The number of coset representatives stored in the manin relations. (Just the size of P^1(Z/NZ)) EXAMPLES:: sage: D = Symk(2) sage: M = PSModularSymbols(Gamma0(2), coefficients=D) sage: M.ncoset_reps() 3 """ return len(self._source.reps()) def level(self): r""" Returns the level `N`, where self is of level `Gamma_0(N)`. OUTPUT: - The level `N`, where self is of level `Gamma_0(N)` EXAMPLES:: sage: D = Distributions(7, 11) sage: M = PSModularSymbols(Gamma1(14), coefficients=D) sage: M.level() 14 """ return self._source.level() def _grab_relations(self): r""" This is used internally as part of a consistency check. EXAMPLES:: sage: D = Distributions(4, 3) sage: M = PSModularSymbols(Gamma1(13), coefficients=D) sage: M._grab_relations() [[(1, [1 0] [0 1], 0)], [(-1, [-1 -1] [ 0 -1], 0)], [(1, [1 0] [0 1], 2)], [(1, [1 0] [0 1], 3)], [(1, [1 0] [0 1], 4)], [(1, [1 0] [0 1], 5)]] """ v = [] for r in range(len(self._source.gens())): for j in range(len(self._source.reps())): R = self._source.relations(j) if len(R) == 1 and R[0][2] == self._source.indices(r): if R[0][0] != -1 or R[0][1] != M2ZSpace.one(): v = v + [R] return v def precision_cap(self): r""" Returns the number of moments of each value of self. OUTPUT: - Integer EXAMPLES:: sage: D = Distributions(2, 5) sage: M = PSModularSymbols(Gamma1(13), coefficients=D) sage: M.precision_cap() 20 sage: D = Distributions(3, 7, prec_cap=10) sage: M = PSModularSymbols(Gamma0(7), coefficients=D) sage: M.precision_cap() 10 """ return self.coefficient_module()._prec_cap def weight(self): r""" Returns the weight of self. We emphasize that in the Pollack-Stevens notation, this is the usual weight minus 2, so a classical weight 2 modular form corresponds to a modular symbol of "weight 0". OUTPUT: - Integer EXAMPLES:: sage: D = Symk(5) sage: M = PSModularSymbols(Gamma1(7), coefficients=D) sage: M.weight() 5 """ return self.coefficient_module()._k def prime(self): r""" Returns the prime of self. OUTPUT: - Integer EXAMPLES: sage: D = Distributions(2, 11) sage: M = PSModularSymbols(Gamma(2), coefficients=D) sage: M.prime() 11 """ return self.coefficient_module()._p def _p_stabilize_parent_space(self, p, new_base_ring): r""" Returns the space of Pollack-Stevens modular symbols of level p * N, with changed base ring. This is used internally when constructing the p-stabilization of a modular symbol. INPUT: - ``p`` -- prime number - ``new_base_ring`` -- the base ring of the result OUTPUT: - The space of modular symbols of level p * N, where N is the level of self, with precision M. EXAMPLES:: sage: D = Distributions(2, 7); M = PSModularSymbols(Gamma(13), coefficients=D) sage: M._p_stabilize_parent_space(7, M.base_ring()) Space of overconvergent modular symbols for Congruence Subgroup Gamma(91) with sign 0 and values in Space of 7-adic distributions with k=2 action and precision cap 20 sage: D = Distributions(4, 17); M = PSModularSymbols(Gamma1(3), coefficients=D) sage: M._p_stabilize_parent_space(17, Qp(17)) Space of overconvergent modular symbols for Congruence Subgroup Gamma1(51) with sign 0 and values in Space of 17-adic distributions with k=4 action and precision cap 20 """ N = self.level() if N % p == 0: raise ValueError("the level isn't prime to p") from sage.modular.arithgroup.all import Gamma, is_Gamma, Gamma0, is_Gamma0, Gamma1, is_Gamma1 G = self.group() if is_Gamma0(G): G = Gamma0(N*p) elif is_Gamma1(G): G = Gamma1(N*p) elif is_Gamma(G): G = Gamma(N*p) else: raise NotImplementedError return PSModularSymbols(G, coefficients=self.coefficient_module().change_ring(new_base_ring), sign=self.sign()) def _specialize_parent_space(self, new_base_ring): """ Internal function that is used by the specialize method on elements. It returns a space with same parameters as this one, but over new_base_ring. EXAMPLES:: sage: D = Distributions(7, 5); M = PSModularSymbols(Gamma0(2), coefficients=D); M Space of overconvergent modular symbols for Congruence Subgroup Gamma0(2) with sign 0 and values in Space of 5-adic distributions with k=7 action and precision cap 20 sage: M._specialize_parent_space(QQ) Space of modular symbols for Congruence Subgroup Gamma0(2) with sign 0 and values in Sym^7 Q^2 sage: M.base_ring() 5-adic Ring with capped absolute precision 20 sage: M._specialize_parent_space(QQ).base_ring() Rational Field """ return PSModularSymbols(self.group(), coefficients=self.coefficient_module().specialize(new_base_ring), sign=self.sign()) def _lift_parent_space(self, p, M, new_base_ring): """ Used internally when lifting modular symbols. INPUT: - `p` -- prime - `M` -- precision cap - ``new_base_ring`` -- ring EXAMPLES:: sage: D = Distributions(4, 17, 2); M = PSModularSymbols(Gamma1(3), coefficients=D) sage: D.is_symk() False sage: M._lift_parent_space(17, 10, Qp(17)) Traceback (most recent call last): ... TypeError: Coefficient module must be a Symk sage: PSModularSymbols(Gamma1(3), weight=3)._lift_parent_space(17,10,Qp(17)) Space of overconvergent modular symbols for Congruence Subgroup Gamma1(3) with sign 0 and values in Space of 17-adic distributions with k=1 action and precision cap 10 """ if self.coefficient_module().is_symk(): return PSModularSymbols(self.group(), coefficients=self.coefficient_module().lift(p, M, new_base_ring), sign=self.sign()) else: raise TypeError("Coefficient module must be a Symk") def change_ring(self, new_base_ring): """ Changes base ring of self to new_base_ring EXAMPLES:: sage: from sage.modular.pollack_stevens.distributions import Symk sage: D = Symk(4) sage: M = PSModularSymbols(Gamma(6), coefficients=D); M Space of modular symbols for Congruence Subgroup Gamma(6) with sign 0 and values in Sym^4 Q^2 sage: M.change_ring(Qp(5,8)) Space of modular symbols for Congruence Subgroup Gamma(6) with sign 0 and values in Sym^4 Q_5^2 """ return PSModularSymbols(self.group(), coefficients=self.coefficient_module().change_ring(new_base_ring), sign=self.sign()) def _an_element_(self): r""" Returns a "typical" element of self; in this case the constant map sending every element to an element of the coefficient module. EXAMPLES:: sage: D = Symk(4) sage: M = PSModularSymbols(Gamma(6), coefficients=D) sage: x = M.an_element(); x # indirect doctest Modular symbol with values in Sym^4 Q^2 sage: x.values() [(2, 1), (2, 1), (2, 1)] sage: D = Symk(2, Qp(11)); M = PSModularSymbols(Gamma0(2), coefficients=D) sage: x = M.an_element(); x.values() [(2 + O(11^20), 1 + O(11^20)), (2 + O(11^20), 1 + O(11^20))] sage: x in M True """ return self(self.coefficient_module().an_element())