3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 17:15:31 +00:00

moved smt tactic to smt folder

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2012-11-01 08:48:54 -07:00
parent 81df5ca96f
commit 7cdf5e493b
5 changed files with 1 additions and 1 deletions

View file

@ -0,0 +1,282 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
ctx_solver_simplify_tactic.cpp
Abstract:
Context simplifier for propagating solver assignments.
Author:
Nikolaj (nbjorner) 2012-3-6
Notes:
--*/
#include"ctx_solver_simplify_tactic.h"
#include"arith_decl_plugin.h"
#include"front_end_params.h"
#include"smt_solver.h"
#include"ast_pp.h"
#include"mk_simplified_app.h"
class ctx_solver_simplify_tactic : public tactic {
ast_manager& m;
params_ref m_params;
front_end_params m_front_p;
smt::solver m_solver;
arith_util m_arith;
mk_simplified_app m_mk_app;
func_decl_ref m_fn;
unsigned m_num_steps;
public:
ctx_solver_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()):
m(m), m_params(p), m_solver(m, m_front_p), m_arith(m), m_mk_app(m), m_fn(m), m_num_steps(0) {
sort* i_sort = m_arith.mk_int();
m_fn = m.mk_func_decl(symbol(0xbeef101), i_sort, m.mk_bool_sort());
}
virtual tactic * translate(ast_manager & m) {
return alloc(ctx_solver_simplify_tactic, m, m_params);
}
virtual ~ctx_solver_simplify_tactic() {}
virtual void updt_params(params_ref const & p) {
m_solver.updt_params(p);
}
virtual void collect_param_descrs(param_descrs & r) {
m_solver.collect_param_descrs(r);
}
virtual void collect_statistics(statistics & st) const {
st.update("solver-simplify-steps", m_num_steps);
}
virtual void reset_statistics() { m_num_steps = 0; }
virtual void operator()(goal_ref const & in,
goal_ref_buffer & result,
model_converter_ref & mc,
proof_converter_ref & pc,
expr_dependency_ref & core) {
mc = 0; pc = 0; core = 0;
reduce(*(in.get()));
in->inc_depth();
result.push_back(in.get());
}
virtual void cleanup() {
reset_statistics();
m_solver.reset();
}
protected:
virtual void set_cancel(bool f) {
m_solver.set_cancel(f);
}
void reduce(goal& g) {
SASSERT(g.is_well_sorted());
m_num_steps = 0;
expr_ref fml(m);
tactic_report report("ctx-solver-simplify", g);
if (g.inconsistent())
return;
ptr_vector<expr> fmls;
g.get_formulas(fmls);
fml = m.mk_and(fmls.size(), fmls.c_ptr());
reduce(fml);
g.reset();
g.assert_expr(fml, 0, 0);
IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(ctx-solver-simplify :num-steps " << m_num_steps << ")\n";);
SASSERT(g.is_well_sorted());
}
void reduce(expr_ref& result){
SASSERT(m.is_bool(result));
ptr_vector<expr> todo;
ptr_vector<expr> names;
svector<bool> is_checked;
svector<unsigned> parent_ids, self_ids;
expr_ref_vector fresh_vars(m), trail(m);
expr_ref res(m);
obj_map<expr,std::pair<unsigned, expr*> > cache;
unsigned id = 1;
expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true));
expr* n2, *fml;
unsigned path_id = 0, self_pos = 0;
app * a;
unsigned sz;
std::pair<unsigned,expr*> path_r;
ptr_vector<expr> found;
fml = result.get();
m_solver.assert_expr(m.mk_not(m.mk_iff(fml, n)));
trail.push_back(n);
todo.push_back(fml);
names.push_back(n);
is_checked.push_back(false);
parent_ids.push_back(0);
self_ids.push_back(0);
m_solver.push();
while (!todo.empty()) {
expr_ref res(m);
ptr_buffer<expr> args;
expr* e = todo.back();
unsigned pos = parent_ids.back();
n = names.back();
bool checked = is_checked.back();
if (cache.contains(e)) {
goto done;
}
if (!m.is_bool(e)) {
res = e;
goto done;
}
if (m.is_bool(e) && !checked && simplify_bool(n, res)) {
goto done;
}
if (!is_app(e)) {
res = e;
goto done;
}
a = to_app(e);
if (!is_checked.back()) {
self_ids.back() = ++path_id;
is_checked.back() = true;
}
self_pos = self_ids.back();
sz = a->get_num_args();
n2 = 0;
found.reset(); // arguments already simplified.
for (unsigned i = 0; i < sz; ++i) {
expr* arg = a->get_arg(i);
if (!m.is_bool(arg)) {
args.push_back(arg);
}
else if (cache.find(arg, path_r) && !found.contains(arg)) {
//
// This is a single traversal version of the context
// simplifier. It simplifies only the first occurrence of
// a formula with respect to the context.
//
found.push_back(arg);
if (path_r.first == self_pos) {
TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << "\n";);
args.push_back(path_r.second);
}
else {
res = local_simplify(a, n, id, i);
TRACE("ctx_solver_simplify_tactic",
tout << "Already cached: " << path_r.first << " " << mk_pp(res, m) << "\n";);
args.push_back(arg);
}
}
else if (!n2 && !found.contains(arg)) {
n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true));
todo.push_back(arg);
parent_ids.push_back(self_pos);
self_ids.push_back(0);
names.push_back(n2);
trail.push_back(n2);
args.push_back(n2);
is_checked.push_back(false);
}
else {
args.push_back(arg);
}
}
m_mk_app(a->get_decl(), args.size(), args.c_ptr(), res);
trail.push_back(res);
// child needs to be visited.
if (n2) {
m_solver.push();
m_solver.assert_expr(m.mk_eq(res, n));
continue;
}
done:
if (res) {
cache.insert(e, std::make_pair(pos, res));
}
TRACE("ctx_solver_simplify_tactic",
tout << mk_pp(e, m) << " checked: " << checked << " cached: " << mk_pp(res?res.get():e, m) << "\n";);
todo.pop_back();
parent_ids.pop_back();
self_ids.pop_back();
names.pop_back();
is_checked.pop_back();
m_solver.pop(1);
}
VERIFY(cache.find(fml, path_r));
result = path_r.second;
}
bool simplify_bool(expr* n, expr_ref& res) {
m_solver.push();
m_solver.assert_expr(n);
lbool is_sat = m_solver.check();
m_solver.pop(1);
if (is_sat == l_false) {
res = m.mk_true();
return true;
}
m_solver.push();
m_solver.assert_expr(m.mk_not(n));
is_sat = m_solver.check();
m_solver.pop(1);
if (is_sat == l_false) {
res = m.mk_false();
return true;
}
return false;
}
expr_ref local_simplify(app* a, expr* n, unsigned& id, unsigned index) {
SASSERT(index < a->get_num_args());
SASSERT(m.is_bool(a->get_arg(index)));
expr_ref n2(m), result(m);
n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true));
ptr_buffer<expr> args;
for (unsigned i = 0; i < a->get_num_args(); ++i) {
if (i == index) {
args.push_back(n2);
}
else {
args.push_back(a->get_arg(i));
}
}
m_mk_app(a->get_decl(), args.size(), args.c_ptr(), result);
m_solver.push();
m_solver.assert_expr(m.mk_eq(result, n));
if (!simplify_bool(n2, result)) {
result = a;
}
m_solver.pop(1);
return result;
}
};
tactic * mk_ctx_solver_simplify_tactic(ast_manager & m, params_ref const & p) {
return clean(alloc(ctx_solver_simplify_tactic, m, p));
}

