Graded rings of Drinfeld modular forms#

This module defines a class named DrinfeldModularForms. Currently, the implementation only supports the full 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\) is the \(i\)-th coefficient form of weight \(q^{i} - 1\).

AUTHORS:

  • David Ayotte (2022): initial version

class sage.modular.drinfeld_modform.ring.DrinfeldModularForms(base_ring, rank, group, has_type, names)[source]#

Bases: Parent, UniqueRepresentation

Base class for the graded ring of Drinfeld modular forms.

If \(K = \mathrm{Frac}(A)\) where \(A = \mathbb{F}_q[T]\), then the ring of Drinfeld modular forms over \(K\) of rank \(r\) and type zero for \(\mathrm{GL}_r(A)\) is

\[M^{r, 0}(\mathrm{GL}_r(A)) = K[g_1, \ldots, g_{r-1}, g_{r}].\]

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

Similarly, the ring of Drinfeld modular forms over \(K\) of rank \(r\) and arbitrary type is

\[M^{r}(\mathrm{GL}_r(A)) = K[g_1, \ldots, g_{r-1}, h_{r}].\]

where \(h_r\) is a form of weight \((q^r - 1)/(q - 1)\) and type \(1\).

We will see the elements of this ring as formal objects given by algebraic combination of the generator of the ring. See the class DrinfeldModularFormsElement for more details about their implementation.

INPUT:

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

  • rank integer (default: None) – the rank of the ring. If the rank is None, then the names of the generators must be specified.

  • group (not implemented, default: None) – the group of the ring. The current implementation only supports the full modular group \(\mathrm{GL}_r(A)\).

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

  • names string, tuple or list (default: None) – a single character, a tuple or list of character, or comma separated string of character representing the names of the generators. If this parameter is set to None and the rank is specified, then the default names for the generators will be:

    • g1, g2, ..., gr for the type zero forms

    • g1, g2, ..., hr for the arbitrary type forms.

    If this parameter is a single character, for example f, and a rank is specified, then the names will be of the form f1, f2, ..., fr. Finally, if this parameter is a list, a tupe or a string of comma separated characters, then each character will corresponds to a generator. Note that in this case, it not necessary to specify the rank.

EXAMPLES:

sage: q = 3
sage: A = GF(q)['T']
sage: K.<T> = Frac(A)
sage: M = DrinfeldModularForms(K, 3)
sage: M
Ring of Drinfeld modular forms of rank 3 over Fraction Field of Univariate Polynomial Ring in T over Finite Field of size 3
>>> from sage.all import *
>>> q = Integer(3)
>>> A = GF(q)['T']
>>> K = Frac(A, names=('T',)); (T,) = K._first_ngens(1)
>>> M = DrinfeldModularForms(K, Integer(3))
>>> M
Ring of Drinfeld modular forms of rank 3 over Fraction Field of Univariate Polynomial Ring in T over Finite Field of size 3

Use the gens() method to obtain the generators of the ring:

sage: M.gens()
[g1, g2, g3]
sage: M.inject_variables()  # assign the variable g1, g2, g3
Defining g1, g2, g3
sage: T*g1*g2 + g3
g3 + T*g1*g2
>>> from sage.all import *
>>> M.gens()
[g1, g2, g3]
>>> M.inject_variables()  # assign the variable g1, g2, g3
Defining g1, g2, g3
>>> T*g1*g2 + g3
g3 + T*g1*g2

When creating the ring, one can name the generators in various ways:

sage: M.<F, G, H> = DrinfeldModularForms(K)
sage: M.gens()
[F, G, H]
sage: M = DrinfeldModularForms(K, 5, names='f')  # must specify the rank
sage: M.gens()
[f1, f2, f3, f4, f5]
sage: M = DrinfeldModularForms(K, names='u, v, w, x')
sage: M.gens()
[u, v, w, x]
sage: M = DrinfeldModularForms(K, names=['F', 'G', 'H'])
sage: M.gens()
[F, G, H]
>>> from sage.all import *
>>> M = DrinfeldModularForms(K, names=('F', 'G', 'H',)); (F, G, H,) = M._first_ngens(3)
>>> M.gens()
[F, G, H]
>>> M = DrinfeldModularForms(K, Integer(5), names='f')  # must specify the rank
>>> M.gens()
[f1, f2, f3, f4, f5]
>>> M = DrinfeldModularForms(K, names='u, v, w, x')
>>> M.gens()
[u, v, w, x]
>>> M = DrinfeldModularForms(K, names=['F', 'G', 'H'])
>>> M.gens()
[F, G, H]

Set the keyword parameter has_type to True in order to create the ring of Drinfeld modular forms of arbitrary type:

sage: M = DrinfeldModularForms(K, 4, has_type=True)
sage: M.gens()
[g1, g2, g3, h4]
sage: h4 = M.3
sage: h4.type()
1
>>> from sage.all import *
>>> M = DrinfeldModularForms(K, Integer(4), has_type=True)
>>> M.gens()
[g1, g2, g3, h4]
>>> h4 = M.gen(3)
>>> h4.type()
1

