def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): r""" Compute and return the Victor Miller basis for modular forms of weight `k` and level 1 to precision `O(q^{prec})`. If ``cusp_only`` is True, return only a basis for the cuspidal subspace. INPUT: - ``k`` -- an integer - ``prec`` -- (default: 10) a positive integer - ``cusp_only`` -- bool (default: False) - ``var`` -- string (default: 'q') OUTPUT: A sequence whose entries are power series in ``ZZ[[var]]``. EXAMPLES:: sage: victor_miller_basis(1, 6) [] sage: victor_miller_basis(0, 6) [ 1 + O(q^6) ] sage: victor_miller_basis(2, 6) [] sage: victor_miller_basis(4, 6) [ 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6) ] sage: victor_miller_basis(6, 6, var='w') [ 1 - 504*w - 16632*w^2 - 122976*w^3 - 532728*w^4 - 1575504*w^5 + O(w^6) ] sage: victor_miller_basis(6, 6) [ 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6) ] sage: victor_miller_basis(12, 6) [ 1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6), q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) ] sage: victor_miller_basis(12, 6, cusp_only=True) [ q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) ] sage: victor_miller_basis(24, 6, cusp_only=True) [ q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) ] sage: victor_miller_basis(24, 6) [ 1 + 52416000*q^3 + 39007332000*q^4 + 6609020221440*q^5 + O(q^6), q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) ] sage: victor_miller_basis(32, 6) [ 1 + 2611200*q^3 + 19524758400*q^4 + 19715347537920*q^5 + O(q^6), q + 50220*q^3 + 87866368*q^4 + 18647219790*q^5 + O(q^6), q^2 + 432*q^3 + 39960*q^4 - 1418560*q^5 + O(q^6) ] sage: victor_miller_basis(40,200)[1:] == victor_miller_basis(40,200,cusp_only=True) True sage: victor_miller_basis(200,40)[1:] == victor_miller_basis(200,40,cusp_only=True) True AUTHORS: - William Stein, Craig Citro: original code - Martin Raum (2009-08-02): use FLINT for polynomial arithmetic (instead of NTL) """ k = Integer(k) if k%2 == 1 or k==2: return Sequence([]) elif k < 0: raise ValueError("k must be non-negative") elif k == 0: return Sequence([PowerSeriesRing(ZZ,var)(1).add_bigoh(prec)], cr=True) e = k.mod(12) if e == 2: e += 12 n = (k-e) // 12 if n == 0 and cusp_only: return Sequence([]) # If prec is less than or equal to the dimension of the space of # cusp forms, which is just n, then we know the answer, and we # simply return it. if prec <= n: q = PowerSeriesRing(ZZ,var).gen(0) err = bigO(q**prec) ls = [0] * (n+1) if not cusp_only: ls[0] = 1 + err for i in range(1,prec): ls[i] = q**i + err for i in range(prec,n+1): ls[i] = err return Sequence(ls, cr=True) F6 = eisenstein_series_poly(6,prec) if e == 0: A = Fmpz_poly(1) elif e == 4: A = eisenstein_series_poly(4,prec) elif e == 6: A = F6 elif e == 8: A = eisenstein_series_poly(8,prec) elif e == 10: A = eisenstein_series_poly(10,prec) else: # e == 14 A = eisenstein_series_poly(14,prec) if A[0] == -1 : A = -A if n == 0: return Sequence([PowerSeriesRing(ZZ,var)(A.list()).add_bigoh(prec)],cr=True) F6_squared = F6**2 F6_squared._unsafe_mutate_truncate(prec) D = _delta_poly(prec) Fprod = F6_squared Dprod = D if cusp_only: ls = [Fmpz_poly(0)] + [A] * n else: ls = [A] * (n+1) for i in xrange(1,n+1): ls[n-i] *= Fprod ls[i] *= Dprod ls[n-i]._unsafe_mutate_truncate(prec) ls[i]._unsafe_mutate_truncate(prec) Fprod *= F6_squared Dprod *= D Fprod._unsafe_mutate_truncate(prec) Dprod._unsafe_mutate_truncate(prec) P = PowerSeriesRing(ZZ,var) if cusp_only : for i in xrange(1,n+1) : for j in xrange(1, i) : ls[j] = ls[j] - ls[j][i]*ls[i] return Sequence(map(lambda l: P(l.list()).add_bigoh(prec), ls[1:]),cr=True) else : for i in xrange(1,n+1) : for j in xrange(i) : ls[j] = ls[j] - ls[j][i]*ls[i] return Sequence(map(lambda l: P(l.list()).add_bigoh(prec), ls), cr=True)
def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): r""" Compute and return the Victor Miller basis for modular forms of weight `k` and level 1 to precision `O(q^{prec})`. If ``cusp_only`` is True, return only a basis for the cuspidal subspace. INPUT: - ``k`` -- an integer - ``prec`` -- (default: 10) a positive integer - ``cusp_only`` -- bool (default: False) - ``var`` -- string (default: 'q') OUTPUT: A sequence whose entries are power series in ``ZZ[[var]]``. EXAMPLES:: sage: victor_miller_basis(1, 6) [] sage: victor_miller_basis(0, 6) [ 1 + O(q^6) ] sage: victor_miller_basis(2, 6) [] sage: victor_miller_basis(4, 6) [ 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6) ] sage: victor_miller_basis(6, 6, var='w') [ 1 - 504*w - 16632*w^2 - 122976*w^3 - 532728*w^4 - 1575504*w^5 + O(w^6) ] sage: victor_miller_basis(6, 6) [ 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6) ] sage: victor_miller_basis(12, 6) [ 1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6), q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) ] sage: victor_miller_basis(12, 6, cusp_only=True) [ q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) ] sage: victor_miller_basis(24, 6, cusp_only=True) [ q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) ] sage: victor_miller_basis(24, 6) [ 1 + 52416000*q^3 + 39007332000*q^4 + 6609020221440*q^5 + O(q^6), q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) ] sage: victor_miller_basis(32, 6) [ 1 + 2611200*q^3 + 19524758400*q^4 + 19715347537920*q^5 + O(q^6), q + 50220*q^3 + 87866368*q^4 + 18647219790*q^5 + O(q^6), q^2 + 432*q^3 + 39960*q^4 - 1418560*q^5 + O(q^6) ] sage: victor_miller_basis(40,200)[1:] == victor_miller_basis(40,200,cusp_only=True) True sage: victor_miller_basis(200,40)[1:] == victor_miller_basis(200,40,cusp_only=True) True AUTHORS: - William Stein, Craig Citro: original code - Martin Raum (2009-08-02): use FLINT for polynomial arithmetic (instead of NTL) """ k = Integer(k) if k % 2 == 1 or k == 2: return Sequence([]) elif k < 0: raise ValueError("k must be non-negative") elif k == 0: return Sequence([PowerSeriesRing(ZZ, var)(1).add_bigoh(prec)], cr=True) e = k.mod(12) if e == 2: e += 12 n = (k - e) // 12 if n == 0 and cusp_only: return Sequence([]) # If prec is less than or equal to the dimension of the space of # cusp forms, which is just n, then we know the answer, and we # simply return it. if prec <= n: q = PowerSeriesRing(ZZ, var).gen(0) err = bigO(q**prec) ls = [0] * (n + 1) if not cusp_only: ls[0] = 1 + err for i in range(1, prec): ls[i] = q**i + err for i in range(prec, n + 1): ls[i] = err return Sequence(ls, cr=True) F6 = eisenstein_series_poly(6, prec) if e == 0: A = Fmpz_poly(1) elif e == 4: A = eisenstein_series_poly(4, prec) elif e == 6: A = F6 elif e == 8: A = eisenstein_series_poly(8, prec) elif e == 10: A = eisenstein_series_poly(10, prec) else: # e == 14 A = eisenstein_series_poly(14, prec) if A[0] == -1: A = -A if n == 0: return Sequence([PowerSeriesRing(ZZ, var)(A.list()).add_bigoh(prec)], cr=True) F6_squared = F6**2 F6_squared._unsafe_mutate_truncate(prec) D = _delta_poly(prec) Fprod = F6_squared Dprod = D if cusp_only: ls = [Fmpz_poly(0)] + [A] * n else: ls = [A] * (n + 1) for i in xrange(1, n + 1): ls[n - i] *= Fprod ls[i] *= Dprod ls[n - i]._unsafe_mutate_truncate(prec) ls[i]._unsafe_mutate_truncate(prec) Fprod *= F6_squared Dprod *= D Fprod._unsafe_mutate_truncate(prec) Dprod._unsafe_mutate_truncate(prec) P = PowerSeriesRing(ZZ, var) if cusp_only: for i in xrange(1, n + 1): for j in xrange(1, i): ls[j] = ls[j] - ls[j][i] * ls[i] return Sequence([P(l.list()).add_bigoh(prec) for l in ls[1:]], cr=True) else: for i in xrange(1, n + 1): for j in xrange(i): ls[j] = ls[j] - ls[j][i] * ls[i] return Sequence([P(l.list()).add_bigoh(prec) for l in ls], cr=True)