Ring of Drinfeld modular forms#

This module defines a class named DrinfeldModularFormsRing.

Currently, the implementation only supports the full group modular group \(\mathrm{GL}_r(A)\) where \(A = \mathbb{F}_q[T]\).

The implementation is based on the following identification:

\[M^r(\mathrm{GL}_r(A)) = \mathbb{C}_{\infty}[g_1, \ldots, g_{r-1}, g_{r}].\]

where \(g_i\) the \(i\)-th coefficient form of weight \(q^{i} - 1\).

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3
sage: A = GF(q)['T']
sage: K.<T> = Frac(A)
sage: M = DrinfeldModularFormsRing(K, 2)  # rank 2
sage: M.gens()  # generators
[g1, g2]
sage: M.inject_variables()  # assign variables
Defining g1, g2
sage: g1.weight()
2
sage: g2.weight()
8
sage: M = DrinfeldModularFormsRing(K, 3)  # rank 3
sage: M.gens()
[g1, g2, g3]
sage: [g.weight() for g in M.gens()]  # list of the weights
[2, 8, 26]
sage: M.inject_variables()
Defining g1, g2, g3
sage: g1.weight() == 3 - 1
True
sage: g2.weight() == 3^2 - 1
True
sage: g3.weight() == 3^3 - 1
True

It is possible to compute the coefficient forms:

sage: M = DrinfeldModularFormsRing(K, 2)
sage: M.coefficient_form(1)
g1
sage: M.coefficient_form(2)
g2
sage: M.coefficient_form(2, T^2)
g1^4 + (T^9 + T)*g2
sage: M.coefficient_forms(T^3)
[(T^6 + T^4 + T^2)*g1,
 (T^9 + T^3 + T)*g1^4 + (T^18 + T^10 + T^2)*g2,
 g1^13 + (T^27 + T^9 + T)*g1^9*g2 + (T^27 + T^3 + T)*g1*g2^3,
 g1^36*g2 + g1^28*g2^3 + g1^4*g2^9 + (T^81 + T^9 + T)*g2^10,
 g1^81*g2^10 + g1^9*g2^28 + g1*g2^30,
 g2^91]

One can compute basis for any subspace of given weight:

sage: M = DrinfeldModularFormsRing(K, 4)
sage: M.basis_of_weight(q^4 - 1)
[g4,
 g2^10,
 g1*g3^3,
 g1^2*g2^3*g3^2,
 g1^3*g2^6*g3,
 g1^4*g2^9,
 g1^6*g2^2*g3^2,
 g1^7*g2^5*g3,
 g1^8*g2^8,
 g1^10*g2*g3^2,
 g1^11*g2^4*g3,
 g1^12*g2^7,
 g1^14*g3^2,
 g1^15*g2^3*g3,
 g1^16*g2^6,
 g1^19*g2^2*g3,
 g1^20*g2^5,
 g1^23*g2*g3,
 g1^24*g2^4,
 g1^27*g3,
 g1^28*g2^3,
 g1^32*g2^2,
 g1^36*g2,
 g1^40]

We note that the elements of this ring may not be modular forms as as they may have mixed weight components:

sage: M = DrinfeldModularFormsRing(K, 4)
sage: M.inject_variables()
Defining g1, g2, g3, g4
sage: F = g1 + g2 + g3 + g4
sage: F.is_drinfeld_modular_form()
False

This is why we call these elements graded Drinfeld modular forms.

One can also consider the ring Drinfeld modular forms of arbitrary type:

sage: A = GF(7)['T']
sage: K.<T> = Frac(A)
sage: M = DrinfeldModularFormsRing(K, 4, has_type=True)
sage: M.inject_variables()
Defining g1, g2, g3, h
sage: h.weight()
400
sage: h.type_m()
1
sage: (g1*h^4).type_m()
4

The last generator is known as Gekeler’s \(h\) function.

The rank 2 case

In rank 2 case, one can also compute the expansion at infinity of Drinfeld modular forms.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3
sage: A = GF(q)['T']
sage: K.<T> = Frac(A)
sage: M = DrinfeldModularFormsRing(K, 2)  # rank 2
sage: M.inject_variables()
Defining g1, g2
sage: g1.expansion()
1 + ((2*T^3+T)*u^2) + O(u^7)
sage: g2.expansion()
u^2 + 2*u^6 + O(u^8)

The returned series is a lazy power series, meaning that it can compute any coefficient at any precision on demands:

sage: g2[6]
2
sage: g2[24]
T^9 + 2*T^3
sage: g2[36]
2*T^9 + T^3
sage: g2[702]  # long time
2*T^252 + T^246 + 2*T^90 + T^84 + 2*T^36 + T^30 + T^18 + T^12 + T^6
sage: M = DrinfeldModularFormsRing(K, 2, has_type=True)
sage: M.inject_variables()
Defining g1, h
sage: h.expansion()
u + u^5 + ((2*T^3+T)*u^7) + O(u^8)

AUTHORS:

  • David Ayotte (2022): initial version

class drinfeld_modular_forms.ring.DrinfeldModularFormsRing(base_ring, rank=2, group=None, has_type=False, names='g')#

