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)[source]

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
>>> from sage.all import *
>>> Fq = GF(Integer(343))
>>> A = Fq['T']; (T,) = A._first_ngens(1)
>>> K = Fq.extension(Integer(2), names=('z6',)); (z6,) = K._first_ngens(1)
>>> phi = DrinfeldModule(A, [z6, Integer(0), Integer(5)])
>>> 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
>>> from sage.all import *
>>> isinstance(phi, DrinfeldModule)
True
>>> from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import DrinfeldModule_finite
>>> 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
>>> from sage.all import *
>>> 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
>>> from sage.all import *
>>> frobenius_endomorphism = phi.frobenius_endomorphism()
>>> 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
>>> from sage.all import *
>>> chi = phi.frobenius_charpoly()
>>> chi
X^2 + (T + 2*z3^2 + 2*z3 + 1)*X + 2*T^2 + (z3^2 + z3 + 4)*T + 2*z3
>>> frob_pol = frobenius_endomorphism.ore_polynomial()
>>> 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
>>> from sage.all import *
>>> phi.frobenius_trace()
6*T + 5*z3^2 + 5*z3 + 6
>>> phi.frobenius_trace() == -chi[Integer(1)]
True
>>> 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
>>> from sage.all import *
>>> phi.is_ordinary()
True
>>> 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
>>> from sage.all import *
>>> a = A.random_element()
>>> phi.invert(phi(a)) == a
True
frobenius_charpoly(var='X', algorithm=None)[source]

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: None) – the algorithm used to compute the characteristic polynomial

Available algorithms are:

  • 'CSA' – it exploits the fact that \(K\{\tau\}\) is a central simple algebra (CSA) over \(\mathbb F_q[\text{Frob}_\phi]\) (see Chapter 4 of [CL2023]).

  • 'crystalline' – it uses the action of the Frobenius on the crystalline cohomology (see [MS2023]).

  • 'gekeler' – it tries to identify coefficients by writing that the characteristic polynomial annihilates the Frobenius endomorphism; this algorithm may fail is some cases (see [Gek2008]).

  • 'motive' – it uses the action of the Frobenius on the Anderson motive (see Chapter 2 of [CL2023]).

The method raises an exception if the user asks for an unimplemented algorithm, even if the characteristic polynomial has already been computed.

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
>>> from sage.all import *
>>> Fq = GF(Integer(25))
>>> A = Fq['T']; (T,) = A._first_ngens(1)
>>> K = Fq.extension(Integer(6), names=('z12',)); (z12,) = K._first_ngens(1)
>>> p_root = Integer(2)*z12**Integer(11) + Integer(2)*z12**Integer(10) + z12**Integer(9) + Integer(3)*z12**Integer(8) + z12**Integer(7) + Integer(2)*z12**Integer(5) + Integer(2)*z12**Integer(4) + Integer(3)*z12**Integer(3) + z12**Integer(2) + Integer(2)*z12
>>> phi = DrinfeldModule(A, [p_root, z12**Integer(3), z12**Integer(5)])
>>> 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(algorithm='crystalline')
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
>>> from sage.all import *
>>> Fq = GF(Integer(343))
>>> A = Fq['T']; (T,) = A._first_ngens(1)
>>> K = Fq.extension(Integer(2), names=('z6',)); (z6,) = K._first_ngens(1)
>>> phi = DrinfeldModule(A, [Integer(1), Integer(0), z6])
>>> chi = phi.frobenius_charpoly(algorithm='crystalline')
>>> 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='motive')(phi.frobenius_endomorphism())
Endomorphism of Drinfeld module defined by T |--> z6*t^2 + 1
  Defn: 0
>>> from sage.all import *
>>> frob_pol = phi.frobenius_endomorphism().ore_polynomial()
>>> chi(frob_pol, phi(T))
0
>>> phi.frobenius_charpoly(algorithm='motive')(phi.frobenius_endomorphism())
Endomorphism of Drinfeld module defined by T |--> z6*t^2 + 1
  Defn: 0

sage: phi.frobenius_charpoly(algorithm="NotImplemented")
Traceback (most recent call last):
...
NotImplementedError: algorithm "NotImplemented" not implemented
>>> from sage.all import *
>>> phi.frobenius_charpoly(algorithm="NotImplemented")
Traceback (most recent call last):
...
NotImplementedError: algorithm "NotImplemented" not implemented

ALGORITHM:

If the user specifies an algorithm, then the characteristic polynomial is computed according to the user’s input (see the note above), even if it had already been computed.

If no algorithm is given, then the function either returns a cached value, or if no cached value is available, the function computes the Frobenius characteristic polynomial from scratch. In that case, if the rank \(r\) is less than the extension degree \(n\), then the crystalline algorithm is used, while the CSA algorithm is used otherwise.

