Graded quasimodular forms ring

Let \(E_2\) be the weight 2 Eisenstein series defined by

\[E_2(z) = 1 - \frac{2k}{B_k} \sum_{n=1}^{\infty} \sigma(n) q^n\]

where \(\sigma\) is the sum of divisors function and \(q = \mathrm{exp}(2\pi i z)\) is the classical parameter at infinity, with \(\mathrm{im}(z)>0\). This weight 2 Eisenstein series is not a modular form as it does not satisfy the modularity condition:

\[z^2 E_2(-1/z) = E_2(z) + \frac{2k}{4\pi i B_k z}.\]

\(E_2\) is a quasimodular form of weight 2. General quasimodular forms of given weight can also be defined. We denote by \(QM\) the graded ring of quasimodular forms for the full modular group \(\SL_2(\ZZ)\).

The SageMath implementation of the graded ring of quasimodular forms uses the following isomorphism:

\[QM \cong M_* [E_2]\]

where \(M_* \cong \CC[E_4, E_6]\) is the graded ring of modular forms for \(\SL_2(\ZZ)\). (see sage.modular.modform.ring.ModularFormsRing).

More generally, if \(\Gamma \leq \SL_2(\ZZ)\) is a congruence subgroup, then the graded ring of quasimodular forms for \(\Gamma\) is given by \(M_*(\Gamma)[E_2]\) where \(M_*(\Gamma)\) is the ring of modular forms for \(\Gamma\).

The SageMath implementation of the graded quasimodular forms ring allows computation of a set of generators and perform usual arithmetic operations.

EXAMPLES:

sage: QM = QuasiModularForms(1); QM
Ring of Quasimodular Forms for Modular Group SL(2,Z) over Rational Field
sage: QM.category()
Category of commutative graded algebras over Rational Field
sage: QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
sage: E2 = QM.0; E4 = QM.1; E6 = QM.2
sage: E2 * E4 + E6
2 - 288*q - 20304*q^2 - 185472*q^3 - 855216*q^4 - 2697408*q^5 + O(q^6)
sage: E2.parent()
Ring of Quasimodular Forms for Modular Group SL(2,Z) over Rational Field
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1)); QM
Ring of Quasimodular Forms for Modular Group SL(2,Z) over Rational Field
>>> QM.category()
Category of commutative graded algebras over Rational Field
>>> QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
>>> E2 = QM.gen(0); E4 = QM.gen(1); E6 = QM.gen(2)
>>> E2 * E4 + E6
2 - 288*q - 20304*q^2 - 185472*q^3 - 855216*q^4 - 2697408*q^5 + O(q^6)
>>> E2.parent()
Ring of Quasimodular Forms for Modular Group SL(2,Z) over Rational Field
QM = QuasiModularForms(1); QM
QM.category()
QM.gens()
E2 = QM.0; E4 = QM.1; E6 = QM.2
E2 * E4 + E6
E2.parent()

The polygen method also return the weight-2 Eisenstein series as a polynomial variable over the ring of modular forms:

sage: QM = QuasiModularForms(1)
sage: E2 = QM.polygen(); E2
E2
sage: E2.parent()
Univariate Polynomial Ring in E2 over Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> E2 = QM.polygen(); E2
E2
>>> E2.parent()
Univariate Polynomial Ring in E2 over Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
QM = QuasiModularForms(1)
E2 = QM.polygen(); E2
E2.parent()

An element of a ring of quasimodular forms can be created via a list of modular forms or graded modular forms. The \(i\)-th index of the list will correspond to the \(i\)-th coefficient of the polynomial in \(E_2\):

sage: QM = QuasiModularForms(1)
sage: E2 = QM.0
sage: Delta = CuspForms(1, 12).0
sage: E4 = ModularForms(1, 4).0
sage: F = QM([Delta, E4, Delta + E4]); F
2 + 410*q - 12696*q^2 - 50424*q^3 + 1076264*q^4 + 10431996*q^5 + O(q^6)
sage: F == Delta + E4 * E2 + (Delta + E4) * E2^2
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> E2 = QM.gen(0)
>>> Delta = CuspForms(Integer(1), Integer(12)).gen(0)
>>> E4 = ModularForms(Integer(1), Integer(4)).gen(0)
>>> F = QM([Delta, E4, Delta + E4]); F
2 + 410*q - 12696*q^2 - 50424*q^3 + 1076264*q^4 + 10431996*q^5 + O(q^6)
>>> F == Delta + E4 * E2 + (Delta + E4) * E2**Integer(2)
True
QM = QuasiModularForms(1)
E2 = QM.0
Delta = CuspForms(1, 12).0
E4 = ModularForms(1, 4).0
F = QM([Delta, E4, Delta + E4]); F
F == Delta + E4 * E2 + (Delta + E4) * E2^2