View file

@ -0,0 +1,29 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
ctx_solver_simplify_tactic.h
Abstract:
Context simplifier for propagating solver assignments.
Author:
Nikolaj (nbjorner) 2012-3-6
Notes:
--*/
#ifndef _CTX_SOLVER_SIMPLIFY_TACTIC_H_
#define _CTX_SOLVER_SIMPLIFY_TACTIC_H_
#include"tactical.h"
tactic * mk_ctx_solver_simplify_tactic(ast_manager & m, params_ref const & p = params_ref());
/*
ADD_TACTIC("ctx-solver-simplify", "apply solver-based contextual simplification rules.", "mk_ctx_solver_simplify_tactic(m, p)")
*/
#endif

View file

@ -0,0 +1,323 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
smt_tactic.h
Abstract:
smt::context as a tactic.
Author:
Leonardo (leonardo) 2011-10-18
Notes:
--*/
#include"tactic.h"
#include"tactical.h"
#include"smt_solver.h"
#include"front_end_params.h"
#include"params2front_end_params.h"
#include"rewriter_types.h"
class smt_tactic : public tactic {
scoped_ptr<front_end_params> m_params;
params_ref m_params_ref;
statistics m_stats;
std::string m_failure;
smt::solver * m_ctx;
symbol m_logic;
progress_callback * m_callback;
bool m_candidate_models;
bool m_fail_if_inconclusive;
public:
smt_tactic(params_ref const & p):
m_params_ref(p),
m_ctx(0),
m_callback(0) {
updt_params_core(p);
TRACE("smt_tactic", tout << this << "\np: " << p << "\n";);
}
virtual tactic * translate(ast_manager & m) {
return alloc(smt_tactic, m_params_ref);
}
virtual ~smt_tactic() {
SASSERT(m_ctx == 0);
}
front_end_params & fparams() {
if (!m_params) {
m_params = alloc(front_end_params);
params2front_end_params(m_params_ref, fparams());
}
return *m_params;
}
void updt_params_core(params_ref const & p) {
m_candidate_models = p.get_bool(":candidate-models", false);
m_fail_if_inconclusive = p.get_bool(":fail-if-inconclusive", true);
}
virtual void updt_params(params_ref const & p) {
TRACE("smt_tactic", tout << this << "\nupdt_params: " << p << "\n";);
updt_params_core(p);
m_params_ref = p;
params2front_end_params(m_params_ref, fparams());
SASSERT(p.get_bool(":auto_config", fparams().m_auto_config) == fparams().m_auto_config);
}
virtual void collect_param_descrs(param_descrs & r) {
r.insert(":candidate-models", CPK_BOOL, "(default: false) create candidate models even when quantifier or theory reasoning is incomplete.");
r.insert(":fail-if-inconclusive", CPK_BOOL, "(default: true) fail if found unsat (sat) for under (over) approximated goal.");
solver_front_end_params_descrs(r);
}
virtual void set_cancel(bool f) {
if (m_ctx)
m_ctx->set_cancel(f);
}
virtual void collect_statistics(statistics & st) const {
if (m_ctx)
m_ctx->collect_statistics(st); // ctx is still running...
else
st.copy(m_stats);
}
virtual void cleanup() {
}
virtual void reset_statistics() {
m_stats.reset();
}
// for backward compatibility
virtual void set_front_end_params(front_end_params & p) {
m_params = alloc(front_end_params, p);
SASSERT(m_params.get() == &fparams());
// must propagate the params_ref to fparams
params2front_end_params(m_params_ref, fparams());
}
virtual void set_logic(symbol const & l) {
m_logic = l;
}
virtual void set_progress_callback(progress_callback * callback) {
m_callback = callback;
}
struct scoped_init_ctx {
smt_tactic & m_owner;
scoped_init_ctx(smt_tactic & o, ast_manager & m):m_owner(o) {
smt::solver * new_ctx = alloc(smt::solver, m, o.fparams());
TRACE("smt_tactic", tout << "logic: " << o.m_logic << "\n";);
new_ctx->set_logic(o.m_logic);
if (o.m_callback) {
new_ctx->set_progress_callback(o.m_callback);
}
#pragma omp critical (as_st_solver)
{
o.m_ctx = new_ctx;
}
}
~scoped_init_ctx() {
smt::solver * d = m_owner.m_ctx;
#pragma omp critical (as_st_cancel)
{
m_owner.m_ctx = 0;
}
if (d)
dealloc(d);
}
};
typedef obj_map<expr, expr *> expr2expr_map;
virtual void operator()(goal_ref const & in,
goal_ref_buffer & result,
model_converter_ref & mc,
proof_converter_ref & pc,
expr_dependency_ref & core) {
try {
SASSERT(in->is_well_sorted());
ast_manager & m = in->m();
TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " "
<< " PREPROCESS: " << fparams().m_preprocess << ", SOLVER:" << fparams().m_solver << "\n";
tout << "fail-if-inconclusive: " << m_fail_if_inconclusive << "\n";
tout << "params_ref: " << m_params_ref << "\n";);
TRACE("smt_tactic_detail", in->display(tout););
TRACE("smt_tactic_memory", tout << "wasted_size: " << m.get_allocator().get_wasted_size() << "\n";);
scoped_init_ctx init(*this, m);
SASSERT(m_ctx != 0);
scoped_ptr<expr2expr_map> dep2bool;
scoped_ptr<expr2expr_map> bool2dep;
ptr_vector<expr> assumptions;
if (in->unsat_core_enabled()) {
if (in->proofs_enabled())
throw tactic_exception("smt tactic does not support simultaneous generation of proofs and unsat cores");
dep2bool = alloc(expr2expr_map);
bool2dep = alloc(expr2expr_map);
ptr_vector<expr> deps;
ptr_vector<expr> clause;
unsigned sz = in->size();
for (unsigned i = 0; i < sz; i++) {
expr * f = in->form(i);
expr_dependency * d = in->dep(i);
if (d == 0) {
m_ctx->assert_expr(f);
}
else {
// create clause (not d1 \/ ... \/ not dn \/ f) when the d's are the assumptions/dependencies of f.
clause.reset();
clause.push_back(f);
deps.reset();
m.linearize(d, deps);
SASSERT(!deps.empty()); // d != 0, then deps must not be empty
ptr_vector<expr>::iterator it = deps.begin();
ptr_vector<expr>::iterator end = deps.end();
for (; it != end; ++it) {
expr * d = *it;
if (is_uninterp_const(d) && m.is_bool(d)) {
// no need to create a fresh boolean variable for d
if (!bool2dep->contains(d)) {
assumptions.push_back(d);
bool2dep->insert(d, d);
}
clause.push_back(m.mk_not(d));
}
else {
// must normalize assumption
expr * b = 0;
if (!dep2bool->find(d, b)) {
b = m.mk_fresh_const(0, m.mk_bool_sort());
dep2bool->insert(d, b);
bool2dep->insert(b, d);
assumptions.push_back(b);
}
clause.push_back(m.mk_not(b));
}
}
SASSERT(clause.size() > 1);
expr_ref cls(m);
cls = m.mk_or(clause.size(), clause.c_ptr());
m_ctx->assert_expr(cls);
}
}
}
else if (in->proofs_enabled()) {
unsigned sz = in->size();
for (unsigned i = 0; i < sz; i++) {
m_ctx->assert_expr(in->form(i), in->pr(i));
}
}
else {
unsigned sz = in->size();
for (unsigned i = 0; i < sz; i++) {
m_ctx->assert_expr(in->form(i));
}
}
lbool r;
if (assumptions.empty())
r = m_ctx->setup_and_check();
else
r = m_ctx->check(assumptions.size(), assumptions.c_ptr());
m_ctx->collect_statistics(m_stats);
switch (r) {
case l_true: {
if (m_fail_if_inconclusive && !in->sat_preserved())
throw tactic_exception("over-approximated goal found to be sat");
// the empty assertion set is trivially satifiable.
in->reset();
result.push_back(in.get());
// store the model in a do nothin model converter.
if (in->models_enabled()) {
model_ref md;
m_ctx->get_model(md);
mc = model2model_converter(md.get());
}
pc = 0;
core = 0;
return;
}
case l_false: {
if (m_fail_if_inconclusive && !in->unsat_preserved()) {
TRACE("smt_tactic", tout << "failed to show to be unsat...\n";);
throw tactic_exception("under-approximated goal found to be unsat");
}
// formula is unsat, reset the goal, and store false there.
in->reset();
proof * pr = 0;
expr_dependency * lcore = 0;
if (in->proofs_enabled())
pr = m_ctx->get_proof();
if (in->unsat_core_enabled()) {
unsigned sz = m_ctx->get_unsat_core_size();
for (unsigned i = 0; i < sz; i++) {
expr * b = m_ctx->get_unsat_core_expr(i);
SASSERT(is_uninterp_const(b) && m.is_bool(b));
expr * d = bool2dep->find(b);
lcore = m.mk_join(lcore, m.mk_leaf(d));
}
}
in->assert_expr(m.mk_false(), pr, lcore);
result.push_back(in.get());
mc = 0;
pc = 0;
core = 0;
return;
}
case l_undef:
if (m_fail_if_inconclusive)
throw tactic_exception("smt tactic failed to show goal to be sat/unsat");
result.push_back(in.get());
if (m_candidate_models) {
switch (m_ctx->last_failure()) {
case smt::NUM_CONFLICTS:
case smt::THEORY:
case smt::QUANTIFIERS:
if (in->models_enabled()) {
model_ref md;
m_ctx->get_model(md);
mc = model2model_converter(md.get());
}
pc = 0;
core = 0;
return;
default:
break;
}
}
m_failure = m_ctx->last_failure_as_string();
throw tactic_exception(m_failure.c_str());
}
}
catch (rewriter_exception & ex) {
throw tactic_exception(ex.msg());
}
}
};
tactic * mk_smt_tactic(params_ref const & p) {
return alloc(smt_tactic, p);
}
tactic * mk_smt_tactic_using(bool auto_config, params_ref const & _p) {
params_ref p = _p;
p.set_bool(":auto-config", auto_config);
tactic * r = mk_smt_tactic(p);
TRACE("smt_tactic", tout << "auto_config: " << auto_config << "\nr: " << r << "\np: " << p << "\n";);
return using_params(r, p);
}

View file

@ -0,0 +1,34 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
smt_tactic.h
Abstract:
smt::context as a tactic.
Author:
Leonardo (leonardo) 2011-10-18
Notes:
--*/
#ifndef _SMT_TACTIC_H_
#define _SMT_TACTIC_H_
#include"params.h"
class tactic;
tactic * mk_smt_tactic(params_ref const & p = params_ref());
// syntax sugar for using_params(mk_smt_tactic(), p) where p = (:auto_config, auto_config)
tactic * mk_smt_tactic_using(bool auto_config = true, params_ref const & p = params_ref());
/*
ADD_TACTIC("smt", "apply a SAT based SMT solver.", "mk_smt_tactic(p)")
*/
#endif