Package sage :: Package modular :: Package modsym :: Module space :: Class ModularSymbolsSpace
[show private | hide private]
[frames | no frames]

Class ModularSymbolsSpace

       Gens --+
              |
HeckeModule --+
              |
             ModularSymbolsSpace

Known Subclasses:
ModularSymbolsAmbient, ModularSymbolsSubspace

Method Summary
  __init__(self, group, weight, character, sign, base_field)
  __cmp__(self, other)
Compare self and other.
  base_field(self)
  base_ring(self)
  basis(self)
Returns a basis for self.
  character(self)
  dimension(self)
  eigenvalue(self, n)
Returns an eigenvalue of T_n acting on self, where self must be new and non-splittable.
  eigenvalues(self)
Return a_n, psi, i, where a_n is the n-th eigenvalue, psi : Z --> V is a map and i:V-->K is an isomorphism of V with a number field (or Q), such that the composition iso(psi(n)) is the eigenvalue of the n-th Hecke operator acting on a fixed element of self (which must be new and non-splittable).
  gen(self, n)
The n-th generator of self.
  group(self)
Returns the group of this modular symbols space.
  hecke_algebra(self, anemic)
  hecke_matrix(self, n)
The matrix of the n-th Hecke operator acting on the basis for self.
  hecke_operator(self, n)
Returns the n-th Hecke operator as a Matrix Function.
  is_ambient(self)
  is_cuspidal(self)
  is_new(self)
  level(self)
Returns the level of this modular symbols space.
  ngens(self)
The number of generators of self.
  projection(self)
Return the projection map from the ambient space to self.
  qeigenform(self, prec)
Returns the q-expansion to precision prec of a newform associated to self, where self must be new, cuspidal, and non-splittable.
  sign(self)
Returns the sign of self.
  sturm_bound(self)
Returns the Sturm bound for this space of modular symbols.
  T(self, n)
Returns the n-th Hecke operator T_n.
  vector_space(self)
Returns the underlying vector space of self.
  weight(self)
Returns the weight of this modular symbols space.
    Inherited from HeckeModule
  decomposition(self, anemic)
  factor_number(self)
  is_splittable(self)
Returns true if and only if only it is possible to split off a nontrivial generalized eigenspace of self as the kernel of some Hecke operator.
  is_splittable_anemic(self)
Returns true if and only if only it is possible to split off a nontrivial generalized eigenspace of self as the kernel of some Hecke operator of index coprime to the level.
  set_factor_number(self, i)
    Inherited from Gens
  __getattr__(self, attrname)
  __getitem__(self, n)
  __getslice__(self, n, m)
  gens(self)
  list(self)

Method Details

__cmp__(self, other)
(Comparison operator)

Compare self and other.

basis(self)

Returns a basis for self.

eigenvalue(self, n)

Returns an eigenvalue of T_n acting on self, where self must be new and non-splittable.

The eigenvalue is of the n-th Hecke operator acting on a fixed eigenvector of self, which is consistent between different calls of this function.

eigenvalues(self)

Return a_n, psi, i, where a_n is the n-th eigenvalue, 
   psi : Z --> V is a map 
and i:V-->K is an isomorphism of V with a
number field (or Q), such that the composition iso(psi(n)) is
the eigenvalue of the n-th Hecke operator acting on a fixed
element of self (which must be new and non-splittable).

The reason we separate psi and i, is that in general the values
of psi take very little space to write down and are easier to
compute, whereas the values i(psi(n)) can be huge (the idea to
separate these maps was suggested to William Stein by John 
Cremona).  The function an is simply the composite of i 
and psi.

INPUT:
    self -- a simple space of modular symbols
    
OUTPUT:
    an  -- a map from positives integers to a field K.
    psi -- a map from the positive integers to
           a vector space V
    i   -- a map from V to a field K.
    
EXAMPLES:
    >>> import modsym
    >>> M = modsym.ModularSymbols(11)      # notice sign=0
    >>> S = M.cuspidal_subspace()
    >>> an, phi, i = S.eigenvalues()
    >>> phi(2)
    [-2, 0]
    >>> i(phi(2))
    -2
    >>> an(2)
    -2
    >>> E = EisensteinSubspace(M)
    >>> an, phi, i = E.eigenvalues()
    >>> an(2)
    3
    >>> M = ModularSymbols(43, sign=1)
    >>> D = M.decomposition()
    >>> E = D[0]
    >>> E.is_eisenstein()
    True
    >>> an, phi, i = E.eigenvalues()
    >>> an(7)
    8
    >>> C = D[2]; C.is_cuspidal()
    True
    >>> an, phi, i = C.eigenvalues()
    >>> phi(2)
    ...
    >>> i(phi(2))
    a
    >>> a2 = an(2); a2
    a
    >>> a2.parent()
    ...

