Skip to content

Commit d27443e

Browse files
author
Release Manager
committed
sagemathgh-40421: Limit the use of RingExtensions in Drinfeld modules Behaviour before this PR: If `phi` is a Drinfeld module, the method `phi.ore_polring()` used to return an Ore polynomial ring with coefficients in `RingExtension`. This causes a lot of headache because currently an instance of `RingExtension` does not always belong to the appropriate category and, consequently, does not implement all relevant methods and/or is not recognized as what it actually is (e.g. a finite field). In this PR, we propose a simple fix: we let `phi.ore_polring()` return an Ore polynomial ring over the underlying regular field. This only changes the way things are printed, but does not alter the user interface. We will maybe come back later to the original implementation when `RingExtension` will be fixed (which does not seem to be straightforward). ### 📝 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. URL: sagemath#40421 Reported by: Xavier Caruso Reviewer(s): Antoine Leudière
2 parents c88a0e9 + 58c4b14 commit d27443e

File tree

4 files changed

+45
-63
lines changed

4 files changed

+45
-63
lines changed

src/sage/categories/drinfeld_modules.py

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class DrinfeldModules(Category_over_base_ring):
7070
sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1])
7171
sage: C = phi.category()
7272
sage: C
73-
Category of Drinfeld modules over Finite Field in z of size 11^4 over its base
73+
Category of Drinfeld modules over Finite Field in z of size 11^4
7474
7575
The output tells the user that the category is only defined by its
7676
base.
@@ -88,7 +88,7 @@ class DrinfeldModules(Category_over_base_ring):
8888
sage: C.base_morphism()
8989
Ring morphism:
9090
From: Univariate Polynomial Ring in T over Finite Field of size 11
91-
To: Finite Field in z of size 11^4 over its base
91+
To: Finite Field in z of size 11^4
9292
Defn: T |--> z^3 + 7*z^2 + 6*z + 10
9393
9494
The so-called constant coefficient --- which is the same for all
@@ -123,7 +123,7 @@ class DrinfeldModules(Category_over_base_ring):
123123
True
124124
125125
sage: C.ore_polring()
126-
Ore Polynomial Ring in t over Finite Field in z of size 11^4 over its base twisted by Frob
126+
Ore Polynomial Ring in t over Finite Field in z of size 11^4 twisted by z |--> z^11
127127
sage: C.ore_polring() is phi.ore_polring()
128128
True
129129
@@ -165,20 +165,24 @@ class DrinfeldModules(Category_over_base_ring):
165165
sage: K.<z> = Fq.extension(4)
166166
sage: from sage.categories.drinfeld_modules import DrinfeldModules
167167
sage: base = Hom(A, K)(0)
168-
sage: C = DrinfeldModules(base)
168+
sage: C = DrinfeldModules(base) # known bug (blankline)
169+
<BLANKLINE>
169170
Traceback (most recent call last):
170171
...
171172
TypeError: base field must be a ring extension
172173
173-
::
174+
Note that `C.base_morphism()` has codomain `K` while
175+
the defining morphism of `C.base()` has codomain `K` viewed
176+
as an `A`-field. Thus, they differ::
174177
175178
sage: C.base().defining_morphism() == C.base_morphism()
176-
True
179+
False
177180
178181
::
179182
180183
sage: base = Hom(A, A)(1)
181-
sage: C = DrinfeldModules(base)
184+
sage: C = DrinfeldModules(base) # known bug (blankline)
185+
<BLANKLINE>
182186
Traceback (most recent call last):
183187
...
184188
TypeError: base field must be a ring extension
@@ -203,7 +207,7 @@ class DrinfeldModules(Category_over_base_ring):
203207
TypeError: function ring base must be a finite field
204208
"""
205209

206-
def __init__(self, base_field, name='t'):
210+
def __init__(self, base_morphism, name='t'):
207211
r"""
208212
Initialize ``self``.
209213
@@ -223,34 +227,23 @@ def __init__(self, base_field, name='t'):
223227
sage: p_root = z^3 + 7*z^2 + 6*z + 10
224228
sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1])
225229
sage: C = phi.category()
226-
sage: ore_polring.<t> = OrePolynomialRing(phi.base(), phi.base().frobenius_endomorphism())
230+
sage: ore_polring.<t> = OrePolynomialRing(K, K.frobenius_endomorphism())
227231
sage: C._ore_polring is ore_polring
228232
True
229-
sage: i = phi.base().coerce_map_from(K)
230-
sage: base_morphism = Hom(A, K)(p_root)
231-
sage: C.base() == K.over(base_morphism)
232-
True
233-
sage: C._base_morphism == i * base_morphism
234-
True
235233
sage: C._function_ring is A
236234
True
237-
sage: C._constant_coefficient == base_morphism(T)
235+
sage: C._constant_coefficient == C._base_morphism(T)
238236
True
239237
sage: C._characteristic(C._constant_coefficient)
240238
0
241239
"""
242-
# Check input is a ring extension
243-
if not isinstance(base_field, RingExtension_generic):
244-
raise TypeError('base field must be a ring extension')
245-
base_morphism = base_field.defining_morphism()
246240
self._base_morphism = base_morphism
241+
function_ring = self._function_ring = base_morphism.domain()
242+
base_field = self._base_field = base_morphism.codomain()
247243
# Check input is a field
248244
if not base_field.is_field():
249245
raise TypeError('input must be a field')
250-
self._base_field = base_field
251-
self._function_ring = base_morphism.domain()
252246
# Check domain of base morphism is Fq[T]
253-
function_ring = self._function_ring
254247
if not isinstance(function_ring, PolynomialRing_generic):
255248
raise NotImplementedError('function ring must be a polynomial '
256249
'ring')
@@ -262,7 +255,7 @@ def __init__(self, base_field, name='t'):
262255
Fq = function_ring_base
263256
A = function_ring
264257
T = A.gen()
265-
K = base_field # A ring extension
258+
K = base_field
266259
# Build K{t}
267260
d = log(Fq.cardinality(), Fq.characteristic())
268261
tau = K.frobenius_endomorphism(d)
@@ -284,7 +277,7 @@ def __init__(self, base_field, name='t'):
284277
i = A.coerce_map_from(Fq)
285278
Fq_to_K = self._base_morphism * i
286279
self._base_over_constants_field = base_field.over(Fq_to_K)
287-
super().__init__(base=base_field)
280+
super().__init__(base=base_field.over(base_morphism))
288281

289282
def _latex_(self):
290283
r"""
@@ -321,7 +314,7 @@ def _repr_(self):
321314
sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1])
322315
sage: C = phi.category()
323316
sage: C
324-
Category of Drinfeld modules over Finite Field in z of size 11^4 over its base
317+
Category of Drinfeld modules over Finite Field in z of size 11^4
325318
"""
326319
return f'Category of Drinfeld modules over {self._base_field}'
327320

@@ -402,7 +395,7 @@ def base_morphism(self):
402395
sage: C.base_morphism()
403396
Ring morphism:
404397
From: Univariate Polynomial Ring in T over Finite Field of size 11
405-
To: Finite Field in z of size 11^4 over its base
398+
To: Finite Field in z of size 11^4
406399
Defn: T |--> z^3 + 7*z^2 + 6*z + 10
407400
408401
sage: C.constant_coefficient() == C.base_morphism()(T)
@@ -541,7 +534,7 @@ def ore_polring(self):
541534
sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1])
542535
sage: C = phi.category()
543536
sage: C.ore_polring()
544-
Ore Polynomial Ring in t over Finite Field in z of size 11^4 over its base twisted by Frob
537+
Ore Polynomial Ring in t over Finite Field in z of size 11^4 twisted by z |--> z^11
545538
"""
546539
return self._ore_polring
547540

