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 metaclassDrinfeldModule
is responsible for instantiatingDrinfeldModule
orDrinfeldModule_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 theis_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 variablealgorithm
(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 theCSA
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:
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 theCSA
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
whenself
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