Graded quasimodular forms ring#
Let \(E_2\) be the weight 2 Eisenstein series defined by
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:
\(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:
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.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
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
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
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
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)
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)]
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
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
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
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)
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')#
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)]
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)
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
- Element#
alias of
QuasiModularFormsElement
- from_polynomial(polynomial)#
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
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
- gen(n)#
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
- generators()#
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)]
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)]
- gens()#
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)]
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)]
- group()#
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)
- modular_forms_of_weight(weight)#
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
- modular_forms_subring()#
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
- ngens()#
Return the number of generators of the given graded quasimodular forms ring.
EXAMPLES:
sage: QuasiModularForms(1).ngens() 3
- one()#
Return the one element of this ring.
EXAMPLES:
sage: QM = QuasiModularForms(1) sage: QM.one() 1 sage: QM.one().is_one() True
- polygen()#
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
- polynomial_ring(names=None)#
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
(str, default:None
) – a 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
andSk_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
andE6
;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
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
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
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
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
- quasimodular_forms_of_weight(weight)#
Return the space of quasimodular forms on this group of the given weight.
INPUT:
weight
(int, 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
- some_elements()#
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)]
- weight_2_eisenstein_series()#
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
- zero()#
Return the zero element of this ring.
EXAMPLES:
sage: QM = QuasiModularForms(1) sage: QM.zero() 0 sage: QM.zero().is_zero() True