Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/modular/modform/find_generators.py
8820 views
1
"""
2
Graded Rings of Modular Forms
3
4
This module contains functions to find generators for the graded ring of
5
modular forms of given level.
6
7
AUTHORS:
8
9
- William Stein (2007-08-24): first version
10
"""
11
12
13
from sage.rings.all import Integer, QQ, ZZ, PowerSeriesRing
14
from sage.misc.misc import prod, verbose
15
from sage.misc.cachefunc import cached_method
16
from sage.modular.arithgroup.all import Gamma0, is_CongruenceSubgroup
17
from constructor import ModularForms
18
from sage.structure.sage_object import SageObject
19
from random import shuffle
20
21
def _span_of_forms_in_weight(forms, weight, prec, stop_dim=None, use_random=False):
22
r"""
23
Utility function. Given a nonempty list of pairs ``(k,f)``, where `k` is an
24
integer and `f` is a power series, and a weight l, return all weight l
25
forms obtained by multiplying together the given forms.
26
27
INPUT:
28
29
- ``forms`` -- list of pairs `(k, f)` with k an integer and f a power
30
series (all over the same base ring)
31
- ``weight`` -- an integer
32
- ``prec`` -- an integer (less than or equal to the precision of all the
33
forms in ``forms``) -- precision to use in power series computations.
34
- ``stop_dim`` -- an integer: stop as soon as we have enough forms to span
35
a submodule of this rank (a saturated one if the base ring is `\ZZ`).
36
Ignored if ``use_random`` is False.
37
- ``use_random`` -- which algorithm to use. If True, tries random products
38
of the generators of the appropriate weight until a large enough
39
submodule is found (determined by ``stop_dim``). If False, just tries
40
everything.
41
42
Note that if the given forms do generate the whole space, then
43
``use_random=True`` will often be quicker (particularly if the weight is
44
large); but if the forms don't generate, the randomized algorithm is no
45
help and will actually be substantially slower, because it needs to do
46
repeated echelon form calls to check if vectors are in a submodule, while
47
the non-randomized algorithm just echelonizes one enormous matrix at the
48
end.
49
50
EXAMPLES::
51
52
sage: import sage.modular.modform.find_generators as f
53
sage: forms = [(4, 240*eisenstein_series_qexp(4,5)), (6,504*eisenstein_series_qexp(6,5))]
54
sage: f._span_of_forms_in_weight(forms, 12, prec=5)
55
Vector space of degree 5 and dimension 2 over Rational Field
56
Basis matrix:
57
[ 1 0 196560 16773120 398034000]
58
[ 0 1 -24 252 -1472]
59
sage: f._span_of_forms_in_weight(forms, 24, prec=5)
60
Vector space of degree 5 and dimension 3 over Rational Field
61
Basis matrix:
62
[ 1 0 0 52416000 39007332000]
63
[ 0 1 0 195660 12080128]
64
[ 0 0 1 -48 1080]
65
sage: ModularForms(1, 24).q_echelon_basis(prec=5)
66
[
67
1 + 52416000*q^3 + 39007332000*q^4 + O(q^5),
68
q + 195660*q^3 + 12080128*q^4 + O(q^5),
69
q^2 - 48*q^3 + 1080*q^4 + O(q^5)
70
]
71
72
Test the alternative randomized algorithm::
73
74
sage: f._span_of_forms_in_weight(forms, 24, prec=5, use_random=True, stop_dim=3)
75
Vector space of degree 5 and dimension 3 over Rational Field
76
Basis matrix:
77
[ 1 0 0 52416000 39007332000]
78
[ 0 1 0 195660 12080128]
79
[ 0 0 1 -48 1080]
80
"""
81
t = verbose('multiplying forms up to weight %s'%weight)
82
# Algorithm: run through the monomials of the appropriate weight, and build
83
# up the vector space they span.
84
85
n = len(forms)
86
R = forms[0][1].base_ring()
87
V = R ** prec
88
W = V.zero_submodule()
89
shortforms = [f[1].truncate_powerseries(prec) for f in forms]
90
91
# List of weights
92
from sage.combinat.integer_vector_weighted import WeightedIntegerVectors
93
wts = list(WeightedIntegerVectors(weight, [f[0] for f in forms]))
94
t = verbose("calculated weight list", t)
95
N = len(wts)
96
97
if use_random:
98
if stop_dim is None:
99
raise ValueError("stop_dim must be provided if use_random is True")
100
shuffle(wts)
101
102
for c in xrange(N):
103
w = V(prod(shortforms[i]**wts[c][i] for i in xrange(n)).padded_list(prec))
104
if w in W: continue
105
W = V.span(list(W.gens()) + [w])
106
if stop_dim and W.rank() == stop_dim:
107
if R != ZZ or W.index_in_saturation() == 1:
108
verbose("Succeeded after %s of %s" % (c, N), t)
109
return W
110
verbose("Nothing worked", t)
111
return W
112
else:
113
G = [V(prod(forms[i][1]**c[i] for i in xrange(n)).padded_list(prec)) for c in wts]
114
t = verbose('found %s candidates' % N, t)
115
W = V.span(G)
116
verbose('span has dimension %s' % W.rank(), t)
117
return W
118
119
def find_generators(*args):
120
r"""
121
This function, which existed in earlier versions of Sage, has now been
122
replaced by the :meth:`~ModularFormsRing.generators` method of
123
ModularFormsRing objects.
124
125
EXAMPLE::
126
127
sage: from sage.modular.modform.find_generators import find_generators
128
sage: find_generators()
129
Traceback (most recent call last):
130
...
131
NotImplementedError: find_generators has been removed -- use ModularFormsRing.generators()
132
"""
133
raise NotImplementedError("find_generators has been removed -- use ModularFormsRing.generators()")
134
135
def basis_for_modform_space(*args):
136
r"""
137
This function, which existed in earlier versions of Sage, has now been
138
replaced by the :meth:`~ModularFormsRing.q_expansion_basis` method of
139
ModularFormsRing objects.
140
141
EXAMPLE::
142
143
sage: from sage.modular.modform.find_generators import basis_for_modform_space
144
sage: basis_for_modform_space()
145
Traceback (most recent call last):
146
...
147
NotImplementedError: basis_for_modform_space has been removed -- use ModularFormsRing.q_expansion_basis()
148
"""
149
raise NotImplementedError("basis_for_modform_space has been removed -- use ModularFormsRing.q_expansion_basis()")
150
151
class ModularFormsRing(SageObject):
152
153
def __init__(self, group, base_ring=QQ):
154
r"""
155
The ring of modular forms (of weights 0 or at least 2) for a congruence
156
subgroup of `{\rm SL}_2(\ZZ)`, with coefficients in a specified base ring.
157
158
INPUT:
159
160
- ``group`` -- a congruence subgroup of `{\rm SL}_2(\ZZ)`, or a
161
positive integer `N` (interpreted as `\Gamma_0(N)`)
162
163
- ``base_ring`` (ring, default: `\QQ`) -- a base ring, which should be
164
`\QQ`, `\ZZ`, or the integers mod `p` for some prime `p`.
165
166
EXAMPLES::
167
168
sage: ModularFormsRing(Gamma1(13))
169
Ring of modular forms for Congruence Subgroup Gamma1(13) with coefficients in Rational Field
170
sage: m = ModularFormsRing(4); m
171
Ring of modular forms for Congruence Subgroup Gamma0(4) with coefficients in Rational Field
172
sage: m.modular_forms_of_weight(2)
173
Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(4) of weight 2 over Rational Field
174
sage: m.modular_forms_of_weight(10)
175
Modular Forms space of dimension 6 for Congruence Subgroup Gamma0(4) of weight 10 over Rational Field
176
sage: m == loads(dumps(m))
177
True
178
sage: m.generators()
179
[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10)),
180
(2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10))]
181
sage: m.q_expansion_basis(2,10)
182
[1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10),
183
q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)]
184
sage: m.q_expansion_basis(3,10)
185
[]
186
sage: m.q_expansion_basis(10,10)
187
[1 + 10560*q^6 + 3960*q^8 + O(q^10),
188
q - 8056*q^7 - 30855*q^9 + O(q^10),
189
q^2 - 796*q^6 - 8192*q^8 + O(q^10),
190
q^3 + 66*q^7 + 832*q^9 + O(q^10),
191
q^4 + 40*q^6 + 528*q^8 + O(q^10),
192
q^5 + 20*q^7 + 190*q^9 + O(q^10)]
193
194
TESTS:
195
196
Check that :trac:`15037` is fixed::
197
198
sage: ModularFormsRing(3.4)
199
Traceback (most recent call last):
200
...
201
ValueError: Group (=3.40000000000000) should be a congruence subgroup
202
sage: ModularFormsRing(Gamma0(2), base_ring=PolynomialRing(ZZ,x))
203
Traceback (most recent call last):
204
...
205
ValueError: Base ring (=Univariate Polynomial Ring in x over Integer Ring) should be QQ, ZZ or a finite prime field
206
"""
207
if isinstance(group, (int, long, Integer)):
208
group = Gamma0(group)
209
elif not is_CongruenceSubgroup(group):
210
raise ValueError("Group (=%s) should be a congruence subgroup" % group)
211
212
if base_ring != ZZ and not base_ring.is_prime_field():
213
raise ValueError("Base ring (=%s) should be QQ, ZZ or a finite prime field" % base_ring)
214
215
self.__group = group
216
self.__base_ring = base_ring
217
self.__cached_maxweight = ZZ(-1)
218
self.__cached_gens = []
219
self.__cached_cusp_maxweight = ZZ(-1)
220
self.__cached_cusp_gens = []
221
222
def group(self):
223
r"""
224
Return the congruence subgroup for which this is the ring of modular forms.
225
226
EXAMPLE::
227
228
sage: R = ModularFormsRing(Gamma1(13))
229
sage: R.group() is Gamma1(13)
230
True
231
"""
232
return self.__group
233
234
def base_ring(self):
235
r"""
236
Return the coefficient ring of this modular forms ring.
237
238
EXAMPLE::
239
240
sage: ModularFormsRing(Gamma1(13)).base_ring()
241
Rational Field
242
sage: ModularFormsRing(Gamma1(13), base_ring = ZZ).base_ring()
243
Integer Ring
244
"""
245
return self.__base_ring
246
247
def __cmp__(self, other):
248
r"""
249
Compare self to other. Rings are equal if and only if their groups and
250
base rings are.
251
252
EXAMPLE::
253
254
sage: ModularFormsRing(3) == 3
255
False
256
sage: ModularFormsRing(Gamma0(3)) == ModularFormsRing(Gamma0(7))
257
False
258
sage: ModularFormsRing(Gamma0(3)) == ModularFormsRing(Gamma0(3))
259
True
260
"""
261
262
if not isinstance(other, ModularFormsRing):
263
return cmp( type(self), type(other) )
264
else:
265
return cmp(self.group(), other.group()) or cmp(self.base_ring(), other.base_ring())
266
267
def _repr_(self):
268
r"""
269
String representation of self.
270
271
EXAMPLES::
272
273
sage: ModularFormsRing(Gamma0(13))._repr_()
274
'Ring of modular forms for Congruence Subgroup Gamma0(13) with coefficients in Rational Field'
275
sage: ModularFormsRing(Gamma1(13), base_ring=ZZ)._repr_()
276
'Ring of modular forms for Congruence Subgroup Gamma1(13) with coefficients in Integer Ring'
277
"""
278
return "Ring of modular forms for %s with coefficients in %s" % (self.group(), self.base_ring())
279
280
def modular_forms_of_weight(self, weight):
281
"""
282
Return the space of modular forms on this group of the given weight.
283
284
EXAMPLES::
285
286
sage: R = ModularFormsRing(13)
287
sage: R.modular_forms_of_weight(10)
288
Modular Forms space of dimension 11 for Congruence Subgroup Gamma0(13) of weight 10 over Rational Field
289
sage: ModularFormsRing(Gamma1(13)).modular_forms_of_weight(3)
290
Modular Forms space of dimension 20 for Congruence Subgroup Gamma1(13) of weight 3 over Rational Field
291
"""
292
return ModularForms(self.group(), weight)
293
294
def generators(self, maxweight=8, prec=10, start_gens=[], start_weight=2):
295
r"""
296
If `R` is the base ring of self, then this function calculates a set of
297
modular forms which generate the `R`-algebra of all modular forms of
298
weight up to ``maxweight`` with coefficients in `R`.
299
300
INPUT:
301
302
- ``maxweight`` (integer, default: 8) -- check up to this weight for
303
generators
304
305
- ``prec`` (integer, default: 10) -- return `q`-expansions to this
306
precision
307
308
- ``start_gens`` (list, default: ``[]``) -- list of pairs `(k, f)`, or
309
triples `(k, f, F)`, where:
310
311
- `k` is an integer,
312
- `f` is the `q`-expansion of a modular form of weight `k`, as a power series over the base ring of self,
313
- `F` (if provided) is a modular form object corresponding to F.
314
315
If this list is nonempty, we find a minimal generating set containing
316
these forms. If `F` is not supplied, then `f` needs to have
317
sufficiently large precision (an error will be raised if this is not
318
the case); otherwise, more terms will be calculated from the modular
319
form object `F`.
320
321
- ``start_weight`` (integer, default: 2) -- calculate the graded
322
subalgebra of forms of weight at least ``start_weight``.
323
324
OUTPUT:
325
326
a list of pairs (k, f), where f is the q-expansion to precision
327
``prec`` of a modular form of weight k.
328
329
.. seealso::
330
331
:meth:`gen_forms`, which does exactly the same thing, but returns
332
Sage modular form objects rather than bare power series, and keeps
333
track of a lifting to characteristic 0 when the base ring is a
334
finite field.
335
336
.. note::
337
338
If called with the default values of ``start_gens`` (an empty list)
339
and ``start_weight`` (2), the values will be cached for re-use on
340
subsequent calls to this function. (This cache is shared with
341
:meth:`gen_forms`). If called with non-default values for these
342
parameters, caching will be disabled.
343
344
EXAMPLES::
345
346
sage: ModularFormsRing(SL2Z).generators()
347
[(4, 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + 60480*q^6 + 82560*q^7 + 140400*q^8 + 181680*q^9 + O(q^10)), (6, 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 - 4058208*q^6 - 8471232*q^7 - 17047800*q^8 - 29883672*q^9 + O(q^10))]
348
sage: s = ModularFormsRing(SL2Z).generators(maxweight=5, prec=3); s
349
[(4, 1 + 240*q + 2160*q^2 + O(q^3))]
350
sage: s[0][1].parent()
351
Power Series Ring in q over Rational Field
352
353
sage: ModularFormsRing(1).generators(prec=4)
354
[(4, 1 + 240*q + 2160*q^2 + 6720*q^3 + O(q^4)), (6, 1 - 504*q - 16632*q^2 - 122976*q^3 + O(q^4))]
355
sage: ModularFormsRing(2).generators(prec=12)
356
[(2, 1 + 24*q + 24*q^2 + 96*q^3 + 24*q^4 + 144*q^5 + 96*q^6 + 192*q^7 + 24*q^8 + 312*q^9 + 144*q^10 + 288*q^11 + O(q^12)), (4, 1 + 240*q^2 + 2160*q^4 + 6720*q^6 + 17520*q^8 + 30240*q^10 + O(q^12))]
357
sage: ModularFormsRing(4).generators(maxweight=2, prec=20)
358
[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + 144*q^10 + 96*q^12 + 192*q^14 + 24*q^16 + 312*q^18 + O(q^20)), (2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + 12*q^11 + 14*q^13 + 24*q^15 + 18*q^17 + 20*q^19 + O(q^20))]
359
360
Here we see that for ``\Gamma_0(11)`` taking a basis of forms in weights 2
361
and 4 is enough to generate everything up to weight 12 (and probably
362
everything else).::
363
364
sage: v = ModularFormsRing(11).generators(maxweight=12)
365
sage: len(v)
366
3
367
sage: [k for k, _ in v]
368
[2, 2, 4]
369
sage: dimension_modular_forms(11,2)
370
2
371
sage: dimension_modular_forms(11,4)
372
4
373
374
For congruence subgroups not containing -1, we miss out some forms since we
375
can't calculate weight 1 forms at present, but we can still find generators
376
for the ring of forms of weight `\ge 2`::
377
378
sage: ModularFormsRing(Gamma1(4)).generators(prec=10, maxweight=10)
379
[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10)),
380
(2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)),
381
(3, 1 + 12*q^2 + 64*q^3 + 60*q^4 + 160*q^6 + 384*q^7 + 252*q^8 + O(q^10)),
382
(3, q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + 32*q^6 + 48*q^7 + 64*q^8 + 73*q^9 + O(q^10))]
383
384
Using different base rings will change the generators::
385
386
sage: ModularFormsRing(Gamma0(13)).generators(maxweight=12, prec=4)
387
[(2, 1 + 2*q + 6*q^2 + 8*q^3 + O(q^4)), (4, 1 + O(q^4)), (4, q + O(q^4)), (4, q^2 + O(q^4)), (4, q^3 + O(q^4)), (6, 1 + O(q^4)), (6, q + O(q^4))]
388
sage: ModularFormsRing(Gamma0(13),base_ring=ZZ).generators(maxweight=12, prec=4)
389
[(2, 1 + 2*q + 6*q^2 + 8*q^3 + O(q^4)), (4, O(q^4)), (4, q^3 + O(q^4)), (4, q^2 + O(q^4)), (4, q + O(q^4)), (6, O(q^4)), (6, O(q^4)), (12, O(q^4))]
390
391
sage: [k for k,f in ModularFormsRing(1, QQ).generators(maxweight=12)]
392
[4, 6]
393
sage: [k for k,f in ModularFormsRing(1, ZZ).generators(maxweight=12)]
394
[4, 6, 12]
395
sage: [k for k,f in ModularFormsRing(1, Zmod(5)).generators(maxweight=12)]
396
[4, 6]
397
sage: [k for k,f in ModularFormsRing(1, Zmod(2)).generators(maxweight=12)]
398
[4, 6, 12]
399
400
An example where ``start_gens`` are specified::
401
402
sage: M = ModularForms(11, 2); f = (M.0 + M.1).qexp(8)
403
sage: ModularFormsRing(11).generators(start_gens = [(2, f)])
404
Traceback (most recent call last):
405
...
406
ValueError: Requested precision cannot be higher than precision of approximate starting generators!
407
sage: f = (M.0 + M.1).qexp(10); f
408
1 + 17/5*q + 26/5*q^2 + 43/5*q^3 + 94/5*q^4 + 77/5*q^5 + 154/5*q^6 + 86/5*q^7 + 36*q^8 + 146/5*q^9 + O(q^10)
409
sage: ModularFormsRing(11).generators(start_gens = [(2, f)])
410
[(2, 1 + 17/5*q + 26/5*q^2 + 43/5*q^3 + 94/5*q^4 + 77/5*q^5 + 154/5*q^6 + 86/5*q^7 + 36*q^8 + 146/5*q^9 + O(q^10)), (2, 1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + 24*q^6 + 24*q^7 + 36*q^8 + 36*q^9 + O(q^10)), (4, 1 + O(q^10))]
411
"""
412
sgs = []
413
for x in start_gens:
414
if len(x) == 2:
415
if x[1].prec() < prec:
416
raise ValueError("Requested precision cannot be higher than precision of approximate starting generators!")
417
sgs.append((x[0], x[1], None))
418
else:
419
sgs.append(x)
420
421
G = self._find_generators(maxweight, tuple(sgs), start_weight)
422
423
ret = []
424
# Returned generators may be a funny mixture of precisions if start_gens has been used.
425
for k, f, F in G:
426
if f.prec() < prec:
427
f = F.qexp(prec).change_ring(self.base_ring())
428
else:
429
f = f.truncate_powerseries(prec)
430
ret.append((k, f))
431
432
return ret
433
434
435
def gen_forms(self, maxweight=8, start_gens=[], start_weight=2):
436
r"""
437
This function calculates a list of modular forms generating this ring
438
(as an algebra over the appropriate base ring). It differs from
439
:meth:`generators` only in that it returns Sage modular form objects,
440
rather than bare `q`-expansions; and if the base ring is a finite
441
field, the modular forms returned will be forms in characteristic 0
442
with integral `q`-expansions whose reductions modulo `p` generate the
443
ring of modular forms mod `p`.
444
445
INPUT:
446
447
- ``maxweight`` (integer, default: 8) -- calculate forms generating all
448
forms up to this weight.
449
450
- ``start_gens`` (list, default: ``[]``) -- a list of modular forms. If
451
this list is nonempty, we find a minimal generating set containing
452
these forms.
453
454
- ``start_weight`` (integer, default: 2) -- calculate the graded
455
subalgebra of forms of weight at least ``start_weight``.
456
457
.. note::
458
459
If called with the default values of ``start_gens`` (an empty list)
460
and ``start_weight`` (2), the values will be cached for re-use on
461
subsequent calls to this function. (This cache is shared with
462
:meth:`generators`). If called with non-default values for these
463
parameters, caching will be disabled.
464
465
EXAMPLE::
466
467
sage: A = ModularFormsRing(Gamma0(11), Zmod(5)).gen_forms(); A
468
[1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6), q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6), q - 9*q^4 - 10*q^5 + O(q^6)]
469
sage: A[0].parent()
470
Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
471
"""
472
sgs = tuple( (F.weight(), None, F) for F in start_gens )
473
G = self._find_generators(maxweight, sgs, start_weight)
474
return [F for k,f,F in G]
475
476
def _find_generators(self, maxweight, start_gens, start_weight):
477
r"""
478
For internal use. This function is called by :meth:`generators` and
479
:meth:`gen_forms`: it returns a list of triples `(k, f, F)` where `F`
480
is a modular form of weight `k` and `f` is its `q`-expansion coerced
481
into the base ring of self.
482
483
INPUT:
484
485
- maxweight: maximum weight to try
486
- start_weight: minimum weight to try
487
- start_gens: a sequence of tuples of the form `(k, f, F)`, where `F` is a
488
modular form of weight `k` and `f` is its `q`-expansion coerced into
489
``self.base_ring()`. Either (but not both) of `f` and `F` may be
490
None.
491
492
OUTPUT:
493
494
a list of tuples, formatted as with ``start_gens``.
495
496
EXAMPLE::
497
498
sage: R = ModularFormsRing(Gamma1(4))
499
sage: R._find_generators(8, (), 2)
500
[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^9), 1 + 24*q^2 + 24*q^4 + O(q^6)), (2, q + 4*q^3 + 6*q^5 + 8*q^7 + O(q^9), q + 4*q^3 + 6*q^5 + O(q^6)), (3, 1 + 12*q^2 + 64*q^3 + 60*q^4 + 160*q^6 + 384*q^7 + 252*q^8 + O(q^9), 1 + 12*q^2 + 64*q^3 + 60*q^4 + O(q^6)), (3, q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + 32*q^6 + 48*q^7 + 64*q^8 + O(q^9), q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + O(q^6))]
501
"""
502
default_params = (start_gens == () and start_weight == 2)
503
504
if default_params and self.__cached_maxweight != -1:
505
verbose("Already know generators up to weight %s -- using those" % self.__cached_maxweight)
506
507
if self.__cached_maxweight >= maxweight:
508
return [(k, f, F) for k, f, F in self.__cached_gens if k <= maxweight]
509
510
start_gens = self.__cached_gens
511
start_weight = self.__cached_maxweight + 1
512
513
if self.group().is_even():
514
increment = 2
515
else:
516
increment = 1
517
518
working_prec = self.modular_forms_of_weight(maxweight).sturm_bound()
519
520
# parse the list of start gens
521
G = []
522
for x in start_gens:
523
k, f, F = x
524
if F is None and f.prec() < working_prec:
525
raise ValueError("Need start gens to precision at least %s" % working_prec)
526
elif f is None or f.prec() < working_prec:
527
f = F.qexp(working_prec).change_ring(self.base_ring())
528
G.append((k, f, F))
529
530
k = start_weight
531
if increment == 2 and (k % 2) == 1: k += 1
532
533
while k <= maxweight:
534
535
if self.modular_forms_of_weight(k).dimension() == 0:
536
k += increment
537
continue
538
539
verbose('Looking at k = %s'%k)
540
M = self.modular_forms_of_weight(k)
541
542
# 1. Multiply together all forms in G that give an element
543
# of M.
544
if G != []:
545
F = _span_of_forms_in_weight(G, k, M.sturm_bound(), None, False)
546
else:
547
F = (self.base_ring() ** M.sturm_bound()).zero_submodule()
548
549
# 2. If the dimension of the span of the result is equal
550
# to the dimension of M, increment k.
551
if F.rank() == M.dimension():
552
if self.base_ring().is_field() or F.index_in_saturation() == 1:
553
# TODO: Do something clever if the submodule's of the right
554
# rank but not saturated -- avoid triggering needless
555
# modular symbol computations.
556
verbose('Nothing new in weight %s' % k)
557
k += increment
558
continue
559
560
# 3. If the dimension is less, compute a basis for G, and
561
# try adding basis elements of M into G.
562
563
verbose("Known generators span a subspace of dimension %s of space of dimension %s" % (F.dimension(), M.dimension()))
564
if self.base_ring() == ZZ: verbose("saturation index is %s" % F.index_in_saturation())
565
566
t = verbose("Computing more modular forms at weight %s" % k)
567
kprec = M.sturm_bound()
568
if self.base_ring() == QQ:
569
B = M.q_echelon_basis(working_prec)
570
else:
571
B = M.q_integral_basis(working_prec)
572
t = verbose("done computing forms", t)
573
V = F.ambient_module().submodule_with_basis([f.padded_list(kprec) for f in B])
574
Q = V / F
575
for q in Q.gens():
576
try:
577
qc = V.coordinates(Q.lift(q))
578
except AttributeError:
579
# work around a silly free module bug
580
qc = V.coordinates(q.lift())
581
qcZZ = map(ZZ, qc) # lift to ZZ so we can define F
582
f = sum([B[i] * qcZZ[i] for i in xrange(len(B))])
583
F = M(f)
584
G.append((k, f.change_ring(self.base_ring()), F))
585
586
verbose('added %s new generators' % Q.ngens(), t)
587
k += increment
588
589
if default_params:
590
self.__cached_maxweight = maxweight
591
self.__cached_gens = G
592
593
return G
594
595
@cached_method
596
def q_expansion_basis(self, weight, prec=None, use_random=True):
597
r"""
598
Calculate a basis of q-expansions for the space of modular forms of the
599
given weight for this group, calculated using the ring generators given
600
by ``find_generators``.
601
602
INPUT:
603
604
- ``weight`` (integer) -- the weight
605
- ``prec`` (integer or ``None``, default: ``None``) -- power series
606
precision. If ``None``, the precision defaults to the Sturm bound for
607
the requested level and weight.
608
- ``use_random`` (boolean, default: True) -- whether or not to use a
609
randomized algorithm when building up the space of forms at the given
610
weight from known generators of small weight.
611
612
EXAMPLES::
613
614
sage: m = ModularFormsRing(Gamma0(4))
615
sage: m.q_expansion_basis(2,10)
616
[1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10),
617
q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)]
618
sage: m.q_expansion_basis(3,10)
619
[]
620
621
sage: X = ModularFormsRing(SL2Z)
622
sage: X.q_expansion_basis(12, 10)
623
[1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + 34417656000*q^6 + 187489935360*q^7 + 814879774800*q^8 + 2975551488000*q^9 + O(q^10),
624
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 + O(q^10)]
625
626
We calculate a basis of a massive modular forms space, in two ways.
627
Using this module is about twice as fast as Sage's generic code. ::
628
629
sage: A = ModularFormsRing(11).q_expansion_basis(30, prec=40) # long time (5s)
630
sage: B = ModularForms(Gamma0(11), 30).q_echelon_basis(prec=40) # long time (9s)
631
sage: A == B # long time
632
True
633
634
Check that absurdly small values of ``prec`` don't mess things up::
635
636
sage: ModularFormsRing(11).q_expansion_basis(10, prec=5)
637
[1 + O(q^5), q + O(q^5), q^2 + O(q^5), q^3 + O(q^5), q^4 + O(q^5), O(q^5), O(q^5), O(q^5), O(q^5), O(q^5)]
638
"""
639
d = self.modular_forms_of_weight(weight).dimension()
640
if d == 0: return []
641
642
if prec is None:
643
prec=self.modular_forms_of_weight(weight).sturm_bound()
644
645
working_prec = max(prec, self.modular_forms_of_weight(weight).sturm_bound())
646
647
gen_weight = min(6, weight)
648
649
while 1:
650
verbose("Trying to generate the %s-dimensional space at weight %s using generators of weight up to %s" % (d, weight, gen_weight))
651
G = self.generators(maxweight=gen_weight, prec=working_prec)
652
V = _span_of_forms_in_weight(G, weight, prec=working_prec, use_random=use_random, stop_dim=d)
653
if V.rank() == d and (self.base_ring().is_field() or V.index_in_saturation() == 1):
654
break
655
else:
656
gen_weight += 1
657
verbose("Need more generators: trying again with generators of weight up to %s" % gen_weight)
658
659
R = G[0][1].parent()
660
return [R(list(x), prec=prec) for x in V.gens()]
661
662
def cuspidal_ideal_generators(self, maxweight=8, prec=None):
663
r"""
664
Calculate generators for the ideal of cuspidal forms in this ring, as a
665
module over the whole ring.
666
667
EXAMPLE::
668
669
sage: ModularFormsRing(Gamma0(3)).cuspidal_ideal_generators(maxweight=12)
670
[(6, q - 6*q^2 + 9*q^3 + 4*q^4 + O(q^5), q - 6*q^2 + 9*q^3 + 4*q^4 + 6*q^5 + O(q^6))]
671
sage: [k for k,f,F in ModularFormsRing(13, base_ring=ZZ).cuspidal_ideal_generators(maxweight=14)]
672
[4, 4, 4, 6, 6, 12]
673
"""
674
working_prec = self.modular_forms_of_weight(maxweight).sturm_bound()
675
676
if self.__cached_cusp_maxweight > -1:
677
k = self.__cached_cusp_maxweight + 1
678
verbose("Already calculated cusp gens up to weight %s -- using those" % (k-1))
679
680
# we may need to increase the precision of the cached cusp
681
# generators
682
G = []
683
for j,f,F in self.__cached_cusp_gens:
684
if f.prec() >= working_prec:
685
f = F.qexp(working_prec).change_ring(self.base_ring())
686
G.append( (j,f,F) )
687
else:
688
k = 2
689
G = []
690
691
692
while k <= maxweight:
693
t = verbose("Looking for cusp generators in weight %s" % k)
694
695
kprec = self.modular_forms_of_weight(k).sturm_bound()
696
697
flist = []
698
699
for (j, f, F) in G:
700
for g in self.q_expansion_basis(k - j, prec=kprec):
701
flist.append(g*f)
702
A = self.base_ring() ** kprec
703
W = A.span([A(f.padded_list(kprec)) for f in flist])
704
705
S = self.modular_forms_of_weight(k).cuspidal_submodule()
706
if (W.rank() == S.dimension()
707
and (self.base_ring().is_field() or W.index_in_saturation() == 1)):
708
verbose("Nothing new in weight %s" % k, t)
709
k += 1
710
continue
711
712
t = verbose("Known cusp generators span a submodule of dimension %s of space of dimension %s" % (W.rank(), S.dimension()), t)
713
714
B = S.q_integral_basis(prec=working_prec)
715
V = A.span([A(f.change_ring(self.base_ring()).padded_list(kprec)) for f in B])
716
Q = V/W
717
718
for q in Q.gens():
719
try:
720
qc = V.coordinates(Q.lift(q))
721
except AttributeError:
722
# work around a silly free module bug
723
qc = V.coordinates(q.lift())
724
qcZZ = map(ZZ, qc) # lift to ZZ so we can define F
725
f = sum([B[i] * qcZZ[i] for i in xrange(len(B))])
726
F = S(f)
727
G.append((k, f.change_ring(self.base_ring()), F))
728
729
verbose('added %s new generators' % Q.ngens(), t)
730
k += 1
731
732
self.__cached_cusp_maxweight = maxweight
733
self.__cached_cusp_gens = G
734
735
if prec is None:
736
return G
737
elif prec <= working_prec:
738
return [ (k, f.truncate_powerseries(prec), F) for k,f,F in G]
739
else:
740
# user wants increased precision, so we may as well cache that
741
Gnew = [ (k, F.qexp(prec).change_ring(self.base_ring()), F) for k,f,F in G]
742
self.__cached_cusp_gens = Gnew
743
return Gnew
744
745
def cuspidal_submodule_q_expansion_basis(self, weight, prec=None):
746
r"""
747
Calculate a basis of `q`-expansions for the space of cusp forms of
748
weight ``weight`` for this group.
749
750
INPUT:
751
752
- ``weight`` (integer) -- the weight
753
- ``prec`` (integer or None) -- precision of `q`-expansions to return
754
755
ALGORITHM: Uses the method :meth:`cuspidal_ideal_generators` to
756
calculate generators of the ideal of cusp forms inside this ring. Then
757
multiply these up to weight ``weight`` using the generators of the
758
whole modular form space returned by :meth:`q_expansion_basis`.
759
760
EXAMPLES::
761
762
sage: R = ModularFormsRing(Gamma0(3))
763
sage: R.cuspidal_submodule_q_expansion_basis(20)
764
[q - 8532*q^6 - 88442*q^7 + O(q^8), q^2 + 207*q^6 + 24516*q^7 + O(q^8), q^3 + 456*q^6 + O(q^8), q^4 - 135*q^6 - 926*q^7 + O(q^8), q^5 + 18*q^6 + 135*q^7 + O(q^8)]
765
766
We compute a basis of a space of very large weight, quickly (using this
767
module) and slowly (using modular symbols), and verify that the answers
768
are the same. ::
769
770
sage: A = R.cuspidal_submodule_q_expansion_basis(80, prec=30) # long time (1s on sage.math, 2013)
771
sage: B = R.modular_forms_of_weight(80).cuspidal_submodule().q_expansion_basis(prec=30) # long time (19s on sage.math, 2013)
772
sage: A == B # long time
773
True
774
"""
775
d = self.modular_forms_of_weight(weight).cuspidal_submodule().dimension()
776
if d == 0: return []
777
778
minprec = self.modular_forms_of_weight(weight).sturm_bound()
779
if prec is None:
780
prec = working_prec = minprec
781
else:
782
working_prec = max(prec, minprec)
783
784
gen_weight = min(6, weight)
785
786
while 1:
787
verbose("Trying to generate the %s-dimensional cuspidal submodule at weight %s using generators of weight up to %s" % (d, weight, gen_weight))
788
G = self.cuspidal_ideal_generators(maxweight=gen_weight, prec=working_prec)
789
790
flist = []
791
for (j, f, F) in G:
792
for g in self.q_expansion_basis(weight - j, prec=working_prec):
793
flist.append(g*f)
794
795
A = self.base_ring() ** working_prec
796
W = A.span([A(f.padded_list(working_prec)) for f in flist])
797
if W.rank() == d and (self.base_ring().is_field() or W.index_in_saturation() == 1):
798
break
799
else:
800
gen_weight += 1
801
verbose("Need more generators: trying again with generators of weight up to %s" % gen_weight)
802
803
R = G[0][1].parent()
804
return [R(list(x), prec=prec) for x in W.gens()]
805
806