Elements of quasimodular forms rings

AUTHORS:

  • DAVID AYOTTE (2021-03-18): initial version

  • Seewoo Lee (2023-09): coefficients method

class sage.modular.quasimodform.element.QuasiModularFormsElement(parent, polynomial)[source]

Bases: ModuleElement

A quasimodular forms ring element. Such an element is described by SageMath as a polynomial

\[F = f_0 + f_1 E_2 + f_2 E_2^2 + \cdots + f_m E_2^m\]

where each \(f_i\) a graded modular form element (see GradedModularFormElement)

For an integer \(k\), we say that \(F\) is homogeneous of weight \(k\) if it lies in an homogeneous component of degree \(k\) of the graded ring of quasimodular 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.0 + QM.1
2 + 216*q + 2088*q^2 + 6624*q^3 + 17352*q^4 + 30096*q^5 + O(q^6)
sage: QM.0 * QM.1
1 + 216*q - 3672*q^2 - 62496*q^3 - 322488*q^4 - 1121904*q^5 + O(q^6)
sage: (QM.0)^2
1 - 48*q + 432*q^2 + 3264*q^3 + 9456*q^4 + 21600*q^5 + O(q^6)
sage: QM.0 == QM.1
False
>>> 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.gen(0) + QM.gen(1)
2 + 216*q + 2088*q^2 + 6624*q^3 + 17352*q^4 + 30096*q^5 + O(q^6)
>>> QM.gen(0) * QM.gen(1)
1 + 216*q - 3672*q^2 - 62496*q^3 - 322488*q^4 - 1121904*q^5 + O(q^6)
>>> (QM.gen(0))**Integer(2)
1 - 48*q + 432*q^2 + 3264*q^3 + 9456*q^4 + 21600*q^5 + O(q^6)
>>> QM.gen(0) == QM.gen(1)
False
QM = QuasiModularForms(1)
QM.gens()
QM.0 + QM.1
QM.0 * QM.1
(QM.0)^2
QM.0 == QM.1

Quasimodular forms ring element can be created via a polynomial in \(E2\) over the ring of modular forms:

sage: E2 = QM.polygen()
sage: E2.parent()
Univariate Polynomial Ring in E2 over Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
sage: QM(E2)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
sage: M = QM.modular_forms_subring()
sage: QM(M.0 * E2 + M.1 * E2^2)
2 - 336*q + 4320*q^2 + 398400*q^3 - 3772992*q^4 - 89283168*q^5 + O(q^6)
>>> from sage.all import *
>>> E2 = QM.polygen()
>>> E2.parent()
Univariate Polynomial Ring in E2 over Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
>>> QM(E2)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> M = QM.modular_forms_subring()
>>> QM(M.gen(0) * E2 + M.gen(1) * E2**Integer(2))
2 - 336*q + 4320*q^2 + 398400*q^3 - 3772992*q^4 - 89283168*q^5 + O(q^6)
E2 = QM.polygen()
E2.parent()
QM(E2)
M = QM.modular_forms_subring()
QM(M.0 * E2 + M.1 * E2^2)

One may convert a quasimodular form into a multivariate polynomial in the generators of the ring by calling polynomial():

sage: QM = QuasiModularForms(1)
sage: F = QM.0^2 + QM.1^2 + QM.0*QM.1*QM.2
sage: F.polynomial()
E2*E4*E6 + E4^2 + E2^2
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> F = QM.gen(0)**Integer(2) + QM.gen(1)**Integer(2) + QM.gen(0)*QM.gen(1)*QM.gen(2)
>>> F.polynomial()
E2*E4*E6 + E4^2 + E2^2
QM = QuasiModularForms(1)
F = QM.0^2 + QM.1^2 + QM.0*QM.1*QM.2
F.polynomial()

If the group is not the full modular group, the default names of the generators are given by Ek_i and Sk_i to denote the \(i\)-th basis element of the weight \(k\) Eisenstein subspace and cuspidal subspace respectively (for more details, see the documentation of polynomial_ring())

sage: QM = QuasiModularForms(Gamma1(4))
sage: F = (QM.0^4)*(QM.1^3) + QM.3
sage: F.polynomial()
-512*E2^4*E2_1^3 + E2^4*E3_0^2 + 48*E2^4*E3_1^2 + E3_0
>>> from sage.all import *
>>> QM = QuasiModularForms(Gamma1(Integer(4)))
>>> F = (QM.gen(0)**Integer(4))*(QM.gen(1)**Integer(3)) + QM.gen(3)
>>> F.polynomial()
-512*E2^4*E2_1^3 + E2^4*E3_0^2 + 48*E2^4*E3_1^2 + E3_0
QM = QuasiModularForms(Gamma1(4))
F = (QM.0^4)*(QM.1^3) + QM.3
F.polynomial()
coefficients(X)[source]

Return the coefficients of \(q^n\) of the \(q\)-expansion of this, graded quasimodular form for \(n\) in the list \(X\).

If X is an integer, return coefficients for indices from 1 to X. This method caches the result.

EXAMPLES:

sage: E2, E4 = QuasiModularForms(1).0, QuasiModularForms(1).1
sage: f = E2^2
sage: g = E2^3 * E4
sage: f.coefficients(10)
[-48, 432, 3264, 9456, 21600, 39744, 66432, 105840, 147984, 220320]
sage: f.coefficients([0,1])
[1, -48]
sage: f.coefficients([0,1,2,3])
[1, -48, 432, 3264]
sage: f.coefficients([2,3])
[432, 3264]
sage: g.coefficients(10)
[168,
 -13608,
 210336,
 1805496,
 -22562064,
 -322437024,
 -2063087808,
 -9165872520,
 -32250917496,
 -96383477232]
sage: g.coefficients([3, 7])
[210336, -2063087808]
>>> from sage.all import *
>>> E2, E4 = QuasiModularForms(Integer(1)).gen(0), QuasiModularForms(Integer(1)).gen(1)
>>> f = E2**Integer(2)
>>> g = E2**Integer(3) * E4
>>> f.coefficients(Integer(10))
[-48, 432, 3264, 9456, 21600, 39744, 66432, 105840, 147984, 220320]
>>> f.coefficients([Integer(0),Integer(1)])
[1, -48]
>>> f.coefficients([Integer(0),Integer(1),Integer(2),Integer(3)])
[1, -48, 432, 3264]
>>> f.coefficients([Integer(2),Integer(3)])
[432, 3264]
>>> g.coefficients(Integer(10))
[168,
 -13608,
 210336,
 1805496,
 -22562064,
 -322437024,
 -2063087808,
 -9165872520,
 -32250917496,
 -96383477232]
>>> g.coefficients([Integer(3), Integer(7)])
[210336, -2063087808]
E2, E4 = QuasiModularForms(1).0, QuasiModularForms(1).1
f = E2^2
g = E2^3 * E4
f.coefficients(10)
f.coefficients([0,1])
f.coefficients([0,1,2,3])
f.coefficients([2,3])
g.coefficients(10)
g.coefficients([3, 7])
degree()[source]

Return the weight of the given quasimodular form.

Note that the given form must be homogeneous. An alias of this method is degree.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: (QM.0).weight()
2
sage: (QM.0 * QM.1 + QM.2).weight()
6
sage: QM(1/2).weight()
0
sage: (QM.0).degree()
2
sage: (QM.0 + QM.1).weight()
Traceback (most recent call last):
...
ValueError: the given graded quasiform is not an homogeneous element
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> (QM.gen(0)).weight()
2
>>> (QM.gen(0) * QM.gen(1) + QM.gen(2)).weight()
6
>>> QM(Integer(1)/Integer(2)).weight()
0
>>> (QM.gen(0)).degree()
2
>>> (QM.gen(0) + QM.gen(1)).weight()
Traceback (most recent call last):
...
ValueError: the given graded quasiform is not an homogeneous element
QM = QuasiModularForms(1)
(QM.0).weight()
(QM.0 * QM.1 + QM.2).weight()
QM(1/2).weight()
(QM.0).degree()
(QM.0 + QM.1).weight()
depth()[source]

Return the depth of this quasimodular form.

Note that the quasimodular form must be homogeneous of weight \(k\). Recall that the depth is the integer \(p\) such that

\[f = f_0 + f_1 E_2 + \cdots + f_p E_2^p,\]

where \(f_i\) is a modular form of weight \(k - 2i\) and \(f_p\) is nonzero.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: E2, E4, E6 = QM.gens()
sage: E2.depth()
1
sage: F = E4^2 + E6*E2 + E4*E2^2 + E2^4
sage: F.depth()
4
sage: QM(7/11).depth()
0
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> E2, E4, E6 = QM.gens()
>>> E2.depth()
1
>>> F = E4**Integer(2) + E6*E2 + E4*E2**Integer(2) + E2**Integer(4)
>>> F.depth()
4
>>> QM(Integer(7)/Integer(11)).depth()
0
QM = QuasiModularForms(1)
E2, E4, E6 = QM.gens()
E2.depth()
F = E4^2 + E6*E2 + E4*E2^2 + E2^4
F.depth()
QM(7/11).depth()
derivative()[source]

Return the derivative \(q \frac{d}{dq}\) of the given quasimodular form.

If the form is not homogeneous, then this method sums the derivative of each homogeneous component.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: E2, E4, E6 = QM.gens()
sage: dE2 = E2.derivative(); dE2
-24*q - 144*q^2 - 288*q^3 - 672*q^4 - 720*q^5 + O(q^6)
sage: dE2 == (E2^2 - E4)/12 # Ramanujan identity
True
sage: dE4 = E4.derivative(); dE4
240*q + 4320*q^2 + 20160*q^3 + 70080*q^4 + 151200*q^5 + O(q^6)
sage: dE4 == (E2 * E4 - E6)/3 # Ramanujan identity
True
sage: dE6 = E6.derivative(); dE6
-504*q - 33264*q^2 - 368928*q^3 - 2130912*q^4 - 7877520*q^5 + O(q^6)
sage: dE6 == (E2 * E6 - E4^2)/2 # Ramanujan identity
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> E2, E4, E6 = QM.gens()
>>> dE2 = E2.derivative(); dE2
-24*q - 144*q^2 - 288*q^3 - 672*q^4 - 720*q^5 + O(q^6)
>>> dE2 == (E2**Integer(2) - E4)/Integer(12) # Ramanujan identity
True
>>> dE4 = E4.derivative(); dE4
240*q + 4320*q^2 + 20160*q^3 + 70080*q^4 + 151200*q^5 + O(q^6)
>>> dE4 == (E2 * E4 - E6)/Integer(3) # Ramanujan identity
True
>>> dE6 = E6.derivative(); dE6
-504*q - 33264*q^2 - 368928*q^3 - 2130912*q^4 - 7877520*q^5 + O(q^6)
>>> dE6 == (E2 * E6 - E4**Integer(2))/Integer(2) # Ramanujan identity
True
QM = QuasiModularForms(1)
E2, E4, E6 = QM.gens()
dE2 = E2.derivative(); dE2
dE2 == (E2^2 - E4)/12 # Ramanujan identity
dE4 = E4.derivative(); dE4
dE4 == (E2 * E4 - E6)/3 # Ramanujan identity
dE6 = E6.derivative(); dE6
dE6 == (E2 * E6 - E4^2)/2 # Ramanujan identity

Note that the derivative of a modular form is not necessarily a modular form:

sage: dE4.is_modular_form()
False
sage: dE4.weight()
6
>>> from sage.all import *
>>> dE4.is_modular_form()
False
>>> dE4.weight()
6
dE4.is_modular_form()
dE4.weight()
homogeneous_component(weight)[source]

Return the homogeneous component of the given quasimodular form ring element.

An alias of this method is homogeneous_component.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: E2, E4, E6 = QM.gens()
sage: F = E2 + E4*E6 + E2^3*E6
sage: F[2]
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
sage: F[10]
1 - 264*q - 135432*q^2 - 5196576*q^3 - 69341448*q^4 - 515625264*q^5 + O(q^6)
sage: F[12]
1 - 576*q + 21168*q^2 + 308736*q^3 - 15034608*q^4 - 39208320*q^5 + O(q^6)
sage: F[4]
0
sage: F.homogeneous_component(2)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> E2, E4, E6 = QM.gens()
>>> F = E2 + E4*E6 + E2**Integer(3)*E6
>>> F[Integer(2)]
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> F[Integer(10)]
1 - 264*q - 135432*q^2 - 5196576*q^3 - 69341448*q^4 - 515625264*q^5 + O(q^6)
>>> F[Integer(12)]
1 - 576*q + 21168*q^2 + 308736*q^3 - 15034608*q^4 - 39208320*q^5 + O(q^6)
>>> F[Integer(4)]
0
>>> F.homogeneous_component(Integer(2))
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
QM = QuasiModularForms(1)
E2, E4, E6 = QM.gens()
F = E2 + E4*E6 + E2^3*E6
F[2]
F[10]
F[12]
F[4]
F.homogeneous_component(2)
homogeneous_components()[source]

Return a dictionary where the values are the homogeneous components of the given graded form and the keys are the weights of those components.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: (QM.0).homogeneous_components()
{2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)}
sage: (QM.0 + QM.1 + QM.2).homogeneous_components()
{2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
 4: 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
 6: 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)}
sage: (1 + QM.0).homogeneous_components()
{0: 1, 2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)}
sage: QM5 = QuasiModularForms(Gamma1(3))
sage: F = QM.1 + QM.1*QM.2 + QM.1*QM.0 + (QM.1 + QM.2^2)*QM.0^3
sage: F.homogeneous_components()
{4: 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
 6: 1 + 216*q - 3672*q^2 - 62496*q^3 - 322488*q^4 - 1121904*q^5 + O(q^6),
 10: 2 - 96*q - 149040*q^2 - 4986240*q^3 - 67535952*q^4 - 538187328*q^5 + O(q^6),
 18: 1 - 1080*q + 294840*q^2 - 902880*q^3 - 452402280*q^4 + 105456816*q^5 + O(q^6)}
sage: F = QM.zero()
sage: F.homogeneous_components()
{0: 0}
sage: F = QM(42/13)
sage: F.homogeneous_components()
{0: 42/13}
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> (QM.gen(0)).homogeneous_components()
{2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)}
>>> (QM.gen(0) + QM.gen(1) + QM.gen(2)).homogeneous_components()
{2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6),
 4: 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
 6: 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)}
>>> (Integer(1) + QM.gen(0)).homogeneous_components()
{0: 1, 2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)}
>>> QM5 = QuasiModularForms(Gamma1(Integer(3)))
>>> F = QM.gen(1) + QM.gen(1)*QM.gen(2) + QM.gen(1)*QM.gen(0) + (QM.gen(1) + QM.gen(2)**Integer(2))*QM.gen(0)**Integer(3)
>>> F.homogeneous_components()
{4: 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
 6: 1 + 216*q - 3672*q^2 - 62496*q^3 - 322488*q^4 - 1121904*q^5 + O(q^6),
 10: 2 - 96*q - 149040*q^2 - 4986240*q^3 - 67535952*q^4 - 538187328*q^5 + O(q^6),
 18: 1 - 1080*q + 294840*q^2 - 902880*q^3 - 452402280*q^4 + 105456816*q^5 + O(q^6)}
>>> F = QM.zero()
>>> F.homogeneous_components()
{0: 0}
>>> F = QM(Integer(42)/Integer(13))
>>> F.homogeneous_components()
{0: 42/13}
QM = QuasiModularForms(1)
(QM.0).homogeneous_components()
(QM.0 + QM.1 + QM.2).homogeneous_components()
(1 + QM.0).homogeneous_components()
QM5 = QuasiModularForms(Gamma1(3))
F = QM.1 + QM.1*QM.2 + QM.1*QM.0 + (QM.1 + QM.2^2)*QM.0^3
F.homogeneous_components()
F = QM.zero()
F.homogeneous_components()
F = QM(42/13)
F.homogeneous_components()
is_graded_modular_form()[source]

Return whether the given quasimodular form is a graded modular form element (see GradedModularFormElement).

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: (QM.0).is_graded_modular_form()
False
sage: (QM.1).is_graded_modular_form()
True
sage: (QM.1 + QM.0^2).is_graded_modular_form()
False
sage: (QM.1^2 + QM.2).is_graded_modular_form()
True
sage: QM = QuasiModularForms(Gamma0(6))
sage: (QM.0).is_graded_modular_form()
False
sage: (QM.1 + QM.2 + QM.1 * QM.3).is_graded_modular_form()
True
sage: QM.zero().is_graded_modular_form()
True
sage: QM = QuasiModularForms(Gamma0(6))
sage: (QM.0).is_graded_modular_form()
False
sage: (QM.0 + QM.1*QM.2 + QM.3).is_graded_modular_form()
False
sage: (QM.1*QM.2 + QM.3).is_graded_modular_form()
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> (QM.gen(0)).is_graded_modular_form()
False
>>> (QM.gen(1)).is_graded_modular_form()
True
>>> (QM.gen(1) + QM.gen(0)**Integer(2)).is_graded_modular_form()
False
>>> (QM.gen(1)**Integer(2) + QM.gen(2)).is_graded_modular_form()
True
>>> QM = QuasiModularForms(Gamma0(Integer(6)))
>>> (QM.gen(0)).is_graded_modular_form()
False
>>> (QM.gen(1) + QM.gen(2) + QM.gen(1) * QM.gen(3)).is_graded_modular_form()
True
>>> QM.zero().is_graded_modular_form()
True
>>> QM = QuasiModularForms(Gamma0(Integer(6)))
>>> (QM.gen(0)).is_graded_modular_form()
False
>>> (QM.gen(0) + QM.gen(1)*QM.gen(2) + QM.gen(3)).is_graded_modular_form()
False
>>> (QM.gen(1)*QM.gen(2) + QM.gen(3)).is_graded_modular_form()
True
QM = QuasiModularForms(1)
(QM.0).is_graded_modular_form()
(QM.1).is_graded_modular_form()
(QM.1 + QM.0^2).is_graded_modular_form()
(QM.1^2 + QM.2).is_graded_modular_form()
QM = QuasiModularForms(Gamma0(6))
(QM.0).is_graded_modular_form()
(QM.1 + QM.2 + QM.1 * QM.3).is_graded_modular_form()
QM.zero().is_graded_modular_form()
QM = QuasiModularForms(Gamma0(6))
(QM.0).is_graded_modular_form()
(QM.0 + QM.1*QM.2 + QM.3).is_graded_modular_form()
(QM.1*QM.2 + QM.3).is_graded_modular_form()

Note

A graded modular form in SageMath is not necessarily a modular form as it can have mixed weight components. To check for modular forms only, see the method is_modular_form().

is_homogeneous()[source]

Return whether the graded quasimodular form is a homogeneous element, that is, it lives in a unique graded components of the parent of self.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: E2, E4, E6 = QM.gens()
sage: (E2).is_homogeneous()
True
sage: (E2 + E4).is_homogeneous()
False
sage: (E2 * E4 + E6).is_homogeneous()
True
sage: QM(1).is_homogeneous()
True
sage: (1 + E2).is_homogeneous()
False
sage: F = E6^3 + E4^4*E2 + (E4^2*E6)*E2^2 + (E4^3 + E6^2)*E2^3
sage: F.is_homogeneous()
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> E2, E4, E6 = QM.gens()
>>> (E2).is_homogeneous()
True
>>> (E2 + E4).is_homogeneous()
False
>>> (E2 * E4 + E6).is_homogeneous()
True
>>> QM(Integer(1)).is_homogeneous()
True
>>> (Integer(1) + E2).is_homogeneous()
False
>>> F = E6**Integer(3) + E4**Integer(4)*E2 + (E4**Integer(2)*E6)*E2**Integer(2) + (E4**Integer(3) + E6**Integer(2))*E2**Integer(3)
>>> F.is_homogeneous()
True
QM = QuasiModularForms(1)
E2, E4, E6 = QM.gens()
(E2).is_homogeneous()
(E2 + E4).is_homogeneous()
(E2 * E4 + E6).is_homogeneous()
QM(1).is_homogeneous()
(1 + E2).is_homogeneous()
F = E6^3 + E4^4*E2 + (E4^2*E6)*E2^2 + (E4^3 + E6^2)*E2^3
F.is_homogeneous()
is_modular_form()[source]

Return whether the given quasimodular form is a modular form.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: (QM.0).is_modular_form()
False
sage: (QM.1).is_modular_form()
True
sage: (QM.1 + QM.2).is_modular_form() # mixed weight components
False
sage: QM.zero().is_modular_form()
True
sage: QM = QuasiModularForms(Gamma0(4))
sage: (QM.0).is_modular_form()
False
sage: (QM.1).is_modular_form()
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> (QM.gen(0)).is_modular_form()
False
>>> (QM.gen(1)).is_modular_form()
True
>>> (QM.gen(1) + QM.gen(2)).is_modular_form() # mixed weight components
False
>>> QM.zero().is_modular_form()
True
>>> QM = QuasiModularForms(Gamma0(Integer(4)))
>>> (QM.gen(0)).is_modular_form()
False
>>> (QM.gen(1)).is_modular_form()
True
QM = QuasiModularForms(1)
(QM.0).is_modular_form()
(QM.1).is_modular_form()
(QM.1 + QM.2).is_modular_form() # mixed weight components
QM.zero().is_modular_form()
QM = QuasiModularForms(Gamma0(4))
(QM.0).is_modular_form()
(QM.1).is_modular_form()
is_one()[source]

Return whether the given quasimodular form is 1, i.e. the multiplicative identity.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.one().is_one()
True
sage: QM(1).is_one()
True
sage: (QM.0).is_one()
False
sage: QM = QuasiModularForms(Gamma0(2))
sage: QM(1).is_one()
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.one().is_one()
True
>>> QM(Integer(1)).is_one()
True
>>> (QM.gen(0)).is_one()
False
>>> QM = QuasiModularForms(Gamma0(Integer(2)))
>>> QM(Integer(1)).is_one()
True
QM = QuasiModularForms(1)
QM.one().is_one()
QM(1).is_one()
(QM.0).is_one()
QM = QuasiModularForms(Gamma0(2))
QM(1).is_one()
is_zero()[source]

Return whether the given quasimodular form is zero.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: QM.zero().is_zero()
True
sage: QM(0).is_zero()
True
sage: QM(1/2).is_zero()
False
sage: (QM.0).is_zero()
False
sage: QM = QuasiModularForms(Gamma0(2))
sage: QM(0).is_zero()
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> QM.zero().is_zero()
True
>>> QM(Integer(0)).is_zero()
True
>>> QM(Integer(1)/Integer(2)).is_zero()
False
>>> (QM.gen(0)).is_zero()
False
>>> QM = QuasiModularForms(Gamma0(Integer(2)))
>>> QM(Integer(0)).is_zero()
True
QM = QuasiModularForms(1)
QM.zero().is_zero()
QM(0).is_zero()
QM(1/2).is_zero()
(QM.0).is_zero()
QM = QuasiModularForms(Gamma0(2))
QM(0).is_zero()
polynomial(names=None)[source]

Return a multivariate polynomial such that every variable corresponds to a generator of the ring, ordered by the method: gens().

An alias of this method is to_polynomial.

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 form ABCk where k is a number corresponding to the weight of the form ABC.

OUTPUT: a multivariate polynomial in the variables names

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: (QM.0 + QM.1).polynomial()
E4 + E2
sage: (1/2 + QM.0 + 2*QM.1^2 + QM.0*QM.2).polynomial()
E2*E6 + 2*E4^2 + E2 + 1/2
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> (QM.gen(0) + QM.gen(1)).polynomial()
E4 + E2
>>> (Integer(1)/Integer(2) + QM.gen(0) + Integer(2)*QM.gen(1)**Integer(2) + QM.gen(0)*QM.gen(2)).polynomial()
E2*E6 + 2*E4^2 + E2 + 1/2
QM = QuasiModularForms(1)
(QM.0 + QM.1).polynomial()
(1/2 + QM.0 + 2*QM.1^2 + QM.0*QM.2).polynomial()

Check that Issue #34569 is fixed:

sage: QM = QuasiModularForms(Gamma1(3))
sage: QM.ngens()
5
sage: (QM.0 + QM.1 + QM.2*QM.1 + QM.3*QM.4).polynomial()
E3_1*E4_0 + E2_0*E3_0 + E2 + E2_0
>>> from sage.all import *
>>> QM = QuasiModularForms(Gamma1(Integer(3)))
>>> QM.ngens()
5
>>> (QM.gen(0) + QM.gen(1) + QM.gen(2)*QM.gen(1) + QM.gen(3)*QM.gen(4)).polynomial()
E3_1*E4_0 + E2_0*E3_0 + E2 + E2_0
QM = QuasiModularForms(Gamma1(3))
QM.ngens()
(QM.0 + QM.1 + QM.2*QM.1 + QM.3*QM.4).polynomial()
q_expansion(prec=6)[source]

Return the \(q\)-expansion of the given quasimodular form up to precision prec (default: 6).

An alias of this method is qexp.

EXAMPLES:

sage: QM = QuasiModularForms()
sage: E2 = QM.0
sage: E2.q_expansion()
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
sage: E2.q_expansion(prec=10)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 - 288*q^6 - 192*q^7 - 360*q^8 - 312*q^9 + O(q^10)
>>> from sage.all import *
>>> QM = QuasiModularForms()
>>> E2 = QM.gen(0)
>>> E2.q_expansion()
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> E2.q_expansion(prec=Integer(10))
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 - 288*q^6 - 192*q^7 - 360*q^8 - 312*q^9 + O(q^10)
QM = QuasiModularForms()
E2 = QM.0
E2.q_expansion()
E2.q_expansion(prec=10)
qexp(prec=6)[source]

Return the \(q\)-expansion of the given quasimodular form up to precision prec (default: 6).

An alias of this method is qexp.

EXAMPLES:

sage: QM = QuasiModularForms()
sage: E2 = QM.0
sage: E2.q_expansion()
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
sage: E2.q_expansion(prec=10)
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 - 288*q^6 - 192*q^7 - 360*q^8 - 312*q^9 + O(q^10)
>>> from sage.all import *
>>> QM = QuasiModularForms()
>>> E2 = QM.gen(0)
>>> E2.q_expansion()
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
>>> E2.q_expansion(prec=Integer(10))
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 - 288*q^6 - 192*q^7 - 360*q^8 - 312*q^9 + O(q^10)
QM = QuasiModularForms()
E2 = QM.0
E2.q_expansion()
E2.q_expansion(prec=10)
serre_derivative()[source]

Return the Serre derivative of the given quasimodular form.

If the form is not homogeneous, then this method sums the Serre derivative of each homogeneous component.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: E2, E4, E6 = QM.gens()
sage: DE2 = E2.serre_derivative(); DE2
-1/6 - 16*q - 216*q^2 - 832*q^3 - 2248*q^4 - 4320*q^5 + O(q^6)
sage: DE2 == (-E2^2 - E4)/12
True
sage: DE4 = E4.serre_derivative(); DE4
-1/3 + 168*q + 5544*q^2 + 40992*q^3 + 177576*q^4 + 525168*q^5 + O(q^6)
sage: DE4 == (-1/3) * E6
True
sage: DE6 = E6.serre_derivative(); DE6
-1/2 - 240*q - 30960*q^2 - 525120*q^3 - 3963120*q^4 - 18750240*q^5 + O(q^6)
sage: DE6 == (-1/2) * E4^2
True
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> E2, E4, E6 = QM.gens()
>>> DE2 = E2.serre_derivative(); DE2
-1/6 - 16*q - 216*q^2 - 832*q^3 - 2248*q^4 - 4320*q^5 + O(q^6)
>>> DE2 == (-E2**Integer(2) - E4)/Integer(12)
True
>>> DE4 = E4.serre_derivative(); DE4
-1/3 + 168*q + 5544*q^2 + 40992*q^3 + 177576*q^4 + 525168*q^5 + O(q^6)
>>> DE4 == (-Integer(1)/Integer(3)) * E6
True
>>> DE6 = E6.serre_derivative(); DE6
-1/2 - 240*q - 30960*q^2 - 525120*q^3 - 3963120*q^4 - 18750240*q^5 + O(q^6)
>>> DE6 == (-Integer(1)/Integer(2)) * E4**Integer(2)
True
QM = QuasiModularForms(1)
E2, E4, E6 = QM.gens()
DE2 = E2.serre_derivative(); DE2
DE2 == (-E2^2 - E4)/12
DE4 = E4.serre_derivative(); DE4
DE4 == (-1/3) * E6
DE6 = E6.serre_derivative(); DE6
DE6 == (-1/2) * E4^2

The Serre derivative raises the weight of homogeneous elements by 2:

sage: F = E6 + E4 * E2
sage: F.weight()
6
sage: F.serre_derivative().weight()
8
>>> from sage.all import *
>>> F = E6 + E4 * E2
>>> F.weight()
6
>>> F.serre_derivative().weight()
8
F = E6 + E4 * E2
F.weight()
F.serre_derivative().weight()

Check that Issue #34569 is fixed:

sage: QM = QuasiModularForms(Gamma1(3))
sage: E2 = QM.weight_2_eisenstein_series()
sage: E2.serre_derivative()
-1/6 - 16*q - 216*q^2 - 832*q^3 - 2248*q^4 - 4320*q^5 + O(q^6)
sage: F = QM.0 + QM.1*QM.2
>>> from sage.all import *
>>> QM = QuasiModularForms(Gamma1(Integer(3)))
>>> E2 = QM.weight_2_eisenstein_series()
>>> E2.serre_derivative()
-1/6 - 16*q - 216*q^2 - 832*q^3 - 2248*q^4 - 4320*q^5 + O(q^6)
>>> F = QM.gen(0) + QM.gen(1)*QM.gen(2)
QM = QuasiModularForms(Gamma1(3))
E2 = QM.weight_2_eisenstein_series()
E2.serre_derivative()
F = QM.0 + QM.1*QM.2
to_polynomial(names=None)[source]

Return a multivariate polynomial such that every variable corresponds to a generator of the ring, ordered by the method: gens().

An alias of this method is to_polynomial.

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 form ABCk where k is a number corresponding to the weight of the form ABC.