@@ -666,17 +659,16 @@ def base_morphism(self):
666659
sage: phi.base_morphism()
667660
Ring morphism:
668661
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
669-
To: Finite Field in z12 of size 5^12 over its base
662+
To: Finite Field in z12 of size 5^12
670663
Defn: 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
671664
672665
The base field can be infinite::
673666
674667
sage: sigma = DrinfeldModule(A, [Frac(A).gen(), 1])
675668
sage: sigma.base_morphism()
676-
Ring morphism:
669+
Coercion map:
677670
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
678-
To: Fraction Field of Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 over its base
679-
Defn: T |--> T
671+
To: Fraction Field of Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
680672
"""
681673
return self.category().base_morphism()
682674

@@ -804,7 +796,7 @@ def ore_polring(self):
804796
sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5])
805797
sage: S = phi.ore_polring()
806798
sage: S
807-
Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 over its base twisted by Frob^2
799+
Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 twisted by z12 |--> z12^(5^2)
808800
809801
The Ore polynomial ring can also be retrieved from the category
810802
of the Drinfeld module::
@@ -833,7 +825,7 @@ def ore_variable(self):
833825
sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5])
834826
835827
sage: phi.ore_polring()
836-
Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 over its base twisted by Frob^2
828+
Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 twisted by z12 |--> z12^(5^2)
837829
sage: phi.ore_variable()
838830
t
839831
"""

