From e57c2f69749ac8750f798a80f32b2c59d11f0f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 10 Dec 2024 18:19:26 +0100 Subject: [PATCH 1/4] first step towards removal of IntegralDomain --- src/sage/categories/integral_domains.py | 32 ++++++++++++++ src/sage/categories/rings.py | 16 +++++++ src/sage/rings/abc.pyx | 5 +-- src/sage/rings/localization.py | 19 ++++----- .../rings/number_field/number_field_base.pyx | 2 +- src/sage/rings/power_series_ring.py | 4 +- src/sage/rings/ring.pyx | 42 ------------------- 7 files changed, 61 insertions(+), 59 deletions(-) diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 4dd66a9277b..27983661520 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -143,6 +143,38 @@ def is_integral_domain(self, proof=True): """ return True + def is_field(self, proof=True): + r""" + Return ``True`` if this ring is a field. + + EXAMPLES:: + + sage: ZZ['x'].is_field() + False + """ + if self.is_finite(): + return True + if proof: + raise NotImplementedError("unable to determine whether or not is a field.") + else: + return False + + def localization(self, additional_units, names=None, normalize=True, category=None): + """ + Return the localization of ``self`` at the given additional units. + + EXAMPLES:: + + sage: R. = GF(3)[] + sage: R.localization((x*y, x**2 + y**2)) # needs sage.rings.finite_rings + Multivariate Polynomial Ring in x, y over Finite Field of size 3 + localized at (y, x, x^2 + y^2) + sage: ~y in _ # needs sage.rings.finite_rings + True + """ + from sage.rings.localization import Localization + return Localization(self, additional_units, names=names, normalize=normalize, category=category) + def _test_fraction_field(self, **options): r""" Test that the fraction field, if it is implemented, works diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index adfc75c00ec..e0769336c6f 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -554,6 +554,22 @@ def is_subring(self, other): except (TypeError, AttributeError): return False + def localization(self, *args, **kwds): + """ + Return the localization of ``self``. + + This only works for integral domains. + + EXAMPLES:: + + sage: R = Zmod(6) + sage: R.localization((4)) + Traceback (most recent call last): + ... + TypeError: self must be an integral domain + """ + raise TypeError("self must be an integral domain") + def bracket(self, x, y): """ Return the Lie bracket `[x, y] = x y - y x` of `x` and `y`. diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index e8078f97743..cc8c3ec9a10 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -1,9 +1,6 @@ """ Abstract base classes for rings """ -from sage.rings.ring import IntegralDomain - - class NumberField_quadratic(Field): r""" Abstract base class for :class:`~sage.rings.number_field.number_field.NumberField_quadratic`. @@ -419,7 +416,7 @@ class Order: pass -class pAdicRing(IntegralDomain): +class pAdicRing(CommutativeRing): r""" Abstract base class for :class:`~sage.rings.padics.generic_nodes.pAdicRingGeneric`. diff --git a/src/sage/rings/localization.py b/src/sage/rings/localization.py index ab6916d36c8..e5015e95a7a 100644 --- a/src/sage/rings/localization.py +++ b/src/sage/rings/localization.py @@ -180,7 +180,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.integral_domains import IntegralDomains -from sage.rings.ring import IntegralDomain +from sage.structure.parent import Parent from sage.structure.element import IntegralDomainElement @@ -193,7 +193,7 @@ def normalize_extra_units(base_ring, add_units, warning=True): INPUT: - - ``base_ring`` -- an instance of :class:`IntegralDomain` + - ``base_ring`` -- a ring in the category of :class:`IntegralDomains` - ``add_units`` -- list of elements from base ring - ``warning`` -- boolean (default: ``True``); to suppress a warning which is thrown if no normalization was possible @@ -561,7 +561,7 @@ def _integer_(self, Z=None): return self._value._integer_(Z=Z) -class Localization(IntegralDomain, UniqueRepresentation): +class Localization(Parent, UniqueRepresentation): r""" The localization generalizes the construction of the field of fractions of an integral domain to an arbitrary ring. Given a (not necessarily @@ -580,21 +580,18 @@ class Localization(IntegralDomain, UniqueRepresentation): this class relies on the construction of the field of fraction and is therefore restricted to integral domains. - Accordingly, this class is inherited from :class:`IntegralDomain` and can - only be used in that context. Furthermore, the base ring should support + Accordingly, the base ring must be in the category of ``IntegralDomains``. + Furthermore, the base ring should support :meth:`sage.structure.element.CommutativeRingElement.divides` and the exact division operator ``//`` (:meth:`sage.structure.element.Element.__floordiv__`) in order to guarantee a successful application. INPUT: - - ``base_ring`` -- an instance of :class:`Ring` allowing the construction - of :meth:`fraction_field` (that is an integral domain) + - ``base_ring`` -- a ring in the category of ``IntegralDomains`` - ``extra_units`` -- tuple of elements of ``base_ring`` which should be turned into units - - ``names`` -- passed to :class:`IntegralDomain` - - ``normalize`` -- boolean (default: ``True``); passed to :class:`IntegralDomain` - - ``category`` -- (default: ``None``) passed to :class:`IntegralDomain` + - ``category`` -- (default: ``None``) passed to :class:`Parent` - ``warning`` -- boolean (default: ``True``); to suppress a warning which is thrown if ``self`` cannot be represented uniquely @@ -712,7 +709,7 @@ def __init__(self, base_ring, extra_units, names=None, normalize=True, category= # since by construction the base ring must contain non units self must be infinite category = IntegralDomains().Infinite() - IntegralDomain.__init__(self, base_ring, names=names, normalize=normalize, category=category) + Parent.__init__(self, base=base_ring, names=names, normalize=normalize, category=category) self._extra_units = tuple(extra_units) self._fraction_field = base_ring.fraction_field() self._populate_coercion_lists_() diff --git a/src/sage/rings/number_field/number_field_base.pyx b/src/sage/rings/number_field/number_field_base.pyx index 910f6ff7904..1c8259a8250 100644 --- a/src/sage/rings/number_field/number_field_base.pyx +++ b/src/sage/rings/number_field/number_field_base.pyx @@ -65,7 +65,7 @@ cdef class NumberField(Field): +Infinity """ # This token docstring is mostly there to prevent Sphinx from pasting in - # the docstring of the __init__ method inherited from IntegralDomain, which + # the docstring of the __init__ method inherited from Field, which # is rather confusing. def _pushout_(self, other): r""" diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index e6c932aadff..512ab8d6e20 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -1323,7 +1323,9 @@ def laurent_series_ring(self): return self.__laurent_series_ring -class PowerSeriesRing_domain(PowerSeriesRing_generic, ring.IntegralDomain): +class PowerSeriesRing_domain(PowerSeriesRing_generic): + _default_category = _IntegralDomains + def fraction_field(self): """ Return the Laurent series ring over the fraction field of the base diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index c4137a6974f..36b84c399fe 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -773,25 +773,6 @@ cdef class CommutativeRing(Ring): Ring.__init__(self, base_ring, names=names, normalize=normalize, category=category) - def localization(self, additional_units, names=None, normalize=True, category=None): - """ - Return the localization of ``self`` at the given additional units. - - EXAMPLES:: - - sage: R. = GF(3)[] - sage: R.localization((x*y, x**2 + y**2)) # needs sage.rings.finite_rings - Multivariate Polynomial Ring in x, y over Finite Field of size 3 - localized at (y, x, x^2 + y^2) - sage: ~y in _ # needs sage.rings.finite_rings - True - """ - if not self.is_integral_domain(): - raise TypeError("self must be an integral domain.") - - from sage.rings.localization import Localization - return Localization(self, additional_units, names=names, normalize=normalize, category=category) - def fraction_field(self): """ Return the fraction field of ``self``. @@ -1018,29 +999,6 @@ cdef class IntegralDomain(CommutativeRing): CommutativeRing.__init__(self, base_ring, names=names, normalize=normalize, category=category) - def is_field(self, proof=True): - r""" - Return ``True`` if this ring is a field. - - EXAMPLES:: - - sage: GF(7).is_field() - True - - The following examples have their own ``is_field`` implementations:: - - sage: ZZ.is_field(); QQ.is_field() - False - True - sage: R. = PolynomialRing(QQ); R.is_field() - False - """ - if self.is_finite(): - return True - if proof: - raise NotImplementedError("unable to determine whether or not is a field.") - else: - return False cdef class NoetherianRing(CommutativeRing): _default_category = NoetherianRings() From b57db7671b48eface8e6fd64e9bc25085d8dc9e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 10 Dec 2024 19:47:15 +0100 Subject: [PATCH 2/4] fix linter --- src/sage/rings/abc.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index cc8c3ec9a10..ef74bf34d4a 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -1,6 +1,8 @@ """ Abstract base classes for rings """ + + class NumberField_quadratic(Field): r""" Abstract base class for :class:`~sage.rings.number_field.number_field.NumberField_quadratic`. From 2d110bdf49161a45e30204cf76d4ed99c9a4377d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 11 Dec 2024 08:39:21 +0100 Subject: [PATCH 3/4] detail in is_field Co-authored-by: Martin Rubey --- src/sage/categories/integral_domains.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 27983661520..c66b609a5e3 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -155,9 +155,8 @@ def is_field(self, proof=True): if self.is_finite(): return True if proof: - raise NotImplementedError("unable to determine whether or not is a field.") - else: - return False + raise NotImplementedError(f"unable to determine whether or not {self} is a field.") + return False def localization(self, additional_units, names=None, normalize=True, category=None): """ From 52bb268e699ab22ef4cac53f4923a643bb55314d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 11 Dec 2024 10:29:52 +0100 Subject: [PATCH 4/4] fix doctest in src/doc --- src/doc/en/thematic_tutorials/coercion_and_categories.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 5eeddc3a7f6..2339cc57f26 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -133,7 +133,6 @@ This base class provides a lot more methods than a general parent:: 'is_commutative', 'is_field', 'krull_dimension', - 'localization', 'ngens', 'one', 'order',