Drinfeld modules¶
This module provides the class
sage.rings.function_field.drinfeld_module.drinfeld_module.DrinfeldModule.
For finite Drinfeld modules and their theory of complex multiplication, see
class
sage.rings.function_field.drinfeld_module.finite_drinfeld_module.DrinfeldModule.
AUTHORS:
- Antoine Leudière (2022-04): initial version 
- Xavier Caruso (2022-06): initial version 
- David Ayotte (2023-03): added basic \(j\)-invariants 
- class sage.rings.function_field.drinfeld_modules.drinfeld_module.DrinfeldModule(gen, category)[source]¶
- Bases: - Parent,- UniqueRepresentation- This class implements Drinfeld \(\mathbb{F}_q[T]\)-modules. - Let \(\mathbb{F}_q[T]\) be a polynomial ring with coefficients in a finite field \(\mathbb{F}_q\) and let \(K\) be a field. Fix a ring morphism \(\gamma: \mathbb{F}_q[T] \to K\); we say that \(K\) is an \(\mathbb{F}_q[T]\)-field. Let \(K\{\tau\}\) be the ring of Ore polynomials with coefficients in \(K\), whose multiplication is given by the rule \(\tau \lambda = \lambda^q \tau\) for any \(\lambda \in K\). - A Drinfeld \(\mathbb{F}_q[T]\)-module over the base \(\mathbb{F}_q[T]\)-field \(K\) is an \(\mathbb{F}_q\)-algebra morphism \(\phi: \mathbb{F}_q[T] \to K\{\tau\}\) such that \(\mathrm{Im}(\phi) \not\subset K\) and \(\phi\) agrees with \(\gamma\) on \(\mathbb{F}_q\). - For \(a\) in \(\mathbb{F}_q[T]\), \(\phi(a)\) is denoted \(\phi_a\). - The Drinfeld \(\mathbb{F}_q[T]\)-module \(\phi\) is uniquely determined by the image \(\phi_T\) of \(T\); this serves as input of the class. - Note - See also - sage.categories.drinfeld_modules.- The base morphism is the morphism \(\gamma: \mathbb{F}_q[T] \to K\). The monic polynomial that generates the kernel of \(\gamma\) is called the \(\mathbb{F}_q[T]\)-characteristic, or function-field characteristic, of the base field. We say that \(\mathbb{F}_q[T]\) is the function ring of \(\phi\); \(K\{\tau\}\) is the Ore polynomial ring. Further, the generator is \(\phi_T\) and the constant coefficient is the constant coefficient of \(\phi_T\). - A Drinfeld module is said to be finite if the field \(K\) is. Despite an emphasis on this case, the base field can be any extension of \(\mathbb{F}_q\): - sage: Fq = GF(25) sage: A.<T> = Fq[] sage: K.<z> = Fq.extension(6) sage: phi = DrinfeldModule(A, [z, 4, 1]) sage: phi Drinfeld module defined by T |--> t^2 + 4*t + z - >>> from sage.all import * >>> Fq = GF(Integer(25)) >>> A = Fq['T']; (T,) = A._first_ngens(1) >>> K = Fq.extension(Integer(6), names=('z',)); (z,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [z, Integer(4), Integer(1)]) >>> phi Drinfeld module defined by T |--> t^2 + 4*t + z - sage: Fq = GF(49) sage: A.<T> = Fq[] sage: K = Frac(A) sage: psi = DrinfeldModule(A, [K(T), T+1]) sage: psi Drinfeld module defined by T |--> (T + 1)*t + T - >>> from sage.all import * >>> Fq = GF(Integer(49)) >>> A = Fq['T']; (T,) = A._first_ngens(1) >>> K = Frac(A) >>> psi = DrinfeldModule(A, [K(T), T+Integer(1)]) >>> psi Drinfeld module defined by T |--> (T + 1)*t + T - Note - Finite Drinfeld modules are implemented in the class - sage.rings.function_field.drinfeld_modules.finite_drinfeld_module.- Classical references on Drinfeld modules include [Gos1998], [Rosen2002], [VS06] and [Gek1991]. - Note - Drinfeld modules are defined in a larger setting, in which the polynomial ring \(\mathbb{F}_q[T]\) is replaced by a more general function ring: the ring of functions in \(k\) that are regular outside \(\infty\), where \(k\) is a function field over \(\mathbb{F}_q\) with transcendence degree \(1\) and \(\infty\) is a fixed place of \(k\). This is out of the scope of this implementation. - INPUT: - function_ring– a univariate polynomial ring whose base field is a finite field
- gen– the generator of the Drinfeld module; as a list of coefficients or an Ore polynomial
- name– (default:- 't') the name of the Ore polynomial ring generator
 - Construction - A Drinfeld module object is constructed by giving the function ring and the generator: - sage: Fq.<z2> = GF(3^2) sage: A.<T> = Fq[] sage: K.<z> = Fq.extension(6) sage: phi = DrinfeldModule(A, [z, 1, 1]) sage: phi Drinfeld module defined by T |--> t^2 + t + z - >>> from sage.all import * >>> Fq = GF(Integer(3)**Integer(2), names=('z2',)); (z2,) = Fq._first_ngens(1) >>> A = Fq['T']; (T,) = A._first_ngens(1) >>> K = Fq.extension(Integer(6), names=('z',)); (z,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [z, Integer(1), Integer(1)]) >>> phi Drinfeld module defined by T |--> t^2 + t + z - Note - Note that the definition of the base field is implicit; it is automatically defined as the compositum of all the parents of the coefficients. - The above Drinfeld module is finite; it can also be infinite: - sage: L = Frac(A) sage: psi = DrinfeldModule(A, [L(T), 1, T^3 + T + 1]) sage: psi Drinfeld module defined by T |--> (T^3 + T + 1)*t^2 + t + T - >>> from sage.all import * >>> L = Frac(A) >>> psi = DrinfeldModule(A, [L(T), Integer(1), T**Integer(3) + T + Integer(1)]) >>> psi Drinfeld module defined by T |--> (T^3 + T + 1)*t^2 + t + T - sage: phi.is_finite() True sage: psi.is_finite() False - >>> from sage.all import * >>> phi.is_finite() True >>> psi.is_finite() False - In those examples, we used a list of coefficients ( - [z, 1, 1]) to represent the generator \(\phi_T = z + t + t^2\). One can also use regular Ore polynomials:- sage: ore_polring = phi.ore_polring() sage: t = ore_polring.gen() sage: rho_T = z + t^3 sage: rho = DrinfeldModule(A, rho_T) sage: rho Drinfeld module defined by T |--> t^3 + z sage: rho(T) == rho_T True - >>> from sage.all import * >>> ore_polring = phi.ore_polring() >>> t = ore_polring.gen() >>> rho_T = z + t**Integer(3) >>> rho = DrinfeldModule(A, rho_T) >>> rho Drinfeld module defined by T |--> t^3 + z >>> rho(T) == rho_T True - Images under the Drinfeld module are computed by calling the object: - sage: phi(T) # phi_T, the generator of the Drinfeld module t^2 + t + z sage: phi(T^3 + T + 1) # phi_(T^3 + T + 1) t^6 + (z^11 + z^9 + 2*z^6 + 2*z^4 + 2*z + 1)*t^4 + (2*z^11 + 2*z^10 + z^9 + z^8 + 2*z^7 + 2*z^6 + z^5 + 2*z^3)*t^3 + (2*z^11 + z^10 + z^9 + 2*z^7 + 2*z^6 + z^5 + z^4 + 2*z^3 + 2*z + 2)*t^2 + (2*z^11 + 2*z^8 + 2*z^6 + z^5 + z^4 + 2*z^2)*t + z^3 + z + 1 sage: phi(1) # phi_1 1 - >>> from sage.all import * >>> phi(T) # phi_T, the generator of the Drinfeld module t^2 + t + z >>> phi(T**Integer(3) + T + Integer(1)) # phi_(T^3 + T + 1) t^6 + (z^11 + z^9 + 2*z^6 + 2*z^4 + 2*z + 1)*t^4 + (2*z^11 + 2*z^10 + z^9 + z^8 + 2*z^7 + 2*z^6 + z^5 + 2*z^3)*t^3 + (2*z^11 + z^10 + z^9 + 2*z^7 + 2*z^6 + z^5 + z^4 + 2*z^3 + 2*z + 2)*t^2 + (2*z^11 + 2*z^8 + 2*z^6 + z^5 + z^4 + 2*z^2)*t + z^3 + z + 1 >>> phi(Integer(1)) # phi_1 1 - The category of Drinfeld modules - Drinfeld modules have their own category (see class - sage.categories.drinfeld_modules.DrinfeldModules):- sage: phi.category() Category of Drinfeld modules over Finite Field in z of size 3^12 over its base sage: phi.category() is psi.category() False sage: phi.category() is rho.category() True - >>> from sage.all import * >>> phi.category() Category of Drinfeld modules over Finite Field in z of size 3^12 over its base >>> phi.category() is psi.category() False >>> phi.category() is rho.category() True - One can use the category to directly create new objects: - sage: cat = phi.category() sage: cat.object([z, 0, 0, 1]) Drinfeld module defined by T |--> t^3 + z - >>> from sage.all import * >>> cat = phi.category() >>> cat.object([z, Integer(0), Integer(0), Integer(1)]) Drinfeld module defined by T |--> t^3 + z - The base field of a Drinfeld module - The base field of the Drinfeld module is retrieved using - base():- sage: phi.base() Finite Field in z of size 3^12 over its base - >>> from sage.all import * >>> phi.base() Finite Field in z of size 3^12 over its base - The base morphism is retrieved using - base_morphism():- sage: phi.base_morphism() Ring morphism: From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 To: Finite Field in z of size 3^12 over its base Defn: T |--> z - >>> from sage.all import * >>> phi.base_morphism() Ring morphism: From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 To: Finite Field in z of size 3^12 over its base Defn: T |--> z - Note that the base field is not the field \(K\). Rather, it is a ring extension (see - sage.rings.ring_extension.RingExtension) whose underlying ring is \(K\) and whose base is the base morphism:- sage: phi.base() is K False - >>> from sage.all import * >>> phi.base() is K False - Getters - One can retrieve basic properties: - sage: phi.base_morphism() Ring morphism: From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 To: Finite Field in z of size 3^12 over its base Defn: T |--> z - >>> from sage.all import * >>> phi.base_morphism() Ring morphism: From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 To: Finite Field in z of size 3^12 over its base Defn: T |--> z - sage: phi.ore_polring() # K{t} Ore Polynomial Ring in t over Finite Field in z of size 3^12 over its base twisted by Frob^2 - >>> from sage.all import * >>> phi.ore_polring() # K{t} Ore Polynomial Ring in t over Finite Field in z of size 3^12 over its base twisted by Frob^2 - sage: phi.function_ring() # Fq[T] Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 - >>> from sage.all import * >>> phi.function_ring() # Fq[T] Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 - sage: phi.gen() # phi_T t^2 + t + z sage: phi.gen() == phi(T) True - >>> from sage.all import * >>> phi.gen() # phi_T t^2 + t + z >>> phi.gen() == phi(T) True - sage: phi.constant_coefficient() # Constant coefficient of phi_T z - >>> from sage.all import * >>> phi.constant_coefficient() # Constant coefficient of phi_T z - sage: phi.morphism() # The Drinfeld module as a morphism Ring morphism: From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 To: Ore Polynomial Ring in t over Finite Field in z of size 3^12 over its base twisted by Frob^2 Defn: T |--> t^2 + t + z - >>> from sage.all import * >>> phi.morphism() # The Drinfeld module as a morphism Ring morphism: From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 To: Ore Polynomial Ring in t over Finite Field in z of size 3^12 over its base twisted by Frob^2 Defn: T |--> t^2 + t + z - One can compute the rank and height: - sage: phi.rank() 2 sage: phi.height() 1 - >>> from sage.all import * >>> phi.rank() 2 >>> phi.height() 1 - As well as the j-invariant: - sage: phi.j_invariant() # j-invariant 1 - >>> from sage.all import * >>> phi.j_invariant() # j-invariant 1 - A Drinfeld \(\mathbb{F}_q[T]\)-module can be seen as an Ore polynomial with positive degree and constant coefficient \(\gamma(T)\), where \(\gamma\) is the base morphism. This analogy is the motivation for the following methods: - sage: phi.coefficients() [z, 1, 1] - >>> from sage.all import * >>> phi.coefficients() [z, 1, 1] - sage: phi.coefficient(1) 1 - >>> from sage.all import * >>> phi.coefficient(Integer(1)) 1 - Morphisms and isogenies - A morphism of Drinfeld modules \(\phi \to \psi\) is an Ore polynomial \(f \in K\{\tau\}\) such that \(f \phi_a = \psi_a f\) for every \(a\) in the function ring. In our case, this is equivalent to \(f \phi_T = \psi_T f\). An isogeny is a nonzero morphism. - Use the - insyntax to test if an Ore polynomial defines a morphism:- sage: phi(T) in Hom(phi, phi) True sage: t^6 in Hom(phi, phi) True sage: t^5 + 2*t^3 + 1 in Hom(phi, phi) False sage: 1 in Hom(phi, rho) False sage: 1 in Hom(phi, phi) True sage: 0 in Hom(phi, rho) True - >>> from sage.all import * >>> phi(T) in Hom(phi, phi) True >>> t**Integer(6) in Hom(phi, phi) True >>> t**Integer(5) + Integer(2)*t**Integer(3) + Integer(1) in Hom(phi, phi) False >>> Integer(1) in Hom(phi, rho) False >>> Integer(1) in Hom(phi, phi) True >>> Integer(0) in Hom(phi, rho) True - To create a SageMath object representing the morphism, call the homset ( - hom):- sage: hom = Hom(phi, phi) sage: frobenius_endomorphism = hom(t^6) sage: identity_morphism = hom(1) sage: zero_morphism = hom(0) sage: frobenius_endomorphism Endomorphism of Drinfeld module defined by T |--> t^2 + t + z Defn: t^6 sage: identity_morphism Identity morphism of Drinfeld module defined by T |--> t^2 + t + z sage: zero_morphism Endomorphism of Drinfeld module defined by T |--> t^2 + t + z Defn: 0 - >>> from sage.all import * >>> hom = Hom(phi, phi) >>> frobenius_endomorphism = hom(t**Integer(6)) >>> identity_morphism = hom(Integer(1)) >>> zero_morphism = hom(Integer(0)) >>> frobenius_endomorphism Endomorphism of Drinfeld module defined by T |--> t^2 + t + z Defn: t^6 >>> identity_morphism Identity morphism of Drinfeld module defined by T |--> t^2 + t + z >>> zero_morphism Endomorphism of Drinfeld module defined by T |--> t^2 + t + z Defn: 0 - The underlying Ore polynomial is retrieved with the method - ore_polynomial():- sage: frobenius_endomorphism.ore_polynomial() t^6 sage: identity_morphism.ore_polynomial() 1 - >>> from sage.all import * >>> frobenius_endomorphism.ore_polynomial() t^6 >>> identity_morphism.ore_polynomial() 1 - One checks if a morphism is an isogeny, endomorphism or isomorphism: - sage: frobenius_endomorphism.is_isogeny() True sage: identity_morphism.is_isogeny() True sage: zero_morphism.is_isogeny() False sage: frobenius_endomorphism.is_isomorphism() False sage: identity_morphism.is_isomorphism() True sage: zero_morphism.is_isomorphism() False - >>> from sage.all import * >>> frobenius_endomorphism.is_isogeny() True >>> identity_morphism.is_isogeny() True >>> zero_morphism.is_isogeny() False >>> frobenius_endomorphism.is_isomorphism() False >>> identity_morphism.is_isomorphism() True >>> zero_morphism.is_isomorphism() False - The Vélu formula - Let - Pbe a nonzero Ore polynomial. We can decide if- Pdefines an isogeny with a given domain and, if it does, find the codomain:- sage: P = (2*z^6 + z^3 + 2*z^2 + z + 2)*t + z^11 + 2*z^10 + 2*z^9 + 2*z^8 + z^7 + 2*z^6 + z^5 + z^3 + z^2 + z sage: psi = phi.velu(P) sage: psi Drinfeld module defined by T |--> (2*z^11 + 2*z^9 + z^6 + 2*z^5 + 2*z^4 + 2*z^2 + 1)*t^2 + (2*z^11 + 2*z^10 + 2*z^9 + z^8 + 2*z^7 + 2*z^6 + z^5 + 2*z^4 + 2*z^2 + 2*z)*t + z sage: P in Hom(phi, psi) True sage: P * phi(T) == psi(T) * P True - >>> from sage.all import * >>> P = (Integer(2)*z**Integer(6) + z**Integer(3) + Integer(2)*z**Integer(2) + z + Integer(2))*t + z**Integer(11) + Integer(2)*z**Integer(10) + Integer(2)*z**Integer(9) + Integer(2)*z**Integer(8) + z**Integer(7) + Integer(2)*z**Integer(6) + z**Integer(5) + z**Integer(3) + z**Integer(2) + z >>> psi = phi.velu(P) >>> psi Drinfeld module defined by T |--> (2*z^11 + 2*z^9 + z^6 + 2*z^5 + 2*z^4 + 2*z^2 + 1)*t^2 + (2*z^11 + 2*z^10 + 2*z^9 + z^8 + 2*z^7 + 2*z^6 + z^5 + 2*z^4 + 2*z^2 + 2*z)*t + z >>> P in Hom(phi, psi) True >>> P * phi(T) == psi(T) * P True - If the input does not define an isogeny, an exception is raised: - sage: phi.velu(0) Traceback (most recent call last): ... ValueError: the input does not define an isogeny sage: phi.velu(t) Traceback (most recent call last): ... ValueError: the input does not define an isogeny - >>> from sage.all import * >>> phi.velu(Integer(0)) Traceback (most recent call last): ... ValueError: the input does not define an isogeny >>> phi.velu(t) Traceback (most recent call last): ... ValueError: the input does not define an isogeny - The action of a Drinfeld module - The \(\mathbb{F}_q[T]\)-Drinfeld module \(\phi\) induces a special left \(\mathbb{F}_q[T]\)-module structure on any field extension \(L/K\). Let \(x \in L\) and \(a\) be in the function ring; the action is defined as \((a, x) \mapsto \phi_a(x)\). The method - action()returns a- sage.rings.function_field.drinfeld_modules.action.Actionobject representing the Drinfeld module action.- Note - In this implementation, \(L\) is \(K\): - sage: action = phi.action() sage: action Action on Finite Field in z of size 3^12 over its base induced by Drinfeld module defined by T |--> t^2 + t + z - >>> from sage.all import * >>> action = phi.action() >>> action Action on Finite Field in z of size 3^12 over its base induced by Drinfeld module defined by T |--> t^2 + t + z - The action on elements is computed by calling the action object: - sage: P = T + 1 sage: a = z sage: action(P, a) ... z^9 + 2*z^8 + 2*z^7 + 2*z^6 + 2*z^3 + z^2 sage: action(0, K.random_element()) 0 sage: action(A.random_element(), 0) 0 - >>> from sage.all import * >>> P = T + Integer(1) >>> a = z >>> action(P, a) ... z^9 + 2*z^8 + 2*z^7 + 2*z^6 + 2*z^3 + z^2 >>> action(Integer(0), K.random_element()) 0 >>> action(A.random_element(), Integer(0)) 0 - Warning - The class - DrinfeldModuleActionmay be replaced later on. See issues #34833 and #34834.- action()[source]¶
