Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/modsym/space.py
4045 views
1
# -*- coding: utf-8 -*-
2
"""
3
Space of modular symbols (base class)
4
5
All the spaces of modular symbols derive from this class. This class is an
6
abstract base class.
7
"""
8
9
#*****************************************************************************
10
# Sage: System for Algebra and Geometry Experimentation
11
#
12
# Copyright (C) 2005 William Stein <[email protected]>
13
#
14
# Distributed under the terms of the GNU General Public License (GPL)
15
#
16
# This code is distributed in the hope that it will be useful,
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
# General Public License for more details.
20
#
21
# The full text of the GPL is available at:
22
#
23
# http://www.gnu.org/licenses/
24
#*****************************************************************************
25
26
import sage.modules.free_module as free_module
27
import sage.matrix.matrix_space as matrix_space
28
from sage.modules.free_module_element import is_FreeModuleElement
29
import sage.misc.misc as misc
30
import sage.modular.hecke.all as hecke
31
import sage.rings.arith as arith
32
import sage.rings.fast_arith as fast_arith
33
from sage.rings.all import PowerSeriesRing, Integer, O, QQ, ZZ, is_NumberField, infinity, Zmod
34
from sage.structure.all import Sequence, SageObject
35
import sage.modular.modsym.ambient
36
37
from sage.modular.arithgroup.all import Gamma0, is_Gamma0 # for Sturm bound given a character
38
39
import hecke_operator
40
41
from sage.misc.cachefunc import cached_method
42
43
def is_ModularSymbolsSpace(x):
44
r"""
45
Return True if x is a space of modular symbols.
46
47
EXAMPLES::
48
49
sage: M = ModularForms(3, 2)
50
sage: sage.modular.modsym.space.is_ModularSymbolsSpace(M)
51
False
52
sage: sage.modular.modsym.space.is_ModularSymbolsSpace(M.modular_symbols(sign=1))
53
True
54
"""
55
return isinstance(x, ModularSymbolsSpace)
56
57
class ModularSymbolsSpace(hecke.HeckeModule_free_module):
58
r"""
59
Base class for spaces of modular symbols.
60
"""
61
def __init__(self, group, weight, character, sign, base_ring):
62
"""
63
Create a space of modular symbols.
64
65
EXAMPLES::
66
67
sage: M = ModularSymbols(22,6) ; M
68
Modular Symbols space of dimension 30 for Gamma_0(22) of weight 6 with sign 0 over Rational Field
69
sage: M == loads(dumps(M))
70
True
71
"""
72
self.__group = group
73
self.__character = character
74
self.__sign = sign
75
hecke.HeckeModule_free_module.__init__(self, base_ring, group.level(), weight)
76
77
def __cmp__(self, other):
78
"""
79
Compare self and other.
80
81
When spaces are in a common ambient space, we order
82
lexicographically by the sequence of traces of Hecke operators
83
`T_p`, for all primes `p`. In general we order
84
first by the group, then the weight, then the character, then the
85
sign then the base ring, then the dimension.
86
87
EXAMPLES::
88
89
sage: M = ModularSymbols(21,4) ; N = ModularSymbols(Gamma1(5),6)
90
sage: M.cuspidal_submodule().__cmp__(N)
91
1
92
sage: M.cuspidal_submodule() == N
93
False
94
"""
95
if not isinstance(other, ModularSymbolsSpace):
96
return cmp(type(self), type(other))
97
c = cmp(self.__group,other.__group)
98
if c: return c
99
c = cmp(self.weight(), other.weight())
100
if c: return c
101
c = cmp(self.__character, other.__character)
102
if c: return c
103
c = cmp(self.__sign, other.__sign)
104
if c: return c
105
c = cmp(self.base_ring(), other.base_ring())
106
if c: return c
107
if self.is_ambient() or other.is_ambient():
108
# if one is ambient they are equal iff they have same
109
# dimension at this point, since all defining properties
110
# are the same, so they are in the same ambient space.
111
return cmp(self.dimension(), other.dimension())
112
113
c = cmp(self.ambient_hecke_module(), other.ambient_hecke_module())
114
if c: return c
115
c = cmp(self.dimension(), other.dimension())
116
if c: return c
117
d = cmp(self.free_module(), other.free_module())
118
if d == 0:
119
return d
120
# distinguish using Hecke operators, if possible.
121
try:
122
for p in fast_arith.prime_range(self.hecke_bound()):
123
ap = self.hecke_matrix(p).trace()
124
bp = other.hecke_matrix(p).trace()
125
c = cmp(ap, bp)
126
if c: return c
127
except ArithmeticError:
128
pass
129
# fallback on subspace comparison
130
return d
131
132
def _hecke_operator_class(self):
133
"""
134
Return the class to be used for instantiating Hecke operators
135
acting on self.
136
137
EXAMPLES::
138
139
sage: ModularSymbols(81,2)._hecke_operator_class()
140
<class 'sage.modular.modsym.hecke_operator.HeckeOperator'>
141
"""
142
return hecke_operator.HeckeOperator
143
144
def compact_system_of_eigenvalues(self, v, names='alpha', nz=None):
145
r"""
146
Return a compact system of eigenvalues `a_n` for
147
`n\in v`. This should only be called on simple factors of
148
modular symbols spaces.
149
150
INPUT:
151
152
- ``v`` - a list of positive integers
153
- ``nz`` - (default: None); if given specifies a column index
154
such that the dual module has that column nonzero.
155
156
157
OUTPUT:
158
159
- ``E`` - matrix such that E\*v is a vector with components
160
the eigenvalues `a_n` for `n \in v`.
161
- ``v`` - a vector over a number field
162
163
EXAMPLES::
164
165
sage: M = ModularSymbols(43,2,1)[2]; M
166
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 for Gamma_0(43) of weight 2 with sign 1 over Rational Field
167
sage: E, v = M.compact_system_of_eigenvalues(prime_range(10))
168
sage: E
169
[ 3 -2]
170
[-3 2]
171
[-1 2]
172
[ 1 -2]
173
sage: v
174
(1, -1/2*alpha + 3/2)
175
sage: E*v
176
(alpha, -alpha, -alpha + 2, alpha - 2)
177
178
TESTS:
179
180
Verify that Trac #12772 is fixed::
181
182
sage: M = ModularSymbols(1,12,sign=1).cuspidal_subspace().new_subspace()
183
sage: A = M.decomposition()[0]
184
sage: A.compact_system_of_eigenvalues(prime_range(10))
185
(
186
[ -24]
187
[ 252]
188
[ 4830]
189
[-16744], (1)
190
)
191
"""
192
if nz is None:
193
nz = self._eigen_nonzero()
194
M = self.ambient()
195
try:
196
E = M.hecke_images(nz, v) * self.dual_free_module().basis_matrix().transpose()
197
except AttributeError:
198
# TODO!!!
199
raise NotImplementedError, "ambient space must implement hecke_images but doesn't yet"
200
v = self.dual_eigenvector(names=names, lift=False, nz=nz)
201
return E, v
202
203
def character(self):
204
"""
205
Return the character associated to self.
206
207
EXAMPLES::
208
209
sage: ModularSymbols(12,8).character()
210
Dirichlet character modulo 12 of conductor 1 mapping 7 |--> 1, 5 |--> 1
211
sage: ModularSymbols(DirichletGroup(25).0, 4).character()
212
Dirichlet character modulo 25 of conductor 25 mapping 2 |--> zeta20
213
"""
214
return self.__character
215
216
def cuspidal_submodule(self):
217
"""
218
Return the cuspidal submodule of self.
219
220
.. note::
221
222
This should be overridden by all derived classes.
223
224
EXAMPLES::
225
226
sage: sage.modular.modsym.space.ModularSymbolsSpace(Gamma0(11),2,DirichletGroup(11).gens()[0]**10,0,QQ).cuspidal_submodule()
227
Traceback (most recent call last):
228
...
229
NotImplementedError: computation of cuspidal submodule not yet implemented for this class
230
sage: ModularSymbols(Gamma0(11),2).cuspidal_submodule()
231
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
232
"""
233
raise NotImplementedError, "computation of cuspidal submodule not yet implemented for this class"
234
235
def cuspidal_subspace(self):
236
"""
237
Synonym for cuspidal_submodule.
238
239
EXAMPLES::
240
241
sage: m = ModularSymbols(Gamma1(3),12); m.dimension()
242
8
243
sage: m.cuspidal_subspace().new_subspace().dimension()
244
2
245
"""
246
return self.cuspidal_submodule()
247
248
def new_subspace(self, p=None):
249
"""
250
Synonym for new_submodule.
251
252
EXAMPLES::
253
254
sage: m = ModularSymbols(Gamma0(5),12); m.dimension()
255
12
256
sage: m.new_subspace().dimension()
257
6
258
sage: m = ModularSymbols(Gamma1(3),12); m.dimension()
259
8
260
sage: m.new_subspace().dimension()
261
2
262
"""
263
return self.new_submodule(p)
264
265
def old_subspace(self, p=None):
266
"""
267
Synonym for old_submodule.
268
269
EXAMPLES::
270
271
sage: m = ModularSymbols(Gamma1(3),12); m.dimension()
272
8
273
sage: m.old_subspace().dimension()
274
6
275
"""
276
return self.old_submodule(p)
277
278
def eisenstein_subspace(self):
279
"""
280
Synonym for eisenstein_submodule.
281
282
EXAMPLES::
283
284
sage: m = ModularSymbols(Gamma1(3),12); m.dimension()
285
8
286
sage: m.eisenstein_subspace().dimension()
287
2
288
sage: m.cuspidal_subspace().dimension()
289
6
290
"""
291
return self.eisenstein_submodule()
292
293
def dimension_of_associated_cuspform_space(self):
294
"""
295
Return the dimension of the corresponding space of cusp forms.
296
297
The input space must be cuspidal, otherwise there is no
298
corresponding space of cusp forms.
299
300
EXAMPLES::
301
302
sage: m = ModularSymbols(Gamma0(389),2).cuspidal_subspace(); m.dimension()
303
64
304
sage: m.dimension_of_associated_cuspform_space()
305
32
306
sage: m = ModularSymbols(Gamma0(389),2,sign=1).cuspidal_subspace(); m.dimension()
307
32
308
sage: m.dimension_of_associated_cuspform_space()
309
32
310
"""
311
if not self.is_cuspidal():
312
raise ArithmeticError, "space must be cuspidal"
313
if self.sign() == 0:
314
return self.dimension() // 2
315
return self.dimension()
316
317
def dual_star_involution_matrix(self):
318
"""
319
Return the matrix of the dual star involution, which is induced by
320
complex conjugation on the linear dual of modular symbols.
321
322
.. note::
323
324
This should be overridden in all derived classes.
325
326
EXAMPLES::
327
328
sage: sage.modular.modsym.space.ModularSymbolsSpace(Gamma0(11),2,DirichletGroup(11).gens()[0]**10,0,QQ).dual_star_involution_matrix()
329
Traceback (most recent call last):
330
...
331
NotImplementedError: computation of dual star involution matrix not yet implemented for this class
332
sage: ModularSymbols(Gamma0(11),2).dual_star_involution_matrix()
333
[ 1 0 0]
334
[ 0 -1 0]
335
[ 0 1 1]
336
"""
337
raise NotImplementedError, "computation of dual star involution matrix not yet implemented for this class"
338
339
def group(self):
340
"""
341
Returns the group of this modular symbols space.
342
343
INPUT:
344
345
346
- ``ModularSymbols self`` - an arbitrary space of
347
modular symbols
348
349
350
OUTPUT:
351
352
- ``CongruenceSubgroup`` - the congruence subgroup
353
that this is a space of modular symbols for.
354
355
356
ALGORITHM: The group is recorded when this space is created.
357
358
EXAMPLES::
359
360
sage: m = ModularSymbols(20)
361
sage: m.group()
362
Congruence Subgroup Gamma0(20)
363
"""
364
return self.__group
365
366
def is_ambient(self):
367
"""
368
Return True if self is an ambient space of modular symbols.
369
370
EXAMPLES::
371
372
sage: ModularSymbols(21,4).is_ambient()
373
True
374
sage: ModularSymbols(21,4).cuspidal_submodule().is_ambient()
375
False
376
"""
377
return isinstance(self, sage.modular.modsym.ambient.ModularSymbolsAmbient)
378
379
def is_cuspidal(self):
380
"""
381
Return True if self is a cuspidal space of modular symbols.
382
383
.. note::
384
385
This should be overridden in all derived classes.
386
387
EXAMPLES::
388
389
sage: sage.modular.modsym.space.ModularSymbolsSpace(Gamma0(11),2,DirichletGroup(11).gens()[0]**10,0,QQ).is_cuspidal()
390
Traceback (most recent call last):
391
...
392
NotImplementedError: computation of cuspidal subspace not yet implemented for this class
393
sage: ModularSymbols(Gamma0(11),2).is_cuspidal()
394
False
395
"""
396
raise NotImplementedError, "computation of cuspidal subspace not yet implemented for this class"
397
398
def is_simple(self):
399
"""
400
Return whether not this modular symbols space is simple as a module
401
over the anemic Hecke algebra adjoin \*.
402
403
EXAMPLES::
404
405
sage: m = ModularSymbols(Gamma0(33),2,sign=1)
406
sage: m.is_simple()
407
False
408
sage: o = m.old_subspace()
409
sage: o.decomposition()
410
[
411
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field,
412
Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field
413
]
414
sage: C=ModularSymbols(1,14,0,GF(5)).cuspidal_submodule()
415
sage: C
416
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 for Gamma_0(1) of weight 14 with sign 0 over Finite Field of size 5
417
sage: C.is_simple()
418
True
419
"""
420
try:
421
return self._is_simple
422
except AttributeError:
423
D = self.factorization()
424
if len(D) == 0 or len(D) == 1 and D[0][1] == 1:
425
self._is_simple = True
426
else:
427
self._is_simple = False
428
return self._is_simple
429
430
def multiplicity(self, S, check_simple=True):
431
"""
432
Return the multiplicity of the simple modular symbols space S in
433
self. S must be a simple anemic Hecke module.
434
435
ASSUMPTION: self is an anemic Hecke module with the same weight and
436
group as S, and S is simple.
437
438
EXAMPLES::
439
440
sage: M = ModularSymbols(11,2,sign=1)
441
sage: N1, N2 = M.decomposition()
442
sage: N1.multiplicity(N2)
443
0
444
sage: M.multiplicity(N1)
445
1
446
sage: M.multiplicity(ModularSymbols(14,2))
447
0
448
"""
449
if self.level() % S.level() != 0 or S.weight() != self.weight():
450
return 0
451
if check_simple and not S.is_simple():
452
raise ArithmeticError, "S must be simple"
453
A = self.ambient_hecke_module()
454
B = A.submodule_generated_by_images(S)
455
C = self.intersection(B)
456
d = C.rank()
457
n = S.rank()
458
assert d % n == 0, "the dimension of intersection must be a multiple of dimension of simple space. bug!"
459
return d//n
460
461
def ngens(self):
462
"""
463
The number of generators of self.
464
465
INPUT:
466
467
- ``ModularSymbols self`` - arbitrary space of modular symbols.
468
469
OUTPUT:
470
471
- ``int`` - the number of generators, which is the same as the
472
dimension of self.
473
474
475
ALGORITHM: Call the dimension function.
476
477
EXAMPLES::
478
479
sage: m = ModularSymbols(33)
480
sage: m.ngens()
481
9
482
sage: m.rank()
483
9
484
sage: ModularSymbols(100, weight=2, sign=1).ngens()
485
18
486
"""
487
return self.rank()
488
489
#########################################################################
490
#
491
# Computation of q-expansions
492
#
493
#########################################################################
494
495
def default_prec(self):
496
r"""
497
Get the default precision for computation of `q`-expansion
498
associated to the ambient space of this space of modular symbols
499
(and all subspaces). Use ``set_default_prec`` to
500
change the default precision.
501
502
EXAMPLES::
503
504
sage: M = ModularSymbols(15)
505
sage: M.cuspidal_submodule().q_expansion_basis()
506
[
507
q - q^2 - q^3 - q^4 + q^5 + q^6 + O(q^8)
508
]
509
sage: M.set_default_prec(20)
510
511
Notice that setting the default precision of the ambient space
512
affects the subspaces.
513
514
::
515
516
sage: M.cuspidal_submodule().q_expansion_basis()
517
[
518
q - q^2 - q^3 - q^4 + q^5 + q^6 + 3*q^8 + q^9 - q^10 - 4*q^11 + q^12 - 2*q^13 - q^15 - q^16 + 2*q^17 - q^18 + 4*q^19 + O(q^20)
519
]
520
sage: M.cuspidal_submodule().default_prec()
521
20
522
"""
523
if not self.is_ambient():
524
return self.ambient_hecke_module().default_prec()
525
try:
526
return self.__default_prec
527
except AttributeError:
528
self.__default_prec = Integer(8)
529
return self.__default_prec
530
531
def set_default_prec(self, prec):
532
"""
533
Set the default precision for computation of `q`-expansion
534
associated to the ambient space of this space of modular symbols
535
(and all subspaces).
536
537
EXAMPLES::
538
539
sage: M = ModularSymbols(Gamma1(13),2)
540
sage: M.set_default_prec(5)
541
sage: M.cuspidal_submodule().q_expansion_basis()
542
[
543
q - 4*q^3 - q^4 + O(q^5),
544
q^2 - 2*q^3 - q^4 + O(q^5)
545
]
546
"""
547
if not self.is_ambient():
548
return self.ambient_hecke_module().set_default_prec(prec)
549
else:
550
self.__default_prec = Integer(prec)
551
552
def set_precision(self, prec):
553
"""
554
Same as self.set_default_prec(prec).
555
556
EXAMPLES::
557
558
sage: M = ModularSymbols(17,2)
559
sage: M.cuspidal_submodule().q_expansion_basis()
560
[
561
q - q^2 - q^4 - 2*q^5 + 4*q^7 + O(q^8)
562
]
563
sage: M.set_precision(10)
564
sage: M.cuspidal_submodule().q_expansion_basis()
565
[
566
q - q^2 - q^4 - 2*q^5 + 4*q^7 + 3*q^8 - 3*q^9 + O(q^10)
567
]
568
"""
569
self.set_default_prec(prec)
570
571
def q_expansion_basis(self, prec=None, algorithm='default'):
572
r"""
573
Returns a basis of q-expansions (as power series) to precision prec
574
of the space of modular forms associated to self. The q-expansions
575
are defined over the same base ring as self, and a put in echelon
576
form.
577
578
INPUT:
579
580
581
- ``self`` - a space of CUSPIDAL modular symbols
582
583
- ``prec`` - an integer
584
585
- ``algorithm`` - string:
586
587
- ``'default' (default)`` - decide which algorithm to
588
use based on heuristics
589
590
- ``'hecke'`` - compute basis by computing
591
homomorphisms T - K, where T is the Hecke algebra
592
593
- ``'eigen'`` - compute basis using eigenvectors for
594
the Hecke action and Atkin-Lehner-Li theory to patch them together
595
596
- ``'all'`` - compute using hecke_dual and eigen
597
algorithms and verify that the results are the same.
598
599
600
The computed basis is *not* cached, though of course Hecke
601
operators used in computing the basis are cached.
602
603
EXAMPLES::
604
605
sage: M = ModularSymbols(1, 12).cuspidal_submodule()
606
sage: M.q_expansion_basis(8)
607
[
608
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8)
609
]
610
611
::
612
613
sage: M.q_expansion_basis(8, algorithm='eigen')
614
[
615
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8)
616
]
617
618
::
619
620
sage: M = ModularSymbols(1, 24).cuspidal_submodule()
621
sage: M.q_expansion_basis(8, algorithm='eigen')
622
[
623
q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 - 982499328*q^6 - 147247240*q^7 + O(q^8),
624
q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + 143820*q^6 - 985824*q^7 + O(q^8)
625
]
626
627
::
628
629
sage: M = ModularSymbols(11, 2, sign=-1).cuspidal_submodule()
630
sage: M.q_expansion_basis(8, algorithm='eigen')
631
[
632
q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 + O(q^8)
633
]
634
635
::
636
637
sage: M = ModularSymbols(Gamma1(13), 2, sign=1).cuspidal_submodule()
638
sage: M.q_expansion_basis(8, algorithm='eigen')
639
[
640
q - 4*q^3 - q^4 + 3*q^5 + 6*q^6 + O(q^8),
641
q^2 - 2*q^3 - q^4 + 2*q^5 + 2*q^6 + O(q^8)
642
]
643
644
::
645
646
sage: M = ModularSymbols(Gamma1(5), 3, sign=-1).cuspidal_submodule()
647
sage: M.q_expansion_basis(8, algorithm='eigen') # dimension is 0
648
[]
649
650
::
651
652
sage: M = ModularSymbols(Gamma1(7), 3, sign=-1).cuspidal_submodule()
653
sage: M.q_expansion_basis(8)
654
[
655
q - 3*q^2 + 5*q^4 - 7*q^7 + O(q^8)
656
]
657
658
::
659
660
sage: M = ModularSymbols(43, 2, sign=0).cuspidal_submodule()
661
sage: M[0]
662
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 7 for Gamma_0(43) of weight 2 with sign 0 over Rational Field
663
sage: M[0].q_expansion_basis()
664
[
665
q - 2*q^2 - 2*q^3 + 2*q^4 - 4*q^5 + 4*q^6 + O(q^8)
666
]
667
sage: M[1]
668
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 7 for Gamma_0(43) of weight 2 with sign 0 over Rational Field
669
sage: M[1].q_expansion_basis()
670
[
671
q + 2*q^5 - 2*q^6 - 2*q^7 + O(q^8),
672
q^2 - q^3 - q^5 + q^7 + O(q^8)
673
]
674
"""
675
if prec is None:
676
prec = self.default_prec()
677
else:
678
prec = Integer(prec)
679
680
if prec < 1:
681
raise ValueError, "prec (=%s) must be >= 1"%prec
682
683
if not self.is_cuspidal():
684
raise ArithmeticError, "space must be cuspidal"
685
686
if self.sign() == 0:
687
P = self.plus_submodule(compute_dual=True)
688
return Sequence(P.q_expansion_basis(prec=prec, algorithm=algorithm), cr=True)
689
690
if self.dimension() == 0:
691
return Sequence([])
692
693
if algorithm == 'default':
694
algorithm = 'hecke'
695
if algorithm == 'hecke':
696
return Sequence(self._q_expansion_basis_hecke_dual(prec), cr=True)
697
elif algorithm == 'eigen':
698
return Sequence(self._q_expansion_basis_eigen(prec, 'alpha'), cr=True)
699
elif algorithm == 'all':
700
B1 = self._q_expansion_basis_hecke_dual(prec)
701
B2 = self._q_expansion_basis_eigen(prec, 'alpha')
702
if B1 != B2:
703
raise RuntimeError, "There is a bug in q_expansion_basis -- basis computed differently with two algorithms:\n%s\n%s\n"%(B1, B2,)
704
return Sequence(B1, cr=True)
705
else:
706
raise ValueError, "no algorithm '%s'"%algorithm
707
708
def q_expansion_module(self, prec = None, R=None):
709
r"""
710
Return a basis over R for the space spanned by the coefficient
711
vectors of the `q`-expansions corresponding to self. If R
712
is not the base ring of self, returns the restriction of scalars
713
down to R (for this, self must have base ring `\QQ`
714
or a number field).
715
716
INPUT:
717
718
- ``self`` - must be cuspidal
719
720
- ``prec`` - an integer (default:
721
self.default_prec())
722
723
- ``R`` - either ZZ, QQ, or the base_ring of self
724
(which is the default)
725
726
OUTPUT: A free module over R.
727
728
TODO - extend to more general R (though that is fairly easy for the
729
user to get by just doing base_extend or change_ring on the
730
output of this function).
731
732
Note that the prec needed to distinguish elements of the
733
restricted-down-to-R basis may be bigger than ``self.hecke_bound()``,
734
since one must use the Sturm bound for modular forms on `\Gamma_H(N)`.
735
736
EXAMPLES WITH SIGN 1 and R=QQ:
737
738
Basic example with sign 1::
739
740
sage: M = ModularSymbols(11, sign=1).cuspidal_submodule()
741
sage: M.q_expansion_module(5, QQ)
742
Vector space of degree 5 and dimension 1 over Rational Field
743
Basis matrix:
744
[ 0 1 -2 -1 2]
745
746
Same example with sign -1::
747
748
sage: M = ModularSymbols(11, sign=-1).cuspidal_submodule()
749
sage: M.q_expansion_module(5, QQ)
750
Vector space of degree 5 and dimension 1 over Rational Field
751
Basis matrix:
752
[ 0 1 -2 -1 2]
753
754
An example involving old forms::
755
756
sage: M = ModularSymbols(22, sign=1).cuspidal_submodule()
757
sage: M.q_expansion_module(5, QQ)
758
Vector space of degree 5 and dimension 2 over Rational Field
759
Basis matrix:
760
[ 0 1 0 -1 -2]
761
[ 0 0 1 0 -2]
762
763
An example that (somewhat spuriously) is over a number field::
764
765
sage: x = polygen(QQ)
766
sage: k = NumberField(x^2+1, 'a')
767
sage: M = ModularSymbols(11, base_ring=k, sign=1).cuspidal_submodule()
768
sage: M.q_expansion_module(5, QQ)
769
Vector space of degree 5 and dimension 1 over Rational Field
770
Basis matrix:
771
[ 0 1 -2 -1 2]
772
773
An example that involves an eigenform with coefficients in a number
774
field::
775
776
sage: M = ModularSymbols(23, sign=1).cuspidal_submodule()
777
sage: M.q_eigenform(4, 'gamma')
778
q + gamma*q^2 + (-2*gamma - 1)*q^3 + O(q^4)
779
sage: M.q_expansion_module(11, QQ)
780
Vector space of degree 11 and dimension 2 over Rational Field
781
Basis matrix:
782
[ 0 1 0 -1 -1 0 -2 2 -1 2 2]
783
[ 0 0 1 -2 -1 2 1 2 -2 0 -2]
784
785
An example that is genuinely over a base field besides QQ.
786
787
::
788
789
sage: eps = DirichletGroup(11).0
790
sage: M = ModularSymbols(eps,3,sign=1).cuspidal_submodule(); M
791
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 and level 11, weight 3, character [zeta10], sign 1, over Cyclotomic Field of order 10 and degree 4
792
sage: M.q_eigenform(4, 'beta')
793
q + (-zeta10^3 + 2*zeta10^2 - 2*zeta10)*q^2 + (2*zeta10^3 - 3*zeta10^2 + 3*zeta10 - 2)*q^3 + O(q^4)
794
sage: M.q_expansion_module(7, QQ)
795
Vector space of degree 7 and dimension 4 over Rational Field
796
Basis matrix:
797
[ 0 1 0 0 0 -40 64]
798
[ 0 0 1 0 0 -24 41]
799
[ 0 0 0 1 0 -12 21]
800
[ 0 0 0 0 1 -4 4]
801
802
An example involving an eigenform rational over the base, but the
803
base is not QQ.
804
805
::
806
807
sage: k.<a> = NumberField(x^2-5)
808
sage: M = ModularSymbols(23, base_ring=k, sign=1).cuspidal_submodule()
809
sage: D = M.decomposition(); D
810
[
811
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(23) of weight 2 with sign 1 over Number Field in a with defining polynomial x^2 - 5,
812
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(23) of weight 2 with sign 1 over Number Field in a with defining polynomial x^2 - 5
813
]
814
sage: M.q_expansion_module(8, QQ)
815
Vector space of degree 8 and dimension 2 over Rational Field
816
Basis matrix:
817
[ 0 1 0 -1 -1 0 -2 2]
818
[ 0 0 1 -2 -1 2 1 2]
819
820
An example involving an eigenform not rational over the base and
821
for which the base is not QQ.
822
823
::
824
825
sage: eps = DirichletGroup(25).0^2
826
sage: M = ModularSymbols(eps,2,sign=1).cuspidal_submodule(); M
827
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 and level 25, weight 2, character [zeta10], sign 1, over Cyclotomic Field of order 10 and degree 4
828
sage: D = M.decomposition(); D
829
[
830
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 and level 25, weight 2, character [zeta10], sign 1, over Cyclotomic Field of order 10 and degree 4
831
]
832
sage: D[0].q_eigenform(4, 'mu')
833
q + mu*q^2 + ((zeta10^3 + zeta10 - 1)*mu + zeta10^2 - 1)*q^3 + O(q^4)
834
sage: D[0].q_expansion_module(11, QQ)
835
Vector space of degree 11 and dimension 8 over Rational Field
836
Basis matrix:
837
[ 0 1 0 0 0 0 0 0 -20 -3 0]
838
[ 0 0 1 0 0 0 0 0 -16 -1 0]
839
[ 0 0 0 1 0 0 0 0 -11 -2 0]
840
[ 0 0 0 0 1 0 0 0 -8 -1 0]
841
[ 0 0 0 0 0 1 0 0 -5 -1 0]
842
[ 0 0 0 0 0 0 1 0 -3 -1 0]
843
[ 0 0 0 0 0 0 0 1 -2 0 0]
844
[ 0 0 0 0 0 0 0 0 0 0 1]
845
sage: D[0].q_expansion_module(11)
846
Vector space of degree 11 and dimension 2 over Cyclotomic Field of order 10 and degree 4
847
Basis matrix:
848
[ 0 1 0 zeta10^2 - 1 -zeta10^2 - 1 -zeta10^3 - zeta10^2 zeta10^2 - zeta10 2*zeta10^3 + 2*zeta10 - 1 zeta10^3 - zeta10^2 - zeta10 + 1 zeta10^3 - zeta10^2 + zeta10 -2*zeta10^3 + 2*zeta10^2 - zeta10]
849
[ 0 0 1 zeta10^3 + zeta10 - 1 -zeta10 - 1 -zeta10^3 - zeta10^2 -2*zeta10^3 + zeta10^2 - zeta10 + 1 zeta10^2 0 zeta10^3 + 1 2*zeta10^3 - zeta10^2 + zeta10 - 1]
850
851
EXAMPLES WITH SIGN 0 and R=QQ:
852
853
TODO - this doesn't work yet as it's not implemented!!
854
855
::
856
857
sage: M = ModularSymbols(11,2).cuspidal_submodule() #not tested
858
sage: M.q_expansion_module() #not tested
859
... boom ...
860
861
EXAMPLES WITH SIGN 1 and R=ZZ (computes saturation)::
862
863
sage: M = ModularSymbols(43,2, sign=1).cuspidal_submodule()
864
sage: M.q_expansion_module(8, QQ)
865
Vector space of degree 8 and dimension 3 over Rational Field
866
Basis matrix:
867
[ 0 1 0 0 0 2 -2 -2]
868
[ 0 0 1 0 -1/2 1 -3/2 0]
869
[ 0 0 0 1 -1/2 2 -3/2 -1]
870
sage: M.q_expansion_module(8, ZZ)
871
Free module of degree 8 and rank 3 over Integer Ring
872
Echelon basis matrix:
873
[ 0 1 0 0 0 2 -2 -2]
874
[ 0 0 1 1 -1 3 -3 -1]
875
[ 0 0 0 2 -1 4 -3 -2]
876
"""
877
if prec is None:
878
prec = self.default_prec()
879
if R == ZZ and self.base_ring() == QQ:
880
return self._q_expansion_module_integral(prec)
881
elif R == QQ:
882
return self._q_expansion_module_rational(prec)
883
elif R is None or R == self.base_ring():
884
## names is never used in this case
885
return self._q_expansion_module(prec)
886
else:
887
raise NotImplementedError, "R must be ZZ, QQ, or the base ring of the modular symbols space."
888
889
def _q_eigenform_images(self, A, prec, names):
890
"""
891
Return list of images in space corresponding to self of eigenform
892
corresponding to A under the degeneracy maps. This is mainly a
893
helper function for other internal functions.
894
895
INPUT:
896
897
- ``self`` - space of modular symbols
898
899
- ``A`` - cuspidal simple space of level dividing the
900
level of self and the same weight
901
902
- ``prec`` - a positive integer
903
904
905
EXAMPLES::
906
907
sage: M = ModularSymbols(33,2,sign=1)
908
sage: A = M.modular_symbols_of_level(11).cuspidal_submodule()
909
sage: M._q_eigenform_images(A, 10, names='a')
910
[q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10),
911
q^3 - 2*q^6 - q^9 + 2*q^12 + q^15 + 2*q^18 - 2*q^21 - 2*q^27 + O(q^30)]
912
"""
913
f = A.q_eigenform(prec, names)
914
if A.level() == self.level():
915
return [f]
916
D = arith.divisors(self.level() // A.level())
917
q = f.parent().gen()
918
return [f] + [f(q**d) for d in D if d > 1]
919
920
def _q_expansion_module(self, prec, algorithm='hecke'):
921
"""
922
Return module spanned by the `q`-expansions corresponding to self. See
923
the docstring for ``q_expansion_module`` (without underscore) for
924
further details. Note that this will not work if ``algorithm=eigen``
925
and the sign is 0.
926
927
EXAMPLE::
928
929
sage: ModularSymbols(11, 2, base_ring=GF(4,'a')).cuspidal_submodule()._q_expansion_module(prec=4, algorithm="hecke")
930
Vector space of degree 4 and dimension 1 over Finite Field in a of size 2^2
931
Basis matrix:
932
[0 1 0 1]
933
sage: ModularSymbols(11, 2, base_ring=QuadraticField(-7,'b'), sign=1).cuspidal_submodule()._q_expansion_module(prec=4, algorithm="eigen")
934
Vector space of degree 4 and dimension 1 over Number Field in b with defining polynomial x^2 + 7
935
Basis matrix:
936
[ 0 1 -2 -1]
937
938
"""
939
if not self.is_cuspidal():
940
raise ValueError, "self must be cuspidal"
941
R = self.base_ring()
942
if not R.is_field():
943
if R == ZZ:
944
return self._q_expansion_module_integral(prec)
945
raise NotImplementedError, "base ring must be a field (or ZZ)."
946
947
if algorithm == 'hecke' or algorithm == 'default':
948
A = R ** prec
949
return A.span([f.padded_list(prec) for f in self.q_expansion_basis(prec, algorithm)])
950
951
if algorithm != 'eigen':
952
raise ValueError, "unknown algorithm '%s'"%algorithm
953
954
V = R ** prec
955
def q_eigen_gens(f):
956
r""" Temporary function for internal use.
957
958
EXAMPLE::
959
960
sage: ModularSymbols(11, 4, base_ring=QuadraticField(-7,'b'),sign=1).cuspidal_submodule()._q_expansion_module(prec=5, algorithm="eigen") # indirect doctest
961
Vector space of degree 5 and dimension 2 over Number Field in b with defining polynomial x^2 + 7
962
Basis matrix:
963
[ 0 1 0 3 -6]
964
[ 0 0 1 -4 2]
965
"""
966
X = f.padded_list(prec)
967
d = A.dimension()
968
if d == 1:
969
# X is just a list of elements of R
970
return [X]
971
else:
972
# X is a list of elements of a poly quotient ring
973
return [[X[i][j] for i in xrange(prec)] for j in xrange(d)]
974
975
if self.sign() == 0:
976
X = self.plus_submodule(compute_dual=True)
977
else:
978
X = self
979
980
B = [sum([q_eigen_gens(f) for f in self._q_eigenform_images(A, prec, 'zeta')], []) for A, _ in X.factorization()]
981
982
A = R ** prec
983
return A.span(sum(B, []))
984
985
def _q_expansion_module_rational(self, prec):
986
"""
987
Return a vector space over `\QQ` for the space spanned by the
988
`q`-expansions corresponding to self. The base ring of self must be
989
`\QQ` or a number field, and self must be cuspidal. The returned space
990
is a `\QQ`-vector space, where the coordinates are the coefficients of
991
`q`-expansions.
992
993
INPUT:
994
995
- ``prec`` (integer) - number of q-expansion terms to calculate.
996
997
EXAMPLE::
998
999
sage: ModularSymbols(11, 4).cuspidal_submodule()._q_expansion_module_rational(5)
1000
Vector space of degree 5 and dimension 2 over Rational Field
1001
Basis matrix:
1002
[ 0 1 0 3 -6]
1003
[ 0 0 1 -4 2]
1004
"""
1005
if not self.is_cuspidal():
1006
raise ValueError, "self must be cuspidal"
1007
K = self.base_ring()
1008
if not is_NumberField(K):
1009
raise TypeError, "self must be over QQ or a number field."
1010
n = K.degree()
1011
if n == 1:
1012
return self._q_expansion_module(prec)
1013
1014
# Construct the vector space over QQ of dimension equal to
1015
# the degree of the base field times the dimension over C
1016
# of the space of cusp forms corresponding to self.
1017
V = QQ**prec ## is this needed?
1018
def q_eigen_gens(f):
1019
r"""
1020
Temporary function for internal use.
1021
1022
EXAMPLE::
1023
1024
sage: ModularSymbols(13, 6).cuspidal_submodule()._q_expansion_module_rational(4) # indirect doctest
1025
Vector space of degree 4 and dimension 3 over Rational Field
1026
Basis matrix:
1027
[0 1 0 0]
1028
[0 0 1 0]
1029
[0 0 0 1]
1030
"""
1031
# Return restricted down to QQ gens for cusp space corresponding
1032
# to the simple factor A.
1033
X = f.padded_list(prec)
1034
d = A.dimension()
1035
if d == 1:
1036
return [[X[i][j] for i in xrange(prec)] for j in xrange(n)]
1037
else:
1038
# This looks like it might be really slow -- though
1039
# perhaps it's nothing compared to the time taken by
1040
# whatever computed this in the first place.
1041
return [[(X[i].list())[j][k] for i in xrange(prec)] for j in xrange(d) for k in range(n)]
1042
if self.sign() == 0:
1043
X = self.plus_submodule(compute_dual=True)
1044
else:
1045
X = self
1046
1047
B = [sum([q_eigen_gens(f) for f in self._q_eigenform_images(A, prec, 'alpha')], []) for A, _ in X.factorization()]
1048
A = QQ**prec
1049
W = A.span(sum(B, []))
1050
return W
1051
1052
1053
def _q_expansion_module_integral(self, prec):
1054
r"""
1055
Return module over `\ZZ` for the space spanned by
1056
the `q`-expansions corresponding to self. The base ring of
1057
self must be `\QQ` or a number field, and self must
1058
be cuspidal. The returned space is a `\ZZ`-module,
1059
where the coordinates are the coefficients of
1060
`q`-expansions.
1061
1062
EXAMPLES::
1063
1064
sage: M = ModularSymbols(11, sign=1).cuspidal_submodule()
1065
sage: M._q_expansion_module_integral(5)
1066
Free module of degree 5 and rank 1 over Integer Ring
1067
Echelon basis matrix:
1068
[ 0 1 -2 -1 2]
1069
sage: V = M.complement().cuspidal_submodule()
1070
sage: V._q_expansion_module_integral(5)
1071
Free module of degree 5 and rank 0 over Integer Ring
1072
Echelon basis matrix:
1073
[]
1074
"""
1075
V = self.q_expansion_module(prec, QQ)
1076
return free_module.FreeModule(ZZ, V.degree()).span(V.basis()).saturation()
1077
1078
1079
def congruence_number(self, other, prec=None):
1080
r"""
1081
Given two cuspidal spaces of modular symbols, compute the
1082
congruence number, using prec terms of the `q`-expansions.
1083
1084
The congruence number is defined as follows. If `V` is the
1085
submodule of integral cusp forms corresponding to self (saturated in
1086
`\ZZ[[q]]`, by definition) and `W` is the
1087
submodule corresponding to other, each computed to precision prec,
1088
the congruence number is the index of `V+W` in its
1089
saturation in `\ZZ[[q]]`.
1090
1091
If prec is not given it is set equal to the max of the
1092
``hecke_bound`` function called on each space.
1093
1094
EXAMPLES:
1095
1096
sage: A, B = ModularSymbols(48, 2).cuspidal_submodule().decomposition()
1097
sage: A.congruence_number(B)
1098
2
1099
"""
1100
if not self.is_cuspidal():
1101
raise ValueError, "self must be cuspidal"
1102
if not other.is_cuspidal():
1103
raise ValueError, "right must be cuspidal"
1104
if prec is None:
1105
prec = max(self.hecke_bound(), other.hecke_bound())
1106
prec = int(prec)
1107
1108
V = self.q_expansion_module(prec, ZZ)
1109
W = other.q_expansion_module(prec, ZZ)
1110
K = V+W
1111
return K.index_in_saturation()
1112
1113
#########################################################################
1114
#
1115
# Computation of a basis using eigenforms
1116
#
1117
#########################################################################
1118
1119
@cached_method
1120
def q_eigenform_character(self, names=None):
1121
"""
1122
Return the Dirichlet character associated to the specific
1123
choice of `q`-eigenform attached to this simple cuspidal
1124
modular symbols space.
1125
1126
INPUT::
1127
1128
- ``names` -- string, name of the variable.
1129
1130
OUTPUT:
1131
1132
- a Dirichlet character taking values in the Hecke eigenvalue
1133
field, where the indeterminant of that field is determined
1134
by the given variable name.
1135
1136
EXAMPLES::
1137
1138
sage: f = ModularSymbols(Gamma1(13),2,sign=1).cuspidal_subspace().decomposition()[0]
1139
sage: eps = f.q_eigenform_character('a'); eps
1140
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -a - 1
1141
sage: parent(eps)
1142
Group of Dirichlet characters of modulus 13 over Number Field in a with defining polynomial x^2 + 3*x + 3
1143
sage: eps(3)
1144
a + 1
1145
1146
The modular symbols space must be simple.::
1147
1148
sage: ModularSymbols(Gamma1(17),2,sign=1).cuspidal_submodule().q_eigenform_character('a')
1149
Traceback (most recent call last):
1150
...
1151
ArithmeticError: self must be simple
1152
1153
If the character is specified when making the modular symbols
1154
space, then names need not be given and the returned character
1155
is just the character of the space.::
1156
1157
sage: f = ModularSymbols(kronecker_character(19),2,sign=1).cuspidal_subspace().decomposition()[0]
1158
sage: f
1159
Modular Symbols subspace of dimension 8 of Modular Symbols space of dimension 10 and level 76, weight 2, character [-1, -1], sign 1, over Rational Field
1160
sage: f.q_eigenform_character()
1161
Dirichlet character modulo 76 of conductor 76 mapping 39 |--> -1, 21 |--> -1
1162
sage: f.q_eigenform_character() is f.character()
1163
True
1164
1165
The input space need not be cuspidal::
1166
1167
sage: M = ModularSymbols(Gamma1(13),2,sign=1).eisenstein_submodule()[0]
1168
sage: M.q_eigenform_character('a')
1169
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -1
1170
1171
The modular symbols space does not have to come from a decomposition::
1172
1173
sage: ModularSymbols(Gamma1(16),2,sign=1).cuspidal_submodule().q_eigenform_character('a')
1174
Dirichlet character modulo 16 of conductor 16 mapping 15 |--> 1, 5 |--> -a - 1
1175
"""
1176
eps = self.character()
1177
if eps is not None:
1178
# easy case
1179
return eps
1180
1181
v = self.dual_eigenvector(names=names)
1182
i = v.nonzero_positions()[0]
1183
K = v.base_ring()
1184
from sage.modular.dirichlet import DirichletGroup
1185
G = DirichletGroup(self.level(), K)
1186
M = self.ambient_module()
1187
# act on right since v is a in the dual
1188
b = [(M.diamond_bracket_matrix(u)*v)[i] / v[i] for u in G.unit_gens()]
1189
return G(b)
1190
1191
def q_eigenform(self, prec, names=None):
1192
"""
1193
Returns the q-expansion to precision prec of a new eigenform
1194
associated to self, where self must be new, cuspidal, and simple.
1195
1196
EXAMPLES::
1197
1198
sage: ModularSymbols(2, 8)[1].q_eigenform(5, 'a')
1199
q - 8*q^2 + 12*q^3 + 64*q^4 + O(q^5)
1200
sage: ModularSymbols(2, 8)[0].q_eigenform(5,'a')
1201
Traceback (most recent call last):
1202
...
1203
ArithmeticError: self must be cuspidal.
1204
"""
1205
if self.dimension() > 1 and names is None:
1206
raise ValueError, "please specify a name to use for the field of eigenvalues"
1207
1208
if prec is None:
1209
prec = self.default_prec()
1210
try:
1211
f = self._q_expansion_dict[names]
1212
except (AttributeError, KeyError):
1213
self._q_expansion_dict = {}
1214
if not self.is_cuspidal():
1215
raise ArithmeticError, "self must be cuspidal."
1216
1217
if not self.is_simple():
1218
if self.sign() == 0:
1219
return self.plus_submodule(compute_dual=True).q_eigenform(prec, names)
1220
raise ArithmeticError, "self must be simple."
1221
a2 = self.eigenvalue(2, names)
1222
R = PowerSeriesRing(a2.parent(), "q")
1223
q = R.gen(0)
1224
f = q + a2*q**2 + O(q**3)
1225
1226
if f.prec() < prec:
1227
R = f.parent()
1228
ext = [self.eigenvalue(n, names) for n in range(f.prec(),prec)]
1229
f = R(f.padded_list(f.prec()) + ext)
1230
self._q_expansion_dict[names] = f.add_bigoh(prec)
1231
return self._q_expansion_dict[names]
1232
else:
1233
return f.O(prec)
1234
1235
def _q_expansion_basis_eigen(self, prec, names):
1236
r"""
1237
Return a basis of eigenforms corresponding to this space, which must be
1238
new, cuspidal and simple.
1239
1240
EXAMPLE::
1241
1242
sage: ModularSymbols(17, 2,sign=1).cuspidal_submodule()._q_expansion_basis_eigen(2, "a")
1243
[q + O(q^2)]
1244
"""
1245
if self.is_simple():
1246
# should we perhaps check at this point if self is new?
1247
f = self.q_eigenform(prec, names)
1248
R = PowerSeriesRing(self.base_ring(), 'q')
1249
B = [R([f[i][j] for i in xrange(prec)],prec) for j in range(self.rank())]
1250
return B
1251
else:
1252
raise NotImplementedError
1253
1254
1255
#########################################################################
1256
#
1257
# Computation of a basis using linear functionals on the Hecke algebra.
1258
#
1259
#########################################################################
1260
1261
def q_expansion_cuspforms(self, prec=None):
1262
"""
1263
Returns a function f(i,j) such that each value f(i,j) is the
1264
q-expansion, to the given precision, of an element of the
1265
corresponding space `S` of cusp forms. Together these
1266
functions span `S`. Here `i,j` are integers with
1267
`0\leq i,j < d`, where `d` is the dimension of
1268
self.
1269
1270
For a reduced echelon basis, use the function
1271
``q_expansion_basis`` instead.
1272
1273
More precisely, this function returns the `q`-expansions
1274
obtained by taking the `ij` entry of the matrices of the
1275
Hecke operators `T_n` acting on the subspace of the linear
1276
dual of modular symbols corresponding to self.
1277
1278
EXAMPLES::
1279
1280
sage: S = ModularSymbols(11,2, sign=1).cuspidal_submodule()
1281
sage: f = S.q_expansion_cuspforms(8)
1282
sage: f(0,0)
1283
q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 + O(q^8)
1284
1285
::
1286
1287
sage: S = ModularSymbols(37,2).cuspidal_submodule()
1288
sage: f = S.q_expansion_cuspforms(8)
1289
sage: f(0,0)
1290
q + q^3 - 2*q^4 - q^7 + O(q^8)
1291
sage: f(3,3)
1292
q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + 6*q^6 - q^7 + O(q^8)
1293
sage: f(1,2)
1294
q^2 + 2*q^3 - 2*q^4 + q^5 - 3*q^6 + O(q^8)
1295
1296
::
1297
1298
sage: S = ModularSymbols(Gamma1(13),2,sign=-1).cuspidal_submodule()
1299
sage: f = S.q_expansion_cuspforms(8)
1300
sage: f(0,0)
1301
q - 2*q^2 + q^4 - q^5 + 2*q^6 + O(q^8)
1302
sage: f(0,1)
1303
q^2 - 2*q^3 - q^4 + 2*q^5 + 2*q^6 + O(q^8)
1304
1305
::
1306
1307
sage: S = ModularSymbols(1,12,sign=-1).cuspidal_submodule()
1308
sage: f = S.q_expansion_cuspforms(8)
1309
sage: f(0,0)
1310
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8)
1311
"""
1312
if prec is None:
1313
prec = self.default_prec()
1314
if not self.is_cuspidal():
1315
raise ArithmeticError, "self must be cuspidal"
1316
K = self.base_ring()
1317
M = matrix_space.MatrixSpace(K, prec-1, self.dimension())
1318
T = [self.dual_hecke_matrix(n) for n in range(1,prec)]
1319
R = PowerSeriesRing(self.base_ring(), 'q')
1320
return lambda i, j: R([0] + [t[i,j] for t in T], prec)
1321
1322
def _q_expansion_basis_hecke_dual(self, prec):
1323
r"""
1324
Compute a basis of q-expansions for the associated space of cusp forms
1325
to the given precision, by using linear functionals on the Hecke
1326
algebra as described in William Stein's book (Algorithm 3.26, page 56)
1327
1328
EXAMPLES::
1329
1330
sage: ModularSymbols(37, 2).cuspidal_submodule()._q_expansion_basis_hecke_dual(12)
1331
[q + q^3 - 2*q^4 - q^7 - 2*q^9 + 3*q^11 + O(q^12),
1332
q^2 + 2*q^3 - 2*q^4 + q^5 - 3*q^6 - 4*q^9 - 2*q^10 + 4*q^11 + O(q^12)]
1333
sage: ModularSymbols(37, 2).cuspidal_submodule()._q_expansion_basis_hecke_dual(2)
1334
[q + O(q^2)]
1335
"""
1336
d = self.dimension_of_associated_cuspform_space()
1337
prec = Integer(prec)
1338
if prec < 1:
1339
raise ValueError, "prec (=%s) must be >= 1"%prec
1340
if d >= prec-1:
1341
d = prec-1
1342
K = self.base_ring()
1343
1344
A = free_module.VectorSpace(K, prec-1)
1345
M = matrix_space.MatrixSpace(K, prec-1, self.dimension())
1346
1347
V = A.zero_submodule()
1348
i = self.dimension()-1
1349
j = 0
1350
1351
t = misc.verbose('computing basis to precision %s'%prec)
1352
while V.dimension() < d and i >= 0:
1353
v = [self.dual_hecke_matrix(n).column(i) for n in range(1,prec)]
1354
t = misc.verbose('iteration: %s'%j,t)
1355
X = M(v).transpose()
1356
V += X.row_space()
1357
t = misc.verbose('addition of row space: %s'%j,t)
1358
i -= 1
1359
j += 1
1360
1361
R = PowerSeriesRing(K, 'q')
1362
B = V.basis()
1363
if len(B) < d:
1364
B += [V(0)] * (d-len(B))
1365
return [R([0] + b.list(), prec) for b in B]
1366
1367
1368
#########################################################################
1369
#
1370
# Decomposition of spaces
1371
#
1372
##########################################################################
1373
1374
# def factorization(self):
1375
# """
1376
# Returns a list of pairs `(S,e)` where `S` is simple
1377
# spaces of modular symbols and self is isomorphic to the direct sum
1378
# of the `S^e` as a module over the *anemic* Hecke algebra
1379
# adjoin the star involution.
1380
#
1381
# ASSUMPTION: self is a module over the anemic Hecke algebra.
1382
# """
1383
# try:
1384
# return self._factorization
1385
# except AttributeError:
1386
# raise NotImplementedError
1387
1388
def hecke_module_of_level(self, level):
1389
r"""
1390
Alias for ``self.modular_symbols_of_level(level)``.
1391
1392
EXAMPLE::
1393
1394
sage: ModularSymbols(11, 2).hecke_module_of_level(22)
1395
Modular Symbols space of dimension 7 for Gamma_0(22) of weight 2 with sign 0 over Rational Field
1396
"""
1397
return self.modular_symbols_of_level(Integer(level))
1398
1399
def sign(self):
1400
"""
1401
Returns the sign of self.
1402
1403
For efficiency reasons, it is often useful to compute in the
1404
(largest) quotient of modular symbols where the \* involution acts
1405
as +1, or where it acts as -1.
1406
1407
INPUT:
1408
1409
1410
- ``ModularSymbols self`` - arbitrary space of modular
1411
symbols.
1412
1413
1414
OUTPUT:
1415
1416
1417
- ``int`` - the sign of self, either -1, 0, or 1.
1418
1419
- ``-1`` - if this is factor of quotient where \* acts
1420
as -1,
1421
1422
- ``+1`` - if this is factor of quotient where \* acts
1423
as +1,
1424
1425
- ``0`` - if this is full space of modular symbols (no
1426
quotient).
1427
1428
1429
EXAMPLES::
1430
1431
sage: m = ModularSymbols(33)
1432
sage: m.rank()
1433
9
1434
sage: m.sign()
1435
0
1436
sage: m = ModularSymbols(33, sign=0)
1437
sage: m.sign()
1438
0
1439
sage: m.rank()
1440
9
1441
sage: m = ModularSymbols(33, sign=-1)
1442
sage: m.sign()
1443
-1
1444
sage: m.rank()
1445
3
1446
"""
1447
return self.__sign
1448
1449
def simple_factors(self):
1450
"""
1451
Returns a list modular symbols spaces `S` where `S`
1452
is simple spaces of modular symbols (for the anemic Hecke algebra)
1453
and self is isomorphic to the direct sum of the `S` with
1454
some multiplicities, as a module over the *anemic* Hecke algebra.
1455
For the multiplicities use factorization() instead.
1456
1457
ASSUMPTION: self is a module over the anemic Hecke algebra.
1458
1459
EXAMPLES::
1460
1461
sage: ModularSymbols(1,100,sign=-1).simple_factors()
1462
[Modular Symbols subspace of dimension 8 of Modular Symbols space of dimension 8 for Gamma_0(1) of weight 100 with sign -1 over Rational Field]
1463
sage: ModularSymbols(1,16,0,GF(5)).simple_factors()
1464
[Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(1) of weight 16 with sign 0 over Finite Field of size 5,
1465
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(1) of weight 16 with sign 0 over Finite Field of size 5,
1466
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(1) of weight 16 with sign 0 over Finite Field of size 5]
1467
"""
1468
return [S for S,_ in self.factorization()]
1469
1470
def star_eigenvalues(self):
1471
"""
1472
Returns the eigenvalues of the star involution acting on self.
1473
1474
EXAMPLES::
1475
1476
sage: M = ModularSymbols(11)
1477
sage: D = M.decomposition()
1478
sage: M.star_eigenvalues()
1479
[1, -1]
1480
sage: D[0].star_eigenvalues()
1481
[1]
1482
sage: D[1].star_eigenvalues()
1483
[1, -1]
1484
sage: D[1].plus_submodule().star_eigenvalues()
1485
[1]
1486
sage: D[1].minus_submodule().star_eigenvalues()
1487
[-1]
1488
"""
1489
try:
1490
return self.__star_eigenvalues
1491
except AttributeError:
1492
pass
1493
if self.sign() != 0:
1494
return [self.sign()]
1495
M = self.star_involution().matrix()
1496
R = self.base_ring()
1497
if M == R(1):
1498
self.__star_eigenvalues = [R(1)]
1499
elif M == R(-1):
1500
self.__star_eigenvalues = [R(-1)]
1501
else:
1502
self.__star_eigenvalues = [R(1), R(-1)]
1503
return self.__star_eigenvalues
1504
1505
def star_decomposition(self):
1506
r"""
1507
Decompose self into subspaces which are eigenspaces for the star
1508
involution.
1509
1510
EXAMPLE::
1511
1512
sage: ModularSymbols(Gamma1(19), 2).cuspidal_submodule().star_decomposition()
1513
[
1514
Modular Symbols subspace of dimension 7 of Modular Symbols space of dimension 31 for Gamma_1(19) of weight 2 with sign 0 and over Rational Field,
1515
Modular Symbols subspace of dimension 7 of Modular Symbols space of dimension 31 for Gamma_1(19) of weight 2 with sign 0 and over Rational Field
1516
]
1517
"""
1518
S = self.star_involution()
1519
return S.decomposition()
1520
1521
def integral_structure(self):
1522
r"""
1523
Return the `\ZZ`-structure of this modular symbols
1524
spaces generated by all integral modular symbols.
1525
1526
EXAMPLES::
1527
1528
sage: M = ModularSymbols(11,4)
1529
sage: M.integral_structure()
1530
Free module of degree 6 and rank 6 over Integer Ring
1531
Echelon basis matrix:
1532
[ 1 0 0 0 0 0]
1533
[ 0 1/14 1/7 5/14 1/2 13/14]
1534
[ 0 0 1/2 0 0 1/2]
1535
[ 0 0 0 1 0 0]
1536
[ 0 0 0 0 1 0]
1537
[ 0 0 0 0 0 1]
1538
sage: M.cuspidal_submodule().integral_structure()
1539
Free module of degree 6 and rank 4 over Integer Ring
1540
Echelon basis matrix:
1541
[ 0 1/14 1/7 5/14 1/2 -15/14]
1542
[ 0 0 1/2 0 0 -1/2]
1543
[ 0 0 0 1 0 -1]
1544
[ 0 0 0 0 1 -1]
1545
"""
1546
try:
1547
return self.__integral_structure
1548
except AttributeError:
1549
pass
1550
A = self.ambient_hecke_module()
1551
I = A.integral_structure()
1552
if I.echelonized_basis_matrix().is_one() and (self.free_module().denominator() == 1):
1553
J = I.submodule(self.free_module().basis(), check=False, already_echelonized=True)
1554
else:
1555
J = self.free_module().intersection(I)
1556
self.__integral_structure = J
1557
return J
1558
1559
def intersection_number(self, M):
1560
"""
1561
Given modular symbols spaces self and M in some common ambient
1562
space, returns the intersection number of these two spaces. This is
1563
the index in their saturation of the sum of their underlying
1564
integral structures.
1565
1566
If self and M are of weight two and defined over QQ, and correspond
1567
to newforms f and g, then this number equals the order of the
1568
intersection of the modular abelian varieties attached to f and g.
1569
1570
EXAMPLES::
1571
1572
sage: m = ModularSymbols(389,2)
1573
sage: d = m.decomposition(2)
1574
sage: eis = d[0]
1575
sage: ell = d[1]
1576
sage: af = d[-1]
1577
sage: af.intersection_number(eis)
1578
97
1579
sage: af.intersection_number(ell)
1580
400
1581
"""
1582
if not isinstance(M, ModularSymbolsSpace):
1583
raise TypeError, "M must be a modular symbols space"
1584
if M.ambient() != self.ambient():
1585
raise ValueError, "self and M must be in the same ambient space."
1586
A = self.integral_structure()
1587
B = M.integral_structure()
1588
return (A+B).index_in_saturation()
1589
1590
def integral_basis(self):
1591
r"""
1592
Return a basis for the `\ZZ`-submodule of this
1593
modular symbols space spanned by the generators.
1594
1595
Modular symbols spaces for congruence subgroups have a
1596
`\ZZ`-structure. Computing this
1597
`\ZZ`-structure is expensive, so by default modular
1598
symbols spaces for congruence subgroups in Sage are defined over
1599
`\QQ`. This function returns a tuple of independent
1600
elements in this modular symbols space whose
1601
`\ZZ`-span is the corresponding space of modular
1602
symbols over `\ZZ`.
1603
1604
EXAMPLES::
1605
1606
sage: M = ModularSymbols(11)
1607
sage: M.basis()
1608
((1,0), (1,8), (1,9))
1609
sage: M.integral_basis()
1610
((1,0), (1,8), (1,9))
1611
sage: S = M.cuspidal_submodule()
1612
sage: S.basis()
1613
((1,8), (1,9))
1614
sage: S.integral_basis()
1615
((1,8), (1,9))
1616
1617
::
1618
1619
sage: M = ModularSymbols(13,4)
1620
sage: M.basis()
1621
([X^2,(0,1)], [X^2,(1,4)], [X^2,(1,5)], [X^2,(1,7)], [X^2,(1,9)], [X^2,(1,10)], [X^2,(1,11)], [X^2,(1,12)])
1622
sage: M.integral_basis()
1623
([X^2,(0,1)], 1/28*[X^2,(1,4)] + 2/7*[X^2,(1,5)] + 3/28*[X^2,(1,7)] + 11/14*[X^2,(1,9)] + 2/7*[X^2,(1,10)] + 11/28*[X^2,(1,11)] + 3/28*[X^2,(1,12)], [X^2,(1,5)], 1/2*[X^2,(1,7)] + 1/2*[X^2,(1,9)], [X^2,(1,9)], [X^2,(1,10)], [X^2,(1,11)], [X^2,(1,12)])
1624
sage: S = M.cuspidal_submodule()
1625
sage: S.basis()
1626
([X^2,(1,4)] - [X^2,(1,12)], [X^2,(1,5)] - [X^2,(1,12)], [X^2,(1,7)] - [X^2,(1,12)], [X^2,(1,9)] - [X^2,(1,12)], [X^2,(1,10)] - [X^2,(1,12)], [X^2,(1,11)] - [X^2,(1,12)])
1627
sage: S.integral_basis()
1628
(1/28*[X^2,(1,4)] + 2/7*[X^2,(1,5)] + 3/28*[X^2,(1,7)] + 11/14*[X^2,(1,9)] + 2/7*[X^2,(1,10)] + 11/28*[X^2,(1,11)] - 53/28*[X^2,(1,12)], [X^2,(1,5)] - [X^2,(1,12)], 1/2*[X^2,(1,7)] + 1/2*[X^2,(1,9)] - [X^2,(1,12)], [X^2,(1,9)] - [X^2,(1,12)], [X^2,(1,10)] - [X^2,(1,12)], [X^2,(1,11)] - [X^2,(1,12)])
1629
1630
This function currently raises a NotImplementedError on modular
1631
symbols spaces with character of order bigger than `2`:
1632
1633
EXAMPLES::
1634
1635
sage: M = ModularSymbols(DirichletGroup(13).0^2, 2); M
1636
Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta6], sign 0, over Cyclotomic Field of order 6 and degree 2
1637
sage: M.basis()
1638
((1,0), (1,5), (1,10), (1,11))
1639
sage: M.integral_basis()
1640
Traceback (most recent call last):
1641
...
1642
NotImplementedError
1643
"""
1644
try:
1645
return self.__integral_basis
1646
except AttributeError:
1647
pass
1648
B = self.integral_structure().basis()
1649
self.__integral_basis = tuple([self(b) for b in B])
1650
return self.__integral_basis
1651
1652
1653
def integral_hecke_matrix(self, n):
1654
r"""
1655
Return the matrix of the `n`th Hecke operator acting on the integral
1656
structure on self (as returned by ``self.integral_structure()``). This
1657
is often (but not always) different from the matrix returned by
1658
``self.hecke_matrix``, even if the latter has integral entries.
1659
1660
EXAMPLE::
1661
1662
sage: M = ModularSymbols(6,4)
1663
sage: M.hecke_matrix(3)
1664
[27 0 0 0 6 -6]
1665
[ 0 1 -4 4 8 10]
1666
[18 0 1 0 6 -6]
1667
[18 0 4 -3 6 -6]
1668
[ 0 0 0 0 9 18]
1669
[ 0 0 0 0 12 15]
1670
sage: M.integral_hecke_matrix(3)
1671
[ 27 0 0 0 6 -6]
1672
[ 0 1 -8 8 12 14]
1673
[ 18 0 5 -4 14 8]
1674
[ 18 0 8 -7 2 -10]
1675
[ 0 0 0 0 9 18]
1676
[ 0 0 0 0 12 15]
1677
"""
1678
n = int(n)
1679
try:
1680
return self.__integral_hecke_matrix[n]
1681
except AttributeError:
1682
self.__integral_hecke_matrix = {}
1683
except KeyError:
1684
pass
1685
#raise NotImplementedError, "code past this point is broken / not done" # todo
1686
A = self.ambient_hecke_module()
1687
T = A.hecke_matrix(n)
1688
S = T.restrict(self.integral_structure()).change_ring(ZZ)
1689
self.__integral_hecke_matrix[n] = S
1690
return S
1691
1692
def sturm_bound(self):
1693
r"""
1694
Returns the Sturm bound for this space of modular symbols.
1695
1696
Type ``sturm_bound?`` for more details.
1697
1698
EXAMPLES::
1699
1700
sage: ModularSymbols(11,2).sturm_bound()
1701
2
1702
sage: ModularSymbols(389,2).sturm_bound()
1703
65
1704
sage: ModularSymbols(1,12).sturm_bound()
1705
1
1706
sage: ModularSymbols(1,36).sturm_bound()
1707
3
1708
sage: ModularSymbols(DirichletGroup(31).0^2).sturm_bound()
1709
6
1710
sage: ModularSymbols(Gamma1(31)).sturm_bound()
1711
160
1712
"""
1713
# For Gamma_0(N), n = \frac{k}{12}[\SL_2(\Z):\Gamma_0(N)]
1714
try:
1715
return self.__sturm_bound
1716
except:
1717
if self.character() is not None:
1718
self.__sturm_bound = Gamma0(self.level()).sturm_bound(self.weight())
1719
else:
1720
self.__sturm_bound = self.group().sturm_bound(self.weight())
1721
return self.__sturm_bound
1722
1723
1724
def plus_submodule(self, compute_dual=True):
1725
"""
1726
Return the subspace of self on which the star involution acts as
1727
+1.
1728
1729
INPUT:
1730
1731
1732
- ``compute_dual`` - bool (default: True) also
1733
compute dual subspace. This are useful for many algorithms.
1734
1735
1736
OUTPUT: subspace of modular symbols
1737
1738
EXAMPLES::
1739
1740
sage: ModularSymbols(17,2)
1741
Modular Symbols space of dimension 3 for Gamma_0(17) of weight 2 with sign 0 over Rational Field
1742
sage: ModularSymbols(17,2).plus_submodule()
1743
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(17) of weight 2 with sign 0 over Rational Field
1744
"""
1745
return self.sign_submodule(+1, compute_dual)
1746
1747
def minus_submodule(self, compute_dual=True):
1748
"""
1749
Return the subspace of self on which the star involution acts as
1750
-1.
1751
1752
INPUT:
1753
1754
1755
- ``compute_dual`` - bool (default: True) also
1756
compute dual subspace. This are useful for many algorithms.
1757
1758
OUTPUT: subspace of modular symbols
1759
1760
EXAMPLES::
1761
1762
sage: ModularSymbols(14,4)
1763
Modular Symbols space of dimension 12 for Gamma_0(14) of weight 4 with sign 0 over Rational Field
1764
sage: ModularSymbols(14,4).minus_submodule()
1765
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 12 for Gamma_0(14) of weight 4 with sign 0 over Rational Field
1766
"""
1767
return self.sign_submodule(-1, compute_dual)
1768
1769
def _compute_sign_submodule(self, sign, compute_dual=True):
1770
r"""
1771
Compute the submodule of self which is an eigenspace for the star involution with the given sign.
1772
1773
INPUT:
1774
1775
- sign (integer): 1 or -1
1776
1777
- compute_dual (True or False, default True): also compute the dual submodule (useful for some algorithms)
1778
1779
OUTPUT: a submodule of self
1780
1781
EXAMPLE::
1782
1783
sage: ModularSymbols(Gamma1(11), 3)._compute_sign_submodule(-1)
1784
Modular Symbols subspace of dimension 10 of Modular Symbols space of dimension 20 for Gamma_1(11) of weight 3 with sign 0 and over Rational Field
1785
"""
1786
A = self.ambient()
1787
S = A.sign_submodule(sign, compute_dual=compute_dual)
1788
V = S.free_module().intersection(self.free_module())
1789
if compute_dual:
1790
W = S.dual_free_module()
1791
Y = self.dual_free_module()
1792
D = W.intersection(Y)
1793
M = A.submodule(V, D, check=False)
1794
else:
1795
M = A.submodule(V, check=False)
1796
M._set_sign(sign)
1797
return M
1798
1799
def _set_sign(self, sign):
1800
r"""
1801
Store the sign of this module (used by various initialisation
1802
routines).
1803
1804
INPUT:
1805
1806
- (integer) sign (must be -1, 0 or 1)
1807
1808
OUTPUT: none
1809
1810
EXAMPLES::
1811
1812
sage: ModularSymbols(11, 2)._set_sign(123)
1813
Traceback (most recent call last):
1814
...
1815
ValueError: sign (=123) must be -1, 0, or 1
1816
sage: M = ModularSymbols(11, 2); M
1817
Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
1818
sage: M._set_sign(-1); M
1819
Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign -1 over Rational Field
1820
sage: M._set_sign(0)
1821
"""
1822
sign = int(sign)
1823
if not (sign in [-1,0,1]):
1824
raise ValueError, "sign (=%s) must be -1, 0, or 1"%sign
1825
self.__sign = sign
1826
1827
def sign_submodule(self, sign, compute_dual=True):
1828
"""
1829
Return the subspace of self that is fixed under the star
1830
involution.
1831
1832
INPUT:
1833
1834
1835
- ``sign`` - int (either -1, 0 or +1)
1836
1837
- ``compute_dual`` - bool (default: True) also
1838
compute dual subspace. This are useful for many algorithms.
1839
1840
1841
OUTPUT: subspace of modular symbols
1842
1843
EXAMPLES::
1844
1845
sage: M = ModularSymbols(29,2)
1846
sage: M.sign_submodule(1)
1847
Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 5 for Gamma_0(29) of weight 2 with sign 0 over Rational Field
1848
sage: M.sign_submodule(-1)
1849
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(29) of weight 2 with sign 0 over Rational Field
1850
sage: M.sign_submodule(-1).sign()
1851
-1
1852
"""
1853
sign = int(sign)
1854
if not sign in [-1, 0, 1]:
1855
raise ValueError, "sign must be -1, 0 or 1"
1856
if self.sign() == sign: # an easy case
1857
return self
1858
if self.sign() == -sign: # another easy case
1859
return self.zero_submodule()
1860
if sign == 0:
1861
# if sign is zero then self.sign() isn't 0 because
1862
# of the above checks.
1863
raise ArithmeticError, "There is no sign 0 subspace of a space of modular symbols with nonzero sign."
1864
try:
1865
return self.__plus_submodule[(sign, compute_dual)]
1866
except AttributeError:
1867
self.__plus_submodule = {}
1868
except KeyError:
1869
pass
1870
P = self._compute_sign_submodule(sign, compute_dual)
1871
P.__star_eigenvalue = sign
1872
self.__plus_submodule[(sign,compute_dual)] = P
1873
return P
1874
1875
def star_involution(self):
1876
"""
1877
Return the star involution on self, which is induced by complex
1878
conjugation on modular symbols. Not implemented in this abstract base
1879
class.
1880
1881
EXAMPLES::
1882
1883
sage: M = ModularSymbols(11, 2); sage.modular.modsym.space.ModularSymbolsSpace.star_involution(M)
1884
Traceback (most recent call last):
1885
...
1886
NotImplementedError
1887
"""
1888
raise NotImplementedError
1889
1890
def abelian_variety(self):
1891
"""
1892
Return the corresponding abelian variety.
1893
1894
INPUT:
1895
1896
1897
- ``self`` - modular symbols space of weight 2 for a
1898
congruence subgroup such as Gamma0, Gamma1 or GammaH.
1899
1900
1901
EXAMPLES::
1902
1903
sage: ModularSymbols(Gamma0(11)).cuspidal_submodule().abelian_variety()
1904
Abelian variety J0(11) of dimension 1
1905
sage: ModularSymbols(Gamma1(11)).cuspidal_submodule().abelian_variety()
1906
Abelian variety J1(11) of dimension 1
1907
sage: ModularSymbols(GammaH(11,[3])).cuspidal_submodule().abelian_variety()
1908
Abelian variety JH(11,[3]) of dimension 1
1909
1910
The abelian variety command only works on cuspidal modular symbols
1911
spaces::
1912
1913
sage: M = ModularSymbols(37)
1914
sage: M[0].abelian_variety()
1915
Traceback (most recent call last):
1916
...
1917
ValueError: self must be cuspidal
1918
sage: M[1].abelian_variety()
1919
Abelian subvariety of dimension 1 of J0(37)
1920
sage: M[2].abelian_variety()
1921
Abelian subvariety of dimension 1 of J0(37)
1922
"""
1923
try:
1924
return self.__modular_abelian_variety
1925
except AttributeError:
1926
if not self.is_cuspidal():
1927
raise ValueError, "self must be cuspidal"
1928
from sage.modular.abvar.abvar import ModularAbelianVariety_modsym
1929
A = ModularAbelianVariety_modsym(self, check=False)
1930
self.__modular_abelian_variety = A
1931
return A
1932
1933
def rational_period_mapping(self):
1934
r"""
1935
Return the rational period mapping associated to self.
1936
1937
This is a homomorphism to a vector space whose kernel is the same as
1938
the kernel of the period mapping associated to self. For this to exist,
1939
self must be Hecke equivariant.
1940
1941
Use ``integral_period_mapping`` to obtain a homomorphism to a
1942
`\ZZ`-module, normalized so the image of integral modular symbols is
1943
exactly `\ZZ^n`.
1944
1945
EXAMPLES::
1946
1947
sage: M = ModularSymbols(37)
1948
sage: A = M[1]; A
1949
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(37) of weight 2 with sign 0 over Rational Field
1950
sage: r = A.rational_period_mapping(); r
1951
Rational period mapping associated to Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(37) of weight 2 with sign 0 over Rational Field
1952
sage: r(M.0)
1953
(0, 0)
1954
sage: r(M.1)
1955
(1, 0)
1956
sage: r.matrix()
1957
[ 0 0]
1958
[ 1 0]
1959
[ 0 1]
1960
[-1 -1]
1961
[ 0 0]
1962
sage: r.domain()
1963
Modular Symbols space of dimension 5 for Gamma_0(37) of weight 2 with sign 0 over Rational Field
1964
sage: r.codomain()
1965
Vector space of degree 2 and dimension 2 over Rational Field
1966
Basis matrix:
1967
[1 0]
1968
[0 1]
1969
"""
1970
try:
1971
return self.__rational_period_mapping
1972
except AttributeError:
1973
pass
1974
V = self.dual_free_module()
1975
# the rational period mapping is just dotting with
1976
# each element of V.
1977
A = V.basis_matrix().transpose()
1978
A.set_immutable()
1979
R = RationalPeriodMapping(self, A)
1980
self.__rational_period_mapping = R
1981
return R
1982
1983
1984
def integral_period_mapping(self):
1985
r"""
1986
Return the integral period mapping associated to self.
1987
1988
This is a homomorphism to a vector space whose kernel is the same
1989
as the kernel of the period mapping associated to self, normalized
1990
so the image of integral modular symbols is exactly
1991
`\ZZ^n`.
1992
1993
EXAMPLES::
1994
1995
sage: m = ModularSymbols(23).cuspidal_submodule()
1996
sage: i = m.integral_period_mapping()
1997
sage: i
1998
Integral period mapping associated to Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
1999
sage: i.matrix()
2000
[-1/11 1/11 0 3/11]
2001
[ 1 0 0 0]
2002
[ 0 1 0 0]
2003
[ 0 0 1 0]
2004
[ 0 0 0 1]
2005
sage: [i(b) for b in m.integral_structure().basis()]
2006
[(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)]
2007
sage: [i(b) for b in m.ambient_module().basis()]
2008
[(-1/11, 1/11, 0, 3/11),
2009
(1, 0, 0, 0),
2010
(0, 1, 0, 0),
2011
(0, 0, 1, 0),
2012
(0, 0, 0, 1)]
2013
2014
We compute the image of the winding element::
2015
2016
sage: m = ModularSymbols(37,sign=1)
2017
sage: a = m[1]
2018
sage: f = a.integral_period_mapping()
2019
sage: e = m([0,oo])
2020
sage: f(e)
2021
(-2/3)
2022
2023
The input space must be cuspidal::
2024
2025
sage: m = ModularSymbols(37,2,sign=1)
2026
sage: m.integral_period_mapping()
2027
Traceback (most recent call last):
2028
...
2029
ValueError: integral mapping only defined for cuspidal spaces
2030
"""
2031
try:
2032
return self.__integral_period_mapping
2033
except AttributeError:
2034
pass
2035
if self.base_ring() != QQ:
2036
raise ValueError, "integral mapping only defined for spaces over QQ"
2037
if not self.is_cuspidal():
2038
raise ValueError, "integral mapping only defined for cuspidal spaces"
2039
D = self.dual_free_module().basis_matrix().transpose()
2040
I = self.ambient_module().cuspidal_submodule().integral_structure().basis_matrix()
2041
# image of cuspidal integral submodule
2042
C = I * D
2043
if not C.is_one():
2044
if not C.is_square():
2045
C = (ZZ**C.ncols()).span(C.rows()).basis_matrix()
2046
D = D * C**(-1)
2047
D.set_immutable()
2048
R = IntegralPeriodMapping(self, D)
2049
self.__integral_period_mapping = R
2050
return R
2051
2052
def modular_symbols_of_sign(self, sign, bound=None):
2053
"""
2054
Returns a space of modular symbols with the same defining
2055
properties (weight, level, etc.) and Hecke eigenvalues as this
2056
space except with given sign.
2057
2058
INPUT:
2059
2060
2061
- ``self`` - a cuspidal space of modular symbols
2062
2063
- ``sign`` - an integer, one of -1, 0, or 1
2064
2065
- ``bound`` - integer (default: None); if specified
2066
only use Hecke operators up to the given bound.
2067
2068
2069
EXAMPLES::
2070
2071
sage: S = ModularSymbols(Gamma0(11),2,sign=0).cuspidal_subspace()
2072
sage: S
2073
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
2074
sage: S.modular_symbols_of_sign(-1)
2075
Modular Symbols space of dimension 1 for Gamma_0(11) of weight 2 with sign -1 over Rational Field
2076
2077
::
2078
2079
sage: S = ModularSymbols(43,2,sign=1)[2]; S
2080
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 for Gamma_0(43) of weight 2 with sign 1 over Rational Field
2081
sage: S.modular_symbols_of_sign(-1)
2082
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(43) of weight 2 with sign -1 over Rational Field
2083
2084
::
2085
2086
sage: S.modular_symbols_of_sign(0)
2087
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 7 for Gamma_0(43) of weight 2 with sign 0 over Rational Field
2088
2089
::
2090
2091
sage: S = ModularSymbols(389,sign=1)[3]; S
2092
Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 33 for Gamma_0(389) of weight 2 with sign 1 over Rational Field
2093
sage: S.modular_symbols_of_sign(-1)
2094
Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 32 for Gamma_0(389) of weight 2 with sign -1 over Rational Field
2095
sage: S.modular_symbols_of_sign(0)
2096
Modular Symbols subspace of dimension 6 of Modular Symbols space of dimension 65 for Gamma_0(389) of weight 2 with sign 0 over Rational Field
2097
2098
::
2099
2100
sage: S = ModularSymbols(23,sign=1,weight=4)[2]; S
2101
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 7 for Gamma_0(23) of weight 4 with sign 1 over Rational Field
2102
sage: S.modular_symbols_of_sign(1) is S
2103
True
2104
sage: S.modular_symbols_of_sign(0)
2105
Modular Symbols subspace of dimension 8 of Modular Symbols space of dimension 12 for Gamma_0(23) of weight 4 with sign 0 over Rational Field
2106
sage: S.modular_symbols_of_sign(-1)
2107
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 4 with sign -1 over Rational Field
2108
"""
2109
if sign == self.sign():
2110
return self
2111
if not self.is_cuspidal():
2112
raise ValueError, "self must be cuspidal for modular symbols space with given sign to be defined."
2113
d = self.dimension()
2114
if d == 0:
2115
return self
2116
if sign != 0:
2117
if self.sign() == 0:
2118
d = d//2
2119
elif sign == 0: # self has nonzero sign
2120
d = 2*d
2121
B = self.ambient_module().modular_symbols_of_sign(sign)
2122
p = 2
2123
if bound is None:
2124
bound = self.hecke_bound()
2125
while B.dimension() > d and p <= bound:
2126
while self.level() % p == 0:
2127
p = arith.next_prime(p)
2128
f = self.hecke_polynomial(p)
2129
g = misc.prod(g for g,_ in f.factor()) # square free part
2130
t = B.hecke_operator(p)
2131
s = g(t)
2132
B = s.kernel()
2133
p = arith.next_prime(p)
2134
return B
2135
2136
#########################################################
2137
# Cuspidal torsion groups
2138
#########################################################
2139
2140
def abvarquo_cuspidal_subgroup(self):
2141
"""
2142
Compute the rational subgroup of the cuspidal subgroup (as an
2143
abstract abelian group) of the abelian variety quotient A of
2144
the relevant modular Jacobian attached to this modular symbols
2145
space.
2146
2147
We assume that self is defined over QQ and has weight 2. If
2148
the sign of self is not 0, then the power of 2 may be wrong.
2149
2150
EXAMPLES::
2151
2152
sage: D = ModularSymbols(66,2,sign=0).cuspidal_subspace().new_subspace().decomposition()
2153
sage: D[0].abvarquo_cuspidal_subgroup()
2154
Finitely generated module V/W over Integer Ring with invariants (3)
2155
sage: [A.abvarquo_cuspidal_subgroup().invariants() for A in D]
2156
[(3,), (2,), ()]
2157
sage: D = ModularSymbols(66,2,sign=1).cuspidal_subspace().new_subspace().decomposition()
2158
sage: [A.abvarquo_cuspidal_subgroup().invariants() for A in D]
2159
[(3,), (2,), ()]
2160
sage: D = ModularSymbols(66,2,sign=-1).cuspidal_subspace().new_subspace().decomposition()
2161
sage: [A.abvarquo_cuspidal_subgroup().invariants() for A in D]
2162
[(), (), ()]
2163
"""
2164
try: return self.__abvarquo_cuspidal_subgroup
2165
except AttributeError: pass
2166
if self.base_ring() != QQ:
2167
raise ValueError, "base ring must be QQ"
2168
if self.weight() != 2:
2169
raise NotImplementedError, "only implemented when weight is 2"
2170
M = self.ambient_module()
2171
phi = self.integral_period_mapping()
2172
2173
# Make a list of all the finite cusps.
2174
P = [c for c in M.cusps() if not c.is_infinity()]
2175
2176
# Compute the images of the cusp classes (c)-(oo) in the
2177
# rational homology of the quotient modular abelian variety.
2178
ims = [phi(M([c,infinity])) for c in P]
2179
2180
# Take the span of the ims over ZZ
2181
A = phi.codomain().span(ims, ZZ)
2182
2183
# The cuspidal subgroup is then the quotient of that module +
2184
# H_1(A) by H_1(A)
2185
C = (A.ambient_module() + A)/A.ambient_module()
2186
2187
self.__abvarquo_cuspidal_subgroup = C
2188
return C
2189
2190
def abvarquo_rational_cuspidal_subgroup(self):
2191
r"""
2192
Compute the rational subgroup of the cuspidal subgroup (as an
2193
abstract abelian group) of the abelian variety quotient A of
2194
the relevant modular Jacobian attached to this modular symbols
2195
space. If C is the subgroup of A generated by differences of
2196
cusps, then C is equipped with an action of Gal(Qbar/Q), and
2197
this function computes the fixed subgroup, i.e., C(Q).
2198
2199
We assume that self is defined over QQ and has weight 2. If
2200
the sign of self is not 0, then the power of 2 may be wrong.
2201
2202
EXAMPLES:
2203
2204
First we consider the fairly straightforward level 37 case,
2205
where the torsion subgroup of the optimal quotients (which are
2206
all elliptic curves) are all cuspidal::
2207
2208
sage: M = ModularSymbols(37).cuspidal_subspace().new_subspace()
2209
sage: D = M.decomposition()
2210
sage: [(A.abvarquo_rational_cuspidal_subgroup().invariants(), A.T(19)[0,0]) for A in D]
2211
[((), 0), ((3,), 2)]
2212
sage: [(E.torsion_subgroup().invariants(),E.ap(19)) for E in cremona_optimal_curves([37])]
2213
[((), 0), ((3,), 2)]
2214
2215
Next we consider level 54, where the rational cuspidal
2216
subgroups of the quotients are also cuspidal::
2217
2218
sage: M = ModularSymbols(54).cuspidal_subspace().new_subspace()
2219
sage: D = M.decomposition()
2220
sage: [A.abvarquo_rational_cuspidal_subgroup().invariants() for A in D]
2221
[(3,), (3,)]
2222
sage: [E.torsion_subgroup().invariants() for E in cremona_optimal_curves([54])]
2223
[(3,), (3,)]
2224
2225
Level 66 is interesting, since not all torsion of the quotient
2226
is rational. In fact, for each elliptic curve quotient, the
2227
`\QQ`-rational subgroup of the image of the cuspidal subgroup
2228
in the quotient is a nontrivial subgroup of `E(\QQ)_{tor}`.
2229
Thus not all torsion in the quotient is cuspidal!
2230
2231
sage: M = ModularSymbols(66).cuspidal_subspace().new_subspace()
2232
sage: D = M.decomposition()
2233
sage: [(A.abvarquo_rational_cuspidal_subgroup().invariants(), A.T(19)[0,0]) for A in D]
2234
[((3,), -4), ((2,), 4), ((), 0)]
2235
sage: [(E.torsion_subgroup().invariants(),E.ap(19)) for E in cremona_optimal_curves([66])]
2236
[((6,), -4), ((4,), 4), ((10,), 0)]
2237
sage: [A.abelian_variety().rational_cuspidal_subgroup().invariants() for A in D]
2238
[[6], [4], [10]]
2239
2240
In this example, the abelian varieties involved all having
2241
dimension bigger than 1 (unlike above). We find that all torsion
2242
in the quotient in each of these cases is cuspidal::
2243
2244
sage: M = ModularSymbols(125).cuspidal_subspace().new_subspace()
2245
sage: D = M.decomposition()
2246
sage: [A.abvarquo_rational_cuspidal_subgroup().invariants() for A in D]
2247
[(), (5,), (5,)]
2248
sage: [A.abelian_variety().rational_torsion_subgroup().multiple_of_order() for A in D]
2249
[1, 5, 5]
2250
"""
2251
try: return self.__abvarquo_rational_cuspidal_subgroup
2252
except AttributeError: pass
2253
if self.base_ring() != QQ:
2254
raise ValueError, "base ring must be QQ"
2255
if self.weight() != 2:
2256
raise NotImplementedError, "only implemented when weight is 2"
2257
if not is_Gamma0(self.group()):
2258
# todo -- do Gamma1 and GammaH, which are easy
2259
raise NotImplementedError, "only implemented when group is Gamma0"
2260
N = self.level()
2261
if N.is_squarefree():
2262
return self.abvarquo_cuspidal_subgroup()
2263
2264
M = self.ambient_module()
2265
phi = self.integral_period_mapping()
2266
2267
# Make a list of all the finite cusps.
2268
P = [c for c in M.cusps() if not c.is_infinity()]
2269
2270
# Define the vector space V, which we think of as
2271
# the vector space with basis (c)-(oo), where c runs
2272
# through the finite cusp *classes*.
2273
V = ZZ**len(P) # vector space on (c)-(oo)
2274
2275
# Compute the images of the cusp classes (c)-(oo) in the
2276
# rational homology of the quotient modular abelian variety.
2277
ims = [phi(M([c,infinity])) for c in P]
2278
2279
# Take the span of the ims over ZZ
2280
A = phi.codomain().span(ims, ZZ)
2281
2282
# The cuspidal subgroup is then the quotient of that module +
2283
# H_1(A) by H_1(A)
2284
C = (A.ambient_module() + A)/A.ambient_module()
2285
2286
# Make fgp module version of V.
2287
D = V/V.zero_submodule()
2288
psi = D.hom([C(x) for x in ims])
2289
2290
# The rational cuspidal subgroup is got by intersecting kernels
2291
# of tau - 1, for all automorphisms tau.
2292
G = Zmod(N).unit_gens()
2293
CQ = C
2294
for t in G:
2295
T = self._matrix_of_galois_action(t, P) - 1
2296
if not T: continue
2297
im_gens = [psi(psi.lift(g).lift() * T) for g in CQ.gens()]
2298
h = CQ.hom(im_gens)
2299
CQ = h.kernel()
2300
if CQ.cardinality() == 1:
2301
break # done -- no point in wasting more time shrinking CQ
2302
2303
self.__abvarquo_rational_cuspidal_subgroup = CQ
2304
return CQ
2305
2306
def _matrix_of_galois_action(self, t, P):
2307
"""
2308
Compute the matrix of the action of the element of the
2309
cyclotomic Galois group defined by t on the set of cusps in P
2310
(which is the set of finite cusps). This function is used
2311
internally by the (rational) cuspidal subgroup and quotient
2312
functions.
2313
2314
INPUT:
2315
2316
- `t` -- integer
2317
- `P` -- list of cusps
2318
2319
EXAMPLES::
2320
2321
We compute the matrix of the element of the Galois group
2322
associated to 5 and 31 for level 32. In the first case the
2323
Galois action is trivial, and in the second it is
2324
nontrivial.::
2325
2326
sage: M = ModularSymbols(32)
2327
sage: P = [c for c in Gamma0(32).cusps() if not c.is_infinity()]
2328
sage: M._matrix_of_galois_action(5, P)
2329
[1 0 0 0 0 0 0]
2330
[0 1 0 0 0 0 0]
2331
[0 0 1 0 0 0 0]
2332
[0 0 0 1 0 0 0]
2333
[0 0 0 0 1 0 0]
2334
[0 0 0 0 0 1 0]
2335
[0 0 0 0 0 0 1]
2336
sage: z = M._matrix_of_galois_action(31, P); z
2337
[1 0 0 0 0 0 0]
2338
[0 1 0 0 0 0 0]
2339
[0 0 0 0 1 0 0]
2340
[0 0 0 0 0 0 1]
2341
[0 0 1 0 0 0 0]
2342
[0 0 0 0 0 1 0]
2343
[0 0 0 1 0 0 0]
2344
sage: z.charpoly().factor()
2345
(x + 1)^2 * (x - 1)^5
2346
"""
2347
N = self.level()
2348
from sage.matrix.constructor import matrix
2349
A = matrix(ZZ, len(P))
2350
for i, c in enumerate(P):
2351
d = c.galois_action(t, N)
2352
for j, e in enumerate(P):
2353
if d.is_gamma0_equiv(e, N, False):
2354
A[i,j] = 1
2355
A.set_immutable()
2356
return A
2357
2358
class PeriodMapping(SageObject):
2359
r"""
2360
Base class for representing a period mapping attached to a space of modular
2361
symbols. To be used via the derived classes RationalPeriodMapping and
2362
IntegralPeriodMapping.
2363
"""
2364
def __init__(self, modsym, A):
2365
r"""
2366
Standard initialisation function.
2367
2368
INPUT:
2369
2370
- ``modsym`` - a space of modular symbols
2371
2372
- ``A`` - matrix of the associated period map
2373
2374
EXAMPLE::
2375
2376
sage: ModularSymbols(2, 8).cuspidal_submodule().integral_period_mapping() # indirect doctest
2377
Integral period mapping associated to Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 for Gamma_0(2) of weight 8 with sign 0 over Rational Field
2378
"""
2379
self.__modsym = modsym
2380
self.__domain = modsym.ambient_module()
2381
self.__A = A
2382
A.set_immutable()
2383
2384
def modular_symbols_space(self):
2385
r"""
2386
Return the space of modular symbols to which this period mapping
2387
corresponds.
2388
2389
EXAMPLES::
2390
2391
sage: ModularSymbols(17, 2).rational_period_mapping().modular_symbols_space()
2392
Modular Symbols space of dimension 3 for Gamma_0(17) of weight 2 with sign 0 over Rational Field
2393
"""
2394
return self.__modsym
2395
2396
def __call__(self, x):
2397
r"""
2398
Evaluate this mapping at an element of the domain.
2399
2400
EXAMPLE::
2401
2402
sage: M = ModularSymbols(17, 2).cuspidal_submodule().integral_period_mapping()
2403
sage: M(vector([1,0,2]))
2404
(0, 9/4)
2405
"""
2406
if is_FreeModuleElement(x):
2407
v = x
2408
else:
2409
v = self.__domain(x).element()
2410
return v*self.__A
2411
2412
def matrix(self):
2413
r"""
2414
Return the matrix of this period mapping.
2415
2416
EXAMPLE::
2417
2418
sage: ModularSymbols(11, 2).cuspidal_submodule().integral_period_mapping().matrix()
2419
[ 0 1/5]
2420
[ 1 0]
2421
[ 0 1]
2422
"""
2423
return self.__A
2424
2425
def domain(self):
2426
r"""
2427
Return the domain of this mapping (which is the ambient space of the
2428
corresponding modular symbols space).
2429
2430
EXAMPLE::
2431
2432
sage: ModularSymbols(17, 2).cuspidal_submodule().integral_period_mapping().domain()
2433
Modular Symbols space of dimension 3 for Gamma_0(17) of weight 2 with sign 0 over Rational Field
2434
"""
2435
return self.__domain
2436
2437
def codomain(self):
2438
r"""
2439
Return the codomain of this mapping.
2440
2441
EXAMPLE:
2442
2443
Note that this presently returns the wrong answer, as a consequence of
2444
various bugs in the free module routines::
2445
2446
sage: ModularSymbols(11, 2).cuspidal_submodule().integral_period_mapping().codomain()
2447
Vector space of degree 2 and dimension 2 over Rational Field
2448
Basis matrix:
2449
[1 0]
2450
[0 1]
2451
"""
2452
return self.__A.row_module()
2453
2454
class RationalPeriodMapping(PeriodMapping):
2455
def _repr_(self):
2456
"""
2457
Return the string representation of self.
2458
2459
EXAMPLES::
2460
2461
sage: ModularSymbols(40,2).rational_period_mapping()._repr_()
2462
'Rational period mapping associated to Modular Symbols space of dimension 13 for Gamma_0(40) of weight 2 with sign 0 over Rational Field'
2463
"""
2464
return "Rational period mapping associated to %s"%self.modular_symbols_space()
2465
2466
2467
class IntegralPeriodMapping(PeriodMapping):
2468
def _repr_(self):
2469
"""
2470
Return the string representation of self.
2471
2472
EXAMPLES::
2473
2474
sage: ModularSymbols(40,2).cuspidal_submodule().integral_period_mapping()._repr_()
2475
'Integral period mapping associated to Modular Symbols subspace of dimension 6 of Modular Symbols space of dimension 13 for Gamma_0(40) of weight 2 with sign 0 over Rational Field'
2476
"""
2477
return "Integral period mapping associated to %s"%self.modular_symbols_space()
2478
2479