Skip to content

moving two methods to the categories of rings and fields #40392

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

Merged
merged 3 commits into from
Jul 25, 2025
Merged
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
2 changes: 0 additions & 2 deletions src/doc/en/thematic_tutorials/coercion_and_categories.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,7 @@ as this base class still provides a few more methods than a general parent::
'_one_element',
'_pseudo_fraction_field',
'_zero_element',
'an_embedding',
'base_extend',
'epsilon',
'extension',
'fraction_field',
'gen',
Expand Down
68 changes: 52 additions & 16 deletions src/sage/categories/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,58 @@
"""
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')

Check warning on line 319 in src/sage/categories/fields.py

View check run for this annotation

Codecov / codecov/patch

src/sage/categories/fields.py#L319

Added line #L319 was not covered by tests

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}')

def prime_subfield(self):
"""
Return the prime subfield of ``self``.
Expand Down Expand Up @@ -699,22 +751,6 @@
"""
return self.free_module(*args, **kwds)

def _pseudo_fraction_field(self):
"""
The fraction field of ``self`` is always available as ``self``.

EXAMPLES::

sage: QQ._pseudo_fraction_field()
Rational Field
sage: K = GF(5)
sage: K._pseudo_fraction_field()
Finite Field of size 5
sage: K._pseudo_fraction_field() is K
True
"""
return self

class ElementMethods:
def euclidean_degree(self):
r"""
Expand Down
61 changes: 61 additions & 0 deletions src/sage/categories/rings.py
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,67 @@
a, b = args[0], args[1]
return randint(a, b) * self.one()

@cached_method
def epsilon(self):
"""
Return the precision error of elements in this ring.

.. NOTE:: This is not used anywhere inside the code base.

EXAMPLES::

sage: RDF.epsilon()
2.220446049250313e-16
sage: ComplexField(53).epsilon() # needs sage.rings.real_mpfr
2.22044604925031e-16
sage: RealField(10).epsilon() # needs sage.rings.real_mpfr
0.0020

For exact rings, zero is returned::

sage: ZZ.epsilon()
0

This also works over derived rings::

sage: RR['x'].epsilon() # needs sage.rings.real_mpfr
2.22044604925031e-16
sage: QQ['x'].epsilon()
0

For the symbolic ring, there is no reasonable answer::

sage: SR.epsilon() # needs sage.symbolic
Traceback (most recent call last):
...
NotImplementedError
"""
one = self.one()

# ulp is only defined in some real fields
try:
return one.ulp()
except AttributeError:
pass

try:
eps = one.real().ulp()
except AttributeError:
pass
else:
return self(eps)

if self.is_exact():
return self.zero()

S = self.base_ring()
if self is not S:
try:
return self(S.epsilon())
except AttributeError:
pass

Check warning on line 1808 in src/sage/categories/rings.py

View check run for this annotation

Codecov / codecov/patch

src/sage/categories/rings.py#L1807-L1808

Added lines #L1807 - L1808 were not covered by tests
raise NotImplementedError

class ElementMethods:
def is_unit(self) -> bool:
r"""
Expand Down
105 changes: 0 additions & 105 deletions src/sage/rings/ring.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -484,59 +484,6 @@ cdef class Ring(ParentWithGens):
return 1
raise NotImplementedError

@cached_method
def epsilon(self):
"""
Return the precision error of elements in this ring.

EXAMPLES::

sage: RDF.epsilon()
2.220446049250313e-16
sage: ComplexField(53).epsilon() # needs sage.rings.real_mpfr
2.22044604925031e-16
sage: RealField(10).epsilon() # needs sage.rings.real_mpfr
0.0020

For exact rings, zero is returned::

sage: ZZ.epsilon()
0

This also works over derived rings::

sage: RR['x'].epsilon() # needs sage.rings.real_mpfr
2.22044604925031e-16
sage: QQ['x'].epsilon()
0

For the symbolic ring, there is no reasonable answer::

sage: SR.epsilon() # needs sage.symbolic
Traceback (most recent call last):
...
NotImplementedError
"""
one = self.one()
try:
return one.ulp()
except AttributeError:
pass

try:
eps = one.real().ulp()
except AttributeError:
pass
else:
return self(eps)

B = self._base
if B is not None and B is not self:
eps = self.base_ring().epsilon()
return self(eps)
if self.is_exact():
return self.zero()
raise NotImplementedError

cdef class CommutativeRing(Ring):
"""
Expand Down Expand Up @@ -757,58 +704,6 @@ cdef class Field(CommutativeRing):
"""
_default_category = _Fields

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
Loading