Coverage for /usr/lib/python3/dist-packages/sympy/sets/sets.py: 32%
1154 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from typing import Any, Callable
2from functools import reduce
3from collections import defaultdict
4import inspect
6from sympy.core.kind import Kind, UndefinedKind, NumberKind
7from sympy.core.basic import Basic
8from sympy.core.containers import Tuple, TupleKind
9from sympy.core.decorators import sympify_method_args, sympify_return
10from sympy.core.evalf import EvalfMixin
11from sympy.core.expr import Expr
12from sympy.core.function import Lambda
13from sympy.core.logic import (FuzzyBool, fuzzy_bool, fuzzy_or, fuzzy_and,
14 fuzzy_not)
15from sympy.core.numbers import Float, Integer
16from sympy.core.operations import LatticeOp
17from sympy.core.parameters import global_parameters
18from sympy.core.relational import Eq, Ne, is_lt
19from sympy.core.singleton import Singleton, S
20from sympy.core.sorting import ordered
21from sympy.core.symbol import symbols, Symbol, Dummy, uniquely_named_symbol
22from sympy.core.sympify import _sympify, sympify, _sympy_converter
23from sympy.functions.elementary.exponential import exp, log
24from sympy.functions.elementary.miscellaneous import Max, Min
25from sympy.logic.boolalg import And, Or, Not, Xor, true, false
26from sympy.utilities.decorator import deprecated
27from sympy.utilities.exceptions import sympy_deprecation_warning
28from sympy.utilities.iterables import (iproduct, sift, roundrobin, iterable,
29 subsets)
30from sympy.utilities.misc import func_name, filldedent
32from mpmath import mpi, mpf
34from mpmath.libmp.libmpf import prec_to_dps
37tfn = defaultdict(lambda: None, {
38 True: S.true,
39 S.true: S.true,
40 False: S.false,
41 S.false: S.false})
44@sympify_method_args
45class Set(Basic, EvalfMixin):
46 """
47 The base class for any kind of set.
49 Explanation
50 ===========
52 This is not meant to be used directly as a container of items. It does not
53 behave like the builtin ``set``; see :class:`FiniteSet` for that.
55 Real intervals are represented by the :class:`Interval` class and unions of
56 sets by the :class:`Union` class. The empty set is represented by the
57 :class:`EmptySet` class and available as a singleton as ``S.EmptySet``.
58 """
60 __slots__ = ()
62 is_number = False
63 is_iterable = False
64 is_interval = False
66 is_FiniteSet = False
67 is_Interval = False
68 is_ProductSet = False
69 is_Union = False
70 is_Intersection: FuzzyBool = None
71 is_UniversalSet: FuzzyBool = None
72 is_Complement: FuzzyBool = None
73 is_ComplexRegion = False
75 is_empty: FuzzyBool = None
76 is_finite_set: FuzzyBool = None
78 @property # type: ignore
79 @deprecated(
80 """
81 The is_EmptySet attribute of Set objects is deprecated.
82 Use 's is S.EmptySet" or 's.is_empty' instead.
83 """,
84 deprecated_since_version="1.5",
85 active_deprecations_target="deprecated-is-emptyset",
86 )
87 def is_EmptySet(self):
88 return None
90 @staticmethod
91 def _infimum_key(expr):
92 """
93 Return infimum (if possible) else S.Infinity.
94 """
95 try:
96 infimum = expr.inf
97 assert infimum.is_comparable
98 infimum = infimum.evalf() # issue #18505
99 except (NotImplementedError,
100 AttributeError, AssertionError, ValueError):
101 infimum = S.Infinity
102 return infimum
104 def union(self, other):
105 """
106 Returns the union of ``self`` and ``other``.
108 Examples
109 ========
111 As a shortcut it is possible to use the ``+`` operator:
113 >>> from sympy import Interval, FiniteSet
114 >>> Interval(0, 1).union(Interval(2, 3))
115 Union(Interval(0, 1), Interval(2, 3))
116 >>> Interval(0, 1) + Interval(2, 3)
117 Union(Interval(0, 1), Interval(2, 3))
118 >>> Interval(1, 2, True, True) + FiniteSet(2, 3)
119 Union({3}, Interval.Lopen(1, 2))
121 Similarly it is possible to use the ``-`` operator for set differences:
123 >>> Interval(0, 2) - Interval(0, 1)
124 Interval.Lopen(1, 2)
125 >>> Interval(1, 3) - FiniteSet(2)
126 Union(Interval.Ropen(1, 2), Interval.Lopen(2, 3))
128 """
129 return Union(self, other)
131 def intersect(self, other):
132 """
133 Returns the intersection of 'self' and 'other'.
135 Examples
136 ========
138 >>> from sympy import Interval
140 >>> Interval(1, 3).intersect(Interval(1, 2))
141 Interval(1, 2)
143 >>> from sympy import imageset, Lambda, symbols, S
144 >>> n, m = symbols('n m')
145 >>> a = imageset(Lambda(n, 2*n), S.Integers)
146 >>> a.intersect(imageset(Lambda(m, 2*m + 1), S.Integers))
147 EmptySet
149 """
150 return Intersection(self, other)
152 def intersection(self, other):
153 """
154 Alias for :meth:`intersect()`
155 """
156 return self.intersect(other)
158 def is_disjoint(self, other):
159 """
160 Returns True if ``self`` and ``other`` are disjoint.
162 Examples
163 ========
165 >>> from sympy import Interval
166 >>> Interval(0, 2).is_disjoint(Interval(1, 2))
167 False
168 >>> Interval(0, 2).is_disjoint(Interval(3, 4))
169 True
171 References
172 ==========
174 .. [1] https://en.wikipedia.org/wiki/Disjoint_sets
175 """
176 return self.intersect(other) == S.EmptySet
178 def isdisjoint(self, other):
179 """
180 Alias for :meth:`is_disjoint()`
181 """
182 return self.is_disjoint(other)
184 def complement(self, universe):
185 r"""
186 The complement of 'self' w.r.t the given universe.
188 Examples
189 ========
191 >>> from sympy import Interval, S
192 >>> Interval(0, 1).complement(S.Reals)
193 Union(Interval.open(-oo, 0), Interval.open(1, oo))
195 >>> Interval(0, 1).complement(S.UniversalSet)
196 Complement(UniversalSet, Interval(0, 1))
198 """
199 return Complement(universe, self)
201 def _complement(self, other):
202 # this behaves as other - self
203 if isinstance(self, ProductSet) and isinstance(other, ProductSet):
204 # If self and other are disjoint then other - self == self
205 if len(self.sets) != len(other.sets):
206 return other
208 # There can be other ways to represent this but this gives:
209 # (A x B) - (C x D) = ((A - C) x B) U (A x (B - D))
210 overlaps = []
211 pairs = list(zip(self.sets, other.sets))
212 for n in range(len(pairs)):
213 sets = (o if i != n else o-s for i, (s, o) in enumerate(pairs))
214 overlaps.append(ProductSet(*sets))
215 return Union(*overlaps)
217 elif isinstance(other, Interval):
218 if isinstance(self, (Interval, FiniteSet)):
219 return Intersection(other, self.complement(S.Reals))
221 elif isinstance(other, Union):
222 return Union(*(o - self for o in other.args))
224 elif isinstance(other, Complement):
225 return Complement(other.args[0], Union(other.args[1], self), evaluate=False)
227 elif other is S.EmptySet:
228 return S.EmptySet
230 elif isinstance(other, FiniteSet):
231 sifted = sift(other, lambda x: fuzzy_bool(self.contains(x)))
232 # ignore those that are contained in self
233 return Union(FiniteSet(*(sifted[False])),
234 Complement(FiniteSet(*(sifted[None])), self, evaluate=False)
235 if sifted[None] else S.EmptySet)
237 def symmetric_difference(self, other):
238 """
239 Returns symmetric difference of ``self`` and ``other``.
241 Examples
242 ========
244 >>> from sympy import Interval, S
245 >>> Interval(1, 3).symmetric_difference(S.Reals)
246 Union(Interval.open(-oo, 1), Interval.open(3, oo))
247 >>> Interval(1, 10).symmetric_difference(S.Reals)
248 Union(Interval.open(-oo, 1), Interval.open(10, oo))
250 >>> from sympy import S, EmptySet
251 >>> S.Reals.symmetric_difference(EmptySet)
252 Reals
254 References
255 ==========
256 .. [1] https://en.wikipedia.org/wiki/Symmetric_difference
258 """
259 return SymmetricDifference(self, other)
261 def _symmetric_difference(self, other):
262 return Union(Complement(self, other), Complement(other, self))
264 @property
265 def inf(self):
266 """
267 The infimum of ``self``.
269 Examples
270 ========
272 >>> from sympy import Interval, Union
273 >>> Interval(0, 1).inf
274 0
275 >>> Union(Interval(0, 1), Interval(2, 3)).inf
276 0
278 """
279 return self._inf
281 @property
282 def _inf(self):
283 raise NotImplementedError("(%s)._inf" % self)
285 @property
286 def sup(self):
287 """
288 The supremum of ``self``.
290 Examples
291 ========
293 >>> from sympy import Interval, Union
294 >>> Interval(0, 1).sup
295 1
296 >>> Union(Interval(0, 1), Interval(2, 3)).sup
297 3
299 """
300 return self._sup
302 @property
303 def _sup(self):
304 raise NotImplementedError("(%s)._sup" % self)
306 def contains(self, other):
307 """
308 Returns a SymPy value indicating whether ``other`` is contained
309 in ``self``: ``true`` if it is, ``false`` if it is not, else
310 an unevaluated ``Contains`` expression (or, as in the case of
311 ConditionSet and a union of FiniteSet/Intervals, an expression
312 indicating the conditions for containment).
314 Examples
315 ========
317 >>> from sympy import Interval, S
318 >>> from sympy.abc import x
320 >>> Interval(0, 1).contains(0.5)
321 True
323 As a shortcut it is possible to use the ``in`` operator, but that
324 will raise an error unless an affirmative true or false is not
325 obtained.
327 >>> Interval(0, 1).contains(x)
328 (0 <= x) & (x <= 1)
329 >>> x in Interval(0, 1)
330 Traceback (most recent call last):
331 ...
332 TypeError: did not evaluate to a bool: None
334 The result of 'in' is a bool, not a SymPy value
336 >>> 1 in Interval(0, 2)
337 True
338 >>> _ is S.true
339 False
340 """
341 from .contains import Contains
342 other = sympify(other, strict=True)
344 c = self._contains(other)
345 if isinstance(c, Contains):
346 return c
347 if c is None:
348 return Contains(other, self, evaluate=False)
349 b = tfn[c]
350 if b is None:
351 return c
352 return b
354 def _contains(self, other):
355 raise NotImplementedError(filldedent('''
356 (%s)._contains(%s) is not defined. This method, when
357 defined, will receive a sympified object. The method
358 should return True, False, None or something that
359 expresses what must be true for the containment of that
360 object in self to be evaluated. If None is returned
361 then a generic Contains object will be returned
362 by the ``contains`` method.''' % (self, other)))
364 def is_subset(self, other):
365 """
366 Returns True if ``self`` is a subset of ``other``.
368 Examples
369 ========
371 >>> from sympy import Interval
372 >>> Interval(0, 0.5).is_subset(Interval(0, 1))
373 True
374 >>> Interval(0, 1).is_subset(Interval(0, 1, left_open=True))
375 False
377 """
378 if not isinstance(other, Set):
379 raise ValueError("Unknown argument '%s'" % other)
381 # Handle the trivial cases
382 if self == other:
383 return True
384 is_empty = self.is_empty
385 if is_empty is True:
386 return True
387 elif fuzzy_not(is_empty) and other.is_empty:
388 return False
389 if self.is_finite_set is False and other.is_finite_set:
390 return False
392 # Dispatch on subclass rules
393 ret = self._eval_is_subset(other)
394 if ret is not None:
395 return ret
396 ret = other._eval_is_superset(self)
397 if ret is not None:
398 return ret
400 # Use pairwise rules from multiple dispatch
401 from sympy.sets.handlers.issubset import is_subset_sets
402 ret = is_subset_sets(self, other)
403 if ret is not None:
404 return ret
406 # Fall back on computing the intersection
407 # XXX: We shouldn't do this. A query like this should be handled
408 # without evaluating new Set objects. It should be the other way round
409 # so that the intersect method uses is_subset for evaluation.
410 if self.intersect(other) == self:
411 return True
413 def _eval_is_subset(self, other):
414 '''Returns a fuzzy bool for whether self is a subset of other.'''
415 return None
417 def _eval_is_superset(self, other):
418 '''Returns a fuzzy bool for whether self is a subset of other.'''
419 return None
421 # This should be deprecated:
422 def issubset(self, other):
423 """
424 Alias for :meth:`is_subset()`
425 """
426 return self.is_subset(other)
428 def is_proper_subset(self, other):
429 """
430 Returns True if ``self`` is a proper subset of ``other``.
432 Examples
433 ========
435 >>> from sympy import Interval
436 >>> Interval(0, 0.5).is_proper_subset(Interval(0, 1))
437 True
438 >>> Interval(0, 1).is_proper_subset(Interval(0, 1))
439 False
441 """
442 if isinstance(other, Set):
443 return self != other and self.is_subset(other)
444 else:
445 raise ValueError("Unknown argument '%s'" % other)
447 def is_superset(self, other):
448 """
449 Returns True if ``self`` is a superset of ``other``.
451 Examples
452 ========
454 >>> from sympy import Interval
455 >>> Interval(0, 0.5).is_superset(Interval(0, 1))
456 False
457 >>> Interval(0, 1).is_superset(Interval(0, 1, left_open=True))
458 True
460 """
461 if isinstance(other, Set):
462 return other.is_subset(self)
463 else:
464 raise ValueError("Unknown argument '%s'" % other)
466 # This should be deprecated:
467 def issuperset(self, other):
468 """
469 Alias for :meth:`is_superset()`
470 """
471 return self.is_superset(other)
473 def is_proper_superset(self, other):
474 """
475 Returns True if ``self`` is a proper superset of ``other``.
477 Examples
478 ========
480 >>> from sympy import Interval
481 >>> Interval(0, 1).is_proper_superset(Interval(0, 0.5))
482 True
483 >>> Interval(0, 1).is_proper_superset(Interval(0, 1))
484 False
486 """
487 if isinstance(other, Set):
488 return self != other and self.is_superset(other)
489 else:
490 raise ValueError("Unknown argument '%s'" % other)
492 def _eval_powerset(self):
493 from .powerset import PowerSet
494 return PowerSet(self)
496 def powerset(self):
497 """
498 Find the Power set of ``self``.
500 Examples
501 ========
503 >>> from sympy import EmptySet, FiniteSet, Interval
505 A power set of an empty set:
507 >>> A = EmptySet
508 >>> A.powerset()
509 {EmptySet}
511 A power set of a finite set:
513 >>> A = FiniteSet(1, 2)
514 >>> a, b, c = FiniteSet(1), FiniteSet(2), FiniteSet(1, 2)
515 >>> A.powerset() == FiniteSet(a, b, c, EmptySet)
516 True
518 A power set of an interval:
520 >>> Interval(1, 2).powerset()
521 PowerSet(Interval(1, 2))
523 References
524 ==========
526 .. [1] https://en.wikipedia.org/wiki/Power_set
528 """
529 return self._eval_powerset()
531 @property
532 def measure(self):
533 """
534 The (Lebesgue) measure of ``self``.
536 Examples
537 ========
539 >>> from sympy import Interval, Union
540 >>> Interval(0, 1).measure
541 1
542 >>> Union(Interval(0, 1), Interval(2, 3)).measure
543 2
545 """
546 return self._measure
548 @property
549 def kind(self):
550 """
551 The kind of a Set
553 Explanation
554 ===========
556 Any :class:`Set` will have kind :class:`SetKind` which is
557 parametrised by the kind of the elements of the set. For example
558 most sets are sets of numbers and will have kind
559 ``SetKind(NumberKind)``. If elements of sets are different in kind than
560 their kind will ``SetKind(UndefinedKind)``. See
561 :class:`sympy.core.kind.Kind` for an explanation of the kind system.
563 Examples
564 ========
566 >>> from sympy import Interval, Matrix, FiniteSet, EmptySet, ProductSet, PowerSet
568 >>> FiniteSet(Matrix([1, 2])).kind
569 SetKind(MatrixKind(NumberKind))
571 >>> Interval(1, 2).kind
572 SetKind(NumberKind)
574 >>> EmptySet.kind
575 SetKind()
577 A :class:`sympy.sets.powerset.PowerSet` is a set of sets:
579 >>> PowerSet({1, 2, 3}).kind
580 SetKind(SetKind(NumberKind))
582 A :class:`ProductSet` represents the set of tuples of elements of
583 other sets. Its kind is :class:`sympy.core.containers.TupleKind`
584 parametrised by the kinds of the elements of those sets:
586 >>> p = ProductSet(FiniteSet(1, 2), FiniteSet(3, 4))
587 >>> list(p)
588 [(1, 3), (2, 3), (1, 4), (2, 4)]
589 >>> p.kind
590 SetKind(TupleKind(NumberKind, NumberKind))
592 When all elements of the set do not have same kind, the kind
593 will be returned as ``SetKind(UndefinedKind)``:
595 >>> FiniteSet(0, Matrix([1, 2])).kind
596 SetKind(UndefinedKind)
598 The kind of the elements of a set are given by the ``element_kind``
599 attribute of ``SetKind``:
601 >>> Interval(1, 2).kind.element_kind
602 NumberKind
604 See Also
605 ========
607 NumberKind
608 sympy.core.kind.UndefinedKind
609 sympy.core.containers.TupleKind
610 MatrixKind
611 sympy.matrices.expressions.sets.MatrixSet
612 sympy.sets.conditionset.ConditionSet
613 Rationals
614 Naturals
615 Integers
616 sympy.sets.fancysets.ImageSet
617 sympy.sets.fancysets.Range
618 sympy.sets.fancysets.ComplexRegion
619 sympy.sets.powerset.PowerSet
620 sympy.sets.sets.ProductSet
621 sympy.sets.sets.Interval
622 sympy.sets.sets.Union
623 sympy.sets.sets.Intersection
624 sympy.sets.sets.Complement
625 sympy.sets.sets.EmptySet
626 sympy.sets.sets.UniversalSet
627 sympy.sets.sets.FiniteSet
628 sympy.sets.sets.SymmetricDifference
629 sympy.sets.sets.DisjointUnion
630 """
631 return self._kind()
633 @property
634 def boundary(self):
635 """
636 The boundary or frontier of a set.
638 Explanation
639 ===========
641 A point x is on the boundary of a set S if
643 1. x is in the closure of S.
644 I.e. Every neighborhood of x contains a point in S.
645 2. x is not in the interior of S.
646 I.e. There does not exist an open set centered on x contained
647 entirely within S.
649 There are the points on the outer rim of S. If S is open then these
650 points need not actually be contained within S.
652 For example, the boundary of an interval is its start and end points.
653 This is true regardless of whether or not the interval is open.
655 Examples
656 ========
658 >>> from sympy import Interval
659 >>> Interval(0, 1).boundary
660 {0, 1}
661 >>> Interval(0, 1, True, False).boundary
662 {0, 1}
663 """
664 return self._boundary
666 @property
667 def is_open(self):
668 """
669 Property method to check whether a set is open.
671 Explanation
672 ===========
674 A set is open if and only if it has an empty intersection with its
675 boundary. In particular, a subset A of the reals is open if and only
676 if each one of its points is contained in an open interval that is a
677 subset of A.
679 Examples
680 ========
681 >>> from sympy import S
682 >>> S.Reals.is_open
683 True
684 >>> S.Rationals.is_open
685 False
686 """
687 return Intersection(self, self.boundary).is_empty
689 @property
690 def is_closed(self):
691 """
692 A property method to check whether a set is closed.
694 Explanation
695 ===========
697 A set is closed if its complement is an open set. The closedness of a
698 subset of the reals is determined with respect to R and its standard
699 topology.
701 Examples
702 ========
703 >>> from sympy import Interval
704 >>> Interval(0, 1).is_closed
705 True
706 """
707 return self.boundary.is_subset(self)
709 @property
710 def closure(self):
711 """
712 Property method which returns the closure of a set.
713 The closure is defined as the union of the set itself and its
714 boundary.
716 Examples
717 ========
718 >>> from sympy import S, Interval
719 >>> S.Reals.closure
720 Reals
721 >>> Interval(0, 1).closure
722 Interval(0, 1)
723 """
724 return self + self.boundary
726 @property
727 def interior(self):
728 """
729 Property method which returns the interior of a set.
730 The interior of a set S consists all points of S that do not
731 belong to the boundary of S.
733 Examples
734 ========
735 >>> from sympy import Interval
736 >>> Interval(0, 1).interior
737 Interval.open(0, 1)
738 >>> Interval(0, 1).boundary.interior
739 EmptySet
740 """
741 return self - self.boundary
743 @property
744 def _boundary(self):
745 raise NotImplementedError()
747 @property
748 def _measure(self):
749 raise NotImplementedError("(%s)._measure" % self)
751 def _kind(self):
752 return SetKind(UndefinedKind)
754 def _eval_evalf(self, prec):
755 dps = prec_to_dps(prec)
756 return self.func(*[arg.evalf(n=dps) for arg in self.args])
758 @sympify_return([('other', 'Set')], NotImplemented)
759 def __add__(self, other):
760 return self.union(other)
762 @sympify_return([('other', 'Set')], NotImplemented)
763 def __or__(self, other):
764 return self.union(other)
766 @sympify_return([('other', 'Set')], NotImplemented)
767 def __and__(self, other):
768 return self.intersect(other)
770 @sympify_return([('other', 'Set')], NotImplemented)
771 def __mul__(self, other):
772 return ProductSet(self, other)
774 @sympify_return([('other', 'Set')], NotImplemented)
775 def __xor__(self, other):
776 return SymmetricDifference(self, other)
778 @sympify_return([('exp', Expr)], NotImplemented)
779 def __pow__(self, exp):
780 if not (exp.is_Integer and exp >= 0):
781 raise ValueError("%s: Exponent must be a positive Integer" % exp)
782 return ProductSet(*[self]*exp)
784 @sympify_return([('other', 'Set')], NotImplemented)
785 def __sub__(self, other):
786 return Complement(self, other)
788 def __contains__(self, other):
789 other = _sympify(other)
790 c = self._contains(other)
791 b = tfn[c]
792 if b is None:
793 # x in y must evaluate to T or F; to entertain a None
794 # result with Set use y.contains(x)
795 raise TypeError('did not evaluate to a bool: %r' % c)
796 return b
799class ProductSet(Set):
800 """
801 Represents a Cartesian Product of Sets.
803 Explanation
804 ===========
806 Returns a Cartesian product given several sets as either an iterable
807 or individual arguments.
809 Can use ``*`` operator on any sets for convenient shorthand.
811 Examples
812 ========
814 >>> from sympy import Interval, FiniteSet, ProductSet
815 >>> I = Interval(0, 5); S = FiniteSet(1, 2, 3)
816 >>> ProductSet(I, S)
817 ProductSet(Interval(0, 5), {1, 2, 3})
819 >>> (2, 2) in ProductSet(I, S)
820 True
822 >>> Interval(0, 1) * Interval(0, 1) # The unit square
823 ProductSet(Interval(0, 1), Interval(0, 1))
825 >>> coin = FiniteSet('H', 'T')
826 >>> set(coin**2)
827 {(H, H), (H, T), (T, H), (T, T)}
829 The Cartesian product is not commutative or associative e.g.:
831 >>> I*S == S*I
832 False
833 >>> (I*I)*I == I*(I*I)
834 False
836 Notes
837 =====
839 - Passes most operations down to the argument sets
841 References
842 ==========
844 .. [1] https://en.wikipedia.org/wiki/Cartesian_product
845 """
846 is_ProductSet = True
848 def __new__(cls, *sets, **assumptions):
849 if len(sets) == 1 and iterable(sets[0]) and not isinstance(sets[0], (Set, set)):
850 sympy_deprecation_warning(
851 """
852ProductSet(iterable) is deprecated. Use ProductSet(*iterable) instead.
853 """,
854 deprecated_since_version="1.5",
855 active_deprecations_target="deprecated-productset-iterable",
856 )
857 sets = tuple(sets[0])
859 sets = [sympify(s) for s in sets]
861 if not all(isinstance(s, Set) for s in sets):
862 raise TypeError("Arguments to ProductSet should be of type Set")
864 # Nullary product of sets is *not* the empty set
865 if len(sets) == 0:
866 return FiniteSet(())
868 if S.EmptySet in sets:
869 return S.EmptySet
871 return Basic.__new__(cls, *sets, **assumptions)
873 @property
874 def sets(self):
875 return self.args
877 def flatten(self):
878 def _flatten(sets):
879 for s in sets:
880 if s.is_ProductSet:
881 yield from _flatten(s.sets)
882 else:
883 yield s
884 return ProductSet(*_flatten(self.sets))
888 def _contains(self, element):
889 """
890 ``in`` operator for ProductSets.
892 Examples
893 ========
895 >>> from sympy import Interval
896 >>> (2, 3) in Interval(0, 5) * Interval(0, 5)
897 True
899 >>> (10, 10) in Interval(0, 5) * Interval(0, 5)
900 False
902 Passes operation on to constituent sets
903 """
904 if element.is_Symbol:
905 return None
907 if not isinstance(element, Tuple) or len(element) != len(self.sets):
908 return False
910 return fuzzy_and(s._contains(e) for s, e in zip(self.sets, element))
912 def as_relational(self, *symbols):
913 symbols = [_sympify(s) for s in symbols]
914 if len(symbols) != len(self.sets) or not all(
915 i.is_Symbol for i in symbols):
916 raise ValueError(
917 'number of symbols must match the number of sets')
918 return And(*[s.as_relational(i) for s, i in zip(self.sets, symbols)])
920 @property
921 def _boundary(self):
922 return Union(*(ProductSet(*(b + b.boundary if i != j else b.boundary
923 for j, b in enumerate(self.sets)))
924 for i, a in enumerate(self.sets)))
926 @property
927 def is_iterable(self):
928 """
929 A property method which tests whether a set is iterable or not.
930 Returns True if set is iterable, otherwise returns False.
932 Examples
933 ========
935 >>> from sympy import FiniteSet, Interval
936 >>> I = Interval(0, 1)
937 >>> A = FiniteSet(1, 2, 3, 4, 5)
938 >>> I.is_iterable
939 False
940 >>> A.is_iterable
941 True
943 """
944 return all(set.is_iterable for set in self.sets)
946 def __iter__(self):
947 """
948 A method which implements is_iterable property method.
949 If self.is_iterable returns True (both constituent sets are iterable),
950 then return the Cartesian Product. Otherwise, raise TypeError.
951 """
952 return iproduct(*self.sets)
954 @property
955 def is_empty(self):
956 return fuzzy_or(s.is_empty for s in self.sets)
958 @property
959 def is_finite_set(self):
960 all_finite = fuzzy_and(s.is_finite_set for s in self.sets)
961 return fuzzy_or([self.is_empty, all_finite])
963 @property
964 def _measure(self):
965 measure = 1
966 for s in self.sets:
967 measure *= s.measure
968 return measure
970 def _kind(self):
971 return SetKind(TupleKind(*(i.kind.element_kind for i in self.args)))
973 def __len__(self):
974 return reduce(lambda a, b: a*b, (len(s) for s in self.args))
976 def __bool__(self):
977 return all(self.sets)
980class Interval(Set):
981 """
982 Represents a real interval as a Set.
984 Usage:
985 Returns an interval with end points ``start`` and ``end``.
987 For ``left_open=True`` (default ``left_open`` is ``False``) the interval
988 will be open on the left. Similarly, for ``right_open=True`` the interval
989 will be open on the right.
991 Examples
992 ========
994 >>> from sympy import Symbol, Interval
995 >>> Interval(0, 1)
996 Interval(0, 1)
997 >>> Interval.Ropen(0, 1)
998 Interval.Ropen(0, 1)
999 >>> Interval.Ropen(0, 1)
1000 Interval.Ropen(0, 1)
1001 >>> Interval.Lopen(0, 1)
1002 Interval.Lopen(0, 1)
1003 >>> Interval.open(0, 1)
1004 Interval.open(0, 1)
1006 >>> a = Symbol('a', real=True)
1007 >>> Interval(0, a)
1008 Interval(0, a)
1010 Notes
1011 =====
1012 - Only real end points are supported
1013 - ``Interval(a, b)`` with $a > b$ will return the empty set
1014 - Use the ``evalf()`` method to turn an Interval into an mpmath
1015 ``mpi`` interval instance
1017 References
1018 ==========
1020 .. [1] https://en.wikipedia.org/wiki/Interval_%28mathematics%29
1021 """
1022 is_Interval = True
1024 def __new__(cls, start, end, left_open=False, right_open=False):
1026 start = _sympify(start)
1027 end = _sympify(end)
1028 left_open = _sympify(left_open)
1029 right_open = _sympify(right_open)
1031 if not all(isinstance(a, (type(true), type(false)))
1032 for a in [left_open, right_open]):
1033 raise NotImplementedError(
1034 "left_open and right_open can have only true/false values, "
1035 "got %s and %s" % (left_open, right_open))
1037 # Only allow real intervals
1038 if fuzzy_not(fuzzy_and(i.is_extended_real for i in (start, end, end-start))):
1039 raise ValueError("Non-real intervals are not supported")
1041 # evaluate if possible
1042 if is_lt(end, start):
1043 return S.EmptySet
1044 elif (end - start).is_negative:
1045 return S.EmptySet
1047 if end == start and (left_open or right_open):
1048 return S.EmptySet
1049 if end == start and not (left_open or right_open):
1050 if start is S.Infinity or start is S.NegativeInfinity:
1051 return S.EmptySet
1052 return FiniteSet(end)
1054 # Make sure infinite interval end points are open.
1055 if start is S.NegativeInfinity:
1056 left_open = true
1057 if end is S.Infinity:
1058 right_open = true
1059 if start == S.Infinity or end == S.NegativeInfinity:
1060 return S.EmptySet
1062 return Basic.__new__(cls, start, end, left_open, right_open)
1064 @property
1065 def start(self):
1066 """
1067 The left end point of the interval.
1069 This property takes the same value as the ``inf`` property.
1071 Examples
1072 ========
1074 >>> from sympy import Interval
1075 >>> Interval(0, 1).start
1076 0
1078 """
1079 return self._args[0]
1081 @property
1082 def end(self):
1083 """
1084 The right end point of the interval.
1086 This property takes the same value as the ``sup`` property.
1088 Examples
1089 ========
1091 >>> from sympy import Interval
1092 >>> Interval(0, 1).end
1093 1
1095 """
1096 return self._args[1]
1098 @property
1099 def left_open(self):
1100 """
1101 True if interval is left-open.
1103 Examples
1104 ========
1106 >>> from sympy import Interval
1107 >>> Interval(0, 1, left_open=True).left_open
1108 True
1109 >>> Interval(0, 1, left_open=False).left_open
1110 False
1112 """
1113 return self._args[2]
1115 @property
1116 def right_open(self):
1117 """
1118 True if interval is right-open.
1120 Examples
1121 ========
1123 >>> from sympy import Interval
1124 >>> Interval(0, 1, right_open=True).right_open
1125 True
1126 >>> Interval(0, 1, right_open=False).right_open
1127 False
1129 """
1130 return self._args[3]
1132 @classmethod
1133 def open(cls, a, b):
1134 """Return an interval including neither boundary."""
1135 return cls(a, b, True, True)
1137 @classmethod
1138 def Lopen(cls, a, b):
1139 """Return an interval not including the left boundary."""
1140 return cls(a, b, True, False)
1142 @classmethod
1143 def Ropen(cls, a, b):
1144 """Return an interval not including the right boundary."""
1145 return cls(a, b, False, True)
1147 @property
1148 def _inf(self):
1149 return self.start
1151 @property
1152 def _sup(self):
1153 return self.end
1155 @property
1156 def left(self):
1157 return self.start
1159 @property
1160 def right(self):
1161 return self.end
1163 @property
1164 def is_empty(self):
1165 if self.left_open or self.right_open:
1166 cond = self.start >= self.end # One/both bounds open
1167 else:
1168 cond = self.start > self.end # Both bounds closed
1169 return fuzzy_bool(cond)
1171 @property
1172 def is_finite_set(self):
1173 return self.measure.is_zero
1175 def _complement(self, other):
1176 if other == S.Reals:
1177 a = Interval(S.NegativeInfinity, self.start,
1178 True, not self.left_open)
1179 b = Interval(self.end, S.Infinity, not self.right_open, True)
1180 return Union(a, b)
1182 if isinstance(other, FiniteSet):
1183 nums = [m for m in other.args if m.is_number]
1184 if nums == []:
1185 return None
1187 return Set._complement(self, other)
1189 @property
1190 def _boundary(self):
1191 finite_points = [p for p in (self.start, self.end)
1192 if abs(p) != S.Infinity]
1193 return FiniteSet(*finite_points)
1195 def _contains(self, other):
1196 if (not isinstance(other, Expr) or other is S.NaN
1197 or other.is_real is False or other.has(S.ComplexInfinity)):
1198 # if an expression has zoo it will be zoo or nan
1199 # and neither of those is real
1200 return false
1202 if self.start is S.NegativeInfinity and self.end is S.Infinity:
1203 if other.is_real is not None:
1204 return other.is_real
1206 d = Dummy()
1207 return self.as_relational(d).subs(d, other)
1209 def as_relational(self, x):
1210 """Rewrite an interval in terms of inequalities and logic operators."""
1211 x = sympify(x)
1212 if self.right_open:
1213 right = x < self.end
1214 else:
1215 right = x <= self.end
1216 if self.left_open:
1217 left = self.start < x
1218 else:
1219 left = self.start <= x
1220 return And(left, right)
1222 @property
1223 def _measure(self):
1224 return self.end - self.start
1226 def _kind(self):
1227 return SetKind(NumberKind)
1229 def to_mpi(self, prec=53):
1230 return mpi(mpf(self.start._eval_evalf(prec)),
1231 mpf(self.end._eval_evalf(prec)))
1233 def _eval_evalf(self, prec):
1234 return Interval(self.left._evalf(prec), self.right._evalf(prec),
1235 left_open=self.left_open, right_open=self.right_open)
1237 def _is_comparable(self, other):
1238 is_comparable = self.start.is_comparable
1239 is_comparable &= self.end.is_comparable
1240 is_comparable &= other.start.is_comparable
1241 is_comparable &= other.end.is_comparable
1243 return is_comparable
1245 @property
1246 def is_left_unbounded(self):
1247 """Return ``True`` if the left endpoint is negative infinity. """
1248 return self.left is S.NegativeInfinity or self.left == Float("-inf")
1250 @property
1251 def is_right_unbounded(self):
1252 """Return ``True`` if the right endpoint is positive infinity. """
1253 return self.right is S.Infinity or self.right == Float("+inf")
1255 def _eval_Eq(self, other):
1256 if not isinstance(other, Interval):
1257 if isinstance(other, FiniteSet):
1258 return false
1259 elif isinstance(other, Set):
1260 return None
1261 return false
1264class Union(Set, LatticeOp):
1265 """
1266 Represents a union of sets as a :class:`Set`.
1268 Examples
1269 ========
1271 >>> from sympy import Union, Interval
1272 >>> Union(Interval(1, 2), Interval(3, 4))
1273 Union(Interval(1, 2), Interval(3, 4))
1275 The Union constructor will always try to merge overlapping intervals,
1276 if possible. For example:
1278 >>> Union(Interval(1, 2), Interval(2, 3))
1279 Interval(1, 3)
1281 See Also
1282 ========
1284 Intersection
1286 References
1287 ==========
1289 .. [1] https://en.wikipedia.org/wiki/Union_%28set_theory%29
1290 """
1291 is_Union = True
1293 @property
1294 def identity(self):
1295 return S.EmptySet
1297 @property
1298 def zero(self):
1299 return S.UniversalSet
1301 def __new__(cls, *args, **kwargs):
1302 evaluate = kwargs.get('evaluate', global_parameters.evaluate)
1304 # flatten inputs to merge intersections and iterables
1305 args = _sympify(args)
1307 # Reduce sets using known rules
1308 if evaluate:
1309 args = list(cls._new_args_filter(args))
1310 return simplify_union(args)
1312 args = list(ordered(args, Set._infimum_key))
1314 obj = Basic.__new__(cls, *args)
1315 obj._argset = frozenset(args)
1316 return obj
1318 @property
1319 def args(self):
1320 return self._args
1322 def _complement(self, universe):
1323 # DeMorgan's Law
1324 return Intersection(s.complement(universe) for s in self.args)
1326 @property
1327 def _inf(self):
1328 # We use Min so that sup is meaningful in combination with symbolic
1329 # interval end points.
1330 return Min(*[set.inf for set in self.args])
1332 @property
1333 def _sup(self):
1334 # We use Max so that sup is meaningful in combination with symbolic
1335 # end points.
1336 return Max(*[set.sup for set in self.args])
1338 @property
1339 def is_empty(self):
1340 return fuzzy_and(set.is_empty for set in self.args)
1342 @property
1343 def is_finite_set(self):
1344 return fuzzy_and(set.is_finite_set for set in self.args)
1346 @property
1347 def _measure(self):
1348 # Measure of a union is the sum of the measures of the sets minus
1349 # the sum of their pairwise intersections plus the sum of their
1350 # triple-wise intersections minus ... etc...
1352 # Sets is a collection of intersections and a set of elementary
1353 # sets which made up those intersections (called "sos" for set of sets)
1354 # An example element might of this list might be:
1355 # ( {A,B,C}, A.intersect(B).intersect(C) )
1357 # Start with just elementary sets ( ({A}, A), ({B}, B), ... )
1358 # Then get and subtract ( ({A,B}, (A int B), ... ) while non-zero
1359 sets = [(FiniteSet(s), s) for s in self.args]
1360 measure = 0
1361 parity = 1
1362 while sets:
1363 # Add up the measure of these sets and add or subtract it to total
1364 measure += parity * sum(inter.measure for sos, inter in sets)
1366 # For each intersection in sets, compute the intersection with every
1367 # other set not already part of the intersection.
1368 sets = ((sos + FiniteSet(newset), newset.intersect(intersection))
1369 for sos, intersection in sets for newset in self.args
1370 if newset not in sos)
1372 # Clear out sets with no measure
1373 sets = [(sos, inter) for sos, inter in sets if inter.measure != 0]
1375 # Clear out duplicates
1376 sos_list = []
1377 sets_list = []
1378 for _set in sets:
1379 if _set[0] in sos_list:
1380 continue
1381 else:
1382 sos_list.append(_set[0])
1383 sets_list.append(_set)
1384 sets = sets_list
1386 # Flip Parity - next time subtract/add if we added/subtracted here
1387 parity *= -1
1388 return measure
1390 def _kind(self):
1391 kinds = tuple(arg.kind for arg in self.args if arg is not S.EmptySet)
1392 if not kinds:
1393 return SetKind()
1394 elif all(i == kinds[0] for i in kinds):
1395 return kinds[0]
1396 else:
1397 return SetKind(UndefinedKind)
1399 @property
1400 def _boundary(self):
1401 def boundary_of_set(i):
1402 """ The boundary of set i minus interior of all other sets """
1403 b = self.args[i].boundary
1404 for j, a in enumerate(self.args):
1405 if j != i:
1406 b = b - a.interior
1407 return b
1408 return Union(*map(boundary_of_set, range(len(self.args))))
1410 def _contains(self, other):
1411 return Or(*[s.contains(other) for s in self.args])
1413 def is_subset(self, other):
1414 return fuzzy_and(s.is_subset(other) for s in self.args)
1416 def as_relational(self, symbol):
1417 """Rewrite a Union in terms of equalities and logic operators. """
1418 if (len(self.args) == 2 and
1419 all(isinstance(i, Interval) for i in self.args)):
1420 # optimization to give 3 args as (x > 1) & (x < 5) & Ne(x, 3)
1421 # instead of as 4, ((1 <= x) & (x < 3)) | ((x <= 5) & (3 < x))
1422 # XXX: This should be ideally be improved to handle any number of
1423 # intervals and also not to assume that the intervals are in any
1424 # particular sorted order.
1425 a, b = self.args
1426 if a.sup == b.inf and a.right_open and b.left_open:
1427 mincond = symbol > a.inf if a.left_open else symbol >= a.inf
1428 maxcond = symbol < b.sup if b.right_open else symbol <= b.sup
1429 necond = Ne(symbol, a.sup)
1430 return And(necond, mincond, maxcond)
1431 return Or(*[i.as_relational(symbol) for i in self.args])
1433 @property
1434 def is_iterable(self):
1435 return all(arg.is_iterable for arg in self.args)
1437 def __iter__(self):
1438 return roundrobin(*(iter(arg) for arg in self.args))
1441class Intersection(Set, LatticeOp):
1442 """
1443 Represents an intersection of sets as a :class:`Set`.
1445 Examples
1446 ========
1448 >>> from sympy import Intersection, Interval
1449 >>> Intersection(Interval(1, 3), Interval(2, 4))
1450 Interval(2, 3)
1452 We often use the .intersect method
1454 >>> Interval(1,3).intersect(Interval(2,4))
1455 Interval(2, 3)
1457 See Also
1458 ========
1460 Union
1462 References
1463 ==========
1465 .. [1] https://en.wikipedia.org/wiki/Intersection_%28set_theory%29
1466 """
1467 is_Intersection = True
1469 @property
1470 def identity(self):
1471 return S.UniversalSet
1473 @property
1474 def zero(self):
1475 return S.EmptySet
1477 def __new__(cls, *args, **kwargs):
1478 evaluate = kwargs.get('evaluate', global_parameters.evaluate)
1480 # flatten inputs to merge intersections and iterables
1481 args = list(ordered(set(_sympify(args))))
1483 # Reduce sets using known rules
1484 if evaluate:
1485 args = list(cls._new_args_filter(args))
1486 return simplify_intersection(args)
1488 args = list(ordered(args, Set._infimum_key))
1490 obj = Basic.__new__(cls, *args)
1491 obj._argset = frozenset(args)
1492 return obj
1494 @property
1495 def args(self):
1496 return self._args
1498 @property
1499 def is_iterable(self):
1500 return any(arg.is_iterable for arg in self.args)
1502 @property
1503 def is_finite_set(self):
1504 if fuzzy_or(arg.is_finite_set for arg in self.args):
1505 return True
1507 def _kind(self):
1508 kinds = tuple(arg.kind for arg in self.args if arg is not S.UniversalSet)
1509 if not kinds:
1510 return SetKind(UndefinedKind)
1511 elif all(i == kinds[0] for i in kinds):
1512 return kinds[0]
1513 else:
1514 return SetKind()
1516 @property
1517 def _inf(self):
1518 raise NotImplementedError()
1520 @property
1521 def _sup(self):
1522 raise NotImplementedError()
1524 def _contains(self, other):
1525 return And(*[set.contains(other) for set in self.args])
1527 def __iter__(self):
1528 sets_sift = sift(self.args, lambda x: x.is_iterable)
1530 completed = False
1531 candidates = sets_sift[True] + sets_sift[None]
1533 finite_candidates, others = [], []
1534 for candidate in candidates:
1535 length = None
1536 try:
1537 length = len(candidate)
1538 except TypeError:
1539 others.append(candidate)
1541 if length is not None:
1542 finite_candidates.append(candidate)
1543 finite_candidates.sort(key=len)
1545 for s in finite_candidates + others:
1546 other_sets = set(self.args) - {s}
1547 other = Intersection(*other_sets, evaluate=False)
1548 completed = True
1549 for x in s:
1550 try:
1551 if x in other:
1552 yield x
1553 except TypeError:
1554 completed = False
1555 if completed:
1556 return
1558 if not completed:
1559 if not candidates:
1560 raise TypeError("None of the constituent sets are iterable")
1561 raise TypeError(
1562 "The computation had not completed because of the "
1563 "undecidable set membership is found in every candidates.")
1565 @staticmethod
1566 def _handle_finite_sets(args):
1567 '''Simplify intersection of one or more FiniteSets and other sets'''
1569 # First separate the FiniteSets from the others
1570 fs_args, others = sift(args, lambda x: x.is_FiniteSet, binary=True)
1572 # Let the caller handle intersection of non-FiniteSets
1573 if not fs_args:
1574 return
1576 # Convert to Python sets and build the set of all elements
1577 fs_sets = [set(fs) for fs in fs_args]
1578 all_elements = reduce(lambda a, b: a | b, fs_sets, set())
1580 # Extract elements that are definitely in or definitely not in the
1581 # intersection. Here we check contains for all of args.
1582 definite = set()
1583 for e in all_elements:
1584 inall = fuzzy_and(s.contains(e) for s in args)
1585 if inall is True:
1586 definite.add(e)
1587 if inall is not None:
1588 for s in fs_sets:
1589 s.discard(e)
1591 # At this point all elements in all of fs_sets are possibly in the
1592 # intersection. In some cases this is because they are definitely in
1593 # the intersection of the finite sets but it's not clear if they are
1594 # members of others. We might have {m, n}, {m}, and Reals where we
1595 # don't know if m or n is real. We want to remove n here but it is
1596 # possibly in because it might be equal to m. So what we do now is
1597 # extract the elements that are definitely in the remaining finite
1598 # sets iteratively until we end up with {n}, {}. At that point if we
1599 # get any empty set all remaining elements are discarded.
1601 fs_elements = reduce(lambda a, b: a | b, fs_sets, set())
1603 # Need fuzzy containment testing
1604 fs_symsets = [FiniteSet(*s) for s in fs_sets]
1606 while fs_elements:
1607 for e in fs_elements:
1608 infs = fuzzy_and(s.contains(e) for s in fs_symsets)
1609 if infs is True:
1610 definite.add(e)
1611 if infs is not None:
1612 for n, s in enumerate(fs_sets):
1613 # Update Python set and FiniteSet
1614 if e in s:
1615 s.remove(e)
1616 fs_symsets[n] = FiniteSet(*s)
1617 fs_elements.remove(e)
1618 break
1619 # If we completed the for loop without removing anything we are
1620 # done so quit the outer while loop
1621 else:
1622 break
1624 # If any of the sets of remainder elements is empty then we discard
1625 # all of them for the intersection.
1626 if not all(fs_sets):
1627 fs_sets = [set()]
1629 # Here we fold back the definitely included elements into each fs.
1630 # Since they are definitely included they must have been members of
1631 # each FiniteSet to begin with. We could instead fold these in with a
1632 # Union at the end to get e.g. {3}|({x}&{y}) rather than {3,x}&{3,y}.
1633 if definite:
1634 fs_sets = [fs | definite for fs in fs_sets]
1636 if fs_sets == [set()]:
1637 return S.EmptySet
1639 sets = [FiniteSet(*s) for s in fs_sets]
1641 # Any set in others is redundant if it contains all the elements that
1642 # are in the finite sets so we don't need it in the Intersection
1643 all_elements = reduce(lambda a, b: a | b, fs_sets, set())
1644 is_redundant = lambda o: all(fuzzy_bool(o.contains(e)) for e in all_elements)
1645 others = [o for o in others if not is_redundant(o)]
1647 if others:
1648 rest = Intersection(*others)
1649 # XXX: Maybe this shortcut should be at the beginning. For large
1650 # FiniteSets it could much more efficient to process the other
1651 # sets first...
1652 if rest is S.EmptySet:
1653 return S.EmptySet
1654 # Flatten the Intersection
1655 if rest.is_Intersection:
1656 sets.extend(rest.args)
1657 else:
1658 sets.append(rest)
1660 if len(sets) == 1:
1661 return sets[0]
1662 else:
1663 return Intersection(*sets, evaluate=False)
1665 def as_relational(self, symbol):
1666 """Rewrite an Intersection in terms of equalities and logic operators"""
1667 return And(*[set.as_relational(symbol) for set in self.args])
1670class Complement(Set):
1671 r"""Represents the set difference or relative complement of a set with
1672 another set.
1674 $$A - B = \{x \in A \mid x \notin B\}$$
1677 Examples
1678 ========
1680 >>> from sympy import Complement, FiniteSet
1681 >>> Complement(FiniteSet(0, 1, 2), FiniteSet(1))
1682 {0, 2}
1684 See Also
1685 =========
1687 Intersection, Union
1689 References
1690 ==========
1692 .. [1] https://mathworld.wolfram.com/ComplementSet.html
1693 """
1695 is_Complement = True
1697 def __new__(cls, a, b, evaluate=True):
1698 a, b = map(_sympify, (a, b))
1699 if evaluate:
1700 return Complement.reduce(a, b)
1702 return Basic.__new__(cls, a, b)
1704 @staticmethod
1705 def reduce(A, B):
1706 """
1707 Simplify a :class:`Complement`.
1709 """
1710 if B == S.UniversalSet or A.is_subset(B):
1711 return S.EmptySet
1713 if isinstance(B, Union):
1714 return Intersection(*(s.complement(A) for s in B.args))
1716 result = B._complement(A)
1717 if result is not None:
1718 return result
1719 else:
1720 return Complement(A, B, evaluate=False)
1722 def _contains(self, other):
1723 A = self.args[0]
1724 B = self.args[1]
1725 return And(A.contains(other), Not(B.contains(other)))
1727 def as_relational(self, symbol):
1728 """Rewrite a complement in terms of equalities and logic
1729 operators"""
1730 A, B = self.args
1732 A_rel = A.as_relational(symbol)
1733 B_rel = Not(B.as_relational(symbol))
1735 return And(A_rel, B_rel)
1737 def _kind(self):
1738 return self.args[0].kind
1740 @property
1741 def is_iterable(self):
1742 if self.args[0].is_iterable:
1743 return True
1745 @property
1746 def is_finite_set(self):
1747 A, B = self.args
1748 a_finite = A.is_finite_set
1749 if a_finite is True:
1750 return True
1751 elif a_finite is False and B.is_finite_set:
1752 return False
1754 def __iter__(self):
1755 A, B = self.args
1756 for a in A:
1757 if a not in B:
1758 yield a
1759 else:
1760 continue
1763class EmptySet(Set, metaclass=Singleton):
1764 """
1765 Represents the empty set. The empty set is available as a singleton
1766 as ``S.EmptySet``.
1768 Examples
1769 ========
1771 >>> from sympy import S, Interval
1772 >>> S.EmptySet
1773 EmptySet
1775 >>> Interval(1, 2).intersect(S.EmptySet)
1776 EmptySet
1778 See Also
1779 ========
1781 UniversalSet
1783 References
1784 ==========
1786 .. [1] https://en.wikipedia.org/wiki/Empty_set
1787 """
1788 is_empty = True
1789 is_finite_set = True
1790 is_FiniteSet = True
1792 @property # type: ignore
1793 @deprecated(
1794 """
1795 The is_EmptySet attribute of Set objects is deprecated.
1796 Use 's is S.EmptySet" or 's.is_empty' instead.
1797 """,
1798 deprecated_since_version="1.5",
1799 active_deprecations_target="deprecated-is-emptyset",
1800 )
1801 def is_EmptySet(self):
1802 return True
1804 @property
1805 def _measure(self):
1806 return 0
1808 def _contains(self, other):
1809 return false
1811 def as_relational(self, symbol):
1812 return false
1814 def __len__(self):
1815 return 0
1817 def __iter__(self):
1818 return iter([])
1820 def _eval_powerset(self):
1821 return FiniteSet(self)
1823 @property
1824 def _boundary(self):
1825 return self
1827 def _complement(self, other):
1828 return other
1830 def _kind(self):
1831 return SetKind()
1833 def _symmetric_difference(self, other):
1834 return other
1837class UniversalSet(Set, metaclass=Singleton):
1838 """
1839 Represents the set of all things.
1840 The universal set is available as a singleton as ``S.UniversalSet``.
1842 Examples
1843 ========
1845 >>> from sympy import S, Interval
1846 >>> S.UniversalSet
1847 UniversalSet
1849 >>> Interval(1, 2).intersect(S.UniversalSet)
1850 Interval(1, 2)
1852 See Also
1853 ========
1855 EmptySet
1857 References
1858 ==========
1860 .. [1] https://en.wikipedia.org/wiki/Universal_set
1861 """
1863 is_UniversalSet = True
1864 is_empty = False
1865 is_finite_set = False
1867 def _complement(self, other):
1868 return S.EmptySet
1870 def _symmetric_difference(self, other):
1871 return other
1873 @property
1874 def _measure(self):
1875 return S.Infinity
1877 def _kind(self):
1878 return SetKind(UndefinedKind)
1880 def _contains(self, other):
1881 return true
1883 def as_relational(self, symbol):
1884 return true
1886 @property
1887 def _boundary(self):
1888 return S.EmptySet
1891class FiniteSet(Set):
1892 """
1893 Represents a finite set of Sympy expressions.
1895 Examples
1896 ========
1898 >>> from sympy import FiniteSet, Symbol, Interval, Naturals0
1899 >>> FiniteSet(1, 2, 3, 4)
1900 {1, 2, 3, 4}
1901 >>> 3 in FiniteSet(1, 2, 3, 4)
1902 True
1903 >>> FiniteSet(1, (1, 2), Symbol('x'))
1904 {1, x, (1, 2)}
1905 >>> FiniteSet(Interval(1, 2), Naturals0, {1, 2})
1906 FiniteSet({1, 2}, Interval(1, 2), Naturals0)
1907 >>> members = [1, 2, 3, 4]
1908 >>> f = FiniteSet(*members)
1909 >>> f
1910 {1, 2, 3, 4}
1911 >>> f - FiniteSet(2)
1912 {1, 3, 4}
1913 >>> f + FiniteSet(2, 5)
1914 {1, 2, 3, 4, 5}
1916 References
1917 ==========
1919 .. [1] https://en.wikipedia.org/wiki/Finite_set
1920 """
1921 is_FiniteSet = True
1922 is_iterable = True
1923 is_empty = False
1924 is_finite_set = True
1926 def __new__(cls, *args, **kwargs):
1927 evaluate = kwargs.get('evaluate', global_parameters.evaluate)
1928 if evaluate:
1929 args = list(map(sympify, args))
1931 if len(args) == 0:
1932 return S.EmptySet
1933 else:
1934 args = list(map(sympify, args))
1936 # keep the form of the first canonical arg
1937 dargs = {}
1938 for i in reversed(list(ordered(args))):
1939 if i.is_Symbol:
1940 dargs[i] = i
1941 else:
1942 try:
1943 dargs[i.as_dummy()] = i
1944 except TypeError:
1945 # e.g. i = class without args like `Interval`
1946 dargs[i] = i
1947 _args_set = set(dargs.values())
1948 args = list(ordered(_args_set, Set._infimum_key))
1949 obj = Basic.__new__(cls, *args)
1950 obj._args_set = _args_set
1951 return obj
1954 def __iter__(self):
1955 return iter(self.args)
1957 def _complement(self, other):
1958 if isinstance(other, Interval):
1959 # Splitting in sub-intervals is only done for S.Reals;
1960 # other cases that need splitting will first pass through
1961 # Set._complement().
1962 nums, syms = [], []
1963 for m in self.args:
1964 if m.is_number and m.is_real:
1965 nums.append(m)
1966 elif m.is_real == False:
1967 pass # drop non-reals
1968 else:
1969 syms.append(m) # various symbolic expressions
1970 if other == S.Reals and nums != []:
1971 nums.sort()
1972 intervals = [] # Build up a list of intervals between the elements
1973 intervals += [Interval(S.NegativeInfinity, nums[0], True, True)]
1974 for a, b in zip(nums[:-1], nums[1:]):
1975 intervals.append(Interval(a, b, True, True)) # both open
1976 intervals.append(Interval(nums[-1], S.Infinity, True, True))
1977 if syms != []:
1978 return Complement(Union(*intervals, evaluate=False),
1979 FiniteSet(*syms), evaluate=False)
1980 else:
1981 return Union(*intervals, evaluate=False)
1982 elif nums == []: # no splitting necessary or possible:
1983 if syms:
1984 return Complement(other, FiniteSet(*syms), evaluate=False)
1985 else:
1986 return other
1988 elif isinstance(other, FiniteSet):
1989 unk = []
1990 for i in self:
1991 c = sympify(other.contains(i))
1992 if c is not S.true and c is not S.false:
1993 unk.append(i)
1994 unk = FiniteSet(*unk)
1995 if unk == self:
1996 return
1997 not_true = []
1998 for i in other:
1999 c = sympify(self.contains(i))
2000 if c is not S.true:
2001 not_true.append(i)
2002 return Complement(FiniteSet(*not_true), unk)
2004 return Set._complement(self, other)
2006 def _contains(self, other):
2007 """
2008 Tests whether an element, other, is in the set.
2010 Explanation
2011 ===========
2013 The actual test is for mathematical equality (as opposed to
2014 syntactical equality). In the worst case all elements of the
2015 set must be checked.
2017 Examples
2018 ========
2020 >>> from sympy import FiniteSet
2021 >>> 1 in FiniteSet(1, 2)
2022 True
2023 >>> 5 in FiniteSet(1, 2)
2024 False
2026 """
2027 if other in self._args_set:
2028 return True
2029 else:
2030 # evaluate=True is needed to override evaluate=False context;
2031 # we need Eq to do the evaluation
2032 return fuzzy_or(fuzzy_bool(Eq(e, other, evaluate=True))
2033 for e in self.args)
2035 def _eval_is_subset(self, other):
2036 return fuzzy_and(other._contains(e) for e in self.args)
2038 @property
2039 def _boundary(self):
2040 return self
2042 @property
2043 def _inf(self):
2044 return Min(*self)
2046 @property
2047 def _sup(self):
2048 return Max(*self)
2050 @property
2051 def measure(self):
2052 return 0
2054 def _kind(self):
2055 if not self.args:
2056 return SetKind()
2057 elif all(i.kind == self.args[0].kind for i in self.args):
2058 return SetKind(self.args[0].kind)
2059 else:
2060 return SetKind(UndefinedKind)
2062 def __len__(self):
2063 return len(self.args)
2065 def as_relational(self, symbol):
2066 """Rewrite a FiniteSet in terms of equalities and logic operators. """
2067 return Or(*[Eq(symbol, elem) for elem in self])
2069 def compare(self, other):
2070 return (hash(self) - hash(other))
2072 def _eval_evalf(self, prec):
2073 dps = prec_to_dps(prec)
2074 return FiniteSet(*[elem.evalf(n=dps) for elem in self])
2076 def _eval_simplify(self, **kwargs):
2077 from sympy.simplify import simplify
2078 return FiniteSet(*[simplify(elem, **kwargs) for elem in self])
2080 @property
2081 def _sorted_args(self):
2082 return self.args
2084 def _eval_powerset(self):
2085 return self.func(*[self.func(*s) for s in subsets(self.args)])
2087 def _eval_rewrite_as_PowerSet(self, *args, **kwargs):
2088 """Rewriting method for a finite set to a power set."""
2089 from .powerset import PowerSet
2091 is2pow = lambda n: bool(n and not n & (n - 1))
2092 if not is2pow(len(self)):
2093 return None
2095 fs_test = lambda arg: isinstance(arg, Set) and arg.is_FiniteSet
2096 if not all(fs_test(arg) for arg in args):
2097 return None
2099 biggest = max(args, key=len)
2100 for arg in subsets(biggest.args):
2101 arg_set = FiniteSet(*arg)
2102 if arg_set not in args:
2103 return None
2104 return PowerSet(biggest)
2106 def __ge__(self, other):
2107 if not isinstance(other, Set):
2108 raise TypeError("Invalid comparison of set with %s" % func_name(other))
2109 return other.is_subset(self)
2111 def __gt__(self, other):
2112 if not isinstance(other, Set):
2113 raise TypeError("Invalid comparison of set with %s" % func_name(other))
2114 return self.is_proper_superset(other)
2116 def __le__(self, other):
2117 if not isinstance(other, Set):
2118 raise TypeError("Invalid comparison of set with %s" % func_name(other))
2119 return self.is_subset(other)
2121 def __lt__(self, other):
2122 if not isinstance(other, Set):
2123 raise TypeError("Invalid comparison of set with %s" % func_name(other))
2124 return self.is_proper_subset(other)
2126 def __eq__(self, other):
2127 if isinstance(other, (set, frozenset)):
2128 return self._args_set == other
2129 return super().__eq__(other)
2131 __hash__ : Callable[[Basic], Any] = Basic.__hash__
2133_sympy_converter[set] = lambda x: FiniteSet(*x)
2134_sympy_converter[frozenset] = lambda x: FiniteSet(*x)
2137class SymmetricDifference(Set):
2138 """Represents the set of elements which are in either of the
2139 sets and not in their intersection.
2141 Examples
2142 ========
2144 >>> from sympy import SymmetricDifference, FiniteSet
2145 >>> SymmetricDifference(FiniteSet(1, 2, 3), FiniteSet(3, 4, 5))
2146 {1, 2, 4, 5}
2148 See Also
2149 ========
2151 Complement, Union
2153 References
2154 ==========
2156 .. [1] https://en.wikipedia.org/wiki/Symmetric_difference
2157 """
2159 is_SymmetricDifference = True
2161 def __new__(cls, a, b, evaluate=True):
2162 if evaluate:
2163 return SymmetricDifference.reduce(a, b)
2165 return Basic.__new__(cls, a, b)
2167 @staticmethod
2168 def reduce(A, B):
2169 result = B._symmetric_difference(A)
2170 if result is not None:
2171 return result
2172 else:
2173 return SymmetricDifference(A, B, evaluate=False)
2175 def as_relational(self, symbol):
2176 """Rewrite a symmetric_difference in terms of equalities and
2177 logic operators"""
2178 A, B = self.args
2180 A_rel = A.as_relational(symbol)
2181 B_rel = B.as_relational(symbol)
2183 return Xor(A_rel, B_rel)
2185 @property
2186 def is_iterable(self):
2187 if all(arg.is_iterable for arg in self.args):
2188 return True
2190 def __iter__(self):
2192 args = self.args
2193 union = roundrobin(*(iter(arg) for arg in args))
2195 for item in union:
2196 count = 0
2197 for s in args:
2198 if item in s:
2199 count += 1
2201 if count % 2 == 1:
2202 yield item
2206class DisjointUnion(Set):
2207 """ Represents the disjoint union (also known as the external disjoint union)
2208 of a finite number of sets.
2210 Examples
2211 ========
2213 >>> from sympy import DisjointUnion, FiniteSet, Interval, Union, Symbol
2214 >>> A = FiniteSet(1, 2, 3)
2215 >>> B = Interval(0, 5)
2216 >>> DisjointUnion(A, B)
2217 DisjointUnion({1, 2, 3}, Interval(0, 5))
2218 >>> DisjointUnion(A, B).rewrite(Union)
2219 Union(ProductSet({1, 2, 3}, {0}), ProductSet(Interval(0, 5), {1}))
2220 >>> C = FiniteSet(Symbol('x'), Symbol('y'), Symbol('z'))
2221 >>> DisjointUnion(C, C)
2222 DisjointUnion({x, y, z}, {x, y, z})
2223 >>> DisjointUnion(C, C).rewrite(Union)
2224 ProductSet({x, y, z}, {0, 1})
2226 References
2227 ==========
2229 https://en.wikipedia.org/wiki/Disjoint_union
2230 """
2232 def __new__(cls, *sets):
2233 dj_collection = []
2234 for set_i in sets:
2235 if isinstance(set_i, Set):
2236 dj_collection.append(set_i)
2237 else:
2238 raise TypeError("Invalid input: '%s', input args \
2239 to DisjointUnion must be Sets" % set_i)
2240 obj = Basic.__new__(cls, *dj_collection)
2241 return obj
2243 @property
2244 def sets(self):
2245 return self.args
2247 @property
2248 def is_empty(self):
2249 return fuzzy_and(s.is_empty for s in self.sets)
2251 @property
2252 def is_finite_set(self):
2253 all_finite = fuzzy_and(s.is_finite_set for s in self.sets)
2254 return fuzzy_or([self.is_empty, all_finite])
2256 @property
2257 def is_iterable(self):
2258 if self.is_empty:
2259 return False
2260 iter_flag = True
2261 for set_i in self.sets:
2262 if not set_i.is_empty:
2263 iter_flag = iter_flag and set_i.is_iterable
2264 return iter_flag
2266 def _eval_rewrite_as_Union(self, *sets):
2267 """
2268 Rewrites the disjoint union as the union of (``set`` x {``i``})
2269 where ``set`` is the element in ``sets`` at index = ``i``
2270 """
2272 dj_union = S.EmptySet
2273 index = 0
2274 for set_i in sets:
2275 if isinstance(set_i, Set):
2276 cross = ProductSet(set_i, FiniteSet(index))
2277 dj_union = Union(dj_union, cross)
2278 index = index + 1
2279 return dj_union
2281 def _contains(self, element):
2282 """
2283 ``in`` operator for DisjointUnion
2285 Examples
2286 ========
2288 >>> from sympy import Interval, DisjointUnion
2289 >>> D = DisjointUnion(Interval(0, 1), Interval(0, 2))
2290 >>> (0.5, 0) in D
2291 True
2292 >>> (0.5, 1) in D
2293 True
2294 >>> (1.5, 0) in D
2295 False
2296 >>> (1.5, 1) in D
2297 True
2299 Passes operation on to constituent sets
2300 """
2301 if not isinstance(element, Tuple) or len(element) != 2:
2302 return False
2304 if not element[1].is_Integer:
2305 return False
2307 if element[1] >= len(self.sets) or element[1] < 0:
2308 return False
2310 return element[0] in self.sets[element[1]]
2312 def _kind(self):
2313 if not self.args:
2314 return SetKind()
2315 elif all(i.kind == self.args[0].kind for i in self.args):
2316 return self.args[0].kind
2317 else:
2318 return SetKind(UndefinedKind)
2320 def __iter__(self):
2321 if self.is_iterable:
2323 iters = []
2324 for i, s in enumerate(self.sets):
2325 iters.append(iproduct(s, {Integer(i)}))
2327 return iter(roundrobin(*iters))
2328 else:
2329 raise ValueError("'%s' is not iterable." % self)
2331 def __len__(self):
2332 """
2333 Returns the length of the disjoint union, i.e., the number of elements in the set.
2335 Examples
2336 ========
2338 >>> from sympy import FiniteSet, DisjointUnion, EmptySet
2339 >>> D1 = DisjointUnion(FiniteSet(1, 2, 3, 4), EmptySet, FiniteSet(3, 4, 5))
2340 >>> len(D1)
2341 7
2342 >>> D2 = DisjointUnion(FiniteSet(3, 5, 7), EmptySet, FiniteSet(3, 5, 7))
2343 >>> len(D2)
2344 6
2345 >>> D3 = DisjointUnion(EmptySet, EmptySet)
2346 >>> len(D3)
2347 0
2349 Adds up the lengths of the constituent sets.
2350 """
2352 if self.is_finite_set:
2353 size = 0
2354 for set in self.sets:
2355 size += len(set)
2356 return size
2357 else:
2358 raise ValueError("'%s' is not a finite set." % self)
2361def imageset(*args):
2362 r"""
2363 Return an image of the set under transformation ``f``.
2365 Explanation
2366 ===========
2368 If this function cannot compute the image, it returns an
2369 unevaluated ImageSet object.
2371 .. math::
2372 \{ f(x) \mid x \in \mathrm{self} \}
2374 Examples
2375 ========
2377 >>> from sympy import S, Interval, imageset, sin, Lambda
2378 >>> from sympy.abc import x
2380 >>> imageset(x, 2*x, Interval(0, 2))
2381 Interval(0, 4)
2383 >>> imageset(lambda x: 2*x, Interval(0, 2))
2384 Interval(0, 4)
2386 >>> imageset(Lambda(x, sin(x)), Interval(-2, 1))
2387 ImageSet(Lambda(x, sin(x)), Interval(-2, 1))
2389 >>> imageset(sin, Interval(-2, 1))
2390 ImageSet(Lambda(x, sin(x)), Interval(-2, 1))
2391 >>> imageset(lambda y: x + y, Interval(-2, 1))
2392 ImageSet(Lambda(y, x + y), Interval(-2, 1))
2394 Expressions applied to the set of Integers are simplified
2395 to show as few negatives as possible and linear expressions
2396 are converted to a canonical form. If this is not desirable
2397 then the unevaluated ImageSet should be used.
2399 >>> imageset(x, -2*x + 5, S.Integers)
2400 ImageSet(Lambda(x, 2*x + 1), Integers)
2402 See Also
2403 ========
2405 sympy.sets.fancysets.ImageSet
2407 """
2408 from .fancysets import ImageSet
2409 from .setexpr import set_function
2411 if len(args) < 2:
2412 raise ValueError('imageset expects at least 2 args, got: %s' % len(args))
2414 if isinstance(args[0], (Symbol, tuple)) and len(args) > 2:
2415 f = Lambda(args[0], args[1])
2416 set_list = args[2:]
2417 else:
2418 f = args[0]
2419 set_list = args[1:]
2421 if isinstance(f, Lambda):
2422 pass
2423 elif callable(f):
2424 nargs = getattr(f, 'nargs', {})
2425 if nargs:
2426 if len(nargs) != 1:
2427 raise NotImplementedError(filldedent('''
2428 This function can take more than 1 arg
2429 but the potentially complicated set input
2430 has not been analyzed at this point to
2431 know its dimensions. TODO
2432 '''))
2433 N = nargs.args[0]
2434 if N == 1:
2435 s = 'x'
2436 else:
2437 s = [Symbol('x%i' % i) for i in range(1, N + 1)]
2438 else:
2439 s = inspect.signature(f).parameters
2441 dexpr = _sympify(f(*[Dummy() for i in s]))
2442 var = tuple(uniquely_named_symbol(
2443 Symbol(i), dexpr) for i in s)
2444 f = Lambda(var, f(*var))
2445 else:
2446 raise TypeError(filldedent('''
2447 expecting lambda, Lambda, or FunctionClass,
2448 not \'%s\'.''' % func_name(f)))
2450 if any(not isinstance(s, Set) for s in set_list):
2451 name = [func_name(s) for s in set_list]
2452 raise ValueError(
2453 'arguments after mapping should be sets, not %s' % name)
2455 if len(set_list) == 1:
2456 set = set_list[0]
2457 try:
2458 # TypeError if arg count != set dimensions
2459 r = set_function(f, set)
2460 if r is None:
2461 raise TypeError
2462 if not r:
2463 return r
2464 except TypeError:
2465 r = ImageSet(f, set)
2466 if isinstance(r, ImageSet):
2467 f, set = r.args
2469 if f.variables[0] == f.expr:
2470 return set
2472 if isinstance(set, ImageSet):
2473 # XXX: Maybe this should just be:
2474 # f2 = set.lambda
2475 # fun = Lambda(f2.signature, f(*f2.expr))
2476 # return imageset(fun, *set.base_sets)
2477 if len(set.lamda.variables) == 1 and len(f.variables) == 1:
2478 x = set.lamda.variables[0]
2479 y = f.variables[0]
2480 return imageset(
2481 Lambda(x, f.expr.subs(y, set.lamda.expr)), *set.base_sets)
2483 if r is not None:
2484 return r
2486 return ImageSet(f, *set_list)
2489def is_function_invertible_in_set(func, setv):
2490 """
2491 Checks whether function ``func`` is invertible when the domain is
2492 restricted to set ``setv``.
2493 """
2494 # Functions known to always be invertible:
2495 if func in (exp, log):
2496 return True
2497 u = Dummy("u")
2498 fdiff = func(u).diff(u)
2499 # monotonous functions:
2500 # TODO: check subsets (`func` in `setv`)
2501 if (fdiff > 0) == True or (fdiff < 0) == True:
2502 return True
2503 # TODO: support more
2504 return None
2507def simplify_union(args):
2508 """
2509 Simplify a :class:`Union` using known rules.
2511 Explanation
2512 ===========
2514 We first start with global rules like 'Merge all FiniteSets'
2516 Then we iterate through all pairs and ask the constituent sets if they
2517 can simplify themselves with any other constituent. This process depends
2518 on ``union_sets(a, b)`` functions.
2519 """
2520 from sympy.sets.handlers.union import union_sets
2522 # ===== Global Rules =====
2523 if not args:
2524 return S.EmptySet
2526 for arg in args:
2527 if not isinstance(arg, Set):
2528 raise TypeError("Input args to Union must be Sets")
2530 # Merge all finite sets
2531 finite_sets = [x for x in args if x.is_FiniteSet]
2532 if len(finite_sets) > 1:
2533 a = (x for set in finite_sets for x in set)
2534 finite_set = FiniteSet(*a)
2535 args = [finite_set] + [x for x in args if not x.is_FiniteSet]
2537 # ===== Pair-wise Rules =====
2538 # Here we depend on rules built into the constituent sets
2539 args = set(args)
2540 new_args = True
2541 while new_args:
2542 for s in args:
2543 new_args = False
2544 for t in args - {s}:
2545 new_set = union_sets(s, t)
2546 # This returns None if s does not know how to intersect
2547 # with t. Returns the newly intersected set otherwise
2548 if new_set is not None:
2549 if not isinstance(new_set, set):
2550 new_set = {new_set}
2551 new_args = (args - {s, t}).union(new_set)
2552 break
2553 if new_args:
2554 args = new_args
2555 break
2557 if len(args) == 1:
2558 return args.pop()
2559 else:
2560 return Union(*args, evaluate=False)
2563def simplify_intersection(args):
2564 """
2565 Simplify an intersection using known rules.
2567 Explanation
2568 ===========
2570 We first start with global rules like
2571 'if any empty sets return empty set' and 'distribute any unions'
2573 Then we iterate through all pairs and ask the constituent sets if they
2574 can simplify themselves with any other constituent
2575 """
2577 # ===== Global Rules =====
2578 if not args:
2579 return S.UniversalSet
2581 for arg in args:
2582 if not isinstance(arg, Set):
2583 raise TypeError("Input args to Union must be Sets")
2585 # If any EmptySets return EmptySet
2586 if S.EmptySet in args:
2587 return S.EmptySet
2589 # Handle Finite sets
2590 rv = Intersection._handle_finite_sets(args)
2592 if rv is not None:
2593 return rv
2595 # If any of the sets are unions, return a Union of Intersections
2596 for s in args:
2597 if s.is_Union:
2598 other_sets = set(args) - {s}
2599 if len(other_sets) > 0:
2600 other = Intersection(*other_sets)
2601 return Union(*(Intersection(arg, other) for arg in s.args))
2602 else:
2603 return Union(*s.args)
2605 for s in args:
2606 if s.is_Complement:
2607 args.remove(s)
2608 other_sets = args + [s.args[0]]
2609 return Complement(Intersection(*other_sets), s.args[1])
2611 from sympy.sets.handlers.intersection import intersection_sets
2613 # At this stage we are guaranteed not to have any
2614 # EmptySets, FiniteSets, or Unions in the intersection
2616 # ===== Pair-wise Rules =====
2617 # Here we depend on rules built into the constituent sets
2618 args = set(args)
2619 new_args = True
2620 while new_args:
2621 for s in args:
2622 new_args = False
2623 for t in args - {s}:
2624 new_set = intersection_sets(s, t)
2625 # This returns None if s does not know how to intersect
2626 # with t. Returns the newly intersected set otherwise
2628 if new_set is not None:
2629 new_args = (args - {s, t}).union({new_set})
2630 break
2631 if new_args:
2632 args = new_args
2633 break
2635 if len(args) == 1:
2636 return args.pop()
2637 else:
2638 return Intersection(*args, evaluate=False)
2641def _handle_finite_sets(op, x, y, commutative):
2642 # Handle finite sets:
2643 fs_args, other = sift([x, y], lambda x: isinstance(x, FiniteSet), binary=True)
2644 if len(fs_args) == 2:
2645 return FiniteSet(*[op(i, j) for i in fs_args[0] for j in fs_args[1]])
2646 elif len(fs_args) == 1:
2647 sets = [_apply_operation(op, other[0], i, commutative) for i in fs_args[0]]
2648 return Union(*sets)
2649 else:
2650 return None
2653def _apply_operation(op, x, y, commutative):
2654 from .fancysets import ImageSet
2655 d = Dummy('d')
2657 out = _handle_finite_sets(op, x, y, commutative)
2658 if out is None:
2659 out = op(x, y)
2661 if out is None and commutative:
2662 out = op(y, x)
2663 if out is None:
2664 _x, _y = symbols("x y")
2665 if isinstance(x, Set) and not isinstance(y, Set):
2666 out = ImageSet(Lambda(d, op(d, y)), x).doit()
2667 elif not isinstance(x, Set) and isinstance(y, Set):
2668 out = ImageSet(Lambda(d, op(x, d)), y).doit()
2669 else:
2670 out = ImageSet(Lambda((_x, _y), op(_x, _y)), x, y)
2671 return out
2674def set_add(x, y):
2675 from sympy.sets.handlers.add import _set_add
2676 return _apply_operation(_set_add, x, y, commutative=True)
2679def set_sub(x, y):
2680 from sympy.sets.handlers.add import _set_sub
2681 return _apply_operation(_set_sub, x, y, commutative=False)
2684def set_mul(x, y):
2685 from sympy.sets.handlers.mul import _set_mul
2686 return _apply_operation(_set_mul, x, y, commutative=True)
2689def set_div(x, y):
2690 from sympy.sets.handlers.mul import _set_div
2691 return _apply_operation(_set_div, x, y, commutative=False)
2694def set_pow(x, y):
2695 from sympy.sets.handlers.power import _set_pow
2696 return _apply_operation(_set_pow, x, y, commutative=False)
2699def set_function(f, x):
2700 from sympy.sets.handlers.functions import _set_function
2701 return _set_function(f, x)
2704class SetKind(Kind):
2705 """
2706 SetKind is kind for all Sets
2708 Every instance of Set will have kind ``SetKind`` parametrised by the kind
2709 of the elements of the ``Set``. The kind of the elements might be
2710 ``NumberKind``, or ``TupleKind`` or something else. When not all elements
2711 have the same kind then the kind of the elements will be given as
2712 ``UndefinedKind``.
2714 Parameters
2715 ==========
2717 element_kind: Kind (optional)
2718 The kind of the elements of the set. In a well defined set all elements
2719 will have the same kind. Otherwise the kind should
2720 :class:`sympy.core.kind.UndefinedKind`. The ``element_kind`` argument is optional but
2721 should only be omitted in the case of ``EmptySet`` whose kind is simply
2722 ``SetKind()``
2724 Examples
2725 ========
2727 >>> from sympy import Interval
2728 >>> Interval(1, 2).kind
2729 SetKind(NumberKind)
2730 >>> Interval(1,2).kind.element_kind
2731 NumberKind
2733 See Also
2734 ========
2736 sympy.core.kind.NumberKind
2737 sympy.matrices.common.MatrixKind
2738 sympy.core.containers.TupleKind
2739 """
2740 def __new__(cls, element_kind=None):
2741 obj = super().__new__(cls, element_kind)
2742 obj.element_kind = element_kind
2743 return obj
2745 def __repr__(self):
2746 if not self.element_kind:
2747 return "SetKind()"
2748 else:
2749 return "SetKind(%s)" % self.element_kind