One may also create rings of quasimodular forms for certain congruence subgroups:

sage: QM = QuasiModularForms(Gamma0(5)); QM
Ring of Quasimodular Forms for Congruence Subgroup Gamma0(5) over Rational Field
sage: QM.ngens()
4
>>> from sage.all import *
>>> QM = QuasiModularForms(Gamma0(Integer(5))); QM
Ring of Quasimodular Forms for Congruence Subgroup Gamma0(5) over Rational Field
>>> QM.ngens()
4
QM = QuasiModularForms(Gamma0(5)); QM
QM.ngens()

The first generator is the weight 2 Eisenstein series:

sage: E2 = QM.0; E2
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> from sage.all import *
>>> E2 = QM.gen(0); E2
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
E2 = QM.0; E2

The other generators correspond to the generators given by the method sage.modular.modform.ring.ModularFormsRing.gens():

sage: QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
 1 + 6*q + 18*q^2 + 24*q^3 + 42*q^4 + 6*q^5 + O(q^6),
 1 + 240*q^5 + O(q^6),
 q + 10*q^3 + 28*q^4 + 35*q^5 + O(q^6)]
sage: QM.modular_forms_subring().gens()
[1 + 6*q + 18*q^2 + 24*q^3 + 42*q^4 + 6*q^5 + O(q^6),
 1 + 240*q^5 + O(q^6),
 q + 10*q^3 + 28*q^4 + 35*q^5 + O(q^6)]
>>> from sage.all import *
>>> QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
 1 + 6*q + 18*q^2 + 24*q^3 + 42*q^4 + 6*q^5 + O(q^6),
 1 + 240*q^5 + O(q^6),
 q + 10*q^3 + 28*q^4 + 35*q^5 + O(q^6)]
>>> QM.modular_forms_subring().gens()
[1 + 6*q + 18*q^2 + 24*q^3 + 42*q^4 + 6*q^5 + O(q^6),
 1 + 240*q^5 + O(q^6),
 q + 10*q^3 + 28*q^4 + 35*q^5 + O(q^6)]
QM.gens()
QM.modular_forms_subring().gens()

It is possible to convert a graded quasimodular form into a polynomial where each variable corresponds to a generator of the ring:

sage: QM = QuasiModularForms(1)
sage: E2, E4, E6 = QM.gens()
sage: F = E2*E4*E6 + E6^2; F
2 - 1296*q + 91584*q^2 + 14591808*q^3 + 464670432*q^4 + 6160281120*q^5 + O(q^6)
sage: p = F.polynomial('E2, E4, E6'); p
E2*E4*E6 + E6^2
sage: P = p.parent(); P
Multivariate Polynomial Ring in E2, E4, E6 over Rational Field
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> E2, E4, E6 = QM.gens()
>>> F = E2*E4*E6 + E6**Integer(2); F
2 - 1296*q + 91584*q^2 + 14591808*q^3 + 464670432*q^4 + 6160281120*q^5 + O(q^6)
>>> p = F.polynomial('E2, E4, E6'); p
E2*E4*E6 + E6^2
>>> P = p.parent(); P
Multivariate Polynomial Ring in E2, E4, E6 over Rational Field
QM = QuasiModularForms(1)
E2, E4, E6 = QM.gens()
F = E2*E4*E6 + E6^2; F
p = F.polynomial('E2, E4, E6'); p
P = p.parent(); P

The generators of the polynomial ring have degree equal to the weight of the corresponding form:

sage: P.inject_variables()
Defining E2, E4, E6
sage: E2.degree()
2
sage: E4.degree()
4
sage: E6.degree()
6
>>> from sage.all import *
>>> P.inject_variables()
Defining E2, E4, E6
>>> E2.degree()
2
>>> E4.degree()
4
>>> E6.degree()
6
P.inject_variables()
E2.degree()
E4.degree()
E6.degree()

