Skip to content

Commit

Permalink
gh-38487: convenience methods for field embeddings
Browse files Browse the repository at this point in the history
    
Currently, the best(?) way to compute embeddings between fields is
somewhat hidden inside the `Hom` object. In this patch we add helper
methods to access such embeddings. In addition, we add an
`.algebraic_closure()` method to non-prime finite fields.

These seem useful.
    
URL: #38487
Reported by: Lorenz Panny
Reviewer(s): Giacomo Pope, Sebastian A. Spindler
  • Loading branch information
Release Manager committed Oct 25, 2024
2 parents 67e6234 + a2fdcc9 commit 5c25c12
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/doc/en/thematic_tutorials/coercion_and_categories.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ This base class provides a lot more methods than a general parent::
'_pseudo_fraction_field',
'_zero_element',
'algebraic_closure',
'an_embedding',
'base_extend',
'divides',
'epsilon',
Expand Down
6 changes: 3 additions & 3 deletions src/sage/matrix/matrix2.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -12524,7 +12524,7 @@ cdef class Matrix(Matrix1):
_, SA = A.jordan_form(transformation=True)
_, SB = B.jordan_form(transformation=True)
return (True, SB * SA.inverse())
except (ValueError, RuntimeError, NotImplementedError):
except (ValueError, RuntimeError, NotImplementedError, TypeError):
raise RuntimeError('unable to compute transformation for similar matrices')

def symplectic_form(self):
Expand Down Expand Up @@ -17098,7 +17098,7 @@ cdef class Matrix(Matrix1):
sage: A.eigenvalues()
Traceback (most recent call last):
...
NotImplementedError: algebraic closures of finite fields are only implemented for prime fields
TypeError: no canonical coercion from Finite Field in a of size 5^4 to Finite Field in z4 of size 5^4

Subdivisions are optional. ::

Expand Down Expand Up @@ -17460,7 +17460,7 @@ cdef class Matrix(Matrix1):
sage: A.eigenvalues()
Traceback (most recent call last):
...
NotImplementedError: algebraic closures of finite fields are only implemented for prime fields
TypeError: no canonical coercion from Finite Field in a of size 7^2 to Finite Field in z2 of size 7^2

