Skip to content

Commit d8ef9cc

Browse files
author
Release Manager
committed
sagemathgh-40433: Constructor for the Carlitz module We add a constructor for instantiating easily the Carlitz module. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [ ] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [x] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies sagemath#40430, sagemath#40436 URL: sagemath#40433 Reported by: Xavier Caruso Reviewer(s): Antoine Leudière, Xavier Caruso
2 parents f99f68c + 5dc097f commit d8ef9cc

File tree

7 files changed

+244
-83
lines changed

7 files changed

+244
-83
lines changed

src/sage/categories/drinfeld_modules.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ def characteristic(self):
439439
440440
::
441441
442-
sage: psi = DrinfeldModule(A, [Frac(A).gen(), 1])
442+
sage: psi = DrinfeldModule(A, [T, 1])
443443
sage: C = psi.category()
444444
sage: C.characteristic()
445445
0
@@ -640,7 +640,7 @@ def base(self):
640640
641641
The base can be infinite::
642642
643-
sage: sigma = DrinfeldModule(A, [Frac(A).gen(), 1])
643+
sage: sigma = DrinfeldModule(A, [T, 1])
644644
sage: sigma.base()
645645
Fraction Field of Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 over its base
646646
"""
@@ -665,7 +665,7 @@ def base_morphism(self):
665665
666666
The base field can be infinite::
667667
668-
sage: sigma = DrinfeldModule(A, [Frac(A).gen(), 1])
668+
sage: sigma = DrinfeldModule(A, [T, 1])
669669
sage: sigma.base_morphism()
670670
Coercion map:
671671
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
@@ -712,8 +712,7 @@ def characteristic(self):
712712
::
713713
714714
sage: B.<Y> = Fq[]
715-
sage: L = Frac(B)
716-
sage: psi = DrinfeldModule(A, [L(1), 0, 0, L(1)])
715+
sage: psi = DrinfeldModule(A, [B(1), 0, 0, 1])
717716
sage: psi.characteristic()
718717
Traceback (most recent call last):
719718
...

src/sage/rings/function_field/all.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33
from sage.misc.lazy_import import lazy_import
44

55
lazy_import("sage.rings.function_field.drinfeld_modules.drinfeld_module", "DrinfeldModule")
6+
lazy_import("sage.rings.function_field.drinfeld_modules.carlitz_module", "CarlitzModule")
7+
lazy_import("sage.rings.function_field.drinfeld_modules.carlitz_module", "carlitz_exponential")
8+
lazy_import("sage.rings.function_field.drinfeld_modules.carlitz_module", "carlitz_logarithm")
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
r"""
2+
Carlitz module
3+
4+
AUTHORS:
5+
6+
- Xavier Caruso (2025-07): initial version
7+
"""
8+
9+
# *****************************************************************************
10+
# Copyright (C) 2025 Xavier Caruso <[email protected]>
11+
#
12+
# This program is free software: you can redistribute it and/or modify
13+
# it under the terms of the GNU General Public License as published by
14+
# the Free Software Foundation, either version 2 of the License, or
15+
# (at your option) any later version.
16+
# http://www.gnu.org/licenses/
17+
# *****************************************************************************
18+
19+
from sage.structure.parent import Parent
20+
from sage.structure.element import Element
21+
from sage.categories.finite_fields import FiniteFields
22+
23+
from sage.rings.infinity import Infinity
24+
25+
from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic
26+
from sage.rings.function_field.drinfeld_modules.drinfeld_module import DrinfeldModule
27+
28+
29+
def CarlitzModule(A, base=None):
30+
r"""
31+
Return the Carlitz module over `A`.
32+
33+
INPUT:
34+
35+
- ``A`` -- a polynomial ring over a finite field
36+
37+
- ``base`` -- a field, an element in a field or a
38+
string (default: the fraction field of ``A``)
39+
40+
EXAMPLES::
41+
42+
sage: Fq = GF(7)
43+
sage: A.<T> = Fq[]
44+
sage: CarlitzModule(A)
45+
Drinfeld module defined by T |--> τ + T
46+
47+
We can specify a different base.
48+
This is interesting for instance for having two different variable
49+
names::
50+
51+
sage: R.<z> = Fq[]
52+
sage: CarlitzModule(A, R)
53+
Drinfeld module defined by T |--> τ + z
54+
55+
One can even use the following shortcut, which avoids the
56+
construction of `R`::
57+
58+
sage: CarlitzModule(A, 'z')
59+
Drinfeld module defined by T |--> τ + z
60+
61+
Using a similar syntax, we can construct the reduction of the
62+
Carlitz module modulo primes::
63+
64+
sage: F.<a> = Fq.extension(z^2 + 1)
65+
sage: CarlitzModule(A, F)
66+
Drinfeld module defined by T |--> τ + a
67+
68+
It is also possible to pass in any element in the base field
69+
(in this case, the result might not be strictly speaking the
70+
Carlitz module, but it is always a Drinfeld module of rank 1)::
71+
72+
sage: CarlitzModule(A, z^2)
73+
Drinfeld module defined by T |--> τ + z^2
74+
75+
TESTS::
76+
77+
sage: CarlitzModule(Fq)
78+
Traceback (most recent call last):
79+
...
80+
TypeError: the function ring must be defined over a finite field
81+
82+
::
83+
84+
sage: S.<x,y> = QQ[]
85+
sage: CarlitzModule(A, S)
86+
Traceback (most recent call last):
87+
...
88+
ValueError: function ring base must coerce into base field
89+
"""
90+
if (not isinstance(A, PolynomialRing_generic)
91+
or A.base_ring() not in FiniteFields()):
92+
raise TypeError('the function ring must be defined over a finite field')
93+
if base is None:
94+
K = A.fraction_field()
95+
z = K.gen()
96+
elif isinstance(base, Parent):
97+
if base.has_coerce_map_from(A):
98+
z = base(A.gen())
99+
else:
100+
z = base.gen()
101+
elif isinstance(base, Element):
102+
z = base
103+
elif isinstance(base, str):
104+
K = A.base_ring()[base]
105+
z = K.gen()
106+
else:
107+
raise ValueError("cannot construct a Carlitz module from the given data")
108+
return DrinfeldModule(A, [z, 1])
109+
110+
111+
def carlitz_exponential(A, prec=+Infinity, name='z'):
112+
r"""
113+
Return the Carlitz exponential attached the ring `A`.
114+
115+
INPUT:
116+
117+
- ``prec`` -- an integer or ``Infinity`` (default: ``Infinity``);
118+
the precision at which the series is returned; if ``Infinity``,
119+
a lazy power series in returned, else, a classical power series
120+
is returned.
121+
122+
- ``name`` -- string (default: ``'z'``); the name of the
123+
generator of the lazy power series ring
124+
125+
EXAMPLES::
126+
127+
sage: A.<T> = GF(2)[]
128+
129+
When ``prec`` is ``Infinity`` (which is the default),
130+
the exponential is returned as a lazy power series, meaning
131+
that any of its coefficients can be computed on demands::
132+
133+
sage: exp = carlitz_exponential(A)
134+
sage: exp
135+
z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8)
136+
sage: exp[2^4]
137+
1/(T^64 + T^56 + T^52 + ... + T^27 + T^23 + T^15)
138+
sage: exp[2^5]
139+
1/(T^160 + T^144 + T^136 + ... + T^55 + T^47 + T^31)
140+
141+
On the contrary, when ``prec`` is a finite number, all the
142+
required coefficients are computed at once::
143+
144+
sage: carlitz_exponential(A, prec=10)
145+
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)
146+
147+
We check that the Carlitz exponential is the compositional inverse
148+
of the Carlitz logarithm::
149+
150+
sage: log = carlitz_logarithm(A)
151+
sage: exp(log)
152+
z + O(z^8)
153+
sage: log(exp)
154+
z + O(z^8)
155+
"""
156+
C = CarlitzModule(A)
157+
return C.exponential(prec, name)
158+
159+
160+
def carlitz_logarithm(A, prec=+Infinity, name='z'):
161+
r"""
162+
Return the Carlitz exponential attached the ring `A`.
163+
164+
INPUT:
165+
166+
- ``prec`` -- an integer or ``Infinity`` (default: ``Infinity``);
167+
the precision at which the series is returned; if ``Infinity``,
168+
a lazy power series in returned, else, a classical power series
169+
is returned.
170+
171+
- ``name`` -- string (default: ``'z'``); the name of the
172+
generator of the lazy power series ring
173+
174+
EXAMPLES::
175+
176+
sage: A.<T> = GF(2)[]
177+
178+
When ``prec`` is ``Infinity`` (which is the default),
179+
the exponential is returned as a lazy power series, meaning
180+
that any of its coefficients can be computed on demands::
181+
182+
sage: log = carlitz_logarithm(A)
183+
sage: log
184+
z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8)
185+
sage: log[2^4]
186+
1/(T^30 + T^29 + T^27 + ... + T^7 + T^5 + T^4)
187+
sage: log[2^5]
188+
1/(T^62 + T^61 + T^59 + ... + T^8 + T^6 + T^5)
189+
190+
On the contrary, when ``prec`` is a finite number, all the
191+
required coefficients are computed at once::
192+
193+
sage: carlitz_logarithm(A, prec=10)
194+
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)
195+
"""
196+
C = CarlitzModule(A)
197+
return C.logarithm(prec, name)

0 commit comments

Comments
 (0)