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:
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 isNone
, 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 toTrue
, returns the graded ring of arbitrary typenames
– 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 toNone
and the rank is specified, then the default names for the generators will be:g1, g2, ..., gr
for the type zero formsg1, 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 formf1, 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
q = 3 A = GF(q)['T'] K.<T> = Frac(A) M = DrinfeldModularForms(K, 3) M
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
M.gens() M.inject_variables() # assign the variable g1, g2, g3 T*g1*g2 + g3
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]
M.<F, G, H> = DrinfeldModularForms(K) M.gens() M = DrinfeldModularForms(K, 5, names='f') # must specify the rank M.gens() M = DrinfeldModularForms(K, names='u, v, w, x') M.gens() M = DrinfeldModularForms(K, names=['F', 'G', 'H']) M.gens()
Set the keyword parameter
has_type
toTrue
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
M = DrinfeldModularForms(K, 4, has_type=True) M.gens() h4 = M.3 h4.type()
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]
M = DrinfeldModularForms(K, 2) M.basis_of_weight(q^3 - 1)
In order to compute the coefficient forms, use the methods
coefficient_form()
andcoefficient_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]
M = DrinfeldModularForms(K, 3) M.coefficient_form(1) M.coefficient_form(2) M.coefficient_form(3) M.coefficient_forms(T) M.coefficient_forms(T^2)
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
– 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]
q = 3; A = GF(q)['T']; K = Frac(A); M = DrinfeldModularForms(K, 2) M.basis_of_weight(q - 1) M.basis_of_weight(q^2 - 1) M.basis_of_weight(q^3 - 1) M.basis_of_weight(19*(q-1))
- 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
– 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]
q = 3; A = GF(q)['T']; K = Frac(A); M = DrinfeldModularForms(K, 2) M.basis_of_weight(q - 1) M.basis_of_weight(q^2 - 1) M.basis_of_weight(q^3 - 1) M.basis_of_weight(19*(q-1))
- 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
– integer between 1 and \(r d_a\)a
– (default:None
) an element in the ring of regular functions. If \(a\) isNone
, 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
q = 3 A = GF(q)['T'] K.<T> = Frac(A) M = DrinfeldModularForms(K, 3) M.coefficient_form(1) M.coefficient_form(2) M.coefficient_form(3) M.coefficient_form(3, T^2)
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
M = DrinfeldModularForms(K, 2, has_type=True) M.coefficient_form(1) M.coefficient_form(2) M.coefficient_form(2, T^3 + T^2 + T)
- 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\) isNone
, then the method returns the coefficients forms at \(a = T\).
OUTPUT: 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]
q = 3 A = GF(q)['T'] K.<T> = Frac(A) M = DrinfeldModularForms(K, 2) M.coefficient_forms() M.coefficient_forms(T^2) M.coefficient_forms(T^3)
- 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
A = GF(3)['T']; K = Frac(A); T = K.gen() M = DrinfeldModularForms(K, 2) M.gen(0) M.1 # equivalent to M.gen(1)
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]
A = GF(3)['T']; K = Frac(A); T = K.gen() M = DrinfeldModularForms(K, 5) M.gens()
- 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
A = GF(3)['T']; K = Frac(A); T = K.gen() M = DrinfeldModularForms(K, 5) M.ngens()
- 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
A = GF(3)['T']; K = Frac(A); T = K.gen() M = DrinfeldModularForms(K, 2) M.one() M.one() * M.0 M.one().is_one()
- 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
q = 3; A = GF(q)['T']; K = Frac(A); M = DrinfeldModularForms(K, 2) P = M.polynomial_ring() P
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
P.inject_variables() g1.degree() g2.degree()
- 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
A = GF(3)['T']; K = Frac(A); DrinfeldModularForms(K, 2).rank() DrinfeldModularForms(K, 3).rank() DrinfeldModularForms(K, 4).rank()
- 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
A = GF(3)['T']; K = Frac(A); T = K.gen() M = DrinfeldModularForms(K, 2) M.zero() M.zero() + M.1 M.zero() * M.1 M.zero().is_zero()