Skip to content

Commit 5c25c12

Browse files
author
Release Manager
committed
gh-38487: convenience methods for field embeddings 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
2 parents 67e6234 + a2fdcc9 commit 5c25c12

File tree

7 files changed

+186
-12
lines changed

7 files changed

+186
-12
lines changed

src/doc/en/thematic_tutorials/coercion_and_categories.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ This base class provides a lot more methods than a general parent::
121121
'_pseudo_fraction_field',
122122
'_zero_element',
123123
'algebraic_closure',
124+
'an_embedding',
124125
'base_extend',
125126
'divides',
126127
'epsilon',

src/sage/matrix/matrix2.pyx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12524,7 +12524,7 @@ cdef class Matrix(Matrix1):
1252412524
_, SA = A.jordan_form(transformation=True)
1252512525
_, SB = B.jordan_form(transformation=True)
1252612526
return (True, SB * SA.inverse())
12527-
except (ValueError, RuntimeError, NotImplementedError):
12527+
except (ValueError, RuntimeError, NotImplementedError, TypeError):
1252812528
raise RuntimeError('unable to compute transformation for similar matrices')
1252912529

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

1710317103
Subdivisions are optional. ::
1710417104

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

1746517465
Companion matrices may be selected as any one of four different types.
1746617466
See the documentation for the companion matrix constructor,

src/sage/rings/finite_rings/finite_field_base.pyx

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1871,6 +1871,12 @@ cdef class FiniteField(Field):
18711871
sage: F.gen(3)
18721872
z3
18731873
1874+
For finite fields, the algebraic closure is always (isomorphic
1875+
to) the algebraic closure of the prime field::
1876+
1877+
sage: GF(5^2).algebraic_closure() == F
1878+
True
1879+
18741880
The default name is 'z' but you can change it through the option
18751881
``name``::
18761882
@@ -1890,13 +1896,18 @@ cdef class FiniteField(Field):
18901896
18911897
.. NOTE::
18921898
1893-
This is currently only implemented for prime fields.
1899+
For non-prime finite fields, this method currently simply
1900+
returns the algebraic closure of the prime field. This may
1901+
or may not change in the future when extension towers are
1902+
supported properly.
18941903
18951904
TESTS::
18961905
18971906
sage: GF(5).algebraic_closure() is GF(5).algebraic_closure()
18981907
True
18991908
"""
1909+
if not self.is_prime_field():
1910+
return self.prime_subfield().algebraic_closure()
19001911
from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField
19011912
return AlgebraicClosureFiniteField(self, name, **kwds)
19021913

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

1934+
def an_embedding(self, K):
1935+
r"""
1936+
Return some embedding of this field into another field `K`,
1937+
and raise a :class:`ValueError` if none exists.
1938+
1939+
.. SEEALSO::
1940+
1941+
:meth:`sage.rings.ring.Field.an_embedding`
1942+
1943+
EXAMPLES::
1944+
1945+
sage: GF(4,'a').an_embedding(GF(2).algebraic_closure())
1946+
Ring morphism:
1947+
From: Finite Field in a of size 2^2
1948+
To: Algebraic closure of Finite Field of size 2
1949+
Defn: a |--> ...
1950+
"""
1951+
if self.characteristic() != K.characteristic():
1952+
raise ValueError(f'no embedding from {self} to {K}: incompatible characteristics')
1953+
try:
1954+
return super().an_embedding(K)
1955+
except (NotImplementedError, ValueError):
1956+
pass
1957+
if K not in FiniteFields():
1958+
from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic
1959+
if not isinstance(K, AlgebraicClosureFiniteField_generic):
1960+
raise NotImplementedError('computing embeddings into this ring not implemented')
1961+
g = self.gen()
1962+
if (emb := K.coerce_map_from(self)) is not None:
1963+
return self.hom([emb(g)])
1964+
try:
1965+
r = g.minpoly().change_ring(K).any_root()
1966+
except ValueError:
1967+
raise ValueError(f'no embedding from {self} to {K}')
1968+
return self.hom([r])
1969+
1970+
def embeddings(self, K):
1971+
r"""
1972+
Return a list of all embeddings of this field in another field `K`.
1973+
1974+
EXAMPLES::
1975+
1976+
sage: GF(2).embeddings(GF(4))
1977+
[Ring morphism:
1978+
From: Finite Field of size 2
1979+
To: Finite Field in z2 of size 2^2
1980+
Defn: 1 |--> 1]
1981+
sage: GF(4).embeddings(GF(2).algebraic_closure())
1982+
[Ring morphism:
1983+
From: Finite Field in z2 of size 2^2
1984+
To: Algebraic closure of Finite Field of size 2
1985+
Defn: z2 |--> z2,
1986+
Ring morphism:
1987+
From: Finite Field in z2 of size 2^2
1988+
To: Algebraic closure of Finite Field of size 2
1989+
Defn: z2 |--> z2 + 1]
1990+
"""
1991+
if self.characteristic() != K.characteristic():
1992+
return []
1993+
if K not in FiniteFields():
1994+
from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic
1995+
if not isinstance(K, AlgebraicClosureFiniteField_generic):
1996+
raise NotImplementedError('computing embeddings into this ring not implemented')
1997+
g = self.gen()
1998+
rs = []
1999+
if (emb := K.coerce_map_from(self)) is not None:
2000+
rs.append(emb(g))
2001+
rs += [r for r,_ in g.minpoly().roots(ring=K) if r not in rs]
2002+
return [self.hom([r]) for r in rs]
2003+
19232004
def frobenius_endomorphism(self, n=1):
19242005
"""
19252006
INPUT:

src/sage/rings/number_field/number_field.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9345,6 +9345,41 @@ def embeddings(self, K):
93459345
Defn: a |--> 1.25992104989487
93469346
]
93479347
9348+
Some more (possible and impossible) embeddings of cyclotomic fields::
9349+
9350+
sage: CyclotomicField(5).embeddings(QQbar)
9351+
[
9352+
Ring morphism:
9353+
From: Cyclotomic Field of order 5 and degree 4
9354+
To: Algebraic Field
9355+
Defn: zeta5 |--> 0.3090169943749474? + 0.9510565162951536?*I,
9356+
Ring morphism:
9357+
From: Cyclotomic Field of order 5 and degree 4
9358+
To: Algebraic Field
9359+
Defn: zeta5 |--> -0.8090169943749474? + 0.5877852522924731?*I,
9360+
Ring morphism:
9361+
From: Cyclotomic Field of order 5 and degree 4
9362+
To: Algebraic Field
9363+
Defn: zeta5 |--> -0.8090169943749474? - 0.5877852522924731?*I,
9364+
Ring morphism:
9365+
From: Cyclotomic Field of order 5 and degree 4
9366+
To: Algebraic Field
9367+
Defn: zeta5 |--> 0.3090169943749474? - 0.9510565162951536?*I
9368+
]
9369+
sage: CyclotomicField(3).embeddings(CyclotomicField(7))
9370+
[ ]
9371+
sage: CyclotomicField(3).embeddings(CyclotomicField(6))
9372+
[
9373+
Ring morphism:
9374+
From: Cyclotomic Field of order 3 and degree 2
9375+
To: Cyclotomic Field of order 6 and degree 2
9376+
Defn: zeta3 |--> zeta6 - 1,
9377+
Ring morphism:
9378+
From: Cyclotomic Field of order 3 and degree 2
9379+
To: Cyclotomic Field of order 6 and degree 2
9380+
Defn: zeta3 |--> -zeta6
9381+
]
9382+
93489383
Test that :issue:`15053` is fixed::
93499384
93509385
sage: K = NumberField(x^3 - 2, 'a')