This works also for congruence subgroup:

sage: QM = QuasiModularForms(Gamma1(4))
sage: QM.ngens()
5
sage: QM.polynomial_ring()
Multivariate Polynomial Ring in E2, E2_0, E2_1, E3_0, E3_1 over Rational Field
sage: (QM.0 + QM.1*QM.0^2 + QM.3 + QM.4^3).polynomial()
E3_1^3 + E2^2*E2_0 + E3_0 + E2
>>> from sage.all import *
>>> QM = QuasiModularForms(Gamma1(Integer(4)))
>>> QM.ngens()
5
>>> QM.polynomial_ring()
Multivariate Polynomial Ring in E2, E2_0, E2_1, E3_0, E3_1 over Rational Field
>>> (QM.gen(0) + QM.gen(1)*QM.gen(0)**Integer(2) + QM.gen(3) + QM.gen(4)**Integer(3)).polynomial()
E3_1^3 + E2^2*E2_0 + E3_0 + E2
QM = QuasiModularForms(Gamma1(4))
QM.ngens()
QM.polynomial_ring()
(QM.0 + QM.1*QM.0^2 + QM.3 + QM.4^3).polynomial()

One can also convert a multivariate polynomial into a quasimodular form:

sage: QM.polynomial_ring().inject_variables()
Defining E2, E2_0, E2_1, E3_0, E3_1
sage: QM.from_polynomial(E3_1^3 + E2^2*E2_0 + E3_0 + E2)
3 - 72*q + 396*q^2 + 2081*q^3 + 19752*q^4 + 98712*q^5 + O(q^6)
>>> from sage.all import *
>>> QM.polynomial_ring().inject_variables()
Defining E2, E2_0, E2_1, E3_0, E3_1
>>> QM.from_polynomial(E3_1**Integer(3) + E2**Integer(2)*E2_0 + E3_0 + E2)
3 - 72*q + 396*q^2 + 2081*q^3 + 19752*q^4 + 98712*q^5 + O(q^6)
QM.polynomial_ring().inject_variables()
QM.from_polynomial(E3_1^3 + E2^2*E2_0 + E3_0 + E2)

Note

  • Currently, the only supported base ring is the Rational Field;

  • Spaces of quasimodular forms of fixed weight are not yet implemented.

REFERENCE:

See section 5.3 (page 58) of [Zag2008]

AUTHORS:

  • David Ayotte (2021-03-18): initial version

class sage.modular.quasimodform.ring.QuasiModularForms(group=1, base_ring=Rational Field, name='E2')[source]

Bases: Parent, UniqueRepresentation

The graded ring of quasimodular forms for the full modular group \(\SL_2(\ZZ)\), with coefficients in a ring.

EXAMPLES:

sage: QM = QuasiModularForms(1); QM
Ring of Quasimodular Forms for Modular Group SL(2,Z) over Rational Field
sage: QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1)); QM
Ring of Quasimodular Forms for Modular Group SL(2,Z) over Rational Field
>>> QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
QM = QuasiModularForms(1); QM
QM.gens()

It is possible to access the weight 2 Eisenstein series:

sage: QM.weight_2_eisenstein_series()
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> from sage.all import *
>>> QM.weight_2_eisenstein_series()
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
QM.weight_2_eisenstein_series()

Currently, the only supported base ring is the rational numbers:

sage: QuasiModularForms(1, GF(5))
Traceback (most recent call last):
...
NotImplementedError: base ring other than Q are not yet supported for quasimodular forms ring
>>> from sage.all import *
>>> QuasiModularForms(Integer(1), GF(Integer(5)))
Traceback (most recent call last):
...
NotImplementedError: base ring other than Q are not yet supported for quasimodular forms ring
QuasiModularForms(1, GF(5))
Element[source]

alias of QuasiModularFormsElement

basis_of_weight(weight)[source]

Return a basis of elements generating the subspace of the given weight.

INPUT:

  • weight – integer; the weight of the subspace

OUTPUT: list of quasimodular forms of the given weight

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.basis_of_weight(12)
[q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6),
 1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6),
 1 - 288*q - 129168*q^2 - 1927296*q^3 + 65152656*q^4 + 1535768640*q^5 + O(q^6),
 1 + 432*q + 39312*q^2 - 1711296*q^3 - 14159664*q^4 + 317412000*q^5 + O(q^6),
 1 - 576*q + 21168*q^2 + 308736*q^3 - 15034608*q^4 - 39208320*q^5 + O(q^6),
 1 + 144*q - 17712*q^2 + 524736*q^3 - 2279088*q^4 - 79760160*q^5 + O(q^6),
 1 - 144*q + 8208*q^2 - 225216*q^3 + 2634192*q^4 + 1488672*q^5 + O(q^6)]
sage: QM = QuasiModularForms(Gamma1(3))
sage: QM.basis_of_weight(3)
[1 + 54*q^2 + 72*q^3 + 432*q^5 + O(q^6),
 q + 3*q^2 + 9*q^3 + 13*q^4 + 24*q^5 + O(q^6)]
sage: QM.basis_of_weight(5)
[1 - 90*q^2 - 240*q^3 - 3744*q^5 + O(q^6),
 q + 15*q^2 + 81*q^3 + 241*q^4 + 624*q^5 + O(q^6),
 1 - 24*q - 18*q^2 - 1320*q^3 - 5784*q^4 - 10080*q^5 + O(q^6),
 q - 21*q^2 - 135*q^3 - 515*q^4 - 1392*q^5 + O(q^6)]
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.basis_of_weight(Integer(12))
[q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6),
 1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6),
 1 - 288*q - 129168*q^2 - 1927296*q^3 + 65152656*q^4 + 1535768640*q^5 + O(q^6),
 1 + 432*q + 39312*q^2 - 1711296*q^3 - 14159664*q^4 + 317412000*q^5 + O(q^6),
 1 - 576*q + 21168*q^2 + 308736*q^3 - 15034608*q^4 - 39208320*q^5 + O(q^6),
 1 + 144*q - 17712*q^2 + 524736*q^3 - 2279088*q^4 - 79760160*q^5 + O(q^6),
 1 - 144*q + 8208*q^2 - 225216*q^3 + 2634192*q^4 + 1488672*q^5 + O(q^6)]
>>> QM = QuasiModularForms(Gamma1(Integer(3)))
>>> QM.basis_of_weight(Integer(3))
[1 + 54*q^2 + 72*q^3 + 432*q^5 + O(q^6),
 q + 3*q^2 + 9*q^3 + 13*q^4 + 24*q^5 + O(q^6)]
>>> QM.basis_of_weight(Integer(5))
[1 - 90*q^2 - 240*q^3 - 3744*q^5 + O(q^6),
 q + 15*q^2 + 81*q^3 + 241*q^4 + 624*q^5 + O(q^6),
 1 - 24*q - 18*q^2 - 1320*q^3 - 5784*q^4 - 10080*q^5 + O(q^6),
 q - 21*q^2 - 135*q^3 - 515*q^4 - 1392*q^5 + O(q^6)]
QM = QuasiModularForms(1)
QM.basis_of_weight(12)
QM = QuasiModularForms(Gamma1(3))
QM.basis_of_weight(3)
QM.basis_of_weight(5)
from_polynomial(polynomial)[source]

Convert the given polynomial \(P(x,\ldots, y)\) to the graded quasiform \(P(g_0, \ldots, g_n)\) where the \(g_i\) are the generators given by gens().

INPUT:

  • polynomial – a multivariate polynomial

OUTPUT: the graded quasimodular forms \(P(g_0, \ldots, g_n)\)

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: P.<x, y, z> = QQ[]
sage: QM.from_polynomial(x)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
sage: QM.from_polynomial(x) == QM.0
True
sage: QM.from_polynomial(y) == QM.1
True
sage: QM.from_polynomial(z) == QM.2
True
sage: QM.from_polynomial(x^2 + y + x*z + 1)
4 - 336*q - 2016*q^2 + 322368*q^3 + 3691392*q^4 + 21797280*q^5 + O(q^6)
sage: QM = QuasiModularForms(Gamma0(2))
sage: P = QM.polynomial_ring()
sage: P.inject_variables()
Defining E2, E2_0, E4_0
sage: QM.from_polynomial(E2)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
sage: QM.from_polynomial(E2 + E4_0*E2_0) == QM.0 + QM.2*QM.1
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> P = QQ['x, y, z']; (x, y, z,) = P._first_ngens(3)
>>> QM.from_polynomial(x)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> QM.from_polynomial(x) == QM.gen(0)
True
>>> QM.from_polynomial(y) == QM.gen(1)
True
>>> QM.from_polynomial(z) == QM.gen(2)
True
>>> QM.from_polynomial(x**Integer(2) + y + x*z + Integer(1))
4 - 336*q - 2016*q^2 + 322368*q^3 + 3691392*q^4 + 21797280*q^5 + O(q^6)
>>> QM = QuasiModularForms(Gamma0(Integer(2)))
>>> P = QM.polynomial_ring()
>>> P.inject_variables()
Defining E2, E2_0, E4_0
>>> QM.from_polynomial(E2)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> QM.from_polynomial(E2 + E4_0*E2_0) == QM.gen(0) + QM.gen(2)*QM.gen(1)
True
QM = QuasiModularForms(1)
P.<x, y, z> = QQ[]
QM.from_polynomial(x)
QM.from_polynomial(x) == QM.0
QM.from_polynomial(y) == QM.1
QM.from_polynomial(z) == QM.2
QM.from_polynomial(x^2 + y + x*z + 1)
QM = QuasiModularForms(Gamma0(2))
P = QM.polynomial_ring()
P.inject_variables()
QM.from_polynomial(E2)
QM.from_polynomial(E2 + E4_0*E2_0) == QM.0 + QM.2*QM.1

Naturally, the number of variable must not exceed the number of generators:

sage: P = PolynomialRing(QQ, 'F', 4)
sage: P.inject_variables()
Defining F0, F1, F2, F3
sage: QM.from_polynomial(F0 + F1 + F2 + F3)
Traceback (most recent call last):
...
ValueError: the number of variables (4) of the given polynomial cannot exceed the number of generators (3) of the quasimodular forms ring
>>> from sage.all import *
>>> P = PolynomialRing(QQ, 'F', Integer(4))
>>> P.inject_variables()
Defining F0, F1, F2, F3
>>> QM.from_polynomial(F0 + F1 + F2 + F3)
Traceback (most recent call last):
...
ValueError: the number of variables (4) of the given polynomial cannot exceed the number of generators (3) of the quasimodular forms ring
P = PolynomialRing(QQ, 'F', 4)
P.inject_variables()
QM.from_polynomial(F0 + F1 + F2 + F3)
gen(n)[source]

Return the \(n\)-th generator of the quasimodular forms ring.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.0
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
sage: QM.1
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)
sage: QM.2
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)
sage: QM = QuasiModularForms(5)
sage: QM.0
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
sage: QM.1
1 + 6*q + 18*q^2 + 24*q^3 + 42*q^4 + 6*q^5 + O(q^6)
sage: QM.2
1 + 240*q^5 + O(q^6)
sage: QM.3
q + 10*q^3 + 28*q^4 + 35*q^5 + O(q^6)
sage: QM.4
Traceback (most recent call last):
...
IndexError: list index out of range
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.gen(0)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> QM.gen(1)
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)
>>> QM.gen(2)
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)
>>> QM = QuasiModularForms(Integer(5))
>>> QM.gen(0)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> QM.gen(1)
1 + 6*q + 18*q^2 + 24*q^3 + 42*q^4 + 6*q^5 + O(q^6)
>>> QM.gen(2)
1 + 240*q^5 + O(q^6)
>>> QM.gen(3)
q + 10*q^3 + 28*q^4 + 35*q^5 + O(q^6)
>>> QM.gen(4)
Traceback (most recent call last):
...
IndexError: list index out of range
QM = QuasiModularForms(1)
QM.0
QM.1
QM.2
QM = QuasiModularForms(5)
QM.0
QM.1
QM.2
QM.3
QM.4
generators()[source]

Return a list of generators of the quasimodular forms ring.

Note that the generators of the modular forms subring are the one given by the method sage.modular.modform.ring.ModularFormsRing.gen_forms()

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
sage: QM.modular_forms_subring().gen_forms()
[1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
sage: QM = QuasiModularForms(5)
sage: QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 6*q + 18*q^2 + 24*q^3 + 42*q^4 + 6*q^5 + O(q^6),
1 + 240*q^5 + O(q^6),
q + 10*q^3 + 28*q^4 + 35*q^5 + O(q^6)]
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
>>> QM.modular_forms_subring().gen_forms()
[1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
>>> QM = QuasiModularForms(Integer(5))
>>> QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 6*q + 18*q^2 + 24*q^3 + 42*q^4 + 6*q^5 + O(q^6),
1 + 240*q^5 + O(q^6),
q + 10*q^3 + 28*q^4 + 35*q^5 + O(q^6)]
QM = QuasiModularForms(1)
QM.gens()
QM.modular_forms_subring().gen_forms()
QM = QuasiModularForms(5)
QM.gens()

An alias of this method is generators:

sage: QuasiModularForms(1).generators()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
>>> from sage.all import *
>>> QuasiModularForms(Integer(1)).generators()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
QuasiModularForms(1).generators()
gens()[source]

Return a list of generators of the quasimodular forms ring.

Note that the generators of the modular forms subring are the one given by the method sage.modular.modform.ring.ModularFormsRing.gen_forms()

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
sage: QM.modular_forms_subring().gen_forms()
[1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
sage: QM = QuasiModularForms(5)
sage: QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 6*q + 18*q^2 + 24*q^3 + 42*q^4 + 6*q^5 + O(q^6),
1 + 240*q^5 + O(q^6),
q + 10*q^3 + 28*q^4 + 35*q^5 + O(q^6)]
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
>>> QM.modular_forms_subring().gen_forms()
[1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
>>> QM = QuasiModularForms(Integer(5))
>>> QM.gens()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 6*q + 18*q^2 + 24*q^3 + 42*q^4 + 6*q^5 + O(q^6),
1 + 240*q^5 + O(q^6),
q + 10*q^3 + 28*q^4 + 35*q^5 + O(q^6)]
QM = QuasiModularForms(1)
QM.gens()
QM.modular_forms_subring().gen_forms()
QM = QuasiModularForms(5)
QM.gens()

An alias of this method is generators:

sage: QuasiModularForms(1).generators()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
>>> from sage.all import *
>>> QuasiModularForms(Integer(1)).generators()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
QuasiModularForms(1).generators()
group()[source]

Return the congruence subgroup attached to the given quasimodular forms ring.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.group()
Modular Group SL(2,Z)
sage: QM.group() is SL2Z
True
sage: QuasiModularForms(3).group()
Congruence Subgroup Gamma0(3)
sage: QuasiModularForms(Gamma1(5)).group()
Congruence Subgroup Gamma1(5)
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.group()
Modular Group SL(2,Z)
>>> QM.group() is SL2Z
True
>>> QuasiModularForms(Integer(3)).group()
Congruence Subgroup Gamma0(3)
>>> QuasiModularForms(Gamma1(Integer(5))).group()
Congruence Subgroup Gamma1(5)
QM = QuasiModularForms(1)
QM.group()
QM.group() is SL2Z
QuasiModularForms(3).group()
QuasiModularForms(Gamma1(5)).group()
modular_forms_of_weight(weight)[source]

Return the space of modular forms on this group of the given weight.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.modular_forms_of_weight(12)
Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field
sage: QM = QuasiModularForms(Gamma1(3))
sage: QM.modular_forms_of_weight(4)
Modular Forms space of dimension 2 for Congruence Subgroup Gamma1(3) of weight 4 over Rational Field
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.modular_forms_of_weight(Integer(12))
Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field
>>> QM = QuasiModularForms(Gamma1(Integer(3)))
>>> QM.modular_forms_of_weight(Integer(4))
Modular Forms space of dimension 2 for Congruence Subgroup Gamma1(3) of weight 4 over Rational Field
QM = QuasiModularForms(1)
QM.modular_forms_of_weight(12)
QM = QuasiModularForms(Gamma1(3))
QM.modular_forms_of_weight(4)
modular_forms_subring()[source]

Return the subring of modular forms of this ring of quasimodular forms.

EXAMPLES:

sage: QuasiModularForms(1).modular_forms_subring()
Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
sage: QuasiModularForms(5).modular_forms_subring()
Ring of Modular Forms for Congruence Subgroup Gamma0(5) over Rational Field
>>> from sage.all import *
>>> QuasiModularForms(Integer(1)).modular_forms_subring()
Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
>>> QuasiModularForms(Integer(5)).modular_forms_subring()
Ring of Modular Forms for Congruence Subgroup Gamma0(5) over Rational Field
QuasiModularForms(1).modular_forms_subring()
QuasiModularForms(5).modular_forms_subring()
ngens()[source]

