Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/modform/eis_series_cython.pyx
4097 views
1
"""
2
Eisenstein Series (optimized compiled functions)
3
"""
4
5
include 'sage/ext/cdefs.pxi'
6
include 'sage/ext/stdsage.pxi'
7
include 'sage/ext/interrupt.pxi'
8
include 'sage/ext/gmp.pxi'
9
include 'sage/libs/flint/fmpz_poly.pxi'
10
11
from sage.rings.rational_field import QQ
12
from sage.rings.power_series_ring import PowerSeriesRing
13
from sage.rings.integer cimport Integer
14
from sage.rings.arith import primes, bernoulli
15
from sage.rings.fast_arith cimport prime_range
16
from sage.libs.flint.fmpz_poly cimport Fmpz_poly
17
18
cpdef Ek_ZZ(int k, int prec=10):
19
"""
20
Return list of prec integer coefficients of the weight k
21
Eisenstein series of level 1, normalized so the coefficient of q
22
is 1, except that the 0th coefficient is set to 1 instead of its
23
actual value.
24
25
INPUT:
26
27
- `k` -- int
28
- ``prec`` -- int
29
30
OUTPUT:
31
32
- list of Sage Integers.
33
34
EXAMPLES::
35
36
sage: from sage.modular.modform.eis_series_cython import Ek_ZZ
37
sage: Ek_ZZ(4,10)
38
[1, 1, 9, 28, 73, 126, 252, 344, 585, 757]
39
sage: [sigma(n,3) for n in [1..9]]
40
[1, 9, 28, 73, 126, 252, 344, 585, 757]
41
sage: Ek_ZZ(10,10^3) == [1] + [sigma(n,9) for n in range(1,10^3)]
42
True
43
"""
44
cdef Integer pp
45
cdef mpz_t q, current_sum, q_plus_one
46
47
cdef unsigned long p
48
cdef Py_ssize_t i, ind
49
cdef bint continue_flag
50
51
cdef list power_sum_ls
52
53
cdef unsigned long max_power_sum, temp_index
54
cdef unsigned long remainder, prev_index
55
cdef unsigned long additional_p_powers
56
57
mpz_init(q)
58
mpz_init(current_sum)
59
mpz_init(q_plus_one)
60
61
# allocate the list for the result
62
cdef list val = []
63
for i from 0 <= i < prec:
64
pp = <Integer>(PY_NEW(Integer))
65
mpz_set_si(pp.value, 1)
66
val.append(pp)
67
68
# no need to reallocate this list every time -- just reuse the
69
# Integers in it
70
power_sum_ls = []
71
max_power_sum = prec
72
while max_power_sum:
73
max_power_sum >>= 1
74
pp = <Integer>(PY_NEW(Integer))
75
mpz_set_si(pp.value, 1)
76
power_sum_ls.append(pp)
77
78
for pp in prime_range(prec):
79
p = mpz_get_ui((<Integer>pp).value)
80
mpz_ui_pow_ui(q, p, k - 1)
81
mpz_add_ui(q_plus_one, q, 1)
82
mpz_set(current_sum, q_plus_one)
83
84
# NOTE: I (wstein) did benchmarks, and the use of
85
# PyList_GET_ITEM in the code below is worth it since it leads
86
# to a significant speedup by not doing bounds checking.
87
88
# set power_sum_ls[1] = q+1
89
mpz_set((<Integer>(PyList_GET_ITEM(power_sum_ls, 1))).value,
90
current_sum)
91
max_power_sum = 1
92
93
ind = 0
94
while True:
95
continue_flag = 0
96
# do the first p-1
97
for i from 0 < i < p:
98
ind += p
99
if (ind >= prec):
100
continue_flag = 1
101
break
102
mpz_mul((<Integer>(PyList_GET_ITEM(val, ind))).value,
103
(<Integer>(PyList_GET_ITEM(val, ind))).value,
104
q_plus_one)
105
ind += p
106
if (ind >= prec or continue_flag):
107
break
108
109
# now do the pth one, which is harder.
110
111
# compute the valuation of n at p
112
additional_p_powers = 0
113
temp_index = ind / p
114
remainder = 0
115
while not remainder:
116
additional_p_powers += 1
117
prev_index = temp_index
118
temp_index = temp_index / p
119
remainder = prev_index - p*temp_index
120
121
# if we need a new sum, it has to be the next uncomputed one.
122
if (additional_p_powers > max_power_sum):
123
mpz_mul(current_sum, current_sum, q)
124
mpz_add_ui(current_sum, current_sum, 1)
125
max_power_sum += 1
126
127
mpz_set((<Integer>(PyList_GET_ITEM(power_sum_ls,
128
max_power_sum))).value,
129
current_sum)
130
131
# finally, set the coefficient
132
mpz_mul((<Integer>(PyList_GET_ITEM(val, ind))).value,
133
(<Integer>(PyList_GET_ITEM(val, ind))).value,
134
(<Integer>(PyList_GET_ITEM(power_sum_ls,
135
additional_p_powers))).value)
136
137
mpz_clear(q)
138
mpz_clear(current_sum)
139
mpz_clear(q_plus_one)
140
141
return val
142
143
144
cpdef eisenstein_series_poly(int k, int prec = 10) :
145
r"""
146
Return the q-expansion up to precision ``prec`` of the weight `k`
147
Eisenstein series, as a FLINT :class:`~sage.libs.flint.fmpz_poly.Fmpz_poly`
148
object, normalised so the coefficients are integers with no common factor.
149
150
Used internally by the functions
151
:func:`~sage.modular.modform.eis_series.eisenstein_series_qexp` and
152
:func:`~sage.modular.modform.vm_basis.victor_miller_basis`; see the
153
docstring of the former for further details.
154
155
EXAMPLES::
156
157
sage: from sage.modular.modform.eis_series_cython import eisenstein_series_poly
158
sage: eisenstein_series_poly(12, prec=5)
159
5 691 65520 134250480 11606736960 274945048560
160
"""
161
cdef mpz_t *val = <mpz_t *>sage_malloc(prec * sizeof(mpz_t))
162
cdef mpz_t one, mult, term, last, term_m1, last_m1
163
cdef unsigned long int expt
164
cdef long ind, ppow, int_p
165
cdef int i
166
cdef Fmpz_poly res = PY_NEW(Fmpz_poly)
167
168
if k%2 or k < 2:
169
raise ValueError, "k (=%s) must be an even positive integer"%k
170
if prec < 0:
171
raise ValueError, "prec (=%s) must be an even nonnegative integer"%prec
172
if (prec == 0):
173
return PY_NEW(Fmpz_poly)
174
175
sig_on()
176
177
mpz_init(one)
178
mpz_init(term)
179
mpz_init(last)
180
mpz_init(mult)
181
mpz_init(term_m1)
182
mpz_init(last_m1)
183
184
for i from 0 <= i < prec :
185
mpz_init(val[i])
186
mpz_set_si(val[i], 1)
187
188
mpz_set_si(one, 1)
189
190
expt = <unsigned long int>(k - 1)
191
a0 = - bernoulli(k) / (2*k)
192
193
for p in primes(1,prec) :
194
int_p = int(p)
195
ppow = <long int>int_p
196
197
mpz_set_si(mult, int_p)
198
mpz_pow_ui(mult, mult, expt)
199
mpz_mul(term, mult, mult)
200
mpz_set(last, mult)
201
202
while (ppow < prec):
203
ind = ppow
204
mpz_sub(term_m1, term, one)
205
mpz_sub(last_m1, last, one)
206
while (ind < prec):
207
mpz_mul(val[ind], val[ind], term_m1)
208
mpz_fdiv_q(val[ind], val[ind], last_m1)
209
ind += ppow
210
ppow *= int_p
211
mpz_set(last, term)
212
mpz_mul(term, term, mult)
213
214
mpz_clear(one)
215
mpz_clear(term)
216
mpz_clear(last)
217
mpz_clear(mult)
218
mpz_clear(term_m1)
219
mpz_clear(last_m1)
220
221
fmpz_poly_set_coeff_mpz(res.poly, prec-1, val[prec-1])
222
for i from 1 <= i < prec - 1 :
223
fmpz_poly_set_coeff_mpz(res.poly, i, val[i])
224
225
fmpz_poly_scalar_mul_mpz(res.poly, res.poly, (<Integer>(a0.denominator())).value)
226
fmpz_poly_set_coeff_mpz(res.poly, 0, (<Integer>(a0.numerator())).value)
227
228
sage_free(val)
229
230
sig_off()
231
232
return res
233
234