-
-
Notifications
You must be signed in to change notification settings - Fork 405
/
module.py
1801 lines (1460 loc) · 63.1 KB
/
module.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
Hecke modules
"""
#*****************************************************************************
# Copyright (C) 2004,2005,2006 William Stein <wstein@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************
import sage.rings.all
import sage.arith.all as arith
import sage.misc.misc as misc
import sage.modules.module
from sage.structure.all import Sequence
import sage.matrix.matrix_space as matrix_space
from sage.structure.parent import Parent
import sage.misc.prandom as random
import algebra
import element
import hecke_operator
from sage.modules.all import FreeModule
def is_HeckeModule(x):
r"""
Return True if x is a Hecke module.
EXAMPLES::
sage: from sage.modular.hecke.module import is_HeckeModule
sage: is_HeckeModule(ModularForms(Gamma0(7), 4))
True
sage: is_HeckeModule(QQ^3)
False
sage: is_HeckeModule(J0(37).homology())
True
"""
return isinstance(x, HeckeModule_generic)
class HeckeModule_generic(sage.modules.module.Module):
r"""
A very general base class for Hecke modules.
We define a Hecke module of weight `k` to be a module over a commutative
ring equipped with an action of operators `T_m` for all positive integers `m`
coprime to some integer `n`(the level), which satisfy `T_r T_s = T_{rs}` for
`r,s` coprime, and for powers of a prime `p`, `T_{p^r} = T_{p} T_{p^{r-1}} -
\varepsilon(p) p^{k-1} T_{p^{r-2}}`, where `\varepsilon(p)` is some
endomorphism of the module which commutes with the `T_m`.
We distinguish between *full* Hecke modules, which also have an action of
operators `T_m` for `m` not assumed to be coprime to the level, and
*anemic* Hecke modules, for which this does not hold.
"""
Element = element.HeckeModuleElement
def __init__(self, base_ring, level, category=None):
r"""
Create a Hecke module. Not intended to be called directly.
EXAMPLE::
sage: CuspForms(Gamma0(17),2) # indirect doctest
Cuspidal subspace of dimension 1 of Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(17) of weight 2 over Rational Field
sage: ModularForms(3, 3).category()
Category of Hecke modules over Rational Field
"""
if not isinstance(base_ring, sage.rings.all.CommutativeRing):
raise TypeError("base_ring must be commutative ring")
from sage.categories.hecke_modules import HeckeModules
default_category = HeckeModules(base_ring)
if category is None:
category = default_category
else:
assert category.is_subcategory(default_category), "%s is not a subcategory of %s"%(category, default_category)
sage.modules.module.Module.__init__(self, base_ring, category=category)
level = sage.rings.all.ZZ(level)
if level <= 0:
raise ValueError("level (=%s) must be positive"%level)
self.__level = level
self._hecke_matrices = {}
self._diamond_matrices = {}
def __setstate__(self, state):
r"""
Ensure that the category is initialized correctly on unpickling.
EXAMPLE::
sage: loads(dumps(ModularSymbols(11))).category() # indirect doctest
Category of Hecke modules over Rational Field
"""
if not self._is_category_initialized():
from sage.categories.hecke_modules import HeckeModules
self._init_category_(HeckeModules(state['_base']))
sage.modules.module.Module.__setstate__(self, state)
def __hash__(self):
r"""
The hash is determined by the base ring and the level.
EXAMPLE::
sage: MS = sage.modular.hecke.module.HeckeModule_generic(QQ,1)
sage: hash(MS) == hash((MS.base_ring(), MS.level()))
True
"""
return hash((self.base_ring(), self.__level))
def __cmp__(self, other):
r"""
Compare self to other. This must be overridden in all subclasses.
EXAMPLE::
sage: M = ModularForms(Gamma0(3))
sage: sage.modular.hecke.module.HeckeModule_generic.__cmp__(M, M)
Traceback (most recent call last):
...
NotImplementedError: ...
"""
raise NotImplementedError("Derived class %s should implement __cmp__" % type(self))
def _compute_hecke_matrix_prime_power(self, p, r, **kwds):
r"""
Compute the Hecke matrix T_{p^r}, where `p` is prime and `r \ge 2`, assuming that
`T_p` is known. This is carried out by recursion.
All derived classes must override either this function or ``self.character()``.
EXAMPLE::
sage: M = ModularForms(SL2Z, 24)
sage: M._compute_hecke_matrix_prime_power(3, 3)
[ 834385168339943471891603972970040 462582247568491031177169792000 3880421605193373124143717311013888000]
[ 0 -4112503986561480 53074162446443642880]
[ 0 2592937954080 -1312130996155080]
"""
# convert input arguments to int's.
(p,r) = (int(p), int(r))
if not arith.is_prime(p):
raise ArithmeticError("p must be a prime")
# T_{p^r} := T_p * T_{p^{r-1}} - eps(p)p^{k-1} T_{p^{r-2}}.
pow = p**(r-1)
if pow not in self._hecke_matrices:
# The following will force computation of T_{p^s}
# for all s<=r-1, except possibly s=0.
self._hecke_matrices[pow] = self._compute_hecke_matrix(pow)
if 1 not in self._hecke_matrices:
self._hecke_matrices[1] = self._compute_hecke_matrix(1)
Tp = self._hecke_matrices[p]
Tpr1 = self._hecke_matrices[pow]
eps = self.character()
if eps is None:
raise NotImplementedError("either character or _compute_hecke_matrix_prime_power must be overloaded in a derived class")
k = self.weight()
Tpr2 = self._hecke_matrices[pow/p]
return Tp*Tpr1 - eps(p)*(p**(k-1)) * Tpr2
def _compute_hecke_matrix_general_product(self, F, **kwds):
r"""
Compute the matrix of a general Hecke operator acting on this space, by
factorising n into prime powers and multiplying together the Hecke
operators for each of these.
EXAMPLE::
sage: M = ModularSymbols(Gamma0(3), 4)
sage: M._compute_hecke_matrix_general_product(factor(10))
[1134 0]
[ 0 1134]
"""
prod = None
for p, r in F:
pow = int(p**r)
if pow not in self._hecke_matrices:
self._hecke_matrices[pow] = self._compute_hecke_matrix(pow)
if prod is None:
prod = self._hecke_matrices[pow]
else:
prod *= self._hecke_matrices[pow]
return prod
def _compute_dual_hecke_matrix(self, n):
r"""
Compute the matrix of the Hecke operator `T_n` acting on the dual of self.
EXAMPLE::
sage: M = ModularSymbols(Gamma0(3), 4)
sage: M._compute_dual_hecke_matrix(10)
[1134 0]
[ 0 1134]
"""
return self.hecke_matrix(n).transpose()
def _compute_hecke_matrix(self, n, **kwds):
r"""
Compute the matrix of the Hecke operator `T_n` acting on self.
EXAMPLE::
sage: M = EisensteinForms(DirichletGroup(3).0, 3)
sage: M._compute_hecke_matrix(16)
[205 0]
[ 0 205]
"""
n = int(n)
if n<1:
raise ValueError("Hecke operator T_%s is not defined."%n)
if n==1:
Mat = matrix_space.MatrixSpace(self.base_ring(),self.rank())
return Mat(1)
if arith.is_prime(n):
return self._compute_hecke_matrix_prime(n, **kwds)
F = arith.factor(n)
if len(F) == 1: # nontrivial prime power case
return self._compute_hecke_matrix_prime_power(F[0][0],F[0][1], **kwds)
else:
return self._compute_hecke_matrix_general_product(F, **kwds)
def _compute_hecke_matrix_prime(self, p, **kwds):
"""
Compute and return the matrix of the p-th Hecke operator for p prime.
Derived classes should overload this function, and they will inherit
the machinery for calculating general Hecke operators.
EXAMPLE::
sage: M = EisensteinForms(DirichletGroup(3).0, 3)
sage: sage.modular.hecke.module.HeckeModule_generic._compute_hecke_matrix_prime(M, 3)
Traceback (most recent call last):
...
NotImplementedError: All subclasses must implement _compute_hecke_matrix_prime
"""
raise NotImplementedError("All subclasses must implement _compute_hecke_matrix_prime")
def _compute_diamond_matrix(self, d):
r"""
Compute the matrix of the diamond bracket operator `\langle d \rangle` on this space,
in cases where this isn't self-evident (i.e. when this is not a space
with fixed character).
EXAMPLE::
sage: M = EisensteinForms(Gamma1(5), 3)
sage: sage.modular.hecke.module.HeckeModule_generic._compute_diamond_matrix(M, 2)
Traceback (most recent call last):
...
NotImplementedError: All subclasses without fixed character must implement _compute_diamond_matrix
"""
raise NotImplementedError("All subclasses without fixed character must implement _compute_diamond_matrix")
def _hecke_operator_class(self):
"""
Return the class to be used for instantiating Hecke operators
acting on self.
EXAMPLES::
sage: sage.modular.hecke.module.HeckeModule_generic(QQ,1)._hecke_operator_class()
<class 'sage.modular.hecke.hecke_operator.HeckeOperator'>
sage: ModularSymbols(1,12)._hecke_operator_class()
<class 'sage.modular.modsym.hecke_operator.HeckeOperator'>
"""
return hecke_operator.HeckeOperator
def _diamond_operator_class(self):
r"""
Return the class to be used for instantiating diamond bracket operators
acting on self.
EXAMPLES::
sage: sage.modular.hecke.module.HeckeModule_generic(QQ,1)._diamond_operator_class()
<class 'sage.modular.hecke.hecke_operator.DiamondBracketOperator'>
sage: ModularSymbols(1,12)._diamond_operator_class()
<class 'sage.modular.hecke.hecke_operator.DiamondBracketOperator'>
"""
return hecke_operator.DiamondBracketOperator
def anemic_hecke_algebra(self):
"""
Return the Hecke algebra associated to this Hecke module.
EXAMPLES::
sage: T = ModularSymbols(1,12).hecke_algebra()
sage: A = ModularSymbols(1,12).anemic_hecke_algebra()
sage: T == A
False
sage: A
Anemic Hecke algebra acting on Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field
sage: A.is_anemic()
True
"""
try:
return self.__anemic_hecke_algebra
except AttributeError:
self.__anemic_hecke_algebra = algebra.AnemicHeckeAlgebra(self)
return self.__anemic_hecke_algebra
def character(self):
r"""
The character of this space. As this is an abstract base class, return None.
EXAMPLE::
sage: sage.modular.hecke.module.HeckeModule_generic(QQ, 10).character() is None
True
"""
return None
def dimension(self):
r"""
Synonym for rank.
EXAMPLE::
sage: M = sage.modular.hecke.module.HeckeModule_generic(QQ, 10).dimension()
Traceback (most recent call last):
...
NotImplementedError: Derived subclasses must implement rank
"""
return self.rank()
def hecke_algebra(self):
"""
Return the Hecke algebra associated to this Hecke module.
EXAMPLES::
sage: T = ModularSymbols(Gamma1(5),3).hecke_algebra()
sage: T
Full Hecke algebra acting on Modular Symbols space of dimension 4 for Gamma_1(5) of weight 3 with sign 0 and over Rational Field
sage: T.is_anemic()
False
::
sage: M = ModularSymbols(37,sign=1)
sage: E, A, B = M.decomposition()
sage: A.hecke_algebra() == B.hecke_algebra()
False
"""
try:
return self.__hecke_algebra
except AttributeError:
self.__hecke_algebra = algebra.HeckeAlgebra(self)
return self.__hecke_algebra
def is_zero(self):
"""
Return True if this Hecke module has dimension 0.
EXAMPLES::
sage: ModularSymbols(11).is_zero()
False
sage: ModularSymbols(11).old_submodule().is_zero()
True
sage: CuspForms(10).is_zero()
True
sage: CuspForms(1,12).is_zero()
False
"""
return self.dimension() == 0
def is_full_hecke_module(self):
"""
Return True if this space is invariant under all Hecke operators.
Since self is guaranteed to be an anemic Hecke module, the significance
of this function is that it also ensures invariance under Hecke
operators of index that divide the level.
EXAMPLES::
sage: M = ModularSymbols(22); M.is_full_hecke_module()
True
sage: M.submodule(M.free_module().span([M.0.list()]), check=False).is_full_hecke_module()
False
"""
try:
return self._is_full_hecke_module
except AttributeError:
pass
# now compute whether invariant under Hecke operators of index
# dividing the level
misc.verbose("Determining if Hecke module is full.")
N = self.level()
for p in arith.prime_divisors(N):
if not self.is_hecke_invariant(p):
self._is_full_hecke_module = False
return False
self._is_full_hecke_module = True
return True
def is_hecke_invariant(self, n):
"""
Return True if self is invariant under the Hecke operator
`T_n`.
Since self is guaranteed to be an anemic Hecke module it is only
interesting to call this function when `n` is not coprime
to the level.
EXAMPLES::
sage: M = ModularSymbols(22).cuspidal_subspace()
sage: M.is_hecke_invariant(2)
True
We use check=False to create a nasty "module" that is not invariant
under `T_2`::
sage: S = M.submodule(M.free_module().span([M.0.list()]), check=False); S
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 7 for Gamma_0(22) of weight 2 with sign 0 over Rational Field
sage: S.is_hecke_invariant(2)
False
sage: [n for n in range(1,12) if S.is_hecke_invariant(n)]
[1, 3, 5, 7, 9, 11]
"""
if arith.gcd(n, self.level()) == 1:
return True
if self.is_ambient():
return True
try:
self.hecke_operator(n).matrix()
except ArithmeticError:
return False
return True
def level(self):
"""
Returns the level of this modular symbols space.
INPUT:
- ``ModularSymbols self`` - an arbitrary space of
modular symbols
OUTPUT:
- ``int`` - the level
EXAMPLES::
sage: m = ModularSymbols(20)
sage: m.level()
20
"""
return self.__level
def rank(self):
r"""
Return the rank of this module over its base ring. Returns
NotImplementedError, since this is an abstract base class.
EXAMPLES::
sage: sage.modular.hecke.module.HeckeModule_generic(QQ, 10).rank()
Traceback (most recent call last):
...
NotImplementedError: Derived subclasses must implement rank
"""
raise NotImplementedError("Derived subclasses must implement rank")
def submodule(self, X):
r"""
Return the submodule of self corresponding to X. As this is an abstract
base class, this raises a NotImplementedError.
EXAMPLES::
sage: sage.modular.hecke.module.HeckeModule_generic(QQ, 10).submodule(0)
Traceback (most recent call last):
...
NotImplementedError: Derived subclasses should implement submodule
"""
raise NotImplementedError("Derived subclasses should implement submodule")
class HeckeModule_free_module(HeckeModule_generic):
"""
A Hecke module modeled on a free module over a commutative ring.
"""
def __init__(self, base_ring, level, weight, category=None):
r"""
Initialise a module.
EXAMPLES::
sage: M = sage.modular.hecke.module.HeckeModule_free_module(QQ, 12, -4); M
<class 'sage.modular.hecke.module.HeckeModule_free_module_with_category'>
sage: TestSuite(M).run(skip = ["_test_additive_associativity",\
"_test_an_element",\
"_test_elements",\
"_test_elements_eq_reflexive",\
"_test_elements_eq_symmetric",\
"_test_elements_eq_transitive",\
"_test_elements_neq",\
"_test_pickling",\
"_test_some_elements",\
"_test_zero",\
"_test_eq"]) # is this supposed to be an abstract parent without elements?
"""
HeckeModule_generic.__init__(self, base_ring, level, category=category)
self.__weight = weight
# def __cmp__(self, other):
# if not isinstance(other, HeckeModule_free_module):
# return -1
# c = HeckeModule_generic.__cmp__(self, other)
# if c: return c
# return cmp(self.__weight, other.__weight)
# def __contains__(self, x):
# r"""
# Return True if x is an element of self.
#
# This shouldn't be getting called, ever (?)
# """
# if not element.is_HeckeModuleElement(x):
# return False
# if x.parent() == self: # easy case
# return True
# return x.element() in self.free_module()
def _repr_(self):
r"""
EXAMPLES::
sage: M = sage.modular.hecke.module.HeckeModule_free_module(QQ, 12, -4); M
<class 'sage.modular.hecke.module.HeckeModule_free_module_with_category'>
.. TODO::
Implement a nicer repr, or implement the methods required
by :class:`ModulesWithBasis` to benefit from
:meth:`ModulesWithBasis.ParentMethods._repr_`.
"""
return repr(type(self))
def __getitem__(self, n):
r"""
Return the nth term in the decomposition of self. See the docstring for
``decomposition`` for further information.
EXAMPLES::
sage: ModularSymbols(22)[0]
Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 7 for Gamma_0(22) of weight 2 with sign 0 over Rational Field
"""
n = int(n)
D = self.decomposition()
if n < 0 or n >= len(D):
raise IndexError("index (=%s) must be between 0 and %s"%(n, len(D)-1))
return D[n]
def __hash__(self):
r"""
The hash is determined by the weight, the level and the base ring.
EXAMPLES::
sage: MS = ModularSymbols(22)
sage: hash(MS) == hash((MS.weight(), MS.level(), MS.base_ring()))
True
"""
return hash((self.__weight, self.level(), self.base_ring()))
def __len__(self):
r"""
The number of factors in the decomposition of self.
EXAMPLES::
sage: len(ModularSymbols(22))
2
"""
return len(self.decomposition())
def _eigen_nonzero(self):
"""
Return smallest integer i such that the i-th entries of the entries
of a basis for the dual vector space are not all 0.
EXAMPLES::
sage: M = ModularSymbols(31,2)
sage: M._eigen_nonzero()
0
sage: M.dual_free_module().basis()
[
(1, 0, 0, 0, 0),
(0, 1, 0, 0, 0),
(0, 0, 1, 0, 0),
(0, 0, 0, 1, 0),
(0, 0, 0, 0, 1)
]
sage: M.cuspidal_submodule().minus_submodule()._eigen_nonzero()
1
sage: M.cuspidal_submodule().minus_submodule().dual_free_module().basis()
[
(0, 1, 0, 0, 0),
(0, 0, 1, 0, 0)
]
"""
try:
return self.__eigen_nonzero
except AttributeError:
pass
A = self.ambient_hecke_module()
V = self.dual_free_module()
B = V.basis()
for i in range(V.degree()):
for b in B:
if b[i] != 0:
self.__eigen_nonzero = i
return i
assert False, 'bug in _eigen_nonzero'
def _eigen_nonzero_element(self, n=1):
r"""
Return `T_n(x)` where `x` is a sparse modular
symbol such that the image of `x` is nonzero under the dual
projection map associated to this space, and `T_n` is the
`n^{th}` Hecke operator.
Used in the dual_eigenvector and eigenvalue methods.
EXAMPLES::
sage: ModularSymbols(22)._eigen_nonzero_element(3)
4*(1,0) + (2,21) - (11,1) + (11,2)
"""
if self.rank() == 0:
raise ArithmeticError("the rank of self must be positive")
A = self.ambient_hecke_module()
i = self._eigen_nonzero()
return A._hecke_image_of_ith_basis_vector(n, i)
def _hecke_image_of_ith_basis_vector(self, n, i):
r"""
Return `T_n(e_i)`, where `e_i` is the
`i`th basis vector of the ambient space.
EXAMPLE::
sage: ModularSymbols(Gamma0(3))._hecke_image_of_ith_basis_vector(4, 0)
7*(1,0)
sage: ModularForms(Gamma0(3))._hecke_image_of_ith_basis_vector(4, 0)
7 + 84*q + 252*q^2 + 84*q^3 + 588*q^4 + 504*q^5 + O(q^6)
"""
T = self.hecke_operator(n)
return T.apply_sparse(self.gen(i))
def _element_eigenvalue(self, x, name='alpha'):
r"""
Return the dot product of self with the eigenvector returned by dual_eigenvector.
EXAMPLE::
sage: M = ModularSymbols(11)[0]
sage: M._element_eigenvalue(M.0)
1
"""
if not element.is_HeckeModuleElement(x):
raise TypeError("x must be a Hecke module element.")
if not x in self.ambient_hecke_module():
raise ArithmeticError("x must be in the ambient Hecke module.")
v = self.dual_eigenvector(names=name)
return v.dot_product(x.element())
def _is_hecke_equivariant_free_module(self, submodule):
"""
Returns True if the given free submodule of the ambient free module
is invariant under all Hecke operators.
EXAMPLES::
sage: M = ModularSymbols(11); V = M.free_module()
sage: M._is_hecke_equivariant_free_module(V.span([V.0]))
False
sage: M._is_hecke_equivariant_free_module(V)
True
sage: M._is_hecke_equivariant_free_module(M.cuspidal_submodule().free_module())
True
We do the same as above, but with a modular forms space::
sage: M = ModularForms(11); V = M.free_module()
sage: M._is_hecke_equivariant_free_module(V.span([V.0 + V.1]))
False
sage: M._is_hecke_equivariant_free_module(V)
True
sage: M._is_hecke_equivariant_free_module(M.cuspidal_submodule().free_module())
True
"""
misc.verbose("Determining if free module is Hecke equivariant.")
bound = self.hecke_bound()
for p in arith.primes(bound+1):
try:
self.T(p).matrix().restrict(submodule, check=True)
except ArithmeticError:
return False
return True
def _set_factor_number(self, i):
r"""
For internal use. If this Hecke module was computed via a decomposition of another
Hecke module, this method stores the index of this space in that decomposition.
EXAMPLE::
sage: ModularSymbols(Gamma0(3))[0].factor_number() # indirect doctest
0
"""
self.__factor_number = i
def ambient(self):
r"""
Synonym for ambient_hecke_module. Return the ambient module associated to this module.
EXAMPLE::
sage: CuspForms(1, 12).ambient()
Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field
"""
return self.ambient_hecke_module()
def ambient_module(self):
r"""
Synonym for ambient_hecke_module. Return the ambient module associated to this module.
EXAMPLE::
sage: CuspForms(1, 12).ambient_module()
Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field
sage: sage.modular.hecke.module.HeckeModule_free_module(QQ, 10, 3).ambient_module()
Traceback (most recent call last):
...
NotImplementedError
"""
return self.ambient_hecke_module()
def ambient_hecke_module(self):
r"""
Return the ambient module associated to this module. As this is an
abstract base class, return NotImplementedError.
EXAMPLE::
sage: sage.modular.hecke.module.HeckeModule_free_module(QQ, 10, 3).ambient_hecke_module()
Traceback (most recent call last):
...
NotImplementedError
"""
raise NotImplementedError
def atkin_lehner_operator(self, d=None):
"""
Return the Atkin-Lehner operator `W_d` on this space, if
defined, where `d` is a divisor of the level `N`
such that `N/d` and `d` are coprime.
EXAMPLES::
sage: M = ModularSymbols(11)
sage: w = M.atkin_lehner_operator()
sage: w
Hecke module morphism Atkin-Lehner operator W_11 defined by the matrix
[-1 0 0]
[ 0 -1 0]
[ 0 0 -1]
Domain: Modular Symbols space of dimension 3 for Gamma_0(11) of weight ...
Codomain: Modular Symbols space of dimension 3 for Gamma_0(11) of weight ...
sage: M = ModularSymbols(Gamma1(13))
sage: w = M.atkin_lehner_operator()
sage: w.fcp('x')
(x - 1)^7 * (x + 1)^8
::
sage: M = ModularSymbols(33)
sage: S = M.cuspidal_submodule()
sage: S.atkin_lehner_operator()
Hecke module morphism Atkin-Lehner operator W_33 defined by the matrix
[ 0 -1 0 1 -1 0]
[ 0 -1 0 0 0 0]
[ 0 -1 0 0 -1 1]
[ 1 -1 0 0 -1 0]
[ 0 0 0 0 -1 0]
[ 0 -1 1 0 -1 0]
Domain: Modular Symbols subspace of dimension 6 of Modular Symbols space ...
Codomain: Modular Symbols subspace of dimension 6 of Modular Symbols space ...
::
sage: S.atkin_lehner_operator(3)
Hecke module morphism Atkin-Lehner operator W_3 defined by the matrix
[ 0 1 0 -1 1 0]
[ 0 1 0 0 0 0]
[ 0 1 0 0 1 -1]
[-1 1 0 0 1 0]
[ 0 0 0 0 1 0]
[ 0 1 -1 0 1 0]
Domain: Modular Symbols subspace of dimension 6 of Modular Symbols space ...
Codomain: Modular Symbols subspace of dimension 6 of Modular Symbols space ...
::
sage: N = M.new_submodule()
sage: N.atkin_lehner_operator()
Hecke module morphism Atkin-Lehner operator W_33 defined by the matrix
[ 1 2/5 4/5]
[ 0 -1 0]
[ 0 0 -1]
Domain: Modular Symbols subspace of dimension 3 of Modular Symbols space ...
Codomain: Modular Symbols subspace of dimension 3 of Modular Symbols space ...
"""
if d is None:
d = self.level()
d = int(d)
if self.level() % d != 0:
raise ArithmeticError("d (=%s) must be a divisor of the level (=%s)"%(d,self.level()))
N = self.level()
for p, e in arith.factor(d):
v = arith.valuation(N, p)
if e < v:
d *= p**(v-e)
d = int(d)
try:
return self.__atkin_lehner_operator[d]
except AttributeError:
self.__atkin_lehner_operator = {}
except KeyError:
pass
Wmat = self._compute_atkin_lehner_matrix(d)
H = self.endomorphism_ring()
W = H(Wmat, "Atkin-Lehner operator W_%s"%d)
self.__atkin_lehner_operator[d] = W
return W
def basis(self):
"""
Returns a basis for self.
EXAMPLES::
sage: m = ModularSymbols(43)
sage: m.basis()
((1,0), (1,31), (1,32), (1,38), (1,39), (1,40), (1,41))
"""
try:
return self.__basis
except AttributeError:
self.__basis = self.gens()
return self.__basis
def basis_matrix(self):
r"""
Return the matrix of the basis vectors of self (as vectors in some
ambient module)
EXAMPLE::
sage: CuspForms(1, 12).basis_matrix()
[1 0]
"""
return self.free_module().basis_matrix()
def coordinate_vector(self, x):
"""
Write x as a vector with respect to the basis given by
self.basis().
EXAMPLES::
sage: S = ModularSymbols(11,2).cuspidal_submodule()
sage: S.0
(1,8)
sage: S.basis()
((1,8), (1,9))
sage: S.coordinate_vector(S.0)
(1, 0)
"""
return self.free_module().coordinate_vector(x.element())
def decomposition(self, bound=None, anemic=True, height_guess=1, sort_by_basis = False,
proof=None):
"""
Returns the maximal decomposition of this Hecke module under the
action of Hecke operators of index coprime to the level. This is
the finest decomposition of self that we can obtain using factors
obtained by taking kernels of Hecke operators.
Each factor in the decomposition is a Hecke submodule obtained as
the kernel of `f(T_n)^r` acting on self, where n is
coprime to the level and `r=1`. If anemic is False, instead
choose `r` so that `f(X)^r` exactly divides the
characteristic polynomial.
INPUT:
- ``anemic`` - bool (default: True), if True, use only
Hecke operators of index coprime to the level.
- ``bound`` - int or None, (default: None). If None,
use all Hecke operators up to the Sturm bound, and hence obtain the
same result as one would obtain by using every element of the Hecke
ring. If a fixed integer, decompose using only Hecke operators
`T_p`, with `p` prime, up to bound.
- ``sort_by_basis`` - bool (default: ``False``); If True the resulting
decomposition will be sorted as if it was free modules, ignoring the
Hecke module structure. This will save a lot of time.
OUTPUT:
- ``list`` - a list of subspaces of self.
EXAMPLES::
sage: ModularSymbols(17,2).decomposition()
[
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(17) of weight 2 with sign 0 over Rational Field,
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
]
sage: ModularSymbols(Gamma1(10),4).decomposition()
[
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 and over Rational Field,
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 and over Rational Field,
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 and over Rational Field,
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 and over Rational Field,
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 and over Rational Field,
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 and over Rational Field
]
sage: ModularSymbols(GammaH(12, [11])).decomposition()
[
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 and over Rational Field,
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 and over Rational Field,
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 and over Rational Field,
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 and over Rational Field,
Modular Symbols subspace of dimension 5 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 and over Rational Field
]
TESTS::
sage: M = ModularSymbols(1000,2,sign=1).new_subspace().cuspidal_subspace()
sage: M.decomposition(3, sort_by_basis = True)
[
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field,
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field,
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field,
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field,
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field,
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field
]
"""
if not isinstance(anemic, bool):
raise TypeError("anemic must be of type bool.")
key = (bound, anemic)
try:
if self.__decomposition[key] is not None:
return self.__decomposition[key]
except AttributeError:
self.__decomposition = {}
except KeyError:
pass
if self.rank() == 0: