boolalg.py 109 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502
  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 S.true
  46. if e == False:
  47. return S.false
  48. if isinstance(e, Symbol):
  49. z = e.is_zero
  50. if z is None:
  51. return e
  52. return S.false if z else S.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. Don't 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 S.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 S.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: S.true if x else S.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. S.true in r.args or
  403. S.false in r.args):
  404. reps[r] = S.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 return different things 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 [S.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 S.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, S.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 [S.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 S.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'], S.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 = map(lambda x: to_anf(x, deep=deep) if deep else x, 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 S.true
  1029. elif A.is_Relational and B.is_Relational:
  1030. if A.canonical == B.canonical:
  1031. return S.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 S.true:
  1159. a = a.rhs
  1160. elif a.rhs is S.true:
  1161. a = a.lhs
  1162. elif a.lhs is S.false:
  1163. a = Not(a.rhs)
  1164. elif a.rhs is S.false:
  1165. a = Not(a.lhs)
  1166. else:
  1167. # binary can only equal True or False
  1168. a = S.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 S.true in a.args:
  1188. a = a.lhs if a.rhs is S.true else a.rhs
  1189. elif S.false in a.args:
  1190. a = Not(a.lhs) if a.rhs is S.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 S.true:
  1196. return b
  1197. if a is S.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 S.true and c is S.false:
  1205. return a
  1206. if b is S.false and c is S.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 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 And, Or and Not, and Not is applied only to literals.
  1363. If ``simplify`` is ``True``, the result contains no redundant clauses.
  1364. Examples
  1365. ========
  1366. >>> from sympy.abc import A, B, C, D
  1367. >>> from sympy.logic.boolalg import Not, Equivalent, to_nnf
  1368. >>> to_nnf(Not((~A & ~B) | (C & D)))
  1369. (A | B) & (~C | ~D)
  1370. >>> to_nnf(Equivalent(A >> B, B >> A))
  1371. (A | ~B | (A & ~B)) & (B | ~A | (B & ~A))
  1372. """
  1373. if is_nnf(expr, simplify):
  1374. return expr
  1375. return expr.to_nnf(simplify)
  1376. def to_cnf(expr, simplify=False, force=False):
  1377. """
  1378. Convert a propositional logical sentence ``expr`` to conjunctive normal
  1379. form: ``((A | ~B | ...) & (B | C | ...) & ...)``.
  1380. If ``simplify`` is ``True``, ``expr`` is evaluated to its simplest CNF
  1381. form using the Quine-McCluskey algorithm; this may take a long
  1382. time if there are more than 8 variables and requires that the
  1383. ``force`` flag be set to ``True`` (default is ``False``).
  1384. Examples
  1385. ========
  1386. >>> from sympy.logic.boolalg import to_cnf
  1387. >>> from sympy.abc import A, B, D
  1388. >>> to_cnf(~(A | B) | D)
  1389. (D | ~A) & (D | ~B)
  1390. >>> to_cnf((A | B) & (A | ~A), True)
  1391. A | B
  1392. """
  1393. expr = sympify(expr)
  1394. if not isinstance(expr, BooleanFunction):
  1395. return expr
  1396. if simplify:
  1397. if not force and len(_find_predicates(expr)) > 8:
  1398. raise ValueError(filldedent('''
  1399. To simplify a logical expression with more
  1400. than 8 variables may take a long time and requires
  1401. the use of `force=True`.'''))
  1402. return simplify_logic(expr, 'cnf', True, force=force)
  1403. # Don't convert unless we have to
  1404. if is_cnf(expr):
  1405. return expr
  1406. expr = eliminate_implications(expr)
  1407. res = distribute_and_over_or(expr)
  1408. return res
  1409. def to_dnf(expr, simplify=False, force=False):
  1410. """
  1411. Convert a propositional logical sentence ``expr`` to disjunctive normal
  1412. form: ``((A & ~B & ...) | (B & C & ...) | ...)``.
  1413. If ``simplify`` is ``True``, ``expr`` is evaluated to its simplest DNF form using
  1414. the Quine-McCluskey algorithm; this may take a long
  1415. time if there are more than 8 variables and requires that the
  1416. ``force`` flag be set to ``True`` (default is ``False``).
  1417. Examples
  1418. ========
  1419. >>> from sympy.logic.boolalg import to_dnf
  1420. >>> from sympy.abc import A, B, C
  1421. >>> to_dnf(B & (A | C))
  1422. (A & B) | (B & C)
  1423. >>> to_dnf((A & B) | (A & ~B) | (B & C) | (~B & C), True)
  1424. A | C
  1425. """
  1426. expr = sympify(expr)
  1427. if not isinstance(expr, BooleanFunction):
  1428. return expr
  1429. if simplify:
  1430. if not force and len(_find_predicates(expr)) > 8:
  1431. raise ValueError(filldedent('''
  1432. To simplify a logical expression with more
  1433. than 8 variables may take a long time and requires
  1434. the use of `force=True`.'''))
  1435. return simplify_logic(expr, 'dnf', True, force=force)
  1436. # Don't convert unless we have to
  1437. if is_dnf(expr):
  1438. return expr
  1439. expr = eliminate_implications(expr)
  1440. return distribute_or_over_and(expr)
  1441. def is_anf(expr):
  1442. r"""
  1443. Checks if ``expr`` is in Algebraic Normal Form (ANF).
  1444. A logical expression is in ANF if it has the form
  1445. .. math:: 1 \oplus a \oplus b \oplus ab \oplus abc
  1446. i.e. it is purely true, purely false, conjunction of
  1447. variables or exclusive disjunction. The exclusive
  1448. disjunction can only contain true, variables or
  1449. conjunction of variables. No negations are permitted.
  1450. Examples
  1451. ========
  1452. >>> from sympy.logic.boolalg import And, Not, Xor, true, is_anf
  1453. >>> from sympy.abc import A, B, C
  1454. >>> is_anf(true)
  1455. True
  1456. >>> is_anf(A)
  1457. True
  1458. >>> is_anf(And(A, B, C))
  1459. True
  1460. >>> is_anf(Xor(A, Not(B)))
  1461. False
  1462. """
  1463. expr = sympify(expr)
  1464. if is_literal(expr) and not isinstance(expr, Not):
  1465. return True
  1466. if isinstance(expr, And):
  1467. for arg in expr.args:
  1468. if not arg.is_Symbol:
  1469. return False
  1470. return True
  1471. elif isinstance(expr, Xor):
  1472. for arg in expr.args:
  1473. if isinstance(arg, And):
  1474. for a in arg.args:
  1475. if not a.is_Symbol:
  1476. return False
  1477. elif is_literal(arg):
  1478. if isinstance(arg, Not):
  1479. return False
  1480. else:
  1481. return False
  1482. return True
  1483. else:
  1484. return False
  1485. def is_nnf(expr, simplified=True):
  1486. """
  1487. Checks if ``expr`` is in Negation Normal Form (NNF).
  1488. A logical expression is in NNF if it
  1489. contains only And, Or and Not, and Not is applied only to literals.
  1490. If ``simplified`` is ``True``, checks if result contains no redundant clauses.
  1491. Examples
  1492. ========
  1493. >>> from sympy.abc import A, B, C
  1494. >>> from sympy.logic.boolalg import Not, is_nnf
  1495. >>> is_nnf(A & B | ~C)
  1496. True
  1497. >>> is_nnf((A | ~A) & (B | C))
  1498. False
  1499. >>> is_nnf((A | ~A) & (B | C), False)
  1500. True
  1501. >>> is_nnf(Not(A & B) | C)
  1502. False
  1503. >>> is_nnf((A >> B) & (B >> A))
  1504. False
  1505. """
  1506. expr = sympify(expr)
  1507. if is_literal(expr):
  1508. return True
  1509. stack = [expr]
  1510. while stack:
  1511. expr = stack.pop()
  1512. if expr.func in (And, Or):
  1513. if simplified:
  1514. args = expr.args
  1515. for arg in args:
  1516. if Not(arg) in args:
  1517. return False
  1518. stack.extend(expr.args)
  1519. elif not is_literal(expr):
  1520. return False
  1521. return True
  1522. def is_cnf(expr):
  1523. """
  1524. Test whether or not an expression is in conjunctive normal form.
  1525. Examples
  1526. ========
  1527. >>> from sympy.logic.boolalg import is_cnf
  1528. >>> from sympy.abc import A, B, C
  1529. >>> is_cnf(A | B | C)
  1530. True
  1531. >>> is_cnf(A & B & C)
  1532. True
  1533. >>> is_cnf((A & B) | C)
  1534. False
  1535. """
  1536. return _is_form(expr, And, Or)
  1537. def is_dnf(expr):
  1538. """
  1539. Test whether or not an expression is in disjunctive normal form.
  1540. Examples
  1541. ========
  1542. >>> from sympy.logic.boolalg import is_dnf
  1543. >>> from sympy.abc import A, B, C
  1544. >>> is_dnf(A | B | C)
  1545. True
  1546. >>> is_dnf(A & B & C)
  1547. True
  1548. >>> is_dnf((A & B) | C)
  1549. True
  1550. >>> is_dnf(A & (B | C))
  1551. False
  1552. """
  1553. return _is_form(expr, Or, And)
  1554. def _is_form(expr, function1, function2):
  1555. """
  1556. Test whether or not an expression is of the required form.
  1557. """
  1558. expr = sympify(expr)
  1559. vals = function1.make_args(expr) if isinstance(expr, function1) else [expr]
  1560. for lit in vals:
  1561. if isinstance(lit, function2):
  1562. vals2 = function2.make_args(lit) if isinstance(lit, function2) else [lit]
  1563. for l in vals2:
  1564. if is_literal(l) is False:
  1565. return False
  1566. elif is_literal(lit) is False:
  1567. return False
  1568. return True
  1569. def eliminate_implications(expr):
  1570. """
  1571. Change ``Implies`` and ``Equivalent`` into ``And``, ``Or``, and ``Not``.
  1572. That is, return an expression that is equivalent to ``expr``, but has only
  1573. ``&``, ``|``, and ``~`` as logical
  1574. operators.
  1575. Examples
  1576. ========
  1577. >>> from sympy.logic.boolalg import Implies, Equivalent, \
  1578. eliminate_implications
  1579. >>> from sympy.abc import A, B, C
  1580. >>> eliminate_implications(Implies(A, B))
  1581. B | ~A
  1582. >>> eliminate_implications(Equivalent(A, B))
  1583. (A | ~B) & (B | ~A)
  1584. >>> eliminate_implications(Equivalent(A, B, C))
  1585. (A | ~C) & (B | ~A) & (C | ~B)
  1586. """
  1587. return to_nnf(expr, simplify=False)
  1588. def is_literal(expr):
  1589. """
  1590. Returns True if expr is a literal, else False.
  1591. Examples
  1592. ========
  1593. >>> from sympy import Or, Q
  1594. >>> from sympy.abc import A, B
  1595. >>> from sympy.logic.boolalg import is_literal
  1596. >>> is_literal(A)
  1597. True
  1598. >>> is_literal(~A)
  1599. True
  1600. >>> is_literal(Q.zero(A))
  1601. True
  1602. >>> is_literal(A + B)
  1603. True
  1604. >>> is_literal(Or(A, B))
  1605. False
  1606. """
  1607. from sympy.assumptions import AppliedPredicate
  1608. if isinstance(expr, Not):
  1609. return is_literal(expr.args[0])
  1610. elif expr in (True, False) or isinstance(expr, AppliedPredicate) or expr.is_Atom:
  1611. return True
  1612. elif not isinstance(expr, BooleanFunction) and all(
  1613. (isinstance(expr, AppliedPredicate) or a.is_Atom) for a in expr.args):
  1614. return True
  1615. return False
  1616. def to_int_repr(clauses, symbols):
  1617. """
  1618. Takes clauses in CNF format and puts them into an integer representation.
  1619. Examples
  1620. ========
  1621. >>> from sympy.logic.boolalg import to_int_repr
  1622. >>> from sympy.abc import x, y
  1623. >>> to_int_repr([x | y, y], [x, y]) == [{1, 2}, {2}]
  1624. True
  1625. """
  1626. # Convert the symbol list into a dict
  1627. symbols = dict(list(zip(symbols, list(range(1, len(symbols) + 1)))))
  1628. def append_symbol(arg, symbols):
  1629. if isinstance(arg, Not):
  1630. return -symbols[arg.args[0]]
  1631. else:
  1632. return symbols[arg]
  1633. return [{append_symbol(arg, symbols) for arg in Or.make_args(c)}
  1634. for c in clauses]
  1635. def term_to_integer(term):
  1636. """
  1637. Return an integer corresponding to the base-2 digits given by ``term``.
  1638. Parameters
  1639. ==========
  1640. term : a string or list of ones and zeros
  1641. Examples
  1642. ========
  1643. >>> from sympy.logic.boolalg import term_to_integer
  1644. >>> term_to_integer([1, 0, 0])
  1645. 4
  1646. >>> term_to_integer('100')
  1647. 4
  1648. """
  1649. return int(''.join(list(map(str, list(term)))), 2)
  1650. integer_to_term = ibin # XXX could delete?
  1651. def truth_table(expr, variables, input=True):
  1652. """
  1653. Return a generator of all possible configurations of the input variables,
  1654. and the result of the boolean expression for those values.
  1655. Parameters
  1656. ==========
  1657. expr : Boolean expression
  1658. variables : list of variables
  1659. input : bool (default ``True``)
  1660. Indicates whether to return the input combinations.
  1661. Examples
  1662. ========
  1663. >>> from sympy.logic.boolalg import truth_table
  1664. >>> from sympy.abc import x,y
  1665. >>> table = truth_table(x >> y, [x, y])
  1666. >>> for t in table:
  1667. ... print('{0} -> {1}'.format(*t))
  1668. [0, 0] -> True
  1669. [0, 1] -> True
  1670. [1, 0] -> False
  1671. [1, 1] -> True
  1672. >>> table = truth_table(x | y, [x, y])
  1673. >>> list(table)
  1674. [([0, 0], False), ([0, 1], True), ([1, 0], True), ([1, 1], True)]
  1675. If ``input`` is ``False``, ``truth_table`` returns only a list of truth values.
  1676. In this case, the corresponding input values of variables can be
  1677. deduced from the index of a given output.
  1678. >>> from sympy.utilities.iterables import ibin
  1679. >>> vars = [y, x]
  1680. >>> values = truth_table(x >> y, vars, input=False)
  1681. >>> values = list(values)
  1682. >>> values
  1683. [True, False, True, True]
  1684. >>> for i, value in enumerate(values):
  1685. ... print('{0} -> {1}'.format(list(zip(
  1686. ... vars, ibin(i, len(vars)))), value))
  1687. [(y, 0), (x, 0)] -> True
  1688. [(y, 0), (x, 1)] -> False
  1689. [(y, 1), (x, 0)] -> True
  1690. [(y, 1), (x, 1)] -> True
  1691. """
  1692. variables = [sympify(v) for v in variables]
  1693. expr = sympify(expr)
  1694. if not isinstance(expr, BooleanFunction) and not is_literal(expr):
  1695. return
  1696. table = product((0, 1), repeat=len(variables))
  1697. for term in table:
  1698. value = expr.xreplace(dict(zip(variables, term)))
  1699. if input:
  1700. yield list(term), value
  1701. else:
  1702. yield value
  1703. def _check_pair(minterm1, minterm2):
  1704. """
  1705. Checks if a pair of minterms differs by only one bit. If yes, returns
  1706. index, else returns `-1`.
  1707. """
  1708. # Early termination seems to be faster than list comprehension,
  1709. # at least for large examples.
  1710. index = -1
  1711. for x, i in enumerate(minterm1): # zip(minterm1, minterm2) is slower
  1712. if i != minterm2[x]:
  1713. if index == -1:
  1714. index = x
  1715. else:
  1716. return -1
  1717. return index
  1718. def _convert_to_varsSOP(minterm, variables):
  1719. """
  1720. Converts a term in the expansion of a function from binary to its
  1721. variable form (for SOP).
  1722. """
  1723. temp = [variables[n] if val == 1 else Not(variables[n])
  1724. for n, val in enumerate(minterm) if val != 3]
  1725. return And(*temp)
  1726. def _convert_to_varsPOS(maxterm, variables):
  1727. """
  1728. Converts a term in the expansion of a function from binary to its
  1729. variable form (for POS).
  1730. """
  1731. temp = [variables[n] if val == 0 else Not(variables[n])
  1732. for n, val in enumerate(maxterm) if val != 3]
  1733. return Or(*temp)
  1734. def _convert_to_varsANF(term, variables):
  1735. """
  1736. Converts a term in the expansion of a function from binary to it's
  1737. variable form (for ANF).
  1738. Parameters
  1739. ==========
  1740. term : list of 1's and 0's (complementation patter)
  1741. variables : list of variables
  1742. """
  1743. temp = [variables[n] for n, t in enumerate(term) if t == 1]
  1744. if not temp:
  1745. return true
  1746. return And(*temp)
  1747. def _get_odd_parity_terms(n):
  1748. """
  1749. Returns a list of lists, with all possible combinations of n zeros and ones
  1750. with an odd number of ones.
  1751. """
  1752. return [e for e in [ibin(i, n) for i in range(2**n)] if sum(e) % 2 == 1]
  1753. def _get_even_parity_terms(n):
  1754. """
  1755. Returns a list of lists, with all possible combinations of n zeros and ones
  1756. with an even number of ones.
  1757. """
  1758. return [e for e in [ibin(i, n) for i in range(2**n)] if sum(e) % 2 == 0]
  1759. def _simplified_pairs(terms):
  1760. """
  1761. Reduces a set of minterms, if possible, to a simplified set of minterms
  1762. with one less variable in the terms using QM method.
  1763. """
  1764. if not terms:
  1765. return []
  1766. simplified_terms = []
  1767. todo = list(range(len(terms)))
  1768. # Count number of ones as _check_pair can only potentially match if there
  1769. # is at most a difference of a single one
  1770. termdict = defaultdict(list)
  1771. for n, term in enumerate(terms):
  1772. ones = sum([1 for t in term if t == 1])
  1773. termdict[ones].append(n)
  1774. variables = len(terms[0])
  1775. for k in range(variables):
  1776. for i in termdict[k]:
  1777. for j in termdict[k+1]:
  1778. index = _check_pair(terms[i], terms[j])
  1779. if index != -1:
  1780. # Mark terms handled
  1781. todo[i] = todo[j] = None
  1782. # Copy old term
  1783. newterm = terms[i][:]
  1784. # Set differing position to don't care
  1785. newterm[index] = 3
  1786. # Add if not already there
  1787. if newterm not in simplified_terms:
  1788. simplified_terms.append(newterm)
  1789. if simplified_terms:
  1790. # Further simplifications only among the new terms
  1791. simplified_terms = _simplified_pairs(simplified_terms)
  1792. # Add remaining, non-simplified, terms
  1793. simplified_terms.extend([terms[i] for i in todo if i is not None])
  1794. return simplified_terms
  1795. def _rem_redundancy(l1, terms):
  1796. """
  1797. After the truth table has been sufficiently simplified, use the prime
  1798. implicant table method to recognize and eliminate redundant pairs,
  1799. and return the essential arguments.
  1800. """
  1801. if not terms:
  1802. return []
  1803. nterms = len(terms)
  1804. nl1 = len(l1)
  1805. # Create dominating matrix
  1806. dommatrix = [[0]*nl1 for n in range(nterms)]
  1807. colcount = [0]*nl1
  1808. rowcount = [0]*nterms
  1809. for primei, prime in enumerate(l1):
  1810. for termi, term in enumerate(terms):
  1811. # Check prime implicant covering term
  1812. if all(t == 3 or t == mt for t, mt in zip(prime, term)):
  1813. dommatrix[termi][primei] = 1
  1814. colcount[primei] += 1
  1815. rowcount[termi] += 1
  1816. # Keep track if anything changed
  1817. anythingchanged = True
  1818. # Then, go again
  1819. while anythingchanged:
  1820. anythingchanged = False
  1821. for rowi in range(nterms):
  1822. # Still non-dominated?
  1823. if rowcount[rowi]:
  1824. row = dommatrix[rowi]
  1825. for row2i in range(nterms):
  1826. # Still non-dominated?
  1827. if rowi != row2i and rowcount[rowi] and (rowcount[rowi] <= rowcount[row2i]):
  1828. row2 = dommatrix[row2i]
  1829. if all(row2[n] >= row[n] for n in range(nl1)):
  1830. # row2 dominating row, remove row2
  1831. rowcount[row2i] = 0
  1832. anythingchanged = True
  1833. for primei, prime in enumerate(row2):
  1834. if prime:
  1835. # Make corresponding entry 0
  1836. dommatrix[row2i][primei] = 0
  1837. colcount[primei] -= 1
  1838. colcache = dict()
  1839. for coli in range(nl1):
  1840. # Still non-dominated?
  1841. if colcount[coli]:
  1842. if coli in colcache:
  1843. col = colcache[coli]
  1844. else:
  1845. col = [dommatrix[i][coli] for i in range(nterms)]
  1846. colcache[coli] = col
  1847. for col2i in range(nl1):
  1848. # Still non-dominated?
  1849. if coli != col2i and colcount[col2i] and (colcount[coli] >= colcount[col2i]):
  1850. if col2i in colcache:
  1851. col2 = colcache[col2i]
  1852. else:
  1853. col2 = [dommatrix[i][col2i] for i in range(nterms)]
  1854. colcache[col2i] = col2
  1855. if all(col[n] >= col2[n] for n in range(nterms)):
  1856. # col dominating col2, remove col2
  1857. colcount[col2i] = 0
  1858. anythingchanged = True
  1859. for termi, term in enumerate(col2):
  1860. if term and dommatrix[termi][col2i]:
  1861. # Make corresponding entry 0
  1862. dommatrix[termi][col2i] = 0
  1863. rowcount[termi] -= 1
  1864. if not anythingchanged:
  1865. # Heuristically select the prime implicant covering most terms
  1866. maxterms = 0
  1867. bestcolidx = -1
  1868. for coli in range(nl1):
  1869. s = colcount[coli]
  1870. if s > maxterms:
  1871. bestcolidx = coli
  1872. maxterms = s
  1873. # In case we found a prime implicant covering at least two terms
  1874. if bestcolidx != -1 and maxterms > 1:
  1875. for primei, prime in enumerate(l1):
  1876. if primei != bestcolidx:
  1877. for termi, term in enumerate(colcache[bestcolidx]):
  1878. if term and dommatrix[termi][primei]:
  1879. # Make corresponding entry 0
  1880. dommatrix[termi][primei] = 0
  1881. anythingchanged = True
  1882. rowcount[termi] -= 1
  1883. colcount[primei] -= 1
  1884. return [l1[i] for i in range(nl1) if colcount[i]]
  1885. def _input_to_binlist(inputlist, variables):
  1886. binlist = []
  1887. bits = len(variables)
  1888. for val in inputlist:
  1889. if isinstance(val, int):
  1890. binlist.append(ibin(val, bits))
  1891. elif isinstance(val, dict):
  1892. nonspecvars = list(variables)
  1893. for key in val.keys():
  1894. nonspecvars.remove(key)
  1895. for t in product((0, 1), repeat=len(nonspecvars)):
  1896. d = dict(zip(nonspecvars, t))
  1897. d.update(val)
  1898. binlist.append([d[v] for v in variables])
  1899. elif isinstance(val, (list, tuple)):
  1900. if len(val) != bits:
  1901. raise ValueError("Each term must contain {bits} bits as there are"
  1902. "\n{bits} variables (or be an integer)."
  1903. "".format(bits=bits))
  1904. binlist.append(list(val))
  1905. else:
  1906. raise TypeError("A term list can only contain lists,"
  1907. " ints or dicts.")
  1908. return binlist
  1909. def SOPform(variables, minterms, dontcares=None):
  1910. """
  1911. The SOPform function uses simplified_pairs and a redundant group-
  1912. eliminating algorithm to convert the list of all input combos that
  1913. generate '1' (the minterms) into the smallest Sum of Products form.
  1914. The variables must be given as the first argument.
  1915. Return a logical Or function (i.e., the "sum of products" or "SOP"
  1916. form) that gives the desired outcome. If there are inputs that can
  1917. be ignored, pass them as a list, too.
  1918. The result will be one of the (perhaps many) functions that satisfy
  1919. the conditions.
  1920. Examples
  1921. ========
  1922. >>> from sympy.logic import SOPform
  1923. >>> from sympy import symbols
  1924. >>> w, x, y, z = symbols('w x y z')
  1925. >>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1],
  1926. ... [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]]
  1927. >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]]
  1928. >>> SOPform([w, x, y, z], minterms, dontcares)
  1929. (y & z) | (~w & ~x)
  1930. The terms can also be represented as integers:
  1931. >>> minterms = [1, 3, 7, 11, 15]
  1932. >>> dontcares = [0, 2, 5]
  1933. >>> SOPform([w, x, y, z], minterms, dontcares)
  1934. (y & z) | (~w & ~x)
  1935. They can also be specified using dicts, which does not have to be fully
  1936. specified:
  1937. >>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}]
  1938. >>> SOPform([w, x, y, z], minterms)
  1939. (x & ~w) | (y & z & ~x)
  1940. Or a combination:
  1941. >>> minterms = [4, 7, 11, [1, 1, 1, 1]]
  1942. >>> dontcares = [{w : 0, x : 0, y: 0}, 5]
  1943. >>> SOPform([w, x, y, z], minterms, dontcares)
  1944. (w & y & z) | (~w & ~y) | (x & z & ~w)
  1945. References
  1946. ==========
  1947. .. [1] https://en.wikipedia.org/wiki/Quine-McCluskey_algorithm
  1948. """
  1949. if not minterms:
  1950. return false
  1951. variables = tuple(map(sympify, variables))
  1952. minterms = _input_to_binlist(minterms, variables)
  1953. dontcares = _input_to_binlist((dontcares or []), variables)
  1954. for d in dontcares:
  1955. if d in minterms:
  1956. raise ValueError('%s in minterms is also in dontcares' % d)
  1957. return _sop_form(variables, minterms, dontcares)
  1958. def _sop_form(variables, minterms, dontcares):
  1959. new = _simplified_pairs(minterms + dontcares)
  1960. essential = _rem_redundancy(new, minterms)
  1961. return Or(*[_convert_to_varsSOP(x, variables) for x in essential])
  1962. def POSform(variables, minterms, dontcares=None):
  1963. """
  1964. The POSform function uses simplified_pairs and a redundant-group
  1965. eliminating algorithm to convert the list of all input combinations
  1966. that generate '1' (the minterms) into the smallest Product of Sums form.
  1967. The variables must be given as the first argument.
  1968. Return a logical And function (i.e., the "product of sums" or "POS"
  1969. form) that gives the desired outcome. If there are inputs that can
  1970. be ignored, pass them as a list, too.
  1971. The result will be one of the (perhaps many) functions that satisfy
  1972. the conditions.
  1973. Examples
  1974. ========
  1975. >>> from sympy.logic import POSform
  1976. >>> from sympy import symbols
  1977. >>> w, x, y, z = symbols('w x y z')
  1978. >>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1],
  1979. ... [1, 0, 1, 1], [1, 1, 1, 1]]
  1980. >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]]
  1981. >>> POSform([w, x, y, z], minterms, dontcares)
  1982. z & (y | ~w)
  1983. The terms can also be represented as integers:
  1984. >>> minterms = [1, 3, 7, 11, 15]
  1985. >>> dontcares = [0, 2, 5]
  1986. >>> POSform([w, x, y, z], minterms, dontcares)
  1987. z & (y | ~w)
  1988. They can also be specified using dicts, which does not have to be fully
  1989. specified:
  1990. >>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}]
  1991. >>> POSform([w, x, y, z], minterms)
  1992. (x | y) & (x | z) & (~w | ~x)
  1993. Or a combination:
  1994. >>> minterms = [4, 7, 11, [1, 1, 1, 1]]
  1995. >>> dontcares = [{w : 0, x : 0, y: 0}, 5]
  1996. >>> POSform([w, x, y, z], minterms, dontcares)
  1997. (w | x) & (y | ~w) & (z | ~y)
  1998. References
  1999. ==========
  2000. .. [1] https://en.wikipedia.org/wiki/Quine-McCluskey_algorithm
  2001. """
  2002. if not minterms:
  2003. return false
  2004. variables = tuple(map(sympify, variables))
  2005. minterms = _input_to_binlist(minterms, variables)
  2006. dontcares = _input_to_binlist((dontcares or []), variables)
  2007. for d in dontcares:
  2008. if d in minterms:
  2009. raise ValueError('%s in minterms is also in dontcares' % d)
  2010. maxterms = []
  2011. for t in product((0, 1), repeat=len(variables)):
  2012. t = list(t)
  2013. if (t not in minterms) and (t not in dontcares):
  2014. maxterms.append(t)
  2015. new = _simplified_pairs(maxterms + dontcares)
  2016. essential = _rem_redundancy(new, maxterms)
  2017. return And(*[_convert_to_varsPOS(x, variables) for x in essential])
  2018. def ANFform(variables, truthvalues):
  2019. """
  2020. The ANFform function converts the list of truth values to
  2021. Algebraic Normal Form (ANF).
  2022. The variables must be given as the first argument.
  2023. Return True, False, logical And funciton (i.e., the
  2024. "Zhegalkin monomial") or logical Xor function (i.e.,
  2025. the "Zhegalkin polynomial"). When True and False
  2026. are represented by 1 and 0, respectively, then
  2027. And is multiplication and Xor is addition.
  2028. Formally a "Zhegalkin monomial" is the product (logical
  2029. And) of a finite set of distinct variables, including
  2030. the empty set whose product is denoted 1 (True).
  2031. A "Zhegalkin polynomial" is the sum (logical Xor) of a
  2032. set of Zhegalkin monomials, with the empty set denoted
  2033. by 0 (False).
  2034. Parameters
  2035. ==========
  2036. variables : list of variables
  2037. truthvalues : list of 1's and 0's (result column of truth table)
  2038. Examples
  2039. ========
  2040. >>> from sympy.logic.boolalg import ANFform
  2041. >>> from sympy.abc import x, y
  2042. >>> ANFform([x], [1, 0])
  2043. x ^ True
  2044. >>> ANFform([x, y], [0, 1, 1, 1])
  2045. x ^ y ^ (x & y)
  2046. References
  2047. ==========
  2048. .. [1] https://en.wikipedia.org/wiki/Zhegalkin_polynomial
  2049. """
  2050. n_vars = len(variables)
  2051. n_values = len(truthvalues)
  2052. if n_values != 2 ** n_vars:
  2053. raise ValueError("The number of truth values must be equal to 2^%d, "
  2054. "got %d" % (n_vars, n_values))
  2055. variables = tuple(map(sympify, variables))
  2056. coeffs = anf_coeffs(truthvalues)
  2057. terms = []
  2058. for i, t in enumerate(product((0, 1), repeat=n_vars)):
  2059. if coeffs[i] == 1:
  2060. terms.append(t)
  2061. return Xor(*[_convert_to_varsANF(x, variables) for x in terms],
  2062. remove_true=False)
  2063. def anf_coeffs(truthvalues):
  2064. """
  2065. Convert a list of truth values of some boolean expression
  2066. to the list of coefficients of the polynomial mod 2 (exclusive
  2067. disjunction) representing the boolean expression in ANF
  2068. (i.e., the "Zhegalkin polynomial").
  2069. There are `2^n` possible Zhegalkin monomials in `n` variables, since
  2070. each monomial is fully specified by the presence or absence of
  2071. each variable.
  2072. We can enumerate all the monomials. For example, boolean
  2073. function with four variables ``(a, b, c, d)`` can contain
  2074. up to `2^4 = 16` monomials. The 13-th monomial is the
  2075. product ``a & b & d``, because 13 in binary is 1, 1, 0, 1.
  2076. A given monomial's presence or absence in a polynomial corresponds
  2077. to that monomial's coefficient being 1 or 0 respectively.
  2078. Examples
  2079. ========
  2080. >>> from sympy.logic.boolalg import anf_coeffs, bool_monomial, Xor
  2081. >>> from sympy.abc import a, b, c
  2082. >>> truthvalues = [0, 1, 1, 0, 0, 1, 0, 1]
  2083. >>> coeffs = anf_coeffs(truthvalues)
  2084. >>> coeffs
  2085. [0, 1, 1, 0, 0, 0, 1, 0]
  2086. >>> polynomial = Xor(*[
  2087. ... bool_monomial(k, [a, b, c])
  2088. ... for k, coeff in enumerate(coeffs) if coeff == 1
  2089. ... ])
  2090. >>> polynomial
  2091. b ^ c ^ (a & b)
  2092. """
  2093. s = '{:b}'.format(len(truthvalues))
  2094. n = len(s) - 1
  2095. if len(truthvalues) != 2**n:
  2096. raise ValueError("The number of truth values must be a power of two, "
  2097. "got %d" % len(truthvalues))
  2098. coeffs = [[v] for v in truthvalues]
  2099. for i in range(n):
  2100. tmp = []
  2101. for j in range(2 ** (n-i-1)):
  2102. tmp.append(coeffs[2*j] +
  2103. list(map(lambda x, y: x^y, coeffs[2*j], coeffs[2*j+1])))
  2104. coeffs = tmp
  2105. return coeffs[0]
  2106. def bool_minterm(k, variables):
  2107. """
  2108. Return the k-th minterm.
  2109. Minterms are numbered by a binary encoding of the complementation
  2110. pattern of the variables. This convention assigns the value 1 to
  2111. the direct form and 0 to the complemented form.
  2112. Parameters
  2113. ==========
  2114. k : int or list of 1's and 0's (complementation patter)
  2115. variables : list of variables
  2116. Examples
  2117. ========
  2118. >>> from sympy.logic.boolalg import bool_minterm
  2119. >>> from sympy.abc import x, y, z
  2120. >>> bool_minterm([1, 0, 1], [x, y, z])
  2121. x & z & ~y
  2122. >>> bool_minterm(6, [x, y, z])
  2123. x & y & ~z
  2124. References
  2125. ==========
  2126. .. [1] https://en.wikipedia.org/wiki/Canonical_normal_form#Indexing_minterms
  2127. """
  2128. if isinstance(k, int):
  2129. k = ibin(k, len(variables))
  2130. variables = tuple(map(sympify, variables))
  2131. return _convert_to_varsSOP(k, variables)
  2132. def bool_maxterm(k, variables):
  2133. """
  2134. Return the k-th maxterm.
  2135. Each maxterm is assigned an index based on the opposite
  2136. conventional binary encoding used for minterms. The maxterm
  2137. convention assigns the value 0 to the direct form and 1 to
  2138. the complemented form.
  2139. Parameters
  2140. ==========
  2141. k : int or list of 1's and 0's (complementation pattern)
  2142. variables : list of variables
  2143. Examples
  2144. ========
  2145. >>> from sympy.logic.boolalg import bool_maxterm
  2146. >>> from sympy.abc import x, y, z
  2147. >>> bool_maxterm([1, 0, 1], [x, y, z])
  2148. y | ~x | ~z
  2149. >>> bool_maxterm(6, [x, y, z])
  2150. z | ~x | ~y
  2151. References
  2152. ==========
  2153. .. [1] https://en.wikipedia.org/wiki/Canonical_normal_form#Indexing_maxterms
  2154. """
  2155. if isinstance(k, int):
  2156. k = ibin(k, len(variables))
  2157. variables = tuple(map(sympify, variables))
  2158. return _convert_to_varsPOS(k, variables)
  2159. def bool_monomial(k, variables):
  2160. """
  2161. Return the k-th monomial.
  2162. Monomials are numbered by a binary encoding of the presence and
  2163. absences of the variables. This convention assigns the value
  2164. 1 to the presence of variable and 0 to the absence of variable.
  2165. Each boolean function can be uniquely represented by a
  2166. Zhegalkin Polynomial (Algebraic Normal Form). The Zhegalkin
  2167. Polynomial of the boolean function with `n` variables can contain
  2168. up to `2^n` monomials. We can enumarate all the monomials.
  2169. Each monomial is fully specified by the presence or absence
  2170. of each variable.
  2171. For example, boolean function with four variables ``(a, b, c, d)``
  2172. can contain up to `2^4 = 16` monomials. The 13-th monomial is the
  2173. product ``a & b & d``, because 13 in binary is 1, 1, 0, 1.
  2174. Parameters
  2175. ==========
  2176. k : int or list of 1's and 0's
  2177. variables : list of variables
  2178. Examples
  2179. ========
  2180. >>> from sympy.logic.boolalg import bool_monomial
  2181. >>> from sympy.abc import x, y, z
  2182. >>> bool_monomial([1, 0, 1], [x, y, z])
  2183. x & z
  2184. >>> bool_monomial(6, [x, y, z])
  2185. x & y
  2186. """
  2187. if isinstance(k, int):
  2188. k = ibin(k, len(variables))
  2189. variables = tuple(map(sympify, variables))
  2190. return _convert_to_varsANF(k, variables)
  2191. def _find_predicates(expr):
  2192. """Helper to find logical predicates in BooleanFunctions.
  2193. A logical predicate is defined here as anything within a BooleanFunction
  2194. that is not a BooleanFunction itself.
  2195. """
  2196. if not isinstance(expr, BooleanFunction):
  2197. return {expr}
  2198. return set().union(*(map(_find_predicates, expr.args)))
  2199. def simplify_logic(expr, form=None, deep=True, force=False):
  2200. """
  2201. This function simplifies a boolean function to its simplified version
  2202. in SOP or POS form. The return type is an Or or And object in SymPy.
  2203. Parameters
  2204. ==========
  2205. expr : Boolean expression
  2206. form : string (``'cnf'`` or ``'dnf'``) or ``None`` (default).
  2207. If ``'cnf'`` or ``'dnf'``, the simplest expression in the corresponding
  2208. normal form is returned; if ``None``, the answer is returned
  2209. according to the form with fewest args (in CNF by default).
  2210. deep : bool (default ``True``)
  2211. Indicates whether to recursively simplify any
  2212. non-boolean functions contained within the input.
  2213. force : bool (default ``False``)
  2214. As the simplifications require exponential time in the number
  2215. of variables, there is by default a limit on expressions with
  2216. 8 variables. When the expression has more than 8 variables
  2217. only symbolical simplification (controlled by ``deep``) is
  2218. made. By setting ``force`` to ``True``, this limit is removed. Be
  2219. aware that this can lead to very long simplification times.
  2220. Examples
  2221. ========
  2222. >>> from sympy.logic import simplify_logic
  2223. >>> from sympy.abc import x, y, z
  2224. >>> from sympy import S
  2225. >>> b = (~x & ~y & ~z) | ( ~x & ~y & z)
  2226. >>> simplify_logic(b)
  2227. ~x & ~y
  2228. >>> S(b)
  2229. (z & ~x & ~y) | (~x & ~y & ~z)
  2230. >>> simplify_logic(_)
  2231. ~x & ~y
  2232. """
  2233. if form not in (None, 'cnf', 'dnf'):
  2234. raise ValueError("form can be cnf or dnf only")
  2235. expr = sympify(expr)
  2236. # check for quick exit if form is given: right form and all args are
  2237. # literal and do not involve Not
  2238. if form:
  2239. form_ok = False
  2240. if form == 'cnf':
  2241. form_ok = is_cnf(expr)
  2242. elif form == 'dnf':
  2243. form_ok = is_dnf(expr)
  2244. if form_ok and all(is_literal(a)
  2245. for a in expr.args):
  2246. return expr
  2247. from sympy.core.relational import Relational
  2248. if deep:
  2249. variables = expr.atoms(Relational)
  2250. from sympy.simplify.simplify import simplify
  2251. s = tuple(map(simplify, variables))
  2252. expr = expr.xreplace(dict(zip(variables, s)))
  2253. if not isinstance(expr, BooleanFunction):
  2254. return expr
  2255. # Replace Relationals with Dummys to possibly
  2256. # reduce the number of variables
  2257. repl = dict()
  2258. undo = dict()
  2259. from sympy.core.symbol import Dummy
  2260. variables = expr.atoms(Relational)
  2261. while variables:
  2262. var = variables.pop()
  2263. if var.is_Relational:
  2264. d = Dummy()
  2265. undo[d] = var
  2266. repl[var] = d
  2267. nvar = var.negated
  2268. if nvar in variables:
  2269. repl[nvar] = Not(d)
  2270. variables.remove(nvar)
  2271. expr = expr.xreplace(repl)
  2272. # Get new variables after replacing
  2273. variables = _find_predicates(expr)
  2274. if not force and len(variables) > 8:
  2275. return expr.xreplace(undo)
  2276. # group into constants and variable values
  2277. c, v = sift(ordered(variables), lambda x: x in (True, False), binary=True)
  2278. variables = c + v
  2279. truthtable = []
  2280. # standardize constants to be 1 or 0 in keeping with truthtable
  2281. c = [1 if i == True else 0 for i in c]
  2282. truthtable = _get_truthtable(v, expr, c)
  2283. big = len(truthtable) >= (2 ** (len(variables) - 1))
  2284. if form == 'dnf' or form is None and big:
  2285. return _sop_form(variables, truthtable, []).xreplace(undo)
  2286. return POSform(variables, truthtable).xreplace(undo)
  2287. def _get_truthtable(variables, expr, const):
  2288. """ Return a list of all combinations leading to a True result for ``expr``.
  2289. """
  2290. def _get_tt(inputs):
  2291. if variables:
  2292. v = variables.pop()
  2293. tab = [[i[0].xreplace({v: false}), [0] + i[1]] for i in inputs if i[0] is not false]
  2294. tab.extend([[i[0].xreplace({v: true}), [1] + i[1]] for i in inputs if i[0] is not false])
  2295. return _get_tt(tab)
  2296. return inputs
  2297. return [const + k[1] for k in _get_tt([[expr, []]]) if k[0]]
  2298. def _finger(eq):
  2299. """
  2300. Assign a 5-item fingerprint to each symbol in the equation:
  2301. [
  2302. # of times it appeared as a Symbol;
  2303. # of times it appeared as a Not(symbol);
  2304. # of times it appeared as a Symbol in an And or Or;
  2305. # of times it appeared as a Not(Symbol) in an And or Or;
  2306. a sorted tuple of tuples, (i, j, k), where i is the number of arguments
  2307. in an And or Or with which it appeared as a Symbol, and j is
  2308. the number of arguments that were Not(Symbol); k is the number
  2309. of times that (i, j) was seen.
  2310. ]
  2311. Examples
  2312. ========
  2313. >>> from sympy.logic.boolalg import _finger as finger
  2314. >>> from sympy import And, Or, Not, Xor, to_cnf, symbols
  2315. >>> from sympy.abc import a, b, x, y
  2316. >>> eq = Or(And(Not(y), a), And(Not(y), b), And(x, y))
  2317. >>> dict(finger(eq))
  2318. {(0, 0, 1, 0, ((2, 0, 1),)): [x],
  2319. (0, 0, 1, 0, ((2, 1, 1),)): [a, b],
  2320. (0, 0, 1, 2, ((2, 0, 1),)): [y]}
  2321. >>> dict(finger(x & ~y))
  2322. {(0, 1, 0, 0, ()): [y], (1, 0, 0, 0, ()): [x]}
  2323. In the following, the (5, 2, 6) means that there were 6 Or
  2324. functions in which a symbol appeared as itself amongst 5 arguments in
  2325. which there were also 2 negated symbols, e.g. ``(a0 | a1 | a2 | ~a3 | ~a4)``
  2326. is counted once for a0, a1 and a2.
  2327. >>> dict(finger(to_cnf(Xor(*symbols('a:5')))))
  2328. {(0, 0, 8, 8, ((5, 0, 1), (5, 2, 6), (5, 4, 1))): [a0, a1, a2, a3, a4]}
  2329. The equation must not have more than one level of nesting:
  2330. >>> dict(finger(And(Or(x, y), y)))
  2331. {(0, 0, 1, 0, ((2, 0, 1),)): [x], (1, 0, 1, 0, ((2, 0, 1),)): [y]}
  2332. >>> dict(finger(And(Or(x, And(a, x)), y)))
  2333. Traceback (most recent call last):
  2334. ...
  2335. NotImplementedError: unexpected level of nesting
  2336. So y and x have unique fingerprints, but a and b do not.
  2337. """
  2338. f = eq.free_symbols
  2339. d = dict(list(zip(f, [[0]*4 + [defaultdict(int)] for fi in f])))
  2340. for a in eq.args:
  2341. if a.is_Symbol:
  2342. d[a][0] += 1
  2343. elif a.is_Not:
  2344. d[a.args[0]][1] += 1
  2345. else:
  2346. o = len(a.args), sum(isinstance(ai, Not) for ai in a.args)
  2347. for ai in a.args:
  2348. if ai.is_Symbol:
  2349. d[ai][2] += 1
  2350. d[ai][-1][o] += 1
  2351. elif ai.is_Not:
  2352. d[ai.args[0]][3] += 1
  2353. else:
  2354. raise NotImplementedError('unexpected level of nesting')
  2355. inv = defaultdict(list)
  2356. for k, v in ordered(iter(d.items())):
  2357. v[-1] = tuple(sorted([i + (j,) for i, j in v[-1].items()]))
  2358. inv[tuple(v)].append(k)
  2359. return inv
  2360. def bool_map(bool1, bool2):
  2361. """
  2362. Return the simplified version of *bool1*, and the mapping of variables
  2363. that makes the two expressions *bool1* and *bool2* represent the same
  2364. logical behaviour for some correspondence between the variables
  2365. of each.
  2366. If more than one mappings of this sort exist, one of them
  2367. is returned.
  2368. For example, ``And(x, y)`` is logically equivalent to ``And(a, b)`` for
  2369. the mapping ``{x: a, y: b}`` or ``{x: b, y: a}``.
  2370. If no such mapping exists, return ``False``.
  2371. Examples
  2372. ========
  2373. >>> from sympy import SOPform, bool_map, Or, And, Not, Xor
  2374. >>> from sympy.abc import w, x, y, z, a, b, c, d
  2375. >>> function1 = SOPform([x, z, y],[[1, 0, 1], [0, 0, 1]])
  2376. >>> function2 = SOPform([a, b, c],[[1, 0, 1], [1, 0, 0]])
  2377. >>> bool_map(function1, function2)
  2378. (y & ~z, {y: a, z: b})
  2379. The results are not necessarily unique, but they are canonical. Here,
  2380. ``(w, z)`` could be ``(a, d)`` or ``(d, a)``:
  2381. >>> eq = Or(And(Not(y), w), And(Not(y), z), And(x, y))
  2382. >>> eq2 = Or(And(Not(c), a), And(Not(c), d), And(b, c))
  2383. >>> bool_map(eq, eq2)
  2384. ((x & y) | (w & ~y) | (z & ~y), {w: a, x: b, y: c, z: d})
  2385. >>> eq = And(Xor(a, b), c, And(c,d))
  2386. >>> bool_map(eq, eq.subs(c, x))
  2387. (c & d & (a | b) & (~a | ~b), {a: a, b: b, c: d, d: x})
  2388. """
  2389. def match(function1, function2):
  2390. """Return the mapping that equates variables between two
  2391. simplified boolean expressions if possible.
  2392. By "simplified" we mean that a function has been denested
  2393. and is either an And (or an Or) whose arguments are either
  2394. symbols (x), negated symbols (Not(x)), or Or (or an And) whose
  2395. arguments are only symbols or negated symbols. For example,
  2396. ``And(x, Not(y), Or(w, Not(z)))``.
  2397. Basic.match is not robust enough (see issue 4835) so this is
  2398. a workaround that is valid for simplified boolean expressions
  2399. """
  2400. # do some quick checks
  2401. if function1.__class__ != function2.__class__:
  2402. return None # maybe simplification makes them the same?
  2403. if len(function1.args) != len(function2.args):
  2404. return None # maybe simplification makes them the same?
  2405. if function1.is_Symbol:
  2406. return {function1: function2}
  2407. # get the fingerprint dictionaries
  2408. f1 = _finger(function1)
  2409. f2 = _finger(function2)
  2410. # more quick checks
  2411. if len(f1) != len(f2):
  2412. return False
  2413. # assemble the match dictionary if possible
  2414. matchdict = {}
  2415. for k in f1.keys():
  2416. if k not in f2:
  2417. return False
  2418. if len(f1[k]) != len(f2[k]):
  2419. return False
  2420. for i, x in enumerate(f1[k]):
  2421. matchdict[x] = f2[k][i]
  2422. return matchdict
  2423. a = simplify_logic(bool1)
  2424. b = simplify_logic(bool2)
  2425. m = match(a, b)
  2426. if m:
  2427. return a, m
  2428. return m
  2429. def _apply_patternbased_simplification(rv, patterns, measure,
  2430. dominatingvalue,
  2431. replacementvalue=None,
  2432. threeterm_patterns=None):
  2433. """
  2434. Replace patterns of Relational
  2435. Parameters
  2436. ==========
  2437. rv : Expr
  2438. Boolean expression
  2439. patterns : tuple
  2440. Tuple of tuples, with (pattern to simplify, simplified pattern).
  2441. measure : function
  2442. Simplification measure.
  2443. dominatingvalue : Boolean or ``None``
  2444. The dominating value for the function of consideration.
  2445. For example, for :py:class:`~.And` ``S.false`` is dominating.
  2446. As soon as one expression is ``S.false`` in :py:class:`~.And`,
  2447. the whole expression is ``S.false``.
  2448. replacementvalue : Boolean or ``None``, optional
  2449. The resulting value for the whole expression if one argument
  2450. evaluates to ``dominatingvalue``.
  2451. For example, for :py:class:`~.Nand` ``S.false`` is dominating, but
  2452. in this case the resulting value is ``S.true``. Default is ``None``.
  2453. If ``replacementvalue`` is ``None`` and ``dominatingvalue`` is not
  2454. ``None``, ``replacementvalue = dominatingvalue``.
  2455. """
  2456. from sympy.core.relational import Relational, _canonical
  2457. if replacementvalue is None and dominatingvalue is not None:
  2458. replacementvalue = dominatingvalue
  2459. # Use replacement patterns for Relationals
  2460. Rel, nonRel = sift(rv.args, lambda i: isinstance(i, Relational),
  2461. binary=True)
  2462. if len(Rel) <= 1:
  2463. return rv
  2464. Rel, nonRealRel = sift(Rel, lambda i: not any(s.is_real is False
  2465. for s in i.free_symbols),
  2466. binary=True)
  2467. Rel = [i.canonical for i in Rel]
  2468. if threeterm_patterns and len(Rel) >= 3:
  2469. Rel = _apply_patternbased_threeterm_simplification(Rel,
  2470. threeterm_patterns, rv.func, dominatingvalue,
  2471. replacementvalue, measure)
  2472. Rel = _apply_patternbased_twoterm_simplification(Rel, patterns,
  2473. rv.func, dominatingvalue, replacementvalue, measure)
  2474. rv = rv.func(*([_canonical(i) for i in ordered(Rel)]
  2475. + nonRel + nonRealRel))
  2476. return rv
  2477. def _apply_patternbased_twoterm_simplification(Rel, patterns, func,
  2478. dominatingvalue,
  2479. replacementvalue,
  2480. measure):
  2481. """ Apply pattern-based two-term simplification."""
  2482. from sympy.functions.elementary.miscellaneous import Min, Max
  2483. from sympy.core.relational import Ge, Gt, _Inequality
  2484. changed = True
  2485. while changed and len(Rel) >= 2:
  2486. changed = False
  2487. # Use only < or <=
  2488. Rel = [r.reversed if isinstance(r, (Ge, Gt)) else r for r in Rel]
  2489. # Sort based on ordered
  2490. Rel = list(ordered(Rel))
  2491. # Eq and Ne must be tested reversed as well
  2492. rtmp = [(r, ) if isinstance(r, _Inequality) else (r, r.reversed) for r in Rel]
  2493. # Create a list of possible replacements
  2494. results = []
  2495. # Try all combinations of possibly reversed relational
  2496. for ((i, pi), (j, pj)) in combinations(enumerate(rtmp), 2):
  2497. for pattern, simp in patterns:
  2498. res = []
  2499. for p1, p2 in product(pi, pj):
  2500. # use SymPy matching
  2501. oldexpr = Tuple(p1, p2)
  2502. tmpres = oldexpr.match(pattern)
  2503. if tmpres:
  2504. res.append((tmpres, oldexpr))
  2505. if res:
  2506. for tmpres, oldexpr in res:
  2507. # we have a matching, compute replacement
  2508. np = simp.xreplace(tmpres)
  2509. if np == dominatingvalue:
  2510. # if dominatingvalue, the whole expression
  2511. # will be replacementvalue
  2512. return [replacementvalue]
  2513. # add replacement
  2514. if not isinstance(np, ITE) and not np.has(Min, Max):
  2515. # We only want to use ITE and Min/Max replacements if
  2516. # they simplify to a relational
  2517. costsaving = measure(func(*oldexpr.args)) - measure(np)
  2518. if costsaving > 0:
  2519. results.append((costsaving, ([i, j], np)))
  2520. if results:
  2521. # Sort results based on complexity
  2522. results = list(reversed(sorted(results,
  2523. key=lambda pair: pair[0])))
  2524. # Replace the one providing most simplification
  2525. replacement = results[0][1]
  2526. idx, newrel = replacement
  2527. idx.sort()
  2528. # Remove the old relationals
  2529. for index in reversed(idx):
  2530. del Rel[index]
  2531. if dominatingvalue is None or newrel != Not(dominatingvalue):
  2532. # Insert the new one (no need to insert a value that will
  2533. # not affect the result)
  2534. if newrel.func == func:
  2535. for a in newrel.args:
  2536. Rel.append(a)
  2537. else:
  2538. Rel.append(newrel)
  2539. # We did change something so try again
  2540. changed = True
  2541. return Rel
  2542. def _apply_patternbased_threeterm_simplification(Rel, patterns, func,
  2543. dominatingvalue,
  2544. replacementvalue,
  2545. measure):
  2546. """ Apply pattern-based three-term simplification."""
  2547. from sympy.functions.elementary.miscellaneous import Min, Max
  2548. from sympy.core.relational import Le, Lt, _Inequality
  2549. changed = True
  2550. while changed and len(Rel) >= 3:
  2551. changed = False
  2552. # Use only > or >=
  2553. Rel = [r.reversed if isinstance(r, (Le, Lt)) else r for r in Rel]
  2554. # Sort based on ordered
  2555. Rel = list(ordered(Rel))
  2556. # Create a list of possible replacements
  2557. results = []
  2558. # Eq and Ne must be tested reversed as well
  2559. rtmp = [(r, ) if isinstance(r, _Inequality) else (r, r.reversed) for r in Rel]
  2560. # Try all combinations of possibly reversed relational
  2561. for ((i, pi), (j, pj), (k, pk)) in permutations(enumerate(rtmp), 3):
  2562. for pattern, simp in patterns:
  2563. res = []
  2564. for p1, p2, p3 in product(pi, pj, pk):
  2565. # use SymPy matching
  2566. oldexpr = Tuple(p1, p2, p3)
  2567. tmpres = oldexpr.match(pattern)
  2568. if tmpres:
  2569. res.append((tmpres, oldexpr))
  2570. if res:
  2571. for tmpres, oldexpr in res:
  2572. # we have a matching, compute replacement
  2573. np = simp.xreplace(tmpres)
  2574. if np == dominatingvalue:
  2575. # if dominatingvalue, the whole expression
  2576. # will be replacementvalue
  2577. return [replacementvalue]
  2578. # add replacement
  2579. if not isinstance(np, ITE) and not np.has(Min, Max):
  2580. # We only want to use ITE and Min/Max replacements if
  2581. # they simplify to a relational
  2582. costsaving = measure(func(*oldexpr.args)) - measure(np)
  2583. if costsaving > 0:
  2584. results.append((costsaving, ([i, j, k], np)))
  2585. if results:
  2586. # Sort results based on complexity
  2587. results = list(reversed(sorted(results,
  2588. key=lambda pair: pair[0])))
  2589. # Replace the one providing most simplification
  2590. replacement = results[0][1]
  2591. idx, newrel = replacement
  2592. idx.sort()
  2593. # Remove the old relationals
  2594. for index in reversed(idx):
  2595. del Rel[index]
  2596. if dominatingvalue is None or newrel != Not(dominatingvalue):
  2597. # Insert the new one (no need to insert a value that will
  2598. # not affect the result)
  2599. if newrel.func == func:
  2600. for a in newrel.args:
  2601. Rel.append(a)
  2602. else:
  2603. Rel.append(newrel)
  2604. # We did change something so try again
  2605. changed = True
  2606. return Rel
  2607. def _simplify_patterns_and():
  2608. """ Two-term patterns for And."""
  2609. from sympy.core import Wild
  2610. from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt
  2611. from sympy.functions.elementary.complexes import Abs
  2612. from sympy.functions.elementary.miscellaneous import Min, Max
  2613. a = Wild('a')
  2614. b = Wild('b')
  2615. c = Wild('c')
  2616. # Relationals patterns should be in alphabetical order
  2617. # (pattern1, pattern2, simplified)
  2618. # Do not use Ge, Gt
  2619. _matchers_and = ((Tuple(Eq(a, b), Lt(a, b)), S.false),
  2620. #(Tuple(Eq(a, b), Lt(b, a)), S.false),
  2621. #(Tuple(Le(b, a), Lt(a, b)), S.false),
  2622. #(Tuple(Lt(b, a), Le(a, b)), S.false),
  2623. (Tuple(Lt(b, a), Lt(a, b)), S.false),
  2624. (Tuple(Eq(a, b), Le(b, a)), Eq(a, b)),
  2625. #(Tuple(Eq(a, b), Le(a, b)), Eq(a, b)),
  2626. #(Tuple(Le(b, a), Lt(b, a)), Gt(a, b)),
  2627. (Tuple(Le(b, a), Le(a, b)), Eq(a, b)),
  2628. #(Tuple(Le(b, a), Ne(a, b)), Gt(a, b)),
  2629. #(Tuple(Lt(b, a), Ne(a, b)), Gt(a, b)),
  2630. (Tuple(Le(a, b), Lt(a, b)), Lt(a, b)),
  2631. (Tuple(Le(a, b), Ne(a, b)), Lt(a, b)),
  2632. (Tuple(Lt(a, b), Ne(a, b)), Lt(a, b)),
  2633. # Sign
  2634. (Tuple(Eq(a, b), Eq(a, -b)), And(Eq(a, S.Zero), Eq(b, S.Zero))),
  2635. # Min/Max/ITE
  2636. (Tuple(Le(b, a), Le(c, a)), Ge(a, Max(b, c))),
  2637. (Tuple(Le(b, a), Lt(c, a)), ITE(b > c, Ge(a, b), Gt(a, c))),
  2638. (Tuple(Lt(b, a), Lt(c, a)), Gt(a, Max(b, c))),
  2639. (Tuple(Le(a, b), Le(a, c)), Le(a, Min(b, c))),
  2640. (Tuple(Le(a, b), Lt(a, c)), ITE(b < c, Le(a, b), Lt(a, c))),
  2641. (Tuple(Lt(a, b), Lt(a, c)), Lt(a, Min(b, c))),
  2642. (Tuple(Le(a, b), Le(c, a)), ITE(Eq(b, c), Eq(a, b), ITE(b < c, S.false, And(Le(a, b), Ge(a, c))))),
  2643. (Tuple(Le(c, a), Le(a, b)), ITE(Eq(b, c), Eq(a, b), ITE(b < c, S.false, And(Le(a, b), Ge(a, c))))),
  2644. (Tuple(Lt(a, b), Lt(c, a)), ITE(b < c, S.false, And(Lt(a, b), Gt(a, c)))),
  2645. (Tuple(Lt(c, a), Lt(a, b)), ITE(b < c, S.false, And(Lt(a, b), Gt(a, c)))),
  2646. (Tuple(Le(a, b), Lt(c, a)), ITE(b <= c, S.false, And(Le(a, b), Gt(a, c)))),
  2647. (Tuple(Le(c, a), Lt(a, b)), ITE(b <= c, S.false, And(Lt(a, b), Ge(a, c)))),
  2648. (Tuple(Eq(a, b), Eq(a, c)), ITE(Eq(b, c), Eq(a, b), S.false)),
  2649. (Tuple(Lt(a, b), Lt(-b, a)), ITE(b > 0, Lt(Abs(a), b), S.false)),
  2650. (Tuple(Le(a, b), Le(-b, a)), ITE(b >= 0, Le(Abs(a), b), S.false)),
  2651. )
  2652. return _matchers_and
  2653. def _simplify_patterns_and3():
  2654. """ Three-term patterns for And."""
  2655. from sympy.core import Wild
  2656. from sympy.core.relational import Eq, Ge, Gt
  2657. a = Wild('a')
  2658. b = Wild('b')
  2659. c = Wild('c')
  2660. # Relationals patterns should be in alphabetical order
  2661. # (pattern1, pattern2, pattern3, simplified)
  2662. # Do not use Le, Lt
  2663. _matchers_and = ((Tuple(Ge(a, b), Ge(b, c), Gt(c, a)), S.false),
  2664. (Tuple(Ge(a, b), Gt(b, c), Gt(c, a)), S.false),
  2665. (Tuple(Gt(a, b), Gt(b, c), Gt(c, a)), S.false),
  2666. # (Tuple(Ge(c, a), Gt(a, b), Gt(b, c)), S.false),
  2667. # Lower bound relations
  2668. # Commented out combinations that does not simplify
  2669. (Tuple(Ge(a, b), Ge(a, c), Ge(b, c)), And(Ge(a, b), Ge(b, c))),
  2670. (Tuple(Ge(a, b), Ge(a, c), Gt(b, c)), And(Ge(a, b), Gt(b, c))),
  2671. # (Tuple(Ge(a, b), Gt(a, c), Ge(b, c)), And(Ge(a, b), Ge(b, c))),
  2672. (Tuple(Ge(a, b), Gt(a, c), Gt(b, c)), And(Ge(a, b), Gt(b, c))),
  2673. # (Tuple(Gt(a, b), Ge(a, c), Ge(b, c)), And(Gt(a, b), Ge(b, c))),
  2674. (Tuple(Ge(a, c), Gt(a, b), Gt(b, c)), And(Gt(a, b), Gt(b, c))),
  2675. (Tuple(Ge(b, c), Gt(a, b), Gt(a, c)), And(Gt(a, b), Ge(b, c))),
  2676. (Tuple(Gt(a, b), Gt(a, c), Gt(b, c)), And(Gt(a, b), Gt(b, c))),
  2677. # Upper bound relations
  2678. # Commented out combinations that does not simplify
  2679. (Tuple(Ge(b, a), Ge(c, a), Ge(b, c)), And(Ge(c, a), Ge(b, c))),
  2680. (Tuple(Ge(b, a), Ge(c, a), Gt(b, c)), And(Ge(c, a), Gt(b, c))),
  2681. # (Tuple(Ge(b, a), Gt(c, a), Ge(b, c)), And(Gt(c, a), Ge(b, c))),
  2682. (Tuple(Ge(b, a), Gt(c, a), Gt(b, c)), And(Gt(c, a), Gt(b, c))),
  2683. # (Tuple(Gt(b, a), Ge(c, a), Ge(b, c)), And(Ge(c, a), Ge(b, c))),
  2684. (Tuple(Ge(c, a), Gt(b, a), Gt(b, c)), And(Ge(c, a), Gt(b, c))),
  2685. (Tuple(Ge(b, c), Gt(b, a), Gt(c, a)), And(Gt(c, a), Ge(b, c))),
  2686. (Tuple(Gt(b, a), Gt(c, a), Gt(b, c)), And(Gt(c, a), Gt(b, c))),
  2687. # Circular relation
  2688. (Tuple(Ge(a, b), Ge(b, c), Ge(c, a)), And(Eq(a, b), Eq(b, c))),
  2689. )
  2690. return _matchers_and
  2691. def _simplify_patterns_or():
  2692. """ Two-term patterns for Or."""
  2693. from sympy.core import Wild
  2694. from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt
  2695. from sympy.functions.elementary.complexes import Abs
  2696. from sympy.functions.elementary.miscellaneous import Min, Max
  2697. a = Wild('a')
  2698. b = Wild('b')
  2699. c = Wild('c')
  2700. # Relationals patterns should be in alphabetical order
  2701. # (pattern1, pattern2, simplified)
  2702. # Do not use Ge, Gt
  2703. _matchers_or = ((Tuple(Le(b, a), Le(a, b)), S.true),
  2704. #(Tuple(Le(b, a), Lt(a, b)), S.true),
  2705. (Tuple(Le(b, a), Ne(a, b)), S.true),
  2706. #(Tuple(Le(a, b), Lt(b, a)), S.true),
  2707. #(Tuple(Le(a, b), Ne(a, b)), S.true),
  2708. #(Tuple(Eq(a, b), Le(b, a)), Ge(a, b)),
  2709. #(Tuple(Eq(a, b), Lt(b, a)), Ge(a, b)),
  2710. (Tuple(Eq(a, b), Le(a, b)), Le(a, b)),
  2711. (Tuple(Eq(a, b), Lt(a, b)), Le(a, b)),
  2712. #(Tuple(Le(b, a), Lt(b, a)), Ge(a, b)),
  2713. (Tuple(Lt(b, a), Lt(a, b)), Ne(a, b)),
  2714. (Tuple(Lt(b, a), Ne(a, b)), Ne(a, b)),
  2715. (Tuple(Le(a, b), Lt(a, b)), Le(a, b)),
  2716. #(Tuple(Lt(a, b), Ne(a, b)), Ne(a, b)),
  2717. # Min/Max/ITE
  2718. (Tuple(Le(b, a), Le(c, a)), Ge(a, Min(b, c))),
  2719. #(Tuple(Ge(b, a), Ge(c, a)), Ge(Min(b, c), a)),
  2720. (Tuple(Le(b, a), Lt(c, a)), ITE(b > c, Gt(a, c), Ge(a, b))),
  2721. (Tuple(Lt(b, a), Lt(c, a)), Gt(a, Min(b, c))),
  2722. #(Tuple(Gt(b, a), Gt(c, a)), Gt(Min(b, c), a)),
  2723. (Tuple(Le(a, b), Le(a, c)), Le(a, Max(b, c))),
  2724. #(Tuple(Le(b, a), Le(c, a)), Le(Max(b, c), a)),
  2725. (Tuple(Le(a, b), Lt(a, c)), ITE(b >= c, Le(a, b), Lt(a, c))),
  2726. (Tuple(Lt(a, b), Lt(a, c)), Lt(a, Max(b, c))),
  2727. #(Tuple(Lt(b, a), Lt(c, a)), Lt(Max(b, c), a)),
  2728. (Tuple(Le(a, b), Le(c, a)), ITE(b >= c, S.true, Or(Le(a, b), Ge(a, c)))),
  2729. (Tuple(Le(c, a), Le(a, b)), ITE(b >= c, S.true, Or(Le(a, b), Ge(a, c)))),
  2730. (Tuple(Lt(a, b), Lt(c, a)), ITE(b > c, S.true, Or(Lt(a, b), Gt(a, c)))),
  2731. (Tuple(Lt(c, a), Lt(a, b)), ITE(b > c, S.true, Or(Lt(a, b), Gt(a, c)))),
  2732. (Tuple(Le(a, b), Lt(c, a)), ITE(b >= c, S.true, Or(Le(a, b), Gt(a, c)))),
  2733. (Tuple(Le(c, a), Lt(a, b)), ITE(b >= c, S.true, Or(Lt(a, b), Ge(a, c)))),
  2734. (Tuple(Lt(b, a), Lt(a, -b)), ITE(b >= 0, Gt(Abs(a), b), S.true)),
  2735. (Tuple(Le(b, a), Le(a, -b)), ITE(b > 0, Ge(Abs(a), b), S.true)),
  2736. )
  2737. return _matchers_or
  2738. def _simplify_patterns_xor():
  2739. """ Two-term patterns for Xor."""
  2740. from sympy.functions.elementary.miscellaneous import Min, Max
  2741. from sympy.core import Wild
  2742. from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt
  2743. a = Wild('a')
  2744. b = Wild('b')
  2745. c = Wild('c')
  2746. # Relationals patterns should be in alphabetical order
  2747. # (pattern1, pattern2, simplified)
  2748. # Do not use Ge, Gt
  2749. _matchers_xor = (#(Tuple(Le(b, a), Lt(a, b)), S.true),
  2750. #(Tuple(Lt(b, a), Le(a, b)), S.true),
  2751. #(Tuple(Eq(a, b), Le(b, a)), Gt(a, b)),
  2752. #(Tuple(Eq(a, b), Lt(b, a)), Ge(a, b)),
  2753. (Tuple(Eq(a, b), Le(a, b)), Lt(a, b)),
  2754. (Tuple(Eq(a, b), Lt(a, b)), Le(a, b)),
  2755. (Tuple(Le(a, b), Lt(a, b)), Eq(a, b)),
  2756. (Tuple(Le(a, b), Le(b, a)), Ne(a, b)),
  2757. (Tuple(Le(b, a), Ne(a, b)), Le(a, b)),
  2758. # (Tuple(Lt(b, a), Lt(a, b)), Ne(a, b)),
  2759. (Tuple(Lt(b, a), Ne(a, b)), Lt(a, b)),
  2760. # (Tuple(Le(a, b), Lt(a, b)), Eq(a, b)),
  2761. # (Tuple(Le(a, b), Ne(a, b)), Ge(a, b)),
  2762. # (Tuple(Lt(a, b), Ne(a, b)), Gt(a, b)),
  2763. # Min/Max/ITE
  2764. (Tuple(Le(b, a), Le(c, a)),
  2765. And(Ge(a, Min(b, c)), Lt(a, Max(b, c)))),
  2766. (Tuple(Le(b, a), Lt(c, a)),
  2767. ITE(b > c, And(Gt(a, c), Lt(a, b)),
  2768. And(Ge(a, b), Le(a, c)))),
  2769. (Tuple(Lt(b, a), Lt(c, a)),
  2770. And(Gt(a, Min(b, c)), Le(a, Max(b, c)))),
  2771. (Tuple(Le(a, b), Le(a, c)),
  2772. And(Le(a, Max(b, c)), Gt(a, Min(b, c)))),
  2773. (Tuple(Le(a, b), Lt(a, c)),
  2774. ITE(b < c, And(Lt(a, c), Gt(a, b)),
  2775. And(Le(a, b), Ge(a, c)))),
  2776. (Tuple(Lt(a, b), Lt(a, c)),
  2777. And(Lt(a, Max(b, c)), Ge(a, Min(b, c)))),
  2778. )
  2779. return _matchers_xor
  2780. def simplify_univariate(expr):
  2781. """return a simplified version of univariate boolean expression, else ``expr``"""
  2782. from sympy.functions.elementary.piecewise import Piecewise
  2783. from sympy.core.relational import Eq, Ne
  2784. if not isinstance(expr, BooleanFunction):
  2785. return expr
  2786. if expr.atoms(Eq, Ne):
  2787. return expr
  2788. c = expr
  2789. free = c.free_symbols
  2790. if len(free) != 1:
  2791. return c
  2792. x = free.pop()
  2793. ok, i = Piecewise((0, c), evaluate=False
  2794. )._intervals(x, err_on_Eq=True)
  2795. if not ok:
  2796. return c
  2797. if not i:
  2798. return S.false
  2799. args = []
  2800. for a, b, _, _ in i:
  2801. if a is S.NegativeInfinity:
  2802. if b is S.Infinity:
  2803. c = S.true
  2804. else:
  2805. if c.subs(x, b) == True:
  2806. c = (x <= b)
  2807. else:
  2808. c = (x < b)
  2809. else:
  2810. incl_a = (c.subs(x, a) == True)
  2811. incl_b = (c.subs(x, b) == True)
  2812. if incl_a and incl_b:
  2813. if b.is_infinite:
  2814. c = (x >= a)
  2815. else:
  2816. c = And(a <= x, x <= b)
  2817. elif incl_a:
  2818. c = And(a <= x, x < b)
  2819. elif incl_b:
  2820. if b.is_infinite:
  2821. c = (x > a)
  2822. else:
  2823. c = And(a < x, x <= b)
  2824. else:
  2825. c = And(a < x, x < b)
  2826. args.append(c)
  2827. return Or(*args)
  2828. # Classes corresponding to logic gates
  2829. # Used in gateinputcount method
  2830. BooleanGates = (And, Or, Xor, Nand, Nor, Not, Xnor, ITE)
  2831. def gateinputcount(expr):
  2832. """
  2833. Return the total number of inputs for the logic gates realizing the
  2834. Boolean expression.
  2835. Returns
  2836. =======
  2837. int
  2838. Number of gate inputs
  2839. Note
  2840. ====
  2841. Not all Boolean functions count as gate here, only those that are
  2842. considered to be standard gates. These are: ``And``, ``Or``, ``Xor``,
  2843. ``Not``, and ``ITE`` (multiplexer). ``Nand``, ``Nor``, and ``Xnor`` will
  2844. be evaluated to ``Not(And())`` etc.
  2845. Examples
  2846. ========
  2847. >>> from sympy.logic import And, Or, Nand, Not, gateinputcount
  2848. >>> from sympy.abc import x, y, z
  2849. >>> expr = And(x, y)
  2850. >>> gateinputcount(expr)
  2851. 2
  2852. >>> gateinputcount(Or(expr, z))
  2853. 4
  2854. Note that ``Nand`` is automatically evaluated to ``Not(And())`` so
  2855. >>> gateinputcount(Nand(x, y, z))
  2856. 4
  2857. >>> gateinputcount(Not(And(x, y, z)))
  2858. 4
  2859. Although this can be avoided by using ``evaluate=False``
  2860. >>> gateinputcount(Nand(x, y, z, evaluate=False))
  2861. 3
  2862. Also note that a comparison will count as a Boolean variable:
  2863. >>> gateinputcount(And(x > z, y >= 2))
  2864. 2
  2865. As will a symbol:
  2866. >>> gateinputcount(x)
  2867. 0
  2868. """
  2869. if not isinstance(expr, Boolean):
  2870. raise TypeError("Expression must be Boolean")
  2871. if isinstance(expr, BooleanGates):
  2872. return len(expr.args) + sum(gateinputcount(x) for x in expr.args)
  2873. return 0