- Return the action object ( - sage.rings.function_field.drinfeld_modules.action.Action) that represents the module action, on the base codomain, that is induced by the Drinfeld module.- OUTPUT: a Drinfeld module action object - 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: action = phi.action() sage: action Action on Finite Field in z12 of size 5^12 over its base induced by Drinfeld module defined by T |--> z12^5*t^2 + z12^3*t + 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 - >>> 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)]) >>> action = phi.action() >>> action Action on Finite Field in z12 of size 5^12 over its base induced by Drinfeld module defined by T |--> z12^5*t^2 + z12^3*t + 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 - The action on elements is computed as follows: - sage: P = T^2 + T + 1 sage: a = z12 + 1 sage: action(P, a) 3*z12^11 + 2*z12^10 + 3*z12^9 + 3*z12^7 + 4*z12^5 + z12^4 + z12^3 + 2*z12 + 1 sage: action(0, a) 0 sage: action(P, 0) 0 - >>> from sage.all import * >>> P = T**Integer(2) + T + Integer(1) >>> a = z12 + Integer(1) >>> action(P, a) 3*z12^11 + 2*z12^10 + 3*z12^9 + 3*z12^7 + 4*z12^5 + z12^4 + z12^3 + 2*z12 + 1 >>> action(Integer(0), a) 0 >>> action(P, Integer(0)) 0 
 - basic_j_invariant_parameters(coeff_indices=None, nonzero=False)[source]¶