OUTPUT: a multivariate polynomial in the variables names

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: (QM.0 + QM.1).polynomial()
E4 + E2
sage: (1/2 + QM.0 + 2*QM.1^2 + QM.0*QM.2).polynomial()
E2*E6 + 2*E4^2 + E2 + 1/2
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> (QM.gen(0) + QM.gen(1)).polynomial()
E4 + E2
>>> (Integer(1)/Integer(2) + QM.gen(0) + Integer(2)*QM.gen(1)**Integer(2) + QM.gen(0)*QM.gen(2)).polynomial()
E2*E6 + 2*E4^2 + E2 + 1/2
QM = QuasiModularForms(1)
(QM.0 + QM.1).polynomial()
(1/2 + QM.0 + 2*QM.1^2 + QM.0*QM.2).polynomial()

Check that Issue #34569 is fixed:

sage: QM = QuasiModularForms(Gamma1(3))
sage: QM.ngens()
5
sage: (QM.0 + QM.1 + QM.2*QM.1 + QM.3*QM.4).polynomial()
E3_1*E4_0 + E2_0*E3_0 + E2 + E2_0
>>> from sage.all import *
>>> QM = QuasiModularForms(Gamma1(Integer(3)))
>>> QM.ngens()
5
>>> (QM.gen(0) + QM.gen(1) + QM.gen(2)*QM.gen(1) + QM.gen(3)*QM.gen(4)).polynomial()
E3_1*E4_0 + E2_0*E3_0 + E2 + E2_0
QM = QuasiModularForms(Gamma1(3))
QM.ngens()
(QM.0 + QM.1 + QM.2*QM.1 + QM.3*QM.4).polynomial()
weight()[source]

Return the weight of the given quasimodular form.

Note that the given form must be homogeneous. An alias of this method is degree.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: (QM.0).weight()
2
sage: (QM.0 * QM.1 + QM.2).weight()
6
sage: QM(1/2).weight()
0
sage: (QM.0).degree()
2
sage: (QM.0 + QM.1).weight()
Traceback (most recent call last):
...
ValueError: the given graded quasiform is not an homogeneous element
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> (QM.gen(0)).weight()
2
>>> (QM.gen(0) * QM.gen(1) + QM.gen(2)).weight()
6
>>> QM(Integer(1)/Integer(2)).weight()
0
>>> (QM.gen(0)).degree()
2
>>> (QM.gen(0) + QM.gen(1)).weight()
Traceback (most recent call last):
...
ValueError: the given graded quasiform is not an homogeneous element
QM = QuasiModularForms(1)
(QM.0).weight()
(QM.0 * QM.1 + QM.2).weight()
QM(1/2).weight()
(QM.0).degree()
(QM.0 + QM.1).weight()
weights_list()[source]

Return the list of the weights of all the graded components of the given graded quasimodular form.

EXAMPLES:

sage: QM = QuasiModularForms(1)
sage: (QM.0).weights_list()
[2]
sage: (QM.0 + QM.1 + QM.2).weights_list()
[2, 4, 6]
sage: (QM.0 * QM.1 + QM.2).weights_list()
[6]
sage: QM(1/2).weights_list()
[0]
sage: QM = QuasiModularForms(Gamma1(3))
sage: (QM.0 + QM.1 + QM.2*QM.1 + QM.3*QM.4).weights_list()
[2, 5, 7]
>>> from sage.all import *
>>> QM = QuasiModularForms(Integer(1))
>>> (QM.gen(0)).weights_list()
[2]
>>> (QM.gen(0) + QM.gen(1) + QM.gen(2)).weights_list()
[2, 4, 6]
>>> (QM.gen(0) * QM.gen(1) + QM.gen(2)).weights_list()
[6]
>>> QM(Integer(1)/Integer(2)).weights_list()
[0]
>>> QM = QuasiModularForms(Gamma1(Integer(3)))
>>> (QM.gen(0) + QM.gen(1) + QM.gen(2)*QM.gen(1) + QM.gen(3)*QM.gen(4)).weights_list()
[2, 5, 7]
QM = QuasiModularForms(1)
(QM.0).weights_list()
(QM.0 + QM.1 + QM.2).weights_list()
(QM.0 * QM.1 + QM.2).weights_list()
QM(1/2).weights_list()
QM = QuasiModularForms(Gamma1(3))
(QM.0 + QM.1 + QM.2*QM.1 + QM.3*QM.4).weights_list()