boolalg.py 112 KB

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