def eisenstein_basis(N, k, verbose=False): r""" Find spanning list of 'easy' generators for the subspace of `M_k(\Gamma_0(N))` generated by level 1 Eisenstein series and their images of even integer weights up to `k`. INPUT: - N -- positive integer - k -- positive integer - ``verbose`` -- bool (default: False) OUTPUT: - list of monomials in images of level 1 Eisenstein series - prec of q-expansions needed to determine element of `M_k(\Gamma_0(N))`. EXAMPLES:: sage: from psage.modform.rational.special import eisenstein_basis sage: eisenstein_basis(5,4) ([E4(q^5)^1, E4(q^1)^1, E2^*(q^5)^2], 3) sage: eisenstein_basis(11,2,verbose=True) # warning below because of verbose Warning -- not enough series. ([E2^*(q^11)^1], 2) sage: eisenstein_basis(11,2,verbose=False) ([E2^*(q^11)^1], 2) """ assert N > 1 if k % 2 != 0: return [] # Make list E of Eisenstein series, to enough precision to # determine them, until we span space. M = ModularForms(N, k) prec = M.echelon_basis()[-1].valuation() + 1 gens = eisenstein_gens(N, k, prec) R = PolynomialRing(ZZ, len(gens), ['E%sq%s'%(g[1],g[0]) for g in gens]) z = [(R.gen(i), g[1]) for i, g in enumerate(gens)] m = monomials(z, k) A = QQ**prec V = A.zero_subspace() E = [] for i, z in enumerate(m): d = z.degrees() f = prod(g[2]**d[i] for i, g in enumerate(gens) if d[i]) v = A(f.padded_list(prec)) if v not in V: V = V + A.span([v]) w = [(gens[i][0],gens[i][1],d[i]) for i in range(len(d)) if d[i]] E.append(EisensteinMonomial(w)) if V.dimension() == M.dimension(): return E, prec if verbose: print "Warning -- not enough series." return E, prec
def _rank(self, K): """ Return the dimension of the level N space of given weight. """ if not K is QQ: raise NotImplementedError if not self.__level.is_prime(): raise NotImplementedError if self.__weight % 2 != 0: raise NotImplementedError("Only even weights available") N = self.__level if N == 1: ## By Igusa's theorem on the generators of the graded ring P = PowerSeriesRing(ZZ, 't') t = P.gen(0) dims = 1 / ((1 - t**4) * (1 - t**6) * (1 - t**10) * (1 - t**12)).add_bigoh(self.__weight + 1) return dims[self.__weight] if N == 2: ## As in Ibukiyama, Onodera - On the graded ring of modular forms of the Siegel ## paramodular group of level 2, Proposition 2 P = PowerSeriesRing(ZZ, 't') t = P.gen(0) dims = ((1 + t**10) * (1 + t**12) * (1 + t**11)) dims = dims / ((1 - t**4) * (1 - t**6) * (1 - t**8) * (1 - t**12)).add_bigoh(self.__weight + 1) return dims[self.__weight] if N == 3: ## By Dern, Paramodular forms of degree 2 and level 3, Corollary 5.6 P = PowerSeriesRing(ZZ, 't') t = P.gen(0) dims = ((1 + t**12) * (1 + t**8 + t**9 + t**10 + t**11 + t**19)) dims = dims / ((1 - t**4) * (1 - t**6)**2 * (1 - t**12)).add_bigoh(self.__weight + 1) return dims[self.__weight] if N == 5: ## By Marschner, Paramodular forms of degree 2 with particular emphasis on level t = 5, ## Corollary 7.3.4. PhD thesis electronically available via the library of ## RWTH University, Aachen, Germany P = PowerSeriesRing(ZZ, 't') t = P.gen(0) dims = t**30 + t**24 + t**23 + 2*t**22 + t**21 + 2*t**20 + t**19 + 2*t**18 \ + 2*t**16 + 2*t**14 + 2*t**12 + t**11 + 2*t**10 + t**9 + 2*t**8 + t**7 + t**6 + 1 dims = dims / ((1 - t**4) * (1 - t**5) * (1 - t**6) * (1 - t**12)).add_bigoh(self.__weight + 1) return dims[self.__weight] if self.__weight == 2: ## There are only cuspforms, since there is no elliptic modular form ## of weight 2. if N < 277: ## Poor, Yuen - Paramodular cusp forms tells us that all forms are ## Gritsenko lifts return JacobiFormD1NN_Gamma(self.__level, 2)._rank(QQ) raise NotImplementedError elif self.__weight == 4: ## This is the formula cited by Poor and Yuen in Paramodular cusp forms cuspidal_dim = Integer((N**2 - 143) / Integer(576) + N / Integer(8) + kronecker_symbol(-1, N) * (N - 12) / Integer(96) + kronecker_symbol(2, N) / Integer(8) + kronecker_symbol(3, N) / Integer(12) + kronecker_symbol(-3, N) * N / Integer(36)) else: ## This is the formula given by Ibukiyama in ## Relations of dimension of automorphic forms of Sp(2,R) and its compact twist Sp(2), ## Theorem 4 p = N k = self.__weight ## This is the reversed Ibukiyama symbol [.., .., ..; ..] def ibukiyama_symbol(modulus, *args): return args[k % modulus] ## if p == 2 this formula is wrong. If the weight is even it differs by ## -3/16 from the true dimension and if the weight is odd it differs by ## -1/16 from the true dimension. H1 = (p**2 + 1) * (2 * k - 2) * (2 * k - 3) * ( 2 * k - 4) / Integer(2**9 * 3**3 * 5) H2 = (-1)**k * (2 * k - 2) * (2 * k - 4) / Integer(2**8 * 3**2) \ + ( (-1)**k * (2 * k - 2) * (2 * k - 4) / Integer(2**7 * 3) if p !=2 else (-1)**k * (2 * k - 2) * (2 * k - 4) / Integer(2**9) ) H3 = (ibukiyama_symbol(4, k - 2, -k + 1, -k + 2, k - 1) / Integer(2**4 * 3) if p != 3 else 5 * ibukiyama_symbol(4, k - 2, -k + 1, -k + 2, k - 1) / Integer(2**5 * 3)) H4 = (ibukiyama_symbol(3, 2 * k - 3, -k + 1, -k + 2) / Integer(2**2 * 3**3) if p != 2 else 5 * ibukiyama_symbol(3, 2 * k - 3, -k + 1, -k + 2) / Integer(2**2 * 3**3)) H5 = ibukiyama_symbol(6, -1, -k + 1, -k + 2, 1, k - 1, k - 2) / Integer(2**2 * 3**2) if p % 4 == 1: H6 = 5 * (2 * k - 3) * (p + 1) / Integer( 2**7 * 3) + (-1)**k * (p + 1) / Integer(2**7) elif p % 4 == 3: H6 = (2 * k - 3) * (p - 1) / Integer( 2**7) + 5 * (-1)**k * (p - 1) / Integer(2**7 * 3) else: H6 = 3 * (2 * k - 3) / Integer(2**7) + 7 * (-1)**k / Integer( 2**7 * 3) if p % 3 == 1: H7 = (2 * k - 3) * (p + 1) / Integer(2 * 3**3) \ + (p + 1) * ibukiyama_symbol(3, 0, -1, 1) / Integer(2**2 * 3**3) elif p % 3 == 2: H7 = (2 * k - 3) * (p - 1) / Integer(2**2 * 3**3) \ + (p - 1) * ibukiyama_symbol(3, 0, -1, 1) / Integer(2 * 3**3) else: H7 = 5 * (2 * k - 3) / Integer(2**2 * 3**3) \ + ibukiyama_symbol(3, 0, -1, 1) / Integer(3**3) H8 = ibukiyama_symbol(12, 1, 0, 0, -1, -1, -1, -1, 0, 0, 1, 1, 1) / Integer(2 * 3) H9 = (2 * ibukiyama_symbol(6, 1, 0, 0, -1, 0, 0) / Integer(3**2) if p != 2 else ibukiyama_symbol(6, 1, 0, 0, -1, 0, 0) / Integer(2 * 3**2)) H10 = (1 + kronecker_symbol(5, p)) * ibukiyama_symbol( 5, 1, 0, 0, -1, 0) / Integer(5) H11 = (1 + kronecker_symbol(2, p)) * ibukiyama_symbol( 4, 1, 0, 0, -1) / Integer(2**3) if p % 12 == 1: H12 = ibukiyama_symbol(3, 0, 1, -1) / Integer(2 * 3) elif p % 12 == 11: H12 = (-1)**k / Integer(2 * 3) elif p == 2 or p == 3: H12 = (-1)**k / Integer(2**2 * 3) else: H12 = 0 I1 = ibukiyama_symbol(6, 0, 1, 1, 0, -1, -1) / Integer(6) I2 = ibukiyama_symbol(3, -2, 1, 1) / Integer(2 * 3**2) if p == 3: I3 = ibukiyama_symbol(3, -2, 1, 1) / Integer(3**2) elif p % 3 == 1: I3 = 2 * ibukiyama_symbol(3, -1, 1, 0) / Integer(3**2) else: I3 = 2 * ibukiyama_symbol(3, -1, 0, 1) / Integer(3**2) I4 = ibukiyama_symbol(4, -1, 1, 1, -1) / Integer(2**2) I5 = (-1)**k / Integer(2**3) I6 = (-1)**k * (2 - kronecker_symbol(-1, p)) / Integer(2**4) I7 = -(-1)**k * (2 * k - 3) / Integer(2**3 * 3) I8 = -p * (2 * k - 3) / Integer(2**4 * 3**2) I9 = -1 / Integer(2**3 * 3) I10 = (p + 1) / Integer(2**3 * 3) I11 = -(1 + kronecker_symbol(-1, p)) / Integer(8) I12 = -(1 + kronecker_symbol(-3, p)) / Integer(6) cuspidal_dim = H1 + H2 + H3 + H4 + H5 + H6 + H7 + H8 + H9 + H10 + H11 + H12 \ + I1 + I2 + I3 + I4 + I5 + I6 + I7 + I8 + I9 + I10 + I11 + I12 mfs = ModularForms(1, self.__weight) return cuspidal_dim + mfs.dimension() + mfs.cuspidal_subspace( ).dimension()
def _rank(self, K): """ Return the dimension of the level N space of given weight. """ if not K is QQ: raise NotImplementedError if not self.__level.is_prime(): raise NotImplementedError if self.__weight % 2 != 0: raise NotImplementedError("Only even weights available") N = self.__level if N == 1: ## By Igusa's theorem on the generators of the graded ring P = PowerSeriesRing(ZZ, "t") t = P.gen(0) dims = 1 / ((1 - t ** 4) * (1 - t ** 6) * (1 - t ** 10) * (1 - t ** 12)).add_bigoh(self.__weight + 1) return dims[self.__weight] if N == 2: ## As in Ibukiyama, Onodera - On the graded ring of modular forms of the Siegel ## paramodular group of level 2, Proposition 2 P = PowerSeriesRing(ZZ, "t") t = P.gen(0) dims = (1 + t ** 10) * (1 + t ** 12) * (1 + t ** 11) dims = dims / ((1 - t ** 4) * (1 - t ** 6) * (1 - t ** 8) * (1 - t ** 12)).add_bigoh(self.__weight + 1) return dims[self.__weight] if N == 3: ## By Dern, Paramodular forms of degree 2 and level 3, Corollary 5.6 P = PowerSeriesRing(ZZ, "t") t = P.gen(0) dims = (1 + t ** 12) * (1 + t ** 8 + t ** 9 + t ** 10 + t ** 11 + t ** 19) dims = dims / ((1 - t ** 4) * (1 - t ** 6) ** 2 * (1 - t ** 12)).add_bigoh(self.__weight + 1) return dims[self.__weight] if N == 5: ## By Marschner, Paramodular forms of degree 2 with particular emphasis on level t = 5, ## Corollary 7.3.4. PhD thesis electronically available via the library of ## RWTH University, Aachen, Germany P = PowerSeriesRing(ZZ, "t") t = P.gen(0) dims = ( t ** 30 + t ** 24 + t ** 23 + 2 * t ** 22 + t ** 21 + 2 * t ** 20 + t ** 19 + 2 * t ** 18 + 2 * t ** 16 + 2 * t ** 14 + 2 * t ** 12 + t ** 11 + 2 * t ** 10 + t ** 9 + 2 * t ** 8 + t ** 7 + t ** 6 + 1 ) dims = dims / ((1 - t ** 4) * (1 - t ** 5) * (1 - t ** 6) * (1 - t ** 12)).add_bigoh(self.__weight + 1) return dims[self.__weight] if self.__weight == 2: ## There are only cuspforms, since there is no elliptic modular form ## of weight 2. if N < 277: ## Poor, Yuen - Paramodular cusp forms tells us that all forms are ## Gritsenko lifts return JacobiFormD1NN_Gamma(self.__level, 2)._rank(QQ) raise NotImplementedError elif self.__weight == 4: ## This is the formula cited by Poor and Yuen in Paramodular cusp forms cuspidal_dim = Integer( (N ** 2 - 143) / Integer(576) + N / Integer(8) + kronecker_symbol(-1, N) * (N - 12) / Integer(96) + kronecker_symbol(2, N) / Integer(8) + kronecker_symbol(3, N) / Integer(12) + kronecker_symbol(-3, N) * N / Integer(36) ) else: ## This is the formula given by Ibukiyama in ## Relations of dimension of automorphic forms of Sp(2,R) and its compact twist Sp(2), ## Theorem 4 p = N k = self.__weight ## This is the reversed Ibukiyama symbol [.., .., ..; ..] def ibukiyama_symbol(modulus, *args): return args[k % modulus] ## if p == 2 this formula is wrong. If the weight is even it differs by ## -3/16 from the true dimension and if the weight is odd it differs by ## -1/16 from the true dimension. H1 = (p ** 2 + 1) * (2 * k - 2) * (2 * k - 3) * (2 * k - 4) / Integer(2 ** 9 * 3 ** 3 * 5) H2 = (-1) ** k * (2 * k - 2) * (2 * k - 4) / Integer(2 ** 8 * 3 ** 2) + ( (-1) ** k * (2 * k - 2) * (2 * k - 4) / Integer(2 ** 7 * 3) if p != 2 else (-1) ** k * (2 * k - 2) * (2 * k - 4) / Integer(2 ** 9) ) H3 = ( ibukiyama_symbol(4, k - 2, -k + 1, -k + 2, k - 1) / Integer(2 ** 4 * 3) if p != 3 else 5 * ibukiyama_symbol(4, k - 2, -k + 1, -k + 2, k - 1) / Integer(2 ** 5 * 3) ) H4 = ( ibukiyama_symbol(3, 2 * k - 3, -k + 1, -k + 2) / Integer(2 ** 2 * 3 ** 3) if p != 2 else 5 * ibukiyama_symbol(3, 2 * k - 3, -k + 1, -k + 2) / Integer(2 ** 2 * 3 ** 3) ) H5 = ibukiyama_symbol(6, -1, -k + 1, -k + 2, 1, k - 1, k - 2) / Integer(2 ** 2 * 3 ** 2) if p % 4 == 1: H6 = 5 * (2 * k - 3) * (p + 1) / Integer(2 ** 7 * 3) + (-1) ** k * (p + 1) / Integer(2 ** 7) elif p % 4 == 3: H6 = (2 * k - 3) * (p - 1) / Integer(2 ** 7) + 5 * (-1) ** k * (p - 1) / Integer(2 ** 7 * 3) else: H6 = 3 * (2 * k - 3) / Integer(2 ** 7) + 7 * (-1) ** k / Integer(2 ** 7 * 3) if p % 3 == 1: H7 = (2 * k - 3) * (p + 1) / Integer(2 * 3 ** 3) + (p + 1) * ibukiyama_symbol(3, 0, -1, 1) / Integer( 2 ** 2 * 3 ** 3 ) elif p % 3 == 2: H7 = (2 * k - 3) * (p - 1) / Integer(2 ** 2 * 3 ** 3) + (p - 1) * ibukiyama_symbol( 3, 0, -1, 1 ) / Integer(2 * 3 ** 3) else: H7 = 5 * (2 * k - 3) / Integer(2 ** 2 * 3 ** 3) + ibukiyama_symbol(3, 0, -1, 1) / Integer(3 ** 3) H8 = ibukiyama_symbol(12, 1, 0, 0, -1, -1, -1, -1, 0, 0, 1, 1, 1) / Integer(2 * 3) H9 = ( 2 * ibukiyama_symbol(6, 1, 0, 0, -1, 0, 0) / Integer(3 ** 2) if p != 2 else ibukiyama_symbol(6, 1, 0, 0, -1, 0, 0) / Integer(2 * 3 ** 2) ) H10 = (1 + kronecker_symbol(5, p)) * ibukiyama_symbol(5, 1, 0, 0, -1, 0) / Integer(5) H11 = (1 + kronecker_symbol(2, p)) * ibukiyama_symbol(4, 1, 0, 0, -1) / Integer(2 ** 3) if p % 12 == 1: H12 = ibukiyama_symbol(3, 0, 1, -1) / Integer(2 * 3) elif p % 12 == 11: H12 = (-1) ** k / Integer(2 * 3) elif p == 2 or p == 3: H12 = (-1) ** k / Integer(2 ** 2 * 3) else: H12 = 0 I1 = ibukiyama_symbol(6, 0, 1, 1, 0, -1, -1) / Integer(6) I2 = ibukiyama_symbol(3, -2, 1, 1) / Integer(2 * 3 ** 2) if p == 3: I3 = ibukiyama_symbol(3, -2, 1, 1) / Integer(3 ** 2) elif p % 3 == 1: I3 = 2 * ibukiyama_symbol(3, -1, 1, 0) / Integer(3 ** 2) else: I3 = 2 * ibukiyama_symbol(3, -1, 0, 1) / Integer(3 ** 2) I4 = ibukiyama_symbol(4, -1, 1, 1, -1) / Integer(2 ** 2) I5 = (-1) ** k / Integer(2 ** 3) I6 = (-1) ** k * (2 - kronecker_symbol(-1, p)) / Integer(2 ** 4) I7 = -(-1) ** k * (2 * k - 3) / Integer(2 ** 3 * 3) I8 = -p * (2 * k - 3) / Integer(2 ** 4 * 3 ** 2) I9 = -1 / Integer(2 ** 3 * 3) I10 = (p + 1) / Integer(2 ** 3 * 3) I11 = -(1 + kronecker_symbol(-1, p)) / Integer(8) I12 = -(1 + kronecker_symbol(-3, p)) / Integer(6) cuspidal_dim = ( H1 + H2 + H3 + H4 + H5 + H6 + H7 + H8 + H9 + H10 + H11 + H12 + I1 + I2 + I3 + I4 + I5 + I6 + I7 + I8 + I9 + I10 + I11 + I12 ) mfs = ModularForms(1, self.__weight) return cuspidal_dim + mfs.dimension() + mfs.cuspidal_subspace().dimension()
def _siegel_modular_forms_generators(parent, prec=None, degree=0): r""" Compute the four Igusa generators of the ring of Siegel modular forms of degree 2 and level 1 and even weight (this happens if weights='even'). If weights = 'all' you get the Siegel modular forms of degree 2, level 1 and even and odd weight. EXAMPLES:: sage: A, B, C, D = SiegelModularFormsAlgebra().gens() sage: C[(2, 0, 9)] -390420 sage: D[(4, 2, 5)] 17689760 sage: A2, B2, C2, D2 = SiegelModularFormsAlgebra().gens(prec=50) sage: A[(1, 0, 1)] == A2[(1, 0, 1)] True sage: A3, B3, C3, D3 = SiegelModularFormsAlgebra().gens(prec=500) sage: B2[(2, 1, 3)] == B3[(2, 1, 3)] True TESTS:: sage: from sage.modular.siegel.siegel_modular_forms_algebra import _siegel_modular_forms_generators sage: S = SiegelModularFormsAlgebra() sage: S.gens() == _siegel_modular_forms_generators(S) True """ group = parent.group() weights = parent.weights() if prec is None: prec = parent.default_prec() if group == 'Sp(4,Z)' and 0 == degree: from sage.modular.all import ModularForms E4 = ModularForms(1, 4).gen(0) M6 = ModularForms(1, 6) E6 = ModularForms(1, 6).gen(0) M8 = ModularForms(1, 8) M10 = ModularForms(1, 10) Delta = ModularForms(1, 12).cuspidal_subspace().gen(0) M14 = ModularForms(1, 14) A = SiegelModularForm(60 * E4, M6(0), prec=prec, name='Igusa_4') B = SiegelModularForm(-84 * E6, M8(0), prec=prec, name='Igusa_6') C = SiegelModularForm(M10(0), -Delta, prec=prec, name='Igusa_10') D = SiegelModularForm(Delta, M14(0), prec=prec, name='Igusa_12') # TODO: the base_ring of A, B, ... should be ZZ # Here a hack for now: a = [A, B, C, D] b = [] from sage.rings.all import ZZ for F in a: c = F.coeffs() for f in c.iterkeys(): c[f] = ZZ(c[f]) F = parent.element_class(parent=parent, weight=F.weight(), coeffs=c, prec=prec, name=F.name()) b.append(F) if weights == 'even': return b if weights == 'all': from fastmult import chi35 coeffs35 = chi35(prec, b[0], b[1], b[2], b[3]) from sage.groups.all import KleinFourGroup G = KleinFourGroup() from sage.algebras.all import GroupAlgebra R = GroupAlgebra(G) det = R(G.gen(0)) E = parent.element_class(parent=parent, weight=35, coeffs=coeffs35, prec=prec, name='Delta_35') E = E * det b.append(E) return b raise ValueError, "weights = '%s': should be 'all' or 'even'" % weights if group == 'Sp(4,Z)' and weights == 'even' and 2 == degree: b = _siegel_modular_forms_generators(parent=parent) c = [] for F in b: i = b.index(F) for G in b[(i + 1):]: c.append(F.satoh_bracket(G)) return c raise NotImplementedError, "Not yet implemented"