Logic
Introduction
The logic module for Diofant allows to form and manipulate logic expressions using symbolic and Boolean values.
Forming logical expressions
You can build Boolean expressions with the standard python operators &
(And
), |
(Or
),
~
(Not
):
>>> y | (x & y)
y | (x & y)
>>> x | y
x | y
>>> ~x
~x
You can also form implications with >>
and <<
:
>>> x >> y
Implies(x, y)
>>> x << y
Implies(y, x)
Like most types in Diofant, Boolean expressions inherit from
Basic
:
>>> (y & x).subs({x: True, y: True})
true
>>> (x | y).atoms()
{x, y}
The logic module also includes the following functions to derive boolean expressions from their truth tables-
- diofant.logic.boolalg.SOPform(variables, minterms, dontcares=None)[source]
The SOPform function uses simplified_pairs and a redundant group- eliminating algorithm to convert the list of all input combos that generate ‘1’ (the minterms) into the smallest Sum of Products form.
The variables must be given as the first argument.
Return a logical Or function (i.e., the “sum of products” or “SOP” form) that gives the desired outcome. If there are inputs that can be ignored, pass them as a list, too.
The result will be one of the (perhaps many) functions that satisfy the conditions.
Examples
>>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], ... [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]] >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] >>> SOPform([t, x, y, z], minterms, dontcares) (y & z) | (z & ~t)
References
- diofant.logic.boolalg.POSform(variables, minterms, dontcares=None)[source]
The POSform function uses simplified_pairs and a redundant-group eliminating algorithm to convert the list of all input combinations that generate ‘1’ (the minterms) into the smallest Product of Sums form.
The variables must be given as the first argument.
Return a logical And function (i.e., the “product of sums” or “POS” form) that gives the desired outcome. If there are inputs that can be ignored, pass them as a list, too.
The result will be one of the (perhaps many) functions that satisfy the conditions.
Examples
>>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], ... [1, 0, 1, 1], [1, 1, 1, 1]] >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] >>> POSform([t, x, y, z], minterms, dontcares) z & (y | ~t)
References
Boolean functions
- class diofant.logic.boolalg.BooleanTrue(*args, **kwargs)[source]
Diofant version of True, a singleton that can be accessed via
true
.This is the Diofant version of True, for use in the logic module. The primary advantage of using true instead of True is that shorthand boolean operations like ~ and >> will work as expected on this class, whereas with True they act bitwise on 1. Functions in the logic module will return this class when they evaluate to true.
Notes
There is liable to be some confusion as to when
True
should be used and whentrue
should be used in various contexts throughout Diofant. An important thing to remember is thatsympify(True)
returnstrue
. This means that for the most part, you can just useTrue
and it will automatically be converted totrue
when necessary, similar to how you can generally use 1 instead ofInteger(1)
.The rule of thumb is:
“If the boolean in question can be replaced by an arbitrary symbolic
Boolean
, likeOr(x, y)
orx > 1
, usetrue
. Otherwise, useTrue
”.In other words, use
true
only on those contexts where the boolean is being used as a symbolic representation of truth. For example, if the object ends up in the.args
of any expression, then it must necessarily betrue
instead ofTrue
, as elements of.args
must beBasic
. On the other hand,==
is not a symbolic operation in Diofant, since it always returnsTrue
orFalse
, and does so in terms of structural equality rather than mathematical, so it should returnTrue
. The assumptions system should useTrue
andFalse
. Aside from not satisfying the above rule of thumb, the assumptions system uses a three-valued logic (True
,False
,None
), whereastrue
andfalse
represent a two-valued logic. When in doubt, useTrue
.“
true == True is True
.”While “
true is True
” isFalse
, “true == True
” isTrue
, so if there is any doubt over whether a function or expression will returntrue
orTrue
, just use==
instead ofis
to do the comparison, and it will work in either case. Finally, for boolean flags, it’s better to just useif x
instead ofif x is True
. To quote PEP 8:Don’t compare boolean values to
True
orFalse
using==
.Yes:
if greeting:
No:
if greeting == True:
Worse:
if greeting is True:
Examples
>>> sympify(True) true >>> ~true false >>> ~True -2 >>> Or(True, False) true
See also
- class diofant.logic.boolalg.BooleanFalse(*args, **kwargs)[source]
Diofant version of False, a singleton that can be accessed via
false
.This is the Diofant version of False, for use in the logic module. The primary advantage of using false instead of False is that shorthand boolean operations like ~ and >> will work as expected on this class, whereas with False they act bitwise on 0. Functions in the logic module will return this class when they evaluate to false.
Notes
See note in
BooleanTrue
.Examples
>>> sympify(False) false >>> false >> false true >>> False >> False 0 >>> Or(True, False) true
See also
- class diofant.logic.boolalg.And(*args)[source]
Logical AND function.
It evaluates its arguments in order, giving False immediately if any of them are False, and True if they are all True.
Examples
>>> x & y x & y
Notes
The
&
operator is provided as a convenience, but note that its use here is different from its normal use in Python, which is bitwise and. Hence,And(a, b)
anda & b
will return different things ifa
andb
are integers.>>> And(x, y).subs({x: 1}) y
- class diofant.logic.boolalg.Or(*args)[source]
Logical OR function
It evaluates its arguments in order, giving True immediately if any of them are True, and False if they are all False.
Examples
>>> x | y x | y
Notes
The
|
operator is provided as a convenience, but note that its use here is different from its normal use in Python, which is bitwise or. Hence,Or(a, b)
anda | b
will return different things ifa
andb
are integers.>>> Or(x, y).subs({x: 0}) y
- class diofant.logic.boolalg.Not(arg)[source]
Logical Not function (negation).
Returns True if the statement is False. Returns False if the statement is True.
Examples
>>> Not(True) false >>> Not(False) true >>> Not(And(True, False)) true >>> Not(Or(True, False)) false >>> Not(And(And(True, x), Or(x, False))) ~x >>> ~x ~x >>> Not(And(Or(x, y), Or(~x, ~y))) ~((x | y) & (~x | ~y))
Notes
The
~
operator is provided as a convenience, but note that its use here is different from its normal use in Python, which is bitwise not. In particular,~a
andNot(a)
will be different ifa
is an integer. Furthermore, since bools in Python subclass fromint
,~True
is the same as~1
which is-2
, which has a boolean value of True. To avoid this issue, use the Diofant boolean typestrue
andfalse
.>>> ~True -2 >>> ~true false
- class diofant.logic.boolalg.Xor(*args)[source]
Logical XOR (exclusive OR) function.
Returns True if an odd number of the arguments are True and the rest are False.
Returns False if an even number of the arguments are True and the rest are False.
Examples
>>> Xor(True, False) true >>> Xor(True, True) false >>> Xor(True, False, True, True, False) true >>> Xor(True, False, True, False) false >>> x ^ y Xor(x, y)
Notes
The
^
operator is provided as a convenience, but note that its use here is different from its normal use in Python, which is bitwise xor. In particular,a ^ b
andXor(a, b)
will be different ifa
andb
are integers.>>> Xor(x, y).subs({y: 0}) x
- class diofant.logic.boolalg.Nand(*args)[source]
Logical NAND function.
It evaluates its arguments in order, giving True immediately if any of them are False, and False if they are all True.
Returns True if any of the arguments are False. Returns False if all arguments are True.
Examples
>>> Nand(False, True) true >>> Nand(True, True) false >>> Nand(x, y) ~(x & y)
- class diofant.logic.boolalg.Nor(*args)[source]
Logical NOR function.
It evaluates its arguments in order, giving False immediately if any of them are True, and True if they are all False.
Returns False if any argument is True. Returns True if all arguments are False.
Examples
>>> Nor(True, False) false >>> Nor(True, True) false >>> Nor(False, True) false >>> Nor(False, False) true >>> Nor(x, y) ~(x | y)
- class diofant.logic.boolalg.Implies(*args)[source]
Logical implication.
A implies B is equivalent to !A v B
Accepts two Boolean arguments; A and B. Returns False if A is True and B is False. Returns True otherwise.
Examples
>>> Implies(True, False) false >>> Implies(False, False) true >>> Implies(True, True) true >>> Implies(False, True) true >>> x >> y Implies(x, y) >>> y << x Implies(x, y)
Notes
The
>>
and<<
operators are provided as a convenience, but note that their use here is different from their normal use in Python, which is bit shifts. Hence,Implies(a, b)
anda >> b
will return different things ifa
andb
are integers. In particular, since Python considersTrue
andFalse
to be integers,True >> True
will be the same as1 >> 1
, i.e., 0, which has a truth value of False. To avoid this issue, use the Diofant objectstrue
andfalse
.>>> True >> False 1 >>> true >> false false
- class diofant.logic.boolalg.Equivalent(*args)[source]
Equivalence relation.
Equivalent(A, B) is True iff A and B are both True or both False.
Returns True if all of the arguments are logically equivalent. Returns False otherwise.
Examples
>>> Equivalent(False, False, False) true >>> Equivalent(True, False, False) false >>> Equivalent(x, And(x, True)) true
- class diofant.logic.boolalg.ITE(*args)[source]
If then else clause.
ITE(A, B, C) evaluates and returns the result of B if A is true else it returns the result of C.
Examples
>>> ITE(True, False, True) false >>> ITE(Or(True, False), And(True, True), Xor(True, True)) true >>> ITE(x, y, z) ITE(x, y, z) >>> ITE(True, x, y) x >>> ITE(False, x, y) y >>> ITE(x, y, y) y
The following functions can be used to handle Conjunctive and Disjunctive Normal forms-
- diofant.logic.boolalg.to_cnf(expr, simplify=False)[source]
Convert a propositional logical sentence s to conjunctive normal form. That is, of the form ((A | ~B | …) & (B | C | …) & …). If simplify is True, the expr is evaluated to its simplest CNF form.
Examples
>>> to_cnf(~(a | b) | c) (c | ~a) & (c | ~b) >>> to_cnf((a | b) & (a | ~a), True) a | b
- diofant.logic.boolalg.to_dnf(expr, simplify=False)[source]
Convert a propositional logical sentence s to disjunctive normal form. That is, of the form ((A & ~B & …) | (B & C & …) | …). If simplify is True, the expr is evaluated to its simplest DNF form.
Examples
>>> to_dnf(b & (a | c)) (a & b) | (b & c) >>> to_dnf((a & b) | (a & ~b) | (b & c) | (~b & c), True) a | c
Simplification and equivalence-testing
- diofant.logic.boolalg.simplify_logic(expr, form=None, deep=True)[source]
This function simplifies a boolean function to its simplified version in SOP or POS form. The return type is an Or or And object in Diofant.
- Parameters
expr (string or boolean expression)
form (string (‘cnf’ or ‘dnf’) or None (default).) – If ‘cnf’ or ‘dnf’, the simplest expression in the corresponding normal form is returned; if None, the answer is returned according to the form with fewest args (in CNF by default).
deep (boolean (default True)) – indicates whether to recursively simplify any non-boolean functions contained within the input.
Examples
>>> b = (~x & ~y & ~z) | (~x & ~y & z) >>> simplify_logic(b) ~x & ~y
>>> sympify(b) (z & ~x & ~y) | (~x & ~y & ~z) >>> simplify_logic(_) ~x & ~y
Diofant’s simplify() function can also be used to simplify logic expressions to their simplest forms.
- diofant.logic.boolalg.bool_map(bool1, bool2)[source]
Return the simplified version of bool1, and the mapping of variables that makes the two expressions bool1 and bool2 represent the same logical behaviour for some correspondence between the variables of each. If more than one mappings of this sort exist, one of them is returned. For example, And(x, y) is logically equivalent to And(a, b) for the mapping {x: a, y:b} or {x: b, y:a}. If no such mapping exists, return False.
Examples
>>> function1 = SOPform([x, z, y], [[1, 0, 1], [0, 0, 1]]) >>> function2 = SOPform([a, b, c], [[1, 0, 1], [1, 0, 0]]) >>> bool_map(function1, function2) (y & ~z, {y: a, z: b})
The results are not necessarily unique, but they are canonical. Here,
(t, z)
could be(a, d)
or(d, a)
:>>> eq1 = Or(And(Not(y), t), And(Not(y), z), And(x, y)) >>> eq2 = Or(And(Not(c), a), And(Not(c), d), And(b, c)) >>> bool_map(eq1, eq2) ((x & y) | (t & ~y) | (z & ~y), {t: a, x: b, y: c, z: d}) >>> eq = And(Xor(a, b), c, And(c, d)) >>> bool_map(eq, eq.subs({c: x})) (c & d & (a | b) & (~a | ~b), {a: a, b: b, c: d, d: x})
Inference
This module implements some inference routines in propositional logic.
The function satisfiable will test that a given Boolean expression is satisfiable, that is, you can assign values to the variables to make the sentence \(True\).
For example, the expression x & ~x
is not satisfiable, since there are no
values for x
that make this sentence True
. On the other hand, (x
| y) & (x | ~y) & (~x | y)
is satisfiable with both x
and y
being
True
.
>>> satisfiable(x & ~x)
False
>>> satisfiable((x | y) & (x | ~y) & (~x | y))
{x: True, y: True}
As you see, when a sentence is satisfiable, it returns a model that makes that
sentence True
. If it is not satisfiable it will return False
.
- diofant.logic.inference.satisfiable(expr, algorithm='dpll2', all_models=False)[source]
Check satisfiability of a propositional sentence. Returns a model when it succeeds. Returns {true: true} for trivially true expressions.
On setting all_models to True, if given expr is satisfiable then returns a generator of models. However, if expr is unsatisfiable then returns a generator containing the single element False.
Examples
>>> satisfiable(a & ~b) {a: True, b: False} >>> satisfiable(a & ~a) False >>> satisfiable(True) {true: True} >>> next(satisfiable(a & ~a, all_models=True)) False >>> models = satisfiable((a >> b) & b, all_models=True) >>> next(models) {a: False, b: True} >>> next(models) {a: True, b: True} >>> def use_models(models): ... for model in models: ... if model: ... # Do something with the model. ... return model ... else: ... # Given expr is unsatisfiable. ... print('UNSAT') >>> use_models(satisfiable(a >> ~a, all_models=True)) {a: False} >>> use_models(satisfiable(a ^ a, all_models=True)) UNSAT