def _check_logic(self, formulas): for f in formulas: logic = get_logic(f, self.environment) ok = any(logic <= l for l in self.LOGICS) if not ok: raise PysmtValueError("Logic not supported by Z3 interpolation." "(detected logic is: %s)" % str(logic))
def eliminate_quantifiers(self, formula): logic = get_logic(formula, self.environment) if not logic <= LRA and not logic <= LIA: raise PysmtValueError("Z3 quantifier elimination only "\ "supports LRA or LIA without combination."\ "(detected logic is: %s)" % str(logic)) simplifier = z3.Tactic('simplify') eliminator = z3.Tactic('qe') f = self.converter.convert(formula) s = simplifier(f, elim_and=True, pull_cheap_ite=True, ite_extra_rules=True).as_expr() res = eliminator(f).as_expr() pysmt_res = None try: pysmt_res = self.converter.back(res) except ConvertExpressionError: if logic <= LRA: raise raise ConvertExpressionError(message=("Unable to represent" \ "expression %s in pySMT: the quantifier elimination for " \ "LIA is incomplete as it requires the modulus. You can " \ "find the Z3 expression representing the quantifier " \ "elimination as the attribute 'expression' of this " \ "exception object" % str(res)), expression=res) return pysmt_res
def smtlibscript_from_formula(formula): script = SmtLibScript() # Get the simplest SmtLib logic that contains the formula f_logic = get_logic(formula) smt_logic = None try: smt_logic = get_closer_smtlib_logic(f_logic) except NoLogicAvailableError: warnings.warn("The logic %s is not reducible to any SMTLib2 " \ "standard logic. Proceeding with non-standard " \ "logic '%s'" % (f_logic, f_logic)) smt_logic = f_logic script.add(name=smtcmd.SET_LOGIC, args=[smt_logic]) deps = formula.get_free_variables() # Declare all variables for symbol in deps: assert symbol.is_symbol() script.add(name=smtcmd.DECLARE_FUN, args=[symbol]) # Assert formula script.add_command(SmtLibCommand(name=smtcmd.ASSERT, args=[formula])) # check-sat script.add_command(SmtLibCommand(name=smtcmd.CHECK_SAT, args=[])) return script
def sequence_interpolant(self, formulas, solver_name=None, logic=None): if logic is None or logic == AUTO_LOGIC: _And = self.environment.formula_manager.And logic = get_logic(_And(formulas)) with self.Interpolator(name=solver_name, logic=logic) as itp: return itp.sequence_interpolant(formulas)
def get_implicant(self, formula, solver_name=None, logic=None): mgr = self.environment.formula_manager if logic is None or logic == AUTO_LOGIC: logic = get_logic(formula, self.environment) with self.Solver(name=solver_name, logic=logic) \ as solver: solver.add_assertion(formula) check = solver.solve() if not check: return None else: model = solver.get_model() atoms = formula.get_atoms() res = [] for a in atoms: fv = a.get_free_variables() if any(v in model for v in fv): if solver.get_value(a).is_true(): res.append(a) else: assert solver.get_value(a).is_false() res.append(mgr.Not(a)) return mgr.And(res)
def establish_solver(self): self.formulas = self.encode_constraints() target_logic = get_logic(self.formulas) print("Target Logic: %s" % target_logic) self.solver = Solver(logic=target_logic) self.solver.add_assertion(self.formulas) self.num_sol = 0
def is_unsat(self, formula, solver_name=None, logic=None): if logic is None or logic == AUTO_LOGIC: logic = get_logic(formula, self.environment) with self.Solver(name=solver_name, logic=logic, generate_models=False, incremental=False) as solver: return solver.is_unsat(formula)
def is_sat(self, formula, solver_name=None, logic=None): if logic is None or logic == AUTO_LOGIC: logic = get_logic(formula, self.environment) with self.Solver(name=solver_name, logic=logic, generate_models=False, incremental=False) \ as solver: return solver.is_sat(formula)
def init_solver(self): self.formula = self.encode_constraint() target_logic = get_logic(self.formula) print("Target Logic: %s" % target_logic) self.solver = Solver(logic=target_logic) self.solver.add_assertion(self.formula) self.num_solution = 0
def _check_logic(self, formulas): for f in formulas: logic = get_logic(f, self.environment) ok = any(logic <= l for l in self.LOGICS) if not ok: raise PysmtValueError( "Logic not supported by Z3 interpolation." "(detected logic is: %s)" % str(logic))
def binary_interpolant(self, formula_a, formula_b, solver_name=None, logic=None): if logic == AUTO_LOGIC: logic = get_logic( self.environment.formula_manager.And(formula_a, formula_b)) with self.Interpolator(name=solver_name, logic=logic) as itp: return itp.binary_interpolant(formula_a, formula_b)
def binary_interpolant(self, formula_a, formula_b, solver_name=None, logic=None): if logic is None or logic == AUTO_LOGIC: logic = get_logic( self.environment.formula_manager.And(formula_a, formula_b)) with self.Interpolator(name=solver_name, logic=logic) as itp: return itp.binary_interpolant(formula_a, formula_b)
def all_smt(formula, keys): target_logic = get_logic(formula) print("Target Logic: %s" % target_logic) with Solver(logic=target_logic) as solver: solver.add_assertion(formula) while solver.solve(): partial_model = [EqualsOrIff(k, solver.get_value(k)) for k in keys] print(partial_model) solver.add_assertion(Not(And(partial_model)))
def test_theory_oracle(self): from pysmt.oracles import get_logic s1 = Symbol("s1", STRING) s2 = Symbol("s2", STRING) f = Equals(StrConcat(s1, s1), s2) theory = get_logic(f).theory self.assertTrue(theory.strings, theory) f = Not( And(GE(StrLength(StrConcat(s1, s2)), StrLength(s1)), GE(StrLength(StrConcat(s1, s2)), StrLength(s2)))) theory = get_logic(f).theory self.assertTrue(theory.strings, theory) f = And(GT(StrLength(s1), Int(2)), GT(StrLength(s2), StrLength(s1)), And(StrSuffixOf(s2, s1), StrContains(s2, s1))) theory = get_logic(f).theory self.assertTrue(theory.strings, theory)
def eliminate_quantifiers(self, formula): logic = get_logic(formula, self.environment) if not logic <= pysmt.logics.BOOL: raise NotImplementedError("BDD-based quantifier elimination only "\ "supports pure-boolean formulae."\ "(detected logic is: %s)" % str(logic)) bdd = self.converter.convert(formula) pysmt_res = self.converter.back(bdd) return pysmt_res
def get_model(self, formula, solver_name=None, logic=None): if logic is None or logic == AUTO_LOGIC: logic = get_logic(formula, self.environment) with self.Solver(name=solver_name, logic=logic, generate_models=True, incremental=False) as solver: solver.add_assertion(formula) if solver.solve(): return solver.get_model() return None
def get_model(self, formula, solver_name=None, logic=None): if logic == AUTO_LOGIC: logic = get_logic(formula, self.environment) with self.Solver(name=solver_name, logic=logic) \ as solver: solver.add_assertion(formula) check = solver.solve() retval = None if check: retval = solver.get_model() return retval
def test_theory_oracle(self): from pysmt.oracles import get_logic s1 = Symbol("s1", STRING) s2 = Symbol("s2", STRING) f = Equals(StrConcat(s1, s1), s2) theory = get_logic(f).theory self.assertTrue(theory.strings, theory) f = Not(And(GE(StrLength(StrConcat(s1, s2)), StrLength(s1)), GE(StrLength(StrConcat(s1, s2)), StrLength(s2)))) theory = get_logic(f).theory self.assertTrue(theory.strings, theory) f = And(GT(StrLength(s1), Int(2)), GT(StrLength(s2), StrLength(s1)), And(StrSuffixOf(s2, s1), StrContains(s2, s1))) theory = get_logic(f).theory self.assertTrue(theory.strings, theory)
def _check_sat(cls, zsolver, using_nla=False, myseed=None): zlogic = 'QF_NIA' if using_nla else 'QF_LIA' solver_opts = {"random_seed": myseed} if myseed else {} zf = z3.And(zsolver.assertions()) # @timeit def _convert(zf): zvs = z3.z3util.get_vars(zf) vs = [ Symbol(v.decl().name(), INT if v.is_int() else REAL) for v in zvs ] z3s = Solver(name='z3', logic=zlogic) f = z3s.converter.back(zf) return vs, f vs, f = _convert(zf) f_logic = get_logic(f) # @timeit def _solve(f): with Portfolio( [ ("cvc4", solver_opts), # ("z3", solver_opts), ("yices", solver_opts) ], logic=f_logic, incremental=True, generate_models=True) as solver: # with z3s as solver: solver.add_assertion(f) model = [] try: # mlog.debug("PySMT: solving {}".format(f)) r = solver.solve() # mlog.debug("r: {}".format(r)) if r: # for v in vs: # # mv = solver.get_value(v).constant_value() # mv = solver.get_py_value(v) # model.append((v.symbol_name(), int(mv))) py_model = solver.get_model() model = [(v.symbol_name(), int(py_model.get_py_value(v))) for v in vs] # mlog.debug("model: {}".format(model)) return (z3.sat if r else z3.unsat), model except Exception as e: mlog.debug("check_sat: {}".format(e)) return z3.unknown, [] return _solve(f)
def is_unsat(self, formula, solver_name=None, logic=None, portfolio=None): if logic is None or logic == AUTO_LOGIC: logic = get_logic(formula, self.environment) if portfolio is not None: solver = Portfolio(solvers_set=portfolio, environment=self.environment, logic=logic, generate_models=False, incremental=False) else: solver = self.Solver(name=solver_name, logic=logic, generate_models=False, incremental=False) with solver: return solver.is_unsat(formula)
def simplify(self, formula): from pysmt.oracles import get_logic from pysmt.logics import BOOL, QF_BOOL if self.bool_abstraction: logic = get_logic(formula) if logic > QF_BOOL and logic != BOOL: res = self.abstract_and_simplify(formula) else: res = self.back(self.convert(formula)) else: res = self.back(self.convert(formula)) self._validate(formula, res) return res
def get_unsat_core(self, clauses, solver_name=None, logic=None): if logic is None or logic == AUTO_LOGIC: logic = get_logic(self.environment.formula_manager.And(clauses), self.environment) with self.UnsatCoreSolver(name=solver_name, logic=logic) \ as solver: for c in clauses: solver.add_assertion(c) check = solver.solve() if check: return None return solver.get_unsat_core()
def smtlibscript_from_formula(formula, logic=None): script = SmtLibScript() if logic is None: # Get the simplest SmtLib logic that contains the formula f_logic = get_logic(formula) smt_logic = None try: smt_logic = get_closer_smtlib_logic(f_logic) except NoLogicAvailableError: warnings.warn("The logic %s is not reducible to any SMTLib2 " \ "standard logic. Proceeding with non-standard " \ "logic '%s'" % (f_logic, f_logic), stacklevel=3) smt_logic = f_logic elif not (isinstance(logic, Logic) or isinstance(logic, str)): raise UndefinedLogicError(str(logic)) else: if logic not in SMTLIB2_LOGICS: warnings.warn("The logic %s is not reducible to any SMTLib2 " \ "standard logic. Proceeding with non-standard " \ "logic '%s'" % (logic, logic), stacklevel=3) smt_logic = logic script.add(name=smtcmd.SET_LOGIC, args=[smt_logic]) # Declare all types types = get_env().typeso.get_types(formula, custom_only=True) for type_ in types: script.add(name=smtcmd.DECLARE_SORT, args=[type_.decl]) deps = formula.get_free_variables() # Declare all variables for symbol in deps: assert symbol.is_symbol() script.add(name=smtcmd.DECLARE_FUN, args=[symbol]) # Assert formula script.add_command(SmtLibCommand(name=smtcmd.ASSERT, args=[formula])) # check-sat script.add_command(SmtLibCommand(name=smtcmd.CHECK_SAT, args=[])) return script
def exist_elim(self, variables, formula): logic = get_logic(formula, self.env) if not logic <= LRA: raise NotImplementedError("MathSAT quantifier elimination only"\ " supports LRA (detected logic " \ "is: %s)" % str(logic)) fterm = self.converter.convert(formula) tvars = [self.converter.convert(x) for x in variables] algo = mathsat.MSAT_EXIST_ELIM_ALLSMT_FM if self.algorithm == 'lw': algo = mathsat.MSAT_EXIST_ELIM_VTS res = mathsat.msat_exist_elim(self.msat_env, fterm, tvars, algo) return self.converter.back(res)
def exist_elim(self, variables, formula): logic = get_logic(formula, self.env) if not logic <= LRA: raise NotImplementedError("MathSAT quantifier elimination only"\ " supports LRA (detected logic " \ "is: %s)" % str(logic)) fterm = self.converter.convert(formula) tvars = [self.converter.convert(x) for x in variables] algo = mathsat.MSAT_EXIST_ELIM_ALLSMT_FM if self.algorithm == 'lw': algo = mathsat.MSAT_EXIST_ELIM_VTS res = mathsat.msat_exist_elim(self.msat_env(), fterm, tvars, algo) return self.converter.back(res)
def get_models(self, fml, blocking, count): t_logic = get_logic(fml) models = [] m_index = 0 with Solver(logic=t_logic) as solver: solver.add_assertion(fml) while (solver.solve()): partial_model = [ EqualsOrIff(b, solver.get_value(b)) for b in blocking ] m = solver.get_model() models.append(m) solver.add_assertion(Not(And(partial_model))) m_index += 1 if m_index > count: break return models
def smtlibscript_from_formula(formula): script = SmtLibScript() # Get the simplest SmtLib logic that contains the formula f_logic = get_logic(formula) smt_logic = get_closer_smtlib_logic(f_logic) script.add(name=smtcmd.SET_LOGIC, args=[smt_logic]) deps = formula.get_free_variables() # Declare all variables for symbol in deps: assert symbol.is_symbol() script.add(name=smtcmd.DECLARE_FUN, args=[symbol]) # Assert formula script.add_command(SmtLibCommand(name=smtcmd.ASSERT, args=[formula])) # check-sat script.add_command(SmtLibCommand(name=smtcmd.CHECK_SAT, args=[])) return script
def solve_safety_inc_int(self, hts, prop, k): init = hts.single_init() trans = hts.single_trans() invar = hts.single_invar() solver_proof = self.solver.copy("inc_int_proof") solver = self.solver.copy("inc_int") has_next = TS.has_next(prop) map_10 = dict([(TS.get_timed_name(v.symbol_name(), 1), TS.get_timed_name(v.symbol_name(), 0)) for v in hts.vars]) itp = Interpolator(logic=get_logic(trans)) init = And(init, invar) nprop = Not(prop) def check_overappr(Ri, R): self._reset_assertions(solver_proof) self._add_assertion(solver_proof, And(Ri, Not(R))) if not self._solve(solver_proof): Logger.log("Proof found with k=%s"%(t), 1) return TRUE() Logger.log("Extending initial states (%s)"%int_c, 1) return Or(R, Ri) t = 1 if has_next else 0 trans_t = self.unroll(trans, invar, k+1, gen_list=True) pivot = 2 trans_tA = And(trans_t[:pivot]) init_0 = self.at_time(init, 0) is_sat = True Ri = None self._reset_assertions(solver) while (t < k+1): Logger.log("\nSolving for k=%s"%t, 1) int_c = 0 R = init_0 # trans_t is composed as trans_i, invar_i, trans_i+1, invar_i+1, ... self._add_assertion(solver, trans_t[2*t]) self._add_assertion(solver, trans_t[(2*t)+1]) while True: Logger.log("Add init and invar", 2) self._push(solver) self._add_assertion(solver, R) npropt = self.at_time(nprop, t-1 if has_next else t) Logger.log("Add property time %d"%t, 2) self._add_assertion(solver, npropt) Logger.log("Interpolation at k=%s"%(t), 2) if t > 0: trans_tB = And(trans_t[pivot:(t*2)]) Ri = And(itp.binary_interpolant(And(R, trans_tA), And(trans_tB, npropt))) is_sat = Ri == None if is_sat and self._solve(solver): if R == init_0: Logger.log("Counterexample found with k=%s"%(t), 1) model = self._get_model(solver) return (t, model) else: Logger.log("No counterexample or proof found with k=%s"%(t), 1) Logger.msg(".", 0, not(Logger.level(1))) self._pop(solver) break else: self._pop(solver) if Ri is None: break Ri = substitute(Ri, map_10) res = check_overappr(Ri, R) if res == TRUE(): Logger.log("Proof found with k=%s"%(t), 1) return (t, True) R = res int_c += 1 t += 1 return (t-1, None)
def test_get_logic(self): for example in get_example_formulae(): target_logic = example.logic res = get_logic(example.expr) self.assertEqual(res, target_logic, "%s - %s != %s" % \ (example.expr, target_logic, res))
# represents the grid distance (aka Manhattan distance) of (x,y) from # the origin. z = Symbol("z", REAL) distance= z.Equals(x + y) # We want to characterize the set of points in the rectangle, in terms # of their grid distance from the origin. In other words, we want to # constraint z to be able to assume values that are possible within # the rectangle. We want a formula in z that is satisfiable iff there # is a value for z s.t. exists a value for x,y within the rectangle. # An example of the type of information that we expect to see is the # maximum and minimum value of z. f3 = Exists([x,y], rect & distance) qe_f3 = qelim(f3) print(qe_f3.serialize()) # Depending on the solver in use you might get a different # result. Try: qelim(f3, solver_name="msat_fm") # # MathSAT Fourier Motzkin (FM) returns a compact result: (0.0 # <= z) & (z <= 15.0) , meaning that the further point in grid # distance is at most 15.0 units away from the origin. # # By definition, the expression obtained after performing quantifier # elimination is in the quantifier free fragment of the logic. It is # therefore possible to remove the quantifiers using qelim, and use a # solver that does not support quantifiers natively to solve the new # formula. from pysmt.oracles import get_logic print(get_logic(f3), get_logic(qe_f3))
def is_unsat(self, formula, solver_name=None, logic=None): if logic == AUTO_LOGIC: logic = get_logic(formula, self.environment) with self.Solver(name=solver_name, logic=logic) \ as solver: return solver.is_unsat(formula)
def test_oracle(self): x = FreshSymbol(REAL) f = Equals(Times(x, x), Real(2)) logic = get_logic(f) self.assertFalse(logic.theory.linear)
def test_get_logic(self): for example in EXAMPLE_FORMULAS: target_logic = example.logic res = get_logic(example.expr) self.assertEqual(res, target_logic, "%s - %s != %s" % \ (example.expr, target_logic, res))
def qelim(self, formula, solver_name=None, logic=None): if logic is None or logic == AUTO_LOGIC: logic = get_logic(formula, self.environment) with self.QuantifierEliminator(name=solver_name, logic=logic) as qe: return qe.eliminate_quantifiers(formula)
def solve_safety_int(self, hts, prop, k): init = hts.single_init() trans = hts.single_trans() invar = hts.single_invar() has_next = TS.has_next(prop) map_10 = dict([(TS.get_timed_name(v.symbol_name(), 1), TS.get_timed_name(v.symbol_name(), 0)) for v in hts.vars]) itp = Interpolator(logic=get_logic(trans)) init = And(init, invar) nprop = Not(prop) pivot = 2 t = 1 if has_next else 0 while (t < k+1): Logger.log("\nSolving for k=%s"%t, 1) int_c = 0 init_0 = self.at_time(init, 0) R = init_0 trans_t = self.unroll(trans, invar, t, gen_list=True) trans_tA = And(trans_t[:pivot]) if t > 0 else TRUE() trans_tB = And(trans_t[pivot:]) if t > 0 else TRUE() while True: self._reset_assertions(self.solver) Logger.log("Add init and invar", 2) self._add_assertion(self.solver, R) self._add_assertion(self.solver, And(trans_tA, trans_tB)) npropt = self.at_time(nprop, t-1 if has_next else t) Logger.log("Add property time %d"%t, 2) self._add_assertion(self.solver, npropt) if self._solve(self.solver): if R == init_0: Logger.log("Counterexample found with k=%s"%(t), 1) model = self._get_model(self.solver) return (t, model) else: Logger.log("No counterexample or proof found with k=%s"%(t), 1) Logger.msg(".", 0, not(Logger.level(1))) break else: if len(trans_t) < 2: Logger.log("No counterexample found with k=%s"%(t), 1) Logger.msg(".", 0, not(Logger.level(1))) break Ri = And(itp.binary_interpolant(And(R, trans_tA), And(trans_tB, npropt))) Ri = substitute(Ri, map_10) self._reset_assertions(self.solver) self._add_assertion(self.solver, And(Ri, Not(R))) if not self._solve(self.solver): Logger.log("Proof found with k=%s"%(t), 1) return (t, True) else: R = Or(R, Ri) int_c += 1 Logger.log("Extending initial states (%s)"%int_c, 1) t += 1 return (t-1, None)
def test_get_logic(self): for example in EXAMPLE_FORMULAS: target_logic = example.logic res = get_logic(example.expr) self.assertEqual(res, target_logic, "%s - %s != %s" % (example.expr, target_logic, res))
# represents the grid distance (aka Manhattan distance) of (x,y) from # the origin. z = Symbol("z", REAL) distance = z.Equals(x + y) # We want to characterize the set of points in the rectangle, in terms # of their grid distance from the origin. In other words, we want to # constraint z to be able to assume values that are possible within # the rectangle. We want a formula in z that is satisfiable iff there # is a value for z s.t. exists a value for x,y within the rectangle. # An example of the type of information that we expect to see is the # maximum and minimum value of z. f3 = Exists([x, y], rect & distance) qe_f3 = qelim(f3) print(qe_f3.serialize()) # Depending on the solver in use you might get a different # result. Try: qelim(f3, solver_name="msat_fm") # # MathSAT Fourier Motzkin (FM) returns a compact result: (0.0 # <= z) & (z <= 15.0) , meaning that the further point in grid # distance is at most 15.0 units away from the origin. # # By definition, the expression obtained after performing quantifier # elimination is in the quantifier free fragment of the logic. It is # therefore possible to remove the quantifiers using qelim, and use a # solver that does not support quantifiers natively to solve the new # formula. from pysmt.oracles import get_logic print(get_logic(f3), get_logic(qe_f3))