Skip to content
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

Improve morphisms between Drinfeld modules #35527

Merged
merged 34 commits into from Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9a6a31b
small additions
xcaruso Apr 15, 2023
c9f04e0
add ore_variable
xcaruso Apr 15, 2023
b283f44
composition of morphisms
xcaruso Apr 15, 2023
b56e6c2
norm and characteristic polynomial
xcaruso Apr 16, 2023
18d07c4
doctests
xcaruso Apr 16, 2023
7f8ba08
fix RST
xcaruso Apr 16, 2023
79d8be5
use in_base in invert method
xcaruso Apr 17, 2023
14b5a1b
addition of morphisms
xcaruso Apr 17, 2023
7c8861c
check isomorphisms between Drinfeld modules
xcaruso Apr 17, 2023
63e62c5
small fixes
xcaruso Apr 17, 2023
dc68919
fix RST
xcaruso Apr 17, 2023
6b9966d
some fixes
xcaruso Apr 18, 2023
8a1a284
improve error message
xcaruso Apr 20, 2023
fbc175b
Merge branch 'develop' into drinfeld-module-morphisms
xcaruso Jun 20, 2023
d0a0ea3
address Joseph's remarks
xcaruso Jun 20, 2023
ee9ae63
typo
xcaruso Jun 20, 2023
e41261c
remove blank line
xcaruso Jun 20, 2023
bd8afed
typo: endomorphism -> homomorphism
xcaruso Jun 20, 2023
43f0702
address David's comments and implement inversion for general isomorph…
xcaruso Jun 21, 2023
45097cc
fix documentation
xcaruso Jun 21, 2023
125a9d6
typos
xcaruso Jun 24, 2023
bfd7f9d
Merge branch 'drinfeld-module-morphisms' of github:xcaruso/sage into …
xcaruso Jun 24, 2023
08de7d3
Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
xcaruso Jul 6, 2023
d6e4044
Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
xcaruso Jul 6, 2023
3d6f7e6
Update src/sage/rings/function_field/drinfeld_modules/finite_drinfeld…
xcaruso Jul 6, 2023
f344eb0
Update src/sage/rings/function_field/drinfeld_modules/finite_drinfeld…
xcaruso Jul 6, 2023
b939d21
Update src/sage/rings/function_field/drinfeld_modules/homset.py
xcaruso Jul 6, 2023
3bf7d82
Update src/sage/rings/function_field/drinfeld_modules/homset.py
xcaruso Jul 6, 2023
8515adc
Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
xcaruso Jul 6, 2023
0949dfd
Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
xcaruso Jul 6, 2023
ec5691f
Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
xcaruso Jul 6, 2023
f87597c
Antoine's comments
xcaruso Jul 7, 2023
1e75afd
is_ordinary/is_supersingular + more doctests
xcaruso Jul 9, 2023
5f76571
typos
xcaruso Jul 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/sage/categories/drinfeld_modules.py
Expand Up @@ -768,3 +768,23 @@
True
"""
return self.category().ore_polring()

def ore_variable(self):
r"""
Return the variable of the Ore polynomial ring of this Drinfeld module.
xcaruso marked this conversation as resolved.
Show resolved Hide resolved

EXAMPLES::

sage: Fq = GF(25)
sage: A.<T> = Fq[]
sage: K.<z12> = Fq.extension(6)
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])

xcaruso marked this conversation as resolved.
Show resolved Hide resolved
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
sage: phi.ore_variable()
t

"""
return self.category().ore_polring().gen()

Check warning on line 790 in src/sage/categories/drinfeld_modules.py

View check run for this annotation

Codecov / codecov/patch

src/sage/categories/drinfeld_modules.py#L790

Added line #L790 was not covered by tests
293 changes: 272 additions & 21 deletions src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
Expand Up @@ -930,8 +930,7 @@
...
ValueError: input must be >= 0 and <= rank
"""
if not isinstance(n, Integer) and not isinstance(n, int):
raise TypeError('input must be an integer')
n = Integer(n)

Check warning on line 933 in src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py

View check run for this annotation

Codecov / codecov/patch

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

Added line #L933 was not covered by tests
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
if not 0 <= n <= self.rank():
raise ValueError('input must be >= 0 and <= rank')
return self.coefficients(sparse=False)[n]
Expand Down Expand Up @@ -1139,9 +1138,6 @@

See [Gos1998]_, Definition 4.5.8 for the general definition.

A rank two Drinfeld module is supersingular if and only if its
height equals its rank.

EXAMPLES::

sage: Fq = GF(25)
Expand All @@ -1154,16 +1150,6 @@
sage: phi.is_ordinary()
True

::

sage: B.<Y> = Fq[]
sage: L = Frac(B)
sage: phi = DrinfeldModule(A, [L(2), L(1)])
sage: phi.height()
Traceback (most recent call last):
...
NotImplementedError: height not implemented in this case

::

