Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/modform/find_generators.py
4057 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
if isinstance(group, (int, long, Integer)):
195
group = Gamma0(group)
196
elif not is_CongruenceSubgroup(group):
197
raise ValueError("Group (=%s) should be a congruence subgroup")
198
199
if base_ring != ZZ and not base_ring.is_prime_field():
200
raise ValueError("Base ring (=%s) should be QQ, ZZ or a finite prime field")
201
202
self.__group = group
203
self.__base_ring = base_ring
204
self.__cached_maxweight = ZZ(-1)
205
self.__cached_gens = []
206
self.__cached_cusp_maxweight = ZZ(-1)
207
self.__cached_cusp_gens = []
208
209
210
211
def group(self):
212
r"""
213
Return the congruence subgroup for which this is the ring of modular forms.
214
215
EXAMPLE::
216
217
sage: R = ModularFormsRing(Gamma1(13))
218
sage: R.group() is Gamma1(13)
219
True
220
"""
221
return self.__group
222
223
def base_ring(self):
224
r"""
225
Return the coefficient ring of this modular forms ring.
226
227
EXAMPLE::
228
229
sage: ModularFormsRing(Gamma1(13)).base_ring()
230
Rational Field
231
sage: ModularFormsRing(Gamma1(13), base_ring = ZZ).base_ring()
232
Integer Ring
233
"""
234
return self.__base_ring
235
236
def __cmp__(self, other):
237
r"""
238
Compare self to other. Rings are equal if and only if their groups and
239
base rings are.
240
241
EXAMPLE::
242
243
sage: ModularFormsRing(3) == 3
244
False
245
sage: ModularFormsRing(Gamma0(3)) == ModularFormsRing(Gamma0(7))
246
False
247
sage: ModularFormsRing(Gamma0(3)) == ModularFormsRing(Gamma0(3))
248
True
249
"""
250
251
if not isinstance(other, ModularFormsRing):
252
return cmp( type(self), type(other) )
253
else:
254
return cmp(self.group(), other.group()) or cmp(self.base_ring(), other.base_ring())
255
256
def _repr_(self):
257
r"""
258
String representation of self.
259
260
EXAMPLES::
261
262
sage: ModularFormsRing(Gamma0(13))._repr_()
263
'Ring of modular forms for Congruence Subgroup Gamma0(13) with coefficients in Rational Field'
264
sage: ModularFormsRing(Gamma1(13), base_ring=ZZ)._repr_()
265
'Ring of modular forms for Congruence Subgroup Gamma1(13) with coefficients in Integer Ring'
266
"""
267
return "Ring of modular forms for %s with coefficients in %s" % (self.group(), self.base_ring())
268
269
def modular_forms_of_weight(self, weight):
270
"""
271
Return the space of modular forms on this group of the given weight.
272
273
EXAMPLES::
274
275
sage: R = ModularFormsRing(13)
276
sage: R.modular_forms_of_weight(10)
277
Modular Forms space of dimension 11 for Congruence Subgroup Gamma0(13) of weight 10 over Rational Field
278
sage: ModularFormsRing(Gamma1(13)).modular_forms_of_weight(3)
279
Modular Forms space of dimension 20 for Congruence Subgroup Gamma1(13) of weight 3 over Rational Field
280
"""
281
return ModularForms(self.group(), weight)
282
283
def generators(self, maxweight=8, prec=10, start_gens=[], start_weight=2):
284
r"""
285
If `R` is the base ring of self, then this function calculates a set of
286
modular forms which generate the `R`-algebra of all modular forms of
287
weight up to ``maxweight`` with coefficients in `R`.
288
289
INPUT:
290
291
- ``maxweight`` (integer, default: 8) -- check up to this weight for
292
generators
293
294
- ``prec`` (integer, default: 10) -- return `q`-expansions to this
295
precision
296
297
- ``start_gens`` (list, default: ``[]``) -- list of pairs `(k, f)`, or
298
triples `(k, f, F)`, where:
299
300
- `k` is an integer,
301
- `f` is the `q`-expansion of a modular form of weight `k`, as a power series over the base ring of self,
302
- `F` (if provided) is a modular form object corresponding to F.
303
304
If this list is nonempty, we find a minimal generating set containing
305
these forms. If `F` is not supplied, then `f` needs to have
306
sufficiently large precision (an error will be raised if this is not
307
the case); otherwise, more terms will be calculated from the modular
308
form object `F`.
309
310
- ``start_weight`` (integer, default: 2) -- calculate the graded
311
subalgebra of forms of weight at least ``start_weight``.
312
313
OUTPUT:
314
315
a list of pairs (k, f), where f is the q-expansion to precision
316
``prec`` of a modular form of weight k.
317
318
.. seealso::
319
320
:meth:`gen_forms`, which does exactly the same thing, but returns
321
Sage modular form objects rather than bare power series, and keeps
322
track of a lifting to characteristic 0 when the base ring is a
323
finite field.
324
325
.. note::
326
327
If called with the default values of ``start_gens`` (an empty list)
328
and ``start_weight`` (2), the values will be cached for re-use on
329
subsequent calls to this function. (This cache is shared with
330
:meth:`gen_forms`). If called with non-default values for these
331
parameters, caching will be disabled.
332
333
EXAMPLES::
334
335
sage: ModularFormsRing(SL2Z).generators()
336
[(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))]
337
sage: s = ModularFormsRing(SL2Z).generators(maxweight=5, prec=3); s
338
[(4, 1 + 240*q + 2160*q^2 + O(q^3))]
339
sage: s[0][1].parent()
340
Power Series Ring in q over Rational Field
341
342
sage: ModularFormsRing(1).generators(prec=4)
343
[(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))]
344
sage: ModularFormsRing(2).generators(prec=12)
345
[(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))]
346
sage: ModularFormsRing(4).generators(maxweight=2, prec=20)
347
[(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))]
348
349
Here we see that for ``\Gamma_0(11)`` taking a basis of forms in weights 2
350
and 4 is enough to generate everything up to weight 12 (and probably
351
everything else).::
352
353
sage: v = ModularFormsRing(11).generators(maxweight=12)
354
sage: len(v)
355
3
356
sage: [k for k, _ in v]
357
[2, 2, 4]
358
sage: dimension_modular_forms(11,2)
359
2
360
sage: dimension_modular_forms(11,4)
361
4
362
363
For congruence subgroups not containing -1, we miss out some forms since we
364
can't calculate weight 1 forms at present, but we can still find generators
365
for the ring of forms of weight `\ge 2`::
366
367
sage: ModularFormsRing(Gamma1(4)).generators(prec=10, maxweight=10)
368
[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10)),
369
(2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)),
370
(3, 1 + 12*q^2 + 64*q^3 + 60*q^4 + 160*q^6 + 384*q^7 + 252*q^8 + O(q^10)),
371
(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))]
372
373
Using different base rings will change the generators::
374
375
sage: ModularFormsRing(Gamma0(13)).generators(maxweight=12, prec=4)
376
[(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))]
377
sage: ModularFormsRing(Gamma0(13),base_ring=ZZ).generators(maxweight=12, prec=4)
378
[(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))]
379
380
sage: [k for k,f in ModularFormsRing(1, QQ).generators(maxweight=12)]
381
[4, 6]
382
sage: [k for k,f in ModularFormsRing(1, ZZ).generators(maxweight=12)]
383
[4, 6, 12]
384
sage: [k for k,f in ModularFormsRing(1, Zmod(5)).generators(maxweight=12)]
385
[4, 6]
386
sage: [k for k,f in ModularFormsRing(1, Zmod(2)).generators(maxweight=12)]
387
[4, 6, 12]
388
389
An example where ``start_gens`` are specified::
390
391
sage: M = ModularForms(11, 2); f = (M.0 + M.1).qexp(8)
392
sage: ModularFormsRing(11).generators(start_gens = [(2, f)])
393
Traceback (most recent call last):
394
...
395
ValueError: Requested precision cannot be higher than precision of approximate starting generators!
396
sage: f = (M.0 + M.1).qexp(10); f
397
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)
398
sage: ModularFormsRing(11).generators(start_gens = [(2, f)])
399
[(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))]
400
"""
401
sgs = []
402
for x in start_gens:
403
if len(x) == 2:
404
if x[1].prec() < prec:
405
raise ValueError("Requested precision cannot be higher than precision of approximate starting generators!")
406
sgs.append((x[0], x[1], None))
407
else:
408
sgs.append(x)
409
410
G = self._find_generators(maxweight, tuple(sgs), start_weight)
411
412
ret = []
413
# Returned generators may be a funny mixture of precisions if start_gens has been used.
414
for k, f, F in G:
415
if f.prec() < prec:
416
f = F.qexp(prec).change_ring(self.base_ring())
417
else:
418
f = f.truncate_powerseries(prec)
419
ret.append((k, f))
420
421
return ret
422
423
424
def gen_forms(self, maxweight=8, start_gens=[], start_weight=2):
425
r"""
426
This function calculates a list of modular forms generating this ring
427
(as an algebra over the appropriate base ring). It differs from
428
:meth:`generators` only in that it returns Sage modular form objects,
429
rather than bare `q`-expansions; and if the base ring is a finite
430
field, the modular forms returned will be forms in characteristic 0
431
with integral `q`-expansions whose reductions modulo `p` generate the
432
ring of modular forms mod `p`.
433
434
INPUT:
435
436
- ``maxweight`` (integer, default: 8) -- calculate forms generating all
437
forms up to this weight.
438
439
- ``start_gens`` (list, default: ``[]``) -- a list of modular forms. If
440
this list is nonempty, we find a minimal generating set containing
441
these forms.
442
443
- ``start_weight`` (integer, default: 2) -- calculate the graded
444
subalgebra of forms of weight at least ``start_weight``.
445
446
.. note::
447
448
If called with the default values of ``start_gens`` (an empty list)
449
and ``start_weight`` (2), the values will be cached for re-use on
450
subsequent calls to this function. (This cache is shared with
451
:meth:`generators`). If called with non-default values for these
452
parameters, caching will be disabled.
453
454
EXAMPLE::
455
456
sage: A = ModularFormsRing(Gamma0(11), Zmod(5)).gen_forms(); A
457
[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)]
458
sage: A[0].parent()
459
Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
460
"""
461
sgs = tuple( (F.weight(), None, F) for F in start_gens )
462
G = self._find_generators(maxweight, sgs, start_weight)
463
return [F for k,f,F in G]
464
465
def _find_generators(self, maxweight, start_gens, start_weight):
466
r"""
467
For internal use. This function is called by :meth:`generators` and
468
:meth:`gen_forms`: it returns a list of triples `(k, f, F)` where `F`
469
is a modular form of weight `k` and `f` is its `q`-expansion coerced
470
into the base ring of self.
471
472
INPUT:
473
474
- maxweight: maximum weight to try
475
- start_weight: minimum weight to try
476
- start_gens: a sequence of tuples of the form `(k, f, F)`, where `F` is a
477
modular form of weight `k` and `f` is its `q`-expansion coerced into
478
``self.base_ring()`. Either (but not both) of `f` and `F` may be
479
None.
480
481
OUTPUT:
482
483
a list of tuples, formatted as with ``start_gens``.
484
485
EXAMPLE::
486
487
sage: R = ModularFormsRing(Gamma1(4))
488
sage: R._find_generators(8, (), 2)
489
[(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))]
490
"""
491
default_params = (start_gens == () and start_weight == 2)
492
493
if default_params and self.__cached_maxweight != -1:
494
verbose("Already know generators up to weight %s -- using those" % self.__cached_maxweight)
495
496
if self.__cached_maxweight >= maxweight:
497
return [(k, f, F) for k, f, F in self.__cached_gens if k <= maxweight]
498
499
start_gens = self.__cached_gens
500
start_weight = self.__cached_maxweight + 1
501
502
if self.group().is_even():
503
increment = 2
504
else:
505
increment = 1
506
507
working_prec = self.modular_forms_of_weight(maxweight).sturm_bound()
508
509
# parse the list of start gens
510
G = []
511
for x in start_gens:
512
k, f, F = x
513
if F is None and f.prec() < working_prec:
514
raise ValueError("Need start gens to precision at least %s" % working_prec)
515
elif f is None or f.prec() < working_prec:
516
f = F.qexp(working_prec).change_ring(self.base_ring())
517
G.append((k, f, F))
518
519
k = start_weight
520
if increment == 2 and (k % 2) == 1: k += 1
521
522
while k <= maxweight:
523
524
if self.modular_forms_of_weight(k).dimension() == 0:
525
k += increment
526
continue
527
528
verbose('Looking at k = %s'%k)
529
M = self.modular_forms_of_weight(k)
530
531
# 1. Multiply together all forms in G that give an element
532
# of M.
533
if G != []:
534
F = _span_of_forms_in_weight(G, k, M.sturm_bound(), None, False)
535
else:
536
F = (self.base_ring() ** M.sturm_bound()).zero_submodule()
537
538
# 2. If the dimension of the span of the result is equal
539
# to the dimension of M, increment k.
540
if F.rank() == M.dimension():
541
if self.base_ring().is_field() or F.index_in_saturation() == 1:
542
# TODO: Do something clever if the submodule's of the right
543
# rank but not saturated -- avoid triggering needless
544
# modular symbol computations.
545
verbose('Nothing new in weight %s' % k)
546
k += increment
547
continue
548
549
# 3. If the dimension is less, compute a basis for G, and
550
# try adding basis elements of M into G.
551
552
verbose("Known generators span a subspace of dimension %s of space of dimension %s" % (F.dimension(), M.dimension()))
553
if self.base_ring() == ZZ: verbose("saturation index is %s" % F.index_in_saturation())
554
555
t = verbose("Computing more modular forms at weight %s" % k)
556
kprec = M.sturm_bound()
557
if self.base_ring() == QQ:
558
B = M.q_echelon_basis(working_prec)
559
else:
560
B = M.q_integral_basis(working_prec)
561
t = verbose("done computing forms", t)
562
V = F.ambient_module().submodule_with_basis([f.padded_list(kprec) for f in B])
563
Q = V / F
564
for q in Q.gens():
565
try:
566
qc = V.coordinates(Q.lift(q))
567
except AttributeError:
568
# work around a silly free module bug
569
qc = V.coordinates(q.lift())
570
qcZZ = map(ZZ, qc) # lift to ZZ so we can define F
571
f = sum([B[i] * qcZZ[i] for i in xrange(len(B))])
572
F = M(f)
573
G.append((k, f.change_ring(self.base_ring()), F))
574
575
verbose('added %s new generators' % Q.ngens(), t)
576
k += increment
577
578
if default_params:
579
self.__cached_maxweight = maxweight
580
self.__cached_gens = G
581
582
return G
583
584
@cached_method
585
def q_expansion_basis(self, weight, prec=None, use_random=True):
586
r"""
587
Calculate a basis of q-expansions for the space of modular forms of the
588
given weight for this group, calculated using the ring generators given
589
by ``find_generators``.
590
591
INPUT:
592
593
- ``weight`` (integer) -- the weight
594
- ``prec`` (integer or ``None``, default: ``None``) -- power series
595
precision. If ``None``, the precision defaults to the Sturm bound for
596
the requested level and weight.
597
- ``use_random`` (boolean, default: True) -- whether or not to use a
598
randomized algorithm when building up the space of forms at the given
599
weight from known generators of small weight.
600
601
EXAMPLES::
602
603
sage: m = ModularFormsRing(Gamma0(4))
604
sage: m.q_expansion_basis(2,10)
605
[1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10),
606
q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)]
607
sage: m.q_expansion_basis(3,10)
608
[]
609
610
sage: X = ModularFormsRing(SL2Z)
611
sage: X.q_expansion_basis(12, 10)
612
[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),
613
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)]
614
615
We calculate a basis of a massive modular forms space, in two ways.
616
Using this module is about twice as fast as Sage's generic code. ::
617
618
sage: A = ModularFormsRing(11).q_expansion_basis(30, prec=40) # long time (5s)
619
sage: B = ModularForms(Gamma0(11), 30).q_echelon_basis(prec=40) # long time (9s)
620
sage: A == B # long time
621
True
622
623
Check that absurdly small values of ``prec`` don't mess things up::
624
625
sage: ModularFormsRing(11).q_expansion_basis(10, prec=5)
626
[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)]
627
"""
628
d = self.modular_forms_of_weight(weight).dimension()
629
if d == 0: return []
630
631
if prec is None:
632
prec=self.modular_forms_of_weight(weight).sturm_bound()
633
634
working_prec = max(prec, self.modular_forms_of_weight(weight).sturm_bound())
635
636
gen_weight = min(6, weight)
637
638
while 1:
639
verbose("Trying to generate the %s-dimensional space at weight %s using generators of weight up to %s" % (d, weight, gen_weight))
640
G = self.generators(maxweight=gen_weight, prec=working_prec)
641
V = _span_of_forms_in_weight(G, weight, prec=working_prec, use_random=use_random, stop_dim=d)
642
if V.rank() == d and (self.base_ring().is_field() or V.index_in_saturation() == 1):
643
break
644
else:
645
gen_weight += 1
646
verbose("Need more generators: trying again with generators of weight up to %s" % gen_weight)
647
648
R = G[0][1].parent()
649
return [R(list(x), prec=prec) for x in V.gens()]
650
651
def cuspidal_ideal_generators(self, maxweight=8, prec=None):
652
r"""
653
Calculate generators for the ideal of cuspidal forms in this ring, as a
654
module over the whole ring.
655
656
EXAMPLE::
657
658
sage: ModularFormsRing(Gamma0(3)).cuspidal_ideal_generators(maxweight=12)
659
[(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))]
660
sage: [k for k,f,F in ModularFormsRing(13, base_ring=ZZ).cuspidal_ideal_generators(maxweight=14)]
661
[4, 4, 4, 6, 6, 12]
662
"""
663
working_prec = self.modular_forms_of_weight(maxweight).sturm_bound()
664
665
if self.__cached_cusp_maxweight > -1:
666
k = self.__cached_cusp_maxweight + 1
667
verbose("Already calculated cusp gens up to weight %s -- using those" % (k-1))
668
669
# we may need to increase the precision of the cached cusp
670
# generators
671
G = []
672
for j,f,F in self.__cached_cusp_gens:
673
if f.prec() >= working_prec:
674
f = F.qexp(working_prec).change_ring(self.base_ring())
675
G.append( (j,f,F) )
676
else:
677
k = 2
678
G = []
679
680
681
while k <= maxweight:
682
t = verbose("Looking for cusp generators in weight %s" % k)
683
684
kprec = self.modular_forms_of_weight(k).sturm_bound()
685
686
flist = []
687
688
for (j, f, F) in G:
689
for g in self.q_expansion_basis(k - j, prec=kprec):
690
flist.append(g*f)
691
A = self.base_ring() ** kprec
692
W = A.span([A(f.padded_list(kprec)) for f in flist])
693
694
S = self.modular_forms_of_weight(k).cuspidal_submodule()
695
if (W.rank() == S.dimension()
696
and (self.base_ring().is_field() or W.index_in_saturation() == 1)):
697
verbose("Nothing new in weight %s" % k, t)
698
k += 1
699
continue
700
701
t = verbose("Known cusp generators span a submodule of dimension %s of space of dimension %s" % (W.rank(), S.dimension()), t)
702
703
B = S.q_integral_basis(prec=working_prec)
704
V = A.span([A(f.change_ring(self.base_ring()).padded_list(kprec)) for f in B])
705
Q = V/W
706
707
for q in Q.gens():
708
try:
709
qc = V.coordinates(Q.lift(q))
710
except AttributeError:
711
# work around a silly free module bug
712
qc = V.coordinates(q.lift())
713
qcZZ = map(ZZ, qc) # lift to ZZ so we can define F
714
f = sum([B[i] * qcZZ[i] for i in xrange(len(B))])
715
F = S(f)
716
G.append((k, f.change_ring(self.base_ring()), F))
717
718
verbose('added %s new generators' % Q.ngens(), t)
719
k += 1
720
721
self.__cached_cusp_maxweight = maxweight
722
self.__cached_cusp_gens = G
723
724
if prec is None:
725
return G
726
elif prec <= working_prec:
727
return [ (k, f.truncate_powerseries(prec), F) for k,f,F in G]
728
else:
729
# user wants increased precision, so we may as well cache that
730
Gnew = [ (k, F.qexp(prec).change_ring(self.base_ring()), F) for k,f,F in G]
731
self.__cached_cusp_gens = Gnew
732
return Gnew
733
734
def cuspidal_submodule_q_expansion_basis(self, weight, prec=None):
735
r"""
736
Calculate a basis of `q`-expansions for the space of cusp forms of
737
weight ``weight`` for this group.
738
739
INPUT:
740
741
- ``weight`` (integer) -- the weight
742
- ``prec`` (integer or None) -- precision of `q`-expansions to return
743
744
ALGORITHM: Uses the method :meth:`cuspidal_ideal_generators` to
745
calculate generators of the ideal of cusp forms inside this ring. Then
746
multiply these up to weight ``weight`` using the generators of the
747
whole modular form space returned by :meth:`q_expansion_basis`.
748
749
EXAMPLES::
750
751
sage: R = ModularFormsRing(Gamma0(3))
752
sage: R.cuspidal_submodule_q_expansion_basis(20)
753
[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)]
754
755
We compute a basis of a space of very large weight, quickly (using this
756
module) and slowly (using modular symbols), and verify that the answers
757
are the same. ::
758
759
sage: A=R.cuspidal_submodule_q_expansion_basis(80, prec=30)
760
sage: B=R.modular_forms_of_weight(80).cuspidal_submodule().q_expansion_basis(prec=30) # long time (20s)
761
sage: A == B # long time
762
True
763
"""
764
d = self.modular_forms_of_weight(weight).cuspidal_submodule().dimension()
765
if d == 0: return []
766
767
minprec = self.modular_forms_of_weight(weight).sturm_bound()
768
if prec is None:
769
prec = working_prec = minprec
770
else:
771
working_prec = max(prec, minprec)
772
773
gen_weight = min(6, weight)
774
775
while 1:
776
verbose("Trying to generate the %s-dimensional cuspidal submodule at weight %s using generators of weight up to %s" % (d, weight, gen_weight))
777
G = self.cuspidal_ideal_generators(maxweight=gen_weight, prec=working_prec)
778
779
flist = []
780
for (j, f, F) in G:
781
for g in self.q_expansion_basis(weight - j, prec=working_prec):
782
flist.append(g*f)
783
784
A = self.base_ring() ** working_prec
785
W = A.span([A(f.padded_list(working_prec)) for f in flist])
786
if W.rank() == d and (self.base_ring().is_field() or W.index_in_saturation() == 1):
787
break
788
else:
789
gen_weight += 1
790
verbose("Need more generators: trying again with generators of weight up to %s" % gen_weight)
791
792
R = G[0][1].parent()
793
return [R(list(x), prec=prec) for x in W.gens()]
794
795