Bases: Parent, UniqueRepresentation

Base class for the graded Drinfeld modular forms ring.

INPUT:

  • base_ring – The fraction field of a univariate polynomial ring over \(\mathbb{F}_q\).

  • rank (integer, default: 2) – the rank of the ring

  • group (NoneType) – the group of self. The current implementation only supports the full group \(\mathrm{GL}_r(A)\).

  • has_type (bool, default: False) – if set to True, returns the graded ring of arbitrary type.

  • names (string, default: 'g') – a single character or a comma seperated string of character representing the names of the generators.

Element#

alias of DrinfeldModularFormsRingElement

basis(k)#

Return a list of Drinfeld modular forms which forms a basis for the subspace of weight \(k\).

Note that if \(k\not\equiv 0\) modulo \(q-1\), then the subspace is 0.

An alias of this method is basis.

INPUT:

  • k – an integer.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3; A = GF(q)['T']; K = Frac(A);
sage: M = DrinfeldModularFormsRing(K, 2)
sage: M.basis_of_weight(q - 1)
[g1]
sage: M.basis_of_weight(q^2 - 1)
[g2, g1^4]
sage: M.basis_of_weight(q^3 - 1)
[g1*g2^3, g1^5*g2^2, g1^9*g2, g1^13]
sage: M.basis_of_weight(19*(q-1))
[g1^3*g2^4, g1^7*g2^3, g1^11*g2^2, g1^15*g2, g1^19]
basis_of_weight(k)#

Return a list of Drinfeld modular forms which forms a basis for the subspace of weight \(k\).

Note that if \(k\not\equiv 0\) modulo \(q-1\), then the subspace is 0.

An alias of this method is basis.

INPUT:

  • k – an integer.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3; A = GF(q)['T']; K = Frac(A);
sage: M = DrinfeldModularFormsRing(K, 2)
sage: M.basis_of_weight(q - 1)
[g1]
sage: M.basis_of_weight(q^2 - 1)
[g2, g1^4]
sage: M.basis_of_weight(q^3 - 1)
[g1*g2^3, g1^5*g2^2, g1^9*g2, g1^13]
sage: M.basis_of_weight(19*(q-1))
[g1^3*g2^4, g1^7*g2^3, g1^11*g2^2, g1^15*g2, g1^19]
coefficient_form(i, a=None)#

Return the \(i\)-th coefficient form of the universal Drinfeld module over \(\Omega^r(\mathbb{C}_{\infty})\):

..MATH:

\phi_{w, a} = a + g_{1, a}\tau + \cdots + g_{r d_a, a}\tau^{r d_a}

where \(d_a := \mathrm{deg}(a)\).

INPUT:

  • i – an integer between 1 and \(r d_a\);

  • a – (default: None) an element in the ring of regular functions. If \(a\) is None, then the method returns the \(i\)-th coefficient form of \(\phi_{w, T}\).

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3
sage: A = GF(q)['T']
sage: K.<T> = Frac(A)
sage: M = DrinfeldModularFormsRing(K, 3)
sage: M.coefficient_form(1)
g1
sage: M.coefficient_form(2)
g2
sage: M.coefficient_form(3)
g3
sage: M.coefficient_form(5, T^2)
g2^27*g3 + g2*g3^9
sage: M = DrinfeldModularFormsRing(K, 2, has_type=True)
sage: M.coefficient_form(1)
g1
sage: M.coefficient_form(2)
h^2
sage: M.coefficient_form(2, T^3 + T^2 + T)
(T^9 + T^3 + T + 1)*g1^4 + (T^18 + T^10 + T^9 + T^2 + T + 1)*h^2
coefficient_forms(a=None)#

Return the list of all coefficient forms at \(a\).

See also coefficient_form().

EXAMPLE:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3
sage: A = GF(q)['T']
sage: K.<T> = Frac(A)
sage: M = DrinfeldModularFormsRing(K, 2)
sage: M.coefficient_forms()
[g1, g2]
sage: M.coefficient_forms(T^2)
[(T^3 + T)*g1, g1^4 + (T^9 + T)*g2, g1^9*g2 + g1*g2^3, g2^10]
sage: M.coefficient_forms(T^3)
[(T^6 + T^4 + T^2)*g1,
 (T^9 + T^3 + T)*g1^4 + (T^18 + T^10 + T^2)*g2,
 g1^13 + (T^27 + T^9 + T)*g1^9*g2 + (T^27 + T^3 + T)*g1*g2^3,
 g1^36*g2 + g1^28*g2^3 + g1^4*g2^9 + (T^81 + T^9 + T)*g2^10,
 g1^81*g2^10 + g1^9*g2^28 + g1*g2^30,
 g2^91]
eisenstein_series(k)#

Return the Drinfeld Eisenstein series of weight \(k\).

The method is currently only implemented for rank 2 and when \(k\) is of of the form \(q^i - 1\). If \(k = 0\), the method returns 0.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3
sage: A = GF(q)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularFormsRing(K, 2)
sage: M.eisenstein_series(0)
0
sage: M.eisenstein_series(q - 1)
g1
sage: M.eisenstein_series(q^2 - 1)
g1^4
sage: M.eisenstein_series(q^3 - 1)
g1^13 + (-T^9 + T)*g1*g2^3
from_expansion(expansion, k)#

