r"""
Generic spaces of modular forms
EXAMPLES (computation of base ring): Return the base ring of this
space of modular forms.
EXAMPLES: For spaces of modular forms for `\Gamma_0(N)` or
`\Gamma_1(N)`, the default base ring is
`\QQ`::
sage: ModularForms(11,2).base_ring()
Rational Field
sage: ModularForms(1,12).base_ring()
Rational Field
sage: CuspForms(Gamma1(13),3).base_ring()
Rational Field
The base ring can be explicitly specified in the constructor
function.
::
sage: ModularForms(11,2,base_ring=GF(13)).base_ring()
Finite Field of size 13
For modular forms with character the default base ring is the field
generated by the image of the character.
::
sage: ModularForms(DirichletGroup(13).0,3).base_ring()
Cyclotomic Field of order 12 and degree 4
For example, if the character is quadratic then the field is
`\QQ` (if the characteristic is `0`).
::
sage: ModularForms(DirichletGroup(13).0^6,3).base_ring()
Rational Field
An example in characteristic `7`::
sage: ModularForms(13,3,base_ring=GF(7)).base_ring()
Finite Field of size 7
"""
from sage.structure.all import Sequence
import sage.modular.hecke.all as hecke
import sage.modular.arithgroup.all as arithgroup
import sage.modular.dirichlet as dirichlet
import sage.rings.all as rings
import defaults
import element
import hecke_operator_on_qexp
import submodule
import sage.modular.modform.constructor
from sage.matrix.constructor import zero_matrix
from sage.rings.arith import gcd
WARN=False
def is_ModularFormsSpace(x):
r"""
Return True if x is a ```ModularFormsSpace```.
EXAMPLES::
sage: from sage.modular.modform.space import is_ModularFormsSpace
sage: is_ModularFormsSpace(ModularForms(11,2))
True
sage: is_ModularFormsSpace(CuspForms(11,2))
True
sage: is_ModularFormsSpace(3)
False
"""
return isinstance(x, ModularFormsSpace)
class ModularFormsSpace(hecke.HeckeModule_generic):
"""
A generic space of modular forms.
"""
def __init__(self, group, weight, character, base_ring):
r"""
Generic spaces of modular forms. For spaces of modular forms for
`\Gamma_0(N)` or `\Gamma_1(N)`, the default base
ring is `\QQ`.
EXAMPLES::
sage: ModularForms(11,2)
Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
::
sage: ModularForms(11,2,base_ring=GF(13))
Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Finite Field of size 13
::
sage: ModularForms(DirichletGroup(13).0,3)
Modular Forms space of dimension 3, character [zeta12] and weight 3 over Cyclotomic Field of order 12 and degree 4
::
sage: M = ModularForms(11,2)
sage: M == loads(dumps(M))
True
"""
global WARN
if WARN:
print "Modular forms -- under development -- do not trust yet."
WARN=False
if not arithgroup.is_CongruenceSubgroup(group):
raise TypeError, "group (=%s) must be a congruence subgroup"%group
weight = int(weight)
if not ((character is None) or isinstance(character, dirichlet.DirichletCharacter)):
raise TypeError, "character must be a Dirichlet character"
if not isinstance(base_ring, rings.Ring):
raise TypeError, "base_ring must be a ring"
self.__sturm_bound = None
self.__weight, self.__group, self.__character = weight, group, character
hecke.HeckeModule_generic.__init__(self, base_ring, group.level())
def prec(self, new_prec=None):
"""
Return or set the default precision used for displaying
`q`-expansions of elements of this space.
INPUT:
- ``new_prec`` - positive integer (default: None)
OUTPUT: if new_prec is None, returns the current precision.
EXAMPLES::
sage: M = ModularForms(1,12)
sage: S = M.cuspidal_subspace()
sage: S.prec()
6
sage: S.basis()
[
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)
]
sage: S.prec(8)
8
sage: S.basis()
[
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8)
]
"""
return self.ambient().prec(new_prec)
def set_precision(self, new_prec):
"""
Set the default precision used for displaying
`q`-expansions.
INPUT:
- ``new_prec`` - positive integer
EXAMPLES::
sage: M = ModularForms(Gamma0(37),2)
sage: M.set_precision(10)
sage: S = M.cuspidal_subspace()
sage: S.basis()
[
q + q^3 - 2*q^4 - q^7 - 2*q^9 + O(q^10),
q^2 + 2*q^3 - 2*q^4 + q^5 - 3*q^6 - 4*q^9 + O(q^10)
]
::
sage: S.set_precision(0)
sage: S.basis()
[
O(q^0),
O(q^0)
]
The precision of subspaces is the same as the precision of the
ambient space.
::
sage: S.set_precision(2)
sage: M.basis()
[
q + O(q^2),
O(q^2),
1 + 2/3*q + O(q^2)
]
The precision must be nonnegative::
sage: S.set_precision(-1)
Traceback (most recent call last):
...
ValueError: n (=-1) must be >= 0
We do another example with nontrivial character.
::
sage: M = ModularForms(DirichletGroup(13).0^2)
sage: M.set_precision(10)
sage: M.cuspidal_subspace().0
q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10)
"""
self.ambient().set_precision(new_prec)
def change_ring(self, R):
"""
Change the base ring of this space of modular forms. To be implemented in derived classes.
EXAMPLES::
sage: sage.modular.modform.space.ModularFormsSpace(Gamma0(11),2,DirichletGroup(1).0,QQ).change_ring(GF(7))
Traceback (most recent call last):
...
NotImplementedError: This function has not yet been implemented.
"""
raise NotImplementedError, "This function has not yet been implemented."
def weight(self):
"""
Return the weight of this space of modular forms.
EXAMPLES::
sage: M = ModularForms(Gamma1(13),11)
sage: M.weight()
11
::
sage: M = ModularForms(Gamma0(997),100)
sage: M.weight()
100
::
sage: M = ModularForms(Gamma0(97),4)
sage: M.weight()
4
sage: M.eisenstein_submodule().weight()
4
"""
return self.__weight
def group(self):
r"""
Return the congruence subgroup associated to this space of modular
forms.
EXAMPLES::
sage: ModularForms(Gamma0(12),4).group()
Congruence Subgroup Gamma0(12)
::
sage: CuspForms(Gamma1(113),2).group()
Congruence Subgroup Gamma1(113)
Note that `\Gamma_1(1)` and `\Gamma_0(1)` are replaced by
`\mathrm{SL}_2(\ZZ)`.
::
sage: CuspForms(Gamma1(1),12).group()
Modular Group SL(2,Z)
sage: CuspForms(SL2Z,12).group()
Modular Group SL(2,Z)
"""
return self.__group
def character(self):
"""
Return the Dirichlet character corresponding to this space of
modular forms. Returns None if there is no specific character
corresponding to this space, e.g., if this is a space of modular
forms on `\Gamma_1(N)` with `N>1`.
EXAMPLES: The trivial character::
sage: ModularForms(Gamma0(11),2).character()
Dirichlet character modulo 11 of conductor 1 mapping 2 |--> 1
A space of forms with nontrivial character::
sage: ModularForms(DirichletGroup(20).0,3).character()
Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1
A space of forms with no particular character (hence None is
returned)::
sage: print ModularForms(Gamma1(11),2).character()
None
If the level is one then the character is trivial.
::
sage: ModularForms(Gamma1(1),12).character()
Dirichlet character modulo 1 of conductor 1 mapping 0 |--> 1
"""
return self.__character
def has_character(self):
"""
Return True if this space of modular forms has a specific
character.
This is True exactly when the character() function does not return
None.
EXAMPLES: A space for `\Gamma_0(N)` has trivial character,
hence has a character.
::
sage: CuspForms(Gamma0(11),2).has_character()
True
A space for `\Gamma_1(N)` (for `N\geq 2`) never
has a specific character.
::
sage: CuspForms(Gamma1(11),2).has_character()
False
sage: CuspForms(DirichletGroup(11).0,3).has_character()
True
"""
return not self.character() is None
def is_ambient(self):
"""
Return True if this an ambient space of modular forms.
EXAMPLES::
sage: M = ModularForms(Gamma1(4),4)
sage: M.is_ambient()
True
::
sage: E = M.eisenstein_subspace()
sage: E.is_ambient()
False
"""
return False
def __normalize_prec(self, prec):
"""
If prec=None, return self.prec(). Otherwise, make sure prec is a
sensible choice of precision and return it.
EXAMPLES::
sage: N = ModularForms(6,4)
sage: N._ModularFormsSpace__normalize_prec(int(3))
3
::
sage: type(N._ModularFormsSpace__normalize_prec(int(3)))
<type 'sage.rings.integer.Integer'>
"""
if prec is None:
prec = self.prec()
else:
prec = rings.Integer(prec)
if prec < 0:
raise ValueError, "prec (=%s) must be at least 0"%prec
return prec
def base_extend(self, base_ring):
"""
Return the base extension of self to base_ring. This first checks
whether there is a canonical coercion defined, and if so it calls the
change_ring method.
EXAMPLE::
sage: N = ModularForms(6, 4)
sage: N.base_extend(CyclotomicField(7))
Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Cyclotomic Field of order 7 and degree 6
sage: m = ModularForms(DirichletGroup(13).0^2,2); m
Modular Forms space of dimension 3, character [zeta6] and weight 2 over Cyclotomic Field of order 6 and degree 2
sage: m.base_extend(CyclotomicField(12))
Modular Forms space of dimension 3, character [zeta6] and weight 2 over Cyclotomic Field of order 12 and degree 4
sage: chi = DirichletGroup(109, CyclotomicField(3)).0
sage: S3 = CuspForms(chi, 2)
sage: S9 = S3.base_extend(CyclotomicField(9))
sage: S9
Cuspidal subspace of dimension 8 of Modular Forms space of dimension 10, character [zeta3 + 1] and weight 2 over Cyclotomic Field of order 9 and degree 6
sage: S9.has_coerce_map_from(S3) # not implemented
True
sage: S9.base_extend(CyclotomicField(3))
Traceback (most recent call last):
...
ValueError: No coercion defined
"""
if not base_ring.has_coerce_map_from(self.base_ring()):
raise ValueError, "No coercion defined"
else:
return self.change_ring(base_ring)
def echelon_form(self):
r"""
Return a space of modular forms isomorphic to self but with basis
of `q`-expansions in reduced echelon form.
This is useful, e.g., the default basis for spaces of modular forms
is rarely in echelon form, but echelon form is useful for quickly
recognizing whether a `q`-expansion is in the space.
EXAMPLES: We first illustrate two ambient spaces and their echelon
forms.
::
sage: M = ModularForms(11)
sage: M.basis()
[
q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6),
1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6)
]
sage: M.echelon_form().basis()
[
1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6),
q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)
]
::
sage: M = ModularForms(Gamma1(6),4)
sage: M.basis()
[
q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6),
1 + O(q^6),
q - 8*q^4 + 126*q^5 + O(q^6),
q^2 + 9*q^4 + O(q^6),
q^3 + O(q^6)
]
sage: M.echelon_form().basis()
[
1 + O(q^6),
q + 94*q^5 + O(q^6),
q^2 + 36*q^5 + O(q^6),
q^3 + O(q^6),
q^4 - 4*q^5 + O(q^6)
]
We create a space with a funny basis then compute the corresponding
echelon form.
::
sage: M = ModularForms(11,4)
sage: M.basis()
[
q + 3*q^3 - 6*q^4 - 7*q^5 + O(q^6),
q^2 - 4*q^3 + 2*q^4 + 8*q^5 + O(q^6),
1 + O(q^6),
q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6)
]
sage: F = M.span_of_basis([M.0 + 1/3*M.1, M.2 + M.3]); F.basis()
[
q + 1/3*q^2 + 5/3*q^3 - 16/3*q^4 - 13/3*q^5 + O(q^6),
1 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6)
]
sage: E = F.echelon_form(); E.basis()
[
1 + 26/3*q^2 + 79/3*q^3 + 235/3*q^4 + 391/3*q^5 + O(q^6),
q + 1/3*q^2 + 5/3*q^3 - 16/3*q^4 - 13/3*q^5 + O(q^6)
]
"""
try:
return self.__echelon_form
except AttributeError:
E = self.span_of_basis(self.echelon_basis())
self.__echelon_form = E
return E
def echelon_basis(self):
"""
Return a basis for self in reduced echelon form. This means that if
we view the `q`-expansions of the basis as defining rows of
a matrix (with infinitely many columns), then this matrix is in
reduced echelon form.
EXAMPLES::
sage: M = ModularForms(Gamma0(11),4)
sage: M.echelon_basis()
[
1 + O(q^6),
q - 9*q^4 - 10*q^5 + O(q^6),
q^2 + 6*q^4 + 12*q^5 + O(q^6),
q^3 + q^4 + q^5 + O(q^6)
]
sage: M.cuspidal_subspace().echelon_basis()
[
q + 3*q^3 - 6*q^4 - 7*q^5 + O(q^6),
q^2 - 4*q^3 + 2*q^4 + 8*q^5 + O(q^6)
]
::
sage: M = ModularForms(SL2Z, 12)
sage: M.echelon_basis()
[
1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6),
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)
]
::
sage: M = CuspForms(Gamma0(17),4, prec=10)
sage: M.echelon_basis()
[
q + 2*q^5 - 8*q^7 - 8*q^8 + 7*q^9 + O(q^10),
q^2 - 3/2*q^5 - 7/2*q^6 + 9/2*q^7 + q^8 - 4*q^9 + O(q^10),
q^3 - 2*q^6 + q^7 - 4*q^8 - 2*q^9 + O(q^10),
q^4 - 1/2*q^5 - 5/2*q^6 + 3/2*q^7 + 2*q^9 + O(q^10)
]
"""
try:
return self.__echelon_basis
except AttributeError:
F = self.free_module()
W = self._q_expansion_module()
pr = W.degree()
B = self.q_echelon_basis(pr)
E = [self(F.linear_combination_of_basis(W.coordinates(f.padded_list(pr)))) \
for f in B]
E = Sequence(E, cr=True, immutable=True)
self.__echelon_basis = E
return E
def integral_basis(self):
"""
Return an integral basis for this space of modular forms.
EXAMPLES: In this example the integral and echelon bases are
different.
::
sage: m = ModularForms(97,2,prec=10)
sage: s = m.cuspidal_subspace()
sage: s.integral_basis()
[
q + 2*q^7 + 4*q^8 - 2*q^9 + O(q^10),
q^2 + q^4 + q^7 + 3*q^8 - 3*q^9 + O(q^10),
q^3 + q^4 - 3*q^8 + q^9 + O(q^10),
2*q^4 - 2*q^8 + O(q^10),
q^5 - 2*q^8 + 2*q^9 + O(q^10),
q^6 + 2*q^7 + 5*q^8 - 5*q^9 + O(q^10),
3*q^7 + 6*q^8 - 4*q^9 + O(q^10)
]
sage: s.echelon_basis()
[
q + 2/3*q^9 + O(q^10),
q^2 + 2*q^8 - 5/3*q^9 + O(q^10),
q^3 - 2*q^8 + q^9 + O(q^10),
q^4 - q^8 + O(q^10),
q^5 - 2*q^8 + 2*q^9 + O(q^10),
q^6 + q^8 - 7/3*q^9 + O(q^10),
q^7 + 2*q^8 - 4/3*q^9 + O(q^10)
]
Here's another example where there is a big gap in the valuations::
sage: m = CuspForms(64,2)
sage: m.integral_basis()
[
q + O(q^6),
q^2 + O(q^6),
q^5 + O(q^6)
]
TESTS::
sage: m = CuspForms(11*2^4,2, prec=13); m
Cuspidal subspace of dimension 19 of Modular Forms space of dimension 30 for Congruence Subgroup Gamma0(176) of weight 2 over Rational Field
sage: m.integral_basis() # takes a long time (3 or 4 seconds)
[
q + O(q^13),
q^2 + O(q^13),
q^3 + O(q^13),
q^4 + O(q^13),
q^5 + O(q^13),
q^6 + O(q^13),
q^7 + O(q^13),
q^8 + O(q^13),
q^9 + O(q^13),
q^10 + O(q^13),
q^11 + O(q^13),
q^12 + O(q^13),
O(q^13),
O(q^13),
O(q^13),
O(q^13),
O(q^13),
O(q^13),
O(q^13)
]
"""
try:
return self.__integral_basis
except AttributeError:
W = self._q_expansion_module()
pr = W.degree()
B = self.q_integral_basis(pr)
I = [self.linear_combination_of_basis(
W.coordinates(f.padded_list(pr))) for f in B]
I = Sequence(I, cr=True, immutable=True)
self.__integral_basis = I
return I
def _q_expansion_module(self):
"""
Return module spanned by coefficients of q-expansions to sufficient
precision to determine elements of this space.
EXAMPLES::
sage: M = ModularForms(11,2)
sage: M._q_expansion_module()
Vector space of degree 3 and dimension 2 over Rational Field
User basis matrix:
[ 0 1 -2]
[ 1 12/5 36/5]
sage: CuspForms(1,12)._q_expansion_module()
Vector space of degree 2 and dimension 1 over Rational Field
User basis matrix:
[0 1]
"""
try:
return self.__q_expansion_module
except AttributeError:
pass
prec = self.sturm_bound()
C = self.q_expansion_basis(prec)
V = self.base_ring()**prec
W = V.span_of_basis([f.padded_list(prec) for f in C])
self.__q_expansion_module = W
return W
def q_expansion_basis(self, prec=None):
"""
Return a sequence of q-expansions for the basis of this space
computed to the given input precision.
INPUT:
- ``prec`` - integer (=0) or None
If prec is None, the prec is computed to be *at least* large
enough so that each q-expansion determines the form as an element
of this space.
.. note::
In fact, the q-expansion basis is always computed to
*at least* ``self.prec()``.
EXAMPLES::
sage: S = ModularForms(11,2).cuspidal_submodule()
sage: S.q_expansion_basis()
[
q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)
]
sage: S.q_expansion_basis(5)
[
q - 2*q^2 - q^3 + 2*q^4 + O(q^5)
]
sage: S = ModularForms(1,24).cuspidal_submodule()
sage: S.q_expansion_basis(8)
[
q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 - 982499328*q^6 - 147247240*q^7 + O(q^8),
q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + 143820*q^6 - 985824*q^7 + O(q^8)
]
"""
if prec is None:
try:
return self.__q_expansion_basis[1]
except AttributeError:
pass
prec = -1
else:
prec = rings.Integer(self.__normalize_prec(prec))
if prec == 0:
z = self._q_expansion_ring()(0,prec)
return Sequence([z]*int(self.dimension()), immutable=True, cr=True)
elif prec != -1:
try:
current_prec, B = self.__q_expansion_basis
if current_prec == prec:
return B
elif current_prec > prec:
return Sequence([f.add_bigoh(prec) for f in B], immutable=True, cr=True)
except AttributeError:
pass
d = self.dimension()
current_prec = max(prec, self.prec(), int(1.2*d) + 3)
if prec == -1:
prec = current_prec
tries = 0
while True:
B = self._compute_q_expansion_basis(current_prec)
if len(B) == d:
break
else:
tries += 1
current_prec += d
if tries > 5:
print "WARNING: possible bug in q_expansion_basis for modular forms space %s"%self
B = Sequence(B, immutable=True, cr=True)
self.__q_expansion_basis = (current_prec, B)
if current_prec == prec:
return B
return Sequence([f.add_bigoh(prec) for f in B], immutable=True, cr=True)
def _compute_q_expansion_basis(self, prec):
"""
EXAMPLES::
sage: sage.modular.modform.space.ModularFormsSpace(Gamma0(11),2,DirichletGroup(1).0,QQ)._compute_q_expansion_basis(5)
Traceback (most recent call last):
...
NotImplementedError: this must be implemented in the derived class
"""
raise NotImplementedError, "this must be implemented in the derived class"
def q_echelon_basis(self, prec=None):
r"""
Return the echelon form of the basis of `q`-expansions of
self up to precision prec.
The `q`-expansions are power series (not actual modular
forms). The number of `q`-expansions returned equals the
dimension.
EXAMPLES::
sage: M = ModularForms(11,2)
sage: M.q_expansion_basis()
[
q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6),
1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6)
]
::
sage: M.q_echelon_basis()
[
1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6),
q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)
]
"""
prec = self.__normalize_prec(prec)
if prec == 0:
z = self._q_expansion_ring()(0,0)
return Sequence([z]*int(self.dimension()), cr=True)
try:
current_prec, B = self.__q_echelon_basis
except AttributeError:
current_prec, B = -1, []
if current_prec == prec:
return B
elif current_prec > prec:
return Sequence([f.add_bigoh(prec) for f in B], cr=True)
B = self.q_expansion_basis(prec)
R = self.base_ring()
A = R**prec
gens = [f.padded_list(prec) for f in B]
C = A.span(gens)
T = self._q_expansion_ring()
S = [T(f.list(), prec) for f in C.basis()]
for _ in range(self.dimension() - len(S)):
S.append(T(0,prec))
S = Sequence(S, immutable=True, cr=True)
self.__q_echelon_basis = (prec, S)
return S
def q_integral_basis(self, prec=None):
r"""
Return a `\ZZ`-reduced echelon basis of
`q`-expansions for self.
The `q`-expansions are power series with coefficients in
`\ZZ`; they are *not* actual modular forms.
The base ring of self must be `\QQ`. The number of
`q`-expansions returned equals the dimension.
EXAMPLES::
sage: S = CuspForms(11,2)
sage: S.q_integral_basis(5)
[
q - 2*q^2 - q^3 + 2*q^4 + O(q^5)
]
"""
if not self.base_ring() == rings.QQ:
raise TypeError, "the base ring must be Q"
prec = self.__normalize_prec(prec)
R = rings.PowerSeriesRing(rings.ZZ, name=defaults.DEFAULT_VARIABLE)
if prec == 0:
z = R(0,prec)
return Sequence([z]*int(self.dimension()), cr=True)
try:
current_prec, B = self.__q_integral_basis
except AttributeError:
current_prec, B = -1, Sequence([], cr=True, immutable=True)
if current_prec == prec:
return B
elif current_prec > prec:
return Sequence([f.add_bigoh(prec) for f in B], cr=True)
B = self.q_expansion_basis(prec)
A = rings.ZZ**prec
zero = rings.ZZ(0)
gens = [f.padded_list(prec) for f in B]
C = A.span(gens)
D = C.saturation()
S = [R(f.list(),prec) for f in D.basis()]
for _ in range(self.dimension() - len(S)):
S.append(R(0,prec))
S = Sequence(S, immutable=True, cr=True)
self.__q_integral_basis = (prec, S)
return S
def _q_expansion_ring(self):
"""
Returns the parent for q-expansions of modular forms in self.
EXAMPLES::
sage: M = ModularForms(11,2)
sage: M._q_expansion_ring()
Power Series Ring in q over Rational Field
"""
try:
return self.__q_expansion_ring
except AttributeError:
R = rings.PowerSeriesRing(self.base_ring(), name=defaults.DEFAULT_VARIABLE)
self.__q_expansion_ring = R
return R
def _q_expansion_zero(self):
"""
Returns the q-expansion of the modular form 0.
EXAMPLES::
sage: M = ModularForms(11,2)
sage: M._q_expansion_zero()
0
sage: M._q_expansion_zero() == M._q_expansion_ring()(0)
True
"""
try:
return self.__q_expansion_zero
except AttributeError:
f = self._q_expansion_ring()(0)
self.__q_expansion_zero = f
return f
def _q_expansion(self, element, prec):
"""
Take an element of self (specified as a list, tuple, or vector),
and return the corresponding q-expansion.
EXAMPLES::
sage: m = ModularForms(Gamma0(23),2); m
Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(23) of weight 2 over Rational Field
sage: m.basis()
[
q - q^3 - q^4 + O(q^6),
q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6),
1 + 12/11*q + 36/11*q^2 + 48/11*q^3 + 84/11*q^4 + 72/11*q^5 + O(q^6)
]
sage: m._q_expansion([1,2,0], 5)
q + 2*q^2 - 5*q^3 - 3*q^4 + O(q^5)
"""
return self.ambient_module()._q_expansion(element, prec)
def __add__(self, right):
"""
If self and right live inside the same ambient module, return the
sum of the two spaces (as modules).
EXAMPLES::
sage: N = CuspForms(44,2) ; ls = [N.submodule([N(u) for u in x.q_expansion_basis(20)]) for x in N.modular_symbols().decomposition()]; ls
[Modular Forms subspace of dimension 1 of Modular Forms space of dimension 9 for Congruence Subgroup Gamma0(44) of weight 2 over Rational Field,
Modular Forms subspace of dimension 3 of Modular Forms space of dimension 9 for Congruence Subgroup Gamma0(44) of weight 2 over Rational Field]
::
sage: N1 = ls[0] ; N2 = ls[1]
sage: N1 + N2 # indirect doctest
Modular Forms subspace of dimension 4 of Modular Forms space of dimension 9 for Congruence Subgroup Gamma0(44) of weight 2 over Rational Field
"""
from sage.modular.modform.submodule import ModularFormsSubmodule
if self.ambient_module() != right.ambient_module():
raise ArithmeticError, ("Sum of %s and %s not defined because " + \
"they do not lie in a common ambient space.")%\
(self, right)
if self.is_ambient(): return self
if right.is_ambient(): return right
V = self.free_module() + right.free_module()
return ModularFormsSubmodule(self.ambient_module(), V)
def _has_natural_inclusion_map_to(self, right):
"""
Return true if there is a natural inclusion map from modular forms
in self to modular forms in right.
INPUT:
- ``self, right`` - spaces of modular forms
OUTPUT: True if self embeds in right, and False otherwise.
TODO: Barring a few trivial cases, this only works in the case that
right.is_ambient() returns True.
EXAMPLES::
sage: N = ModularForms(6,4) ; S = N.cuspidal_subspace()
::
sage: N._has_natural_inclusion_map_to(S)
Traceback (most recent call last):
...
NotImplementedError
::
sage: S._has_natural_inclusion_map_to(N)
True
::
sage: M = ModularForms(11,2)
sage: N._has_natural_inclusion_map_to(M)
False
"""
if not right.group().is_subgroup(self.group()):
return False
if right.character() is None:
return True
if right.is_ambient():
e = self.character()
f = right.character()
return f.parent()(e) == f
raise NotImplementedError
def has_coerce_map_from_impl(self, from_par):
"""
Code to make ModularFormsSpace work well with coercion framework.
EXAMPLES::
sage: M = ModularForms(22,2)
sage: M.has_coerce_map_from_impl(M.cuspidal_subspace())
True
sage: M.has_coerce_map_from(ModularForms(22,4))
False
"""
if isinstance(from_par, ModularFormsSpace):
if from_par.ambient() == self:
return True
elif self.is_ambient() and self.group().is_subgroup(from_par.group()) and self.weight() == from_par.weight():
return True
return False
def _coerce_impl(self, x):
"""
Code to coerce an element into self.
EXAMPLES::
sage: M = ModularForms(22,2) ; S = CuspForms(22,2)
sage: sum(S.basis())
q + q^2 - q^3 - 4*q^4 + q^5 + O(q^6)
sage: sum(S.basis() + M.basis())
1 + 3*q + 3*q^2 + 2*q^3 - 7*q^4 + 8*q^5 + O(q^6)
sage: M._coerce_impl(S.basis()[0])
q - q^3 - 2*q^4 + q^5 + O(q^6)
::
sage: M = ModularForms(Gamma0(22)) ; N = ModularForms(Gamma0(44))
sage: M.basis()[0]
q - q^3 - 2*q^4 + q^5 + O(q^6)
sage: N(M.basis()[0])
q - q^3 - 2*q^4 + q^5 + O(q^6)
"""
if isinstance(x, element.ModularFormElement):
if x.parent().ambient() == self:
return self(x.element())
elif self.group().is_subgroup(x.parent().group()):
return self(x.q_expansion(self._q_expansion_module().degree()))
raise TypeError, "no known coercion to modular form"
def __call__(self, x, check=True):
"""
Try to coerce x into self. If x is a vector of length
self.dimension(), interpret it as a list of coefficients for
self.basis() and return that linear combination. If x is a power
series, it tries to determine whether or not x lives in self. If
so, it returns x as an element of M, and throws an error if not.
EXAMPLES::
sage: M = ModularForms(13,4)
sage: M.dimension()
5
::
sage: M([1,2,3,4,5])
4 + 6*q + 47*q^2 + 143*q^3 + 358*q^4 + 630*q^5 + O(q^6)
::
sage: M([1,3])
Traceback (most recent call last):
...
TypeError: entries must be a list of length 5
::
sage: R = M._q_expansion_ring()
sage: M(R([0,1,0,0,0,-2,-4,-2,-12]).add_bigoh(9))
q - 2*q^5 + O(q^6)
::
sage: M.set_precision(9)
sage: M(R([0,1,0,0,0,-2,-4,-2,-12]).add_bigoh(9))
q - 2*q^5 - 4*q^6 - 2*q^7 - 12*q^8 + O(q^9)
Note that one only needs coefficients up to self.sturm_bound() to
determine the form::
sage: M(R([0,1,0,0,0,-2,-4,-2,-12]).add_bigoh(8))
q - 2*q^5 - 4*q^6 - 2*q^7 - 12*q^8 + O(q^9)
::
sage: M(R([0,1,1,0,0,0,-4,-2,-12]).add_bigoh(9))
Traceback (most recent call last):
...
ValueError: q-expansion does not correspond to a form in self
::
sage: S = CuspForms(1,12) ; R = PowerSeriesRing(QQ,'q') ; q = R.0
sage: f = q+O(q^2) ; S(f)
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)
sage: f = q+2*q^2+O(q^3) ; S(f)
Traceback (most recent call last):
...
ValueError: q-expansion does not correspond to a form in self
sage: f = q-24*q^2+O(q^3) ; S(f)
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)
"""
if isinstance(x, element.ModularFormElement):
if x.parent() is self:
return x
if not check:
from copy import copy
f = copy(x)
f._set_parent(self)
return f
try:
if x.parent()._has_natural_inclusion_map_to(self.ambient()):
W = self._q_expansion_module()
return self(x.q_expansion(W.degree()))
except NotImplementedError:
pass
raise TypeError, "unable to coerce x (= %s) into %s"%(x, self)
elif rings.is_PowerSeries(x):
W = self._q_expansion_module()
if W.degree() <= x.prec():
try:
x_potential = W.coordinates(x.padded_list(W.degree()))
except ArithmeticError:
raise ValueError, "q-expansion does not correspond to a form in self"
x_potential = self.free_module().linear_combination_of_basis(x_potential)
x_potential = element.ModularFormElement(self, x_potential)
for i in range(int(W.degree()), x.prec()):
if x_potential[i] != x[i]:
raise ValueError, "q-expansion does not correspond to a form in self"
return x_potential
else:
raise TypeError, "q-expansion needed to at least precision %s"%W.degree()
return element.ModularFormElement(self, self.free_module()(x,check))
def __cmp__(self, x):
"""
Compare self and x.
For spaces of modular forms, we order first by signature, then by
dimension, and then by the ordering on the underlying free
modules.
EXAMPLES::
sage: N = ModularForms(6,4) ; S = N.cuspidal_subspace()
sage: S.__cmp__(N)
-1
sage: N.__cmp__(S)
1
sage: N.__cmp__(N)
0
sage: M = ModularForms(11,2)
sage: N.__cmp__(M)
-1
sage: M.__cmp__(N)
-1
"""
from sage.modular.modform.constructor import canonical_parameters as params
if self is x:
return 0
if not isinstance(x, ModularFormsSpace):
return cmp( type(self), type(x) )
left_ambient = self.ambient()
right_ambient = x.ambient()
if params(left_ambient.character(), left_ambient.level(),
left_ambient.weight(), left_ambient.base_ring()) != \
params(right_ambient.character(), right_ambient.level(),
right_ambient.weight(), right_ambient.base_ring()):
return -1
if self.is_ambient() or x.is_ambient():
return cmp(self.dimension(), x.dimension())
else:
return cmp(self.free_module(), x.free_module())
def span_of_basis(self, B):
"""
Take a set B of forms, and return the subspace of self with B as a
basis.
EXAMPLES::
sage: N = ModularForms(6,4) ; N
Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
::
sage: N.span_of_basis([N.basis()[0]])
Modular Forms subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
::
sage: N.span_of_basis([N.basis()[0], N.basis()[1]])
Modular Forms subspace of dimension 2 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
::
sage: N.span_of_basis( N.basis() )
Modular Forms subspace of dimension 5 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
"""
W = self._q_expansion_module()
F = self.free_module()
prec = W.degree()
C = [F.linear_combination_of_basis(W.coordinates(f.padded_list(prec))) for f in B]
S = F.span_of_basis(C)
return submodule.ModularFormsSubmoduleWithBasis(self.ambient(), S)
span = span_of_basis
def __submodule_from_subset_of_basis(self, x):
"""
Return the submodule of self generated by the elements of x.
EXAMPLES::
sage: N = ModularForms(6,4)
sage: N._ModularFormsSpace__submodule_from_subset_of_basis( [0,2] )
Vector space of degree 5 and dimension 2 over Rational Field
Basis matrix:
[1 0 0 0 0]
[0 0 1 0 0]
"""
V = self.free_module()
return V.submodule([V.gen(i) for i in x], check=False)
def _compute_hecke_matrix_prime(self, p, prec=None):
"""
Compute the matrix of the Hecke operator T_p acting on self.
EXAMPLES::
sage: M = ModularForms(11,2)
sage: M._compute_hecke_matrix_prime(2)
[-2 0]
[ 0 3]
::
sage: M = ModularForms(11,2)
sage: M2 = M.span([M.0 + M.1])
sage: M2.hecke_matrix(2)
Traceback (most recent call last):
...
ArithmeticError: vector is not in free module
"""
if prec is None:
prec = p*self.dimension() + 8
try:
cur, _ = self.__q_expansion_basis
except AttributeError:
pass
else:
if prec < cur:
prec = cur
B = self.q_expansion_basis(prec)
eps = self.character()
if eps is None:
raise NotImplementedError
try:
return hecke_operator_on_qexp.hecke_operator_on_basis(B, p,
self.weight(), eps, already_echelonized=False)
except ValueError:
return self._compute_hecke_matrix_prime(p, prec = 2*prec+1)
def _compute_hecke_matrix(self, n):
"""
Compute the matrix of the Hecke operator T_n acting on self.
EXAMPLES::
sage: M = ModularForms(11,2)
sage: M._compute_hecke_matrix(6)
[ 2 0]
[ 0 12]
::
sage: M = ModularForms(11,2)
sage: M2 = M.span([M.0 + M.1])
sage: M2.hecke_matrix(2)
Traceback (most recent call last):
...
ArithmeticError: vector is not in free module
We check that #10450 is fixed::
sage: M = CuspForms(Gamma1(22), 2).new_submodule() # long time (3s on sage.math, 2011)
sage: M.hecke_matrix(3) # long time
[ 0 -2 3 0]
[ 0 -3 5 -1]
[ 1 -1 0 -1]
[ 0 -2 3 -1]
sage: M.hecke_matrix(9) # long time
[ 3 3 -4 -4]
[ 2 6 -9 -4]
[ 0 3 -2 -1]
[ 3 2 -7 0]
"""
if hasattr(self, '_compute_q_expansion_basis') and self.character() is not None:
return hecke.HeckeModule_generic._compute_hecke_matrix(self, n)
else:
if self.is_cuspidal():
M = self.ambient().cuspidal_submodule().hecke_matrix(n).block_sum(zero_matrix(self.base_ring(), self.ambient().eisenstein_submodule().rank()))
elif self.is_eisenstein():
M = zero_matrix(self.base_ring(), self.ambient().cuspidal_submodule().rank()).block_sum(self.ambient().eisenstein_submodule().hecke_matrix(n))
else:
M = self.ambient().hecke_matrix(n)
return M.restrict(self.free_module(), check=(gcd(n, self.level()) > 1))
def basis(self):
"""
Return a basis for self.
EXAMPLES::
sage: MM = ModularForms(11,2)
sage: MM.basis()
[
q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6),
1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6)
]
"""
try:
return self.__basis
except AttributeError:
self.__basis = Sequence([element.ModularFormElement(self, x) for \
x in self.free_module().basis()], immutable=True,
cr = True)
return self.__basis
def gen(self, n):
"""
Return the nth generator of self.
EXAMPLES::
sage: N = ModularForms(6,4)
sage: N.basis()
[
q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6),
1 + O(q^6),
q - 8*q^4 + 126*q^5 + O(q^6),
q^2 + 9*q^4 + O(q^6),
q^3 + O(q^6)
]
::
sage: N.gen(0)
q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6)
::
sage: N.gen(4)
q^3 + O(q^6)
::
sage: N.gen(5)
Traceback (most recent call last):
...
ValueError: Generator 5 not defined
"""
try:
return self.basis()[int(n)]
except IndexError:
raise ValueError, "Generator %s not defined"%n
def gens(self):
"""
Return a complete set of generators for self.
EXAMPLES::
sage: N = ModularForms(6,4)
sage: N.gens()
[
q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6),
1 + O(q^6),
q - 8*q^4 + 126*q^5 + O(q^6),
q^2 + 9*q^4 + O(q^6),
q^3 + O(q^6)
]
"""
return self.basis()
def sturm_bound(self, M=None):
r"""
For a space M of modular forms, this function returns an integer B
such that two modular forms in either self or M are equal if and
only if their q-expansions are equal to precision B (note that this
is 1+ the usual Sturm bound, since `O(q^\mathrm{prec})` has
precision prec). If M is none, then M is set equal to self.
EXAMPLES::
sage: S37=CuspForms(37,2)
sage: S37.sturm_bound()
8
sage: M = ModularForms(11,2)
sage: M.sturm_bound()
3
sage: ModularForms(Gamma1(15),2).sturm_bound()
33
sage: CuspForms(Gamma1(144), 3).sturm_bound()
3457
sage: CuspForms(DirichletGroup(144).1^2, 3).sturm_bound()
73
sage: CuspForms(Gamma0(144), 3).sturm_bound()
73
REFERENCE:
- [Sturm] J. Sturm, On the congruence of modular forms, Number theory
(New York, 1984-1985), Springer, Berlin, 1987, pp. 275-280.
NOTE:
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\cong 0\pmod{p}` for first `s` coefficients, then
`f^r = 0 \pmod{p}` for first `s r` coefficients.
Since the weight of `f^r` is
`r \text{weight}(f)`, it follows that if
`s \geq` the Sturm bound for `\Gamma_0` at
weight(f), then `f^r` has valuation large enough to be
forced to be `0` at `r\cdot` weight(f) by Sturm
bound (which is valid if we choose `r` right). Thus
`f \cong 0 \pmod{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
`\ZZ[\varepsilon]` generators for the Hecke algebra
here, not `\ZZ`-generators. So if one wants
generators for the Hecke algebra over `\ZZ`, this
bound is wrong.
This bound works over any base, even a finite field. There might be
much better bounds over `\QQ`, or for comparing two
eigenforms.
"""
if M is not None:
raise NotImplementedError
if self.__sturm_bound is None:
G = self.group()
from sage.modular.arithgroup.all import is_Gamma1
if is_Gamma1(G) and self.character() is not None:
from sage.modular.arithgroup.all import Gamma0
G = Gamma0(self.level())
self.__sturm_bound = G.sturm_bound(self.weight())+1
return self.__sturm_bound
def character(self):
"""
Return the Dirichlet character of this space.
EXAMPLES::
sage: M = ModularForms(DirichletGroup(11).0, 3)
sage: M.character()
Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta10
sage: s = M.cuspidal_submodule()
sage: s.character()
Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta10
sage: CuspForms(DirichletGroup(11).0,3).character()
Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta10
"""
return self.__character
def cuspidal_submodule(self):
"""
Return the cuspidal submodule of self.
EXAMPLES::
sage: N = ModularForms(6,4) ; N
Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
sage: N.eisenstein_subspace().dimension()
4
::
sage: N.cuspidal_submodule()
Cuspidal subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
::
sage: N.cuspidal_submodule().dimension()
1
We check that a bug noticed on trac #10450 is fixed::
sage: M = ModularForms(6, 10)
sage: W = M.span_of_basis(M.basis()[0:2])
sage: W.cuspidal_submodule()
Modular Forms subspace of dimension 2 of Modular Forms space of dimension 11 for Congruence Subgroup Gamma0(6) of weight 10 over Rational Field
"""
try:
if self.__is_cuspidal == True:
return self
if self.__cuspidal_submodule != None:
return self.__cuspidal_submodule
except AttributeError:
pass
if self.is_ambient():
n = self.__ambient_cusp_dimension()
W = self.__submodule_from_subset_of_basis(range(n))
S = ModularForms(self, W)
S.__is_cuspidal = True
S.__is_eisenstein = (n==0)
self.__cuspidal_submodule = S
return S
C = self.ambient_module().cuspidal_submodule()
S = self.intersection(C)
if S.dimension() < self.dimension():
self.__is_cuspidal = False
self.__cuspidal_submodule = S
else:
assert S.dimension() == self.dimension()
self.__is_cuspidal = True
S.__is_eisenstein = (S.dimension()==0)
return S
def cuspidal_subspace(self):
"""
Synonym for cuspidal_submodule.
EXAMPLES::
sage: N = ModularForms(6,4) ; N
Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
sage: N.eisenstein_subspace().dimension()
4
::
sage: N.cuspidal_subspace()
Cuspidal subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
::
sage: N.cuspidal_submodule().dimension()
1
"""
return self.cuspidal_submodule()
def is_cuspidal(self):
r"""
Return True if this space is cuspidal.
EXAMPLE::
sage: M = ModularForms(Gamma0(11), 2).new_submodule()
sage: M.is_cuspidal()
False
sage: M.cuspidal_submodule().is_cuspidal()
True
"""
return (self.cuspidal_submodule() == self)
def is_eisenstein(self):
r"""
Return True if this space is Eisenstein.
EXAMPLE::
sage: M = ModularForms(Gamma0(11), 2).new_submodule()
sage: M.is_eisenstein()
False
sage: M.eisenstein_submodule().is_eisenstein()
True
"""
return (self.eisenstein_submodule() == self)
def new_submodule(self, p=None):
"""
Return the new submodule of self. If p is specified, return the
p-new submodule of self.
.. note::
This function should be overridden by all derived classes.
EXAMPLES::
sage: M = sage.modular.modform.space.ModularFormsSpace(Gamma0(11),2,DirichletGroup(1).0,base_ring=QQ) ; M.new_submodule()
Traceback (most recent call last):
...
NotImplementedError: computation of new submodule not yet implemented
"""
raise NotImplementedError, "computation of new submodule not yet implemented"
def new_subspace(self, p=None):
"""
Synonym for new_submodule.
EXAMPLES::
sage: M = sage.modular.modform.space.ModularFormsSpace(Gamma0(11),2,DirichletGroup(1).0,base_ring=QQ) ; M.new_subspace()
Traceback (most recent call last):
...
NotImplementedError: computation of new submodule not yet implemented
"""
return self.new_submodule(p)
def eisenstein_series(self):
"""
Compute the Eisenstein series associated to this space.
.. note::
This function should be overridden by all derived classes.
EXAMPLES::
sage: M = sage.modular.modform.space.ModularFormsSpace(Gamma0(11),2,DirichletGroup(1).0,base_ring=QQ) ; M.eisenstein_series()
Traceback (most recent call last):
...
NotImplementedError: computation of Eisenstein series in this space not yet implemented
"""
raise NotImplementedError, "computation of Eisenstein series in this space not yet implemented"
def decomposition(self):
"""
This function returns a list of submodules `V(f_i,t)`
corresponding to newforms `f_i` of some level dividing the
level of self, such that the direct sum of the submodules equals
self, if possible. The space `V(f_i,t)` is the image under
`g(q)` maps to `g(q^t)` of the intersection with
`R[[q]]` of the space spanned by the conjugates of
`f_i`, where `R` is the base ring of self.
TODO: Implement this function.
EXAMPLES::
sage: M = ModularForms(11,2); M.decomposition()
Traceback (most recent call last):
...
NotImplementedError
"""
raise NotImplementedError
def newforms(self, names=None):
"""
Return all newforms in the cuspidal subspace of self.
EXAMPLES::
sage: CuspForms(18,4).newforms()
[q + 2*q^2 + 4*q^4 - 6*q^5 + O(q^6)]
sage: CuspForms(32,4).newforms()
[q - 8*q^3 - 10*q^5 + O(q^6), q + 22*q^5 + O(q^6), q + 8*q^3 - 10*q^5 + O(q^6)]
sage: CuspForms(23).newforms('b')
[q + b0*q^2 + (-2*b0 - 1)*q^3 + (-b0 - 1)*q^4 + 2*b0*q^5 + O(q^6)]
sage: CuspForms(23).newforms()
Traceback (most recent call last):
...
ValueError: Please specify a name to be used when generating names for generators of Hecke eigenvalue fields corresponding to the newforms.
"""
M = self.modular_symbols(sign=1)
factors = M.cuspidal_subspace().new_subspace().decomposition()
large_dims = [ X.dimension() for X in factors if X.dimension() != 1 ]
if len(large_dims) > 0 and names is None:
raise ValueError, "Please specify a name to be used when generating names for generators of Hecke eigenvalue fields corresponding to the newforms."
elif names is None:
names = 'a'
return [ element.Newform(self, factors[i], names=(names+str(i)) )
for i in range(len(factors)) ]
def eisenstein_submodule(self):
"""
Return the Eisenstein submodule for this space of modular forms.
EXAMPLES::
sage: M = ModularForms(11,2)
sage: M.eisenstein_submodule()
Eisenstein subspace of dimension 1 of Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
We check that a bug noticed on trac #10450 is fixed::
sage: M = ModularForms(6, 10)
sage: W = M.span_of_basis(M.basis()[0:2])
sage: W.eisenstein_submodule()
Modular Forms subspace of dimension 0 of Modular Forms space of dimension 11 for Congruence Subgroup Gamma0(6) of weight 10 over Rational Field
"""
try:
if self.__is_eisenstein == True:
return self
except AttributeError:
pass
try:
if self.__eisenstein_submodule != None:
return self.__eisenstein_submodule
except AttributeError:
pass
if self.is_ambient():
n = self.__ambient_cusp_dimension()
d = self.__ambient_eis_dimension()
W = self.__submodule_from_subset_of_basis(range(n,n+d))
E = ModularForms(self, W)
E.__is_eisenstein = True
E.__is_cuspidal = (d==0)
self.__eisenstein_submodule = E
return E
A = self.ambient_module().eisenstein_submodule()
E = self.intersection(A)
if E.dimension() < self.dimension():
self.__is_eisenstein = False
self.__eisenstein_submodule = E
else:
assert E.dimension() == self.dimension()
self.__is_eisenstein = True
E.__is_cuspidal = (E.dimension()==0)
return E
def eisenstein_subspace(self):
"""
Synonym for eisenstein_submodule.
EXAMPLES::
sage: M = ModularForms(11,2)
sage: M.eisenstein_subspace()
Eisenstein subspace of dimension 1 of Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
"""
return self.eisenstein_submodule()
def embedded_submodule(self):
"""
Return the underlying module of self.
EXAMPLES::
sage: N = ModularForms(6,4)
sage: N.dimension()
5
::
sage: N.embedded_submodule()
Vector space of dimension 5 over Rational Field
"""
return self.free_module()
def level(self):
"""
Return the level of self.
EXAMPLES::
sage: M = ModularForms(47,3)
sage: M.level()
47
"""
return self.group().level()
def modular_symbols(self, sign=0):
"""
Return the space of modular symbols corresponding to self with the
given sign.
.. note;:
This function should be overridden by all derived classes.
EXAMPLES::
sage: M = sage.modular.modform.space.ModularFormsSpace(Gamma0(11),2,DirichletGroup(1).0,base_ring=QQ) ; M.modular_symbols()
Traceback (most recent call last):
...
NotImplementedError: computation of associated modular symbols space not yet implemented
"""
raise NotImplementedError, "computation of associated modular symbols space not yet implemented"
def find_in_space(self, f, forms=None, prec=None, indep=True):
"""
INPUT:
- ``f`` - a modular form or power series
- ``forms`` - (default: None) a specific list of
modular forms or q-expansions.
- ``prec`` - if forms are given, compute with them to
the given precision
- ``indep`` - (default: True) whether the given list
of forms are assumed to form a basis.
OUTPUT: A list of numbers that give f as a linear combination of
the basis for this space or of the given forms if
independent=True.
.. note::
If the list of forms is given, they do *not* have to be in
self.
EXAMPLES::
sage: M = ModularForms(11,2)
sage: N = ModularForms(10,2)
sage: M.find_in_space( M.basis()[0] )
[1, 0]
::
sage: M.find_in_space( N.basis()[0], forms=N.basis() )
[1, 0, 0]
::
sage: M.find_in_space( N.basis()[0] )
Traceback (most recent call last):
...
ArithmeticError: vector is not in free module
"""
if forms is None or (forms == []):
B = self._q_expansion_module()
V = B.ambient_module()
n = B.degree()
else:
if not isinstance(forms, (list, tuple)):
raise TypeError, "forms must be a list or tuple"
if prec is None:
n = forms[0].parent().prec()
else:
n = prec
V = self.base_ring()**n
w = [V(g.padded_list(n)) for g in forms]
if indep:
B = V.span_of_basis(w)
else:
B = V.span(w)
if rings.is_PowerSeries(f) and f.prec() < n:
raise ValueError, "you need at least %s terms of precision"%n
x = V(f.padded_list(n))
return B.coordinates(x)
def contains_each(V, B):
"""
Determine whether or not V contains every element of B. Used here
for linear algebra, but works very generally.
EXAMPLES::
sage: contains_each = sage.modular.modform.space.contains_each
sage: contains_each( range(20), prime_range(20) )
True
sage: contains_each( range(20), range(30) )
False
"""
for b in B:
if not (b in V):
return False
return True