Ask Your Question
2

Meaning of the names of generators of ring of (quasi)modular forms

asked 2024-02-09 17:52:38 +0200

seewoo5 gravatar image

updated 2024-02-12 11:35:51 +0200

FrédéricC gravatar image

Recently, I used Sage to do computations on (quasi)modular forms and I found some mysterious namings of them. The following code

QM2 = QuasiModularForms(Gamma0(2))

for qm in QM2.gens():
    print(qm.polynomial(), qm)

gives

E2 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)
E2_0 1 + 24*q + 24*q^2 + 96*q^3 + 24*q^4 + 144*q^5 + O(q^6)
E4_0 1 + 240*q^2 + 2160*q^4 + O(q^6)

and I know that the first one is the weight 2 and level 1 Eisenstein series, but it is not clear to me what the E2_0 and E4_0 stand for. Based on q-series, I guess that those are 2E2(2z) - E2(z) and E4(2z), but I wonder how it works in general. I tried to find the corresponding code in GitHub but failed. Any helps appreciated.

edit retag flag offensive close merge delete

1 Answer

Sort by » oldest newest most voted
2

answered 2024-02-12 21:21:09 +0200

dan_fulea gravatar image

Let us take a look at the constructor called in order to build the instance QM2.

First of all, it is mathematically a ring (with further structure),

sage: QM2.category()
Category of graded algebras over Rational Field

If we ask via ?QM2 for more information on the instance, we get...

Type:           QuasiModularForms_with_category
String form:    Ring of Quasimodular Forms for Congruence Subgroup Gamma0(2) over Rational Field
File:           /usr/lib/python3.11/site-packages/sage/modular/quasimodform/ring.py
Docstring:
   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
Init docstring:
   INPUT:

   * "group" (default: \SL_2(\ZZ)) -- a congruence subgroup of
     \SL_2(\ZZ), or a positive integer N (interpreted as \Gamma_0(N)).

   * "base_ring" (ring, default: \QQ) -- a base ring, which should be
     \QQ, \ZZ, or the integers mod p for some prime p.

   * "name" (str, default: "'E2'") -- a variable name corresponding to
     the weight 2 Eisenstein series.

And so on.

We have above also the location of the corresponding py-module on the hard disk, so we have access to the code. This is the open source world. To have the code of the class (starting with the above doc string) also in the interpreter, just ask for ??QM2 instead.

So we have a ring in our hands. When we explicitly ask for this ring, forgetting about everything else...

sage: QM2.polynomial_ring()
Multivariate Polynomial Ring in E2, E2_0, E4_0 over Rational Field

So the ring has three generators,

sage: QM2.polynomial_ring().ngens()
3

and sage uses for them the names E2, E2_0, E4_0. Let us consider the following code:

N = 2
QM = QuasiModularForms(Gamma0(N))

for qm in QM.gens():
    print(f"The q-modular form {qm} has:\n\t"
          f"weight     = {qm.weight()}\n\t"
          f"polynomial = {qm.polynomial()}\n\t"
          f"is_modular = {qm.is_modular_form()}")

It gives:

The q-modular form 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6) has:
    weight     = 2
    polynomial = E2
    is_modular = False
The q-modular form 1 + 24*q + 24*q^2 + 96*q^3 + 24*q^4 + 144*q^5 + O(q^6) has:
    weight     = 2
    polynomial = E2_0
    is_modular = True
The q-modular form 1 + 240*q^2 + 2160*q^4 + O(q^6) has:
    weight     = 4
    polynomial = E4_0
    is_modular = True

The names are... see also https://doc.sagemath.org/html/en/reference/modfrm/sage/modular/quasimodform/element.html, when the method polynomial is mentioned:

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())

And in this last documentation...

sage: QM.polynomial_ring?

Signature:      QM.polynomial_ring(names=None)
Docstring:
   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" 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:
   :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

there is also a mention about the default convention of denoting elements of the associated polynomial ring.

In fact, replacing above N = 2 and letting the definition of QM use the new N,

N = 24
QM = QuasiModularForms(Gamma0(N))

we obtain a new list of default names:

The q-modular form 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6) has:
    weight     = 2
    polynomial = E2
    is_modular = False
The q-modular form 1 + O(q^6) has:
    weight     = 2
    polynomial = E2_0
    is_modular = True
The q-modular form q + O(q^6) has:
    weight     = 2
    polynomial = F2
    is_modular = True
The q-modular form q^2 + O(q^6) has:
    weight     = 2
    polynomial = E2_2
    is_modular = True
The q-modular form q^3 + O(q^6) has:
    weight     = 2
    polynomial = E2_3
    is_modular = True
The q-modular form q^4 + O(q^6) has:
    weight     = 2
    polynomial = E2_4
    is_modular = True
The q-modular form q^5 + O(q^6) has:
    weight     = 2
    polynomial = G2
    is_modular = True
The q-modular form O(q^6) has:
    weight     = 2
    polynomial = E2_5
    is_modular = True
The q-modular form O(q^6) has:
    weight     = 2
    polynomial = E2_6
    is_modular = True

Let us ask for...

sage: QM.polynomial_ring()
Multivariate Polynomial Ring in E2, E2_0, F2, E2_2, E2_3, E2_4, G2, E2_5, E2_6 over Rational Field

And let us decide, we want our own names, using the letter U uniformly.

sage: R = QM.polynomial_ring(names='U')
sage: R
Multivariate Polynomial Ring in U0, U1, U2, U3, U4, U5, U6, U7, U8 over Rational Field
sage: R.inject_variables()
Defining U0, U1, U2, U3, U4, U5, U6, U7, U8

And now we can work with U0, U1, ... , U8 instead.

edit flag offensive delete link more

Comments

Thank you for your very detailed answer. However, I want to confirm that my guess for the E2_0 and E4_0 are correct, and it seems that I need to check the actual implementation of QM.polynomial_ring() to see how Ek_i are actually defined/determined.

seewoo5 gravatar imageseewoo5 ( 2024-02-14 23:38:40 +0200 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2024-02-09 17:51:52 +0200

Seen: 269 times

Last updated: Feb 12