Creating spaces of modular forms

EXAMPLES:

sage: m = ModularForms(Gamma1(4),11)
sage: m
Modular Forms space of dimension 6 for
 Congruence Subgroup Gamma1(4) of weight 11 over Rational Field
sage: m.basis()
[
q - 134*q^5 + O(q^6),
q^2 + 80*q^5 + O(q^6),
q^3 + 16*q^5 + O(q^6),
q^4 - 4*q^5 + O(q^6),
1 + 4092/50521*q^2 + 472384/50521*q^3 + 4194300/50521*q^4 + O(q^6),
q + 1024*q^2 + 59048*q^3 + 1048576*q^4 + 9765626*q^5 + O(q^6)
]
>>> from sage.all import *
>>> m = ModularForms(Gamma1(Integer(4)),Integer(11))
>>> m
Modular Forms space of dimension 6 for
 Congruence Subgroup Gamma1(4) of weight 11 over Rational Field
>>> m.basis()
[
q - 134*q^5 + O(q^6),
q^2 + 80*q^5 + O(q^6),
q^3 + 16*q^5 + O(q^6),
q^4 - 4*q^5 + O(q^6),
1 + 4092/50521*q^2 + 472384/50521*q^3 + 4194300/50521*q^4 + O(q^6),
q + 1024*q^2 + 59048*q^3 + 1048576*q^4 + 9765626*q^5 + O(q^6)
]
m = ModularForms(Gamma1(4),11)
m
m.basis()
sage.modular.modform.constructor.CuspForms(group=1, weight=2, base_ring=None, use_cache=True, prec=6)[source]

Create a space of cuspidal modular forms.

See the documentation for the ModularForms command for a description of the input parameters.

EXAMPLES:

sage: CuspForms(11,2)
Cuspidal subspace of dimension 1 of Modular Forms space of dimension 2
 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
>>> from sage.all import *
>>> CuspForms(Integer(11),Integer(2))
Cuspidal subspace of dimension 1 of Modular Forms space of dimension 2
 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
CuspForms(11,2)
sage.modular.modform.constructor.EisensteinForms(group=1, weight=2, base_ring=None, use_cache=True, prec=6)[source]

Create a space of Eisenstein modular forms.

See the documentation for the ModularForms command for a description of the input parameters.

EXAMPLES:

sage: EisensteinForms(11,2)
Eisenstein subspace of dimension 1 of Modular Forms space of dimension 2
 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
>>> from sage.all import *
>>> EisensteinForms(Integer(11),Integer(2))
Eisenstein subspace of dimension 1 of Modular Forms space of dimension 2
 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
EisensteinForms(11,2)
sage.modular.modform.constructor.ModularForms(group=1, weight=2, base_ring=None, eis_only=False, use_cache=True, prec=6)[source]

Create an ambient space of modular forms.

INPUT:

  • group – a congruence subgroup or a Dirichlet character eps

  • weight – integer; the weight (\(\geq 1\))

  • base_ring – the base ring (ignored if group is a Dirichlet character)

  • eis_only – if True, compute only the Eisenstein part of the space. Only permitted (and only useful) in weight 1, where computing dimensions of cusp form spaces is expensive.

Create using the command ModularForms(group, weight, base_ring) where group could be either a congruence subgroup or a Dirichlet character.

EXAMPLES: First we create some spaces with trivial character:

sage: ModularForms(Gamma0(11),2).dimension()
2
sage: ModularForms(Gamma0(1),12).dimension()
2
>>> from sage.all import *
>>> ModularForms(Gamma0(Integer(11)),Integer(2)).dimension()
2
>>> ModularForms(Gamma0(Integer(1)),Integer(12)).dimension()
2
ModularForms(Gamma0(11),2).dimension()
ModularForms(Gamma0(1),12).dimension()

If we give an integer N for the congruence subgroup, it defaults to \(\Gamma_0(N)\):

sage: ModularForms(1,12).dimension()
2
sage: ModularForms(11,4)
Modular Forms space of dimension 4 for Congruence Subgroup Gamma0(11)
 of weight 4 over Rational Field
