Skip to content

Commit

Permalink
Trac #34376: Set_object_enumerated should be in FiniteEnumeratedSets()
Browse files Browse the repository at this point in the history
{{{
sage: Set([0, 1, 2, 3])
{0, 1, 2, 3}
sage: _.category()
Category of finite sets
sage: Set([0, 1, 2, 3], category=FiniteEnumeratedSets())
TypeError: Set() got an unexpected keyword argument 'category'
}}}

Likewise for the `Set_object_binary` classes (which implement lazy
union, intersection, ...), the category should be computed from the
categories of the inputs.

Also we add a `category` argument to the `Set` factory and the
`__init__` methods of the various implementation classes.

Follow ups:
- #34398 the relation between `Set_object_enumerated` and
`FiniteEnumeratedSet` (and `TrivialFamily`, `EnumeratedFamily`) should
be clarified
- #34387 `Set()` should construct facade parents

URL: https://trac.sagemath.org/34376
Reported by: mkoeppe
Ticket author(s): Matthias Koeppe
Reviewer(s): Travis Scrimshaw
  • Loading branch information
Release Manager committed Aug 29, 2022
2 parents f84d7a4 + e58d2ab commit d83fb88
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/sage/categories/cartesian_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion src/sage/categories/enumerated_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down
2 changes: 1 addition & 1 deletion src/sage/categories/homset.py
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
4 changes: 2 additions & 2 deletions src/sage/categories/sets_cat.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions src/sage/combinat/sidon_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down
108 changes: 87 additions & 21 deletions src/sage/sets/set.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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``.
Expand Down Expand Up @@ -187,22 +188,22 @@ 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")

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():
Expand Down Expand Up @@ -474,7 +475,7 @@ def __init__(self, X, category=None):
sage: type(Set(QQ))
<class 'sage.sets.set.Set_object_with_category'>
sage: Set(QQ).category()
Category of sets
Category of infinite sets
TESTS::
Expand All @@ -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

Expand Down Expand Up @@ -666,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

Expand All @@ -680,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):
"""
Expand Down Expand Up @@ -733,6 +746,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
Expand Down Expand Up @@ -830,7 +847,7 @@ class Set_object_enumerated(Set_object):
"""
A finite enumerated set.
"""
def __init__(self, X):
def __init__(self, X, category=None):
r"""
Initialize ``self``.
Expand All @@ -839,12 +856,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"""
Expand Down Expand Up @@ -1267,7 +1284,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.
Expand All @@ -1284,7 +1301,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"""
Expand Down Expand Up @@ -1338,7 +1355,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``.
Expand All @@ -1348,13 +1365,23 @@ def __init__(self, X, Y):
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()
"""
Set_object_binary.__init__(self, X, Y, "union", "\\cup")
if category is None:
category = Sets()
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):
r"""
Expand Down Expand Up @@ -1481,7 +1508,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``.
Expand All @@ -1491,15 +1518,32 @@ def __init__(self, X, Y):
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.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()
"""
Set_object_binary.__init__(self, X, Y, "intersection", "\\cap")
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 is_finite(self):
r"""
Expand Down Expand Up @@ -1643,7 +1687,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``.
Expand All @@ -1653,12 +1697,22 @@ def __init__(self, X, Y):
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()
"""
Set_object_binary.__init__(self, X, Y, "difference", "-")
if category is None:
category = Sets()
if X in Sets().Enumerated():
category = category.Enumerated()
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)

def is_finite(self):
r"""
Expand Down Expand Up @@ -1787,13 +1841,17 @@ 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)
sage: X = Set(ZZ).difference(Set(QQ)); X
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
"""
Expand All @@ -1807,7 +1865,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``.
Expand All @@ -1817,12 +1875,20 @@ def __init__(self, X, Y):
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()
"""
Set_object_binary.__init__(self, X, Y, "symmetric difference", "\\bigtriangleup")
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):
r"""
Expand Down
2 changes: 1 addition & 1 deletion src/sage/structure/parent.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2863,7 +2863,7 @@ cdef class Set_generic(Parent):
TESTS::
sage: Set(QQ).category()
Category of sets
Category of infinite sets
"""
def object(self):
Expand Down

0 comments on commit d83fb88

Please sign in to comment.