src/sage/rings/number_field/number_field_rel.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,6 +2072,9 @@ def embeddings(self, K):
20722072
sage: f[0](a+b)
20732073
-0.62996052494743693 - 0.091123635971721295*I
20742074
"""
2075+
if K.characteristic():
2076+
return Sequence([], immutable=True, check=False, universe=self.Hom(K))
2077+
20752078
try:
20762079
# this should be concordant with automorphisms
20772080
return self.__embeddings[K]

src/sage/rings/rational_field.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,8 @@ def signature(self):
601601

602602
def embeddings(self, K):
603603
r"""
604-
Return list of the one embedding of `\QQ` into `K`, if it exists.
604+
Return the list containing the unique embedding of `\QQ` into `K`,
605+
if it exists, and an empty list otherwise.
605606
606607
EXAMPLES::
607608
@@ -612,16 +613,17 @@ def embeddings(self, K):
612613
From: Rational Field
613614
To: Cyclotomic Field of order 5 and degree 4]
614615
615-
`K` must have characteristic 0::
616+
The field `K` must have characteristic `0` for an embedding of `\QQ`
617+
to exist::
616618
617619
sage: QQ.embeddings(GF(3))
618-
Traceback (most recent call last):
619-
...
620-
ValueError: no embeddings of the rational field into K.
620+
[]
621621
"""
622-
if K.characteristic():
623-
raise ValueError("no embeddings of the rational field into K.")
624-
return [self.hom(K)]
622+
if K.characteristic() == 0:
623+
v = [self.hom(K)]
624+
else:
625+
v = []
626+
return Sequence(v, check=False, universe=self.Hom(K))
625627

626628
def automorphisms(self):
627629
r"""

src/sage/rings/ring.pyx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,58 @@ cdef class Field(CommutativeRing):
14881488
"""
14891489
raise NotImplementedError("Algebraic closures of general fields not implemented.")
14901490

1491+
def an_embedding(self, K):
1492+
r"""
1493+
Return some embedding of this field into another field `K`,
1494+
and raise a :class:`ValueError` if none exists.
1495+
1496+
EXAMPLES::
1497+
1498+
sage: GF(2).an_embedding(GF(4))
1499+
Ring morphism:
1500+
From: Finite Field of size 2
1501+
To: Finite Field in z2 of size 2^2
1502+
Defn: 1 |--> 1
1503+
sage: GF(4).an_embedding(GF(8))
1504+
Traceback (most recent call last):
1505+
...
1506+
ValueError: no embedding from Finite Field in z2 of size 2^2 to Finite Field in z3 of size 2^3
1507+
sage: GF(4).an_embedding(GF(16))
1508+
Ring morphism:
1509+
From: Finite Field in z2 of size 2^2
1510+
To: Finite Field in z4 of size 2^4
1511+
Defn: z2 |--> z4^2 + z4
1512+
1513+
::
1514+
1515+
sage: CyclotomicField(5).an_embedding(QQbar)
1516+
Coercion map:
1517+
From: Cyclotomic Field of order 5 and degree 4
1518+
To: Algebraic Field
1519+
sage: CyclotomicField(3).an_embedding(CyclotomicField(7))
1520+
Traceback (most recent call last):
1521+
...
1522+
ValueError: no embedding from Cyclotomic Field of order 3 and degree 2 to Cyclotomic Field of order 7 and degree 6
1523+
sage: CyclotomicField(3).an_embedding(CyclotomicField(6))
1524+
Generic morphism:
1525+
From: Cyclotomic Field of order 3 and degree 2
1526+
To: Cyclotomic Field of order 6 and degree 2
1527+
Defn: zeta3 -> zeta6 - 1
1528+
"""
1529+
if self.characteristic() != K.characteristic():
1530+
raise ValueError(f'no embedding from {self} to {K}: incompatible characteristics')
1531+
1532+
H = self.Hom(K)
1533+
try:
1534+
return H.natural_map()
1535+
except TypeError:
1536+
pass
1537+
from sage.categories.sets_cat import EmptySetError
1538+
try:
1539+
return H.an_element()
1540+
except EmptySetError:
1541+
raise ValueError(f'no embedding from {self} to {K}')
1542+
14911543

14921544
cdef class Algebra(Ring):
14931545
def __init__(self, base_ring, *args, **kwds):

0 commit comments

Comments
 (0)