Finite Drinfeld modules#

This module provides the class sage.rings.function_fields.drinfeld_module.finite_drinfeld_module.DrinfeldModule_finite, which inherits sage.rings.function_fields.drinfeld_module.drinfeld_module.DrinfeldModule.

AUTHORS:

  • Antoine Leudière (2022-04)

  • Yossef Musleh (2023-02): added characteristic polynomial methods

class sage.rings.function_field.drinfeld_modules.finite_drinfeld_module.DrinfeldModule_finite(gen, category)#

Bases: DrinfeldModule

This class implements finite Drinfeld \(\mathbb{F}_q[T]\)-modules.

A finite Drinfeld module is a Drinfeld module whose base field is finite. In this case, the function field characteristic is a prime ideal.

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_finite — the metaclass DrinfeldModule is responsible for instantiating DrinfeldModule or DrinfeldModule_finite depending on the input:

sage: Fq = GF(343)
sage: A.<T> = Fq[]
sage: K.<z6> = Fq.extension(2)
sage: phi = DrinfeldModule(A, [z6, 0, 5])
sage: phi
Drinfeld module defined by T |--> 5*t^2 + z6
sage: isinstance(phi, DrinfeldModule)
True
sage: from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import DrinfeldModule_finite
sage: isinstance(phi, DrinfeldModule_finite)
True

The user should never use DrinfeldModule_finite to test if a Drinfeld module is finite, but rather the is_finite method:

sage: phi.is_finite()
True

Complex multiplication of rank two finite Drinfeld modules

We can handle some aspects of the theory of complex multiplication of finite Drinfeld modules. Apart from the method frobenius_endomorphism, we only handle rank two Drinfeld modules.

First of all, it is easy to create the Frobenius endomorphism:

sage: frobenius_endomorphism = phi.frobenius_endomorphism()
sage: frobenius_endomorphism
Endomorphism of Drinfeld module defined by T |--> 5*t^2 + z6
  Defn: t^2

Its characteristic polynomial can be computed:

sage: chi = phi.frobenius_charpoly()
sage: chi
X^2 + (T + 2*z3^2 + 2*z3 + 1)*X + 2*T^2 + (z3^2 + z3 + 4)*T + 2*z3
sage: frob_pol = frobenius_endomorphism.ore_polynomial()
sage: chi(frob_pol, phi(T))
0

as well as its trace and norm:

sage: phi.frobenius_trace()
6*T + 5*z3^2 + 5*z3 + 6
sage: phi.frobenius_trace() == -chi[1]
True
sage: phi.frobenius_norm()
2*T^2 + (z3^2 + z3 + 4)*T + 2*z3

We can decide if a Drinfeld module is ordinary or supersingular:

sage: phi.is_ordinary()
True
sage: phi.is_supersingular()
False

Inverting the Drinfeld module

The morphism that defines a Drinfeld module is injective (see [Gos1998], cor. 4.5.2). If the Drinfeld module is finite, one can retrieve preimages:

sage: a = A.random_element()
sage: phi.invert(phi(a)) == a
True
frobenius_charpoly(var='X', algorithm='crystalline')#

Return the characteristic polynomial of the Frobenius endomorphism.

Let \(\mathbb{F}_q\) be the base field of the function ring. The characteristic polynomial \(\chi\) of the Frobenius endomorphism is defined in [Gek1991]. An important feature of this polynomial is that it is monic, univariate, and has coefficients in the function ring. As in our case the function ring is a univariate polynomial ring, it is customary to see the characteristic polynomial of the Frobenius endomorphism as a bivariate polynomial.

Let \(\chi = X^r + \sum_{i=0}^{r-1} A_{i}(T)X^{i}\) be the characteristic polynomial of the Frobenius endomorphism, and let \(t^n\) be the Ore polynomial that defines the Frobenius endomorphism of \(\phi\); by definition, \(n\) is the degree of \(K\) over the base field \(\mathbb{F}_q\). Then we have

\[\chi(t^n)(\phi(T)) = t^{nr} + \sum_{i=1}^{r} \phi_{A_{i}}t^{n(i)} = 0,\]

with \(\deg(A_i) \leq \frac{n(r-i)}{r}\).

Note that the Frobenius trace is defined as \(A_{r-1}(T)\) and the Frobenius norm is defined as \(A_0(T)\).

