Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/hecke/submodule.py
4048 views
1
"""
2
Submodules of 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 sage.rings.arith as arith
23
import sage.misc.misc as misc
24
from sage.misc.cachefunc import cached_method
25
26
import sage.modules.all
27
28
import module
29
import ambient_module
30
31
32
def is_HeckeSubmodule(x):
33
r"""
34
Return True if x is of type HeckeSubmodule.
35
36
EXAMPLES::
37
38
sage: sage.modular.hecke.submodule.is_HeckeSubmodule(ModularForms(1, 12))
39
False
40
sage: sage.modular.hecke.submodule.is_HeckeSubmodule(CuspForms(1, 12))
41
True
42
"""
43
return isinstance(x, HeckeSubmodule)
44
45
class HeckeSubmodule(module.HeckeModule_free_module):
46
"""
47
Submodule of a Hecke module.
48
"""
49
def __init__(self, ambient, submodule, dual_free_module=None, check=True):
50
r"""
51
Initialise a submodule of an ambient Hecke module.
52
53
INPUT:
54
55
- ``ambient`` - an ambient Hecke module
56
57
- ``submodule`` - a free module over the base ring which is a submodule
58
of the free module attached to the ambient Hecke module. This should
59
be invariant under all Hecke operators.
60
61
- ``dual_free_module`` - the submodule of the dual of the ambient
62
module corresponding to this submodule (or None).
63
64
- ``check`` - whether or not to explicitly check that the submodule is
65
Hecke equivariant.
66
67
EXAMPLES::
68
69
sage: CuspForms(1,60) # indirect doctest
70
Cuspidal subspace of dimension 5 of Modular Forms space of dimension 6 for Modular Group SL(2,Z) of weight 60 over Rational Field
71
72
sage: M = ModularForms(4,10)
73
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.submodule(M.basis()[:3]).free_module())
74
sage: S
75
Rank 3 submodule of a Hecke module of level 4
76
77
sage: S == loads(dumps(S))
78
True
79
"""
80
if not isinstance(ambient, ambient_module.AmbientHeckeModule):
81
raise TypeError, "ambient must be an ambient Hecke module"
82
if not sage.modules.all.is_FreeModule(submodule):
83
raise TypeError, "submodule must be a free module"
84
if not submodule.is_submodule(ambient.free_module()):
85
raise ValueError, "submodule must be a submodule of the ambient free module"
86
87
if check:
88
if not ambient._is_hecke_equivariant_free_module(submodule):
89
raise ValueError, "The submodule must be invariant under all Hecke operators."
90
91
self.__ambient = ambient
92
self.__submodule = submodule
93
module.HeckeModule_free_module.__init__(self,
94
ambient.base_ring(), ambient.level(), ambient.weight())
95
if not (dual_free_module is None):
96
if not sage.modules.all.is_FreeModule(dual_free_module):
97
raise TypeError, "dual_free_module must be a free module"
98
if dual_free_module.rank () != submodule.rank():
99
raise ArithmeticError, "dual_free_module must have the same rank as submodule"
100
self.dual_free_module.set_cache(dual_free_module)
101
102
103
def _repr_(self):
104
r"""
105
String representation of self.
106
107
EXAMPLES::
108
109
sage: M = ModularForms(4,10)
110
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.submodule(M.basis()[:3]).free_module())
111
sage: S._repr_()
112
'Rank 3 submodule of a Hecke module of level 4'
113
"""
114
return "Rank %s submodule of a Hecke module of level %s"%(
115
self.rank(), self.level())
116
117
def __add__(self, other):
118
r"""
119
Sum of self and other (as submodules of a common ambient
120
module).
121
122
EXAMPLES::
123
124
sage: M = ModularForms(4,10)
125
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.submodule(M.basis()[:3]).free_module())
126
sage: E = sage.modular.hecke.submodule.HeckeSubmodule(M, M.submodule(M.basis()[3:]).free_module())
127
sage: S + E # indirect doctest
128
Modular Forms subspace of dimension 6 of Modular Forms space of dimension 6 for Congruence Subgroup Gamma0(4) of weight 10 over Rational Field
129
"""
130
if not isinstance(other, module.HeckeModule_free_module):
131
raise TypeError, "other (=%s) must be a Hecke module."%other
132
if self.ambient() != other.ambient():
133
raise ArithmeticError, "Sum only defined for submodules of a common ambient space."
134
if other.is_ambient():
135
return other
136
# Neither is ambient
137
M = self.free_module() + other.free_module()
138
return self.ambient().submodule(M, check=False)
139
140
def __call__(self, x, check=True):
141
"""
142
Coerce x into the ambient module and checks that x is in this
143
submodule.
144
145
EXAMPLES::
146
147
sage: M = ModularSymbols(37)
148
sage: S = M.cuspidal_submodule()
149
sage: M([0,oo])
150
-(1,0)
151
sage: S([0,oo])
152
Traceback (most recent call last):
153
...
154
TypeError: x does not coerce to an element of this Hecke module
155
sage: S([-1/23,0])
156
(1,23)
157
"""
158
z = self.ambient_hecke_module()(x)
159
if check:
160
if not z.element() in self.__submodule:
161
raise TypeError, "x does not coerce to an element of this Hecke module"
162
return z
163
164
def __cmp__(self, other):
165
"""
166
Compare self to other. Returns 0 if self is the same as
167
other, and -1 otherwise.
168
169
EXAMPLES::
170
sage: M = ModularSymbols(12,6)
171
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.cuspidal_submodule().free_module())
172
sage: T = sage.modular.hecke.submodule.HeckeSubmodule(M, M.new_submodule().free_module())
173
sage: S
174
Rank 14 submodule of a Hecke module of level 12
175
sage: T
176
Rank 0 submodule of a Hecke module of level 12
177
sage: S.__cmp__(T)
178
1
179
sage: T.__cmp__(S)
180
-1
181
sage: S.__cmp__(S)
182
0
183
"""
184
if not isinstance(other, module.HeckeModule_free_module):
185
return cmp(type(self), type(other))
186
c = cmp(self.ambient(), other.ambient())
187
if c:
188
return c
189
else:
190
return cmp(self.free_module(), other.free_module())
191
192
################################
193
# Semi-Private functions
194
################################
195
def _compute_dual_hecke_matrix(self, n):
196
"""
197
Compute the matrix for the nth Hecke operator acting on
198
the dual of self.
199
200
EXAMPLES::
201
202
sage: M = ModularForms(4,10)
203
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.submodule(M.basis()[:3]).free_module())
204
sage: S._compute_dual_hecke_matrix(3)
205
[ 0 0 1]
206
[ 0 -156 0]
207
[35568 0 72]
208
sage: CuspForms(4,10).dual_hecke_matrix(3)
209
[ 0 0 1]
210
[ 0 -156 0]
211
[35568 0 72]
212
"""
213
A = self.ambient_hecke_module().dual_hecke_matrix(n)
214
check = arith.gcd(self.level(), n) != 1
215
return A.restrict(self.dual_free_module(), check=check)
216
217
def _compute_hecke_matrix(self, n):
218
r"""
219
Compute the matrix of the nth Hecke operator acting on this space, by
220
calling the corresponding function for the ambient space and
221
restricting. If n is not coprime to the level, we check that the
222
restriction is well-defined.
223
224
EXAMPLES::
225
226
sage: R.<q> = QQ[[]]
227
sage: M = ModularForms(2, 12)
228
sage: f = M(q^2 - 24*q^4 + O(q^6))
229
sage: A = M.submodule(M.free_module().span([f.element()]),check=False)
230
sage: sage.modular.hecke.submodule.HeckeSubmodule._compute_hecke_matrix(A, 3)
231
[252]
232
sage: sage.modular.hecke.submodule.HeckeSubmodule._compute_hecke_matrix(A, 4)
233
Traceback (most recent call last):
234
...
235
ArithmeticError: subspace is not invariant under matrix
236
"""
237
A = self.ambient_hecke_module().hecke_matrix(n)
238
check = arith.gcd(self.level(), n) != 1
239
return A.restrict(self.free_module(), check=check)
240
241
def _compute_diamond_matrix(self, d):
242
r"""
243
EXAMPLE:
244
245
sage: f = ModularSymbols(Gamma1(13),2,sign=1).cuspidal_subspace().decomposition()[0]
246
sage: a = f.diamond_bracket_operator(2).matrix() # indirect doctest
247
sage: a.charpoly()
248
x^2 - x + 1
249
sage: a^12
250
[1 0]
251
[0 1]
252
"""
253
return self.ambient_hecke_module().diamond_bracket_matrix(d).restrict(self.free_module(), check=False)
254
255
def _compute_atkin_lehner_matrix(self, d):
256
"""
257
Compute the Atkin-Lehner matrix corresponding to the
258
divisor d of the level of self.
259
260
EXAMPLES::
261
262
sage: M = ModularSymbols(4,10)
263
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.cuspidal_submodule().free_module())
264
sage: S
265
Rank 6 submodule of a Hecke module of level 4
266
sage: S._compute_atkin_lehner_matrix(1)
267
[1 0 0 0 0 0]
268
[0 1 0 0 0 0]
269
[0 0 1 0 0 0]
270
[0 0 0 1 0 0]
271
[0 0 0 0 1 0]
272
[0 0 0 0 0 1]
273
"""
274
A = self.ambient_hecke_module()._compute_atkin_lehner_matrix(d)
275
return A.restrict(self.free_module(), check=True)
276
277
def _set_dual_free_module(self, V):
278
"""
279
Set the dual free module of self to V. Here V must be a vector
280
space of the same dimension as self, embedded in a space of
281
the same dimension as the ambient space of self.
282
283
EXAMPLES::
284
285
sage: M = ModularSymbols(4,10)
286
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.cuspidal_submodule().free_module())
287
sage: S._set_dual_free_module(M.cuspidal_submodule().dual_free_module())
288
sage: S._set_dual_free_module(S)
289
"""
290
if V.degree() != self.ambient_hecke_module().rank():
291
raise ArithmeticError, "The degree of V must equal the rank of the ambient space."
292
if V.rank() != self.rank():
293
raise ArithmeticError, "The rank of V must equal the rank of self."
294
self.dual_free_module.set_cache(V)
295
296
297
################################
298
# Public functions
299
################################
300
301
def ambient_hecke_module(self):
302
r"""
303
Return the ambient Hecke module of which this is a submodule.
304
305
EXAMPLES::
306
307
sage: CuspForms(2, 12).ambient_hecke_module()
308
Modular Forms space of dimension 4 for Congruence Subgroup Gamma0(2) of weight 12 over Rational Field
309
"""
310
return self.__ambient
311
312
def ambient(self):
313
r"""
314
Synonym for ambient_hecke_module.
315
316
EXAMPLES::
317
318
sage: CuspForms(2, 12).ambient()
319
Modular Forms space of dimension 4 for Congruence Subgroup Gamma0(2) of weight 12 over Rational Field
320
"""
321
return self.__ambient
322
323
@cached_method
324
def complement(self, bound=None):
325
"""
326
Return the largest Hecke-stable complement of this space.
327
328
EXAMPLES::
329
330
sage: M = ModularSymbols(15, 6).cuspidal_subspace()
331
sage: M.complement()
332
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 20 for Gamma_0(15) of weight 6 with sign 0 over Rational Field
333
sage: E = EllipticCurve("128a")
334
sage: ME = E.modular_symbol_space()
335
sage: ME.complement()
336
Modular Symbols subspace of dimension 17 of Modular Symbols space of dimension 18 for Gamma_0(128) of weight 2 with sign 1 over Rational Field
337
"""
338
339
if self.dual_free_module.is_in_cache():
340
D = self.dual_free_module()
341
V = D.basis_matrix().right_kernel()
342
return self.submodule(V, check=False)
343
344
if self.is_ambient():
345
return self.ambient_hecke_module().zero_submodule()
346
347
if self.is_zero():
348
return self.ambient_hecke_module()
349
350
if self.is_full_hecke_module():
351
anemic = False
352
else:
353
anemic = True
354
355
# TODO: optimize in some cases by computing image of
356
# complementary factor instead of kernel...?
357
misc.verbose("computing")
358
N = self.level()
359
A = self.ambient_hecke_module()
360
V = A.free_module()
361
p = 2
362
if bound is None:
363
bound = A.hecke_bound()
364
while True:
365
if anemic:
366
while N % p == 0: p = arith.next_prime(p)
367
misc.verbose("using T_%s"%p)
368
f = self.hecke_polynomial(p)
369
T = A.hecke_matrix(p)
370
g = T.charpoly('x')
371
V = T.kernel_on(V, poly=g//f, check=False)
372
if V.rank() + self.rank() <= A.rank():
373
break
374
p = arith.next_prime(p)
375
if p > bound: # to avoid computing hecke bound unless necessary
376
break
377
378
if V.rank() + self.rank() == A.rank():
379
C = A.submodule(V, check=False)
380
return C
381
382
# first attempt to compute the complement failed, we now try
383
# the following naive approach: decompose the ambient space,
384
# decompose self, and sum the pieces of ambient that are not
385
# subspaces of self
386
misc.verbose("falling back on naive algorithm")
387
D = A.decomposition()
388
C = A.zero_submodule()
389
for X in D:
390
if self.intersection(X).dimension() == 0:
391
C = C + X
392
if C.rank() + self.rank() == A.rank():
393
return C
394
395
# failed miserably
396
raise RuntimeError, "Computation of complementary space failed (cut down to rank %s, but should have cut down to rank %s)."%(V.rank(), A.rank()-self.rank())
397
398
399
def degeneracy_map(self, level, t=1):
400
"""
401
The t-th degeneracy map from self to the space of ambient modular
402
symbols of the given level. The level of self must be a divisor or
403
multiple of level, and t must be a divisor of the quotient.
404
405
INPUT:
406
407
408
- ``level`` - int, the level of the codomain of the
409
map (positive int).
410
411
- ``t`` - int, the parameter of the degeneracy map,
412
i.e., the map is related to `f(q)` - `f(q^t)`.
413
414
415
OUTPUT: A linear function from self to the space of modular symbols
416
of given level with the same weight, character, sign, etc., as this
417
space.
418
419
EXAMPLES::
420
421
sage: D = ModularSymbols(10,4).cuspidal_submodule().decomposition(); D
422
[
423
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,
424
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
425
]
426
sage: d = D[1].degeneracy_map(5); d
427
Hecke module morphism defined by the matrix
428
[ 0 0 -1 1]
429
[ 0 1/2 3/2 -2]
430
[ 0 -1 1 0]
431
[ 0 -3/4 -1/4 1]
432
Domain: Modular Symbols subspace of dimension 4 of Modular Symbols space ...
433
Codomain: Modular Symbols space of dimension 4 for Gamma_0(5) of weight ...
434
435
::
436
437
sage: d.rank()
438
2
439
sage: d.kernel()
440
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
441
sage: d.image()
442
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 for Gamma_0(5) of weight 4 with sign 0 over Rational Field
443
"""
444
d = self.ambient_hecke_module().degeneracy_map(level, t)
445
return d.restrict_domain(self)
446
447
448
@cached_method
449
def dual_free_module(self, bound=None, anemic=True, use_star=True):
450
r"""
451
Compute embedded dual free module if possible. In general this won't be
452
possible, e.g., if this space is not Hecke equivariant, possibly if it
453
is not cuspidal, or if the characteristic is not 0. In all these cases
454
we raise a RuntimeError exception.
455
456
If use_star is True (which is the default), we also use the +/-
457
eigenspaces for the star operator to find the dual free module of self.
458
If self does not have a star involution, use_star will automatically be
459
set to False.
460
461
EXAMPLES::
462
463
sage: M = ModularSymbols(11, 2)
464
sage: M.dual_free_module()
465
Vector space of dimension 3 over Rational Field
466
sage: Mpc = M.plus_submodule().cuspidal_submodule()
467
sage: Mcp = M.cuspidal_submodule().plus_submodule()
468
sage: Mcp.dual_free_module() == Mpc.dual_free_module()
469
True
470
sage: Mpc.dual_free_module()
471
Vector space of degree 3 and dimension 1 over Rational Field
472
Basis matrix:
473
[ 1 5/2 5]
474
475
sage: M = ModularSymbols(35,2).cuspidal_submodule()
476
sage: M.dual_free_module(use_star=False)
477
Vector space of degree 9 and dimension 6 over Rational Field
478
Basis matrix:
479
[ 1 0 0 0 -1 0 0 4 -2]
480
[ 0 1 0 0 0 0 0 -1/2 1/2]
481
[ 0 0 1 0 0 0 0 -1/2 1/2]
482
[ 0 0 0 1 -1 0 0 1 0]
483
[ 0 0 0 0 0 1 0 -2 1]
484
[ 0 0 0 0 0 0 1 -2 1]
485
486
sage: M = ModularSymbols(40,2)
487
sage: Mmc = M.minus_submodule().cuspidal_submodule()
488
sage: Mcm = M.cuspidal_submodule().minus_submodule()
489
sage: Mcm.dual_free_module() == Mmc.dual_free_module()
490
True
491
sage: Mcm.dual_free_module()
492
Vector space of degree 13 and dimension 3 over Rational Field
493
Basis matrix:
494
[ 0 1 0 0 0 0 1 0 -1 -1 1 -1 0]
495
[ 0 0 1 0 -1 0 -1 0 1 0 0 0 0]
496
[ 0 0 0 0 0 1 1 0 -1 0 0 0 0]
497
498
sage: M = ModularSymbols(43).cuspidal_submodule()
499
sage: S = M[0].plus_submodule() + M[1].minus_submodule()
500
sage: S.dual_free_module(use_star=False)
501
Traceback (most recent call last):
502
...
503
RuntimeError: Computation of complementary space failed (cut down to rank 7, but should have cut down to rank 4).
504
sage: S.dual_free_module().dimension() == S.dimension()
505
True
506
507
We test that #5080 is fixed::
508
509
sage: EllipticCurve('128a').congruence_number()
510
32
511
512
"""
513
514
# if we know the complement we can read off the dual module
515
if self.complement.is_in_cache():
516
misc.verbose('This module knows its complement already -- cheating in dual_free_module')
517
C = self.complement()
518
V = C.basis_matrix().right_kernel()
519
return V
520
521
misc.verbose("computing dual")
522
523
A = self.ambient_hecke_module()
524
525
if self.dimension() == 0:
526
return A.zero_submodule()
527
528
if A.dimension() == self.dimension():
529
return A.free_module()
530
531
# ALGORITHM: Compute the char poly of each Hecke operator on
532
# the submodule, then use it to cut out a submodule of the
533
# dual. If the dimension cuts down to the dimension of self
534
# terminate with success. If it stays larger beyond the Sturm
535
# bound, raise a RuntimeError exception.
536
537
# In the case that the sign of self is not 1, we need to use
538
# the star involution as well as the Hecke operators in order
539
# to find the dual of self.
540
#
541
# Note that one needs to comment out the line caching the
542
# result of this computation below in order to get meaningful
543
# timings.
544
545
# If the star involution doesn't make sense for self, then we
546
# can't use it.
547
if not hasattr(self, 'star_eigenvalues'):
548
use_star = False
549
550
if use_star:
551
# If the star involution has both + and - eigenspaces on self,
552
# then we compute the dual on each eigenspace, then put them
553
# together.
554
if len(self.star_eigenvalues()) == 2:
555
V = self.plus_submodule(compute_dual = False).dual_free_module() + \
556
self.minus_submodule(compute_dual = False).dual_free_module()
557
return V
558
559
# At this point, we know that self is an eigenspace for star.
560
V = A.sign_submodule(self.sign()).dual_free_module()
561
else:
562
V = A.free_module()
563
564
N = self.level()
565
p = 2
566
if bound is None:
567
bound = A.hecke_bound()
568
while True:
569
if anemic:
570
while N % p == 0: p = arith.next_prime(p)
571
misc.verbose("using T_%s"%p)
572
f = self.hecke_polynomial(p)
573
T = A.dual_hecke_matrix(p)
574
V = T.kernel_on(V, poly=f, check=False)
575
if V.dimension() <= self.dimension():
576
break
577
p = arith.next_prime(p)
578
if p > bound:
579
break
580
581
if V.rank() == self.rank():
582
return V
583
else:
584
# Failed to reduce V to the appropriate dimension
585
W = self.complement()
586
V2 = W.basis_matrix().right_kernel()
587
if V2.rank() == self.rank():
588
return V2
589
else:
590
raise RuntimeError, "Computation of embedded dual vector space failed " + \
591
"(cut down to rank %s, but should have cut down to rank %s)."%(V.rank(), self.rank())
592
593
594
def free_module(self):
595
"""
596
Return the free module corresponding to self.
597
598
EXAMPLES::
599
600
sage: M = ModularSymbols(33,2).cuspidal_subspace() ; M
601
Modular Symbols subspace of dimension 6 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field
602
sage: M.free_module()
603
Vector space of degree 9 and dimension 6 over Rational Field
604
Basis matrix:
605
[ 0 1 0 0 0 0 0 -1 1]
606
[ 0 0 1 0 0 0 0 -1 1]
607
[ 0 0 0 1 0 0 0 -1 1]
608
[ 0 0 0 0 1 0 0 -1 1]
609
[ 0 0 0 0 0 1 0 -1 1]
610
[ 0 0 0 0 0 0 1 -1 0]
611
"""
612
return self.__submodule
613
614
def module(self):
615
r"""
616
Alias for \code{self.free_module()}.
617
618
EXAMPLES::
619
620
sage: M = ModularSymbols(17,4).cuspidal_subspace()
621
sage: M.free_module() is M.module()
622
True
623
"""
624
return self.free_module()
625
626
def intersection(self, other):
627
"""
628
Returns the intersection of self and other, which must both lie in
629
a common ambient space of modular symbols.
630
631
EXAMPLES::
632
633
sage: M = ModularSymbols(43, sign=1)
634
sage: A = M[0] + M[1]
635
sage: B = M[1] + M[2]
636
sage: A.dimension(), B.dimension()
637
(2, 3)
638
sage: C = A.intersection(B); C.dimension()
639
1
640
641
TESTS::
642
643
sage: M = ModularSymbols(1,80)
644
sage: M.plus_submodule().cuspidal_submodule().sign() # indirect doctest
645
1
646
"""
647
if self.ambient_hecke_module() != other.ambient_hecke_module():
648
raise ArithmeticError, "Intersection only defined for subspaces of"\
649
+ " a common ambient modular symbols space."
650
if other.is_ambient():
651
return self
652
if self.is_ambient():
653
return other
654
655
# Neither is ambient
656
V = self.free_module().intersection(other.free_module())
657
M = self.ambient_hecke_module().submodule(V,check=False)
658
659
## if sign is nonzero, the intersection will be, too
660
## this only makes sense for modular symbols spaces (and hence shouldn't really be in this file)
661
try:
662
if self.sign():
663
M._set_sign(self.sign())
664
elif other.sign():
665
M._set_sign(other.sign())
666
except AttributeError:
667
pass
668
669
return M
670
671
def is_ambient(self):
672
r"""
673
Return ``True`` if self is an ambient space of modular
674
symbols.
675
676
EXAMPLES::
677
678
sage: M = ModularSymbols(17,4)
679
sage: M.cuspidal_subspace().is_ambient()
680
False
681
sage: A = M.ambient_hecke_module()
682
sage: S = A.submodule(A.basis())
683
sage: sage.modular.hecke.submodule.HeckeSubmodule.is_ambient(S)
684
True
685
"""
686
return self.free_module() == self.ambient_hecke_module().free_module()
687
688
def is_new(self, p=None):
689
"""
690
Returns True if this Hecke module is p-new. If p is None,
691
returns True if it is new.
692
693
EXAMPLES::
694
695
sage: M = ModularSymbols(1,16)
696
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.cuspidal_submodule().free_module())
697
sage: S.is_new()
698
True
699
"""
700
try:
701
return self.__is_new[p]
702
except AttributeError:
703
self.__is_new = {}
704
except KeyError:
705
pass
706
N = self.ambient_hecke_module().new_submodule(p)
707
self.__is_new[p] = self.is_submodule(N)
708
return self.__is_new[p]
709
710
def is_old(self, p=None):
711
"""
712
Returns True if this Hecke module is p-old. If p is None,
713
returns True if it is old.
714
715
EXAMPLES::
716
717
sage: M = ModularSymbols(50,2)
718
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.old_submodule().free_module())
719
sage: S.is_old()
720
True
721
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.new_submodule().free_module())
722
sage: S.is_old()
723
False
724
"""
725
try:
726
return self.__is_old[p]
727
except AttributeError:
728
self.__is_old = {}
729
except KeyError:
730
pass
731
O = self.ambient_hecke_module().old_submodule(p)
732
self.__is_old[p] = self.is_submodule(O)
733
return self.__is_old[p]
734
735
def is_submodule(self, V):
736
"""
737
Returns True if and only if self is a submodule of V.
738
739
EXAMPLES::
740
741
sage: M = ModularSymbols(30,4)
742
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.cuspidal_submodule().free_module())
743
sage: S.is_submodule(M)
744
True
745
sage: SS = sage.modular.hecke.submodule.HeckeSubmodule(M, M.old_submodule().free_module())
746
sage: S.is_submodule(SS)
747
False
748
"""
749
if not isinstance(V, module.HeckeModule_free_module):
750
return False
751
return self.ambient_hecke_module() == V.ambient_hecke_module() and \
752
self.free_module().is_subspace(V.free_module())
753
754
def linear_combination_of_basis(self, v):
755
"""
756
Return the linear combination of the basis of self given by the
757
entries of v.
758
759
EXAMPLES::
760
761
sage: M = ModularForms(Gamma0(2),12)
762
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.cuspidal_submodule().free_module())
763
sage: S.basis()
764
(q + 252*q^3 - 2048*q^4 + 4830*q^5 + O(q^6), q^2 - 24*q^4 + O(q^6))
765
sage: S.linear_combination_of_basis([3,10])
766
3*q + 10*q^2 + 756*q^3 - 6384*q^4 + 14490*q^5 + O(q^6)
767
"""
768
x = self.free_module().linear_combination_of_basis(v)
769
return self.__ambient(x)
770
771
def new_submodule(self, p=None):
772
"""
773
Return the new or p-new submodule of this space of modular
774
symbols.
775
776
EXAMPLES::
777
778
sage: M = ModularSymbols(20,4)
779
sage: M.new_submodule()
780
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_0(20) of weight 4 with sign 0 over Rational Field
781
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.cuspidal_submodule().free_module())
782
sage: S
783
Rank 12 submodule of a Hecke module of level 20
784
sage: S.new_submodule()
785
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_0(20) of weight 4 with sign 0 over Rational Field
786
"""
787
try:
788
if self.__is_new[p]:
789
return self
790
except AttributeError:
791
self.__is_new = {}
792
except KeyError:
793
pass
794
795
if self.rank() == 0:
796
self.__is_new[p] = True
797
return self
798
try:
799
return self.__new_submodule[p]
800
except AttributeError:
801
self.__new_submodule = {}
802
except KeyError:
803
pass
804
805
S = self.ambient_hecke_module().new_submodule(p)
806
ns = S.intersection(self)
807
if ns.rank() == self.rank():
808
self.__is_new[p] = True
809
ns.__is_new = {p:True}
810
self.__new_submodule[p] = ns
811
return ns
812
813
def nonembedded_free_module(self):
814
"""
815
Return the free module corresponding to self as an abstract
816
free module, i.e. not as an embedded vector space.
817
818
EXAMPLES::
819
820
sage: M = ModularSymbols(12,6)
821
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.cuspidal_submodule().free_module())
822
sage: S
823
Rank 14 submodule of a Hecke module of level 12
824
sage: S.nonembedded_free_module()
825
Vector space of dimension 14 over Rational Field
826
"""
827
return self.free_module().nonembedded_free_module()
828
829
def old_submodule(self, p=None):
830
"""
831
Return the old or p-old submodule of this space of modular
832
symbols.
833
834
EXAMPLES: We compute the old and new submodules of
835
`\mathbf{S}_2(\Gamma_0(33))`.
836
837
::
838
839
sage: M = ModularSymbols(33); S = M.cuspidal_submodule(); S
840
Modular Symbols subspace of dimension 6 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field
841
sage: S.old_submodule()
842
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field
843
sage: S.new_submodule()
844
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
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
S = self.ambient_hecke_module().old_submodule(p)
865
os = S.intersection(self)
866
if os.rank() == self.rank():
867
self.__is_old[p] = True
868
os.__is_old = {p:True}
869
self.__old_submodule[p] = os
870
return os
871
872
def rank(self):
873
r"""
874
Return the rank of self as a free module over the base ring.
875
876
EXAMPLE::
877
878
sage: ModularSymbols(6, 4).cuspidal_subspace().rank()
879
2
880
sage: ModularSymbols(6, 4).cuspidal_subspace().dimension()
881
2
882
"""
883
return self.__submodule.rank()
884
885
def submodule(self, M, Mdual=None, check=True):
886
"""
887
Construct a submodule of self from the free module M, which
888
must be a subspace of self.
889
890
EXAMPLES::
891
892
sage: M = ModularSymbols(18,4)
893
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.cuspidal_submodule().free_module())
894
sage: S[0]
895
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_0(18) of weight 4 with sign 0 over Rational Field
896
sage: S.submodule(S[0].free_module())
897
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_0(18) of weight 4 with sign 0 over Rational Field
898
"""
899
if not sage.modules.all.is_FreeModule(M):
900
V = self.ambient_module().free_module()
901
if isinstance(M, (list,tuple)):
902
M = V.span([V(x.element()) for x in M])
903
else:
904
M = V.span(M)
905
906
if check:
907
if not M.is_submodule(self.free_module()):
908
raise TypeError, "M (=%s) must be a submodule of the free module (=%s) associated to this module."%(M, self.free_module())
909
910
return self.ambient().submodule(M, Mdual, check=check)
911
912
def submodule_from_nonembedded_module(self, V, Vdual=None, check=True):
913
"""
914
Construct a submodule of self from V. Here V should be a
915
subspace of a vector space whose dimension is the same as that
916
of self.
917
918
INPUT:
919
920
921
- ``V`` - submodule of ambient free module of the same
922
rank as the rank of self.
923
924
- ``check`` - whether to check that V is Hecke
925
equivariant.
926
927
928
OUTPUT: Hecke submodule of self
929
930
EXAMPLES::
931
932
sage: M = ModularSymbols(37,2)
933
sage: S = sage.modular.hecke.submodule.HeckeSubmodule(M, M.cuspidal_submodule().free_module())
934
sage: V = (QQ**4).subspace([[1,-1,0,1/2],[0,0,1,-1/2]])
935
sage: S.submodule_from_nonembedded_module(V)
936
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
937
"""
938
E = self.free_module()
939
M_V = V.matrix()
940
M_E = E.matrix()
941
# We encode the operation of taking the linear combinations of
942
# the basis of E given by the basis of V as a single matrix
943
# multiplication, since matrix multiplication is (presumed to be)
944
# so fast, and their are asymptotically fast algorithms.
945
A = M_V * M_E
946
V = A.row_space()
947
if not (Vdual is None):
948
E = self.dual_free_module()
949
M_Vdual = Vdual.matrix()
950
M_E = E.matrix()
951
A = M_Vdual * M_E
952
Vdual = A.row_space()
953
return self.ambient_hecke_module().submodule(V, Vdual, check=check)
954
955
956