12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546 |
- from typing import Any, Callable, Optional
- from functools import reduce
- from collections import defaultdict
- import inspect
- from sympy.core.basic import Basic
- from sympy.core.containers import Tuple
- from sympy.core.decorators import sympify_method_args, sympify_return
- from sympy.core.evalf import EvalfMixin
- from sympy.core.expr import Expr
- from sympy.core.function import Lambda
- from sympy.core.logic import (FuzzyBool, fuzzy_bool, fuzzy_or, fuzzy_and,
- fuzzy_not)
- from sympy.core.numbers import Float, Integer
- from sympy.core.operations import LatticeOp
- from sympy.core.parameters import global_parameters
- from sympy.core.relational import Eq, Ne, is_lt
- from sympy.core.singleton import Singleton, S
- from sympy.core.sorting import ordered
- from sympy.core.symbol import symbols, Symbol, Dummy, uniquely_named_symbol
- from sympy.core.sympify import _sympify, sympify, _sympy_converter
- from sympy.functions.elementary.miscellaneous import Max, Min
- from sympy.logic.boolalg import And, Or, Not, Xor, true, false
- from sympy.utilities.decorator import deprecated
- from sympy.utilities.exceptions import sympy_deprecation_warning
- from sympy.utilities.iterables import (iproduct, sift, roundrobin, iterable,
- subsets)
- from sympy.utilities.misc import func_name, filldedent
- from mpmath import mpi, mpf
- from mpmath.libmp.libmpf import prec_to_dps
- tfn = defaultdict(lambda: None, {
- True: S.true,
- S.true: S.true,
- False: S.false,
- S.false: S.false})
- @sympify_method_args
- class Set(Basic, EvalfMixin):
- """
- The base class for any kind of set.
- Explanation
- ===========
- This is not meant to be used directly as a container of items. It does not
- behave like the builtin ``set``; see :class:`FiniteSet` for that.
- Real intervals are represented by the :class:`Interval` class and unions of
- sets by the :class:`Union` class. The empty set is represented by the
- :class:`EmptySet` class and available as a singleton as ``S.EmptySet``.
- """
- is_number = False
- is_iterable = False
- is_interval = False
- is_FiniteSet = False
- is_Interval = False
- is_ProductSet = False
- is_Union = False
- is_Intersection = None # type: Optional[bool]
- is_UniversalSet = None # type: Optional[bool]
- is_Complement = None # type: Optional[bool]
- is_ComplexRegion = False
- is_empty = None # type: FuzzyBool
- is_finite_set = None # type: FuzzyBool
- @property # type: ignore
- @deprecated(
- """
- The is_EmptySet attribute of Set objects is deprecated.
- Use 's is S.EmptySet" or 's.is_empty' instead.
- """,
- deprecated_since_version="1.5",
- active_deprecations_target="deprecated-is-emptyset",
- )
- def is_EmptySet(self):
- return None
- @staticmethod
- def _infimum_key(expr):
- """
- Return infimum (if possible) else S.Infinity.
- """
- try:
- infimum = expr.inf
- assert infimum.is_comparable
- infimum = infimum.evalf() # issue #18505
- except (NotImplementedError,
- AttributeError, AssertionError, ValueError):
- infimum = S.Infinity
- return infimum
- def union(self, other):
- """
- Returns the union of ``self`` and ``other``.
- Examples
- ========
- As a shortcut it is possible to use the ``+`` operator:
- >>> from sympy import Interval, FiniteSet
- >>> Interval(0, 1).union(Interval(2, 3))
- Union(Interval(0, 1), Interval(2, 3))
- >>> Interval(0, 1) + Interval(2, 3)
- Union(Interval(0, 1), Interval(2, 3))
- >>> Interval(1, 2, True, True) + FiniteSet(2, 3)
- Union({3}, Interval.Lopen(1, 2))
- Similarly it is possible to use the ``-`` operator for set differences:
- >>> Interval(0, 2) - Interval(0, 1)
- Interval.Lopen(1, 2)
- >>> Interval(1, 3) - FiniteSet(2)
- Union(Interval.Ropen(1, 2), Interval.Lopen(2, 3))
- """
- return Union(self, other)
- def intersect(self, other):
- """
- Returns the intersection of 'self' and 'other'.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(1, 3).intersect(Interval(1, 2))
- Interval(1, 2)
- >>> from sympy import imageset, Lambda, symbols, S
- >>> n, m = symbols('n m')
- >>> a = imageset(Lambda(n, 2*n), S.Integers)
- >>> a.intersect(imageset(Lambda(m, 2*m + 1), S.Integers))
- EmptySet
- """
- return Intersection(self, other)
- def intersection(self, other):
- """
- Alias for :meth:`intersect()`
- """
- return self.intersect(other)
- def is_disjoint(self, other):
- """
- Returns True if ``self`` and ``other`` are disjoint.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(0, 2).is_disjoint(Interval(1, 2))
- False
- >>> Interval(0, 2).is_disjoint(Interval(3, 4))
- True
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Disjoint_sets
- """
- return self.intersect(other) == S.EmptySet
- def isdisjoint(self, other):
- """
- Alias for :meth:`is_disjoint()`
- """
- return self.is_disjoint(other)
- def complement(self, universe):
- r"""
- The complement of 'self' w.r.t the given universe.
- Examples
- ========
- >>> from sympy import Interval, S
- >>> Interval(0, 1).complement(S.Reals)
- Union(Interval.open(-oo, 0), Interval.open(1, oo))
- >>> Interval(0, 1).complement(S.UniversalSet)
- Complement(UniversalSet, Interval(0, 1))
- """
- return Complement(universe, self)
- def _complement(self, other):
- # this behaves as other - self
- if isinstance(self, ProductSet) and isinstance(other, ProductSet):
- # If self and other are disjoint then other - self == self
- if len(self.sets) != len(other.sets):
- return other
- # There can be other ways to represent this but this gives:
- # (A x B) - (C x D) = ((A - C) x B) U (A x (B - D))
- overlaps = []
- pairs = list(zip(self.sets, other.sets))
- for n in range(len(pairs)):
- sets = (o if i != n else o-s for i, (s, o) in enumerate(pairs))
- overlaps.append(ProductSet(*sets))
- return Union(*overlaps)
- elif isinstance(other, Interval):
- if isinstance(self, (Interval, FiniteSet)):
- return Intersection(other, self.complement(S.Reals))
- elif isinstance(other, Union):
- return Union(*(o - self for o in other.args))
- elif isinstance(other, Complement):
- return Complement(other.args[0], Union(other.args[1], self), evaluate=False)
- elif other is S.EmptySet:
- return S.EmptySet
- elif isinstance(other, FiniteSet):
- sifted = sift(other, lambda x: fuzzy_bool(self.contains(x)))
- # ignore those that are contained in self
- return Union(FiniteSet(*(sifted[False])),
- Complement(FiniteSet(*(sifted[None])), self, evaluate=False)
- if sifted[None] else S.EmptySet)
- def symmetric_difference(self, other):
- """
- Returns symmetric difference of ``self`` and ``other``.
- Examples
- ========
- >>> from sympy import Interval, S
- >>> Interval(1, 3).symmetric_difference(S.Reals)
- Union(Interval.open(-oo, 1), Interval.open(3, oo))
- >>> Interval(1, 10).symmetric_difference(S.Reals)
- Union(Interval.open(-oo, 1), Interval.open(10, oo))
- >>> from sympy import S, EmptySet
- >>> S.Reals.symmetric_difference(EmptySet)
- Reals
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Symmetric_difference
- """
- return SymmetricDifference(self, other)
- def _symmetric_difference(self, other):
- return Union(Complement(self, other), Complement(other, self))
- @property
- def inf(self):
- """
- The infimum of ``self``.
- Examples
- ========
- >>> 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
- def sup(self):
- """
- The supremum of ``self``.
- Examples
- ========
- >>> 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)
- def contains(self, other):
- """
- Returns a SymPy value indicating whether ``other`` is contained
- in ``self``: ``true`` if it is, ``false`` if it isn't, else
- an unevaluated ``Contains`` expression (or, as in the case of
- ConditionSet and a union of FiniteSet/Intervals, an expression
- indicating the conditions for containment).
- Examples
- ========
- >>> from sympy import Interval, S
- >>> from sympy.abc import x
- >>> Interval(0, 1).contains(0.5)
- True
- As a shortcut it is possible to use the ``in`` operator, but that
- will raise an error unless an affirmative true or false is not
- obtained.
- >>> Interval(0, 1).contains(x)
- (0 <= x) & (x <= 1)
- >>> x in Interval(0, 1)
- Traceback (most recent call last):
- ...
- TypeError: did not evaluate to a bool: None
- The result of 'in' is a bool, not a SymPy value
- >>> 1 in Interval(0, 2)
- True
- >>> _ is S.true
- False
- """
- from .contains import Contains
- other = sympify(other, strict=True)
- c = self._contains(other)
- if isinstance(c, Contains):
- return c
- if c is None:
- return Contains(other, self, evaluate=False)
- b = tfn[c]
- if b is None:
- return c
- return b
- def _contains(self, other):
- raise NotImplementedError(filldedent('''
- (%s)._contains(%s) is not defined. This method, when
- defined, will receive a sympified object. The method
- should return True, False, None or something that
- expresses what must be true for the containment of that
- object in self to be evaluated. If None is returned
- then a generic Contains object will be returned
- by the ``contains`` method.''' % (self, other)))
- def is_subset(self, other):
- """
- Returns True if ``self`` is a subset of ``other``.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(0, 0.5).is_subset(Interval(0, 1))
- True
- >>> Interval(0, 1).is_subset(Interval(0, 1, left_open=True))
- False
- """
- if not isinstance(other, Set):
- raise ValueError("Unknown argument '%s'" % other)
- # Handle the trivial cases
- if self == other:
- return True
- is_empty = self.is_empty
- if is_empty is True:
- return True
- elif fuzzy_not(is_empty) and other.is_empty:
- return False
- if self.is_finite_set is False and other.is_finite_set:
- return False
- # Dispatch on subclass rules
- ret = self._eval_is_subset(other)
- if ret is not None:
- return ret
- ret = other._eval_is_superset(self)
- if ret is not None:
- return ret
- # Use pairwise rules from multiple dispatch
- from sympy.sets.handlers.issubset import is_subset_sets
- ret = is_subset_sets(self, other)
- if ret is not None:
- return ret
- # Fall back on computing the intersection
- # XXX: We shouldn't do this. A query like this should be handled
- # without evaluating new Set objects. It should be the other way round
- # so that the intersect method uses is_subset for evaluation.
- if self.intersect(other) == self:
- return True
- def _eval_is_subset(self, other):
- '''Returns a fuzzy bool for whether self is a subset of other.'''
- return None
- def _eval_is_superset(self, other):
- '''Returns a fuzzy bool for whether self is a subset of other.'''
- return None
- # This should be deprecated:
- def issubset(self, other):
- """
- Alias for :meth:`is_subset()`
- """
- return self.is_subset(other)
- def is_proper_subset(self, other):
- """
- Returns True if ``self`` is a proper subset of ``other``.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(0, 0.5).is_proper_subset(Interval(0, 1))
- True
- >>> Interval(0, 1).is_proper_subset(Interval(0, 1))
- False
- """
- if isinstance(other, Set):
- return self != other and self.is_subset(other)
- else:
- raise ValueError("Unknown argument '%s'" % other)
- def is_superset(self, other):
- """
- Returns True if ``self`` is a superset of ``other``.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(0, 0.5).is_superset(Interval(0, 1))
- False
- >>> Interval(0, 1).is_superset(Interval(0, 1, left_open=True))
- True
- """
- if isinstance(other, Set):
- return other.is_subset(self)
- else:
- raise ValueError("Unknown argument '%s'" % other)
- # This should be deprecated:
- def issuperset(self, other):
- """
- Alias for :meth:`is_superset()`
- """
- return self.is_superset(other)
- def is_proper_superset(self, other):
- """
- Returns True if ``self`` is a proper superset of ``other``.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(0, 1).is_proper_superset(Interval(0, 0.5))
- True
- >>> Interval(0, 1).is_proper_superset(Interval(0, 1))
- False
- """
- if isinstance(other, Set):
- return self != other and self.is_superset(other)
- else:
- raise ValueError("Unknown argument '%s'" % other)
- def _eval_powerset(self):
- from .powerset import PowerSet
- return PowerSet(self)
- def powerset(self):
- """
- Find the Power set of ``self``.
- Examples
- ========
- >>> from sympy import EmptySet, FiniteSet, Interval
- A power set of an empty set:
- >>> A = EmptySet
- >>> A.powerset()
- {EmptySet}
- A power set of a finite set:
- >>> A = FiniteSet(1, 2)
- >>> a, b, c = FiniteSet(1), FiniteSet(2), FiniteSet(1, 2)
- >>> A.powerset() == FiniteSet(a, b, c, EmptySet)
- True
- A power set of an interval:
- >>> Interval(1, 2).powerset()
- PowerSet(Interval(1, 2))
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Power_set
- """
- return self._eval_powerset()
- @property
- def measure(self):
- """
- The (Lebesgue) measure of ``self``.
- Examples
- ========
- >>> from sympy import Interval, Union
- >>> Interval(0, 1).measure
- 1
- >>> Union(Interval(0, 1), Interval(2, 3)).measure
- 2
- """
- return self._measure
- @property
- def boundary(self):
- """
- The boundary or frontier of a set.
- Explanation
- ===========
- A point x is on the boundary of a set S if
- 1. x is in the closure of S.
- I.e. Every neighborhood of x contains a point in S.
- 2. x is not in the interior of S.
- I.e. There does not exist an open set centered on x contained
- entirely within S.
- There are the points on the outer rim of S. If S is open then these
- points need not actually be contained within S.
- For example, the boundary of an interval is its start and end points.
- This is true regardless of whether or not the interval is open.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(0, 1).boundary
- {0, 1}
- >>> Interval(0, 1, True, False).boundary
- {0, 1}
- """
- return self._boundary
- @property
- def is_open(self):
- """
- Property method to check whether a set is open.
- Explanation
- ===========
- A set is open if and only if it has an empty intersection with its
- boundary. In particular, a subset A of the reals is open if and only
- if each one of its points is contained in an open interval that is a
- subset of A.
- Examples
- ========
- >>> from sympy import S
- >>> S.Reals.is_open
- True
- >>> S.Rationals.is_open
- False
- """
- return Intersection(self, self.boundary).is_empty
- @property
- def is_closed(self):
- """
- A property method to check whether a set is closed.
- Explanation
- ===========
- A set is closed if its complement is an open set. The closedness of a
- subset of the reals is determined with respect to R and its standard
- topology.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(0, 1).is_closed
- True
- """
- return self.boundary.is_subset(self)
- @property
- def closure(self):
- """
- Property method which returns the closure of a set.
- The closure is defined as the union of the set itself and its
- boundary.
- Examples
- ========
- >>> from sympy import S, Interval
- >>> S.Reals.closure
- Reals
- >>> Interval(0, 1).closure
- Interval(0, 1)
- """
- return self + self.boundary
- @property
- def interior(self):
- """
- Property method which returns the interior of a set.
- The interior of a set S consists all points of S that do not
- belong to the boundary of S.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(0, 1).interior
- Interval.open(0, 1)
- >>> Interval(0, 1).boundary.interior
- EmptySet
- """
- return self - self.boundary
- @property
- def _boundary(self):
- raise NotImplementedError()
- @property
- def _measure(self):
- raise NotImplementedError("(%s)._measure" % self)
- def _eval_evalf(self, prec):
- dps = prec_to_dps(prec)
- return self.func(*[arg.evalf(n=dps) for arg in self.args])
- @sympify_return([('other', 'Set')], NotImplemented)
- def __add__(self, other):
- return self.union(other)
- @sympify_return([('other', 'Set')], NotImplemented)
- def __or__(self, other):
- return self.union(other)
- @sympify_return([('other', 'Set')], NotImplemented)
- def __and__(self, other):
- return self.intersect(other)
- @sympify_return([('other', 'Set')], NotImplemented)
- def __mul__(self, other):
- return ProductSet(self, other)
- @sympify_return([('other', 'Set')], NotImplemented)
- def __xor__(self, other):
- return SymmetricDifference(self, other)
- @sympify_return([('exp', Expr)], NotImplemented)
- def __pow__(self, exp):
- if not (exp.is_Integer and exp >= 0):
- raise ValueError("%s: Exponent must be a positive Integer" % exp)
- return ProductSet(*[self]*exp)
- @sympify_return([('other', 'Set')], NotImplemented)
- def __sub__(self, other):
- return Complement(self, other)
- def __contains__(self, other):
- other = _sympify(other)
- c = self._contains(other)
- b = tfn[c]
- if b is None:
- # x in y must evaluate to T or F; to entertain a None
- # result with Set use y.contains(x)
- raise TypeError('did not evaluate to a bool: %r' % c)
- return b
- class ProductSet(Set):
- """
- Represents a Cartesian Product of Sets.
- Explanation
- ===========
- 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)
- ProductSet(Interval(0, 5), {1, 2, 3})
- >>> (2, 2) in ProductSet(I, S)
- True
- >>> Interval(0, 1) * Interval(0, 1) # The unit square
- ProductSet(Interval(0, 1), Interval(0, 1))
- >>> coin = FiniteSet('H', 'T')
- >>> set(coin**2)
- {(H, H), (H, T), (T, H), (T, T)}
- The Cartesian product is not commutative or associative e.g.:
- >>> I*S == S*I
- False
- >>> (I*I)*I == I*(I*I)
- False
- Notes
- =====
- - Passes most operations down to the argument sets
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Cartesian_product
- """
- is_ProductSet = True
- def __new__(cls, *sets, **assumptions):
- if len(sets) == 1 and iterable(sets[0]) and not isinstance(sets[0], (Set, set)):
- sympy_deprecation_warning(
- """
- ProductSet(iterable) is deprecated. Use ProductSet(*iterable) instead.
- """,
- deprecated_since_version="1.5",
- active_deprecations_target="deprecated-productset-iterable",
- )
- sets = tuple(sets[0])
- sets = [sympify(s) for s in sets]
- if not all(isinstance(s, Set) for s in sets):
- raise TypeError("Arguments to ProductSet should be of type Set")
- # Nullary product of sets is *not* the empty set
- if len(sets) == 0:
- return FiniteSet(())
- if S.EmptySet in sets:
- return S.EmptySet
- return Basic.__new__(cls, *sets, **assumptions)
- @property
- def sets(self):
- return self.args
- def flatten(self):
- def _flatten(sets):
- for s in sets:
- if s.is_ProductSet:
- yield from _flatten(s.sets)
- else:
- yield s
- return ProductSet(*_flatten(self.sets))
- def _contains(self, element):
- """
- ``in`` operator for ProductSets.
- Examples
- ========
- >>> 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 constituent sets
- """
- if element.is_Symbol:
- return None
- if not isinstance(element, Tuple) or len(element) != len(self.sets):
- return False
- return fuzzy_and(s._contains(e) for s, e in zip(self.sets, element))
- def as_relational(self, *symbols):
- symbols = [_sympify(s) for s in symbols]
- if len(symbols) != len(self.sets) or not all(
- i.is_Symbol for i in symbols):
- raise ValueError(
- 'number of symbols must match the number of sets')
- return And(*[s.as_relational(i) for s, i in zip(self.sets, symbols)])
- @property
- def _boundary(self):
- return Union(*(ProductSet(*(b + b.boundary if i != j else b.boundary
- for j, b in enumerate(self.sets)))
- for i, a in enumerate(self.sets)))
- @property
- def is_iterable(self):
- """
- A property method which tests whether a set is iterable or not.
- Returns True if set is iterable, otherwise returns False.
- Examples
- ========
- >>> from sympy import FiniteSet, Interval
- >>> I = Interval(0, 1)
- >>> A = FiniteSet(1, 2, 3, 4, 5)
- >>> I.is_iterable
- False
- >>> A.is_iterable
- True
- """
- return all(set.is_iterable for set in self.sets)
- def __iter__(self):
- """
- A method which implements is_iterable property method.
- If self.is_iterable returns True (both constituent sets are iterable),
- then return the Cartesian Product. Otherwise, raise TypeError.
- """
- return iproduct(*self.sets)
- @property
- def is_empty(self):
- return fuzzy_or(s.is_empty for s in self.sets)
- @property
- def is_finite_set(self):
- all_finite = fuzzy_and(s.is_finite_set for s in self.sets)
- return fuzzy_or([self.is_empty, all_finite])
- @property
- def _measure(self):
- measure = 1
- for s in self.sets:
- measure *= s.measure
- return measure
- def __len__(self):
- return reduce(lambda a, b: a*b, (len(s) for s in self.args))
- def __bool__(self):
- return all(self.sets)
- class Interval(Set):
- """
- 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
- >>> Interval(0, 1)
- Interval(0, 1)
- >>> Interval.Ropen(0, 1)
- Interval.Ropen(0, 1)
- >>> Interval.Ropen(0, 1)
- Interval.Ropen(0, 1)
- >>> Interval.Lopen(0, 1)
- Interval.Lopen(0, 1)
- >>> Interval.open(0, 1)
- Interval.open(0, 1)
- >>> a = Symbol('a', real=True)
- >>> Interval(0, a)
- Interval(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
- ==========
- .. [1] https://en.wikipedia.org/wiki/Interval_%28mathematics%29
- """
- is_Interval = True
- def __new__(cls, start, end, left_open=False, right_open=False):
- start = _sympify(start)
- end = _sympify(end)
- left_open = _sympify(left_open)
- right_open = _sympify(right_open)
- if not all(isinstance(a, (type(true), type(false)))
- for a in [left_open, right_open]):
- raise NotImplementedError(
- "left_open and right_open can have only true/false values, "
- "got %s and %s" % (left_open, right_open))
- # Only allow real intervals
- if fuzzy_not(fuzzy_and(i.is_extended_real for i in (start, end, end-start))):
- raise ValueError("Non-real intervals are not supported")
- # evaluate if possible
- if is_lt(end, start):
- return S.EmptySet
- elif (end - start).is_negative:
- 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):
- if start is S.Infinity or start is S.NegativeInfinity:
- return S.EmptySet
- return FiniteSet(end)
- # Make sure infinite interval end points are open.
- if start is S.NegativeInfinity:
- left_open = true
- if end is S.Infinity:
- right_open = true
- if start == S.Infinity or end == S.NegativeInfinity:
- return S.EmptySet
- return Basic.__new__(cls, start, end, left_open, right_open)
- @property
- def start(self):
- """
- The left end point of the interval.
- This property takes the same value as the ``inf`` property.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(0, 1).start
- 0
- """
- return self._args[0]
- @property
- def end(self):
- """
- The right end point of the interval.
- This property takes the same value as the ``sup`` property.
- Examples
- ========
- >>> from sympy import Interval
- >>> Interval(0, 1).end
- 1
- """
- return self._args[1]
- @property
- def left_open(self):
- """
- True if interval is left-open.
- Examples
- ========
- >>> 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
- def right_open(self):
- """
- True if interval is right-open.
- Examples
- ========
- >>> 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]
- @classmethod
- def open(cls, a, b):
- """Return an interval including neither boundary."""
- return cls(a, b, True, True)
- @classmethod
- def Lopen(cls, a, b):
- """Return an interval not including the left boundary."""
- return cls(a, b, True, False)
- @classmethod
- def Ropen(cls, a, b):
- """Return an interval not including the right boundary."""
- return cls(a, b, False, True)
- @property
- def _inf(self):
- return self.start
- @property
- def _sup(self):
- return self.end
- @property
- def left(self):
- return self.start
- @property
- def right(self):
- return self.end
- @property
- def is_empty(self):
- if self.left_open or self.right_open:
- cond = self.start >= self.end # One/both bounds open
- else:
- cond = self.start > self.end # Both bounds closed
- return fuzzy_bool(cond)
- @property
- def is_finite_set(self):
- return self.measure.is_zero
- def _complement(self, other):
- if other == S.Reals:
- 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)
- if isinstance(other, FiniteSet):
- nums = [m for m in other.args if m.is_number]
- if nums == []:
- return None
- return Set._complement(self, other)
- @property
- def _boundary(self):
- finite_points = [p for p in (self.start, self.end)
- if abs(p) != S.Infinity]
- return FiniteSet(*finite_points)
- def _contains(self, other):
- if (not isinstance(other, Expr) or other is S.NaN
- or other.is_real is False or other.has(S.ComplexInfinity)):
- # if an expression has zoo it will be zoo or nan
- # and neither of those is real
- return false
- if self.start is S.NegativeInfinity and self.end is S.Infinity:
- if other.is_real is not None:
- return other.is_real
- d = Dummy()
- return self.as_relational(d).subs(d, other)
- def as_relational(self, x):
- """Rewrite an interval in terms of inequalities and logic operators."""
- x = sympify(x)
- if self.right_open:
- right = x < self.end
- else:
- right = x <= self.end
- if self.left_open:
- left = self.start < x
- else:
- left = self.start <= x
- return And(left, right)
- @property
- def _measure(self):
- return self.end - self.start
- def to_mpi(self, prec=53):
- return mpi(mpf(self.start._eval_evalf(prec)),
- mpf(self.end._eval_evalf(prec)))
- def _eval_evalf(self, prec):
- return Interval(self.left._evalf(prec), self.right._evalf(prec),
- 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_left_unbounded(self):
- """Return ``True`` if the left endpoint is negative infinity. """
- return self.left is S.NegativeInfinity or self.left == Float("-inf")
- @property
- 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")
- def _eval_Eq(self, other):
- if not isinstance(other, Interval):
- if isinstance(other, FiniteSet):
- return false
- elif isinstance(other, Set):
- return None
- return false
- class Union(Set, LatticeOp):
- """
- Represents a union of sets as a :class:`Set`.
- Examples
- ========
- >>> from sympy import Union, Interval
- >>> Union(Interval(1, 2), Interval(3, 4))
- Union(Interval(1, 2), Interval(3, 4))
- The Union constructor will always try to merge overlapping intervals,
- if possible. For example:
- >>> Union(Interval(1, 2), Interval(2, 3))
- Interval(1, 3)
- See Also
- ========
- Intersection
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Union_%28set_theory%29
- """
- is_Union = True
- @property
- def identity(self):
- return S.EmptySet
- @property
- def zero(self):
- return S.UniversalSet
- def __new__(cls, *args, **kwargs):
- evaluate = kwargs.get('evaluate', global_parameters.evaluate)
- # flatten inputs to merge intersections and iterables
- args = _sympify(args)
- # Reduce sets using known rules
- if evaluate:
- args = list(cls._new_args_filter(args))
- return simplify_union(args)
- args = list(ordered(args, Set._infimum_key))
- obj = Basic.__new__(cls, *args)
- obj._argset = frozenset(args)
- return obj
- @property
- def args(self):
- return self._args
- def _complement(self, universe):
- # DeMorgan's Law
- return Intersection(s.complement(universe) for s in self.args)
- @property
- def _inf(self):
- # We use Min so that sup is meaningful in combination with symbolic
- # interval end points.
- 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.
- return Max(*[set.sup for set in self.args])
- @property
- def is_empty(self):
- return fuzzy_and(set.is_empty for set in self.args)
- @property
- def is_finite_set(self):
- return fuzzy_and(set.is_finite_set for set in self.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 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-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
- @property
- def _boundary(self):
- def boundary_of_set(i):
- """ The boundary of set i minus interior of all other sets """
- b = self.args[i].boundary
- for j, a in enumerate(self.args):
- if j != i:
- b = b - a.interior
- return b
- return Union(*map(boundary_of_set, range(len(self.args))))
- def _contains(self, other):
- return Or(*[s.contains(other) for s in self.args])
- def is_subset(self, other):
- return fuzzy_and(s.is_subset(other) for s in self.args)
- def as_relational(self, symbol):
- """Rewrite a Union in terms of equalities and logic operators. """
- if (len(self.args) == 2 and
- all(isinstance(i, Interval) for i in self.args)):
- # optimization to give 3 args as (x > 1) & (x < 5) & Ne(x, 3)
- # instead of as 4, ((1 <= x) & (x < 3)) | ((x <= 5) & (3 < x))
- a, b = self.args
- if (a.sup == b.inf and
- not any(a.sup in i for i in self.args)):
- return And(Ne(symbol, a.sup), symbol < b.sup, symbol > a.inf)
- return Or(*[i.as_relational(symbol) for i in self.args])
- @property
- def is_iterable(self):
- return all(arg.is_iterable for arg in self.args)
- def __iter__(self):
- return roundrobin(*(iter(arg) for arg in self.args))
- class Intersection(Set, LatticeOp):
- """
- Represents an intersection of sets as a :class:`Set`.
- Examples
- ========
- >>> from sympy import Intersection, Interval
- >>> Intersection(Interval(1, 3), Interval(2, 4))
- Interval(2, 3)
- We often use the .intersect method
- >>> Interval(1,3).intersect(Interval(2,4))
- Interval(2, 3)
- See Also
- ========
- Union
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Intersection_%28set_theory%29
- """
- is_Intersection = True
- @property
- def identity(self):
- return S.UniversalSet
- @property
- def zero(self):
- return S.EmptySet
- def __new__(cls, *args, **kwargs):
- evaluate = kwargs.get('evaluate', global_parameters.evaluate)
- # flatten inputs to merge intersections and iterables
- args = list(ordered(set(_sympify(args))))
- # Reduce sets using known rules
- if evaluate:
- args = list(cls._new_args_filter(args))
- return simplify_intersection(args)
- args = list(ordered(args, Set._infimum_key))
- obj = Basic.__new__(cls, *args)
- obj._argset = frozenset(args)
- return obj
- @property
- def args(self):
- return self._args
- @property
- def is_iterable(self):
- return any(arg.is_iterable for arg in self.args)
- @property
- def is_finite_set(self):
- if fuzzy_or(arg.is_finite_set for arg in self.args):
- return True
- @property
- def _inf(self):
- raise NotImplementedError()
- @property
- def _sup(self):
- raise NotImplementedError()
- def _contains(self, other):
- return And(*[set.contains(other) for set in self.args])
- def __iter__(self):
- sets_sift = sift(self.args, lambda x: x.is_iterable)
- completed = False
- candidates = sets_sift[True] + sets_sift[None]
- finite_candidates, others = [], []
- for candidate in candidates:
- length = None
- try:
- length = len(candidate)
- except TypeError:
- others.append(candidate)
- if length is not None:
- finite_candidates.append(candidate)
- finite_candidates.sort(key=len)
- for s in finite_candidates + others:
- other_sets = set(self.args) - {s}
- other = Intersection(*other_sets, evaluate=False)
- completed = True
- for x in s:
- try:
- if x in other:
- yield x
- except TypeError:
- completed = False
- if completed:
- return
- if not completed:
- if not candidates:
- raise TypeError("None of the constituent sets are iterable")
- raise TypeError(
- "The computation had not completed because of the "
- "undecidable set membership is found in every candidates.")
- @staticmethod
- def _handle_finite_sets(args):
- '''Simplify intersection of one or more FiniteSets and other sets'''
- # First separate the FiniteSets from the others
- fs_args, others = sift(args, lambda x: x.is_FiniteSet, binary=True)
- # Let the caller handle intersection of non-FiniteSets
- if not fs_args:
- return
- # Convert to Python sets and build the set of all elements
- fs_sets = [set(fs) for fs in fs_args]
- all_elements = reduce(lambda a, b: a | b, fs_sets, set())
- # Extract elements that are definitely in or definitely not in the
- # intersection. Here we check contains for all of args.
- definite = set()
- for e in all_elements:
- inall = fuzzy_and(s.contains(e) for s in args)
- if inall is True:
- definite.add(e)
- if inall is not None:
- for s in fs_sets:
- s.discard(e)
- # At this point all elements in all of fs_sets are possibly in the
- # intersection. In some cases this is because they are definitely in
- # the intersection of the finite sets but it's not clear if they are
- # members of others. We might have {m, n}, {m}, and Reals where we
- # don't know if m or n is real. We want to remove n here but it is
- # possibly in because it might be equal to m. So what we do now is
- # extract the elements that are definitely in the remaining finite
- # sets iteratively until we end up with {n}, {}. At that point if we
- # get any empty set all remaining elements are discarded.
- fs_elements = reduce(lambda a, b: a | b, fs_sets, set())
- # Need fuzzy containment testing
- fs_symsets = [FiniteSet(*s) for s in fs_sets]
- while fs_elements:
- for e in fs_elements:
- infs = fuzzy_and(s.contains(e) for s in fs_symsets)
- if infs is True:
- definite.add(e)
- if infs is not None:
- for n, s in enumerate(fs_sets):
- # Update Python set and FiniteSet
- if e in s:
- s.remove(e)
- fs_symsets[n] = FiniteSet(*s)
- fs_elements.remove(e)
- break
- # If we completed the for loop without removing anything we are
- # done so quit the outer while loop
- else:
- break
- # If any of the sets of remainder elements is empty then we discard
- # all of them for the intersection.
- if not all(fs_sets):
- fs_sets = [set()]
- # Here we fold back the definitely included elements into each fs.
- # Since they are definitely included they must have been members of
- # each FiniteSet to begin with. We could instead fold these in with a
- # Union at the end to get e.g. {3}|({x}&{y}) rather than {3,x}&{3,y}.
- if definite:
- fs_sets = [fs | definite for fs in fs_sets]
- if fs_sets == [set()]:
- return S.EmptySet
- sets = [FiniteSet(*s) for s in fs_sets]
- # Any set in others is redundant if it contains all the elements that
- # are in the finite sets so we don't need it in the Intersection
- all_elements = reduce(lambda a, b: a | b, fs_sets, set())
- is_redundant = lambda o: all(fuzzy_bool(o.contains(e)) for e in all_elements)
- others = [o for o in others if not is_redundant(o)]
- if others:
- rest = Intersection(*others)
- # XXX: Maybe this shortcut should be at the beginning. For large
- # FiniteSets it could much more efficient to process the other
- # sets first...
- if rest is S.EmptySet:
- return S.EmptySet
- # Flatten the Intersection
- if rest.is_Intersection:
- sets.extend(rest.args)
- else:
- sets.append(rest)
- if len(sets) == 1:
- return sets[0]
- else:
- return Intersection(*sets, evaluate=False)
- def as_relational(self, symbol):
- """Rewrite an Intersection in terms of equalities and logic operators"""
- return And(*[set.as_relational(symbol) for set in self.args])
- class Complement(Set):
- r"""Represents the set difference or relative complement of a set with
- another set.
- $$A - B = \{x \in A \mid x \notin B\}$$
- Examples
- ========
- >>> from sympy import Complement, FiniteSet
- >>> Complement(FiniteSet(0, 1, 2), FiniteSet(1))
- {0, 2}
- See Also
- =========
- Intersection, Union
- References
- ==========
- .. [1] http://mathworld.wolfram.com/ComplementSet.html
- """
- is_Complement = True
- def __new__(cls, a, b, evaluate=True):
- a, b = map(_sympify, (a, b))
- if evaluate:
- return Complement.reduce(a, b)
- return Basic.__new__(cls, a, b)
- @staticmethod
- def reduce(A, B):
- """
- Simplify a :class:`Complement`.
- """
- if B == S.UniversalSet or A.is_subset(B):
- return S.EmptySet
- if isinstance(B, Union):
- return Intersection(*(s.complement(A) for s in B.args))
- result = B._complement(A)
- if result is not None:
- return result
- else:
- return Complement(A, B, evaluate=False)
- def _contains(self, other):
- A = self.args[0]
- B = self.args[1]
- return And(A.contains(other), Not(B.contains(other)))
- def as_relational(self, symbol):
- """Rewrite a complement in terms of equalities and logic
- operators"""
- A, B = self.args
- A_rel = A.as_relational(symbol)
- B_rel = Not(B.as_relational(symbol))
- return And(A_rel, B_rel)
- @property
- def is_iterable(self):
- if self.args[0].is_iterable:
- return True
- @property
- def is_finite_set(self):
- A, B = self.args
- a_finite = A.is_finite_set
- if a_finite is True:
- return True
- elif a_finite is False and B.is_finite_set:
- return False
- def __iter__(self):
- A, B = self.args
- for a in A:
- if a not in B:
- yield a
- else:
- continue
- class EmptySet(Set, metaclass=Singleton):
- """
- 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
- See Also
- ========
- UniversalSet
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Empty_set
- """
- is_empty = True
- is_finite_set = True
- is_FiniteSet = True
- @property # type: ignore
- @deprecated(
- """
- The is_EmptySet attribute of Set objects is deprecated.
- Use 's is S.EmptySet" or 's.is_empty' instead.
- """,
- deprecated_since_version="1.5",
- active_deprecations_target="deprecated-is-emptyset",
- )
- def is_EmptySet(self):
- return True
- @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 __iter__(self):
- return iter([])
- def _eval_powerset(self):
- return FiniteSet(self)
- @property
- def _boundary(self):
- return self
- def _complement(self, other):
- return other
- def _symmetric_difference(self, other):
- return other
- class UniversalSet(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)
- Interval(1, 2)
- See Also
- ========
- EmptySet
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Universal_set
- """
- is_UniversalSet = True
- is_empty = False
- is_finite_set = False
- def _complement(self, other):
- return S.EmptySet
- def _symmetric_difference(self, other):
- return other
- @property
- def _measure(self):
- return S.Infinity
- def _contains(self, other):
- return true
- def as_relational(self, symbol):
- return true
- @property
- def _boundary(self):
- return S.EmptySet
- class FiniteSet(Set):
- """
- Represents a finite set of discrete numbers.
- Examples
- ========
- >>> from sympy import FiniteSet
- >>> FiniteSet(1, 2, 3, 4)
- {1, 2, 3, 4}
- >>> 3 in FiniteSet(1, 2, 3, 4)
- True
- >>> members = [1, 2, 3, 4]
- >>> f = FiniteSet(*members)
- >>> f
- {1, 2, 3, 4}
- >>> f - FiniteSet(2)
- {1, 3, 4}
- >>> f + FiniteSet(2, 5)
- {1, 2, 3, 4, 5}
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Finite_set
- """
- is_FiniteSet = True
- is_iterable = True
- is_empty = False
- is_finite_set = True
- def __new__(cls, *args, **kwargs):
- evaluate = kwargs.get('evaluate', global_parameters.evaluate)
- if evaluate:
- args = list(map(sympify, args))
- if len(args) == 0:
- return S.EmptySet
- else:
- args = list(map(sympify, args))
- # keep the form of the first canonical arg
- dargs = {}
- for i in reversed(list(ordered(args))):
- if i.is_Symbol:
- dargs[i] = i
- else:
- try:
- dargs[i.as_dummy()] = i
- except TypeError:
- # e.g. i = class without args like `Interval`
- dargs[i] = i
- _args_set = set(dargs.values())
- args = list(ordered(_args_set, Set._infimum_key))
- obj = Basic.__new__(cls, *args)
- obj._args_set = _args_set
- return obj
- def __iter__(self):
- return iter(self.args)
- def _complement(self, other):
- if isinstance(other, Interval):
- # Splitting in sub-intervals is only done for S.Reals;
- # other cases that need splitting will first pass through
- # Set._complement().
- nums, syms = [], []
- for m in self.args:
- if m.is_number and m.is_real:
- nums.append(m)
- elif m.is_real == False:
- pass # drop non-reals
- else:
- syms.append(m) # various symbolic expressions
- if other == S.Reals and nums != []:
- nums.sort()
- intervals = [] # Build up a list of intervals between the elements
- intervals += [Interval(S.NegativeInfinity, nums[0], True, True)]
- for a, b in zip(nums[:-1], nums[1:]):
- intervals.append(Interval(a, b, True, True)) # both open
- intervals.append(Interval(nums[-1], S.Infinity, True, True))
- if syms != []:
- return Complement(Union(*intervals, evaluate=False),
- FiniteSet(*syms), evaluate=False)
- else:
- return Union(*intervals, evaluate=False)
- elif nums == []: # no splitting necessary or possible:
- if syms:
- return Complement(other, FiniteSet(*syms), evaluate=False)
- else:
- return other
- elif isinstance(other, FiniteSet):
- unk = []
- for i in self:
- c = sympify(other.contains(i))
- if c is not S.true and c is not S.false:
- unk.append(i)
- unk = FiniteSet(*unk)
- if unk == self:
- return
- not_true = []
- for i in other:
- c = sympify(self.contains(i))
- if c is not S.true:
- not_true.append(i)
- return Complement(FiniteSet(*not_true), unk)
- return Set._complement(self, other)
- def _contains(self, other):
- """
- Tests whether an element, other, is in the set.
- Explanation
- ===========
- The actual test is for mathematical equality (as opposed to
- syntactical equality). In the worst case all elements of the
- set must be checked.
- Examples
- ========
- >>> from sympy import FiniteSet
- >>> 1 in FiniteSet(1, 2)
- True
- >>> 5 in FiniteSet(1, 2)
- False
- """
- if other in self._args_set:
- return True
- else:
- # evaluate=True is needed to override evaluate=False context;
- # we need Eq to do the evaluation
- return fuzzy_or(fuzzy_bool(Eq(e, other, evaluate=True))
- for e in self.args)
- def _eval_is_subset(self, other):
- return fuzzy_and(other._contains(e) for e in self.args)
- @property
- def _boundary(self):
- return self
- @property
- def _inf(self):
- return Min(*self)
- @property
- def _sup(self):
- return Max(*self)
- @property
- def measure(self):
- return 0
- def __len__(self):
- return len(self.args)
- def as_relational(self, symbol):
- """Rewrite a FiniteSet in terms of equalities and logic operators. """
- return Or(*[Eq(symbol, elem) for elem in self])
- def compare(self, other):
- return (hash(self) - hash(other))
- def _eval_evalf(self, prec):
- dps = prec_to_dps(prec)
- return FiniteSet(*[elem.evalf(n=dps) for elem in self])
- def _eval_simplify(self, **kwargs):
- from sympy.simplify import simplify
- return FiniteSet(*[simplify(elem, **kwargs) for elem in self])
- @property
- def _sorted_args(self):
- return self.args
- def _eval_powerset(self):
- return self.func(*[self.func(*s) for s in subsets(self.args)])
- def _eval_rewrite_as_PowerSet(self, *args, **kwargs):
- """Rewriting method for a finite set to a power set."""
- from .powerset import PowerSet
- is2pow = lambda n: bool(n and not n & (n - 1))
- if not is2pow(len(self)):
- return None
- fs_test = lambda arg: isinstance(arg, Set) and arg.is_FiniteSet
- if not all(fs_test(arg) for arg in args):
- return None
- biggest = max(args, key=len)
- for arg in subsets(biggest.args):
- arg_set = FiniteSet(*arg)
- if arg_set not in args:
- return None
- return PowerSet(biggest)
- def __ge__(self, other):
- if not isinstance(other, Set):
- raise TypeError("Invalid comparison of set with %s" % func_name(other))
- return other.is_subset(self)
- def __gt__(self, other):
- if not isinstance(other, Set):
- raise TypeError("Invalid comparison of set with %s" % func_name(other))
- return self.is_proper_superset(other)
- def __le__(self, other):
- if not isinstance(other, Set):
- raise TypeError("Invalid comparison of set with %s" % func_name(other))
- return self.is_subset(other)
- def __lt__(self, other):
- if not isinstance(other, Set):
- raise TypeError("Invalid comparison of set with %s" % func_name(other))
- return self.is_proper_subset(other)
- def __eq__(self, other):
- if isinstance(other, (set, frozenset)):
- return self._args_set == other
- return super().__eq__(other)
- __hash__ : Callable[[Basic], Any] = Basic.__hash__
- _sympy_converter[set] = lambda x: FiniteSet(*x)
- _sympy_converter[frozenset] = lambda x: FiniteSet(*x)
- class SymmetricDifference(Set):
- """Represents the set of elements which are in either of the
- sets and not in their intersection.
- Examples
- ========
- >>> from sympy import SymmetricDifference, FiniteSet
- >>> SymmetricDifference(FiniteSet(1, 2, 3), FiniteSet(3, 4, 5))
- {1, 2, 4, 5}
- See Also
- ========
- Complement, Union
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Symmetric_difference
- """
- is_SymmetricDifference = True
- def __new__(cls, a, b, evaluate=True):
- if evaluate:
- return SymmetricDifference.reduce(a, b)
- return Basic.__new__(cls, a, b)
- @staticmethod
- def reduce(A, B):
- result = B._symmetric_difference(A)
- if result is not None:
- return result
- else:
- return SymmetricDifference(A, B, evaluate=False)
- def as_relational(self, symbol):
- """Rewrite a symmetric_difference in terms of equalities and
- logic operators"""
- A, B = self.args
- A_rel = A.as_relational(symbol)
- B_rel = B.as_relational(symbol)
- return Xor(A_rel, B_rel)
- @property
- def is_iterable(self):
- if all(arg.is_iterable for arg in self.args):
- return True
- def __iter__(self):
- args = self.args
- union = roundrobin(*(iter(arg) for arg in args))
- for item in union:
- count = 0
- for s in args:
- if item in s:
- count += 1
- if count % 2 == 1:
- yield item
- class DisjointUnion(Set):
- """ Represents the disjoint union (also known as the external disjoint union)
- of a finite number of sets.
- Examples
- ========
- >>> from sympy import DisjointUnion, FiniteSet, Interval, Union, Symbol
- >>> A = FiniteSet(1, 2, 3)
- >>> B = Interval(0, 5)
- >>> DisjointUnion(A, B)
- DisjointUnion({1, 2, 3}, Interval(0, 5))
- >>> DisjointUnion(A, B).rewrite(Union)
- Union(ProductSet({1, 2, 3}, {0}), ProductSet(Interval(0, 5), {1}))
- >>> C = FiniteSet(Symbol('x'), Symbol('y'), Symbol('z'))
- >>> DisjointUnion(C, C)
- DisjointUnion({x, y, z}, {x, y, z})
- >>> DisjointUnion(C, C).rewrite(Union)
- ProductSet({x, y, z}, {0, 1})
- References
- ==========
- https://en.wikipedia.org/wiki/Disjoint_union
- """
- def __new__(cls, *sets):
- dj_collection = []
- for set_i in sets:
- if isinstance(set_i, Set):
- dj_collection.append(set_i)
- else:
- raise TypeError("Invalid input: '%s', input args \
- to DisjointUnion must be Sets" % set_i)
- obj = Basic.__new__(cls, *dj_collection)
- return obj
- @property
- def sets(self):
- return self.args
- @property
- def is_empty(self):
- return fuzzy_and(s.is_empty for s in self.sets)
- @property
- def is_finite_set(self):
- all_finite = fuzzy_and(s.is_finite_set for s in self.sets)
- return fuzzy_or([self.is_empty, all_finite])
- @property
- def is_iterable(self):
- if self.is_empty:
- return False
- iter_flag = True
- for set_i in self.sets:
- if not set_i.is_empty:
- iter_flag = iter_flag and set_i.is_iterable
- return iter_flag
- def _eval_rewrite_as_Union(self, *sets):
- """
- Rewrites the disjoint union as the union of (``set`` x {``i``})
- where ``set`` is the element in ``sets`` at index = ``i``
- """
- dj_union = S.EmptySet
- index = 0
- for set_i in sets:
- if isinstance(set_i, Set):
- cross = ProductSet(set_i, FiniteSet(index))
- dj_union = Union(dj_union, cross)
- index = index + 1
- return dj_union
- def _contains(self, element):
- """
- ``in`` operator for DisjointUnion
- Examples
- ========
- >>> from sympy import Interval, DisjointUnion
- >>> D = DisjointUnion(Interval(0, 1), Interval(0, 2))
- >>> (0.5, 0) in D
- True
- >>> (0.5, 1) in D
- True
- >>> (1.5, 0) in D
- False
- >>> (1.5, 1) in D
- True
- Passes operation on to constituent sets
- """
- if not isinstance(element, Tuple) or len(element) != 2:
- return False
- if not element[1].is_Integer:
- return False
- if element[1] >= len(self.sets) or element[1] < 0:
- return False
- return element[0] in self.sets[element[1]]
- def __iter__(self):
- if self.is_iterable:
- iters = []
- for i, s in enumerate(self.sets):
- iters.append(iproduct(s, {Integer(i)}))
- return iter(roundrobin(*iters))
- else:
- raise ValueError("'%s' is not iterable." % self)
- def __len__(self):
- """
- Returns the length of the disjoint union, i.e., the number of elements in the set.
- Examples
- ========
- >>> from sympy import FiniteSet, DisjointUnion, EmptySet
- >>> D1 = DisjointUnion(FiniteSet(1, 2, 3, 4), EmptySet, FiniteSet(3, 4, 5))
- >>> len(D1)
- 7
- >>> D2 = DisjointUnion(FiniteSet(3, 5, 7), EmptySet, FiniteSet(3, 5, 7))
- >>> len(D2)
- 6
- >>> D3 = DisjointUnion(EmptySet, EmptySet)
- >>> len(D3)
- 0
- Adds up the lengths of the constituent sets.
- """
- if self.is_finite_set:
- size = 0
- for set in self.sets:
- size += len(set)
- return size
- else:
- raise ValueError("'%s' is not a finite set." % self)
- def imageset(*args):
- r"""
- Return an image of the set under transformation ``f``.
- Explanation
- ===========
- If this function cannot compute the image, it returns an
- unevaluated ImageSet object.
- .. math::
- \{ f(x) \mid x \in \mathrm{self} \}
- Examples
- ========
- >>> from sympy import S, Interval, imageset, sin, Lambda
- >>> from sympy.abc import x
- >>> imageset(x, 2*x, Interval(0, 2))
- Interval(0, 4)
- >>> imageset(lambda x: 2*x, Interval(0, 2))
- Interval(0, 4)
- >>> imageset(Lambda(x, sin(x)), Interval(-2, 1))
- ImageSet(Lambda(x, sin(x)), Interval(-2, 1))
- >>> imageset(sin, Interval(-2, 1))
- ImageSet(Lambda(x, sin(x)), Interval(-2, 1))
- >>> imageset(lambda y: x + y, Interval(-2, 1))
- ImageSet(Lambda(y, x + y), Interval(-2, 1))
- Expressions applied to the set of Integers are simplified
- to show as few negatives as possible and linear expressions
- are converted to a canonical form. If this is not desirable
- then the unevaluated ImageSet should be used.
- >>> imageset(x, -2*x + 5, S.Integers)
- ImageSet(Lambda(x, 2*x + 1), Integers)
- See Also
- ========
- sympy.sets.fancysets.ImageSet
- """
- from .fancysets import ImageSet
- from .setexpr import set_function
- if len(args) < 2:
- raise ValueError('imageset expects at least 2 args, got: %s' % len(args))
- if isinstance(args[0], (Symbol, tuple)) and len(args) > 2:
- f = Lambda(args[0], args[1])
- set_list = args[2:]
- else:
- f = args[0]
- set_list = args[1:]
- if isinstance(f, Lambda):
- pass
- elif callable(f):
- nargs = getattr(f, 'nargs', {})
- if nargs:
- if len(nargs) != 1:
- raise NotImplementedError(filldedent('''
- This function can take more than 1 arg
- but the potentially complicated set input
- has not been analyzed at this point to
- know its dimensions. TODO
- '''))
- N = nargs.args[0]
- if N == 1:
- s = 'x'
- else:
- s = [Symbol('x%i' % i) for i in range(1, N + 1)]
- else:
- s = inspect.signature(f).parameters
- dexpr = _sympify(f(*[Dummy() for i in s]))
- var = tuple(uniquely_named_symbol(
- Symbol(i), dexpr) for i in s)
- f = Lambda(var, f(*var))
- else:
- raise TypeError(filldedent('''
- expecting lambda, Lambda, or FunctionClass,
- not \'%s\'.''' % func_name(f)))
- if any(not isinstance(s, Set) for s in set_list):
- name = [func_name(s) for s in set_list]
- raise ValueError(
- 'arguments after mapping should be sets, not %s' % name)
- if len(set_list) == 1:
- set = set_list[0]
- try:
- # TypeError if arg count != set dimensions
- r = set_function(f, set)
- if r is None:
- raise TypeError
- if not r:
- return r
- except TypeError:
- r = ImageSet(f, set)
- if isinstance(r, ImageSet):
- f, set = r.args
- if f.variables[0] == f.expr:
- return set
- if isinstance(set, ImageSet):
- # XXX: Maybe this should just be:
- # f2 = set.lambda
- # fun = Lambda(f2.signature, f(*f2.expr))
- # return imageset(fun, *set.base_sets)
- if len(set.lamda.variables) == 1 and len(f.variables) == 1:
- x = set.lamda.variables[0]
- y = f.variables[0]
- return imageset(
- Lambda(x, f.expr.subs(y, set.lamda.expr)), *set.base_sets)
- if r is not None:
- return r
- return ImageSet(f, *set_list)
- def is_function_invertible_in_set(func, setv):
- """
- Checks whether function ``func`` is invertible when the domain is
- restricted to set ``setv``.
- """
- from sympy.functions.elementary.exponential import exp, log
- # Functions known to always be invertible:
- if func in (exp, log):
- return True
- u = Dummy("u")
- fdiff = func(u).diff(u)
- # monotonous functions:
- # TODO: check subsets (`func` in `setv`)
- if (fdiff > 0) == True or (fdiff < 0) == True:
- return True
- # TODO: support more
- return None
- def simplify_union(args):
- """
- Simplify a :class:`Union` using known rules.
- Explanation
- ===========
- 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. This process depends
- on ``union_sets(a, b)`` functions.
- """
- from sympy.sets.handlers.union import union_sets
- # ===== Global Rules =====
- if not args:
- return S.EmptySet
- for arg in args:
- if not isinstance(arg, Set):
- raise TypeError("Input args to Union must be Sets")
- # Merge all finite sets
- finite_sets = [x for x in args if x.is_FiniteSet]
- if len(finite_sets) > 1:
- a = (x for set in finite_sets for x in set)
- finite_set = FiniteSet(*a)
- args = [finite_set] + [x for x in args if not x.is_FiniteSet]
- # ===== Pair-wise Rules =====
- # Here we depend on rules built into the constituent sets
- args = set(args)
- new_args = True
- while new_args:
- for s in args:
- new_args = False
- for t in args - {s}:
- new_set = union_sets(s, t)
- # This returns None if s does not know how to intersect
- # with t. Returns the newly intersected set otherwise
- if new_set is not None:
- if not isinstance(new_set, set):
- new_set = {new_set}
- new_args = (args - {s, t}).union(new_set)
- break
- if new_args:
- args = new_args
- break
- if len(args) == 1:
- return args.pop()
- else:
- return Union(*args, evaluate=False)
- def simplify_intersection(args):
- """
- Simplify an intersection using known rules.
- Explanation
- ===========
- 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 not args:
- return S.UniversalSet
- for arg in args:
- if not isinstance(arg, Set):
- raise TypeError("Input args to Union must be Sets")
- # If any EmptySets return EmptySet
- if S.EmptySet in args:
- return S.EmptySet
- # Handle Finite sets
- rv = Intersection._handle_finite_sets(args)
- if rv is not None:
- return rv
- # If any of the sets are unions, return a Union of Intersections
- for s in args:
- if s.is_Union:
- other_sets = set(args) - {s}
- if len(other_sets) > 0:
- other = Intersection(*other_sets)
- return Union(*(Intersection(arg, other) for arg in s.args))
- else:
- return Union(*[arg for arg in s.args])
- for s in args:
- if s.is_Complement:
- args.remove(s)
- other_sets = args + [s.args[0]]
- return Complement(Intersection(*other_sets), s.args[1])
- from sympy.sets.handlers.intersection import intersection_sets
- # 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 sets
- args = set(args)
- new_args = True
- while new_args:
- for s in args:
- new_args = False
- for t in args - {s}:
- new_set = intersection_sets(s, t)
- # This returns None if s does not know how to intersect
- # with t. Returns the newly intersected set otherwise
- if new_set is not None:
- new_args = (args - {s, t}).union({new_set})
- break
- if new_args:
- args = new_args
- break
- if len(args) == 1:
- return args.pop()
- else:
- return Intersection(*args, evaluate=False)
- def _handle_finite_sets(op, x, y, commutative):
- # Handle finite sets:
- fs_args, other = sift([x, y], lambda x: isinstance(x, FiniteSet), binary=True)
- if len(fs_args) == 2:
- return FiniteSet(*[op(i, j) for i in fs_args[0] for j in fs_args[1]])
- elif len(fs_args) == 1:
- sets = [_apply_operation(op, other[0], i, commutative) for i in fs_args[0]]
- return Union(*sets)
- else:
- return None
- def _apply_operation(op, x, y, commutative):
- from .fancysets import ImageSet
- d = Dummy('d')
- out = _handle_finite_sets(op, x, y, commutative)
- if out is None:
- out = op(x, y)
- if out is None and commutative:
- out = op(y, x)
- if out is None:
- _x, _y = symbols("x y")
- if isinstance(x, Set) and not isinstance(y, Set):
- out = ImageSet(Lambda(d, op(d, y)), x).doit()
- elif not isinstance(x, Set) and isinstance(y, Set):
- out = ImageSet(Lambda(d, op(x, d)), y).doit()
- else:
- out = ImageSet(Lambda((_x, _y), op(_x, _y)), x, y)
- return out
- def set_add(x, y):
- from sympy.sets.handlers.add import _set_add
- return _apply_operation(_set_add, x, y, commutative=True)
- def set_sub(x, y):
- from sympy.sets.handlers.add import _set_sub
- return _apply_operation(_set_sub, x, y, commutative=False)
- def set_mul(x, y):
- from sympy.sets.handlers.mul import _set_mul
- return _apply_operation(_set_mul, x, y, commutative=True)
- def set_div(x, y):
- from sympy.sets.handlers.mul import _set_div
- return _apply_operation(_set_div, x, y, commutative=False)
- def set_pow(x, y):
- from sympy.sets.handlers.power import _set_pow
- return _apply_operation(_set_pow, x, y, commutative=False)
- def set_function(f, x):
- from sympy.sets.handlers.functions import _set_function
- return _set_function(f, x)
|