INPUT:

  • var (default: 'X') – the name of the second variable

  • algorithm (default: 'crystalline') – the algorithm used to compute the characteristic polynomial

EXAMPLES:

sage: Fq = GF(25)
sage: A.<T> = Fq[]
sage: K.<z12> = Fq.extension(6)
sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12
sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5])
sage: phi.frobenius_charpoly()
X^2 + ((4*z2 + 4)*T^3 + (z2 + 3)*T^2 + 3*T + 2*z2 + 3)*X + 3*z2*T^6 + (4*z2 + 3)*T^5 + (4*z2 + 4)*T^4 + 2*T^3 + (3*z2 + 3)*T^2 + (z2 + 2)*T + 4*z2
sage: Fq = GF(343)
sage: A.<T> = Fq[]
sage: K.<z6> = Fq.extension(2)
sage: phi = DrinfeldModule(A, [1, 0, z6])
sage: chi = phi.frobenius_charpoly()
sage: chi
X^2 + ((3*z3^2 + z3 + 4)*T + 4*z3^2 + 6*z3 + 3)*X + (5*z3^2 + 2*z3)*T^2 + (4*z3^2 + 3*z3)*T + 5*z3^2 + 2*z3
sage: frob_pol = phi.frobenius_endomorphism().ore_polynomial()
sage: chi(frob_pol, phi(T))
0
sage: phi.frobenius_charpoly(algorithm="NotImplemented")
Traceback (most recent call last):
...
NotImplementedError: algorithm "NotImplemented" not implemented

ALGORITHM:

By default, this method uses the so-called crystalline algorithm which computes the characteristic polynomial of the Frobenius acting on the crystalline cohomology of the Drinfeld module. For further details, see [Ang1997].

The available options for ‘algorithm’ are:

  • 'crystalline' – Computes the characteristic polynomial of the Frobenius endomorphism on the crystalline cohomology of a Drinfeld module.

  • 'motive' – Based on computing the characteristic polynomial of the Frobenius endomorphism on the motive of a Drinfeld module. This instantiates the Frobenius as a morphism object and calls its 'characteristic_polynomial' method.

frobenius_endomorphism()#

Return the Frobenius endomorphism of the Drinfeld module as a morphism object.

Let \(q\) be the order of the base field of the function ring. The Frobenius endomorphism is defined as the endomorphism whose defining Ore polynomial is \(t^q\).

EXAMPLES:

sage: Fq = GF(343)
sage: A.<T> = Fq[]
sage: K.<z6> = Fq.extension(2)
sage: phi = DrinfeldModule(A, [1, 0, z6])
sage: phi.frobenius_endomorphism()
Endomorphism of Drinfeld module defined by T |--> z6*t^2 + 1
  Defn: t^2
frobenius_norm()#

Return the Frobenius norm of the Drinfeld module.

Let \(C(X) = \sum_{i=0}^r a_iX^{i}\) denote the characteristic polynomial of the Frobenius endomorphism. The Frobenius norm is \((-1)^r a_{0}\). This is an element of the regular function ring and if \(n\) is the degree of the base field over \(\mathbb{F}_q\), then the Frobenius norm has degree \(n\).

EXAMPLES:

sage: Fq = GF(343)
sage: A.<T> = Fq[]
sage: K.<z6> = Fq.extension(2)
sage: phi = DrinfeldModule(A, [1, 0, z6])
sage: B = phi.frobenius_norm()
sage: B
(5*z3^2 + 2*z3)*T^2 + (4*z3^2 + 3*z3)*T + 5*z3^2 + 2*z3
sage: n = 2  # Degree of the base field over Fq
sage: B.degree() == n
True
sage: B == phi.frobenius_charpoly()[0]
True

ALGORITHM:

The Frobenius norm is computed using the formula, by Gekeler, given in [MS2019], Section 4, Proposition 3.

frobenius_trace()#

Return the Frobenius trace of the Drinfeld module.

Let \(C(X) = \sum_{i=0}^r a_iX^{i}\) denote the characteristic polynomial of the Frobenius endomorphism. The Frobenius trace is \(-a_{r-1}\). This is an element of the regular function ring and if \(n\) is the degree of the base field over \(\mathbb{F}_q\), then the Frobenius trace has degree at most \(\frac{n}{r}\).

