From b19a1ffe144f09f01aea3134630a2a8262c41c32 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 11:46:48 -0700 Subject: [PATCH 01/10] src/sage/sets/set.py: Accept and handle 'category' arguments --- src/sage/sets/set.py | 50 ++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 96e3b2ad7a4..3e034bd7125 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -48,6 +48,7 @@ from sage.categories.sets_cat import Sets from sage.categories.enumerated_sets import EnumeratedSets +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets import sage.rings.infinity @@ -85,7 +86,7 @@ def has_finite_length(obj): return True -def Set(X=None): +def Set(X=None, category=None): r""" Create the underlying set of ``X``. @@ -187,12 +188,12 @@ def Set(X=None): if X is None: X = [] elif isinstance(X, CategoryObject): - if isinstance(X, Set_generic): + if isinstance(X, Set_generic) and category is None: return X elif X in Sets().Finite(): - return Set_object_enumerated(X) + return Set_object_enumerated(X, category=category) else: - return Set_object(X) + return Set_object(X, category=category) if isinstance(X, Element) and not isinstance(X, Set_base): raise TypeError("Element has no defined underlying set") @@ -200,9 +201,9 @@ def Set(X=None): try: X = frozenset(X) except TypeError: - return Set_object(X) + return Set_object(X, category=category) else: - return Set_object_enumerated(X) + return Set_object_enumerated(X, category=category) class Set_base(): @@ -474,7 +475,7 @@ def __init__(self, X, category=None): sage: type(Set(QQ)) sage: Set(QQ).category() - Category of sets + Category of infinite sets TESTS:: @@ -492,6 +493,15 @@ def __init__(self, X, category=None): if category is None: category = Sets() + + if isinstance(X, CategoryObject): + if X in Sets().Finite(): + category = category.Finite() + elif X in Sets().Infinite(): + category = category.Infinite() + if X in Sets().Enumerated(): + category = category.Enumerated() + Parent.__init__(self, category=category) self.__object = X @@ -830,7 +840,7 @@ class Set_object_enumerated(Set_object): """ A finite enumerated set. """ - def __init__(self, X): + def __init__(self, X, category=None): r""" Initialize ``self``. @@ -839,12 +849,12 @@ def __init__(self, X): sage: S = Set(GF(19)); S {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} sage: S.category() - Category of finite sets + Category of finite enumerated sets sage: print(latex(S)) \left\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18\right\} sage: TestSuite(S).run() """ - Set_object.__init__(self, X, category=Sets().Finite()) + Set_object.__init__(self, X, category=FiniteEnumeratedSets().or_subcategory(category)) def random_element(self): r""" @@ -1267,7 +1277,7 @@ def __classcall__(cls, X, Y, *args, **kwds): Y = Set(Y) return type.__call__(cls, X, Y, *args, **kwds) - def __init__(self, X, Y, op, latex_op): + def __init__(self, X, Y, op, latex_op, category=None): r""" Initialization. @@ -1284,7 +1294,7 @@ def __init__(self, X, Y, op, latex_op): self._Y = Y self._op = op self._latex_op = latex_op - Set_object.__init__(self, self) + Set_object.__init__(self, self, category=category) def _repr_(self): r""" @@ -1338,7 +1348,7 @@ class Set_object_union(Set_object_binary): """ A formal union of two sets. """ - def __init__(self, X, Y): + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1354,7 +1364,7 @@ def __init__(self, X, Y): sage: TestSuite(X).run() """ - Set_object_binary.__init__(self, X, Y, "union", "\\cup") + Set_object_binary.__init__(self, X, Y, "union", "\\cup", category=category) def is_finite(self): r""" @@ -1481,7 +1491,7 @@ class Set_object_intersection(Set_object_binary): """ Formal intersection of two sets. """ - def __init__(self, X, Y): + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1499,7 +1509,7 @@ def __init__(self, X, Y): True sage: TestSuite(X).run() """ - Set_object_binary.__init__(self, X, Y, "intersection", "\\cap") + Set_object_binary.__init__(self, X, Y, "intersection", "\\cap", category=category) def is_finite(self): r""" @@ -1643,7 +1653,7 @@ class Set_object_difference(Set_object_binary): """ Formal difference of two sets. """ - def __init__(self, X, Y): + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1658,7 +1668,7 @@ def __init__(self, X, Y): sage: TestSuite(X).run() """ - Set_object_binary.__init__(self, X, Y, "difference", "-") + Set_object_binary.__init__(self, X, Y, "difference", "-", category=category) def is_finite(self): r""" @@ -1807,7 +1817,7 @@ class Set_object_symmetric_difference(Set_object_binary): """ Formal symmetric difference of two sets. """ - def __init__(self, X, Y): + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1822,7 +1832,7 @@ def __init__(self, X, Y): sage: TestSuite(X).run() """ - Set_object_binary.__init__(self, X, Y, "symmetric difference", "\\bigtriangleup") + Set_object_binary.__init__(self, X, Y, "symmetric difference", "\\bigtriangleup", category=category) def is_finite(self): r""" From d461411617f8bca18f3e9575daaa3adf3bed1551 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 13:35:07 -0700 Subject: [PATCH 02/10] Update doctest outputs --- src/sage/categories/cartesian_product.py | 2 +- src/sage/categories/enumerated_sets.py | 2 +- src/sage/categories/homset.py | 2 +- src/sage/combinat/sidon_sets.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index 33f5c5b9b02..e6fbf670750 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -153,7 +153,7 @@ def __call__(self, args, **kwds): sage: cartesian_product([set([0,1,2]), [0,1]]) The Cartesian product of ({0, 1, 2}, {0, 1}) sage: _.category() - Category of Cartesian products of sets + Category of Cartesian products of finite enumerated sets Check that the empty product is handled correctly: diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 563a8025e6d..e1dcbd86839 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -137,7 +137,7 @@ def _call_(self, X): sage: S = EnumeratedSets()(Set([1, 2, 3])); S {1, 2, 3} sage: S.category() - Category of facade finite enumerated sets + Category of finite enumerated sets Also Python3 range are now accepted:: diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index bfd78e8d8a5..219286af8b9 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -828,7 +828,7 @@ def _element_constructor_(self, x, check=None, **options): sage: H = Hom(Set([1,2,3]), Set([1,2,3])) sage: f = H( lambda x: 4-x ) sage: f.parent() - Set of Morphisms from {1, 2, 3} to {1, 2, 3} in Category of finite sets + Set of Morphisms from {1, 2, 3} to {1, 2, 3} in Category of finite enumerated sets sage: f(1), f(2), f(3) # todo: not implemented sage: H = Hom(ZZ, QQ, Sets()) diff --git a/src/sage/combinat/sidon_sets.py b/src/sage/combinat/sidon_sets.py index 3f5cfcb3173..ec5038eb2c4 100644 --- a/src/sage/combinat/sidon_sets.py +++ b/src/sage/combinat/sidon_sets.py @@ -46,12 +46,12 @@ def sidon_sets(N, g = 1): sage: S.cardinality() 8 sage: S.category() - Category of finite sets + Category of finite enumerated sets sage: sid = S.an_element() sage: sid {2} sage: sid.category() - Category of finite sets + Category of finite enumerated sets TESTS:: From df327b9d5d76bc5b9807a937b7bb04ed334b60ae Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 17:26:27 -0700 Subject: [PATCH 03/10] src/sage/sets/set.py: Refine categories of unions, intersections, differences --- src/sage/sets/set.py | 63 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 3e034bd7125..5d2380b3d24 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -1358,12 +1358,22 @@ def __init__(self, X, Y, category=None): sage: T = Set(ZZ) sage: X = S.union(T); X Set-theoretic union of Set of elements of Vector space of dimension 2 over Rational Field and Set of elements of Integer Ring + sage: X.category() + Category of infinite sets sage: latex(X) \Bold{Q}^{2} \cup \Bold{Z} sage: TestSuite(X).run() """ + if category is None: + category = Sets() + if all(S in Sets().Finite() for S in (X, Y)): + category = category.Finite() + if all(S in Sets().Enumerated() for S in (X, Y)): + category = category.Enumerated() + if any(S in Sets().Infinite() for S in (X, Y)): + category = category.Infinite() Set_object_binary.__init__(self, X, Y, "union", "\\cup", category=category) def is_finite(self): @@ -1501,16 +1511,47 @@ def __init__(self, X, Y, category=None): sage: T = Set(ZZ) sage: X = S.intersection(T); X Set-theoretic intersection of Set of elements of Vector space of dimension 2 over Rational Field and Set of elements of Integer Ring + sage: X.category() + Category of enumerated sets sage: latex(X) \Bold{Q}^{2} \cap \Bold{Z} sage: X = Set(IntegerRange(100)).intersection(Primes()) sage: X.is_finite() True + sage: X.category() + Category of finite enumerated sets sage: TestSuite(X).run() """ + if category is None: + category = Sets() + if any(S in Sets().Finite() for S in (X, Y)): + category = category.Finite() + if any(S in Sets().Enumerated() for S in (X, Y)): + category = category.Enumerated() Set_object_binary.__init__(self, X, Y, "intersection", "\\cap", category=category) + def cardinality(self): + r""" + Return the cardinality of this set. + + EXAMPLES:: + + sage: X = Set(IntegerRange(100)).intersection(Primes()) + sage: X.cardinality() + 25 + + sage: X = Set(Primes(), category=Sets()).intersection(Set(IntegerRange(200))) + sage: X.cardinality() + 46 + """ + if self in Sets().Infinite(): + return Infinity + if self in Sets().Finite(): + from sage.rings.integer import Integer + return Integer(len(list(iter(self)))) + return super().cardinality() + def is_finite(self): r""" Return whether this set is finite. @@ -1663,11 +1704,21 @@ def __init__(self, X, Y, category=None): sage: T = Set(ZZ) sage: X = S.difference(T); X Set-theoretic difference of Set of elements of Rational Field and Set of elements of Integer Ring + sage: X.category() + Category of sets sage: latex(X) \Bold{Q} - \Bold{Z} sage: TestSuite(X).run() """ + if category is None: + category = Sets() + if X in Sets().Finite(): + category = category.Finite() + if X in Sets().Enumerated(): + category = category.Enumerated() + if X in Sets().Infinite() and Y in Sets().Finite(): + category = category.Infinite() Set_object_binary.__init__(self, X, Y, "difference", "-", category=category) def is_finite(self): @@ -1797,6 +1848,8 @@ def _sympy_(self): Set-theoretic difference of Set of elements of Rational Field and Set of elements of Integer Ring + sage: X.category() + Category of sets sage: X._sympy_() Complement(Rationals, Integers) @@ -1804,6 +1857,8 @@ def _sympy_(self): Set-theoretic difference of Set of elements of Integer Ring and Set of elements of Rational Field + sage: X.category() + Category of enumerated sets sage: X._sympy_() EmptySet """ @@ -1827,11 +1882,19 @@ def __init__(self, X, Y, category=None): sage: T = Set(ZZ) sage: X = S.symmetric_difference(T); X Set-theoretic symmetric difference of Set of elements of Rational Field and Set of elements of Integer Ring + sage: X.category() + Category of sets sage: latex(X) \Bold{Q} \bigtriangleup \Bold{Z} sage: TestSuite(X).run() """ + if category is None: + category = Sets() + if all(S in Sets().Finite() for S in (X, Y)): + category = category.Finite() + if all(S in Sets().Enumerated() for S in (X, Y)): + category = category.Enumerated() Set_object_binary.__init__(self, X, Y, "symmetric difference", "\\bigtriangleup", category=category) def is_finite(self): From 8a304931879a0ce4292d284439c8e717540755cf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 20:31:44 -0700 Subject: [PATCH 04/10] src/sage/sets/set.py: Simplify category checks as suggested --- src/sage/sets/set.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 5d2380b3d24..bd94a217e0d 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -1368,12 +1368,12 @@ def __init__(self, X, Y, category=None): """ if category is None: category = Sets() - if all(S in Sets().Finite() for S in (X, Y)): - category = category.Finite() if all(S in Sets().Enumerated() for S in (X, Y)): category = category.Enumerated() if any(S in Sets().Infinite() for S in (X, Y)): category = category.Infinite() + elif all(S in Sets().Finite() for S in (X, Y)): + category = category.Finite() Set_object_binary.__init__(self, X, Y, "union", "\\cup", category=category) def is_finite(self): @@ -1713,11 +1713,11 @@ def __init__(self, X, Y, category=None): """ if category is None: category = Sets() - if X in Sets().Finite(): - category = category.Finite() if X in Sets().Enumerated(): category = category.Enumerated() - if X in Sets().Infinite() and Y in Sets().Finite(): + if X in Sets().Finite(): + category = category.Finite() + elif X in Sets().Infinite() and Y in Sets().Finite(): category = category.Infinite() Set_object_binary.__init__(self, X, Y, "difference", "-", category=category) From 141ebf14d80478128540f39ff1bac46e80eaca26 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 20:39:59 -0700 Subject: [PATCH 05/10] src/sage/categories/sets_cat.py: Update doctest output --- src/sage/categories/sets_cat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 09a57770a3b..4d7e0c11da4 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -247,7 +247,7 @@ def _call_(self, X, enumerated_set=False): {1, 2, 3} sage: S = Sets()([1, 2, 3]); S.category() - Category of finite sets + Category of finite enumerated sets sage: S = Sets()([1, 2, 3], enumerated_set=True); S.category() Category of facade finite enumerated sets From 8aa274ef877e4c987daa7d20fa761d2e5af94567 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 20:47:41 -0700 Subject: [PATCH 06/10] src/sage/categories/sets_cat.py: Fix doctest --- src/sage/categories/sets_cat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 4d7e0c11da4..b6fc0779716 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1361,7 +1361,7 @@ def some_elements(self): sage: S.some_elements() [47] sage: S = Set([]) - sage: S.some_elements() + sage: list(S.some_elements()) [] This method should return an iterable, *not* an iterator. From d711a61aeacde364b4ab76b59e55c2f01d8a90d7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 22:50:41 -0700 Subject: [PATCH 07/10] src/sage/structure/parent.pyx: Update doctest output --- src/sage/structure/parent.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 36b1e45d223..585ec9e559e 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -2863,7 +2863,7 @@ cdef class Set_generic(Parent): TESTS:: sage: Set(QQ).category() - Category of sets + Category of infinite sets """ def object(self): From e63e4f0bb4950985b13c4fbcc4c76110efb338c5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 18 Aug 2022 18:38:56 -0700 Subject: [PATCH 08/10] Set_object.is_finite: Check category --- src/sage/sets/set.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index bd94a217e0d..707f8887c72 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -743,6 +743,10 @@ def is_finite(self): sage: Set([1,'a',ZZ]).is_finite() True """ + if self in Sets().Finite(): + return True + if self in Sets().Infinite(): + return False obj = self.__object try: is_finite = obj.is_finite From 970d46772d84a0d31bc12517b16eb936be59a2c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 18 Aug 2022 18:47:32 -0700 Subject: [PATCH 09/10] Set_object.cardinality: Check category --- src/sage/sets/set.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 707f8887c72..8c0668724d0 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -676,6 +676,9 @@ def cardinality(self): sage: Set(GF(5^2,'a')).cardinality() 25 """ + if self in Sets().Infinite(): + return sage.rings.infinity.infinity + if not self.is_finite(): return sage.rings.infinity.infinity From e58d2abf9490496346fb4f114d98a9c9393a2b8d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 18 Aug 2022 18:48:10 -0700 Subject: [PATCH 10/10] Set_object_intersection.cardinality: Remove; move delegation to super to Set_object --- src/sage/sets/set.py | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 8c0668724d0..b76e6b064ef 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -693,7 +693,7 @@ def cardinality(self): except TypeError: pass - raise NotImplementedError("computation of cardinality of %s not yet implemented" % self.__object) + return super().cardinality() def is_empty(self): """ @@ -1526,9 +1526,16 @@ def __init__(self, X, Y, category=None): sage: X = Set(IntegerRange(100)).intersection(Primes()) sage: X.is_finite() True + sage: X.cardinality() + 25 sage: X.category() Category of finite enumerated sets sage: TestSuite(X).run() + + sage: X = Set(Primes(), category=Sets()).intersection(Set(IntegerRange(200))) + sage: X.cardinality() + 46 + sage: TestSuite(X).run() """ if category is None: category = Sets() @@ -1538,27 +1545,6 @@ def __init__(self, X, Y, category=None): category = category.Enumerated() Set_object_binary.__init__(self, X, Y, "intersection", "\\cap", category=category) - def cardinality(self): - r""" - Return the cardinality of this set. - - EXAMPLES:: - - sage: X = Set(IntegerRange(100)).intersection(Primes()) - sage: X.cardinality() - 25 - - sage: X = Set(Primes(), category=Sets()).intersection(Set(IntegerRange(200))) - sage: X.cardinality() - 46 - """ - if self in Sets().Infinite(): - return Infinity - if self in Sets().Finite(): - from sage.rings.integer import Integer - return Integer(len(list(iter(self)))) - return super().cardinality() - def is_finite(self): r""" Return whether this set is finite.