Drinfeld modules over rings of characteristic zero - Drinfeld modules

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

# Drinfeld modules over rings of characteristic zero

This module provides the classes `sage.rings.function_fields.drinfeld_module.charzero_drinfeld_module.DrinfeldModule_charzero` and `sage.rings.function_fields.drinfeld_module.charzero_drinfeld_module.DrinfeldModule_rational`, which both inherit `sage.rings.function_fields.drinfeld_module.drinfeld_module.DrinfeldModule`.

AUTHORS:

- David Ayotte (2023-09)

- Xavier Caruso (2024-12) - computation of class polynomials

class sage.rings.function_field.drinfeld_modules.charzero_drinfeld_module.DrinfeldModule_charzero(gen, category)

  Bases: `DrinfeldModule`

  This class implements Drinfeld \(\GF{q}[T]\)-modules defined over fields of \(\GF{q}[T]\)-characteristic zero.

  Recall that the \(\GF{q}[T]\)-characteristic is defined as the kernel of the underlying structure morphism. For general definitions and help on Drinfeld modules, see class `sage.rings.function_fields.drinfeld_module.drinfeld_module.DrinfeldModule`.

  Construction:

  The user does not ever need to directly call `DrinfeldModule_charzero` — the metaclass `DrinfeldModule` is responsible for instantiating the right class depending on the input:

  Sage

      sage: A.<T> = GF(3)[]
      sage: phi = DrinfeldModule(A, [T, 1])
      sage: phi
      Drinfeld module defined by T |--> τ + T

  Python

      >>> from sage.all import *
      >>> A = GF(Integer(3))['T']; (T,) = A._first_ngens(1)
      >>> phi = DrinfeldModule(A, [T, Integer(1)])
      >>> phi
      Drinfeld module defined by T |--> τ + T

  Sage

      sage: isinstance(phi, DrinfeldModule)
      True
      sage: from sage.rings.function_field.drinfeld_modules.charzero_drinfeld_module import DrinfeldModule_charzero
      sage: isinstance(phi, DrinfeldModule_charzero)
      True

  [Python]

      >>> from sage.all import *
      >>> isinstance(phi, DrinfeldModule)
      True
      >>> from sage.rings.function_field.drinfeld_modules.charzero_drinfeld_module import DrinfeldModule_charzero
      >>> isinstance(phi, DrinfeldModule_charzero)
      True

  Logarithm and exponential

  It is possible to calculate the logarithm and the exponential of any Drinfeld modules of characteristic zero:

  Sage

      sage: A.<T> = GF(2)[]
      sage: phi = DrinfeldModule(A, [T, 1])
      sage: phi.exponential()
      z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8)
      sage: phi.logarithm()
      z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8)

  Python

      >>> from sage.all import *
      >>> A = GF(Integer(2))['T']; (T,) = A._first_ngens(1)
      >>> phi = DrinfeldModule(A, [T, Integer(1)])
      >>> phi.exponential()
      z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8)
      >>> phi.logarithm()
      z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8)

  Goss polynomials

  Goss polynomials are a sequence of polynomials related with the analytic theory of Drinfeld module. They provide a function field analogue of certain classical trigonometric functions:

  Sage

      sage: A.<T> = GF(2)[]
      sage: phi = DrinfeldModule(A, [T, 1])
      sage: phi.goss_polynomial(1)
      X
      sage: phi.goss_polynomial(2)
      X^2
      sage: phi.goss_polynomial(3)
      X^3 + (1/(T^2 + T))*X^2

  [Python]

      >>> from sage.all import *
      >>> A = GF(Integer(2))['T']; (T,) = A._first_ngens(1)
      >>> phi = DrinfeldModule(A, [T, Integer(1)])
      >>> phi.goss_polynomial(Integer(1))
      X
      >>> phi.goss_polynomial(Integer(2))
      X^2
      >>> phi.goss_polynomial(Integer(3))
      X^3 + (1/(T^2 + T))*X^2

  Base fields of \(\GF{q}[T]\)-characteristic zero

  The base fields need not only be fraction fields of polynomials ring. In the following example, we construct a Drinfeld module over \(\GF{q}((1/T))\), the completion of the rational function field at the place \(1/T\):

  Sage

      sage: A.<T> = GF(2)[]
      sage: L.<s> = LaurentSeriesRing(GF(2))  # s = 1/T
      sage: phi = DrinfeldModule(A, [1/s, s + s^2 + s^5 + O(s^6), 1+1/s])
      sage: phi(T)
      (s^-1 + 1)*τ^2 + (s + s^2 + s^5 + O(s^6))*τ + s^-1

  Python

      >>> from sage.all import *
      >>> A = GF(Integer(2))['T']; (T,) = A._first_ngens(1)
      >>> L = LaurentSeriesRing(GF(Integer(2)), names=('s',)); (s,) = L._first_ngens(1)# s = 1/T
      >>> phi = DrinfeldModule(A, [Integer(1)/s, s + s**Integer(2) + s**Integer(5) + O(s**Integer(6)), Integer(1)+Integer(1)/s])
      >>> phi(T)
      (s^-1 + 1)*τ^2 + (s + s^2 + s^5 + O(s^6))*τ + s^-1

  One can also construct Drinfeld modules over SageMath’s global function fields:

  Sage

      sage: A.<T> = GF(5)[]
      sage: K.<z> = FunctionField(GF(5))  # z = T
      sage: phi = DrinfeldModule(A, [z, 1, z^2])
      sage: phi(T)
      z^2*τ^2 + τ + z

  [Python]

      >>> from sage.all import *
      >>> A = GF(Integer(5))['T']; (T,) = A._first_ngens(1)
      >>> K = FunctionField(GF(Integer(5)), names=('z',)); (z,) = K._first_ngens(1)# z = T
      >>> phi = DrinfeldModule(A, [z, Integer(1), z**Integer(2)])
      >>> phi(T)
      z^2*τ^2 + τ + z

  exponential(prec=+Infinity, name='z')

    Return the exponential of this Drinfeld module.

    Note that the exponential is only defined when the \(\GF{q}[T]\)-characteristic is zero.

    INPUT:

    - `prec` – an integer or `Infinity` (default: `Infinity`); the precision at which the series is returned; if `Infinity`, a lazy power series in returned, else, a classical power series is returned.

    - `name` – string (default: `'z'`); the name of the generator of the lazy power series ring

    EXAMPLES:

    Sage

        sage: A.<T> = GF(2)[]
        sage: phi = DrinfeldModule(A, [T, 1])
        sage: q = A.base_ring().cardinality()

    Python

        >>> from sage.all import *
        >>> A = GF(Integer(2))['T']; (T,) = A._first_ngens(1)
        >>> phi = DrinfeldModule(A, [T, Integer(1)])
        >>> q = A.base_ring().cardinality()

    When `prec` is `Infinity` (which is the default), the exponential is returned as a lazy power series, meaning that any of its coefficients can be computed on demands:

    Sage

        sage: exp = phi.exponential(); exp
        z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8)
        sage: exp[2^4]
        1/(T^64 + T^56 + T^52 + ... + T^27 + T^23 + T^15)
        sage: exp[2^5]
        1/(T^160 + T^144 + T^136 + ... + T^55 + T^47 + T^31)

    [Python]

        >>> from sage.all import *
        >>> exp = phi.exponential(); exp
        z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8)
        >>> exp[Integer(2)**Integer(4)]
        1/(T^64 + T^56 + T^52 + ... + T^27 + T^23 + T^15)
        >>> exp[Integer(2)**Integer(5)]
        1/(T^160 + T^144 + T^136 + ... + T^55 + T^47 + T^31)

    On the contrary, when `prec` is a finite number, all the required coefficients are computed at once:

    Sage

        sage: phi.exponential(prec=10)
        z + (1/(T^2 + T))*z^2 + (1/(T^8 + T^6 + T^5 + T^3))*z^4 + (1/(T^24 + T^20 + T^18 + T^17 + T^14 + T^13 + T^11 + T^7))*z^8 + O(z^10)

    Python

        >>> from sage.all import *
        >>> phi.exponential(prec=Integer(10))
        z + (1/(T^2 + T))*z^2 + (1/(T^8 + T^6 + T^5 + T^3))*z^4 + (1/(T^24 + T^20 + T^18 + T^17 + T^14 + T^13 + T^11 + T^7))*z^8 + O(z^10)

    Example in higher rank:

    Sage

        sage: A.<T> = GF(5)[]
        sage: phi = DrinfeldModule(A, [T, T^2, T + T^2 + T^4, 1])
        sage: exp = phi.exponential(); exp
        z + ((T/(T^4+4))*z^5) + O(z^8)

    [Python]

        >>> from sage.all import *
        >>> A = GF(Integer(5))['T']; (T,) = A._first_ngens(1)
        >>> phi = DrinfeldModule(A, [T, T**Integer(2), T + T**Integer(2) + T**Integer(4), Integer(1)])
        >>> exp = phi.exponential(); exp
        z + ((T/(T^4+4))*z^5) + O(z^8)

    The exponential is the compositional inverse of the logarithm (see `logarithm()`):

    Sage

        sage: log = phi.logarithm(); log
        z + ((4*T/(T^4+4))*z^5) + O(z^8)
        sage: exp.compose(log)
        z + O(z^8)
        sage: log.compose(exp)
        z + O(z^8)

    Python

        >>> from sage.all import *
        >>> log = phi.logarithm(); log
        z + ((4*T/(T^4+4))*z^5) + O(z^8)
        >>> exp.compose(log)
        z + O(z^8)
        >>> log.compose(exp)
        z + O(z^8)

    REFERENCE:

    See section 4.6 of [Gos1998] for the definition of the exponential.

  goss_polynomial(n, var='X')

    Return the \(n\)-th Goss polynomial of the Drinfeld module.

    Note that Goss polynomials are only defined for Drinfeld modules of characteristic zero.

    INPUT:

    - `n` – integer; the index of the Goss polynomial

    - `var`– string (default: `'X'`); the name of polynomial variable

    OUTPUT: a univariate polynomial in `var` over the base \(A\)-field

    EXAMPLES:

    Sage

        sage: A.<T> = GF(3)[]
        sage: phi = DrinfeldModule(A, [T, 1])  # Carlitz module
        sage: phi.goss_polynomial(1)
        X
        sage: phi.goss_polynomial(2)
        X^2
        sage: phi.goss_polynomial(4)
        X^4 + (1/(T^3 + 2*T))*X^2
        sage: phi.goss_polynomial(5)
        X^5 + (2/(T^3 + 2*T))*X^3
        sage: phi.goss_polynomial(10)
        X^10 + (1/(T^3 + 2*T))*X^8 + (1/(T^6 + T^4 + T^2))*X^6 + (1/(T^9 + 2*T^3))*X^4 + (1/(T^18 + 2*T^12 + 2*T^10 + T^4))*X^2

    Python

        >>> from sage.all import *
        >>> A = GF(Integer(3))['T']; (T,) = A._first_ngens(1)
        >>> phi = DrinfeldModule(A, [T, Integer(1)])  # Carlitz module
        >>> phi.goss_polynomial(Integer(1))
        X
        >>> phi.goss_polynomial(Integer(2))
        X^2
        >>> phi.goss_polynomial(Integer(4))
        X^4 + (1/(T^3 + 2*T))*X^2
        >>> phi.goss_polynomial(Integer(5))
        X^5 + (2/(T^3 + 2*T))*X^3
        >>> phi.goss_polynomial(Integer(10))
        X^10 + (1/(T^3 + 2*T))*X^8 + (1/(T^6 + T^4 + T^2))*X^6 + (1/(T^9 + 2*T^3))*X^4 + (1/(T^18 + 2*T^12 + 2*T^10 + T^4))*X^2

    REFERENCE:

    Section 3 of [Gek1988] provides an exposition of Goss polynomials.

  logarithm(prec=+Infinity, name='z')

    Return the logarithm of the given Drinfeld module.

    By definition, the logarithm is the compositional inverse of the exponential (see `exponential()`). Note that the logarithm is only defined when the \(\GF{q}[T]\)-characteristic is zero.

    INPUT:

    - `prec` – an integer or `Infinity` (default: `Infinity`); the precision at which the series is returned; if `Infinity`, a lazy power series in returned

    - `name` – string (default: `'z'`); the name of the generator of the lazy power series ring

    EXAMPLES:

    Sage

        sage: A.<T> = GF(2)[]
        sage: phi = DrinfeldModule(A, [T, 1])

    Python

        >>> from sage.all import *
        >>> A = GF(Integer(2))['T']; (T,) = A._first_ngens(1)
        >>> phi = DrinfeldModule(A, [T, Integer(1)])

    When `prec` is `Infinity` (which is the default), the logarithm is returned as a lazy power series, meaning that any of its coefficients can be computed on demands:

    Sage

        sage: log = phi.logarithm(); log
        z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8)
        sage: log[2^4]
        1/(T^30 + T^29 + T^27 + ... + T^7 + T^5 + T^4)
        sage: log[2^5]
        1/(T^62 + T^61 + T^59 + ... + T^8 + T^6 + T^5)

    [Python]

        >>> from sage.all import *
        >>> log = phi.logarithm(); log
        z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8)
        >>> log[Integer(2)**Integer(4)]
        1/(T^30 + T^29 + T^27 + ... + T^7 + T^5 + T^4)
        >>> log[Integer(2)**Integer(5)]
        1/(T^62 + T^61 + T^59 + ... + T^8 + T^6 + T^5)

    If `prec` is a finite number, all the required coefficients are computed at once:

    Sage

        sage: phi.logarithm(prec=10)
        z + (1/(T^2 + T))*z^2 + (1/(T^6 + T^5 + T^3 + T^2))*z^4 + (1/(T^14 + T^13 + T^11 + T^10 + T^7 + T^6 + T^4 + T^3))*z^8 + O(z^10)

    Python

        >>> from sage.all import *
        >>> phi.logarithm(prec=Integer(10))
        z + (1/(T^2 + T))*z^2 + (1/(T^6 + T^5 + T^3 + T^2))*z^4 + (1/(T^14 + T^13 + T^11 + T^10 + T^7 + T^6 + T^4 + T^3))*z^8 + O(z^10)

    Example in higher rank:

    Sage

        sage: A.<T> = GF(5)[]
        sage: phi = DrinfeldModule(A, [T, T^2, T + T^2 + T^4, 1])
        sage: phi.logarithm()
        z + ((4*T/(T^4+4))*z^5) + O(z^8)

    [Python]

        >>> from sage.all import *
        >>> A = GF(Integer(5))['T']; (T,) = A._first_ngens(1)
        >>> phi = DrinfeldModule(A, [T, T**Integer(2), T + T**Integer(2) + T**Integer(4), Integer(1)])
        >>> phi.logarithm()
        z + ((4*T/(T^4+4))*z^5) + O(z^8)

