diff --git a/src/sage/categories/drinfeld_modules.py b/src/sage/categories/drinfeld_modules.py index 95b7f67c8e0..5ae21d57657 100644 --- a/src/sage/categories/drinfeld_modules.py +++ b/src/sage/categories/drinfeld_modules.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # sage_setup: distribution = sagemath-categories # sage.doctest: needs sage.rings.finite_rings r""" @@ -123,7 +124,7 @@ class DrinfeldModules(Category_over_base_ring): True sage: C.ore_polring() - Ore Polynomial Ring in t over Finite Field in z of size 11^4 twisted by z |--> z^11 + Ore Polynomial Ring in τ over Finite Field in z of size 11^4 twisted by z |--> z^11 sage: C.ore_polring() is phi.ore_polring() True @@ -135,7 +136,7 @@ class DrinfeldModules(Category_over_base_ring): sage: psi = C.object([p_root, 1]) sage: psi - Drinfeld module defined by T |--> t + z^3 + 7*z^2 + 6*z + 10 + Drinfeld module defined by T |--> τ + z^3 + 7*z^2 + 6*z + 10 sage: psi.category() is C True @@ -207,7 +208,7 @@ class DrinfeldModules(Category_over_base_ring): TypeError: function ring base must be a finite field """ - def __init__(self, base_morphism, name='t'): + def __init__(self, base_morphism, name='τ'): r""" Initialize ``self``. @@ -216,7 +217,7 @@ def __init__(self, base_morphism, name='t'): - ``base_field`` -- the base field, which is a ring extension over a base - - ``name`` -- (default: ``'t'``) the name of the Ore polynomial + - ``name`` -- (default: ``'τ'``) the name of the Ore polynomial variable TESTS:: @@ -227,7 +228,7 @@ def __init__(self, base_morphism, name='t'): sage: p_root = z^3 + 7*z^2 + 6*z + 10 sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) sage: C = phi.category() - sage: ore_polring. = OrePolynomialRing(K, K.frobenius_endomorphism()) + sage: ore_polring.<τ> = OrePolynomialRing(K, K.frobenius_endomorphism()) sage: C._ore_polring is ore_polring True sage: C._function_ring is A @@ -438,7 +439,7 @@ def characteristic(self): :: - sage: psi = DrinfeldModule(A, [Frac(A).gen(), 1]) + sage: psi = DrinfeldModule(A, [T, 1]) sage: C = psi.category() sage: C.characteristic() 0 @@ -507,7 +508,7 @@ def object(self, gen): sage: phi = C.object([p_root, 0, 1]) sage: phi - Drinfeld module defined by T |--> t^2 + z^3 + 7*z^2 + 6*z + 10 + Drinfeld module defined by T |--> τ^2 + z^3 + 7*z^2 + 6*z + 10 sage: t = phi.ore_polring().gen() sage: C.object(t^2 + z^3 + 7*z^2 + 6*z + 10) is phi True @@ -534,7 +535,7 @@ def ore_polring(self): sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) sage: C = phi.category() sage: C.ore_polring() - Ore Polynomial Ring in t over Finite Field in z of size 11^4 twisted by z |--> z^11 + Ore Polynomial Ring in τ over Finite Field in z of size 11^4 twisted by z |--> z^11 """ return self._ore_polring @@ -639,7 +640,7 @@ def base(self): The base can be infinite:: - sage: sigma = DrinfeldModule(A, [Frac(A).gen(), 1]) + sage: sigma = DrinfeldModule(A, [T, 1]) sage: sigma.base() Fraction Field of Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 over its base """ @@ -664,7 +665,7 @@ def base_morphism(self): The base field can be infinite:: - sage: sigma = DrinfeldModule(A, [Frac(A).gen(), 1]) + sage: sigma = DrinfeldModule(A, [T, 1]) sage: sigma.base_morphism() Coercion map: From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 @@ -711,8 +712,7 @@ def characteristic(self): :: sage: B. = Fq[] - sage: L = Frac(B) - sage: psi = DrinfeldModule(A, [L(1), 0, 0, L(1)]) + sage: psi = DrinfeldModule(A, [B(1), 0, 0, 1]) sage: psi.characteristic() Traceback (most recent call last): ... @@ -770,7 +770,7 @@ def constant_coefficient(self): sage: t = phi.ore_polring().gen() sage: psi = C.object(phi.constant_coefficient() + t^3) sage: psi - Drinfeld module defined by T |--> t^3 + 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 + Drinfeld module defined by T |--> τ^3 + 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 Reciprocally, it is impossible to create two Drinfeld modules in this category if they do not share the same constant @@ -796,7 +796,7 @@ def ore_polring(self): sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) sage: S = phi.ore_polring() sage: S - Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 twisted by z12 |--> z12^(5^2) + Ore Polynomial Ring in τ over Finite Field in z12 of size 5^12 twisted by z12 |--> z12^(5^2) The Ore polynomial ring can also be retrieved from the category of the Drinfeld module:: @@ -825,8 +825,8 @@ def ore_variable(self): sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) sage: phi.ore_polring() - Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 twisted by z12 |--> z12^(5^2) + Ore Polynomial Ring in τ over Finite Field in z12 of size 5^12 twisted by z12 |--> z12^(5^2) sage: phi.ore_variable() - t + τ """ return self.category().ore_polring().gen() diff --git a/src/sage/rings/function_field/all.py b/src/sage/rings/function_field/all.py index b423a0d58f5..459ad867b0d 100644 --- a/src/sage/rings/function_field/all.py +++ b/src/sage/rings/function_field/all.py @@ -3,3 +3,6 @@ from sage.misc.lazy_import import lazy_import lazy_import("sage.rings.function_field.drinfeld_modules.drinfeld_module", "DrinfeldModule") +lazy_import("sage.rings.function_field.drinfeld_modules.carlitz_module", "CarlitzModule") +lazy_import("sage.rings.function_field.drinfeld_modules.carlitz_module", "carlitz_exponential") +lazy_import("sage.rings.function_field.drinfeld_modules.carlitz_module", "carlitz_logarithm") diff --git a/src/sage/rings/function_field/drinfeld_modules/action.py b/src/sage/rings/function_field/drinfeld_modules/action.py index 4962162424e..06f8897326d 100644 --- a/src/sage/rings/function_field/drinfeld_modules/action.py +++ b/src/sage/rings/function_field/drinfeld_modules/action.py @@ -60,7 +60,7 @@ class DrinfeldModuleAction(Action): sage: action = phi.action() sage: action Action on Finite Field in z of size 11^2 over its base - induced by Drinfeld module defined by T |--> t^3 + z + induced by Drinfeld module defined by T |--> τ^3 + z The action on elements is computed as follows:: @@ -154,7 +154,7 @@ def _latex_(self): sage: phi = DrinfeldModule(A, [z, 0, 0, 1]) sage: action = phi.action() sage: latex(action) - \text{Action{ }on{ }}\Bold{F}_{11^{2}}\text{{ }induced{ }by{ }}\phi: T \mapsto t^{3} + z + \text{Action{ }on{ }}\Bold{F}_{11^{2}}\text{{ }induced{ }by{ }}\phi: T \mapsto τ^{3} + z """ return f'\\text{{Action{{ }}on{{ }}}}' \ f'{latex(self._base)}\\text{{{{ }}' \ @@ -174,7 +174,7 @@ def _repr_(self): sage: phi = DrinfeldModule(A, [z, 0, 0, 1]) sage: action = phi.action() sage: action - Action on Finite Field in z of size 11^2 over its base induced by Drinfeld module defined by T |--> t^3 + z + Action on Finite Field in z of size 11^2 over its base induced by Drinfeld module defined by T |--> τ^3 + z """ return f'Action on {self._base} induced by ' \ f'{self._drinfeld_module}' diff --git a/src/sage/rings/function_field/drinfeld_modules/carlitz_module.py b/src/sage/rings/function_field/drinfeld_modules/carlitz_module.py new file mode 100644 index 00000000000..efac57955f2 --- /dev/null +++ b/src/sage/rings/function_field/drinfeld_modules/carlitz_module.py @@ -0,0 +1,197 @@ +r""" +Carlitz module + +AUTHORS: + +- Xavier Caruso (2025-07): initial version +""" + +# ***************************************************************************** +# Copyright (C) 2025 Xavier Caruso +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.structure.parent import Parent +from sage.structure.element import Element +from sage.categories.finite_fields import FiniteFields + +from sage.rings.infinity import Infinity + +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic +from sage.rings.function_field.drinfeld_modules.drinfeld_module import DrinfeldModule + + +def CarlitzModule(A, base=None): + r""" + Return the Carlitz module over `A`. + + INPUT: + + - ``A`` -- a polynomial ring over a finite field + + - ``base`` -- a field, an element in a field or a + string (default: the fraction field of ``A``) + + EXAMPLES:: + + sage: Fq = GF(7) + sage: A. = Fq[] + sage: CarlitzModule(A) + Drinfeld module defined by T |--> τ + T + + We can specify a different base. + This is interesting for instance for having two different variable + names:: + + sage: R. = Fq[] + sage: CarlitzModule(A, R) + Drinfeld module defined by T |--> τ + z + + One can even use the following shortcut, which avoids the + construction of `R`:: + + sage: CarlitzModule(A, 'z') + Drinfeld module defined by T |--> τ + z + + Using a similar syntax, we can construct the reduction of the + Carlitz module modulo primes:: + + sage: F. = Fq.extension(z^2 + 1) + sage: CarlitzModule(A, F) + Drinfeld module defined by T |--> τ + a + + It is also possible to pass in any element in the base field + (in this case, the result might not be strictly speaking the + Carlitz module, but it is always a Drinfeld module of rank 1):: + + sage: CarlitzModule(A, z^2) + Drinfeld module defined by T |--> τ + z^2 + + TESTS:: + + sage: CarlitzModule(Fq) + Traceback (most recent call last): + ... + TypeError: the function ring must be defined over a finite field + + :: + + sage: S. = QQ[] + sage: CarlitzModule(A, S) + Traceback (most recent call last): + ... + ValueError: function ring base must coerce into base field + """ + if (not isinstance(A, PolynomialRing_generic) + or A.base_ring() not in FiniteFields()): + raise TypeError('the function ring must be defined over a finite field') + if base is None: + K = A.fraction_field() + z = K.gen() + elif isinstance(base, Parent): + if base.has_coerce_map_from(A): + z = base(A.gen()) + else: + z = base.gen() + elif isinstance(base, Element): + z = base + elif isinstance(base, str): + K = A.base_ring()[base] + z = K.gen() + else: + raise ValueError("cannot construct a Carlitz module from the given data") + return DrinfeldModule(A, [z, 1]) + + +def carlitz_exponential(A, prec=+Infinity, name='z'): + r""" + Return the Carlitz exponential attached the ring `A`. + + INPUT: + + - ``prec`` -- an integer or ``Infinity`` (default: ``Infinity``); + the precision at which the series is returned; if ``Infinity``, + a lazy power series in returned, else, a classical power series + is returned. + + - ``name`` -- string (default: ``'z'``); the name of the + generator of the lazy power series ring + + EXAMPLES:: + + sage: A. = GF(2)[] + + When ``prec`` is ``Infinity`` (which is the default), + the exponential is returned as a lazy power series, meaning + that any of its coefficients can be computed on demands:: + + sage: exp = carlitz_exponential(A) + sage: exp + z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8) + sage: exp[2^4] + 1/(T^64 + T^56 + T^52 + ... + T^27 + T^23 + T^15) + sage: exp[2^5] + 1/(T^160 + T^144 + T^136 + ... + T^55 + T^47 + T^31) + + On the contrary, when ``prec`` is a finite number, all the + required coefficients are computed at once:: + + sage: carlitz_exponential(A, prec=10) + z + (1/(T^2 + T))*z^2 + (1/(T^8 + T^6 + T^5 + T^3))*z^4 + (1/(T^24 + T^20 + T^18 + T^17 + T^14 + T^13 + T^11 + T^7))*z^8 + O(z^10) + + We check that the Carlitz exponential is the compositional inverse + of the Carlitz logarithm:: + + sage: log = carlitz_logarithm(A) + sage: exp(log) + z + O(z^8) + sage: log(exp) + z + O(z^8) + """ + C = CarlitzModule(A) + return C.exponential(prec, name) + + +def carlitz_logarithm(A, prec=+Infinity, name='z'): + r""" + Return the Carlitz exponential attached the ring `A`. + + INPUT: + + - ``prec`` -- an integer or ``Infinity`` (default: ``Infinity``); + the precision at which the series is returned; if ``Infinity``, + a lazy power series in returned, else, a classical power series + is returned. + + - ``name`` -- string (default: ``'z'``); the name of the + generator of the lazy power series ring + + EXAMPLES:: + + sage: A. = GF(2)[] + + When ``prec`` is ``Infinity`` (which is the default), + the exponential is returned as a lazy power series, meaning + that any of its coefficients can be computed on demands:: + + sage: log = carlitz_logarithm(A) + sage: log + z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8) + sage: log[2^4] + 1/(T^30 + T^29 + T^27 + ... + T^7 + T^5 + T^4) + sage: log[2^5] + 1/(T^62 + T^61 + T^59 + ... + T^8 + T^6 + T^5) + + On the contrary, when ``prec`` is a finite number, all the + required coefficients are computed at once:: + + sage: carlitz_logarithm(A, prec=10) + z + (1/(T^2 + T))*z^2 + (1/(T^6 + T^5 + T^3 + T^2))*z^4 + (1/(T^14 + T^13 + T^11 + T^10 + T^7 + T^6 + T^4 + T^3))*z^8 + O(z^10) + """ + C = CarlitzModule(A) + return C.logarithm(prec, name) diff --git a/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py index 594f8645ae1..0a1a4389cec 100644 --- a/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py @@ -56,11 +56,10 @@ class DrinfeldModule_charzero(DrinfeldModule): responsible for instantiating the right class depending on the input:: - sage: A = GF(3)['T'] - sage: K. = Frac(A) + sage: A. = GF(3)[] sage: phi = DrinfeldModule(A, [T, 1]) sage: phi - Drinfeld module defined by T |--> t + T + Drinfeld module defined by T |--> τ + T :: @@ -75,8 +74,7 @@ class DrinfeldModule_charzero(DrinfeldModule): It is possible to calculate the logarithm and the exponential of any Drinfeld modules of characteristic zero:: - sage: A = GF(2)['T'] - sage: K. = Frac(A) + sage: A. = GF(2)[] sage: phi = DrinfeldModule(A, [T, 1]) sage: phi.exponential() z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8) @@ -89,8 +87,7 @@ class DrinfeldModule_charzero(DrinfeldModule): analytic theory of Drinfeld module. They provide a function field analogue of certain classical trigonometric functions:: - sage: A = GF(2)['T'] - sage: K. = Frac(A) + sage: A. = GF(2)[] sage: phi = DrinfeldModule(A, [T, 1]) sage: phi.goss_polynomial(1) X @@ -110,7 +107,7 @@ class DrinfeldModule_charzero(DrinfeldModule): sage: L. = LaurentSeriesRing(GF(2)) # s = 1/T sage: phi = DrinfeldModule(A, [1/s, s + s^2 + s^5 + O(s^6), 1+1/s]) sage: phi(T) - (s^-1 + 1)*t^2 + (s + s^2 + s^5 + O(s^6))*t + s^-1 + (s^-1 + 1)*τ^2 + (s + s^2 + s^5 + O(s^6))*τ + s^-1 One can also construct Drinfeld modules over SageMath's global function fields:: @@ -119,7 +116,7 @@ class DrinfeldModule_charzero(DrinfeldModule): sage: K. = FunctionField(GF(5)) # z = T sage: phi = DrinfeldModule(A, [z, 1, z^2]) sage: phi(T) - z^2*t^2 + t + z + z^2*τ^2 + τ + z """ @cached_method def _compute_coefficient_exp(self, k): @@ -133,8 +130,7 @@ def _compute_coefficient_exp(self, k): TESTS:: - sage: A = GF(2)['T'] - sage: K. = Frac(A) + sage: A. = GF(2)[] sage: phi = DrinfeldModule(A, [T, 1]) sage: q = A.base_ring().cardinality() sage: phi._compute_coefficient_exp(0) @@ -175,8 +171,7 @@ def exponential(self, prec=Infinity, name='z'): EXAMPLES:: - sage: A = GF(2)['T'] - sage: K. = Frac(A) + sage: A. = GF(2)[] sage: phi = DrinfeldModule(A, [T, 1]) sage: q = A.base_ring().cardinality() @@ -199,8 +194,7 @@ def exponential(self, prec=Infinity, name='z'): Example in higher rank:: - sage: A = GF(5)['T'] - sage: K. = Frac(A) + sage: A. = GF(5)[] sage: phi = DrinfeldModule(A, [T, T^2, T + T^2 + T^4, 1]) sage: exp = phi.exponential(); exp z + ((T/(T^4+4))*z^5) + O(z^8) @@ -217,8 +211,7 @@ def exponential(self, prec=Infinity, name='z'): TESTS:: - sage: A = GF(2)['T'] - sage: K. = Frac(A) + sage: A. = GF(2)[] sage: phi = DrinfeldModule(A, [T, 1]) sage: exp = phi.exponential() sage: exp[2] == 1/(T**q - T) # expected value @@ -259,8 +252,7 @@ def _compute_coefficient_log(self, k): TESTS:: - sage: A = GF(2)['T'] - sage: K. = Frac(A) + sage: A. = GF(2)[] sage: phi = DrinfeldModule(A, [T, 1]) sage: q = A.base_ring().cardinality() sage: phi._compute_coefficient_log(0) @@ -305,8 +297,7 @@ def logarithm(self, prec=Infinity, name='z'): EXAMPLES:: - sage: A = GF(2)['T'] - sage: K. = Frac(A) + sage: A. = GF(2)[] sage: phi = DrinfeldModule(A, [T, 1]) When ``prec`` is ``Infinity`` (which is the default), @@ -328,16 +319,14 @@ def logarithm(self, prec=Infinity, name='z'): Example in higher rank:: - sage: A = GF(5)['T'] - sage: K. = Frac(A) + sage: A. = GF(5)[] sage: phi = DrinfeldModule(A, [T, T^2, T + T^2 + T^4, 1]) sage: phi.logarithm() z + ((4*T/(T^4+4))*z^5) + O(z^8) TESTS:: - sage: A = GF(2)['T'] - sage: K. = Frac(A) + sage: A. = GF(2)[] sage: phi = DrinfeldModule(A, [T, 1]) sage: q = 2 sage: log[2] == -1/((T**q - T)) # expected value @@ -374,8 +363,7 @@ def _compute_goss_polynomial(self, n, q, poly_ring, X): TESTS:: - sage: A = GF(2^2)['T'] - sage: K. = Frac(A) + sage: A. = GF(2^2)[] sage: phi = DrinfeldModule(A, [T, T+1, T^2, 1]) sage: poly_ring = phi.base()['X'] sage: X = poly_ring.gen() @@ -423,8 +411,7 @@ def goss_polynomial(self, n, var='X'): EXAMPLES:: - sage: A = GF(3)['T'] - sage: K. = Frac(A) + sage: A. = GF(3)[] sage: phi = DrinfeldModule(A, [T, 1]) # Carlitz module sage: phi.goss_polynomial(1) X @@ -459,10 +446,9 @@ class DrinfeldModule_rational(DrinfeldModule_charzero): sage: q = 9 sage: Fq = GF(q) - sage: A = Fq['T'] - sage: K. = Frac(A) + sage: A. = Fq[] sage: C = DrinfeldModule(A, [T, 1]); C - Drinfeld module defined by T |--> t + T + Drinfeld module defined by T |--> τ + T sage: type(C) """ @@ -479,9 +465,8 @@ def coefficient_in_function_ring(self, n): sage: q = 5 sage: Fq = GF(q) - sage: A = Fq['T'] - sage: R = Fq['U'] - sage: K. = Frac(R) + sage: A. = Fq[] + sage: R. = Fq[] sage: phi = DrinfeldModule(A, [U, 0, U^2, U^3]) sage: phi.coefficient_in_function_ring(2) T^2 @@ -524,9 +509,8 @@ def coefficients_in_function_ring(self, sparse=True): sage: q = 5 sage: Fq = GF(q) - sage: A = Fq['T'] - sage: R = Fq['U'] - sage: K. = Frac(R) + sage: A. = Fq[] + sage: R. = Fq[] sage: phi = DrinfeldModule(A, [U, 0, U^2, U^3]) sage: phi.coefficients_in_function_ring() [T, T^2, T^3] @@ -570,10 +554,9 @@ def class_polynomial(self): sage: q = 5 sage: Fq = GF(q) - sage: A = Fq['T'] - sage: K. = Frac(A) + sage: A. = Fq[] sage: C = DrinfeldModule(A, [T, 1]); C - Drinfeld module defined by T |--> t + T + Drinfeld module defined by T |--> τ + T sage: C.class_polynomial() 1 diff --git a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py index 6c2f2450118..9a2c37bd459 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -90,16 +90,15 @@ class DrinfeldModule(Parent, UniqueRepresentation): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z, 4, 1]) sage: phi - Drinfeld module defined by T |--> t^2 + 4*t + z + Drinfeld module defined by T |--> τ^2 + 4*τ + z :: sage: Fq = GF(49) sage: A. = Fq[] - sage: K = Frac(A) - sage: psi = DrinfeldModule(A, [K(T), T+1]) + sage: psi = DrinfeldModule(A, [T, T+1]) sage: psi - Drinfeld module defined by T |--> (T + 1)*t + T + Drinfeld module defined by T |--> (T + 1)*τ + T .. NOTE:: @@ -127,7 +126,7 @@ class DrinfeldModule(Parent, UniqueRepresentation): - ``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 + - ``name`` -- (default: ``'τ'``) the name of the Ore polynomial ring generator .. RUBRIC:: Construction @@ -140,7 +139,7 @@ class DrinfeldModule(Parent, UniqueRepresentation): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z, 1, 1]) sage: phi - Drinfeld module defined by T |--> t^2 + t + z + Drinfeld module defined by T |--> τ^2 + τ + z .. NOTE:: @@ -150,10 +149,9 @@ class DrinfeldModule(Parent, UniqueRepresentation): 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 = DrinfeldModule(A, [T, 1, T^3 + T + 1]) sage: psi - Drinfeld module defined by T |--> (T^3 + T + 1)*t^2 + t + T + Drinfeld module defined by T |--> (T^3 + T + 1)*τ^2 + τ + T :: @@ -163,15 +161,15 @@ class DrinfeldModule(Parent, UniqueRepresentation): 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 + represent the generator `\phi_T = z + τ + τ^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: tau = ore_polring.gen() + sage: rho_T = z + tau^3 sage: rho = DrinfeldModule(A, rho_T) sage: rho - Drinfeld module defined by T |--> t^3 + z + Drinfeld module defined by T |--> τ^3 + z sage: rho(T) == rho_T True @@ -179,12 +177,12 @@ class DrinfeldModule(Parent, UniqueRepresentation): object:: sage: phi(T) # phi_T, the generator of the Drinfeld module - t^2 + t + z + τ^2 + τ + 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 + τ^6 + (z^11 + z^9 + 2*z^6 + 2*z^4 + 2*z + 1)*τ^4 + + (2*z^11 + 2*z^10 + z^9 + z^8 + 2*z^7 + 2*z^6 + z^5 + 2*z^3)*τ^3 + + (2*z^11 + z^10 + z^9 + 2*z^7 + 2*z^6 + z^5 + z^4 + 2*z^3 + 2*z + 2)*τ^2 + + (2*z^11 + 2*z^8 + 2*z^6 + z^5 + z^4 + 2*z^2)*τ + z^3 + z + 1 sage: phi(1) # phi_1 1 @@ -204,7 +202,7 @@ class DrinfeldModule(Parent, UniqueRepresentation): sage: cat = phi.category() sage: cat.object([z, 0, 0, 1]) - Drinfeld module defined by T |--> t^3 + z + Drinfeld module defined by T |--> τ^3 + z .. RUBRIC:: The base field of a Drinfeld module @@ -243,7 +241,7 @@ class DrinfeldModule(Parent, UniqueRepresentation): :: sage: phi.ore_polring() # K{t} - Ore Polynomial Ring in t over Finite Field in z of size 3^12 twisted by z |--> z^(3^2) + Ore Polynomial Ring in τ over Finite Field in z of size 3^12 twisted by z |--> z^(3^2) :: @@ -253,7 +251,7 @@ class DrinfeldModule(Parent, UniqueRepresentation): :: sage: phi.gen() # phi_T - t^2 + t + z + τ^2 + τ + z sage: phi.gen() == phi(T) True @@ -267,9 +265,9 @@ class DrinfeldModule(Parent, UniqueRepresentation): 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 + To: Ore Polynomial Ring in τ over Finite Field in z of size 3^12 twisted by z |--> z^(3^2) - Defn: T |--> t^2 + t + z + Defn: T |--> τ^2 + τ + z One can compute the rank and height:: @@ -309,9 +307,9 @@ class DrinfeldModule(Parent, UniqueRepresentation): sage: phi(T) in Hom(phi, phi) True - sage: t^6 in Hom(phi, phi) + sage: tau^6 in Hom(phi, phi) True - sage: t^5 + 2*t^3 + 1 in Hom(phi, phi) + sage: tau^5 + 2*tau^3 + 1 in Hom(phi, phi) False sage: 1 in Hom(phi, rho) False @@ -324,23 +322,23 @@ class DrinfeldModule(Parent, UniqueRepresentation): homset (``hom``):: sage: hom = Hom(phi, phi) - sage: frobenius_endomorphism = hom(t^6) + sage: frobenius_endomorphism = hom(tau^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 + Endomorphism of Drinfeld module defined by T |--> τ^2 + τ + z + Defn: τ^6 sage: identity_morphism - Identity morphism of Drinfeld module defined by T |--> t^2 + t + z + Identity morphism of Drinfeld module defined by T |--> τ^2 + τ + z sage: zero_morphism - Endomorphism of Drinfeld module defined by T |--> t^2 + t + z + Endomorphism of Drinfeld module defined by T |--> τ^2 + τ + z Defn: 0 The underlying Ore polynomial is retrieved with the method :meth:`ore_polynomial`:: sage: frobenius_endomorphism.ore_polynomial() - t^6 + τ^6 sage: identity_morphism.ore_polynomial() 1 @@ -366,11 +364,11 @@ class DrinfeldModule(Parent, UniqueRepresentation): defines 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: P = (2*z^6 + z^3 + 2*z^2 + z + 2)*tau + 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 + Drinfeld module defined by T |--> (2*z^11 + 2*z^9 + z^6 + 2*z^5 + 2*z^4 + 2*z^2 + 1)*τ^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)*τ + z sage: P in Hom(phi, psi) True sage: P * phi(T) == psi(T) * P @@ -382,7 +380,7 @@ class DrinfeldModule(Parent, UniqueRepresentation): Traceback (most recent call last): ... ValueError: the input does not define an isogeny - sage: phi.velu(t) + sage: phi.velu(tau) Traceback (most recent call last): ... ValueError: the input does not define an isogeny @@ -403,7 +401,7 @@ class DrinfeldModule(Parent, UniqueRepresentation): 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 + induced by Drinfeld module defined by T |--> τ^2 + τ + z The action on elements is computed by calling the action object:: @@ -434,16 +432,6 @@ class DrinfeldModule(Parent, UniqueRepresentation): ... ValueError: generator must have positive degree - The constant coefficient must be nonzero:: - - sage: Fq = GF(2) - sage: K. = Fq.extension(2) - sage: A. = Fq[] - sage: DrinfeldModule(A, [K(0), K(1)]) - Traceback (most recent call last): - ... - ValueError: constant coefficient must be nonzero - The coefficients of the generator must lie in an `\mathbb{F}_q[T]`-field, where `\mathbb{F}_q[T]` is the function ring of the Drinfeld module:: @@ -520,7 +508,7 @@ class DrinfeldModule(Parent, UniqueRepresentation): """ @staticmethod - def __classcall_private__(cls, function_ring, gen, name='t'): + def __classcall_private__(cls, function_ring, gen, name='τ'): """ Check input validity and return a ``DrinfeldModule`` or ``DrinfeldModule_finite`` object accordingly. @@ -533,8 +521,8 @@ def __classcall_private__(cls, function_ring, gen, name='t'): - ``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 gen + - ``name`` -- (default: ``'τ'``) the name of the variable of + the Ore polynomial OUTPUT: a DrinfeldModule or DrinfeldModule_finite @@ -551,8 +539,7 @@ def __classcall_private__(cls, function_ring, gen, name='t'): :: - sage: K = Frac(A) - sage: phi = DrinfeldModule(A, [K(T), 1]) + sage: phi = DrinfeldModule(A, [T, 1]) sage: isinstance(psi, DrinfeldModule_finite) False """ @@ -583,12 +570,13 @@ def __classcall_private__(cls, function_ring, gen, name='t'): ore_polring = None # Base ring without morphism structure: base_field = Sequence(gen).universe() + try: + base_field = base_field.fraction_field() + except AttributeError: + pass else: raise TypeError('generator must be list of coefficients or Ore ' 'polynomial') - # Constant coefficient must be nonzero: - if gen[0].is_zero(): - raise ValueError('constant coefficient must be nonzero') # The coefficients are in a base field that has coercion from Fq: if not (hasattr(base_field, 'has_coerce_map_from') and base_field.has_coerce_map_from(function_ring.base_ring())): @@ -645,8 +633,8 @@ def __init__(self, gen, category): - ``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 gen + - ``name`` -- (default: ``'τ'``) the name of the variable of + the Ore polynomial ring TESTS:: @@ -774,7 +762,7 @@ def _latex_(self): 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: latex(phi) - \phi: T \mapsto z_{12}^{5} t^{2} + z_{12}^{3} t + 2 z_{12}^{11} + 2 z_{12}^{10} + z_{12}^{9} + 3 z_{12}^{8} + z_{12}^{7} + 2 z_{12}^{5} + 2 z_{12}^{4} + 3 z_{12}^{3} + z_{12}^{2} + 2 z_{12} + \phi: T \mapsto z_{12}^{5} τ^{2} + z_{12}^{3} τ + 2 z_{12}^{11} + 2 z_{12}^{10} + z_{12}^{9} + 3 z_{12}^{8} + z_{12}^{7} + 2 z_{12}^{5} + 2 z_{12}^{4} + 3 z_{12}^{3} + z_{12}^{2} + 2 z_{12} :: @@ -801,7 +789,7 @@ def _repr_(self): 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 - 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 + Drinfeld module defined by T |--> z12^5*τ^2 + z12^3*τ + 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 """ return f'Drinfeld module defined by {self._function_ring.gen()} ' \ f'|--> {self._gen}' @@ -868,7 +856,7 @@ def action(self): 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 + induced by Drinfeld module defined by T |--> z12^5*τ^2 + z12^3*τ + 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:: @@ -913,8 +901,7 @@ def basic_j_invariant_parameters(self, coeff_indices=None, nonzero=False): EXAMPLES:: - sage: A = GF(5)['T'] - sage: K. = Frac(A) + sage: A. = GF(5)[] sage: phi = DrinfeldModule(A, [T, 0, T+1, T^2 + 1]) sage: phi.basic_j_invariant_parameters() [((1,), (31, 1)), @@ -948,8 +935,7 @@ def basic_j_invariant_parameters(self, coeff_indices=None, nonzero=False): One can specify the list of coefficients indices to be considered in the computation:: - sage: A = GF(2)['T'] - sage: K. = Frac(A) + sage: A. = GF(2)[] sage: phi = DrinfeldModule(A, [T, T, 1, T]) sage: phi.basic_j_invariant_parameters([1, 2]) [((1,), (7, 1)), @@ -962,8 +948,7 @@ def basic_j_invariant_parameters(self, coeff_indices=None, nonzero=False): TESTS:: - sage: A = GF(5)['T'] - sage: K. = Frac(A) + sage: A. = GF(5)[] sage: phi = DrinfeldModule(A, [T, 0, T+1, T^2 + 1]) sage: phi.basic_j_invariant_parameters([1, 'x']) Traceback (most recent call last): @@ -1100,8 +1085,7 @@ def basic_j_invariants(self, nonzero=False): :: - sage: A = GF(5)['T'] - sage: K. = Frac(A) + sage: A. = GF(5)[] 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, @@ -1267,8 +1251,7 @@ def height(self): characteristic; that is why an error is raised:: sage: B. = Fq[] - sage: L = Frac(B) - sage: phi = DrinfeldModule(A, [L(2), L(1)]) + sage: phi = DrinfeldModule(A, [B(2), B(1)]) sage: phi.height() Traceback (most recent call last): ... @@ -1301,7 +1284,7 @@ def is_isomorphic(self, other, absolutely=False): sage: A. = Fq[] sage: K. = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 0, 1, z]) - sage: t = phi.ore_variable() + sage: tau = phi.ore_variable() We create a second Drinfeld module, which is isomorphic to `\phi` and then check that they are indeed isomorphic:: @@ -1313,7 +1296,7 @@ def is_isomorphic(self, other, absolutely=False): In the example below, `\phi` and `\psi` are isogenous but not isomorphic:: - sage: psi = phi.velu(t + 1) + sage: psi = phi.velu(tau + 1) sage: phi.is_isomorphic(psi) False @@ -1458,8 +1441,7 @@ def is_finite(self) -> bool: sage: phi.is_finite() True sage: B. = Fq[] - sage: L = Frac(B) - sage: psi = DrinfeldModule(A, [L(2), L(1)]) + sage: psi = DrinfeldModule(A, [B(2), B(1)]) sage: psi.is_finite() False """ @@ -1564,8 +1546,7 @@ def j_invariant(self, parameter=None, check=True): :: - sage: A = GF(5)['T'] - sage: K. = Frac(A) + sage: A. = GF(5)[] sage: phi = DrinfeldModule(A, [T, T^2, 1, T + 1, T^3]) sage: phi.j_invariant(1) T^309 @@ -1591,8 +1572,7 @@ def j_invariant(self, parameter=None, check=True): The list of all basic `j`-invariant parameters can be retrieved using the method :meth:`basic_j_invariant_parameters`:: - sage: A = GF(3)['T'] - sage: K. = Frac(A) + sage: A. = GF(3)[] 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]) @@ -1602,8 +1582,7 @@ def j_invariant(self, parameter=None, check=True): TESTS:: - sage: A = GF(5)['T'] - sage: K. = Frac(A) + sage: A. = GF(5)[] sage: phi = DrinfeldModule(A, [T, T^2, 1, T + 1, T^3]) sage: phi.j_invariant() Traceback (most recent call last): @@ -1743,8 +1722,7 @@ def jk_invariants(self): EXAMPLES:: - sage: A = GF(3)['T'] - sage: K. = Frac(A) + sage: A. = GF(3)[] 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} @@ -1783,9 +1761,9 @@ def morphism(self): 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 + To: Ore Polynomial Ring in τ over Finite Field in z12 of size 5^12 twisted by z12 |--> z12^(5^2) - Defn: T |--> z12^5*t^2 + z12^3*t + 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + Defn: T |--> z12^5*τ^2 + z12^3*τ + 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) @@ -1809,7 +1787,7 @@ class the ``__call__`` method of this morphism:: 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^5*τ^2 + z12^3*τ + 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 @@ -1899,8 +1877,8 @@ def velu(self, isog): 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 + (z12^11 + 3*z12^10 + z12^9 + z12^7 + z12^5 + 4*z12^4 + 4*z12^3 + z12^2 + 1)*τ^2 + + (2*z12^11 + 4*z12^10 + 2*z12^8 + z12^6 + 3*z12^5 + z12^4 + 2*z12^3 + z12^2 + z12 + 4)*τ + 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 @@ -1963,7 +1941,7 @@ def hom(self, x, codomain=None): sage: K. = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 0, 1, z]) sage: phi - Drinfeld module defined by T |--> z*t^3 + t^2 + z + Drinfeld module defined by T |--> z*τ^3 + τ^2 + z An important class of endomorphisms of a Drinfeld module `\phi` is given by scalar multiplications, that are endomorphisms @@ -1971,37 +1949,37 @@ def hom(self, x, codomain=None): 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 + Endomorphism of Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + Defn: z*τ^3 + τ^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 + Endomorphism of Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + Defn: z^2*τ^6 + (3*z^2 + z + 1)*τ^5 + τ^4 + 2*z^2*τ^3 + (3*z^2 + z + 1)*τ^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 + sage: tau = phi.ore_variable() + sage: phi.hom(tau^3) + Endomorphism of Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + Defn: τ^3 If the input Ore polynomial defines a morphism to another Drinfeld module, the latter is determined automatically:: - sage: phi.hom(t + 1) + sage: phi.hom(tau + 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: Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*τ^3 + (3*z^2 + 2*z + 2)*τ^2 + (2*z^2 + 3*z + 4)*τ + z + Defn: τ + 1 TESTS:: - sage: phi.hom(t) + sage: phi.hom(tau) Traceback (most recent call last): ... ValueError: the input does not define an isogeny @@ -2015,7 +1993,7 @@ def hom(self, x, codomain=None): :: - sage: phi.hom(t + 1, codomain=phi) + sage: phi.hom(tau + 1, codomain=phi) Traceback (most recent call last): ... ValueError: Ore polynomial does not define a morphism @@ -2062,16 +2040,16 @@ def scalar_multiplication(self, x): sage: K. = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 0, 1, z]) sage: phi - Drinfeld module defined by T |--> z*t^3 + t^2 + z + Drinfeld module defined by T |--> z*τ^3 + τ^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 + Endomorphism of Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + Defn: z*τ^3 + τ^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 + Endomorphism of Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + Defn: z^2*τ^6 + (3*z^2 + z + 1)*τ^5 + τ^4 + 2*z^2*τ^3 + (3*z^2 + z + 1)*τ^2 + z^2 + 1 """ if not self.function_ring().has_coerce_map_from(x.parent()): raise ValueError("%s is not element of the function ring" % x) diff --git a/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py index dca578e2296..6f7684f14cb 100644 --- a/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py @@ -28,6 +28,7 @@ from sage.matrix.constructor import Matrix from sage.matrix.matrix_space import MatrixSpace from sage.matrix.special import companion_matrix +from sage.misc.functional import log from sage.misc.misc_c import prod from sage.modules.free_module_element import vector from sage.rings.function_field.drinfeld_modules.drinfeld_module import DrinfeldModule @@ -57,7 +58,7 @@ class DrinfeldModule_finite(DrinfeldModule): sage: K. = Fq.extension(2) sage: phi = DrinfeldModule(A, [z6, 0, 5]) sage: phi - Drinfeld module defined by T |--> 5*t^2 + z6 + Drinfeld module defined by T |--> 5*τ^2 + z6 :: @@ -84,8 +85,8 @@ class DrinfeldModule_finite(DrinfeldModule): sage: frobenius_endomorphism = phi.frobenius_endomorphism() sage: frobenius_endomorphism - Endomorphism of Drinfeld module defined by T |--> 5*t^2 + z6 - Defn: t^2 + Endomorphism of Drinfeld module defined by T |--> 5*τ^2 + z6 + Defn: τ^2 Its characteristic polynomial can be computed:: @@ -138,8 +139,8 @@ def __init__(self, gen, category): - ``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 gen + - ``name`` -- (default: ``'τ'``) the name of the variable of + the Ore polynomial ring TESTS:: @@ -157,7 +158,7 @@ def __init__(self, gen, category): # added one to ensure that DrinfeldModule_finite would always # have _frobenius_norm and _frobenius_trace attributes. super().__init__(gen, category) - self._base_degree_over_constants = self.base_over_constants_field().degree(self._Fq) + self._base_degree_over_constants = log(self._base.cardinality(), self._Fq.cardinality()) self._frobenius_norm = None self._frobenius_trace = None self._frobenius_charpoly = None @@ -235,7 +236,7 @@ def frobenius_endomorphism(self): 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`. + defining Ore polynomial is `τ^q`. EXAMPLES:: @@ -244,8 +245,8 @@ def frobenius_endomorphism(self): sage: K. = 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 + Endomorphism of Drinfeld module defined by T |--> z6*τ^2 + 1 + Defn: τ^2 TESTS:: @@ -254,7 +255,7 @@ def frobenius_endomorphism(self): True """ t = self.ore_polring().gen() - deg = self.base_over_constants_field().degree_over() + deg = self._base_degree_over_constants return self._Hom_(self, category=self.category())(t**deg) def frobenius_charpoly(self, var='X', algorithm=None): @@ -273,14 +274,14 @@ def frobenius_charpoly(self, var='X', algorithm=None): 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 + let `τ^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 .. MATH:: - \chi(t^n)(\phi(T)) - = t^{nr} + \sum_{i=1}^{r} \phi_{A_{i}}t^{n(i)} + \chi(τ^n)(\phi(T)) + = τ^{nr} + \sum_{i=1}^{r} \phi_{A_{i}}τ^{n(i)} = 0, with `\deg(A_i) \leq \frac{n(r-i)}{r}`. @@ -340,7 +341,7 @@ def frobenius_charpoly(self, var='X', algorithm=None): 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 + Endomorphism of Drinfeld module defined by T |--> z6*τ^2 + 1 Defn: 0 :: @@ -935,15 +936,15 @@ def invert(self, ore_pol): 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) + sage: tau = phi.ore_variable() + sage: phi.invert(tau + 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) + sage: phi.invert(tau^4 + tau^2 + 1) Traceback (most recent call last): ... ValueError: input must be in the image of the Drinfeld module @@ -1091,7 +1092,7 @@ def is_supersingular(self): sage: phi.is_supersingular() True sage: phi(phi.characteristic()) # Purely inseparable - z6*t^2 + z6*τ^2 In rank two, a Drinfeld module is either ordinary or supersinguler. In higher ranks, it could be neither of diff --git a/src/sage/rings/function_field/drinfeld_modules/homset.py b/src/sage/rings/function_field/drinfeld_modules/homset.py index faf6b45c5b4..480b1fdfe08 100644 --- a/src/sage/rings/function_field/drinfeld_modules/homset.py +++ b/src/sage/rings/function_field/drinfeld_modules/homset.py @@ -41,16 +41,16 @@ class DrinfeldModuleMorphismAction(Action): sage: phi = DrinfeldModule(A, [z, 1, z]) sage: psi = DrinfeldModule(A, [z, z^2 + 4*z + 3, 2*z^2 + 4*z + 4]) sage: H = Hom(phi, psi) - sage: t = phi.ore_variable() - sage: f = H(t + 2) + sage: tau = phi.ore_variable() + sage: f = H(tau + 2) Left action:: sage: (T + 1) * f Drinfeld Module morphism: - From: Drinfeld module defined by T |--> z*t^2 + t + z - To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^2 + (z^2 + 4*z + 3)*t + z - Defn: (2*z^2 + 4*z + 4)*t^3 + (2*z + 1)*t^2 + (2*z^2 + 4*z + 2)*t + 2*z + 2 + From: Drinfeld module defined by T |--> z*τ^2 + τ + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*τ^2 + (z^2 + 4*z + 3)*τ + z + Defn: (2*z^2 + 4*z + 4)*τ^3 + (2*z + 1)*τ^2 + (2*z^2 + 4*z + 2)*τ + 2*z + 2 Right action currently does not work (it is a known bug, due to an incompatibility between multiplication of morphisms and the coercion @@ -60,9 +60,9 @@ class DrinfeldModuleMorphismAction(Action): Traceback (most recent call last): ... TypeError: right (=T + 1) must be a map to multiply it by Drinfeld Module morphism: - From: Drinfeld module defined by T |--> z*t^2 + t + z - To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^2 + (z^2 + 4*z + 3)*t + z - Defn: t + 2 + From: Drinfeld module defined by T |--> z*τ^2 + τ + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*τ^2 + (z^2 + 4*z + 3)*τ + z + Defn: τ + 2 """ def __init__(self, A, H, is_left, op): r""" @@ -114,9 +114,9 @@ def _act_(self, a, f): sage: f = phi.hom(t + 1) sage: T*f # indirect doctest 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: (2*z^2 + 4*z + 4)*t^4 + (z + 1)*t^3 + t^2 + (2*z^2 + 4*z + 4)*t + z + From: Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*τ^3 + (3*z^2 + 2*z + 2)*τ^2 + (2*z^2 + 3*z + 4)*τ + z + Defn: (2*z^2 + 4*z + 4)*τ^4 + (z + 1)*τ^3 + τ^2 + (2*z^2 + 4*z + 4)*τ + z """ u = f.ore_polynomial() if self._is_left: @@ -147,8 +147,8 @@ class DrinfeldModuleHomset(Homset): sage: H = Hom(phi, psi) sage: H Set of Drinfeld module morphisms - from (gen) 2*t^2 + z6*t + z6 - to (gen) 2*t^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*t + z6 + from (gen) 2*τ^2 + z6*τ + z6 + to (gen) 2*τ^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*τ + z6 :: @@ -160,14 +160,14 @@ class DrinfeldModuleHomset(Homset): sage: E = End(phi) sage: E - Set of Drinfeld module morphisms from (gen) 2*t^2 + z6*t + z6 to (gen) 2*t^2 + z6*t + z6 + Set of Drinfeld module morphisms from (gen) 2*τ^2 + z6*τ + z6 to (gen) 2*τ^2 + z6*τ + z6 sage: E is Hom(phi, phi) True The domain and codomain must have the same Drinfeld modules category:: - sage: rho = DrinfeldModule(A, [Frac(A)(T), 1]) + sage: rho = DrinfeldModule(A, [T, 1]) sage: Hom(phi, rho) Traceback (most recent call last): ... @@ -185,39 +185,39 @@ class DrinfeldModuleHomset(Homset): sage: identity_morphism = E(1) sage: identity_morphism - Identity morphism of Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 + Identity morphism of Drinfeld module defined by T |--> 2*τ^2 + z6*τ + z6 :: - sage: t = phi.ore_polring().gen() - sage: frobenius_endomorphism = E(t^6) + sage: tau = phi.ore_variable() + sage: frobenius_endomorphism = E(tau^6) sage: frobenius_endomorphism - Endomorphism of Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 - Defn: t^6 + Endomorphism of Drinfeld module defined by T |--> 2*τ^2 + z6*τ + z6 + Defn: τ^6 :: - sage: isogeny = H(t + 1) + sage: isogeny = H(tau + 1) sage: isogeny Drinfeld Module morphism: - From: Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 - To: Drinfeld module defined by T |--> 2*t^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*t + z6 - Defn: t + 1 + From: Drinfeld module defined by T |--> 2*τ^2 + z6*τ + z6 + To: Drinfeld module defined by T |--> 2*τ^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*τ + z6 + Defn: τ + 1 And one can test if an Ore polynomial defines a morphism using the ``in`` syntax:: sage: 1 in H False - sage: t^6 in H + sage: tau^6 in H False - sage: t + 1 in H + sage: tau + 1 in H True sage: 1 in E True - sage: t^6 in E + sage: tau^6 in E True - sage: t + 1 in E + sage: tau + 1 in E False This also works if the candidate is a morphism object:: @@ -293,7 +293,7 @@ def _latex_(self): sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) sage: H = Hom(phi, psi) sage: latex(H) - \text{Set{ }of{ }Drinfeld{ }module{ }morphisms{ }from{ }(gen){ }}2 t^{2} + z_{6} t + z_{6}\text{{ }to{ }(gen){ }}2 t^{2} + \left(2 z_{6}^{5} + 2 z_{6}^{4} + 2 z_{6} + 1\right) t + z_{6} + \text{Set{ }of{ }Drinfeld{ }module{ }morphisms{ }from{ }(gen){ }}2 τ^{2} + z_{6} τ + z_{6}\text{{ }to{ }(gen){ }}2 τ^{2} + \left(2 z_{6}^{5} + 2 z_{6}^{4} + 2 z_{6} + 1\right) τ + z_{6} """ return f'\\text{{Set{{ }}of{{ }}Drinfeld{{ }}module{{ }}morphisms' \ f'{{ }}from{{ }}(gen){{ }}}}{latex(self.domain().gen())}' \ @@ -313,7 +313,7 @@ def _repr_(self): sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) sage: H = Hom(phi, psi) sage: H - Set of Drinfeld module morphisms from (gen) 2*t^2 + z6*t + z6 to (gen) 2*t^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*t + z6 + Set of Drinfeld module morphisms from (gen) 2*τ^2 + z6*τ + z6 to (gen) 2*τ^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*τ + z6 """ return f'Set of Drinfeld module morphisms from (gen) '\ f'{self.domain().gen()} to (gen) {self.codomain().gen()}' @@ -337,23 +337,23 @@ def __contains__(self, x): sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) sage: H = Hom(phi, psi) sage: E = End(phi) - sage: t = phi.ore_polring().gen() + sage: tau = phi.ore_variable() sage: 1 in H False - sage: t^6 in H + sage: tau^6 in H False - sage: t + 1 in H + sage: tau + 1 in H True sage: 1 in E True - sage: t^6 in E + sage: tau^6 in E True - sage: t + 1 in E + sage: tau + 1 in E False Whereas the input is now a Drinfeld module morphism:: - sage: isogeny = H(t + 1) + sage: isogeny = H(tau + 1) sage: isogeny in H True sage: E(0) in E @@ -385,33 +385,33 @@ def _element_constructor_(self, *args, **kwds): sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) sage: H = Hom(phi, psi) sage: E = End(phi) - sage: t = phi.ore_polring().gen() + sage: tau = phi.ore_variable() sage: identity_morphism = E(1) sage: identity_morphism - Identity morphism of Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 + Identity morphism of Drinfeld module defined by T |--> 2*τ^2 + z6*τ + z6 :: sage: scalar_multiplication = E(T) sage: scalar_multiplication - Endomorphism of Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 - Defn: 2*t^2 + z6*t + z6 + Endomorphism of Drinfeld module defined by T |--> 2*τ^2 + z6*τ + z6 + Defn: 2*τ^2 + z6*τ + z6 :: - sage: frobenius_endomorphism = E(t^6) + sage: frobenius_endomorphism = E(tau^6) sage: frobenius_endomorphism - Endomorphism of Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 - Defn: t^6 + Endomorphism of Drinfeld module defined by T |--> 2*τ^2 + z6*τ + z6 + Defn: τ^6 :: - sage: isogeny = H(t + 1) + sage: isogeny = H(tau + 1) sage: isogeny Drinfeld Module morphism: - From: Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 - To: Drinfeld module defined by T |--> 2*t^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*t + z6 - Defn: t + 1 + From: Drinfeld module defined by T |--> 2*τ^2 + z6*τ + z6 + To: Drinfeld module defined by T |--> 2*τ^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*τ + z6 + Defn: τ + 1 """ # NOTE: This used to be self.element_class(self, ...), but this # would call __init__ instead of __classcall_private__. This diff --git a/src/sage/rings/function_field/drinfeld_modules/morphism.py b/src/sage/rings/function_field/drinfeld_modules/morphism.py index beff948f980..2c7bf3b19c8 100644 --- a/src/sage/rings/function_field/drinfeld_modules/morphism.py +++ b/src/sage/rings/function_field/drinfeld_modules/morphism.py @@ -48,15 +48,15 @@ class DrinfeldModuleMorphism(Morphism, UniqueRepresentation, sage: A. = Fq[] sage: K. = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, z^2 + z, z^2 + z]) - sage: t = phi.ore_polring().gen() - sage: ore_pol = t + z^5 + z^3 + z + 1 + sage: tau = phi.ore_variable() + sage: ore_pol = tau + z^5 + z^3 + z + 1 sage: psi = phi.velu(ore_pol) sage: morphism = Hom(phi, psi)(ore_pol) sage: morphism Drinfeld Module morphism: - From: Drinfeld module defined by T |--> (z^2 + z)*t^2 + (z^2 + z)*t + z - To: Drinfeld module defined by T |--> (z^5 + z^2 + z + 1)*t^2 + (z^4 + z + 1)*t + z - Defn: t + z^5 + z^3 + z + 1 + From: Drinfeld module defined by T |--> (z^2 + z)*τ^2 + (z^2 + z)*τ + z + To: Drinfeld module defined by T |--> (z^5 + z^2 + z + 1)*τ^2 + (z^4 + z + 1)*τ + z + Defn: τ + z^5 + z^3 + z + 1 The given Ore polynomial must indeed define a morphism:: @@ -69,19 +69,19 @@ class DrinfeldModuleMorphism(Morphism, UniqueRepresentation, One can get basic data on the morphism:: sage: morphism.domain() - Drinfeld module defined by T |--> (z^2 + z)*t^2 + (z^2 + z)*t + z + Drinfeld module defined by T |--> (z^2 + z)*τ^2 + (z^2 + z)*τ + z sage: morphism.domain() is phi True sage: morphism.codomain() - Drinfeld module defined by T |--> (z^5 + z^2 + z + 1)*t^2 + (z^4 + z + 1)*t + z + Drinfeld module defined by T |--> (z^5 + z^2 + z + 1)*τ^2 + (z^4 + z + 1)*τ + z sage: morphism.codomain() is psi True :: sage: morphism.ore_polynomial() - t + z^5 + z^3 + z + 1 + τ + z^5 + z^3 + z + 1 sage: morphism.ore_polynomial() is ore_pol True @@ -117,9 +117,9 @@ class DrinfeldModuleMorphism(Morphism, UniqueRepresentation, sage: from sage.rings.function_field.drinfeld_modules.morphism import DrinfeldModuleMorphism sage: DrinfeldModuleMorphism(Hom(phi, psi), ore_pol) Drinfeld Module morphism: - From: Drinfeld module defined by T |--> (z^2 + z)*t^2 + (z^2 + z)*t + z - To: Drinfeld module defined by T |--> (z^5 + z^2 + z + 1)*t^2 + (z^4 + z + 1)*t + z - Defn: t + z^5 + z^3 + z + 1 + From: Drinfeld module defined by T |--> (z^2 + z)*τ^2 + (z^2 + z)*τ + z + To: Drinfeld module defined by T |--> (z^5 + z^2 + z + 1)*τ^2 + (z^4 + z + 1)*τ + z + Defn: τ + z^5 + z^3 + z + 1 sage: DrinfeldModuleMorphism(Hom(phi, psi), ore_pol) is morphism True """ @@ -145,21 +145,21 @@ def __classcall_private__(cls, parent, x): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z6, 1, 1]) sage: End(phi)(T + 1) - Endomorphism of Drinfeld module defined by T |--> t^2 + t + z6 - Defn: t^2 + t + z6 + 1 + Endomorphism of Drinfeld module defined by T |--> τ^2 + τ + z6 + Defn: τ^2 + τ + z6 + 1 :: - sage: t = phi.ore_polring().gen() + sage: tau = phi.ore_variable() sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) - sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: morphism = Hom(phi, psi)(tau + z6^5 + z6^2 + 1) sage: morphism is Hom(phi, psi)(morphism) True :: sage: from sage.rings.function_field.drinfeld_modules.morphism import DrinfeldModuleMorphism - sage: morphism = DrinfeldModuleMorphism(Sets(), t + 1) + sage: morphism = DrinfeldModuleMorphism(Sets(), tau + 1) Traceback (most recent call last): ... TypeError: parent should be a DrinfeldModuleHomset @@ -203,13 +203,13 @@ def __init__(self, parent, ore_pol): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z6, 1, 1]) sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) - sage: t = phi.ore_polring().gen() - sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: tau = phi.ore_variable() + sage: morphism = Hom(phi, psi)(tau + z6^5 + z6^2 + 1) sage: morphism._domain is phi True sage: morphism._codomain is psi True - sage: morphism._ore_polynomial == t + z6^5 + z6^2 + 1 + sage: morphism._ore_polynomial == tau + z6^5 + z6^2 + 1 True """ super().__init__(parent) @@ -228,10 +228,10 @@ def _latex_(self): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z6, 1, 1]) sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) - sage: t = phi.ore_polring().gen() - sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: tau = phi.ore_variable() + sage: morphism = Hom(phi, psi)(tau + z6^5 + z6^2 + 1) sage: latex(morphism) - t + z_{6}^{5} + z_{6}^{2} + 1 + τ + z_{6}^{5} + z_{6}^{2} + 1 """ return f'{latex(self._ore_polynomial)}' @@ -246,13 +246,13 @@ def _repr_(self): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z6, 1, 1]) sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) - sage: t = phi.ore_polring().gen() - sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: tau = phi.ore_variable() + sage: morphism = Hom(phi, psi)(tau + z6^5 + z6^2 + 1) sage: morphism Drinfeld Module morphism: - From: Drinfeld module defined by T |--> t^2 + t + z6 - To: Drinfeld module defined by T |--> t^2 + (z6^4 + z6^2 + 1)*t + z6 - Defn: t + z6^5 + z6^2 + 1 + From: Drinfeld module defined by T |--> τ^2 + τ + z6 + To: Drinfeld module defined by T |--> τ^2 + (z6^4 + z6^2 + 1)*τ + z6 + Defn: τ + z6^5 + z6^2 + 1 """ if self.is_identity(): return f'Identity morphism of {self._domain}' @@ -276,8 +276,8 @@ def __hash__(self): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z6, 1, 1]) sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) - sage: t = phi.ore_polring().gen() - sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: tau = phi.ore_variable() + sage: morphism = Hom(phi, psi)(tau + z6^5 + z6^2 + 1) sage: hash(morphism) # random -4214883752078138009 """ @@ -294,8 +294,8 @@ def is_zero(self): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z6, 1, 1]) sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) - sage: t = phi.ore_polring().gen() - sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: tau = phi.ore_variable() + sage: morphism = Hom(phi, psi)(tau + z6^5 + z6^2 + 1) sage: morphism.is_zero() False @@ -324,8 +324,8 @@ def is_identity(self): :: sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) - sage: t = phi.ore_polring().gen() - sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: tau = phi.ore_variable() + sage: morphism = Hom(phi, psi)(tau + z6^5 + z6^2 + 1) sage: morphism.is_identity() False """ @@ -342,8 +342,8 @@ def is_isogeny(self): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z6, 1, 1]) sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) - sage: t = phi.ore_polring().gen() - sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: tau = phi.ore_variable() + sage: morphism = Hom(phi, psi)(tau + z6^5 + z6^2 + 1) sage: morphism.is_isogeny() True @@ -378,8 +378,8 @@ def is_isomorphism(self): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z6, 1, 1]) sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) - sage: t = phi.ore_polring().gen() - sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: tau = phi.ore_variable() + sage: morphism = Hom(phi, psi)(tau + z6^5 + z6^2 + 1) sage: morphism.is_isomorphism() False @@ -414,11 +414,11 @@ def ore_polynomial(self): sage: K. = Fq.extension(6) sage: phi = DrinfeldModule(A, [z6, 1, 1]) sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) - sage: t = phi.ore_polring().gen() - sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: tau = phi.ore_variable() + sage: morphism = Hom(phi, psi)(tau + z6^5 + z6^2 + 1) sage: ore_pol = morphism.ore_polynomial() sage: ore_pol - t + z6^5 + z6^2 + 1 + τ + z6^5 + z6^2 + 1 :: @@ -443,21 +443,21 @@ def __add__(self, other): sage: A. = Fq[] sage: K. = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 0, 1, z]) - sage: t = phi.ore_variable() - sage: f = phi.hom(t + 1) + sage: tau = phi.ore_variable() + sage: f = phi.hom(tau + 1) sage: g = T * f sage: f + g # indirect doctest 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: (2*z^2 + 4*z + 4)*t^4 + (z + 1)*t^3 + t^2 + (2*z^2 + 4*z)*t + z + 1 + From: Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*τ^3 + (3*z^2 + 2*z + 2)*τ^2 + (2*z^2 + 3*z + 4)*τ + z + Defn: (2*z^2 + 4*z + 4)*τ^4 + (z + 1)*τ^3 + τ^2 + (2*z^2 + 4*z)*τ + z + 1 We check that coercion from the function ring works:: sage: F = phi.frobenius_endomorphism() sage: F + T - Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z - Defn: (z + 1)*t^3 + t^2 + z + Endomorphism of Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + Defn: (z + 1)*τ^3 + τ^2 + z """ return self.parent()(self.ore_polynomial() + other.ore_polynomial()) @@ -473,11 +473,11 @@ def _composition_(self, other, H): sage: phi = DrinfeldModule(A, [z, 1, z, z^2]) sage: f = phi.frobenius_endomorphism() sage: f - Endomorphism of Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z - Defn: t^3 + Endomorphism of Drinfeld module defined by T |--> z^2*τ^3 + z*τ^2 + τ + z + Defn: τ^3 sage: f * f # indirect doctest - Endomorphism of Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z - Defn: t^6 + Endomorphism of Drinfeld module defined by T |--> z^2*τ^3 + z*τ^2 + τ + z + Defn: τ^6 """ return H(self.ore_polynomial() * other.ore_polynomial()) @@ -495,10 +495,10 @@ def inverse(self): sage: K. = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 1, z, z^2]) sage: f = phi.hom(2); f - Endomorphism of Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z + Endomorphism of Drinfeld module defined by T |--> z^2*τ^3 + z*τ^2 + τ + z Defn: 2 sage: f.inverse() - Endomorphism of Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z + Endomorphism of Drinfeld module defined by T |--> z^2*τ^3 + z*τ^2 + τ + z Defn: 3 Inversion of general isomorphisms between different Drinfeld modules @@ -506,13 +506,13 @@ def inverse(self): sage: g = phi.hom(z); g Drinfeld Module morphism: - From: Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z - To: Drinfeld module defined by T |--> z^2*t^3 + (z^2 + 2*z + 3)*t^2 + (z^2 + 3*z)*t + z + From: Drinfeld module defined by T |--> z^2*τ^3 + z*τ^2 + τ + z + To: Drinfeld module defined by T |--> z^2*τ^3 + (z^2 + 2*z + 3)*τ^2 + (z^2 + 3*z)*τ + z Defn: z sage: g.inverse() Drinfeld Module morphism: - From: Drinfeld module defined by T |--> z^2*t^3 + (z^2 + 2*z + 3)*t^2 + (z^2 + 3*z)*t + z - To: Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z + From: Drinfeld module defined by T |--> z^2*τ^3 + (z^2 + 2*z + 3)*τ^2 + (z^2 + 3*z)*τ + z + To: Drinfeld module defined by T |--> z^2*τ^3 + z*τ^2 + τ + z Defn: 3*z^2 + 4 When the morphism is not invertible, an error is raised:: @@ -564,8 +564,8 @@ def _motive_matrix(self): sage: A. = Fq[] sage: K. = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 0, 1]) - sage: t = phi.ore_variable() - sage: u = t^2 + (2*z^2 + 3*z + 3)*t + (2*z + 3) + sage: tau = phi.ore_variable() + sage: u = tau^2 + (2*z^2 + 3*z + 3)*tau + (2*z + 3) sage: f = phi.hom(u) sage: f._motive_matrix() [ T + 3 + z 3 + 3*z + 2*z^2] @@ -621,8 +621,8 @@ def norm(self, ideal=True): sage: A. = Fq[] sage: K. = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 0, 1, z]) - sage: t = phi.ore_variable() - sage: f = phi.hom(t + 1) + sage: tau = phi.ore_variable() + sage: f = phi.hom(tau + 1) sage: f.norm() Principal ideal (T + 4) of Univariate Polynomial Ring in T over Finite Field of size 5 @@ -682,19 +682,19 @@ def dual_isogeny(self): sage: A. = Fq[] sage: K. = Fq.extension(3) sage: phi = DrinfeldModule(A, [z, 0, 1, z]) - sage: t = phi.ore_variable() - sage: f = phi.hom(t + 1) + sage: tau = phi.ore_variable() + sage: f = phi.hom(tau + 1) sage: f 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: Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*τ^3 + (3*z^2 + 2*z + 2)*τ^2 + (2*z^2 + 3*z + 4)*τ + z + Defn: τ + 1 sage: g = f.dual_isogeny() sage: g Drinfeld Module morphism: - From: 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 - To: Drinfeld module defined by T |--> z*t^3 + t^2 + z - Defn: z*t^2 + (4*z + 1)*t + z + 4 + From: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*τ^3 + (3*z^2 + 2*z + 2)*τ^2 + (2*z^2 + 3*z + 4)*τ + z + To: Drinfeld module defined by T |--> z*τ^3 + τ^2 + z + Defn: z*τ^2 + (4*z + 1)*τ + z + 4 We check that `f \circ g` (resp. `g \circ f`) is the multiplication by the norm of `f`:: @@ -760,8 +760,8 @@ def characteristic_polynomial(self, var='X'): TESTS:: - sage: t = phi.ore_variable() - sage: isog = phi.hom(t + 1) + sage: tau = phi.ore_variable() + sage: isog = phi.hom(tau + 1) sage: isog.characteristic_polynomial() Traceback (most recent call last): ... @@ -800,7 +800,7 @@ def charpoly(self, var='X'): morphism (Cayley-Hamilton's theorem):: sage: chi(f) - Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z + Endomorphism of Drinfeld module defined by T |--> z*τ^3 + τ^2 + z Defn: 0 We verify, on an example, that the characteristic polynomial