- Return the list of basic \(j\)-invariant parameters. - See the method - j_invariant()for definitions.- INPUT: - coeff_indices– list or tuple, or NoneType (default:- None); indices of the Drinfeld module generator coefficients to be considered in the computation. If the parameter is- None(default), all the coefficients are involved.
- nonzero– boolean (default:- False); if this flag is set to- True, then only the parameters for which the corresponding basic \(j\)-invariant is nonzero are returned
 - Warning - The usage of this method can be computationally expensive e.g. if the rank is greater than four, or if \(q\) is large. Setting the - nonzeroflag to- Truecan speed up the computation considerably if the Drinfeld module generator possesses multiple zero coefficients.- EXAMPLES: - sage: A = GF(5)['T'] sage: K.<T> = Frac(A) sage: phi = DrinfeldModule(A, [T, 0, T+1, T^2 + 1]) sage: phi.basic_j_invariant_parameters() [((1,), (31, 1)), ((1, 2), (1, 5, 1)), ((1, 2), (7, 4, 1)), ((1, 2), (8, 9, 2)), ((1, 2), (9, 14, 3)), ((1, 2), (10, 19, 4)), ((1, 2), (11, 24, 5)), ((1, 2), (12, 29, 6)), ((1, 2), (13, 3, 1)), ((1, 2), (15, 13, 3)), ((1, 2), (17, 23, 5)), ((1, 2), (19, 2, 1)), ((1, 2), (20, 7, 2)), ((1, 2), (22, 17, 4)), ((1, 2), (23, 22, 5)), ((1, 2), (25, 1, 1)), ((1, 2), (27, 11, 3)), ((1, 2), (29, 21, 5)), ((1, 2), (31, 31, 7)), ((2,), (31, 6))] - >>> from sage.all import * >>> A = GF(Integer(5))['T'] >>> K = Frac(A, names=('T',)); (T,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [T, Integer(0), T+Integer(1), T**Integer(2) + Integer(1)]) >>> phi.basic_j_invariant_parameters() [((1,), (31, 1)), ((1, 2), (1, 5, 1)), ((1, 2), (7, 4, 1)), ((1, 2), (8, 9, 2)), ((1, 2), (9, 14, 3)), ((1, 2), (10, 19, 4)), ((1, 2), (11, 24, 5)), ((1, 2), (12, 29, 6)), ((1, 2), (13, 3, 1)), ((1, 2), (15, 13, 3)), ((1, 2), (17, 23, 5)), ((1, 2), (19, 2, 1)), ((1, 2), (20, 7, 2)), ((1, 2), (22, 17, 4)), ((1, 2), (23, 22, 5)), ((1, 2), (25, 1, 1)), ((1, 2), (27, 11, 3)), ((1, 2), (29, 21, 5)), ((1, 2), (31, 31, 7)), ((2,), (31, 6))] - Use the - nonzero=Trueflag to display only the parameters whose \(j\)-invariant value is nonzero:- sage: phi.basic_j_invariant_parameters(nonzero=True) [((2,), (31, 6))] - >>> from sage.all import * >>> phi.basic_j_invariant_parameters(nonzero=True) [((2,), (31, 6))] - One can specify the list of coefficients indices to be considered in the computation: - sage: A = GF(2)['T'] sage: K.<T> = Frac(A) sage: phi = DrinfeldModule(A, [T, T, 1, T]) sage: phi.basic_j_invariant_parameters([1, 2]) [((1,), (7, 1)), ((1, 2), (1, 2, 1)), ((1, 2), (4, 1, 1)), ((1, 2), (5, 3, 2)), ((1, 2), (6, 5, 3)), ((1, 2), (7, 7, 4)), ((2,), (7, 3))] - >>> from sage.all import * >>> A = GF(Integer(2))['T'] >>> K = Frac(A, names=('T',)); (T,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [T, T, Integer(1), T]) >>> phi.basic_j_invariant_parameters([Integer(1), Integer(2)]) [((1,), (7, 1)), ((1, 2), (1, 2, 1)), ((1, 2), (4, 1, 1)), ((1, 2), (5, 3, 2)), ((1, 2), (6, 5, 3)), ((1, 2), (7, 7, 4)), ((2,), (7, 3))] 
 - basic_j_invariants(nonzero=False)[source]¶
