from basic import Basic
from singleton import Singleton, S
from evalf import EvalfMixin
from numbers import Float, Integer
from sympify import _sympify, sympify, SympifyError
from sympy.mpmath import mpi, mpf
from containers import Tuple
[docs]class Set(Basic):
"""
Represents any kind of set.
Real intervals are represented by the Interval class and unions of sets
by the Union class. The empty set is represented by the EmptySet class
and available as a singleton as S.EmptySet.
"""
[docs] def union(self, other):
"""
Returns the union of 'self' and 'other'. As a shortcut it is possible
to use the '+' operator:
>>> from sympy import Interval, FiniteSet
>>> Interval(0, 1).union(Interval(2, 3))
[0, 1] U [2, 3]
>>> Interval(0, 1) + Interval(2, 3)
[0, 1] U [2, 3]
>>> Interval(1, 2, True, True) + FiniteSet(2, 3)
(1, 2] U {3}
Similarly it is possible to use the '-' operator for set
differences:
>>> Interval(0, 2) - Interval(0, 1)
(1, 2]
>>> Interval(1, 3) - FiniteSet(2)
[1, 2) U (2, 3]
"""
return Union(self, other)
[docs] def intersect(self, other):
"""
Returns the intersection of 'self' and 'other'.
>>> from sympy import Interval
>>> Interval(1, 3).intersect(Interval(1, 2))
[1, 2]
"""
return self._intersect(other)
def _intersect(self, other):
raise NotImplementedError("(%s)._intersect(%s)" % (self, other))
@property
[docs] def complement(self):
"""
The complement of 'self'.
As a shortcut it is possible to use the '~' or '-' operators:
>>> from sympy import Interval
>>> Interval(0, 1).complement
(-oo, 0) U (1, oo)
>>> ~Interval(0, 1)
(-oo, 0) U (1, oo)
>>> -Interval(0, 1)
(-oo, 0) U (1, oo)
"""
return self._complement
@property
def _complement(self):
raise NotImplementedError("(%s)._complement" % self)
@property
[docs] def inf(self):
"""
The infimum of 'self'.
>>> from sympy import Interval, Union
>>> Interval(0, 1).inf
0
>>> Union(Interval(0, 1), Interval(2, 3)).inf
0
"""
return self._inf
@property
def _inf(self):
raise NotImplementedError("(%s)._inf" % self)
@property
[docs] def sup(self):
""" The supremum of 'self'.
>>> from sympy import Interval, Union
>>> Interval(0, 1).sup
1
>>> Union(Interval(0, 1), Interval(2, 3)).sup
3
"""
return self._sup
@property
def _sup(self):
raise NotImplementedError("(%s)._sup" % self)
[docs] def contains(self, other):
"""
Returns True if 'other' is contained in 'self' as an element.
As a shortcut it is possible to use the 'in' operator:
>>> from sympy import Interval
>>> Interval(0, 1).contains(0.5)
True
>>> 0.5 in Interval(0, 1)
True
"""
return self._contains(other)
def _contains(self, other):
raise NotImplementedError("(%s)._contains(%s)" % (self, other))
[docs] def subset(self, other):
"""
Returns True if 'other' is a subset of 'self'.
>>> from sympy import Interval
>>> Interval(0, 1).contains(0)
True
>>> Interval(0, 1, left_open=True).contains(0)
False
"""
if isinstance(other, Set):
return self.intersect(other) == other
else:
raise ValueError("Unknown argument '%s'" % other)
@property
[docs] def measure(self):
"""
The (Lebesgue) measure of 'self'.
>>> from sympy import Interval, Union
>>> Interval(0, 1).measure
1
>>> Union(Interval(0, 1), Interval(2, 3)).measure
2
"""
return self._measure
@property
def _measure(self):
raise NotImplementedError("(%s)._measure" % self)
def __add__(self, other):
return self.union(other)
def __or__(self, other):
return self.union(other)
def __and__(self, other):
return self.intersect(other)
def __mul__(self, other):
return ProductSet(self, other)
def __pow__(self, exp):
if not sympify(exp).is_Integer and exp>=0:
raise ValueError("%s: Exponent must be a positive Integer"%exp)
return ProductSet([self]*exp)
def __sub__(self, other):
return self.intersect(other.complement)
def __neg__(self):
return self.complement
def __invert__(self):
return self.complement
def __contains__(self, other):
result = self.contains(other)
if not isinstance(result, bool):
raise TypeError('contains did not evaluate to a bool: %r' % result)
return result
def _eval_subs(self, old, new):
if self == old:
return new
new_args = []
for arg in self.args:
if arg == old:
new_args.append(new)
elif isinstance(arg, Basic):
new_args.append(arg._eval_subs(old, new))
else:
new_args.append(arg)
return self.__class__(*new_args)
@property
def is_number(self):
return False
@property
def is_real(self):
return False
@property
def is_iterable(self):
return False
@property
def is_interval(self):
return False
@property
def is_FiniteSet(self):
return False
@property
def is_Interval(self):
return False
@property
def is_ProductSet(self):
return False
@property
def is_Union(self):
return False
class RealSet(Set, EvalfMixin):
"""
A set of real values
"""
@property
def is_real(self):
return True
class ProductSet(Set):
"""
Represents a Cartesian Product of Sets.
Usage:
Returns a cartesian product given several sets as either an iterable
or individual arguments.
Can use '*' operator on any sets for convenient shorthand.
Examples:
>>> from sympy import Interval, FiniteSet, ProductSet
>>> I = Interval(0, 5); S = FiniteSet(1, 2, 3)
>>> ProductSet(I, S)
[0, 5] x {1, 2, 3}
>>> (2, 2) in ProductSet(I, S)
True
>>> Interval(0, 1) * Interval(0, 1) # The unit square
[0, 1] x [0, 1]
>>> coin = FiniteSet('H','T')
>>> for pair in coin**2: print pair
(H, H)
(H, T)
(T, H)
(T, T)
Notes:
- Passes most operations down to the argument sets
- Flattens Products of ProductSets
"""
def __new__(cls, *sets, **assumptions):
def flatten(arg):
if isinstance(arg, Set):
if arg.is_ProductSet:
return sum(map(flatten, arg.args), [])
else:
return [arg]
elif is_flattenable(arg):
return sum(map(flatten, arg), [])
raise TypeError("Input must be Sets or iterables of Sets")
sets = flatten(list(sets))
if EmptySet() in sets or len(sets)==0:
return EmptySet()
return Basic.__new__(cls, *sets, **assumptions)
def _contains(self, element):
"""
in operator for ProductSets
>>> from sympy import Interval
>>> (2, 3) in Interval(0, 5) * Interval(0, 5)
True
>>> (10, 10) in Interval(0, 5) * Interval(0, 5)
False
Passes operation on to constitent sets
"""
if len(element) is not len(self.args):
return False
from sympy.logic.boolalg import And
return And(*[set.contains(item) for set,item in zip(self.sets,element)])
def _intersect(self, other):
if other.is_Union:
return Union(self.intersect(set) for set in other.args)
if not other.is_ProductSet:
raise TypeError("%s is not a Product Set."%str(other))
if len(other.args) != len(self.args):
raise ValueError("Sets not the same size Left: %d, Right: %d"
%(len(self.args), len(other.args)))
return ProductSet(a.intersect(b)
for a, b in zip(self.sets, other.sets))
@property
def sets(self):
return self.args
@property
def _complement(self):
# For each set consider it or it's complement
# We need at least one of the sets to be complemented
# Consider all 2^n combinations.
# We can conveniently represent these options easily using a ProductSet
switch_sets = ProductSet(FiniteSet(set, set.complement)
for set in self.sets)
product_sets = (ProductSet(*set) for set in switch_sets)
# Union of all combinations but this one
return Union(p for p in product_sets if p != self)
@property
def is_real(self):
return all(set.is_real for set in self.sets)
@property
def is_iterable(self):
return all(set.is_iterable for set in self.sets)
def __iter__(self):
if self.is_iterable:
from sympy.core.compatibility import product
return product(*self.sets)
else:
raise TypeError("Not all constituent sets are iterable")
@property
def _measure(self):
measure = 1
for set in self.sets:
measure *= set.measure
return measure
@property
def is_ProductSet(self):
return True
class RealSet(Set, EvalfMixin):
"""
A set of real values
"""
@property
def is_real(self):
return True
class CountableSet(Set):
"""
Represents a set of countable numbers such as {1, 2, 3, 4} or {1, 2, 3, ...}
"""
@property
def _measure(self):
return 0
@property
def is_iterable(self):
return True
def __iter__(self):
raise NotImplementedError("Iteration not yet implemented")
[docs]class Interval(RealSet):
"""
Represents a real interval as a Set.
Usage:
Returns an interval with end points "start" and "end".
For left_open=True (default left_open is False) the interval
will be open on the left. Similarly, for right_open=True the interval
will be open on the right.
Examples:
>>> from sympy import Symbol, Interval, sets
>>> Interval(0, 1)
[0, 1]
>>> Interval(0, 1, False, True)
[0, 1)
>>> a = Symbol('a', real=True)
>>> Interval(0, a)
[0, a]
Notes:
- Only real end points are supported
- Interval(a, b) with a > b will return the empty set
- Use the evalf() method to turn an Interval into an mpmath
'mpi' interval instance
"""
def __new__(cls, start, end, left_open=False, right_open=False):
start = _sympify(start)
end = _sympify(end)
# Only allow real intervals (use symbols with 'is_real=True').
if not start.is_real or not end.is_real:
raise ValueError("Only real intervals are supported")
# Make sure that the created interval will be valid.
if end.is_comparable and start.is_comparable:
if end < start:
return S.EmptySet
if end == start and (left_open or right_open):
return S.EmptySet
if end == start and not (left_open or right_open):
return FiniteSet(end)
# Make sure infinite interval end points are open.
if start == S.NegativeInfinity:
left_open = True
if end == S.Infinity:
right_open = True
return Basic.__new__(cls, start, end, left_open, right_open)
@property
[docs] def start(self):
"""
The left end point of 'self'. This property takes the same value as the
'inf' property.
>>> from sympy import Interval
>>> Interval(0, 1).start
0
"""
return self._args[0]
_inf = left = start
@property
[docs] def end(self):
"""
The right end point of 'self'. This property takes the same value as the
'sup' property.
>>> from sympy import Interval
>>> Interval(0, 1).end
1
"""
return self._args[1]
_sup = right = end
@property
[docs] def left_open(self):
"""
True if 'self' is left-open.
>>> from sympy import Interval
>>> Interval(0, 1, left_open=True).left_open
True
>>> Interval(0, 1, left_open=False).left_open
False
"""
return self._args[2]
@property
[docs] def right_open(self):
"""
True if 'self' is right-open.
>>> from sympy import Interval
>>> Interval(0, 1, right_open=True).right_open
True
>>> Interval(0, 1, right_open=False).right_open
False
"""
return self._args[3]
def _intersect(self, other):
if not isinstance(other, Interval):
return other.intersect(self)
if not self._is_comparable(other):
raise NotImplementedError("Intersection of intervals with symbolic "
"end points is not yet implemented")
empty = False
if self.start <= other.end and other.start <= self.end:
# Get topology right.
if self.start < other.start:
start = other.start
left_open = other.left_open
elif self.start > other.start:
start = self.start
left_open = self.left_open
else:
start = self.start
left_open = self.left_open or other.left_open
if self.end < other.end:
end = self.end
right_open = self.right_open
elif self.end > other.end:
end = other.end
right_open = other.right_open
else:
end = self.end
right_open = self.right_open or other.right_open
if end - start == 0 and (left_open or right_open):
empty = True
else:
empty = True
if empty:
return S.EmptySet
return self.__class__(start, end, left_open, right_open)
@property
def _complement(self):
a = Interval(S.NegativeInfinity, self.start, True, not self.left_open)
b = Interval(self.end, S.Infinity, not self.right_open, True)
return Union(a, b)
def _contains(self, other):
# We use the logic module here so that this method is meaningful
# when used with symbolic end points.
from sympy.logic.boolalg import And
try:
other = _sympify(other)
except SympifyError:
return False
if self.left_open:
expr = other > self.start
else:
expr = other >= self.start
if self.right_open:
expr = And(expr, other < self.end)
else:
expr = And(expr, other <= self.end)
return expr
@property
def _measure(self):
return self.end - self.start
def to_mpi(self, prec=53):
return mpi(mpf(self.start.evalf(prec)), mpf(self.end.evalf(prec)))
def _eval_evalf(self, prec):
return Interval(self.left.evalf(), self.right.evalf(),
left_open=self.left_open, right_open=self.right_open)
def _is_comparable(self, other):
is_comparable = self.start.is_comparable
is_comparable &= self.end.is_comparable
is_comparable &= other.start.is_comparable
is_comparable &= other.end.is_comparable
return is_comparable
@property
def is_Interval(self):
return True
@property
[docs] def is_left_unbounded(self):
"""Return ``True`` if the left endpoint is negative infinity. """
return self.left is S.NegativeInfinity or self.left == Float("-inf")
@property
[docs] def is_right_unbounded(self):
"""Return ``True`` if the right endpoint is positive infinity. """
return self.right is S.Infinity or self.right == Float("+inf")
[docs] def as_relational(self, symbol):
"""Rewrite an interval in terms of inequalities and logic operators. """
from sympy.core.relational import Eq, Lt, Le
from sympy.logic.boolalg import And
if not self.is_left_unbounded:
if self.left_open:
left = Lt(self.start, symbol)
else:
left = Le(self.start, symbol)
if not self.is_right_unbounded:
if self.right_open:
right = Lt(symbol, self.right)
else:
right = Le(symbol, self.right)
if self.is_left_unbounded and self.is_right_unbounded:
return True # XXX: Contained(symbol, Floats)
elif self.is_left_unbounded:
return right
elif self.is_right_unbounded:
return left
else:
return And(left, right)
[docs]class Union(Set):
"""
Represents a union of sets as a Set.
Examples:
>>> from sympy import Union, Interval
>>> Union(Interval(1, 2), Interval(3, 4))
[1, 2] U [3, 4]
The Union constructor will always try to merge overlapping intervals,
if possible. For example:
>>> Union(Interval(1, 2), Interval(2, 3))
[1, 3]
"""
def __new__(cls, *args):
# Flatten out Iterators and Unions to form one list of sets
args = list(args)
def flatten(arg):
if arg == S.EmptySet:
return []
if isinstance(arg, Set):
if arg.is_Union:
return sum(map(flatten, arg.args), [])
else:
return [arg]
if is_flattenable(arg): # and not isinstance(arg, Set) (implicit)
return sum(map(flatten, arg), [])
raise TypeError("Input must be Sets or iterables of Sets")
args = flatten(args)
if len(args) == 0:
return S.EmptySet
# Only real parts? Return a RealUnion
if all(arg.is_real for arg in args):
return RealUnion(args)
# Lets find and merge real elements if we have them
# Separate into finite, real and other sets
finite_set = sum([s for s in args if s.is_FiniteSet], S.EmptySet)
real_sets = [s for s in args if s.is_real]
other_sets = [s for s in args if not s.is_FiniteSet and not s.is_real]
# Separate finite_set into real and other part
real_finite = RealFiniteSet(i for i in finite_set if i.is_real)
other_finite = FiniteSet(i for i in finite_set if not i.is_real)
# Merge real part of set
real_union = RealUnion(real_sets+[real_finite])
if not real_union: # Real part was empty
sets = other_sets + [other_finite]
elif real_union.is_FiniteSet: # Real part was just a FiniteSet
sets = other_sets + [real_union+other_finite]
elif real_union.is_Interval: # Real part was just an Interval
sets = [real_union] + other_sets + [other_finite]
# If is_RealUnion then separate
elif real_union.is_Union and real_union.is_real:
intervals = [s for s in real_union.args if s.is_Interval]
finite_set = sum([s for s in real_union.args if s.is_FiniteSet] +
[other_finite], S.EmptySet) # Join FiniteSet back together
sets = intervals + [finite_set] + other_sets
# Clear out Empty Sets
sets = [set for set in sets if set != S.EmptySet]
# If a single set is left over, don't create a new Union object but
# rather return the single set.
if len(sets) == 1:
return sets[0]
return Basic.__new__(cls, *sets)
@property
def _inf(self):
# We use Min so that sup is meaningful in combination with symbolic
# interval end points.
from sympy.functions.elementary.miscellaneous import Min
return Min(*[set.inf for set in self.args])
@property
def _sup(self):
# We use Max so that sup is meaningful in combination with symbolic
# end points.
from sympy.functions.elementary.miscellaneous import Max
return Max(*[set.sup for set in self.args])
def _intersect(self, other):
# Distributivity.
if other.is_Interval:
intersections = []
for interval in self.args:
intersections.append(interval.intersect(other))
return self.__class__(*intersections)
if other.is_FiniteSet:
return other._intersect(self)
elif other.is_Union:
intersections = []
for s in other.args:
intersections.append(self.intersect(s))
return self.__class__(*intersections)
else:
return other.intersect(self)
@property
def _complement(self):
# De Morgan's formula.
complement = self.args[0].complement
for set in self.args[1:]:
complement = complement.intersect(set.complement)
return complement
def _contains(self, other):
from sympy.logic.boolalg import Or
or_args = [the_set.contains(other) for the_set in self.args]
return Or(*or_args)
@property
def _measure(self):
# Measure of a union is the sum of the measures of the sets minus
# the sum of their pairwise intersections plus the sum of their
# triple-wise intersections minus ... etc...
# Sets is a collection of intersections and a set of elementary
# sets which made up those interections (called "sos" for set of sets)
# An example element might of this list might be:
# ( {A,B,C}, A.intersect(B).intersect(C) )
# Start with just elementary sets ( ({A}, A), ({B}, B), ... )
# Then get and subtract ( ({A,B}, (A int B), ... ) while non-zero
sets = [(FiniteSet(s), s) for s in self.args]
measure = 0
parity = 1
while sets:
# Add up the measure of these sets and add or subtract it to total
measure += parity * sum(inter.measure for sos, inter in sets)
# For each intersection in sets, compute the intersection with every
# other set not already part of the intersection.
sets = ((sos + FiniteSet(newset), newset.intersect(intersection))
for sos, intersection in sets for newset in self.args
if newset not in sos)
# Clear out sets with no measure
sets = [(sos, inter) for sos, inter in sets if inter.measure != 0]
# Clear out duplicates
sos_list = []
sets_list = []
for set in sets:
if set[0] in sos_list:
continue
else:
sos_list.append(set[0])
sets_list.append(set)
sets = sets_list
# Flip Parity - next time subtract/add if we added/subtracted here
parity *= -1
return measure
[docs] def as_relational(self, symbol):
"""Rewrite a Union in terms of equalities and logic operators.
"""
from sympy.logic.boolalg import Or
return Or(*[set.as_relational(symbol) for set in self.args])
@property
def is_iterable(self):
return all(arg.is_iterable for arg in self.args)
@property
def is_Union(self):
return True
class RealUnion(Union, RealSet):
"""
Represents a union of Real Sets (Intervals, RealFiniteSets)
This class should only be used internally.
Please make unions with Union class.
See Union for details
"""
def __new__(cls, *args):
intervals, finite_sets, other_sets = [], [], []
args = list(args)
for arg in args:
if isinstance(arg, Set):
if arg == S.EmptySet:
continue
elif arg.is_Union:
args += arg.args
elif arg.is_FiniteSet:
finite_sets.append(arg)
elif arg.is_Interval:
intervals.append(arg)
else:
other_sets.append(arg)
elif is_flattenable(arg):
args += arg
else:
raise TypeError("%s: Not a set or iterable of sets"%arg)
# Sort intervals according to their infimum
intervals.sort(key=lambda i: i.start)
# Merge comparable overlapping intervals
i = 0
while i < len(intervals) - 1:
cur = intervals[i]
next = intervals[i + 1]
merge = False
if cur._is_comparable(next):
if next.start < cur.end:
merge = True
elif next.start == cur.end:
# Must be careful with boundaries.
merge = not(next.left_open and cur.right_open)
if merge:
if cur.start == next.start:
left_open = cur.left_open and next.left_open
else:
left_open = cur.left_open
if cur.end < next.end:
right_open = next.right_open
end = next.end
elif cur.end > next.end:
right_open = cur.right_open
end = cur.end
else:
right_open = cur.right_open and next.right_open
end = cur.end
intervals[i] = Interval(cur.start, end, left_open, right_open)
del intervals[i + 1]
else:
i += 1
# Collect all elements in the finite sets not in any interval
if finite_sets:
# Merge Finite Sets
finite_set = sum(finite_sets, S.EmptySet)
# Close open intervals if boundary is in finite_set
for num, i in enumerate(intervals):
closeLeft = i.start in finite_set if i.left_open else False
closeRight = i.end in finite_set if i.right_open else False
if ((closeLeft and i.left_open)
or (closeRight and i.right_open)):
intervals[num] = Interval(i.start, i.end,
not closeLeft, not closeRight)
# All elements in finite_set not in any interval
finite_complement = FiniteSet(
el for el in finite_set
if not el.is_number
or not any(el in i for i in intervals))
if len(finite_complement)>0: # Anything left?
other_sets.append(finite_complement)
# Clear out empty sets
sets = [set for set in (intervals + other_sets) if set]
# If nothing is there then return the empty set
if not sets:
return S.EmptySet
# If a single set is left over, don't create a new Union object but
# rather return the single set.
if len(sets) == 1:
return sets[0]
return Basic.__new__(cls, *sets)
def _eval_evalf(self, prec):
return RealUnion(set.evalf() for set in self.args)
def __iter__(self):
import itertools
if all(set.is_iterable for set in self.args):
return itertools.chain(*(iter(arg) for arg in self.args))
else:
raise TypeError("Not all constituent sets are iterable")
[docs]class EmptySet(Set):
"""
Represents the empty set. The empty set is available as a singleton
as S.EmptySet.
Examples:
>>> from sympy import S, Interval
>>> S.EmptySet
EmptySet()
>>> Interval(1, 2).intersect(S.EmptySet)
EmptySet()
"""
__metaclass__ = Singleton
def _intersect(self, other):
return S.EmptySet
@property
def _complement(self):
return Interval(S.NegativeInfinity, S.Infinity)
@property
def _measure(self):
return 0
def _contains(self, other):
return False
def as_relational(self, symbol):
return False
def __len__(self):
return 0
def union(self, other):
return other
def __iter__(self):
return iter([])
class FiniteSet(CountableSet):
"""
Represents a finite set of discrete numbers
Examples:
>>> from sympy import Symbol, FiniteSet, sets
>>> FiniteSet(1, 2, 3, 4)
{1, 2, 3, 4}
>>> 3 in FiniteSet(1, 2, 3, 4)
True
"""
def __new__(cls, *args):
def flatten(arg):
if is_flattenable(arg):
return sum(map(flatten, arg), [])
return [arg]
args = flatten(list(args))
# Sympify Arguments
args = map(sympify, args)
# Turn tuples into Tuples
args = [Tuple(*arg) if arg.__class__ is tuple else arg for arg in args]
if len(args) == 0:
return EmptySet()
if all([arg.is_real and arg.is_number for arg in args]):
cls = RealFiniteSet
elements = frozenset(map(sympify, args))
obj = Basic.__new__(cls, *elements)
obj.elements = elements
return obj
def __iter__(self):
return self.elements.__iter__()
def _intersect(self, other):
if isinstance(other, self.__class__):
return self.__class__(*(self.elements & other.elements))
return self.__class__(el for el in self if el in other)
def union(self, other):
"""
Returns the union of 'self' and 'other'. As a shortcut it is possible
to use the '+' operator:
>>> from sympy import FiniteSet, Interval, Symbol
>>> FiniteSet(0, 1).union(FiniteSet(2, 3))
{0, 1, 2, 3}
>>> FiniteSet(Symbol('x'), 1, 2) + FiniteSet(2, 3)
{1, 2, 3, x}
>>> Interval(1, 2, True, True) + FiniteSet(2, 3)
(1, 2] U {3}
Similarly it is possible to use the '-' operator for set
differences:
>>> FiniteSet(Symbol('x'), 1, 2) - FiniteSet(2, 3)
{1, x}
>>> Interval(1, 2) - FiniteSet(2, 3)
[1, 2)
"""
if other == S.EmptySet:
return self
if other.is_FiniteSet:
return FiniteSet(*(self.elements | other.elements))
return Union(self, other) # Resort to default
def _contains(self, other):
"""
Tests whether an element, other, is in the set.
Relies on Python's set class. This tests for object equality
All inputs are sympified
>>> from sympy import FiniteSet
>>> 1 in FiniteSet(1, 2)
True
>>> 5 in FiniteSet(1, 2)
False
"""
return sympify(other) in self.elements
@property
def _inf(self):
from sympy.functions.elementary.miscellaneous import Min
return Min(*self)
@property
def _sup(self):
from sympy.functions.elementary.miscellaneous import Max
return Max(*self)
def __len__(self):
return len(self.elements)
def __sub__(self, other):
return FiniteSet(el for el in self if el not in other)
def as_relational(self, symbol):
"""Rewrite a FiniteSet in terms of equalities and logic operators.
"""
from sympy.core.relational import Eq
from sympy.logic.boolalg import Or
return Or(*[Eq(symbol, elem) for elem in self])
@property
def is_FiniteSet(self):
return True
@property
def is_real(self):
return all(el.is_real for el in self)
class RealFiniteSet(FiniteSet, RealSet):
"""
A FiniteSet with all elements Real Numbers.
Allows for good integration with Intervals
This class for internal use only. Use FiniteSet to create a RealFiniteSet
See FiniteSet for more details
"""
def _eval_evalf(self, prec):
return RealFiniteSet(elem.evalf(prec) for elem in self)
@property
def _complement(self):
"""
The complement of a real finite set is the Union of open Intervals
between the elements of the set.
>>> from sympy import FiniteSet
>>> FiniteSet(1, 2, 3).complement
(-oo, 1) U (1, 2) U (2, 3) U (3, oo)
"""
if not all(elem.is_number for elem in self.elements):
raise ValueError("%s: Complement not defined for symbolic inputs"
%self)
sorted_elements = sorted(list(self.elements))
intervals = [] # Build up a list of intervals between the elements
intervals += [Interval(S.NegativeInfinity,sorted_elements[0],True,True)]
for a, b in zip(sorted_elements[0:-1], sorted_elements[1:]):
intervals.append(Interval(a, b, True, True)) # open intervals
intervals.append(Interval(sorted_elements[-1], S.Infinity, True, True))
return Union(*intervals)
def as_relational(self, symbol):
"""Rewrite a FiniteSet in terms of equalities and logic operators.
"""
from sympy.core.relational import Eq
from sympy.logic.boolalg import Or
return Or(*[Eq(symbol, elem) for elem in self])
def _eval_evalf(self, prec):
return FiniteSet(elem.evalf(prec) for elem in self)
genclass = (1 for i in xrange(2)).__class__
def is_flattenable(obj):
"""
Checks that an argument to a Set constructor should be flattened
"""
return obj.__class__ in [list, set, genclass]