def get_magma_qexpansions(filename, i1, prec, base_ring, magma=None): if magma is None: from sage.interfaces.magma import Magma magma = Magma() magma.set('prec',prec) magma.load("get_qexpansions.m") if i1 is None: for line in filename: print line magma.eval(line) magma.eval("f := g") # In case text is reversed f = 'f' eps_data_f = 'eps_on_gens' else: magma.load(filename) f = 'eigenforms_list[%s][1]'%i1 eps_data_f = 'eigenforms_list[%s][2]'%i1 qexpm = magma.extend_qexpansion(f, eps_data_f, prec) F0 = [0] * qexpm.Valuation().sage() + [o.sage() for o in qexpm.ElementToSequence()] K = F0[-1].parent() a = K.gen() phi = find_embeddings(K,base_ring)[0] F = [phi(o) for o in F0] eps_f = magma.get_character(f, eps_data_f).ValueList().sage() eps_f_full = magma.get_character_full(f, eps_data_f).ValueList().sage() N = len(eps_f) Geps = DirichletGroup(N, base_ring = K) eps_f = Geps([eps_f[i - 1] for i in Geps.unit_gens()]) Geps_full = DirichletGroup(N) psi = eps_f_full[0].parent().embeddings(Geps_full.base_ring())[0] eps_f_full = Geps_full([psi(eps_f_full[i - 1]) for i in Geps_full.unit_gens()]) if a == 1: sigma = lambda x:x else: try: sigma = next((s for s in K.automorphisms() if s(a)*a == 1)) except StopIteration: raise NotImplementedError G = [phi(sigma(o)) for o in F0] eps_g = eps_f**-1 eps_g_full = eps_f_full**-1 F = ModFormqExp(F, base_ring, weight=1, level = N, character = eps_f, character_full = eps_f_full) G = ModFormqExp(G, base_ring, weight=1, level = N, character = eps_g, character_full = eps_g_full) return F, G
def dimension_new_cusp_forms(self, k=2, eps=None, p=0, algorithm="CohenOesterle"): r""" Dimension of the new subspace (or `p`-new subspace) of cusp forms of weight `k` and character `\varepsilon`. INPUT: - ``k`` - an integer (default: 2) - ``eps`` - a Dirichlet character - ``p`` - a prime (default: 0); just the `p`-new subspace if given - ``algorithm`` - either "CohenOesterle" (the default) or "Quer". This specifies the method to use in the case of nontrivial character: either the Cohen--Oesterle formula as described in Stein's book, or by Möbius inversion using the subgroups GammaH (a method due to Jordi Quer). EXAMPLES:: sage: G = DirichletGroup(9) sage: eps = G.0^3 sage: eps.conductor() 3 sage: [Gamma1(9).dimension_new_cusp_forms(k, eps) for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0] sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [2..10]] [0, 0, 0, 2, 0, 4, 0, 6, 0] sage: [Gamma1(9).dimension_new_cusp_forms(k, eps, 3) for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0] Double check using modular symbols (independent calculation):: sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace().dimension() for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0] sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace(3).dimension() for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0] Another example at level 33:: sage: G = DirichletGroup(33) sage: eps = G.1 sage: eps.conductor() 11 sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1) for k in [2..4]] [0, 4, 0] sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1, algorithm="Quer") for k in [2..4]] [0, 4, 0] sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2) for k in [2..4]] [2, 0, 6] sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2, p=3) for k in [2..4]] [2, 0, 6] """ if eps is None: return GammaH_class.dimension_new_cusp_forms(self, k, p) N = self.level() eps = DirichletGroup(N, eps.base_ring())(eps) if eps.is_trivial(): from .all import Gamma0 return Gamma0(N).dimension_new_cusp_forms(k, p) from .congroup_gammaH import mumu if p == 0 or N % p != 0 or eps.conductor().valuation(p) == N.valuation( p): D = [eps.conductor() * d for d in divisors(N // eps.conductor())] return sum([ Gamma1_constructor(M).dimension_cusp_forms( k, eps.restrict(M), algorithm) * mumu(N // M) for M in D ]) eps_p = eps.restrict(N // p) old = Gamma1_constructor(N // p).dimension_cusp_forms( k, eps_p, algorithm) return self.dimension_cusp_forms(k, eps, algorithm) - 2 * old
def dimension_eis(self, k=2, eps=None, algorithm="CohenOesterle"): r""" Return the dimension of the space of Eisenstein series forms for self, or the dimension of the subspace corresponding to the given character if one is supplied. INPUT: - ``k`` - an integer (default: 2), the weight. - ``eps`` - either None or a Dirichlet character modulo N, where N is the level of this group. If this is None, then the dimension of the whole space is returned; otherwise, the dimension of the subspace of Eisenstein series of character eps. - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This specifies the method to use in the case of nontrivial character: either the Cohen--Oesterle formula as described in Stein's book, or by Moebius inversion using the subgroups GammaH (a method due to Jordi Quer). AUTHORS: - William Stein - Cohen--Oesterle algorithm - Jordi Quer - algorithm based on GammaH subgroups - David Loeffler (2009) - code refactoring EXAMPLES: The following two computations use different algorithms: :: sage: [Gamma1(36).dimension_eis(1,eps) for eps in DirichletGroup(36)] [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0] sage: [Gamma1(36).dimension_eis(1,eps,algorithm="Quer") for eps in DirichletGroup(36)] [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0] So do these: :: sage: [Gamma1(48).dimension_eis(3,eps) for eps in DirichletGroup(48)] [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0] sage: [Gamma1(48).dimension_eis(3,eps,algorithm="Quer") for eps in DirichletGroup(48)] [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0] """ from all import Gamma0 # first deal with special cases if eps is None: return GammaH_class.dimension_eis(self, k) N = self.level() eps = DirichletGroup(N)(eps) if eps.is_trivial(): return Gamma0(N).dimension_eis(k) # Note case of k = 0 and trivial character already dealt with separately, so k <= 0 here is valid: if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k%2) == 0 and eps.is_odd()): return ZZ(0) if algorithm == "Quer": n = eps.order() dim = ZZ(0) for d in n.divisors(): G = GammaH_constructor(N,(eps**d).kernel()) dim = dim + moebius(d)*G.dimension_eis(k) return dim//phi(n) elif algorithm == "CohenOesterle": from sage.modular.dims import CohenOesterle K = eps.base_ring() j = 2-k # We use the Cohen-Oesterle formula in a subtle way to # compute dim M_k(N,eps) (see Ch. 6 of William Stein's book on # computing with modular forms). alpha = -ZZ( K(Gamma0(N).index()*(j-1)/ZZ(12)) + CohenOesterle(eps,j) ) if k == 1: return alpha else: return alpha - self.dimension_cusp_forms(k, eps) else: #algorithm not in ["CohenOesterle", "Quer"]: raise ValueError, "Unrecognised algorithm in dimension_eis"
def dimension_cusp_forms(self, k=2, eps=None, algorithm="CohenOesterle"): r""" Return the dimension of the space of cusp forms for self, or the dimension of the subspace corresponding to the given character if one is supplied. INPUT: - ``k`` - an integer (default: 2), the weight. - ``eps`` - either None or a Dirichlet character modulo N, where N is the level of this group. If this is None, then the dimension of the whole space is returned; otherwise, the dimension of the subspace of forms of character eps. - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This specifies the method to use in the case of nontrivial character: either the Cohen--Oesterle formula as described in Stein's book, or by Moebius inversion using the subgroups GammaH (a method due to Jordi Quer). EXAMPLES: We compute the same dimension in two different ways :: sage: K = CyclotomicField(3) sage: eps = DirichletGroup(7*43,K).0^2 sage: G = Gamma1(7*43) Via Cohen--Oesterle: :: sage: Gamma1(7*43).dimension_cusp_forms(2, eps) 28 Via Quer's method: :: sage: Gamma1(7*43).dimension_cusp_forms(2, eps, algorithm="Quer") 28 Some more examples: :: sage: G.<eps> = DirichletGroup(9) sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [1..10]] [0, 0, 1, 0, 3, 0, 5, 0, 7, 0] sage: [Gamma1(9).dimension_cusp_forms(k, eps^2) for k in [1..10]] [0, 0, 0, 2, 0, 4, 0, 6, 0, 8] """ from all import Gamma0 # first deal with special cases if eps is None: return GammaH_class.dimension_cusp_forms(self, k) N = self.level() if eps.base_ring().characteristic() != 0: raise ValueError eps = DirichletGroup(N, eps.base_ring())(eps) if eps.is_trivial(): return Gamma0(N).dimension_cusp_forms(k) if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k%2) == 0 and eps.is_odd()): return ZZ(0) if k == 1: try: n = self.dimension_cusp_forms(1) if n == 0: return ZZ(0) else: # never happens at present raise NotImplementedError, "Computations of dimensions of spaces of weight 1 cusp forms not implemented at present" except NotImplementedError: raise # now the main part if algorithm == "Quer": n = eps.order() dim = ZZ(0) for d in n.divisors(): G = GammaH_constructor(N,(eps**d).kernel()) dim = dim + moebius(d)*G.dimension_cusp_forms(k) return dim//phi(n) elif algorithm == "CohenOesterle": K = eps.base_ring() from sage.modular.dims import CohenOesterle from all import Gamma0 return ZZ( K(Gamma0(N).index() * (k-1)/ZZ(12)) + CohenOesterle(eps,k) ) else: #algorithm not in ["CohenOesterle", "Quer"]: raise ValueError, "Unrecognised algorithm in dimension_cusp_forms"
def dimension_eis(self, k=2, eps=None, algorithm="CohenOesterle"): r""" Return the dimension of the space of Eisenstein series forms for self, or the dimension of the subspace corresponding to the given character if one is supplied. INPUT: - ``k`` - an integer (default: 2), the weight. - ``eps`` - either None or a Dirichlet character modulo N, where N is the level of this group. If this is None, then the dimension of the whole space is returned; otherwise, the dimension of the subspace of Eisenstein series of character eps. - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This specifies the method to use in the case of nontrivial character: either the Cohen--Oesterle formula as described in Stein's book, or by Moebius inversion using the subgroups GammaH (a method due to Jordi Quer). AUTHORS: - William Stein - Cohen--Oesterle algorithm - Jordi Quer - algorithm based on GammaH subgroups - David Loeffler (2009) - code refactoring EXAMPLES: The following two computations use different algorithms: :: sage: [Gamma1(36).dimension_eis(1,eps) for eps in DirichletGroup(36)] [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0] sage: [Gamma1(36).dimension_eis(1,eps,algorithm="Quer") for eps in DirichletGroup(36)] [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0] So do these: :: sage: [Gamma1(48).dimension_eis(3,eps) for eps in DirichletGroup(48)] [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0] sage: [Gamma1(48).dimension_eis(3,eps,algorithm="Quer") for eps in DirichletGroup(48)] [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0] """ from all import Gamma0 # first deal with special cases if eps is None: return GammaH_class.dimension_eis(self, k) N = self.level() eps = DirichletGroup(N)(eps) if eps.is_trivial(): return Gamma0(N).dimension_eis(k) # Note case of k = 0 and trivial character already dealt with separately, so k <= 0 here is valid: if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k % 2) == 0 and eps.is_odd()): return ZZ(0) if algorithm == "Quer": n = eps.order() dim = ZZ(0) for d in n.divisors(): G = GammaH_constructor(N, (eps**d).kernel()) dim = dim + moebius(d) * G.dimension_eis(k) return dim // phi(n) elif algorithm == "CohenOesterle": from sage.modular.dims import CohenOesterle K = eps.base_ring() j = 2 - k # We use the Cohen-Oesterle formula in a subtle way to # compute dim M_k(N,eps) (see Ch. 6 of William Stein's book on # computing with modular forms). alpha = -ZZ( K(Gamma0(N).index() * (j - 1) / ZZ(12)) + CohenOesterle(eps, j)) if k == 1: return alpha else: return alpha - self.dimension_cusp_forms(k, eps) else: #algorithm not in ["CohenOesterle", "Quer"]: raise ValueError, "Unrecognised algorithm in dimension_eis"
def dimension_cusp_forms(self, k=2, eps=None, algorithm="CohenOesterle"): r""" Return the dimension of the space of cusp forms for self, or the dimension of the subspace corresponding to the given character if one is supplied. INPUT: - ``k`` - an integer (default: 2), the weight. - ``eps`` - either None or a Dirichlet character modulo N, where N is the level of this group. If this is None, then the dimension of the whole space is returned; otherwise, the dimension of the subspace of forms of character eps. - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This specifies the method to use in the case of nontrivial character: either the Cohen--Oesterle formula as described in Stein's book, or by Moebius inversion using the subgroups GammaH (a method due to Jordi Quer). EXAMPLES: We compute the same dimension in two different ways :: sage: K = CyclotomicField(3) sage: eps = DirichletGroup(7*43,K).0^2 sage: G = Gamma1(7*43) Via Cohen--Oesterle: :: sage: Gamma1(7*43).dimension_cusp_forms(2, eps) 28 Via Quer's method: :: sage: Gamma1(7*43).dimension_cusp_forms(2, eps, algorithm="Quer") 28 Some more examples: :: sage: G.<eps> = DirichletGroup(9) sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [1..10]] [0, 0, 1, 0, 3, 0, 5, 0, 7, 0] sage: [Gamma1(9).dimension_cusp_forms(k, eps^2) for k in [1..10]] [0, 0, 0, 2, 0, 4, 0, 6, 0, 8] """ from all import Gamma0 # first deal with special cases if eps is None: return GammaH_class.dimension_cusp_forms(self, k) N = self.level() if eps.base_ring().characteristic() != 0: raise ValueError eps = DirichletGroup(N, eps.base_ring())(eps) if eps.is_trivial(): return Gamma0(N).dimension_cusp_forms(k) if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k % 2) == 0 and eps.is_odd()): return ZZ(0) if k == 1: try: n = self.dimension_cusp_forms(1) if n == 0: return ZZ(0) else: # never happens at present raise NotImplementedError, "Computations of dimensions of spaces of weight 1 cusp forms not implemented at present" except NotImplementedError: raise # now the main part if algorithm == "Quer": n = eps.order() dim = ZZ(0) for d in n.divisors(): G = GammaH_constructor(N, (eps**d).kernel()) dim = dim + moebius(d) * G.dimension_cusp_forms(k) return dim // phi(n) elif algorithm == "CohenOesterle": K = eps.base_ring() from sage.modular.dims import CohenOesterle from all import Gamma0 return ZZ( K(Gamma0(N).index() * (k - 1) / ZZ(12)) + CohenOesterle(eps, k)) else: #algorithm not in ["CohenOesterle", "Quer"]: raise ValueError, "Unrecognised algorithm in dimension_cusp_forms"
def dimension_new_cusp_forms(self, k=2, eps=None, p=0, algorithm="CohenOesterle"): r""" Dimension of the new subspace (or `p`-new subspace) of cusp forms of weight `k` and character `\varepsilon`. INPUT: - ``k`` - an integer (default: 2) - ``eps`` - a Dirichlet character - ``p`` - a prime (default: 0); just the `p`-new subspace if given - ``algorithm`` - either "CohenOesterle" (the default) or "Quer". This specifies the method to use in the case of nontrivial character: either the Cohen--Oesterle formula as described in Stein's book, or by Möbius inversion using the subgroups GammaH (a method due to Jordi Quer). EXAMPLES:: sage: G = DirichletGroup(9) sage: eps = G.0^3 sage: eps.conductor() 3 sage: [Gamma1(9).dimension_new_cusp_forms(k, eps) for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0] sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [2..10]] [0, 0, 0, 2, 0, 4, 0, 6, 0] sage: [Gamma1(9).dimension_new_cusp_forms(k, eps, 3) for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0] Double check using modular symbols (independent calculation):: sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace().dimension() for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0] sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace(3).dimension() for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0] Another example at level 33:: sage: G = DirichletGroup(33) sage: eps = G.1 sage: eps.conductor() 11 sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1) for k in [2..4]] [0, 4, 0] sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1, algorithm="Quer") for k in [2..4]] [0, 4, 0] sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2) for k in [2..4]] [2, 0, 6] sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2, p=3) for k in [2..4]] [2, 0, 6] """ if eps is None: return GammaH_class.dimension_new_cusp_forms(self, k, p) N = self.level() eps = DirichletGroup(N, eps.base_ring())(eps) if eps.is_trivial(): from all import Gamma0 return Gamma0(N).dimension_new_cusp_forms(k, p) from congroup_gammaH import mumu if p == 0 or N%p != 0 or eps.conductor().valuation(p) == N.valuation(p): D = [eps.conductor()*d for d in divisors(N//eps.conductor())] return sum([Gamma1_constructor(M).dimension_cusp_forms(k, eps.restrict(M), algorithm)*mumu(N//M) for M in D]) eps_p = eps.restrict(N//p) old = Gamma1_constructor(N//p).dimension_cusp_forms(k, eps_p, algorithm) return self.dimension_cusp_forms(k, eps, algorithm) - 2*old