- Return a dictionary whose keys are all the basic \(j\)-invariants parameters and values are the corresponding \(j\)-invariant. - See the method - j_invariant()for definitions.- INPUT: - nonzero– boolean (default:- False); if this flag is set to- True, then only the parameters for which the corresponding basic \(j\)-invariant is nonzero are returned
 - Warning - The usage of this method can be computationally expensive e.g. if the rank is greater than four, or if \(q\) is large. Setting the - nonzeroflag to- Truecan speed up the computation considerably if the Drinfeld module generator possesses multiple zero coefficients.- 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.basic_j_invariants() {((1,), (26, 1)): z12^10 + 4*z12^9 + 3*z12^8 + 2*z12^7 + 3*z12^6 + z12^5 + z12^3 + 4*z12^2 + z12 + 2} - >>> 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.basic_j_invariants() {((1,), (26, 1)): z12^10 + 4*z12^9 + 3*z12^8 + 2*z12^7 + 3*z12^6 + z12^5 + z12^3 + 4*z12^2 + z12 + 2} - sage: phi = DrinfeldModule(A, [p_root, 0, 1, z12]) sage: phi.basic_j_invariants(nonzero=True) {((2,), (651, 26)): z12^11 + 3*z12^10 + 4*z12^9 + 3*z12^8 + z12^7 + 2*z12^6 + 3*z12^4 + 2*z12^3 + z12^2 + 4*z12} - >>> from sage.all import * >>> phi = DrinfeldModule(A, [p_root, Integer(0), Integer(1), z12]) >>> phi.basic_j_invariants(nonzero=True) {((2,), (651, 26)): z12^11 + 3*z12^10 + 4*z12^9 + 3*z12^8 + z12^7 + 2*z12^6 + 3*z12^4 + 2*z12^3 + z12^2 + 4*z12} - sage: A = GF(5)['T'] sage: K.<T> = Frac(A) sage: phi = DrinfeldModule(A, [T, T + 2, T+1, 1]) sage: J_phi = phi.basic_j_invariants(); J_phi {((1,), (31, 1)): T^31 + 2*T^30 + 2*T^26 + 4*T^25 + 2*T^6 + 4*T^5 + 4*T + 3, ((1, 2), (1, 5, 1)): T^6 + 2*T^5 + T + 2, ((1, 2), (7, 4, 1)): T^11 + 3*T^10 + T^9 + 4*T^8 + T^7 + 2*T^6 + 2*T^4 + 3*T^3 + 2*T^2 + 3, ((1, 2), (8, 9, 2)): T^17 + 2*T^15 + T^14 + 4*T^13 + 4*T^11 + 4*T^10 + 3*T^9 + 2*T^8 + 3*T^7 + 2*T^6 + 3*T^5 + 2*T^4 + 3*T^3 + 4*T^2 + 3*T + 1, ((1, 2), (9, 14, 3)): T^23 + 2*T^22 + 2*T^21 + T^19 + 4*T^18 + T^17 + 4*T^16 + T^15 + 4*T^14 + 2*T^12 + 4*T^11 + 4*T^10 + 2*T^8 + 4*T^7 + 4*T^6 + 2*T^4 + T^2 + 2*T + 2, ((1, 2), (10, 19, 4)): T^29 + 4*T^28 + T^27 + 4*T^26 + T^25 + 2*T^24 + 3*T^23 + 2*T^22 + 3*T^21 + 2*T^20 + 4*T^19 + T^18 + 4*T^17 + T^16 + 4*T^15 + T^9 + 4*T^8 + T^7 + 4*T^6 + T^5 + 4*T^4 + T^3 + 4*T^2 + T + 4, ... ((2,), (31, 6)): T^31 + T^30 + T^26 + T^25 + T^6 + T^5 + T + 1} sage: J_phi[((1, 2), (7, 4, 1))] T^11 + 3*T^10 + T^9 + 4*T^8 + T^7 + 2*T^6 + 2*T^4 + 3*T^3 + 2*T^2 + 3 - >>> from sage.all import * >>> A = GF(Integer(5))['T'] >>> K = Frac(A, names=('T',)); (T,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [T, T + Integer(2), T+Integer(1), Integer(1)]) >>> J_phi = phi.basic_j_invariants(); J_phi {((1,), (31, 1)): T^31 + 2*T^30 + 2*T^26 + 4*T^25 + 2*T^6 + 4*T^5 + 4*T + 3, ((1, 2), (1, 5, 1)): T^6 + 2*T^5 + T + 2, ((1, 2), (7, 4, 1)): T^11 + 3*T^10 + T^9 + 4*T^8 + T^7 + 2*T^6 + 2*T^4 + 3*T^3 + 2*T^2 + 3, ((1, 2), (8, 9, 2)): T^17 + 2*T^15 + T^14 + 4*T^13 + 4*T^11 + 4*T^10 + 3*T^9 + 2*T^8 + 3*T^7 + 2*T^6 + 3*T^5 + 2*T^4 + 3*T^3 + 4*T^2 + 3*T + 1, ((1, 2), (9, 14, 3)): T^23 + 2*T^22 + 2*T^21 + T^19 + 4*T^18 + T^17 + 4*T^16 + T^15 + 4*T^14 + 2*T^12 + 4*T^11 + 4*T^10 + 2*T^8 + 4*T^7 + 4*T^6 + 2*T^4 + T^2 + 2*T + 2, ((1, 2), (10, 19, 4)): T^29 + 4*T^28 + T^27 + 4*T^26 + T^25 + 2*T^24 + 3*T^23 + 2*T^22 + 3*T^21 + 2*T^20 + 4*T^19 + T^18 + 4*T^17 + T^16 + 4*T^15 + T^9 + 4*T^8 + T^7 + 4*T^6 + T^5 + 4*T^4 + T^3 + 4*T^2 + T + 4, ... ((2,), (31, 6)): T^31 + T^30 + T^26 + T^25 + T^6 + T^5 + T + 1} >>> J_phi[((Integer(1), Integer(2)), (Integer(7), Integer(4), Integer(1)))] T^11 + 3*T^10 + T^9 + 4*T^8 + T^7 + 2*T^6 + 2*T^4 + 3*T^3 + 2*T^2 + 3 
 - coefficient(n)[source]¶
