Path: blob/master/src/sage/modular/modform/numerical.py
8820 views
"""1Numerical computation of newforms2"""34#########################################################################5# Copyright (C) 2004--2006 William Stein <[email protected]>6#7# Distributed under the terms of the GNU General Public License (GPL)8#9# http://www.gnu.org/licenses/10#########################################################################1112from sage.structure.sage_object import SageObject13from sage.structure.sequence import Sequence14from sage.modular.modsym.all import ModularSymbols15from sage.modular.arithgroup.all import Gamma016from sage.modules.all import vector17from sage.misc.misc import verbose18from sage.rings.all import CDF, Integer, QQ, next_prime, prime_range19from sage.misc.prandom import randint20from sage.matrix.constructor import matrix2122# This variable controls importing the SciPy library sparingly23scipy=None2425class NumericalEigenforms(SageObject):26"""27numerical_eigenforms(group, weight=2, eps=1e-20, delta=1e-2, tp=[2,3,5])2829INPUT:3031- ``group`` - a congruence subgroup of a Dirichlet character of32order 1 or 23334- ``weight`` - an integer >= 23536- ``eps`` - a small float; abs( ) < eps is what "equal to zero" is37interpreted as for floating point numbers.3839- ``delta`` - a small-ish float; eigenvalues are considered distinct40if their difference has absolute value at least delta4142- ``tp`` - use the Hecke operators T_p for p in tp when searching43for a random Hecke operator with distinct Hecke eigenvalues.4445OUTPUT:4647A numerical eigenforms object, with the following useful methods:4849- :meth:`ap` - return all eigenvalues of $T_p$5051- :meth:`eigenvalues` - list of eigenvalues corresponding52to the given list of primes, e.g.,::5354[[eigenvalues of T_2],55[eigenvalues of T_3],56[eigenvalues of T_5], ...]5758- :meth:`systems_of_eigenvalues` - a list of the systems of59eigenvalues of eigenforms such that the chosen random linear60combination of Hecke operators has multiplicity 1 eigenvalues.6162EXAMPLES::6364sage: n = numerical_eigenforms(23)65sage: n == loads(dumps(n))66True67sage: n.ap(2)68[3.0, 0.61803398875, -1.61803398875]69sage: n.systems_of_eigenvalues(7)70[71[-1.61803398875, 2.2360679775, -3.2360679775],72[0.61803398875, -2.2360679775, 1.2360679775],73[3.0, 4.0, 6.0]74]75sage: n.systems_of_abs(7)76[77[0.6180339887..., 2.236067977..., 1.236067977...],78[1.6180339887..., 2.236067977..., 3.236067977...],79[3.0, 4.0, 6.0]80]81sage: n.eigenvalues([2,3,5])82[[3.0, 0.61803398875, -1.61803398875],83[4.0, -2.2360679775, 2.2360679775],84[6.0, 1.2360679775, -3.2360679775]]85"""86def __init__(self, group, weight=2, eps=1e-20,87delta=1e-2, tp=[2,3,5]):88"""89Create a new space of numerical eigenforms.9091EXAMPLES::9293sage: numerical_eigenforms(61) # indirect doctest94Numerical Hecke eigenvalues for Congruence Subgroup Gamma0(61) of weight 295"""96if isinstance(group, (int, long, Integer)):97group = Gamma0(Integer(group))98self._group = group99self._weight = Integer(weight)100self._tp = tp101if self._weight < 2:102raise ValueError, "weight must be at least 2"103self._eps = eps104self._delta = delta105106def __cmp__(self, other):107"""108Compare two spaces of numerical eigenforms. Currently109returns 0 if they come from the same space of modular110symbols, and -1 otherwise.111112EXAMPLES::113114sage: n = numerical_eigenforms(23)115sage: n.__cmp__(loads(dumps(n)))1160117"""118if not isinstance( other, NumericalEigenforms ):119raise ValueError, "%s is not a space of numerical eigenforms"%other120if self.modular_symbols() == other.modular_symbols():121return 0122else:123return -1124125def level(self):126"""127Return the level of this set of modular eigenforms.128129EXAMPLES::130131sage: n = numerical_eigenforms(61) ; n.level()13261133"""134return self._group.level()135136def weight(self):137"""138Return the weight of this set of modular eigenforms.139140EXAMPLES::141142sage: n = numerical_eigenforms(61) ; n.weight()1432144"""145return self._weight146147def _repr_(self):148"""149Print string representation of self.150151EXAMPLES::152153sage: n = numerical_eigenforms(61) ; n154Numerical Hecke eigenvalues for Congruence Subgroup Gamma0(61) of weight 2155156sage: n._repr_()157'Numerical Hecke eigenvalues for Congruence Subgroup Gamma0(61) of weight 2'158"""159return "Numerical Hecke eigenvalues for %s of weight %s"%(160self._group, self._weight)161162def modular_symbols(self):163"""164Return the space of modular symbols used for computing this165set of modular eigenforms.166167EXAMPLES::168169sage: n = numerical_eigenforms(61) ; n.modular_symbols()170Modular Symbols space of dimension 5 for Gamma_0(61) of weight 2 with sign 1 over Rational Field171"""172try:173return self.__modular_symbols174except AttributeError:175M = ModularSymbols(self._group,176self._weight, sign=1)177if M.base_ring() != QQ:178raise ValueError, "modular forms space must be defined over QQ"179self.__modular_symbols = M180return M181182def _eigenvectors(self):183r"""184Find numerical approximations to simultaneous eigenvectors in185self.modular_symbols() for all T_p in self._tp.186187EXAMPLES::188189sage: n = numerical_eigenforms(61)190sage: n._eigenvectors() # random order191[ 1.0 0.289473640239 0.176788851952 0.336707726757 2.4182243084e-16]192[ 0 -0.0702748344418 0.491416161212 0.155925712173 0.707106781187]193[ 0 0.413171180356 0.141163094698 0.0923242547901 0.707106781187]194[ 0 0.826342360711 0.282326189397 0.18464850958 6.79812569682e-16]195[ 0 0.2402380858 0.792225196393 0.905370774276 4.70805946682e-16]196197TESTS:198199This tests if this routine selects only eigenvectors with200multiplicity one. Two of the eigenvalues are201(roughly) -92.21 and -90.30 so if we set ``eps = 2.0``202then they should compare as equal, causing both eigenvectors203to be absent from the matrix returned. The remaining eigenvalues204(ostensibly unique) are visible in the test, which should be205indepedent of which eigenvectors are returned, but it does presume206an ordering of these eigenvectors for the test to succeed.207This exercises a correction in Trac 8018. ::208209sage: n = numerical_eigenforms(61, eps=2.0)210sage: evectors = n._eigenvectors()211sage: evalues = diagonal_matrix(CDF, [-283.0, 108.522012456, 142.0])212sage: diff = n._hecke_matrix*evectors - evectors*evalues213sage: sum([abs(diff[i,j]) for i in range(5) for j in range(3)]) < 1.0e-9214True215"""216try:217return self.__eigenvectors218except AttributeError:219pass220verbose('Finding eigenvector basis')221M = self.modular_symbols()222N = self.level()223224tp = self._tp225p = tp[0]226t = M.T(p).matrix()227for p in tp[1:]:228t += randint(-50,50)*M.T(p).matrix()229230self._hecke_matrix = t231232global scipy233if scipy is None:234import scipy235import scipy.linalg236evals,eig = scipy.linalg.eig(self._hecke_matrix.numpy(), right=True, left=False)237B = matrix(eig)238v = [CDF(evals[i]) for i in range(len(evals))]239240# Determine the eigenvectors with eigenvalues of multiplicity241# one, with equality controlled by the value of eps242# Keep just these eigenvectors243eps = self._eps244w = []245for i in range(len(v)):246e = v[i]247uniq = True248for j in range(len(v)):249if uniq and i != j and abs(e-v[j]) < eps:250uniq = False251if uniq:252w.append(i)253self.__eigenvectors = B.matrix_from_columns(w)254return self.__eigenvectors255256def _easy_vector(self):257"""258Return a very sparse vector v such that v times the eigenvector matrix259has all entries nonzero.260261ALGORITHM:2622631. Choose row with the most nonzero entries. (put 1 there)2642652. Consider submatrix of columns corresponding to zero entries266in row chosen in 1.2672683. Find row of submatrix with most nonzero entries, and add269appropriate multiple. Repeat.270271EXAMPLES::272273sage: n = numerical_eigenforms(37)274sage: n._easy_vector() # slightly random output275(1.0, 1.0, 0)276sage: n = numerical_eigenforms(43)277sage: n._easy_vector() # slightly random output278(1.0, 0, 1.0, 0)279sage: n = numerical_eigenforms(125)280sage: n._easy_vector() # slightly random output281(0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0)282"""283try:284return self.__easy_vector285except AttributeError:286pass287E = self._eigenvectors()288delta = self._delta289x = (CDF**E.nrows()).zero_vector()290if E.nrows() == 0:291return x292293294295def best_row(M):296"""297Find the best row among rows of M, i.e. the row298with the most entries supported outside [-delta, delta].299300EXAMPLES::301302sage: numerical_eigenforms(61)._easy_vector() # indirect doctest303(1.0, 1.0, 0.0, 0.0, 0.0)304"""305R = M.rows()306v = [len(support(r, delta)) for r in R]307m = max(v)308i = v.index(m)309return i, R[i]310311i, e = best_row(E)312313x[i] = 1314315while True:316s = set(support(e, delta))317zp = [i for i in range(e.degree()) if not i in s]318if len(zp) == 0:319break320C = E.matrix_from_columns(zp)321# best row322i, f = best_row(C)323x[i] += 1 # simplistic324e = x*E325326self.__easy_vector = x327return x328329def _eigendata(self):330"""331Return all eigendata for self._easy_vector().332333EXAMPLES::334335sage: numerical_eigenforms(61)._eigendata() # random order336((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))337"""338try:339return self.__eigendata340except AttributeError:341pass342x = self._easy_vector()343344B = self._eigenvectors()345def phi(y):346"""347Take coefficients and a basis, and return that348linear combination of basis vectors.349350EXAMPLES::351352sage: n = numerical_eigenforms(61) # indirect doctest353sage: n._eigendata() # random order354((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"""356return y.element() * B357358phi_x = phi(x)359V = phi_x.parent()360phi_x_inv = V([a**(-1) for a in phi_x])361eps = self._eps362nzp = support(x, eps)363x_nzp = vector(CDF, x.list_from_positions(nzp))364self.__eigendata = (phi_x, phi_x_inv, nzp, x_nzp)365return self.__eigendata366367def ap(self, p):368"""369Return a list of the eigenvalues of the Hecke operator `T_p`370on all the computed eigenforms. The eigenvalues match up371between one prime and the next.372373INPUT:374375- ``p`` - integer, a prime number376377OUTPUT:378379- ``list`` - a list of double precision complex numbers380381EXAMPLES::382383sage: n = numerical_eigenforms(11,4)384sage: n.ap(2) # random order385[9.0, 9.0, 2.73205080757, -0.732050807569]386sage: n.ap(3) # random order387[28.0, 28.0, -7.92820323028, 5.92820323028]388sage: m = n.modular_symbols()389sage: x = polygen(QQ, 'x')390sage: m.T(2).charpoly(x).factor()391(x - 9)^2 * (x^2 - 2*x - 2)392sage: m.T(3).charpoly(x).factor()393(x - 28)^2 * (x^2 + 2*x - 47)394"""395p = Integer(p)396if not p.is_prime():397raise ValueError, "p must be a prime"398try:399return self._ap[p]400except AttributeError:401self._ap = {}402except KeyError:403pass404a = Sequence(self.eigenvalues([p])[0], immutable=True)405self._ap[p] = a406return a407408def eigenvalues(self, primes):409"""410Return the eigenvalues of the Hecke operators corresponding411to the primes in the input list of primes. The eigenvalues412match up between one prime and the next.413414INPUT:415416- ``primes`` - a list of primes417418OUTPUT:419420list of lists of eigenvalues.421422EXAMPLES::423424sage: n = numerical_eigenforms(1,12)425sage: n.eigenvalues([3,5,13])426[[177148.0, 252.0], [48828126.0, 4830.0], [1.79216039404e+12, -577737.999...]]427"""428primes = [Integer(p) for p in primes]429for p in primes:430if not p.is_prime():431raise ValueError, 'each element of primes must be prime.'432phi_x, phi_x_inv, nzp, x_nzp = self._eigendata()433B = self._eigenvectors()434def phi(y):435"""436Take coefficients and a basis, and return that437linear combination of basis vectors.438439EXAMPLES::440441sage: n = numerical_eigenforms(1,12) # indirect doctest442sage: n.eigenvalues([3,5,13])443[[177148.0, 252.0], [48828126.0, 4830.0], [1.79216039404e+12, -577737.999...]]444"""445return y.element() * B446447ans = []448m = self.modular_symbols().ambient_module()449for p in primes:450t = m._compute_hecke_matrix_prime(p, nzp)451w = phi(x_nzp*t)452ans.append([w[i]*phi_x_inv[i] for i in range(w.degree())])453return ans454455def systems_of_eigenvalues(self, bound):456"""457Return all systems of eigenvalues for self for primes458up to bound.459460EXAMPLES::461462sage: numerical_eigenforms(61).systems_of_eigenvalues(10)463[464[-1.48119430409..., 0.806063433525..., 3.15632517466..., 0.675130870567...],465[-1.0..., -2.0..., -3.0..., 1.0...],466[0.311107817466..., 2.90321192591..., -2.52542756084..., -3.21431974338...],467[2.17008648663..., -1.70927535944..., -1.63089761382..., -0.460811127189...],468[3.0, 4.0, 6.0, 8.0]469]470"""471P = prime_range(bound)472e = self.eigenvalues(P)473v = Sequence([], cr=True)474if len(e) == 0:475return v476for i in range(len(e[0])):477v.append([e[j][i] for j in range(len(e))])478v.sort()479v.set_immutable()480return v481482def systems_of_abs(self, bound):483"""484Return the absolute values of all systems of eigenvalues for485self for primes up to bound.486487EXAMPLES::488489sage: numerical_eigenforms(61).systems_of_abs(10)490[491[0.311107817466, 2.90321192591, 2.52542756084, 3.21431974338],492[1.0, 2.0, 3.0, 1.0],493[1.48119430409, 0.806063433525, 3.15632517466, 0.675130870567],494[2.17008648663, 1.70927535944, 1.63089761382, 0.460811127189],495[3.0, 4.0, 6.0, 8.0]496]497"""498P = prime_range(bound)499e = self.eigenvalues(P)500v = Sequence([], cr=True)501if len(e) == 0:502return v503for i in range(len(e[0])):504v.append([abs(e[j][i]) for j in range(len(e))])505v.sort()506v.set_immutable()507return v508509def support(v, eps):510"""511Given a vector `v` and a threshold eps, return all512indices where `|v|` is larger than eps.513514EXAMPLES::515516sage: sage.modular.modform.numerical.support( numerical_eigenforms(61)._easy_vector(), 1.0 )517[]518519sage: sage.modular.modform.numerical.support( numerical_eigenforms(61)._easy_vector(), 0.5 )520[0, 1]521522"""523return [i for i in range(v.degree()) if abs(v[i]) > eps]524525526527528529