Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions src/sage/categories/enumerated_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -934,29 +934,6 @@ def _some_elements_from_iterator(self):

some_elements = _some_elements_from_iterator

def random_element(self):
"""
Return a random element in ``self``.

Unless otherwise stated, and for finite enumerated sets,
the probability is uniform.

This is a generic implementation from the category
``EnumeratedSets()``. It raises a :exc:`NotImplementedError`
since one does not know whether the set is finite.

EXAMPLES::

sage: class broken(UniqueRepresentation, Parent):
....: def __init__(self):
....: Parent.__init__(self, category = EnumeratedSets())
sage: broken().random_element()
Traceback (most recent call last):
...
NotImplementedError: unknown cardinality
"""
raise NotImplementedError("unknown cardinality")

def map(self, f, name=None, *, is_injective=True):
r"""
Return the image `\{f(x) | x \in \text{self}\}` of this
Expand Down
4 changes: 3 additions & 1 deletion src/sage/categories/finite_enumerated_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,9 @@ def _test_random(self, random_seed=123332938836894739865, **options):
E = float(N) / float(n)
chi_2 = sum(float(o) ** 2
for o in Counter(elements).values()) / E - float(N)
tester.assertLessEqual(chi_2, critical, f"assuming random_element of {self} follows a uniform distribution, this outcome would only occur with probability {1-T.cum_distribution_function(chi_2)}")
tester.assertLessEqual(
chi_2, critical, f"assuming random_element of {self} follows a uniform distribution, "
f"this outcome would only occur with probability {1-T.cum_distribution_function(chi_2)} (using seed {random_seed})")

def _test_rank(self, **options):
r"""
Expand Down
16 changes: 0 additions & 16 deletions src/sage/categories/infinite_enumerated_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,6 @@ class InfiniteEnumeratedSets(CategoryWithAxiom):

class ParentMethods:

def random_element(self):
"""
Raise an error because ``self`` is an infinite enumerated set.

EXAMPLES::

sage: NN = InfiniteEnumeratedSets().example()
sage: NN.random_element()
Traceback (most recent call last):
...
NotImplementedError: infinite set

TODO: should this be an optional abstract_method instead?
"""
raise NotImplementedError("infinite set")

def tuple(self):
"""
Raise an error because ``self`` is an infinite enumerated set.
Expand Down
14 changes: 14 additions & 0 deletions src/sage/sets/condition_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,20 @@ def _an_element_(self):
return element
raise NotImplementedError

def random_element(self):
"""
Return a random element in this set. Note that this might run forever.

EXAMPLES::

sage: ConditionSet(Set(ZZ), lambda x: x == 0).random_element()
0
"""
while True:
x = self._universe.random_element()
if x in self:
return x

def ambient(self):
r"""
Return the universe of ``self``.
Expand Down
10 changes: 10 additions & 0 deletions src/sage/sets/non_negative_integers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
from sage.structure.unique_representation import UniqueRepresentation
from sage.rings.integer import Integer
from sage.rings.integer_ring import ZZ


class NonNegativeIntegers(UniqueRepresentation, Parent):
Expand Down Expand Up @@ -195,6 +196,15 @@ def an_element(self):
"""
return self.from_integer(Integer(42))

def random_element(self):
"""
EXAMPLES::

sage: NonNegativeIntegers().an_element()
42
"""
return self.from_integer(ZZ.random_element().abs())

def some_elements(self):
"""
EXAMPLES::
Expand Down
83 changes: 82 additions & 1 deletion src/sage/sets/set.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,23 @@ def difference(self, X):

sage: X = Set(GF(9,'b')).difference(Set(GF(27,'b'))); X # needs sage.rings.finite_rings
{0, 1, 2, b, b + 1, b + 2, 2*b, 2*b + 1, 2*b + 2}

TESTS:

Check that some trivial simplifications are performed::

sage: Set(QQ) - Set([])
Set of elements of Rational Field
sage: Set(ZZ) - (Set(ZZ) - Set([0, 1/2, 1]))
Set-theoretic intersection of Set of elements of Integer Ring and {0, 1, 1/2}
"""
if isinstance(X, (Set_generic, Set_base)):
if self is X:
return Set([])
if X.is_empty():
return self
if isinstance(X, Set_object_difference) and X._X == self:
return self.intersection(X._Y)
return Set_object_difference(self, X)
raise TypeError("X (=%s) must be a Set" % X)

Expand Down Expand Up @@ -602,6 +615,19 @@ def _an_element_(self):
pass
return self._an_element_from_iterator()

def random_element(self):
"""
Return a random element of ``self``.

EXAMPLES::

sage: Set(ZZ).random_element() # random
4
"""
if self.__object is self:
raise NotImplementedError # some subclasses uses __object weirdly...
return self.__object.random_element()

def __contains__(self, x):
"""
Return ``True`` if `x` is in ``self``.
Expand Down Expand Up @@ -1503,6 +1529,18 @@ def cardinality(self):
"""
return self._X.cardinality() + self._Y.cardinality()

def random_element(self):
"""
Return a random element in this set.
Note that even when the set is finite, the distribution may not be uniform.

EXAMPLES::

sage: x = (Set(ZZ) | Set(RR)).random_element(); x # random
1
"""
return choice([self._X, self._Y]).random_element()

@cached_method
def _sympy_(self):
"""
Expand Down Expand Up @@ -1582,7 +1620,8 @@ def __init__(self, X, Y, category=None):
25
sage: X.category()
Category of finite enumerated sets
sage: TestSuite(X).run()
sage: TestSuite(X).run(skip=["_test_random"])
sage: for seed in range(1, 100): X._test_random(seed)

sage: X = Set(Primes(), category=Sets()).intersection(Set(IntegerRange(200)))
sage: X.cardinality()
Expand Down Expand Up @@ -1687,6 +1726,31 @@ def __iter__(self):
if x in Y:
yield x

def random_element(self):
"""
Return a random element in this set. Note that this might run forever.

EXAMPLES::

sage: (Set([1, 2]) & Set([2, 3])).random_element()
2
sage: (Set(NN) & ConditionSet(Set(ZZ), lambda x: x <= 0)).random_element()
0
"""
try:
y_is_finite = self._Y.is_finite()
except (AttributeError, NotImplementedError):
y_is_finite = None
if y_is_finite: # if Y.random_element() is uniform, this is also uniform
while True:
y = self._Y.random_element()
if y in self._X:
return y
while True:
x = self._X.random_element()
if x in self._Y:
return x

def __contains__(self, x):
"""
Return ``True`` if ``self`` contains ``x``.
Expand Down Expand Up @@ -1914,6 +1978,23 @@ def _sympy_(self):
sympy_init()
return Complement(self._X._sympy_(), self._Y._sympy_())

def random_element(self):
"""
Return a random element in this set. Note that this might run forever.

EXAMPLES::

sage: x = (Set(ZZ) - Set([0])).random_element(); x # random
1
sage: assert x != 0, x
sage: x = (Set(ZZ) - (Set(ZZ) - Set([1]))).random_element(); x # random
"""
Y = self._Y
while True:
x = self._X.random_element()
if x not in Y:
return x


class Set_object_symmetric_difference(Set_object_binary):
"""
Expand Down
Loading