To obtain a generating set of the subspace of forms of a fixed weight, use the methode basis_of_weight():

sage: M = DrinfeldModularForms(K, 2)
sage: M.basis_of_weight(q^3 - 1)
[g1*g2^3, g1^5*g2^2, g1^9*g2, g1^13]
>>> from sage.all import *
>>> M = DrinfeldModularForms(K, Integer(2))
>>> M.basis_of_weight(q**Integer(3) - Integer(1))
[g1*g2^3, g1^5*g2^2, g1^9*g2, g1^13]

In order to compute the coefficient forms, use the methods coefficient_form() and coefficient_forms():

sage: M = DrinfeldModularForms(K, 3)
sage: M.coefficient_form(1)
g1
sage: M.coefficient_form(2)
g2
sage: M.coefficient_form(3)
g3
sage: M.coefficient_forms(T)
[g1, g2, g3]
sage: M.coefficient_forms(T^2)
[(T^3 + T)*g1,
 g1^4 + (T^9 + T)*g2,
 g1^9*g2 + g1*g2^3 + (T^27 + T)*g3,
 g1^27*g3 + g1*g3^3 + g2^10,
 g2^27*g3 + g2*g3^9,
 g3^28]
>>> from sage.all import *
>>> M = DrinfeldModularForms(K, Integer(3))
>>> M.coefficient_form(Integer(1))
g1
>>> M.coefficient_form(Integer(2))
g2
>>> M.coefficient_form(Integer(3))
g3
>>> M.coefficient_forms(T)
[g1, g2, g3]
>>> M.coefficient_forms(T**Integer(2))
[(T^3 + T)*g1,
 g1^4 + (T^9 + T)*g2,
 g1^9*g2 + g1*g2^3 + (T^27 + T)*g3,
 g1^27*g3 + g1*g3^3 + g2^10,
 g2^27*g3 + g2*g3^9,
 g3^28]

REFERENCE:

For a quick introduction to Drinfeld modular forms, see the tutorial. For more extensive references, see [Gek1988] and [BRP2018].

Element[source]#

alias of DrinfeldModularFormsElement

basis(k)[source]#

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: q = 3; A = GF(q)['T']; K = Frac(A);
sage: M = DrinfeldModularForms(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]
>>> from sage.all import *
>>> q = Integer(3); A = GF(q)['T']; K = Frac(A);
>>> M = DrinfeldModularForms(K, Integer(2))
>>> M.basis_of_weight(q - Integer(1))
[g1]
>>> M.basis_of_weight(q**Integer(2) - Integer(1))
[g2, g1^4]
>>> M.basis_of_weight(q**Integer(3) - Integer(1))
[g1*g2^3, g1^5*g2^2, g1^9*g2, g1^13]
>>> M.basis_of_weight(Integer(19)*(q-Integer(1)))
[g1^3*g2^4, g1^7*g2^3, g1^11*g2^2, g1^15*g2, g1^19]
basis_of_weight(k)[source]#

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: q = 3; A = GF(q)['T']; K = Frac(A);
sage: M = DrinfeldModularForms(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]
>>> from sage.all import *
>>> q = Integer(3); A = GF(q)['T']; K = Frac(A);
>>> M = DrinfeldModularForms(K, Integer(2))
>>> M.basis_of_weight(q - Integer(1))
[g1]
>>> M.basis_of_weight(q**Integer(2) - Integer(1))
[g2, g1^4]
>>> M.basis_of_weight(q**Integer(3) - Integer(1))
[g1*g2^3, g1^5*g2^2, g1^9*g2, g1^13]
>>> M.basis_of_weight(Integer(19)*(q-Integer(1)))
[g1^3*g2^4, g1^7*g2^3, g1^11*g2^2, g1^15*g2, g1^19]
coefficient_form(i, a=None)[source]#

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

\[\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: q = 3
sage: A = GF(q)['T']
sage: K.<T> = Frac(A)
sage: M = DrinfeldModularForms(K, 3)
sage: M.coefficient_form(1)
g1
sage: M.coefficient_form(2)
g2
sage: M.coefficient_form(3)
g3
sage: M.coefficient_form(3, T^2)
g1^9*g2 + g1*g2^3 + (T^27 + T)*g3
>>> from sage.all import *
>>> q = Integer(3)
>>> A = GF(q)['T']
>>> K = Frac(A, names=('T',)); (T,) = K._first_ngens(1)
>>> M = DrinfeldModularForms(K, Integer(3))
>>> M.coefficient_form(Integer(1))
g1
>>> M.coefficient_form(Integer(2))
g2
>>> M.coefficient_form(Integer(3))
g3
>>> M.coefficient_form(Integer(3), T**Integer(2))
g1^9*g2 + g1*g2^3 + (T^27 + T)*g3
sage: M = DrinfeldModularForms(K, 2, has_type=True)
sage: M.coefficient_form(1)
g1
sage: M.coefficient_form(2)
h2^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)*h2^2
>>> from sage.all import *
>>> M = DrinfeldModularForms(K, Integer(2), has_type=True)
>>> M.coefficient_form(Integer(1))
g1
>>> M.coefficient_form(Integer(2))
h2^2
>>> M.coefficient_form(Integer(2), T**Integer(3) + T**Integer(2) + T)
(T^9 + T^3 + T + 1)*g1^4 + (T^18 + T^10 + T^9 + T^2 + T + 1)*h2^2
coefficient_forms(a=None)[source]#