frobenius_endomorphism()[source]

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
>>> from sage.all import *
>>> Fq = GF(Integer(343))
>>> A = Fq['T']; (T,) = A._first_ngens(1)
>>> K = Fq.extension(Integer(2), names=('z6',)); (z6,) = K._first_ngens(1)
>>> phi = DrinfeldModule(A, [Integer(1), Integer(0), z6])
>>> phi.frobenius_endomorphism()
Endomorphism of Drinfeld module defined by T |--> z6*t^2 + 1
  Defn: t^2
frobenius_norm()[source]

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 \(a_{0}\), and given by the formula

\[a_0 = (-1)^{nr - n -r} \mathrm{Norm}_{K/\mathbb F_q}(\Delta)^{-1} p^{n / \mathrm{deg}(p)},\]

where \(K\) is the ground field, which as degree \(n\) over \(\mathbb F_q\), \(r\) is the rank of the Drinfeld module, and \(\Delta\) is the leading coefficient of the generator. This formula is given in Theorem~4.2.7 of [Pap2023].

Note that the Frobenius norm computed by this method may be different than what is computed as the isogeny norm of the Frobenius endomorphism (see norm() on the Frobenius endomorphism), which is an ideal defined of the function ring given by its monic generator; the Frobenius norm may not be monic.

EXAMPLES:

sage: Fq = GF(343)
sage: A.<T> = Fq[]
sage: K.<z6> = Fq.extension(2)
sage: phi = DrinfeldModule(A, [1, 0, z6])
sage: frobenius_norm = phi.frobenius_norm()
sage: frobenius_norm
(5*z3^2 + 2*z3)*T^2 + (4*z3^2 + 3*z3)*T + 5*z3^2 + 2*z3
>>> from sage.all import *
>>> Fq = GF(Integer(343))
>>> A = Fq['T']; (T,) = A._first_ngens(1)
>>> K = Fq.extension(Integer(2), names=('z6',)); (z6,) = K._first_ngens(1)
>>> phi = DrinfeldModule(A, [Integer(1), Integer(0), z6])
>>> frobenius_norm = phi.frobenius_norm()
>>> frobenius_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: frobenius_norm.degree() == n
True
>>> from sage.all import *
>>> n = Integer(2)  # Degree of the base field over Fq
>>> frobenius_norm.degree() == n
True

sage: frobenius_norm == phi.frobenius_charpoly()[0]
True
>>> from sage.all import *
>>> frobenius_norm == phi.frobenius_charpoly()[Integer(0)]
True

sage: lc = frobenius_norm.leading_coefficient()
sage: isogeny_norm = phi.frobenius_endomorphism().norm()
sage: isogeny_norm.gen() == frobenius_norm / lc
True
sage: A.ideal(frobenius_norm) == isogeny_norm
True
>>> from sage.all import *
>>> lc = frobenius_norm.leading_coefficient()
>>> isogeny_norm = phi.frobenius_endomorphism().norm()
>>> isogeny_norm.gen() == frobenius_norm / lc
True
>>> A.ideal(frobenius_norm) == isogeny_norm
True

ALGORITHM:

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

frobenius_trace(algorithm=None)[source]

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}\).

INPUT:

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

Available algorithms are:

  • 'CSA' – it exploits the fact that \(K\{\tau\}\) is a central simple algebra (CSA) over \(\mathbb F_q[\text{Frob}_\phi]\) (see Chapter 4 of [CL2023]).

  • 'crystalline' – it uses the action of the Frobenius on the crystalline cohomology (see [MS2023]).

The method raises an exception if the user asks for an unimplemented algorithm, even if the characteristic has already been computed. See frobenius_charpoly() for more details.

EXAMPLES:

sage: Fq = GF(343)
sage: A.<T> = Fq[]
sage: K.<z6> = Fq.extension(2)
sage: phi = DrinfeldModule(A, [1, 0, z6])
sage: frobenius_trace = phi.frobenius_trace()
sage: frobenius_trace
(4*z3^2 + 6*z3 + 3)*T + 3*z3^2 + z3 + 4
>>> from sage.all import *
>>> Fq = GF(Integer(343))
>>> A = Fq['T']; (T,) = A._first_ngens(1)
>>> K = Fq.extension(Integer(2), names=('z6',)); (z6,) = K._first_ngens(1)
>>> phi = DrinfeldModule(A, [Integer(1), Integer(0), z6])
>>> frobenius_trace = phi.frobenius_trace()
>>> frobenius_trace
(4*z3^2 + 6*z3 + 3)*T + 3*z3^2 + z3 + 4

sage: n = 2  # Degree over Fq of the base codomain
sage: frobenius_trace.degree() <= n/2
True
>>> from sage.all import *
>>> n = Integer(2)  # Degree over Fq of the base codomain
>>> frobenius_trace.degree() <= n/Integer(2)
True