- Return the \(n\)-th coefficient of the generator. - INPUT: - n– nonnegative integer
 - OUTPUT: an element in the base codomain - 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.coefficient(0) 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.coefficient(0) == p_root True sage: phi.coefficient(1) z12^3 sage: phi.coefficient(2) z12^5 sage: phi.coefficient(5) Traceback (most recent call last): ... ValueError: input must be >= 0 and <= rank - >>> 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.coefficient(Integer(0)) 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 >>> phi.coefficient(Integer(0)) == p_root True >>> phi.coefficient(Integer(1)) z12^3 >>> phi.coefficient(Integer(2)) z12^5 >>> phi.coefficient(Integer(5)) Traceback (most recent call last): ... ValueError: input must be >= 0 and <= rank 
 - coefficients(sparse=True)[source]¶
- Return the coefficients of the generator, as a list. - If the flag - sparseis- True(default), only return the nonzero coefficients; otherwise, return all of them.- INPUT: - sparse– boolean
 - 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.coefficients() [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, z12^3, z12^5] - >>> 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.coefficients() [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, z12^3, z12^5] - Careful, the method only returns the nonzero coefficients, unless otherwise specified: - sage: rho = DrinfeldModule(A, [p_root, 0, 0, 0, 1]) sage: rho.coefficients() [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, 1] sage: rho.coefficients(sparse=False) [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, 0, 0, 0, 1] - >>> from sage.all import * >>> rho = DrinfeldModule(A, [p_root, Integer(0), Integer(0), Integer(0), Integer(1)]) >>> rho.coefficients() [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, 1] >>> rho.coefficients(sparse=False) [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, 0, 0, 0, 1] 
 - gen()[source]¶
- Return the generator of the Drinfeld module. - 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.gen() == phi(T) 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)]) >>> phi.gen() == phi(T) True 
 - height()[source]¶
- Return the height of the Drinfeld module if the function field characteristic is a prime ideal; raise - ValueErrorotherwise.- The height of a Drinfeld module is defined when the function field characteristic is a prime ideal. In our case, this ideal is even generated by a monic polynomial \(\mathfrak{p}\) in the function field. Write \(\phi_\mathfrak{p} = a_s \tau^s + \dots + \tau^{r*\deg(\mathfrak{p})}\). The height of the Drinfeld module is the well-defined positive integer \(h = \frac{s}{\deg(\mathfrak{p})}\). - Note - See [Gos1998], Definition 4.5.8 for the general definition. - 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.height() == 1 True sage: phi.is_ordinary() 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)]) >>> phi.height() == Integer(1) True >>> phi.is_ordinary() True - sage: Fq = GF(343) sage: A.<T> = Fq[] sage: K.<z6> = Fq.extension(2) sage: phi = DrinfeldModule(A, [1, 0, z6]) sage: phi.height() 2 sage: phi.is_supersingular() True - >>> 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.height() 2 >>> phi.is_supersingular() True - In characteristic zero, height is not defined: - sage: L = A.fraction_field() sage: phi = DrinfeldModule(A, [L(T), L(1)]) sage: phi.height() Traceback (most recent call last): ... ValueError: height is only defined for prime function field characteristic - >>> from sage.all import * >>> L = A.fraction_field() >>> phi = DrinfeldModule(A, [L(T), L(Integer(1))]) >>> phi.height() Traceback (most recent call last): ... ValueError: height is only defined for prime function field characteristic 
 - hom(x, codomain=None)[source]¶
- Return the homomorphism defined by - xhaving this Drinfeld module as domain.- We recall that a homomorphism \(f : \phi \to \psi\) between two Drinfeld modules is defined by an Ore polynomial \(u\), which is subject to the relation \(phi_T u = u \psi_T\). - INPUT: - x– an element of the ring of functions, or an Ore polynomial
- codomain– a Drinfeld module or- None(default:- None)
 - EXAMPLES: - sage: Fq = GF(5) sage: A.<T> = Fq[] sage: K.<z> = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 0, 1, z]) sage: phi Drinfeld module defined by T |--> z*t^3 + t^2 + z - >>> from sage.all import * >>> Fq = GF(Integer(5)) >>> A = Fq['T']; (T,) = A._first_ngens(1) >>> K = Fq.extension(Integer(3), names=('z',)); (z,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [z, Integer(0), Integer(1), z]) >>> phi Drinfeld module defined by T |--> z*t^3 + t^2 + z - An important class of endomorphisms of a Drinfeld module \(\phi\) is given by scalar multiplications, that are endomorphisms corresponding to the Ore polynomials \(\phi_a\) with \(a\) in the function ring \(A\). We construct them as follows: - sage: phi.hom(T) Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z Defn: z*t^3 + t^2 + z - >>> from sage.all import * >>> phi.hom(T) Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z Defn: z*t^3 + t^2 + z - sage: phi.hom(T^2 + 1) Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z Defn: z^2*t^6 + (3*z^2 + z + 1)*t^5 + t^4 + 2*z^2*t^3 + (3*z^2 + z + 1)*t^2 + z^2 + 1 - >>> from sage.all import * >>> phi.hom(T**Integer(2) + Integer(1)) Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z Defn: z^2*t^6 + (3*z^2 + z + 1)*t^5 + t^4 + 2*z^2*t^3 + (3*z^2 + z + 1)*t^2 + z^2 + 1 - We can also define a morphism by passing in the Ore polynomial defining it. For example, below, we construct the Frobenius endomorphism of \(\phi\): - sage: t = phi.ore_variable() sage: phi.hom(t^3) Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z Defn: t^3 - >>> from sage.all import * >>> t = phi.ore_variable() >>> phi.hom(t**Integer(3)) Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z Defn: t^3 - If the input Ore polynomial defines a morphism to another Drinfeld module, the latter is determined automatically: - sage: phi.hom(t + 1) Drinfeld Module morphism: From: Drinfeld module defined by T |--> z*t^3 + t^2 + z To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^3 + (3*z^2 + 2*z + 2)*t^2 + (2*z^2 + 3*z + 4)*t + z Defn: t + 1 - >>> from sage.all import * >>> phi.hom(t + Integer(1)) Drinfeld Module morphism: From: Drinfeld module defined by T |--> z*t^3 + t^2 + z To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^3 + (3*z^2 + 2*z + 2)*t^2 + (2*z^2 + 3*z + 4)*t + z Defn: t + 1 
 - is_finite()[source]¶
