boolalg.py 112 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587
  1. """
  2. Boolean algebra module for SymPy
  3. """
  4. from __future__ import annotations
  5. from typing import TYPE_CHECKING, overload, Any
  6. from collections.abc import Iterable, Mapping
  7. from collections import defaultdict
  8. from itertools import chain, combinations, product, permutations
  9. from sympy.core.add import Add
  10. from sympy.core.basic import Basic
  11. from sympy.core.cache import cacheit
  12. from sympy.core.containers import Tuple
  13. from sympy.core.decorators import sympify_method_args, sympify_return
  14. from sympy.core.function import Application, Derivative
  15. from sympy.core.kind import BooleanKind, NumberKind
  16. from sympy.core.numbers import Number
  17. from sympy.core.operations import LatticeOp
  18. from sympy.core.singleton import Singleton, S
  19. from sympy.core.sorting import ordered
  20. from sympy.core.sympify import _sympy_converter, _sympify, sympify
  21. from sympy.utilities.iterables import sift, ibin
  22. from sympy.utilities.misc import filldedent
  23. def as_Boolean(e):
  24. """Like ``bool``, return the Boolean value of an expression, e,
  25. which can be any instance of :py:class:`~.Boolean` or ``bool``.
  26. Examples
  27. ========
  28. >>> from sympy import true, false, nan
  29. >>> from sympy.logic.boolalg import as_Boolean
  30. >>> from sympy.abc import x
  31. >>> as_Boolean(0) is false
  32. True
  33. >>> as_Boolean(1) is true
  34. True
  35. >>> as_Boolean(x)
  36. x
  37. >>> as_Boolean(2)
  38. Traceback (most recent call last):
  39. ...
  40. TypeError: expecting bool or Boolean, not `2`.
  41. >>> as_Boolean(nan)
  42. Traceback (most recent call last):
  43. ...
  44. TypeError: expecting bool or Boolean, not `nan`.
  45. """
  46. from sympy.core.symbol import Symbol
  47. if e == True:
  48. return true
  49. if e == False:
  50. return false
  51. if isinstance(e, Symbol):
  52. z = e.is_zero
  53. if z is None:
  54. return e
  55. return false if z else true
  56. if isinstance(e, Boolean):
  57. return e
  58. raise TypeError('expecting bool or Boolean, not `%s`.' % e)
  59. @sympify_method_args
  60. class Boolean(Basic):
  61. """A Boolean object is an object for which logic operations make sense."""
  62. __slots__ = ()
  63. kind = BooleanKind
  64. if TYPE_CHECKING:
  65. def __new__(cls, *args: Basic | complex) -> Boolean:
  66. ...
  67. @overload # type: ignore
  68. def subs(self, arg1: Mapping[Basic | complex, Boolean | complex], arg2: None=None) -> Boolean: ...
  69. @overload
  70. def subs(self, arg1: Iterable[tuple[Basic | complex, Boolean | complex]], arg2: None=None, **kwargs: Any) -> Boolean: ...
  71. @overload
  72. def subs(self, arg1: Boolean | complex, arg2: Boolean | complex) -> Boolean: ...
  73. @overload
  74. def subs(self, arg1: Mapping[Basic | complex, Basic | complex], arg2: None=None, **kwargs: Any) -> Basic: ...
  75. @overload
  76. def subs(self, arg1: Iterable[tuple[Basic | complex, Basic | complex]], arg2: None=None, **kwargs: Any) -> Basic: ...
  77. @overload
  78. def subs(self, arg1: Basic | complex, arg2: Basic | complex, **kwargs: Any) -> Basic: ...
  79. def subs(self, arg1: Mapping[Basic | complex, Basic | complex] | Basic | complex, # type: ignore
  80. arg2: Basic | complex | None = None, **kwargs: Any) -> Basic:
  81. ...
  82. def simplify(self, **kwargs) -> Boolean:
  83. ...
  84. @sympify_return([('other', 'Boolean')], NotImplemented)
  85. def __and__(self, other):
  86. return And(self, other)
  87. __rand__ = __and__
  88. @sympify_return([('other', 'Boolean')], NotImplemented)
  89. def __or__(self, other):
  90. return Or(self, other)
  91. __ror__ = __or__
  92. def __invert__(self):
  93. """Overloading for ~"""
  94. return Not(self)
  95. @sympify_return([('other', 'Boolean')], NotImplemented)
  96. def __rshift__(self, other):
  97. return Implies(self, other)
  98. @sympify_return([('other', 'Boolean')], NotImplemented)
  99. def __lshift__(self, other):
  100. return Implies(other, self)
  101. __rrshift__ = __lshift__
  102. __rlshift__ = __rshift__
  103. @sympify_return([('other', 'Boolean')], NotImplemented)
  104. def __xor__(self, other):
  105. return Xor(self, other)
  106. __rxor__ = __xor__
  107. def equals(self, other):
  108. """
  109. Returns ``True`` if the given formulas have the same truth table.
  110. For two formulas to be equal they must have the same literals.
  111. Examples
  112. ========
  113. >>> from sympy.abc import A, B, C
  114. >>> from sympy import And, Or, Not
  115. >>> (A >> B).equals(~B >> ~A)
  116. True
  117. >>> Not(And(A, B, C)).equals(And(Not(A), Not(B), Not(C)))
  118. False
  119. >>> Not(And(A, Not(A))).equals(Or(B, Not(B)))
  120. False
  121. """
  122. from sympy.logic.inference import satisfiable
  123. from sympy.core.relational import Relational
  124. if self.has(Relational) or other.has(Relational):
  125. raise NotImplementedError('handling of relationals')
  126. return self.atoms() == other.atoms() and \
  127. not satisfiable(Not(Equivalent(self, other)))
  128. def to_nnf(self, simplify=True):
  129. # override where necessary
  130. return self
  131. def as_set(self):
  132. """
  133. Rewrites Boolean expression in terms of real sets.
  134. Examples
  135. ========
  136. >>> from sympy import Symbol, Eq, Or, And
  137. >>> x = Symbol('x', real=True)
  138. >>> Eq(x, 0).as_set()
  139. {0}
  140. >>> (x > 0).as_set()
  141. Interval.open(0, oo)
  142. >>> And(-2 < x, x < 2).as_set()
  143. Interval.open(-2, 2)
  144. >>> Or(x < -2, 2 < x).as_set()
  145. Union(Interval.open(-oo, -2), Interval.open(2, oo))
  146. """
  147. from sympy.calculus.util import periodicity
  148. from sympy.core.relational import Relational
  149. free = self.free_symbols
  150. if len(free) == 1:
  151. x = free.pop()
  152. if x.kind is NumberKind:
  153. reps = {}
  154. for r in self.atoms(Relational):
  155. if periodicity(r, x) not in (0, None):
  156. s = r._eval_as_set()
  157. if s in (S.EmptySet, S.UniversalSet, S.Reals):
  158. reps[r] = s.as_relational(x)
  159. continue
  160. raise NotImplementedError(filldedent('''
  161. as_set is not implemented for relationals
  162. with periodic solutions
  163. '''))
  164. new = self.subs(reps)
  165. if new.func != self.func:
  166. return new.as_set() # restart with new obj
  167. else:
  168. return new._eval_as_set()
  169. return self._eval_as_set()
  170. else:
  171. raise NotImplementedError("Sorry, as_set has not yet been"
  172. " implemented for multivariate"
  173. " expressions")
  174. @property
  175. def binary_symbols(self):
  176. from sympy.core.relational import Eq, Ne
  177. return set().union(*[i.binary_symbols for i in self.args
  178. if i.is_Boolean or i.is_Symbol
  179. or isinstance(i, (Eq, Ne))])
  180. def _eval_refine(self, assumptions):
  181. from sympy.assumptions import ask
  182. ret = ask(self, assumptions)
  183. if ret is True:
  184. return true
  185. elif ret is False:
  186. return false
  187. return None
  188. class BooleanAtom(Boolean):
  189. """
  190. Base class of :py:class:`~.BooleanTrue` and :py:class:`~.BooleanFalse`.
  191. """
  192. is_Boolean = True
  193. is_Atom = True
  194. _op_priority = 11 # higher than Expr
  195. def simplify(self, *a, **kw):
  196. return self
  197. def expand(self, *a, **kw):
  198. return self
  199. @property
  200. def canonical(self):
  201. return self
  202. def _noop(self, other=None):
  203. raise TypeError('BooleanAtom not allowed in this context.')
  204. __add__ = _noop
  205. __radd__ = _noop
  206. __sub__ = _noop
  207. __rsub__ = _noop
  208. __mul__ = _noop
  209. __rmul__ = _noop
  210. __pow__ = _noop
  211. __rpow__ = _noop
  212. __truediv__ = _noop
  213. __rtruediv__ = _noop
  214. __mod__ = _noop
  215. __rmod__ = _noop
  216. _eval_power = _noop
  217. def __lt__(self, other):
  218. raise TypeError(filldedent('''
  219. A Boolean argument can only be used in
  220. Eq and Ne; all other relationals expect
  221. real expressions.
  222. '''))
  223. __le__ = __lt__
  224. __gt__ = __lt__
  225. __ge__ = __lt__
  226. # \\\
  227. def _eval_simplify(self, **kwargs):
  228. return self
  229. class BooleanTrue(BooleanAtom, metaclass=Singleton):
  230. """
  231. SymPy version of ``True``, a singleton that can be accessed via ``S.true``.
  232. This is the SymPy version of ``True``, for use in the logic module. The
  233. primary advantage of using ``true`` instead of ``True`` is that shorthand Boolean
  234. operations like ``~`` and ``>>`` will work as expected on this class, whereas with
  235. True they act bitwise on 1. Functions in the logic module will return this
  236. class when they evaluate to true.
  237. Notes
  238. =====
  239. There is liable to be some confusion as to when ``True`` should
  240. be used and when ``S.true`` should be used in various contexts
  241. throughout SymPy. An important thing to remember is that
  242. ``sympify(True)`` returns ``S.true``. This means that for the most
  243. part, you can just use ``True`` and it will automatically be converted
  244. to ``S.true`` when necessary, similar to how you can generally use 1
  245. instead of ``S.One``.
  246. The rule of thumb is:
  247. "If the boolean in question can be replaced by an arbitrary symbolic
  248. ``Boolean``, like ``Or(x, y)`` or ``x > 1``, use ``S.true``.
  249. Otherwise, use ``True``"
  250. In other words, use ``S.true`` only on those contexts where the
  251. boolean is being used as a symbolic representation of truth.
  252. For example, if the object ends up in the ``.args`` of any expression,
  253. then it must necessarily be ``S.true`` instead of ``True``, as
  254. elements of ``.args`` must be ``Basic``. On the other hand,
  255. ``==`` is not a symbolic operation in SymPy, since it always returns
  256. ``True`` or ``False``, and does so in terms of structural equality
  257. rather than mathematical, so it should return ``True``. The assumptions
  258. system should use ``True`` and ``False``. Aside from not satisfying
  259. the above rule of thumb, the assumptions system uses a three-valued logic
  260. (``True``, ``False``, ``None``), whereas ``S.true`` and ``S.false``
  261. represent a two-valued logic. When in doubt, use ``True``.
  262. "``S.true == True is True``."
  263. While "``S.true is True``" is ``False``, "``S.true == True``"
  264. is ``True``, so if there is any doubt over whether a function or
  265. expression will return ``S.true`` or ``True``, just use ``==``
  266. instead of ``is`` to do the comparison, and it will work in either
  267. case. Finally, for boolean flags, it's better to just use ``if x``
  268. instead of ``if x is True``. To quote PEP 8:
  269. Do not compare boolean values to ``True`` or ``False``
  270. using ``==``.
  271. * Yes: ``if greeting:``
  272. * No: ``if greeting == True:``
  273. * Worse: ``if greeting is True:``
  274. Examples
  275. ========
  276. >>> from sympy import sympify, true, false, Or
  277. >>> sympify(True)
  278. True
  279. >>> _ is True, _ is true
  280. (False, True)
  281. >>> Or(true, false)
  282. True
  283. >>> _ is true
  284. True
  285. Python operators give a boolean result for true but a
  286. bitwise result for True
  287. >>> ~true, ~True # doctest: +SKIP
  288. (False, -2)
  289. >>> true >> true, True >> True
  290. (True, 0)
  291. See Also
  292. ========
  293. sympy.logic.boolalg.BooleanFalse
  294. """
  295. def __bool__(self):
  296. return True
  297. def __hash__(self):
  298. return hash(True)
  299. def __eq__(self, other):
  300. if other is True:
  301. return True
  302. if other is False:
  303. return False
  304. return super().__eq__(other)
  305. @property
  306. def negated(self):
  307. return false
  308. def as_set(self):
  309. """
  310. Rewrite logic operators and relationals in terms of real sets.
  311. Examples
  312. ========
  313. >>> from sympy import true
  314. >>> true.as_set()
  315. UniversalSet
  316. """
  317. return S.UniversalSet
  318. class BooleanFalse(BooleanAtom, metaclass=Singleton):
  319. """
  320. SymPy version of ``False``, a singleton that can be accessed via ``S.false``.
  321. This is the SymPy version of ``False``, for use in the logic module. The
  322. primary advantage of using ``false`` instead of ``False`` is that shorthand
  323. Boolean operations like ``~`` and ``>>`` will work as expected on this class,
  324. whereas with ``False`` they act bitwise on 0. Functions in the logic module
  325. will return this class when they evaluate to false.
  326. Notes
  327. ======
  328. See the notes section in :py:class:`sympy.logic.boolalg.BooleanTrue`
  329. Examples
  330. ========
  331. >>> from sympy import sympify, true, false, Or
  332. >>> sympify(False)
  333. False
  334. >>> _ is False, _ is false
  335. (False, True)
  336. >>> Or(true, false)
  337. True
  338. >>> _ is true
  339. True
  340. Python operators give a boolean result for false but a
  341. bitwise result for False
  342. >>> ~false, ~False # doctest: +SKIP
  343. (True, -1)
  344. >>> false >> false, False >> False
  345. (True, 0)
  346. See Also
  347. ========
  348. sympy.logic.boolalg.BooleanTrue
  349. """
  350. def __bool__(self):
  351. return False
  352. def __hash__(self):
  353. return hash(False)
  354. def __eq__(self, other):
  355. if other is True:
  356. return False
  357. if other is False:
  358. return True
  359. return super().__eq__(other)
  360. @property
  361. def negated(self):
  362. return true
  363. def as_set(self):
  364. """
  365. Rewrite logic operators and relationals in terms of real sets.
  366. Examples
  367. ========
  368. >>> from sympy import false
  369. >>> false.as_set()
  370. EmptySet
  371. """
  372. return S.EmptySet
  373. true = BooleanTrue()
  374. false = BooleanFalse()
  375. # We want S.true and S.false to work, rather than S.BooleanTrue and
  376. # S.BooleanFalse, but making the class and instance names the same causes some
  377. # major issues (like the inability to import the class directly from this
  378. # file).
  379. S.true = true
  380. S.false = false
  381. _sympy_converter[bool] = lambda x: true if x else false
  382. class BooleanFunction(Application, Boolean):
  383. """Boolean function is a function that lives in a boolean space
  384. It is used as base class for :py:class:`~.And`, :py:class:`~.Or`,
  385. :py:class:`~.Not`, etc.
  386. """
  387. is_Boolean = True
  388. def _eval_simplify(self, **kwargs):
  389. rv = simplify_univariate(self)
  390. if not isinstance(rv, BooleanFunction):
  391. return rv.simplify(**kwargs)
  392. rv = rv.func(*[a.simplify(**kwargs) for a in rv.args])
  393. return simplify_logic(rv)
  394. def simplify(self, **kwargs):
  395. from sympy.simplify.simplify import simplify
  396. return simplify(self, **kwargs)
  397. def __lt__(self, other):
  398. raise TypeError(filldedent('''
  399. A Boolean argument can only be used in
  400. Eq and Ne; all other relationals expect
  401. real expressions.
  402. '''))
  403. __le__ = __lt__
  404. __ge__ = __lt__
  405. __gt__ = __lt__
  406. @classmethod
  407. def binary_check_and_simplify(self, *args):
  408. return [as_Boolean(i) for i in args]
  409. def to_nnf(self, simplify=True):
  410. return self._to_nnf(*self.args, simplify=simplify)
  411. def to_anf(self, deep=True):
  412. return self._to_anf(*self.args, deep=deep)
  413. @classmethod
  414. def _to_nnf(cls, *args, **kwargs):
  415. simplify = kwargs.get('simplify', True)
  416. argset = set()
  417. for arg in args:
  418. if not is_literal(arg):
  419. arg = arg.to_nnf(simplify)
  420. if simplify:
  421. if isinstance(arg, cls):
  422. arg = arg.args
  423. else:
  424. arg = (arg,)
  425. for a in arg:
  426. if Not(a) in argset:
  427. return cls.zero
  428. argset.add(a)
  429. else:
  430. argset.add(arg)
  431. return cls(*argset)
  432. @classmethod
  433. def _to_anf(cls, *args, **kwargs):
  434. deep = kwargs.get('deep', True)
  435. new_args = []
  436. for arg in args:
  437. if deep:
  438. if not is_literal(arg) or isinstance(arg, Not):
  439. arg = arg.to_anf(deep=deep)
  440. new_args.append(arg)
  441. return cls(*new_args, remove_true=False)
  442. # the diff method below is copied from Expr class
  443. def diff(self, *symbols, **assumptions):
  444. assumptions.setdefault("evaluate", True)
  445. return Derivative(self, *symbols, **assumptions)
  446. def _eval_derivative(self, x):
  447. if x in self.binary_symbols:
  448. from sympy.core.relational import Eq
  449. from sympy.functions.elementary.piecewise import Piecewise
  450. return Piecewise(
  451. (0, Eq(self.subs(x, 0), self.subs(x, 1))),
  452. (1, True))
  453. elif x in self.free_symbols:
  454. # not implemented, see https://www.encyclopediaofmath.org/
  455. # index.php/Boolean_differential_calculus
  456. pass
  457. else:
  458. return S.Zero
  459. class And(LatticeOp, BooleanFunction):
  460. """
  461. Logical AND function.
  462. It evaluates its arguments in order, returning false immediately
  463. when an argument is false and true if they are all true.
  464. Examples
  465. ========
  466. >>> from sympy.abc import x, y
  467. >>> from sympy import And
  468. >>> x & y
  469. x & y
  470. Notes
  471. =====
  472. The ``&`` operator is provided as a convenience, but note that its use
  473. here is different from its normal use in Python, which is bitwise
  474. and. Hence, ``And(a, b)`` and ``a & b`` will produce different results if
  475. ``a`` and ``b`` are integers.
  476. >>> And(x, y).subs(x, 1)
  477. y
  478. """
  479. zero = false
  480. identity = true
  481. nargs = None
  482. if TYPE_CHECKING:
  483. def __new__(cls, *args: Boolean | bool) -> Boolean: # type: ignore
  484. ...
  485. @property
  486. def args(self) -> tuple[Boolean, ...]:
  487. ...
  488. @classmethod
  489. def _new_args_filter(cls, args):
  490. args = BooleanFunction.binary_check_and_simplify(*args)
  491. args = LatticeOp._new_args_filter(args, And)
  492. newargs = []
  493. rel = set()
  494. for x in ordered(args):
  495. if x.is_Relational:
  496. c = x.canonical
  497. if c in rel:
  498. continue
  499. elif c.negated.canonical in rel:
  500. return [false]
  501. else:
  502. rel.add(c)
  503. newargs.append(x)
  504. return newargs
  505. def _eval_subs(self, old, new):
  506. args = []
  507. bad = None
  508. for i in self.args:
  509. try:
  510. i = i.subs(old, new)
  511. except TypeError:
  512. # store TypeError
  513. if bad is None:
  514. bad = i
  515. continue
  516. if i == False:
  517. return false
  518. elif i != True:
  519. args.append(i)
  520. if bad is not None:
  521. # let it raise
  522. bad.subs(old, new)
  523. # If old is And, replace the parts of the arguments with new if all
  524. # are there
  525. if isinstance(old, And):
  526. old_set = set(old.args)
  527. if old_set.issubset(args):
  528. args = set(args) - old_set
  529. args.add(new)
  530. return self.func(*args)
  531. def _eval_simplify(self, **kwargs):
  532. from sympy.core.relational import Equality, Relational
  533. from sympy.solvers.solveset import linear_coeffs
  534. # standard simplify
  535. rv = super()._eval_simplify(**kwargs)
  536. if not isinstance(rv, And):
  537. return rv
  538. # simplify args that are equalities involving
  539. # symbols so x == 0 & x == y -> x==0 & y == 0
  540. Rel, nonRel = sift(rv.args, lambda i: isinstance(i, Relational),
  541. binary=True)
  542. if not Rel:
  543. return rv
  544. eqs, other = sift(Rel, lambda i: isinstance(i, Equality), binary=True)
  545. measure = kwargs['measure']
  546. if eqs:
  547. ratio = kwargs['ratio']
  548. reps = {}
  549. sifted = {}
  550. # group by length of free symbols
  551. sifted = sift(ordered([
  552. (i.free_symbols, i) for i in eqs]),
  553. lambda x: len(x[0]))
  554. eqs = []
  555. nonlineqs = []
  556. while 1 in sifted:
  557. for free, e in sifted.pop(1):
  558. x = free.pop()
  559. if (e.lhs != x or x in e.rhs.free_symbols) and x not in reps:
  560. try:
  561. m, b = linear_coeffs(
  562. Add(e.lhs, -e.rhs, evaluate=False), x)
  563. enew = e.func(x, -b/m)
  564. if measure(enew) <= ratio*measure(e):
  565. e = enew
  566. else:
  567. eqs.append(e)
  568. continue
  569. except ValueError:
  570. pass
  571. if x in reps:
  572. eqs.append(e.subs(x, reps[x]))
  573. elif e.lhs == x and x not in e.rhs.free_symbols:
  574. reps[x] = e.rhs
  575. eqs.append(e)
  576. else:
  577. # x is not yet identified, but may be later
  578. nonlineqs.append(e)
  579. resifted = defaultdict(list)
  580. for k in sifted:
  581. for f, e in sifted[k]:
  582. e = e.xreplace(reps)
  583. f = e.free_symbols
  584. resifted[len(f)].append((f, e))
  585. sifted = resifted
  586. for k in sifted:
  587. eqs.extend([e for f, e in sifted[k]])
  588. nonlineqs = [ei.subs(reps) for ei in nonlineqs]
  589. other = [ei.subs(reps) for ei in other]
  590. rv = rv.func(*([i.canonical for i in (eqs + nonlineqs + other)] + nonRel))
  591. patterns = _simplify_patterns_and()
  592. threeterm_patterns = _simplify_patterns_and3()
  593. return _apply_patternbased_simplification(rv, patterns,
  594. measure, false,
  595. threeterm_patterns=threeterm_patterns)
  596. def _eval_as_set(self):
  597. from sympy.sets.sets import Intersection
  598. return Intersection(*[arg.as_set() for arg in self.args])
  599. def _eval_rewrite_as_Nor(self, *args, **kwargs):
  600. return Nor(*[Not(arg) for arg in self.args])
  601. def to_anf(self, deep=True):
  602. if deep:
  603. result = And._to_anf(*self.args, deep=deep)
  604. return distribute_xor_over_and(result)
  605. return self
  606. class Or(LatticeOp, BooleanFunction):
  607. """
  608. Logical OR function
  609. It evaluates its arguments in order, returning true immediately
  610. when an argument is true, and false if they are all false.
  611. Examples
  612. ========
  613. >>> from sympy.abc import x, y
  614. >>> from sympy import Or
  615. >>> x | y
  616. x | y
  617. Notes
  618. =====
  619. The ``|`` operator is provided as a convenience, but note that its use
  620. here is different from its normal use in Python, which is bitwise
  621. or. Hence, ``Or(a, b)`` and ``a | b`` will return different things if
  622. ``a`` and ``b`` are integers.
  623. >>> Or(x, y).subs(x, 0)
  624. y
  625. """
  626. zero = true
  627. identity = false
  628. if TYPE_CHECKING:
  629. def __new__(cls, *args: Boolean | bool) -> Boolean: # type: ignore
  630. ...
  631. @property
  632. def args(self) -> tuple[Boolean, ...]:
  633. ...
  634. @classmethod
  635. def _new_args_filter(cls, args):
  636. newargs = []
  637. rel = []
  638. args = BooleanFunction.binary_check_and_simplify(*args)
  639. for x in args:
  640. if x.is_Relational:
  641. c = x.canonical
  642. if c in rel:
  643. continue
  644. nc = c.negated.canonical
  645. if any(r == nc for r in rel):
  646. return [true]
  647. rel.append(c)
  648. newargs.append(x)
  649. return LatticeOp._new_args_filter(newargs, Or)
  650. def _eval_subs(self, old, new):
  651. args = []
  652. bad = None
  653. for i in self.args:
  654. try:
  655. i = i.subs(old, new)
  656. except TypeError:
  657. # store TypeError
  658. if bad is None:
  659. bad = i
  660. continue
  661. if i == True:
  662. return true
  663. elif i != False:
  664. args.append(i)
  665. if bad is not None:
  666. # let it raise
  667. bad.subs(old, new)
  668. # If old is Or, replace the parts of the arguments with new if all
  669. # are there
  670. if isinstance(old, Or):
  671. old_set = set(old.args)
  672. if old_set.issubset(args):
  673. args = set(args) - old_set
  674. args.add(new)
  675. return self.func(*args)
  676. def _eval_as_set(self):
  677. from sympy.sets.sets import Union
  678. return Union(*[arg.as_set() for arg in self.args])
  679. def _eval_rewrite_as_Nand(self, *args, **kwargs):
  680. return Nand(*[Not(arg) for arg in self.args])
  681. def _eval_simplify(self, **kwargs):
  682. from sympy.core.relational import Le, Ge, Eq
  683. lege = self.atoms(Le, Ge)
  684. if lege:
  685. reps = {i: self.func(
  686. Eq(i.lhs, i.rhs), i.strict) for i in lege}
  687. return self.xreplace(reps)._eval_simplify(**kwargs)
  688. # standard simplify
  689. rv = super()._eval_simplify(**kwargs)
  690. if not isinstance(rv, Or):
  691. return rv
  692. patterns = _simplify_patterns_or()
  693. return _apply_patternbased_simplification(rv, patterns,
  694. kwargs['measure'], true)
  695. def to_anf(self, deep=True):
  696. args = range(1, len(self.args) + 1)
  697. args = (combinations(self.args, j) for j in args)
  698. args = chain.from_iterable(args) # powerset
  699. args = (And(*arg) for arg in args)
  700. args = (to_anf(x, deep=deep) if deep else x for x in args)
  701. return Xor(*list(args), remove_true=False)
  702. class Not(BooleanFunction):
  703. """
  704. Logical Not function (negation)
  705. Returns ``true`` if the statement is ``false`` or ``False``.
  706. Returns ``false`` if the statement is ``true`` or ``True``.
  707. Examples
  708. ========
  709. >>> from sympy import Not, And, Or
  710. >>> from sympy.abc import x, A, B
  711. >>> Not(True)
  712. False
  713. >>> Not(False)
  714. True
  715. >>> Not(And(True, False))
  716. True
  717. >>> Not(Or(True, False))
  718. False
  719. >>> Not(And(And(True, x), Or(x, False)))
  720. ~x
  721. >>> ~x
  722. ~x
  723. >>> Not(And(Or(A, B), Or(~A, ~B)))
  724. ~((A | B) & (~A | ~B))
  725. Notes
  726. =====
  727. - The ``~`` operator is provided as a convenience, but note that its use
  728. here is different from its normal use in Python, which is bitwise
  729. not. In particular, ``~a`` and ``Not(a)`` will be different if ``a`` is
  730. an integer. Furthermore, since bools in Python subclass from ``int``,
  731. ``~True`` is the same as ``~1`` which is ``-2``, which has a boolean
  732. value of True. To avoid this issue, use the SymPy boolean types
  733. ``true`` and ``false``.
  734. - As of Python 3.12, the bitwise not operator ``~`` used on a
  735. Python ``bool`` is deprecated and will emit a warning.
  736. >>> from sympy import true
  737. >>> ~True # doctest: +SKIP
  738. -2
  739. >>> ~true
  740. False
  741. """
  742. is_Not = True
  743. @classmethod
  744. def eval(cls, arg):
  745. if isinstance(arg, Number) or arg in (True, False):
  746. return false if arg else true
  747. if arg.is_Not:
  748. return arg.args[0]
  749. # Simplify Relational objects.
  750. if arg.is_Relational:
  751. return arg.negated
  752. def _eval_as_set(self):
  753. """
  754. Rewrite logic operators and relationals in terms of real sets.
  755. Examples
  756. ========
  757. >>> from sympy import Not, Symbol
  758. >>> x = Symbol('x')
  759. >>> Not(x > 0).as_set()
  760. Interval(-oo, 0)
  761. """
  762. return self.args[0].as_set().complement(S.Reals)
  763. def to_nnf(self, simplify=True):
  764. if is_literal(self):
  765. return self
  766. expr = self.args[0]
  767. func, args = expr.func, expr.args
  768. if func == And:
  769. return Or._to_nnf(*[Not(arg) for arg in args], simplify=simplify)
  770. if func == Or:
  771. return And._to_nnf(*[Not(arg) for arg in args], simplify=simplify)
  772. if func == Implies:
  773. a, b = args
  774. return And._to_nnf(a, Not(b), simplify=simplify)
  775. if func == Equivalent:
  776. return And._to_nnf(Or(*args), Or(*[Not(arg) for arg in args]),
  777. simplify=simplify)
  778. if func == Xor:
  779. result = []
  780. for i in range(1, len(args)+1, 2):
  781. for neg in combinations(args, i):
  782. clause = [Not(s) if s in neg else s for s in args]
  783. result.append(Or(*clause))
  784. return And._to_nnf(*result, simplify=simplify)
  785. if func == ITE:
  786. a, b, c = args
  787. return And._to_nnf(Or(a, Not(c)), Or(Not(a), Not(b)), simplify=simplify)
  788. raise ValueError("Illegal operator %s in expression" % func)
  789. def to_anf(self, deep=True):
  790. return Xor._to_anf(true, self.args[0], deep=deep)
  791. class Xor(BooleanFunction):
  792. """
  793. Logical XOR (exclusive OR) function.
  794. Returns True if an odd number of the arguments are True and the rest are
  795. False.
  796. Returns False if an even number of the arguments are True and the rest are
  797. False.
  798. Examples
  799. ========
  800. >>> from sympy.logic.boolalg import Xor
  801. >>> from sympy import symbols
  802. >>> x, y = symbols('x y')
  803. >>> Xor(True, False)
  804. True
  805. >>> Xor(True, True)
  806. False
  807. >>> Xor(True, False, True, True, False)
  808. True
  809. >>> Xor(True, False, True, False)
  810. False
  811. >>> x ^ y
  812. x ^ y
  813. Notes
  814. =====
  815. The ``^`` operator is provided as a convenience, but note that its use
  816. here is different from its normal use in Python, which is bitwise xor. In
  817. particular, ``a ^ b`` and ``Xor(a, b)`` will be different if ``a`` and
  818. ``b`` are integers.
  819. >>> Xor(x, y).subs(y, 0)
  820. x
  821. """
  822. def __new__(cls, *args, remove_true=True, **kwargs):
  823. argset = set()
  824. obj = super().__new__(cls, *args, **kwargs)
  825. for arg in obj._args:
  826. if isinstance(arg, Number) or arg in (True, False):
  827. if arg:
  828. arg = true
  829. else:
  830. continue
  831. if isinstance(arg, Xor):
  832. for a in arg.args:
  833. argset.remove(a) if a in argset else argset.add(a)
  834. elif arg in argset:
  835. argset.remove(arg)
  836. else:
  837. argset.add(arg)
  838. rel = [(r, r.canonical, r.negated.canonical)
  839. for r in argset if r.is_Relational]
  840. odd = False # is number of complimentary pairs odd? start 0 -> False
  841. remove = []
  842. for i, (r, c, nc) in enumerate(rel):
  843. for j in range(i + 1, len(rel)):
  844. rj, cj = rel[j][:2]
  845. if cj == nc:
  846. odd = not odd
  847. break
  848. elif cj == c:
  849. break
  850. else:
  851. continue
  852. remove.append((r, rj))
  853. if odd:
  854. argset.remove(true) if true in argset else argset.add(true)
  855. for a, b in remove:
  856. argset.remove(a)
  857. argset.remove(b)
  858. if len(argset) == 0:
  859. return false
  860. elif len(argset) == 1:
  861. return argset.pop()
  862. elif True in argset and remove_true:
  863. argset.remove(True)
  864. return Not(Xor(*argset))
  865. else:
  866. obj._args = tuple(ordered(argset))
  867. obj._argset = frozenset(argset)
  868. return obj
  869. # XXX: This should be cached on the object rather than using cacheit
  870. # Maybe it can be computed in __new__?
  871. @property # type: ignore
  872. @cacheit
  873. def args(self):
  874. return tuple(ordered(self._argset))
  875. def to_nnf(self, simplify=True):
  876. args = []
  877. for i in range(0, len(self.args)+1, 2):
  878. for neg in combinations(self.args, i):
  879. clause = [Not(s) if s in neg else s for s in self.args]
  880. args.append(Or(*clause))
  881. return And._to_nnf(*args, simplify=simplify)
  882. def _eval_rewrite_as_Or(self, *args, **kwargs):
  883. a = self.args
  884. return Or(*[_convert_to_varsSOP(x, self.args)
  885. for x in _get_odd_parity_terms(len(a))])
  886. def _eval_rewrite_as_And(self, *args, **kwargs):
  887. a = self.args
  888. return And(*[_convert_to_varsPOS(x, self.args)
  889. for x in _get_even_parity_terms(len(a))])
  890. def _eval_simplify(self, **kwargs):
  891. # as standard simplify uses simplify_logic which writes things as
  892. # And and Or, we only simplify the partial expressions before using
  893. # patterns
  894. rv = self.func(*[a.simplify(**kwargs) for a in self.args])
  895. rv = rv.to_anf()
  896. if not isinstance(rv, Xor): # This shouldn't really happen here
  897. return rv
  898. patterns = _simplify_patterns_xor()
  899. return _apply_patternbased_simplification(rv, patterns,
  900. kwargs['measure'], None)
  901. def _eval_subs(self, old, new):
  902. # If old is Xor, replace the parts of the arguments with new if all
  903. # are there
  904. if isinstance(old, Xor):
  905. old_set = set(old.args)
  906. if old_set.issubset(self.args):
  907. args = set(self.args) - old_set
  908. args.add(new)
  909. return self.func(*args)
  910. class Nand(BooleanFunction):
  911. """
  912. Logical NAND function.
  913. It evaluates its arguments in order, giving True immediately if any
  914. of them are False, and False if they are all True.
  915. Returns True if any of the arguments are False
  916. Returns False if all arguments are True
  917. Examples
  918. ========
  919. >>> from sympy.logic.boolalg import Nand
  920. >>> from sympy import symbols
  921. >>> x, y = symbols('x y')
  922. >>> Nand(False, True)
  923. True
  924. >>> Nand(True, True)
  925. False
  926. >>> Nand(x, y)
  927. ~(x & y)
  928. """
  929. @classmethod
  930. def eval(cls, *args):
  931. return Not(And(*args))
  932. class Nor(BooleanFunction):
  933. """
  934. Logical NOR function.
  935. It evaluates its arguments in order, giving False immediately if any
  936. of them are True, and True if they are all False.
  937. Returns False if any argument is True
  938. Returns True if all arguments are False
  939. Examples
  940. ========
  941. >>> from sympy.logic.boolalg import Nor
  942. >>> from sympy import symbols
  943. >>> x, y = symbols('x y')
  944. >>> Nor(True, False)
  945. False
  946. >>> Nor(True, True)
  947. False
  948. >>> Nor(False, True)
  949. False
  950. >>> Nor(False, False)
  951. True
  952. >>> Nor(x, y)
  953. ~(x | y)
  954. """
  955. @classmethod
  956. def eval(cls, *args):
  957. return Not(Or(*args))
  958. class Xnor(BooleanFunction):
  959. """
  960. Logical XNOR function.
  961. Returns False if an odd number of the arguments are True and the rest are
  962. False.
  963. Returns True if an even number of the arguments are True and the rest are
  964. False.
  965. Examples
  966. ========
  967. >>> from sympy.logic.boolalg import Xnor
  968. >>> from sympy import symbols
  969. >>> x, y = symbols('x y')
  970. >>> Xnor(True, False)
  971. False
  972. >>> Xnor(True, True)
  973. True
  974. >>> Xnor(True, False, True, True, False)
  975. False
  976. >>> Xnor(True, False, True, False)
  977. True
  978. """
  979. @classmethod
  980. def eval(cls, *args):
  981. return Not(Xor(*args))
  982. class Implies(BooleanFunction):
  983. r"""
  984. Logical implication.
  985. A implies B is equivalent to if A then B. Mathematically, it is written
  986. as `A \Rightarrow B` and is equivalent to `\neg A \vee B` or ``~A | B``.
  987. Accepts two Boolean arguments; A and B.
  988. Returns False if A is True and B is False
  989. Returns True otherwise.
  990. Examples
  991. ========
  992. >>> from sympy.logic.boolalg import Implies
  993. >>> from sympy import symbols
  994. >>> x, y = symbols('x y')
  995. >>> Implies(True, False)
  996. False
  997. >>> Implies(False, False)
  998. True
  999. >>> Implies(True, True)
  1000. True
  1001. >>> Implies(False, True)
  1002. True
  1003. >>> x >> y
  1004. Implies(x, y)
  1005. >>> y << x
  1006. Implies(x, y)
  1007. Notes
  1008. =====
  1009. The ``>>`` and ``<<`` operators are provided as a convenience, but note
  1010. that their use here is different from their normal use in Python, which is
  1011. bit shifts. Hence, ``Implies(a, b)`` and ``a >> b`` will return different
  1012. things if ``a`` and ``b`` are integers. In particular, since Python
  1013. considers ``True`` and ``False`` to be integers, ``True >> True`` will be
  1014. the same as ``1 >> 1``, i.e., 0, which has a truth value of False. To
  1015. avoid this issue, use the SymPy objects ``true`` and ``false``.
  1016. >>> from sympy import true, false
  1017. >>> True >> False
  1018. 1
  1019. >>> true >> false
  1020. False
  1021. """
  1022. @classmethod
  1023. def eval(cls, *args):
  1024. try:
  1025. newargs = []
  1026. for x in args:
  1027. if isinstance(x, Number) or x in (0, 1):
  1028. newargs.append(bool(x))
  1029. else:
  1030. newargs.append(x)
  1031. A, B = newargs
  1032. except ValueError:
  1033. raise ValueError(
  1034. "%d operand(s) used for an Implies "
  1035. "(pairs are required): %s" % (len(args), str(args)))
  1036. if A in (True, False) or B in (True, False):
  1037. return Or(Not(A), B)
  1038. elif A == B:
  1039. return true
  1040. elif A.is_Relational and B.is_Relational:
  1041. if A.canonical == B.canonical:
  1042. return true
  1043. if A.negated.canonical == B.canonical:
  1044. return B
  1045. else:
  1046. return Basic.__new__(cls, *args)
  1047. def to_nnf(self, simplify=True):
  1048. a, b = self.args
  1049. return Or._to_nnf(Not(a), b, simplify=simplify)
  1050. def to_anf(self, deep=True):
  1051. a, b = self.args
  1052. return Xor._to_anf(true, a, And(a, b), deep=deep)
  1053. class Equivalent(BooleanFunction):
  1054. """
  1055. Equivalence relation.
  1056. ``Equivalent(A, B)`` is True iff A and B are both True or both False.
  1057. Returns True if all of the arguments are logically equivalent.
  1058. Returns False otherwise.
  1059. For two arguments, this is equivalent to :py:class:`~.Xnor`.
  1060. Examples
  1061. ========
  1062. >>> from sympy.logic.boolalg import Equivalent, And
  1063. >>> from sympy.abc import x
  1064. >>> Equivalent(False, False, False)
  1065. True
  1066. >>> Equivalent(True, False, False)
  1067. False
  1068. >>> Equivalent(x, And(x, True))
  1069. True
  1070. """
  1071. def __new__(cls, *args, **options):
  1072. from sympy.core.relational import Relational
  1073. args = [_sympify(arg) for arg in args]
  1074. argset = set(args)
  1075. for x in args:
  1076. if isinstance(x, Number) or x in [True, False]: # Includes 0, 1
  1077. argset.discard(x)
  1078. argset.add(bool(x))
  1079. rel = []
  1080. for r in argset:
  1081. if isinstance(r, Relational):
  1082. rel.append((r, r.canonical, r.negated.canonical))
  1083. remove = []
  1084. for i, (r, c, nc) in enumerate(rel):
  1085. for j in range(i + 1, len(rel)):
  1086. rj, cj = rel[j][:2]
  1087. if cj == nc:
  1088. return false
  1089. elif cj == c:
  1090. remove.append((r, rj))
  1091. break
  1092. for a, b in remove:
  1093. argset.remove(a)
  1094. argset.remove(b)
  1095. argset.add(True)
  1096. if len(argset) <= 1:
  1097. return true
  1098. if True in argset:
  1099. argset.discard(True)
  1100. return And(*argset)
  1101. if False in argset:
  1102. argset.discard(False)
  1103. return And(*[Not(arg) for arg in argset])
  1104. _args = frozenset(argset)
  1105. obj = super().__new__(cls, _args)
  1106. obj._argset = _args
  1107. return obj
  1108. # XXX: This should be cached on the object rather than using cacheit
  1109. # Maybe it can be computed in __new__?
  1110. @property # type: ignore
  1111. @cacheit
  1112. def args(self):
  1113. return tuple(ordered(self._argset))
  1114. def to_nnf(self, simplify=True):
  1115. args = []
  1116. for a, b in zip(self.args, self.args[1:]):
  1117. args.append(Or(Not(a), b))
  1118. args.append(Or(Not(self.args[-1]), self.args[0]))
  1119. return And._to_nnf(*args, simplify=simplify)
  1120. def to_anf(self, deep=True):
  1121. a = And(*self.args)
  1122. b = And(*[to_anf(Not(arg), deep=False) for arg in self.args])
  1123. b = distribute_xor_over_and(b)
  1124. return Xor._to_anf(a, b, deep=deep)
  1125. class ITE(BooleanFunction):
  1126. """
  1127. If-then-else clause.
  1128. ``ITE(A, B, C)`` evaluates and returns the result of B if A is true
  1129. else it returns the result of C. All args must be Booleans.
  1130. From a logic gate perspective, ITE corresponds to a 2-to-1 multiplexer,
  1131. where A is the select signal.
  1132. Examples
  1133. ========
  1134. >>> from sympy.logic.boolalg import ITE, And, Xor, Or
  1135. >>> from sympy.abc import x, y, z
  1136. >>> ITE(True, False, True)
  1137. False
  1138. >>> ITE(Or(True, False), And(True, True), Xor(True, True))
  1139. True
  1140. >>> ITE(x, y, z)
  1141. ITE(x, y, z)
  1142. >>> ITE(True, x, y)
  1143. x
  1144. >>> ITE(False, x, y)
  1145. y
  1146. >>> ITE(x, y, y)
  1147. y
  1148. Trying to use non-Boolean args will generate a TypeError:
  1149. >>> ITE(True, [], ())
  1150. Traceback (most recent call last):
  1151. ...
  1152. TypeError: expecting bool, Boolean or ITE, not `[]`
  1153. """
  1154. def __new__(cls, *args, **kwargs):
  1155. from sympy.core.relational import Eq, Ne
  1156. if len(args) != 3:
  1157. raise ValueError('expecting exactly 3 args')
  1158. a, b, c = args
  1159. # check use of binary symbols
  1160. if isinstance(a, (Eq, Ne)):
  1161. # in this context, we can evaluate the Eq/Ne
  1162. # if one arg is a binary symbol and the other
  1163. # is true/false
  1164. b, c = map(as_Boolean, (b, c))
  1165. bin_syms = set().union(*[i.binary_symbols for i in (b, c)])
  1166. if len(set(a.args) - bin_syms) == 1:
  1167. # one arg is a binary_symbols
  1168. _a = a
  1169. if a.lhs is true:
  1170. a = a.rhs
  1171. elif a.rhs is true:
  1172. a = a.lhs
  1173. elif a.lhs is false:
  1174. a = Not(a.rhs)
  1175. elif a.rhs is false:
  1176. a = Not(a.lhs)
  1177. else:
  1178. # binary can only equal True or False
  1179. a = false
  1180. if isinstance(_a, Ne):
  1181. a = Not(a)
  1182. else:
  1183. a, b, c = BooleanFunction.binary_check_and_simplify(
  1184. a, b, c)
  1185. rv = None
  1186. if kwargs.get('evaluate', True):
  1187. rv = cls.eval(a, b, c)
  1188. if rv is None:
  1189. rv = BooleanFunction.__new__(cls, a, b, c, evaluate=False)
  1190. return rv
  1191. @classmethod
  1192. def eval(cls, *args):
  1193. from sympy.core.relational import Eq, Ne
  1194. # do the args give a singular result?
  1195. a, b, c = args
  1196. if isinstance(a, (Ne, Eq)):
  1197. _a = a
  1198. if true in a.args:
  1199. a = a.lhs if a.rhs is true else a.rhs
  1200. elif false in a.args:
  1201. a = Not(a.lhs) if a.rhs is false else Not(a.rhs)
  1202. else:
  1203. _a = None
  1204. if _a is not None and isinstance(_a, Ne):
  1205. a = Not(a)
  1206. if a is true:
  1207. return b
  1208. if a is false:
  1209. return c
  1210. if b == c:
  1211. return b
  1212. else:
  1213. # or maybe the results allow the answer to be expressed
  1214. # in terms of the condition
  1215. if b is true and c is false:
  1216. return a
  1217. if b is false and c is true:
  1218. return Not(a)
  1219. if [a, b, c] != args:
  1220. return cls(a, b, c, evaluate=False)
  1221. def to_nnf(self, simplify=True):
  1222. a, b, c = self.args
  1223. return And._to_nnf(Or(Not(a), b), Or(a, c), simplify=simplify)
  1224. def _eval_as_set(self):
  1225. return self.to_nnf().as_set()
  1226. def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
  1227. from sympy.functions.elementary.piecewise import Piecewise
  1228. return Piecewise((args[1], args[0]), (args[2], True))
  1229. class Exclusive(BooleanFunction):
  1230. """
  1231. True if only one or no argument is true.
  1232. ``Exclusive(A, B, C)`` is equivalent to ``~(A & B) & ~(A & C) & ~(B & C)``.
  1233. For two arguments, this is equivalent to :py:class:`~.Xor`.
  1234. Examples
  1235. ========
  1236. >>> from sympy.logic.boolalg import Exclusive
  1237. >>> Exclusive(False, False, False)
  1238. True
  1239. >>> Exclusive(False, True, False)
  1240. True
  1241. >>> Exclusive(False, True, True)
  1242. False
  1243. """
  1244. @classmethod
  1245. def eval(cls, *args):
  1246. and_args = []
  1247. for a, b in combinations(args, 2):
  1248. and_args.append(Not(And(a, b)))
  1249. return And(*and_args)
  1250. # end class definitions. Some useful methods
  1251. def conjuncts(expr):
  1252. """Return a list of the conjuncts in ``expr``.
  1253. Examples
  1254. ========
  1255. >>> from sympy.logic.boolalg import conjuncts
  1256. >>> from sympy.abc import A, B
  1257. >>> conjuncts(A & B)
  1258. frozenset({A, B})
  1259. >>> conjuncts(A | B)
  1260. frozenset({A | B})
  1261. """
  1262. return And.make_args(expr)
  1263. def disjuncts(expr):
  1264. """Return a list of the disjuncts in ``expr``.
  1265. Examples
  1266. ========
  1267. >>> from sympy.logic.boolalg import disjuncts
  1268. >>> from sympy.abc import A, B
  1269. >>> disjuncts(A | B)
  1270. frozenset({A, B})
  1271. >>> disjuncts(A & B)
  1272. frozenset({A & B})
  1273. """
  1274. return Or.make_args(expr)
  1275. def distribute_and_over_or(expr):
  1276. """
  1277. Given a sentence ``expr`` consisting of conjunctions and disjunctions
  1278. of literals, return an equivalent sentence in CNF.
  1279. Examples
  1280. ========
  1281. >>> from sympy.logic.boolalg import distribute_and_over_or, And, Or, Not
  1282. >>> from sympy.abc import A, B, C
  1283. >>> distribute_and_over_or(Or(A, And(Not(B), Not(C))))
  1284. (A | ~B) & (A | ~C)
  1285. """
  1286. return _distribute((expr, And, Or))
  1287. def distribute_or_over_and(expr):
  1288. """
  1289. Given a sentence ``expr`` consisting of conjunctions and disjunctions
  1290. of literals, return an equivalent sentence in DNF.
  1291. Note that the output is NOT simplified.
  1292. Examples
  1293. ========
  1294. >>> from sympy.logic.boolalg import distribute_or_over_and, And, Or, Not
  1295. >>> from sympy.abc import A, B, C
  1296. >>> distribute_or_over_and(And(Or(Not(A), B), C))
  1297. (B & C) | (C & ~A)
  1298. """
  1299. return _distribute((expr, Or, And))
  1300. def distribute_xor_over_and(expr):
  1301. """
  1302. Given a sentence ``expr`` consisting of conjunction and
  1303. exclusive disjunctions of literals, return an
  1304. equivalent exclusive disjunction.
  1305. Note that the output is NOT simplified.
  1306. Examples
  1307. ========
  1308. >>> from sympy.logic.boolalg import distribute_xor_over_and, And, Xor, Not
  1309. >>> from sympy.abc import A, B, C
  1310. >>> distribute_xor_over_and(And(Xor(Not(A), B), C))
  1311. (B & C) ^ (C & ~A)
  1312. """
  1313. return _distribute((expr, Xor, And))
  1314. def _distribute(info):
  1315. """
  1316. Distributes ``info[1]`` over ``info[2]`` with respect to ``info[0]``.
  1317. """
  1318. if isinstance(info[0], info[2]):
  1319. for arg in info[0].args:
  1320. if isinstance(arg, info[1]):
  1321. conj = arg
  1322. break
  1323. else:
  1324. return info[0]
  1325. rest = info[2](*[a for a in info[0].args if a is not conj])
  1326. return info[1](*list(map(_distribute,
  1327. [(info[2](c, rest), info[1], info[2])
  1328. for c in conj.args])), remove_true=False)
  1329. elif isinstance(info[0], info[1]):
  1330. return info[1](*list(map(_distribute,
  1331. [(x, info[1], info[2])
  1332. for x in info[0].args])),
  1333. remove_true=False)
  1334. else:
  1335. return info[0]
  1336. def to_anf(expr, deep=True):
  1337. r"""
  1338. Converts expr to Algebraic Normal Form (ANF).
  1339. ANF is a canonical normal form, which means that two
  1340. equivalent formulas will convert to the same ANF.
  1341. A logical expression is in ANF if it has the form
  1342. .. math:: 1 \oplus a \oplus b \oplus ab \oplus abc
  1343. i.e. it can be:
  1344. - purely true,
  1345. - purely false,
  1346. - conjunction of variables,
  1347. - exclusive disjunction.
  1348. The exclusive disjunction can only contain true, variables
  1349. or conjunction of variables. No negations are permitted.
  1350. If ``deep`` is ``False``, arguments of the boolean
  1351. expression are considered variables, i.e. only the
  1352. top-level expression is converted to ANF.
  1353. Examples
  1354. ========
  1355. >>> from sympy.logic.boolalg import And, Or, Not, Implies, Equivalent
  1356. >>> from sympy.logic.boolalg import to_anf
  1357. >>> from sympy.abc import A, B, C
  1358. >>> to_anf(Not(A))
  1359. A ^ True
  1360. >>> to_anf(And(Or(A, B), Not(C)))
  1361. A ^ B ^ (A & B) ^ (A & C) ^ (B & C) ^ (A & B & C)
  1362. >>> to_anf(Implies(Not(A), Equivalent(B, C)), deep=False)
  1363. True ^ ~A ^ (~A & (Equivalent(B, C)))
  1364. """
  1365. expr = sympify(expr)
  1366. if is_anf(expr):
  1367. return expr
  1368. return expr.to_anf(deep=deep)
  1369. def to_nnf(expr, simplify=True):
  1370. """
  1371. Converts ``expr`` to Negation Normal Form (NNF).
  1372. A logical expression is in NNF if it
  1373. contains only :py:class:`~.And`, :py:class:`~.Or` and :py:class:`~.Not`,
  1374. and :py:class:`~.Not` is applied only to literals.
  1375. If ``simplify`` is ``True``, the result contains no redundant clauses.
  1376. Examples
  1377. ========
  1378. >>> from sympy.abc import A, B, C, D
  1379. >>> from sympy.logic.boolalg import Not, Equivalent, to_nnf
  1380. >>> to_nnf(Not((~A & ~B) | (C & D)))
  1381. (A | B) & (~C | ~D)
  1382. >>> to_nnf(Equivalent(A >> B, B >> A))
  1383. (A | ~B | (A & ~B)) & (B | ~A | (B & ~A))
  1384. """
  1385. if is_nnf(expr, simplify):
  1386. return expr
  1387. return expr.to_nnf(simplify)
  1388. def to_cnf(expr, simplify=False, force=False):
  1389. """
  1390. Convert a propositional logical sentence ``expr`` to conjunctive normal
  1391. form: ``((A | ~B | ...) & (B | C | ...) & ...)``.
  1392. If ``simplify`` is ``True``, ``expr`` is evaluated to its simplest CNF
  1393. form using the Quine-McCluskey algorithm; this may take a long
  1394. time. If there are more than 8 variables the ``force`` flag must be set
  1395. to ``True`` to simplify (default is ``False``).
  1396. Examples
  1397. ========
  1398. >>> from sympy.logic.boolalg import to_cnf
  1399. >>> from sympy.abc import A, B, D
  1400. >>> to_cnf(~(A | B) | D)
  1401. (D | ~A) & (D | ~B)
  1402. >>> to_cnf((A | B) & (A | ~A), True)
  1403. A | B
  1404. """
  1405. expr = sympify(expr)
  1406. if not isinstance(expr, BooleanFunction):
  1407. return expr
  1408. if simplify:
  1409. if not force and len(_find_predicates(expr)) > 8:
  1410. raise ValueError(filldedent('''
  1411. To simplify a logical expression with more
  1412. than 8 variables may take a long time and requires
  1413. the use of `force=True`.'''))
  1414. return simplify_logic(expr, 'cnf', True, force=force)
  1415. # Don't convert unless we have to
  1416. if is_cnf(expr):
  1417. return expr
  1418. expr = eliminate_implications(expr)
  1419. res = distribute_and_over_or(expr)
  1420. return res
  1421. def to_dnf(expr, simplify=False, force=False):
  1422. """
  1423. Convert a propositional logical sentence ``expr`` to disjunctive normal
  1424. form: ``((A & ~B & ...) | (B & C & ...) | ...)``.
  1425. If ``simplify`` is ``True``, ``expr`` is evaluated to its simplest DNF form using
  1426. the Quine-McCluskey algorithm; this may take a long
  1427. time. If there are more than 8 variables, the ``force`` flag must be set to
  1428. ``True`` to simplify (default is ``False``).
  1429. Examples
  1430. ========
  1431. >>> from sympy.logic.boolalg import to_dnf
  1432. >>> from sympy.abc import A, B, C
  1433. >>> to_dnf(B & (A | C))
  1434. (A & B) | (B & C)
  1435. >>> to_dnf((A & B) | (A & ~B) | (B & C) | (~B & C), True)
  1436. A | C
  1437. """
  1438. expr = sympify(expr)
  1439. if not isinstance(expr, BooleanFunction):
  1440. return expr
  1441. if simplify:
  1442. if not force and len(_find_predicates(expr)) > 8:
  1443. raise ValueError(filldedent('''
  1444. To simplify a logical expression with more
  1445. than 8 variables may take a long time and requires
  1446. the use of `force=True`.'''))
  1447. return simplify_logic(expr, 'dnf', True, force=force)
  1448. # Don't convert unless we have to
  1449. if is_dnf(expr):
  1450. return expr
  1451. expr = eliminate_implications(expr)
  1452. return distribute_or_over_and(expr)
  1453. def is_anf(expr):
  1454. r"""
  1455. Checks if ``expr`` is in Algebraic Normal Form (ANF).
  1456. A logical expression is in ANF if it has the form
  1457. .. math:: 1 \oplus a \oplus b \oplus ab \oplus abc
  1458. i.e. it is purely true, purely false, conjunction of
  1459. variables or exclusive disjunction. The exclusive
  1460. disjunction can only contain true, variables or
  1461. conjunction of variables. No negations are permitted.
  1462. Examples
  1463. ========
  1464. >>> from sympy.logic.boolalg import And, Not, Xor, true, is_anf
  1465. >>> from sympy.abc import A, B, C
  1466. >>> is_anf(true)
  1467. True
  1468. >>> is_anf(A)
  1469. True
  1470. >>> is_anf(And(A, B, C))
  1471. True
  1472. >>> is_anf(Xor(A, Not(B)))
  1473. False
  1474. """
  1475. expr = sympify(expr)
  1476. if is_literal(expr) and not isinstance(expr, Not):
  1477. return True
  1478. if isinstance(expr, And):
  1479. for arg in expr.args:
  1480. if not arg.is_Symbol:
  1481. return False
  1482. return True
  1483. elif isinstance(expr, Xor):
  1484. for arg in expr.args:
  1485. if isinstance(arg, And):
  1486. for a in arg.args:
  1487. if not a.is_Symbol:
  1488. return False
  1489. elif is_literal(arg):
  1490. if isinstance(arg, Not):
  1491. return False
  1492. else:
  1493. return False
  1494. return True
  1495. else:
  1496. return False
  1497. def is_nnf(expr, simplified=True):
  1498. """
  1499. Checks if ``expr`` is in Negation Normal Form (NNF).
  1500. A logical expression is in NNF if it
  1501. contains only :py:class:`~.And`, :py:class:`~.Or` and :py:class:`~.Not`,
  1502. and :py:class:`~.Not` is applied only to literals.
  1503. If ``simplified`` is ``True``, checks if result contains no redundant clauses.
  1504. Examples
  1505. ========
  1506. >>> from sympy.abc import A, B, C
  1507. >>> from sympy.logic.boolalg import Not, is_nnf
  1508. >>> is_nnf(A & B | ~C)
  1509. True
  1510. >>> is_nnf((A | ~A) & (B | C))
  1511. False
  1512. >>> is_nnf((A | ~A) & (B | C), False)
  1513. True
  1514. >>> is_nnf(Not(A & B) | C)
  1515. False
  1516. >>> is_nnf((A >> B) & (B >> A))
  1517. False
  1518. """
  1519. expr = sympify(expr)
  1520. if is_literal(expr):
  1521. return True
  1522. stack = [expr]
  1523. while stack:
  1524. expr = stack.pop()
  1525. if expr.func in (And, Or):
  1526. if simplified:
  1527. args = expr.args
  1528. for arg in args:
  1529. if Not(arg) in args:
  1530. return False
  1531. stack.extend(expr.args)
  1532. elif not is_literal(expr):
  1533. return False
  1534. return True
  1535. def is_cnf(expr):
  1536. """
  1537. Test whether or not an expression is in conjunctive normal form.
  1538. Examples
  1539. ========
  1540. >>> from sympy.logic.boolalg import is_cnf
  1541. >>> from sympy.abc import A, B, C
  1542. >>> is_cnf(A | B | C)
  1543. True
  1544. >>> is_cnf(A & B & C)
  1545. True
  1546. >>> is_cnf((A & B) | C)
  1547. False
  1548. """
  1549. return _is_form(expr, And, Or)
  1550. def is_dnf(expr):
  1551. """
  1552. Test whether or not an expression is in disjunctive normal form.
  1553. Examples
  1554. ========
  1555. >>> from sympy.logic.boolalg import is_dnf
  1556. >>> from sympy.abc import A, B, C
  1557. >>> is_dnf(A | B | C)
  1558. True
  1559. >>> is_dnf(A & B & C)
  1560. True
  1561. >>> is_dnf((A & B) | C)
  1562. True
  1563. >>> is_dnf(A & (B | C))
  1564. False
  1565. """
  1566. return _is_form(expr, Or, And)
  1567. def _is_form(expr, function1, function2):
  1568. """
  1569. Test whether or not an expression is of the required form.
  1570. """
  1571. expr = sympify(expr)
  1572. vals = function1.make_args(expr) if isinstance(expr, function1) else [expr]
  1573. for lit in vals:
  1574. if isinstance(lit, function2):
  1575. vals2 = function2.make_args(lit) if isinstance(lit, function2) else [lit]
  1576. for l in vals2:
  1577. if is_literal(l) is False:
  1578. return False
  1579. elif is_literal(lit) is False:
  1580. return False
  1581. return True
  1582. def eliminate_implications(expr):
  1583. """
  1584. Change :py:class:`~.Implies` and :py:class:`~.Equivalent` into
  1585. :py:class:`~.And`, :py:class:`~.Or`, and :py:class:`~.Not`.
  1586. That is, return an expression that is equivalent to ``expr``, but has only
  1587. ``&``, ``|``, and ``~`` as logical
  1588. operators.
  1589. Examples
  1590. ========
  1591. >>> from sympy.logic.boolalg import Implies, Equivalent, \
  1592. eliminate_implications
  1593. >>> from sympy.abc import A, B, C
  1594. >>> eliminate_implications(Implies(A, B))
  1595. B | ~A
  1596. >>> eliminate_implications(Equivalent(A, B))
  1597. (A | ~B) & (B | ~A)
  1598. >>> eliminate_implications(Equivalent(A, B, C))
  1599. (A | ~C) & (B | ~A) & (C | ~B)
  1600. """
  1601. return to_nnf(expr, simplify=False)
  1602. def is_literal(expr):
  1603. """
  1604. Returns True if expr is a literal, else False.
  1605. Examples
  1606. ========
  1607. >>> from sympy import Or, Q
  1608. >>> from sympy.abc import A, B
  1609. >>> from sympy.logic.boolalg import is_literal
  1610. >>> is_literal(A)
  1611. True
  1612. >>> is_literal(~A)
  1613. True
  1614. >>> is_literal(Q.zero(A))
  1615. True
  1616. >>> is_literal(A + B)
  1617. True
  1618. >>> is_literal(Or(A, B))
  1619. False
  1620. """
  1621. from sympy.assumptions import AppliedPredicate
  1622. if isinstance(expr, Not):
  1623. return is_literal(expr.args[0])
  1624. elif expr in (True, False) or isinstance(expr, AppliedPredicate) or expr.is_Atom:
  1625. return True
  1626. elif not isinstance(expr, BooleanFunction) and all(
  1627. (isinstance(expr, AppliedPredicate) or a.is_Atom) for a in expr.args):
  1628. return True
  1629. return False
  1630. def to_int_repr(clauses, symbols):
  1631. """
  1632. Takes clauses in CNF format and puts them into an integer representation.
  1633. Examples
  1634. ========
  1635. >>> from sympy.logic.boolalg import to_int_repr
  1636. >>> from sympy.abc import x, y
  1637. >>> to_int_repr([x | y, y], [x, y]) == [{1, 2}, {2}]
  1638. True
  1639. """
  1640. # Convert the symbol list into a dict
  1641. symbols = dict(zip(symbols, range(1, len(symbols) + 1)))
  1642. def append_symbol(arg, symbols):
  1643. if isinstance(arg, Not):
  1644. return -symbols[arg.args[0]]
  1645. else:
  1646. return symbols[arg]
  1647. return [{append_symbol(arg, symbols) for arg in Or.make_args(c)}
  1648. for c in clauses]
  1649. def term_to_integer(term):
  1650. """
  1651. Return an integer corresponding to the base-2 digits given by *term*.
  1652. Parameters
  1653. ==========
  1654. term : a string or list of ones and zeros
  1655. Examples
  1656. ========
  1657. >>> from sympy.logic.boolalg import term_to_integer
  1658. >>> term_to_integer([1, 0, 0])
  1659. 4
  1660. >>> term_to_integer('100')
  1661. 4
  1662. """
  1663. return int(''.join(list(map(str, list(term)))), 2)
  1664. integer_to_term = ibin # XXX could delete?
  1665. def truth_table(expr, variables, input=True):
  1666. """
  1667. Return a generator of all possible configurations of the input variables,
  1668. and the result of the boolean expression for those values.
  1669. Parameters
  1670. ==========
  1671. expr : Boolean expression
  1672. variables : list of variables
  1673. input : bool (default ``True``)
  1674. Indicates whether to return the input combinations.
  1675. Examples
  1676. ========
  1677. >>> from sympy.logic.boolalg import truth_table
  1678. >>> from sympy.abc import x,y
  1679. >>> table = truth_table(x >> y, [x, y])
  1680. >>> for t in table:
  1681. ... print('{0} -> {1}'.format(*t))
  1682. [0, 0] -> True
  1683. [0, 1] -> True
  1684. [1, 0] -> False
  1685. [1, 1] -> True
  1686. >>> table = truth_table(x | y, [x, y])
  1687. >>> list(table)
  1688. [([0, 0], False), ([0, 1], True), ([1, 0], True), ([1, 1], True)]
  1689. If ``input`` is ``False``, ``truth_table`` returns only a list of truth values.
  1690. In this case, the corresponding input values of variables can be
  1691. deduced from the index of a given output.
  1692. >>> from sympy.utilities.iterables import ibin
  1693. >>> vars = [y, x]
  1694. >>> values = truth_table(x >> y, vars, input=False)
  1695. >>> values = list(values)
  1696. >>> values
  1697. [True, False, True, True]
  1698. >>> for i, value in enumerate(values):
  1699. ... print('{0} -> {1}'.format(list(zip(
  1700. ... vars, ibin(i, len(vars)))), value))
  1701. [(y, 0), (x, 0)] -> True
  1702. [(y, 0), (x, 1)] -> False
  1703. [(y, 1), (x, 0)] -> True
  1704. [(y, 1), (x, 1)] -> True
  1705. """
  1706. variables = [sympify(v) for v in variables]
  1707. expr = sympify(expr)
  1708. if not isinstance(expr, BooleanFunction) and not is_literal(expr):
  1709. return
  1710. table = product((0, 1), repeat=len(variables))
  1711. for term in table:
  1712. value = expr.xreplace(dict(zip(variables, term)))
  1713. if input:
  1714. yield list(term), value
  1715. else:
  1716. yield value
  1717. def _check_pair(minterm1, minterm2):
  1718. """
  1719. Checks if a pair of minterms differs by only one bit. If yes, returns
  1720. index, else returns `-1`.
  1721. """
  1722. # Early termination seems to be faster than list comprehension,
  1723. # at least for large examples.
  1724. index = -1
  1725. for x, i in enumerate(minterm1): # zip(minterm1, minterm2) is slower
  1726. if i != minterm2[x]:
  1727. if index == -1:
  1728. index = x
  1729. else:
  1730. return -1
  1731. return index
  1732. def _convert_to_varsSOP(minterm, variables):
  1733. """
  1734. Converts a term in the expansion of a function from binary to its
  1735. variable form (for SOP).
  1736. """
  1737. temp = [variables[n] if val == 1 else Not(variables[n])
  1738. for n, val in enumerate(minterm) if val != 3]
  1739. return And(*temp)
  1740. def _convert_to_varsPOS(maxterm, variables):
  1741. """
  1742. Converts a term in the expansion of a function from binary to its
  1743. variable form (for POS).
  1744. """
  1745. temp = [variables[n] if val == 0 else Not(variables[n])
  1746. for n, val in enumerate(maxterm) if val != 3]
  1747. return Or(*temp)
  1748. def _convert_to_varsANF(term, variables):
  1749. """
  1750. Converts a term in the expansion of a function from binary to its
  1751. variable form (for ANF).
  1752. Parameters
  1753. ==========
  1754. term : list of 1's and 0's (complementation pattern)
  1755. variables : list of variables
  1756. """
  1757. temp = [variables[n] for n, t in enumerate(term) if t == 1]
  1758. if not temp:
  1759. return true
  1760. return And(*temp)
  1761. def _get_odd_parity_terms(n):
  1762. """
  1763. Returns a list of lists, with all possible combinations of n zeros and ones
  1764. with an odd number of ones.
  1765. """
  1766. return [e for e in [ibin(i, n) for i in range(2**n)] if sum(e) % 2 == 1]
  1767. def _get_even_parity_terms(n):
  1768. """
  1769. Returns a list of lists, with all possible combinations of n zeros and ones
  1770. with an even number of ones.
  1771. """
  1772. return [e for e in [ibin(i, n) for i in range(2**n)] if sum(e) % 2 == 0]
  1773. def _simplified_pairs(terms):
  1774. """
  1775. Reduces a set of minterms, if possible, to a simplified set of minterms
  1776. with one less variable in the terms using QM method.
  1777. """
  1778. if not terms:
  1779. return []
  1780. simplified_terms = []
  1781. todo = list(range(len(terms)))
  1782. # Count number of ones as _check_pair can only potentially match if there
  1783. # is at most a difference of a single one
  1784. termdict = defaultdict(list)
  1785. for n, term in enumerate(terms):
  1786. ones = sum(1 for t in term if t == 1)
  1787. termdict[ones].append(n)
  1788. variables = len(terms[0])
  1789. for k in range(variables):
  1790. for i in termdict[k]:
  1791. for j in termdict[k+1]:
  1792. index = _check_pair(terms[i], terms[j])
  1793. if index != -1:
  1794. # Mark terms handled
  1795. todo[i] = todo[j] = None
  1796. # Copy old term
  1797. newterm = terms[i][:]
  1798. # Set differing position to don't care
  1799. newterm[index] = 3
  1800. # Add if not already there
  1801. if newterm not in simplified_terms:
  1802. simplified_terms.append(newterm)
  1803. if simplified_terms:
  1804. # Further simplifications only among the new terms
  1805. simplified_terms = _simplified_pairs(simplified_terms)
  1806. # Add remaining, non-simplified, terms
  1807. simplified_terms.extend([terms[i] for i in todo if i is not None])
  1808. return simplified_terms
  1809. def _rem_redundancy(l1, terms):
  1810. """
  1811. After the truth table has been sufficiently simplified, use the prime
  1812. implicant table method to recognize and eliminate redundant pairs,
  1813. and return the essential arguments.
  1814. """
  1815. if not terms:
  1816. return []
  1817. nterms = len(terms)
  1818. nl1 = len(l1)
  1819. # Create dominating matrix
  1820. dommatrix = [[0]*nl1 for n in range(nterms)]
  1821. colcount = [0]*nl1
  1822. rowcount = [0]*nterms
  1823. for primei, prime in enumerate(l1):
  1824. for termi, term in enumerate(terms):
  1825. # Check prime implicant covering term
  1826. if all(t == 3 or t == mt for t, mt in zip(prime, term)):
  1827. dommatrix[termi][primei] = 1
  1828. colcount[primei] += 1
  1829. rowcount[termi] += 1
  1830. # Keep track if anything changed
  1831. anythingchanged = True
  1832. # Then, go again
  1833. while anythingchanged:
  1834. anythingchanged = False
  1835. for rowi in range(nterms):
  1836. # Still non-dominated?
  1837. if rowcount[rowi]:
  1838. row = dommatrix[rowi]
  1839. for row2i in range(nterms):
  1840. # Still non-dominated?
  1841. if rowi != row2i and rowcount[rowi] and (rowcount[rowi] <= rowcount[row2i]):
  1842. row2 = dommatrix[row2i]
  1843. if all(row2[n] >= row[n] for n in range(nl1)):
  1844. # row2 dominating row, remove row2
  1845. rowcount[row2i] = 0
  1846. anythingchanged = True
  1847. for primei, prime in enumerate(row2):
  1848. if prime:
  1849. # Make corresponding entry 0
  1850. dommatrix[row2i][primei] = 0
  1851. colcount[primei] -= 1
  1852. colcache = {}
  1853. for coli in range(nl1):
  1854. # Still non-dominated?
  1855. if colcount[coli]:
  1856. if coli in colcache:
  1857. col = colcache[coli]
  1858. else:
  1859. col = [dommatrix[i][coli] for i in range(nterms)]
  1860. colcache[coli] = col
  1861. for col2i in range(nl1):
  1862. # Still non-dominated?
  1863. if coli != col2i and colcount[col2i] and (colcount[coli] >= colcount[col2i]):
  1864. if col2i in colcache:
  1865. col2 = colcache[col2i]
  1866. else:
  1867. col2 = [dommatrix[i][col2i] for i in range(nterms)]
  1868. colcache[col2i] = col2
  1869. if all(col[n] >= col2[n] for n in range(nterms)):
  1870. # col dominating col2, remove col2
  1871. colcount[col2i] = 0
  1872. anythingchanged = True
  1873. for termi, term in enumerate(col2):
  1874. if term and dommatrix[termi][col2i]:
  1875. # Make corresponding entry 0
  1876. dommatrix[termi][col2i] = 0
  1877. rowcount[termi] -= 1
  1878. if not anythingchanged:
  1879. # Heuristically select the prime implicant covering most terms
  1880. maxterms = 0
  1881. bestcolidx = -1
  1882. for coli in range(nl1):
  1883. s = colcount[coli]
  1884. if s > maxterms:
  1885. bestcolidx = coli
  1886. maxterms = s
  1887. # In case we found a prime implicant covering at least two terms
  1888. if bestcolidx != -1 and maxterms > 1:
  1889. for primei, prime in enumerate(l1):
  1890. if primei != bestcolidx:
  1891. for termi, term in enumerate(colcache[bestcolidx]):
  1892. if term and dommatrix[termi][primei]:
  1893. # Make corresponding entry 0
  1894. dommatrix[termi][primei] = 0
  1895. anythingchanged = True
  1896. rowcount[termi] -= 1
  1897. colcount[primei] -= 1
  1898. return [l1[i] for i in range(nl1) if colcount[i]]
  1899. def _input_to_binlist(inputlist, variables):
  1900. binlist = []
  1901. bits = len(variables)
  1902. for val in inputlist:
  1903. if isinstance(val, int):
  1904. binlist.append(ibin(val, bits))
  1905. elif isinstance(val, dict):
  1906. nonspecvars = list(variables)
  1907. for key in val.keys():
  1908. nonspecvars.remove(key)
  1909. for t in product((0, 1), repeat=len(nonspecvars)):
  1910. d = dict(zip(nonspecvars, t))
  1911. d.update(val)
  1912. binlist.append([d[v] for v in variables])
  1913. elif isinstance(val, (list, tuple)):
  1914. if len(val) != bits:
  1915. raise ValueError("Each term must contain {bits} bits as there are"
  1916. "\n{bits} variables (or be an integer)."
  1917. "".format(bits=bits))
  1918. binlist.append(list(val))
  1919. else:
  1920. raise TypeError("A term list can only contain lists,"
  1921. " ints or dicts.")
  1922. return binlist
  1923. def SOPform(variables, minterms, dontcares=None):
  1924. """
  1925. The SOPform function uses simplified_pairs and a redundant group-
  1926. eliminating algorithm to convert the list of all input combos that
  1927. generate '1' (the minterms) into the smallest sum-of-products form.
  1928. The variables must be given as the first argument.
  1929. Return a logical :py:class:`~.Or` function (i.e., the "sum of products" or
  1930. "SOP" form) that gives the desired outcome. If there are inputs that can
  1931. be ignored, pass them as a list, too.
  1932. The result will be one of the (perhaps many) functions that satisfy
  1933. the conditions.
  1934. Examples
  1935. ========
  1936. >>> from sympy.logic import SOPform
  1937. >>> from sympy import symbols
  1938. >>> w, x, y, z = symbols('w x y z')
  1939. >>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1],
  1940. ... [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]]
  1941. >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]]
  1942. >>> SOPform([w, x, y, z], minterms, dontcares)
  1943. (y & z) | (~w & ~x)
  1944. The terms can also be represented as integers:
  1945. >>> minterms = [1, 3, 7, 11, 15]
  1946. >>> dontcares = [0, 2, 5]
  1947. >>> SOPform([w, x, y, z], minterms, dontcares)
  1948. (y & z) | (~w & ~x)
  1949. They can also be specified using dicts, which does not have to be fully
  1950. specified:
  1951. >>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}]
  1952. >>> SOPform([w, x, y, z], minterms)
  1953. (x & ~w) | (y & z & ~x)
  1954. Or a combination:
  1955. >>> minterms = [4, 7, 11, [1, 1, 1, 1]]
  1956. >>> dontcares = [{w : 0, x : 0, y: 0}, 5]
  1957. >>> SOPform([w, x, y, z], minterms, dontcares)
  1958. (w & y & z) | (~w & ~y) | (x & z & ~w)
  1959. See also
  1960. ========
  1961. POSform
  1962. References
  1963. ==========
  1964. .. [1] https://en.wikipedia.org/wiki/Quine-McCluskey_algorithm
  1965. .. [2] https://en.wikipedia.org/wiki/Don%27t-care_term
  1966. """
  1967. if not minterms:
  1968. return false
  1969. variables = tuple(map(sympify, variables))
  1970. minterms = _input_to_binlist(minterms, variables)
  1971. dontcares = _input_to_binlist((dontcares or []), variables)
  1972. for d in dontcares:
  1973. if d in minterms:
  1974. raise ValueError('%s in minterms is also in dontcares' % d)
  1975. return _sop_form(variables, minterms, dontcares)
  1976. def _sop_form(variables, minterms, dontcares):
  1977. new = _simplified_pairs(minterms + dontcares)
  1978. essential = _rem_redundancy(new, minterms)
  1979. return Or(*[_convert_to_varsSOP(x, variables) for x in essential])
  1980. def POSform(variables, minterms, dontcares=None):
  1981. """
  1982. The POSform function uses simplified_pairs and a redundant-group
  1983. eliminating algorithm to convert the list of all input combinations
  1984. that generate '1' (the minterms) into the smallest product-of-sums form.
  1985. The variables must be given as the first argument.
  1986. Return a logical :py:class:`~.And` function (i.e., the "product of sums"
  1987. or "POS" form) that gives the desired outcome. If there are inputs that can
  1988. be ignored, pass them as a list, too.
  1989. The result will be one of the (perhaps many) functions that satisfy
  1990. the conditions.
  1991. Examples
  1992. ========
  1993. >>> from sympy.logic import POSform
  1994. >>> from sympy import symbols
  1995. >>> w, x, y, z = symbols('w x y z')
  1996. >>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1],
  1997. ... [1, 0, 1, 1], [1, 1, 1, 1]]
  1998. >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]]
  1999. >>> POSform([w, x, y, z], minterms, dontcares)
  2000. z & (y | ~w)
  2001. The terms can also be represented as integers:
  2002. >>> minterms = [1, 3, 7, 11, 15]
  2003. >>> dontcares = [0, 2, 5]
  2004. >>> POSform([w, x, y, z], minterms, dontcares)
  2005. z & (y | ~w)
  2006. They can also be specified using dicts, which does not have to be fully
  2007. specified:
  2008. >>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}]
  2009. >>> POSform([w, x, y, z], minterms)
  2010. (x | y) & (x | z) & (~w | ~x)
  2011. Or a combination:
  2012. >>> minterms = [4, 7, 11, [1, 1, 1, 1]]
  2013. >>> dontcares = [{w : 0, x : 0, y: 0}, 5]
  2014. >>> POSform([w, x, y, z], minterms, dontcares)
  2015. (w | x) & (y | ~w) & (z | ~y)
  2016. See also
  2017. ========
  2018. SOPform
  2019. References
  2020. ==========
  2021. .. [1] https://en.wikipedia.org/wiki/Quine-McCluskey_algorithm
  2022. .. [2] https://en.wikipedia.org/wiki/Don%27t-care_term
  2023. """
  2024. if not minterms:
  2025. return false
  2026. variables = tuple(map(sympify, variables))
  2027. minterms = _input_to_binlist(minterms, variables)
  2028. dontcares = _input_to_binlist((dontcares or []), variables)
  2029. for d in dontcares:
  2030. if d in minterms:
  2031. raise ValueError('%s in minterms is also in dontcares' % d)
  2032. maxterms = []
  2033. for t in product((0, 1), repeat=len(variables)):
  2034. t = list(t)
  2035. if (t not in minterms) and (t not in dontcares):
  2036. maxterms.append(t)
  2037. new = _simplified_pairs(maxterms + dontcares)
  2038. essential = _rem_redundancy(new, maxterms)
  2039. return And(*[_convert_to_varsPOS(x, variables) for x in essential])
  2040. def ANFform(variables, truthvalues):
  2041. """
  2042. The ANFform function converts the list of truth values to
  2043. Algebraic Normal Form (ANF).
  2044. The variables must be given as the first argument.
  2045. Return True, False, logical :py:class:`~.And` function (i.e., the
  2046. "Zhegalkin monomial") or logical :py:class:`~.Xor` function (i.e.,
  2047. the "Zhegalkin polynomial"). When True and False
  2048. are represented by 1 and 0, respectively, then
  2049. :py:class:`~.And` is multiplication and :py:class:`~.Xor` is addition.
  2050. Formally a "Zhegalkin monomial" is the product (logical
  2051. And) of a finite set of distinct variables, including
  2052. the empty set whose product is denoted 1 (True).
  2053. A "Zhegalkin polynomial" is the sum (logical Xor) of a
  2054. set of Zhegalkin monomials, with the empty set denoted
  2055. by 0 (False).
  2056. Parameters
  2057. ==========
  2058. variables : list of variables
  2059. truthvalues : list of 1's and 0's (result column of truth table)
  2060. Examples
  2061. ========
  2062. >>> from sympy.logic.boolalg import ANFform
  2063. >>> from sympy.abc import x, y
  2064. >>> ANFform([x], [1, 0])
  2065. x ^ True
  2066. >>> ANFform([x, y], [0, 1, 1, 1])
  2067. x ^ y ^ (x & y)
  2068. References
  2069. ==========
  2070. .. [1] https://en.wikipedia.org/wiki/Zhegalkin_polynomial
  2071. """
  2072. n_vars = len(variables)
  2073. n_values = len(truthvalues)
  2074. if n_values != 2 ** n_vars:
  2075. raise ValueError("The number of truth values must be equal to 2^%d, "
  2076. "got %d" % (n_vars, n_values))
  2077. variables = tuple(map(sympify, variables))
  2078. coeffs = anf_coeffs(truthvalues)
  2079. terms = []
  2080. for i, t in enumerate(product((0, 1), repeat=n_vars)):
  2081. if coeffs[i] == 1:
  2082. terms.append(t)
  2083. return Xor(*[_convert_to_varsANF(x, variables) for x in terms],
  2084. remove_true=False)
  2085. def anf_coeffs(truthvalues):
  2086. """
  2087. Convert a list of truth values of some boolean expression
  2088. to the list of coefficients of the polynomial mod 2 (exclusive
  2089. disjunction) representing the boolean expression in ANF
  2090. (i.e., the "Zhegalkin polynomial").
  2091. There are `2^n` possible Zhegalkin monomials in `n` variables, since
  2092. each monomial is fully specified by the presence or absence of
  2093. each variable.
  2094. We can enumerate all the monomials. For example, boolean
  2095. function with four variables ``(a, b, c, d)`` can contain
  2096. up to `2^4 = 16` monomials. The 13-th monomial is the
  2097. product ``a & b & d``, because 13 in binary is 1, 1, 0, 1.
  2098. A given monomial's presence or absence in a polynomial corresponds
  2099. to that monomial's coefficient being 1 or 0 respectively.
  2100. Examples
  2101. ========
  2102. >>> from sympy.logic.boolalg import anf_coeffs, bool_monomial, Xor
  2103. >>> from sympy.abc import a, b, c
  2104. >>> truthvalues = [0, 1, 1, 0, 0, 1, 0, 1]
  2105. >>> coeffs = anf_coeffs(truthvalues)
  2106. >>> coeffs
  2107. [0, 1, 1, 0, 0, 0, 1, 0]
  2108. >>> polynomial = Xor(*[
  2109. ... bool_monomial(k, [a, b, c])
  2110. ... for k, coeff in enumerate(coeffs) if coeff == 1
  2111. ... ])
  2112. >>> polynomial
  2113. b ^ c ^ (a & b)
  2114. """
  2115. s = '{:b}'.format(len(truthvalues))
  2116. n = len(s) - 1
  2117. if len(truthvalues) != 2**n:
  2118. raise ValueError("The number of truth values must be a power of two, "
  2119. "got %d" % len(truthvalues))
  2120. coeffs = [[v] for v in truthvalues]
  2121. for i in range(n):
  2122. tmp = []
  2123. for j in range(2 ** (n-i-1)):
  2124. tmp.append(coeffs[2*j] +
  2125. list(map(lambda x, y: x^y, coeffs[2*j], coeffs[2*j+1])))
  2126. coeffs = tmp
  2127. return coeffs[0]
  2128. def bool_minterm(k, variables):
  2129. """
  2130. Return the k-th minterm.
  2131. Minterms are numbered by a binary encoding of the complementation
  2132. pattern of the variables. This convention assigns the value 1 to
  2133. the direct form and 0 to the complemented form.
  2134. Parameters
  2135. ==========
  2136. k : int or list of 1's and 0's (complementation pattern)
  2137. variables : list of variables
  2138. Examples
  2139. ========
  2140. >>> from sympy.logic.boolalg import bool_minterm
  2141. >>> from sympy.abc import x, y, z
  2142. >>> bool_minterm([1, 0, 1], [x, y, z])
  2143. x & z & ~y
  2144. >>> bool_minterm(6, [x, y, z])
  2145. x & y & ~z
  2146. References
  2147. ==========
  2148. .. [1] https://en.wikipedia.org/wiki/Canonical_normal_form#Indexing_minterms
  2149. """
  2150. if isinstance(k, int):
  2151. k = ibin(k, len(variables))
  2152. variables = tuple(map(sympify, variables))
  2153. return _convert_to_varsSOP(k, variables)
  2154. def bool_maxterm(k, variables):
  2155. """
  2156. Return the k-th maxterm.
  2157. Each maxterm is assigned an index based on the opposite
  2158. conventional binary encoding used for minterms. The maxterm
  2159. convention assigns the value 0 to the direct form and 1 to
  2160. the complemented form.
  2161. Parameters
  2162. ==========
  2163. k : int or list of 1's and 0's (complementation pattern)
  2164. variables : list of variables
  2165. Examples
  2166. ========
  2167. >>> from sympy.logic.boolalg import bool_maxterm
  2168. >>> from sympy.abc import x, y, z
  2169. >>> bool_maxterm([1, 0, 1], [x, y, z])
  2170. y | ~x | ~z
  2171. >>> bool_maxterm(6, [x, y, z])
  2172. z | ~x | ~y
  2173. References
  2174. ==========
  2175. .. [1] https://en.wikipedia.org/wiki/Canonical_normal_form#Indexing_maxterms
  2176. """
  2177. if isinstance(k, int):
  2178. k = ibin(k, len(variables))
  2179. variables = tuple(map(sympify, variables))
  2180. return _convert_to_varsPOS(k, variables)
  2181. def bool_monomial(k, variables):
  2182. """
  2183. Return the k-th monomial.
  2184. Monomials are numbered by a binary encoding of the presence and
  2185. absences of the variables. This convention assigns the value
  2186. 1 to the presence of variable and 0 to the absence of variable.
  2187. Each boolean function can be uniquely represented by a
  2188. Zhegalkin Polynomial (Algebraic Normal Form). The Zhegalkin
  2189. Polynomial of the boolean function with `n` variables can contain
  2190. up to `2^n` monomials. We can enumerate all the monomials.
  2191. Each monomial is fully specified by the presence or absence
  2192. of each variable.
  2193. For example, boolean function with four variables ``(a, b, c, d)``
  2194. can contain up to `2^4 = 16` monomials. The 13-th monomial is the
  2195. product ``a & b & d``, because 13 in binary is 1, 1, 0, 1.
  2196. Parameters
  2197. ==========
  2198. k : int or list of 1's and 0's
  2199. variables : list of variables
  2200. Examples
  2201. ========
  2202. >>> from sympy.logic.boolalg import bool_monomial
  2203. >>> from sympy.abc import x, y, z
  2204. >>> bool_monomial([1, 0, 1], [x, y, z])
  2205. x & z
  2206. >>> bool_monomial(6, [x, y, z])
  2207. x & y
  2208. """
  2209. if isinstance(k, int):
  2210. k = ibin(k, len(variables))
  2211. variables = tuple(map(sympify, variables))
  2212. return _convert_to_varsANF(k, variables)
  2213. def _find_predicates(expr):
  2214. """Helper to find logical predicates in BooleanFunctions.
  2215. A logical predicate is defined here as anything within a BooleanFunction
  2216. that is not a BooleanFunction itself.
  2217. """
  2218. if not isinstance(expr, BooleanFunction):
  2219. return {expr}
  2220. return set().union(*(map(_find_predicates, expr.args)))
  2221. def simplify_logic(expr, form=None, deep=True, force=False, dontcare=None):
  2222. """
  2223. This function simplifies a boolean function to its simplified version
  2224. in SOP or POS form. The return type is an :py:class:`~.Or` or
  2225. :py:class:`~.And` object in SymPy.
  2226. Parameters
  2227. ==========
  2228. expr : Boolean
  2229. form : string (``'cnf'`` or ``'dnf'``) or ``None`` (default).
  2230. If ``'cnf'`` or ``'dnf'``, the simplest expression in the corresponding
  2231. normal form is returned; if ``None``, the answer is returned
  2232. according to the form with fewest args (in CNF by default).
  2233. deep : bool (default ``True``)
  2234. Indicates whether to recursively simplify any
  2235. non-boolean functions contained within the input.
  2236. force : bool (default ``False``)
  2237. As the simplifications require exponential time in the number
  2238. of variables, there is by default a limit on expressions with
  2239. 8 variables. When the expression has more than 8 variables
  2240. only symbolical simplification (controlled by ``deep``) is
  2241. made. By setting ``force`` to ``True``, this limit is removed. Be
  2242. aware that this can lead to very long simplification times.
  2243. dontcare : Boolean
  2244. Optimize expression under the assumption that inputs where this
  2245. expression is true are don't care. This is useful in e.g. Piecewise
  2246. conditions, where later conditions do not need to consider inputs that
  2247. are converted by previous conditions. For example, if a previous
  2248. condition is ``And(A, B)``, the simplification of expr can be made
  2249. with don't cares for ``And(A, B)``.
  2250. Examples
  2251. ========
  2252. >>> from sympy.logic import simplify_logic
  2253. >>> from sympy.abc import x, y, z
  2254. >>> b = (~x & ~y & ~z) | ( ~x & ~y & z)
  2255. >>> simplify_logic(b)
  2256. ~x & ~y
  2257. >>> simplify_logic(x | y, dontcare=y)
  2258. x
  2259. References
  2260. ==========
  2261. .. [1] https://en.wikipedia.org/wiki/Don%27t-care_term
  2262. """
  2263. if form not in (None, 'cnf', 'dnf'):
  2264. raise ValueError("form can be cnf or dnf only")
  2265. expr = sympify(expr)
  2266. # check for quick exit if form is given: right form and all args are
  2267. # literal and do not involve Not
  2268. if form:
  2269. form_ok = False
  2270. if form == 'cnf':
  2271. form_ok = is_cnf(expr)
  2272. elif form == 'dnf':
  2273. form_ok = is_dnf(expr)
  2274. if form_ok and all(is_literal(a)
  2275. for a in expr.args):
  2276. return expr
  2277. from sympy.core.relational import Relational
  2278. if deep:
  2279. variables = expr.atoms(Relational)
  2280. from sympy.simplify.simplify import simplify
  2281. s = tuple(map(simplify, variables))
  2282. expr = expr.xreplace(dict(zip(variables, s)))
  2283. if not isinstance(expr, BooleanFunction):
  2284. return expr
  2285. # Replace Relationals with Dummys to possibly
  2286. # reduce the number of variables
  2287. repl = {}
  2288. undo = {}
  2289. from sympy.core.symbol import Dummy
  2290. variables = expr.atoms(Relational)
  2291. if dontcare is not None:
  2292. dontcare = sympify(dontcare)
  2293. variables.update(dontcare.atoms(Relational))
  2294. while variables:
  2295. var = variables.pop()
  2296. if var.is_Relational:
  2297. d = Dummy()
  2298. undo[d] = var
  2299. repl[var] = d
  2300. nvar = var.negated
  2301. if nvar in variables:
  2302. repl[nvar] = Not(d)
  2303. variables.remove(nvar)
  2304. expr = expr.xreplace(repl)
  2305. if dontcare is not None:
  2306. dontcare = dontcare.xreplace(repl)
  2307. # Get new variables after replacing
  2308. variables = _find_predicates(expr)
  2309. if not force and len(variables) > 8:
  2310. return expr.xreplace(undo)
  2311. if dontcare is not None:
  2312. # Add variables from dontcare
  2313. dcvariables = _find_predicates(dontcare)
  2314. variables.update(dcvariables)
  2315. # if too many restore to variables only
  2316. if not force and len(variables) > 8:
  2317. variables = _find_predicates(expr)
  2318. dontcare = None
  2319. # group into constants and variable values
  2320. c, v = sift(ordered(variables), lambda x: x in (True, False), binary=True)
  2321. variables = c + v
  2322. # standardize constants to be 1 or 0 in keeping with truthtable
  2323. c = [1 if i == True else 0 for i in c]
  2324. truthtable = _get_truthtable(v, expr, c)
  2325. if dontcare is not None:
  2326. dctruthtable = _get_truthtable(v, dontcare, c)
  2327. truthtable = [t for t in truthtable if t not in dctruthtable]
  2328. else:
  2329. dctruthtable = []
  2330. big = len(truthtable) >= (2 ** (len(variables) - 1))
  2331. if form == 'dnf' or form is None and big:
  2332. return _sop_form(variables, truthtable, dctruthtable).xreplace(undo)
  2333. return POSform(variables, truthtable, dctruthtable).xreplace(undo)
  2334. def _get_truthtable(variables, expr, const):
  2335. """ Return a list of all combinations leading to a True result for ``expr``.
  2336. """
  2337. _variables = variables.copy()
  2338. def _get_tt(inputs):
  2339. if _variables:
  2340. v = _variables.pop()
  2341. tab = [[i[0].xreplace({v: false}), [0] + i[1]] for i in inputs if i[0] is not false]
  2342. tab.extend([[i[0].xreplace({v: true}), [1] + i[1]] for i in inputs if i[0] is not false])
  2343. return _get_tt(tab)
  2344. return inputs
  2345. res = [const + k[1] for k in _get_tt([[expr, []]]) if k[0]]
  2346. if res == [[]]:
  2347. return []
  2348. else:
  2349. return res
  2350. def _finger(eq):
  2351. """
  2352. Assign a 5-item fingerprint to each symbol in the equation:
  2353. [
  2354. # of times it appeared as a Symbol;
  2355. # of times it appeared as a Not(symbol);
  2356. # of times it appeared as a Symbol in an And or Or;
  2357. # of times it appeared as a Not(Symbol) in an And or Or;
  2358. a sorted tuple of tuples, (i, j, k), where i is the number of arguments
  2359. in an And or Or with which it appeared as a Symbol, and j is
  2360. the number of arguments that were Not(Symbol); k is the number
  2361. of times that (i, j) was seen.
  2362. ]
  2363. Examples
  2364. ========
  2365. >>> from sympy.logic.boolalg import _finger as finger
  2366. >>> from sympy import And, Or, Not, Xor, to_cnf, symbols
  2367. >>> from sympy.abc import a, b, x, y
  2368. >>> eq = Or(And(Not(y), a), And(Not(y), b), And(x, y))
  2369. >>> dict(finger(eq))
  2370. {(0, 0, 1, 0, ((2, 0, 1),)): [x],
  2371. (0, 0, 1, 0, ((2, 1, 1),)): [a, b],
  2372. (0, 0, 1, 2, ((2, 0, 1),)): [y]}
  2373. >>> dict(finger(x & ~y))
  2374. {(0, 1, 0, 0, ()): [y], (1, 0, 0, 0, ()): [x]}
  2375. In the following, the (5, 2, 6) means that there were 6 Or
  2376. functions in which a symbol appeared as itself amongst 5 arguments in
  2377. which there were also 2 negated symbols, e.g. ``(a0 | a1 | a2 | ~a3 | ~a4)``
  2378. is counted once for a0, a1 and a2.
  2379. >>> dict(finger(to_cnf(Xor(*symbols('a:5')))))
  2380. {(0, 0, 8, 8, ((5, 0, 1), (5, 2, 6), (5, 4, 1))): [a0, a1, a2, a3, a4]}
  2381. The equation must not have more than one level of nesting:
  2382. >>> dict(finger(And(Or(x, y), y)))
  2383. {(0, 0, 1, 0, ((2, 0, 1),)): [x], (1, 0, 1, 0, ((2, 0, 1),)): [y]}
  2384. >>> dict(finger(And(Or(x, And(a, x)), y)))
  2385. Traceback (most recent call last):
  2386. ...
  2387. NotImplementedError: unexpected level of nesting
  2388. So y and x have unique fingerprints, but a and b do not.
  2389. """
  2390. f = eq.free_symbols
  2391. d = dict(list(zip(f, [[0]*4 + [defaultdict(int)] for fi in f])))
  2392. for a in eq.args:
  2393. if a.is_Symbol:
  2394. d[a][0] += 1
  2395. elif a.is_Not:
  2396. d[a.args[0]][1] += 1
  2397. else:
  2398. o = len(a.args), sum(isinstance(ai, Not) for ai in a.args)
  2399. for ai in a.args:
  2400. if ai.is_Symbol:
  2401. d[ai][2] += 1
  2402. d[ai][-1][o] += 1
  2403. elif ai.is_Not:
  2404. d[ai.args[0]][3] += 1
  2405. else:
  2406. raise NotImplementedError('unexpected level of nesting')
  2407. inv = defaultdict(list)
  2408. for k, v in ordered(iter(d.items())):
  2409. v[-1] = tuple(sorted([i + (j,) for i, j in v[-1].items()]))
  2410. inv[tuple(v)].append(k)
  2411. return inv
  2412. def bool_map(bool1, bool2):
  2413. """
  2414. Return the simplified version of *bool1*, and the mapping of variables
  2415. that makes the two expressions *bool1* and *bool2* represent the same
  2416. logical behaviour for some correspondence between the variables
  2417. of each.
  2418. If more than one mappings of this sort exist, one of them
  2419. is returned.
  2420. For example, ``And(x, y)`` is logically equivalent to ``And(a, b)`` for
  2421. the mapping ``{x: a, y: b}`` or ``{x: b, y: a}``.
  2422. If no such mapping exists, return ``False``.
  2423. Examples
  2424. ========
  2425. >>> from sympy import SOPform, bool_map, Or, And, Not, Xor
  2426. >>> from sympy.abc import w, x, y, z, a, b, c, d
  2427. >>> function1 = SOPform([x, z, y],[[1, 0, 1], [0, 0, 1]])
  2428. >>> function2 = SOPform([a, b, c],[[1, 0, 1], [1, 0, 0]])
  2429. >>> bool_map(function1, function2)
  2430. (y & ~z, {y: a, z: b})
  2431. The results are not necessarily unique, but they are canonical. Here,
  2432. ``(w, z)`` could be ``(a, d)`` or ``(d, a)``:
  2433. >>> eq = Or(And(Not(y), w), And(Not(y), z), And(x, y))
  2434. >>> eq2 = Or(And(Not(c), a), And(Not(c), d), And(b, c))
  2435. >>> bool_map(eq, eq2)
  2436. ((x & y) | (w & ~y) | (z & ~y), {w: a, x: b, y: c, z: d})
  2437. >>> eq = And(Xor(a, b), c, And(c,d))
  2438. >>> bool_map(eq, eq.subs(c, x))
  2439. (c & d & (a | b) & (~a | ~b), {a: a, b: b, c: d, d: x})
  2440. """
  2441. def match(function1, function2):
  2442. """Return the mapping that equates variables between two
  2443. simplified boolean expressions if possible.
  2444. By "simplified" we mean that a function has been denested
  2445. and is either an And (or an Or) whose arguments are either
  2446. symbols (x), negated symbols (Not(x)), or Or (or an And) whose
  2447. arguments are only symbols or negated symbols. For example,
  2448. ``And(x, Not(y), Or(w, Not(z)))``.
  2449. Basic.match is not robust enough (see issue 4835) so this is
  2450. a workaround that is valid for simplified boolean expressions
  2451. """
  2452. # do some quick checks
  2453. if function1.__class__ != function2.__class__:
  2454. return None # maybe simplification makes them the same?
  2455. if len(function1.args) != len(function2.args):
  2456. return None # maybe simplification makes them the same?
  2457. if function1.is_Symbol:
  2458. return {function1: function2}
  2459. # get the fingerprint dictionaries
  2460. f1 = _finger(function1)
  2461. f2 = _finger(function2)
  2462. # more quick checks
  2463. if len(f1) != len(f2):
  2464. return False
  2465. # assemble the match dictionary if possible
  2466. matchdict = {}
  2467. for k in f1.keys():
  2468. if k not in f2:
  2469. return False
  2470. if len(f1[k]) != len(f2[k]):
  2471. return False
  2472. for i, x in enumerate(f1[k]):
  2473. matchdict[x] = f2[k][i]
  2474. return matchdict
  2475. a = simplify_logic(bool1)
  2476. b = simplify_logic(bool2)
  2477. m = match(a, b)
  2478. if m:
  2479. return a, m
  2480. return m
  2481. def _apply_patternbased_simplification(rv, patterns, measure,
  2482. dominatingvalue,
  2483. replacementvalue=None,
  2484. threeterm_patterns=None):
  2485. """
  2486. Replace patterns of Relational
  2487. Parameters
  2488. ==========
  2489. rv : Expr
  2490. Boolean expression
  2491. patterns : tuple
  2492. Tuple of tuples, with (pattern to simplify, simplified pattern) with
  2493. two terms.
  2494. measure : function
  2495. Simplification measure.
  2496. dominatingvalue : Boolean or ``None``
  2497. The dominating value for the function of consideration.
  2498. For example, for :py:class:`~.And` ``S.false`` is dominating.
  2499. As soon as one expression is ``S.false`` in :py:class:`~.And`,
  2500. the whole expression is ``S.false``.
  2501. replacementvalue : Boolean or ``None``, optional
  2502. The resulting value for the whole expression if one argument
  2503. evaluates to ``dominatingvalue``.
  2504. For example, for :py:class:`~.Nand` ``S.false`` is dominating, but
  2505. in this case the resulting value is ``S.true``. Default is ``None``.
  2506. If ``replacementvalue`` is ``None`` and ``dominatingvalue`` is not
  2507. ``None``, ``replacementvalue = dominatingvalue``.
  2508. threeterm_patterns : tuple, optional
  2509. Tuple of tuples, with (pattern to simplify, simplified pattern) with
  2510. three terms.
  2511. """
  2512. from sympy.core.relational import Relational, _canonical
  2513. if replacementvalue is None and dominatingvalue is not None:
  2514. replacementvalue = dominatingvalue
  2515. # Use replacement patterns for Relationals
  2516. Rel, nonRel = sift(rv.args, lambda i: isinstance(i, Relational),
  2517. binary=True)
  2518. if len(Rel) <= 1:
  2519. return rv
  2520. Rel, nonRealRel = sift(Rel, lambda i: not any(s.is_real is False
  2521. for s in i.free_symbols),
  2522. binary=True)
  2523. Rel = [i.canonical for i in Rel]
  2524. if threeterm_patterns and len(Rel) >= 3:
  2525. Rel = _apply_patternbased_threeterm_simplification(Rel,
  2526. threeterm_patterns, rv.func, dominatingvalue,
  2527. replacementvalue, measure)
  2528. Rel = _apply_patternbased_twoterm_simplification(Rel, patterns,
  2529. rv.func, dominatingvalue, replacementvalue, measure)
  2530. rv = rv.func(*([_canonical(i) for i in ordered(Rel)]
  2531. + nonRel + nonRealRel))
  2532. return rv
  2533. def _apply_patternbased_twoterm_simplification(Rel, patterns, func,
  2534. dominatingvalue,
  2535. replacementvalue,
  2536. measure):
  2537. """ Apply pattern-based two-term simplification."""
  2538. from sympy.functions.elementary.miscellaneous import Min, Max
  2539. from sympy.core.relational import Ge, Gt, _Inequality
  2540. changed = True
  2541. while changed and len(Rel) >= 2:
  2542. changed = False
  2543. # Use only < or <=
  2544. Rel = [r.reversed if isinstance(r, (Ge, Gt)) else r for r in Rel]
  2545. # Sort based on ordered
  2546. Rel = list(ordered(Rel))
  2547. # Eq and Ne must be tested reversed as well
  2548. rtmp = [(r, ) if isinstance(r, _Inequality) else (r, r.reversed) for r in Rel]
  2549. # Create a list of possible replacements
  2550. results = []
  2551. # Try all combinations of possibly reversed relational
  2552. for ((i, pi), (j, pj)) in combinations(enumerate(rtmp), 2):
  2553. for pattern, simp in patterns:
  2554. res = []
  2555. for p1, p2 in product(pi, pj):
  2556. # use SymPy matching
  2557. oldexpr = Tuple(p1, p2)
  2558. tmpres = oldexpr.match(pattern)
  2559. if tmpres:
  2560. res.append((tmpres, oldexpr))
  2561. if res:
  2562. for tmpres, oldexpr in res:
  2563. # we have a matching, compute replacement
  2564. np = simp.xreplace(tmpres)
  2565. if np == dominatingvalue:
  2566. # if dominatingvalue, the whole expression
  2567. # will be replacementvalue
  2568. return [replacementvalue]
  2569. # add replacement
  2570. if not isinstance(np, ITE) and not np.has(Min, Max):
  2571. # We only want to use ITE and Min/Max replacements if
  2572. # they simplify to a relational
  2573. costsaving = measure(func(*oldexpr.args)) - measure(np)
  2574. if costsaving > 0:
  2575. results.append((costsaving, ([i, j], np)))
  2576. if results:
  2577. # Sort results based on complexity
  2578. results = sorted(results,
  2579. key=lambda pair: pair[0], reverse=True)
  2580. # Replace the one providing most simplification
  2581. replacement = results[0][1]
  2582. idx, newrel = replacement
  2583. idx.sort()
  2584. # Remove the old relationals
  2585. for index in reversed(idx):
  2586. del Rel[index]
  2587. if dominatingvalue is None or newrel != Not(dominatingvalue):
  2588. # Insert the new one (no need to insert a value that will
  2589. # not affect the result)
  2590. if newrel.func == func:
  2591. for a in newrel.args:
  2592. Rel.append(a)
  2593. else:
  2594. Rel.append(newrel)
  2595. # We did change something so try again
  2596. changed = True
  2597. return Rel
  2598. def _apply_patternbased_threeterm_simplification(Rel, patterns, func,
  2599. dominatingvalue,
  2600. replacementvalue,
  2601. measure):
  2602. """ Apply pattern-based three-term simplification."""
  2603. from sympy.functions.elementary.miscellaneous import Min, Max
  2604. from sympy.core.relational import Le, Lt, _Inequality
  2605. changed = True
  2606. while changed and len(Rel) >= 3:
  2607. changed = False
  2608. # Use only > or >=
  2609. Rel = [r.reversed if isinstance(r, (Le, Lt)) else r for r in Rel]
  2610. # Sort based on ordered
  2611. Rel = list(ordered(Rel))
  2612. # Create a list of possible replacements
  2613. results = []
  2614. # Eq and Ne must be tested reversed as well
  2615. rtmp = [(r, ) if isinstance(r, _Inequality) else (r, r.reversed) for r in Rel]
  2616. # Try all combinations of possibly reversed relational
  2617. for ((i, pi), (j, pj), (k, pk)) in permutations(enumerate(rtmp), 3):
  2618. for pattern, simp in patterns:
  2619. res = []
  2620. for p1, p2, p3 in product(pi, pj, pk):
  2621. # use SymPy matching
  2622. oldexpr = Tuple(p1, p2, p3)
  2623. tmpres = oldexpr.match(pattern)
  2624. if tmpres:
  2625. res.append((tmpres, oldexpr))
  2626. if res:
  2627. for tmpres, oldexpr in res:
  2628. # we have a matching, compute replacement
  2629. np = simp.xreplace(tmpres)
  2630. if np == dominatingvalue:
  2631. # if dominatingvalue, the whole expression
  2632. # will be replacementvalue
  2633. return [replacementvalue]
  2634. # add replacement
  2635. if not isinstance(np, ITE) and not np.has(Min, Max):
  2636. # We only want to use ITE and Min/Max replacements if
  2637. # they simplify to a relational
  2638. costsaving = measure(func(*oldexpr.args)) - measure(np)
  2639. if costsaving > 0:
  2640. results.append((costsaving, ([i, j, k], np)))
  2641. if results:
  2642. # Sort results based on complexity
  2643. results = sorted(results,
  2644. key=lambda pair: pair[0], reverse=True)
  2645. # Replace the one providing most simplification
  2646. replacement = results[0][1]
  2647. idx, newrel = replacement
  2648. idx.sort()
  2649. # Remove the old relationals
  2650. for index in reversed(idx):
  2651. del Rel[index]
  2652. if dominatingvalue is None or newrel != Not(dominatingvalue):
  2653. # Insert the new one (no need to insert a value that will
  2654. # not affect the result)
  2655. if newrel.func == func:
  2656. for a in newrel.args:
  2657. Rel.append(a)
  2658. else:
  2659. Rel.append(newrel)
  2660. # We did change something so try again
  2661. changed = True
  2662. return Rel
  2663. @cacheit
  2664. def _simplify_patterns_and():
  2665. """ Two-term patterns for And."""
  2666. from sympy.core import Wild
  2667. from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt
  2668. from sympy.functions.elementary.complexes import Abs
  2669. from sympy.functions.elementary.miscellaneous import Min, Max
  2670. a = Wild('a')
  2671. b = Wild('b')
  2672. c = Wild('c')
  2673. # Relationals patterns should be in alphabetical order
  2674. # (pattern1, pattern2, simplified)
  2675. # Do not use Ge, Gt
  2676. _matchers_and = ((Tuple(Eq(a, b), Lt(a, b)), false),
  2677. #(Tuple(Eq(a, b), Lt(b, a)), S.false),
  2678. #(Tuple(Le(b, a), Lt(a, b)), S.false),
  2679. #(Tuple(Lt(b, a), Le(a, b)), S.false),
  2680. (Tuple(Lt(b, a), Lt(a, b)), false),
  2681. (Tuple(Eq(a, b), Le(b, a)), Eq(a, b)),
  2682. #(Tuple(Eq(a, b), Le(a, b)), Eq(a, b)),
  2683. #(Tuple(Le(b, a), Lt(b, a)), Gt(a, b)),
  2684. (Tuple(Le(b, a), Le(a, b)), Eq(a, b)),
  2685. #(Tuple(Le(b, a), Ne(a, b)), Gt(a, b)),
  2686. #(Tuple(Lt(b, a), Ne(a, b)), Gt(a, b)),
  2687. (Tuple(Le(a, b), Lt(a, b)), Lt(a, b)),
  2688. (Tuple(Le(a, b), Ne(a, b)), Lt(a, b)),
  2689. (Tuple(Lt(a, b), Ne(a, b)), Lt(a, b)),
  2690. # Sign
  2691. (Tuple(Eq(a, b), Eq(a, -b)), And(Eq(a, S.Zero), Eq(b, S.Zero))),
  2692. # Min/Max/ITE
  2693. (Tuple(Le(b, a), Le(c, a)), Ge(a, Max(b, c))),
  2694. (Tuple(Le(b, a), Lt(c, a)), ITE(b > c, Ge(a, b), Gt(a, c))),
  2695. (Tuple(Lt(b, a), Lt(c, a)), Gt(a, Max(b, c))),
  2696. (Tuple(Le(a, b), Le(a, c)), Le(a, Min(b, c))),
  2697. (Tuple(Le(a, b), Lt(a, c)), ITE(b < c, Le(a, b), Lt(a, c))),
  2698. (Tuple(Lt(a, b), Lt(a, c)), Lt(a, Min(b, c))),
  2699. (Tuple(Le(a, b), Le(c, a)), ITE(Eq(b, c), Eq(a, b), ITE(b < c, false, And(Le(a, b), Ge(a, c))))),
  2700. (Tuple(Le(c, a), Le(a, b)), ITE(Eq(b, c), Eq(a, b), ITE(b < c, false, And(Le(a, b), Ge(a, c))))),
  2701. (Tuple(Lt(a, b), Lt(c, a)), ITE(b < c, false, And(Lt(a, b), Gt(a, c)))),
  2702. (Tuple(Lt(c, a), Lt(a, b)), ITE(b < c, false, And(Lt(a, b), Gt(a, c)))),
  2703. (Tuple(Le(a, b), Lt(c, a)), ITE(b <= c, false, And(Le(a, b), Gt(a, c)))),
  2704. (Tuple(Le(c, a), Lt(a, b)), ITE(b <= c, false, And(Lt(a, b), Ge(a, c)))),
  2705. (Tuple(Eq(a, b), Eq(a, c)), ITE(Eq(b, c), Eq(a, b), false)),
  2706. (Tuple(Lt(a, b), Lt(-b, a)), ITE(b > 0, Lt(Abs(a), b), false)),
  2707. (Tuple(Le(a, b), Le(-b, a)), ITE(b >= 0, Le(Abs(a), b), false)),
  2708. )
  2709. return _matchers_and
  2710. @cacheit
  2711. def _simplify_patterns_and3():
  2712. """ Three-term patterns for And."""
  2713. from sympy.core import Wild
  2714. from sympy.core.relational import Eq, Ge, Gt
  2715. a = Wild('a')
  2716. b = Wild('b')
  2717. c = Wild('c')
  2718. # Relationals patterns should be in alphabetical order
  2719. # (pattern1, pattern2, pattern3, simplified)
  2720. # Do not use Le, Lt
  2721. _matchers_and = ((Tuple(Ge(a, b), Ge(b, c), Gt(c, a)), false),
  2722. (Tuple(Ge(a, b), Gt(b, c), Gt(c, a)), false),
  2723. (Tuple(Gt(a, b), Gt(b, c), Gt(c, a)), false),
  2724. # (Tuple(Ge(c, a), Gt(a, b), Gt(b, c)), S.false),
  2725. # Lower bound relations
  2726. # Commented out combinations that does not simplify
  2727. (Tuple(Ge(a, b), Ge(a, c), Ge(b, c)), And(Ge(a, b), Ge(b, c))),
  2728. (Tuple(Ge(a, b), Ge(a, c), Gt(b, c)), And(Ge(a, b), Gt(b, c))),
  2729. # (Tuple(Ge(a, b), Gt(a, c), Ge(b, c)), And(Ge(a, b), Ge(b, c))),
  2730. (Tuple(Ge(a, b), Gt(a, c), Gt(b, c)), And(Ge(a, b), Gt(b, c))),
  2731. # (Tuple(Gt(a, b), Ge(a, c), Ge(b, c)), And(Gt(a, b), Ge(b, c))),
  2732. (Tuple(Ge(a, c), Gt(a, b), Gt(b, c)), And(Gt(a, b), Gt(b, c))),
  2733. (Tuple(Ge(b, c), Gt(a, b), Gt(a, c)), And(Gt(a, b), Ge(b, c))),
  2734. (Tuple(Gt(a, b), Gt(a, c), Gt(b, c)), And(Gt(a, b), Gt(b, c))),
  2735. # Upper bound relations
  2736. # Commented out combinations that does not simplify
  2737. (Tuple(Ge(b, a), Ge(c, a), Ge(b, c)), And(Ge(c, a), Ge(b, c))),
  2738. (Tuple(Ge(b, a), Ge(c, a), Gt(b, c)), And(Ge(c, a), Gt(b, c))),
  2739. # (Tuple(Ge(b, a), Gt(c, a), Ge(b, c)), And(Gt(c, a), Ge(b, c))),
  2740. (Tuple(Ge(b, a), Gt(c, a), Gt(b, c)), And(Gt(c, a), Gt(b, c))),
  2741. # (Tuple(Gt(b, a), Ge(c, a), Ge(b, c)), And(Ge(c, a), Ge(b, c))),
  2742. (Tuple(Ge(c, a), Gt(b, a), Gt(b, c)), And(Ge(c, a), Gt(b, c))),
  2743. (Tuple(Ge(b, c), Gt(b, a), Gt(c, a)), And(Gt(c, a), Ge(b, c))),
  2744. (Tuple(Gt(b, a), Gt(c, a), Gt(b, c)), And(Gt(c, a), Gt(b, c))),
  2745. # Circular relation
  2746. (Tuple(Ge(a, b), Ge(b, c), Ge(c, a)), And(Eq(a, b), Eq(b, c))),
  2747. )
  2748. return _matchers_and
  2749. @cacheit
  2750. def _simplify_patterns_or():
  2751. """ Two-term patterns for Or."""
  2752. from sympy.core import Wild
  2753. from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt
  2754. from sympy.functions.elementary.complexes import Abs
  2755. from sympy.functions.elementary.miscellaneous import Min, Max
  2756. a = Wild('a')
  2757. b = Wild('b')
  2758. c = Wild('c')
  2759. # Relationals patterns should be in alphabetical order
  2760. # (pattern1, pattern2, simplified)
  2761. # Do not use Ge, Gt
  2762. _matchers_or = ((Tuple(Le(b, a), Le(a, b)), true),
  2763. #(Tuple(Le(b, a), Lt(a, b)), true),
  2764. (Tuple(Le(b, a), Ne(a, b)), true),
  2765. #(Tuple(Le(a, b), Lt(b, a)), true),
  2766. #(Tuple(Le(a, b), Ne(a, b)), true),
  2767. #(Tuple(Eq(a, b), Le(b, a)), Ge(a, b)),
  2768. #(Tuple(Eq(a, b), Lt(b, a)), Ge(a, b)),
  2769. (Tuple(Eq(a, b), Le(a, b)), Le(a, b)),
  2770. (Tuple(Eq(a, b), Lt(a, b)), Le(a, b)),
  2771. #(Tuple(Le(b, a), Lt(b, a)), Ge(a, b)),
  2772. (Tuple(Lt(b, a), Lt(a, b)), Ne(a, b)),
  2773. (Tuple(Lt(b, a), Ne(a, b)), Ne(a, b)),
  2774. (Tuple(Le(a, b), Lt(a, b)), Le(a, b)),
  2775. #(Tuple(Lt(a, b), Ne(a, b)), Ne(a, b)),
  2776. (Tuple(Eq(a, b), Ne(a, c)), ITE(Eq(b, c), true, Ne(a, c))),
  2777. (Tuple(Ne(a, b), Ne(a, c)), ITE(Eq(b, c), Ne(a, b), true)),
  2778. # Min/Max/ITE
  2779. (Tuple(Le(b, a), Le(c, a)), Ge(a, Min(b, c))),
  2780. #(Tuple(Ge(b, a), Ge(c, a)), Ge(Min(b, c), a)),
  2781. (Tuple(Le(b, a), Lt(c, a)), ITE(b > c, Lt(c, a), Le(b, a))),
  2782. (Tuple(Lt(b, a), Lt(c, a)), Gt(a, Min(b, c))),
  2783. #(Tuple(Gt(b, a), Gt(c, a)), Gt(Min(b, c), a)),
  2784. (Tuple(Le(a, b), Le(a, c)), Le(a, Max(b, c))),
  2785. #(Tuple(Le(b, a), Le(c, a)), Le(Max(b, c), a)),
  2786. (Tuple(Le(a, b), Lt(a, c)), ITE(b >= c, Le(a, b), Lt(a, c))),
  2787. (Tuple(Lt(a, b), Lt(a, c)), Lt(a, Max(b, c))),
  2788. #(Tuple(Lt(b, a), Lt(c, a)), Lt(Max(b, c), a)),
  2789. (Tuple(Le(a, b), Le(c, a)), ITE(b >= c, true, Or(Le(a, b), Ge(a, c)))),
  2790. (Tuple(Le(c, a), Le(a, b)), ITE(b >= c, true, Or(Le(a, b), Ge(a, c)))),
  2791. (Tuple(Lt(a, b), Lt(c, a)), ITE(b > c, true, Or(Lt(a, b), Gt(a, c)))),
  2792. (Tuple(Lt(c, a), Lt(a, b)), ITE(b > c, true, Or(Lt(a, b), Gt(a, c)))),
  2793. (Tuple(Le(a, b), Lt(c, a)), ITE(b >= c, true, Or(Le(a, b), Gt(a, c)))),
  2794. (Tuple(Le(c, a), Lt(a, b)), ITE(b >= c, true, Or(Lt(a, b), Ge(a, c)))),
  2795. (Tuple(Lt(b, a), Lt(a, -b)), ITE(b >= 0, Gt(Abs(a), b), true)),
  2796. (Tuple(Le(b, a), Le(a, -b)), ITE(b > 0, Ge(Abs(a), b), true)),
  2797. )
  2798. return _matchers_or
  2799. @cacheit
  2800. def _simplify_patterns_xor():
  2801. """ Two-term patterns for Xor."""
  2802. from sympy.functions.elementary.miscellaneous import Min, Max
  2803. from sympy.core import Wild
  2804. from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt
  2805. a = Wild('a')
  2806. b = Wild('b')
  2807. c = Wild('c')
  2808. # Relationals patterns should be in alphabetical order
  2809. # (pattern1, pattern2, simplified)
  2810. # Do not use Ge, Gt
  2811. _matchers_xor = (#(Tuple(Le(b, a), Lt(a, b)), true),
  2812. #(Tuple(Lt(b, a), Le(a, b)), true),
  2813. #(Tuple(Eq(a, b), Le(b, a)), Gt(a, b)),
  2814. #(Tuple(Eq(a, b), Lt(b, a)), Ge(a, b)),
  2815. (Tuple(Eq(a, b), Le(a, b)), Lt(a, b)),
  2816. (Tuple(Eq(a, b), Lt(a, b)), Le(a, b)),
  2817. (Tuple(Le(a, b), Lt(a, b)), Eq(a, b)),
  2818. (Tuple(Le(a, b), Le(b, a)), Ne(a, b)),
  2819. (Tuple(Le(b, a), Ne(a, b)), Le(a, b)),
  2820. # (Tuple(Lt(b, a), Lt(a, b)), Ne(a, b)),
  2821. (Tuple(Lt(b, a), Ne(a, b)), Lt(a, b)),
  2822. # (Tuple(Le(a, b), Lt(a, b)), Eq(a, b)),
  2823. # (Tuple(Le(a, b), Ne(a, b)), Ge(a, b)),
  2824. # (Tuple(Lt(a, b), Ne(a, b)), Gt(a, b)),
  2825. # Min/Max/ITE
  2826. (Tuple(Le(b, a), Le(c, a)),
  2827. And(Ge(a, Min(b, c)), Lt(a, Max(b, c)))),
  2828. (Tuple(Le(b, a), Lt(c, a)),
  2829. ITE(b > c, And(Gt(a, c), Lt(a, b)),
  2830. And(Ge(a, b), Le(a, c)))),
  2831. (Tuple(Lt(b, a), Lt(c, a)),
  2832. And(Gt(a, Min(b, c)), Le(a, Max(b, c)))),
  2833. (Tuple(Le(a, b), Le(a, c)),
  2834. And(Le(a, Max(b, c)), Gt(a, Min(b, c)))),
  2835. (Tuple(Le(a, b), Lt(a, c)),
  2836. ITE(b < c, And(Lt(a, c), Gt(a, b)),
  2837. And(Le(a, b), Ge(a, c)))),
  2838. (Tuple(Lt(a, b), Lt(a, c)),
  2839. And(Lt(a, Max(b, c)), Ge(a, Min(b, c)))),
  2840. )
  2841. return _matchers_xor
  2842. def simplify_univariate(expr):
  2843. """return a simplified version of univariate boolean expression, else ``expr``"""
  2844. from sympy.functions.elementary.piecewise import Piecewise
  2845. from sympy.core.relational import Eq, Ne
  2846. if not isinstance(expr, BooleanFunction):
  2847. return expr
  2848. if expr.atoms(Eq, Ne):
  2849. return expr
  2850. c = expr
  2851. free = c.free_symbols
  2852. if len(free) != 1:
  2853. return c
  2854. x = free.pop()
  2855. ok, i = Piecewise((0, c), evaluate=False
  2856. )._intervals(x, err_on_Eq=True)
  2857. if not ok:
  2858. return c
  2859. if not i:
  2860. return false
  2861. args = []
  2862. for a, b, _, _ in i:
  2863. if a is S.NegativeInfinity:
  2864. if b is S.Infinity:
  2865. c = true
  2866. else:
  2867. if c.subs(x, b) == True:
  2868. c = (x <= b)
  2869. else:
  2870. c = (x < b)
  2871. else:
  2872. incl_a = (c.subs(x, a) == True)
  2873. incl_b = (c.subs(x, b) == True)
  2874. if incl_a and incl_b:
  2875. if b.is_infinite:
  2876. c = (x >= a)
  2877. else:
  2878. c = And(a <= x, x <= b)
  2879. elif incl_a:
  2880. c = And(a <= x, x < b)
  2881. elif incl_b:
  2882. if b.is_infinite:
  2883. c = (x > a)
  2884. else:
  2885. c = And(a < x, x <= b)
  2886. else:
  2887. c = And(a < x, x < b)
  2888. args.append(c)
  2889. return Or(*args)
  2890. # Classes corresponding to logic gates
  2891. # Used in gateinputcount method
  2892. BooleanGates = (And, Or, Xor, Nand, Nor, Not, Xnor, ITE)
  2893. def gateinputcount(expr):
  2894. """
  2895. Return the total number of inputs for the logic gates realizing the
  2896. Boolean expression.
  2897. Returns
  2898. =======
  2899. int
  2900. Number of gate inputs
  2901. Note
  2902. ====
  2903. Not all Boolean functions count as gate here, only those that are
  2904. considered to be standard gates. These are: :py:class:`~.And`,
  2905. :py:class:`~.Or`, :py:class:`~.Xor`, :py:class:`~.Not`, and
  2906. :py:class:`~.ITE` (multiplexer). :py:class:`~.Nand`, :py:class:`~.Nor`,
  2907. and :py:class:`~.Xnor` will be evaluated to ``Not(And())`` etc.
  2908. Examples
  2909. ========
  2910. >>> from sympy.logic import And, Or, Nand, Not, gateinputcount
  2911. >>> from sympy.abc import x, y, z
  2912. >>> expr = And(x, y)
  2913. >>> gateinputcount(expr)
  2914. 2
  2915. >>> gateinputcount(Or(expr, z))
  2916. 4
  2917. Note that ``Nand`` is automatically evaluated to ``Not(And())`` so
  2918. >>> gateinputcount(Nand(x, y, z))
  2919. 4
  2920. >>> gateinputcount(Not(And(x, y, z)))
  2921. 4
  2922. Although this can be avoided by using ``evaluate=False``
  2923. >>> gateinputcount(Nand(x, y, z, evaluate=False))
  2924. 3
  2925. Also note that a comparison will count as a Boolean variable:
  2926. >>> gateinputcount(And(x > z, y >= 2))
  2927. 2
  2928. As will a symbol:
  2929. >>> gateinputcount(x)
  2930. 0
  2931. """
  2932. if not isinstance(expr, Boolean):
  2933. raise TypeError("Expression must be Boolean")
  2934. if isinstance(expr, BooleanGates):
  2935. return len(expr.args) + sum(gateinputcount(x) for x in expr.args)
  2936. return 0