Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
#################################################################################
2
#
3
# (c) Copyright 2011 William Stein
4
#
5
# This file is part of PSAGE
6
#
7
# PSAGE is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# PSAGE is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
#
20
#################################################################################
21
22
"""
23
Python code for very fast high precision computation of certain
24
specific modular forms of interest.
25
"""
26
27
import sys
28
from sage.rings.all import ZZ, QQ, PolynomialRing
29
from sage.modular.all import eisenstein_series_qexp, ModularForms
30
from sage.misc.all import cached_function, cputime, prod
31
32
from psage.modform.rational.special_fast import (
33
_change_ring_ZZ, _evaluate_series_at_power_of_gen,
34
Integer_list_to_polynomial)
35
36
def degen(h, n):
37
"""
38
Return power series h(q^n) to the same precision as h.
39
40
INPUT:
41
- h -- power series over the rational numbers
42
- n -- positive integer
43
OUTPUT:
44
- power series over the rational numbers
45
46
EXAMPLES::
47
48
sage: from psage.modform.rational.special import degen
49
sage: R.<q> = QQ[[]]
50
sage: f = 2/3 + 3*q + 14*q^2 + O(q^3)
51
sage: degen(f,2)
52
2/3 + 3*q^2 + O(q^3)
53
"""
54
if n == 1:
55
return h
56
return _evaluate_series_at_power_of_gen(h,n,True)
57
58
#############################################################
59
60
61
@cached_function
62
def cached_eisenstein_series_qexp(k, prec, verbose=False):
63
"""
64
Return q-expansion of the weight k level 1 Eisenstein series to
65
the requested precision. The result is cached, so that subsequent
66
calls are quick.
67
68
INPUT:
69
- k -- even positive integer
70
- prec -- positive integer
71
- verbose -- bool (default: False); if True, print timing information
72
73
OUTPUT:
74
- power series over the rational numbers
75
76
EXAMPLES::
77
78
sage: from psage.modform.rational.special import cached_eisenstein_series_qexp
79
sage: cached_eisenstein_series_qexp(4, 10)
80
1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + 252*q^6 + 344*q^7 + 585*q^8 + 757*q^9 + O(q^10)
81
sage: cached_eisenstein_series_qexp(4, 5, verbose=True)
82
Computing E_4(q) + O(q^5)... (time = ... seconds)
83
1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + O(q^5)
84
sage: cached_eisenstein_series_qexp(4, 5, verbose=True) # cache used, so no timing printed
85
1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + O(q^5)
86
"""
87
if verbose: print "Computing E_%s(q) + O(q^%s)..."%(k,prec),; sys.stdout.flush(); t = cputime()
88
e = eisenstein_series_qexp(k, prec)
89
if verbose: print "(time = %.2f seconds)"%cputime(t)
90
return e
91
92
def eis_qexp(k, t, prec, verbose=False):
93
"""
94
Return the q-expansion of holomorphic level t weight k Eisenstein
95
series. Thus when k=2, this is E2(q) - t*E2(q^t), and is Ek(q^t)
96
otherwise.
97
98
INPUT:
99
- k -- even positive integer
100
- t -- positive integer
101
- prec -- positive integer
102
- verbose -- bool (default: False); if True, print timing information
103
104
OUTPUT:
105
- power series over the rational numbers
106
107
EXAMPLES::
108
109
sage: from psage.modform.rational.special import eis_qexp
110
sage: eis_qexp(2, 1, 8) # output is 0, since holomorphic
111
O(q^8)
112
sage: eis_qexp(2, 3, 8)
113
1/12 + q + 3*q^2 + q^3 + 7*q^4 + 6*q^5 + 3*q^6 + 8*q^7 + O(q^8)
114
sage: E2 = eisenstein_series_qexp(2, 8)
115
sage: q = E2.parent().0
116
sage: E2(q) - 3*E2(q^3)
117
1/12 + q + 3*q^2 + q^3 + 7*q^4 + 6*q^5 + 3*q^6 + 8*q^7 + O(q^8)
118
sage: eis_qexp(4, 3, 8)
119
1/240 + q^3 + 9*q^6 + O(q^8)
120
sage: eisenstein_series_qexp(4, 8)(q^3)
121
1/240 + q^3 + 9*q^6 + 28*q^9 + 73*q^12 + 126*q^15 + 252*q^18 + 344*q^21 + O(q^24)
122
123
Test verbose::
124
125
sage: eis_qexp(2, 5, 7, verbose=True)
126
Computing E_2(q) + O(q^8)... (time = ... seconds)
127
1/6 + q + 3*q^2 + 4*q^3 + 7*q^4 + q^5 + 12*q^6 + O(q^7)
128
"""
129
Ek = cached_eisenstein_series_qexp(k, prec+1, verbose=verbose)
130
q = Ek.parent().gen()
131
if k == 2:
132
e = Ek - t*degen(Ek,t)
133
else:
134
e = degen(Ek,t)
135
return e.add_bigoh(prec)
136
137
def eisenstein_gens(N, k, prec, verbose=False):
138
r"""
139
Find spanning list of 'easy' generators for the subspace of
140
`M_k(\Gamma_0(N))` spanned by polynomials in Eisenstein series.
141
142
The meaning of 'easy' is that the modular form is a monomial of
143
weight `k` in the images of Eisenstein series from level `1` of
144
weight dividing `k`. Note that this list need not span the full
145
space `M_k(\Gamma_0(N))`
146
147
INPUT:
148
- N -- positive integer
149
- k -- even positive integer
150
- prec -- positive integer
151
- verbose -- bool (default: False); if True, print timing information
152
153
OUTPUT:
154
- list of triples (t,w,E), where E is the q-expansion of the
155
weight w, holomorphic Eisenstein series of level t.
156
157
EXAMPLES::
158
159
sage: from psage.modform.rational.special import eisenstein_gens
160
sage: eisenstein_gens(5,4,6)
161
[(1, 2, O(q^6)), (5, 2, 1/6 + q + 3*q^2 + 4*q^3 + 7*q^4 + q^5 + O(q^6)), (1, 4, 1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6)), (5, 4, 1/240 + q^5 + O(q^6))]
162
sage: eisenstein_gens(11,2,6)
163
[(1, 2, O(q^6)), (11, 2, 5/12 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6))]
164
165
Test verbose option::
166
167
sage: eisenstein_gens(11,2,9,verbose=True)
168
Computing E_2(q) + O(q^10)... (time = 0.00 seconds)
169
[(1, 2, O(q^9)), (11, 2, 5/12 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + 12*q^6 + 8*q^7 + 15*q^8 + O(q^9))]
170
"""
171
assert N > 1
172
if k % 2 != 0:
173
return []
174
div = ZZ(N).divisors()
175
gens = []
176
for w in range(2, k+1, 2):
177
d = div if w > 2 else div[1:]
178
for t in div:
179
gens.append((t, w, eis_qexp(w, t, prec, verbose=verbose)))
180
return gens
181
182
class EisensteinMonomial(object):
183
"""
184
A monomial in terms of Eisenstein series.
185
"""
186
def __init__(self, v):
187
"""
188
INPUT:
189
- v -- a list of triples (k,t,n) that corresponds to E_k(q^t)^n.
190
191
EXAMPLES::
192
193
sage: from psage.modform.rational.special import EisensteinMonomial
194
sage: e = EisensteinMonomial([(5,4,2), (5,6,3)]); e
195
E4(q^5)^2*E6(q^5)^3
196
sage: type(e)
197
<class 'psage.modform.rational.special.EisensteinMonomial'>
198
"""
199
self._v = v
200
201
def __repr__(self):
202
"""
203
EXAMPLES::
204
205
sage: from psage.modform.rational.special import EisensteinMonomial
206
sage: e = EisensteinMonomial([(5,4,12), (5,6,3)]); e.__repr__()
207
'E4(q^5)^12*E6(q^5)^3'
208
"""
209
return '*'.join(['E%s%s(q^%s)^%s'%(k,'^*' if k==2 else '', t,e) for t,k,e in self._v])
210
211
def qexp(self, prec, verbose=False):
212
"""
213
The q-expansion of a monomial in Eisenstein series.
214
215
INPUT:
216
- prec -- positive integer
217
- verbose -- bool (default: False)
218
219
EXAMPLES::
220
221
sage: from psage.modform.rational.special import EisensteinMonomial
222
sage: e = EisensteinMonomial([(5,4,2), (5,6,3)])
223
sage: e.qexp(11)
224
-1/7374186086400 + 43/307257753600*q^5 - 671/102419251200*q^10 + O(q^11)
225
sage: E4 = eisenstein_series_qexp(4,11); q = E4.parent().gen()
226
sage: E6 = eisenstein_series_qexp(6,11)
227
sage: (E4(q^5)^2 * E6(q^5)^3).add_bigoh(11)
228
-1/7374186086400 + 43/307257753600*q^5 - 671/102419251200*q^10 + O(q^11)
229
"""
230
z = [eis_qexp(k, t, prec, verbose=verbose)**e for t,k,e in self._v]
231
if verbose: print "Arithmetic to compute %s +O(q^%s)"%(self, prec); sys.stdout.flush(); t=cputime()
232
p = prod(z)
233
if verbose: print "(time = %.2f seconds)"%cputime(t)
234
return p
235
236
237
def _monomials(v, n, i):
238
"""
239
Used internally for recursively computing monomials function.
240
Returns each power of the ith generator times all products not
241
involving the ith generator.
242
243
INPUT:
244
- `v` -- see docstring for monomials
245
- `n` -- see docstring for monomials
246
- `i` -- nonnegative integer
247
248
OUTPUT:
249
- list
250
251
EXAMPLES::
252
253
sage: from psage.modform.rational.special import _monomials
254
sage: R.<x,y> = QQ[]
255
sage: _monomials([(x,2),(y,3)], 6, 0)
256
[y^2, x^3]
257
sage: _monomials([(x,2),(y,3)], 6, 1)
258
[x^3, y^2]
259
"""
260
# each power of the ith generator times all products
261
# not involving the ith generator.
262
if len(v) == 1:
263
b, k = v[0]
264
if n%k == 0:
265
return [b**(n//k)]
266
else:
267
return []
268
else:
269
z, k = v[i]
270
w = list(v)
271
del w[i]
272
m = 0
273
y = 1
274
result = []
275
while m <= n:
276
for X in monomials(w, n - m):
277
result.append(X*y)
278
y *= z
279
m += k
280
return result
281
282
def monomials(v, n):
283
"""
284
Return homogeneous monomials of degree exactly n.
285
286
INPUT:
287
- v -- list of pairs (x,d), where x is a ring element that
288
we view as having degree d.
289
- n -- positive integer
290
291
OUTPUT:
292
- list of monomials in elements of v
293
294
EXAMPLES::
295
296
sage: from psage.modform.rational.special import monomials
297
sage: R.<x,y> = QQ[]
298
sage: monomials([(x,2),(y,3)], 6)
299
[y^2, x^3]
300
sage: [monomials([(x,2),(y,3)], i) for i in [0..6]]
301
[[1], [], [x], [y], [x^2], [x*y], [y^2, x^3]]
302
"""
303
if len(v) == 0:
304
return []
305
return _monomials(v, n, 0)
306
307
308
def eisenstein_basis(N, k, verbose=False):
309
r"""
310
Find spanning list of 'easy' generators for the subspace of
311
`M_k(\Gamma_0(N))` generated by level 1 Eisenstein series and
312
their images of even integer weights up to `k`.
313
314
INPUT:
315
- N -- positive integer
316
- k -- positive integer
317
- ``verbose`` -- bool (default: False)
318
319
OUTPUT:
320
- list of monomials in images of level 1 Eisenstein series
321
- prec of q-expansions needed to determine element of
322
`M_k(\Gamma_0(N))`.
323
324
EXAMPLES::
325
326
sage: from psage.modform.rational.special import eisenstein_basis
327
sage: eisenstein_basis(5,4)
328
([E4(q^5)^1, E4(q^1)^1, E2^*(q^5)^2], 3)
329
sage: eisenstein_basis(11,2,verbose=True) # warning below because of verbose
330
Warning -- not enough series.
331
([E2^*(q^11)^1], 2)
332
sage: eisenstein_basis(11,2,verbose=False)
333
([E2^*(q^11)^1], 2)
334
"""
335
assert N > 1
336
if k % 2 != 0:
337
return []
338
# Make list E of Eisenstein series, to enough precision to
339
# determine them, until we span space.
340
M = ModularForms(N, k)
341
prec = M.echelon_basis()[-1].valuation() + 1
342
343
gens = eisenstein_gens(N, k, prec)
344
R = PolynomialRing(ZZ, len(gens), ['E%sq%s'%(g[1],g[0]) for g in gens])
345
z = [(R.gen(i), g[1]) for i, g in enumerate(gens)]
346
m = monomials(z, k)
347
348
A = QQ**prec
349
V = A.zero_subspace()
350
E = []
351
for i, z in enumerate(m):
352
d = z.degrees()
353
f = prod(g[2]**d[i] for i, g in enumerate(gens) if d[i])
354
v = A(f.padded_list(prec))
355
if v not in V:
356
V = V + A.span([v])
357
w = [(gens[i][0],gens[i][1],d[i]) for i in range(len(d)) if d[i]]
358
E.append(EisensteinMonomial(w))
359
if V.dimension() == M.dimension():
360
return E, prec
361
362
if verbose: print "Warning -- not enough series."
363
return E, prec
364
365
366
class FastModularForm(object):
367
"""
368
EXAMPLES::
369
370
sage: from psage.modform.rational.special import FastModularForm
371
372
Level 5, weight 4::
373
374
sage: f = FastModularForm(CuspForms(5,4).0); f
375
(-250/3)*E4(q^5)^1 + (-10/3)*E4(q^1)^1 + (13)*E2^*(q^5)^2
376
sage: f.qexp(10)
377
q - 4*q^2 + 2*q^3 + 8*q^4 - 5*q^5 - 8*q^6 + 6*q^7 - 23*q^9 + O(q^10)
378
sage: parent(f.qexp(10))
379
Power Series Ring in q over Integer Ring
380
sage: t=cputime(); h=f.qexp(10^5); assert cputime(t)<5 # a little timing test.
381
382
Level 5, weight 6::
383
384
sage: f = CuspForms(5,6).0; g = FastModularForm(f); g
385
(521/6)*E6(q^5)^1 + (-1/30)*E6(q^1)^1 + (248)*E2^*(q^5)^1*E4(q^5)^1
386
387
Level 8, weight 4::
388
389
sage: f = CuspForms(8,4).0; g = FastModularForm(f); g
390
(-256/3)*E4(q^8)^1 + (4)*E4(q^4)^1 + (1)*E4(q^2)^1 + (-4/3)*E4(q^1)^1 + (4)*E2^*(q^8)^2
391
392
Level 7, weight 4::
393
394
sage: f = CuspForms(7,4).0; g = FastModularForm(f); g
395
(-147/2)*E4(q^7)^1 + (-3/2)*E4(q^1)^1 + (5)*E2^*(q^7)^2
396
397
"""
398
def __init__(self, f, verbose=False):
399
"""
400
EXAMPLES::
401
402
Level 3, weight 6::
403
404
sage: from psage.modform.rational.special import FastModularForm
405
sage: f = CuspForms(3,6).0; g = FastModularForm(f); g
406
(549/10)*E6(q^3)^1 + (-3/10)*E6(q^1)^1 + (312)*E2^*(q^3)^1*E4(q^3)^1
407
sage: type(g)
408
<class 'psage.modform.rational.special.FastModularForm'>
409
"""
410
import sage.modular.modform.element
411
if not isinstance(f, sage.modular.modform.element.ModularForm_abstract):
412
raise TypeError
413
chi = f.character()
414
if not chi or not chi.is_trivial():
415
raise ValueError, "form must trivial character"
416
self._f = f
417
418
N = f.level()
419
k = f.weight()
420
B, prec = eisenstein_basis(N, k, verbose=verbose)
421
422
# Now write f in terms of q-expansions of elements in B.
423
V = QQ**prec
424
W = V.span_of_basis([V(h.qexp(prec).padded_list()) for h in B])
425
self._basis = B
426
self._coordinates = W.coordinates(f.qexp(prec).padded_list())
427
self._verbose = verbose
428
429
assert self.qexp(prec) == f.qexp(prec), "bug -- q-expansions don't match"
430
431
def qexp(self, prec):
432
"""
433
Return the q-expansion of this fast modular form to the given
434
precision.
435
436
EXAMPLES::
437
438
sage: from psage.modform.rational.special import FastModularForm
439
sage: f = FastModularForm(CuspForms(5,4).0); f
440
(-250/3)*E4(q^5)^1 + (-10/3)*E4(q^1)^1 + (13)*E2^*(q^5)^2
441
sage: f.qexp(10)
442
q - 4*q^2 + 2*q^3 + 8*q^4 - 5*q^5 - 8*q^6 + 6*q^7 - 23*q^9 + O(q^10)
443
sage: g = f.modular_form(); g
444
q - 4*q^2 + 2*q^3 + 8*q^4 - 5*q^5 + O(q^6)
445
sage: g.qexp(10)
446
q - 4*q^2 + 2*q^3 + 8*q^4 - 5*q^5 - 8*q^6 + 6*q^7 - 23*q^9 + O(q^10)
447
"""
448
f = sum(c*self._basis[i].qexp(prec, verbose=self._verbose)
449
for i, c in enumerate(self._coordinates) if c)
450
return ZZ[['q']](_change_ring_ZZ(f.polynomial()), prec)
451
452
q_expansion = qexp
453
454
def modular_form(self):
455
"""
456
Return the underlying modular form object.
457
458
EXAMPLES::
459
460
sage: from psage.modform.rational.special import FastModularForm
461
sage: f = FastModularForm(CuspForms(5,4).0); f
462
(-250/3)*E4(q^5)^1 + (-10/3)*E4(q^1)^1 + (13)*E2^*(q^5)^2
463
sage: f.qexp(10)
464
q - 4*q^2 + 2*q^3 + 8*q^4 - 5*q^5 - 8*q^6 + 6*q^7 - 23*q^9 + O(q^10)
465
sage: g = f.modular_form(); g.qexp(10)
466
q - 4*q^2 + 2*q^3 + 8*q^4 - 5*q^5 - 8*q^6 + 6*q^7 - 23*q^9 + O(q^10)
467
"""
468
return self._f
469
470
def __repr__(self):
471
"""
472
Print representation.
473
474
EXAMPLES::
475
476
sage: from psage.modform.rational.special import FastModularForm
477
sage: f = FastModularForm(CuspForms(5,4).0)
478
sage: f.__repr__()
479
'(-250/3)*E4(q^5)^1 + (-10/3)*E4(q^1)^1 + (13)*E2^*(q^5)^2'
480
"""
481
return ' + '.join('(%s)*%s'%(c, self._basis[i]) for i, c in enumerate(self._coordinates) if c)
482
483
484
485
486
487
488
#####################################################
489
# CM forms
490
#####################################################
491
492
from sage.all import fast_callable, prime_range, SR
493
from psage.ellcurve.lseries.helper import extend_multiplicatively_generic
494
495
def elliptic_cm_form(E, n, prec, aplist_only=False, anlist_only=False):
496
"""
497
Return q-expansion of the CM modular form associated to the n-th
498
power of the Grossencharacter associated to the elliptic curve E.
499
500
INPUT:
501
- E -- CM elliptic curve
502
- n -- positive integer
503
- prec -- positive integer
504
- aplist_only -- return list only of ap for p prime
505
- anlist_only -- return list only of an
506
507
OUTPUT:
508
- power series with integer coefficients
509
510
EXAMPLES::
511
512
sage: from psage.modform.rational.special import elliptic_cm_form
513
sage: f = CuspForms(121,4).newforms(names='a')[0]; f
514
q + 8*q^3 - 8*q^4 + 18*q^5 + O(q^6)
515
sage: E = EllipticCurve('121b')
516
sage: elliptic_cm_form(E, 3, 7)
517
q + 8*q^3 - 8*q^4 + 18*q^5 + O(q^7)
518
sage: g = elliptic_cm_form(E, 3, 100)
519
sage: g == f.q_expansion(100)
520
True
521
"""
522
if not E.has_cm():
523
raise ValueError, "E must have CM"
524
n = ZZ(n)
525
if n <= 0:
526
raise ValueError, "n must be positive"
527
528
prec = ZZ(prec)
529
if prec <= 0:
530
return []
531
elif prec <= 1:
532
return [ZZ(0)]
533
elif prec <= 2:
534
return [ZZ(0), ZZ(1)]
535
536
# Derive formula for sum of n-th powers of roots
537
a,p,T = SR.var('a,p,T')
538
roots = (T**2 - a*T + p).roots(multiplicities=False)
539
s = sum(alpha**n for alpha in roots).simplify_full()
540
541
# Create fast callable expression from formula
542
g = fast_callable(s.polynomial(ZZ))
543
544
# Compute aplist for the curve
545
v = E.aplist(prec)
546
547
# Use aplist to compute ap values for the CM form attached to n-th
548
# power of Grossencharacter.
549
P = prime_range(prec)
550
551
if aplist_only:
552
# case when we only want the a_p (maybe for computing an
553
# L-series via Euler product)
554
return [g(ap,p) for ap,p in zip(v,P)]
555
556
# Default cause where we want all a_n
557
anlist = [ZZ(0),ZZ(1)] + [None]*(prec-2)
558
for ap,p in zip(v,P):
559
anlist[p] = g(ap,p)
560
561
# Fill in the prime power a_{p^r} for r >= 2.
562
N = E.conductor()
563
for p in P:
564
prm2 = 1
565
prm1 = p
566
pr = p*p
567
pn = p**n
568
e = 1 if N%p else 0
569
while pr < prec:
570
anlist[pr] = anlist[prm1] * anlist[p]
571
if e:
572
anlist[pr] -= pn * anlist[prm2]
573
prm2 = prm1
574
prm1 = pr
575
pr *= p
576
577
# fill in a_n with n divisible by at least 2 primes
578
extend_multiplicatively_generic(anlist)
579
580
if anlist_only:
581
return anlist
582
583
f = Integer_list_to_polynomial(anlist, 'q')
584
return ZZ[['q']](f, prec=prec)
585
586
587
588
589
590