- Return - Trueif this Drinfeld module is finite,- Falseotherwise.- 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.is_finite() True sage: B.<Y> = Fq[] sage: L = Frac(B) sage: psi = DrinfeldModule(A, [L(2), L(1)]) sage: psi.is_finite() False - >>> 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.is_finite() True >>> B = Fq['Y']; (Y,) = B._first_ngens(1) >>> L = Frac(B) >>> psi = DrinfeldModule(A, [L(Integer(2)), L(Integer(1))]) >>> psi.is_finite() False 
 - is_isomorphic(other, absolutely=False)[source]¶
- Return - Trueif this Drinfeld module is isomorphic to- other; return- Falseotherwise.- INPUT: - absolutely– a boolean (default:- False); if- False, check the existence of an isomorphism defined on the base field. If- True, check over an algebraic closure.
 - EXAMPLES: - sage: Fq = GF(5) sage: A.<T> = Fq[] sage: K.<z> = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 0, 1, z]) sage: t = phi.ore_variable() - >>> from sage.all import * >>> Fq = GF(Integer(5)) >>> A = Fq['T']; (T,) = A._first_ngens(1) >>> K = Fq.extension(Integer(3), names=('z',)); (z,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [z, Integer(0), Integer(1), z]) >>> t = phi.ore_variable() - We create a second Drinfeld module, which is isomorphic to \(\phi\) and then check that they are indeed isomorphic: - sage: psi = phi.velu(z) sage: phi.is_isomorphic(psi) True - >>> from sage.all import * >>> psi = phi.velu(z) >>> phi.is_isomorphic(psi) True - In the example below, \(\phi\) and \(\psi\) are isogenous but not isomorphic: - sage: psi = phi.velu(t + 1) sage: phi.is_isomorphic(psi) False - >>> from sage.all import * >>> psi = phi.velu(t + Integer(1)) >>> phi.is_isomorphic(psi) False - Here is an example of two Drinfeld modules which are isomorphic on an algebraic closure but not on the base field: - sage: phi = DrinfeldModule(A, [z, 1]) sage: psi = DrinfeldModule(A, [z, z]) sage: phi.is_isomorphic(psi) False sage: phi.is_isomorphic(psi, absolutely=True) True - >>> from sage.all import * >>> phi = DrinfeldModule(A, [z, Integer(1)]) >>> psi = DrinfeldModule(A, [z, z]) >>> phi.is_isomorphic(psi) False >>> phi.is_isomorphic(psi, absolutely=True) True - In particular, two Drinfeld modules may have the same \(j\)-invariant, while not being isomorphic on the base field: - sage: phi = DrinfeldModule(A, [z, 0, 1]) sage: psi = DrinfeldModule(A, [z, 0, z]) sage: phi.j_invariant() == psi.j_invariant() True sage: phi.is_isomorphic(psi) False sage: phi.is_isomorphic(psi, absolutely=True) True - >>> from sage.all import * >>> phi = DrinfeldModule(A, [z, Integer(0), Integer(1)]) >>> psi = DrinfeldModule(A, [z, Integer(0), z]) >>> phi.j_invariant() == psi.j_invariant() True >>> phi.is_isomorphic(psi) False >>> phi.is_isomorphic(psi, absolutely=True) True - On certain fields, testing isomorphisms over the base field may fail: - sage: L = A.fraction_field() sage: T = L.gen() sage: phi = DrinfeldModule(A, [T, 0, 1]) sage: psi = DrinfeldModule(A, [T, 0, T]) sage: psi.is_isomorphic(phi) Traceback (most recent call last): ... NotImplementedError: cannot solve the equation u^24 == T - >>> from sage.all import * >>> L = A.fraction_field() >>> T = L.gen() >>> phi = DrinfeldModule(A, [T, Integer(0), Integer(1)]) >>> psi = DrinfeldModule(A, [T, Integer(0), T]) >>> psi.is_isomorphic(phi) Traceback (most recent call last): ... NotImplementedError: cannot solve the equation u^24 == T - However, it never fails over the algebraic closure: - sage: psi.is_isomorphic(phi, absolutely=True) True - >>> from sage.all import * >>> psi.is_isomorphic(phi, absolutely=True) True - Note finally that when the constant coefficients of \(\phi_T\) and \(\psi_T\) differ, \(\phi\) and \(\psi\) do not belong to the same category and checking whether they are isomorphic does not make sense; in this case, an error is raised: - sage: phi = DrinfeldModule(A, [z, 0, 1]) sage: psi = DrinfeldModule(A, [z^2, 0, 1]) sage: phi.is_isomorphic(psi) Traceback (most recent call last): ... ValueError: Drinfeld modules are not in the same category - >>> from sage.all import * >>> phi = DrinfeldModule(A, [z, Integer(0), Integer(1)]) >>> psi = DrinfeldModule(A, [z**Integer(2), Integer(0), Integer(1)]) >>> phi.is_isomorphic(psi) Traceback (most recent call last): ... ValueError: Drinfeld modules are not in the same category 
 - j_invariant(parameter=None, check=True)[source]¶
- Return the \(j\)-invariant of the Drinfeld \(\mathbb{F}_q[T]\)-module for the given parameter. - Suppose that \(\phi_T = g_0 + g_1\tau + \cdots + g_r \tau^r\) with \(g_r \neq 0\). Then the \(((k_1, \ldots, k_n), (d_1, \ldots, d_n, d_r))\)-\(j\)-invariant of \(\phi\) is defined by \[j_{k_1, \ldots, k_n}^{d_1, \ldots, d_n, d_r}(\phi) := \frac{1}{g_r^{d_r}}\prod_{i = 1}^n g_{k_i}^{d_i}\]- where \(1\leqslant k_1 < k_2 < \ldots < k_n \leqslant r - 1\) and the integers \(d_i\) satisfy the weight-0 condition: \[d_1 (q^{k_1} - 1) + d_2 (q^{k_2} - 1) + \cdots + d_{n} (q^{k_n} - 1) = d_r (q^r - 1).\]- Furthermore, if \(\gcd(d_1,\ldots, d_n, d_r) = 1\) and \[0 \leq d_i \leq (q^r - 1)/(q^{\gcd(i, r)} - 1), \quad 1 \leq i \leq n,\]- then the \(j\)-invariant is called basic. See the method - basic_j_invariant_parameters()for computing the list of all basic \(j\)-invariant parameters.- Note - In [Pap2023], Papikian follows a slightly different convention: - His \(j\)-invariants (see Definition 3.8.7) correspond to our basic \(j\)-invariants, as defined above. 
- His basic \(j\)-invariant (see Example 3.8.10) correspond to our \(j_k\)-invariants, as implemented in - jk_invariants().
 - We chose to follow Potemine’s convention, as he introduced those objects in [Pot1998]. Theorem 2.2 of [Pot1998] or Theorem 3.8.11 of [Pap2023] assert that two Drinfeld \(\mathbb F_q[T]\)-modules over \(K\) are isomorphic over the separable closure of \(K\) if and only if their basic \(j\)-invariants (as implemented here) coincide for any well-defined couple of tuples \(((k_1, k_2, \ldots, k_n), (d_1, d_2, \ldots, d_n, d_r))\), . - INPUT: - parameter– tuple or list, integer or NoneType (default:- None); the \(j\)-invariant parameter:- If - parameteris a list or a tuple, then it must be of the form: \(((k_1, k_2, \ldots, k_n), (d_1, d_2, \ldots, d_n, d_r))\), where the \(k_i\) and \(d_i\) are integers satisfying the weight-0 condition described above.
- If - parameteris an integer \(k\) then the method returns the- j-invariant associated to the parameter \(((k,), (d_k, d_r))\);
- If - parameteris- Noneand the rank of the Drinfeld module is 2, then the method returns its usual \(j\)-invariant, that is the \(j\)-invariant for the parameter \(((1,), (q+1, 1))\).
 
