Skip to content

Limit the use of RingExtensions in Drinfeld modules #40421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 26 additions & 34 deletions src/sage/categories/drinfeld_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class DrinfeldModules(Category_over_base_ring):
sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1])
sage: C = phi.category()
sage: C
Category of Drinfeld modules over Finite Field in z of size 11^4 over its base
Category of Drinfeld modules over Finite Field in z of size 11^4

The output tells the user that the category is only defined by its
base.
Expand All @@ -88,7 +88,7 @@ class DrinfeldModules(Category_over_base_ring):
sage: C.base_morphism()
Ring morphism:
From: Univariate Polynomial Ring in T over Finite Field of size 11
To: Finite Field in z of size 11^4 over its base
To: Finite Field in z of size 11^4
Defn: T |--> z^3 + 7*z^2 + 6*z + 10

The so-called constant coefficient --- which is the same for all
Expand Down Expand Up @@ -123,7 +123,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 over its base twisted by Frob
Ore Polynomial Ring in t over Finite Field in z of size 11^4 twisted by z |--> z^11
sage: C.ore_polring() is phi.ore_polring()
True

Expand Down Expand Up @@ -165,20 +165,24 @@ class DrinfeldModules(Category_over_base_ring):
sage: K.<z> = Fq.extension(4)
sage: from sage.categories.drinfeld_modules import DrinfeldModules
sage: base = Hom(A, K)(0)
sage: C = DrinfeldModules(base)
sage: C = DrinfeldModules(base) # known bug (blankline)
<BLANKLINE>
Traceback (most recent call last):
...
TypeError: base field must be a ring extension

::
Note that `C.base_morphism()` has codomain `K` while
the defining morphism of `C.base()` has codomain `K` viewed
as an `A`-field. Thus, they differ::

sage: C.base().defining_morphism() == C.base_morphism()
True
False

::

sage: base = Hom(A, A)(1)
sage: C = DrinfeldModules(base)
sage: C = DrinfeldModules(base) # known bug (blankline)
<BLANKLINE>
Traceback (most recent call last):
...
TypeError: base field must be a ring extension
Expand All @@ -203,7 +207,7 @@ class DrinfeldModules(Category_over_base_ring):
TypeError: function ring base must be a finite field
"""

def __init__(self, base_field, name='t'):
def __init__(self, base_morphism, name='t'):
r"""
Initialize ``self``.

Expand All @@ -223,34 +227,23 @@ def __init__(self, base_field, 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.<t> = OrePolynomialRing(phi.base(), phi.base().frobenius_endomorphism())
sage: ore_polring.<t> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: C._ore_polring is ore_polring
True
sage: i = phi.base().coerce_map_from(K)
sage: base_morphism = Hom(A, K)(p_root)
sage: C.base() == K.over(base_morphism)
True
sage: C._base_morphism == i * base_morphism
True
sage: C._function_ring is A
True
sage: C._constant_coefficient == base_morphism(T)
sage: C._constant_coefficient == C._base_morphism(T)
True
sage: C._characteristic(C._constant_coefficient)
0
"""
# Check input is a ring extension
if not isinstance(base_field, RingExtension_generic):
raise TypeError('base field must be a ring extension')
base_morphism = base_field.defining_morphism()
self._base_morphism = base_morphism
function_ring = self._function_ring = base_morphism.domain()
base_field = self._base_field = base_morphism.codomain()
# Check input is a field
if not base_field.is_field():
raise TypeError('input must be a field')
self._base_field = base_field
self._function_ring = base_morphism.domain()
# Check domain of base morphism is Fq[T]
function_ring = self._function_ring
if not isinstance(function_ring, PolynomialRing_generic):
raise NotImplementedError('function ring must be a polynomial '
'ring')
Expand All @@ -262,7 +255,7 @@ def __init__(self, base_field, name='t'):
Fq = function_ring_base
A = function_ring
T = A.gen()
K = base_field # A ring extension
K = base_field
# Build K{t}
d = log(Fq.cardinality(), Fq.characteristic())
tau = K.frobenius_endomorphism(d)
Expand All @@ -284,7 +277,7 @@ def __init__(self, base_field, name='t'):
i = A.coerce_map_from(Fq)
Fq_to_K = self._base_morphism * i
self._base_over_constants_field = base_field.over(Fq_to_K)
super().__init__(base=base_field)
super().__init__(base=base_field.over(base_morphism))

def _latex_(self):
r"""
Expand Down Expand Up @@ -321,7 +314,7 @@ def _repr_(self):
sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1])
sage: C = phi.category()
sage: C
Category of Drinfeld modules over Finite Field in z of size 11^4 over its base
Category of Drinfeld modules over Finite Field in z of size 11^4
"""
return f'Category of Drinfeld modules over {self._base_field}'

Expand Down Expand Up @@ -378,7 +371,7 @@ def base_morphism(self):
sage: C.base_morphism()
Ring morphism:
From: Univariate Polynomial Ring in T over Finite Field of size 11
To: Finite Field in z of size 11^4 over its base
To: Finite Field in z of size 11^4
Defn: T |--> z^3 + 7*z^2 + 6*z + 10

sage: C.constant_coefficient() == C.base_morphism()(T)
Expand Down Expand Up @@ -517,7 +510,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 over its base twisted by Frob
Ore Polynomial Ring in t over Finite Field in z of size 11^4 twisted by z |--> z^11
"""
return self._ore_polring

Expand Down Expand Up @@ -615,17 +608,16 @@ def base_morphism(self):
sage: phi.base_morphism()
Ring morphism:
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
To: Finite Field in z12 of size 5^12 over its base
To: Finite Field in z12 of size 5^12
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

The base field can be infinite::

