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:
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 ringgroup
(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\) isNone
, 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