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 __init__(self, map_data, parent, construct=False): ModuleElement.__init__(self, parent) if construct: self._map = map_data else: self._map = ManinMap(parent._coefficients, parent._source, map_data)
class ModularSymbolElement_generic(ModuleElement): def __init__(self, map_data, parent, construct=False): ModuleElement.__init__(self, parent) if construct: self._map = map_data else: self._map = ManinMap(parent._coefficients, parent._source, map_data) def _repr_(self): r""" Returns the print representation. EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E) sage: phi._repr_() 'Modular symbol with values in Sym^0 Q^2' """ return "Modular symbol with values in %s"%(self.parent().coefficient_module()) def dict(self): r""" Returns dictionary on the modular symbol self, where keys are generators and values are the corresponding values of self on generators EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E) sage: phi.dict() {[1 0] [0 1]: -1/5, [ 0 -1] [ 1 3]: 3/2, [-1 -1] [ 3 2]: -1/2} """ D = {} for g in self.parent().source().gens(): D[g] = self._map[g] return D def weight(self): r""" Returns the weight of this Pollack-Stevens modular symbol. This is `k-2`, where `k` is the usual notion of weight for modular forms! EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E) sage: phi.weight() 0 """ return self.parent().weight() def values(self): r""" Returns the values of the symbol self on our chosen generators (generators are listed in self.dict().keys()) EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E) sage: phi.values() [-1/5, 3/2, -1/2] sage: phi.dict().keys() [ [1 0] [ 0 -1] [-1 -1] [0 1], [ 1 3], [ 3 2] ] sage: phi.values() == phi.dict().values() True """ return [self._map[g] for g in self.parent().source().gens()] def _normalize(self): """ Normalizes all of the values of the symbol self EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E) sage: phi._normalize() Modular symbol with values in Sym^0 Q^2 sage: phi._normalize().values() [-1/5, 3/2, -1/2] """ for val in self._map: val.normalize() return self def __cmp__(self, other): """ Checks if self == other EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E) sage: phi == phi True sage: phi == 2*phi False sage: psi = ps_modsym_from_elliptic_curve(EllipticCurve('37a')) sage: psi == phi False """ gens = self.parent().source().gens() for g in gens: c = cmp(self._map[g], other._map[g]) if c: return c return 0 def _add_(self, right): """ Returns self + right EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E); phi.values() [-1/5, 3/2, -1/2] sage: phi + phi Modular symbol with values in Sym^0 Q^2 sage: (phi + phi).values() [-2/5, 3, -1] """ return self.__class__(self._map + right._map, self.parent(), construct=True) def _lmul_(self, right): """ Returns self * right EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E); phi.values() [-1/5, 3/2, -1/2] sage: 2*phi Modular symbol with values in Sym^0 Q^2 sage: (2*phi).values() [-2/5, 3, -1] """ return self.__class__(self._map * right, self.parent(), construct=True) def _rmul_(self, right): """ Returns self * right EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E); phi.values() [-1/5, 3/2, -1/2] sage: phi*2 Modular symbol with values in Sym^0 Q^2 sage: (phi*2).values() [-2/5, 3, -1] """ return self.__class__(self._map * right, self.parent(), construct=True) def _sub_(self, right): """ Returns self - right EXAMPLES:; sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E); phi.values() [-1/5, 3/2, -1/2] sage: phi - phi Modular symbol with values in Sym^0 Q^2 sage: (phi - phi).values() [0, 0, 0] """ return self.__class__(self._map - right._map, self.parent(), construct=True) def _get_prime(self, p=None, alpha = None, allow_none=False): """ Combines a prime specified by the user with the prime from the parent. INPUT: - ``p`` -- an integer or None (default None); if specified needs to match the prime of the parent. - ``alpha`` -- an element or None (default None); if p-adic can contribute a prime. - ``allow_none`` -- boolean (default False); whether to allow no prime to be specified. OUTPUT: - a prime or None. If ``allow_none`` is False then a ValueError will be raised rather than returning None if no prime can be determined. EXAMPLES:: sage: from sage.modular.pollack_stevens.distributions import Distributions, Symk sage: D = Distributions(0, 5, 10); M = PSModularSymbolSpace(Gamma0(2), D) sage: f = M(1); f._get_prime() 5 sage: f._get_prime(5) 5 sage: f._get_prime(7) Traceback (most recent call last): ... ValueError: inconsistent prime sage: f._get_prime(alpha=Qp(5)(1)) 5 sage: D = Symk(0); M = PSModularSymbolSpace(Gamma0(2), D) sage: f = M(1); f._get_prime(allow_none=True) is None True sage: f._get_prime(alpha=Qp(7)(1)) 7 sage: f._get_prime(7,alpha=Qp(7)(1)) 7 sage: f._get_prime() Traceback (most recent call last): ... ValueError: you must specify a prime """ pp = self.parent().prime() ppp = ((alpha is not None) and hasattr(alpha.parent(),'prime') and alpha.parent().prime()) or None p = ZZ(p) or pp or ppp if not p: if not allow_none: raise ValueError("you must specify a prime") elif (pp and p != pp) or (ppp and p != ppp): raise ValueError("inconsistent prime") return p def plus_part(self): r""" Returns the plus part of self -- i.e. self + self | [1,0,0,-1]. Note that we haven't divided by 2. Is this a problem? OUTPUT: - self + self | [1,0,0,-1] EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E); phi.values() [-1/5, 3/2, -1/2] sage: (phi.plus_part()+phi.minus_part()) == 2 * phi True """ return self * minusproj + self def minus_part(self): r""" Returns the minus part of self -- i.e. self - self | [1,0,0,-1] Note that we haven't divided by 2. Is this a problem? OUTPUT: - self - self | [1,0,0,-1] EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E); phi.values() [-1/5, 3/2, -1/2] sage: (phi.plus_part()+phi.minus_part()) == phi * 2 True """ return self - self * minusproj def hecke(self, ell, algorithm="prep"): r""" Returns self | `T_{\ell}` by making use of the precomputations in self.prep_hecke() INPUT: - ``ell`` -- a prime - ``algorithm`` -- a string, either 'prep' (default) or 'naive' OUTPUT: - The image of this element under the hecke operator `T_{\ell}` ALGORITHMS: - If ``algorithm == 'prep'``, precomputes a list of matrices that only depend on the level, then uses them to speed up the action. - If ``algorithm == 'naive'``, just acts by the matrices defining the Hecke operator. That is, it computes sum_a self | [1,a,0,ell] + self | [ell,0,0,1], the last term occurring only if the level is prime to ell. EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E); phi.values() [-1/5, 3/2, -1/2] sage: phi.hecke(2) == phi * E.ap(2) True sage: phi.hecke(3) == phi * E.ap(3) True sage: phi.hecke(5) == phi * E.ap(5) True sage: phi.hecke(101) == phi * E.ap(101) True sage: all([phi.hecke(p, algorithm='naive') == phi * E.ap(p) for p in [2,3,5,101]]) True """ return self.__class__(self._map.hecke(ell, algorithm), self.parent(), construct=True) def valuation(self, p): r""" Returns the valuation of self at `p`. Here the valuation is the minimum of the valuations of the values of self. INPUT: - ``p`` - prime OUTPUT: - The valuation of self at `p` EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E) sage: phi.values() [-1/5, 3/2, -1/2] sage: phi.valuation(2) -1 sage: phi.valuation(3) 0 sage: phi.valuation(5) -1 sage: phi.valuation(7) 0 """ return min([val.valuation(p) for val in self._map]) def diagonal_valuation(self, p): """ Retuns the minimum of the diagonal valuation on the values of self INPUT: - ``p`` -- a positive integral prime EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E) sage: phi.values() [-1/5, 3/2, -1/2] sage: phi.diagonal_valuation(2) -1 sage: phi.diagonal_valuation(3) 0 sage: phi.diagonal_valuation(5) -1 sage: phi.diagonal_valuation(7) 0 """ return min([val.diagonal_valuation(p) for val in self._map]) @cached_method def is_Tq_eigensymbol(self,q,p=None,M=None): r""" Determines if self is an eigenvector for `T_q` modulo `p^M` INPUT: - ``q`` -- prime of the Hecke operator - ``p`` -- prime we are working modulo - ``M`` -- degree of accuracy of approximation OUTPUT: - True/False EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E) sage: phi.values() [-1/5, 3/2, -1/2] sage: phi_ord = phi.p_stabilize(p = 3, ap = E.ap(3), M = 10, ordinary = True) sage: phi_ord.is_Tq_eigensymbol(2,3,10) True sage: phi_ord.is_Tq_eigensymbol(2,3,100) False sage: phi_ord.is_Tq_eigensymbol(2,3,1000) False sage: phi_ord.is_Tq_eigensymbol(3,3,10) True sage: phi_ord.is_Tq_eigensymbol(3,3,100) False """ try: aq = self.Tq_eigenvalue(q, p, M) return True except ValueError: return False # what happens if a cached method raises an error? Is it recomputed each time? @cached_method def Tq_eigenvalue(self, q, p=None, M=None, check=True): r""" Eigenvalue of `T_q` modulo `p^M` INPUT: - ``q`` -- prime of the Hecke operator - ``p`` -- prime we are working modulo - ``M`` -- degree of accuracy of approximation OUTPUT: - Constant `c` such that `self|T_q - c * self` has valuation greater than or equal to `M` (if it exists), otherwise raises ValueError EXAMPLES:: sage: E = EllipticCurve('11a') sage: from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve sage: phi = ps_modsym_from_elliptic_curve(E) sage: phi.values() [-1/5, 3/2, -1/2] sage: phi_ord = phi.p_stabilize(p = 3, ap = E.ap(3), M = 10, ordinary = True) sage: phi_ord.Tq_eigenvalue(2,3,10) + 2 O(3^10) sage: phi_ord.Tq_eigenvalue(3,3,10) 2 + 3^2 + 2*3^3 + 2*3^4 + 2*3^6 + 3^8 + 2*3^9 + O(3^10) sage: phi_ord.Tq_eigenvalue(3,3,100) Traceback (most recent call last): ... ValueError: not a scalar multiple """ qhecke = self.hecke(q) gens = self.parent().source().gens() if p is None: p = self.parent().prime() i = 0 g = gens[i] verbose("Computing eigenvalue") while self._map[g].is_zero(p, M): if not qhecke._map[g].is_zero(p, M): raise ValueError("not a scalar multiple") i += 1 try: g = gens[i] except IndexError: raise ValueError("self is zero") aq = self._map[g].find_scalar(qhecke._map[g], p, M, check) if check: verbose("Checking that this is actually an eigensymbol") if p is None or M is None: for g in gens[1:]: if qhecke._map[g] != aq * self._map[g]: raise ValueError("not a scalar multiple") elif (qhecke - aq * self).valuation(p) < M: raise ValueError("not a scalar multiple") return aq