EXAMPLES:

sage: Fq = GF(343)
sage: A.<T> = Fq[]
sage: K.<z6> = Fq.extension(2)
sage: phi = DrinfeldModule(A, [1, 0, z6])
sage: A = phi.frobenius_trace()
sage: A
(4*z3^2 + 6*z3 + 3)*T + 3*z3^2 + z3 + 4
sage: n = 2  # Degree over Fq of the base codomain
sage: A.degree() <= n/2
True
sage: A == -phi.frobenius_charpoly()[1]
True

ALGORITHM:

We extract the coefficient of \(X^{r-1}\) from the characteristic polynomial if it has been previously computed, otherwise we compute the trace of the matrix of the Frobenius acting on the crystalline cohomology.

invert(ore_pol)#

Return the preimage of the input under the Drinfeld module, if it exists.

INPUT:

  • ore_pol – the Ore polynomial whose preimage we want to compute

EXAMPLES:

sage: Fq = GF(25)
sage: A.<T> = Fq[]
sage: K.<z12> = Fq.extension(6)
sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12
sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5])
sage: a = A.random_element()
sage: phi.invert(phi(a)) == a
True
sage: phi.invert(phi(T)) == T
True
sage: phi.invert(phi(Fq.gen())) == Fq.gen()
True

When the input is not in the image of the Drinfeld module, an exception is raised:

sage: t = phi.ore_polring().gen()
sage: phi.invert(t + 1)
Traceback (most recent call last):
...
ValueError: input must be in the image of the Drinfeld module
sage: phi.invert(t^4 + t^2 + 1)
Traceback (most recent call last):
...
ValueError: input must be in the image of the Drinfeld module

ALGORITHM:

The algorithm relies on the inversion of a linear algebra system. See [MS2019], 3.2.5 for details.

is_isogenous(psi)#

Return True when self is isogenous to the other Drinfeld module.

If the Drinfeld modules do not belong to the same category, an exception is raised.

EXAMPLES:

sage: Fq = GF(2)
sage: A.<T> = Fq[]
sage: K.<z> = Fq.extension(3)
sage: psi = DrinfeldModule(A, [z, z + 1, z^2 + z + 1])
sage: phi = DrinfeldModule(A, [z, z^2 + z + 1, z^2 + z])
sage: phi.is_isogenous(psi)
True
sage: chi = DrinfeldModule(A, [z, z + 1, z^2 + z])
sage: phi.is_isogenous(chi)
False
sage: mu = DrinfeldModule(A, [z + 1, z^2 + z + 1, z^2 + z])
sage: phi.is_isogenous(mu)
Traceback (most recent call last):
...
TypeError: Drinfeld modules are not in the same category
sage: mu = 1
sage: phi.is_isogenous(mu)
Traceback (most recent call last):
...
TypeError: input must be a Drinfeld module

ALGORITHM:

Two Drinfeld A-modules of equal characteristic are isogenous if and only if:

  • they have the same rank

  • the characteristic polynomial of the Frobenius endomorphism for both Drinfeld modules are equal.

is_ordinary()#

Return True if this Drinfeld module is ordinary.

A Drinfeld module is ordinary if and only if its height is one.

EXAMPLES:

sage: Fq = GF(343)
sage: A.<T> = Fq[]
sage: K.<z6> = Fq.extension(2)
sage: phi = DrinfeldModule(A, [1, 0, z6])
sage: phi.is_ordinary()
False
sage: phi = DrinfeldModule(A, [1, z6, 0, z6])
sage: phi.is_ordinary()
True
is_supersingular()#

Return True if this Drinfeld module is supersingular.

A Drinfeld module is supersingular if and only if its height equals its rank.

EXAMPLES:

sage: Fq = GF(343)
sage: A.<T> = Fq[]
sage: K.<z6> = Fq.extension(2)
sage: phi = DrinfeldModule(A, [1, 0, z6])
sage: phi.is_supersingular()
True
sage: phi(phi.characteristic())   # Purely inseparable
z6*t^2

In rank two, a Drinfeld module is either ordinary or supersinguler. In higher ranks, it could be neither of the two:

sage: psi = DrinfeldModule(A, [1, 0, z6, z6])
sage: psi.is_ordinary()
False
sage: psi.is_supersingular()
False