>>> from sage.all import *
>>> ModularForms(Integer(1),Integer(12)).dimension()
2
>>> ModularForms(Integer(11),Integer(4))
Modular Forms space of dimension 4 for Congruence Subgroup Gamma0(11)
 of weight 4 over Rational Field
ModularForms(1,12).dimension()
ModularForms(11,4)

We create some spaces for \(\Gamma_1(N)\).

sage: ModularForms(Gamma1(13),2)
Modular Forms space of dimension 13 for Congruence Subgroup Gamma1(13)
 of weight 2 over Rational Field
sage: ModularForms(Gamma1(13),2).dimension()
13
sage: [ModularForms(Gamma1(7),k).dimension() for k in [2,3,4,5]]
[5, 7, 9, 11]
sage: ModularForms(Gamma1(5),11).dimension()
12
>>> from sage.all import *
>>> ModularForms(Gamma1(Integer(13)),Integer(2))
Modular Forms space of dimension 13 for Congruence Subgroup Gamma1(13)
 of weight 2 over Rational Field
>>> ModularForms(Gamma1(Integer(13)),Integer(2)).dimension()
13
>>> [ModularForms(Gamma1(Integer(7)),k).dimension() for k in [Integer(2),Integer(3),Integer(4),Integer(5)]]
[5, 7, 9, 11]
>>> ModularForms(Gamma1(Integer(5)),Integer(11)).dimension()
12
ModularForms(Gamma1(13),2)
ModularForms(Gamma1(13),2).dimension()
[ModularForms(Gamma1(7),k).dimension() for k in [2,3,4,5]]
ModularForms(Gamma1(5),11).dimension()

We create a space with character:

sage: # needs sage.rings.number_field
sage: e = (DirichletGroup(13).0)^2
sage: e.order()
6
sage: M = ModularForms(e, 2); M
Modular Forms space of dimension 3, character [zeta6] and weight 2
 over Cyclotomic Field of order 6 and degree 2
