# HG changeset patch
# User Rob Beezer <beezer@ups.edu>
# Date 1264309004 28800
# Node ID fd30b4d4509853ce1580103dd09f634e3ef79c3a
# Parent 6c4190c4ba571ea4615296cce5a44a3d87c2cd0c
[mq]: 8018-modularform-eigen
diff -r 6c4190c4ba57 -r fd30b4d45098 sage/modular/modform/numerical.py
a
|
b
|
|
18 | 18 | from sage.misc.misc import verbose |
19 | 19 | from sage.rings.all import CDF, Integer, QQ, next_prime, prime_range |
20 | 20 | from sage.misc.prandom import randint |
| 21 | from sage.matrix.constructor import matrix |
| 22 | |
| 23 | # This variable controls importing the SciPy library sparingly |
| 24 | scipy=None |
21 | 25 | |
22 | 26 | class NumericalEigenforms(SageObject): |
23 | 27 | """ |
… |
… |
|
27 | 31 | |
28 | 32 | - ``group`` - a congruence subgroup of a Dirichlet character of |
29 | 33 | order 1 or 2 |
30 | | |
| 34 | |
31 | 35 | - ``weight`` - an integer >= 2 |
32 | | |
| 36 | |
33 | 37 | - ``eps`` - a small float; abs( ) < eps is what "equal to zero" is |
34 | 38 | interpreted as for floating point numbers. |
35 | | |
| 39 | |
36 | 40 | - ``delta`` - a small-ish float; eigenvalues are considered distinct |
37 | 41 | if their difference has absolute value at least delta |
38 | | |
| 42 | |
39 | 43 | - ``tp`` - use the Hecke operators T_p for p in tp when searching |
40 | 44 | for a random Hecke operator with distinct Hecke eigenvalues. |
41 | | |
| 45 | |
42 | 46 | OUTPUT: |
43 | 47 | |
44 | 48 | A numerical eigenforms object, with the following useful methods: |
… |
… |
|
51 | 55 | [[eigenvalues of T_2], |
52 | 56 | [eigenvalues of T_3], |
53 | 57 | [eigenvalues of T_5], ...] |
54 | | |
| 58 | |
55 | 59 | - :meth:`systems_of_eigenvalues` - a list of the systems of |
56 | 60 | eigenvalues of eigenforms such that the chosen random linear |
57 | 61 | combination of Hecke operators has multiplicity 1 eigenvalues. |
58 | 62 | |
59 | 63 | EXAMPLES:: |
60 | | |
| 64 | |
61 | 65 | sage: n = numerical_eigenforms(23) |
62 | 66 | sage: n == loads(dumps(n)) |
63 | 67 | True |
… |
… |
|
86 | 90 | Create a new space of numerical eigenforms. |
87 | 91 | |
88 | 92 | EXAMPLES:: |
89 | | |
| 93 | |
90 | 94 | sage: numerical_eigenforms(61) # indirect doctest |
91 | 95 | Numerical Hecke eigenvalues for Congruence Subgroup Gamma0(61) of weight 2 |
92 | 96 | """ |
… |
… |
|
107 | 111 | symbols, and -1 otherwise. |
108 | 112 | |
109 | 113 | EXAMPLES:: |
110 | | |
| 114 | |
111 | 115 | sage: n = numerical_eigenforms(23) |
112 | 116 | sage: n.__cmp__(loads(dumps(n))) |
113 | 117 | 0 |
… |
… |
|
124 | 128 | Return the level of this set of modular eigenforms. |
125 | 129 | |
126 | 130 | EXAMPLES:: |
127 | | |
| 131 | |
128 | 132 | sage: n = numerical_eigenforms(61) ; n.level() |
129 | 133 | 61 |
130 | 134 | """ |
… |
… |
|
135 | 139 | Return the weight of this set of modular eigenforms. |
136 | 140 | |
137 | 141 | EXAMPLES:: |
138 | | |
| 142 | |
139 | 143 | sage: n = numerical_eigenforms(61) ; n.weight() |
140 | 144 | 2 |
141 | 145 | """ |
… |
… |
|
146 | 150 | Print string representation of self. |
147 | 151 | |
148 | 152 | EXAMPLES:: |
149 | | |
| 153 | |
150 | 154 | sage: n = numerical_eigenforms(61) ; n |
151 | 155 | Numerical Hecke eigenvalues for Congruence Subgroup Gamma0(61) of weight 2 |
152 | 156 | |
… |
… |
|
162 | 166 | set of modular eigenforms. |
163 | 167 | |
164 | 168 | EXAMPLES:: |
165 | | |
| 169 | |
166 | 170 | sage: n = numerical_eigenforms(61) ; n.modular_symbols() |
167 | 171 | Modular Symbols space of dimension 5 for Gamma_0(61) of weight 2 with sign 1 over Rational Field |
168 | 172 | """ |
… |
… |
|
177 | 181 | return M |
178 | 182 | |
179 | 183 | def _eigenvectors(self): |
180 | | """ |
| 184 | r""" |
181 | 185 | Find numerical approximations to simultaneous eigenvectors in |
182 | 186 | self.modular_symbols() for all T_p in self._tp. |
183 | 187 | |
184 | 188 | EXAMPLES:: |
185 | | |
| 189 | |
186 | 190 | sage: n = numerical_eigenforms(61) |
187 | 191 | sage: n._eigenvectors() # random order |
188 | 192 | [ 1.0 0.289473640239 0.176788851952 0.336707726757 2.4182243084e-16] |
… |
… |
|
190 | 194 | [ 0 0.413171180356 0.141163094698 0.0923242547901 0.707106781187] |
191 | 195 | [ 0 0.826342360711 0.282326189397 0.18464850958 6.79812569682e-16] |
192 | 196 | [ 0 0.2402380858 0.792225196393 0.905370774276 4.70805946682e-16] |
| 197 | |
| 198 | TESTS: |
| 199 | |
| 200 | This tests if this routine selects only eigenvectors with |
| 201 | multiplicity one. Two of the eigenvalues are |
| 202 | (roughly) -92.21 and -90.30 so if we set ``eps = 2.0`` |
| 203 | then they should compare as equal, causing both eigenvectors |
| 204 | to be absent from the matrix returned. The remaining eigenvalues |
| 205 | (ostensibly unique) are visible in the test, which should be |
| 206 | indepedent of which eigenvectors are returned, but it does presume |
| 207 | an ordering of these eigenvectors for the test to succeed. |
| 208 | This exercises a correction in Trac 8018. :: |
| 209 | |
| 210 | sage: n = numerical_eigenforms(61, eps=2.0) |
| 211 | sage: evectors = n._eigenvectors() |
| 212 | sage: evalues = diagonal_matrix(CDF, [-283.0, 108.522012456, 142.0]) |
| 213 | sage: diff = n._hecke_matrix*evectors - evectors*evalues |
| 214 | sage: sum([abs(diff[i,j]) for i in range(5) for j in range(3)]) < 1.0e-9 |
| 215 | True |
193 | 216 | """ |
194 | 217 | try: |
195 | 218 | return self.__eigenvectors |
… |
… |
|
206 | 229 | t += randint(-50,50)*M.T(p).matrix() |
207 | 230 | |
208 | 231 | self._hecke_matrix = t |
209 | | # evals, B = t.change_ring(CDF).right_eigenvectors() |
210 | | from sage.matrix.constructor import matrix |
211 | | spectrum = t.change_ring(CDF).right_eigenvectors() |
212 | | evals = [spectrum[i][0] for i in range(len(spectrum))] |
213 | | B = matrix(CDF, [spectrum[i][1][0] for i in range(len(spectrum))]).transpose() |
214 | | |
215 | | # Find the eigenvalues that occur with multiplicity 1 up |
216 | | # to the given eps. |
| 232 | |
| 233 | global scipy |
| 234 | if scipy is None: |
| 235 | import scipy |
| 236 | import scipy.linalg |
| 237 | evals,eig = scipy.linalg.eig(self._hecke_matrix.numpy(), right=True, left=False) |
| 238 | B = matrix(eig) |
| 239 | v = [CDF(evals[i]) for i in range(len(evals))] |
| 240 | |
| 241 | # Determine the eigenvectors with eigenvalues of multiplicity |
| 242 | # one, with equality controlled by the value of eps |
| 243 | # Keep just these eigenvectors |
217 | 244 | eps = self._eps |
218 | | v = list(evals) |
219 | | v.sort() |
220 | 245 | w = [] |
221 | 246 | for i in range(len(v)): |
222 | 247 | e = v[i] |
223 | 248 | uniq = True |
224 | 249 | for j in range(len(v)): |
225 | | if i != j and abs(e-v[j]) < eps: |
| 250 | if uniq and i != j and abs(e-v[j]) < eps: |
226 | 251 | uniq = False |
227 | 252 | if uniq: |
228 | 253 | w.append(i) |
229 | 254 | self.__eigenvectors = B.matrix_from_columns(w) |
230 | | return B |
| 255 | return self.__eigenvectors |
231 | 256 | |
232 | 257 | def _easy_vector(self): |
233 | 258 | """ |
… |
… |
|
245 | 270 | appropriate multiple. Repeat. |
246 | 271 | |
247 | 272 | EXAMPLES:: |
248 | | |
| 273 | |
249 | 274 | sage: n = numerical_eigenforms(37) |
250 | 275 | sage: n._easy_vector() # slightly random output |
251 | 276 | (1.0, 1.0, 0) |
… |
… |
|
265 | 290 | x = (CDF**E.nrows()).zero_vector() |
266 | 291 | if E.nrows() == 0: |
267 | 292 | return x |
268 | | |
269 | | |
| 293 | |
| 294 | |
270 | 295 | |
271 | 296 | def best_row(M): |
272 | 297 | """ |
… |
… |
|
274 | 299 | with the most entries supported outside [-delta, delta]. |
275 | 300 | |
276 | 301 | EXAMPLES:: |
277 | | |
| 302 | |
278 | 303 | sage: numerical_eigenforms(61)._easy_vector() # indirect doctest |
279 | 304 | (1.0, 1.0, 0, 0, 0) |
280 | 305 | """ |
… |
… |
|
298 | 323 | i, f = best_row(C) |
299 | 324 | x[i] += 1 # simplistic |
300 | 325 | e = x*E |
301 | | |
| 326 | |
302 | 327 | self.__easy_vector = x |
303 | 328 | return x |
304 | 329 | |
… |
… |
|
307 | 332 | Return all eigendata for self._easy_vector(). |
308 | 333 | |
309 | 334 | EXAMPLES:: |
310 | | |
| 335 | |
311 | 336 | sage: numerical_eigenforms(61)._eigendata() # random order |
312 | 337 | ((1.0, 0.668205013164, 0.219198805797, 0.49263343893, 0.707106781187), (1.0, 1.49654668896, 4.5620686498, 2.02990686579, 1.41421356237), [0, 1], (1.0, 1.0)) |
313 | 338 | """ |
… |
… |
|
316 | 341 | except AttributeError: |
317 | 342 | pass |
318 | 343 | x = self._easy_vector() |
319 | | |
| 344 | |
320 | 345 | B = self._eigenvectors() |
321 | 346 | def phi(y): |
322 | 347 | """ |
… |
… |
|
324 | 349 | linear combination of basis vectors. |
325 | 350 | |
326 | 351 | EXAMPLES:: |
327 | | |
| 352 | |
328 | 353 | sage: n = numerical_eigenforms(61) # indirect doctest |
329 | 354 | sage: n._eigendata() # random order |
330 | | ((1.0, 0.668205013164, 0.219198805797, 0.49263343893, 0.707106781187), (1.0, 1.49654668896, 4.5620686498, 2.02990686579, 1.41421356237), [0, 1], (1.0, 1.0)) |
| 355 | ((1.0, 0.668205013164, 0.219198805797, 0.49263343893, 0.707106781187), (1.0, 1.49654668896, 4.5620686498, 2.02990686579, 1.41421356237), [0, 1], (1.0, 1.0)) |
331 | 356 | """ |
332 | 357 | return y.element() * B |
333 | | |
| 358 | |
334 | 359 | phi_x = phi(x) |
335 | 360 | V = phi_x.parent() |
336 | 361 | phi_x_inv = V([a**(-1) for a in phi_x]) |
… |
… |
|
355 | 380 | - ``list`` - a list of double precision complex numbers |
356 | 381 | |
357 | 382 | EXAMPLES:: |
358 | | |
| 383 | |
359 | 384 | sage: n = numerical_eigenforms(11,4) |
360 | 385 | sage: n.ap(2) # random order |
361 | 386 | [9.0, 9.0, 2.73205080757, -0.732050807569] |
… |
… |
|
380 | 405 | a = Sequence(self.eigenvalues([p])[0], immutable=True) |
381 | 406 | self._ap[p] = a |
382 | 407 | return a |
383 | | |
| 408 | |
384 | 409 | def eigenvalues(self, primes): |
385 | 410 | """ |
386 | 411 | Return the eigenvalues of the Hecke operators corresponding |
387 | 412 | to the primes in the input list of primes. The eigenvalues |
388 | | match up between one prime and the next. |
| 413 | match up between one prime and the next. |
389 | 414 | |
390 | 415 | INPUT: |
391 | 416 | |
392 | 417 | - ``primes`` - a list of primes |
393 | 418 | |
394 | 419 | OUTPUT: |
395 | | |
| 420 | |
396 | 421 | list of lists of eigenvalues. |
397 | 422 | |
398 | 423 | EXAMPLES:: |
399 | | |
| 424 | |
400 | 425 | sage: n = numerical_eigenforms(1,12) |
401 | 426 | sage: n.eigenvalues([3,5,13]) |
402 | 427 | [[177148.0, 252.0], [48828126.0, 4830.0], [1.79216039404e+12, -577737.999...]] |
… |
… |
|
413 | 438 | linear combination of basis vectors. |
414 | 439 | |
415 | 440 | EXAMPLES:: |
416 | | |
| 441 | |
417 | 442 | sage: n = numerical_eigenforms(1,12) # indirect doctest |
418 | 443 | sage: n.eigenvalues([3,5,13]) |
419 | 444 | [[177148.0, 252.0], [48828126.0, 4830.0], [1.79216039404e+12, -577737.999...]] |
… |
… |
|
434 | 459 | up to bound. |
435 | 460 | |
436 | 461 | EXAMPLES:: |
437 | | |
| 462 | |
438 | 463 | sage: numerical_eigenforms(61).systems_of_eigenvalues(10) |
439 | 464 | [ |
440 | 465 | [-1.48119430409..., 0.806063433525..., 3.15632517466..., 0.675130870567...], |
… |
… |
|
454 | 479 | v.sort() |
455 | 480 | v.set_immutable() |
456 | 481 | return v |
457 | | |
| 482 | |
458 | 483 | def systems_of_abs(self, bound): |
459 | 484 | """ |
460 | 485 | Return the absolute values of all systems of eigenvalues for |
461 | 486 | self for primes up to bound. |
462 | 487 | |
463 | 488 | EXAMPLES:: |
464 | | |
| 489 | |
465 | 490 | sage: numerical_eigenforms(61).systems_of_abs(10) |
466 | 491 | [ |
467 | 492 | [0.311107817466, 2.90321192591, 2.52542756084, 3.21431974338], |
… |
… |
|
488 | 513 | indices where `|v|` is larger than eps. |
489 | 514 | |
490 | 515 | EXAMPLES:: |
491 | | |
| 516 | |
492 | 517 | sage: sage.modular.modform.numerical.support( numerical_eigenforms(61)._easy_vector(), 1.0 ) |
493 | 518 | [] |
494 | | |
| 519 | |
495 | 520 | sage: sage.modular.modform.numerical.support( numerical_eigenforms(61)._easy_vector(), 0.5 ) |
496 | 521 | [0, 1] |
497 | 522 | |
… |
… |
|
499 | 524 | return [i for i in range(v.degree()) if abs(v[i]) > eps] |
500 | 525 | |
501 | 526 | |
502 | | |
| 527 | |