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_simplification(): """ 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]] from sympy.abc import w, x, y, z assert SOPform('xyz', set1) == Or(And(Not(x), z), And(Not(z), x)) assert Not(SOPform('xyz', set2)) == And(Or(Not(x), Not(z)), Or(x, z)) assert POSform('xyz', set1 + set2) is True assert SOPform('xyz', 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('wxyz', minterms, dontcares) == Or(And(Not(w), z), And(y, z))) assert POSform('wxyz', minterms, dontcares) == And(Or(Not(w), y), z) # test simplification ans = And(A, Or(B, C)) assert simplify_logic('A & (B | C)') == ans assert simplify_logic('(A & B) | (A & C)') == ans # check input ans = SOPform('xy', [[1, 0]]) assert SOPform([x, y], [[1, 0]]) == ans assert POSform(['x', 'y'], [[1, 0]]) == ans
def test_simplification(): """ 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]] from sympy.abc import w, x, y, z assert SOPform('xyz', set1) == Or(And(Not(x), z), And(Not(z), x)) assert Not(SOPform('xyz', set2)) == Not(Or(And(Not(x), Not(z)), And(x, z))) assert POSform('xyz', set1 + set2) is true assert SOPform('xyz', 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('wxyz', minterms, dontcares) == Or(And(Not(w), z), And(y, z))) assert POSform('wxyz', minterms, dontcares) == And(Or(Not(w), y), z) # 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)) == 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)) e = And(A, x**2 - x) assert simplify_logic(e) == And(A, x*(x - 1)) assert simplify_logic(e, deep=False) == e # check input ans = SOPform('xy', [[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)') == sympify('And(A, Or(B, C))') assert simplify(And(x, Not(x))) == False assert simplify(Or(x, Not(x))) == True
def test_simplification(): """ 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(Not(w), z), And(y, z))) assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z) # 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 # 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
def __eq__(self, other): """Tests this graph for equality with ``other``. Two graphs are equal if they contain the same nodes, edges, and formulas at each node. This operation can be expensive, since it checks whether formulas are equivalent by first simplifying the formulas, and then testing the simplified representations for equivalence. Parameters ---------- other : An object to test for equality with the current Graph Returns ------- ``True`` if ``self`` and ``other`` represent the same graph and scenario; ``False`` otherwise. Examples -------- Create the first graph: >>> G1 = eb.path_graph(4) >>> G1.add_formula(0, 'p & q') >>> G1.add_formula(1, 'q | r') Create the second graph: >>> G2 = eb.path_graph(4) >>> G2.add_formula(0, 'p & q') These graphs are not equal: >>> G1 == G2 False But we can add a formula to G2 to make it equal to G1: >>> G2.add_formula(1, 'q | r') >>> G1 == G2 True """ if not isinstance(other, self.__class__): return False if set(self.nodes()) != set(other.nodes()): return False if set(self.edges()) != set(other.edges()): return False for node in self.nodes(): try: if not simplify_logic(self.formula_conj(node)).equals(simplify_logic(other.formula_conj(node))): return False except Exception: return False return True
def get_condition_from_logic_expression(logic_exp, conditions_map): #return logic_exp if not isinstance(logic_exp, Symbol) and not isinstance(logic_exp, Not) and not isinstance(logic_exp, Or) \ and not isinstance(logic_exp, And) and not isinstance(logic_exp, LocalVariable) and not logic_exp == true: return logic_exp logic_exp = simplify_logic(logic_exp) #return logic_exp if isinstance(logic_exp, Symbol): return conditions_map[logic_exp] elif isinstance(logic_exp, Not): return get_negated_condition( get_condition_from_logic_expression(logic_exp.args[0], conditions_map)) elif isinstance(logic_exp, Or): return ORExpression([ get_condition_from_logic_expression(arg, conditions_map) for arg in logic_exp.args ], is_condition=True) elif isinstance(logic_exp, And): return ANDExpression([ get_condition_from_logic_expression(arg, conditions_map) for arg in logic_exp.args ], is_condition=True) elif logic_exp in [True, true]: return NumericConstant(1) elif isinstance(logic_exp, LocalVariable): return logic_exp else: assert False, 'unrecognised logic expression{0}'.format(logic_exp)
def reduces_to_true(clauses): """ >>> reduces_to_true([('True',), ('a',)]) True >>> reduces_to_true([('r',), ('~r',)]) True >>> reduces_to_true([('r',), ('~a',)]) False >>> reduces_to_true([('r', 'b'), ('~r',)]) False >>> reduces_to_true([('r','b'), ('~r','~b')]) False >>> reduces_to_true(['a b'.split(), '~a ~b'.split(), '~a b'.split(), 'a ~b'.split()]) True >>> reduces_to_true(['a b'.split(), '~a ~b'.split(), '~a b'.split(), 'a ~b'.split()]) True """ clauses = list(clauses) expr = false for c in clauses: new_c = true for l in c: v = l.replace('~', '') if v == 'True' or v == 'False': s = sympify(v) else: s = Symbol(v) new_c &= (~s if '~' in l else s) expr |= new_c return simplify_logic(expr) == true
def test_simplification(): """ 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]] from sympy.abc import w, x, y, z assert SOPform("xyz", set1) == Or(And(Not(x), z), And(Not(z), x)) assert Not(SOPform("xyz", set2)) == And(Or(Not(x), Not(z)), Or(x, z)) assert POSform("xyz", set1 + set2) is True assert SOPform("xyz", 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("wxyz", minterms, dontcares) == Or(And(Not(w), z), And(y, z)) assert POSform("wxyz", minterms, dontcares) == And(Or(Not(w), y), z) # test simplification ans = And(A, Or(B, C)) assert simplify_logic("A & (B | C)") == ans assert simplify_logic("(A & B) | (A & C)") == ans # check input ans = SOPform("xy", [[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)") == sympify("And(A, Or(B, C))") assert simplify(And(x, Not(x))) == False assert simplify(Or(x, Not(x))) == True
def test_simplification(): """ 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]] from sympy.abc import w, x, y, z assert SOPform('xyz', set1) == Or(And(Not(x), z), And(Not(z), x)) assert Not(SOPform('xyz', set2)) == And(Or(Not(x), Not(z)), Or(x, z)) assert POSform('xyz', set1 + set2) is True assert SOPform('xyz', 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('wxyz', minterms, dontcares) == Or(And(Not(w), z), And(y, z))) assert POSform('wxyz', minterms, dontcares) == And(Or(Not(w), y), z) # test simplification ans = And(A, Or(B, C)) assert simplify_logic('A & (B | C)') == ans assert simplify_logic('(A & B) | (A & C)') == ans # check input ans = SOPform('xy', [[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
def generate_training_examples(statement_gen, branching_f, cut_off_depth): initial_stat = statement_gen.generate_complete_expression() #initial_stat = Or(Implies(A, B), Implies(B, Implies(B, A))) print('Stat is initially {}'.format(initial_stat)) print('which has {} terms'.format(num_terms(initial_stat))) simplifed_stat = simplify_logic(initial_stat) print('Can be simplified to {}'.format(simplifed_stat)) min_final_complexity = COMPLEXITY_FUNC(simplifed_stat) print() t0 = time.perf_counter() training_examples = [[initial_stat]] include = False for i in range(50): if i % 5 == 0: print('i={}'.format(i)) best = best_manipulations_search(initial_stat, branching_f, cut_off_depth) print(best) #if COMPLEXITY_FUNC(best[-1]) <= COMPLEXITY_FUNC(best[0]) + 1: if best[-1] != best[0]: if training_examples[-1][-1] == initial_stat: training_examples[-1].extend(best[1:]) else: training_examples.append( best) # is this ever happening under my current set up? if COMPLEXITY_FUNC(best[-1]) <= min_final_complexity: include = True break initial_stat = best[-1] # what to do if this initial_stat is as simple as it's going to get? #else: #print('best[-1]: {} \n complexity: {} \n best[0]: {} \n complexity: {}'.format(best[-1], COMPLEXITY_FUNC(best[-1]), best[0], COMPLEXITY_FUNC(best[0]))) # perhaps we should increase branching_f and start again? # or introduce some more randomness in where the laws are applied? # or increase the double negation factor to try and hit the goldmine? # or maybe my algorithm is so good that things that drop out here # are basically as simple as they can get??! t1 = time.perf_counter() # Printing the generated examples print() print('Printing the generated examples...') for ex in training_examples: for stat in ex: print(stat) if isinstance(stat, BooleanFunction): print('Complexity = {}'.format(COMPLEXITY_FUNC(stat))) print() print('That took {:.1f}s'.format(t1 - t0)) if include: export(training_examples)
def conditions_equal(cond1, cond2): if cond1 == cond2: return True symbols_1 = get_symbols(cond1) symbols_2 = get_symbols(cond2) if symbols_1.symmetric_difference(symbols_2): return False cond1_simplified = simplify_logic(cond1) cond2_simplified = simplify_logic(cond2) if type(cond1_simplified) != type(cond2_simplified): return False elif len(cond1_simplified.args) != len(cond2_simplified.args): return False cond_mapping = bool_map(cond1, cond2) if type(cond_mapping) != bool: for k, v in cond_mapping[1].items(): if k != v: return False return True return False
def piecewise_fold(expr): """ Takes an expression containing a piecewise function and returns the expression in piecewise form. In addition, any ITE conditions are rewritten in negation normal form and simplified. Examples ======== >>> from sympy import Piecewise, piecewise_fold, sympify as S >>> from sympy.abc import x >>> p = Piecewise((x, x < 1), (1, S(1) <= x)) >>> piecewise_fold(x*p) Piecewise((x**2, x < 1), (x, 1 <= x)) See Also ======== Piecewise """ if not isinstance(expr, Basic) or not expr.has(Piecewise): return expr new_args = [] if isinstance(expr, (ExprCondPair, Piecewise)): for e, c in expr.args: if not isinstance(e, Piecewise): e = piecewise_fold(e) # we don't keep Piecewise in condition because # it has to be checked to see that it's complete # and we convert it to ITE at that time assert not c.has(Piecewise) # pragma: no cover if isinstance(c, ITE): c = c.to_nnf() c = simplify_logic(c, form='cnf') if isinstance(e, Piecewise): new_args.extend([(piecewise_fold(ei), And(ci, c)) for ei, ci in e.args]) else: new_args.append((e, c)) else: from sympy.utilities.iterables import cartes folded = list(map(piecewise_fold, expr.args)) for ec in cartes(*[(i.args if isinstance(i, Piecewise) else [(i, true)]) for i in folded]): e, c = zip(*ec) new_args.append((expr.func(*e), And(*c))) return Piecewise(*new_args)
def piecewise_fold(expr): """ Takes an expression containing a piecewise function and returns the expression in piecewise form. In addition, any ITE conditions are rewritten in negation normal form and simplified. Examples ======== >>> from sympy import Piecewise, piecewise_fold, sympify as S >>> from sympy.abc import x >>> p = Piecewise((x, x < 1), (1, S(1) <= x)) >>> piecewise_fold(x*p) Piecewise((x**2, x < 1), (x, 1 <= x)) See Also ======== Piecewise """ if not isinstance(expr, Basic) or not expr.has(Piecewise): return expr new_args = [] if isinstance(expr, (ExprCondPair, Piecewise)): for e, c in expr.args: if not isinstance(e, Piecewise): e = piecewise_fold(e) # we don't keep Piecewise in condition because # it has to be checked to see that it's complete # and we convert it to ITE at that time assert not c.has(Piecewise) # pragma: no cover if isinstance(c, ITE): c = c.to_nnf() c = simplify_logic(c, form='cnf') if isinstance(e, Piecewise): new_args.extend([(piecewise_fold(ei), And(ci, c)) for ei, ci in e.args]) else: new_args.append((e, c)) else: from sympy.utilities.iterables import cartes folded = list(map(piecewise_fold, expr.args)) for ec in cartes(*[ (i.args if isinstance(i, Piecewise) else [(i, true)]) for i in folded]): e, c = zip(*ec) new_args.append((expr.func(*e), And(*c))) return Piecewise(*new_args)
def simplify_boolean(expr, form="dnf", op=(Union, Intersection, AbsoluteComplement, Complement)): """ >>> from sympy import * >>> from symplus.strplus import init_mprinting >>> init_mprinting() >>> A = Set(symbols("A")) >>> B = Set(symbols("B")) >>> C = Set(symbols("C")) >>> simplify_boolean(B & (A | C)) Set(A) n Set(B) u Set(B) n Set(C) >>> simplify_boolean((A & B) | (A - B) | (B & C) | (C - B)) Set(A) u Set(C) >>> simplify_boolean(AbsoluteComplement(A+B+C) | (C-A-B)) -(Set(A)) n -(Set(B)) """ exprs = {} def expr2bool(expr): if isinstance(expr, op[0]): return Or(*map(expr2bool, expr.args)) elif isinstance(expr, op[1]): return And(*map(expr2bool, expr.args)) elif isinstance(expr, op[2]): return Not(expr2bool(expr.args[0])) elif len(op) >= 4 and isinstance(expr, op[3]): return And(expr2bool(expr.args[0]), Not(expr2bool(expr.args[1]))) else: for b, e in exprs.items(): if e == expr: return b else: b = Dummy("b") exprs[b] = expr return b def bool2expr(b): if isinstance(b, Or): return op[0](*map(bool2expr, b.args), evaluate=False) elif isinstance(b, And): return op[1](*map(bool2expr, b.args), evaluate=False) elif isinstance(b, Not): return op[2](bool2expr(b.args[0]), evaluate=False) else: return exprs[b] return bool2expr(simplify_logic(expr2bool(expr), form="dnf", deep=False))
def simplify_edge_labels(edge_labels: dict) -> dict: simplified_edge_labels = dict() sig_by_name = dict() for (src, dst), labels in edge_labels.items(): labels_as_exprs = [_to_expr(l, sig_by_name) for l in labels] labels_as_dnf = sympy.false for le in labels_as_exprs: labels_as_dnf |= le assert labels_as_dnf != sympy.false simplified_expr = simplify_logic(labels_as_dnf, form='dnf') clauses = _clauses(simplified_expr) simplified_labels = [_to_label(e, sig_by_name) for e in clauses] simplified_edge_labels[(src, dst)] = simplified_labels return simplified_edge_labels
def simplify_edge_labels(edge_labels:dict) -> dict: simplified_edge_labels = dict() sig_by_name = dict() for (src, dst), labels in edge_labels.items(): labels_as_exprs = [_to_expr(l, sig_by_name) for l in labels] labels_as_dnf = sympy.false for le in labels_as_exprs: labels_as_dnf |= le assert labels_as_dnf != sympy.false simplified_expr = simplify_logic(labels_as_dnf, form='dnf') clauses = _clauses(simplified_expr) simplified_labels = [_to_label(e, sig_by_name) for e in clauses] simplified_edge_labels[(src, dst)] = simplified_labels return simplified_edge_labels
def test_simplification(): """ 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(Not(w), z), And(y, z))) 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(Not(w), z), And(y, z))) 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(Not(w), z), And(y, z))) 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(Not(w), z), And(y, z))) 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')) # 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 # 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 logicrelsimp(expr, form='dnf', deep=True): """ logically simplify relations using totality (WARNING: it is unstable) >>> from sympy import * >>> from symplus.strplus import init_mprinting >>> init_mprinting() >>> x, y, z = symbols('x y z') >>> logicrelsimp((x>0) >> ((x<=0)&(y<0))) x =< 0 >>> logicrelsimp((x>0) >> (x>=0)) True >>> logicrelsimp((x<0) & (x>0)) False >>> logicrelsimp(((x<0) | (y>0)) & ((x>0) | (y<0))) (x < 0) /\ (y < 0) \/ (x > 0) /\ (y > 0) >>> logicrelsimp(((x<0) & (y>0)) | ((x>0) & (y<0))) (x < 0) /\ (y > 0) \/ (x > 0) /\ (y < 0) """ from sympy.core.symbol import Wild from sympy.core import sympify from sympy.logic.boolalg import (SOPform, POSform, to_nnf, _find_predicates, simplify_logic) Nt = lambda x: Not(x, evaluate=False) if form not in ('cnf', 'dnf'): raise ValueError("form can be cnf or dnf only") expr = sympify(expr) if not isinstance(expr, BooleanFunction): return expr # canonicalize relations expr = expr.replace(lambda rel: isinstance(rel, Rel), lambda rel: canonicalize_polyeq(rel)) # to nnf w = Wild('w') expr = to_nnf(expr) expr = expr.replace(Not(w), lambda w: Not(w, evaluate=True)) if is_simplerel(expr): # standardize relation expr = expr.replace(Ne(w,0), Nt(Eq(w,0))) expr = expr.replace(Ge(w,0), Nt(Lt(w,0))) expr = expr.replace(Le(w,0), Nt(Gt(w,0))) expr = simplify_logic(expr, form, deep) return expr else: # standardize relation expr = expr.replace(Ne(w,0), Or(Gt(w,0), Lt(w,0))) expr = expr.replace(Ge(w,0), Or(Gt(w,0), Eq(w,0))) expr = expr.replace(Le(w,0), Or(Lt(w,0), Eq(w,0))) # make totality variables = _find_predicates(expr) relations = (v for v in variables if isinstance(v, Rel) and v.args[1] == 0) totalities = [] for a in set(rel.args[0] for rel in relations): totalities.append( Or(And(Gt(a,0), Nt(Eq(a,0)), Nt(Lt(a,0))), And(Nt(Gt(a,0)), Eq(a,0), Nt(Lt(a,0))), And(Nt(Gt(a,0)), Nt(Eq(a,0)), Lt(a,0)))) totality = And(*totalities) # make truth table, don't care table truthtable = [] dontcares = [] for t in product([0, 1], repeat=len(variables)): t = list(t) if totality.xreplace(dict(zip(variables, t))) == False: dontcares.append(t) elif expr.xreplace(dict(zip(variables, t))) == True: truthtable.append(t) if deep: variables = [simplify(v) for v in variables] if form == 'dnf': expr = SOPform(variables, truthtable, dontcares) elif form == 'cnf': expr = POSform(variables, truthtable, dontcares) return expr
def piecewise_fold(expr): """ Takes an expression containing a piecewise function and returns the expression in piecewise form. In addition, any ITE conditions are rewritten in negation normal form and simplified. Examples ======== >>> from sympy import Piecewise, piecewise_fold, sympify as S >>> from sympy.abc import x >>> p = Piecewise((x, x < 1), (1, S(1) <= x)) >>> piecewise_fold(x*p) Piecewise((x**2, x < 1), (x, True)) See Also ======== Piecewise """ if not isinstance(expr, Basic) or not expr.has(Piecewise): return expr new_args = [] if isinstance(expr, (ExprCondPair, Piecewise)): for e, c in expr.args: if not isinstance(e, Piecewise): e = piecewise_fold(e) # we don't keep Piecewise in condition because # it has to be checked to see that it's complete # and we convert it to ITE at that time assert not c.has(Piecewise) # pragma: no cover if isinstance(c, ITE): c = c.to_nnf() c = simplify_logic(c, form='cnf') if isinstance(e, Piecewise): new_args.extend([(piecewise_fold(ei), And(ci, c)) for ei, ci in e.args]) else: new_args.append((e, c)) else: from sympy.utilities.iterables import cartes, sift, common_prefix # Given # P1 = Piecewise((e11, c1), (e12, c2), A) # P2 = Piecewise((e21, c1), (e22, c2), B) # ... # the folding of f(P1, P2) is trivially # Piecewise( # (f(e11, e21), c1), # (f(e12, e22), c2), # (f(Piecewise(A), Piecewise(B)), True)) # Certain objects end up rewriting themselves as thus, so # we do that grouping before the more generic folding. # The following applies this idea when f = Add or f = Mul # (and the expression is commutative). if expr.is_Add or expr.is_Mul and expr.is_commutative: p, args = sift(expr.args, lambda x: x.is_Piecewise, binary=True) pc = sift(p, lambda x: x.args[0].cond) for c in pc: if len(pc[c]) > 1: pargs = [list(i.args) for i in pc[c]] # the first one is the same; there may be more com = common_prefix(*[ [i.cond for i in j] for j in pargs]) n = len(com) collected = [] for i in range(n): collected.append(( expr.func(*[ai[i].expr for ai in pargs]), com[i])) remains = [] for a in pargs: if n == len(a): # no more args continue if a[n].cond == True: # no longer Piecewise remains.append(a[n].expr) else: # restore the remaining Piecewise remains.append( Piecewise(*a[n:], evaluate=False)) if remains: collected.append((expr.func(*remains), True)) args.append(Piecewise(*collected, evaluate=False)) continue args.extend(pc[c]) else: args = expr.args # fold folded = list(map(piecewise_fold, args)) for ec in cartes(*[ (i.args if isinstance(i, Piecewise) else [(i, true)]) for i in folded]): e, c = zip(*ec) new_args.append((expr.func(*e), And(*c))) return Piecewise(*new_args)
def add_dnf_clause(self, expr): return simplify_logic(expr, form='cnf', deep=True, force=True).args
def add_dnf_clause(self, expr): e = simplify_logic(expr, form='cnf',deep=True,force=True).args self.clauses += e return len(e)
def has_compound_trivial_condition(condition_list): compound_condition = false for c in condition_list: compound_condition = Or(compound_condition, c) return is_trivial_condition(simplify_logic(compound_condition))
from sympy import * from sympy.logic.boolalg import bool_equal, simplify_logic a, b, c, d, e = symbols("a b c d e") f = (b & ~a) | (a & ~b) g = (a | b) & ~(a & b) print(f) print(g) print(bool_equal(f, g)) print f = (~(a | b) & ~(c | d | e)) | ~(a | b) print(f) print(simplify_logic(f)) print f = (a | b) & (d | ~b) & (d | a) print(f) print(simplify_logic(f)) print
def piecewise_fold(expr): """ Takes an expression containing a piecewise function and returns the expression in piecewise form. In addition, any ITE conditions are rewritten in negation normal form and simplified. Examples ======== >>> from sympy import Piecewise, piecewise_fold, sympify as S >>> from sympy.abc import x >>> p = Piecewise((x, x < 1), (1, S(1) <= x)) >>> piecewise_fold(x*p) Piecewise((x**2, x < 1), (x, True)) See Also ======== Piecewise """ if not isinstance(expr, Basic) or not expr.has(Piecewise): return expr new_args = [] if isinstance(expr, (ExprCondPair, Piecewise)): for e, c in expr.args: if not isinstance(e, Piecewise): e = piecewise_fold(e) # we don't keep Piecewise in condition because # it has to be checked to see that it's complete # and we convert it to ITE at that time assert not c.has(Piecewise) # pragma: no cover if isinstance(c, ITE): c = c.to_nnf() c = simplify_logic(c, form='cnf') if isinstance(e, Piecewise): new_args.extend([(piecewise_fold(ei), And(ci, c)) for ei, ci in e.args]) else: new_args.append((e, c)) else: from sympy.utilities.iterables import cartes, sift, common_prefix # Given # P1 = Piecewise((e11, c1), (e12, c2), A) # P2 = Piecewise((e21, c1), (e22, c2), B) # ... # the folding of f(P1, P2) is trivially # Piecewise( # (f(e11, e21), c1), # (f(e12, e22), c2), # (f(Piecewise(A), Piecewise(B)), True)) # Certain objects end up rewriting themselves as thus, so # we do that grouping before the more generic folding. # The following applies this idea when f = Add or f = Mul # (and the expression is commutative). if expr.is_Add or expr.is_Mul and expr.is_commutative: p, args = sift(expr.args, lambda x: x.is_Piecewise, binary=True) pc = sift(p, lambda x: tuple([c for e, c in x.args])) for c in list(ordered(pc)): if len(pc[c]) > 1: pargs = [list(i.args) for i in pc[c]] # the first one is the same; there may be more com = common_prefix(*[[i.cond for i in j] for j in pargs]) n = len(com) collected = [] for i in range(n): collected.append( (expr.func(*[ai[i].expr for ai in pargs]), com[i])) remains = [] for a in pargs: if n == len(a): # no more args continue if a[n].cond == True: # no longer Piecewise remains.append(a[n].expr) else: # restore the remaining Piecewise remains.append(Piecewise(*a[n:], evaluate=False)) if remains: collected.append((expr.func(*remains), True)) args.append(Piecewise(*collected, evaluate=False)) continue args.extend(pc[c]) else: args = expr.args # fold folded = list(map(piecewise_fold, args)) for ec in cartes(*[(i.args if isinstance(i, Piecewise) else [(i, true)]) for i in folded]): e, c = zip(*ec) new_args.append((expr.func(*e), And(*c))) return Piecewise(*new_args)
def print_cond(cond): """ Problem having an ITE in the cond. """ if cond.has(ITE): return self._print(simplify_logic(cond)) else: return self._print(cond)
def test_simplification(): """ 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(Not(w), z), And(y, z))) 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(Not(w), z), And(y, z))) 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(Not(w), z), And(y, z))) 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 # 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))