From c23ec600afe80da40f5d57016f42ac478acb26d3 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Tue, 7 Mar 2023 19:39:44 -0500 Subject: [PATCH 01/26] inital commit --- .../drinfeld_modules/drinfeld_module.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) 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 1a24f09d66d..37a2de8fb7c 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -28,8 +28,10 @@ from sage.categories.homset import Hom from sage.misc.latex import latex from sage.misc.latex import latex_variable_name +from sage.misc.lazy_import import lazy_import from sage.misc.lazy_string import _LazyString from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.ore_polynomial_element import OrePolynomial from sage.rings.polynomial.polynomial_ring import PolynomialRing_general from sage.rings.ring_extension import RingExtension_generic @@ -38,6 +40,8 @@ from sage.structure.sequence import Sequence from sage.structure.unique_representation import UniqueRepresentation +lazy_import('sage.rings.lazy_series_ring', 'LazyPowerSeriesRing') + class DrinfeldModule(Parent, UniqueRepresentation): r""" @@ -1103,6 +1107,26 @@ def j_invariant(self): q = self._Fq.order() return (g**(q+1)) / delta + def _compute_coefficient(self, k): + if k not in ZZ: + raise TypeError("input must be an integer") + if k == 0: + return self._base.one() + r = self._gen.degree() + T = self._gen[0] + q = self._Fq.cardinality() + c = self._base.zero() + for i in range(k): + j = k - i + if j < r + 1: + c += self._compute_coefficient(i)*self._gen[j]**(q**i) + return c/(T - T**(q**k)) + + def logarithm(self, name='u'): + L = LazyPowerSeriesRing(self._base, name) + return L(self._compute_coefficient) + + def morphism(self): r""" Return the morphism object that defines the Drinfeld module. From 1f608cf7e32a8d35191954209d018c71e9965654 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Fri, 10 Mar 2023 01:51:01 -0500 Subject: [PATCH 02/26] enhance_compute_coeffcient_log --- .../drinfeld_modules/drinfeld_module.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) 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 37a2de8fb7c..3fa7eccab97 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1107,24 +1107,29 @@ def j_invariant(self): q = self._Fq.order() return (g**(q+1)) / delta - def _compute_coefficient(self, k): + def _compute_coefficient_log(self, k): if k not in ZZ: raise TypeError("input must be an integer") + k = ZZ(k) if k == 0: + return self._base.zero() + if k == 1: return self._base.one() r = self._gen.degree() T = self._gen[0] q = self._Fq.cardinality() + if not k.is_power_of(q): + return self._base.zero() c = self._base.zero() - for i in range(k): - j = k - i + for i in range(k.log(q)): + j = k.log(q) - i if j < r + 1: - c += self._compute_coefficient(i)*self._gen[j]**(q**i) - return c/(T - T**(q**k)) + c += self._compute_coefficient_log(q**i)*self._gen[j]**(q**i) + return c/(T - T**k) - def logarithm(self, name='u'): - L = LazyPowerSeriesRing(self._base, name) - return L(self._compute_coefficient) + def logarithm(self, name='z'): + L = LazyPowerSeriesRing(self._base, name, sparse=False) + return L(self._compute_coefficient_log) def morphism(self): From 3daba4a90ccab30920bfb452347d8ab01b207ea0 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Fri, 10 Mar 2023 02:18:52 -0500 Subject: [PATCH 03/26] add documentation --- .../drinfeld_modules/drinfeld_module.py | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) 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 3fa7eccab97..45d257c0068 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1108,6 +1108,30 @@ def j_invariant(self): return (g**(q+1)) / delta def _compute_coefficient_log(self, k): + r""" + Return the `k`-th coefficient of the logarithm of ``self``. + + TESTS:: + + sage: A = GF(2)['T'] + sage: K. = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: q = A.base_ring().cardinality() + sage: phi._compute_coefficient_log(0) + 0 + sage: phi._compute_coefficient_log(1) + 1 + sage: phi._compute_coefficient_log(2) + 1/(T^2 + T) + sage: phi._compute_coefficient_log(3) + 0 + sage: phi._compute_coefficient_log(2^4) + 1/(T^30 + T^29 + T^27 + T^26 + T^23 + T^22 + T^20 + T^19 + T^15 + T^14 + T^12 + T^11 + T^8 + T^7 + T^5 + T^4) + sage: phi._compute_coefficient_log(T) + Traceback (most recent call last): + ... + TypeError: input must be an integer + """ if k not in ZZ: raise TypeError("input must be an integer") k = ZZ(k) @@ -1128,6 +1152,32 @@ def _compute_coefficient_log(self, k): return c/(T - T**k) def logarithm(self, name='z'): + r""" + Return the logarithm of the given Drinfeld module. + + EXAMPLES:: + + sage: A = GF(2)['T'] + sage: K. = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: q = A.base_ring().cardinality() + sage: log = phi.logarithm(); log + z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^7) + sage: log[q] == -1/((T**q - T)) + True + sage: log[q**2] == 1/((T**q - T)*(T**(q**2) - T)) + True + sage: log[q**3] == -1/((T**q - T)*(T**(q**2) - T)*(T**(q**3) - T)) + True + + :: + + sage: A = GF(5)['T'] + sage: K. = Frac(A) + 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^7) + """ L = LazyPowerSeriesRing(self._base, name, sparse=False) return L(self._compute_coefficient_log) From 451cf1f670b5837041caf5a9f6218075588fad3f Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Sat, 11 Mar 2023 10:28:50 -0500 Subject: [PATCH 04/26] implement exponential --- .../drinfeld_modules/drinfeld_module.py | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) 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 45d257c0068..d302b129bb6 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -962,6 +962,27 @@ def coefficients(self, sparse=True): """ return self._gen.coefficients(sparse=sparse) + def _compute_coefficient_exp(self, k): + if k not in ZZ: + raise ValueError + k = ZZ(k) + if k.is_zero(): + return self._base.zero() + if k.is_one(): + return self._base.one() + q = self._Fq.cardinality() + if not k.is_power_of(q): + return self._base.zero() + c = self._base.zero() + for i in range(k.log(q)): + j = k.log(q) - i + c += self._compute_coefficient_exp(q**i)*self._compute_coefficient_log(q**j)**(q**i) + return -c + + def exponential(self, name='z'): + L = LazyPowerSeriesRing(self._base, name) + return L(self._compute_coefficient_exp, valuation=1) + def gen(self): r""" Return the generator of the Drinfeld module. @@ -1135,9 +1156,9 @@ def _compute_coefficient_log(self, k): if k not in ZZ: raise TypeError("input must be an integer") k = ZZ(k) - if k == 0: + if k.is_zero(): return self._base.zero() - if k == 1: + if k.is_one(): return self._base.one() r = self._gen.degree() T = self._gen[0] @@ -1178,8 +1199,8 @@ def logarithm(self, name='z'): sage: phi.logarithm() z + ((4*T/(T^4+4))*z^5) + O(z^7) """ - L = LazyPowerSeriesRing(self._base, name, sparse=False) - return L(self._compute_coefficient_log) + L = LazyPowerSeriesRing(self._base, name) + return L(self._compute_coefficient_log, valuation=1) def morphism(self): From bfe9a0c7961fe4c8e6ccc2fdab23e27c26c32bb8 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Sat, 11 Mar 2023 11:15:35 -0500 Subject: [PATCH 05/26] document exponential method --- .../drinfeld_modules/drinfeld_module.py | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) 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 d302b129bb6..9e0faf0fc68 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -963,8 +963,36 @@ def coefficients(self, sparse=True): return self._gen.coefficients(sparse=sparse) def _compute_coefficient_exp(self, k): + r""" + Return the `k`-th coefficient of the logarithm of ``self``. + + INPUT: + + - ``k`` (integer) -- the index of the coefficient + + TESTS:: + + sage: A = GF(2)['T'] + sage: K. = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: q = A.base_ring().cardinality() + sage: phi._compute_coefficient_exp(0) + 0 + sage: phi._compute_coefficient_exp(1) + 1 + sage: phi._compute_coefficient_exp(2) + 1/(T^2 + T) + sage: phi._compute_coefficient_exp(3) + 0 + sage: phi._compute_coefficient_exp(2^4) + 1/(T^64 + T^56 + T^52 + T^50 + T^49 + T^44 + T^42 + T^41 + T^38 + T^37 + T^35 + T^30 + T^29 + T^27 + T^23 + T^15) + sage: phi._compute_coefficient_exp(T) + Traceback (most recent call last): + ... + TypeError: input must be an integer + """ if k not in ZZ: - raise ValueError + raise TypeError("input must be an integer") k = ZZ(k) if k.is_zero(): return self._base.zero() @@ -980,6 +1008,53 @@ def _compute_coefficient_exp(self, k): return -c def exponential(self, name='z'): + r""" + Return the exponential of the given Drinfeld module. + + INPUT: + + - ``name`` (string, default: ``'z'``) -- the name of the generator of + the lazy power series ring. + + EXAMPLES:: + + sage: A = GF(2)['T'] + sage: K. = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: q = A.base_ring().cardinality() + sage: exp = phi.exponential(); exp + z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8) + + The exponential is returned as a lazy power series, meaning that any of + its coefficients can be computed on demands:: + + sage: exp[2^4] + 1/(T^64 + T^56 + T^52 + T^50 + T^49 + T^44 + T^42 + T^41 + T^38 + T^37 + T^35 + T^30 + T^29 + T^27 + T^23 + T^15) + sage: exp[2^5] + 1/(T^160 + T^144 + T^136 + T^132 + T^130 + T^129 + T^120 + T^116 + T^114 + T^113 + T^108 + T^106 + T^105 + T^102 + T^101 + T^99 + T^92 + T^90 + T^89 + T^86 + T^85 + T^83 + T^78 + T^77 + T^75 + T^71 + T^62 + T^61 + T^59 + T^55 + T^47 + T^31) + + Example in higher rank:: + + sage: A = GF(5)['T'] + sage: K. = Frac(A) + 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) + + The exponential is the compositional inverse of the logarithm + (see :meth:`logarithm`):: + + sage: log = phi.logarithm(); log + z + ((4*T/(T^4+4))*z^5) + O(z^8) + sage: exp.compose(log) + z + O(z^8) + sage: log.compose(exp) + z + O(z^8) + + REFERENCE: + + See section 4.6 of [Gos1998]_ for the definition of the exponential. + """ L = LazyPowerSeriesRing(self._base, name) return L(self._compute_coefficient_exp, valuation=1) From 01d620dd1b8491bf72b93e9cbd40b39e4007cb9f Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Sat, 11 Mar 2023 13:42:27 -0500 Subject: [PATCH 06/26] enhance documentation of logarithm --- .../drinfeld_modules/drinfeld_module.py | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) 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 9e0faf0fc68..d74dad8463e 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1051,6 +1051,19 @@ def exponential(self, name='z'): sage: log.compose(exp) z + O(z^8) + TESTS:: + + sage: A = GF(2)['T'] + sage: K. = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: exp = phi.exponential() + sage: exp[2] == 1/(T**q - T) # expected value + True + sage: exp[2^2] == 1/((T**(q**2) - T)*(T**q - T)**q) # expected value + True + sage: exp[2^3] == 1/((T**(q**3) - T)*(T**(q**2) - T)**q*(T**q - T)**(q**2)) # expected value + True + REFERENCE: See section 4.6 of [Gos1998]_ for the definition of the exponential. @@ -1251,28 +1264,45 @@ def logarithm(self, name='z'): r""" Return the logarithm of the given Drinfeld module. + By definition, the logarithm is the compositional inverse of the + exponential (see :meth:`exponential`). + EXAMPLES:: sage: A = GF(2)['T'] sage: K. = Frac(A) sage: phi = DrinfeldModule(A, [T, 1]) - sage: q = A.base_ring().cardinality() sage: log = phi.logarithm(); log - z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^7) - sage: log[q] == -1/((T**q - T)) - True - sage: log[q**2] == 1/((T**q - T)*(T**(q**2) - T)) - True - sage: log[q**3] == -1/((T**q - T)*(T**(q**2) - T)*(T**(q**3) - T)) - True + z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8) - :: + The logarithm is returned as a lazy power series, meaning that any of + its coefficients can be computed on demands:: + + sage: log[2^4] + 1/(T^30 + T^29 + T^27 + T^26 + T^23 + T^22 + T^20 + T^19 + T^15 + T^14 + T^12 + T^11 + T^8 + T^7 + T^5 + T^4) + sage: log[2^5] + 1/(T^62 + T^61 + T^59 + T^58 + T^55 + T^54 + T^52 + T^51 + T^47 + T^46 + T^44 + T^43 + T^40 + T^39 + T^37 + T^36 + T^31 + T^30 + T^28 + T^27 + T^24 + T^23 + T^21 + T^20 + T^16 + T^15 + T^13 + T^12 + T^9 + T^8 + T^6 + T^5) + + Example in higher rank:: sage: A = GF(5)['T'] sage: K. = Frac(A) 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^7) + z + ((4*T/(T^4+4))*z^5) + O(z^8) + + TESTS:: + + sage: A = GF(2)['T'] + sage: K. = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: q = 2 + sage: log[2] == -1/((T**q - T)) # expected value + True + sage: log[2**2] == 1/((T**q - T)*(T**(q**2) - T)) # expected value + True + sage: log[2**3] == -1/((T**q - T)*(T**(q**2) - T)*(T**(q**3) - T)) # expected value + True """ L = LazyPowerSeriesRing(self._base, name) return L(self._compute_coefficient_log, valuation=1) From 643cfde38388eac3d0b131c34003908a7cf7958b Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Thu, 16 Mar 2023 11:56:44 -0400 Subject: [PATCH 07/26] fix some line length and add some details to the doc --- .../drinfeld_modules/drinfeld_module.py | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) 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 d74dad8463e..9fcdfdc52dd 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1013,8 +1013,12 @@ def exponential(self, name='z'): INPUT: - - ``name`` (string, default: ``'z'``) -- the name of the generator of - the lazy power series ring. + - ``name`` (string, default: ``'z'``) -- the name of the + generator of the lazy power series ring. + + OUTPUT: + + A lazy power series over the base field. EXAMPLES:: @@ -1025,8 +1029,8 @@ def exponential(self, name='z'): sage: exp = phi.exponential(); exp z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8) - The exponential is returned as a lazy power series, meaning that any of - its coefficients can be computed on demands:: + The exponential is returned as a lazy power series, meaning that + any of its coefficients can be computed on demands:: sage: exp[2^4] 1/(T^64 + T^56 + T^52 + T^50 + T^49 + T^44 + T^42 + T^41 + T^38 + T^37 + T^35 + T^30 + T^29 + T^27 + T^23 + T^15) @@ -1066,7 +1070,8 @@ def exponential(self, name='z'): REFERENCE: - See section 4.6 of [Gos1998]_ for the definition of the exponential. + See section 4.6 of [Gos1998]_ for the definition of the + exponential. """ L = LazyPowerSeriesRing(self._base, name) return L(self._compute_coefficient_exp, valuation=1) @@ -1267,6 +1272,15 @@ def logarithm(self, name='z'): By definition, the logarithm is the compositional inverse of the exponential (see :meth:`exponential`). + INPUT: + + - ``name`` (string, default: ``'z'``) -- the name of the + generator of the lazy power series ring. + + OUTPUT: + + A lazy power series over the base field. + EXAMPLES:: sage: A = GF(2)['T'] @@ -1275,8 +1289,8 @@ def logarithm(self, name='z'): sage: log = phi.logarithm(); log z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8) - The logarithm is returned as a lazy power series, meaning that any of - its coefficients can be computed on demands:: + The logarithm is returned as a lazy power series, meaning that + any of its coefficients can be computed on demands:: sage: log[2^4] 1/(T^30 + T^29 + T^27 + T^26 + T^23 + T^22 + T^20 + T^19 + T^15 + T^14 + T^12 + T^11 + T^8 + T^7 + T^5 + T^4) From 5356e394fc0e35ac909fd38bbbb6aa362b1126d4 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Fri, 24 Mar 2023 13:44:00 -0400 Subject: [PATCH 08/26] fix mistake --- .../rings/function_field/drinfeld_modules/drinfeld_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9fcdfdc52dd..467923eda44 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -964,7 +964,7 @@ def coefficients(self, sparse=True): def _compute_coefficient_exp(self, k): r""" - Return the `k`-th coefficient of the logarithm of ``self``. + Return the `k`-th coefficient of the exponential of ``self``. INPUT: From 9c8d4a75ff23ed049ccba544d28e505df121a41c Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 12 Apr 2023 17:33:08 -0400 Subject: [PATCH 09/26] small updates --- .../drinfeld_modules/drinfeld_module.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) 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 903481f65c5..982b13a2378 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1027,7 +1027,7 @@ def exponential(self, name='z'): sage: phi = DrinfeldModule(A, [T, 1]) sage: q = A.base_ring().cardinality() sage: exp = phi.exponential(); exp - z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8) + z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^7) The exponential is returned as a lazy power series, meaning that any of its coefficients can be computed on demands:: @@ -1043,13 +1043,13 @@ def exponential(self, name='z'): sage: K. = Frac(A) 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) + z + ((T/(T^4+4))*z^5) + O(z^7) The exponential is the compositional inverse of the logarithm (see :meth:`logarithm`):: sage: log = phi.logarithm(); log - z + ((4*T/(T^4+4))*z^5) + O(z^8) + z + ((4*T/(T^4+4))*z^5) + O(z^7) sage: exp.compose(log) z + O(z^8) sage: log.compose(exp) @@ -1074,7 +1074,8 @@ def exponential(self, name='z'): exponential. """ L = LazyPowerSeriesRing(self._base, name) - return L(self._compute_coefficient_exp, valuation=1) + exp = lambda k: self._compute_coefficient_exp(k) + return L(exp) def gen(self): r""" @@ -1287,7 +1288,7 @@ def logarithm(self, name='z'): sage: K. = Frac(A) sage: phi = DrinfeldModule(A, [T, 1]) sage: log = phi.logarithm(); log - z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8) + z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^7) The logarithm is returned as a lazy power series, meaning that any of its coefficients can be computed on demands:: @@ -1303,7 +1304,7 @@ def logarithm(self, name='z'): sage: K. = Frac(A) 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) + z + ((4*T/(T^4+4))*z^5) + O(z^7) TESTS:: @@ -1319,7 +1320,8 @@ def logarithm(self, name='z'): True """ L = LazyPowerSeriesRing(self._base, name) - return L(self._compute_coefficient_log, valuation=1) + log = lambda k: self._compute_coefficient_log(k) + return L(log) def morphism(self): From 644cafc88d9916afd622fffab1678ca5043315a7 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 12 Apr 2023 23:23:38 -0400 Subject: [PATCH 10/26] (re)add the valuation=1 flag --- .../rings/function_field/drinfeld_modules/drinfeld_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 982b13a2378..9f728cf715e 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1075,7 +1075,7 @@ def exponential(self, name='z'): """ L = LazyPowerSeriesRing(self._base, name) exp = lambda k: self._compute_coefficient_exp(k) - return L(exp) + return L(exp, valuation=1) def gen(self): r""" @@ -1321,7 +1321,7 @@ def logarithm(self, name='z'): """ L = LazyPowerSeriesRing(self._base, name) log = lambda k: self._compute_coefficient_log(k) - return L(log) + return L(log, valuation=1) def morphism(self): From 8323f6f0bbd3bd1095efc6a2d9f83d7331cb6dab Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Sat, 15 Apr 2023 08:47:48 -0400 Subject: [PATCH 11/26] fix failing doctests --- .../function_field/drinfeld_modules/drinfeld_module.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 9f728cf715e..5f41e874c6f 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1027,7 +1027,7 @@ def exponential(self, name='z'): sage: phi = DrinfeldModule(A, [T, 1]) sage: q = A.base_ring().cardinality() sage: exp = phi.exponential(); exp - z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^7) + z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8) The exponential is returned as a lazy power series, meaning that any of its coefficients can be computed on demands:: @@ -1043,13 +1043,13 @@ def exponential(self, name='z'): sage: K. = Frac(A) 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^7) + z + ((T/(T^4+4))*z^5) + O(z^8) The exponential is the compositional inverse of the logarithm (see :meth:`logarithm`):: sage: log = phi.logarithm(); log - z + ((4*T/(T^4+4))*z^5) + O(z^7) + z + ((4*T/(T^4+4))*z^5) + O(z^8) sage: exp.compose(log) z + O(z^8) sage: log.compose(exp) @@ -1288,7 +1288,7 @@ def logarithm(self, name='z'): sage: K. = Frac(A) sage: phi = DrinfeldModule(A, [T, 1]) sage: log = phi.logarithm(); log - z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^7) + z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8) The logarithm is returned as a lazy power series, meaning that any of its coefficients can be computed on demands:: @@ -1304,7 +1304,7 @@ def logarithm(self, name='z'): sage: K. = Frac(A) 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^7) + z + ((4*T/(T^4+4))*z^5) + O(z^8) TESTS:: From eb781112d67a93cba6371a39fd1b110ed6f8a6f1 Mon Sep 17 00:00:00 2001 From: David Ayotte <34245930+DavidAyotte@users.noreply.github.com> Date: Thu, 27 Apr 2023 09:40:22 -0400 Subject: [PATCH 12/26] Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py Co-authored-by: Xavier Caruso --- .../rings/function_field/drinfeld_modules/drinfeld_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5f41e874c6f..c7f12431921 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1009,7 +1009,7 @@ def _compute_coefficient_exp(self, k): def exponential(self, name='z'): r""" - Return the exponential of the given Drinfeld module. + Return the exponential of this Drinfeld module. INPUT: From b73d1ae52e15ed0b639a41dbf99da5c5feb27226 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 26 Apr 2023 19:58:18 -0400 Subject: [PATCH 13/26] remove unnecessary integer type conversion --- .../drinfeld_modules/drinfeld_module.py | 14 -------------- 1 file changed, 14 deletions(-) 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 c7f12431921..95d52f06e1c 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -986,14 +986,7 @@ def _compute_coefficient_exp(self, k): 0 sage: phi._compute_coefficient_exp(2^4) 1/(T^64 + T^56 + T^52 + T^50 + T^49 + T^44 + T^42 + T^41 + T^38 + T^37 + T^35 + T^30 + T^29 + T^27 + T^23 + T^15) - sage: phi._compute_coefficient_exp(T) - Traceback (most recent call last): - ... - TypeError: input must be an integer """ - if k not in ZZ: - raise TypeError("input must be an integer") - k = ZZ(k) if k.is_zero(): return self._base.zero() if k.is_one(): @@ -1242,14 +1235,7 @@ def _compute_coefficient_log(self, k): 0 sage: phi._compute_coefficient_log(2^4) 1/(T^30 + T^29 + T^27 + T^26 + T^23 + T^22 + T^20 + T^19 + T^15 + T^14 + T^12 + T^11 + T^8 + T^7 + T^5 + T^4) - sage: phi._compute_coefficient_log(T) - Traceback (most recent call last): - ... - TypeError: input must be an integer """ - if k not in ZZ: - raise TypeError("input must be an integer") - k = ZZ(k) if k.is_zero(): return self._base.zero() if k.is_one(): From ba57245bd0cc68ddbc6bf5d8e34d01b5c1cb7305 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 26 Apr 2023 20:00:46 -0400 Subject: [PATCH 14/26] add cached_method decorator --- .../rings/function_field/drinfeld_modules/drinfeld_module.py | 3 +++ 1 file changed, 3 insertions(+) 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 95d52f06e1c..b69314aa908 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -26,6 +26,7 @@ from sage.categories.drinfeld_modules import DrinfeldModules from sage.categories.homset import Hom +from sage.misc.cachefunc import cached_method from sage.misc.latex import latex from sage.misc.latex import latex_variable_name from sage.misc.lazy_import import lazy_import @@ -962,6 +963,7 @@ def coefficients(self, sparse=True): """ return self._gen.coefficients(sparse=sparse) + @cached_method def _compute_coefficient_exp(self, k): r""" Return the `k`-th coefficient of the exponential of ``self``. @@ -1215,6 +1217,7 @@ def j_invariant(self): q = self._Fq.order() return (g**(q+1)) / delta + @cached_method def _compute_coefficient_log(self, k): r""" Return the `k`-th coefficient of the logarithm of ``self``. From 364fd558f459b581015efebbc62bbf6420b2196a Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 26 Apr 2023 20:05:09 -0400 Subject: [PATCH 15/26] use ellipsis --- .../function_field/drinfeld_modules/drinfeld_module.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 b69314aa908..a1ac0f0a1ef 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1028,9 +1028,9 @@ def exponential(self, name='z'): any of its coefficients can be computed on demands:: sage: exp[2^4] - 1/(T^64 + T^56 + T^52 + T^50 + T^49 + T^44 + T^42 + T^41 + T^38 + T^37 + T^35 + T^30 + T^29 + T^27 + T^23 + T^15) + 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^132 + T^130 + T^129 + T^120 + T^116 + T^114 + T^113 + T^108 + T^106 + T^105 + T^102 + T^101 + T^99 + T^92 + T^90 + T^89 + T^86 + T^85 + T^83 + T^78 + T^77 + T^75 + T^71 + T^62 + T^61 + T^59 + T^55 + T^47 + T^31) + 1/(T^160 + T^144 + T^136 + ... + T^55 + T^47 + T^31) Example in higher rank:: @@ -1283,9 +1283,9 @@ def logarithm(self, name='z'): any of its coefficients can be computed on demands:: sage: log[2^4] - 1/(T^30 + T^29 + T^27 + T^26 + T^23 + T^22 + T^20 + T^19 + T^15 + T^14 + T^12 + T^11 + T^8 + T^7 + T^5 + T^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^58 + T^55 + T^54 + T^52 + T^51 + T^47 + T^46 + T^44 + T^43 + T^40 + T^39 + T^37 + T^36 + T^31 + T^30 + T^28 + T^27 + T^24 + T^23 + T^21 + T^20 + T^16 + T^15 + T^13 + T^12 + T^9 + T^8 + T^6 + T^5) + 1/(T^62 + T^61 + T^59 + ... + T^8 + T^6 + T^5) Example in higher rank:: From 8f292e9c7e2e217855ef53adf6a4b8fdf9dc3fbe Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 26 Apr 2023 20:10:25 -0400 Subject: [PATCH 16/26] fix failing doctets --- .../rings/function_field/drinfeld_modules/drinfeld_module.py | 2 ++ 1 file changed, 2 insertions(+) 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 a1ac0f0a1ef..302f541ed85 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -989,6 +989,7 @@ def _compute_coefficient_exp(self, k): sage: phi._compute_coefficient_exp(2^4) 1/(T^64 + T^56 + T^52 + T^50 + T^49 + T^44 + T^42 + T^41 + T^38 + T^37 + T^35 + T^30 + T^29 + T^27 + T^23 + T^15) """ + k = ZZ(k) if k.is_zero(): return self._base.zero() if k.is_one(): @@ -1239,6 +1240,7 @@ def _compute_coefficient_log(self, k): sage: phi._compute_coefficient_log(2^4) 1/(T^30 + T^29 + T^27 + T^26 + T^23 + T^22 + T^20 + T^19 + T^15 + T^14 + T^12 + T^11 + T^8 + T^7 + T^5 + T^4) """ + k = ZZ(k) if k.is_zero(): return self._base.zero() if k.is_one(): From 1504a19b48623084ad60ce8a4550c931758993a2 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Thu, 27 Apr 2023 12:41:41 -0400 Subject: [PATCH 17/26] add checks for finite Drinfeld modules --- .../drinfeld_modules/drinfeld_module.py | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) 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 302f541ed85..2d2ddf31098 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1007,6 +1007,9 @@ def exponential(self, name='z'): r""" Return the exponential of this Drinfeld module. + Note that the exponential is only defined for Drinfeld modules + over nonfinite field. + INPUT: - ``name`` (string, default: ``'z'``) -- the name of the @@ -1051,6 +1054,16 @@ def exponential(self, name='z'): sage: log.compose(exp) z + O(z^8) + :: + + sage: Fq. = GF(3) + sage: A = Fq['T'] + sage: phi = DrinfeldModule(A, [w, 1]) + sage: phi.exponential() + Traceback (most recent call last): + ... + ValueError: base field must not be finite + TESTS:: sage: A = GF(2)['T'] @@ -1069,6 +1082,8 @@ def exponential(self, name='z'): See section 4.6 of [Gos1998]_ for the definition of the exponential. """ + if self.is_finite(): + raise ValueError("base field must not be finite") L = LazyPowerSeriesRing(self._base, name) exp = lambda k: self._compute_coefficient_exp(k) return L(exp, valuation=1) @@ -1262,7 +1277,8 @@ def logarithm(self, name='z'): Return the logarithm of the given Drinfeld module. By definition, the logarithm is the compositional inverse of the - exponential (see :meth:`exponential`). + exponential (see :meth:`exponential`). Note that the logarithm + is only defined for Drinfeld modules over nonfinite field. INPUT: @@ -1309,7 +1325,19 @@ def logarithm(self, name='z'): True sage: log[2**3] == -1/((T**q - T)*(T**(q**2) - T)*(T**(q**3) - T)) # expected value True + + :: + + sage: Fq. = GF(3) + sage: A = Fq['T'] + sage: phi = DrinfeldModule(A, [w, 1]) + sage: phi.logarithm() + Traceback (most recent call last): + ... + ValueError: base field must not be finite """ + if self.is_finite(): + raise ValueError("base field must not be finite") L = LazyPowerSeriesRing(self._base, name) log = lambda k: self._compute_coefficient_log(k) return L(log, valuation=1) From 706ded593f7cb06b51e9ec7e6a4bb10b07cb7290 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Thu, 27 Apr 2023 13:42:29 -0400 Subject: [PATCH 18/26] update error message --- .../function_field/drinfeld_modules/drinfeld_module.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 2d2ddf31098..e58d0189230 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1062,7 +1062,7 @@ def exponential(self, name='z'): sage: phi.exponential() Traceback (most recent call last): ... - ValueError: base field must not be finite + ValueError: characteristic must be zero (=T + 2) TESTS:: @@ -1083,7 +1083,7 @@ def exponential(self, name='z'): exponential. """ if self.is_finite(): - raise ValueError("base field must not be finite") + raise ValueError(f"characteristic must be zero (={self.characteristic()})") L = LazyPowerSeriesRing(self._base, name) exp = lambda k: self._compute_coefficient_exp(k) return L(exp, valuation=1) @@ -1334,10 +1334,10 @@ def logarithm(self, name='z'): sage: phi.logarithm() Traceback (most recent call last): ... - ValueError: base field must not be finite + ValueError: characteristic must be zero (=T + 2) """ if self.is_finite(): - raise ValueError("base field must not be finite") + raise ValueError(f"characteristic must be zero (={self.characteristic()})") L = LazyPowerSeriesRing(self._base, name) log = lambda k: self._compute_coefficient_log(k) return L(log, valuation=1) From 26498b8f2e11369837ddad6d0a3b90f60506c9f7 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Thu, 4 May 2023 10:33:38 -0400 Subject: [PATCH 19/26] refactor _compute_coefficient methods --- .../drinfeld_modules/drinfeld_module.py | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) 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 e58d0189230..27d5c4ee5f3 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -979,28 +979,22 @@ def _compute_coefficient_exp(self, k): sage: phi = DrinfeldModule(A, [T, 1]) sage: q = A.base_ring().cardinality() sage: phi._compute_coefficient_exp(0) - 0 - sage: phi._compute_coefficient_exp(1) 1 - sage: phi._compute_coefficient_exp(2) + sage: phi._compute_coefficient_exp(1) 1/(T^2 + T) + sage: phi._compute_coefficient_exp(2) + 1/(T^8 + T^6 + T^5 + T^3) sage: phi._compute_coefficient_exp(3) - 0 - sage: phi._compute_coefficient_exp(2^4) - 1/(T^64 + T^56 + T^52 + T^50 + T^49 + T^44 + T^42 + T^41 + T^38 + T^37 + T^35 + T^30 + T^29 + T^27 + T^23 + T^15) + 1/(T^24 + T^20 + T^18 + T^17 + T^14 + T^13 + T^11 + T^7) """ k = ZZ(k) if k.is_zero(): - return self._base.zero() - if k.is_one(): return self._base.one() q = self._Fq.cardinality() - if not k.is_power_of(q): - return self._base.zero() c = self._base.zero() - for i in range(k.log(q)): - j = k.log(q) - i - c += self._compute_coefficient_exp(q**i)*self._compute_coefficient_log(q**j)**(q**i) + for i in range(k): + j = k - i + c += self._compute_coefficient_exp(i)*self._compute_coefficient_log(j)**(q**i) return -c def exponential(self, name='z'): @@ -1085,7 +1079,9 @@ def exponential(self, name='z'): if self.is_finite(): raise ValueError(f"characteristic must be zero (={self.characteristic()})") L = LazyPowerSeriesRing(self._base, name) - exp = lambda k: self._compute_coefficient_exp(k) + zero = self._base.zero() + q = self._Fq.cardinality() + exp = lambda k: self._compute_coefficient_exp(ZZ(k).log(q)) if ZZ(k).is_power_of(q) or k == 0 else zero return L(exp, valuation=1) def gen(self): @@ -1245,32 +1241,26 @@ def _compute_coefficient_log(self, k): sage: phi = DrinfeldModule(A, [T, 1]) sage: q = A.base_ring().cardinality() sage: phi._compute_coefficient_log(0) - 0 - sage: phi._compute_coefficient_log(1) 1 - sage: phi._compute_coefficient_log(2) + sage: phi._compute_coefficient_log(1) 1/(T^2 + T) + sage: phi._compute_coefficient_log(2) + 1/(T^6 + T^5 + T^3 + T^2) sage: phi._compute_coefficient_log(3) - 0 - sage: phi._compute_coefficient_log(2^4) - 1/(T^30 + T^29 + T^27 + T^26 + T^23 + T^22 + T^20 + T^19 + T^15 + T^14 + T^12 + T^11 + T^8 + T^7 + T^5 + T^4) + 1/(T^14 + T^13 + T^11 + T^10 + T^7 + T^6 + T^4 + T^3) """ k = ZZ(k) if k.is_zero(): - return self._base.zero() - if k.is_one(): return self._base.one() r = self._gen.degree() T = self._gen[0] q = self._Fq.cardinality() - if not k.is_power_of(q): - return self._base.zero() c = self._base.zero() - for i in range(k.log(q)): - j = k.log(q) - i + for i in range(k): + j = k - i if j < r + 1: - c += self._compute_coefficient_log(q**i)*self._gen[j]**(q**i) - return c/(T - T**k) + c += self._compute_coefficient_log(i)*self._gen[j]**(q**i) + return c/(T - T**(q**k)) def logarithm(self, name='z'): r""" @@ -1339,7 +1329,9 @@ def logarithm(self, name='z'): if self.is_finite(): raise ValueError(f"characteristic must be zero (={self.characteristic()})") L = LazyPowerSeriesRing(self._base, name) - log = lambda k: self._compute_coefficient_log(k) + zero = self._base.zero() + q = self._Fq.cardinality() + log = lambda k: self._compute_coefficient_log(ZZ(k).log(q)) if ZZ(k).is_power_of(q) or k == 0 else zero return L(log, valuation=1) From 005acd55c0cf3954f448067f8e61bfad6ac26feb Mon Sep 17 00:00:00 2001 From: David Ayotte <34245930+DavidAyotte@users.noreply.github.com> Date: Thu, 4 May 2023 14:01:54 -0400 Subject: [PATCH 20/26] Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py Co-authored-by: Xavier Caruso --- .../rings/function_field/drinfeld_modules/drinfeld_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 27d5c4ee5f3..efad8883ea3 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -966,7 +966,7 @@ def coefficients(self, sparse=True): @cached_method def _compute_coefficient_exp(self, k): r""" - Return the `k`-th coefficient of the exponential of ``self``. + Return the `q^k`-th coefficient of the exponential of this Drinfeld module. INPUT: From 7f72a218408df30b7bfc4387490bc90f7a4fe04b Mon Sep 17 00:00:00 2001 From: David Ayotte <34245930+DavidAyotte@users.noreply.github.com> Date: Thu, 4 May 2023 14:02:16 -0400 Subject: [PATCH 21/26] Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py Co-authored-by: Xavier Caruso --- .../rings/function_field/drinfeld_modules/drinfeld_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 efad8883ea3..99aa500a6dd 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1232,7 +1232,7 @@ def j_invariant(self): @cached_method def _compute_coefficient_log(self, k): r""" - Return the `k`-th coefficient of the logarithm of ``self``. + Return the `q^k`-th coefficient of the logarithm of this Drinfeld module. TESTS:: From 962e70db82de734aa023123aa1d8798c9f1a5946 Mon Sep 17 00:00:00 2001 From: David Ayotte <34245930+DavidAyotte@users.noreply.github.com> Date: Fri, 5 May 2023 13:33:48 -0400 Subject: [PATCH 22/26] Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py Co-authored-by: Xavier Caruso --- .../rings/function_field/drinfeld_modules/drinfeld_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 99aa500a6dd..694e0529697 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1076,7 +1076,7 @@ def exponential(self, name='z'): See section 4.6 of [Gos1998]_ for the definition of the exponential. """ - if self.is_finite(): + if not self.category()._characteristic: raise ValueError(f"characteristic must be zero (={self.characteristic()})") L = LazyPowerSeriesRing(self._base, name) zero = self._base.zero() From 3e873b95ba45cf11ccde74c6e65612faac6e435b Mon Sep 17 00:00:00 2001 From: David Ayotte <34245930+DavidAyotte@users.noreply.github.com> Date: Fri, 5 May 2023 13:34:00 -0400 Subject: [PATCH 23/26] Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py Co-authored-by: Xavier Caruso --- .../rings/function_field/drinfeld_modules/drinfeld_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 694e0529697..b4f6ee79b60 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1326,7 +1326,7 @@ def logarithm(self, name='z'): ... ValueError: characteristic must be zero (=T + 2) """ - if self.is_finite(): + if not self.category()._characteristic: raise ValueError(f"characteristic must be zero (={self.characteristic()})") L = LazyPowerSeriesRing(self._base, name) zero = self._base.zero() From f8c867d032c6d80ba2fb89373b86dab3ecf7beea Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Fri, 5 May 2023 12:52:32 -0400 Subject: [PATCH 24/26] fix failing doctest --- .../rings/function_field/drinfeld_modules/drinfeld_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 b4f6ee79b60..21b2dfcb56e 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1076,7 +1076,7 @@ def exponential(self, name='z'): See section 4.6 of [Gos1998]_ for the definition of the exponential. """ - if not self.category()._characteristic: + if self.category()._characteristic: raise ValueError(f"characteristic must be zero (={self.characteristic()})") L = LazyPowerSeriesRing(self._base, name) zero = self._base.zero() @@ -1326,7 +1326,7 @@ def logarithm(self, name='z'): ... ValueError: characteristic must be zero (=T + 2) """ - if not self.category()._characteristic: + if self.category()._characteristic: raise ValueError(f"characteristic must be zero (={self.characteristic()})") L = LazyPowerSeriesRing(self._base, name) zero = self._base.zero() From e85227e63b6c4671c6bb8584b2b9a7acc2d653cc Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Fri, 5 May 2023 13:48:37 -0400 Subject: [PATCH 25/26] minor update to documentation of exponential and logarithm --- .../function_field/drinfeld_modules/drinfeld_module.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 21b2dfcb56e..8bcadf4dbac 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1001,8 +1001,8 @@ def exponential(self, name='z'): r""" Return the exponential of this Drinfeld module. - Note that the exponential is only defined for Drinfeld modules - over nonfinite field. + Note that the exponential is only defined when the + `\mathbb{F}_q[T]`-characteristic is zero. INPUT: @@ -1268,7 +1268,8 @@ def logarithm(self, name='z'): By definition, the logarithm is the compositional inverse of the exponential (see :meth:`exponential`). Note that the logarithm - is only defined for Drinfeld modules over nonfinite field. + is only defined when the `\mathbb{F}_q[T]`-characteristic is + zero. INPUT: From 2b242fbf012de88bb4851c62c312403e2d30f864 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Sun, 14 May 2023 18:19:22 -0400 Subject: [PATCH 26/26] refactor exponential and logarithm --- .../drinfeld_modules/drinfeld_module.py | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) 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 8bcadf4dbac..9c8b2ecde94 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -1081,8 +1081,15 @@ def exponential(self, name='z'): L = LazyPowerSeriesRing(self._base, name) zero = self._base.zero() q = self._Fq.cardinality() - exp = lambda k: self._compute_coefficient_exp(ZZ(k).log(q)) if ZZ(k).is_power_of(q) or k == 0 else zero - return L(exp, valuation=1) + + def coeff_exp(k): + # Return the k-th coefficient of the exponential. + k = ZZ(k) + if k.is_power_of(q): + return self._compute_coefficient_exp(k.log(q)) + else: + return zero + return L(coeff_exp, valuation=1) def gen(self): r""" @@ -1332,8 +1339,15 @@ def logarithm(self, name='z'): L = LazyPowerSeriesRing(self._base, name) zero = self._base.zero() q = self._Fq.cardinality() - log = lambda k: self._compute_coefficient_log(ZZ(k).log(q)) if ZZ(k).is_power_of(q) or k == 0 else zero - return L(log, valuation=1) + + def coeff_log(k): + # Return the k-th coefficient of the logarithm + k = ZZ(k) + if k.is_power_of(q): + return self._compute_coefficient_log(k.log(q)) + else: + return self._base.zero() + return L(coeff_log, valuation=1) def morphism(self):