Companion matrices may be selected as any one of four different types.
See the documentation for the companion matrix constructor,
Expand Down
83 changes: 82 additions & 1 deletion src/sage/rings/finite_rings/finite_field_base.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1871,6 +1871,12 @@ cdef class FiniteField(Field):
sage: F.gen(3)
z3
For finite fields, the algebraic closure is always (isomorphic
to) the algebraic closure of the prime field::
sage: GF(5^2).algebraic_closure() == F
True
The default name is 'z' but you can change it through the option
``name``::
Expand All @@ -1890,13 +1896,18 @@ cdef class FiniteField(Field):
.. NOTE::
This is currently only implemented for prime fields.
For non-prime finite fields, this method currently simply
returns the algebraic closure of the prime field. This may
or may not change in the future when extension towers are
supported properly.
TESTS::
sage: GF(5).algebraic_closure() is GF(5).algebraic_closure()
True
"""
if not self.is_prime_field():
return self.prime_subfield().algebraic_closure()
from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField
return AlgebraicClosureFiniteField(self, name, **kwds)

Expand All @@ -1920,6 +1931,76 @@ cdef class FiniteField(Field):
return (exists_conway_polynomial(p, n)
and self.polynomial() == self.polynomial_ring()(conway_polynomial(p, n)))

def an_embedding(self, K):
r"""
Return some embedding of this field into another field `K`,
and raise a :class:`ValueError` if none exists.
.. SEEALSO::
:meth:`sage.rings.ring.Field.an_embedding`
EXAMPLES::
sage: GF(4,'a').an_embedding(GF(2).algebraic_closure())
Ring morphism:
From: Finite Field in a of size 2^2
To: Algebraic closure of Finite Field of size 2
Defn: a |--> ...
"""
if self.characteristic() != K.characteristic():
raise ValueError(f'no embedding from {self} to {K}: incompatible characteristics')
try:
return super().an_embedding(K)
except (NotImplementedError, ValueError):
pass
if K not in FiniteFields():
from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic
if not isinstance(K, AlgebraicClosureFiniteField_generic):
raise NotImplementedError('computing embeddings into this ring not implemented')
g = self.gen()
if (emb := K.coerce_map_from(self)) is not None:
return self.hom([emb(g)])
try:
r = g.minpoly().change_ring(K).any_root()
except ValueError:
raise ValueError(f'no embedding from {self} to {K}')
return self.hom([r])

def embeddings(self, K):
r"""
Return a list of all embeddings of this field in another field `K`.
EXAMPLES::
sage: GF(2).embeddings(GF(4))
[Ring morphism:
From: Finite Field of size 2
To: Finite Field in z2 of size 2^2
Defn: 1 |--> 1]
sage: GF(4).embeddings(GF(2).algebraic_closure())
[Ring morphism:
From: Finite Field in z2 of size 2^2
To: Algebraic closure of Finite Field of size 2
Defn: z2 |--> z2,
Ring morphism:
From: Finite Field in z2 of size 2^2
To: Algebraic closure of Finite Field of size 2
Defn: z2 |--> z2 + 1]
"""
if self.characteristic() != K.characteristic():
return []
if K not in FiniteFields():
from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic
if not isinstance(K, AlgebraicClosureFiniteField_generic):
raise NotImplementedError('computing embeddings into this ring not implemented')
g = self.gen()
rs = []
if (emb := K.coerce_map_from(self)) is not None:
rs.append(emb(g))
rs += [r for r,_ in g.minpoly().roots(ring=K) if r not in rs]
return [self.hom([r]) for r in rs]

def frobenius_endomorphism(self, n=1):
"""
INPUT:
Expand Down
35 changes: 35 additions & 0 deletions src/sage/rings/number_field/number_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -9345,6 +9345,41 @@ def embeddings(self, K):
Defn: a |--> 1.25992104989487
]
Some more (possible and impossible) embeddings of cyclotomic fields::
sage: CyclotomicField(5).embeddings(QQbar)
[
Ring morphism:
From: Cyclotomic Field of order 5 and degree 4
To: Algebraic Field
Defn: zeta5 |--> 0.3090169943749474? + 0.9510565162951536?*I,
Ring morphism:
From: Cyclotomic Field of order 5 and degree 4
To: Algebraic Field
Defn: zeta5 |--> -0.8090169943749474? + 0.5877852522924731?*I,
Ring morphism:
From: Cyclotomic Field of order 5 and degree 4
To: Algebraic Field
Defn: zeta5 |--> -0.8090169943749474? - 0.5877852522924731?*I,
Ring morphism:
From: Cyclotomic Field of order 5 and degree 4
To: Algebraic Field
Defn: zeta5 |--> 0.3090169943749474? - 0.9510565162951536?*I
]
sage: CyclotomicField(3).embeddings(CyclotomicField(7))
[ ]
sage: CyclotomicField(3).embeddings(CyclotomicField(6))
[
Ring morphism:
From: Cyclotomic Field of order 3 and degree 2
To: Cyclotomic Field of order 6 and degree 2
Defn: zeta3 |--> zeta6 - 1,
Ring morphism:
From: Cyclotomic Field of order 3 and degree 2
To: Cyclotomic Field of order 6 and degree 2
Defn: zeta3 |--> -zeta6
]
Test that :issue:`15053` is fixed::
sage: K = NumberField(x^3 - 2, 'a')
Expand Down
3 changes: 3 additions & 0 deletions src/sage/rings/number_field/number_field_rel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2072,6 +2072,9 @@ def embeddings(self, K):
sage: f[0](a+b)
-0.62996052494743693 - 0.091123635971721295*I
"""
if K.characteristic():
return Sequence([], immutable=True, check=False, universe=self.Hom(K))

try:
# this should be concordant with automorphisms
return self.__embeddings[K]
Expand Down
18 changes: 10 additions & 8 deletions src/sage/rings/rational_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,8 @@ def signature(self):

def embeddings(self, K):
r"""
Return list of the one embedding of `\QQ` into `K`, if it exists.
Return the list containing the unique embedding of `\QQ` into `K`,
if it exists, and an empty list otherwise.
EXAMPLES::
Expand All @@ -612,16 +613,17 @@ def embeddings(self, K):
From: Rational Field
To: Cyclotomic Field of order 5 and degree 4]
`K` must have characteristic 0::
The field `K` must have characteristic `0` for an embedding of `\QQ`
to exist::
sage: QQ.embeddings(GF(3))
Traceback (most recent call last):
...
ValueError: no embeddings of the rational field into K.
[]
"""
if K.characteristic():
raise ValueError("no embeddings of the rational field into K.")
return [self.hom(K)]
if K.characteristic() == 0:
v = [self.hom(K)]
else:
v = []
return Sequence(v, check=False, universe=self.Hom(K))

def automorphisms(self):
r"""
Expand Down
52 changes: 52 additions & 0 deletions src/sage/rings/ring.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,58 @@ cdef class Field(CommutativeRing):
"""
raise NotImplementedError("Algebraic closures of general fields not implemented.")

def an_embedding(self, K):
r"""
Return some embedding of this field into another field `K`,
and raise a :class:`ValueError` if none exists.
EXAMPLES::
sage: GF(2).an_embedding(GF(4))
Ring morphism:
From: Finite Field of size 2
To: Finite Field in z2 of size 2^2
Defn: 1 |--> 1
sage: GF(4).an_embedding(GF(8))
Traceback (most recent call last):
...
ValueError: no embedding from Finite Field in z2 of size 2^2 to Finite Field in z3 of size 2^3
sage: GF(4).an_embedding(GF(16))
Ring morphism:
From: Finite Field in z2 of size 2^2
To: Finite Field in z4 of size 2^4
Defn: z2 |--> z4^2 + z4
::
sage: CyclotomicField(5).an_embedding(QQbar)
Coercion map:
From: Cyclotomic Field of order 5 and degree 4
To: Algebraic Field
sage: CyclotomicField(3).an_embedding(CyclotomicField(7))
Traceback (most recent call last):
...
ValueError: no embedding from Cyclotomic Field of order 3 and degree 2 to Cyclotomic Field of order 7 and degree 6
sage: CyclotomicField(3).an_embedding(CyclotomicField(6))
Generic morphism:
From: Cyclotomic Field of order 3 and degree 2
To: Cyclotomic Field of order 6 and degree 2
Defn: zeta3 -> zeta6 - 1
"""
if self.characteristic() != K.characteristic():
raise ValueError(f'no embedding from {self} to {K}: incompatible characteristics')

H = self.Hom(K)
try:
return H.natural_map()
except TypeError:
pass
from sage.categories.sets_cat import EmptySetError
try:
return H.an_element()
except EmptySetError:
raise ValueError(f'no embedding from {self} to {K}')


cdef class Algebra(Ring):
def __init__(self, base_ring, *args, **kwds):
Expand Down

0 comments on commit 5c25c12

Please sign in to comment.