sage: sigma = DrinfeldModule(A, [Frac(A).gen(), 1])
sage: sigma.base_morphism()
Ring morphism:
Coercion map:
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
To: Fraction Field of Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 over its base
Defn: T |--> T
To: Fraction Field of Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
"""
return self.category().base_morphism()

Expand Down Expand Up @@ -753,7 +745,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 over its base twisted by Frob^2
Ore Polynomial Ring in t 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::
Expand Down Expand Up @@ -782,7 +774,7 @@ 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 over its base twisted by Frob^2
Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 twisted by z12 |--> z12^(5^2)
sage: phi.ore_variable()
t
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,6 @@ def coefficient_in_function_ring(self, n):
"""
A = self.function_ring()
g = self.coefficient(n)
g = g.backend(force=True)
if g.denominator().is_one():
return A(g.numerator().list())
else:
Expand Down Expand Up @@ -550,7 +549,6 @@ def coefficients_in_function_ring(self, sparse=True):
A = self.function_ring()
gs = []
for g in self.coefficients(sparse):
g = g.backend(force=True)
if g.denominator().is_one():
gs.append(A(g.numerator().list()))
else:
Expand Down
44 changes: 18 additions & 26 deletions src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class DrinfeldModule(Parent, UniqueRepresentation):
:class:`sage.categories.drinfeld_modules.DrinfeldModules`)::

sage: phi.category()
Category of Drinfeld modules over Finite Field in z of size 3^12 over its base
Category of Drinfeld modules over Finite Field in z of size 3^12
sage: phi.category() is psi.category()
False
sage: phi.category() is rho.category()
Expand All @@ -219,7 +219,7 @@ class DrinfeldModule(Parent, UniqueRepresentation):
sage: phi.base_morphism()
Ring morphism:
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2
To: Finite Field in z of size 3^12 over its base
To: Finite Field in z of size 3^12
Defn: T |--> z

Note that the base field is *not* the field `K`. Rather, it is a
Expand All @@ -237,14 +237,13 @@ class DrinfeldModule(Parent, UniqueRepresentation):
sage: phi.base_morphism()
Ring morphism:
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2
To: Finite Field in z of size 3^12 over its base
To: Finite Field in z of size 3^12
Defn: T |--> z

::

sage: phi.ore_polring() # K{t}
Ore Polynomial Ring in t over Finite Field in z of size 3^12 over its base
twisted by Frob^2
Ore Polynomial Ring in t over Finite Field in z of size 3^12 twisted by z |--> z^(3^2)

::

Expand All @@ -268,9 +267,8 @@ 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 over its base
twisted by Frob^2
To: Ore Polynomial Ring in t over Finite Field in z of size 3^12
twisted by z |--> z^(3^2)
Defn: T |--> t^2 + t + z

One can compute the rank and height::
Expand Down Expand Up @@ -578,42 +576,37 @@ def __classcall_private__(cls, function_ring, gen, name='t'):
if isinstance(gen, OrePolynomial):
ore_polring = gen.parent()
# Base ring without morphism structure:
base_field_noext = ore_polring.base()
base_field = ore_polring.base()
name = ore_polring.variable_name()
# `gen` is a list of coefficients (function_ring = Fq[T]):
elif isinstance(gen, (list, tuple)):
ore_polring = None
# Base ring without morphism structure:
base_field_noext = Sequence(gen).universe()
base_field = Sequence(gen).universe()
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_noext, 'has_coerce_map_from') and
base_field_noext.has_coerce_map_from(function_ring.base_ring())):
if not (hasattr(base_field, 'has_coerce_map_from') and
base_field.has_coerce_map_from(function_ring.base_ring())):
raise ValueError('function ring base must coerce into base field')

# Build the category
T = function_ring.gen()
if isinstance(base_field_noext, RingExtension_generic):
base_field = base_field_noext
elif base_field_noext.has_coerce_map_from(function_ring) \
and T == gen[0]:
base_morphism = base_field_noext.coerce_map_from(function_ring)
base_field = base_field_noext.over(base_morphism)
if base_field.has_coerce_map_from(function_ring) and T == gen[0]:
base_morphism = base_field.coerce_map_from(function_ring)
else:
base_morphism = Hom(function_ring, base_field_noext)(gen[0])
base_field = base_field_noext.over(base_morphism)
base_morphism = Hom(function_ring, base_field)(gen[0])

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

category = DrinfeldModules(base_field, name=name)
category = DrinfeldModules(base_morphism, name=name)

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

# Instantiate the appropriate class:
backend = base_field.backend(force=True)
if backend.is_finite():
if base_field.is_finite():
from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import DrinfeldModule_finite
return DrinfeldModule_finite(gen, category)
if isinstance(backend, FractionField_generic):
ring = backend.ring()
if isinstance(base_field, FractionField_generic):
ring = base_field.ring()
if (isinstance(ring, PolynomialRing_generic)
and ring.base_ring() is function_ring_base
and base_morphism(T) == ring.gen()):
Expand Down Expand Up @@ -1792,7 +1784,7 @@ def morphism(self):
Ring morphism:
From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
To: Ore Polynomial Ring in t over Finite Field in z12 of size 5^12
over its base twisted by Frob^2
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
+ z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12
sage: from sage.rings.morphism import RingHomomorphism
Expand Down
2 changes: 1 addition & 1 deletion src/sage/rings/function_field/drinfeld_modules/morphism.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ def _motive_matrix(self):
# The next rows:
# each row is obtained from the previous one by
# applying the semi-linear transformation f |-> t*f
inv = K(phiT[r]).inverse()
inv = ~phiT[r]
B = inv * phiT
T = KT.gen()
for i in range(1, r):
Expand Down
Loading