Return the number of generators of the given graded quasimodular forms ring.

EXAMPLES:

sage: QuasiModularForms(1).ngens()
3
>>> from sage.all import *
>>> QuasiModularForms(Integer(1)).ngens()
3
QuasiModularForms(1).ngens()
one()[source]

Return the one element of this ring.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.one()
1
sage: QM.one().is_one()
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.one()
1
>>> QM.one().is_one()
True
QM = QuasiModularForms(1)
QM.one()
QM.one().is_one()
polygen()[source]

Return the generator of this quasimodular form space as a polynomial ring over the modular form subring.

Note that this generator correspond to the weight-2 Eisenstein series. The default name of this generator is E2.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.polygen()
E2
sage: QuasiModularForms(1, name='X').polygen()
X
sage: QM.polygen().parent()
Univariate Polynomial Ring in E2 over Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.polygen()
E2
>>> QuasiModularForms(Integer(1), name='X').polygen()
X
>>> QM.polygen().parent()
Univariate Polynomial Ring in E2 over Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
QM = QuasiModularForms(1)
QM.polygen()
QuasiModularForms(1, name='X').polygen()
QM.polygen().parent()
polynomial_ring(names=None)[source]

Return a multivariate polynomial ring of which the quasimodular forms ring is a quotient.

In the case of the full modular group, this ring is \(R[E_2, E_4, E_6]\) where \(E_2\), \(E_4\) and \(E_6\) have degrees 2, 4 and 6 respectively.

INPUT:

  • names– string (default: None); list or tuple of names (strings), or a comma separated string. Defines the names for the generators of the multivariate polynomial ring. The default names are of the following form:

    • E2 denotes the weight 2 Eisenstein series;

    • Ek_i and Sk_i denote the \(i\)-th basis element of the weight \(k\) Eisenstein subspace and cuspidal subspace respectively;

    • If the level is one, the default names are E2, E4 and E6;

    • In any other cases, we use the letters Fk, Gk, Hk, …, FFk, FGk, … to denote any generator of weight \(k\).

OUTPUT: a multivariate polynomial ring in the variables names

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: P = QM.polynomial_ring(); P
Multivariate Polynomial Ring in E2, E4, E6 over Rational Field
sage: P.inject_variables()
Defining E2, E4, E6
sage: E2.degree()
2
sage: E4.degree()
4
sage: E6.degree()
6
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> P = QM.polynomial_ring(); P
Multivariate Polynomial Ring in E2, E4, E6 over Rational Field
>>> P.inject_variables()
Defining E2, E4, E6
>>> E2.degree()
2
>>> E4.degree()
4
>>> E6.degree()
6
QM = QuasiModularForms(1)
P = QM.polynomial_ring(); P
P.inject_variables()
E2.degree()
E4.degree()
E6.degree()

Example when the level is not one:

sage: QM = QuasiModularForms(Gamma0(29))
sage: P_29 = QM.polynomial_ring()
sage: P_29
Multivariate Polynomial Ring in E2, F2, S2_0, S2_1, E4_0, F4, G4, H4 over Rational Field
sage: P_29.inject_variables()
Defining E2, F2, S2_0, S2_1, E4_0, F4, G4, H4
sage: F2.degree()
2
sage: E4_0.degree()
4
>>> from sage.all import *
>>> QM = QuasiModularForms(Gamma0(Integer(29)))
>>> P_29 = QM.polynomial_ring()
>>> P_29
Multivariate Polynomial Ring in E2, F2, S2_0, S2_1, E4_0, F4, G4, H4 over Rational Field
>>> P_29.inject_variables()
Defining E2, F2, S2_0, S2_1, E4_0, F4, G4, H4
>>> F2.degree()
2
>>> E4_0.degree()
4
QM = QuasiModularForms(Gamma0(29))
P_29 = QM.polynomial_ring()
P_29
P_29.inject_variables()
F2.degree()
E4_0.degree()

The name Sk_i stands for the \(i\)-th basis element of the cuspidal subspace of weight \(k\):