sage: frobenius_trace == -phi.frobenius_charpoly()[1]
True
>>> from sage.all import *
>>> frobenius_trace == -phi.frobenius_charpoly()[Integer(1)]
True

One can specify an algorithm:

sage: psi = DrinfeldModule(A, [z6, 1, z6^3, z6 + 1])
sage: psi.frobenius_trace(algorithm='crystalline')
z3^2 + 6*z3 + 2
sage: psi.frobenius_trace(algorithm='CSA')
z3^2 + 6*z3 + 2
>>> from sage.all import *
>>> psi = DrinfeldModule(A, [z6, Integer(1), z6**Integer(3), z6 + Integer(1)])
>>> psi.frobenius_trace(algorithm='crystalline')
z3^2 + 6*z3 + 2
>>> psi.frobenius_trace(algorithm='CSA')
z3^2 + 6*z3 + 2

ALGORITHM:

If the user specifies an algorithm, then the trace is computed according to the user’s input (see the note above), even if the Frobenius trace or the Frobenius characteristic polynomial had already been computed.

If no algorithm is given, then the function either returns a cached value, or if no cached value is available, the function computes the Frobenius trace from scratch. In that case, if the rank \(r\) is less than the extension degree \(n\), then the crystalline algorithm is used, while the CSA algorithm is used otherwise.

invert(ore_pol)[source]

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
>>> from sage.all import *
>>> Fq = GF(Integer(25))
>>> A = Fq['T']; (T,) = A._first_ngens(1)
>>> K = Fq.extension(Integer(6), names=('z12',)); (z12,) = K._first_ngens(1)
>>> p_root = Integer(2)*z12**Integer(11) + Integer(2)*z12**Integer(10) + z12**Integer(9) + Integer(3)*z12**Integer(8) + z12**Integer(7) + Integer(2)*z12**Integer(5) + Integer(2)*z12**Integer(4) + Integer(3)*z12**Integer(3) + z12**Integer(2) + Integer(2)*z12
>>> phi = DrinfeldModule(A, [p_root, z12**Integer(3), z12**Integer(5)])
>>> a = A.random_element()
>>> phi.invert(phi(a)) == a
True
>>> phi.invert(phi(T)) == T
True
>>> 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
>>> from sage.all import *
>>> t = phi.ore_polring().gen()
>>> phi.invert(t + Integer(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
>>> from sage.all import *
>>> phi.invert(t**Integer(4) + t**Integer(2) + Integer(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)[source]

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
>>> from sage.all import *
>>> Fq = GF(Integer(2))
>>> A = Fq['T']; (T,) = A._first_ngens(1)
>>> K = Fq.extension(Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> psi = DrinfeldModule(A, [z, z + Integer(1), z**Integer(2) + z + Integer(1)])
>>> phi = DrinfeldModule(A, [z, z**Integer(2) + z + Integer(1), z**Integer(2) + z])
>>> phi.is_isogenous(psi)
True

sage: chi = DrinfeldModule(A, [z, z + 1, z^2 + z])
sage: phi.is_isogenous(chi)
False
>>> from sage.all import *
>>> chi = DrinfeldModule(A, [z, z + Integer(1), z**Integer(2) + z])
>>> 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
>>> from sage.all import *
>>> mu = DrinfeldModule(A, [z + Integer(1), z**Integer(2) + z + Integer(1), z**Integer(2) + z])
>>> 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
>>> from sage.all import *
>>> mu = Integer(1)
>>> 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()[source]

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
>>> from sage.all import *
>>> Fq = GF(Integer(343))
>>> A = Fq['T']; (T,) = A._first_ngens(1)
>>> K = Fq.extension(Integer(2), names=('z6',)); (z6,) = K._first_ngens(1)
>>> phi = DrinfeldModule(A, [Integer(1), Integer(0), z6])
>>> phi.is_ordinary()
False

sage: phi = DrinfeldModule(A, [1, z6, 0, z6])
sage: phi.is_ordinary()
True
>>> from sage.all import *
>>> phi = DrinfeldModule(A, [Integer(1), z6, Integer(0), z6])
>>> phi.is_ordinary()
True
is_supersingular()[source]

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
>>> from sage.all import *
>>> Fq = GF(Integer(343))
>>> A = Fq['T']; (T,) = A._first_ngens(1)
>>> K = Fq.extension(Integer(2), names=('z6',)); (z6,) = K._first_ngens(1)
>>> phi = DrinfeldModule(A, [Integer(1), Integer(0), z6])
>>> phi.is_supersingular()
True
>>> 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
>>> from sage.all import *
>>> psi = DrinfeldModule(A, [Integer(1), Integer(0), z6, z6])
>>> psi.is_ordinary()
False
>>> psi.is_supersingular()
False