sage: Fq = GF(343)
Expand All @@ -1175,17 +1161,195 @@
sage: phi.is_supersingular()
True

In characteristic zero, height is not defined::

sage: L = A.fraction_field()
sage: phi = DrinfeldModule(A, [L(T), L(1)])
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
sage: phi.height()
Traceback (most recent call last):
...
ValueError: height is only defined for prime function field characteristic

TESTS:

In the following case, sage is unable to determine the
characteristic; that is why an error is raised::

sage: B.<Y> = Fq[]
sage: L = Frac(B)
sage: phi = DrinfeldModule(A, [L(2), L(1)])
sage: phi.height()
Traceback (most recent call last):
...
NotImplementedError: height not implemented in this case

"""
try:
if self.characteristic().is_zero():
raise ValueError('height is defined for prime '
raise ValueError('height is only defined for prime '

Check warning on line 1189 in src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py

View check run for this annotation

Codecov / codecov/patch

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

Added line #L1189 was not covered by tests
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
'function field characteristic')
else:
p = self.characteristic()
return Integer(self(p).valuation() // p.degree())
except NotImplementedError:
raise NotImplementedError('height not implemented in this case')

def is_isomorphic(self, other, absolutely=False):
r"""
Return ``True`` if this Drinfeld module is isomorphic to
``other``.

INPUT:

- ``absolutely`` -- a boolean (default: ``False``); if ``True``,
check the existence of an isomorphism defined on the base
field; if ``False``, check over an algebraic closure.

EXAMPLES::
xcaruso marked this conversation as resolved.
Show resolved Hide resolved

sage: Fq = GF(5)
sage: A.<T> = Fq[]
sage: K.<z> = Fq.extension(3)
sage: phi = DrinfeldModule(A, [z, 0, 1, z])
sage: t = phi.ore_variable()

We create a second Drinfeld module, which is isomorphic to `\phi`
and then check that they are indeed isomorphic::

sage: psi = phi.velu(z)
sage: phi.is_isomorphic(psi)
True

In the example below, `\phi` and `\psi` are isogenous but not
isomorphic::

sage: psi = phi.velu(t + 1)
sage: phi.is_isomorphic(psi)
False

Here is an example of two Drinfeld modules which are isomorphic
on an algebraic closure but not on the base field::

sage: phi = DrinfeldModule(A, [z, 1])
sage: psi = DrinfeldModule(A, [z, z])
sage: phi.is_isomorphic(psi)
False
sage: phi.is_isomorphic(psi, absolutely=True)
True

On certain fields, testing isomorphisms over the base field may
fail::

sage: L = A.fraction_field()
sage: T = L.gen()
sage: phi = DrinfeldModule(A, [T, 0, 1])
sage: psi = DrinfeldModule(A, [T, 0, T])
sage: psi.is_isomorphic(phi)
Traceback (most recent call last):
...
NotImplementedError: cannot solve the equation u^24 == T

However, it never fails over the algebraic closure::

sage: psi.is_isomorphic(phi, absolutely=True)
True

Note finally that when the constant coefficients of `\phi_T` and
`\psi_T` differ, `\phi` and `\psi` do not belong to the same category
and checking whether they are isomorphic does not make sense; in this
case, an error is raised::

sage: phi = DrinfeldModule(A, [z, 0, 1])
sage: psi = DrinfeldModule(A, [z^2, 0, 1])
sage: phi.is_isomorphic(psi)
Traceback (most recent call last):
...
ValueError: Drinfeld modules are not in the same category

TESTS:
xcaruso marked this conversation as resolved.
Show resolved Hide resolved

A Drinfeld module is always isomorphic to itself::

sage: phi = DrinfeldModule(A, [z] + [K.random_element() for _ in range(3)] + [1])
sage: phi.is_isomorphic(phi)
True

Two Drinfeld modules of different ranks are never isomorphic::

sage: psi = DrinfeldModule(A, [z] + [K.random_element() for _ in range(5)] + [1])
sage: phi.is_isomorphic(psi)
False

Two Drinfeld modules which are not patterned-alike are also not
isomorphic::

