1341 lines
48 KiB
Python
1341 lines
48 KiB
Python
from sympy.assumptions.ask import Q
|
|
from sympy.assumptions.refine import refine
|
|
from sympy.core.numbers import oo
|
|
from sympy.core.relational import Equality, Eq, Ne
|
|
from sympy.core.singleton import S
|
|
from sympy.core.symbol import (Dummy, symbols)
|
|
from sympy.functions import Piecewise
|
|
from sympy.functions.elementary.trigonometric import cos, sin
|
|
from sympy.sets.sets import (Interval, Union)
|
|
from sympy.simplify.simplify import simplify
|
|
from sympy.logic.boolalg import (
|
|
And, Boolean, Equivalent, ITE, Implies, Nand, Nor, Not, Or,
|
|
POSform, SOPform, Xor, Xnor, conjuncts, disjuncts,
|
|
distribute_or_over_and, distribute_and_over_or,
|
|
eliminate_implications, is_nnf, is_cnf, is_dnf, simplify_logic,
|
|
to_nnf, to_cnf, to_dnf, to_int_repr, bool_map, true, false,
|
|
BooleanAtom, is_literal, term_to_integer,
|
|
truth_table, as_Boolean, to_anf, is_anf, distribute_xor_over_and,
|
|
anf_coeffs, ANFform, bool_minterm, bool_maxterm, bool_monomial,
|
|
_check_pair, _convert_to_varsSOP, _convert_to_varsPOS, Exclusive,
|
|
gateinputcount)
|
|
from sympy.assumptions.cnf import CNF
|
|
|
|
from sympy.testing.pytest import raises, XFAIL, slow
|
|
|
|
from itertools import combinations, permutations, product
|
|
|
|
A, B, C, D = symbols('A:D')
|
|
a, b, c, d, e, w, x, y, z = symbols('a:e w:z')
|
|
|
|
|
|
def test_overloading():
|
|
"""Test that |, & are overloaded as expected"""
|
|
|
|
assert A & B == And(A, B)
|
|
assert A | B == Or(A, B)
|
|
assert (A & B) | C == Or(And(A, B), C)
|
|
assert A >> B == Implies(A, B)
|
|
assert A << B == Implies(B, A)
|
|
assert ~A == Not(A)
|
|
assert A ^ B == Xor(A, B)
|
|
|
|
|
|
def test_And():
|
|
assert And() is true
|
|
assert And(A) == A
|
|
assert And(True) is true
|
|
assert And(False) is false
|
|
assert And(True, True) is true
|
|
assert And(True, False) is false
|
|
assert And(False, False) is false
|
|
assert And(True, A) == A
|
|
assert And(False, A) is false
|
|
assert And(True, True, True) is true
|
|
assert And(True, True, A) == A
|
|
assert And(True, False, A) is false
|
|
assert And(1, A) == A
|
|
raises(TypeError, lambda: And(2, A))
|
|
raises(TypeError, lambda: And(A < 2, A))
|
|
assert And(A < 1, A >= 1) is false
|
|
e = A > 1
|
|
assert And(e, e.canonical) == e.canonical
|
|
g, l, ge, le = A > B, B < A, A >= B, B <= A
|
|
assert And(g, l, ge, le) == And(ge, g)
|
|
assert {And(*i) for i in permutations((l,g,le,ge))} == {And(ge, g)}
|
|
assert And(And(Eq(a, 0), Eq(b, 0)), And(Ne(a, 0), Eq(c, 0))) is false
|
|
|
|
|
|
def test_Or():
|
|
assert Or() is false
|
|
assert Or(A) == A
|
|
assert Or(True) is true
|
|
assert Or(False) is false
|
|
assert Or(True, True) is true
|
|
assert Or(True, False) is true
|
|
assert Or(False, False) is false
|
|
assert Or(True, A) is true
|
|
assert Or(False, A) == A
|
|
assert Or(True, False, False) is true
|
|
assert Or(True, False, A) is true
|
|
assert Or(False, False, A) == A
|
|
assert Or(1, A) is true
|
|
raises(TypeError, lambda: Or(2, A))
|
|
raises(TypeError, lambda: Or(A < 2, A))
|
|
assert Or(A < 1, A >= 1) is true
|
|
e = A > 1
|
|
assert Or(e, e.canonical) == e
|
|
g, l, ge, le = A > B, B < A, A >= B, B <= A
|
|
assert Or(g, l, ge, le) == Or(g, ge)
|
|
|
|
|
|
def test_Xor():
|
|
assert Xor() is false
|
|
assert Xor(A) == A
|
|
assert Xor(A, A) is false
|
|
assert Xor(True, A, A) is true
|
|
assert Xor(A, A, A, A, A) == A
|
|
assert Xor(True, False, False, A, B) == ~Xor(A, B)
|
|
assert Xor(True) is true
|
|
assert Xor(False) is false
|
|
assert Xor(True, True) is false
|
|
assert Xor(True, False) is true
|
|
assert Xor(False, False) is false
|
|
assert Xor(True, A) == ~A
|
|
assert Xor(False, A) == A
|
|
assert Xor(True, False, False) is true
|
|
assert Xor(True, False, A) == ~A
|
|
assert Xor(False, False, A) == A
|
|
assert isinstance(Xor(A, B), Xor)
|
|
assert Xor(A, B, Xor(C, D)) == Xor(A, B, C, D)
|
|
assert Xor(A, B, Xor(B, C)) == Xor(A, C)
|
|
assert Xor(A < 1, A >= 1, B) == Xor(0, 1, B) == Xor(1, 0, B)
|
|
e = A > 1
|
|
assert Xor(e, e.canonical) == Xor(0, 0) == Xor(1, 1)
|
|
|
|
|
|
def test_rewrite_as_And():
|
|
expr = x ^ y
|
|
assert expr.rewrite(And) == (x | y) & (~x | ~y)
|
|
|
|
|
|
def test_rewrite_as_Or():
|
|
expr = x ^ y
|
|
assert expr.rewrite(Or) == (x & ~y) | (y & ~x)
|
|
|
|
|
|
def test_rewrite_as_Nand():
|
|
expr = (y & z) | (z & ~w)
|
|
assert expr.rewrite(Nand) == ~(~(y & z) & ~(z & ~w))
|
|
|
|
|
|
def test_rewrite_as_Nor():
|
|
expr = z & (y | ~w)
|
|
assert expr.rewrite(Nor) == ~(~z | ~(y | ~w))
|
|
|
|
|
|
def test_Not():
|
|
raises(TypeError, lambda: Not(True, False))
|
|
assert Not(True) is false
|
|
assert Not(False) is true
|
|
assert Not(0) is true
|
|
assert Not(1) is false
|
|
assert Not(2) is false
|
|
|
|
|
|
def test_Nand():
|
|
assert Nand() is false
|
|
assert Nand(A) == ~A
|
|
assert Nand(True) is false
|
|
assert Nand(False) is true
|
|
assert Nand(True, True) is false
|
|
assert Nand(True, False) is true
|
|
assert Nand(False, False) is true
|
|
assert Nand(True, A) == ~A
|
|
assert Nand(False, A) is true
|
|
assert Nand(True, True, True) is false
|
|
assert Nand(True, True, A) == ~A
|
|
assert Nand(True, False, A) is true
|
|
|
|
|
|
def test_Nor():
|
|
assert Nor() is true
|
|
assert Nor(A) == ~A
|
|
assert Nor(True) is false
|
|
assert Nor(False) is true
|
|
assert Nor(True, True) is false
|
|
assert Nor(True, False) is false
|
|
assert Nor(False, False) is true
|
|
assert Nor(True, A) is false
|
|
assert Nor(False, A) == ~A
|
|
assert Nor(True, True, True) is false
|
|
assert Nor(True, True, A) is false
|
|
assert Nor(True, False, A) is false
|
|
|
|
|
|
def test_Xnor():
|
|
assert Xnor() is true
|
|
assert Xnor(A) == ~A
|
|
assert Xnor(A, A) is true
|
|
assert Xnor(True, A, A) is false
|
|
assert Xnor(A, A, A, A, A) == ~A
|
|
assert Xnor(True) is false
|
|
assert Xnor(False) is true
|
|
assert Xnor(True, True) is true
|
|
assert Xnor(True, False) is false
|
|
assert Xnor(False, False) is true
|
|
assert Xnor(True, A) == A
|
|
assert Xnor(False, A) == ~A
|
|
assert Xnor(True, False, False) is false
|
|
assert Xnor(True, False, A) == A
|
|
assert Xnor(False, False, A) == ~A
|
|
|
|
|
|
def test_Implies():
|
|
raises(ValueError, lambda: Implies(A, B, C))
|
|
assert Implies(True, True) is true
|
|
assert Implies(True, False) is false
|
|
assert Implies(False, True) is true
|
|
assert Implies(False, False) is true
|
|
assert Implies(0, A) is true
|
|
assert Implies(1, 1) is true
|
|
assert Implies(1, 0) is false
|
|
assert A >> B == B << A
|
|
assert (A < 1) >> (A >= 1) == (A >= 1)
|
|
assert (A < 1) >> (S.One > A) is true
|
|
assert A >> A is true
|
|
|
|
|
|
def test_Equivalent():
|
|
assert Equivalent(A, B) == Equivalent(B, A) == Equivalent(A, B, A)
|
|
assert Equivalent() is true
|
|
assert Equivalent(A, A) == Equivalent(A) is true
|
|
assert Equivalent(True, True) == Equivalent(False, False) is true
|
|
assert Equivalent(True, False) == Equivalent(False, True) is false
|
|
assert Equivalent(A, True) == A
|
|
assert Equivalent(A, False) == Not(A)
|
|
assert Equivalent(A, B, True) == A & B
|
|
assert Equivalent(A, B, False) == ~A & ~B
|
|
assert Equivalent(1, A) == A
|
|
assert Equivalent(0, A) == Not(A)
|
|
assert Equivalent(A, Equivalent(B, C)) != Equivalent(Equivalent(A, B), C)
|
|
assert Equivalent(A < 1, A >= 1) is false
|
|
assert Equivalent(A < 1, A >= 1, 0) is false
|
|
assert Equivalent(A < 1, A >= 1, 1) is false
|
|
assert Equivalent(A < 1, S.One > A) == Equivalent(1, 1) == Equivalent(0, 0)
|
|
assert Equivalent(Equality(A, B), Equality(B, A)) is true
|
|
|
|
|
|
def test_Exclusive():
|
|
assert Exclusive(False, False, False) is true
|
|
assert Exclusive(True, False, False) is true
|
|
assert Exclusive(True, True, False) is false
|
|
assert Exclusive(True, True, True) is false
|
|
|
|
|
|
def test_equals():
|
|
assert Not(Or(A, B)).equals(And(Not(A), Not(B))) is True
|
|
assert Equivalent(A, B).equals((A >> B) & (B >> A)) is True
|
|
assert ((A | ~B) & (~A | B)).equals((~A & ~B) | (A & B)) is True
|
|
assert (A >> B).equals(~A >> ~B) is False
|
|
assert (A >> (B >> A)).equals(A >> (C >> A)) is False
|
|
raises(NotImplementedError, lambda: (A & B).equals(A > B))
|
|
|
|
|
|
def test_simplification_boolalg():
|
|
"""
|
|
Test working of simplification methods.
|
|
"""
|
|
set1 = [[0, 0, 1], [0, 1, 1], [1, 0, 0], [1, 1, 0]]
|
|
set2 = [[0, 0, 0], [0, 1, 0], [1, 0, 1], [1, 1, 1]]
|
|
assert SOPform([x, y, z], set1) == Or(And(Not(x), z), And(Not(z), x))
|
|
assert Not(SOPform([x, y, z], set2)) == \
|
|
Not(Or(And(Not(x), Not(z)), And(x, z)))
|
|
assert POSform([x, y, z], set1 + set2) is true
|
|
assert SOPform([x, y, z], set1 + set2) is true
|
|
assert SOPform([Dummy(), Dummy(), Dummy()], set1 + set2) is true
|
|
|
|
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]]
|
|
assert (
|
|
SOPform([w, x, y, z], minterms, dontcares) ==
|
|
Or(And(y, z), And(Not(w), Not(x))))
|
|
assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
|
|
|
|
minterms = [1, 3, 7, 11, 15]
|
|
dontcares = [0, 2, 5]
|
|
assert (
|
|
SOPform([w, x, y, z], minterms, dontcares) ==
|
|
Or(And(y, z), And(Not(w), Not(x))))
|
|
assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
|
|
|
|
minterms = [1, [0, 0, 1, 1], 7, [1, 0, 1, 1],
|
|
[1, 1, 1, 1]]
|
|
dontcares = [0, [0, 0, 1, 0], 5]
|
|
assert (
|
|
SOPform([w, x, y, z], minterms, dontcares) ==
|
|
Or(And(y, z), And(Not(w), Not(x))))
|
|
assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
|
|
|
|
minterms = [1, {y: 1, z: 1}]
|
|
dontcares = [0, [0, 0, 1, 0], 5]
|
|
assert (
|
|
SOPform([w, x, y, z], minterms, dontcares) ==
|
|
Or(And(y, z), And(Not(w), Not(x))))
|
|
assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
|
|
|
|
|
|
minterms = [{y: 1, z: 1}, 1]
|
|
dontcares = [[0, 0, 0, 0]]
|
|
|
|
minterms = [[0, 0, 0]]
|
|
raises(ValueError, lambda: SOPform([w, x, y, z], minterms))
|
|
raises(ValueError, lambda: POSform([w, x, y, z], minterms))
|
|
|
|
raises(TypeError, lambda: POSform([w, x, y, z], ["abcdefg"]))
|
|
|
|
# test simplification
|
|
ans = And(A, Or(B, C))
|
|
assert simplify_logic(A & (B | C)) == ans
|
|
assert simplify_logic((A & B) | (A & C)) == ans
|
|
assert simplify_logic(Implies(A, B)) == Or(Not(A), B)
|
|
assert simplify_logic(Equivalent(A, B)) == \
|
|
Or(And(A, B), And(Not(A), Not(B)))
|
|
assert simplify_logic(And(Equality(A, 2), C)) == And(Equality(A, 2), C)
|
|
assert simplify_logic(And(Equality(A, 2), A)) is S.false
|
|
assert simplify_logic(And(Equality(A, 2), A)) == And(Equality(A, 2), A)
|
|
assert simplify_logic(And(Equality(A, B), C)) == And(Equality(A, B), C)
|
|
assert simplify_logic(Or(And(Equality(A, 3), B), And(Equality(A, 3), C))) \
|
|
== And(Equality(A, 3), Or(B, C))
|
|
b = (~x & ~y & ~z) | (~x & ~y & z)
|
|
e = And(A, b)
|
|
assert simplify_logic(e) == A & ~x & ~y
|
|
raises(ValueError, lambda: simplify_logic(A & (B | C), form='blabla'))
|
|
assert simplify(Or(x <= y, And(x < y, z))) == (x <= y)
|
|
assert simplify(Or(x <= y, And(y > x, z))) == (x <= y)
|
|
assert simplify(Or(x >= y, And(y < x, z))) == (x >= y)
|
|
|
|
# Check that expressions with nine variables or more are not simplified
|
|
# (without the force-flag)
|
|
a, b, c, d, e, f, g, h, j = symbols('a b c d e f g h j')
|
|
expr = a & b & c & d & e & f & g & h & j | \
|
|
a & b & c & d & e & f & g & h & ~j
|
|
# This expression can be simplified to get rid of the j variables
|
|
assert simplify_logic(expr) == expr
|
|
|
|
# Test dontcare
|
|
assert simplify_logic((a & b) | c | d, dontcare=(a & b)) == c | d
|
|
|
|
# check input
|
|
ans = SOPform([x, y], [[1, 0]])
|
|
assert SOPform([x, y], [[1, 0]]) == ans
|
|
assert POSform([x, y], [[1, 0]]) == ans
|
|
|
|
raises(ValueError, lambda: SOPform([x], [[1]], [[1]]))
|
|
assert SOPform([x], [[1]], [[0]]) is true
|
|
assert SOPform([x], [[0]], [[1]]) is true
|
|
assert SOPform([x], [], []) is false
|
|
|
|
raises(ValueError, lambda: POSform([x], [[1]], [[1]]))
|
|
assert POSform([x], [[1]], [[0]]) is true
|
|
assert POSform([x], [[0]], [[1]]) is true
|
|
assert POSform([x], [], []) is false
|
|
|
|
# check working of simplify
|
|
assert simplify((A & B) | (A & C)) == And(A, Or(B, C))
|
|
assert simplify(And(x, Not(x))) == False
|
|
assert simplify(Or(x, Not(x))) == True
|
|
assert simplify(And(Eq(x, 0), Eq(x, y))) == And(Eq(x, 0), Eq(y, 0))
|
|
assert And(Eq(x - 1, 0), Eq(x, y)).simplify() == And(Eq(x, 1), Eq(y, 1))
|
|
assert And(Ne(x - 1, 0), Ne(x, y)).simplify() == And(Ne(x, 1), Ne(x, y))
|
|
assert And(Eq(x - 1, 0), Ne(x, y)).simplify() == And(Eq(x, 1), Ne(y, 1))
|
|
assert And(Eq(x - 1, 0), Eq(x, z + y), Eq(y + x, 0)).simplify(
|
|
) == And(Eq(x, 1), Eq(y, -1), Eq(z, 2))
|
|
assert And(Eq(x - 1, 0), Eq(x + 2, 3)).simplify() == Eq(x, 1)
|
|
assert And(Ne(x - 1, 0), Ne(x + 2, 3)).simplify() == Ne(x, 1)
|
|
assert And(Eq(x - 1, 0), Eq(x + 2, 2)).simplify() == False
|
|
assert And(Ne(x - 1, 0), Ne(x + 2, 2)).simplify(
|
|
) == And(Ne(x, 1), Ne(x, 0))
|
|
|
|
|
|
def test_bool_map():
|
|
"""
|
|
Test working of bool_map function.
|
|
"""
|
|
|
|
minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 0, 1, 1],
|
|
[1, 1, 1, 1]]
|
|
assert bool_map(Not(Not(a)), a) == (a, {a: a})
|
|
assert bool_map(SOPform([w, x, y, z], minterms),
|
|
POSform([w, x, y, z], minterms)) == \
|
|
(And(Or(Not(w), y), Or(Not(x), y), z), {x: x, w: w, z: z, y: y})
|
|
assert bool_map(SOPform([x, z, y], [[1, 0, 1]]),
|
|
SOPform([a, b, c], [[1, 0, 1]])) != False
|
|
function1 = SOPform([x, z, y], [[1, 0, 1], [0, 0, 1]])
|
|
function2 = SOPform([a, b, c], [[1, 0, 1], [1, 0, 0]])
|
|
assert bool_map(function1, function2) == \
|
|
(function1, {y: a, z: b})
|
|
assert bool_map(Xor(x, y), ~Xor(x, y)) == False
|
|
assert bool_map(And(x, y), Or(x, y)) is None
|
|
assert bool_map(And(x, y), And(x, y, z)) is None
|
|
# issue 16179
|
|
assert bool_map(Xor(x, y, z), ~Xor(x, y, z)) == False
|
|
assert bool_map(Xor(a, x, y, z), ~Xor(a, x, y, z)) == False
|
|
|
|
|
|
def test_bool_symbol():
|
|
"""Test that mixing symbols with boolean values
|
|
works as expected"""
|
|
|
|
assert And(A, True) == A
|
|
assert And(A, True, True) == A
|
|
assert And(A, False) is false
|
|
assert And(A, True, False) is false
|
|
assert Or(A, True) is true
|
|
assert Or(A, False) == A
|
|
|
|
|
|
def test_is_boolean():
|
|
assert isinstance(True, Boolean) is False
|
|
assert isinstance(true, Boolean) is True
|
|
assert 1 == True
|
|
assert 1 != true
|
|
assert (1 == true) is False
|
|
assert 0 == False
|
|
assert 0 != false
|
|
assert (0 == false) is False
|
|
assert true.is_Boolean is True
|
|
assert (A & B).is_Boolean
|
|
assert (A | B).is_Boolean
|
|
assert (~A).is_Boolean
|
|
assert (A ^ B).is_Boolean
|
|
assert A.is_Boolean != isinstance(A, Boolean)
|
|
assert isinstance(A, Boolean)
|
|
|
|
|
|
def test_subs():
|
|
assert (A & B).subs(A, True) == B
|
|
assert (A & B).subs(A, False) is false
|
|
assert (A & B).subs(B, True) == A
|
|
assert (A & B).subs(B, False) is false
|
|
assert (A & B).subs({A: True, B: True}) is true
|
|
assert (A | B).subs(A, True) is true
|
|
assert (A | B).subs(A, False) == B
|
|
assert (A | B).subs(B, True) is true
|
|
assert (A | B).subs(B, False) == A
|
|
assert (A | B).subs({A: True, B: True}) is true
|
|
|
|
|
|
"""
|
|
we test for axioms of boolean algebra
|
|
see https://en.wikipedia.org/wiki/Boolean_algebra_(structure)
|
|
"""
|
|
|
|
|
|
def test_commutative():
|
|
"""Test for commutativity of And and Or"""
|
|
A, B = map(Boolean, symbols('A,B'))
|
|
|
|
assert A & B == B & A
|
|
assert A | B == B | A
|
|
|
|
|
|
def test_and_associativity():
|
|
"""Test for associativity of And"""
|
|
|
|
assert (A & B) & C == A & (B & C)
|
|
|
|
|
|
def test_or_assicativity():
|
|
assert ((A | B) | C) == (A | (B | C))
|
|
|
|
|
|
def test_double_negation():
|
|
a = Boolean()
|
|
assert ~(~a) == a
|
|
|
|
|
|
# test methods
|
|
|
|
def test_eliminate_implications():
|
|
assert eliminate_implications(Implies(A, B, evaluate=False)) == (~A) | B
|
|
assert eliminate_implications(
|
|
A >> (C >> Not(B))) == Or(Or(Not(B), Not(C)), Not(A))
|
|
assert eliminate_implications(Equivalent(A, B, C, D)) == \
|
|
(~A | B) & (~B | C) & (~C | D) & (~D | A)
|
|
|
|
|
|
def test_conjuncts():
|
|
assert conjuncts(A & B & C) == {A, B, C}
|
|
assert conjuncts((A | B) & C) == {A | B, C}
|
|
assert conjuncts(A) == {A}
|
|
assert conjuncts(True) == {True}
|
|
assert conjuncts(False) == {False}
|
|
|
|
|
|
def test_disjuncts():
|
|
assert disjuncts(A | B | C) == {A, B, C}
|
|
assert disjuncts((A | B) & C) == {(A | B) & C}
|
|
assert disjuncts(A) == {A}
|
|
assert disjuncts(True) == {True}
|
|
assert disjuncts(False) == {False}
|
|
|
|
|
|
def test_distribute():
|
|
assert distribute_and_over_or(Or(And(A, B), C)) == And(Or(A, C), Or(B, C))
|
|
assert distribute_or_over_and(And(A, Or(B, C))) == Or(And(A, B), And(A, C))
|
|
assert distribute_xor_over_and(And(A, Xor(B, C))) == Xor(And(A, B), And(A, C))
|
|
|
|
|
|
def test_to_anf():
|
|
x, y, z = symbols('x,y,z')
|
|
assert to_anf(And(x, y)) == And(x, y)
|
|
assert to_anf(Or(x, y)) == Xor(x, y, And(x, y))
|
|
assert to_anf(Or(Implies(x, y), And(x, y), y)) == \
|
|
Xor(x, True, x & y, remove_true=False)
|
|
assert to_anf(Or(Nand(x, y), Nor(x, y), Xnor(x, y), Implies(x, y))) == True
|
|
assert to_anf(Or(x, Not(y), Nor(x,z), And(x, y), Nand(y, z))) == \
|
|
Xor(True, And(y, z), And(x, y, z), remove_true=False)
|
|
assert to_anf(Xor(x, y)) == Xor(x, y)
|
|
assert to_anf(Not(x)) == Xor(x, True, remove_true=False)
|
|
assert to_anf(Nand(x, y)) == Xor(True, And(x, y), remove_true=False)
|
|
assert to_anf(Nor(x, y)) == Xor(x, y, True, And(x, y), remove_true=False)
|
|
assert to_anf(Implies(x, y)) == Xor(x, True, And(x, y), remove_true=False)
|
|
assert to_anf(Equivalent(x, y)) == Xor(x, y, True, remove_true=False)
|
|
assert to_anf(Nand(x | y, x >> y), deep=False) == \
|
|
Xor(True, And(Or(x, y), Implies(x, y)), remove_true=False)
|
|
assert to_anf(Nor(x ^ y, x & y), deep=False) == \
|
|
Xor(True, Or(Xor(x, y), And(x, y)), remove_true=False)
|
|
|
|
|
|
def test_to_nnf():
|
|
assert to_nnf(true) is true
|
|
assert to_nnf(false) is false
|
|
assert to_nnf(A) == A
|
|
assert to_nnf(A | ~A | B) is true
|
|
assert to_nnf(A & ~A & B) is false
|
|
assert to_nnf(A >> B) == ~A | B
|
|
assert to_nnf(Equivalent(A, B, C)) == (~A | B) & (~B | C) & (~C | A)
|
|
assert to_nnf(A ^ B ^ C) == \
|
|
(A | B | C) & (~A | ~B | C) & (A | ~B | ~C) & (~A | B | ~C)
|
|
assert to_nnf(ITE(A, B, C)) == (~A | B) & (A | C)
|
|
assert to_nnf(Not(A | B | C)) == ~A & ~B & ~C
|
|
assert to_nnf(Not(A & B & C)) == ~A | ~B | ~C
|
|
assert to_nnf(Not(A >> B)) == A & ~B
|
|
assert to_nnf(Not(Equivalent(A, B, C))) == And(Or(A, B, C), Or(~A, ~B, ~C))
|
|
assert to_nnf(Not(A ^ B ^ C)) == \
|
|
(~A | B | C) & (A | ~B | C) & (A | B | ~C) & (~A | ~B | ~C)
|
|
assert to_nnf(Not(ITE(A, B, C))) == (~A | ~B) & (A | ~C)
|
|
assert to_nnf((A >> B) ^ (B >> A)) == (A & ~B) | (~A & B)
|
|
assert to_nnf((A >> B) ^ (B >> A), False) == \
|
|
(~A | ~B | A | B) & ((A & ~B) | (~A & B))
|
|
assert ITE(A, 1, 0).to_nnf() == A
|
|
assert ITE(A, 0, 1).to_nnf() == ~A
|
|
# although ITE can hold non-Boolean, it will complain if
|
|
# an attempt is made to convert the ITE to Boolean nnf
|
|
raises(TypeError, lambda: ITE(A < 1, [1], B).to_nnf())
|
|
|
|
|
|
def test_to_cnf():
|
|
assert to_cnf(~(B | C)) == And(Not(B), Not(C))
|
|
assert to_cnf((A & B) | C) == And(Or(A, C), Or(B, C))
|
|
assert to_cnf(A >> B) == (~A) | B
|
|
assert to_cnf(A >> (B & C)) == (~A | B) & (~A | C)
|
|
assert to_cnf(A & (B | C) | ~A & (B | C), True) == B | C
|
|
assert to_cnf(A & B) == And(A, B)
|
|
|
|
assert to_cnf(Equivalent(A, B)) == And(Or(A, Not(B)), Or(B, Not(A)))
|
|
assert to_cnf(Equivalent(A, B & C)) == \
|
|
(~A | B) & (~A | C) & (~B | ~C | A)
|
|
assert to_cnf(Equivalent(A, B | C), True) == \
|
|
And(Or(Not(B), A), Or(Not(C), A), Or(B, C, Not(A)))
|
|
assert to_cnf(A + 1) == A + 1
|
|
|
|
|
|
def test_issue_18904():
|
|
x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 = symbols('x1:16')
|
|
eq = (( x1 & x2 & x3 & x4 & x5 & x6 & x7 & x8 & x9 ) |
|
|
( x1 & x2 & x3 & x4 & x5 & x6 & x7 & x10 & x9 ) |
|
|
( x1 & x11 & x3 & x12 & x5 & x13 & x14 & x15 & x9 ))
|
|
assert is_cnf(to_cnf(eq))
|
|
raises(ValueError, lambda: to_cnf(eq, simplify=True))
|
|
for f, t in zip((And, Or), (to_cnf, to_dnf)):
|
|
eq = f(x1, x2, x3, x4, x5, x6, x7, x8, x9)
|
|
raises(ValueError, lambda: to_cnf(eq, simplify=True))
|
|
assert t(eq, simplify=True, force=True) == eq
|
|
|
|
|
|
def test_issue_9949():
|
|
assert is_cnf(to_cnf((b > -5) | (a > 2) & (a < 4)))
|
|
|
|
|
|
def test_to_CNF():
|
|
assert CNF.CNF_to_cnf(CNF.to_CNF(~(B | C))) == to_cnf(~(B | C))
|
|
assert CNF.CNF_to_cnf(CNF.to_CNF((A & B) | C)) == to_cnf((A & B) | C)
|
|
assert CNF.CNF_to_cnf(CNF.to_CNF(A >> B)) == to_cnf(A >> B)
|
|
assert CNF.CNF_to_cnf(CNF.to_CNF(A >> (B & C))) == to_cnf(A >> (B & C))
|
|
assert CNF.CNF_to_cnf(CNF.to_CNF(A & (B | C) | ~A & (B | C))) == to_cnf(A & (B | C) | ~A & (B | C))
|
|
assert CNF.CNF_to_cnf(CNF.to_CNF(A & B)) == to_cnf(A & B)
|
|
|
|
|
|
def test_to_dnf():
|
|
assert to_dnf(~(B | C)) == And(Not(B), Not(C))
|
|
assert to_dnf(A & (B | C)) == Or(And(A, B), And(A, C))
|
|
assert to_dnf(A >> B) == (~A) | B
|
|
assert to_dnf(A >> (B & C)) == (~A) | (B & C)
|
|
assert to_dnf(A | B) == A | B
|
|
|
|
assert to_dnf(Equivalent(A, B), True) == \
|
|
Or(And(A, B), And(Not(A), Not(B)))
|
|
assert to_dnf(Equivalent(A, B & C), True) == \
|
|
Or(And(A, B, C), And(Not(A), Not(B)), And(Not(A), Not(C)))
|
|
assert to_dnf(A + 1) == A + 1
|
|
|
|
|
|
def test_to_int_repr():
|
|
x, y, z = map(Boolean, symbols('x,y,z'))
|
|
|
|
def sorted_recursive(arg):
|
|
try:
|
|
return sorted(sorted_recursive(x) for x in arg)
|
|
except TypeError: # arg is not a sequence
|
|
return arg
|
|
|
|
assert sorted_recursive(to_int_repr([x | y, z | x], [x, y, z])) == \
|
|
sorted_recursive([[1, 2], [1, 3]])
|
|
assert sorted_recursive(to_int_repr([x | y, z | ~x], [x, y, z])) == \
|
|
sorted_recursive([[1, 2], [3, -1]])
|
|
|
|
|
|
def test_is_anf():
|
|
x, y = symbols('x,y')
|
|
assert is_anf(true) is True
|
|
assert is_anf(false) is True
|
|
assert is_anf(x) is True
|
|
assert is_anf(And(x, y)) is True
|
|
assert is_anf(Xor(x, y, And(x, y))) is True
|
|
assert is_anf(Xor(x, y, Or(x, y))) is False
|
|
assert is_anf(Xor(Not(x), y)) is False
|
|
|
|
|
|
def test_is_nnf():
|
|
assert is_nnf(true) is True
|
|
assert is_nnf(A) is True
|
|
assert is_nnf(~A) is True
|
|
assert is_nnf(A & B) is True
|
|
assert is_nnf((A & B) | (~A & A) | (~B & B) | (~A & ~B), False) is True
|
|
assert is_nnf((A | B) & (~A | ~B)) is True
|
|
assert is_nnf(Not(Or(A, B))) is False
|
|
assert is_nnf(A ^ B) is False
|
|
assert is_nnf((A & B) | (~A & A) | (~B & B) | (~A & ~B), True) is False
|
|
|
|
|
|
def test_is_cnf():
|
|
assert is_cnf(x) is True
|
|
assert is_cnf(x | y | z) is True
|
|
assert is_cnf(x & y & z) is True
|
|
assert is_cnf((x | y) & z) is True
|
|
assert is_cnf((x & y) | z) is False
|
|
assert is_cnf(~(x & y) | z) is False
|
|
|
|
|
|
def test_is_dnf():
|
|
assert is_dnf(x) is True
|
|
assert is_dnf(x | y | z) is True
|
|
assert is_dnf(x & y & z) is True
|
|
assert is_dnf((x & y) | z) is True
|
|
assert is_dnf((x | y) & z) is False
|
|
assert is_dnf(~(x | y) & z) is False
|
|
|
|
|
|
def test_ITE():
|
|
A, B, C = symbols('A:C')
|
|
assert ITE(True, False, True) is false
|
|
assert ITE(True, True, False) is true
|
|
assert ITE(False, True, False) is false
|
|
assert ITE(False, False, True) is true
|
|
assert isinstance(ITE(A, B, C), ITE)
|
|
|
|
A = True
|
|
assert ITE(A, B, C) == B
|
|
A = False
|
|
assert ITE(A, B, C) == C
|
|
B = True
|
|
assert ITE(And(A, B), B, C) == C
|
|
assert ITE(Or(A, False), And(B, True), False) is false
|
|
assert ITE(x, A, B) == Not(x)
|
|
assert ITE(x, B, A) == x
|
|
assert ITE(1, x, y) == x
|
|
assert ITE(0, x, y) == y
|
|
raises(TypeError, lambda: ITE(2, x, y))
|
|
raises(TypeError, lambda: ITE(1, [], y))
|
|
raises(TypeError, lambda: ITE(1, (), y))
|
|
raises(TypeError, lambda: ITE(1, y, []))
|
|
assert ITE(1, 1, 1) is S.true
|
|
assert isinstance(ITE(1, 1, 1, evaluate=False), ITE)
|
|
|
|
raises(TypeError, lambda: ITE(x > 1, y, x))
|
|
assert ITE(Eq(x, True), y, x) == ITE(x, y, x)
|
|
assert ITE(Eq(x, False), y, x) == ITE(~x, y, x)
|
|
assert ITE(Ne(x, True), y, x) == ITE(~x, y, x)
|
|
assert ITE(Ne(x, False), y, x) == ITE(x, y, x)
|
|
assert ITE(Eq(S. true, x), y, x) == ITE(x, y, x)
|
|
assert ITE(Eq(S.false, x), y, x) == ITE(~x, y, x)
|
|
assert ITE(Ne(S.true, x), y, x) == ITE(~x, y, x)
|
|
assert ITE(Ne(S.false, x), y, x) == ITE(x, y, x)
|
|
# 0 and 1 in the context are not treated as True/False
|
|
# so the equality must always be False since dissimilar
|
|
# objects cannot be equal
|
|
assert ITE(Eq(x, 0), y, x) == x
|
|
assert ITE(Eq(x, 1), y, x) == x
|
|
assert ITE(Ne(x, 0), y, x) == y
|
|
assert ITE(Ne(x, 1), y, x) == y
|
|
assert ITE(Eq(x, 0), y, z).subs(x, 0) == y
|
|
assert ITE(Eq(x, 0), y, z).subs(x, 1) == z
|
|
raises(ValueError, lambda: ITE(x > 1, y, x, z))
|
|
|
|
|
|
def test_is_literal():
|
|
assert is_literal(True) is True
|
|
assert is_literal(False) is True
|
|
assert is_literal(A) is True
|
|
assert is_literal(~A) is True
|
|
assert is_literal(Or(A, B)) is False
|
|
assert is_literal(Q.zero(A)) is True
|
|
assert is_literal(Not(Q.zero(A))) is True
|
|
assert is_literal(Or(A, B)) is False
|
|
assert is_literal(And(Q.zero(A), Q.zero(B))) is False
|
|
assert is_literal(x < 3)
|
|
assert not is_literal(x + y < 3)
|
|
|
|
|
|
def test_operators():
|
|
# Mostly test __and__, __rand__, and so on
|
|
assert True & A == A & True == A
|
|
assert False & A == A & False == False
|
|
assert A & B == And(A, B)
|
|
assert True | A == A | True == True
|
|
assert False | A == A | False == A
|
|
assert A | B == Or(A, B)
|
|
assert ~A == Not(A)
|
|
assert True >> A == A << True == A
|
|
assert False >> A == A << False == True
|
|
assert A >> True == True << A == True
|
|
assert A >> False == False << A == ~A
|
|
assert A >> B == B << A == Implies(A, B)
|
|
assert True ^ A == A ^ True == ~A
|
|
assert False ^ A == A ^ False == A
|
|
assert A ^ B == Xor(A, B)
|
|
|
|
|
|
def test_true_false():
|
|
assert true is S.true
|
|
assert false is S.false
|
|
assert true is not True
|
|
assert false is not False
|
|
assert true
|
|
assert not false
|
|
assert true == True
|
|
assert false == False
|
|
assert not (true == False)
|
|
assert not (false == True)
|
|
assert not (true == false)
|
|
|
|
assert hash(true) == hash(True)
|
|
assert hash(false) == hash(False)
|
|
assert len({true, True}) == len({false, False}) == 1
|
|
|
|
assert isinstance(true, BooleanAtom)
|
|
assert isinstance(false, BooleanAtom)
|
|
# We don't want to subclass from bool, because bool subclasses from
|
|
# int. But operators like &, |, ^, <<, >>, and ~ act differently on 0 and
|
|
# 1 then we want them to on true and false. See the docstrings of the
|
|
# various And, Or, etc. functions for examples.
|
|
assert not isinstance(true, bool)
|
|
assert not isinstance(false, bool)
|
|
|
|
# Note: using 'is' comparison is important here. We want these to return
|
|
# true and false, not True and False
|
|
|
|
assert Not(true) is false
|
|
assert Not(True) is false
|
|
assert Not(false) is true
|
|
assert Not(False) is true
|
|
assert ~true is false
|
|
assert ~false is true
|
|
|
|
for T, F in product((True, true), (False, false)):
|
|
assert And(T, F) is false
|
|
assert And(F, T) is false
|
|
assert And(F, F) is false
|
|
assert And(T, T) is true
|
|
assert And(T, x) == x
|
|
assert And(F, x) is false
|
|
if not (T is True and F is False):
|
|
assert T & F is false
|
|
assert F & T is false
|
|
if F is not False:
|
|
assert F & F is false
|
|
if T is not True:
|
|
assert T & T is true
|
|
|
|
assert Or(T, F) is true
|
|
assert Or(F, T) is true
|
|
assert Or(F, F) is false
|
|
assert Or(T, T) is true
|
|
assert Or(T, x) is true
|
|
assert Or(F, x) == x
|
|
if not (T is True and F is False):
|
|
assert T | F is true
|
|
assert F | T is true
|
|
if F is not False:
|
|
assert F | F is false
|
|
if T is not True:
|
|
assert T | T is true
|
|
|
|
assert Xor(T, F) is true
|
|
assert Xor(F, T) is true
|
|
assert Xor(F, F) is false
|
|
assert Xor(T, T) is false
|
|
assert Xor(T, x) == ~x
|
|
assert Xor(F, x) == x
|
|
if not (T is True and F is False):
|
|
assert T ^ F is true
|
|
assert F ^ T is true
|
|
if F is not False:
|
|
assert F ^ F is false
|
|
if T is not True:
|
|
assert T ^ T is false
|
|
|
|
assert Nand(T, F) is true
|
|
assert Nand(F, T) is true
|
|
assert Nand(F, F) is true
|
|
assert Nand(T, T) is false
|
|
assert Nand(T, x) == ~x
|
|
assert Nand(F, x) is true
|
|
|
|
assert Nor(T, F) is false
|
|
assert Nor(F, T) is false
|
|
assert Nor(F, F) is true
|
|
assert Nor(T, T) is false
|
|
assert Nor(T, x) is false
|
|
assert Nor(F, x) == ~x
|
|
|
|
assert Implies(T, F) is false
|
|
assert Implies(F, T) is true
|
|
assert Implies(F, F) is true
|
|
assert Implies(T, T) is true
|
|
assert Implies(T, x) == x
|
|
assert Implies(F, x) is true
|
|
assert Implies(x, T) is true
|
|
assert Implies(x, F) == ~x
|
|
if not (T is True and F is False):
|
|
assert T >> F is false
|
|
assert F << T is false
|
|
assert F >> T is true
|
|
assert T << F is true
|
|
if F is not False:
|
|
assert F >> F is true
|
|
assert F << F is true
|
|
if T is not True:
|
|
assert T >> T is true
|
|
assert T << T is true
|
|
|
|
assert Equivalent(T, F) is false
|
|
assert Equivalent(F, T) is false
|
|
assert Equivalent(F, F) is true
|
|
assert Equivalent(T, T) is true
|
|
assert Equivalent(T, x) == x
|
|
assert Equivalent(F, x) == ~x
|
|
assert Equivalent(x, T) == x
|
|
assert Equivalent(x, F) == ~x
|
|
|
|
assert ITE(T, T, T) is true
|
|
assert ITE(T, T, F) is true
|
|
assert ITE(T, F, T) is false
|
|
assert ITE(T, F, F) is false
|
|
assert ITE(F, T, T) is true
|
|
assert ITE(F, T, F) is false
|
|
assert ITE(F, F, T) is true
|
|
assert ITE(F, F, F) is false
|
|
|
|
assert all(i.simplify(1, 2) is i for i in (S.true, S.false))
|
|
|
|
|
|
def test_bool_as_set():
|
|
assert ITE(y <= 0, False, y >= 1).as_set() == Interval(1, oo)
|
|
assert And(x <= 2, x >= -2).as_set() == Interval(-2, 2)
|
|
assert Or(x >= 2, x <= -2).as_set() == Interval(-oo, -2) + Interval(2, oo)
|
|
assert Not(x > 2).as_set() == Interval(-oo, 2)
|
|
# issue 10240
|
|
assert Not(And(x > 2, x < 3)).as_set() == \
|
|
Union(Interval(-oo, 2), Interval(3, oo))
|
|
assert true.as_set() == S.UniversalSet
|
|
assert false.as_set() is S.EmptySet
|
|
assert x.as_set() == S.UniversalSet
|
|
assert And(Or(x < 1, x > 3), x < 2).as_set() == Interval.open(-oo, 1)
|
|
assert And(x < 1, sin(x) < 3).as_set() == (x < 1).as_set()
|
|
raises(NotImplementedError, lambda: (sin(x) < 1).as_set())
|
|
# watch for object morph in as_set
|
|
assert Eq(-1, cos(2*x)**2/sin(2*x)**2).as_set() is S.EmptySet
|
|
|
|
|
|
@XFAIL
|
|
def test_multivariate_bool_as_set():
|
|
x, y = symbols('x,y')
|
|
|
|
assert And(x >= 0, y >= 0).as_set() == Interval(0, oo)*Interval(0, oo)
|
|
assert Or(x >= 0, y >= 0).as_set() == S.Reals*S.Reals - \
|
|
Interval(-oo, 0, True, True)*Interval(-oo, 0, True, True)
|
|
|
|
|
|
def test_all_or_nothing():
|
|
x = symbols('x', extended_real=True)
|
|
args = x >= -oo, x <= oo
|
|
v = And(*args)
|
|
if v.func is And:
|
|
assert len(v.args) == len(args) - args.count(S.true)
|
|
else:
|
|
assert v == True
|
|
v = Or(*args)
|
|
if v.func is Or:
|
|
assert len(v.args) == 2
|
|
else:
|
|
assert v == True
|
|
|
|
|
|
def test_canonical_atoms():
|
|
assert true.canonical == true
|
|
assert false.canonical == false
|
|
|
|
|
|
def test_negated_atoms():
|
|
assert true.negated == false
|
|
assert false.negated == true
|
|
|
|
|
|
def test_issue_8777():
|
|
assert And(x > 2, x < oo).as_set() == Interval(2, oo, left_open=True)
|
|
assert And(x >= 1, x < oo).as_set() == Interval(1, oo)
|
|
assert (x < oo).as_set() == Interval(-oo, oo)
|
|
assert (x > -oo).as_set() == Interval(-oo, oo)
|
|
|
|
|
|
def test_issue_8975():
|
|
assert Or(And(-oo < x, x <= -2), And(2 <= x, x < oo)).as_set() == \
|
|
Interval(-oo, -2) + Interval(2, oo)
|
|
|
|
|
|
def test_term_to_integer():
|
|
assert term_to_integer([1, 0, 1, 0, 0, 1, 0]) == 82
|
|
assert term_to_integer('0010101000111001') == 10809
|
|
|
|
|
|
def test_issue_21971():
|
|
a, b, c, d = symbols('a b c d')
|
|
f = a & b & c | a & c
|
|
assert f.subs(a & c, d) == b & d | d
|
|
assert f.subs(a & b & c, d) == a & c | d
|
|
|
|
f = (a | b | c) & (a | c)
|
|
assert f.subs(a | c, d) == (b | d) & d
|
|
assert f.subs(a | b | c, d) == (a | c) & d
|
|
|
|
f = (a ^ b ^ c) & (a ^ c)
|
|
assert f.subs(a ^ c, d) == (b ^ d) & d
|
|
assert f.subs(a ^ b ^ c, d) == (a ^ c) & d
|
|
|
|
|
|
def test_truth_table():
|
|
assert list(truth_table(And(x, y), [x, y], input=False)) == \
|
|
[False, False, False, True]
|
|
assert list(truth_table(x | y, [x, y], input=False)) == \
|
|
[False, True, True, True]
|
|
assert list(truth_table(x >> y, [x, y], input=False)) == \
|
|
[True, True, False, True]
|
|
assert list(truth_table(And(x, y), [x, y])) == \
|
|
[([0, 0], False), ([0, 1], False), ([1, 0], False), ([1, 1], True)]
|
|
|
|
|
|
def test_issue_8571():
|
|
for t in (S.true, S.false):
|
|
raises(TypeError, lambda: +t)
|
|
raises(TypeError, lambda: -t)
|
|
raises(TypeError, lambda: abs(t))
|
|
# use int(bool(t)) to get 0 or 1
|
|
raises(TypeError, lambda: int(t))
|
|
|
|
for o in [S.Zero, S.One, x]:
|
|
for _ in range(2):
|
|
raises(TypeError, lambda: o + t)
|
|
raises(TypeError, lambda: o - t)
|
|
raises(TypeError, lambda: o % t)
|
|
raises(TypeError, lambda: o*t)
|
|
raises(TypeError, lambda: o/t)
|
|
raises(TypeError, lambda: o**t)
|
|
o, t = t, o # do again in reversed order
|
|
|
|
|
|
def test_expand_relational():
|
|
n = symbols('n', negative=True)
|
|
p, q = symbols('p q', positive=True)
|
|
r = ((n + q*(-n/q + 1))/(q*(-n/q + 1)) < 0)
|
|
assert r is not S.false
|
|
assert r.expand() is S.false
|
|
assert (q > 0).expand() is S.true
|
|
|
|
|
|
def test_issue_12717():
|
|
assert S.true.is_Atom == True
|
|
assert S.false.is_Atom == True
|
|
|
|
|
|
def test_as_Boolean():
|
|
nz = symbols('nz', nonzero=True)
|
|
assert all(as_Boolean(i) is S.true for i in (True, S.true, 1, nz))
|
|
z = symbols('z', zero=True)
|
|
assert all(as_Boolean(i) is S.false for i in (False, S.false, 0, z))
|
|
assert all(as_Boolean(i) == i for i in (x, x < 0))
|
|
for i in (2, S(2), x + 1, []):
|
|
raises(TypeError, lambda: as_Boolean(i))
|
|
|
|
|
|
def test_binary_symbols():
|
|
assert ITE(x < 1, y, z).binary_symbols == {y, z}
|
|
for f in (Eq, Ne):
|
|
assert f(x, 1).binary_symbols == set()
|
|
assert f(x, True).binary_symbols == {x}
|
|
assert f(x, False).binary_symbols == {x}
|
|
assert S.true.binary_symbols == set()
|
|
assert S.false.binary_symbols == set()
|
|
assert x.binary_symbols == {x}
|
|
assert And(x, Eq(y, False), Eq(z, 1)).binary_symbols == {x, y}
|
|
assert Q.prime(x).binary_symbols == set()
|
|
assert Q.lt(x, 1).binary_symbols == set()
|
|
assert Q.is_true(x).binary_symbols == {x}
|
|
assert Q.eq(x, True).binary_symbols == {x}
|
|
assert Q.prime(x).binary_symbols == set()
|
|
|
|
|
|
def test_BooleanFunction_diff():
|
|
assert And(x, y).diff(x) == Piecewise((0, Eq(y, False)), (1, True))
|
|
|
|
|
|
def test_issue_14700():
|
|
A, B, C, D, E, F, G, H = symbols('A B C D E F G H')
|
|
q = ((B & D & H & ~F) | (B & H & ~C & ~D) | (B & H & ~C & ~F) |
|
|
(B & H & ~D & ~G) | (B & H & ~F & ~G) | (C & G & ~B & ~D) |
|
|
(C & G & ~D & ~H) | (C & G & ~F & ~H) | (D & F & H & ~B) |
|
|
(D & F & ~G & ~H) | (B & D & F & ~C & ~H) | (D & E & F & ~B & ~C) |
|
|
(D & F & ~A & ~B & ~C) | (D & F & ~A & ~C & ~H) |
|
|
(A & B & D & F & ~E & ~H))
|
|
soldnf = ((B & D & H & ~F) | (D & F & H & ~B) | (B & H & ~C & ~D) |
|
|
(B & H & ~D & ~G) | (C & G & ~B & ~D) | (C & G & ~D & ~H) |
|
|
(C & G & ~F & ~H) | (D & F & ~G & ~H) | (D & E & F & ~C & ~H) |
|
|
(D & F & ~A & ~C & ~H) | (A & B & D & F & ~E & ~H))
|
|
solcnf = ((B | C | D) & (B | D | G) & (C | D | H) & (C | F | H) &
|
|
(D | G | H) & (F | G | H) & (B | F | ~D | ~H) &
|
|
(~B | ~D | ~F | ~H) & (D | ~B | ~C | ~G | ~H) &
|
|
(A | H | ~C | ~D | ~F | ~G) & (H | ~C | ~D | ~E | ~F | ~G) &
|
|
(B | E | H | ~A | ~D | ~F | ~G))
|
|
assert simplify_logic(q, "dnf") == soldnf
|
|
assert simplify_logic(q, "cnf") == solcnf
|
|
|
|
minterms = [[0, 1, 0, 0], [0, 1, 0, 1], [0, 1, 1, 0], [0, 1, 1, 1],
|
|
[0, 0, 1, 1], [1, 0, 1, 1]]
|
|
dontcares = [[1, 0, 0, 0], [1, 0, 0, 1], [1, 1, 0, 0], [1, 1, 0, 1]]
|
|
assert SOPform([w, x, y, z], minterms) == (x & ~w) | (y & z & ~x)
|
|
# Should not be more complicated with don't cares
|
|
assert SOPform([w, x, y, z], minterms, dontcares) == \
|
|
(x & ~w) | (y & z & ~x)
|
|
|
|
|
|
def test_relational_simplification():
|
|
w, x, y, z = symbols('w x y z', real=True)
|
|
d, e = symbols('d e', real=False)
|
|
# Test all combinations or sign and order
|
|
assert Or(x >= y, x < y).simplify() == S.true
|
|
assert Or(x >= y, y > x).simplify() == S.true
|
|
assert Or(x >= y, -x > -y).simplify() == S.true
|
|
assert Or(x >= y, -y < -x).simplify() == S.true
|
|
assert Or(-x <= -y, x < y).simplify() == S.true
|
|
assert Or(-x <= -y, -x > -y).simplify() == S.true
|
|
assert Or(-x <= -y, y > x).simplify() == S.true
|
|
assert Or(-x <= -y, -y < -x).simplify() == S.true
|
|
assert Or(y <= x, x < y).simplify() == S.true
|
|
assert Or(y <= x, y > x).simplify() == S.true
|
|
assert Or(y <= x, -x > -y).simplify() == S.true
|
|
assert Or(y <= x, -y < -x).simplify() == S.true
|
|
assert Or(-y >= -x, x < y).simplify() == S.true
|
|
assert Or(-y >= -x, y > x).simplify() == S.true
|
|
assert Or(-y >= -x, -x > -y).simplify() == S.true
|
|
assert Or(-y >= -x, -y < -x).simplify() == S.true
|
|
|
|
assert Or(x < y, x >= y).simplify() == S.true
|
|
assert Or(y > x, x >= y).simplify() == S.true
|
|
assert Or(-x > -y, x >= y).simplify() == S.true
|
|
assert Or(-y < -x, x >= y).simplify() == S.true
|
|
assert Or(x < y, -x <= -y).simplify() == S.true
|
|
assert Or(-x > -y, -x <= -y).simplify() == S.true
|
|
assert Or(y > x, -x <= -y).simplify() == S.true
|
|
assert Or(-y < -x, -x <= -y).simplify() == S.true
|
|
assert Or(x < y, y <= x).simplify() == S.true
|
|
assert Or(y > x, y <= x).simplify() == S.true
|
|
assert Or(-x > -y, y <= x).simplify() == S.true
|
|
assert Or(-y < -x, y <= x).simplify() == S.true
|
|
assert Or(x < y, -y >= -x).simplify() == S.true
|
|
assert Or(y > x, -y >= -x).simplify() == S.true
|
|
assert Or(-x > -y, -y >= -x).simplify() == S.true
|
|
assert Or(-y < -x, -y >= -x).simplify() == S.true
|
|
|
|
# Some other tests
|
|
assert Or(x >= y, w < z, x <= y).simplify() == S.true
|
|
assert And(x >= y, x < y).simplify() == S.false
|
|
assert Or(x >= y, Eq(y, x)).simplify() == (x >= y)
|
|
assert And(x >= y, Eq(y, x)).simplify() == Eq(x, y)
|
|
assert And(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y).simplify() == \
|
|
(Eq(x, y) & (x >= 1) & (y >= 5) & (y > z))
|
|
assert Or(Eq(x, y), x >= y, w < y, z < y).simplify() == \
|
|
(x >= y) | (y > z) | (w < y)
|
|
assert And(Eq(x, y), x >= y, w < y, y >= z, z < y).simplify() == \
|
|
Eq(x, y) & (y > z) & (w < y)
|
|
# assert And(Eq(x, y), x >= y, w < y, y >= z, z < y).simplify(relational_minmax=True) == \
|
|
# And(Eq(x, y), y > Max(w, z))
|
|
# assert Or(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y).simplify(relational_minmax=True) == \
|
|
# (Eq(x, y) | (x >= 1) | (y > Min(2, z)))
|
|
assert And(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y).simplify() == \
|
|
(Eq(x, y) & (x >= 1) & (y >= 5) & (y > z))
|
|
assert (Eq(x, y) & Eq(d, e) & (x >= y) & (d >= e)).simplify() == \
|
|
(Eq(x, y) & Eq(d, e) & (d >= e))
|
|
assert And(Eq(x, y), Eq(x, -y)).simplify() == And(Eq(x, 0), Eq(y, 0))
|
|
assert Xor(x >= y, x <= y).simplify() == Ne(x, y)
|
|
assert And(x > 1, x < -1, Eq(x, y)).simplify() == S.false
|
|
# From #16690
|
|
assert And(x >= y, Eq(y, 0)).simplify() == And(x >= 0, Eq(y, 0))
|
|
assert Or(Ne(x, 1), Ne(x, 2)).simplify() == S.true
|
|
assert And(Eq(x, 1), Ne(2, x)).simplify() == Eq(x, 1)
|
|
assert Or(Eq(x, 1), Ne(2, x)).simplify() == Ne(x, 2)
|
|
|
|
def test_issue_8373():
|
|
x = symbols('x', real=True)
|
|
assert Or(x < 1, x > -1).simplify() == S.true
|
|
assert Or(x < 1, x >= 1).simplify() == S.true
|
|
assert And(x < 1, x >= 1).simplify() == S.false
|
|
assert Or(x <= 1, x >= 1).simplify() == S.true
|
|
|
|
|
|
def test_issue_7950():
|
|
x = symbols('x', real=True)
|
|
assert And(Eq(x, 1), Eq(x, 2)).simplify() == S.false
|
|
|
|
|
|
@slow
|
|
def test_relational_simplification_numerically():
|
|
def test_simplification_numerically_function(original, simplified):
|
|
symb = original.free_symbols
|
|
n = len(symb)
|
|
valuelist = list(set(combinations(list(range(-(n-1), n))*n, n)))
|
|
for values in valuelist:
|
|
sublist = dict(zip(symb, values))
|
|
originalvalue = original.subs(sublist)
|
|
simplifiedvalue = simplified.subs(sublist)
|
|
assert originalvalue == simplifiedvalue, "Original: {}\nand"\
|
|
" simplified: {}\ndo not evaluate to the same value for {}"\
|
|
"".format(original, simplified, sublist)
|
|
|
|
w, x, y, z = symbols('w x y z', real=True)
|
|
d, e = symbols('d e', real=False)
|
|
|
|
expressions = (And(Eq(x, y), x >= y, w < y, y >= z, z < y),
|
|
And(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y),
|
|
Or(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y),
|
|
And(x >= y, Eq(y, x)),
|
|
Or(And(Eq(x, y), x >= y, w < y, Or(y >= z, z < y)),
|
|
And(Eq(x, y), x >= 1, 2 < y, y >= -1, z < y)),
|
|
(Eq(x, y) & Eq(d, e) & (x >= y) & (d >= e)),
|
|
)
|
|
|
|
for expression in expressions:
|
|
test_simplification_numerically_function(expression,
|
|
expression.simplify())
|
|
|
|
|
|
def test_relational_simplification_patterns_numerically():
|
|
from sympy.core import Wild
|
|
from sympy.logic.boolalg import _simplify_patterns_and, \
|
|
_simplify_patterns_or, _simplify_patterns_xor
|
|
a = Wild('a')
|
|
b = Wild('b')
|
|
c = Wild('c')
|
|
symb = [a, b, c]
|
|
patternlists = [[And, _simplify_patterns_and()],
|
|
[Or, _simplify_patterns_or()],
|
|
[Xor, _simplify_patterns_xor()]]
|
|
valuelist = list(set(combinations(list(range(-2, 3))*3, 3)))
|
|
# Skip combinations of +/-2 and 0, except for all 0
|
|
valuelist = [v for v in valuelist if any([w % 2 for w in v]) or not any(v)]
|
|
for func, patternlist in patternlists:
|
|
for pattern in patternlist:
|
|
original = func(*pattern[0].args)
|
|
simplified = pattern[1]
|
|
for values in valuelist:
|
|
sublist = dict(zip(symb, values))
|
|
originalvalue = original.xreplace(sublist)
|
|
simplifiedvalue = simplified.xreplace(sublist)
|
|
assert originalvalue == simplifiedvalue, "Original: {}\nand"\
|
|
" simplified: {}\ndo not evaluate to the same value for"\
|
|
"{}".format(pattern[0], simplified, sublist)
|
|
|
|
|
|
def test_issue_16803():
|
|
n = symbols('n')
|
|
# No simplification done, but should not raise an exception
|
|
assert ((n > 3) | (n < 0) | ((n > 0) & (n < 3))).simplify() == \
|
|
(n > 3) | (n < 0) | ((n > 0) & (n < 3))
|
|
|
|
|
|
def test_issue_17530():
|
|
r = {x: oo, y: oo}
|
|
assert Or(x + y > 0, x - y < 0).subs(r)
|
|
assert not And(x + y < 0, x - y < 0).subs(r)
|
|
raises(TypeError, lambda: Or(x + y < 0, x - y < 0).subs(r))
|
|
raises(TypeError, lambda: And(x + y > 0, x - y < 0).subs(r))
|
|
raises(TypeError, lambda: And(x + y > 0, x - y < 0).subs(r))
|
|
|
|
|
|
def test_anf_coeffs():
|
|
assert anf_coeffs([1, 0]) == [1, 1]
|
|
assert anf_coeffs([0, 0, 0, 1]) == [0, 0, 0, 1]
|
|
assert anf_coeffs([0, 1, 1, 1]) == [0, 1, 1, 1]
|
|
assert anf_coeffs([1, 1, 1, 0]) == [1, 0, 0, 1]
|
|
assert anf_coeffs([1, 0, 0, 0]) == [1, 1, 1, 1]
|
|
assert anf_coeffs([1, 0, 0, 1]) == [1, 1, 1, 0]
|
|
assert anf_coeffs([1, 1, 0, 1]) == [1, 0, 1, 1]
|
|
|
|
|
|
def test_ANFform():
|
|
x, y = symbols('x,y')
|
|
assert ANFform([x], [1, 1]) == True
|
|
assert ANFform([x], [0, 0]) == False
|
|
assert ANFform([x], [1, 0]) == Xor(x, True, remove_true=False)
|
|
assert ANFform([x, y], [1, 1, 1, 0]) == \
|
|
Xor(True, And(x, y), remove_true=False)
|
|
|
|
|
|
def test_bool_minterm():
|
|
x, y = symbols('x,y')
|
|
assert bool_minterm(3, [x, y]) == And(x, y)
|
|
assert bool_minterm([1, 0], [x, y]) == And(Not(y), x)
|
|
|
|
|
|
def test_bool_maxterm():
|
|
x, y = symbols('x,y')
|
|
assert bool_maxterm(2, [x, y]) == Or(Not(x), y)
|
|
assert bool_maxterm([0, 1], [x, y]) == Or(Not(y), x)
|
|
|
|
|
|
def test_bool_monomial():
|
|
x, y = symbols('x,y')
|
|
assert bool_monomial(1, [x, y]) == y
|
|
assert bool_monomial([1, 1], [x, y]) == And(x, y)
|
|
|
|
|
|
def test_check_pair():
|
|
assert _check_pair([0, 1, 0], [0, 1, 1]) == 2
|
|
assert _check_pair([0, 1, 0], [1, 1, 1]) == -1
|
|
|
|
|
|
def test_issue_19114():
|
|
expr = (B & C) | (A & ~C) | (~A & ~B)
|
|
# Expression is minimal, but there are multiple minimal forms possible
|
|
res1 = (A & B) | (C & ~A) | (~B & ~C)
|
|
result = to_dnf(expr, simplify=True)
|
|
assert result in (expr, res1)
|
|
|
|
|
|
def test_issue_20870():
|
|
result = SOPform([a, b, c, d], [1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 14, 15])
|
|
expected = ((d & ~b) | (a & b & c) | (a & ~c & ~d) |
|
|
(b & ~a & ~c) | (c & ~a & ~d))
|
|
assert result == expected
|
|
|
|
|
|
def test_convert_to_varsSOP():
|
|
assert _convert_to_varsSOP([0, 1, 0], [x, y, z]) == And(Not(x), y, Not(z))
|
|
assert _convert_to_varsSOP([3, 1, 0], [x, y, z]) == And(y, Not(z))
|
|
|
|
|
|
def test_convert_to_varsPOS():
|
|
assert _convert_to_varsPOS([0, 1, 0], [x, y, z]) == Or(x, Not(y), z)
|
|
assert _convert_to_varsPOS([3, 1, 0], [x, y, z]) == Or(Not(y), z)
|
|
|
|
|
|
def test_gateinputcount():
|
|
a, b, c, d, e = symbols('a:e')
|
|
assert gateinputcount(And(a, b)) == 2
|
|
assert gateinputcount(a | b & c & d ^ (e | a)) == 9
|
|
assert gateinputcount(And(a, True)) == 0
|
|
raises(TypeError, lambda: gateinputcount(a*b))
|
|
|
|
|
|
def test_refine():
|
|
# relational
|
|
assert not refine(x < 0, ~(x < 0))
|
|
assert refine(x < 0, (x < 0))
|
|
assert refine(x < 0, (0 > x)) is S.true
|
|
assert refine(x < 0, (y < 0)) == (x < 0)
|
|
assert not refine(x <= 0, ~(x <= 0))
|
|
assert refine(x <= 0, (x <= 0))
|
|
assert refine(x <= 0, (0 >= x)) is S.true
|
|
assert refine(x <= 0, (y <= 0)) == (x <= 0)
|
|
assert not refine(x > 0, ~(x > 0))
|
|
assert refine(x > 0, (x > 0))
|
|
assert refine(x > 0, (0 < x)) is S.true
|
|
assert refine(x > 0, (y > 0)) == (x > 0)
|
|
assert not refine(x >= 0, ~(x >= 0))
|
|
assert refine(x >= 0, (x >= 0))
|
|
assert refine(x >= 0, (0 <= x)) is S.true
|
|
assert refine(x >= 0, (y >= 0)) == (x >= 0)
|
|
assert not refine(Eq(x, 0), ~(Eq(x, 0)))
|
|
assert refine(Eq(x, 0), (Eq(x, 0)))
|
|
assert refine(Eq(x, 0), (Eq(0, x))) is S.true
|
|
assert refine(Eq(x, 0), (Eq(y, 0))) == Eq(x, 0)
|
|
assert not refine(Ne(x, 0), ~(Ne(x, 0)))
|
|
assert refine(Ne(x, 0), (Ne(0, x))) is S.true
|
|
assert refine(Ne(x, 0), (Ne(x, 0)))
|
|
assert refine(Ne(x, 0), (Ne(y, 0))) == (Ne(x, 0))
|
|
|
|
# boolean functions
|
|
assert refine(And(x > 0, y > 0), (x > 0)) == (y > 0)
|
|
assert refine(And(x > 0, y > 0), (x > 0) & (y > 0)) is S.true
|
|
|
|
# predicates
|
|
assert refine(Q.positive(x), Q.positive(x)) is S.true
|
|
assert refine(Q.positive(x), Q.negative(x)) is S.false
|
|
assert refine(Q.positive(x), Q.real(x)) == Q.positive(x)
|
|
|
|
|
|
def test_relational_threeterm_simplification_patterns_numerically():
|
|
from sympy.core import Wild
|
|
from sympy.logic.boolalg import _simplify_patterns_and3
|
|
a = Wild('a')
|
|
b = Wild('b')
|
|
c = Wild('c')
|
|
symb = [a, b, c]
|
|
patternlists = [[And, _simplify_patterns_and3()]]
|
|
valuelist = list(set(combinations(list(range(-2, 3))*3, 3)))
|
|
# Skip combinations of +/-2 and 0, except for all 0
|
|
valuelist = [v for v in valuelist if any([w % 2 for w in v]) or not any(v)]
|
|
for func, patternlist in patternlists:
|
|
for pattern in patternlist:
|
|
original = func(*pattern[0].args)
|
|
simplified = pattern[1]
|
|
for values in valuelist:
|
|
sublist = dict(zip(symb, values))
|
|
originalvalue = original.xreplace(sublist)
|
|
simplifiedvalue = simplified.xreplace(sublist)
|
|
assert originalvalue == simplifiedvalue, "Original: {}\nand"\
|
|
" simplified: {}\ndo not evaluate to the same value for"\
|
|
"{}".format(pattern[0], simplified, sublist)
|