src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,6 @@ def coefficient_in_function_ring(self, n):
504504
"""
505505
A = self.function_ring()
506506
g = self.coefficient(n)
507-
g = g.backend(force=True)
508507
if g.denominator().is_one():
509508
return A(g.numerator().list())
510509
else:
@@ -550,7 +549,6 @@ def coefficients_in_function_ring(self, sparse=True):
550549
A = self.function_ring()
551550
gs = []
552551
for g in self.coefficients(sparse):
553-
g = g.backend(force=True)
554552
if g.denominator().is_one():
555553
gs.append(A(g.numerator().list()))
556554
else:

src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ class DrinfeldModule(Parent, UniqueRepresentation):
194194
:class:`sage.categories.drinfeld_modules.DrinfeldModules`)::
195195
196196
sage: phi.category()
197-
Category of Drinfeld modules over Finite Field in z of size 3^12 over its base
197+
Category of Drinfeld modules over Finite Field in z of size 3^12
198198
sage: phi.category() is psi.category()
199199
False
200200
sage: phi.category() is rho.category()
@@ -219,7 +219,7 @@ class DrinfeldModule(Parent, UniqueRepresentation):
219219
sage: phi.base_morphism()
220220
Ring morphism:
221221
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2
222-
To: Finite Field in z of size 3^12 over its base
222+
To: Finite Field in z of size 3^12
223223
Defn: T |--> z
224224
225225
Note that the base field is *not* the field `K`. Rather, it is a
@@ -237,14 +237,13 @@ class DrinfeldModule(Parent, UniqueRepresentation):
237237
sage: phi.base_morphism()
238238
Ring morphism:
239239
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2
240-
To: Finite Field in z of size 3^12 over its base
240+
To: Finite Field in z of size 3^12
241241
Defn: T |--> z
242242
243243
::
244244
245245
sage: phi.ore_polring() # K{t}
246-
Ore Polynomial Ring in t over Finite Field in z of size 3^12 over its base
247-
twisted by Frob^2
246+
Ore Polynomial Ring in t over Finite Field in z of size 3^12 twisted by z |--> z^(3^2)
248247
249248
::
250249
@@ -268,9 +267,8 @@ class DrinfeldModule(Parent, UniqueRepresentation):
268267
sage: phi.morphism() # The Drinfeld module as a morphism
269268
Ring morphism:
270269
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2
271-
To: Ore Polynomial Ring in t
272-
over Finite Field in z of size 3^12 over its base
273-
twisted by Frob^2
270+
To: Ore Polynomial Ring in t over Finite Field in z of size 3^12
271+
twisted by z |--> z^(3^2)
274272
Defn: T |--> t^2 + t + z
275273
276274
One can compute the rank and height::
@@ -578,42 +576,37 @@ def __classcall_private__(cls, function_ring, gen, name='t'):
578576
if isinstance(gen, OrePolynomial):
579577
ore_polring = gen.parent()
580578
# Base ring without morphism structure:
581-
base_field_noext = ore_polring.base()
579+
base_field = ore_polring.base()
582580
name = ore_polring.variable_name()
583581
# `gen` is a list of coefficients (function_ring = Fq[T]):
584582
elif isinstance(gen, (list, tuple)):
585583
ore_polring = None
586584
# Base ring without morphism structure:
587-
base_field_noext = Sequence(gen).universe()
585+
base_field = Sequence(gen).universe()
588586
else:
589587
raise TypeError('generator must be list of coefficients or Ore '
590588
'polynomial')
591589
# Constant coefficient must be nonzero:
592590
if gen[0].is_zero():
593591
raise ValueError('constant coefficient must be nonzero')
594592
# The coefficients are in a base field that has coercion from Fq:
595-
if not (hasattr(base_field_noext, 'has_coerce_map_from') and
596-
base_field_noext.has_coerce_map_from(function_ring.base_ring())):
593+
if not (hasattr(base_field, 'has_coerce_map_from') and
594+
base_field.has_coerce_map_from(function_ring.base_ring())):
597595
raise ValueError('function ring base must coerce into base field')
598596

599597
# Build the category
600598
T = function_ring.gen()
601-
if isinstance(base_field_noext, RingExtension_generic):
602-
base_field = base_field_noext
603-
elif base_field_noext.has_coerce_map_from(function_ring) \
604-
and T == gen[0]:
605-
base_morphism = base_field_noext.coerce_map_from(function_ring)
606-
base_field = base_field_noext.over(base_morphism)
599+
if base_field.has_coerce_map_from(function_ring) and T == gen[0]:
600+
base_morphism = base_field.coerce_map_from(function_ring)
607601
else:
608-
base_morphism = Hom(function_ring, base_field_noext)(gen[0])
609-
base_field = base_field_noext.over(base_morphism)
602+
base_morphism = Hom(function_ring, base_field)(gen[0])
610603

611604
# This test is also done in the category. We put it here also
612605
# to have a friendlier error message
613606
if not base_field.is_field():
614607
raise ValueError('generator coefficients must live in a field')
615608

616-
category = DrinfeldModules(base_field, name=name)
609+
category = DrinfeldModules(base_morphism, name=name)
617610

618611
# Check gen as Ore polynomial
619612
ore_polring = category.ore_polring() # Sanity cast
@@ -622,12 +615,11 @@ def __classcall_private__(cls, function_ring, gen, name='t'):
622615
raise ValueError('generator must have positive degree')
623616

624617
# Instantiate the appropriate class:
625-
backend = base_field.backend(force=True)
626-
if backend.is_finite():
618+
if base_field.is_finite():
627619
from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import DrinfeldModule_finite
628620
return DrinfeldModule_finite(gen, category)
629-
if isinstance(backend, FractionField_generic):
630-
ring = backend.ring()
621+
if isinstance(base_field, FractionField_generic):
622+
ring = base_field.ring()
631623
if (isinstance(ring, PolynomialRing_generic)
632624
and ring.base_ring() is function_ring_base
633625
and base_morphism(T) == ring.gen()):
@@ -1792,7 +1784,7 @@ def morphism(self):
17921784
Ring morphism:
17931785
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
17941786
To: Ore Polynomial Ring in t over Finite Field in z12 of size 5^12
1795-
over its base twisted by Frob^2
1787+
twisted by z12 |--> z12^(5^2)
17961788
Defn: T |--> z12^5*t^2 + z12^3*t + 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8
17971789
+ z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12
17981790
sage: from sage.rings.morphism import RingHomomorphism

src/sage/rings/function_field/drinfeld_modules/morphism.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ def _motive_matrix(self):
593593
# The next rows:
594594
# each row is obtained from the previous one by
595595
# applying the semi-linear transformation f |-> t*f
596-
inv = K(phiT[r]).inverse()
596+
inv = ~phiT[r]
597597
B = inv * phiT
598598
T = KT.gen()
599599
for i in range(1, r):

0 commit comments

Comments
 (0)