class sage.rings.function_field.drinfeld_modules.charzero_drinfeld_module.DrinfeldModule_rational(gen, category)

  Bases: `DrinfeldModule_charzero`

  A class for Drinfeld modules defined over the fraction field of the underlying function field.

  class_polynomial()

    Return the class polynomial, that is the Fitting ideal of the class module, of this Drinfeld module.

    We refer to [Tae2012] for the definition and basic properties of the class module.

    EXAMPLES:

    We check that the class module of the Carlitz module is trivial:

    Sage

        sage: q = 5
        sage: Fq = GF(q)
        sage: A.<T> = Fq[]
        sage: C = DrinfeldModule(A, [T, 1]); C
        Drinfeld module defined by T |--> τ + T
        sage: C.class_polynomial()
        1

    Python

        >>> from sage.all import *
        >>> q = Integer(5)
        >>> Fq = GF(q)
        >>> A = Fq['T']; (T,) = A._first_ngens(1)
        >>> C = DrinfeldModule(A, [T, Integer(1)]); C
        Drinfeld module defined by T |--> τ + T
        >>> C.class_polynomial()
        1

    When the coefficients of the Drinfeld module have small enough degrees, the class module is always trivial:

    Sage

        sage: gs = [T] + [A.random_element(degree = q^i)
        ....:             for i in range(1, 5)]
        sage: phi = DrinfeldModule(A, gs)
        sage: phi.class_polynomial()
        1

    [Python]

        >>> from sage.all import *
        >>> gs = [T] + [A.random_element(degree = q**i)
        ...             for i in range(Integer(1), Integer(5))]
        >>> phi = DrinfeldModule(A, gs)
        >>> phi.class_polynomial()
        1

    Here is an example with a nontrivial class module:

    Sage

        sage: phi = DrinfeldModule(A, [T, 2*T^14 + 2*T^4])
        sage: phi.class_polynomial()
        T + 3

    Python

        >>> from sage.all import *
        >>> phi = DrinfeldModule(A, [T, Integer(2)*T**Integer(14) + Integer(2)*T**Integer(4)])
        >>> phi.class_polynomial()
        T + 3

  coefficient_in_function_ring(n)

    Return the \(n\)-th coefficient of this Drinfeld module as an element of the underlying function ring.

    INPUT:

    - `n` – an integer

    EXAMPLES:

    Sage

        sage: q = 5
        sage: Fq = GF(q)
        sage: A.<T> = Fq[]
        sage: R.<U> = Fq[]
        sage: phi = DrinfeldModule(A, [U, 0, U^2, U^3])
        sage: phi.coefficient_in_function_ring(2)
        T^2

    Python

        >>> from sage.all import *
        >>> q = Integer(5)
        >>> Fq = GF(q)
        >>> A = Fq['T']; (T,) = A._first_ngens(1)
        >>> R = Fq['U']; (U,) = R._first_ngens(1)
        >>> phi = DrinfeldModule(A, [U, Integer(0), U**Integer(2), U**Integer(3)])
        >>> phi.coefficient_in_function_ring(Integer(2))
        T^2

    Compare with the method `coefficient()`:

    Sage

        sage: phi.coefficient(2)
        U^2

    [Python]

        >>> from sage.all import *
        >>> phi.coefficient(Integer(2))
        U^2

    If the required coefficient is not a polynomials, an error is raised:

    Sage

        sage: psi = DrinfeldModule(A, [U, 1/U])
        sage: psi.coefficient_in_function_ring(0)
        T
        sage: psi.coefficient_in_function_ring(1)
        Traceback (most recent call last):
        ...
        ValueError: coefficient is not polynomial

    Python

        >>> from sage.all import *
        >>> psi = DrinfeldModule(A, [U, Integer(1)/U])
        >>> psi.coefficient_in_function_ring(Integer(0))
        T
        >>> psi.coefficient_in_function_ring(Integer(1))
        Traceback (most recent call last):
        ...
        ValueError: coefficient is not polynomial

  coefficients_in_function_ring(sparse=True)

    Return the coefficients of this Drinfeld module as elements of the underlying function ring.

    INPUT:

    - `sparse` – a boolean (default: `True`); if `True`, only return the nonzero coefficients; otherwise, return all of them.

    EXAMPLES:

    Sage

        sage: q = 5
        sage: Fq = GF(q)
        sage: A.<T> = Fq[]
        sage: R.<U> = Fq[]
        sage: phi = DrinfeldModule(A, [U, 0, U^2, U^3])
        sage: phi.coefficients_in_function_ring()
        [T, T^2, T^3]
        sage: phi.coefficients_in_function_ring(sparse=False)
        [T, 0, T^2, T^3]

    Python

        >>> from sage.all import *
        >>> q = Integer(5)
        >>> Fq = GF(q)
        >>> A = Fq['T']; (T,) = A._first_ngens(1)
        >>> R = Fq['U']; (U,) = R._first_ngens(1)
        >>> phi = DrinfeldModule(A, [U, Integer(0), U**Integer(2), U**Integer(3)])
        >>> phi.coefficients_in_function_ring()
        [T, T^2, T^3]
        >>> phi.coefficients_in_function_ring(sparse=False)
        [T, 0, T^2, T^3]

    Compare with the method meth:\(coefficients\):

    Sage

        sage: phi.coefficients()
        [U, U^2, U^3]

    [Python]

        >>> from sage.all import *
        >>> phi.coefficients()
        [U, U^2, U^3]

    If the coefficients are not polynomials, an error is raised:

    Sage

        sage: psi = DrinfeldModule(A, [U, 1/U])
        sage: psi.coefficients_in_function_ring()
        Traceback (most recent call last):
        ...
        ValueError: coefficients are not polynomials

    Python

        >>> from sage.all import *
        >>> psi = DrinfeldModule(A, [U, Integer(1)/U])
        >>> psi.coefficients_in_function_ring()
        Traceback (most recent call last):
        ...
        ValueError: coefficients are not polynomials