def _dim_eisenstein(self): """ Return the dimension of the Eisenstein subspace of this modular symbols space, computed using a dimension formula. EXAMPLES:: sage: m = ModularForms(GammaH(13,[4]), 2); m Modular Forms space of dimension 3 for Congruence Subgroup Gamma_H(13) with H generated by [4] of weight 2 over Rational Field sage: m._dim_eisenstein() 3 sage: m = ModularForms(DirichletGroup(13).0,7); m Modular Forms space of dimension 8, character [zeta12] and weight 7 over Cyclotomic Field of order 12 and degree 4 sage: m._dim_eisenstein() 2 sage: m._dim_cuspidal() 6 Test that :trac:`24030` is fixed:: sage: ModularForms(GammaH(40, [21]), 1).dimension() # indirect doctest 16 """ if arithgroup.is_Gamma1(self.group()) and self.character() is not None: return self.group().dimension_eis(self.weight(), self.character()) else: return self.group().dimension_eis(self.weight())
def _dim_cuspidal(self): r""" Return the dimension of the cuspidal subspace of this ambient modular forms space. For weights `k \ge 2` this is computed using a dimension formula. For weight 1, it will trigger a computation of a basis of `q`-expansions using Schaeffer's algorithm, unless this space is a space of Eisenstein forms only, in which case we just return 0. EXAMPLES:: sage: m = ModularForms(GammaH(11,[3]), 2); m Modular Forms space of dimension 2 for Congruence Subgroup Gamma_H(11) with H generated by [3] of weight 2 over Rational Field sage: m._dim_cuspidal() 1 sage: m = ModularForms(DirichletGroup(389,CyclotomicField(4)).0,3); m._dim_cuspidal() 64 sage: m = ModularForms(GammaH(31, [7]), 1) sage: m._dim_cuspidal() 1 sage: m = ModularForms(GammaH(31, [7]), 1, eis_only=True) sage: m._dim_cuspidal() 0 """ if self._eis_only: return 0 if arithgroup.is_Gamma1(self.group()) and self.character() is not None: return self.group().dimension_cusp_forms(self.weight(), self.character()) else: return self.group().dimension_cusp_forms(self.weight())
def newform_decomposition(self, names=None): """ Return the newforms of the simple subvarieties in the decomposition of self as a product of simple subvarieties, up to isogeny. OUTPUT: - an array of newforms EXAMPLES:: sage: J0(81).newform_decomposition('a') [q - 2*q^4 + O(q^6), q - 2*q^4 + O(q^6), q + a0*q^2 + q^4 - a0*q^5 + O(q^6)] sage: J1(19).newform_decomposition('a') [q - 2*q^3 - 2*q^4 + 3*q^5 + O(q^6), q + a1*q^2 + (-1/9*a1^5 - 1/3*a1^4 - 1/3*a1^3 + 1/3*a1^2 - a1 - 1)*q^3 + (4/9*a1^5 + 2*a1^4 + 14/3*a1^3 + 17/3*a1^2 + 6*a1 + 2)*q^4 + (-2/3*a1^5 - 11/3*a1^4 - 10*a1^3 - 14*a1^2 - 15*a1 - 9)*q^5 + O(q^6)] """ if self.dimension() == 0: return [] G = self.group() if not (is_Gamma0(G) or is_Gamma1(G)): return [S.newform(names=names) for S in self.decomposition()] Gtype = G.parent() N = G.level() preans = [Newforms(Gtype(d), names=names) * len(Integer(N/d).divisors()) for d in N.divisors()] ans = [newform for l in preans for newform in l] return ans
def _dim_eisenstein(self): """ Return the dimension of the Eisenstein subspace of this modular symbols space, computed using a dimension formula. EXAMPLES:: sage: m = ModularForms(GammaH(13,[4]), 2); m Modular Forms space of dimension 3 for Congruence Subgroup Gamma_H(13) with H generated by [4] of weight 2 over Rational Field sage: m._dim_eisenstein() 3 """ try: return self.__the_dim_eisenstein except AttributeError: if self.weight() == 1: self.__the_dim_eisenstein = len(self.eisenstein_params()) else: if arithgroup.is_Gamma1( self.group()) and self.character() is not None: self.__the_dim_eisenstein = self.group().dimension_eis( self.weight(), self.character()) else: self.__the_dim_eisenstein = self.group().dimension_eis( self.weight()) return self.__the_dim_eisenstein
def eisenstein_params(self): """ Return parameters that define all Eisenstein series in self. OUTPUT: an immutable Sequence EXAMPLES:: sage: m = ModularForms(Gamma0(22), 2) sage: v = m.eisenstein_params(); v [(Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 2), (Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 11), (Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 22)] sage: type(v) <class 'sage.structure.sequence.Sequence_generic'> """ try: return self.__eisenstein_params except AttributeError: eps = self.character() if eps == None: if arithgroup.is_Gamma1(self.group()): eps = self.level() else: raise NotImplementedError params = eis_series.compute_eisenstein_params(eps, self.weight()) self.__eisenstein_params = Sequence(params, immutable=True) return self.__eisenstein_params
def newform_decomposition(self, names=None): """ Return the newforms of the simple subvarieties in the decomposition of self as a product of simple subvarieties, up to isogeny. OUTPUT: - an array of newforms EXAMPLES:: sage: J0(81).newform_decomposition('a') [q - 2*q^4 + O(q^6), q - 2*q^4 + O(q^6), q + a0*q^2 + q^4 - a0*q^5 + O(q^6)] sage: J1(19).newform_decomposition('a') [q - 2*q^3 - 2*q^4 + 3*q^5 + O(q^6), q + a1*q^2 + (-1/9*a1^5 - 1/3*a1^4 - 1/3*a1^3 + 1/3*a1^2 - a1 - 1)*q^3 + (4/9*a1^5 + 2*a1^4 + 14/3*a1^3 + 17/3*a1^2 + 6*a1 + 2)*q^4 + (-2/3*a1^5 - 11/3*a1^4 - 10*a1^3 - 14*a1^2 - 15*a1 - 9)*q^5 + O(q^6)] """ if self.dimension() == 0: return [] G = self.group() if not (is_Gamma0(G) or is_Gamma1(G)): return [S.newform(names=names) for S in self.decomposition()] Gtype = G.parent() N = G.level() preans = [ Newforms(Gtype(d), names=names) * len((N // d).divisors()) for d in N.divisors() ] return [newform for l in preans for newform in l]
def label(self) -> str: """ Return canonical label that defines this newform modular abelian variety. OUTPUT: string EXAMPLES:: sage: A = AbelianVariety('43b') sage: A.label() '43b' """ G = self.__f.group() if is_Gamma0(G): group = '' elif is_Gamma1(G): group = 'G1' elif is_GammaH(G): group = 'GH[' + ','.join(str(z) for z in G._generators_for_H()) + ']' return '%s%s%s' % (self.level(), cremona_letter_code(self.factor_number()), group)
def eisenstein_params(self): """ Return parameters that define all Eisenstein series in self. OUTPUT: an immutable Sequence EXAMPLES:: sage: m = ModularForms(Gamma0(22), 2) sage: v = m.eisenstein_params(); v [(Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 2), (Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 11), (Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 22)] sage: type(v) <class 'sage.structure.sequence.Sequence_generic'> """ try: return self.__eisenstein_params except AttributeError: eps = self.character() if eps is None: if arithgroup.is_Gamma1(self.group()): eps = self.level() else: raise NotImplementedError params = eis_series.compute_eisenstein_params(eps, self.weight()) self.__eisenstein_params = Sequence(params, immutable=True) return self.__eisenstein_params
def _p_stabilize_parent_space(self, p, new_base_ring): r""" Return 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 = OverconvergentDistributions(2, 7) sage: M = PollackStevensModularSymbols(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 = OverconvergentDistributions(4, 17) sage: M = PollackStevensModularSymbols(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 is not 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 PollackStevensModularSymbols( G, coefficients=self.coefficient_module().change_ring(new_base_ring), sign=self.sign())
def _p_stabilize_parent_space(self, p, new_base_ring): r""" Return 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 = OverconvergentDistributions(2, 7) sage: M = PollackStevensModularSymbols(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 = OverconvergentDistributions(4, 17) sage: M = PollackStevensModularSymbols(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 is not 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 PollackStevensModularSymbols(G, coefficients=self.coefficient_module().change_ring(new_base_ring), sign=self.sign())
def _dim_new_cuspidal(self): """ Return the dimension of the new cuspidal subspace, computed using dimension formulas. EXAMPLES:: sage: m = ModularForms(GammaH(11,[2]), 2); m._dim_new_cuspidal() 1 """ try: return self.__the_dim_new_cuspidal except AttributeError: if arithgroup.is_Gamma1(self.group()) and self.character() is not None: self.__the_dim_new_cuspidal = self.group().dimension_new_cusp_forms(self.weight(), self.character()) else: self.__the_dim_new_cuspidal = self.group().dimension_new_cusp_forms(self.weight()) return self.__the_dim_new_cuspidal
def _dim_cuspidal(self): """ Return the dimension of the cuspidal subspace of this ambient modular forms space, computed using a dimension formula. EXAMPLES:: sage: m = ModularForms(GammaH(11,[4]), 2); m Modular Forms space of dimension 2 for Congruence Subgroup Gamma_H(11) with H generated by [4] of weight 2 over Rational Field sage: m._dim_cuspidal() 1 """ try: return self.__the_dim_cuspidal except AttributeError: if arithgroup.is_Gamma1(self.group()) and self.character() is not None: self.__the_dim_cuspidal = self.group().dimension_cusp_forms(self.weight(), self.character()) else: self.__the_dim_cuspidal = self.group().dimension_cusp_forms(self.weight()) return self.__the_dim_cuspidal
def _dim_new_cuspidal(self): """ Return the dimension of the new cuspidal subspace, computed using dimension formulas. EXAMPLES:: sage: m = ModularForms(GammaH(11,[2]), 2); m._dim_new_cuspidal() 1 sage: m = ModularForms(DirichletGroup(33).0,7); m Modular Forms space of dimension 26, character [-1, 1] and weight 7 over Rational Field sage: m._dim_new_cuspidal() 20 sage: m._dim_cuspidal() 22 """ if arithgroup.is_Gamma1(self.group()) and self.character() is not None: return self.group().dimension_new_cusp_forms(self.weight(), self.character()) else: return self.group().dimension_new_cusp_forms(self.weight())
def label(self): """ Return canonical label that defines this newform modular abelian variety. OUTPUT: string EXAMPLES:: sage: A = AbelianVariety('43b') sage: A.label() '43b' """ G = self.__f.group() if is_Gamma0(G): group = '' elif is_Gamma1(G): group = 'G1' elif is_GammaH(G): group = 'GH[' + ','.join([str(z) for z in G._generators_for_H()]) + ']' return '%s%s%s'%(self.level(), cremona_letter_code(self.factor_number()), group)
def _dim_cuspidal(self): """ Return the dimension of the cuspidal subspace of this ambient modular forms space, computed using a dimension formula. EXAMPLES:: sage: m = ModularForms(GammaH(11,[3]), 2); m Modular Forms space of dimension 2 for Congruence Subgroup Gamma_H(11) with H generated by [3] of weight 2 over Rational Field sage: m._dim_cuspidal() 1 sage: m = ModularForms(DirichletGroup(389,CyclotomicField(4)).0,3); m._dim_cuspidal() 64 """ if self._eis_only: return 0 if arithgroup.is_Gamma1(self.group()) and self.character() is not None: if self.weight() != 1: return self.group().dimension_cusp_forms(self.weight(), self.character()) else: return weight1.dimension_cusp_forms(self.character()) else: return self.group().dimension_cusp_forms(self.weight())
def _dim_eisenstein(self): """ Return the dimension of the Eisenstein subspace of this modular symbols space, computed using a dimension formula. EXAMPLES:: sage: m = ModularForms(GammaH(13,[4]), 2); m Modular Forms space of dimension 3 for Congruence Subgroup Gamma_H(13) with H generated by [4] of weight 2 over Rational Field sage: m._dim_eisenstein() 3 """ try: return self.__the_dim_eisenstein except AttributeError: if self.weight() == 1: self.__the_dim_eisenstein = len(self.eisenstein_params()) else: if arithgroup.is_Gamma1(self.group()) and self.character() is not None: self.__the_dim_eisenstein = self.group().dimension_eis(self.weight(), self.character()) else: self.__the_dim_eisenstein = self.group().dimension_eis(self.weight()) return self.__the_dim_eisenstein
def _dim_cuspidal(self): """ Return the dimension of the cuspidal subspace of this ambient modular forms space, computed using a dimension formula. EXAMPLES:: sage: m = ModularForms(GammaH(11,[3]), 2); m Modular Forms space of dimension 2 for Congruence Subgroup Gamma_H(11) with H generated by [3] of weight 2 over Rational Field sage: m._dim_cuspidal() 1 sage: m = ModularForms(DirichletGroup(389,CyclotomicField(4)).0,3); m._dim_cuspidal() 64 """ if self._eis_only: return 0 if arithgroup.is_Gamma1(self.group()) and self.character() is not None: if self.weight() != 1: return self.group().dimension_cusp_forms( self.weight(), self.character()) else: return weight1.dimension_cusp_forms(self.character()) else: return self.group().dimension_cusp_forms(self.weight())
def ModularSymbols(group=1, weight=2, sign=0, base_ring=None, use_cache=True, custom_init=None): r""" Create an ambient space of modular symbols. INPUT: - ``group`` - A congruence subgroup or a Dirichlet character eps. - ``weight`` - int, the weight, which must be >= 2. - ``sign`` - int, The sign of the involution on modular symbols induced by complex conjugation. The default is 0, which means "no sign", i.e., take the whole space. - ``base_ring`` - the base ring. Defaults to `\QQ` if no character is given, or to the minimal extension of `\QQ` containing the values of the character. - ``custom_init`` - a function that is called with self as input before any computations are done using self; this could be used to set a custom modular symbols presentation. If self is already in the cache and use_cache=True, then this function is not called. EXAMPLES: First we create some spaces with trivial character:: sage: ModularSymbols(Gamma0(11),2).dimension() 3 sage: ModularSymbols(Gamma0(1),12).dimension() 3 If we give an integer N for the congruence subgroup, it defaults to `\Gamma_0(N)`:: sage: ModularSymbols(1,12,-1).dimension() 1 sage: ModularSymbols(11,4, sign=1) Modular Symbols space of dimension 4 for Gamma_0(11) of weight 4 with sign 1 over Rational Field We create some spaces for `\Gamma_1(N)`. :: sage: ModularSymbols(Gamma1(13),2) Modular Symbols space of dimension 15 for Gamma_1(13) of weight 2 with sign 0 and over Rational Field sage: ModularSymbols(Gamma1(13),2, sign=1).dimension() 13 sage: ModularSymbols(Gamma1(13),2, sign=-1).dimension() 2 sage: [ModularSymbols(Gamma1(7),k).dimension() for k in [2,3,4,5]] [5, 8, 12, 16] sage: ModularSymbols(Gamma1(5),11).dimension() 20 We create a space for `\Gamma_H(N)`:: sage: G = GammaH(15,[4,13]) sage: M = ModularSymbols(G,2) sage: M.decomposition() [ Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Congruence Subgroup Gamma_H(15) with H generated by [4, 7] of weight 2 with sign 0 and over Rational Field, Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 5 for Congruence Subgroup Gamma_H(15) with H generated by [4, 7] of weight 2 with sign 0 and over Rational Field ] We create a space with character:: sage: e = (DirichletGroup(13).0)^2 sage: e.order() 6 sage: M = ModularSymbols(e, 2); M Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta6], sign 0, over Cyclotomic Field of order 6 and degree 2 sage: f = M.T(2).charpoly('x'); f x^4 + (-zeta6 - 1)*x^3 - 8*zeta6*x^2 + (10*zeta6 - 5)*x + 21*zeta6 - 21 sage: f.factor() (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)^2 We create a space with character over a larger base ring than the values of the character:: sage: ModularSymbols(e, 2, base_ring = CyclotomicField(24)) Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta24^4], sign 0, over Cyclotomic Field of order 24 and degree 8 More examples of spaces with character:: sage: e = DirichletGroup(5, RationalField()).gen(); e Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1 sage: m = ModularSymbols(e, 2); m Modular Symbols space of dimension 2 and level 5, weight 2, character [-1], sign 0, over Rational Field :: sage: m.T(2).charpoly('x') x^2 - 1 sage: m = ModularSymbols(e, 6); m.dimension() 6 sage: m.T(2).charpoly('x') x^6 - 873*x^4 - 82632*x^2 - 1860496 We create a space of modular symbols with nontrivial character in characteristic 2. :: sage: G = DirichletGroup(13,GF(4,'a')); G Group of Dirichlet characters modulo 13 with values in Finite Field in a of size 2^2 sage: e = G.list()[2]; e Dirichlet character modulo 13 of conductor 13 mapping 2 |--> a + 1 sage: M = ModularSymbols(e,4); M Modular Symbols space of dimension 8 and level 13, weight 4, character [a + 1], sign 0, over Finite Field in a of size 2^2 sage: M.basis() ([X*Y,(1,0)], [X*Y,(1,5)], [X*Y,(1,10)], [X*Y,(1,11)], [X^2,(0,1)], [X^2,(1,10)], [X^2,(1,11)], [X^2,(1,12)]) sage: M.T(2).matrix() [ 0 0 0 0 0 0 1 1] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 a + 1 1 a] [ 0 0 0 0 0 1 a + 1 a] [ 0 0 0 0 a + 1 0 1 1] [ 0 0 0 0 0 a 1 a] [ 0 0 0 0 0 0 a + 1 a] [ 0 0 0 0 0 0 1 0] We illustrate the custom_init function, which can be used to make arbitrary changes to the modular symbols object before its presentation is computed:: sage: ModularSymbols_clear_cache() sage: def custom_init(M): ....: M.customize='hi' sage: M = ModularSymbols(1,12, custom_init=custom_init) sage: M.customize 'hi' We illustrate the relation between custom_init and use_cache:: sage: def custom_init(M): ....: M.customize='hi2' sage: M = ModularSymbols(1,12, custom_init=custom_init) sage: M.customize 'hi' sage: M = ModularSymbols(1,12, custom_init=custom_init, use_cache=False) sage: M.customize 'hi2' TESTS: We test use_cache:: sage: ModularSymbols_clear_cache() sage: M = ModularSymbols(11,use_cache=False) sage: sage.modular.modsym.modsym._cache {} sage: M = ModularSymbols(11,use_cache=True) sage: sage.modular.modsym.modsym._cache {(Congruence Subgroup Gamma0(11), 2, 0, Rational Field): <weakref at ...; to 'ModularSymbolsAmbient_wt2_g0_with_category' at ...>} sage: M is ModularSymbols(11,use_cache=True) True sage: M is ModularSymbols(11,use_cache=False) False """ from . import ambient key = canonical_parameters(group, weight, sign, base_ring) if use_cache and key in _cache: M = _cache[key]() if M is not None: return M (group, weight, sign, base_ring) = key M = None if arithgroup.is_Gamma0(group): if weight == 2: M = ambient.ModularSymbolsAmbient_wt2_g0(group.level(), sign, base_ring, custom_init=custom_init) else: M = ambient.ModularSymbolsAmbient_wtk_g0(group.level(), weight, sign, base_ring, custom_init=custom_init) elif arithgroup.is_Gamma1(group): M = ambient.ModularSymbolsAmbient_wtk_g1(group.level(), weight, sign, base_ring, custom_init=custom_init) elif arithgroup.is_GammaH(group): M = ambient.ModularSymbolsAmbient_wtk_gamma_h(group, weight, sign, base_ring, custom_init=custom_init) elif isinstance(group, tuple): eps = group[0] M = ambient.ModularSymbolsAmbient_wtk_eps(eps, weight, sign, base_ring, custom_init=custom_init) if M is None: raise NotImplementedError( "computation of requested space of modular symbols not defined or implemented" ) if use_cache: _cache[key] = weakref.ref(M) return M
def ModularSymbols(group = 1, weight = 2, sign = 0, base_ring = None, use_cache = True, custom_init=None): r""" Create an ambient space of modular symbols. INPUT: - ``group`` - A congruence subgroup or a Dirichlet character eps. - ``weight`` - int, the weight, which must be = 2. - ``sign`` - int, The sign of the involution on modular symbols induced by complex conjugation. The default is 0, which means "no sign", i.e., take the whole space. - ``base_ring`` - the base ring. Defaults to `\QQ` if no character is given, or to the minimal extension of `\QQ` containing the values of the character. - ``custom_init`` - a function that is called with self as input before any computations are done using self; this could be used to set a custom modular symbols presentation. If self is already in the cache and use_cache=True, then this function is not called. EXAMPLES: First we create some spaces with trivial character:: sage: ModularSymbols(Gamma0(11),2).dimension() 3 sage: ModularSymbols(Gamma0(1),12).dimension() 3 If we give an integer N for the congruence subgroup, it defaults to `\Gamma_0(N)`:: sage: ModularSymbols(1,12,-1).dimension() 1 sage: ModularSymbols(11,4, sign=1) Modular Symbols space of dimension 4 for Gamma_0(11) of weight 4 with sign 1 over Rational Field We create some spaces for `\Gamma_1(N)`. :: sage: ModularSymbols(Gamma1(13),2) Modular Symbols space of dimension 15 for Gamma_1(13) of weight 2 with sign 0 and over Rational Field sage: ModularSymbols(Gamma1(13),2, sign=1).dimension() 13 sage: ModularSymbols(Gamma1(13),2, sign=-1).dimension() 2 sage: [ModularSymbols(Gamma1(7),k).dimension() for k in [2,3,4,5]] [5, 8, 12, 16] sage: ModularSymbols(Gamma1(5),11).dimension() 20 We create a space for `\Gamma_H(N)`:: sage: G = GammaH(15,[4,13]) sage: M = ModularSymbols(G,2) sage: M.decomposition() [ Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Congruence Subgroup Gamma_H(15) with H generated by [4, 13] of weight 2 with sign 0 and over Rational Field, Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 5 for Congruence Subgroup Gamma_H(15) with H generated by [4, 13] of weight 2 with sign 0 and over Rational Field ] We create a space with character:: sage: e = (DirichletGroup(13).0)^2 sage: e.order() 6 sage: M = ModularSymbols(e, 2); M Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta6], sign 0, over Cyclotomic Field of order 6 and degree 2 sage: f = M.T(2).charpoly('x'); f x^4 + (-zeta6 - 1)*x^3 - 8*zeta6*x^2 + (10*zeta6 - 5)*x + 21*zeta6 - 21 sage: f.factor() (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)^2 We create a space with character over a larger base ring than the values of the character:: sage: ModularSymbols(e, 2, base_ring = CyclotomicField(24)) Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta24^4], sign 0, over Cyclotomic Field of order 24 and degree 8 More examples of spaces with character:: sage: e = DirichletGroup(5, RationalField()).gen(); e Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1 sage: m = ModularSymbols(e, 2); m Modular Symbols space of dimension 2 and level 5, weight 2, character [-1], sign 0, over Rational Field :: sage: m.T(2).charpoly('x') x^2 - 1 sage: m = ModularSymbols(e, 6); m.dimension() 6 sage: m.T(2).charpoly('x') x^6 - 873*x^4 - 82632*x^2 - 1860496 We create a space of modular symbols with nontrivial character in characteristic 2. :: sage: G = DirichletGroup(13,GF(4,'a')); G Group of Dirichlet characters modulo 13 with values in Finite Field in a of size 2^2 sage: e = G.list()[2]; e Dirichlet character modulo 13 of conductor 13 mapping 2 |--> a + 1 sage: M = ModularSymbols(e,4); M Modular Symbols space of dimension 8 and level 13, weight 4, character [a + 1], sign 0, over Finite Field in a of size 2^2 sage: M.basis() ([X*Y,(1,0)], [X*Y,(1,5)], [X*Y,(1,10)], [X*Y,(1,11)], [X^2,(0,1)], [X^2,(1,10)], [X^2,(1,11)], [X^2,(1,12)]) sage: M.T(2).matrix() [ 0 0 0 0 0 0 1 1] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 a + 1 1 a] [ 0 0 0 0 0 1 a + 1 a] [ 0 0 0 0 a + 1 0 1 1] [ 0 0 0 0 0 a 1 a] [ 0 0 0 0 0 0 a + 1 a] [ 0 0 0 0 0 0 1 0] We illustrate the custom_init function, which can be used to make arbitrary changes to the modular symbols object before its presentation is computed:: sage: ModularSymbols_clear_cache() sage: def custom_init(M): ....: M.customize='hi' sage: M = ModularSymbols(1,12, custom_init=custom_init) sage: M.customize 'hi' We illustrate the relation between custom_init and use_cache:: sage: def custom_init(M): ....: M.customize='hi2' sage: M = ModularSymbols(1,12, custom_init=custom_init) sage: M.customize 'hi' sage: M = ModularSymbols(1,12, custom_init=custom_init, use_cache=False) sage: M.customize 'hi2' TESTS: We test use_cache:: sage: ModularSymbols_clear_cache() sage: M = ModularSymbols(11,use_cache=False) sage: sage.modular.modsym.modsym._cache {} sage: M = ModularSymbols(11,use_cache=True) sage: sage.modular.modsym.modsym._cache {(Congruence Subgroup Gamma0(11), 2, 0, Rational Field): <weakref at ...; to 'ModularSymbolsAmbient_wt2_g0_with_category' at ...>} sage: M is ModularSymbols(11,use_cache=True) True sage: M is ModularSymbols(11,use_cache=False) False """ from . import ambient key = canonical_parameters(group, weight, sign, base_ring) if use_cache and key in _cache: M = _cache[key]() if not (M is None): return M (group, weight, sign, base_ring) = key M = None if arithgroup.is_Gamma0(group): if weight == 2: M = ambient.ModularSymbolsAmbient_wt2_g0( group.level(),sign, base_ring, custom_init=custom_init) else: M = ambient.ModularSymbolsAmbient_wtk_g0( group.level(), weight, sign, base_ring, custom_init=custom_init) elif arithgroup.is_Gamma1(group): M = ambient.ModularSymbolsAmbient_wtk_g1(group.level(), weight, sign, base_ring, custom_init=custom_init) elif arithgroup.is_GammaH(group): M = ambient.ModularSymbolsAmbient_wtk_gamma_h(group, weight, sign, base_ring, custom_init=custom_init) elif isinstance(group, tuple): eps = group[0] M = ambient.ModularSymbolsAmbient_wtk_eps(eps, weight, sign, base_ring, custom_init=custom_init) if M is None: raise NotImplementedError("computation of requested space of modular symbols not defined or implemented") if use_cache: _cache[key] = weakref.ref(M) return M
def multiple_of_order_using_frobp(self, maxp=None): """ Return a multiple of the order of this torsion group. In the `Gamma_0` case, the multiple is computed using characteristic polynomials of Hecke operators of odd index not dividing the level. In the `Gamma_1` case, the multiple is computed by expressing the frobenius polynomial in terms of the characteristic polynomial of left multiplication by `a_p` for odd primes p not dividing the level. INPUT: - ``maxp`` - (default: None) If maxp is None (the default), return gcd of best bound computed so far with bound obtained by computing GCD's of orders modulo p until this gcd stabilizes for 3 successive primes. If maxp is given, just use all primes up to and including maxp. EXAMPLES:: sage: J = J0(11) sage: G = J.rational_torsion_subgroup() sage: G.multiple_of_order_using_frobp(11) 5 Increasing maxp may yield a tighter bound. If maxp=None, then Sage will use more primes until the multiple stabilizes for 3 successive primes. :: sage: J = J0(389) sage: G = J.rational_torsion_subgroup(); G Torsion subgroup of Abelian variety J0(389) of dimension 32 sage: G.multiple_of_order_using_frobp() 97 sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,11)] [92645296242160800, 7275, 291] sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,13)] [92645296242160800, 7275, 291, 97] sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,19)] [92645296242160800, 7275, 291, 97, 97, 97] We can compute the multiple of order of the torsion subgroup for Gamma0 and Gamma1 varieties, and their products. :: sage: A = J0(11) * J0(33) sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp() 1000 sage: A = J1(23) sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp() 9406793 sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp(maxp=50) 408991 sage: A = J1(19) * J0(21) sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp() 35064 The next example illustrates calling this function with a larger input and how the result may be cached when maxp is None:: sage: T = J0(43)[1].rational_torsion_subgroup() sage: T.multiple_of_order_using_frobp() 14 sage: T.multiple_of_order_using_frobp(50) 7 sage: T.multiple_of_order_using_frobp() 7 This function is not implemented for general congruence subgroups unless the dimension is zero. :: sage: A = JH(13,[2]); A Abelian variety J0(13) of dimension 0 sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp() 1 sage: A = JH(15, [2]); A Abelian variety JH(15,[2]) of dimension 1 sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp() Traceback (most recent call last): ... NotImplementedError: torsion multiple only implemented for Gamma0 and Gamma1 """ if maxp is None: try: return self.__multiple_of_order_using_frobp except AttributeError: pass A = self.abelian_variety() if A.dimension() == 0: T = ZZ(1) self.__multiple_of_order_using_frobp = T return T if not all((is_Gamma0(G) or is_Gamma1(G) for G in A.groups())): raise NotImplementedError("torsion multiple only implemented for Gamma0 and Gamma1") bnd = ZZ(0) N = A.level() cnt = 0 if maxp is None: X = Primes() else: X = prime_range(maxp+1) for p in X: if (2*N) % p == 0: continue if (len(A.groups()) == 1 and is_Gamma0(A.groups()[0])): f = A.hecke_polynomial(p) b = ZZ(f(p+1)) else: from .constructor import AbelianVariety D = [AbelianVariety(f) for f in A.newform_decomposition('a')] b = 1 for simple in D: G = simple.newform_level()[1] if is_Gamma0(G): f = simple.hecke_polynomial(p) b *= ZZ(f(p+1)) else: f = simple.newform('a') Kf = f.base_ring() eps = f.character() Qe = eps.base_ring() if Kf != QQ: # relativize number fields to compute charpoly of # left multiplication of ap on Kf as a Qe-vector # space. Lf = Kf.relativize(Qe.gen(), 'a') to_Lf = Lf.structure()[1] name = Kf._names[0] ap = to_Lf(f.modular_symbols(1).eigenvalue(p, name)) G_ps = ap.matrix().charpoly() b *= ZZ(Qe(G_ps(1 + to_Lf(eps(p))*p)).norm()) else: ap = f.modular_symbols(1).eigenvalue(p) b *= ZZ(1 + eps(p)*p - ap) if bnd == 0: bnd = b else: bnd_last = bnd bnd = ZZ(gcd(bnd, b)) if bnd == bnd_last: cnt += 1 else: cnt = 0 if maxp is None and cnt >= 2: break # The code below caches the computed bound and # will be used if this function is called # again with maxp equal to None (the default). if maxp is None: # maxp is None but self.__multiple_of_order_using_frobp is # not set, since otherwise we would have immediately # returned at the top of this function self.__multiple_of_order_using_frobp = bnd else: # maxp is given -- record new info we get as # a gcd... try: self.__multiple_of_order_using_frobp = \ gcd(self.__multiple_of_order_using_frobp, bnd) except AttributeError: # ... except in the case when # self.__multiple_of_order_using_frobp was never set. In this # case, we just set it as long as the gcd stabilized for 3 in a # row. if cnt >= 2: self.__multiple_of_order_using_frobp = bnd return bnd
def multiple_of_order(self, maxp=None, proof=True): """ Return a multiple of the order. INPUT: - ``proof`` -- a boolean (default: True) The computation of the rational torsion order of J1(p) is conjectural and will only be used if proof=False. See Section 6.2.3 of [CES2003]_. EXAMPLES:: sage: J = J1(11); J Abelian variety J1(11) of dimension 1 sage: J.rational_torsion_subgroup().multiple_of_order() 5 sage: J = J0(17) sage: J.rational_torsion_subgroup().order() 4 This is an example where proof=False leads to a better bound and better performance. :: sage: J = J1(23) sage: J.rational_torsion_subgroup().multiple_of_order() # long time (2s) 9406793 sage: J.rational_torsion_subgroup().multiple_of_order(proof=False) 408991 """ try: if proof: return self._multiple_of_order else: return self._multiple_of_order_proof_false except AttributeError: pass A = self.abelian_variety() N = A.level() if A.dimension() == 0: self._multiple_of_order = ZZ(1) self._multiple_of_order_proof_false = self._multiple_of_order return self._multiple_of_order # return the order of the cuspidal subgroup in the J0(p) case if A.is_J0() and N.is_prime(): self._multiple_of_order = QQ((A.level()-1)/12).numerator() self._multiple_of_order_proof_false = self._multiple_of_order return self._multiple_of_order # The elliptic curve case if A.dimension() == 1: self._multiple_of_order = A.elliptic_curve().torsion_order() self._multiple_of_order_proof_false = self._multiple_of_order return self._multiple_of_order # The conjectural J1(p) case if not proof and A.is_J1() and N.is_prime(): epsilons = [epsilon for epsilon in DirichletGroup(N) if not epsilon.is_trivial() and epsilon.is_even()] bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons] self._multiple_of_order_proof_false = ZZ(N/(2**(N-3))*prod(bernoullis)) return self._multiple_of_order_proof_false # The Gamma0 and Gamma1 case if all((is_Gamma0(G) or is_Gamma1(G) for G in A.groups())): self._multiple_of_order = self.multiple_of_order_using_frobp() return self._multiple_of_order # Unhandled case raise NotImplementedError("No implemented algorithm")
def canonical_parameters(group, level, weight, base_ring): """ Given a group, level, weight, and base_ring as input by the user, return a canonicalized version of them, where level is a Sage integer, group really is a group, weight is a Sage integer, and base_ring a Sage ring. Note that we can't just get the level from the group, because we have the convention that the character for Gamma1(N) is None (which makes good sense). INPUT: - ``group`` - int, long, Sage integer, group, dirichlet character, or - ``level`` - int, long, Sage integer, or group - ``weight`` - coercible to Sage integer - ``base_ring`` - commutative Sage ring OUTPUT: - ``level`` - Sage integer - ``group`` - congruence subgroup - ``weight`` - Sage integer - ``ring`` - commutative Sage ring EXAMPLES:: sage: from sage.modular.modform.constructor import canonical_parameters sage: v = canonical_parameters(5, 5, int(7), ZZ); v (5, Congruence Subgroup Gamma0(5), 7, Integer Ring) sage: type(v[0]), type(v[1]), type(v[2]), type(v[3]) (<type 'sage.rings.integer.Integer'>, <class 'sage.modular.arithgroup.congroup_gamma0.Gamma0_class_with_category'>, <type 'sage.rings.integer.Integer'>, <type 'sage.rings.integer_ring.IntegerRing_class'>) sage: canonical_parameters( 5, 7, 7, ZZ ) Traceback (most recent call last): ... ValueError: group and level do not match. """ weight = rings.Integer(weight) if weight <= 0: raise NotImplementedError, "weight must be at least 1" if isinstance(group, dirichlet.DirichletCharacter): if ( group.level() != rings.Integer(level) ): raise ValueError, "group.level() and level do not match." group = group.minimize_base_ring() level = rings.Integer(level) elif arithgroup.is_CongruenceSubgroup(group): if ( rings.Integer(level) != group.level() ): raise ValueError, "group.level() and level do not match." # normalize the case of SL2Z if arithgroup.is_SL2Z(group) or \ arithgroup.is_Gamma1(group) and group.level() == rings.Integer(1): group = arithgroup.Gamma0(rings.Integer(1)) elif group is None: pass else: try: m = rings.Integer(group) except TypeError: raise TypeError, "group of unknown type." level = rings.Integer(level) if ( m != level ): raise ValueError, "group and level do not match." group = arithgroup.Gamma0(m) if not is_CommutativeRing(base_ring): raise TypeError, "base_ring (=%s) must be a commutative ring"%base_ring # it is *very* important to include the level as part of the data # that defines the key, since dirichlet characters of different # levels can compare equal, but define much different modular # forms spaces. return level, group, weight, base_ring
def ModularForms(group = 1, weight = 2, base_ring = None, use_cache = True, prec = defaults.DEFAULT_PRECISION): r""" Create an ambient space of modular forms. INPUT: - ``group`` - A congruence subgroup or a Dirichlet character eps. - ``weight`` - int, the weight, which must be an integer = 1. - ``base_ring`` - the base ring (ignored if group is a Dirichlet character) Create using the command ModularForms(group, weight, base_ring) where group could be either a congruence subgroup or a Dirichlet character. EXAMPLES: First we create some spaces with trivial character:: sage: ModularForms(Gamma0(11),2).dimension() 2 sage: ModularForms(Gamma0(1),12).dimension() 2 If we give an integer N for the congruence subgroup, it defaults to `\Gamma_0(N)`:: sage: ModularForms(1,12).dimension() 2 sage: ModularForms(11,4) Modular Forms space of dimension 4 for Congruence Subgroup Gamma0(11) of weight 4 over Rational Field We create some spaces for `\Gamma_1(N)`. :: sage: ModularForms(Gamma1(13),2) Modular Forms space of dimension 13 for Congruence Subgroup Gamma1(13) of weight 2 over Rational Field sage: ModularForms(Gamma1(13),2).dimension() 13 sage: [ModularForms(Gamma1(7),k).dimension() for k in [2,3,4,5]] [5, 7, 9, 11] sage: ModularForms(Gamma1(5),11).dimension() 12 We create a space with character:: sage: e = (DirichletGroup(13).0)^2 sage: e.order() 6 sage: M = ModularForms(e, 2); M Modular Forms space of dimension 3, character [zeta6] and weight 2 over Cyclotomic Field of order 6 and degree 2 sage: f = M.T(2).charpoly('x'); f x^3 + (-2*zeta6 - 2)*x^2 - 2*zeta6*x + 14*zeta6 - 7 sage: f.factor() (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1) We can also create spaces corresponding to the groups `\Gamma_H(N)` intermediate between `\Gamma_0(N)` and `\Gamma_1(N)`:: sage: G = GammaH(30, [11]) sage: M = ModularForms(G, 2); M Modular Forms space of dimension 20 for Congruence Subgroup Gamma_H(30) with H generated by [11] of weight 2 over Rational Field sage: M.T(7).charpoly().factor() # long time (7s on sage.math, 2011) (x + 4) * x^2 * (x - 6)^4 * (x + 6)^4 * (x - 8)^7 * (x^2 + 4) More examples of spaces with character:: sage: e = DirichletGroup(5, RationalField()).gen(); e Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1 sage: m = ModularForms(e, 2); m Modular Forms space of dimension 2, character [-1] and weight 2 over Rational Field sage: m == loads(dumps(m)) True sage: m.T(2).charpoly('x') x^2 - 1 sage: m = ModularForms(e, 6); m.dimension() 4 sage: m.T(2).charpoly('x') x^4 - 917*x^2 - 42284 This came up in a subtle bug (trac #5923):: sage: ModularForms(gp(1), gap(12)) Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field This came up in another bug (related to trac #8630):: sage: chi = DirichletGroup(109, CyclotomicField(3)).0 sage: ModularForms(chi, 2, base_ring = CyclotomicField(15)) Modular Forms space of dimension 10, character [zeta3 + 1] and weight 2 over Cyclotomic Field of order 15 and degree 8 We create some weight 1 spaces. The first example works fine, since we can prove purely by Riemann surface theory that there are no weight 1 cusp forms:: sage: M = ModularForms(Gamma1(11), 1); M Modular Forms space of dimension 5 for Congruence Subgroup Gamma1(11) of weight 1 over Rational Field sage: M.basis() [ 1 + 22*q^5 + O(q^6), q + 4*q^5 + O(q^6), q^2 - 4*q^5 + O(q^6), q^3 - 5*q^5 + O(q^6), q^4 - 3*q^5 + O(q^6) ] sage: M.cuspidal_subspace().basis() [ ] sage: M == M.eisenstein_subspace() True This example doesn't work so well, because we can't calculate the cusp forms; but we can still work with the Eisenstein series. sage: M = ModularForms(Gamma1(57), 1); M Modular Forms space of dimension (unknown) for Congruence Subgroup Gamma1(57) of weight 1 over Rational Field sage: M.basis() Traceback (most recent call last): ... NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general sage: M.cuspidal_subspace().basis() Traceback (most recent call last): ... NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general sage: E = M.eisenstein_subspace(); E Eisenstein subspace of dimension 36 of Modular Forms space of dimension (unknown) for Congruence Subgroup Gamma1(57) of weight 1 over Rational Field sage: (E.0 + E.2).q_expansion(40) 1 + q^2 + 1473/2*q^36 - 1101/2*q^37 + q^38 - 373/2*q^39 + O(q^40) """ if isinstance(group, dirichlet.DirichletCharacter): if base_ring is None: base_ring = group.minimize_base_ring().base_ring() if base_ring is None: base_ring = rings.QQ if isinstance(group, dirichlet.DirichletCharacter) \ or arithgroup.is_CongruenceSubgroup(group): level = group.level() else: level = group key = canonical_parameters(group, level, weight, base_ring) if use_cache and _cache.has_key(key): M = _cache[key]() if not (M is None): M.set_precision(prec) return M (level, group, weight, base_ring) = key M = None if arithgroup.is_Gamma0(group): M = ambient_g0.ModularFormsAmbient_g0_Q(group.level(), weight) if base_ring != rings.QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif arithgroup.is_Gamma1(group): M = ambient_g1.ModularFormsAmbient_g1_Q(group.level(), weight) if base_ring != rings.QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif arithgroup.is_GammaH(group): M = ambient_g1.ModularFormsAmbient_gH_Q(group, weight) if base_ring != rings.QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif isinstance(group, dirichlet.DirichletCharacter): eps = group if eps.base_ring().characteristic() != 0: # TODO -- implement this # Need to add a lift_to_char_0 function for characters, # and need to still remember eps. raise NotImplementedError, "currently the character must be over a ring of characteristic 0." eps = eps.minimize_base_ring() if eps.is_trivial(): return ModularForms(eps.modulus(), weight, base_ring, use_cache = use_cache, prec = prec) M = ambient_eps.ModularFormsAmbient_eps(eps, weight) if base_ring != eps.base_ring(): M = M.base_extend(base_ring) # ambient_R.ModularFormsAmbient_R(M, base_ring) if M is None: raise NotImplementedError, \ "computation of requested space of modular forms not defined or implemented" M.set_precision(prec) _cache[key] = weakref.ref(M) return M
def ModularForms(group=1, weight=2, base_ring=None, eis_only=False, use_cache=True, prec=defaults.DEFAULT_PRECISION): r""" Create an ambient space of modular forms. INPUT: - ``group`` - A congruence subgroup or a Dirichlet character eps. - ``weight`` - int, the weight, which must be an integer >= 1. - ``base_ring`` - the base ring (ignored if group is a Dirichlet character) - ``eis_only`` - if True, compute only the Eisenstein part of the space. Only permitted (and only useful) in weight 1, where computing dimensions of cusp form spaces is expensive. Create using the command ModularForms(group, weight, base_ring) where group could be either a congruence subgroup or a Dirichlet character. EXAMPLES: First we create some spaces with trivial character:: sage: ModularForms(Gamma0(11),2).dimension() 2 sage: ModularForms(Gamma0(1),12).dimension() 2 If we give an integer N for the congruence subgroup, it defaults to `\Gamma_0(N)`:: sage: ModularForms(1,12).dimension() 2 sage: ModularForms(11,4) Modular Forms space of dimension 4 for Congruence Subgroup Gamma0(11) of weight 4 over Rational Field We create some spaces for `\Gamma_1(N)`. :: sage: ModularForms(Gamma1(13),2) Modular Forms space of dimension 13 for Congruence Subgroup Gamma1(13) of weight 2 over Rational Field sage: ModularForms(Gamma1(13),2).dimension() 13 sage: [ModularForms(Gamma1(7),k).dimension() for k in [2,3,4,5]] [5, 7, 9, 11] sage: ModularForms(Gamma1(5),11).dimension() 12 We create a space with character:: sage: e = (DirichletGroup(13).0)^2 sage: e.order() 6 sage: M = ModularForms(e, 2); M Modular Forms space of dimension 3, character [zeta6] and weight 2 over Cyclotomic Field of order 6 and degree 2 sage: f = M.T(2).charpoly('x'); f x^3 + (-2*zeta6 - 2)*x^2 - 2*zeta6*x + 14*zeta6 - 7 sage: f.factor() (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1) We can also create spaces corresponding to the groups `\Gamma_H(N)` intermediate between `\Gamma_0(N)` and `\Gamma_1(N)`:: sage: G = GammaH(30, [11]) sage: M = ModularForms(G, 2); M Modular Forms space of dimension 20 for Congruence Subgroup Gamma_H(30) with H generated by [11] of weight 2 over Rational Field sage: M.T(7).charpoly().factor() # long time (7s on sage.math, 2011) (x + 4) * x^2 * (x - 6)^4 * (x + 6)^4 * (x - 8)^7 * (x^2 + 4) More examples of spaces with character:: sage: e = DirichletGroup(5, RationalField()).gen(); e Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1 sage: m = ModularForms(e, 2); m Modular Forms space of dimension 2, character [-1] and weight 2 over Rational Field sage: m == loads(dumps(m)) True sage: m.T(2).charpoly('x') x^2 - 1 sage: m = ModularForms(e, 6); m.dimension() 4 sage: m.T(2).charpoly('x') x^4 - 917*x^2 - 42284 This came up in a subtle bug (:trac:`5923`):: sage: ModularForms(gp(1), gap(12)) Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field This came up in another bug (related to :trac:`8630`):: sage: chi = DirichletGroup(109, CyclotomicField(3)).0 sage: ModularForms(chi, 2, base_ring = CyclotomicField(15)) Modular Forms space of dimension 10, character [zeta3 + 1] and weight 2 over Cyclotomic Field of order 15 and degree 8 We create some weight 1 spaces. Here modular symbol algorithms do not work. In some small examples we can prove using Riemann--Roch that there are no cusp forms anyway, so the entire space is Eisenstein:: sage: M = ModularForms(Gamma1(11), 1); M Modular Forms space of dimension 5 for Congruence Subgroup Gamma1(11) of weight 1 over Rational Field sage: M.basis() [ 1 + 22*q^5 + O(q^6), q + 4*q^5 + O(q^6), q^2 - 4*q^5 + O(q^6), q^3 - 5*q^5 + O(q^6), q^4 - 3*q^5 + O(q^6) ] sage: M.cuspidal_subspace().basis() [ ] sage: M == M.eisenstein_subspace() True When this does not work (which happens as soon as the level is more than about 30), we use the Hecke stability algorithm of George Schaeffer:: sage: M = ModularForms(Gamma1(57), 1); M # long time Modular Forms space of dimension 38 for Congruence Subgroup Gamma1(57) of weight 1 over Rational Field sage: M.cuspidal_submodule().basis() # long time [ q - q^4 + O(q^6), q^3 - q^4 + O(q^6) ] The Eisenstein subspace in weight 1 can be computed quickly, without triggering the expensive computation of the cuspidal part:: sage: E = EisensteinForms(Gamma1(59), 1); E # indirect doctest Eisenstein subspace of dimension 29 of Modular Forms space for Congruence Subgroup Gamma1(59) of weight 1 over Rational Field sage: (E.0 + E.2).q_expansion(40) 1 + q^2 + 196*q^29 - 197*q^30 - q^31 + q^33 + q^34 + q^37 + q^38 - q^39 + O(q^40) """ if isinstance(group, dirichlet.DirichletCharacter): if base_ring is None: base_ring = group.minimize_base_ring().base_ring() if base_ring is None: base_ring = rings.QQ if isinstance(group, dirichlet.DirichletCharacter) \ or arithgroup.is_CongruenceSubgroup(group): level = group.level() else: level = group eis_only = bool(eis_only) key = canonical_parameters(group, level, weight, base_ring) + (eis_only, ) if eis_only and weight != 1: raise ValueError("eis_only parameter only valid in weight 1") if use_cache and key in _cache: M = _cache[key]() if not (M is None): M.set_precision(prec) return M (level, group, weight, base_ring, eis_only) = key M = None if arithgroup.is_Gamma0(group): M = ModularFormsAmbient_g0_Q(group.level(), weight) if base_ring != rings.QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif arithgroup.is_Gamma1(group): M = ModularFormsAmbient_g1_Q(group.level(), weight, eis_only) if base_ring != rings.QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif arithgroup.is_GammaH(group): M = ModularFormsAmbient_gH_Q(group, weight, eis_only) if base_ring != rings.QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif isinstance(group, dirichlet.DirichletCharacter): eps = group if eps.base_ring().characteristic() != 0: # TODO -- implement this # Need to add a lift_to_char_0 function for characters, # and need to still remember eps. raise NotImplementedError( "currently the character must be over a ring of characteristic 0." ) eps = eps.minimize_base_ring() if eps.is_trivial(): return ModularForms(eps.modulus(), weight, base_ring, use_cache=use_cache, prec=prec) M = ModularFormsAmbient_eps(eps, weight, eis_only=eis_only) if base_ring != eps.base_ring(): M = M.base_extend( base_ring) # ambient_R.ModularFormsAmbient_R(M, base_ring) if M is None: raise NotImplementedError( "computation of requested space of modular forms not defined or implemented" ) M.set_precision(prec) _cache[key] = weakref.ref(M) return M