Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/modular/hecke/ambient_module.py
8820 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, codomain, 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
- ``codomain`` - a Hecke module, which should be of the same type as
280
self, or a positive integer (in which case Sage will use
281
:meth:`~hecke_module_of_level` to find the "natural" module of the
282
corresponding level).
283
- ``t`` - int, the parameter of the degeneracy map, i.e., the map is
284
related to `f(q)` - `f(q^t)`.
285
286
287
OUTPUT: A morphism from self to codomain.
288
289
EXAMPLES::
290
291
sage: M = ModularSymbols(11,sign=1)
292
sage: d1 = M.degeneracy_map(33); d1
293
Hecke module morphism degeneracy map corresponding to f(q) |--> f(q) defined by the matrix
294
[ 1 0 0 0 -2 -1]
295
[ 0 0 -2 2 0 0]
296
Domain: Modular Symbols space of dimension 2 for Gamma_0(11) of weight ...
297
Codomain: Modular Symbols space of dimension 6 for Gamma_0(33) of weight ...
298
sage: M.degeneracy_map(33,3).matrix()
299
[ 3 2 2 0 -2 1]
300
[ 0 2 0 -2 0 0]
301
sage: M = ModularSymbols(33,sign=1)
302
sage: d2 = M.degeneracy_map(11); d2.matrix()
303
[ 1 0]
304
[ 0 1/2]
305
[ 0 -1]
306
[ 0 1]
307
[ -1 0]
308
[ -1 0]
309
sage: (d2*d1).matrix()
310
[4 0]
311
[0 4]
312
313
::
314
315
sage: M = ModularSymbols(3,12,sign=1)
316
sage: M.degeneracy_map(1)
317
Hecke module morphism degeneracy map corresponding to f(q) |--> f(q) defined by the matrix
318
[1 0]
319
[0 0]
320
[0 1]
321
[0 1]
322
[0 1]
323
Domain: Modular Symbols space of dimension 5 for Gamma_0(3) of weight ...
324
Codomain: Modular Symbols space of dimension 2 for Gamma_0(1) of weight ...
325
326
::
327
328
sage: S = M.cuspidal_submodule()
329
sage: S.degeneracy_map(1)
330
Hecke module morphism defined by the matrix
331
[1 0]
332
[0 0]
333
[0 0]
334
Domain: Modular Symbols subspace of dimension 3 of Modular Symbols space ...
335
Codomain: Modular Symbols space of dimension 2 for Gamma_0(1) of weight ...
336
337
::
338
339
sage: D = ModularSymbols(10,4).cuspidal_submodule().decomposition()
340
sage: D
341
[
342
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,
343
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
344
]
345
sage: D[1].degeneracy_map(5)
346
Hecke module morphism defined by the matrix
347
[ 0 0 -1 1]
348
[ 0 1/2 3/2 -2]
349
[ 0 -1 1 0]
350
[ 0 -3/4 -1/4 1]
351
Domain: Modular Symbols subspace of dimension 4 of Modular Symbols space ...
352
Codomain: Modular Symbols space of dimension 4 for Gamma_0(5) of weight ...
353
354
We check for a subtle caching bug that came up in work on trac #10453::
355
356
sage: loads(dumps(J0(33).decomposition()[0].modular_symbols()))
357
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
358
359
We check that certain absurd inputs are correctly caught::
360
361
sage: chi = kronecker_character(7)
362
sage: ModularSymbols(Gamma0(7), 4).degeneracy_map(ModularSymbols(chi, 4))
363
Traceback (most recent call last):
364
...
365
ValueError: The characters of the domain and codomain must match
366
"""
367
if is_AmbientHeckeModule(codomain):
368
M = codomain
369
level = int(M.level())
370
else:
371
level = int(codomain)
372
M = None
373
374
t = int(t)
375
376
err = False
377
if self.level() % level == 0:
378
quo = self.level() // level
379
if quo % t != 0:
380
err = True
381
elif level % self.level() == 0:
382
quo = level // self.level()
383
if quo % t != 0:
384
err = True
385
else:
386
err = True
387
if err:
388
raise ValueError, ("The level of self (=%s) must be a divisor or multiple of " + \
389
"level (=%s), and t (=%s) must be a divisor of the quotient.")%\
390
(self.level(), level, t)
391
392
eps = self.character()
393
if not (eps is None) and level % eps.conductor() != 0:
394
raise ArithmeticError, "The conductor of the character of this space " + \
395
"(=%s) must be divisible by the level (=%s)."%\
396
(eps.conductor(), level)
397
398
if M is None:
399
M = self.hecke_module_of_level(level)
400
401
if eps is not None and M.character() is not None:
402
if eps.primitive_character() != M.character().primitive_character():
403
raise ValueError("The characters of the domain and codomain must match")
404
405
key = (M.group(), t)
406
# bad idea to use (M, t) as the key, because using complicated objects
407
# like modular forms spaces as dictionary keys causes weird behaviour;
408
# on the other hand, (M.level(), t) isn't enough information.
409
try:
410
self._degeneracy_maps
411
except AttributeError:
412
self._degeneracy_maps = {}
413
414
if self._degeneracy_maps.has_key(key):
415
return self._degeneracy_maps[key]
416
417
if M.rank() == 0:
418
419
A = matrix_space.MatrixSpace(self.base_ring(), self.rank(),0)(0)
420
421
elif self.level() % level == 0: # lower the level
422
423
A = self._degeneracy_lowering_matrix(M, t)
424
425
elif level % self.level() == 0: # raise the level
426
427
A = self._degeneracy_raising_matrix(M, t)
428
429
d = degenmap.DegeneracyMap(A, self, M, t)
430
self._degeneracy_maps[key] = d
431
return d
432
433
def dual_free_module(self):
434
r"""
435
The free module dual to self, as a submodule of the dual
436
module of the ambient space. As this space is ambient anyway,
437
this just returns self.free_module().
438
439
EXAMPLE::
440
441
sage: M = ModularForms(2,8); M.dual_free_module()
442
Vector space of dimension 3 over Rational Field
443
sage: M.dual_free_module() is M.free_module()
444
True
445
"""
446
return self.free_module()
447
448
def fcp(self, n, var='x'):
449
"""
450
Returns the factorization of the characteristic polynomial of
451
the Hecke operator `T_n` of index `n` acting on this space.
452
453
INPUT:
454
455
456
- ``self`` - Hecke module invariant under the Hecke operator of index
457
n.
458
459
- ``int n`` - a positive integer.
460
461
- ``var`` - variable of polynomial (default `x`)
462
463
464
OUTPUT:
465
466
- ``list`` - list of the pairs (g,e), where g is an
467
irreducible factor of the characteristic polynomial of T_n, and e
468
is its multiplicity.
469
470
EXAMPLES::
471
472
sage: m = ModularSymbols(23, 2, sign=1)
473
sage: m.fcp(2)
474
(x - 3) * (x^2 + x - 1)
475
sage: m.hecke_operator(2).charpoly('x').factor()
476
(x - 3) * (x^2 + x - 1)
477
"""
478
n = int(n)
479
if n <= 0:
480
raise ArithmeticError, "n (=%s) must be positive"%n
481
return self.hecke_operator(n).fcp(var)
482
483
def free_module(self):
484
"""
485
Return the free module underlying this ambient Hecke module (the
486
forgetful functor from Hecke modules to modules over the base ring)
487
488
EXAMPLE::
489
490
sage: ModularForms(59, 2).free_module()
491
Vector space of dimension 6 over Rational Field
492
"""
493
try:
494
return self.__free_module
495
except AttributeError:
496
M = sage.modules.all.FreeModule(self.base_ring(), self.rank())
497
self.__free_module = M
498
return M
499
500
def hecke_bound(self):
501
r"""
502
Return an integer B such that the Hecke operators `T_n`, for `n\leq B`,
503
generate the full Hecke algebra as a module over the base ring. Note
504
that we include the `n` with `n` not coprime to the level.
505
506
At present this returns an unproven guess for non-cuspidal spaces which
507
appears to be valid for `M_k(\Gamma_0(N))`, where k and N are the
508
weight and level of self. (It is clearly valid for *cuspidal* spaces
509
of any fixed character, as a consequence of the Sturm bound theorem.)
510
It returns a hopelessly wrong answer for spaces of full level
511
`\Gamma_1`.
512
513
TODO: Get rid of this dreadful bit of code.
514
515
EXAMPLE::
516
517
sage: ModularSymbols(17, 4).hecke_bound()
518
15
519
sage: ModularSymbols(Gamma1(17), 4).hecke_bound() # wrong!
520
15
521
"""
522
try:
523
if self.is_cuspidal():
524
return Gamma0(self.level()).sturm_bound(self.weight())
525
except AttributeError:
526
pass
527
misc.verbose("WARNING: ambient.py -- hecke_bound; returning unproven guess.")
528
return Gamma0(self.level()).sturm_bound(self.weight()) + 2*Gamma0(self.level()).dimension_eis(self.weight()) + 5
529
530
def hecke_module_of_level(self, level):
531
r"""
532
Return the Hecke module corresponding to self at the given level, which
533
should be either a divisor or a multiple of the level of self. This
534
raises NotImplementedError, and should be overridden in derived
535
classes.
536
537
EXAMPLE::
538
539
sage: sage.modular.hecke.ambient_module.AmbientHeckeModule.hecke_module_of_level(ModularForms(2, 8),6)
540
Traceback (most recent call last):
541
...
542
NotImplementedError
543
"""
544
raise NotImplementedError
545
546
def hecke_images(self, i, v):
547
"""
548
Return images of the `i`-th standard basis vector under the
549
Hecke operators `T_p` for all integers in `v`.
550
551
INPUT:
552
553
554
- ``i`` - nonnegative integer
555
556
- ``v`` - a list of positive integer
557
558
559
OUTPUT:
560
561
562
- ``matrix`` - whose rows are the Hecke images
563
564
565
EXAMPLES::
566
567
sage: M = ModularSymbols(DirichletGroup(13).0, 3)
568
sage: M.T(2)(M.0).element()
569
(zeta12 + 4, 0, -1, 1)
570
sage: M.hecke_images(0, [1,2])
571
[ 1 0 0 0]
572
[zeta12 + 4 0 -1 1]
573
"""
574
try:
575
return self._hecke_images(i, v)
576
except (AttributeError, NotImplementedError):
577
pass
578
# Use slow generic algorithm
579
x = self.gen(i)
580
X = [self.hecke_operator(n).apply_sparse(x).element() for n in v]
581
return matrix(self.base_ring(), X)
582
583
def intersection(self, other):
584
"""
585
Returns the intersection of self and other, which must both lie in
586
a common ambient space of modular symbols.
587
588
EXAMPLES::
589
590
sage: M = ModularSymbols(43, sign=1)
591
sage: A = M[0] + M[1]
592
sage: B = M[1] + M[2]
593
sage: A.rank(), B.rank()
594
(2, 3)
595
sage: C = A.intersection(B); C.rank() # TODO
596
1
597
"""
598
if not isinstance(other, module.HeckeModule_free_module):
599
raise TypeError, "other (=%s) must be a Hecke module."%other
600
if self.ambient_hecke_module() != other.ambient_hecke_module():
601
raise ArithmeticError, "Intersection only defined for subspaces of a common ambient Hecke module."
602
return other # since self is ambient, so the intersection must equal other.
603
604
def is_ambient(self):
605
r"""
606
Returns True if and only if self is an ambient Hecke module.
607
608
.. warning::
609
610
self can only be ambient by being of type
611
AmbientHeckeModule.
612
613
For example, decomposing a simple ambient space yields a
614
single factor, and that factor is *not* considered an
615
ambient space.
616
617
EXAMPLES::
618
619
sage: m = ModularSymbols(10)
620
sage: m.is_ambient()
621
True
622
623
::
624
625
sage: a = m[0] # the unique simple factor
626
sage: a == m
627
True
628
sage: a.is_ambient()
629
False
630
"""
631
return True
632
633
def is_full_hecke_module(self, compute=True):
634
"""
635
Returns True if this space is invariant under the action of
636
all Hecke operators, even those that divide the level. This is
637
always true for ambient Hecke modules, so return True.
638
639
EXAMPLE::
640
641
sage: ModularSymbols(11, 4).is_full_hecke_module()
642
True
643
"""
644
return True
645
646
def is_new(self, p=None):
647
r"""
648
Return True if this module is entirely new.
649
650
EXAMPLE::
651
652
sage: ModularSymbols(11, 4).is_new()
653
False
654
sage: ModularSymbols(1, 12).is_new()
655
True
656
"""
657
try:
658
if self.__is_new.has_key(p):
659
return self.__is_new[p]
660
except AttributeError:
661
pass
662
AmbientHeckeModule.new_submodule(self,p)
663
return self.__is_new[p]
664
665
def is_old(self, p=None):
666
r"""
667
Return True if this module is entirely old.
668
669
EXAMPLE::
670
671
sage: ModularSymbols(22).is_old()
672
True
673
sage: ModularSymbols(3, 12).is_old()
674
False
675
"""
676
try:
677
if self.__is_old.has_key(p):
678
return self.__is_old[p]
679
except AttributeError:
680
pass
681
self.old_submodule(p)
682
return self.__is_old[p]
683
684
def is_submodule(self, V):
685
"""
686
Returns True if and only if self is a submodule of V. Since this is an
687
ambient space, this returns True if and only if V is equal to self.
688
689
EXAMPLE::
690
691
sage: ModularSymbols(1, 4).is_submodule(ModularSymbols(11,4))
692
False
693
sage: ModularSymbols(11, 4).is_submodule(ModularSymbols(11,4))
694
True
695
"""
696
if not isinstance(V, module.HeckeModule_free_module):
697
raise TypeError, "V must be a Hecke module"
698
if not V.is_ambient():
699
return False
700
return V.ambient_hecke_module() == self
701
702
def linear_combination_of_basis(self, v):
703
r"""
704
Given a list or vector of length equal to the dimension of self,
705
construct the appropriate linear combination of the basis vectors of
706
self.
707
708
EXAMPLE::
709
710
sage: ModularForms(3, 12).linear_combination_of_basis([1,0,0,0,1])
711
2*q + 2049*q^2 + 177147*q^3 + 4196177*q^4 + 48830556*q^5 + O(q^6)
712
713
"""
714
return self(v)
715
716
def new_submodule(self, p=None):
717
"""
718
Returns the new or p-new submodule of self.
719
720
INPUT:
721
722
- ``p`` - (default: None); if not None, return only
723
the p-new submodule.
724
725
OUTPUT: the new or p-new submodule of self, i.e. the intersection of
726
the kernel of the degeneracy lowering maps to level `N/p` (for the
727
given prime `p`, or for all prime divisors of `N` if `p` is not given).
728
729
If self is cuspidal this is a Hecke-invariant complement of the
730
corresponding old submodule, but this may break down on Eisenstein
731
subspaces (see the amusing example in William Stein's book of a form
732
which is new and old at the same time).
733
734
EXAMPLES::
735
736
sage: m = ModularSymbols(33); m.rank()
737
9
738
sage: m.new_submodule().rank()
739
3
740
sage: m.new_submodule(3).rank()
741
4
742
sage: m.new_submodule(11).rank()
743
8
744
"""
745
try:
746
if self.__is_new[p]:
747
return self
748
except AttributeError:
749
self.__is_new = {}
750
except KeyError:
751
pass
752
753
if self.rank() == 0:
754
self.__is_new[p] = True
755
return self
756
try:
757
return self.__new_submodule[p]
758
except AttributeError:
759
self.__new_submodule = {}
760
except KeyError:
761
pass
762
763
# Construct the degeneracy map d.
764
N = self.level()
765
d = None
766
eps = self.character()
767
if eps == None:
768
f = 1
769
else:
770
f = eps.conductor()
771
if p == None:
772
D = arith.prime_divisors(N)
773
else:
774
if N % p != 0:
775
raise ValueError, "p must divide the level."
776
D = [p]
777
for q in D:
778
# Here we are only using degeneracy *lowering* maps, so it is fine
779
# to be careless and pass an integer for the level. One needs to be
780
# a bit more careful with degeneracy *raising* maps for the Gamma1
781
# and GammaH cases.
782
if ((N//q) % f) == 0:
783
NN = N//q
784
d1 = self.degeneracy_map(NN,1).matrix()
785
if d is None:
786
d = d1
787
else:
788
d = d.augment(d1)
789
d = d.augment(self.degeneracy_map(NN,q).matrix())
790
#end if
791
#end for
792
if d is None or d == 0:
793
self.__is_new[p] = True
794
return self
795
else:
796
self.__is_new[p] = False
797
ns = self.submodule(d.kernel(), check=False)
798
ns.__is_new = {p:True}
799
ns._is_full_hecke_module = True
800
self.__new_submodule[p] = ns
801
return ns
802
803
def nonembedded_free_module(self):
804
r"""
805
Return the free module corresponding to self as an abstract free module
806
(rather than as a submodule of an ambient free module). As this module
807
is ambient anyway, this just returns ``self.free_module()``.
808
809
EXAMPLES::
810
811
sage: M = ModularSymbols(11, 2)
812
sage: M.nonembedded_free_module() is M.free_module()
813
True
814
"""
815
return self.free_module()
816
817
def old_submodule(self, p=None):
818
"""
819
Returns the old or p-old submodule of self, i.e. the sum of the images
820
of the degeneracy maps from level `N/p` (for the given prime `p`, or
821
for all primes `p` dividing `N` if `p` is not given).
822
823
INPUT:
824
825
- ``p`` - (default: None); if not None, return only the p-old
826
submodule.
827
828
OUTPUT: the old or p-old submodule of self
829
830
EXAMPLES::
831
832
sage: m = ModularSymbols(33); m.rank()
833
9
834
sage: m.old_submodule().rank()
835
7
836
sage: m.old_submodule(3).rank()
837
6
838
sage: m.new_submodule(11).rank()
839
8
840
841
::
842
843
sage: e = DirichletGroup(16)([-1, 1])
844
sage: M = ModularSymbols(e, 3, sign=1); M
845
Modular Symbols space of dimension 4 and level 16, weight 3, character [-1, 1], sign 1, over Rational Field
846
sage: M.old_submodule()
847
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
848
849
Illustrate that trac 10664 is fixed::
850
851
sage: ModularSymbols(DirichletGroup(42)[7], 6, sign=1).old_subspace(3)
852
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
853
854
"""
855
try:
856
if self.__is_old[p]:
857
return self
858
except AttributeError:
859
self.__is_old = {}
860
except KeyError:
861
pass
862
863
if self.rank() == 0:
864
self.__is_old[p] = True
865
return self
866
try:
867
return self.__old_submodule[p]
868
except AttributeError:
869
self.__old_submodule = {}
870
except KeyError:
871
pass
872
873
# Construct the degeneracy map d.
874
N = self.level()
875
d = None
876
877
eps = self.character()
878
if eps is None:
879
f = 1
880
else:
881
f = eps.conductor()
882
883
if p is None:
884
D = arith.prime_divisors(N)
885
else:
886
if N % p != 0:
887
raise ValueError, "p must divide the level."
888
D = [p]
889
890
for q in D:
891
NN = N//q
892
if NN % f == 0:
893
M = self.hecke_module_of_level(NN)
894
895
# Here it is vital to pass self as an argument to
896
# degeneracy_map, because M and the level N don't uniquely
897
# determine self (e.g. the degeneracy map from level 1 to level
898
# N could go to Gamma0(N), Gamma1(N) or anything in between)
899
d1 = M.degeneracy_map(self, 1).matrix()
900
901
if d is None:
902
d = d1
903
else:
904
d = d.stack(d1)
905
d = d.stack(M.degeneracy_map(self, q).matrix())
906
#end if
907
#end for
908
if d is None:
909
os = self.zero_submodule()
910
else:
911
os = self.submodule(d.image(), check=False)
912
913
self.__is_old[p] = (os == self)
914
915
os.__is_old = {p:True}
916
os._is_full_hecke_module = True
917
self.__old_submodule[p] = os
918
return os
919
920
def submodule(self, M, Mdual=None, check=True):
921
"""
922
Return the Hecke submodule of self generated by M, which may be a
923
submodule of the free module of self, or a list of elements of self.
924
925
EXAMPLE::
926
927
sage: M = ModularForms(37, 2)
928
sage: A = M.submodule([M.newforms()[0].element(), M.newforms()[1].element()]); A
929
Modular Forms subspace of dimension 2 of Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(37) of weight 2 over Rational Field
930
"""
931
if check:
932
if not sage.modules.all.is_FreeModule(M):
933
V = self.free_module()
934
if isinstance(M, (list,tuple)):
935
M = V.span([V(x.element()) for x in M])
936
else:
937
M = V.span(M)
938
if not M.is_submodule(self.free_module()):
939
raise TypeError, "M must be a submodule of the free module associated to this module."
940
if M == self.free_module():
941
return self
942
return self._submodule_class()(self, M, Mdual, check=check)
943
944
def _submodule_class(self):
945
r"""
946
The class of submodules of this module. This is a separate method so it
947
can be overridden in derived classes.
948
949
EXAMPLE::
950
951
sage: sage.modular.hecke.ambient_module.AmbientHeckeModule._submodule_class(ModularForms(1, 24))
952
<class 'sage.modular.hecke.submodule.HeckeSubmodule'>
953
sage: ModularForms(1, 24)._submodule_class()
954
<class 'sage.modular.modform.submodule.ModularFormsSubmodule'>
955
"""
956
return submodule.HeckeSubmodule
957
958
def submodule_from_nonembedded_module(self, V, Vdual=None, check=True):
959
"""
960
Create a submodule of this module, from a submodule of an ambient free
961
module of the same rank as the rank of self.
962
963
INPUT:
964
965
- ``V`` - submodule of ambient free module of the same rank as the
966
rank of self.
967
968
- ``Vdual`` - used to pass in dual submodule (may be None)
969
970
- ``check`` - whether to check that submodule is Hecke equivariant
971
972
OUTPUT: Hecke submodule of self
973
974
EXAMPLE::
975
976
sage: V = QQ^8
977
sage: ModularForms(24, 2).submodule_from_nonembedded_module(V.submodule([0]))
978
Modular Forms subspace of dimension 0 of Modular Forms space of dimension 8 for Congruence Subgroup Gamma0(24) of weight 2 over Rational Field
979
"""
980
return self.submodule(V, Vdual, check=check)
981
982
def submodule_generated_by_images(self, M):
983
"""
984
Return the submodule of this ambient modular symbols space
985
generated by the images under all degeneracy maps of M. The space M
986
must have the same weight, sign, and group or character as this
987
ambient space.
988
989
EXAMPLES::
990
991
sage: ModularSymbols(6, 12).submodule_generated_by_images(ModularSymbols(1,12))
992
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
993
"""
994
S = self.zero_submodule()
995
if self.level() % M.level() == 0:
996
D = arith.divisors(self.level() // M.level())
997
elif M.level() % self.level() == 0:
998
D = arith.divisors(M.level() // self.level())
999
else:
1000
D = []
1001
for t in D:
1002
d = M.degeneracy_map(self, t)
1003
if d.codomain() != self:
1004
raise ArithmeticError, "incompatible spaces of modular symbols"
1005
S += d.image()
1006
1007
if self.is_full_hecke_module(compute=False):
1008
S._is_full_hecke_module = True
1009
1010
return S
1011
1012
1013
1014