Return the list of all coefficients of the universal Drinfeld module at \(a\).

See also coefficient_form() for definitions.

INPUT:

  • a – (default: None) an element in the ring of regular functions. If \(a\) is None, then the method returns the coefficients forms at \(a = T\).

OUTPUT: a list of Drinfeld modular forms. The \(i\)-th element of that list corresponds to the \((i+1)\)-th coefficient form at \(a\).

EXAMPLES:

sage: q = 3
sage: A = GF(q)['T']
sage: K.<T> = Frac(A)
sage: M = DrinfeldModularForms(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]
>>> from sage.all import *
>>> q = Integer(3)
>>> A = GF(q)['T']
>>> K = Frac(A, names=('T',)); (T,) = K._first_ngens(1)
>>> M = DrinfeldModularForms(K, Integer(2))
>>> M.coefficient_forms()
[g1, g2]
>>> M.coefficient_forms(T**Integer(2))
[(T^3 + T)*g1, g1^4 + (T^9 + T)*g2, g1^9*g2 + g1*g2^3, g2^10]
>>> M.coefficient_forms(T**Integer(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]
gen(n)[source]#

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

EXAMPLES:

sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularForms(K, 2)
sage: M.gen(0)
g1
sage: M.1  # equivalent to M.gen(1)
g2
>>> from sage.all import *
>>> A = GF(Integer(3))['T']; K = Frac(A); T = K.gen()
>>> M = DrinfeldModularForms(K, Integer(2))
>>> M.gen(Integer(0))
g1
>>> M.gen(1)  # equivalent to M.gen(1)
g2

Note

Recall that the ring of Drinfeld modular forms is generated by the \(r\) coefficient forms of the universal Drinfeld module at \(T\), \(g_1, g_2, \ldots, g_r\), see coefficient_forms(). We highlight however that we make a shift in the indexing so that the \(i\)-th generator corresponds to the \(i+1\)-th coefficient form for \(0\leq i \leq r-1\).

gens()[source]#

Return a list of generators of this ring.

EXAMPLES:

sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularForms(K, 5)
sage: M.gens()
[g1, g2, g3, g4, g5]
>>> from sage.all import *
>>> A = GF(Integer(3))['T']; K = Frac(A); T = K.gen()
>>> M = DrinfeldModularForms(K, Integer(5))
>>> M.gens()
[g1, g2, g3, g4, g5]
ngens()[source]#

Return the number of generators of this ring.

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

EXAMPLES:

sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularForms(K, 5)
sage: M.ngens()
5
>>> from sage.all import *
>>> A = GF(Integer(3))['T']; K = Frac(A); T = K.gen()
>>> M = DrinfeldModularForms(K, Integer(5))
>>> M.ngens()
5
one()[source]#

Return the multiplicative unit.

EXAMPLES:

sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularForms(K, 2)
sage: M.one()
1
sage: M.one() * M.0
g1
sage: M.one().is_one()
True
>>> from sage.all import *
>>> A = GF(Integer(3))['T']; K = Frac(A); T = K.gen()
>>> M = DrinfeldModularForms(K, Integer(2))
>>> M.one()
1
>>> M.one() * M.gen(0)
g1
>>> M.one().is_one()
True
polynomial_ring()[source]#

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

EXAMPLES:

sage: q = 3; A = GF(q)['T']; K = Frac(A);
sage: M = DrinfeldModularForms(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
>>> from sage.all import *
>>> q = Integer(3); A = GF(q)['T']; K = Frac(A);
>>> M = DrinfeldModularForms(K, Integer(2))
>>> P = M.polynomial_ring()
>>> 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
>>> from sage.all import *
>>> P.inject_variables()
Defining g1, g2
>>> g1.degree()
2
>>> g2.degree()
8
rank()[source]#

Return the rank of this ring of Drinfeld modular forms.

EXAMPLES:

sage: A = GF(3)['T']; K = Frac(A);
sage: DrinfeldModularForms(K, 2).rank()
2
sage: DrinfeldModularForms(K, 3).rank()
3
sage: DrinfeldModularForms(K, 4).rank()
4
>>> from sage.all import *
>>> A = GF(Integer(3))['T']; K = Frac(A);
>>> DrinfeldModularForms(K, Integer(2)).rank()
2
>>> DrinfeldModularForms(K, Integer(3)).rank()
3
>>> DrinfeldModularForms(K, Integer(4)).rank()
4
zero()[source]#

Return the additive identity.

EXAMPLES:

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