- check– boolean (default:- True); if this flag is set to- Falsethen the code will not check if the given parameter is valid and satisfy the weight-0 condition.
 - OUTPUT: the \(j\)-invariant of - selffor the given parameter- 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.j_invariant() z12^10 + 4*z12^9 + 3*z12^8 + 2*z12^7 + 3*z12^6 + z12^5 + z12^3 + 4*z12^2 + z12 + 2 sage: psi = DrinfeldModule(A, [p_root, 1, 1]) sage: psi.j_invariant() 1 sage: rho = DrinfeldModule(A, [p_root, 0, 1]) sage: rho.j_invariant() 0 - >>> 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.j_invariant() z12^10 + 4*z12^9 + 3*z12^8 + 2*z12^7 + 3*z12^6 + z12^5 + z12^3 + 4*z12^2 + z12 + 2 >>> psi = DrinfeldModule(A, [p_root, Integer(1), Integer(1)]) >>> psi.j_invariant() 1 >>> rho = DrinfeldModule(A, [p_root, Integer(0), Integer(1)]) >>> rho.j_invariant() 0 - sage: A = GF(5)['T'] sage: K.<T> = Frac(A) sage: phi = DrinfeldModule(A, [T, T^2, 1, T + 1, T^3]) sage: phi.j_invariant(1) T^309 sage: phi.j_invariant(2) 1/T^3 sage: phi.j_invariant(3) (T^156 + T^155 + T^151 + T^150 + T^131 + T^130 + T^126 + T^125 + T^31 + T^30 + T^26 + T^25 + T^6 + T^5 + T + 1)/T^93 - >>> from sage.all import * >>> A = GF(Integer(5))['T'] >>> K = Frac(A, names=('T',)); (T,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [T, T**Integer(2), Integer(1), T + Integer(1), T**Integer(3)]) >>> phi.j_invariant(Integer(1)) T^309 >>> phi.j_invariant(Integer(2)) 1/T^3 >>> phi.j_invariant(Integer(3)) (T^156 + T^155 + T^151 + T^150 + T^131 + T^130 + T^126 + T^125 + T^31 + T^30 + T^26 + T^25 + T^6 + T^5 + T + 1)/T^93 - The parameter can either be a tuple or a list: - sage: Fq.<a> = GF(7) sage: A.<T> = Fq[] sage: phi = DrinfeldModule(A, [a, a^2 + a, 0, 3*a, a^2+1]) sage: J = phi.j_invariant(((1, 3), (267, 269, 39))); J 5 sage: J == (phi.coefficient(1)**267)*(phi.coefficient(3)**269)/(phi.coefficient(4)**39) True sage: phi.j_invariant([[3], [400, 57]]) 4 sage: phi.j_invariant([[3], [400, 57]]) == phi.j_invariant(3) True - >>> from sage.all import * >>> Fq = GF(Integer(7), names=('a',)); (a,) = Fq._first_ngens(1) >>> A = Fq['T']; (T,) = A._first_ngens(1) >>> phi = DrinfeldModule(A, [a, a**Integer(2) + a, Integer(0), Integer(3)*a, a**Integer(2)+Integer(1)]) >>> J = phi.j_invariant(((Integer(1), Integer(3)), (Integer(267), Integer(269), Integer(39)))); J 5 >>> J == (phi.coefficient(Integer(1))**Integer(267))*(phi.coefficient(Integer(3))**Integer(269))/(phi.coefficient(Integer(4))**Integer(39)) True >>> phi.j_invariant([[Integer(3)], [Integer(400), Integer(57)]]) 4 >>> phi.j_invariant([[Integer(3)], [Integer(400), Integer(57)]]) == phi.j_invariant(Integer(3)) True - The list of all basic \(j\)-invariant parameters can be retrieved using the method - basic_j_invariant_parameters():- sage: A = GF(3)['T'] sage: K.<T> = Frac(A) sage: phi = DrinfeldModule(A, [T, T^2 + T + 1, 0, T^4 + 1, T - 1]) sage: param = phi.basic_j_invariant_parameters(nonzero=True) sage: phi.j_invariant(param[1]) T^13 + 2*T^12 + T + 2 sage: phi.j_invariant(param[2]) T^35 + 2*T^31 + T^27 + 2*T^8 + T^4 + 2 - >>> from sage.all import * >>> A = GF(Integer(3))['T'] >>> K = Frac(A, names=('T',)); (T,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [T, T**Integer(2) + T + Integer(1), Integer(0), T**Integer(4) + Integer(1), T - Integer(1)]) >>> param = phi.basic_j_invariant_parameters(nonzero=True) >>> phi.j_invariant(param[Integer(1)]) T^13 + 2*T^12 + T + 2 >>> phi.j_invariant(param[Integer(2)]) T^35 + 2*T^31 + T^27 + 2*T^8 + T^4 + 2 
 - jk_invariants()[source]¶
- Return a dictionary whose keys are all the integers \(1 \leqslant k \leqslant r-1\) and the values are the corresponding \(j_k\)-invariants - Recall that the \(j_k\)-invariant of - selfis defined by:\[j_k := \frac{g_k^{(q^r - 1)/(\mathrm{gcd}(k, r) - 1)}}{g_r^{(q^k - 1)/(\mathrm{gcd}(k, r) - 1)}}\]- where \(g_i\) is the \(i\)-th coefficient of the generator of - self.- EXAMPLES: - sage: A = GF(3)['T'] sage: K.<T> = Frac(A) sage: phi = DrinfeldModule(A, [T, 1, T+1, T^3, T^6]) sage: jk_inv = phi.jk_invariants(); jk_inv {1: 1/T^6, 2: (T^10 + T^9 + T + 1)/T^6, 3: T^42} sage: jk_inv[2] (T^10 + T^9 + T + 1)/T^6 - >>> from sage.all import * >>> A = GF(Integer(3))['T'] >>> K = Frac(A, names=('T',)); (T,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [T, Integer(1), T+Integer(1), T**Integer(3), T**Integer(6)]) >>> jk_inv = phi.jk_invariants(); jk_inv {1: 1/T^6, 2: (T^10 + T^9 + T + 1)/T^6, 3: T^42} >>> jk_inv[Integer(2)] (T^10 + T^9 + T + 1)/T^6 - sage: F = GF(7**2) sage: A = F['T'] sage: E.<z> = F.extension(4) sage: phi = DrinfeldModule(A, [z^2, 1, z+1, z^2, z, z+1]) sage: phi.jk_invariants() {1: 5*z^7 + 2*z^6 + 5*z^5 + 2*z^4 + 5*z^3 + z^2 + z + 2, 2: 3*z^7 + 4*z^6 + 5*z^5 + 6*z^4 + 4*z, 3: 5*z^7 + 6*z^6 + 6*z^5 + 4*z^3 + z^2 + 2*z + 1, 4: 3*z^6 + 2*z^5 + 4*z^4 + 2*z^3 + 4*z^2 + 6*z + 2} - >>> from sage.all import * >>> F = GF(Integer(7)**Integer(2)) >>> A = F['T'] >>> E = F.extension(Integer(4), names=('z',)); (z,) = E._first_ngens(1) >>> phi = DrinfeldModule(A, [z**Integer(2), Integer(1), z+Integer(1), z**Integer(2), z, z+Integer(1)]) >>> phi.jk_invariants() {1: 5*z^7 + 2*z^6 + 5*z^5 + 2*z^4 + 5*z^3 + z^2 + z + 2, 2: 3*z^7 + 4*z^6 + 5*z^5 + 6*z^4 + 4*z, 3: 5*z^7 + 6*z^6 + 6*z^5 + 4*z^3 + z^2 + 2*z + 1, 4: 3*z^6 + 2*z^5 + 4*z^4 + 2*z^3 + 4*z^2 + 6*z + 2} 
 - morphism()[source]¶
