Path: blob/master/sage/modular/modform/eis_series_cython.pyx
4097 views
"""1Eisenstein Series (optimized compiled functions)2"""34include 'sage/ext/cdefs.pxi'5include 'sage/ext/stdsage.pxi'6include 'sage/ext/interrupt.pxi'7include 'sage/ext/gmp.pxi'8include 'sage/libs/flint/fmpz_poly.pxi'910from sage.rings.rational_field import QQ11from sage.rings.power_series_ring import PowerSeriesRing12from sage.rings.integer cimport Integer13from sage.rings.arith import primes, bernoulli14from sage.rings.fast_arith cimport prime_range15from sage.libs.flint.fmpz_poly cimport Fmpz_poly1617cpdef Ek_ZZ(int k, int prec=10):18"""19Return list of prec integer coefficients of the weight k20Eisenstein series of level 1, normalized so the coefficient of q21is 1, except that the 0th coefficient is set to 1 instead of its22actual value.2324INPUT:2526- `k` -- int27- ``prec`` -- int2829OUTPUT:3031- list of Sage Integers.3233EXAMPLES::3435sage: from sage.modular.modform.eis_series_cython import Ek_ZZ36sage: Ek_ZZ(4,10)37[1, 1, 9, 28, 73, 126, 252, 344, 585, 757]38sage: [sigma(n,3) for n in [1..9]]39[1, 9, 28, 73, 126, 252, 344, 585, 757]40sage: Ek_ZZ(10,10^3) == [1] + [sigma(n,9) for n in range(1,10^3)]41True42"""43cdef Integer pp44cdef mpz_t q, current_sum, q_plus_one4546cdef unsigned long p47cdef Py_ssize_t i, ind48cdef bint continue_flag4950cdef list power_sum_ls5152cdef unsigned long max_power_sum, temp_index53cdef unsigned long remainder, prev_index54cdef unsigned long additional_p_powers5556mpz_init(q)57mpz_init(current_sum)58mpz_init(q_plus_one)5960# allocate the list for the result61cdef list val = []62for i from 0 <= i < prec:63pp = <Integer>(PY_NEW(Integer))64mpz_set_si(pp.value, 1)65val.append(pp)6667# no need to reallocate this list every time -- just reuse the68# Integers in it69power_sum_ls = []70max_power_sum = prec71while max_power_sum:72max_power_sum >>= 173pp = <Integer>(PY_NEW(Integer))74mpz_set_si(pp.value, 1)75power_sum_ls.append(pp)7677for pp in prime_range(prec):78p = mpz_get_ui((<Integer>pp).value)79mpz_ui_pow_ui(q, p, k - 1)80mpz_add_ui(q_plus_one, q, 1)81mpz_set(current_sum, q_plus_one)8283# NOTE: I (wstein) did benchmarks, and the use of84# PyList_GET_ITEM in the code below is worth it since it leads85# to a significant speedup by not doing bounds checking.8687# set power_sum_ls[1] = q+188mpz_set((<Integer>(PyList_GET_ITEM(power_sum_ls, 1))).value,89current_sum)90max_power_sum = 19192ind = 093while True:94continue_flag = 095# do the first p-196for i from 0 < i < p:97ind += p98if (ind >= prec):99continue_flag = 1100break101mpz_mul((<Integer>(PyList_GET_ITEM(val, ind))).value,102(<Integer>(PyList_GET_ITEM(val, ind))).value,103q_plus_one)104ind += p105if (ind >= prec or continue_flag):106break107108# now do the pth one, which is harder.109110# compute the valuation of n at p111additional_p_powers = 0112temp_index = ind / p113remainder = 0114while not remainder:115additional_p_powers += 1116prev_index = temp_index117temp_index = temp_index / p118remainder = prev_index - p*temp_index119120# if we need a new sum, it has to be the next uncomputed one.121if (additional_p_powers > max_power_sum):122mpz_mul(current_sum, current_sum, q)123mpz_add_ui(current_sum, current_sum, 1)124max_power_sum += 1125126mpz_set((<Integer>(PyList_GET_ITEM(power_sum_ls,127max_power_sum))).value,128current_sum)129130# finally, set the coefficient131mpz_mul((<Integer>(PyList_GET_ITEM(val, ind))).value,132(<Integer>(PyList_GET_ITEM(val, ind))).value,133(<Integer>(PyList_GET_ITEM(power_sum_ls,134additional_p_powers))).value)135136mpz_clear(q)137mpz_clear(current_sum)138mpz_clear(q_plus_one)139140return val141142143cpdef eisenstein_series_poly(int k, int prec = 10) :144r"""145Return the q-expansion up to precision ``prec`` of the weight `k`146Eisenstein series, as a FLINT :class:`~sage.libs.flint.fmpz_poly.Fmpz_poly`147object, normalised so the coefficients are integers with no common factor.148149Used internally by the functions150:func:`~sage.modular.modform.eis_series.eisenstein_series_qexp` and151:func:`~sage.modular.modform.vm_basis.victor_miller_basis`; see the152docstring of the former for further details.153154EXAMPLES::155156sage: from sage.modular.modform.eis_series_cython import eisenstein_series_poly157sage: eisenstein_series_poly(12, prec=5)1585 691 65520 134250480 11606736960 274945048560159"""160cdef mpz_t *val = <mpz_t *>sage_malloc(prec * sizeof(mpz_t))161cdef mpz_t one, mult, term, last, term_m1, last_m1162cdef unsigned long int expt163cdef long ind, ppow, int_p164cdef int i165cdef Fmpz_poly res = PY_NEW(Fmpz_poly)166167if k%2 or k < 2:168raise ValueError, "k (=%s) must be an even positive integer"%k169if prec < 0:170raise ValueError, "prec (=%s) must be an even nonnegative integer"%prec171if (prec == 0):172return PY_NEW(Fmpz_poly)173174sig_on()175176mpz_init(one)177mpz_init(term)178mpz_init(last)179mpz_init(mult)180mpz_init(term_m1)181mpz_init(last_m1)182183for i from 0 <= i < prec :184mpz_init(val[i])185mpz_set_si(val[i], 1)186187mpz_set_si(one, 1)188189expt = <unsigned long int>(k - 1)190a0 = - bernoulli(k) / (2*k)191192for p in primes(1,prec) :193int_p = int(p)194ppow = <long int>int_p195196mpz_set_si(mult, int_p)197mpz_pow_ui(mult, mult, expt)198mpz_mul(term, mult, mult)199mpz_set(last, mult)200201while (ppow < prec):202ind = ppow203mpz_sub(term_m1, term, one)204mpz_sub(last_m1, last, one)205while (ind < prec):206mpz_mul(val[ind], val[ind], term_m1)207mpz_fdiv_q(val[ind], val[ind], last_m1)208ind += ppow209ppow *= int_p210mpz_set(last, term)211mpz_mul(term, term, mult)212213mpz_clear(one)214mpz_clear(term)215mpz_clear(last)216mpz_clear(mult)217mpz_clear(term_m1)218mpz_clear(last_m1)219220fmpz_poly_set_coeff_mpz(res.poly, prec-1, val[prec-1])221for i from 1 <= i < prec - 1 :222fmpz_poly_set_coeff_mpz(res.poly, i, val[i])223224fmpz_poly_scalar_mul_mpz(res.poly, res.poly, (<Integer>(a0.denominator())).value)225fmpz_poly_set_coeff_mpz(res.poly, 0, (<Integer>(a0.numerator())).value)226227sage_free(val)228229sig_off()230231return res232233234