[docs]classSet(Basic):""" The base class for any kind of set. This is not meant to be used directly as a container of items. It does not behave like the builtin set; see FiniteSet for that. 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. """is_number=Falseis_iterable=Falseis_interval=Falseis_FiniteSet=Falseis_Interval=Falseis_ProductSet=Falseis_Union=Falseis_Intersection=Noneis_EmptySet=Noneis_UniversalSet=None

def_intersect(self,other):""" This function should only be used internally self._intersect(other) returns a new, intersected set if self knows how to intersect itself with other, otherwise it returns None When making a new set class you can be assured that other will not be a Union, FiniteSet, or EmptySet Used within the Intersection class """returnNonedef_union(self,other):""" This function should only be used internally self._union(other) returns a new, joined set if self knows how to join itself with other, otherwise it returns None. It may also return a python set of SymPy Sets if they are somehow simpler. If it does this it must be idempotent i.e. the sets returned must return None with _union'ed with each other Used within the Union class """returnNone@property

[docs]defcontains(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 """returnself._contains(sympify(other,strict=True))

@propertydef_measure(self):raiseNotImplementedError("(%s)._measure"%self)def__add__(self,other):returnself.union(other)def__or__(self,other):returnself.union(other)def__and__(self,other):returnself.intersect(other)def__mul__(self,other):returnProductSet(self,other)def__pow__(self,exp):ifnotsympify(exp).is_Integerandexp>=0:raiseValueError("%s: Exponent must be a positive Integer"%exp)returnProductSet([self]*exp)def__sub__(self,other):returnself.intersect(other.complement)def__neg__(self):returnself.complementdef__invert__(self):returnself.complementdef__contains__(self,other):symb=self.contains(other)result=ask(symb)ifresultisNone:raiseTypeError('contains did not evaluate to a bool: %r'%symb)returnresult@propertydefis_real(self):returnNone

[docs]classInterval(Set,EvalfMixin):""" 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 References ========== <http://en.wikipedia.org/wiki/Interval_(mathematics)> """is_Interval=Trueis_real=Truedef__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').ifnotstart.is_realornotend.is_real:raiseValueError("Only real intervals are supported")# Make sure that the created interval will be valid.ifend.is_comparableandstart.is_comparable:ifend<start:returnS.EmptySetifend==startand(left_openorright_open):returnS.EmptySetifend==startandnot(left_openorright_open):returnFiniteSet(end)# Make sure infinite interval end points are open.ifstart==S.NegativeInfinity:left_open=Trueifend==S.Infinity:right_open=TruereturnBasic.__new__(cls,start,end,left_open,right_open)@property

[docs]defstart(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 """returnself._args[0]

_inf=left=start@property

[docs]defend(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 """returnself._args[1]

def_intersect(self,other):""" This function should only be used internally See Set._intersect for docstring """# We only know how to intersect with other intervalsifnotother.is_Interval:returnNone# We can't intersect [0,3] with [x,6] -- we don't know if x>0 or x<0ifnotself._is_comparable(other):returnNoneempty=Falseifself.start<=other.endandother.start<=self.end:# Get topology right.ifself.start<other.start:start=other.startleft_open=other.left_openelifself.start>other.start:start=self.startleft_open=self.left_openelse:start=self.startleft_open=self.left_openorother.left_openifself.end<other.end:end=self.endright_open=self.right_openelifself.end>other.end:end=other.endright_open=other.right_openelse:end=self.endright_open=self.right_openorother.right_openifend-start==0and(left_openorright_open):empty=Trueelse:empty=Trueifempty:returnS.EmptySetreturnInterval(start,end,left_open,right_open)def_union(self,other):""" This function should only be used internally See Set._union for docstring """ifother.is_Intervalandself._is_comparable(other):fromsympy.functions.elementary.miscellaneousimportMin,Max# Non-overlapping intervalsend=Min(self.end,other.end)start=Max(self.start,other.start)if(end<startor(end==startand(endnotinselfandendnotinother))):returnNoneelse:start=Min(self.start,other.start)end=Max(self.end,other.end)left_open=((self.start!=startorself.left_open)and(other.start!=startorother.left_open))right_open=((self.end!=endorself.right_open)and(other.end!=endorother.right_open))returnInterval(start,end,left_open,right_open)# If I have open end points and these endpoints are contained in otherif((self.left_openandother.contains(self.start)isTrue)or(self.right_openandother.contains(self.end)isTrue)):# Fill in my end points and returnopen_left=self.left_openandself.startnotinotheropen_right=self.right_openandself.endnotinothernew_self=Interval(self.start,self.end,open_left,open_right)returnset((new_self,other))returnNone@propertydef_complement(self):a=Interval(S.NegativeInfinity,self.start,True,notself.left_open)b=Interval(self.end,S.Infinity,notself.right_open,True)returnUnion(a,b)def_contains(self,other):ifself.left_open:expr=other>self.startelse:expr=other>=self.startifself.right_open:expr=And(expr,other<self.end)else:expr=And(expr,other<=self.end)returnexpr@propertydef_measure(self):returnself.end-self.startdefto_mpi(self,prec=53):returnmpi(mpf(self.start.evalf(prec)),mpf(self.end.evalf(prec)))def_eval_evalf(self,prec):returnInterval(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_comparableis_comparable&=self.end.is_comparableis_comparable&=other.start.is_comparableis_comparable&=other.end.is_comparablereturnis_comparable@property

[docs]defis_left_unbounded(self):"""Return ``True`` if the left endpoint is negative infinity. """returnself.leftisS.NegativeInfinityorself.left==Float("-inf")

@property

[docs]defis_right_unbounded(self):"""Return ``True`` if the right endpoint is positive infinity. """returnself.rightisS.Infinityorself.right==Float("+inf")

[docs]defreduce(args):""" Simplify a Union using known rules We first start with global rules like 'Merge all FiniteSets' Then we iterate through all pairs and ask the constituent sets if they can simplify themselves with any other constituent """# ===== Global Rules =====# Merge all finite setsfinite_sets=[xforxinargsifx.is_FiniteSet]iflen(finite_sets)>1:finite_set=FiniteSet(xforsetinfinite_setsforxinset)args=[finite_set]+[xforxinargsifnotx.is_FiniteSet]# ===== Pair-wise Rules =====# Here we depend on rules built into the constituent setsargs=set(args)new_args=Truewhile(new_args):forsinargs:new_args=Falsefortinargs-set((s,)):new_set=s._union(t)# This returns None if s does not know how to intersect# with t. Returns the newly intersected set otherwiseifnew_setisnotNone:ifnotisinstance(new_set,set):new_set=set((new_set,))new_args=(args-set((s,t))).union(new_set)breakifnew_args:args=new_argsbreakiflen(args)==1:returnargs.pop()else:returnUnion(args,evaluate=False)

@propertydef_inf(self):# We use Min so that sup is meaningful in combination with symbolic# interval end points.fromsympy.functions.elementary.miscellaneousimportMinreturnMin(*[set.infforsetinself.args])@propertydef_sup(self):# We use Max so that sup is meaningful in combination with symbolic# end points.fromsympy.functions.elementary.miscellaneousimportMaxreturnMax(*[set.supforsetinself.args])@propertydef_complement(self):# De Morgan's formula.complement=self.args[0].complementforsetinself.args[1:]:complement=complement.intersect(set.complement)returncomplementdef_contains(self,other):or_args=[the_set.contains(other)forthe_setinself.args]returnOr(*or_args)@propertydef_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 intersections (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-zerosets=[(FiniteSet(s),s)forsinself.args]measure=0parity=1whilesets:# Add up the measure of these sets and add or subtract it to totalmeasure+=parity*sum(inter.measureforsos,interinsets)# 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))forsos,intersectioninsetsfornewsetinself.argsifnewsetnotinsos)# Clear out sets with no measuresets=[(sos,inter)forsos,interinsetsifinter.measure!=0]# Clear out duplicatessos_list=[]sets_list=[]forsetinsets:ifset[0]insos_list:continueelse:sos_list.append(set[0])sets_list.append(set)sets=sets_list# Flip Parity - next time subtract/add if we added/subtracted hereparity*=-1returnmeasure

[docs]defas_relational(self,symbol):"""Rewrite a Union in terms of equalities and logic operators. """returnOr(*[set.as_relational(symbol)forsetinself.args])

@propertydefis_iterable(self):returnall(arg.is_iterableforarginself.args)def_eval_evalf(self,prec):try:returnUnion(set.evalf()forsetinself.args)except:raiseTypeError("Not all sets are evalf-able")def__iter__(self):importitertoolsifall(set.is_iterableforsetinself.args):returnitertools.chain(*(iter(arg)forarginself.args))else:raiseTypeError("Not all constituent sets are iterable")@propertydefis_real(self):returnall(set.is_realforsetinself.args)

[docs]classIntersection(Set):""" Represents an intersection of sets as a Set. Examples ======== >>> from sympy import Intersection, Interval >>> Intersection(Interval(1, 3), Interval(2, 4)) [2, 3] We often use the .intersect method >>> Interval(1,3).intersect(Interval(2,4)) [2, 3] See Also ======== Union References ========== <http://en.wikipedia.org/wiki/Intersection_(set_theory)> """is_Intersection=Truedef__new__(cls,*args,**kwargs):evaluate=kwargs.get('evaluate',True)# flatten inputs to merge intersections and iterablesargs=list(args)defflatten(arg):ifisinstance(arg,Set):ifarg.is_Intersection:returnsum(list(map(flatten,arg.args)),[])else:return[arg]ifiterable(arg):# and not isinstance(arg, Set) (implicit)returnsum(list(map(flatten,arg)),[])raiseTypeError("Input must be Sets or iterables of Sets")args=flatten(args)# Intersection of no sets is everythingiflen(args)==0:returnS.UniversalSetargs=sorted(args,key=default_sort_key)# Reduce sets using known rulesifevaluate:returnIntersection.reduce(args)returnBasic.__new__(cls,*args)@propertydefis_iterable(self):returnany(arg.is_iterableforarginself.args)@propertydef_inf(self):raiseNotImplementedError()@propertydef_sup(self):raiseNotImplementedError()@propertydef_complement(self):raiseNotImplementedError()def_contains(self,other):fromsympy.logic.boolalgimportAndreturnAnd(*[set.contains(other)forsetinself.args])def__iter__(self):forsinself.args:ifs.is_iterable:other_sets=set(self.args)-set((s,))other=Intersection(other_sets,evaluate=False)return(xforxinsifxinother)raiseValueError("None of the constituent sets are iterable")@staticmethod

[docs]defreduce(args):""" Simplify an intersection using known rules We first start with global rules like 'if any empty sets return empty set' and 'distribute any unions' Then we iterate through all pairs and ask the constituent sets if they can simplify themselves with any other constituent """# ===== Global Rules =====# If any EmptySets return EmptySetifany(s.is_EmptySetforsinargs):returnS.EmptySet# If any FiniteSets see which elements of that finite set occur within# all other sets in the intersectionforsinargs:ifs.is_FiniteSet:returns.__class__(xforxinsifall(xinotherforotherinargs))# If any of the sets are unions, return a Union of Intersectionsforsinargs:ifs.is_Union:other_sets=set(args)-set((s,))other=Intersection(other_sets)returnUnion(Intersection(arg,other)forargins.args)# At this stage we are guaranteed not to have any# EmptySets, FiniteSets, or Unions in the intersection# ===== Pair-wise Rules =====# Here we depend on rules built into the constituent setsargs=set(args)new_args=Truewhile(new_args):forsinargs:new_args=Falsefortinargs-set((s,)):new_set=s._intersect(t)# This returns None if s does not know how to intersect# with t. Returns the newly intersected set otherwiseifnew_setisnotNone:new_args=(args-set((s,t))).union(set((new_set,)))breakifnew_args:args=new_argsbreakiflen(args)==1:returnargs.pop()else:returnIntersection(args,evaluate=False)

[docs]defas_relational(self,symbol):"""Rewrite an Intersection in terms of equalities and logic operators"""returnAnd(*[set.as_relational(symbol)forsetinself.args])

[docs]classUniversalSet(Set,metaclass=Singleton):""" Represents the set of all things. The universal set is available as a singleton as S.UniversalSet Examples ======== >>> from sympy import S, Interval >>> S.UniversalSet UniversalSet() >>> Interval(1, 2).intersect(S.UniversalSet) [1, 2] See Also ======== EmptySet References ========== http://en.wikipedia.org/wiki/Universal_set """is_UniversalSet=Truedef_intersect(self,other):returnother@propertydef_complement(self):returnS.EmptySet@propertydef_measure(self):returnS.Infinitydef_contains(self,other):returnTruedefas_relational(self,symbol):returnTruedef_union(self,other):returnself

[docs]classFiniteSet(Set,EvalfMixin):""" 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 References ========== http://en.wikipedia.org/wiki/Finite_set """is_FiniteSet=Trueis_iterable=Truedef__new__(cls,*args):iflen(args)==1anditerable(args[0]):args=args[0]args=list(map(sympify,args))iflen(args)==0:returnEmptySet()args=frozenset(args)# remove duplicatesobj=Basic.__new__(cls,*args)obj._elements=argsreturnobjdef__iter__(self):returniter(self.args)def_intersect(self,other):""" This function should only be used internally See Set._intersect for docstring """ifisinstance(other,self.__class__):returnself.__class__(*(self._elements&other._elements))returnself.__class__(elforelinselfifelinother)def_union(self,other):""" This function should only be used internally See Set._union for docstring """ifother.is_FiniteSet:returnFiniteSet(*(self._elements|other._elements))# If other set contains one of my elements, remove it from myselfifany(other.contains(x)isTrueforxinself):returnset((FiniteSet(xforxinselfifother.contains(x)isnotTrue),other))returnNonedef_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 """returnotherinself._elements@propertydef_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) """ifnotall(elem.is_numberforeleminself):raiseValueError("%s: Complement not defined for symbolic inputs"%self)# as there are only numbers involved, a straight sort is sufficient;# default_sort_key is not neededargs=sorted(self.args)intervals=[]# Build up a list of intervals between the elementsintervals+=[Interval(S.NegativeInfinity,args[0],True,True)]fora,binzip(args[:-1],args[1:]):intervals.append(Interval(a,b,True,True))# open intervalsintervals.append(Interval(args[-1],S.Infinity,True,True))returnUnion(intervals,evaluate=False)@propertydef_inf(self):fromsympy.functions.elementary.miscellaneousimportMinreturnMin(*self)@propertydef_sup(self):fromsympy.functions.elementary.miscellaneousimportMaxreturnMax(*self)@propertydefmeasure(self):return0def__len__(self):returnlen(self.args)def__sub__(self,other):returnFiniteSet(elforelinselfifelnotinother)

[docs]defas_relational(self,symbol):"""Rewrite a FiniteSet in terms of equalities and logic operators. """fromsympy.core.relationalimportEqreturnOr(*[Eq(symbol,elem)foreleminself])