- Return the morphism object that defines the Drinfeld module. - OUTPUT: a ring morphism from the function ring to the Ore polynomial ring - 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.morphism() Ring morphism: From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 To: Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 over its base twisted by Frob^2 Defn: T |--> z12^5*t^2 + z12^3*t + 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: from sage.rings.morphism import RingHomomorphism sage: isinstance(phi.morphism(), RingHomomorphism) 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)]) >>> phi.morphism() Ring morphism: From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 To: Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 over its base twisted by Frob^2 Defn: T |--> z12^5*t^2 + z12^3*t + 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 >>> from sage.rings.morphism import RingHomomorphism >>> isinstance(phi.morphism(), RingHomomorphism) True - Actually, the - DrinfeldModulemethod- __call__()simply class the- __call__method of this morphism:- sage: phi.morphism()(T) == phi(T) True sage: a = A.random_element() sage: phi.morphism()(a) == phi(a) True - >>> from sage.all import * >>> phi.morphism()(T) == phi(T) True >>> a = A.random_element() >>> phi.morphism()(a) == phi(a) True - And many methods of the Drinfeld module have a counterpart in the morphism object: - sage: m = phi.morphism() sage: m.domain() is phi.function_ring() True sage: m.codomain() is phi.ore_polring() True sage: m.im_gens() [z12^5*t^2 + z12^3*t + 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(T) == m.im_gens()[0] True - >>> from sage.all import * >>> m = phi.morphism() >>> m.domain() is phi.function_ring() True >>> m.codomain() is phi.ore_polring() True >>> m.im_gens() [z12^5*t^2 + z12^3*t + 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] >>> phi(T) == m.im_gens()[Integer(0)] True 
 - rank()[source]¶
- Return the rank of the Drinfeld module. - In our case, the rank is the degree of the generator. - OUTPUT: integer - 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.rank() 2 sage: psi = DrinfeldModule(A, [p_root, 2]) sage: psi.rank() 1 sage: rho = DrinfeldModule(A, [p_root, 0, 0, 0, 1]) sage: rho.rank() 4 - >>> 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.rank() 2 >>> psi = DrinfeldModule(A, [p_root, Integer(2)]) >>> psi.rank() 1 >>> rho = DrinfeldModule(A, [p_root, Integer(0), Integer(0), Integer(0), Integer(1)]) >>> rho.rank() 4 
 - scalar_multiplication(x)[source]¶
- Return the endomorphism of this Drinfeld module, which is the multiplication by \(x\), i.e. the isogeny defined by the Ore polynomial \(\phi_x\). - INPUT: - x– an element in the ring of functions
 - EXAMPLES: - sage: Fq = GF(5) sage: A.<T> = Fq[] sage: K.<z> = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 0, 1, z]) sage: phi Drinfeld module defined by T |--> z*t^3 + t^2 + z sage: phi.hom(T) # indirect doctest Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z Defn: z*t^3 + t^2 + z - >>> from sage.all import * >>> Fq = GF(Integer(5)) >>> A = Fq['T']; (T,) = A._first_ngens(1) >>> K = Fq.extension(Integer(3), names=('z',)); (z,) = K._first_ngens(1) >>> phi = DrinfeldModule(A, [z, Integer(0), Integer(1), z]) >>> phi Drinfeld module defined by T |--> z*t^3 + t^2 + z >>> phi.hom(T) # indirect doctest Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z Defn: z*t^3 + t^2 + z - sage: phi.hom(T^2 + 1) Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z Defn: z^2*t^6 + (3*z^2 + z + 1)*t^5 + t^4 + 2*z^2*t^3 + (3*z^2 + z + 1)*t^2 + z^2 + 1 - >>> from sage.all import * >>> phi.hom(T**Integer(2) + Integer(1)) Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z Defn: z^2*t^6 + (3*z^2 + z + 1)*t^5 + t^4 + 2*z^2*t^3 + (3*z^2 + z + 1)*t^2 + z^2 + 1 
 - velu(isog)[source]¶
- Return a new Drinfeld module such that - isogdefines an isogeny to this module with domain- self; if no such isogeny exists, raise an exception.- INPUT: - isog– the Ore polynomial that defines the isogeny
 - OUTPUT: a Drinfeld module - ALGORITHM: - The input defines an isogeny if only if: - 1. The degree of the characteristic divides the height of the input. (The height of an Ore polynomial \(P(\tau)\) is the maximum \(n\) such that \(\tau^n\) right-divides \(P(\tau)\).) - 2. The input right-divides the generator, which can be tested with Euclidean division. - We test if the input is an isogeny, and, if it is, we return the quotient of the Euclidean division. - Height and Euclidean division of Ore polynomials are implemented as methods of class - sage.rings.polynomial.ore_polynomial_element.OrePolynomial.- Another possible algorithm is to recursively solve a system, see arXiv 2203.06970, Eq. 1.1. - 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: t = phi.ore_polring().gen() sage: isog = t + 2*z12^11 + 4*z12^9 + 2*z12^8 + 2*z12^6 + 3*z12^5 + z12^4 + 2*z12^3 + 4*z12^2 + 4*z12 + 4 sage: psi = phi.velu(isog) sage: psi Drinfeld module defined by T |--> (z12^11 + 3*z12^10 + z12^9 + z12^7 + z12^5 + 4*z12^4 + 4*z12^3 + z12^2 + 1)*t^2 + (2*z12^11 + 4*z12^10 + 2*z12^8 + z12^6 + 3*z12^5 + z12^4 + 2*z12^3 + z12^2 + z12 + 4)*t + 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: isog in Hom(phi, psi) 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)]) >>> t = phi.ore_polring().gen() >>> isog = t + Integer(2)*z12**Integer(11) + Integer(4)*z12**Integer(9) + Integer(2)*z12**Integer(8) + Integer(2)*z12**Integer(6) + Integer(3)*z12**Integer(5) + z12**Integer(4) + Integer(2)*z12**Integer(3) + Integer(4)*z12**Integer(2) + Integer(4)*z12 + Integer(4) >>> psi = phi.velu(isog) >>> psi Drinfeld module defined by T |--> (z12^11 + 3*z12^10 + z12^9 + z12^7 + z12^5 + 4*z12^4 + 4*z12^3 + z12^2 + 1)*t^2 + (2*z12^11 + 4*z12^10 + 2*z12^8 + z12^6 + 3*z12^5 + z12^4 + 2*z12^3 + z12^2 + z12 + 4)*t + 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 >>> isog in Hom(phi, psi) True - This method works for endomorphisms as well: - sage: phi.velu(phi(T)) is phi True sage: phi.velu(t^6) is phi True - >>> from sage.all import * >>> phi.velu(phi(T)) is phi True >>> phi.velu(t**Integer(6)) is phi True - The following inputs do not define isogenies, and the method returns - None:- sage: phi.velu(0) Traceback (most recent call last): ... ValueError: the input does not define an isogeny sage: phi.velu(t) Traceback (most recent call last): ... ValueError: the input does not define an isogeny sage: phi.velu(t^3 + t + 2) Traceback (most recent call last): ... ValueError: the input does not define an isogeny - >>> from sage.all import * >>> phi.velu(Integer(0)) Traceback (most recent call last): ... ValueError: the input does not define an isogeny >>> phi.velu(t) Traceback (most recent call last): ... ValueError: the input does not define an isogeny >>> phi.velu(t**Integer(3) + t + Integer(2)) Traceback (most recent call last): ... ValueError: the input does not define an isogeny