def clauses(variables): length = len(variables) (first, rest, last) = (variables[0], variables[1:-1], variables[-1]) yield expr.Or(~first, a(1)) yield expr.Or(~last, ~a(length - 1)) for (i, x) in zip(range(2, length), rest): yield expr.Or(~x, a(i)) yield expr.Or(~a(i - 1), a(i)) yield expr.Or(~x, ~a(i - 1))
def _assert_positive_path(self, switch_var=None, position_var=None): switch_var = self._active_switch if switch_var is None else switch_var position_var = self._position_reachable if position_var is None \ else position_var if self.m == 1 or self.n == 1: upper = self._upper_path_bound() for i in range(1, self.m + 1): for j in range(1, self.n + 1): yield expr.Implies(position_var(i, j, upper), switch_var(i, j)).to_cnf() if self.n == 1: for i in range(1, self.m): yield expr.Implies(position_var(i + 1, 1, upper), position_var(i, 1, upper)).to_cnf() else: for i in range(1, self.m + 1): for j in range(1, self.n + 1): reachable = position_var(i, j, 0) if i == 1: yield reachable else: yield ~reachable for rnd in range(1, self._upper_path_bound() + 1): for i in range(1, self.m + 1): for j in range(1, self.n + 1): reachable = position_var(i, j, rnd) elements = [position_var(i_, j_, rnd - 1) & \ switch_var(i_, j_) for (i_, j_) in self._adjacent_4(i, j)] elements.append(position_var(i, j, rnd - 1)) yield expr.Implies(reachable, expr.Or(*elements)).to_cnf()
def test_not_at_most_one(self): self.function = expr.And(self.pos, expr.exprvar("b"), ~expr.Or(*self.neg)) cardinality = constraint.at_most_one(self.function.support) sat = expr.And(self.function, *cardinality).to_cnf().satisfy_one() self.assertIsNone(sat)
def test_at_most_one_zero(self): self.function = ~expr.Or(*self.neg) cardinality = constraint.at_most_one(self.function.support) sat = expr.And(self.function, *cardinality).to_cnf().satisfy_one() self.assertIsNotNone(sat)
def at_least_one(inputs, equivalent=None): assert inputs, "inputs must not be empty" constraint = expr.Or(*inputs) if equivalent is None: yield constraint else: yield expr.Implies(equivalent, constraint).to_cnf() yield expr.Implies(constraint, equivalent).to_cnf()
def _assert_lattice_on_negative_path(self, assignment, path_var): for i in range(1, self.m + 1): for j in range(1, self.n + 1): elements = list( self._literal_at_position_is(i, j, inp) for inp in self._input_literals() if inp.compose(assignment).simplify().is_zero()) assert elements, "list of literal variables must not be empty" yield expr.Implies(path_var(i, j), expr.Or(*elements)).to_cnf()
def test_not_equals_one_not_equivalent(self): self.function = ~expr.Or(*self.neg) equals = expr.exprvar("equals") cardinality = constraint.equals_one(self.function.support, ~equals) sat = expr.And(self.function, equals, *cardinality).to_cnf().satisfy_one() self.assertIsNotNone(sat) self.assertEqual(sat.get(equals), 1)
def test_not_at_least_one_not_equivalent(self): self.function = ~expr.Or(*self.neg) at_least = expr.exprvar("at_least") cardinality = constraint.at_least_one(self.function.support, ~at_least) sat = expr.And(self.function, at_least, *cardinality).to_cnf().satisfy_one() self.assertIsNotNone(sat) self.assertEqual(sat.get(at_least), 1)
def recurse(expression): if expression.ASTOP == "or": return expr.And(*(recurse(e) for e in expression.xs)) if expression.ASTOP == "and": return expr.Or(*(recurse(e) for e in expression.xs)) elif expression.ASTOP == "lit": return expression elif expression.is_one() or expression.is_zero(): return ~expression else: raise NotImplementedError(str(expression))
def _assert_lattice_on_negative_path(self): def _set(i, j, inp): return self._literal_at_position_is(i, j, inp) & ~inp def _negated(i, j, inp): return self._literal_at_position_is(i, j, ~inp) & inp for i in range(1, self.m + 1): for j in range(1, self.n + 1): auxiliaries = list() for inp in self._inputs_plus(): aux = self._next_aux("on_neg_path") on_neg_path = _set(i, j, inp) | _negated(i, j, inp) auxiliaries.append(aux) yield expr.Implies(aux, on_neg_path).to_cnf() yield expr.Implies(self._negative_path_var(i, j), expr.Or(*auxiliaries)).to_cnf()
def test_qbf_forall_cardnet(self): equals = expr.exprvar("equals") cardinality = synth.constraint.equals(self.pos + self.neg, len(self.neg), equals) function = expr.Or(*self.neg, *(~n for n in self.neg), simplify=False) solver = self.get_solver() solver.exists([equals]) solver.forall(self.neg) solver.add(function) for constraint in cardinality: solver.add(constraint) solver.add(equals) sat = solver.solve([equals]) self.assertIsNotNone(sat) self.assertTrue(sat.get(equals))
def convert_to_pyeda(term): """Converts a term object to a PyEDA expression. Args: term (Term): A term object. Returns: expr: The corresponding PyEDA expression. """ if term.operator is None: return expr.exprvar(escape_var_name(term.operands[0]), None) elif term.operator == "NEG": return expr.Not(convert_to_pyeda(term.operands[0]), simplify=False) elif term.operator == "AND": return expr.And( *[convert_to_pyeda(operand) for operand in term.operands], simplify=False) elif term.operator == "OR": return expr.Or( *[convert_to_pyeda(operand) for operand in term.operands], simplify=False) elif term.operator == "IMP": return expr.Implies(convert_to_pyeda(term.operands[0]), convert_to_pyeda(term.operands[0]), simplify=False) elif term.operator == "EQV": return expr.Equal( *[convert_to_pyeda(operand) for operand in term.operands], simplify=False) elif term.operator == "ADD": return expr.exprvar( "___ADD___".join([ escape_var_name(operand.operands[0]) for operand in term.operands ]), None)
def _assert_negative_path_exists_if_function_true(self): elements = (self._inactive_switch(i, self.n) & \ self._position_unreachable(i, self.n, self._upper_path_bound()) for i in range(1, self.m + 1)) yield expr.Implies(self.function, expr.Or(*elements)).to_cnf()
def _cover_to_expression(cover): inputs = (inp for (inp, outputs) in cover if outputs == (1, )) terms = (expr.And(*Function._vector_to_vars(v)) for v in inputs) return expr.Or(*terms)
def setUp(self): self.pos = tuple(expr.exprvar(p) for p in "abc") self.neg = tuple(expr.exprvar(p) for p in "uvwxyz") self.function = expr.And(*self.pos, ~expr.Or(*self.neg))
def _assert_negative_path_exists_if_function_false(self, path_var): elements = (path_var(i, self.n) for i in range(1, self.m + 1)) yield expr.Or(*elements)
def _assert_path_exists_if_function_true(self, path_var): elements = (path_var(self.m, j) for j in range(1, self.n + 1)) yield expr.Or(*elements)
def _merger_recursive_clauses(self, d, e, c, sequence_length): for i in range(1, sequence_length + 1): yield expr.Or(~d[i], ~e[i - 1], c[2 * i]) yield expr.Or(~d[i], c[2 * i - 1]) yield expr.Or(~e[i - 1], c[2 * i - 1])
def _merger_basic_clauses(self, c1, c2, sequence_a, sequence_b): (a, b) = sequence_a + sequence_b yield expr.Or(~a, ~b, c2) yield expr.Or(~a, c1) yield expr.Or(~b, c1)
def _assert_negative_path_exists_if_function_false(self): elements = (self._negative_path_var(i, self.n) for i in range(1, self.m + 1)) yield expr.Implies(~self.function, expr.Or(*elements)).to_cnf()
def _assert_path_exists_if_function_true(self, switch_var, position_var): elements = (switch_var(self.m, j) & \ position_var(self.m, j, self._upper_path_bound()) for j in range(1, self.n + 1)) yield expr.Or(*elements).to_cnf()
def _assert_path_exists_if_function_true(self): elements = (self._path_var(self.m, j) for j in range(1, self.n + 1)) yield expr.Implies(self.function, expr.Or(*elements)).to_cnf()
def _assert_negative_path_exists_if_function_false(self, switch_var, position_var): elements = (switch_var(i, self.n) & \ position_var(i, self.n, self._upper_path_bound()) for i in range(1, self.m + 1)) yield expr.Or(*elements).to_cnf()
def _assert_path_exists_if_function_false(self): elements = (self._active_switch(self.m, j) & \ self._position_reachable(self.m, j, self._upper_path_bound()) for j in range(1, self.n + 1)) yield expr.Implies(~self.function, expr.Or(*elements)).to_cnf()