ALGORITHM:
In the algorithm below, we let T denote the image of the Hecke
algebra in End(M), which we compute efficiently as discussed 
above.  If the sign of M is 0, replace M by the kernel of *-1:

1. Verify that input is valid: i.e., that it is new and simple.

2. Reduce to the prime case using the relations.  Remark:
   Multiplying matrices is O(n^(2+?)), whereas multiplying
   elements of a number field is O(n^2) (I think), so it would
   seem best to reduce to the prime case first, to
   avoid computing Hecke operators T_n, with n composite.  
   This is unclear though.

3. Choose any (preferably "sparse", if possible) nonzero
   element v in M.

4. Let psi be the map T --> M, given by psi(t) = v*t.

5. Choose random elements t in T until we find one such that
   the iterates v, v*t, v*t^2, ..., etc. span M.  Let t be
   the one we find.  Such a t will exist (at least over an
   infinite field) because T is semisimple and M is assumed
   simple.

6. Compute the characteristic polynomial f(x) of t, and let
   K=Q[x]/(f(x)) be the number field generated by a root 
   of f(x).

7. Let e:M --> K be the map such that 

                    e(v*t^i)=x^i (mod f(x))
                    
   for i = 0,1,2,...,deg(f)-1. Since the t^i*v span M, this
   determines e.  To compute e, the main thing is to compute
   the change of basis matrix from the standard basis for M to
   the basis {v*t^i}.  This change of basis matrix is the inverse
   of the matrix whose rows are the v*t^i for i=0,...,deg(f)-1.

8. Finally we have

              a_n = e(psi(T_n)) = e(v*T_n)

   for Hecke operators T_n, where the a_n are eigenvalues.

Remarks:
(1) Space complexity:  The map psi is easy to compute and store
    space-wise, as are the values of psi on many T.
    The map e is likely to involve big numbers, since it's
    the iterates of a vector under a matrix, which can be
    quite large.   Also to compute e on an arbitrary element,
    we have to write it in terms of the iterates of v, which
    means inverting a matrix with large entries.  Thus, and
    this seems unavoidable, it takes a lot of space to store
    e and compute its values.  For many applications, e.g.,
    databases, it is better to store a matrix that defines
    e and the images under psi of lots of T_n.
    
(2) How can we find a minimal collection of information from 
    which we can compute the map n |--> psi(T_n)?  Do we need 
    the whole modular symbols presentation?  No, we need only the
    image of each generating Manin symbol in M under
    projection.  The Hecke operators are then given by the
    standard Manin symbols formulas, where we reduce all
    resulting Manin symbols to their image in M.

gen(self, n)

The n-th generator of self.  
INPUT:
    n -- int, an integer between 0 to the dimension minus 1.
RETURN:
    -- The n-th basis element (ModularSymbol)
NOTE:
    To avoid circular references, this function creates 
    the n-th basis ModularSymbol each time it is called from
    the n-th generator of the underlying vector space.

group(self)

Returns the group of this modular symbols space.

INPUT:
   ModularSymbols self -- an arbitrary space of modular symbols
   
OUTPUT:
   CongruenceSubgroup -- the congruence subgroup that this is a space
                      of modular symbols for.

ALGORITHM:
   The group is recorded when this space is created.

EXAMPLES:
>>> m = ModularSymbols(20)
>>> m.group()
Gamma_0(20)

hecke_matrix(self, n)

The matrix of the n-th Hecke operator acting on the basis for self.
Overrides:
sage.modular.hecke.HeckeModule.hecke_matrix

hecke_operator(self, n)

Returns the n-th Hecke operator as a Matrix Function.
INPUT:
   ModularSymbols self -- Hecke equivariant space of
                           modular symbols
   int n -- an integer at least 1.
OUTPUT:
   function.MatrixFunction -- the matrix function that
            represents the n-th Hecke operator on the chosen
            basis for self.

level(self)

Returns the level of this modular symbols space.

INPUT:
   ModularSymbols self -- an arbitrary space of modular symbols
   
OUTPUT:
   int -- the level

ALGORITHM:
   The level is recorded when self is created.

EXAMPLES:
>>> m = ModularSymbols(20)
>>> m.level()
20
Overrides:
sage.modular.hecke.HeckeModule.level

ngens(self)

The number of generators of self.
INPUT:
   ModularSymbols self -- arbitrary space of modular symbols.
OUTPUT:
   int -- the number of generators, which is the same as the
          dimension of self.
ALGORITHM:
   Call the dimension function.
EXAMPLES:
>>> m = modsym.ModularSymbols(33)
>>> m.ngens()
9
>>> m.dimension()
9
>>> modsym.ModularSymbols(100, weight=2, sign=1).ngens()
18

projection(self)

Return the projection map from the ambient space to self.
INPUT:
   ModularSymbols self -- A decomposition factor of an
                           ambient space.