Return the Drinfeld modular form which corresponds to the given expansion.

INPUT:

  • expansion – a lazy power series, a power series, a list or a tuple. The precision or the length must be at least the Sturm bound + 2 of the weight \(k\) subspace.

  • k – an integer representing the weight of the expected Drinfeld modular form.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3
sage: A = GF(q)['T']
sage: K.<T> = Frac(A)
sage: M = DrinfeldModularFormsRing(K)
sage: M.from_expansion([1, 0, 2*T^3 + T], q - 1)
g1
sage: f = (M.1).expansion()
sage: M.from_expansion(f, (M.1).weight())
g2
gen(n)#

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

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularFormsRing(K, 2)
sage: M.0
g1
sage: M.1
g2
gens()#

Return a list of generators for this ring.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularFormsRing(K, 5)
sage: M.gens()
[g1, g2, g3, g4, g5]
ngens()#

Return the number of generators of the ring.

Note that the number of generators is equal to the rank.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularFormsRing(K, 5)
sage: M.ngens()
5
one()#

Return the multiplicative identity of the ring.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularFormsRing(K, 2)
sage: M.one()
1
sage: M.one() * M.0
g1
sage: M.one().is_one()
True
petrov_expansion(k, n, name='t')#

Return a Drinfeld modular form which admits the \(A\)-expansion for \(k\) and \(n\) as defined by Petrov.

Recall that it is defined by:

\[\begin{split}f_{k, i}(z) := \sum_{\substack{a\in \mathbb{F}_q[T] \\ a\text{ monic}}} a^{k - i}G_i(t(az))\end{split}\]

where \(k\) and \(n\) are 2 integers which are divisible by \(q - 1\) and \(n \leq p^{v_{p}(k - n)}\) (\(p\) is the characteristic).

INPUT:

  • k – an integer equal to the weight of the resulting form.

  • n – an integer congruent to the type modulo \(q-1\) which is stricly less than \(p^{v_{p}(k - n)}\).

  • name – string (default: 'T'), the name of the parameter at infinity.

OUTPUT: a Drinfeld modular form of weight \(k\).

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3
sage: A = GF(q)['T']; K = Frac(A)
sage: M = DrinfeldModularFormsRing(K, 2)
sage: M.petrov_expansion((q + 1)*(q - 1), q - 1)
g2
sage: M.petrov_expansion((q^2 + 1)*(q - 1), q - 1)
g1^6*g2
sage: M.petrov_expansion((q^3 + 1)*(q - 1), q - 1)
g1^24*g2 + (T^27 - T^9)*g1^12*g2^4 + (T^54 + T^36 + T^18)*g2^7
sage: M = DrinfeldModularFormsRing(K, 2, has_type=True)
sage: M.petrov_expansion(q + 1, 1)
h
sage: M.petrov_expansion(q^2 - 1, 1)
g1^2*h
sage: M.petrov_expansion(q^3 - 1, 1)
g1^11*h + (T^21 - T^19 + T^15 - T^13 + T^9 - T^7)*g1^7*h^3 + (-T^24 - T^22 - T^20 - T^18 - T^16 - T^14 - T^12 - T^10 - T^8)*g1^3*h^5
polynomial_ring()#

Return the multivariate polynomial ring over the base ring where each variable corresponds to a generator of a ring.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3; A = GF(q)['T']; K = Frac(A);
sage: M = DrinfeldModularFormsRing(K, 2)
sage: P = M.polynomial_ring()
sage: P
Multivariate Polynomial Ring in g1, g2 over Fraction Field of Univariate Polynomial Ring in T over Finite Field of size 3

The degree of the variables corresponds to the weight of the associated generator:

sage: P.inject_variables()
Defining g1, g2
sage: g1.degree()
2
sage: g2.degree()
8
rank()#

Return the rank of the ring of Drinfeld modular forms.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: A = GF(3)['T']; K = Frac(A);
sage: DrinfeldModularFormsRing(K, 2).rank()
2
sage: DrinfeldModularFormsRing(K, 3).rank()
3
sage: DrinfeldModularFormsRing(K, 4).rank()
4
sturm_bound(k)#

Return the Sturm bound of the subspace of weight \(k\).

Currently only implemented in rank 2.

INPUT:

  • k – an integer

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: q = 3; A = GF(q)['T']; K = Frac(A);
sage: M = DrinfeldModularFormsRing(K, 2)
sage: M.sturm_bound(q - 1)
1
sage: M.sturm_bound(q^2 - 1)
3
sage: M.sturm_bound(q^9 - 1)
4921
zero()#

Return the additive identity of the ring.

EXAMPLES:

sage: from drinfeld_modular_forms import DrinfeldModularFormsRing
sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularFormsRing(K, 2)
sage: M.zero()
0
sage: M.zero() + M.1
g2
sage: M.zero() * M.1
0
sage: M.zero().is_zero()
True