Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/modular/hecke/hecke_operator.py
8820 views
1
"""
2
Hecke operators
3
"""
4
5
#*****************************************************************************
6
# Copyright (C) 2004 William Stein <[email protected]>
7
#
8
# Distributed under the terms of the GNU General Public License (GPL)
9
#
10
# This code is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
# General Public License for more details.
14
#
15
# The full text of the GPL is available at:
16
#
17
# http://www.gnu.org/licenses/
18
#*****************************************************************************
19
20
21
22
import sage.algebras.algebra_element
23
from sage.categories.homset import End
24
import sage.rings.arith as arith
25
from sage.rings.integer import Integer
26
27
import algebra
28
import morphism
29
30
31
def is_HeckeOperator(x):
32
r"""
33
Return True if x is of type HeckeOperator.
34
35
EXAMPLES::
36
37
sage: from sage.modular.hecke.hecke_operator import is_HeckeOperator
38
sage: M = ModularSymbols(Gamma0(7), 4)
39
sage: is_HeckeOperator(M.T(3))
40
True
41
sage: is_HeckeOperator(M.T(3) + M.T(5))
42
False
43
"""
44
return isinstance(x, HeckeOperator)
45
46
def is_HeckeAlgebraElement(x):
47
r"""
48
Return True if x is of type HeckeAlgebraElement.
49
50
EXAMPLES::
51
52
sage: from sage.modular.hecke.hecke_operator import is_HeckeAlgebraElement
53
sage: M = ModularSymbols(Gamma0(7), 4)
54
sage: is_HeckeAlgebraElement(M.T(3))
55
True
56
sage: is_HeckeAlgebraElement(M.T(3) + M.T(5))
57
True
58
"""
59
return isinstance(x, HeckeAlgebraElement)
60
61
class HeckeAlgebraElement(sage.algebras.algebra_element.AlgebraElement):
62
r"""
63
Base class for elements of Hecke algebras.
64
"""
65
def __init__(self, parent):
66
r"""
67
Create an element of a Hecke algebra.
68
69
EXAMPLES::
70
71
sage: R = ModularForms(Gamma0(7), 4).hecke_algebra()
72
sage: sage.modular.hecke.hecke_operator.HeckeAlgebraElement(R) # please don't do this!
73
Generic element of a structure
74
"""
75
if not algebra.is_HeckeAlgebra(parent):
76
raise TypeError, "parent (=%s) must be a Hecke algebra"%parent
77
sage.algebras.algebra_element.AlgebraElement.__init__(self, parent)
78
79
def domain(self):
80
r"""
81
The domain of this operator. This is the Hecke module associated to the
82
parent Hecke algebra.
83
84
EXAMPLE::
85
86
sage: R = ModularForms(Gamma0(7), 4).hecke_algebra()
87
sage: sage.modular.hecke.hecke_operator.HeckeAlgebraElement(R).domain()
88
Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field
89
"""
90
91
return self.parent().module()
92
93
def codomain(self):
94
r"""
95
The codomain of this operator. This is the Hecke module associated to the
96
parent Hecke algebra.
97
98
EXAMPLE::
99
100
sage: R = ModularForms(Gamma0(7), 4).hecke_algebra()
101
sage: sage.modular.hecke.hecke_operator.HeckeAlgebraElement(R).codomain()
102
Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field
103
"""
104
return self.parent().module()
105
106
def hecke_module_morphism(self):
107
"""
108
Return the endomorphism of Hecke modules defined by the matrix
109
attached to this Hecke operator.
110
111
EXAMPLES::
112
113
sage: M = ModularSymbols(Gamma1(13))
114
sage: t = M.hecke_operator(2)
115
sage: t
116
Hecke operator T_2 on Modular Symbols space of dimension 15 for Gamma_1(13) of weight 2 with sign 0 and over Rational Field
117
sage: t.hecke_module_morphism()
118
Hecke module morphism T_2 defined by the matrix
119
[ 2 1 0 0 0 0 0 0 0 0 0 0 0 0 -1]
120
[ 0 2 0 1 0 0 0 -1 0 0 0 0 0 0 0]
121
[ 0 0 2 0 0 1 -1 1 0 -1 0 1 -1 0 0]
122
[ 0 0 0 2 1 0 1 0 0 0 1 -1 0 0 0]
123
[ 0 0 1 0 2 0 0 0 0 1 -1 0 0 0 1]
124
[ 1 0 0 0 0 2 0 0 0 0 0 0 1 0 0]
125
[ 0 0 0 0 0 0 0 1 -1 1 -1 0 -1 1 1]
126
[ 0 0 0 0 0 0 0 -1 1 1 0 0 -1 1 0]
127
[ 0 0 0 0 0 0 -1 -1 0 1 -1 -1 1 0 -1]
128
[ 0 0 0 0 0 0 -2 0 2 -2 0 2 -2 1 -1]
129
[ 0 0 0 0 0 0 0 0 2 -1 1 0 0 1 -1]
130
[ 0 0 0 0 0 0 -1 1 2 -1 1 0 -2 2 0]
131
[ 0 0 0 0 0 0 0 0 1 1 0 -1 0 0 0]
132
[ 0 0 0 0 0 0 -1 1 1 0 1 1 -1 0 0]
133
[ 0 0 0 0 0 0 2 0 0 0 2 -1 0 1 -1]
134
Domain: Modular Symbols space of dimension 15 for Gamma_1(13) of weight ...
135
Codomain: Modular Symbols space of dimension 15 for Gamma_1(13) of weight ...
136
"""
137
try:
138
return self.__hecke_module_morphism
139
except AttributeError:
140
T = self.matrix()
141
M = self.domain()
142
H = End(M)
143
if isinstance(self, HeckeOperator):
144
name = "T_%s"%self.index()
145
else:
146
name = ""
147
self.__hecke_module_morphism = morphism.HeckeModuleMorphism_matrix(H, T, name)
148
return self.__hecke_module_morphism
149
150
def _add_(self, other):
151
"""
152
Add self to other.
153
154
EXAMPLES::
155
156
sage: M = ModularSymbols(11)
157
sage: t = M.hecke_operator(2)
158
sage: t
159
Hecke operator T_2 on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
160
sage: t + t # indirect doctest
161
Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field defined by:
162
[ 6 0 -2]
163
[ 0 -4 0]
164
[ 0 0 -4]
165
166
We can also add Hecke operators with different indexes::
167
168
sage: M = ModularSymbols(Gamma1(6),4)
169
sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3)
170
sage: t2 + t3
171
Hecke operator on Modular Symbols space of dimension 6 for Gamma_1(6) of weight 4 with sign 0 and over Rational Field defined by:
172
[ 35 0 0 -8/7 24/7 -16/7]
173
[ 4 28 0 19/7 -57/7 38/7]
174
[ 18 0 9 -40/7 22/7 18/7]
175
[ 0 18 4 -22/7 -18/7 54/7]
176
[ 0 18 4 13/7 -53/7 54/7]
177
[ 0 18 4 13/7 -18/7 19/7]
178
sage: (t2 - t3).charpoly('x')
179
x^6 + 36*x^5 + 104*x^4 - 3778*x^3 + 7095*x^2 - 3458*x
180
"""
181
return self.parent()(self.matrix() + other.matrix(), check=False)
182
183
def __call__(self, x):
184
"""
185
Apply this Hecke operator to `x`.
186
187
EXAMPLES::
188
189
sage: M = ModularSymbols(11); t2 = M.hecke_operator(2)
190
sage: t2(M.gen(0))
191
3*(1,0) - (1,9)
192
193
::
194
195
sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3)
196
sage: t3(t2(M.gen(0)))
197
12*(1,0) - 2*(1,9)
198
sage: (t3*t2)(M.gen(0))
199
12*(1,0) - 2*(1,9)
200
"""
201
T = self.hecke_module_morphism()
202
return T(x)
203
204
def __rmul__(self, left):
205
"""
206
EXAMPLES::
207
208
sage: M = ModularSymbols(11); t2 = M.hecke_operator(2)
209
sage: 2*t2
210
Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field defined by:
211
[ 6 0 -2]
212
[ 0 -4 0]
213
[ 0 0 -4]
214
"""
215
return self.parent()(left * self.matrix())
216
217
def _sub_(self, other):
218
"""
219
Compute the difference of self and other, where other has already been
220
coerced into the parent of self.
221
222
EXAMPLES::
223
224
sage: M = ModularSymbols(Gamma1(6),4)
225
sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3)
226
sage: t2 - t3 # indirect doctest
227
Hecke operator on Modular Symbols space of dimension 6 for Gamma_1(6) of weight 4 with sign 0 and over Rational Field defined by:
228
[ -19 0 0 4/7 -12/7 8/7]
229
[ 4 -26 0 -17/7 51/7 -34/7]
230
[ -18 0 7 -12/7 -6/7 18/7]
231
[ 0 -18 4 -16/7 34/7 -18/7]
232
[ 0 -18 4 -23/7 41/7 -18/7]
233
[ 0 -18 4 -23/7 34/7 -11/7]
234
"""
235
return self.parent()(self.matrix() - other.matrix(), check=False)
236
237
def apply_sparse(self, x):
238
"""
239
Apply this Hecke operator to x, where we avoid computing the matrix
240
of x if possible.
241
242
EXAMPLES::
243
244
sage: M = ModularSymbols(11)
245
sage: T = M.hecke_operator(23)
246
sage: T.apply_sparse(M.gen(0))
247
24*(1,0) - 5*(1,9)
248
"""
249
if x not in self.domain():
250
raise TypeError, "x (=%s) must be in %s"%(x, self.domain())
251
# Generic implementation which doesn't actually do anything
252
# special regarding sparseness. Override this for speed.
253
T = self.hecke_module_morphism()
254
return T(x)
255
256
def charpoly(self, var='x'):
257
"""
258
Return the characteristic polynomial of this Hecke operator.
259
260
INPUT:
261
262
263
- ``var`` - string (default: 'x')
264
265
266
OUTPUT: a monic polynomial in the given variable.
267
268
EXAMPLES::
269
270
sage: M = ModularSymbols(Gamma1(6),4)
271
sage: M.hecke_operator(2).charpoly('x')
272
x^6 - 14*x^5 + 29*x^4 + 172*x^3 - 124*x^2 - 320*x + 256
273
"""
274
return self.matrix().charpoly(var)
275
276
def decomposition(self):
277
"""
278
Decompose the Hecke module under the action of this Hecke
279
operator.
280
281
EXAMPLES::
282
283
sage: M = ModularSymbols(11)
284
sage: t2 = M.hecke_operator(2)
285
sage: t2.decomposition()
286
[
287
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field,
288
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
289
]
290
291
::
292
293
sage: M = ModularSymbols(33, sign=1).new_submodule()
294
sage: T = M.hecke_operator(2)
295
sage: T.decomposition()
296
[
297
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field,
298
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field
299
]
300
"""
301
try:
302
return self.__decomposition
303
except AttributeError:
304
pass
305
if isinstance(self, HeckeOperator) and \
306
arith.gcd(self.index(), self.domain().level()) == 1:
307
D = self.hecke_module_morphism().decomposition(is_diagonalizable=True)
308
else:
309
# TODO: There are other weaker hypotheses that imply diagonalizability.
310
D = self.hecke_module_morphism().decomposition()
311
D.sort()
312
D.set_immutable()
313
self.__decomposition = D
314
return D
315
316
def det(self):
317
"""
318
Return the determinant of this Hecke operator.
319
320
EXAMPLES::
321
322
sage: M = ModularSymbols(23)
323
sage: T = M.hecke_operator(3)
324
sage: T.det()
325
100
326
"""
327
return self.hecke_module_morphism().det()
328
329
def fcp(self, var='x'):
330
"""
331
Return the factorization of the characteristic polynomial of this
332
Hecke operator.
333
334
EXAMPLES::
335
336
sage: M = ModularSymbols(23)
337
sage: T = M.hecke_operator(3)
338
sage: T.fcp('x')
339
(x - 4) * (x^2 - 5)^2
340
"""
341
return self.hecke_module_morphism().fcp(var)
342
343
def image(self):
344
"""
345
Return the image of this Hecke operator.
346
347
EXAMPLES::
348
349
sage: M = ModularSymbols(23)
350
sage: T = M.hecke_operator(3)
351
sage: T.fcp('x')
352
(x - 4) * (x^2 - 5)^2
353
sage: T.image()
354
Modular Symbols subspace of dimension 5 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
355
sage: (T-4).image()
356
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
357
sage: (T**2-5).image()
358
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
359
"""
360
return self.hecke_module_morphism().image()
361
362
def kernel(self):
363
"""
364
Return the kernel of this Hecke operator.
365
366
EXAMPLES::
367
368
sage: M = ModularSymbols(23)
369
sage: T = M.hecke_operator(3)
370
sage: T.fcp('x')
371
(x - 4) * (x^2 - 5)^2
372
sage: T.kernel()
373
Modular Symbols subspace of dimension 0 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
374
sage: (T-4).kernel()
375
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
376
sage: (T**2-5).kernel()
377
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
378
"""
379
return self.hecke_module_morphism().kernel()
380
381
def trace(self):
382
"""
383
Return the trace of this Hecke operator.
384
385
::
386
387
sage: M = ModularSymbols(1,12)
388
sage: T = M.hecke_operator(2)
389
sage: T.trace()
390
2001
391
"""
392
return self.hecke_module_morphism().trace()
393
394
def __getitem__(self, ij):
395
"""
396
EXAMPLE::
397
398
sage: M = ModularSymbols(1,12)
399
sage: T = M.hecke_operator(2).matrix_form()
400
sage: T[0,0]
401
-24
402
"""
403
return self.matrix()[ij]
404
405
406
class HeckeAlgebraElement_matrix(HeckeAlgebraElement):
407
r"""
408
An element of the Hecke algebra represented by a matrix.
409
"""
410
def __init__(self, parent, A):
411
r"""
412
Initialise an element from a matrix. This *must* be over the base ring
413
of self and have the right size.
414
415
This is a bit overkill as similar checks will be performed by the call
416
and coerce methods of the parent of self, but it can't hurt to be
417
paranoid. Any fancy coercion / base_extension / etc happens there, not
418
here.
419
420
TESTS::
421
422
sage: T = ModularForms(Gamma0(7), 4).hecke_algebra()
423
sage: M = sage.modular.hecke.hecke_operator.HeckeAlgebraElement_matrix(T, matrix(QQ,3,[2,3,0,1,2,3,7,8,9])); M
424
Hecke operator on Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field defined by:
425
[2 3 0]
426
[1 2 3]
427
[7 8 9]
428
sage: loads(dumps(M)) == M
429
True
430
sage: sage.modular.hecke.hecke_operator.HeckeAlgebraElement_matrix(T, matrix(Integers(2),3,[2,3,0,1,2,3,7,8,9]))
431
Traceback (most recent call last):
432
...
433
TypeError: base ring of matrix (Ring of integers modulo 2) does not match base ring of space (Rational Field)
434
sage: sage.modular.hecke.hecke_operator.HeckeAlgebraElement_matrix(T, matrix(QQ,2,[2,3,0,1]))
435
Traceback (most recent call last):
436
...
437
TypeError: A must be a square matrix of rank 3
438
"""
439
HeckeAlgebraElement.__init__(self, parent)
440
from sage.matrix.matrix import is_Matrix
441
if not is_Matrix(A):
442
raise TypeError("A must be a matrix")
443
if not A.base_ring() == self.parent().base_ring():
444
raise TypeError, "base ring of matrix (%s) does not match base ring of space (%s)" % (A.base_ring(), self.parent().base_ring())
445
if not A.nrows() == A.ncols() == self.parent().module().rank():
446
raise TypeError, "A must be a square matrix of rank %s" % self.parent().module().rank()
447
self.__matrix = A
448
449
def __cmp__(self, other):
450
r"""
451
Compare self to other, where the coercion model has already ensured
452
that other has the same parent as self.
453
454
EXAMPLES::
455
456
sage: T = ModularForms(SL2Z, 12).hecke_algebra()
457
sage: m = T(matrix(QQ, 2, [1,2,0,1]), check=False); n = T.hecke_operator(14)
458
sage: m == n
459
False
460
sage: m == n.matrix_form()
461
False
462
sage: n.matrix_form() == T(matrix(QQ, 2, [4051542498456, 384163586352000, 0, 401856]), check=False)
463
True
464
"""
465
if not isinstance(other, HeckeAlgebraElement_matrix):
466
if isinstance(other, HeckeOperator):
467
return cmp(self, other.matrix_form())
468
else:
469
raise RuntimeError, "Bug in coercion code" # can't get here.
470
return cmp(self.__matrix, other.__matrix)
471
472
def _repr_(self):
473
r"""
474
String representation of self.
475
476
EXAMPLES::
477
478
sage: M = ModularSymbols(1,12)
479
sage: M.hecke_operator(2).matrix_form()._repr_()
480
'Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field defined by:\n[ -24 0 0]\n[ 0 -24 0]\n[4860 0 2049]'
481
sage: ModularForms(Gamma0(100)).hecke_operator(4).matrix_form()._repr_()
482
'Hecke operator on Modular Forms space of dimension 24 for Congruence Subgroup Gamma0(100) of weight 2 over Rational Field defined by:\n24 x 24 dense matrix over Rational Field'
483
"""
484
return "Hecke operator on %s defined by:\n%s"%(self.parent().module(), self.__matrix)
485
486
def _latex_(self):
487
r"""
488
Latex representation of self (just prints the matrix)
489
490
EXAMPLE::
491
492
sage: M = ModularSymbols(1,12)
493
sage: M.hecke_operator(2).matrix_form()._latex_()
494
'\\left(\\begin{array}{rrr}\n-24 & 0 & 0 \\\\\n0 & -24 & 0 \\\\\n4860 & 0 & 2049\n\\end{array}\\right)'
495
"""
496
return self.__matrix._latex_()
497
498
def matrix(self):
499
"""
500
Return the matrix that defines this Hecke algebra element.
501
502
EXAMPLES::
503
504
sage: M = ModularSymbols(1,12)
505
sage: T = M.hecke_operator(2).matrix_form()
506
sage: T.matrix()
507
[ -24 0 0]
508
[ 0 -24 0]
509
[4860 0 2049]
510
"""
511
return self.__matrix
512
513
def _mul_(self, other):
514
r"""
515
Multiply self by other (which has already been coerced into an element
516
of the parent of self).
517
518
EXAMPLES::
519
520
sage: M = ModularSymbols(1,12)
521
sage: T = M.hecke_operator(2).matrix_form()
522
sage: T * T # indirect doctest
523
Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field defined by:
524
[ 576 0 0]
525
[ 0 576 0]
526
[9841500 0 4198401]
527
"""
528
return self.parent()(other.matrix() * self.matrix(), check=False)
529
530
531
class DiamondBracketOperator(HeckeAlgebraElement_matrix):
532
r"""
533
The diamond bracket operator `\langle d \rangle` for some `d \in \ZZ /
534
N\ZZ` (which need not be a unit, although if it is not, the operator will
535
be zero).
536
"""
537
def __init__(self, parent, d):
538
r"""
539
Standard init function.
540
541
EXAMPLE::
542
543
sage: M = ModularSymbols(Gamma1(5),6)
544
sage: d = M.diamond_bracket_operator(2); d # indirect doctest
545
Diamond bracket operator <2> on Modular Symbols space of dimension 10 for Gamma_1(5) of weight 6 with sign 0 and over Rational Field
546
sage: type(d)
547
<class 'sage.modular.hecke.hecke_operator.DiamondBracketOperator'>
548
sage: d.matrix()
549
[ 0 1 0 0 0 0 0 0 0 0]
550
[ 1 0 0 0 0 0 0 0 0 0]
551
[ 0 0 0 0 0 0 0 1 0 0]
552
[ 0 0 -8/17 -1 14/17 11/17 0 -8/17 14/17 11/17]
553
[ 0 0 0 0 0 0 0 0 1 0]
554
[ 0 0 0 0 0 0 0 0 0 1]
555
[ 0 0 16/17 0 -11/17 12/17 -1 16/17 -11/17 12/17]
556
[ 0 0 1 0 0 0 0 0 0 0]
557
[ 0 0 0 0 1 0 0 0 0 0]
558
[ 0 0 0 0 0 1 0 0 0 0]
559
sage: d**4 == 1
560
True
561
"""
562
self.__d = d
563
A = parent.diamond_bracket_matrix(d)
564
HeckeAlgebraElement_matrix.__init__(self, parent, A)
565
566
def _repr_(self):
567
r"""
568
EXAMPLE::
569
570
sage: ModularSymbols(Gamma1(5), 6).diamond_bracket_operator(2)._repr_()
571
'Diamond bracket operator <2> on Modular Symbols space of dimension 10 for Gamma_1(5) of weight 6 with sign 0 and over Rational Field'
572
"""
573
return "Diamond bracket operator <%s> on %s" % (self.__d, self.domain())
574
575
def _latex_(self):
576
r"""
577
EXAMPLE::
578
579
sage: latex(ModularSymbols(Gamma1(5), 12).diamond_bracket_operator(2)) # indirect doctest
580
\langle 2 \rangle
581
"""
582
return r"\langle %s \rangle" % self.__d
583
584
class HeckeOperator(HeckeAlgebraElement):
585
r"""
586
The Hecke operator `T_n` for some `n` (which need not be coprime to the
587
level). The matrix is not computed until it is needed.
588
"""
589
def __init__(self, parent, n):
590
"""
591
EXAMPLES::
592
593
sage: M = ModularSymbols(11)
594
sage: H = M.hecke_operator(2005); H
595
Hecke operator T_2005 on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
596
sage: H == loads(dumps(H))
597
True
598
599
We create a Hecke operator of large index (greater than 32 bits)::
600
601
sage: M1 = ModularSymbols(21,2)
602
sage: M1.hecke_operator(13^9)
603
Hecke operator T_10604499373 on Modular Symbols space of dimension 5 for Gamma_0(21) of weight 2 with sign 0 over Rational Field
604
"""
605
HeckeAlgebraElement.__init__(self, parent)
606
if not isinstance(n, (int,long,Integer)):
607
raise TypeError, "n must be an int"
608
self.__n = int(n)
609
610
def __cmp__(self, other):
611
r"""
612
Compare self and other (where the coercion model has already ensured
613
that self and other have the same parent). Hecke operators on the same
614
space compare as equal if and only if their matrices are equal, so we
615
check if the indices are the same and if not we compute the matrices
616
(which is potentially expensive).
617
618
EXAMPLES::
619
620
sage: M = ModularSymbols(Gamma0(7), 4)
621
sage: m = M.hecke_operator(3)
622
sage: m == m
623
True
624
sage: m == 2*m
625
False
626
sage: m == M.hecke_operator(5)
627
False
628
629
These last two tests involve a coercion::
630
631
sage: m == m.matrix_form()
632
True
633
sage: m == m.matrix()
634
False
635
"""
636
637
if not isinstance(other, HeckeOperator):
638
if isinstance(other, HeckeAlgebraElement_matrix):
639
return cmp(self.matrix_form(), other)
640
else:
641
raise RuntimeError, "Bug in coercion code" # can't get here
642
643
if self.__n == other.__n:
644
return 0
645
return cmp(self.matrix(), other.matrix())
646
647
def _repr_(self):
648
r"""
649
String representation of self
650
651
EXAMPLE::
652
653
sage: ModularSymbols(Gamma0(7), 4).hecke_operator(6)._repr_()
654
'Hecke operator T_6 on Modular Symbols space of dimension 4 for Gamma_0(7) of weight 4 with sign 0 over Rational Field'
655
"""
656
return "Hecke operator T_%s on %s"%(self.__n, self.domain())
657
658
def _latex_(self):
659
r"""
660
LaTeX representation of self
661
662
EXAMPLE::
663
664
sage: ModularSymbols(Gamma0(7), 4).hecke_operator(6)._latex_()
665
'T_{6}'
666
"""
667
return "T_{%s}"%self.__n
668
669
def _mul_(self, other):
670
"""
671
Multiply this Hecke operator by another element of the same algebra. If
672
the other element is of the form `T_m` for some m, we check whether the
673
product is equal to `T_{mn}` and return that; if the product is not
674
(easily seen to be) of the form `T_{mn}`, then we calculate the product
675
of the two matrices and return a Hecke algebra element defined by that.
676
677
EXAMPLES: We create the space of modular symbols of level
678
`11` and weight `2`, then compute `T_2`
679
and `T_3` on it, along with their composition.
680
681
::
682
683
sage: M = ModularSymbols(11)
684
sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3)
685
sage: t2*t3 # indirect doctest
686
Hecke operator T_6 on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
687
sage: t3.matrix() * t2.matrix()
688
[12 0 -2]
689
[ 0 2 0]
690
[ 0 0 2]
691
sage: (t2*t3).matrix()
692
[12 0 -2]
693
[ 0 2 0]
694
[ 0 0 2]
695
696
When we compute `T_2^5` the result is not (easily seen to
697
be) a Hecke operator of the form `T_n`, so it is returned
698
as a Hecke module homomorphism defined as a matrix::
699
700
sage: t2**5
701
Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field defined by:
702
[243 0 -55]
703
[ 0 -32 0]
704
[ 0 0 -32]
705
"""
706
if isinstance(other, HeckeOperator) and other.parent() == self.parent():
707
n = None
708
if arith.gcd(self.__n, other.__n) == 1:
709
n = self.__n * other.__n
710
else:
711
P = set(arith.prime_divisors(self.domain().level()))
712
if P.issubset(set(arith.prime_divisors(self.__n))) and \
713
P.issubset(set(arith.prime_divisors(other.__n))):
714
n = self.__n * other.__n
715
if n:
716
return HeckeOperator(self.parent(), n)
717
# otherwise
718
return self.matrix_form() * other
719
720
def index(self):
721
"""
722
Return the index of this Hecke operator, i.e., if this Hecke
723
operator is `T_n`, return the int `n`.
724
725
EXAMPLES::
726
727
sage: T = ModularSymbols(11).hecke_operator(17)
728
sage: T.index()
729
17
730
"""
731
return self.__n
732
733
def matrix(self, *args, **kwds):
734
"""
735
Return the matrix underlying this Hecke operator.
736
737
EXAMPLES::
738
739
sage: T = ModularSymbols(11).hecke_operator(17)
740
sage: T.matrix()
741
[18 0 -4]
742
[ 0 -2 0]
743
[ 0 0 -2]
744
"""
745
try:
746
return self.__matrix
747
except AttributeError:
748
self.__matrix = self.parent().hecke_matrix(self.__n, *args, **kwds)
749
return self.__matrix
750
751
def matrix_form(self):
752
"""
753
Return the matrix form of this element of a Hecke algebra.
754
755
::
756
757
sage: T = ModularSymbols(11).hecke_operator(17)
758
sage: T.matrix_form()
759
Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field defined by:
760
[18 0 -4]
761
[ 0 -2 0]
762
[ 0 0 -2]
763
"""
764
try:
765
return self.__matrix_form
766
except AttributeError:
767
self.__matrix_form = self.parent()(self.matrix(), check=False)
768
return self.__matrix_form
769
770
771