def Orr(in_, out): # INVAR: (in = 0) -> (out = 0) & (in != 0) -> (out = 1) vars_ = [in_, out] comment = "Orr (in, out) = (%s, %s)" % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) if (in_.symbol_type() == BOOL) and (out.symbol_type() == BOOL): invar = EqualsOrIff(in_, out) else: if out.symbol_type() == BOOL: out0 = Not(out) out1 = out else: out0 = EqualsOrIff(out, BV(0, 1)) out1 = EqualsOrIff(out, BV(1, 1)) true_res = Implies( EqualsOrIff(in_, BV(0, in_.symbol_type().width)), out0) false_res = Implies( Not(EqualsOrIff(in_, BV(0, in_.symbol_type().width))), out1) invar = And(true_res, false_res) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def add_relu_eager_constraint(self): # Eager lemma encoding for relus zero = Real(0) for r, relu_in in self.relus: self.formulae.append(Implies(GT(relu_in, zero), Equals(r, relu_in))) self.formulae.append(Implies(LE(relu_in, zero), Equals(r, zero)))
def Mux(in0, in1, sel, out): # if Modules.functional # INVAR: out' = Ite(sel = 0, in0, in1) # else # INVAR: ((sel = 0) -> (out = in0)) & ((sel = 1) -> (out = in1)) vars_ = [in0, in1, sel, out] comment = "Mux (in0, in1, sel, out) = (%s, %s, %s, %s)" % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) if sel.symbol_type() == BOOL: sel0 = Not(sel) sel1 = sel else: sel0 = EqualsOrIff(sel, BV(0, 1)) sel1 = EqualsOrIff(sel, BV(1, 1)) if Modules.functional: invar = And(EqualsOrIff(out, Ite(sel0, in0, in1))) else: invar = And(Implies(sel0, EqualsOrIff(in0, out)), Implies(sel1, EqualsOrIff(in1, out))) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def Neq(in0, in1, out): # INVAR: (((in0 != in1) -> (out = #b1)) & ((in0 == in1) -> (out = #b0))) vars_ = [in0, in1, out] comment = "Eq (in0, in1, out) = (%s, %s, %s)" % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) # TODO: Create functional encoding if Modules.functional: if out.symbol_type() == BOOL: invar = EqualsOrIff(out, Not(EqualsOrIff(in0, in1))) else: invar = EqualsOrIff(out, BVNot(BVComp(in0, in1))) else: eq = EqualsOrIff(in0, in1) if out.symbol_type() == BOOL: out0 = Not(out) out1 = out else: out0 = EqualsOrIff(out, BV(0, 1)) out1 = EqualsOrIff(out, BV(1, 1)) invar = And(Implies(Not(eq), out1), Implies(eq, out0)) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
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 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 Clock(clk): # INIT: clk = 0 # TRANS: clk' = !clk comment = "Clock (clk) = (" + clk.symbol_name() + ")" if clk.symbol_type() == BOOL: clk0 = Not(clk) clk1 = clk else: clk0 = EqualsOrIff(clk, BV(0, 1)) clk1 = EqualsOrIff(clk, BV(1, 1)) init = clk0 invar = TRUE() if False: trans = EqualsOrIff(clk0, TS.to_next(clk1)) else: # Implementation that leverages on the boolean propagation trans1 = Implies(clk0, TS.to_next(clk1)) trans2 = Implies(clk1, TS.to_next(clk0)) trans = And(trans1, trans2) if Modules.abstract_clock: invar = clk0 init = TRUE() trans = TRUE() ts = TS(comment) ts.vars, ts.state_vars = set([clk]), set([clk]) ts.set_behavior(init, trans, invar) return ts
def construct_spread_formula_from_graph(spread_graph, limit, target): initial_infection_ints = [ Symbol('init_int_' + str(i), INT) for i in spread_graph.nodes ] final_infection_ints = [ Symbol('final_int_' + str(i), INT) for i in spread_graph.nodes ] spreading_clauses = [] origin_clauses = [] all_bounds = [] # Here, we ensure that, if node i is selected as an initial infector, all of its neighbors are also infected: for starting_node in spread_graph.nodes: initial_infection_bounds = And( LE(initial_infection_ints[int(starting_node)], Int(1)), GE(initial_infection_ints[int(starting_node)], Int(0))) infected_neighbors = And([ Equals(final_infection_ints[int(i)], Int(1)) for i in spread_graph.successors(starting_node) ]) infected_nodes = And( infected_neighbors, Equals(final_infection_ints[int(starting_node)], Int(1))) spreading_forumla = Implies( Equals(initial_infection_ints[int(starting_node)], Int(1)), infected_nodes) spreading_clauses.append(spreading_forumla) all_bounds.append(initial_infection_bounds) # Here, we ensure that, if node i becomes infected, either it was infected by an initial infectors with an edge to node i # of node i itself was an initial infector. for infected_node in spread_graph.nodes: final_infection_bounds = And( LE(final_infection_ints[int(infected_node)], Int(1)), GE(final_infection_ints[int(infected_node)], Int(0))) origin_neighbors = Or([ Equals(initial_infection_ints[int(i)], Int(1)) for i in spread_graph.predecessors(infected_node) ]) origin_nodes = Or( origin_neighbors, Equals(initial_infection_ints[int(infected_node)], Int(1))) origin_formula = Implies( Equals(final_infection_ints[int(infected_node)], Int(1)), origin_nodes) origin_clauses.append(origin_formula) all_bounds.append(final_infection_bounds) initial_infection_limit = LE(Plus(initial_infection_ints), Int(limit)) final_infection_target = GE(Plus(final_infection_ints), Int(target)) return And( And(spreading_clauses), And(origin_clauses), And(all_bounds), initial_infection_limit, final_infection_target), initial_infection_ints, final_infection_ints
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 message(self, tree, spins, subtheta, auxvars): """Determine the energy of the elimination tree. Args: tree (dict): The current elimination tree spins (dict): The current fixed spins subtheta (dict): Theta with spins fixed. auxvars (dict): The auxiliary variables for the given spins. Returns: The formula for the energy of the tree. """ energy_sources = set() for v, children in iteritems(tree): aux = auxvars[v] assert all(u in spins for u in self._ancestors[v]) # build an iterable over all of the energies contributions # that we can exactly determine given v and our known spins # in these contributions we assume that v is positive def energy_contributions(): yield subtheta.linear[v] for u, bias in iteritems(subtheta.adj[v]): if u in spins: yield SpinTimes(spins[u], bias) plus_energy = Plus(energy_contributions()) minus_energy = SpinTimes(-1, plus_energy) # if the variable has children, we need to recursively determine their energies if children: # set v to be positive spins[v] = 1 plus_energy = Plus(plus_energy, self.message(children, spins, subtheta, auxvars)) spins[v] = -1 minus_energy = Plus(minus_energy, self.message(children, spins, subtheta, auxvars)) del spins[v] # we now need a real-valued smt variable to be our message m = FreshSymbol(REAL) ancestor_aux = {auxvars[u] if spins[u] > 0 else Not(auxvars[u]) for u in self._ancestors[v]} plus_aux = And({aux}.union(ancestor_aux)) minus_aux = And({Not(aux)}.union(ancestor_aux)) self.assertions.update({LE(m, plus_energy), LE(m, minus_energy), Implies(plus_aux, GE(m, plus_energy)), Implies(minus_aux, GE(m, minus_energy)) }) energy_sources.add(m) return Plus(energy_sources)
def add_relu_simplex_friendly_eager(self): # Eager lemma encoding for relus zero = Real(0) for relu_out, relu_in in self.relus: #Introduce f = relu_out - relu_in f = FreshSymbol(REAL) self.formulae.append(Equals(f, Minus(relu_out, relu_in))) self.formulae.append(Implies(GT(relu_in, zero), Equals(f, zero))) self.formulae.append( Implies(LE(relu_in, zero), Equals(relu_out, zero)))
def test_add_assertions(self): varA = Symbol("A", BOOL) varB = Symbol("B", BOOL) varC = Symbol("C", BOOL) assertions = [varA, Implies(varA, varB), Implies(varB, varC)] for name in get_env().factory.all_solvers(logic=QF_BOOL): with Solver(name) as solver: solver.add_assertions(assertions) solver.solve() self.assertTrue(solver.get_py_value(And(assertions)))
def add_relu_maxOA_constraint(self): zero = Real(0) for relu_out, relu_in in self.relus: # MAX abstraction self.formulae.append(GE(relu_out, relu_in)) self.formulae.append(GE(relu_out, zero)) # MAX - case based upper bound self.formulae.append( Implies(GT(relu_in, zero), LE(relu_out, relu_in))) self.formulae.append(Implies(LE(relu_in, zero), LE(relu_out, zero)))
def main(): x,y = [Symbol(n, REAL) for n in "xy"] f_sat = Implies(And(GT(y, Real(0)), LT(y, Real(10))), LT(Minus(y, Times(x, Real(2))), Real(7))) f_incomplete = And(GT(x, Real(0)), LE(x, Real(10)), Implies(And(GT(y, Real(0)), LE(y, Real(10)), Not(Equals(x, y))), GT(y, x))) run_test([y], f_sat) run_test([y], f_incomplete)
def add_relu_simplex_friendly_OA(self): zero = Real(0) for relu_out, relu_in in self.relus: #Introduce f = relu_out - relu_in f = FreshSymbol(REAL) self.formulae.append(Equals(f, Minus(relu_out, relu_in))) # MAX abstraction self.formulae.append(GE(f, zero)) self.formulae.append(GE(relu_out, zero)) # MAX - case based upper bound self.formulae.append(Implies(GT(relu_in, zero), LE(f, zero))) self.formulae.append(Implies(LE(relu_in, zero), LE(relu_out, zero)))
def Andr(in_, out): # INVAR: (in = 2**width - 1) -> (out = 1) & (in != 2**width - 1) -> (out = 0) vars_ = [in_, out] comment = "Andr (in, out) = (%s, %s)"%(tuple([x.symbol_name() for x in vars_])) Logger.log(comment, 3) width = in_.symbol_type().width eq_all_ones = EqualsOrIff(in_, BV(2**width - 1,width)) true_res = Implies(eq_all_ones, EqualsOrIff(out, BV(1,1))) false_res = Implies(Not(eq_all_ones), EqualsOrIff(out, BV(0,1))) invar = And(true_res, false_res) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def IsAttack(attack, plan, gridsize, obstacles, safes): obstacles = IntifyCoords(obstacles) safes = IntifyCoords(safes) # (1) All attack moves are in Z_gridsize x Z_gridsize. bounds = And([IsOnGrid(step, gridsize) for step in attack]) # (2) The attacker never moves more than 1 grid-square at a time. adjacency = IsConnected(attack) # (3) The attack begins in the same place as some path in the plan. init = Or([SamePosition(path[0], attack[0]) for path in plan]) # (4) The attack enters a "safe" zone at some point. reach = Or( [SamePosition(coord, safe) for coord in attack for safe in safes]) # (5) The attack does not cross paths with any plans other than the one it # replaces. avoid = And([ Implies(SamePosition(path[i], attack[i]), SamePosition(path[0], attack[0])) for i in range(len(attack)) for path in plan ]) # (6) The attack never runs into any obstacle. obstacles = And([ Not(SamePosition(coord, obstacle)) for coord in attack for obstacle in obstacles ]) # (7) Any time the attack is adjacent to some plan p, it is in the same # place as another plan p' and therefore could be mistaken for the # innocent plan p'. # i is the attacker, j the observer, k the time-step. undetected = And([ Implies( SamePosition(plan[i][0], attack[0]), And([ And( Implies(Adj(plan[j][k], plan[i][k]), SamePosition(coord, plan[i][k])), Implies(Adj(coord, plan[j][k]), SamePosition(coord, plan[i][k]))) for k, coord in enumerate(attack) for j in range(len(plan)) if j != i ])) for i in range(len(plan)) ]) return And(bounds, adjacency, init, reach, avoid, obstacles, undetected)
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 test_real(self): r, s = Symbol("r", REAL), Symbol("s", REAL) f = ForAll([r], Implies(LT(Real(0), r), LT(s, r))) with Solver(name='cvc4', logic=LRA) as s: s.add_assertion(f) res = s.solve() self.assertTrue(res)
def test_int(self): p, q = Symbol("p", INT), Symbol("q", INT) f = ForAll([p], Implies(LT(Int(0), p), LT(q, p))) with Solver(name='cvc4', logic=LIA) as s: s.add_assertion(f) res = s.solve() self.assertTrue(res)
def test_bool(self): x, y = Symbol("x"), Symbol("y") f = ForAll([x], Implies(x, y)) with Solver(name='cvc4', logic=LIA) as s: s.add_assertion(f) res = s.solve() self.assertTrue(res)
def test_str_contains(self): s1 = Symbol("s1", STRING) s2 = Symbol("s2", STRING) f = Not( Implies(And(StrContains(s1, s2), StrContains(s2, s1)), Equals(s1, s2))) self.assertUnsat(f)
def _bool_example(self, qe): # Bool Example x, y = Symbol("x"), Symbol("y") f = ForAll([x], Implies(x,y)) qf = qe.eliminate_quantifiers(f).simplify() self.assertEqual(qf, y)
def _real_example(self, qe): # Real Example r, s = Symbol("r", REAL), Symbol("s", REAL) f = ForAll([r], Implies(LT(Real(0), r), LT(s, r))) qf = qe.eliminate_quantifiers(f).simplify() self.assertEqual(qf, LE(s, Real(0)))
def compile_ftrans(self): if self.ftrans is None: return None ret_trans = TRUE() ret_invar = TRUE() use_ites = False if use_ites: for var, cond_assign_list in self.ftrans.items(): if TS.has_next(var): ite_list = TS.to_prev(var) else: ite_list = var for (condition, value) in reversed(cond_assign_list): if condition == TRUE(): ite_list = value else: ite_list = Ite(condition, value, ite_list) if TS.has_next(ite_list): ret_trans = And(ret_trans, EqualsOrIff(var, ite_list)) else: ret_invar = And(ret_invar, EqualsOrIff(var, ite_list)) else: for var, cond_assign_list in self.ftrans.items(): effects = [] all_neg_cond = [] for (condition, value) in cond_assign_list: effects.append( simplify(Implies(condition, EqualsOrIff(var, value)))) all_neg_cond.append(Not(condition)) if not TS.has_next(var) and not TS.has_next(condition): ret_invar = And(ret_invar, And(effects)) else: ret_trans = And(ret_trans, And(effects)) if TS.has_next(var): no_change = EqualsOrIff(var, TS.to_prev(var)) ret_trans = And( ret_trans, simplify(Implies(And(all_neg_cond), no_change))) return (ret_invar, ret_trans)
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_examples_get_implicant(self): for (f, _, satisfiability, logic) in get_example_formulae(): if logic.quantifier_free: for sname in get_env().factory.all_solvers(logic=logic): f_i = get_implicant(f, logic=logic, solver_name=sname) if satisfiability: self.assertValid(Implies(f_i, f), logic=logic, msg=(f_i, f)) else: self.assertIsNone(f_i)
def test_get_implicant_sat(self): varA = Symbol("A", BOOL) varX = Symbol("X", REAL) f = And(varA, Equals(varX, Real(8))) for solver in get_env().factory.all_solvers(logic=QF_LRA): res = get_implicant(f, solver_name=solver) self.assertIsNotNone(res, "Formula was expected to be SAT") self.assertValid(Implies(res, f), logic=QF_LRA)
def SMT_solver(rule, a, b, feature_num, con_num, data): letters = [] letters1 = [] for i in range(feature_num): letters.append(Symbol('x' + str(i), REAL)) letters1.append(Symbol('x_' + str(i), INT)) domains = And([ And(GE(letters[i], Real(float(a[i]))), LE(letters[i], Real(float(b[i])))) for i in range(feature_num) ]) problem_rule = [] for node in rule: if node[1] == ">": problem_rule.append(GT(letters[node[0]], Real(float(node[2])))) else: problem_rule.append(LE(letters[node[0]], Real(float(node[2])))) problem = And(problem_rule) constraint = And([ And( Implies(Equals(letters[i], Real(float(data[i]))), Equals(letters1[i], Int(0))), Implies(NotEquals(letters[i], Real(float(data[i]))), Equals(letters1[i], Int(1)))) for i in range(feature_num) ]) sum_letters1 = Plus(letters1) problem1 = LE(sum_letters1, Int(con_num)) formula = And([domains, problem, constraint, problem1]) test_case = [] with Solver(name='z3', random_seed=23) as solver: solver.add_assertion(formula) if solver.solve(): for l in letters: ans = solver.get_py_value(l) test_case.append(float(ans)) print("find a solution") # else: # print("No solution found") return test_case
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)))))" )