Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/hecke/ambient_module.py
4059 views
1
"""
2
Ambient Hecke modules
3
"""
4
5
#*****************************************************************************
6
# Sage: System for Algebra and Geometry Experimentation
7
#
8
# Copyright (C) 2005 William Stein <[email protected]>
9
#
10
# Distributed under the terms of the GNU General Public License (GPL)
11
#
12
# This code is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
# General Public License for more details.
16
#
17
# The full text of the GPL is available at:
18
#
19
# http://www.gnu.org/licenses/
20
#*****************************************************************************
21
22
import degenmap
23
import module
24
import submodule
25
26
import sage.modules.all
27
28
import sage.rings.all
29
30
import sage.misc.misc as misc
31
32
import sage.rings.arith as arith
33
34
import sage.matrix.matrix_space as matrix_space
35
from sage.matrix.constructor import matrix
36
37
from sage.modular.arithgroup.all import Gamma0 # for Sturm bound
38
39
def is_AmbientHeckeModule(x):
40
r"""
41
Return True if x is of type AmbientHeckeModule.
42
43
EXAMPLES::
44
45
sage: from sage.modular.hecke.ambient_module import is_AmbientHeckeModule
46
sage: is_AmbientHeckeModule(ModularSymbols(6))
47
True
48
sage: is_AmbientHeckeModule(ModularSymbols(6).cuspidal_subspace())
49
False
50
sage: is_AmbientHeckeModule(ModularForms(11))
51
True
52
sage: is_AmbientHeckeModule(BrandtModule(2, 3))
53
True
54
"""
55
return isinstance(x, AmbientHeckeModule)
56
57
class AmbientHeckeModule(module.HeckeModule_free_module):
58
"""
59
An ambient Hecke module, i.e. a Hecke module that is isomorphic as a module
60
over its base ring `R` to the standard free module `R^k` for some `k`. This
61
is the base class for ambient spaces of modular forms and modular symbols,
62
and for Brandt modules.
63
"""
64
def __init__(self, base_ring, rank, level, weight):
65
r"""
66
Create an ambient Hecke module.
67
68
EXAMPLES::
69
70
sage: ModularSymbols(6) # indirect doctest
71
Modular Symbols space of dimension 3 for Gamma_0(6) of weight 2 with sign 0 over Rational Field
72
sage: sage.modular.hecke.ambient_module.AmbientHeckeModule(QQ, 3, 2, 4)
73
Generic ambient Hecke module of rank 3, level 2 and weight 4 over Rational Field
74
"""
75
rank = sage.rings.all.Integer(rank)
76
if rank < 0:
77
raise ValueError, "rank (=%s) must be nonnegative"%rank
78
self.__rank = rank
79
module.HeckeModule_free_module.__init__(self, base_ring, level, weight)
80
81
def rank(self):
82
"""
83
Return the rank of this ambient Hecke module.
84
85
OUTPUT:
86
87
Integer
88
89
EXAMPLES::
90
91
sage: M = sage.modular.hecke.ambient_module.AmbientHeckeModule(QQ, 3, 11, 2); M
92
Generic ambient Hecke module of rank 3, level 11 and weight 2 over Rational Field
93
sage: M.rank()
94
3
95
"""
96
return self.__rank
97
98
def __add__(self, other):
99
r"""
100
Sum of self and other. As self is an ambient space, this will only make
101
sense if other is a subspace of self, in which case the answer is self.
102
103
EXAMPLES::
104
105
sage: M = ModularSymbols(23)
106
sage: M + M is M
107
True
108
sage: M + 3
109
Traceback (most recent call last):
110
...
111
TypeError: other (=3) must be a Hecke module.
112
"""
113
if not isinstance(other, module.HeckeModule_free_module):
114
raise TypeError, "other (=%s) must be a Hecke module."%other
115
if other.ambient_hecke_module() == self:
116
return self
117
raise ArithmeticError, "Sum only defined for subspaces of a common ambient Hecke module."
118
119
def _repr_(self):
120
r"""
121
String representation of self. Should be overridden by derived classes.
122
123
EXAMPLE::
124
125
sage: sage.modular.hecke.ambient_module.AmbientHeckeModule(QQ, 3, 2, 4)._repr_()
126
'Generic ambient Hecke module of rank 3, level 2 and weight 4 over Rational Field'
127
"""
128
return "Generic ambient Hecke module of rank %s, level %s and weight %s over %s"%(self.rank(), self.level(), self.weight(), self.base_ring())
129
130
131
def _degeneracy_raising_matrix(self, codomain):
132
"""
133
Matrix of the degeneracy map (with t = 1) from self to codomain, whose
134
level should be a multiple of the level of self.
135
136
EXAMPLE::
137
138
sage: sage.modular.hecke.ambient_module.AmbientHeckeModule(QQ, 3, 2, 4)._degeneracy_raising_matrix(4)
139
Traceback (most recent call last):
140
...
141
NotImplementedError
142
"""
143
raise NotImplementedError
144
145
def _degeneracy_lowering_matrix(self, codomain, t):
146
"""
147
Matrix of the degeneracy map of index t from self to codomain, whose level should be a divisor of the level of self.
148
149
EXAMPLE::
150
151
sage: sage.modular.hecke.ambient_module.AmbientHeckeModule(QQ, 3, 2, 4)._degeneracy_lowering_matrix(2, 2)
152
Traceback (most recent call last):
153
...
154
NotImplementedError
155
"""
156
raise NotImplementedError
157
158
def _hecke_image_of_ith_basis_element(self, n, i):
159
"""
160
Return the image under the Hecke operator T_n of the i-th basis
161
element.
162
163
EXAMPLE::
164
165
sage: sage.modular.hecke.ambient_module.AmbientHeckeModule(QQ, 3, 2, 4)._hecke_image_of_ith_basis_element(4, 2)
166
Traceback (most recent call last):
167
...
168
NotImplementedError
169
170
"""
171
return self.hecke_operator(n)(self.gen(i))
172
173
174
def _set_dual_free_module(self, V):
175
r"""
176
Store the embedded dual module of this module. Since this module is an
177
ambient module, this is not necessary.
178
179
EXAMPLE::
180
181
sage: ModularForms(11, 2)._set_dual_free_module(None)
182
"""
183
pass # setting dual free module of ambient space is not necessary
184
185
186
def ambient_hecke_module(self):
187
r"""
188
Return the ambient space that contains this ambient space. This is,
189
of course, just this space again.
190
191
EXAMPLE::
192
193
sage: M = ModularForms(11, 4); M.ambient_hecke_module() is M
194
True
195
"""
196
return self
197
198
def complement(self):
199
"""
200
Return the largest Hecke-stable complement of this space.
201
202
EXAMPLES::
203
204
sage: M=ModularSymbols(11,2,1)
205
sage: M
206
Modular Symbols space of dimension 2 for Gamma_0(11) of weight 2 with sign 1 over Rational Field
207
sage: M.complement()
208
Modular Symbols subspace of dimension 0 of Modular Symbols space of dimension 2 for Gamma_0(11) of weight 2 with sign 1 over Rational Field
209
sage: C=M.cuspidal_subspace()
210
sage: C
211
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 for Gamma_0(11) of weight 2 with sign 1 over Rational Field
212
sage: C.complement()
213
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 for Gamma_0(11) of weight 2 with sign 1 over Rational Field
214
"""
215
return self.zero_submodule()
216
217
def decomposition_matrix(self):
218
r"""
219
Returns the matrix whose columns form a basis for the canonical
220
sorted decomposition of self coming from the Hecke operators.
221
222
If the simple factors are `D_0, \ldots, D_n`, then the
223
first few columns are an echelonized basis for `D_0`, the
224
next an echelonized basis for `D_1`, the next for
225
`D_2`, etc.
226
227
EXAMPLE::
228
229
sage: S = ModularSymbols(37, 2)
230
sage: S.decomposition_matrix()
231
[ 1 0 0 0 -1/3]
232
[ 0 1 -1 0 1/2]
233
[ 0 0 0 1 -1/2]
234
[ 0 1 1 1 0]
235
[ 0 0 0 0 1]
236
"""
237
try:
238
return self.__decomposition_matrix_cache
239
except AttributeError:
240
rows = []
241
for A in self.decomposition():
242
for x in A.basis():
243
rows.append(x.list())
244
A = matrix_space.MatrixSpace(self.base_ring(),self.rank())(rows)
245
self.__decomposition_matrix_cache = A
246
return self.__decomposition_matrix_cache
247
248
def decomposition_matrix_inverse(self):
249
"""
250
Returns the inverse of the matrix returned by
251
decomposition_matrix().
252
253
EXAMPLE::
254
255
sage: S = ModularSymbols(37, 2)
256
sage: t = S.decomposition_matrix_inverse(); t
257
[ 1 0 0 0 1/3]
258
[ 0 1/2 -1/2 1/2 -1/2]
259
[ 0 -1/2 -1/2 1/2 0]
260
[ 0 0 1 0 1/2]
261
[ 0 0 0 0 1]
262
sage: t * S.decomposition_matrix() == 1
263
True
264
"""
265
try:
266
return self.__decomposition_matrix_inverse_cache
267
except AttributeError:
268
self.__decomposition_matrix_inverse_cache = ~self.decomposition_matrix()
269
return self.__decomposition_matrix_inverse_cache
270
271
def degeneracy_map(self, level, t=1):
272
"""
273
The t-th degeneracy map from self to the module ``codomain``. The
274
level of the codomain must be a divisor or multiple of level, and t
275
must be a divisor of the quotient.
276
277
INPUT:
278
279
280
- ``level`` - a Hecke module, which should be of the same type as
281
self, or a positive integer (in which case Sage will use
282
:meth:`~hecke_module_of_level` to find the "natural" module of the
283
corresponding level).
284
285
- ``t`` - int, the parameter of the degeneracy map, i.e., the map is
286
related to `f(q)` - `f(q^t)`.
287
288
289
OUTPUT: A morphism from self to corresponding the Hecke module of
290
given level.
291
292
EXAMPLES::
293
294
sage: M = ModularSymbols(11,sign=1)
295
sage: d1 = M.degeneracy_map(33); d1
296
Hecke module morphism degeneracy map corresponding to f(q) |--> f(q) defined by the matrix
297
[ 1 0 0 0 -2 -1]
298
[ 0 0 -2 2 0 0]
299
Domain: Modular Symbols space of dimension 2 for Gamma_0(11) of weight ...
300
Codomain: Modular Symbols space of dimension 6 for Gamma_0(33) of weight ...
301
sage: M.degeneracy_map(33,3).matrix()
302
[ 3 2 2 0 -2 1]
303
[ 0 2 0 -2 0 0]
304
sage: M = ModularSymbols(33,sign=1)
305
sage: d2 = M.degeneracy_map(11); d2.matrix()
306
[ 1 0]
307
[ 0 1/2]
308
[ 0 -1]
309
[ 0 1]
310
[ -1 0]
311
[ -1 0]
312
sage: (d2*d1).matrix()
313
[4 0]
314
[0 4]
315
316
::
317
318
sage: M = ModularSymbols(3,12,sign=1)
319
sage: M.degeneracy_map(1)
320
Hecke module morphism degeneracy map corresponding to f(q) |--> f(q) defined by the matrix
321
[1 0]
322
[0 0]
323
[0 1]
324
[0 1]
325
[0 1]
326
Domain: Modular Symbols space of dimension 5 for Gamma_0(3) of weight ...
327
Codomain: Modular Symbols space of dimension 2 for Gamma_0(1) of weight ...
328
329
::
330
331
sage: S = M.cuspidal_submodule()
332
sage: S.degeneracy_map(1)
333
Hecke module morphism defined by the matrix
334
[1 0]
335
[0 0]
336
[0 0]
337
Domain: Modular Symbols subspace of dimension 3 of Modular Symbols space ...
338
Codomain: Modular Symbols space of dimension 2 for Gamma_0(1) of weight ...
339
340
::
341
342
sage: D = ModularSymbols(10,4).cuspidal_submodule().decomposition()
343
sage: D
344
[
345
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 10 for Gamma_0(10) of weight 4 with sign 0 over Rational Field,
346
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 10 for Gamma_0(10) of weight 4 with sign 0 over Rational Field
347
]
348
sage: D[1].degeneracy_map(5)
349
Hecke module morphism defined by the matrix
350
[ 0 0 -1 1]
351
[ 0 1/2 3/2 -2]
352
[ 0 -1 1 0]
353
[ 0 -3/4 -1/4 1]
354
Domain: Modular Symbols subspace of dimension 4 of Modular Symbols space ...
355
Codomain: Modular Symbols space of dimension 4 for Gamma_0(5) of weight ...
356
357
We check for a subtle caching bug that came up in work on trac #10453::
358
359
sage: loads(dumps(J0(33).decomposition()[0].modular_symbols()))
360
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field
361
"""
362
if is_AmbientHeckeModule(level):
363
M = level
364
level = int(M.level())
365
else:
366
level = int(level)
367
M = None
368
369
t = int(t)
370
371
err = False
372
if self.level() % level == 0:
373
quo = self.level() // level
374
if quo % t != 0:
375
err = True
376
elif level % self.level() == 0:
377
quo = level // self.level()
378
if quo % t != 0:
379
err = True
380
else:
381
err = True
382
if err:
383
raise ValueError, ("The level of self (=%s) must be a divisor or multiple of " + \
384
"level (=%s), and t (=%s) must be a divisor of the quotient.")%\
385
(self.level(), level, t)
386
387
eps = self.character()
388
if not (eps is None) and level % eps.conductor() != 0:
389
raise ArithmeticError, "The conductor of the character of this space " + \
390
"(=%s) must be divisible by the level (=%s)."%\
391
(eps.conductor(), level)
392
393
if M is None:
394
M = self.hecke_module_of_level(level)
395
396
key = (M.group(), t)
397
# bad idea to use (M, t) as the key, because using complicated objects
398
# like modular forms spaces as dictionary keys causes weird behaviour;
399
# on the other hand, (M.level(), t) isn't enough information.
400
try:
401
self._degeneracy_maps
402
except AttributeError:
403
self._degeneracy_maps = {}
404
405
if self._degeneracy_maps.has_key(key):
406
return self._degeneracy_maps[key]
407
408
if M.rank() == 0:
409
410
A = matrix_space.MatrixSpace(self.base_ring(), self.rank(),0)(0)
411
412
elif self.level() % level == 0: # lower the level
413
414
A = self._degeneracy_lowering_matrix(M, t)
415
416
elif level % self.level() == 0: # raise the level
417
418
A = self._degeneracy_raising_matrix(M, t)
419
420
d = degenmap.DegeneracyMap(A, self, M, t)
421
self._degeneracy_maps[key] = d
422
return d
423
424
def dual_free_module(self):
425
r"""
426
The free module dual to self, as a submodule of the dual
427
module of the ambient space. As this space is ambient anyway,
428
this just returns self.free_module().
429
430
EXAMPLE::
431
432
sage: M = ModularForms(2,8); M.dual_free_module()
433
Vector space of dimension 3 over Rational Field
434
sage: M.dual_free_module() is M.free_module()
435
True
436
"""
437
return self.free_module()
438
439
def fcp(self, n, var='x'):
440
"""
441
Returns the factorization of the characteristic polynomial of
442
the Hecke operator `T_n` of index `n` acting on this space.
443
444
INPUT:
445
446
447
- ``self`` - Hecke module invariant under the Hecke operator of index
448
n.
449
450
- ``int n`` - a positive integer.
451
452
- ``var`` - variable of polynomial (default `x`)
453
454
455
OUTPUT:
456
457
- ``list`` - list of the pairs (g,e), where g is an
458
irreducible factor of the characteristic polynomial of T_n, and e
459
is its multiplicity.
460
461
EXAMPLES::
462
463
sage: m = ModularSymbols(23, 2, sign=1)
464
sage: m.fcp(2)
465
(x - 3) * (x^2 + x - 1)
466
sage: m.hecke_operator(2).charpoly('x').factor()
467
(x - 3) * (x^2 + x - 1)
468
"""
469
n = int(n)
470
if n <= 0:
471
raise ArithmeticError, "n (=%s) must be positive"%n
472
return self.hecke_operator(n).fcp(var)
473
474
def free_module(self):
475
"""
476
Return the free module underlying this ambient Hecke module (the
477
forgetful functor from Hecke modules to modules over the base ring)
478
479
EXAMPLE::
480
481
sage: ModularForms(59, 2).free_module()
482
Vector space of dimension 6 over Rational Field
483
"""
484
try:
485
return self.__free_module
486
except AttributeError:
487
M = sage.modules.all.FreeModule(self.base_ring(), self.rank())
488
self.__free_module = M
489
return M
490
491
def hecke_bound(self):
492
r"""
493
Return an integer B such that the Hecke operators `T_n`, for `n\leq B`,
494
generate the full Hecke algebra as a module over the base ring. Note
495
that we include the `n` with `n` not coprime to the level.
496
497
At present this returns an unproven guess for non-cuspidal spaces which
498
appears to be valid for `M_k(\Gamma_0(N))`, where k and N are the
499
weight and level of self. (It is clearly valid for *cuspidal* spaces
500
of any fixed character, as a consequence of the Sturm bound theorem.)
501
It returns a hopelessly wrong answer for spaces of full level
502
`\Gamma_1`.
503
504
TODO: Get rid of this dreadful bit of code.
505
506
EXAMPLE::
507
508
sage: ModularSymbols(17, 4).hecke_bound()
509
15
510
sage: ModularSymbols(Gamma1(17), 4).hecke_bound() # wrong!
511
15
512
"""
513
try:
514
if self.is_cuspidal():
515
return Gamma0(self.level()).sturm_bound(self.weight())
516
except AttributeError:
517
pass
518
misc.verbose("WARNING: ambient.py -- hecke_bound; returning unproven guess.")
519
return Gamma0(self.level()).sturm_bound(self.weight()) + 2*Gamma0(self.level()).dimension_eis(self.weight()) + 5
520
521
def hecke_module_of_level(self, level):
522
r"""
523
Return the Hecke module corresponding to self at the given level, which
524
should be either a divisor or a multiple of the level of self. This
525
raises NotImplementedError, and should be overridden in derived
526
classes.
527
528
EXAMPLE::
529
530
sage: sage.modular.hecke.ambient_module.AmbientHeckeModule.hecke_module_of_level(ModularForms(2, 8),6)
531
Traceback (most recent call last):
532
...
533
NotImplementedError
534
"""
535
raise NotImplementedError
536
537
def hecke_images(self, i, v):
538
"""
539
Return images of the `i`-th standard basis vector under the
540
Hecke operators `T_p` for all integers in `v`.
541
542
INPUT:
543
544
545
- ``i`` - nonnegative integer
546
547
- ``v`` - a list of positive integer
548
549
550
OUTPUT:
551
552
553
- ``matrix`` - whose rows are the Hecke images
554
555
556
EXAMPLES::
557
558
sage: M = ModularSymbols(DirichletGroup(13).0, 3)
559
sage: M.T(2)(M.0).element()
560
(zeta12 + 4, 0, -1, 1)
561
sage: M.hecke_images(0, [1,2])
562
[ 1 0 0 0]
563
[zeta12 + 4 0 -1 1]
564
"""
565
try:
566
return self._hecke_images(i, v)
567
except (AttributeError, NotImplementedError):
568
pass
569
# Use slow generic algorithm
570
x = self.gen(i)
571
X = [self.hecke_operator(n).apply_sparse(x).element() for n in v]
572
return matrix(self.base_ring(), X)
573
574
def intersection(self, other):
575
"""
576
Returns the intersection of self and other, which must both lie in
577
a common ambient space of modular symbols.
578
579
EXAMPLES::
580
581
sage: M = ModularSymbols(43, sign=1)
582
sage: A = M[0] + M[1]
583
sage: B = M[1] + M[2]
584
sage: A.rank(), B.rank()
585
(2, 3)
586
sage: C = A.intersection(B); C.rank() # TODO
587
1
588
"""
589
if not isinstance(other, module.HeckeModule_free_module):
590
raise TypeError, "other (=%s) must be a Hecke module."%other
591
if self.ambient_hecke_module() != other.ambient_hecke_module():
592
raise ArithmeticError, "Intersection only defined for subspaces of a common ambient Hecke module."
593
return other # since self is ambient, so the intersection must equal other.
594
595
def is_ambient(self):
596
r"""
597
Returns True if and only if self is an ambient Hecke module.
598
599
.. warning::
600
601
self can only be ambient by being of type
602
AmbientHeckeModule.
603
604
For example, decomposing a simple ambient space yields a
605
single factor, and that factor is *not* considered an
606
ambient space.
607
608
EXAMPLES::
609
610
sage: m = ModularSymbols(10)
611
sage: m.is_ambient()
612
True
613
614
::
615
616
sage: a = m[0] # the unique simple factor
617
sage: a == m
618
True
619
sage: a.is_ambient()
620
False
621
"""
622
return True
623
624
def is_full_hecke_module(self, compute=True):
625
"""
626
Returns True if this space is invariant under the action of
627
all Hecke operators, even those that divide the level. This is
628
always true for ambient Hecke modules, so return True.
629
630
EXAMPLE::
631
632
sage: ModularSymbols(11, 4).is_full_hecke_module()
633
True
634
"""
635
return True
636
637
def is_new(self, p=None):
638
r"""
639
Return True if this module is entirely new.
640
641
EXAMPLE::
642
643
sage: ModularSymbols(11, 4).is_new()
644
False
645
sage: ModularSymbols(1, 12).is_new()
646
True
647
"""
648
try:
649
if self.__is_new.has_key(p):
650
return self.__is_new[p]
651
except AttributeError:
652
pass
653
AmbientHeckeModule.new_submodule(self,p)
654
return self.__is_new[p]
655
656
def is_old(self, p=None):
657
r"""
658
Return True if this module is entirely old.
659
660
EXAMPLE::
661
662
sage: ModularSymbols(22).is_old()
663
True
664
sage: ModularSymbols(3, 12).is_old()
665
False
666
"""
667
try:
668
if self.__is_old.has_key(p):
669
return self.__is_old[p]
670
except AttributeError:
671
pass
672
self.old_submodule(p)
673
return self.__is_old[p]
674
675
def is_submodule(self, V):
676
"""
677
Returns True if and only if self is a submodule of V. Since this is an
678
ambient space, this returns True if and only if V is equal to self.
679
680
EXAMPLE::
681
682
sage: ModularSymbols(1, 4).is_submodule(ModularSymbols(11,4))
683
False
684
sage: ModularSymbols(11, 4).is_submodule(ModularSymbols(11,4))
685
True
686
"""
687
if not isinstance(V, module.HeckeModule_free_module):
688
raise TypeError, "V must be a Hecke module"
689
if not V.is_ambient():
690
return False
691
return V.ambient_hecke_module() == self
692
693
def linear_combination_of_basis(self, v):
694
r"""
695
Given a list or vector of length equal to the dimension of self,
696
construct the appropriate linear combination of the basis vectors of
697
self.
698
699
EXAMPLE::
700
701
sage: ModularForms(3, 12).linear_combination_of_basis([1,0,0,0,1])
702
2*q + 2049*q^2 + 177147*q^3 + 4196177*q^4 + 48830556*q^5 + O(q^6)
703
704
"""
705
return self(v)
706
707
def new_submodule(self, p=None):
708
"""
709
Returns the new or p-new submodule of self.
710
711
INPUT:
712
713
- ``p`` - (default: None); if not None, return only
714
the p-new submodule.
715
716
OUTPUT: the new or p-new submodule of self, i.e. the intersection of
717
the kernel of the degeneracy lowering maps to level `N/p` (for the
718
given prime `p`, or for all prime divisors of `N` if `p` is not given).
719
720
If self is cuspidal this is a Hecke-invariant complement of the
721
corresponding old submodule, but this may break down on Eisenstein
722
subspaces (see the amusing example in William Stein's book of a form
723
which is new and old at the same time).
724
725
EXAMPLES::
726
727
sage: m = ModularSymbols(33); m.rank()
728
9
729
sage: m.new_submodule().rank()
730
3
731
sage: m.new_submodule(3).rank()
732
4
733
sage: m.new_submodule(11).rank()
734
8
735
"""
736
try:
737
if self.__is_new[p]:
738
return self
739
except AttributeError:
740
self.__is_new = {}
741
except KeyError:
742
pass
743
744
if self.rank() == 0:
745
self.__is_new[p] = True
746
return self
747
try:
748
return self.__new_submodule[p]
749
except AttributeError:
750
self.__new_submodule = {}
751
except KeyError:
752
pass
753
754
# Construct the degeneracy map d.
755
N = self.level()
756
d = None
757
eps = self.character()
758
if eps == None:
759
f = 1
760
else:
761
f = eps.conductor()
762
if p == None:
763
D = arith.prime_divisors(N)
764
else:
765
if N % p != 0:
766
raise ValueError, "p must divide the level."
767
D = [p]
768
for q in D:
769
# Here we are only using degeneracy *lowering* maps, so it is fine
770
# to be careless and pass an integer for the level. One needs to be
771
# a bit more careful with degeneracy *raising* maps for the Gamma1
772
# and GammaH cases.
773
if ((N//q) % f) == 0:
774
NN = N//q
775
d1 = self.degeneracy_map(NN,1).matrix()
776
if d is None:
777
d = d1
778
else:
779
d = d.augment(d1)
780
d = d.augment(self.degeneracy_map(NN,q).matrix())
781
#end if
782
#end for
783
if d is None or d == 0:
784
self.__is_new[p] = True
785
return self
786
else:
787
self.__is_new[p] = False
788
ns = self.submodule(d.kernel(), check=False)
789
ns.__is_new = {p:True}
790
ns._is_full_hecke_module = True
791
self.__new_submodule[p] = ns
792
return ns
793
794
def nonembedded_free_module(self):
795
r"""
796
Return the free module corresponding to self as an abstract free module
797
(rather than as a submodule of an ambient free module). As this module
798
is ambient anyway, this just returns ``self.free_module()``.
799
800
EXAMPLES::
801
802
sage: M = ModularSymbols(11, 2)
803
sage: M.nonembedded_free_module() is M.free_module()
804
True
805
"""
806
return self.free_module()
807
808
def old_submodule(self, p=None):
809
"""
810
Returns the old or p-old submodule of self, i.e. the sum of the images
811
of the degeneracy maps from level `N/p` (for the given prime `p`, or
812
for all primes `p` dividing `N` if `p` is not given).
813
814
INPUT:
815
816
- ``p`` - (default: None); if not None, return only the p-old
817
submodule.
818
819
OUTPUT: the old or p-old submodule of self
820
821
EXAMPLES::
822
823
sage: m = ModularSymbols(33); m.rank()
824
9
825
sage: m.old_submodule().rank()
826
7
827
sage: m.old_submodule(3).rank()
828
6
829
sage: m.new_submodule(11).rank()
830
8
831
832
::
833
834
sage: e = DirichletGroup(16)([-1, 1])
835
sage: M = ModularSymbols(e, 3, sign=1); M
836
Modular Symbols space of dimension 4 and level 16, weight 3, character [-1, 1], sign 1, over Rational Field
837
sage: M.old_submodule()
838
Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 4 and level 16, weight 3, character [-1, 1], sign 1, over Rational Field
839
840
Illustrate that trac 10664 is fixed::
841
842
sage: ModularSymbols(DirichletGroup(42)[7], 6, sign=1).old_subspace(3)
843
Modular Symbols subspace of dimension 0 of Modular Symbols space of dimension 40 and level 42, weight 6, character [-1, -1], sign 1, over Rational Field
844
845
"""
846
try:
847
if self.__is_old[p]:
848
return self
849
except AttributeError:
850
self.__is_old = {}
851
except KeyError:
852
pass
853
854
if self.rank() == 0:
855
self.__is_old[p] = True
856
return self
857
try:
858
return self.__old_submodule[p]
859
except AttributeError:
860
self.__old_submodule = {}
861
except KeyError:
862
pass
863
864
# Construct the degeneracy map d.
865
N = self.level()
866
d = None
867
868
eps = self.character()
869
if eps is None:
870
f = 1
871
else:
872
f = eps.conductor()
873
874
if p is None:
875
D = arith.prime_divisors(N)
876
else:
877
if N % p != 0:
878
raise ValueError, "p must divide the level."
879
D = [p]
880
881
for q in D:
882
NN = N//q
883
if NN % f == 0:
884
M = self.hecke_module_of_level(NN)
885
886
# Here it is vital to pass self as an argument to
887
# degeneracy_map, because M and the level N don't uniquely
888
# determine self (e.g. the degeneracy map from level 1 to level
889
# N could go to Gamma0(N), Gamma1(N) or anything in between)
890
d1 = M.degeneracy_map(self, 1).matrix()
891
892
if d is None:
893
d = d1
894
else:
895
d = d.stack(d1)
896
d = d.stack(M.degeneracy_map(self, q).matrix())
897
#end if
898
#end for
899
if d is None:
900
os = self.zero_submodule()
901
else:
902
os = self.submodule(d.image(), check=False)
903
904
self.__is_old[p] = (os == self)
905
906
os.__is_old = {p:True}
907
os._is_full_hecke_module = True
908
self.__old_submodule[p] = os
909
return os
910
911
def submodule(self, M, Mdual=None, check=True):
912
"""
913
Return the Hecke submodule of self generated by M, which may be a
914
submodule of the free module of self, or a list of elements of self.
915
916
EXAMPLE::
917
918
sage: M = ModularForms(37, 2)
919
sage: A = M.submodule([M.newforms()[0].element(), M.newforms()[1].element()]); A
920
Modular Forms subspace of dimension 2 of Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(37) of weight 2 over Rational Field
921
"""
922
if check:
923
if not sage.modules.all.is_FreeModule(M):
924
V = self.free_module()
925
if isinstance(M, (list,tuple)):
926
M = V.span([V(x.element()) for x in M])
927
else:
928
M = V.span(M)
929
if not M.is_submodule(self.free_module()):
930
raise TypeError, "M must be a submodule of the free module associated to this module."
931
if M == self.free_module():
932
return self
933
return self._submodule_class()(self, M, Mdual, check=check)
934
935
def _submodule_class(self):
936
r"""
937
The class of submodules of this module. This is a separate method so it
938
can be overridden in derived classes.
939
940
EXAMPLE::
941
942
sage: sage.modular.hecke.ambient_module.AmbientHeckeModule._submodule_class(ModularForms(1, 24))
943
<class 'sage.modular.hecke.submodule.HeckeSubmodule'>
944
sage: ModularForms(1, 24)._submodule_class()
945
<class 'sage.modular.modform.submodule.ModularFormsSubmodule'>
946
"""
947
return submodule.HeckeSubmodule
948
949
def submodule_from_nonembedded_module(self, V, Vdual=None, check=True):
950
"""
951
Create a submodule of this module, from a submodule of an ambient free
952
module of the same rank as the rank of self.
953
954
INPUT:
955
956
- ``V`` - submodule of ambient free module of the same rank as the
957
rank of self.
958
959
- ``Vdual`` - used to pass in dual submodule (may be None)
960
961
- ``check`` - whether to check that submodule is Hecke equivariant
962
963
OUTPUT: Hecke submodule of self
964
965
EXAMPLE::
966
967
sage: V = QQ^8
968
sage: ModularForms(24, 2).submodule_from_nonembedded_module(V.submodule([0]))
969
Modular Forms subspace of dimension 0 of Modular Forms space of dimension 8 for Congruence Subgroup Gamma0(24) of weight 2 over Rational Field
970
"""
971
return self.submodule(V, Vdual, check=check)
972
973
def submodule_generated_by_images(self, M):
974
"""
975
Return the submodule of this ambient modular symbols space
976
generated by the images under all degeneracy maps of M. The space M
977
must have the same weight, sign, and group or character as this
978
ambient space.
979
980
EXAMPLES::
981
982
sage: ModularSymbols(6, 12).submodule_generated_by_images(ModularSymbols(1,12))
983
Modular Symbols subspace of dimension 12 of Modular Symbols space of dimension 22 for Gamma_0(6) of weight 12 with sign 0 over Rational Field
984
"""
985
S = self.zero_submodule()
986
if self.level() % M.level() == 0:
987
D = arith.divisors(self.level() // M.level())
988
elif M.level() % self.level() == 0:
989
D = arith.divisors(M.level() // self.level())
990
else:
991
D = []
992
for t in D:
993
d = M.degeneracy_map(self, t)
994
if d.codomain() != self:
995
raise ArithmeticError, "incompatible spaces of modular symbols"
996
S += d.image()
997
998
if self.is_full_hecke_module(compute=False):
999
S._is_full_hecke_module = True
1000
1001
return S
1002
1003
1004
1005