def all_loopbacks(self, vars, k, heqvar=None): lvars = list(vars) vars_k = [TS.get_timed(v, k) for v in lvars] loopback = FALSE() eqvar = None heqvars = None if heqvar is not None: eqvar = Symbol(EQVAR, BOOL) heqvars = [] peqvars = FALSE() for i in range(k): vars_i = [TS.get_timed(v, i) for v in lvars] eq_k_i = And( [EqualsOrIff(vars_k[j], vars_i[j]) for j in range(len(lvars))]) if heqvar is not None: eqvar_i = TS.get_timed(eqvar, i) peqvars = Or(peqvars, eqvar_i) eq_k_i = And(eqvar_i, Iff(eqvar_i, eq_k_i)) heqvars.append(Iff(TS.get_timed(heqvar, i), peqvars)) loopback = Or(loopback, eq_k_i) if heqvar is not None: loopback = And(loopback, And(heqvars)) return loopback
def break_dfa_symmetry_bfs(x, y, sigma, prefixes_r, h): epsilon_i = prefixes_r[()] assert epsilon_i == 0 constraints = [] constraints.append(Equals(x[epsilon_i], Int(1))) t = [[Symbol(f"t_{i}_{j}", BOOL) for j in range(h)] for i in range(h)] p = [[Symbol(f"p_{i}_{j}", BOOL) for j in range(h)] for i in range(h)] for i, j in it.combinations(range(h), 2): constraints.append(Iff( t[i][j], Or(*(Equals(Select(y[l], Int(i+1)), Int(j+1)) for l in range(len(sigma)))) )) constraints.append(Iff( p[j][i], And( t[i][j], *(Not(t[k][j]) for k in range(i)) ) )) for j in range(1, h): constraints.append(Or(*(p[j][k] for k in range(j)))) for k, i, j in it.combinations(range(h-1), 3): constraints.append(Implies(p[j][i], Not(p[j+1][k]))) assert len(sigma) == 2 for i, j in it.combinations(range(h-1), 2): constraints.append(Implies(And(p[j][i], p[j+1][i]), Equals(Select(y[0], Int(i+1)), Int(j+1)))) return constraints
def encode_node(self, node): """ Encode a node of a tree. """ if '_' not in node.name: # continuous features => expecting an upper bound # feature and its upper bound (value) f, v = node.name, node.threshold existing = True if tuple([f, v]) in self.idmgr.obj2id else False vid = self.idmgr.id(tuple([f, v])) bv = Symbol('bvar{0}'.format(vid), typename=BOOL) if not existing: if self.intvs: d = self.imaps[f][v] + 1 pos, neg = self.ivars[f][:d], self.ivars[f][d:] self.enc.append(Iff(bv, Or(pos))) self.enc.append(Iff(Not(bv), Or(neg))) else: fvar, fval = Symbol(f, typename=REAL), Real(v) self.enc.append(Iff(bv, LT(fvar, fval))) return bv, Not(bv) else: # all features are expected to be categorical and # encoded with one-hot encoding into Booleans # each node is expected to be of the form: f_i < 0.5 bv = Symbol(node.name, typename=BOOL) # left branch is positive, i.e. bv is true # right branch is negative, i.e. bv is false return Not(bv), bv
def test_z3_iff(self): z3 = Solver(name="z3") conv = z3.converter x, y = Symbol("x"), Symbol("y") term = conv.convert(Iff(x, y)) back = conv.back(term) self.assertEqual(Iff(x, y), back)
def test_implies(self): a, b, c, d = (Symbol(x) for x in "abcd") f = Implies(Iff(a, b), Iff(c, d)) conv = CNFizer() cnf = conv.convert_as_formula(f) self.assertValid(Implies(cnf, f), logic=QF_BOOL)
def test_msat_iff(self): msat = Solver(name="msat") conv = msat.converter x, y = Symbol("x"), Symbol("y") term = conv.convert(Iff(x, y)) back = conv.back(term) # Mathsat can reorder variables... self.assertTrue(Iff(x, y) == back or Iff(y, x) == back)
def test_subst(self): varA = Symbol("At", INT) varB = Symbol("Bt", INT) f = And(LT(varA, Plus(varB, Int(1))), GT(varA, Minus(varB, Int(1)))) g = Equals(varA, varB) h = Iff(f, g) res = substitute(h, subs={varA: varB}) self.assertEqual(res, h.substitute({varA: varB})) res = substitute(h, subs={varA: Int(1)}) self.assertEqual(res, h.substitute({varA: Int(1)}))
def test_annotations(self): x = Symbol('x') x_next = Symbol('x.next') f = Iff(x, Not(x_next)) ann = Annotations() ann.add(x, 'next', x_next.symbol_name()) ann.add(f, 'trans', 'true') ann.add(x, 'init', 'true') tree_buf = StringIO() dag_buf = StringIO() tree_printer = SmtPrinter(tree_buf, annotations=ann) dag_printer = SmtDagPrinter(dag_buf, annotations=ann) dag_printer.printer(f) tree_printer.printer(f) self.assertEqual( tree_buf.getvalue(), "(! (= (! x :next x.next :init true) (not x.next)) :trans true)") self.assertEqual( dag_buf.getvalue(), "(let ((.def_0 (not x.next))) (let ((.def_1 (= (! x :next x.next :init true) .def_0))) (! .def_1 :trans true)))" )
def export_rules(self, formula): ex = self.export_expr uvars, formula = self.extract_universal(formula) precondition = None if formula.is_implies(): precondition = formula.arg(0) formula = formula.arg(1) if formula.is_equals() or formula.is_iff(): if uvars: re = {v: self._qvar_from_symbol(v) for v in uvars} formula = formula.substitute(re) uvars = re.values() uvars = set(uvars) fv = lambda phi: get_free_variables(phi) & uvars lhs, rhs = formula.args() for lhs, rhs in [(lhs, rhs), (rhs, lhs)]: if ((lhs not in uvars) and # avoid e.g. x => x + 0 fv(lhs) >= fv(rhs)): if precondition is not None: yield SExpression([ '=>', self._fresh('rule%d'), ex(Implies(precondition, formula)) ]) else: yield SExpression( ['=>', self._fresh('rule%d'), ex(lhs), ex(rhs)]) elif not (formula.is_not() and self.extract_universal(formula.args()[0])[0]): # this is either a not exp or an expr if uvars: re = {v: self._qvar_from_symbol(v) for v in uvars} formula = formula.substitute(re) uvars = re.values() uvars = set(uvars) equals_to = TRUE() if formula.is_not(): formula = formula.args()[0] equals_to = FALSE() op = '<=>' if uvars: op = '=>' if precondition is not None: yield SExpression([ op, self._fresh('rule%d'), ex(Implies(precondition, Iff(formula, equals_to))) ]) else: yield SExpression( [op, self._fresh('rule%d'), ex(formula), ex(equals_to)])
def test_normalization_negative(): def get_normalization_file(filename): return path.join(path.dirname(__file__), "res", "bug_z_negative", filename) domain = Domain.from_file(get_normalization_file("domain")) support = domain.get_bounds() & read_smtlib( get_normalization_file("vanilla.support")) weight = read_smtlib(get_normalization_file("vanilla.weight")) new_support = read_smtlib(get_normalization_file("renorm.support")) pa_engine = RejectionEngine( domain, Iff(new_support, ~normalize_formula(new_support)), Real(1), 1000000) difference_volume = pa_engine.compute_volume() assert difference_volume == pytest.approx(0, EXACT_REL_ERROR**2) support = normalize_formula(support) new_support = normalize_formula(new_support) weight = normalize_formula(weight) engine = XaddEngine(domain, support, weight) new_weight = engine.normalize(new_support, paths=False) computed_volume = engine.copy_with(weight=new_weight).compute_volume() # print(pa_engine.copy_with(support=domain.get_bounds(), weight=new_weight).compute_volume()) # print(pa_engine.copy_with(support=new_support, weight=new_weight).compute_volume()) illegal_volume = engine.copy_with(support=~new_support, weight=new_weight).compute_volume() print(computed_volume, illegal_volume) # new_new_weight = engine.copy_with(support=domain.get_bounds(), weight=new_weight).normalize(new_support, paths=False) # print(pa_engine.copy_with(support=domain.get_bounds(), weight=new_new_weight).compute_volume()) assert computed_volume == pytest.approx(1, rel=0.1) assert illegal_volume == pytest.approx(0, rel=EXACT_REL_ERROR)
def _validate(self, old, new): if self.validate_simplifications: Iff = self.env.formula_manager.Iff is_valid = self.env.factory.is_valid sname = self._validation_sname assert is_valid(Iff(old, new), solver_name=sname ), \ "Was: %s \n Obtained: %s\n" % (str(old), str(new))
def __init__(self, oracle_cir, obf_cir): self.oracle_cir = oracle_cir self.obf_cir = obf_cir # generate solver formulas for w in self.oracle_cir.wire_objs: lst = [] for op in w.operands: lst.append(Symbol(op.name)) r = self.get_wire_formulas(w, lst) w.formula = Iff(Symbol(w.name), r) # generate formulas for two copies of obfuscated circuit ckt1 = self.gen_dip_chk('dc1', '_0', None) ckt2 = self.gen_dip_chk('dc2', '_1', None) output_xors = [] for w in self.obf_cir.output_wires: output_xors.append( Xor(Symbol(w.name + '@dc1'), Symbol(w.name + '@dc2'))) self.dip_gen_ckt = And(Or(output_xors), ckt1, ckt2) # key inequality circuit key_symbols1 = [] key_symbols2 = [] for w in self.obf_cir.wire_objs: if 'keyinput' in w.name: key_symbols1.append(Symbol(w.name + '_0')) key_symbols2.append(Symbol(w.name + '_1')) output_xors = [] for i in range(self.obf_cir.k_inputs): output_xors.append(Xor(key_symbols1[i], key_symbols2[i])) self.key_inequality_ckt = Or(output_xors)
def checkSatisfiability(self, postFixList): propStack = Stack() p = re.compile('[a-zA-Z0-1]') for op in postFixList: if op == 'ID' or p.match(op): propStack.push(Symbol(op)) elif op in ['NOT', '!']: propStack.push(Not(propStack.pop())) elif op in ['AND', '/\\', ',', 'COMMA']: p2 = propStack.pop() p1 = propStack.pop() propStack.push(And(p1, p2)) elif op in ['OR', '\\/']: p2 = propStack.pop() p1 = propStack.pop() propStack.push(Or(p1, p2)) elif op in ['IFF', '<=>']: p2 = propStack.pop() p1 = propStack.pop() propStack.push(Iff(p1, p2)) elif op in ['IMPLIES', '=>']: p2 = propStack.pop() p1 = propStack.pop() propStack.push(Implies(p1, p2)) print("propStack size: ", propStack.size()) if propStack.size() == 1: p3 = propStack.pop() # print ("Expression for satisfiability:", p3) print("Is sat or not : ", is_sat(p3)) else: print("Error while checking Is sat or not")
def label_formula(self, formula, atoms_to_label): """Labels every atom in the input with a new fresh WMI variable. Args: formula (FNode): The formula containing the atoms. atoms_to_label (list): The list of atoms to assign a new label. Returns: labelled_formula (FNode): The formula with the labels in it and their respective atoms. pa_vars (set): The list of all the atoms_to_label (as labels). labels (dict): The list of the labels and corrispondent atom assigned to it. """ expressions = [] labels = {} pa_vars = set() j = 0 for a in atoms_to_label: if a.is_theory_relation(): label_a = self.variables.new_wmi_label(j) j += 1 expressions.append(Iff(label_a, a)) labels[label_a] = a pa_vars.add(label_a) else: pa_vars.add(a) labelled_formula = And([formula] + expressions) return labelled_formula, pa_vars, labels
def test_bdd_simplify(self): s = BddSimplifier() for (f, _, _, logic) in get_example_formulae(): if logic == QF_BOOL: fprime = s.simplify(f) self.assertValid(Iff(fprime, f)) s = BddSimplifier() try: s.validate_simplifications = True except ValueError: self.assertTrue(len(self.env.factory.all_solvers()) == 1) for (f, _, _, logic) in get_example_formulae(): if logic == QF_BOOL: fprime = s.simplify(f) self.assertValid(Iff(fprime, f))
def gen_dip_chk(self, iteration, key_postfix, dip_list): dip_chk = [] for w in self.obf_cir.wire_objs: r = None if w.type == Wire.INPUT: if 'keyinput' in w.name: continue elif dip_list: # for dip checkers for i in range(len(self.oracle_cir.input_wires)): if w.name == self.oracle_cir.input_wires[i].name: r = dip_list[i] break else: # for dip generator r = Symbol(w.name) else: lst = [] for op in w.operands: if 'keyinput' in op.name and 'inv_keyinput' not in op.name: lst.append(Symbol(op.name + key_postfix)) else: lst.append(Symbol(op.name + '@{}'.format(iteration))) r = self.get_wire_formulas(w, lst) dip_chk.append(Iff(Symbol(w.name + '@{}'.format(iteration)), r)) return And(dip_chk)
def _alternation_bool_example(self, qe): # Alternation of quantifiers x, y = Symbol("x"), Symbol("y") f = ForAll([x], Exists([y], Iff(x, Not(y)))) qf = qe.eliminate_quantifiers(f).simplify() self.assertEqual(qf, TRUE())
def _int_example(self, qe): # Int Example p, q = Symbol("p", INT), Symbol("q", INT) f = ForAll([p], Implies(LT(Int(0), p), LT(q, p))) qf = qe.eliminate_quantifiers(f).simplify() self.assertValid(Iff(qf, LE(q, Int(0))))
def test_propagate_toplevel_examples(self): for (f, _, _, logic) in get_example_formulae(): if self.env.factory.has_solvers(logic=logic): rwf = propagate_toplevel(f) try: ok = is_valid(Iff(f, rwf), logic=logic) except SolverReturnedUnknownResultError: ok = not logic.quantifier_free self.assertTrue(ok)
def test_aig_examples(self): for (f, _, _, logic) in get_example_formulae(): if self.env.factory.has_solvers(logic=logic): f_aig = aig(f) try: ok = is_valid(Iff(f, f_aig), logic=logic) except SolverReturnedUnknownResultError: ok = not logic.quantifier_free self.assertTrue(ok, "Was: %s\n Got:%s" % (f, f_aig))
def export_goals(self, formula): ex = self.export_expr if formula.is_not() and self.extract_universal(formula.args()[0])[0]: formula = formula.arg(0) uvars, inner = self.extract_universal(formula) if inner.is_equals() or inner.is_iff(): goal = formula elif inner.is_implies(): goal = formula if (not inner.arg(1).is_equals()) and ( not inner.arg(1).is_iff()): ForAll( uvars, Implies(inner.arg(0), Iff(inner.arg(1), Bool(True)))) else: goal = ForAll(uvars, Iff(inner, Bool(True))) yield SExpression(['prove', ex(goal)])
def test_disj_partitioning(self): for (f, _, _, logic) in get_example_formulae(): if self.env.factory.has_solvers(logic=logic): disjuncts = list(disjunctive_partition(f)) try: ok = is_valid(Iff(f, Or(disjuncts)), logic=logic) except SolverReturnedUnknownResultError: ok = not logic.quantifier_free self.assertTrue(ok)
def _query_labelling(formula, query_labels): lra_atoms = [a for a in formula.get_atoms() if a.is_theory_relation()] labelling = [] for lra_atom in lra_atoms: q_var = new_query_label(len(query_labels)) query_labels.add(q_var) labelling.append(Iff(q_var, lra_atom)) return And(formula, And(labelling))
def test_prenex_examples(self): for (f, _, _, logic) in get_example_formulae(): if self.env.factory.has_solvers(logic=logic): prenex = prenex_normal_form(f) try: ok = is_valid(Iff(f, prenex), logic=logic) except SolverReturnedUnknownResultError: ok = not logic.quantifier_free self.assertTrue(ok)
def test_nnf_examples(self): for (f, _, _, logic) in get_example_formulae(): if get_env().factory.has_solvers(logic=logic): rf = nnf(f) try: ok = is_valid(Iff(f, rf), logic=logic) except SolverReturnedUnknownResultError: ok = not logic.quantifier_free self.assertTrue(ok)
def test_simplify_q(self): simp = get_env().simplifier for (f, _, _, logic) in get_example_formulae(): if logic.quantifier_free: continue simp.validate_simplifications = True sf = f.simplify() simp.validate_simplifications = False self.assertValid(Iff(f, sf), solver_name='z3', msg="Simplification did not provide equivalent "+ "result:\n f= %s\n sf = %s" % (f, sf))
def do_back(self, solver_name): for formula, _, _, logic in get_example_formulae(): if logic.quantifier_free: try: s = Solver(name=solver_name, logic=logic) term = s.converter.convert(formula) res = s.converter.back(term) self.assertValid(Iff(formula, res), logic=logic) except NoSolverAvailableError: pass
def test_minus_0(self): x = Symbol("x", INT) y = Symbol("y", INT) i_0 = Int(0) src = Plus(x, y) src = Minus(x, src) src = LT(src, i_0) td = TimesDistributor() res = td.walk(src) self.assertValid(Iff(src, res))
def test_boolean(self): x, y, z = Symbol("x"), Symbol("y"), Symbol("z") f = Or(And(Not(x), Iff(x, y)), Implies(x, z)) self.assertEqual(f.to_smtlib(daggify=False), "(or (and (not x) (= x y)) (=> x z))") self.assertEqual( f.to_smtlib(daggify=True), "(let ((.def_0 (=> x z))) (let ((.def_1 (= x y))) (let ((.def_2 (not x))) (let ((.def_3 (and .def_2 .def_1))) (let ((.def_4 (or .def_3 .def_0))) .def_4)))))" )
def test_eq(self): varA = Symbol("At", INT) varB = Symbol("Bt", INT) f = And(LT(varA, Plus(varB, Int(1))), GT(varA, Minus(varB, Int(1)))) g = Equals(varA, varB) self.assertValid(Iff(f, g), "Formulae were expected to be equivalent", logic=QF_LIA)