# HG changeset patch
# User Robert Bradshaw <robertwb@math.washington.edu>
# Date 1252561710 25200
# Node ID 282ed7ea92458f757aeae4b8940ce7819f8df959
# Parent 92b42ec2270c48679428f4da160e1f11847cef0f
#6911 Faster basis for Hecke algebras.
diff -r 92b42ec2270c -r 282ed7ea9245 sage/matrix/matrix2.pyx
a
|
b
|
|
1325 | 1325 | for i from 0 <= i < self._nrows: |
1326 | 1326 | s = s + self.get_unsafe(i,i) |
1327 | 1327 | return s |
| 1328 | |
| 1329 | def trace_of_product(self, Matrix other): |
| 1330 | """ |
| 1331 | Returns the trace of self * other without computing the entire product. |
| 1332 | |
| 1333 | EXAMPLES:: |
| 1334 | |
| 1335 | sage: M = random_matrix(ZZ, 10, 20) |
| 1336 | sage: N = random_matrix(ZZ, 20, 10) |
| 1337 | sage: M.trace_of_product(N) |
| 1338 | -1629 |
| 1339 | sage: (M*N).trace() |
| 1340 | -1629 |
| 1341 | """ |
| 1342 | if self._nrows != other._ncols or other._nrows != self._ncols: |
| 1343 | raise ArithmeticError, "incompatible dimensions" |
| 1344 | s = self._base_ring(0) |
| 1345 | for i from 0 <= i < self._nrows: |
| 1346 | for j from 0 <= j < self._ncols: |
| 1347 | s += self.get_unsafe(i, j) * other.get_unsafe(j, i) |
| 1348 | return s |
1328 | 1349 | |
1329 | 1350 | ##################################################################################### |
1330 | 1351 | # Generic Hessenberg Form and charpoly algorithm |
diff -r 92b42ec2270c -r 282ed7ea9245 sage/modular/hecke/algebra.py
a
|
b
|
|
31 | 31 | import math |
32 | 32 | import weakref |
33 | 33 | |
34 | | import sage.rings.all as rings |
35 | 34 | import sage.rings.arith as arith |
36 | 35 | import sage.rings.infinity |
37 | 36 | import sage.misc.latex as latex |
… |
… |
|
43 | 42 | from sage.matrix.constructor import matrix |
44 | 43 | from sage.rings.arith import lcm |
45 | 44 | from sage.matrix.matrix_space import MatrixSpace |
| 45 | from sage.rings.all import ZZ, QQ |
46 | 46 | |
47 | 47 | def is_HeckeAlgebra(x): |
48 | 48 | r""" |
… |
… |
|
168 | 168 | [0 1] |
169 | 169 | [0 5]] |
170 | 170 | """ |
171 | | QQ = rings.QQ |
172 | | ZZ = rings.ZZ |
173 | 171 | d = M.rank() |
174 | 172 | VV = QQ**(d**2) |
175 | 173 | WW = ZZ**(d**2) |
… |
… |
|
217 | 215 | [0 1] |
218 | 216 | [0 5]] |
219 | 217 | """ |
220 | | QQ = rings.QQ |
221 | | ZZ = rings.ZZ |
222 | 218 | d = M.rank() |
223 | 219 | VV = QQ**(d**2) |
224 | 220 | WW = ZZ**(d**2) |
… |
… |
|
520 | 516 | try: |
521 | 517 | return self.__basis_cache |
522 | 518 | except AttributeError: |
523 | | self.__basis_cache=_heckebasis(self.__M) |
| 519 | pass |
| 520 | level = self.level() |
| 521 | bound = self.__M.hecke_bound() |
| 522 | dim = self.__M.rank() |
| 523 | span = [self.hecke_operator(n) for n in range(2, bound+1) if not self.is_anemic() or gcd(n, level) == 1] |
| 524 | rand_max = 5 |
| 525 | while True: |
| 526 | # Project the full Hecke module to a random submodule to ease the HNF reduction. |
| 527 | v = (ZZ**dim).random_element(x=rand_max) |
| 528 | proj_span = matrix([T.matrix()*v for T in span])._clear_denom()[0] |
| 529 | proj_basis = proj_span.hermite_form() |
| 530 | if proj_basis[dim-1] == 0: |
| 531 | # We got unlucky, choose another projection. |
| 532 | rand_max *= 2 |
| 533 | continue |
| 534 | # Lift the projected basis to a basis in the Hecke algebra. |
| 535 | trans = proj_span.solve_left(proj_basis) |
| 536 | self.__basis_cache = [sum(c*T for c,T in zip(row,span) if c != 0) for row in trans[:dim]] |
524 | 537 | return self.__basis_cache |
525 | 538 | |
526 | 539 | def discriminant(self): |
… |
… |
|
535 | 548 | *Conjectures about discriminants of Hecke algebras of prime |
536 | 549 | level*, Springer LNCS 3076. |
537 | 550 | |
538 | | Not implemented at present. |
539 | | |
540 | 551 | EXAMPLE:: |
541 | 552 | |
542 | 553 | sage: BrandtModule(3, 4).hecke_algebra().discriminant() |
543 | | Traceback (most recent call last): |
544 | | ... |
545 | | NotImplementedError |
| 554 | 1 |
| 555 | sage: ModularSymbols(65, sign=1).cuspidal_submodule().hecke_algebra().discriminant() |
| 556 | 6144 |
546 | 557 | """ |
547 | | raise NotImplementedError |
| 558 | try: |
| 559 | return self.__disc |
| 560 | except AttributeError: |
| 561 | pass |
| 562 | basis = self.basis() |
| 563 | d = len(self.basis()) |
| 564 | trace_matrix = matrix(ZZ, d) |
| 565 | for i in range(d): |
| 566 | for j in range(i+1): |
| 567 | trace_matrix[i,j] = trace_matrix[j,i] = basis[i].matrix().trace_of_product(basis[j].matrix()) |
| 568 | self.__disc = trace_matrix.det() |
| 569 | return self.__disc |
548 | 570 | |
549 | 571 | def gens(self): |
550 | 572 | r""" |
diff -r 92b42ec2270c -r 282ed7ea9245 sage/modular/hecke/ambient_module.py
a
|
b
|
|
477 | 477 | generate the full Hecke algebra as a module over the base ring. Note |
478 | 478 | that we include the `n` with `n` not coprime to the level. |
479 | 479 | |
480 | | At present this returns an unproven guess which appears to be valid for |
481 | | `M_k(\Gamma_0(N))`, where k and N are the weight and level of self. (It |
482 | | is clearly valid for *cuspidal* spaces of any fixed character, as a |
483 | | consequence of the Sturm bound theorem.) It returns a hopelessly wrong |
484 | | answer for spaces of full level `\Gamma_1`. |
| 480 | At present this returns an unproven guess for non-cuspidal spaces which |
| 481 | appears to be valid for `M_k(\Gamma_0(N))`, where k and N are the |
| 482 | weight and level of self. (It is clearly valid for *cuspidal* spaces |
| 483 | of any fixed character, as a consequence of the Sturm bound theorem.) |
| 484 | It returns a hopelessly wrong answer for spaces of full level |
| 485 | `\Gamma_1`. |
485 | 486 | |
486 | 487 | TODO: Get rid of this dreadful bit of code. |
487 | 488 | |
… |
… |
|
492 | 493 | sage: ModularSymbols(Gamma1(17), 4).hecke_bound() # wrong! |
493 | 494 | 15 |
494 | 495 | """ |
495 | | misc.verbose("WARNING: ambient.py -- hecke_bound; returning unproven guess.") |
496 | | return Gamma0(self.level()).sturm_bound(self.weight()) + 2*Gamma0(self.level()).dimension_eis(self.weight()) + 5 |
| 496 | if self.is_cuspidal(): |
| 497 | return Gamma0(self.level()).sturm_bound(self.weight()) |
| 498 | else: |
| 499 | misc.verbose("WARNING: ambient.py -- hecke_bound; returning unproven guess.") |
| 500 | return Gamma0(self.level()).sturm_bound(self.weight()) + 2*Gamma0(self.level()).dimension_eis(self.weight()) + 5 |
497 | 501 | |
498 | 502 | def hecke_module_of_level(self, level): |
499 | 503 | r""" |
diff -r 92b42ec2270c -r 282ed7ea9245 sage/modular/quatalg/brandt.py
a
|
b
|
|
1176 | 1176 | V = A.kernel() |
1177 | 1177 | self.__eisenstein_subspace = V |
1178 | 1178 | return V |
| 1179 | |
| 1180 | def is_cuspidal(self): |
| 1181 | r""" |
| 1182 | Returns whether self is cuspidal, i.e. has no eisenstein part. |
| 1183 | |
| 1184 | EXAMPLES: |
| 1185 | sage: B = BrandtModule(3, 4) |
| 1186 | sage: B.is_cuspidal() |
| 1187 | False |
| 1188 | sage: B.eisenstein_subspace() |
| 1189 | Brandt module of dimension 1 of level 3*4 of weight 2 over Rational Field |
| 1190 | """ |
| 1191 | return self.eisenstein_subspace().dimension() == 0 |
1179 | 1192 | |
1180 | 1193 | def monodromy_weights(self): |
1181 | 1194 | r""" |