sage: F2 = QM.from_polynomial(S2_0)
sage: F2.qexp(10)
q - q^4 - q^5 - q^6 + 2*q^7 - 2*q^8 - 2*q^9 + O(q^10)
sage: CuspForms(Gamma0(29), 2).0.qexp(10)
q - q^4 - q^5 - q^6 + 2*q^7 - 2*q^8 - 2*q^9 + O(q^10)
sage: F2 == CuspForms(Gamma0(29), 2).0
True
>>> from sage.all import *
>>> F2 = QM.from_polynomial(S2_0)
>>> F2.qexp(Integer(10))
q - q^4 - q^5 - q^6 + 2*q^7 - 2*q^8 - 2*q^9 + O(q^10)
>>> CuspForms(Gamma0(Integer(29)), Integer(2)).gen(0).qexp(Integer(10))
q - q^4 - q^5 - q^6 + 2*q^7 - 2*q^8 - 2*q^9 + O(q^10)
>>> F2 == CuspForms(Gamma0(Integer(29)), Integer(2)).gen(0)
True
F2 = QM.from_polynomial(S2_0)
F2.qexp(10)
CuspForms(Gamma0(29), 2).0.qexp(10)
F2 == CuspForms(Gamma0(29), 2).0

The name Ek_i stands for the \(i\)-th basis element of the Eisenstein subspace of weight \(k\):

sage: F4 = QM.from_polynomial(E4_0)
sage: F4.qexp(30)
1 + 240*q^29 + O(q^30)
sage: EisensteinForms(Gamma0(29), 4).0.qexp(30)
1 + 240*q^29 + O(q^30)
sage: F4 == EisensteinForms(Gamma0(29), 4).0
True
>>> from sage.all import *
>>> F4 = QM.from_polynomial(E4_0)
>>> F4.qexp(Integer(30))
1 + 240*q^29 + O(q^30)
>>> EisensteinForms(Gamma0(Integer(29)), Integer(4)).gen(0).qexp(Integer(30))
1 + 240*q^29 + O(q^30)
>>> F4 == EisensteinForms(Gamma0(Integer(29)), Integer(4)).gen(0)
True
F4 = QM.from_polynomial(E4_0)
F4.qexp(30)
EisensteinForms(Gamma0(29), 4).0.qexp(30)
F4 == EisensteinForms(Gamma0(29), 4).0

One may also choose the name of the variables:

sage: QM = QuasiModularForms(1)
sage: QM.polynomial_ring(names="P, Q, R")
Multivariate Polynomial Ring in P, Q, R over Rational Field
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.polynomial_ring(names="P, Q, R")
Multivariate Polynomial Ring in P, Q, R over Rational Field
QM = QuasiModularForms(1)
QM.polynomial_ring(names="P, Q, R")
quasimodular_forms_of_weight(weight)[source]

Return the space of quasimodular forms on this group of the given weight.

INPUT:

  • weight – integer

OUTPUT: a quasimodular forms space of the given weight

EXAMPLES:

sage: QuasiModularForms(1).quasimodular_forms_of_weight(4)
Traceback (most recent call last):
...
NotImplementedError: spaces of quasimodular forms of fixed weight not yet implemented
>>> from sage.all import *
>>> QuasiModularForms(Integer(1)).quasimodular_forms_of_weight(Integer(4))
Traceback (most recent call last):
...
NotImplementedError: spaces of quasimodular forms of fixed weight not yet implemented
QuasiModularForms(1).quasimodular_forms_of_weight(4)
some_elements()[source]

Return a list of generators of self.

EXAMPLES:

sage: QuasiModularForms(1).some_elements()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
>>> from sage.all import *
>>> QuasiModularForms(Integer(1)).some_elements()
[1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
QuasiModularForms(1).some_elements()
weight_2_eisenstein_series()[source]

Return the weight 2 Eisenstein series.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: E2 = QM.weight_2_eisenstein_series(); E2
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
sage: E2.parent()
Ring of Quasimodular Forms for Modular Group SL(2,Z) over Rational Field
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> E2 = QM.weight_2_eisenstein_series(); E2
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> E2.parent()
Ring of Quasimodular Forms for Modular Group SL(2,Z) over Rational Field
QM = QuasiModularForms(1)
E2 = QM.weight_2_eisenstein_series(); E2
E2.parent()
zero()[source]

Return the zero element of this ring.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.zero()
0
sage: QM.zero().is_zero()
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.zero()
0
>>> QM.zero().is_zero()
True
QM = QuasiModularForms(1)
QM.zero()
QM.zero().is_zero()