sage: f = M.T(2).charpoly('x'); f
x^3 + (-2*zeta6 - 2)*x^2 - 2*zeta6*x + 14*zeta6 - 7
sage: f.factor()
(x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> e = (DirichletGroup(Integer(13)).gen(0))**Integer(2)
>>> e.order()
6
>>> M = ModularForms(e, Integer(2)); M
Modular Forms space of dimension 3, character [zeta6] and weight 2
 over Cyclotomic Field of order 6 and degree 2
>>> f = M.T(Integer(2)).charpoly('x'); f
x^3 + (-2*zeta6 - 2)*x^2 - 2*zeta6*x + 14*zeta6 - 7
>>> f.factor()
(x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)
# needs sage.rings.number_field
e = (DirichletGroup(13).0)^2
e.order()
M = ModularForms(e, 2); M
f = M.T(2).charpoly('x'); f
f.factor()

We can also create spaces corresponding to the groups \(\Gamma_H(N)\) intermediate between \(\Gamma_0(N)\) and \(\Gamma_1(N)\):

sage: G = GammaH(30, [11])
sage: M = ModularForms(G, 2); M
Modular Forms space of dimension 20 for Congruence Subgroup Gamma_H(30)
 with H generated by [11] of weight 2 over Rational Field
sage: M.T(7).charpoly().factor()  # long time (7s on sage.math, 2011)
(x + 4) * x^2 * (x - 6)^4 * (x + 6)^4 * (x - 8)^7 * (x^2 + 4)
>>> from sage.all import *
>>> G = GammaH(Integer(30), [Integer(11)])
>>> M = ModularForms(G, Integer(2)); M
Modular Forms space of dimension 20 for Congruence Subgroup Gamma_H(30)
 with H generated by [11] of weight 2 over Rational Field
>>> M.T(Integer(7)).charpoly().factor()  # long time (7s on sage.math, 2011)
(x + 4) * x^2 * (x - 6)^4 * (x + 6)^4 * (x - 8)^7 * (x^2 + 4)
G = GammaH(30, [11])
M = ModularForms(G, 2); M
M.T(7).charpoly().factor()  # long time (7s on sage.math, 2011)

More examples of spaces with character:

sage: e = DirichletGroup(5, RationalField()).gen(); e
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1

sage: m = ModularForms(e, 2); m
Modular Forms space of dimension 2, character [-1] and weight 2
 over Rational Field
sage: m == loads(dumps(m))
True
sage: m.T(2).charpoly('x')
x^2 - 1
sage: m = ModularForms(e, 6); m.dimension()
4
sage: m.T(2).charpoly('x')
x^4 - 917*x^2 - 42284
>>> from sage.all import *
>>> e = DirichletGroup(Integer(5), RationalField()).gen(); e
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1

>>> m = ModularForms(e, Integer(2)); m
Modular Forms space of dimension 2, character [-1] and weight 2
 over Rational Field
>>> m == loads(dumps(m))
True
>>> m.T(Integer(2)).charpoly('x')
x^2 - 1
>>> m = ModularForms(e, Integer(6)); m.dimension()
4
>>> m.T(Integer(2)).charpoly('x')
x^4 - 917*x^2 - 42284
e = DirichletGroup(5, RationalField()).gen(); e
m = ModularForms(e, 2); m
m == loads(dumps(m))
m.T(2).charpoly('x')
m = ModularForms(e, 6); m.dimension()
m.T(2).charpoly('x')

This came up in a subtle bug (Issue #5923):

sage: ModularForms(gp(1), gap(12))
Modular Forms space of dimension 2 for Modular Group SL(2,Z)
 of weight 12 over Rational Field
>>> from sage.all import *
>>> ModularForms(gp(Integer(1)), gap(Integer(12)))
Modular Forms space of dimension 2 for Modular Group SL(2,Z)
 of weight 12 over Rational Field
ModularForms(gp(1), gap(12))

This came up in another bug (related to Issue #8630):

sage: chi = DirichletGroup(109, CyclotomicField(3)).0
sage: ModularForms(chi, 2, base_ring = CyclotomicField(15))
Modular Forms space of dimension 10, character [zeta3 + 1] and weight 2
 over Cyclotomic Field of order 15 and degree 8
>>> from sage.all import *
>>> chi = DirichletGroup(Integer(109), CyclotomicField(Integer(3))).gen(0)
>>> ModularForms(chi, Integer(2), base_ring = CyclotomicField(Integer(15)))
Modular Forms space of dimension 10, character [zeta3 + 1] and weight 2
 over Cyclotomic Field of order 15 and degree 8
chi = DirichletGroup(109, CyclotomicField(3)).0
ModularForms(chi, 2, base_ring = CyclotomicField(15))

We create some weight 1 spaces. Here modular symbol algorithms do not work. In some small examples we can prove using Riemann–Roch that there are no cusp forms anyway, so the entire space is Eisenstein:

sage: M = ModularForms(Gamma1(11), 1); M
Modular Forms space of dimension 5 for Congruence Subgroup Gamma1(11)
 of weight 1 over Rational Field
sage: M.basis()
[
1 + 22*q^5 + O(q^6),
q + 4*q^5 + O(q^6),
q^2 - 4*q^5 + O(q^6),
q^3 - 5*q^5 + O(q^6),
q^4 - 3*q^5 + O(q^6)
]
sage: M.cuspidal_subspace().basis()
[
]
sage: M == M.eisenstein_subspace()
True
>>> from sage.all import *
>>> M = ModularForms(Gamma1(Integer(11)), Integer(1)); M
Modular Forms space of dimension 5 for Congruence Subgroup Gamma1(11)
 of weight 1 over Rational Field
>>> M.basis()
[
1 + 22*q^5 + O(q^6),
q + 4*q^5 + O(q^6),
q^2 - 4*q^5 + O(q^6),
q^3 - 5*q^5 + O(q^6),
q^4 - 3*q^5 + O(q^6)
]
>>> M.cuspidal_subspace().basis()
[
]
>>> M == M.eisenstein_subspace()
True
M = ModularForms(Gamma1(11), 1); M
M.basis()
M.cuspidal_subspace().basis()
M == M.eisenstein_subspace()

When this does not work (which happens as soon as the level is more than about 30), we use the Hecke stability algorithm of George Schaeffer:

sage: M = ModularForms(Gamma1(57), 1); M  # long time
Modular Forms space of dimension 38 for Congruence Subgroup Gamma1(57)
 of weight 1 over Rational Field
sage: M.cuspidal_submodule().basis()      # long time
[
q - q^4 + O(q^6),
q^3 - q^4 + O(q^6)
]
>>> from sage.all import *
>>> M = ModularForms(Gamma1(Integer(57)), Integer(1)); M  # long time
Modular Forms space of dimension 38 for Congruence Subgroup Gamma1(57)
 of weight 1 over Rational Field
>>> M.cuspidal_submodule().basis()      # long time
[
q - q^4 + O(q^6),
q^3 - q^4 + O(q^6)
]
M = ModularForms(Gamma1(57), 1); M  # long time
M.cuspidal_submodule().basis()      # long time

The Eisenstein subspace in weight 1 can be computed quickly, without triggering the expensive computation of the cuspidal part:

sage: E = EisensteinForms(Gamma1(59), 1); E  # indirect doctest
Eisenstein subspace of dimension 29 of Modular Forms space for
 Congruence Subgroup Gamma1(59) of weight 1 over Rational Field
sage: (E.0 + E.2).q_expansion(40)
1 + q^2 + 196*q^29 - 197*q^30 - q^31 + q^33 + q^34 + q^37 + q^38 - q^39 + O(q^40)
>>> from sage.all import *
>>> E = EisensteinForms(Gamma1(Integer(59)), Integer(1)); E  # indirect doctest
Eisenstein subspace of dimension 29 of Modular Forms space for
 Congruence Subgroup Gamma1(59) of weight 1 over Rational Field
>>> (E.gen(0) + E.gen(2)).q_expansion(Integer(40))
1 + q^2 + 196*q^29 - 197*q^30 - q^31 + q^33 + q^34 + q^37 + q^38 - q^39 + O(q^40)
E = EisensteinForms(Gamma1(59), 1); E  # indirect doctest
(E.0 + E.2).q_expansion(40)
sage.modular.modform.constructor.ModularForms_clear_cache()[source]

Clear the cache of modular forms.

EXAMPLES:

sage: M = ModularForms(37,2)
sage: sage.modular.modform.constructor._cache == {}
False
>>> from sage.all import *
>>> M = ModularForms(Integer(37),Integer(2))
>>> sage.modular.modform.constructor._cache == {}
False
M = ModularForms(37,2)
sage.modular.modform.constructor._cache == {}
sage: sage.modular.modform.constructor.ModularForms_clear_cache()
sage: sage.modular.modform.constructor._cache
{}
>>> from sage.all import *
>>> sage.modular.modform.constructor.ModularForms_clear_cache()
>>> sage.modular.modform.constructor._cache
{}
sage.modular.modform.constructor.ModularForms_clear_cache()
sage.modular.modform.constructor._cache
>>> from sage.all import *
>>> sage.modular.modform.constructor.ModularForms_clear_cache()
>>> sage.modular.modform.constructor._cache
{}
sage.modular.modform.constructor.ModularForms_clear_cache()
sage.modular.modform.constructor._cache
sage.modular.modform.constructor.Newform(identifier, group=None, weight=2, base_ring=Rational Field, names=None)[source]

INPUT:

  • identifier – a canonical label, or the index of the specific newform desired

  • group – the congruence subgroup of the newform

  • weight – the weight of the newform (default: 2)

  • base_ring – the base ring

  • names – if the newform has coefficients in a number field, a generator name must be specified

EXAMPLES:

sage: Newform('67a', names='a')
q + 2*q^2 - 2*q^3 + 2*q^4 + 2*q^5 + O(q^6)
sage: Newform('67b', names='a')
q + a1*q^2 + (-a1 - 3)*q^3 + (-3*a1 - 3)*q^4 - 3*q^5 + O(q^6)
>>> from sage.all import *
>>> Newform('67a', names='a')
q + 2*q^2 - 2*q^3 + 2*q^4 + 2*q^5 + O(q^6)
>>> Newform('67b', names='a')
q + a1*q^2 + (-a1 - 3)*q^3 + (-3*a1 - 3)*q^4 - 3*q^5 + O(q^6)
Newform('67a', names='a')
Newform('67b', names='a')
sage.modular.modform.constructor.Newforms(group, weight=2, base_ring=None, names=None)[source]

Return a list of the newforms of the given weight and level (or weight, level and character). These are calculated as \(\operatorname{Gal}(\overline{F} / F)\)-orbits, where \(F\) is the given base field.

INPUT:

  • group – the congruence subgroup of the newform, or a Nebentypus character

  • weight – the weight of the newform (default: 2)

  • base_ring – the base ring (defaults to \(\QQ\) for spaces without character, or the base ring of the character otherwise)

  • names – if the newform has coefficients in a number field, a generator name must be specified

EXAMPLES:

sage: Newforms(11, 2)
[q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)]
sage: Newforms(65, names='a')
[q - q^2 - 2*q^3 - q^4 - q^5 + O(q^6),
 q + a1*q^2 + (a1 + 1)*q^3 + (-2*a1 - 1)*q^4 + q^5 + O(q^6),
 q + a2*q^2 + (-a2 + 1)*q^3 + q^4 - q^5 + O(q^6)]
>>> from sage.all import *
>>> Newforms(Integer(11), Integer(2))
[q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)]
>>> Newforms(Integer(65), names='a')
[q - q^2 - 2*q^3 - q^4 - q^5 + O(q^6),
 q + a1*q^2 + (a1 + 1)*q^3 + (-2*a1 - 1)*q^4 + q^5 + O(q^6),
 q + a2*q^2 + (-a2 + 1)*q^3 + q^4 - q^5 + O(q^6)]
Newforms(11, 2)
Newforms(65, names='a')

A more complicated example involving both a nontrivial character, and a base field that is not minimal for that character:

sage: K.<i> = QuadraticField(-1)
sage: chi = DirichletGroup(5, K)[1]
sage: len(Newforms(chi, 7, names='a'))
1
sage: x = polygen(K); L.<c> = K.extension(x^2 - 402*i)
sage: N = Newforms(chi, 7, base_ring = L); len(N)
2
sage: sorted([N[0][2], N[1][2]]) == sorted([1/2*c - 5/2*i - 5/2, -1/2*c - 5/2*i - 5/2])
True
>>> from sage.all import *
>>> K = QuadraticField(-Integer(1), names=('i',)); (i,) = K._first_ngens(1)
>>> chi = DirichletGroup(Integer(5), K)[Integer(1)]
>>> len(Newforms(chi, Integer(7), names='a'))
1
>>> x = polygen(K); L = K.extension(x**Integer(2) - Integer(402)*i, names=('c',)); (c,) = L._first_ngens(1)
>>> N = Newforms(chi, Integer(7), base_ring = L); len(N)
2
>>> sorted([N[Integer(0)][Integer(2)], N[Integer(1)][Integer(2)]]) == sorted([Integer(1)/Integer(2)*c - Integer(5)/Integer(2)*i - Integer(5)/Integer(2), -Integer(1)/Integer(2)*c - Integer(5)/Integer(2)*i - Integer(5)/Integer(2)])
True
K.<i> = QuadraticField(-1)
chi = DirichletGroup(5, K)[1]
len(Newforms(chi, 7, names='a'))
x = polygen(K); L.<c> = K.extension(x^2 - 402*i)
N = Newforms(chi, 7, base_ring = L); len(N)
sorted([N[0][2], N[1][2]]) == sorted([1/2*c - 5/2*i - 5/2, -1/2*c - 5/2*i - 5/2])
sage.modular.modform.constructor.canonical_parameters(group, level, weight, base_ring)[source]

Given a group, level, weight, and base_ring as input by the user, return a canonicalized version of them, where level is a Sage integer, group really is a group, weight is a Sage integer, and base_ring a Sage ring. Note that we can’t just get the level from the group, because we have the convention that the character for Gamma1(N) is None (which makes good sense).

INPUT:

  • group – integer, group, or Dirichlet character

  • level – integer or group

  • weight – coercible to integer

  • base_ring – commutative ring

OUTPUT:

  • level – integer

  • group – congruence subgroup

  • weight – integer

  • ring – commutative ring

EXAMPLES:

sage: from sage.modular.modform.constructor import canonical_parameters
sage: v = canonical_parameters(5, 5, int(7), ZZ); v
(5, Congruence Subgroup Gamma0(5), 7, Integer Ring)
sage: type(v[0]), type(v[1]), type(v[2]), type(v[3])
(<class 'sage.rings.integer.Integer'>,
 <class 'sage.modular.arithgroup.congroup_gamma0.Gamma0_class_with_category'>,
 <class 'sage.rings.integer.Integer'>,
 <class 'sage.rings.integer_ring.IntegerRing_class'>)
sage: canonical_parameters( 5, 7, 7, ZZ )
Traceback (most recent call last):
...
ValueError: group and level do not match.
>>> from sage.all import *
>>> from sage.modular.modform.constructor import canonical_parameters
>>> v = canonical_parameters(Integer(5), Integer(5), int(Integer(7)), ZZ); v
(5, Congruence Subgroup Gamma0(5), 7, Integer Ring)
>>> type(v[Integer(0)]), type(v[Integer(1)]), type(v[Integer(2)]), type(v[Integer(3)])
(<class 'sage.rings.integer.Integer'>,
 <class 'sage.modular.arithgroup.congroup_gamma0.Gamma0_class_with_category'>,
 <class 'sage.rings.integer.Integer'>,
 <class 'sage.rings.integer_ring.IntegerRing_class'>)
>>> canonical_parameters( Integer(5), Integer(7), Integer(7), ZZ )
Traceback (most recent call last):
...
ValueError: group and level do not match.
from sage.modular.modform.constructor import canonical_parameters
v = canonical_parameters(5, 5, int(7), ZZ); v
type(v[0]), type(v[1]), type(v[2]), type(v[3])
canonical_parameters( 5, 7, 7, ZZ )
sage.modular.modform.constructor.parse_label(s)[source]

Given a string s corresponding to a newform label, return the corresponding group and index.

EXAMPLES:

sage: sage.modular.modform.constructor.parse_label('11a')
(Congruence Subgroup Gamma0(11), 0)
sage: sage.modular.modform.constructor.parse_label('11aG1')
(Congruence Subgroup Gamma1(11), 0)
sage: sage.modular.modform.constructor.parse_label('11wG1')
(Congruence Subgroup Gamma1(11), 22)
>>> from sage.all import *
>>> sage.modular.modform.constructor.parse_label('11a')
(Congruence Subgroup Gamma0(11), 0)
>>> sage.modular.modform.constructor.parse_label('11aG1')
(Congruence Subgroup Gamma1(11), 0)
>>> sage.modular.modform.constructor.parse_label('11wG1')
(Congruence Subgroup Gamma1(11), 22)
sage.modular.modform.constructor.parse_label('11a')
sage.modular.modform.constructor.parse_label('11aG1')
sage.modular.modform.constructor.parse_label('11wG1')

GammaH labels should also return the group and index (Issue #20823):

sage: sage.modular.modform.constructor.parse_label('389cGH[16]')
(Congruence Subgroup Gamma_H(389) with H generated by [16], 2)
>>> from sage.all import *
>>> sage.modular.modform.constructor.parse_label('389cGH[16]')
(Congruence Subgroup Gamma_H(389) with H generated by [16], 2)
sage.modular.modform.constructor.parse_label('389cGH[16]')