OUTPUT:
   function.MatrixFunction -- The output is a matrix function,
                 which defines projection from the ambient
                 space to self.
ALGORITHM:
   Let B be the matrix whose columns are got by concatenating
   together a basis for the factors of the ambient space.
   Then the projection matrix onto self is the submatrix of
   B^(-1) got from the rows corresponding to self, i.e., if
   the basis vectors for self appear as columns n through m of
   B, then the projection matrix is got from rows n through m
   of B^(-1).  This is because projection with respect to the
   B basis is just given by an m-n+1 row slice P of a diagonal
   matrix D with 1's in the n through m positions, so
   projection with respect to the standard basis is given by
   P*B^(-1), which is just rows n through m of B^(-1).

qeigenform(self, prec)

Returns the q-expansion to precision prec of a newform associated to self, where self must be new, cuspidal, and non-splittable.

sign(self)

Returns the sign of self.

For efficiency reasons, it is often useful to compute in the
(largest) quotient of modular symbols where the * involution
acts as +1, or where it acts as -1.


INPUT:
   ModularSymbols self -- arbitrary space of modular symbols.
   
OUTPUT:
   int -- the sign of self, either -1, 0, or 1.
          -1 -- largest quotient where * acts as -1,
          +1 -- largest quotient where * acts as +1, 
           0 -- full space of modular symbols (no quotient).

ALGORITHM:
   Call the dimension function.

EXAMPLES:
>>> m = ModularSymbols(33)
>>> m.dimension()
6
>>> m.sign()
1
>>> m = ModularSymbols(33, sign=0)
>>> m.sign()
0
>>> m.dimension()
9
>>> m = ModularSymbols(33, sign=-1)
>>> m.sign()
-1
>>> m.dimension()
3

sturm_bound(self)

Returns the Sturm bound for this space of modular symbols.

Returns a positive integer n = (k/12)*[SL_2(Z):Gamma_0(N)] such that the Hecke operators T1,...,Tn acting on cusp forms generate the Hecke algebra as a Z-module when the character is trivial or quadratic. Otherwise, T1,...,Tn generate the Hecke algebra at least as a Z[eps]-module, where Z[eps] is the ring generated by the values of eps. Alternatively, this is a bound such that if two cusp forms associated to this space of modular symbols are congruent modulo (lambda, q^n), then they are congruent modulo lambda.

REFERENCE: See the Agashe-Stein appendix to Lario and Schoof's "Some computations with Hecke rings and deformation rings", Experimental Math., 11 (2002), no. 2, 303-311. This result originated in the paper Sturm, "On the congruence of modular forms", Springer LNM 1240, 275--280, 1987.

REMARK: Kevin Buzzard pointed out to me (William Stein) in Fall 2002 that the above bound is fine for Gamma1 with character, as one sees by taking a power of f. More precisely, if f = 0 (mod p) for first s coefficients, then f^r = 0 (mod p) for first s*r coefficents. Since weight of f^r is r*weight(f), it follows that if s >= sturm bound for Gamma_0 at weight(f), then f^r has valuation large enough to be forced to be 0 at r*weight(f) by Sturm bound (which is valid if we choose r right). Thus f = 0 (mod p). Conclusion: For Gamma_1 with fixed character, the Sturm bound is *exactly* the same as for Gamma_0.

A key point is that we are finding Z[eps] generators for the Hecke algebra here, not Z-generators. So if one wants generators for the Hecke algebra over Z, this bound is wrong.

T(self, n)

Returns the n-th Hecke operator T_n. This function is a synonym for for hecke_operator.

vector_space(self)

Returns the underlying vector space of self.
NOTES:
This is always an ambient vector space over the base ring of
dimension equal to the dimension of self.  For the embedded
subspace of the ambient space's vector space, use the
embedded_subspace function.
INPUT:
   ModularSymbols self -- arbitrary space of modular symbols.
OUTPUT:
   VectorSpace
ALGORITHM:
   Create and return the ambient vector space over the base
   field of dimension equal to the dimension of self.
EXAMPLES:
>>> import modsym
>>> m = modsym.ModularSymbols(23)
>>> m.vector_space()
Full Vector space of degree 5 over Rational Field

>.>> a = m[0]
>.>> a.vector_space()
Full Vector space of degree 1 over Rational Field
Overrides:
sage.modular.hecke.HeckeModule.vector_space

weight(self)

Returns the weight of this modular symbols space.

INPUT:
   ModularSymbols self -- an arbitrary space of modular symbols
   
OUTPUT:
   int -- the weight

ALGORITHM:
   The weight is recorded when self is created.

EXAMPLES:
>>> m = ModularSymbols(20, weight=2)
>>> m.weight()
2
Overrides:
sage.modular.hecke.HeckeModule.weight

Generated by Epydoc 2.1 on Fri Jun 24 17:58:45 2005 http://epydoc.sf.net