Graded rings of Drinfeld modular forms - Modular Forms

Skip to content
Back to top
View this page
Edit this page

# 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)

  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 tuple 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

      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

  Python

      >>> 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

      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

  [Python]

      >>> 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

      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)

  Python

      >>> 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

      sage: M = DrinfeldModularForms(K, 4, has_type=True)
      sage: M.gens()
      (g1, g2, g3, h4)
      sage: h4 = M.3
      sage: h4.type()
      1

  [Python]

      >>> 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 method `basis_of_weight()`:

  Sage

      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]

  Python

      >>> 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

      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]

  [Python]

      >>> 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

    alias of `DrinfeldModularFormsElement`

  basis(k)

    alias of `basis_of_weight()`.

  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` – integer

    EXAMPLES:

    Sage

        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]

    Python

        >>> 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)

    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\) is `None`, then the method returns the \(i\)-th coefficient form of \(\phi_{w, T}\).

    EXAMPLES:

    Sage

        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

    Python

        >>> 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

        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

    [Python]

        >>> 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)

    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: list of Drinfeld modular forms. The \(i\)-th element of that list corresponds to the \((i+1)\)-th coefficient form at \(a\).

    EXAMPLES:

    Sage

        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]

    Python

        >>> 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)

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

    EXAMPLES:

    Sage

        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

    Python

        >>> 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()

    Return a tuple of generators of this ring.

    EXAMPLES:

    Sage

        sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
        sage: M = DrinfeldModularForms(K, 5)
        sage: M.gens()
        (g1, g2, g3, g4, g5)

    Python

        >>> 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()

    Return the number of generators of this ring.

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

    EXAMPLES:

    Sage

        sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
        sage: M = DrinfeldModularForms(K, 5)
        sage: M.ngens()
        5

    Python

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

  one()

    Return the multiplicative unit.

    EXAMPLES:

    Sage

        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

    Python

        >>> 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()

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

    EXAMPLES:

    Sage

        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

    Python

        >>> 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

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

    [Python]

        >>> from sage.all import *
        >>> P.inject_variables()
        Defining g1, g2
        >>> g1.degree()
        2
        >>> g2.degree()
        8

  rank()

    Return the rank of this ring of Drinfeld modular forms.

    EXAMPLES:

    Sage

        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

    Python

        >>> 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()

    Return the additive identity.

    EXAMPLES:

    Sage

        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

    Python

        >>> 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