Finite Drinfeld modules#

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

AUTHORS:

  • Antoine Leudière (2022-04)

class sage.rings.function_field.drinfeld_modules.finite_drinfeld_module.FiniteDrinfeldModule(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 FiniteDrinfeldModule — the metaclass DrinfeldModule is responsible for instantiating DrinfeldModule or FiniteDrinfeldModule 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 FiniteDrinfeldModule
sage: isinstance(phi, FiniteDrinfeldModule)
True

The user should never use FiniteDrinfeldModule 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')#

Return the characteristic polynomial of the Frobenius endomorphism if the rank is two. Raise a NotImplementedError otherwise.

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 a monic univariate polynomial with 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^2 - A(T)X + B(T)\) 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 over of the base field over \(\mathbb{F}_q\). We have \(\chi(t^n)(\phi(T)) = t^{2n} - \phi_A t^n + \phi_B = 0\), with \(\deg(A) \leq \frac{n}{2}\) and \(\deg(B) = n\).

Note that the Frobenius trace is defined as \(A(T)\) and the Frobenius norm is defined as \(B(T)\).

INPUT:

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

EXAMPLES:

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: trace = phi.frobenius_trace()
sage: trace
(4*z3^2 + 6*z3 + 3)*T + 3*z3^2 + z3 + 4
sage: norm = phi.frobenius_norm()
sage: norm
(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: trace.degree() <= n/2
True
sage: norm.degree() == n
True

ALGORITHM:

We compute the Frobenius norm, and with it the Frobenius trace. This gives the Frobenius characteristic polynomial. See [MS2019], Section 4.

See docstrings of methods frobenius_norm() and frobenius_trace() for further details on the computation of the norm and of the trace.

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 Frobenius norm of the Drinfeld module, if the rank is two, raise a NotImplementedError otherwise.

Let \(\mathbb{F}_q[T]\) be the function ring, write \(\chi = X^2 - A(T)X + B(T) \in \mathbb{F}_q[T][X]\) for the characteristic polynomial of the Frobenius endomorphism. The Frobenius norm is defined as the polynomial \(B(T) \in \mathbb{F}_q[T]\).

Let \(n\) be 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 Frobenius norm of the Drinfeld module, if the rank is two; raise a NotImplementedError otherwise.

Let \(\mathbb{F}_q[T]\) be the function ring, write \(\chi = T^2 - A(X)T + B(X) \in \mathbb{F}_q[T][X]\) for the characteristic polynomial of the Frobenius endomorphism. The Frobenius trace is defined as the polynomial \(A(T) \in \mathbb{F}_q[T]\).

Let \(n\) be the degree over \(\mathbb{F}_q\) of the base codomain. Then the Frobenius trace has degree at most \(\frac{n}{2}\).

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:

Let \(A(T)\) denote the Frobenius trace and \(B(T)\) denote the Frobenius norm. We begin by computing \(B(T)\), see docstring of method frobenius_norm() for details. The characteristic polynomial of the Frobenius yields \(t^{2n} - \phi_A t^n + \phi_B = 0\), where \(t^n\) is the Frobenius endomorphism. As \(\phi_B\) is now known, we can compute \(\phi_A = (t^{2n} + \phi_B) / t^n\). We get \(A(T)\) by inverting this quantity, using the method sage.rings.function_fields.drinfeld_module.drinfeld_module.DrinfeldModule.invert(), see its docstring for details.

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