From 372a074c61c06050c81f8c9624a0a82cb401be75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 1 Apr 2024 15:48:13 +0200 Subject: [PATCH 01/21] medium-scale refactoring of categories for rings --- src/sage/categories/commutative_rings.py | 49 +++ src/sage/categories/fields.py | 14 +- src/sage/categories/integral_domains.py | 5 + src/sage/categories/noetherian_rings.py | 87 ++++ .../categories/principal_ideal_domains.py | 169 +++++++- src/sage/categories/rings.py | 171 +++++--- src/sage/rings/integer_ring.pxd | 4 +- src/sage/rings/integer_ring.pyx | 4 +- src/sage/rings/padics/local_generic.py | 5 +- src/sage/rings/padics/padic_generic.py | 5 +- .../polynomial/polynomial_ring_constructor.py | 2 +- src/sage/rings/qqbar.py | 2 +- src/sage/rings/ring.pxd | 7 +- src/sage/rings/ring.pyx | 399 ++---------------- src/sage/structure/category_object.pyx | 6 +- 15 files changed, 472 insertions(+), 457 deletions(-) create mode 100644 src/sage/categories/noetherian_rings.py diff --git a/src/sage/categories/commutative_rings.py b/src/sage/categories/commutative_rings.py index 4e63eb8b594..fcf16afd848 100644 --- a/src/sage/categories/commutative_rings.py +++ b/src/sage/categories/commutative_rings.py @@ -65,6 +65,39 @@ def is_commutative(self) -> bool: """ return True + def _ideal_class_(self, n=0): + r""" + Return a callable object that can be used to create ideals in this + commutative ring. + + This class can depend on `n`, the number of generators of the ideal. + The default input of `n=0` indicates an unspecified number of generators, + in which case a class that works for any number of generators is returned. + + EXAMPLES:: + + sage: ZZ._ideal_class_() + + sage: RR._ideal_class_() + + sage: R. = GF(5)[] + sage: R._ideal_class_(1) + + sage: S = R.quo(x^3 - y^2) + sage: S._ideal_class_(1) + + sage: S._ideal_class_(2) + + sage: T. = S[] # needs sage.libs.singular + sage: T._ideal_class_(5) # needs sage.libs.singular + + sage: T._ideal_class_(1) # needs sage.libs.singular + + """ + # One might need more than just n + from sage.rings.ideal import Ideal_generic, Ideal_principal + return Ideal_principal if n == 1 else Ideal_generic + def _test_divides(self, **options): r""" Run generic tests on the method :meth:`divides`. @@ -248,6 +281,22 @@ class Finite(CategoryWithAxiom): ....: GF(5)]) in Rings().Commutative().Finite() True """ + def extra_super_categories(self): + r""" + Let Sage knows that Cartesian products of commutative rings is a + commutative ring. + + EXAMPLES:: + + sage: CommutativeRings().Commutative().CartesianProducts().extra_super_categories() + [Category of commutative rings] + sage: cartesian_product([ZZ, Zmod(34), + ....: QQ, GF(5)]) in CommutativeRings() + True + """ + from sage.categories.noetherian_rings import NoetherianRings + return [NoetherianRings()] + class ParentMethods: def cyclotomic_cosets(self, q, cosets=None): r""" diff --git a/src/sage/categories/fields.py b/src/sage/categories/fields.py index 7407632a93f..e0b03fa0901 100644 --- a/src/sage/categories/fields.py +++ b/src/sage/categories/fields.py @@ -18,6 +18,7 @@ from sage.categories.category_singleton import Category_contains_method_by_parent_class from sage.categories.euclidean_domains import EuclideanDomains from sage.categories.division_rings import DivisionRings +from sage.categories.noetherian_rings import NoetherianRings from sage.structure.element import coerce_binop @@ -33,7 +34,9 @@ class Fields(CategoryWithAxiom): sage: K Category of fields sage: Fields().super_categories() - [Category of euclidean domains, Category of division rings] + [Category of euclidean domains, + Category of division rings, + Category of noetherian rings] sage: K(IntegerRing()) Rational Field @@ -54,10 +57,9 @@ def extra_super_categories(self): EXAMPLES:: sage: Fields().extra_super_categories() - [Category of euclidean domains] - + [Category of euclidean domains, Category of noetherian rings] """ - return [EuclideanDomains()] + return [EuclideanDomains(), NoetherianRings()] def __contains__(self, x): """ @@ -165,7 +167,9 @@ def _call_(self, x): sage: K Category of fields sage: Fields().super_categories() - [Category of euclidean domains, Category of division rings] + [Category of euclidean domains, + Category of division rings, + Category of noetherian rings] sage: K(IntegerRing()) # indirect doctest Rational Field diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index b6e6f59a196..d29b2b159f0 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -103,6 +103,8 @@ def is_integral_domain(self, proof=True): EXAMPLES:: + sage: ZZ.is_integral_domain() + True sage: QQ.is_integral_domain() True sage: Parent(QQ, category=IntegralDomains()).is_integral_domain() @@ -113,6 +115,9 @@ def is_integral_domain(self, proof=True): True sage: L.is_integral_domain(proof=True) # needs sage.combinat True + + sage: ZZ['x'].is_integral_domain() + True """ return True diff --git a/src/sage/categories/noetherian_rings.py b/src/sage/categories/noetherian_rings.py new file mode 100644 index 00000000000..9b8bfe557e5 --- /dev/null +++ b/src/sage/categories/noetherian_rings.py @@ -0,0 +1,87 @@ +r""" +Noetherian rings + +EXAMPLES:: + + sage: from sage.categories.noetherian_rings import NoetherianRings + sage: GF(4, "a") in NoetherianRings() # needs sage.rings.finite_rings + True + sage: QQ in NoetherianRings() + True + sage: ZZ in NoetherianRings() + False? + sage: IntegerModRing(4) in NoetherianRings() + True + sage: IntegerModRing(5) in NoetherianRings() + True +""" +# **************************************************************************** +# Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) +# 2012 Nicolas M. Thiery +# +# Distributed under the terms of the GNU General Public License (GPL) +# https://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.categories.category import Category +from sage.categories.commutative_rings import CommutativeRings + + +class NoetherianRings(Category): + """ + The category of Noetherian rings + + A Noetherian ring is a commutative ring in which + every ideal is finitely generated. + + See :wikipedia:`Noetherian ring` + + EXAMPLES:: + + sage: from sage.categories.noetherian_rings import NoetherianRings + sage: C = NoetherianRings(); C + Category of noetherian rings + sage: sorted(C.super_categories(), key=str) + [Category of commutative rings] + + TESTS:: + + sage: TestSuite(C).run() + """ + def super_categories(self): + """ + EXAMPLES:: + + sage: DedekindDomains().super_categories() + [Category of integral domains] + """ + return [CommutativeRings()] + + class ParentMethods: + def is_noetherian(self, proof=True): + r""" + Return ``True``, since this in an object of the category + of Noetherian rings. + + EXAMPLES:: + + sage: ZZ.is_noetherian() + True + sage: QQ.is_noetherian() + True + sage: ZZ['x'].is_integral_domain() + True + sage: R. = PolynomialRing(QQ) + sage: R.is_noetherian() + True + + sage: L. = LazyLaurentSeriesRing(QQ) # needs sage.combinat + sage: L.is_integral_domain() # needs sage.combinat + True + sage: L.is_integral_domain(proof=True) # needs sage.combinat + True + """ + return True + + class ElementMethods: + pass diff --git a/src/sage/categories/principal_ideal_domains.py b/src/sage/categories/principal_ideal_domains.py index f020cfb383d..30f2969613a 100644 --- a/src/sage/categories/principal_ideal_domains.py +++ b/src/sage/categories/principal_ideal_domains.py @@ -1,16 +1,17 @@ r""" Principal ideal domains """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.categories.category_singleton import Category_singleton from sage.categories.unique_factorization_domains import UniqueFactorizationDomains + class PrincipalIdealDomains(Category_singleton): """ The category of (constructive) principal ideal domains @@ -94,33 +95,175 @@ def _test_gcd_vs_xgcd(self, **options): # there are some strange things in Sage doctests... so it is better # to cut the list in order to avoid lists of size 531441. elts = elts[:10] - pairs = [(x,y) for x in elts for y in elts] + pairs = [(x, y) for x in elts for y in elts] try: - xgcds = [x.xgcd(y) for x,y in pairs] - except (AttributeError,NotImplementedError): + xgcds = [x.xgcd(y) for x, y in pairs] + except (AttributeError, NotImplementedError): return has_gcd = True try: - gcds = [x.gcd(y) for x,y in pairs] - except (AttributeError,NotImplementedError): + gcds = [x.gcd(y) for x, y in pairs] + except (AttributeError, NotImplementedError): has_gcd = False tester.assertTrue(has_gcd, "The ring {} provides a xgcd but no gcd".format(self)) - for (x,y),gcd,xgcd in zip(pairs,gcds,xgcds): + for (x, y), gcd, xgcd in zip(pairs, gcds, xgcds): tester.assertTrue(gcd.parent() == self, "The parent of the gcd is {} for element of {}".format( gcd.parent(), self)) tester.assertTrue(xgcd[0].parent() == self and - xgcd[1].parent() == self and xgcd[2].parent() == self, - "The parent of output in xgcd is different from " - "the parent of input for elements in {}".format(self)) + xgcd[1].parent() == self == xgcd[2].parent(), + "The parent of output in xgcd is different from " + "the parent of input for elements in {}".format(self)) tester.assertTrue(gcd == xgcd[0], "The methods gcd and xgcd disagree on {}:\n" " gcd({},{}) = {}\n" - " xgcd({},{}) = {}\n".format(self,x,y,gcd,x,y,xgcd)) + " xgcd({},{}) = {}\n".format(self, x, y, gcd, x, y, xgcd)) + + def is_noetherian(self) -> bool: + """ + Every principal ideal domain is noetherian, so we return ``True``. + + EXAMPLES:: + + sage: Zp(5).is_noetherian() # needs sage.rings.padics + True + """ + return True + + def class_group(self): + """ + Return the trivial group, since the class group of a PID is trivial. + + EXAMPLES:: + + sage: QQ.class_group() # needs sage.groups + Trivial Abelian group + """ + from sage.groups.abelian_gps.abelian_group import AbelianGroup + return AbelianGroup([]) + + def gcd(self, x, y, coerce=True): + r""" + Return the greatest common divisor of ``x`` and ``y``, as elements + of ``self``. + + EXAMPLES: + + The integers are a principal ideal domain and hence a GCD domain:: + + sage: ZZ.gcd(42, 48) + 6 + sage: 42.factor(); 48.factor() + 2 * 3 * 7 + 2^4 * 3 + sage: ZZ.gcd(2^4*7^2*11, 2^3*11*13) + 88 + sage: 88.factor() + 2^3 * 11 + + In a field, any nonzero element is a GCD of any nonempty set + of nonzero elements. In previous versions, Sage used to return + 1 in the case of the rational field. However, since :issue:`10771`, + the rational field is considered as the + *fraction field* of the integer ring. For the fraction field + of an integral domain that provides both GCD and LCM, it is + possible to pick a GCD that is compatible with the GCD of the + base ring:: + + sage: QQ.gcd(ZZ(42), ZZ(48)); type(QQ.gcd(ZZ(42), ZZ(48))) + 6 + + sage: QQ.gcd(1/2, 1/3) + 1/6 + + Polynomial rings over fields are GCD domains as well. Here is a simple + example over the ring of polynomials over the rationals as well as + over an extension ring. Note that ``gcd`` requires x and y to be + coercible:: + + sage: # needs sage.rings.number_field + sage: R. = PolynomialRing(QQ) + sage: S. = NumberField(x^2 - 2, 'a') + sage: f = (x - a)*(x + a); g = (x - a)*(x^2 - 2) + sage: print(f); print(g) + x^2 - 2 + x^3 - a*x^2 - 2*x + 2*a + sage: f in R + True + sage: g in R + False + sage: R.gcd(f, g) + Traceback (most recent call last): + ... + TypeError: Unable to coerce 2*a to a rational + sage: R.base_extend(S).gcd(f,g) + x^2 - 2 + sage: R.base_extend(S).gcd(f, (x - a)*(x^2 - 3)) + x - a + """ + if coerce: + x = self(x) + y = self(y) + return x.gcd(y) + + def content(self, x, y, coerce=True): + r""" + Return the content of `x` and `y`. + + This is the unique element `c` of + ``self`` such that `x/c` and `y/c` + are coprime and integral. + + EXAMPLES:: + + sage: QQ.content(ZZ(42), ZZ(48)); type(QQ.content(ZZ(42), ZZ(48))) + 6 + + sage: QQ.content(1/2, 1/3) + 1/6 + sage: factor(1/2); factor(1/3); factor(1/6) + 2^-1 + 3^-1 + 2^-1 * 3^-1 + sage: a = (2*3)/(7*11); b = (13*17)/(19*23) + sage: factor(a); factor(b); factor(QQ.content(a,b)) + 2 * 3 * 7^-1 * 11^-1 + 13 * 17 * 19^-1 * 23^-1 + 7^-1 * 11^-1 * 19^-1 * 23^-1 + + Note the changes to the second entry:: + + sage: c = (2*3)/(7*11); d = (13*17)/(7*19*23) + sage: factor(c); factor(d); factor(QQ.content(c,d)) + 2 * 3 * 7^-1 * 11^-1 + 7^-1 * 13 * 17 * 19^-1 * 23^-1 + 7^-1 * 11^-1 * 19^-1 * 23^-1 + sage: e = (2*3)/(7*11); f = (13*17)/(7^3*19*23) + sage: factor(e); factor(f); factor(QQ.content(e,f)) + 2 * 3 * 7^-1 * 11^-1 + 7^-3 * 13 * 17 * 19^-1 * 23^-1 + 7^-3 * 11^-1 * 19^-1 * 23^-1 + """ + if coerce: + x = self(x) + y = self(y) + return x.content(y) + + def _ideal_class_(self, n=0): + """ + Ideals in PIDs have their own special class. + + EXAMPLES:: + + sage: ZZ._ideal_class_() + + """ + from sage.rings.ideal import Ideal_pid + return Ideal_pid class ElementMethods: pass diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index 9685fb80dd4..b6037e95ad8 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -339,6 +339,101 @@ def is_commutative(self) -> bool: """ return False + def is_integral_domain(self, proof=True) -> bool: + """ + Return ``True`` if this ring is an integral domain. + + INPUT: + + - ``proof`` -- (default: ``True``) Determines what to do in unknown + cases + + ALGORITHM: + + If the parameter ``proof`` is set to ``True``, the returned value is + correct but the method might throw an error. Otherwise, if it is set + to ``False``, the method returns ``True`` if it can establish that self + is an integral domain and ``False`` otherwise. + + EXAMPLES:: + + sage: QQ.is_integral_domain() + True + sage: ZZ.is_integral_domain() + True + sage: ZZ['x,y,z'].is_integral_domain() + True + sage: Integers(8).is_integral_domain() + False + sage: Zp(7).is_integral_domain() # needs sage.rings.padics + True + sage: Qp(7).is_integral_domain() # needs sage.rings.padics + True + sage: R. = QQ[] + sage: S. = R.quo((b^3)) # needs sage.libs.singular + sage: S.is_integral_domain() # needs sage.libs.singular + False + sage: R = ZZ.quotient(ZZ.ideal(10)); R.is_integral_domain() + False + + This illustrates the use of the ``proof`` parameter:: + + sage: R. = ZZ[] + sage: S. = R.quo((b^3)) # needs sage.libs.singular + sage: S.is_integral_domain(proof=True) # needs sage.libs.singular + Traceback (most recent call last): + ... + NotImplementedError + sage: S.is_integral_domain(proof=False) # needs sage.libs.singular + False + + TESTS: + + Make sure :issue:`10481` is fixed:: + + sage: x = polygen(ZZ, 'x') + sage: R. = ZZ['x'].quo(x^2) # needs sage.libs.pari + sage: R.fraction_field() # needs sage.libs.pari + Traceback (most recent call last): + ... + TypeError: self must be an integral domain. + sage: R.is_integral_domain() # needs sage.libs.pari + False + + Forward the proof flag to ``is_field``, see :issue:`22910`:: + + sage: # needs sage.libs.singular + sage: R1. = GF(5)[] + sage: F1 = R1.quotient_ring(x^2 + x + 1) + sage: R2. = F1[] + sage: F2 = R2.quotient_ring(x^2 + x + 1) + sage: F2.is_integral_domain(False) + False + """ + if self.is_field(proof): + return True + + if self.is_zero(): + return False + + if proof: + raise NotImplementedError + + return False + + def is_noetherian(self): + """ + Return ``True`` if this ring is Noetherian. + + EXAMPLES:: + + sage: QQ.is_noetherian() + True + sage: ZZ.is_noetherian() + True + """ + return False + def is_zero(self) -> bool: """ Return ``True`` if this is the zero ring. @@ -579,6 +674,26 @@ def ideal_monoid(self): from sage.rings.noncommutative_ideals import IdealMonoid_nc return IdealMonoid_nc(self) + def _ideal_class_(self, n=0): + r""" + Return a callable object that can be used to create ideals in this + ring. + + EXAMPLES:: + + sage: MS = MatrixSpace(QQ, 2, 2) # needs sage.modules + sage: MS._ideal_class_() # needs sage.modules + + + Since :issue:`7797`, non-commutative rings have ideals as well:: + + sage: A = SteenrodAlgebra(2) # needs sage.combinat sage.modules + sage: A._ideal_class_() # needs sage.combinat sage.modules + + """ + from sage.rings.noncommutative_ideals import Ideal_nc + return Ideal_nc + def characteristic(self): """ Return the characteristic of this ring. @@ -734,62 +849,6 @@ def ideal(self, *args, **kwds): gens = gens[0] return C(self, gens, **kwds) - def _ideal_class_(self, n=0): - """ - Return the class that is used to implement ideals of this ring. - - .. NOTE:: - - We copy the code from :class:`~sage.rings.ring.Ring`. This is - necessary because not all rings inherit from that class, such - as matrix algebras. - - INPUT: - - - ``n`` (optional integer, default 0): The number of generators - of the ideal to be created. - - OUTPUT: - - The class that is used to implement ideals of this ring with - ``n`` generators. - - .. NOTE:: - - Often principal ideals (``n==1``) are implemented via - a different class. - - EXAMPLES:: - - sage: MS = MatrixSpace(QQ, 2, 2) # needs sage.modules - sage: MS._ideal_class_() # needs sage.modules - - - We do not know of a commutative ring in Sage that does not inherit - from the base class of rings. So, we need to cheat in the next - example:: - - sage: super(Ring,QQ)._ideal_class_.__module__ - 'sage.categories.rings' - sage: super(Ring,QQ)._ideal_class_() - - sage: super(Ring,QQ)._ideal_class_(1) - - sage: super(Ring,QQ)._ideal_class_(2) - - """ - from sage.rings.noncommutative_ideals import Ideal_nc - try: - if not self.is_commutative(): - return Ideal_nc - except (NotImplementedError, AttributeError): - return Ideal_nc - from sage.rings.ideal import Ideal_generic, Ideal_principal - if n == 1: - return Ideal_principal - return Ideal_generic - - ## # Quotient rings def quotient(self, I, names=None, **kwds): """ diff --git a/src/sage/rings/integer_ring.pxd b/src/sage/rings/integer_ring.pxd index d0af1bc068f..204ccbe141c 100644 --- a/src/sage/rings/integer_ring.pxd +++ b/src/sage/rings/integer_ring.pxd @@ -1,7 +1,7 @@ -from sage.rings.ring cimport PrincipalIdealDomain +from sage.rings.ring cimport CommutativeRing from sage.rings.integer cimport Integer from sage.libs.gmp.types cimport mpz_t -cdef class IntegerRing_class(PrincipalIdealDomain): +cdef class IntegerRing_class(CommutativeRing): cdef int _randomize_mpz(self, mpz_t value, x, y, distribution) except -1 cdef object _zero diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index 013e67fedc3..7871e2c6d0a 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -106,7 +106,7 @@ def is_IntegerRing(x): """ return isinstance(x, IntegerRing_class) -cdef class IntegerRing_class(PrincipalIdealDomain): +cdef class IntegerRing_class(CommutativeRing): r""" The ring of integers. @@ -422,7 +422,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): K, _ = parent(x).subfield(x) return K.order(K.gen()) - return PrincipalIdealDomain.__getitem__(self, x) + return CommutativeRing.__getitem__(self, x) def range(self, start, end=None, step=None): """ diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 066459c65a2..8d888c0b728 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -21,7 +21,7 @@ # ***************************************************************************** from copy import copy -from sage.rings.ring import CommutativeRing + from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationRings, CompleteDiscreteValuationFields from sage.structure.category_object import check_default_category from sage.structure.parent import Parent @@ -29,7 +29,8 @@ from sage.rings.integer_ring import ZZ from sage.rings.infinity import Infinity -class LocalGeneric(CommutativeRing): + +class LocalGeneric(Parent): def __init__(self, base, prec, names, element_class, category=None): r""" Initialize ``self``. diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 6452d77db22..60eb71e9e7c 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -33,7 +33,6 @@ from sage.categories.fields import Fields from sage.rings.infinity import infinity from .local_generic import LocalGeneric -from sage.rings.ring import PrincipalIdealDomain from sage.rings.integer import Integer from sage.rings.infinity import Infinity from sage.rings.padics.precision_error import PrecisionError @@ -41,7 +40,7 @@ from sage.structure.richcmp import richcmp_not_equal -class pAdicGeneric(PrincipalIdealDomain, LocalGeneric): +class pAdicGeneric(LocalGeneric): def __init__(self, base, p, prec, print_mode, names, element_class, category=None): r""" Initialize ``self``. @@ -68,7 +67,7 @@ def __init__(self, base, p, prec, print_mode, names, element_class, category=Non category = category.Metric().Complete() LocalGeneric.__init__(self, base, prec, names, element_class, category) self._printer = pAdicPrinter(self, print_mode) - self._qth_roots_of_unity = [ (1, Infinity) ] + self._qth_roots_of_unity = [(1, Infinity)] def some_elements(self): r""" diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index 2a1fb99131f..ac0f1c8d79f 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -862,7 +862,7 @@ def _multi_variate(base_ring, names, sparse=None, order="degrevlex", implementat if R is None and implementation == "generic": from . import multi_polynomial_ring - if isinstance(base_ring, IntegralDomain): + if base_ring in _Domains: constructor = multi_polynomial_ring.MPolynomialRing_polydict_domain else: constructor = multi_polynomial_ring.MPolynomialRing_polydict diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 4e4454988ca..386fd544812 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -8789,7 +8789,7 @@ def an_binop_element(a, b, op): for t2 in (ANUnaryExpr, ANBinaryExpr, ANRoot): _binop_algo[t1, t2] = _binop_algo[t2, t1] = an_binop_expr -qq_generator = AlgebraicGenerator(QQ, ANRoot(AAPoly.gen() - 1, RIF(1))) +qq_generator = AlgebraicGenerator(QQ, ANRoot(AAPoly([1, -1]), RIF.one())) def _init_qqbar(): diff --git a/src/sage/rings/ring.pxd b/src/sage/rings/ring.pxd index e74638b91e2..cf5399b66d9 100644 --- a/src/sage/rings/ring.pxd +++ b/src/sage/rings/ring.pxd @@ -16,14 +16,13 @@ cdef class CommutativeRing(Ring): cdef class IntegralDomain(CommutativeRing): pass -cdef class DedekindDomain(IntegralDomain): +cdef class DedekindDomain(CommutativeRing): pass - -cdef class PrincipalIdealDomain(IntegralDomain): +cdef class PrincipalIdealDomain(CommutativeRing): pass -cdef class Field(PrincipalIdealDomain): +cdef class Field(CommutativeRing): pass cdef class Algebra(Ring): diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index fe346931ce5..429344042d4 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -25,9 +25,9 @@ The class inheritance hierarchy is: - :class:`IntegralDomain` (deprecated) - :class:`DedekindDomain` (deprecated and essentially removed) - - :class:`PrincipalIdealDomain` (deprecated) + - :class:`PrincipalIdealDomain` (deprecated and essentially removed) -Subclasses of :class:`PrincipalIdealDomain` are +Subclasses of :class:`CommutativeRing` are - :class:`Field` @@ -35,9 +35,7 @@ Subclasses of :class:`PrincipalIdealDomain` are Some aspects of this structure may seem strange, but this is an unfortunate consequence of the fact that Cython classes do not support multiple -inheritance. Hence, for instance, :class:`Field` cannot be a subclass of both -:class:`NoetherianRing` and :class:`PrincipalIdealDomain`, although all fields -are Noetherian PIDs. +inheritance. (A distinct but equally awkward issue is that sometimes we may not know *in advance* whether or not a ring belongs in one of these classes; e.g. some @@ -58,7 +56,7 @@ TESTS: This is to test a deprecation:: - sage: from sage.rings.ring import DedekindDomain, CommutativeAlgebra + sage: from sage.rings.ring import DedekindDomain sage: class No(DedekindDomain): ....: pass sage: F = No(QQ) @@ -68,6 +66,7 @@ This is to test a deprecation:: sage: F.category() Category of Dedekind domains + sage: from sage.rings.ring import CommutativeAlgebra sage: class Nein(CommutativeAlgebra): ....: pass sage: F = Nein(QQ, QQ) @@ -76,6 +75,16 @@ This is to test a deprecation:: See https://github.com/sagemath/sage/issues/37999 for details. sage: F.category() Category of commutative rings + + sage: from sage.rings.ring import PrincipalIdealDomain + sage: class Non(PrincipalIdealDomain): + ....: pass + sage: F = Non(QQ) + ...: + DeprecationWarning: use the category PrincipalIdealDomains + See https://github.com/sagemath/sage/issues/44444 for details. + sage: F.category() + Category of principal ideal domains """ # **************************************************************************** @@ -100,6 +109,7 @@ from sage.categories.commutative_rings import CommutativeRings from sage.categories.integral_domains import IntegralDomains from sage.categories.dedekind_domains import DedekindDomains from sage.categories.principal_ideal_domains import PrincipalIdealDomains +from sage.categories.noetherian_rings import NoetherianRings _Rings = Rings() _CommutativeRings = CommutativeRings() @@ -225,7 +235,7 @@ cdef class Ring(ParentWithGens): # This is a low-level class. For performance, we trust that the category # is fine, if it is provided. If it isn't, we use the category of rings. if category is None: - category=_Rings + category = _Rings Parent.__init__(self, base=base, names=names, normalize=normalize, category=category) @@ -445,14 +455,14 @@ cdef class Ring(ParentWithGens): if coerce: gens = [self(g) for g in gens] - if isinstance(self, PrincipalIdealDomain): + if self in PrincipalIdealDomains(): # Use GCD algorithm to obtain a principal ideal g = gens[0] if len(gens) == 1: try: # note: we set g = gcd(g, g) to "canonicalize" the generator: make polynomials monic, etc. g = g.gcd(g) - except (AttributeError, NotImplementedError): + except (AttributeError, NotImplementedError, IndexError): pass else: for h in gens[1:]: @@ -531,57 +541,6 @@ cdef class Ring(ParentWithGens): else: raise TypeError("Don't know how to transform %s into an ideal of %s" % (self, x)) - def _ideal_class_(self, n=0): - r""" - Return a callable object that can be used to create ideals in this - ring. For generic rings, this returns the factory function - :func:`sage.rings.ideal.Ideal`, which does its best to be clever about - what is required. - - This class can depend on `n`, the number of generators of the ideal. - The default input of `n=0` indicates an unspecified number of generators, - in which case a class that works for any number of generators is returned. - - EXAMPLES:: - - sage: ZZ._ideal_class_() - - sage: RR._ideal_class_() - - sage: R. = GF(5)[] - sage: R._ideal_class_(1) - - sage: S = R.quo(x^3 - y^2) - sage: S._ideal_class_(1) - - sage: S._ideal_class_(2) - - sage: T. = S[] # needs sage.libs.singular - sage: T._ideal_class_(5) # needs sage.libs.singular - - sage: T._ideal_class_(1) # needs sage.libs.singular - - - Since :issue:`7797`, non-commutative rings have ideals as well:: - - sage: A = SteenrodAlgebra(2) # needs sage.combinat sage.modules - sage: A._ideal_class_() # needs sage.combinat sage.modules - - - """ - # One might need more than just n, but I can't think of an example. - from sage.rings.noncommutative_ideals import Ideal_nc - try: - if not self.is_commutative(): - return Ideal_nc - except (NotImplementedError, AttributeError): - return Ideal_nc - from sage.rings.ideal import Ideal_generic, Ideal_principal - if n == 1: - return Ideal_principal - else: - return Ideal_generic - def principal_ideal(self, gen, coerce=True): """ Return the principal ideal generated by gen. @@ -837,99 +796,6 @@ cdef class Ring(ParentWithGens): """ return False - def is_integral_domain(self, proof = True): - """ - Return ``True`` if this ring is an integral domain. - - INPUT: - - - ``proof`` -- (default: ``True``) Determines what to do in unknown - cases - - ALGORITHM: - - If the parameter ``proof`` is set to ``True``, the returned value is - correct but the method might throw an error. Otherwise, if it is set - to ``False``, the method returns ``True`` if it can establish that self - is an integral domain and ``False`` otherwise. - - EXAMPLES:: - - sage: QQ.is_integral_domain() - True - sage: ZZ.is_integral_domain() - True - sage: ZZ['x,y,z'].is_integral_domain() - True - sage: Integers(8).is_integral_domain() - False - sage: Zp(7).is_integral_domain() # needs sage.rings.padics - True - sage: Qp(7).is_integral_domain() # needs sage.rings.padics - True - sage: R. = QQ[] - sage: S. = R.quo((b^3)) # needs sage.libs.singular - sage: S.is_integral_domain() # needs sage.libs.singular - False - - This illustrates the use of the ``proof`` parameter:: - - sage: R. = ZZ[] - sage: S. = R.quo((b^3)) # needs sage.libs.singular - sage: S.is_integral_domain(proof=True) # needs sage.libs.singular - Traceback (most recent call last): - ... - NotImplementedError - sage: S.is_integral_domain(proof=False) # needs sage.libs.singular - False - - TESTS: - - Make sure :issue:`10481` is fixed:: - - sage: x = polygen(ZZ, 'x') - sage: R. = ZZ['x'].quo(x^2) # needs sage.libs.pari - sage: R.fraction_field() # needs sage.libs.pari - Traceback (most recent call last): - ... - TypeError: self must be an integral domain. - sage: R.is_integral_domain() # needs sage.libs.pari - False - - Forward the proof flag to ``is_field``, see :issue:`22910`:: - - sage: # needs sage.libs.singular - sage: R1. = GF(5)[] - sage: F1 = R1.quotient_ring(x^2 + x + 1) - sage: R2. = F1[] - sage: F2 = R2.quotient_ring(x^2 + x + 1) - sage: F2.is_integral_domain(False) - False - """ - if self.is_field(proof): - return True - - if self.is_zero(): - return False - - if proof: - raise NotImplementedError - else: - return False - - def is_noetherian(self): - """ - Return ``True`` if this ring is Noetherian. - - EXAMPLES:: - - sage: QQ.is_noetherian() - True - sage: ZZ.is_noetherian() - True - """ - raise NotImplementedError - def order(self): """ The number of elements of ``self``. @@ -1158,6 +1024,8 @@ cdef class CommutativeRing(Ring): """ Generic commutative ring. """ + _default_category = _CommutativeRings + def __init__(self, base_ring, names=None, normalize=True, category=None): """ Initialize ``self``. @@ -1175,8 +1043,7 @@ cdef class CommutativeRing(Ring): # This is a low-level class. For performance, we trust that # the category is fine, if it is provided. If it isn't, we use # the category of commutative rings. - if category is None: - category=_CommutativeRings + category = check_default_category(self._default_category, category) Ring.__init__(self, base_ring, names=names, normalize=normalize, category=category) @@ -1615,10 +1482,9 @@ cdef class IntegralDomain(CommutativeRing): This method is used by all the abstract subclasses of :class:`IntegralDomain`, like :class:`NoetherianRing`, - :class:`PrincipalIdealDomain`, :class:`Field`, ... in order to avoid cascade calls Field.__init__ -> - PrincipalIdealDomain.__init__ -> IntegralDomain.__init__ -> + IntegralDomain.__init__ -> ... EXAMPLES:: @@ -1627,56 +1493,22 @@ cdef class IntegralDomain(CommutativeRing): sage: F.category() Category of integral domains - sage: F = PrincipalIdealDomain(QQ) - sage: F.category() - Category of principal ideal domains - sage: F = Field(QQ) sage: F.category() Category of fields - If a category is specified, then the category is set to the - join of that category with the default category:: - - sage: F = PrincipalIdealDomain(QQ, category=EnumeratedSets()) - The default value for the category is specified by the class attribute ``default_category``:: sage: IntegralDomain._default_category Category of integral domains - sage: PrincipalIdealDomain._default_category - Category of principal ideal domains - sage: Field._default_category Category of fields - """ - category = check_default_category(self._default_category, category) CommutativeRing.__init__(self, base_ring, names=names, normalize=normalize, category=category) - def is_integral_domain(self, proof = True): - """ - Return ``True``, since this ring is an integral domain. - - (This is a naive implementation for objects with type - ``IntegralDomain``) - - EXAMPLES:: - - sage: ZZ.is_integral_domain() - True - sage: QQ.is_integral_domain() - True - sage: ZZ['x'].is_integral_domain() - True - sage: R = ZZ.quotient(ZZ.ideal(10)); R.is_integral_domain() - False - """ - return True - def is_integrally_closed(self): r""" Return ``True`` if this ring is integrally closed in its field of @@ -1733,35 +1565,14 @@ cdef class IntegralDomain(CommutativeRing): return False cdef class NoetherianRing(CommutativeRing): - """ - Generic Noetherian ring class. - - A Noetherian ring is a commutative ring in which every ideal is - finitely generated. - - This class is deprecated, and not actually used anywhere in the - Sage code base. If you think you need it, please create a - category :class:`NoetherianRings`, move the code of this class - there, and use it instead. - """ - def is_noetherian(self): - """ - Return ``True`` since this ring is Noetherian. - - EXAMPLES:: + _default_category = NoetherianRings() - sage: ZZ.is_noetherian() - True - sage: QQ.is_noetherian() - True - sage: R. = PolynomialRing(QQ) - sage: R.is_noetherian() - True - """ - return True + def __init__(self, *args, **kwds): + deprecation(37234, "use the category DedekindDomains") + super().__init__(*args, **kwds) -cdef class DedekindDomain(IntegralDomain): +cdef class DedekindDomain(CommutativeRing): _default_category = DedekindDomains() def __init__(self, *args, **kwds): @@ -1769,154 +1580,12 @@ cdef class DedekindDomain(IntegralDomain): super().__init__(*args, **kwds) -cdef class PrincipalIdealDomain(IntegralDomain): - """ - Generic principal ideal domain. - - This class is deprecated. Please use the - :class:`~sage.categories.principal_ideal_domains.PrincipalIdealDomains` - category instead. - """ +cdef class PrincipalIdealDomain(CommutativeRing): _default_category = PrincipalIdealDomains() - def is_noetherian(self): - """ - Every principal ideal domain is noetherian, so we return ``True``. - - EXAMPLES:: - - sage: Zp(5).is_noetherian() # needs sage.rings.padics - True - """ - return True - - def class_group(self): - """ - Return the trivial group, since the class group of a PID is trivial. - - EXAMPLES:: - - sage: QQ.class_group() # needs sage.groups - Trivial Abelian group - """ - from sage.groups.abelian_gps.abelian_group import AbelianGroup - return AbelianGroup([]) - - def gcd(self, x, y, coerce=True): - r""" - Return the greatest common divisor of ``x`` and ``y``, as elements - of ``self``. - - EXAMPLES: - - The integers are a principal ideal domain and hence a GCD domain:: - - sage: ZZ.gcd(42, 48) - 6 - sage: 42.factor(); 48.factor() - 2 * 3 * 7 - 2^4 * 3 - sage: ZZ.gcd(2^4*7^2*11, 2^3*11*13) - 88 - sage: 88.factor() - 2^3 * 11 - - In a field, any nonzero element is a GCD of any nonempty set - of nonzero elements. In previous versions, Sage used to return - 1 in the case of the rational field. However, since :issue:`10771`, - the rational field is considered as the - *fraction field* of the integer ring. For the fraction field - of an integral domain that provides both GCD and LCM, it is - possible to pick a GCD that is compatible with the GCD of the - base ring:: - - sage: QQ.gcd(ZZ(42), ZZ(48)); type(QQ.gcd(ZZ(42), ZZ(48))) - 6 - - sage: QQ.gcd(1/2, 1/3) - 1/6 - - Polynomial rings over fields are GCD domains as well. Here is a simple - example over the ring of polynomials over the rationals as well as - over an extension ring. Note that ``gcd`` requires x and y to be - coercible:: - - sage: # needs sage.rings.number_field - sage: R. = PolynomialRing(QQ) - sage: S. = NumberField(x^2 - 2, 'a') - sage: f = (x - a)*(x + a); g = (x - a)*(x^2 - 2) - sage: print(f); print(g) - x^2 - 2 - x^3 - a*x^2 - 2*x + 2*a - sage: f in R - True - sage: g in R - False - sage: R.gcd(f, g) - Traceback (most recent call last): - ... - TypeError: Unable to coerce 2*a to a rational - sage: R.base_extend(S).gcd(f,g) - x^2 - 2 - sage: R.base_extend(S).gcd(f, (x - a)*(x^2 - 3)) - x - a - """ - if coerce: - x = self(x) - y = self(y) - return x.gcd(y) - - def content(self, x, y, coerce=True): - r""" - Return the content of `x` and `y`, i.e. the unique element `c` of - ``self`` such that `x/c` and `y/c` are coprime and integral. - - EXAMPLES:: - - sage: QQ.content(ZZ(42), ZZ(48)); type(QQ.content(ZZ(42), ZZ(48))) - 6 - - sage: QQ.content(1/2, 1/3) - 1/6 - sage: factor(1/2); factor(1/3); factor(1/6) - 2^-1 - 3^-1 - 2^-1 * 3^-1 - sage: a = (2*3)/(7*11); b = (13*17)/(19*23) - sage: factor(a); factor(b); factor(QQ.content(a,b)) - 2 * 3 * 7^-1 * 11^-1 - 13 * 17 * 19^-1 * 23^-1 - 7^-1 * 11^-1 * 19^-1 * 23^-1 - - Note the changes to the second entry:: - - sage: c = (2*3)/(7*11); d = (13*17)/(7*19*23) - sage: factor(c); factor(d); factor(QQ.content(c,d)) - 2 * 3 * 7^-1 * 11^-1 - 7^-1 * 13 * 17 * 19^-1 * 23^-1 - 7^-1 * 11^-1 * 19^-1 * 23^-1 - sage: e = (2*3)/(7*11); f = (13*17)/(7^3*19*23) - sage: factor(e); factor(f); factor(QQ.content(e,f)) - 2 * 3 * 7^-1 * 11^-1 - 7^-3 * 13 * 17 * 19^-1 * 23^-1 - 7^-3 * 11^-1 * 19^-1 * 23^-1 - """ - if coerce: - x = self(x) - y = self(y) - return x.content(y) - - def _ideal_class_(self, n=0): - """ - Ideals in PIDs have their own special class. - - EXAMPLES:: - - sage: ZZ._ideal_class_() - - """ - from sage.rings.ideal import Ideal_pid - return Ideal_pid + def __init__(self, *args, **kwds): + deprecation(44444, "use the category PrincipalIdealDomains") + super().__init__(*args, **kwds) cpdef bint _is_Field(x) except -2: @@ -1955,7 +1624,7 @@ from sage.categories.commutative_algebras import CommutativeAlgebras from sage.categories.fields import Fields _Fields = Fields() -cdef class Field(PrincipalIdealDomain): +cdef class Field(CommutativeRing): """ Generic field """ @@ -2160,7 +1829,7 @@ cdef class Algebra(Ring): cdef class CommutativeAlgebra(CommutativeRing): - __default_category = CommutativeRings() + __default_category = _CommutativeRings def __init__(self, base_ring, *args, **kwds): deprecation(37999, "use the category CommutativeAlgebras") diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index 2c25ca4066d..cd39d91f8fb 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -64,11 +64,11 @@ from sage.structure.dynamic_class import DynamicMetaclass cpdef inline check_default_category(default_category, category) noexcept: - ## The resulting category is guaranteed to be - ## a sub-category of the default. + # The resulting category is guaranteed to be + # a sub-category of the default. if category is None: return default_category - return default_category.join([default_category,category]) + return default_category.join([default_category, category]) cdef class CategoryObject(SageObject): From 217255ddafa5a926a09ca69a38c2ac4c4a520512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 1 Apr 2024 17:01:44 +0200 Subject: [PATCH 02/21] some fixes --- src/sage/rings/polynomial/multi_polynomial.pyx | 7 ++++++- src/sage/rings/polynomial/polynomial_ring_constructor.py | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 65290e9e2d7..96281d8f4dd 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -2154,7 +2154,12 @@ cdef class MPolynomial(CommutativePolynomial): except (TypeError, AttributeError): pass - x = self._parent.gens()[-1] + gens = self.parent().gens() + if not gens: + base = self.parent().base_ring() + return base(self).gcd(base(other)) + + x = gens[-1] uniself = self.polynomial(x) unibase = uniself.base_ring() try: diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index ac0f1c8d79f..e417e8a6779 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -22,7 +22,6 @@ # **************************************************************************** from sage.structure.category_object import normalize_names -from sage.rings.ring import IntegralDomain try: import sage.rings.padics.padic_base_leaves as padic_base_leaves From 9f85768667086d5952b6f6970482c7baaa7de630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 1 Apr 2024 17:40:05 +0200 Subject: [PATCH 03/21] one more fix --- src/sage/categories/commutative_rings.py | 15 ++++++--------- src/sage/categories/noetherian_rings.py | 13 ++++++------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/sage/categories/commutative_rings.py b/src/sage/categories/commutative_rings.py index fcf16afd848..6c563714f9e 100644 --- a/src/sage/categories/commutative_rings.py +++ b/src/sage/categories/commutative_rings.py @@ -283,16 +283,13 @@ class Finite(CategoryWithAxiom): """ def extra_super_categories(self): r""" - Let Sage knows that Cartesian products of commutative rings is a - commutative ring. + Let Sage knows that finite commutative rings + are Noetherian. EXAMPLES:: - sage: CommutativeRings().Commutative().CartesianProducts().extra_super_categories() - [Category of commutative rings] - sage: cartesian_product([ZZ, Zmod(34), - ....: QQ, GF(5)]) in CommutativeRings() - True + sage: CommutativeRings().Finite().extra_super_categories() + [Category of noetherian rings] """ from sage.categories.noetherian_rings import NoetherianRings return [NoetherianRings()] @@ -416,7 +413,7 @@ def cyclotomic_cosets(self, q, cosets=None): try: ~q except ZeroDivisionError: - raise ValueError("%s is not invertible in %s" % (q,self)) + raise ValueError("%s is not invertible in %s" % (q, self)) if cosets is None: rest = set(self) @@ -427,7 +424,7 @@ def cyclotomic_cosets(self, q, cosets=None): while rest: x0 = rest.pop() o = [x0] - x = q*x0 + x = q * x0 while x != x0: o.append(x) rest.discard(x) diff --git a/src/sage/categories/noetherian_rings.py b/src/sage/categories/noetherian_rings.py index 9b8bfe557e5..bdffb796243 100644 --- a/src/sage/categories/noetherian_rings.py +++ b/src/sage/categories/noetherian_rings.py @@ -9,7 +9,7 @@ sage: QQ in NoetherianRings() True sage: ZZ in NoetherianRings() - False? + True sage: IntegerModRing(4) in NoetherianRings() True sage: IntegerModRing(5) in NoetherianRings() @@ -52,8 +52,9 @@ def super_categories(self): """ EXAMPLES:: - sage: DedekindDomains().super_categories() - [Category of integral domains] + sage: from sage.categories.noetherian_rings import NoetherianRings + sage: NoetherianRings().super_categories() + [Category of commutative rings] """ return [CommutativeRings()] @@ -69,16 +70,14 @@ def is_noetherian(self, proof=True): True sage: QQ.is_noetherian() True - sage: ZZ['x'].is_integral_domain() + sage: ZZ['x'].is_noetherian() True sage: R. = PolynomialRing(QQ) sage: R.is_noetherian() True sage: L. = LazyLaurentSeriesRing(QQ) # needs sage.combinat - sage: L.is_integral_domain() # needs sage.combinat - True - sage: L.is_integral_domain(proof=True) # needs sage.combinat + sage: L.is_noetherian() # needs sage.combinat True """ return True From 3b7d5176e3df814d74b12f288b6c971ab449bc33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 1 Apr 2024 17:48:51 +0200 Subject: [PATCH 04/21] fix ticket number --- src/sage/rings/ring.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 429344042d4..1c540e14aa6 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -82,7 +82,7 @@ This is to test a deprecation:: sage: F = Non(QQ) ...: DeprecationWarning: use the category PrincipalIdealDomains - See https://github.com/sagemath/sage/issues/44444 for details. + See https://github.com/sagemath/sage/issues/37719 for details. sage: F.category() Category of principal ideal domains """ @@ -1584,7 +1584,7 @@ cdef class PrincipalIdealDomain(CommutativeRing): _default_category = PrincipalIdealDomains() def __init__(self, *args, **kwds): - deprecation(44444, "use the category PrincipalIdealDomains") + deprecation(37719, "use the category PrincipalIdealDomains") super().__init__(*args, **kwds) From 6604f957d233f7a86f1d343c797072e54d7f3cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 1 Apr 2024 20:12:33 +0200 Subject: [PATCH 05/21] fix easy doctests --- src/doc/en/thematic_tutorials/coercion_and_categories.rst | 5 ----- src/sage/categories/category.py | 2 +- src/sage/misc/c3_controlled.pyx | 4 ++-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index edd89ad3c42..2720de5ca0e 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -116,7 +116,6 @@ This base class provides a lot more methods than a general parent:: '_coerce_impl', '_default_category', '_gens', - '_ideal_class_', '_ideal_monoid', '_latex_names', '_list', @@ -127,8 +126,6 @@ This base class provides a lot more methods than a general parent:: '_zero_ideal', 'algebraic_closure', 'base_extend', - 'class_group', - 'content', 'derivation', 'derivation_module', 'divides', @@ -136,7 +133,6 @@ This base class provides a lot more methods than a general parent:: 'extension', 'fraction_field', 'frobenius_endomorphism', - 'gcd', 'gen', 'gens', 'ideal', @@ -144,7 +140,6 @@ This base class provides a lot more methods than a general parent:: 'integral_closure', 'is_commutative', 'is_field', - 'is_integral_domain', 'is_integrally_closed', 'is_noetherian', 'is_prime_field', diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index 84ba7163bd8..d59845b8f29 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -1228,7 +1228,7 @@ def structure(self): sage: structure(Rings()) (Category of unital magmas, Category of additive unital additive magmas) sage: structure(Fields()) - (Category of euclidean domains,) + (Category of euclidean domains, Category of noetherian rings) sage: structure(Algebras(QQ)) (Category of unital magmas, Category of right modules over Rational Field, diff --git a/src/sage/misc/c3_controlled.pyx b/src/sage/misc/c3_controlled.pyx index 2b334565fdc..f3efe4dd538 100644 --- a/src/sage/misc/c3_controlled.pyx +++ b/src/sage/misc/c3_controlled.pyx @@ -319,9 +319,9 @@ For a typical category, few bases, if any, need to be added to force sage: x.mro == x.mro_standard False sage: x.all_bases_len() - 70 + 72 sage: x.all_bases_controlled_len() - 74 + 76 sage: C = GradedHopfAlgebrasWithBasis(QQ) sage: x = HierarchyElement(C, attrcall("super_categories"), attrgetter("_cmp_key")) From d33122644b0bada46a81916712b5cc832cd22118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 3 Apr 2024 15:54:38 +0200 Subject: [PATCH 06/21] fix code and many trivial doctests --- src/sage/categories/bimodules.py | 2 ++ src/sage/categories/category.py | 3 ++ src/sage/categories/category_types.py | 3 +- src/sage/categories/homset.py | 4 +-- src/sage/categories/modules.py | 3 +- src/sage/categories/morphism.pyx | 7 ++-- src/sage/categories/primer.py | 4 ++- src/sage/matrix/matrix2.pyx | 5 +-- src/sage/matrix/matrix_space.py | 4 +++ src/sage/rings/integer_ring.pyx | 6 +++- src/sage/rings/laurent_series_ring.py | 5 +-- src/sage/rings/lazy_series_ring.py | 2 ++ src/sage/rings/polynomial/plural.pyx | 3 +- src/sage/rings/polynomial/polynomial_ring.py | 34 +++++++++++++------- src/sage/rings/ring.pyx | 6 ++-- src/sage/structure/category_object.pyx | 5 +-- 16 files changed, 66 insertions(+), 30 deletions(-) diff --git a/src/sage/categories/bimodules.py b/src/sage/categories/bimodules.py index 4e92f890cd0..f45f42c52dc 100644 --- a/src/sage/categories/bimodules.py +++ b/src/sage/categories/bimodules.py @@ -77,6 +77,7 @@ def _make_named_class_key(self, name): and Category of metric spaces, Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces) @@ -85,6 +86,7 @@ def _make_named_class_key(self, name): (Category of fields, Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces) diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index d59845b8f29..5579f888a7d 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -2839,6 +2839,7 @@ def _make_named_class_key(self, name): sage: Algebras(ZZ)._make_named_class_key("parent_class") Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces @@ -2851,6 +2852,7 @@ def _make_named_class_key(self, name): and Category of metric spaces, Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces) @@ -2978,6 +2980,7 @@ def _make_named_class_key(self, name): sage: Modules(ZZ)._make_named_class_key('element_class') Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces sage: Modules(QQ)._make_named_class_key('parent_class') diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index d80f5aa7bac..46736d03620 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -226,7 +226,8 @@ def _make_named_class_key(self, name): sage: Modules(ZZ)._make_named_class_key('element_class') Join of Category of Dedekind domains - and Category of euclidean domains + and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces sage: Modules(QQ)._make_named_class_key('parent_class') diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index deb489a9042..29f4c7df69a 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -1245,7 +1245,7 @@ def reversed(self): the principal ideal domain Integer Ring to Ambient free module of rank 3 over the principal ideal domain Integer Ring in Category of finite dimensional modules with basis over (Dedekind - domains and euclidean domains + domains and euclidean domains and noetherian rings and infinite enumerated sets and metric spaces) sage: type(H) @@ -1254,7 +1254,7 @@ def reversed(self): the principal ideal domain Integer Ring to Ambient free module of rank 2 over the principal ideal domain Integer Ring in Category of finite dimensional modules with basis over (Dedekind - domains and euclidean domains + domains and euclidean domains and noetherian rings and infinite enumerated sets and metric spaces) sage: type(H.reversed()) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index c5b1aa2afb5..952ca09fbde 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -885,7 +885,8 @@ def __init_extra__(self): sage: M.category() # needs sage.modules Category of Cartesian products of modules with basis over (Dedekind domains and euclidean domains - and infinite enumerated sets and metric spaces) + and noetherian rings + and infinite enumerated sets and metric spaces) sage: M.base_ring() # needs sage.modules Integer Ring diff --git a/src/sage/categories/morphism.pyx b/src/sage/categories/morphism.pyx index e36c32b34bc..9eebece9f8b 100644 --- a/src/sage/categories/morphism.pyx +++ b/src/sage/categories/morphism.pyx @@ -179,9 +179,12 @@ cdef class Morphism(Map): sage: f.category() Category of endsets of unital magmas and right modules over (Dedekind domains and euclidean domains + and noetherian rings + and infinite enumerated sets and metric spaces) + and left modules over + (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) - and left modules over (Dedekind domains and euclidean domains - and infinite enumerated sets and metric spaces) sage: # needs sage.rings.number_field sage: K = CyclotomicField(12) diff --git a/src/sage/categories/primer.py b/src/sage/categories/primer.py index c7339b712e3..aa47130b205 100644 --- a/src/sage/categories/primer.py +++ b/src/sage/categories/primer.py @@ -352,18 +352,20 @@ sage: ZZ.category() Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces sage: ZZ.categories() [Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces, Category of Dedekind domains, Category of euclidean domains, Category of principal ideal domains, Category of unique factorization domains, Category of gcd domains, - Category of integral domains, Category of domains, + Category of integral domains, Category of domains, ... Category of commutative rings, Category of rings, ... Category of magmas and additive magmas, ... Category of monoids, Category of semigroups, diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 46a5277673a..edfa77af61a 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -18265,12 +18265,13 @@ def _generic_clear_column(m): I = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes for k in range(1, a.nrows()): if a[k, 0] not in I: + new_ideal = ideal_or_fractional(R, a[0, 0], a[k, 0]) try: - v = ideal_or_fractional(R, a[0, 0], a[k, 0]).gens_reduced() + v = new_ideal.gens_reduced() except Exception as msg: raise ArithmeticError("%s\nCan't create ideal on %s and %s" % (msg, a[0, 0], a[k, 0])) if len(v) > 1: - raise ArithmeticError("Ideal %s not principal" % ideal_or_fractional(R, a[0, 0], a[k, 0])) + raise ArithmeticError("Ideal %s not principal" % new_ideal) B = v[0] # now we find c,d, using the fact that c * (a_{0,0}/B) - d * diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index aa9a6fe6111..7fd97598691 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -483,10 +483,12 @@ class MatrixSpace(UniqueRepresentation, Parent): sage: MatrixSpace(ZZ,10,5).category() Category of infinite enumerated finite dimensional modules with basis over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: MatrixSpace(ZZ,10,10).category() Category of infinite enumerated finite dimensional algebras with basis over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: MatrixSpace(QQ,10).category() Category of infinite finite dimensional algebras with basis over @@ -652,10 +654,12 @@ def __init__(self, base_ring, nrows, ncols, sparse, implementation): sage: MatrixSpace(ZZ,10,5).category() Category of infinite enumerated finite dimensional modules with basis over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: MatrixSpace(ZZ,10,10).category() Category of infinite enumerated finite dimensional algebras with basis over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: MatrixSpace(QQ,10).category() Category of infinite finite dimensional algebras with basis over diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index 7871e2c6d0a..2882c7960f1 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -58,6 +58,7 @@ import sage.libs.pari.all import sage.rings.ideal from sage.categories.basic import EuclideanDomains, DedekindDomains from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +from sage.categories.noetherian_rings import NoetherianRings from sage.rings.number_field.number_field_element_base import NumberFieldElement_base from sage.structure.coerce cimport is_numpy_type from sage.structure.element cimport parent @@ -124,6 +125,7 @@ cdef class IntegerRing_class(CommutativeRing): sage: Z.category() Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces sage: Z(2^(2^5) + 1) @@ -312,8 +314,10 @@ cdef class IntegerRing_class(CommutativeRing): sage: A in InfiniteEnumeratedSets() True """ + cat = (EuclideanDomains(), DedekindDomains(), + InfiniteEnumeratedSets().Metric(), NoetherianRings()) Parent.__init__(self, base=self, names=('x',), normalize=False, - category=(EuclideanDomains(), DedekindDomains(), InfiniteEnumeratedSets().Metric())) + category=cat) self._populate_coercion_lists_(init_no_parent=True, convert_method_name='_integer_') diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index 4e0c6f0d557..b8bd1cf062f 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -155,7 +155,7 @@ class LaurentSeriesRing(UniqueRepresentation, CommutativeRing): sage: LaurentSeriesRing(ZZ, 'x').category() Category of infinite commutative no zero divisors algebras over (Dedekind domains and euclidean domains - and infinite enumerated sets and metric spaces) + and noetherian rings and infinite enumerated sets and metric spaces) sage: LaurentSeriesRing(QQ, 'x').category() Join of Category of complete discrete valuation fields and Category of commutative algebras over (number fields and quotient fields and metric spaces) and Category of infinite sets @@ -227,7 +227,8 @@ def __init__(self, power_series): sage: RZZ.category() Category of infinite commutative no zero divisors algebras over (Dedekind domains and euclidean domains - and infinite enumerated sets and metric spaces) + and noetherian rings and infinite enumerated sets + and metric spaces) sage: TestSuite(RZZ).run() sage: R1 = LaurentSeriesRing(Zmod(1), 't') diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 06fd7a5d595..6f96ffc839d 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1475,6 +1475,7 @@ def __init__(self, base_ring, names, sparse=True, category=None): sage: L.category() Category of infinite commutative no zero divisors algebras over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: L = LazyLaurentSeriesRing(QQ, 't') @@ -1490,6 +1491,7 @@ def __init__(self, base_ring, names, sparse=True, category=None): Category of infinite commutative no zero divisors algebras over (unique factorization domains and commutative algebras over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) and infinite sets) diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 30e6aa89dc3..aa127cdbd8d 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -126,7 +126,8 @@ from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_ from sage.rings.polynomial.multi_polynomial_ideal import NCPolynomialIdeal from sage.rings.polynomial.polydict import ETuple -from sage.rings.ring import check_default_category, CommutativeRing +from sage.rings.ring import CommutativeRing +from sage.structure.category_object cimport check_default_category from sage.structure.element cimport CommutativeRingElement, Element, RingElement from sage.structure.factory import UniqueFactory from sage.structure.richcmp cimport rich_to_bool diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index d2dab0db512..953049a663e 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -144,9 +144,11 @@ import sys from sage.structure.element import Element +from sage.structure.category_object import check_default_category import sage.categories as categories from sage.categories.morphism import IdentityMorphism +from sage.categories.principal_ideal_domains import PrincipalIdealDomains from sage.categories.rings import Rings from sage.rings.ring import (Ring, IntegralDomain, PrincipalIdealDomain) @@ -246,7 +248,8 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, Join of Category of unique factorization domains and Category of commutative algebras over (Dedekind domains and euclidean domains - and infinite enumerated sets and metric spaces) + and noetherian rings and infinite enumerated sets + and metric spaces) and Category of infinite sets sage: category(GF(7)['x']) Join of Category of euclidean domains @@ -284,11 +287,11 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, """ # We trust that, if category is given, it is useful and does not need to be joined # with the default category - if category is None: - if base_ring.is_zero(): - category = categories.rings.Rings().Finite() - else: - category = polynomial_default_category(base_ring.category(), 1) + if base_ring.is_zero(): + category = categories.rings.Rings().Commutative().Finite() + else: + defaultcat = polynomial_default_category(base_ring.category(), 1) + category = check_default_category(defaultcat, category) self.__is_sparse = sparse if element_class: self._polynomial_class = element_class @@ -1781,11 +1784,11 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, if base_ring not in _CommutativeRings: raise TypeError("Base ring %s must be a commutative ring." % repr(base_ring)) # We trust that, if a category is given, that it is useful. - if category is None: - if base_ring.is_zero(): - category = categories.algebras.Algebras(base_ring.category()).Commutative().Finite() - else: - category = polynomial_default_category(base_ring.category(), 1) + if base_ring.is_zero(): + category = categories.algebras.Algebras(base_ring.category()).Commutative().Finite() + else: + defaultcat = polynomial_default_category(base_ring.category(), 1) + category = check_default_category(defaultcat, category) PolynomialRing_general.__init__(self, base_ring, name=name, sparse=sparse, implementation=implementation, element_class=element_class, category=category) @@ -3203,7 +3206,7 @@ def __init__(self, base_ring, name=None, implementation=None, element_class=None class PolynomialRing_dense_mod_n(PolynomialRing_commutative): def __init__(self, base_ring, name=None, element_class=None, - implementation=None, category=None): + implementation=None, category=None): """ TESTS:: @@ -3446,6 +3449,9 @@ def __init__(self, base_ring, name="x", implementation=None, element_class=None, self._implementation_repr = ' (using GF2X)' break + category = check_default_category(PrincipalIdealDomains(), + category) + PolynomialRing_dense_mod_n.__init__(self, base_ring, name=name, implementation=implementation, element_class=element_class, category=category) @@ -3467,6 +3473,10 @@ def _implementation_names_impl(implementation, base_ring, sparse): Traceback (most recent call last): ... ValueError: GF2X only supports modulus 2 + sage: A = PolynomialRing(Zmod(2), 'x'); A + Univariate Polynomial Ring in x over Ring of integers modulo 2 (using GF2X) + sage: A in PrincipalIdealDomains() + True sage: PolynomialRing(GF(2), 'x', implementation="FLINT") # needs sage.libs.flint Univariate Polynomial Ring in x over Finite Field of size 2 diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 1c540e14aa6..7bf0421f258 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -101,7 +101,7 @@ from sage.misc.superseded import deprecation from sage.structure.coerce cimport coercion_model from sage.structure.parent cimport Parent -from sage.structure.category_object import check_default_category +from sage.structure.category_object cimport check_default_category from sage.structure.sequence import Sequence from sage.misc.prandom import randint from sage.categories.rings import Rings @@ -235,7 +235,7 @@ cdef class Ring(ParentWithGens): # This is a low-level class. For performance, we trust that the category # is fine, if it is provided. If it isn't, we use the category of rings. if category is None: - category = _Rings + category = check_default_category(_Rings, category) Parent.__init__(self, base=base, names=names, normalize=normalize, category=category) @@ -1823,7 +1823,7 @@ cdef class Algebra(Ring): # This is a low-level class. For performance, we trust that the category # is fine, if it is provided. If it isn't, we use the category of Algebras(base_ring). if category is None: - category = Algebras(base_ring) + category = check_default_category(Algebras(base_ring), category) Ring.__init__(self,base_ring, names=names, normalize=normalize, category=category) diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index cd39d91f8fb..079c2b59e22 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -64,8 +64,9 @@ from sage.structure.dynamic_class import DynamicMetaclass cpdef inline check_default_category(default_category, category) noexcept: - # The resulting category is guaranteed to be - # a sub-category of the default. + """ + The resulting category is guaranteed to be a sub-category of the default. + """ if category is None: return default_category return default_category.join([default_category, category]) From 2c058cdbdfb05d80f388d8418f3e610040e0887c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 3 Apr 2024 16:22:49 +0200 Subject: [PATCH 07/21] fix doctest in Clifford --- src/sage/algebras/clifford_algebra.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index f87d52c94ce..05a686f95d0 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -514,6 +514,7 @@ def __init__(self, Q, names, category=None): sage: Cl.category() Category of finite dimensional super algebras with basis over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: TestSuite(Cl).run() @@ -1093,6 +1094,7 @@ def lift_module_morphism(self, m, names=None): sage: phi.category_for() Category of finite dimensional super algebras with basis over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: phi.matrix() [ 1 0 0 0 7 -3 -7 0] @@ -1177,6 +1179,7 @@ def lift_isometry(self, m, names=None): sage: phi.category_for() Category of finite dimensional super algebras with basis over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: phi.matrix() [ 1 0 0 0 1 2 5 0] From 1119b6aa0dac6461a92fb391b8a45aefaf50b5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 3 Apr 2024 16:27:13 +0200 Subject: [PATCH 08/21] fix two more easy doctests --- src/sage/modules/free_module.py | 3 ++- src/sage/modules/free_module_homspace.py | 1 + src/sage/tensor/modules/finite_rank_free_module.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 6e2c9e4dc1d..257a766010f 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1943,7 +1943,8 @@ class FreeModule_generic(Module_free_ambient): (finite enumerated fields and subquotients of monoids and quotients of semigroups) sage: FreeModule(ZZ,3).category() Category of finite dimensional modules with basis over - (Dedekind domains and euclidean domains and infinite enumerated sets + (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: (QQ^0).category() Category of finite enumerated finite dimensional vector spaces with basis diff --git a/src/sage/modules/free_module_homspace.py b/src/sage/modules/free_module_homspace.py index 9513a56ea56..9222bd8105e 100644 --- a/src/sage/modules/free_module_homspace.py +++ b/src/sage/modules/free_module_homspace.py @@ -28,6 +28,7 @@ to Ambient free module of rank 2 over the principal ideal domain Integer Ring in Category of finite dimensional modules with basis over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: B = H.basis() sage: len(B) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 0434ed84c53..9564202844c 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -248,7 +248,7 @@ class :class:`~sage.modules.free_module.FreeModule_generic` Category of finite dimensional modules over Integer Ring sage: N.category() Category of finite dimensional modules with basis over - (Dedekind domains and euclidean domains + (Dedekind domains and euclidean domains and noetherian rings and infinite enumerated sets and metric spaces) In other words, the module created by ``FreeModule`` is actually `\ZZ^3`, From 055412724e1d4d35a8b631c114d3bd31450e80ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 3 Apr 2024 16:30:19 +0200 Subject: [PATCH 09/21] fix one more easy doctest --- src/sage/structure/category_object.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index 079c2b59e22..82566b633c9 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -213,6 +213,7 @@ cdef class CategoryObject(SageObject): sage: ZZ.categories() [Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces, Category of Dedekind domains, @@ -221,7 +222,7 @@ cdef class CategoryObject(SageObject): Category of unique factorization domains, Category of gcd domains, Category of integral domains, - Category of domains, + Category of domains, ... Category of commutative rings, ... Category of monoids, ..., Category of commutative additive groups, ..., From b286a24467701d5a5f62d71164beec8172b546c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 3 Apr 2024 18:00:06 +0200 Subject: [PATCH 10/21] fix the linter --- src/sage/rings/ring.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 7bf0421f258..36f8336786c 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -446,7 +446,7 @@ cdef class Ring(ParentWithGens): elif isinstance(first, (list, tuple)): gens = first elif is_Parent(first) and self.has_coerce_map_from(first): - gens = first.gens() # we have a ring as argument + gens = first.gens() # we have a ring as argument else: break @@ -655,7 +655,7 @@ cdef class Ring(ParentWithGens): return x return self._one_element - def is_field(self, proof = True): + def is_field(self, proof=True): """ Return ``True`` if this ring is a field. @@ -1025,7 +1025,7 @@ cdef class CommutativeRing(Ring): Generic commutative ring. """ _default_category = _CommutativeRings - + def __init__(self, base_ring, names=None, normalize=True, category=None): """ Initialize ``self``. @@ -1540,7 +1540,7 @@ cdef class IntegralDomain(CommutativeRing): """ raise NotImplementedError - def is_field(self, proof = True): + def is_field(self, proof=True): r""" Return ``True`` if this ring is a field. From 3e3b16f54a3d7677e9bfcc123f6c1a48d43d46c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 3 Apr 2024 19:47:05 +0200 Subject: [PATCH 11/21] fix doctests in documentation --- src/doc/en/thematic_tutorials/coercion_and_categories.rst | 4 +++- src/doc/en/tutorial/tour_coercion.rst | 1 + src/doc/fr/tutorial/tour_coercion.rst | 1 + src/doc/ja/tutorial/tour_coercion.rst | 1 + src/doc/pt/tutorial/tour_coercion.rst | 1 + 5 files changed, 7 insertions(+), 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 2720de5ca0e..4fe358cd5af 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -853,7 +853,9 @@ The four axioms requested for coercions rational field is a homomorphism of euclidean domains:: sage: QQ.coerce_map_from(ZZ).category_for() - Join of Category of euclidean domains and Category of infinite sets + Join of Category of euclidean domains + and Category of noetherian rings + and Category of infinite sets and Category of metric spaces .. end of output diff --git a/src/doc/en/tutorial/tour_coercion.rst b/src/doc/en/tutorial/tour_coercion.rst index 9a3cb8e8ee7..f5c17d619d9 100644 --- a/src/doc/en/tutorial/tour_coercion.rst +++ b/src/doc/en/tutorial/tour_coercion.rst @@ -118,6 +118,7 @@ implemented in Sage as well: sage: ZZ.category() Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces sage: ZZ.category().is_subcategory(Rings()) diff --git a/src/doc/fr/tutorial/tour_coercion.rst b/src/doc/fr/tutorial/tour_coercion.rst index 41ec9264ae6..e19487c0cbd 100644 --- a/src/doc/fr/tutorial/tour_coercion.rst +++ b/src/doc/fr/tutorial/tour_coercion.rst @@ -119,6 +119,7 @@ par ailleurs les catégories en tant que telles : sage: ZZ.category() Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces sage: ZZ.category().is_subcategory(Rings()) diff --git a/src/doc/ja/tutorial/tour_coercion.rst b/src/doc/ja/tutorial/tour_coercion.rst index 6aaf7aa2911..f13b48c782b 100644 --- a/src/doc/ja/tutorial/tour_coercion.rst +++ b/src/doc/ja/tutorial/tour_coercion.rst @@ -101,6 +101,7 @@ Sageのクラス階層と圏の階層構造にはそれなりに類似が見ら sage: ZZ.category() Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces sage: ZZ.category().is_subcategory(Rings()) diff --git a/src/doc/pt/tutorial/tour_coercion.rst b/src/doc/pt/tutorial/tour_coercion.rst index b5eeaa85a9f..94efa8cec15 100644 --- a/src/doc/pt/tutorial/tour_coercion.rst +++ b/src/doc/pt/tutorial/tour_coercion.rst @@ -125,6 +125,7 @@ categorias matemáticas também são implementadas no Sage: sage: ZZ.category() Join of Category of Dedekind domains and Category of euclidean domains + and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces sage: ZZ.category().is_subcategory(Rings()) From 0b91fbed59b40a0433e321cd1f0652b7b162a38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 4 Apr 2024 10:26:37 +0200 Subject: [PATCH 12/21] skip one doctest in TestSuite of Laurent over Zmod(2) --- src/sage/rings/polynomial/laurent_polynomial_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 6d24de9f96f..bd48822a6a1 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -442,7 +442,7 @@ def __init__(self, R): TESTS:: - sage: TestSuite(LaurentPolynomialRing(Zmod(2), 'y')).run() + sage: TestSuite(LaurentPolynomialRing(Zmod(2), 'y')).run(skip=['_test_gcd_vs_xgcd']) sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() sage: TestSuite(LaurentPolynomialRing(ZZ, 'u')).run() sage: TestSuite(LaurentPolynomialRing(Zmod(2)['T'], 'u')).run() From 3b59518c9d6e126cc77572744c193cc71f3dd0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 4 Apr 2024 11:25:16 +0200 Subject: [PATCH 13/21] fix the coercion for polynomials over zero ring --- src/sage/rings/polynomial/multi_polynomial.pyx | 5 +++++ src/sage/rings/polynomial/polynomial_ring.py | 9 ++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 96281d8f4dd..34bf7630dc4 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -2140,6 +2140,10 @@ cdef class MPolynomial(CommutativePolynomial): sage: Pol = QQ['x']['x','y'] sage: Pol.one().gcd(1) 1 + + sage: P = PolynomialRing(QQ, 'x', 0) + sage: P.gens() + () """ flatten = self._parent.flattening_morphism() tgt = flatten.codomain() @@ -2156,6 +2160,7 @@ cdef class MPolynomial(CommutativePolynomial): gens = self.parent().gens() if not gens: + # no variables base = self.parent().base_ring() return base(self).gcd(base(other)) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 953049a663e..cfe201b55dd 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -267,9 +267,7 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, Check that category for zero ring:: sage: PolynomialRing(Zmod(1), 'x').category() - Category of finite commutative algebras over - (finite commutative rings and subquotients of monoids and - quotients of semigroups and finite enumerated sets) + Category of finite commutative ring Check `is_finite` inherited from category (:issue:`24432`):: @@ -791,6 +789,11 @@ def _coerce_map_from_(self, P): False """ base_ring = self.base_ring() + + # workaround, useful for the zero ring + if P == base_ring: + return self._coerce_map_from_base_ring() + # handle constants that canonically coerce into self.base_ring() # first, if possible try: From 35a183595c418c3f22d45def8e2244ef307a113e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 4 Apr 2024 16:53:29 +0200 Subject: [PATCH 14/21] fix oups --- src/sage/rings/polynomial/polynomial_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index cfe201b55dd..f5cab5bbc88 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -267,7 +267,7 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, Check that category for zero ring:: sage: PolynomialRing(Zmod(1), 'x').category() - Category of finite commutative ring + Category of finite commutative rings Check `is_finite` inherited from category (:issue:`24432`):: From 20348dcdd579406de6f3e6f8d55f3d358fe55dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 9 Apr 2024 11:36:35 +0200 Subject: [PATCH 15/21] step back in local_generic --- src/sage/rings/padics/local_generic.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 8d888c0b728..349a8ec17dc 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -24,13 +24,13 @@ from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationRings, CompleteDiscreteValuationFields from sage.structure.category_object import check_default_category -from sage.structure.parent import Parent from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.infinity import Infinity +from sage.rings.ring import CommutativeRing -class LocalGeneric(Parent): +class LocalGeneric(CommutativeRing): def __init__(self, base, prec, names, element_class, category=None): r""" Initialize ``self``. @@ -74,7 +74,8 @@ def __init__(self, base, prec, names, element_class, category=None): category = category.Metric().Complete().Infinite() if default_category is not None: category = check_default_category(default_category, category) - Parent.__init__(self, base, names=(names,), normalize=False, category=category) + CommutativeRing.__init__(self, base, names=(names,), + normalize=False, category=category) def is_capped_relative(self): r""" @@ -452,7 +453,7 @@ def get_unramified_modulus(q, res_name): kwds['type'] = 'capped-rel' elif self._prec_type() == 'fixed-mod': kwds['type'] = 'floating-point' - kwds['show_prec'] = False # This can be removed once printing of fixed mod elements is changed. + kwds['show_prec'] = False # This can be removed once printing of fixed mod elements is changed. # There are two kinds of functors possible: # CompletionFunctor and AlgebraicExtensionFunctor @@ -489,7 +490,7 @@ def get_unramified_modulus(q, res_name): # Labels for lattice precision if 'label' in kwds: functor.extras['label'] = kwds.pop('label') - elif 'label' in functor.extras and functor.type not in ['lattice-cap','lattice-float']: + elif 'label' in functor.extras and functor.type not in ['lattice-cap', 'lattice-float']: del functor.extras['label'] for atr in ('ram_name', 'var_name'): if atr in kwds: @@ -660,9 +661,9 @@ def defining_polynomial(self, var='x', exact=False): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing if exact: from sage.rings.integer_ring import ZZ - return PolynomialRing(ZZ,var).gen() + return PolynomialRing(ZZ, var).gen() else: - return PolynomialRing(self,var).gen() + return PolynomialRing(self, var).gen() def ground_ring(self): r""" @@ -1118,7 +1119,7 @@ def _test_add_bigoh(self, **options): tester.assertLessEqual(y.precision_absolute(), -1) # make sure that we handle very large values correctly - if self._prec_type() not in [ 'lattice-float', 'relaxed' ]: # no cap in these models + if self._prec_type() not in ['lattice-float', 'relaxed']: # no cap in these models absprec = Integer(2)**1000 tester.assertEqual(x.add_bigoh(absprec), x) @@ -1195,15 +1196,15 @@ def _matrix_flatten_precision(self, M): cap = parent.precision_cap() n = M.nrows() m = M.ncols() - shift_rows = n * [ ZZ(0) ] - shift_cols = m * [ ZZ(0) ] + shift_rows = n * [ZZ.zero()] + shift_cols = m * [ZZ.zero()] for i in range(n): - prec = min(M[i,j].precision_absolute() for j in range(m)) + prec = min(M[i, j].precision_absolute() for j in range(m)) if prec is Infinity or prec == cap: continue shift_rows[i] = s = cap - prec for j in range(m): - M[i,j] <<= s + M[i, j] <<= s for j in range(m): prec = min(M[i,j].precision_absolute() for i in range(n)) if prec is Infinity or prec == cap: From 8449171b6e86a10481d2e4ca3e68718cb8464746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 12 Apr 2024 08:00:12 +0200 Subject: [PATCH 16/21] re-activate full TestSuite --- src/sage/rings/polynomial/laurent_polynomial_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index bd48822a6a1..6d24de9f96f 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -442,7 +442,7 @@ def __init__(self, R): TESTS:: - sage: TestSuite(LaurentPolynomialRing(Zmod(2), 'y')).run(skip=['_test_gcd_vs_xgcd']) + sage: TestSuite(LaurentPolynomialRing(Zmod(2), 'y')).run() sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() sage: TestSuite(LaurentPolynomialRing(ZZ, 'u')).run() sage: TestSuite(LaurentPolynomialRing(Zmod(2)['T'], 'u')).run() From e9aa0cb3269fae80db373ed9ac44ff9bc8e64ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 8 May 2024 13:57:46 +0200 Subject: [PATCH 17/21] fix two doctests --- src/sage/matrix/matrix_space.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index b8de2e414e9..12d0cf4c2bd 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -493,10 +493,12 @@ class MatrixSpace(UniqueRepresentation, Parent): sage: MatrixSpace(ZZ, 10, 5).category() Category of infinite enumerated finite dimensional modules with basis over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: MatrixSpace(ZZ, 10, 10).category() Category of infinite enumerated finite dimensional algebras with basis over (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets and metric spaces) sage: MatrixSpace(QQ, 10).category() Category of infinite finite dimensional algebras with basis over From d33b00e5edf072ce6a942e7e9ec3ffc93765c258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 8 May 2024 16:18:52 +0200 Subject: [PATCH 18/21] fix more doctests --- src/sage/matrix/args.pyx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/args.pyx b/src/sage/matrix/args.pyx index b01f3466998..e6856126489 100644 --- a/src/sage/matrix/args.pyx +++ b/src/sage/matrix/args.pyx @@ -931,7 +931,8 @@ cdef class MatrixArgs: Integer Ring in Category of finite dimensional modules with basis over (Dedekind domains and euclidean domains - and infinite enumerated sets and metric spaces); + and noetherian rings and infinite enumerated sets + and metric spaces); typ=ZERO; entries=None> """ if self.column_keys is not None and self.column_keys != column_keys: @@ -967,7 +968,8 @@ cdef class MatrixArgs: to Free module generated by {'u', 'v'} over Integer Ring in Category of finite dimensional modules with basis over (Dedekind domains and euclidean domains - and infinite enumerated sets and metric spaces); + and noetherian rings and infinite enumerated sets + and metric spaces); typ=ZERO; entries=None> """ if self.row_keys is not None and self.row_keys != row_keys: From 4489ce46523eb73e0f5b8e7dbf33342c638e8121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 8 May 2024 20:32:02 +0200 Subject: [PATCH 19/21] fix testmod --- pkgs/sagemath-categories/known-test-failures.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkgs/sagemath-categories/known-test-failures.json b/pkgs/sagemath-categories/known-test-failures.json index ab27f65ca8d..80705635b7e 100644 --- a/pkgs/sagemath-categories/known-test-failures.json +++ b/pkgs/sagemath-categories/known-test-failures.json @@ -597,6 +597,10 @@ "failed": true, "ntests": 126 }, + "sage.categories.noetherian_rings": { + "failed": true, + "ntests": 19 + }, "sage.categories.number_fields": { "failed": true, "ntests": 41 @@ -1428,4 +1432,4 @@ "sage.typeset.unicode_characters": { "ntests": 27 } -} \ No newline at end of file +} From 9dca29731a05492c806a8aeb1fa7f9a57bdd104c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 9 May 2024 08:04:55 +0200 Subject: [PATCH 20/21] Update src/sage/categories/rings.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Köppe --- src/sage/categories/rings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index b6037e95ad8..02e81ff1f63 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -352,7 +352,7 @@ def is_integral_domain(self, proof=True) -> bool: If the parameter ``proof`` is set to ``True``, the returned value is correct but the method might throw an error. Otherwise, if it is set - to ``False``, the method returns ``True`` if it can establish that self + to ``False``, the method returns ``True`` if it can establish that ``self`` is an integral domain and ``False`` otherwise. EXAMPLES:: From eb758e6e7db04bdc86803305a72a8bfd6887e53a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 9 May 2024 08:17:09 +0200 Subject: [PATCH 21/21] more capitals for Noetherian --- src/sage/algebras/quatalg/quaternion_algebra.py | 2 +- src/sage/algebras/steenrod/steenrod_algebra.py | 2 +- src/sage/categories/commutative_rings.py | 3 +-- src/sage/categories/group_algebras.py | 2 +- src/sage/categories/principal_ideal_domains.py | 2 +- src/sage/rings/function_field/order.py | 2 +- src/sage/rings/polynomial/infinite_polynomial_ring.py | 4 ++-- 7 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index 4077d52de00..fdbdf590e5e 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -515,7 +515,7 @@ def is_integral_domain(self, proof=True) -> bool: def is_noetherian(self) -> bool: """ - Return ``True`` always, since any quaternion algebra is a noetherian + Return ``True`` always, since any quaternion algebra is a Noetherian ring (because it is a finitely generated module over a field). EXAMPLES:: diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index 3f9153cf962..f3f5447245f 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -3054,7 +3054,7 @@ def is_integral_domain(self, proof=True): def is_noetherian(self): """ - This algebra is noetherian if and only if it is finite. + This algebra is Noetherian if and only if it is finite. EXAMPLES:: diff --git a/src/sage/categories/commutative_rings.py b/src/sage/categories/commutative_rings.py index 6c563714f9e..38ae0d22ada 100644 --- a/src/sage/categories/commutative_rings.py +++ b/src/sage/categories/commutative_rings.py @@ -283,8 +283,7 @@ class Finite(CategoryWithAxiom): """ def extra_super_categories(self): r""" - Let Sage knows that finite commutative rings - are Noetherian. + Let Sage know that finite commutative rings are Noetherian. EXAMPLES:: diff --git a/src/sage/categories/group_algebras.py b/src/sage/categories/group_algebras.py index c5cceb53633..6732a49b150 100644 --- a/src/sage/categories/group_algebras.py +++ b/src/sage/categories/group_algebras.py @@ -358,7 +358,7 @@ def is_integral_domain(self, proof=True): return ans # I haven't written is_noetherian(), because I don't know when group - # algebras are noetherian, and I haven't written is_prime_field(), because + # algebras are Noetherian, and I haven't written is_prime_field(), because # I don't know if that means "is canonically isomorphic to a prime field" # or "is identical to a prime field". diff --git a/src/sage/categories/principal_ideal_domains.py b/src/sage/categories/principal_ideal_domains.py index 30f2969613a..6118e06b1c7 100644 --- a/src/sage/categories/principal_ideal_domains.py +++ b/src/sage/categories/principal_ideal_domains.py @@ -125,7 +125,7 @@ def _test_gcd_vs_xgcd(self, **options): def is_noetherian(self) -> bool: """ - Every principal ideal domain is noetherian, so we return ``True``. + Every principal ideal domain is Noetherian, so we return ``True``. EXAMPLES:: diff --git a/src/sage/rings/function_field/order.py b/src/sage/rings/function_field/order.py index 615cbab3690..5b550555f34 100644 --- a/src/sage/rings/function_field/order.py +++ b/src/sage/rings/function_field/order.py @@ -162,7 +162,7 @@ def is_field(self, proof=True): def is_noetherian(self): """ - Return ``True`` since orders in function fields are noetherian. + Return ``True`` since orders in function fields are Noetherian. EXAMPLES:: diff --git a/src/sage/rings/polynomial/infinite_polynomial_ring.py b/src/sage/rings/polynomial/infinite_polynomial_ring.py index dbb71289f89..e962e1f1a2e 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_ring.py +++ b/src/sage/rings/polynomial/infinite_polynomial_ring.py @@ -1098,11 +1098,11 @@ def is_noetherian(self): Since Infinite Polynomial Rings must have at least one generator, they have infinitely many variables and are thus - not noetherian, as a ring. + not Noetherian, as a ring. .. NOTE:: - Infinite Polynomial Rings over a field `F` are noetherian as + Infinite Polynomial Rings over a field `F` are Noetherian as `F(G)` modules, where `G` is the symmetric group of the natural numbers. But this is not what the method ``is_noetherian()`` is answering.