sage: phi = DrinfeldModule(A, [T, 1, 0, 1])
sage: psi = DrinfeldModule(A, [T, 1, 1, 1])
sage: phi.is_isomorphic(psi)
False
"""
if self.category() is not other.category():
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError("Drinfeld modules are not in the same category")
if self is other:
return True
r = self.rank()
if other.rank() != r:
return False
q = self._Fq.cardinality()
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
A = self.gen()
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
B = other.gen()
e = Integer(0)
ue = self._base(1)
for i in range(1, r+1):
ai = A[i]
bi = B[i]
if ai == 0 and bi == 0:
continue
if ai == 0 or bi == 0:
return False
if e != q - 1:

Check warning on line 1310 in src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py

View check run for this annotation

Codecov / codecov/patch

src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py#L1291-L1310

Added lines #L1291 - L1310 were not covered by tests
# u^e = ue
# u^(q^i - 1) = ai/bi
e, s, t = e.xgcd(q**i - 1)
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
ue = ue**s * (ai/bi)**t
for i in range(1, r+1):
if A[i]:
f = (q**i - 1) // e
if A[i] != B[i] * ue**f:
return False
if absolutely:
return True

Check warning on line 1321 in src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py

View check run for this annotation

Codecov / codecov/patch

src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py#L1313-L1321

Added lines #L1313 - L1321 were not covered by tests
else:
ue = ue.backend(force=True)
try:
_ = ue.nth_root(e)
except ValueError:
return False
except (AttributeError, NotImplementedError):
raise NotImplementedError("cannot solve the equation u^%s == %s" % (e, ue))
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
return True

Check warning on line 1330 in src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py

View check run for this annotation

Codecov / codecov/patch

src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py#L1323-L1330

Added lines #L1323 - L1330 were not covered by tests

xcaruso marked this conversation as resolved.
Show resolved Hide resolved
def is_supersingular(self):
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
r"""
Return ``True`` if the Drinfeld module is supersingular.
xcaruso marked this conversation as resolved.
Show resolved Hide resolved

A Drinfeld module is supersingular if and only if its
height equals its rank.

EXAMPLES::

sage: Fq = GF(343)
sage: A.<T> = Fq[]
sage: K.<z6> = Fq.extension(2)
sage: phi = DrinfeldModule(A, [1, 0, z6])
sage: phi.is_supersingular()
True
sage: phi(phi.characteristic()) # Purely inseparable
z6*t^2

"""
return self.height() == self.rank()

Check warning on line 1351 in src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py

View check run for this annotation

Codecov / codecov/patch

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

Added line #L1351 was not covered by tests

def is_finite(self) -> bool:
r"""
Return ``True`` if this Drinfeld module is finite,
Expand Down Expand Up @@ -1532,9 +1696,96 @@
if isog == 0:
raise e
quo, rem = (isog * self.gen()).right_quo_rem(isog)
char_deg = self.characteristic().degree()
if not char_deg.divides(isog.valuation()) \
or rem != 0:
raise e
else:
if rem.is_zero() and quo[0] == self.gen()[0]:

Check warning on line 1699 in src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py

View check run for this annotation

Codecov / codecov/patch

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

Added line #L1699 was not covered by tests
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
return self.category().object(quo)
else:
raise e

Check warning on line 1702 in src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py

View check run for this annotation

Codecov / codecov/patch

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

Added line #L1702 was not covered by tests

def hom(self, x, codomain=None):
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
r"""
Return the homomorphism defined by ``x`` having this Drinfeld
module as domain.

We recall that a homomorphism `f : \phi \to \psi` between
two Drinfeld modules is defined by a Ore polynomial `u`,
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
which is subject to the relation `phi_T u = u \psi_T`.

INPUT:

- ``x`` -- an element of the ring of functions, or a
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
Ore polynomial

- ``codomain`` -- a Drinfeld module or ``None`` (default:
``None``)

EXAMPLES::
xcaruso marked this conversation as resolved.
Show resolved Hide resolved

sage: Fq = GF(5)
sage: A.<T> = Fq[]
sage: K.<z> = Fq.extension(3)
sage: phi = DrinfeldModule(A, [z, 0, 1, z])
sage: phi
Drinfeld module defined by T |--> z*t^3 + t^2 + z

An important class of endomorphisms of a Drinfeld module
`\phi` is given by scalar multiplications, that are endomorphisms
corresponding to the Ore polynomials `\phi_a` with `a` in the function
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

xcaruso marked this conversation as resolved.
Show resolved Hide resolved
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

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

If the input Ore polynomial defines a morphism to another
Drinfeld module, the latter is determined automatically::

sage: phi.hom(t + 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

TESTS::

sage: phi.hom(t)
Traceback (most recent call last):
...
ValueError: the input does not define an isogeny

::

sage: phi.hom(T + z)
Traceback (most recent call last):
...
ValueError: the input does not define an isogeny

"""
if self.function_ring().has_coerce_map_from(x.parent()):
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
return self.Hom(self)(x)
xcaruso marked this conversation as resolved.
Show resolved Hide resolved
if codomain is None:
try:
codomain = self.velu(x)
except TypeError:
raise ValueError("the input does not define an isogeny")
H = self.Hom(codomain)
return H(x)

Check warning on line 1785 in src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py

View check run for this annotation

Codecov / codecov/patch

src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py#L1777-L1785

Added lines #L1777 - L1785 were not covered by tests

# TODO: implement the method `moh`, the analogue of `hom`
# with fixed codomain.
# It's not straightforward because `left_divides` does not
# work currently because Sage does not know how to invert the
# Frobenius endomorphism; this is due to the RingExtension stuff.