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 dimension_new_cusp_forms(X, k=2, p=0): """ Return the dimension of the new (or `p`-new) subspace of cusp forms for the character or group `X`. INPUT: - ``X`` -- integer, congruence subgroup or Dirichlet character - ``k`` -- weight (integer) - ``p`` -- 0 or a prime EXAMPLES:: sage: from sage.modular.dims import dimension_new_cusp_forms sage: dimension_new_cusp_forms(100,2) 1 sage: dimension_new_cusp_forms(Gamma0(100),2) 1 sage: dimension_new_cusp_forms(Gamma0(100),4) 5 sage: dimension_new_cusp_forms(Gamma1(100),2) 141 sage: dimension_new_cusp_forms(Gamma1(100),4) 463 sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,2) 2 sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,4) 8 sage: sum(dimension_new_cusp_forms(e,3) for e in DirichletGroup(30)) 12 sage: dimension_new_cusp_forms(Gamma1(30),3) 12 Check that :trac:`12640` is fixed:: sage: dimension_new_cusp_forms(DirichletGroup(1)(1), 12) 1 sage: dimension_new_cusp_forms(DirichletGroup(2)(1), 24) 1 """ if is_GammaH(X): return X.dimension_new_cusp_forms(k, p=p) elif isinstance(X, dirichlet.DirichletCharacter): N = X.modulus() if N <= 2: return Gamma0(N).dimension_new_cusp_forms(k, p=p) else: # Gamma1(N) for N<=2 just returns Gamma0(N), which has no # eps parameter. See trac #12640. return Gamma1(N).dimension_new_cusp_forms(k, eps=X, p=p) elif isinstance(X, (int, Integer)): return Gamma0(X).dimension_new_cusp_forms(k, p=p) raise TypeError(f"X (={X}) must be an integer, a Dirichlet character or a congruence subgroup of type Gamma0, Gamma1 or GammaH")
def dimension_new_cusp_forms(X, k=2, p=0): """ Return the dimension of the new (or `p`-new) subspace of cusp forms for the character or group `X`. INPUT: - ``X`` - integer, congruence subgroup or Dirichlet character - ``k`` - weight (integer) - ``p`` - 0 or a prime EXAMPLES:: sage: dimension_new_cusp_forms(100,2) 1 :: sage: dimension_new_cusp_forms(Gamma0(100),2) 1 sage: dimension_new_cusp_forms(Gamma0(100),4) 5 :: sage: dimension_new_cusp_forms(Gamma1(100),2) 141 sage: dimension_new_cusp_forms(Gamma1(100),4) 463 :: sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,2) 2 sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,4) 8 :: sage: sum(dimension_new_cusp_forms(e,3) for e in DirichletGroup(30)) 12 sage: dimension_new_cusp_forms(Gamma1(30),3) 12 """ if is_GammaH(X): return X.dimension_new_cusp_forms(k,p=p) elif isinstance(X, dirichlet.DirichletCharacter): return Gamma1(X.modulus()).dimension_new_cusp_forms(k,eps=X,p=p) elif isinstance(X, (int,long,Integer)): return Gamma0(X).dimension_new_cusp_forms(k,p=p) else: raise TypeError, "X (=%s) must be an integer, a Dirichlet character or a congruence subgroup of type Gamma0, Gamma1 or GammaH" % X
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 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 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 dimension_new_cusp_forms(X, k=2, p=0): """ Return the dimension of the new (or `p`-new) subspace of cusp forms for the character or group `X`. INPUT: - ``X`` - integer, congruence subgroup or Dirichlet character - ``k`` - weight (integer) - ``p`` - 0 or a prime EXAMPLES:: sage: dimension_new_cusp_forms(100,2) 1 :: sage: dimension_new_cusp_forms(Gamma0(100),2) 1 sage: dimension_new_cusp_forms(Gamma0(100),4) 5 :: sage: dimension_new_cusp_forms(Gamma1(100),2) 141 sage: dimension_new_cusp_forms(Gamma1(100),4) 463 :: sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,2) 2 sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,4) 8 :: sage: sum(dimension_new_cusp_forms(e,3) for e in DirichletGroup(30)) 12 sage: dimension_new_cusp_forms(Gamma1(30),3) 12 Check that :trac:`12640` is fixed:: sage: dimension_new_cusp_forms(DirichletGroup(1)(1), 12) 1 sage: dimension_new_cusp_forms(DirichletGroup(2)(1), 24) 1 """ if is_GammaH(X): return X.dimension_new_cusp_forms(k,p=p) elif isinstance(X, dirichlet.DirichletCharacter): N = X.modulus() if N <= 2: return Gamma0(N).dimension_new_cusp_forms(k,p=p) else: # Gamma1(N) for N<=2 just returns Gamma0(N), which has no eps parameter. See trac #12640. return Gamma1(N).dimension_new_cusp_forms(k,eps=X,p=p) elif isinstance(X, (int,long,Integer)): return Gamma0(X).dimension_new_cusp_forms(k,p=p) else: raise TypeError("X (=%s) must be an integer, a Dirichlet character or a congruence subgroup of type Gamma0, Gamma1 or GammaH" % X)
def is_gamma_h_equiv(self, other, G): r""" Return a pair (b, t), where b is True or False as self and other are equivalent under the action of G, and t is 1 or -1, as described below. Two cusps `u1/v1` and `u2/v2` are equivalent modulo Gamma_H(N) if and only if `v1 = h*v2 (\mathrm{mod} N)` and `u1 = h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` or `v1 = -h*v2 (mod N)` and `u1 = -h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` for some `h \in H`. Then t is 1 or -1 as c and c' fall into the first or second case, respectively. INPUT: - ``other`` - Cusp - ``G`` - a congruence subgroup Gamma_H(N) OUTPUT: - ``bool`` - True if self and other are equivalent - ``int`` - -1, 0, 1; extra info EXAMPLES:: sage: x = Cusp(2,3) sage: y = Cusp(4,5) sage: x.is_gamma_h_equiv(y,GammaH(13,[2])) (True, 1) sage: x.is_gamma_h_equiv(y,GammaH(13,[5])) (False, 0) sage: x.is_gamma_h_equiv(y,GammaH(5,[])) (False, 0) sage: x.is_gamma_h_equiv(y,GammaH(23,[4])) (True, -1) Enumerating the cusps for a space of modular symbols uses this function. :: sage: G = GammaH(25,[6]) ; M = G.modular_symbols() ; M Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25) with H generated by [6] of weight 2 with sign 0 and over Rational Field sage: M.cusps() [33/100, 1/3, 31/125, 1/4, 1/15, -7/15, 7/15, 4/15, 1/20, 3/20, 7/20, 9/20] sage: len(M.cusps()) 12 This is always one more than the associated space of weight 2 Eisenstein series. :: sage: G.dimension_eis(2) 11 sage: M.cuspidal_subspace() Modular Symbols subspace of dimension 0 of Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25) with H generated by [6] of weight 2 with sign 0 and over Rational Field sage: G.dimension_cusp_forms(2) 0 """ from sage.modular.arithgroup.all import is_GammaH if not isinstance(other, Cusp): other = Cusp(other) if not is_GammaH(G): raise TypeError("G must be a group GammaH(N).") H = G._list_of_elements_in_H() N = ZZ(G.level()) u1 = self.__a v1 = self.__b u2 = other.__a v2 = other.__b g = v1.gcd(N) for h in H: v_tmp = (h * v1) % N u_tmp = (h * u2) % N if (v_tmp - v2) % N == 0 and (u_tmp - u1) % g == 0: return True, 1 if (v_tmp + v2) % N == 0 and (u_tmp + u1) % g == 0: return True, -1 return False, 0
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 is_gamma_h_equiv(self, other, G): """ Return a pair (b, t), where b is True or False as self and other are equivalent under the action of G, and t is 1 or -1, as described below. Two cusps `u1/v1` and `u2/v2` are equivalent modulo Gamma_H(N) if and only if `v1 = h*v2 (\mathrm{mod} N)` and `u1 = h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` or `v1 = -h*v2 (mod N)` and `u1 = -h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` for some `h \in H`. Then t is 1 or -1 as c and c' fall into the first or second case, respectively. INPUT: - ``other`` - Cusp - ``G`` - a congruence subgroup Gamma_H(N) OUTPUT: - ``bool`` - True if self and other are equivalent - ``int`` - -1, 0, 1; extra info EXAMPLES:: sage: x = Cusp(2,3) sage: y = Cusp(4,5) sage: x.is_gamma_h_equiv(y,GammaH(13,[2])) (True, 1) sage: x.is_gamma_h_equiv(y,GammaH(13,[5])) (False, 0) sage: x.is_gamma_h_equiv(y,GammaH(5,[])) (False, 0) sage: x.is_gamma_h_equiv(y,GammaH(23,[4])) (True, -1) Enumerating the cusps for a space of modular symbols uses this function. :: sage: G = GammaH(25,[6]) ; M = G.modular_symbols() ; M Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25) with H generated by [6] of weight 2 with sign 0 and over Rational Field sage: M.cusps() [37/75, 1/2, 31/125, 1/4, -2/5, 2/5, -1/5, 1/10, -3/10, 1/15, 7/15, 9/20] sage: len(M.cusps()) 12 This is always one more than the associated space of weight 2 Eisenstein series. :: sage: G.dimension_eis(2) 11 sage: M.cuspidal_subspace() Modular Symbols subspace of dimension 0 of Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25) with H generated by [6] of weight 2 with sign 0 and over Rational Field sage: G.dimension_cusp_forms(2) 0 """ from sage.modular.arithgroup.all import is_GammaH if not isinstance(other, Cusp): other = Cusp(other) if not is_GammaH(G): raise TypeError, "G must be a group GammaH(N)." H = G._list_of_elements_in_H() N = ZZ(G.level()) u1 = self.__a v1 = self.__b u2 = other.__a v2 = other.__b g = v1.gcd(N) for h in H: v_tmp = (h*v1)%N u_tmp = (h*u2)%N if (v_tmp - v2)%N == 0 and (u_tmp - u1)%g == 0: return True, 1 if (v_tmp + v2)%N == 0 and (u_tmp + u1)%g == 0: return True, -1 return False, 0
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