# 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
2
sage: g2
T^9 + 2*T^3
sage: g2
2*T^9 + T^3
sage: g2  # 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#
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