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

bmc improvements, move fd_solver to self-contained directory

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2018-08-05 10:00:49 -07:00
parent fd09b1a7d0
commit e041ebbe80
21 changed files with 120 additions and 76 deletions

View file

@ -57,7 +57,8 @@ namespace datalog {
m_hnf(m),
m_qe(m, params_ref(), false),
m_rwr(m),
m_ufproc(m) {}
m_ufproc(m),
m_fd_proc(m) {}
void rule_manager::inc_ref(rule * r) {
if (r) {
@ -928,6 +929,23 @@ namespace datalog {
return exist || univ;
}
bool rule_manager::is_finite_domain(rule const& r) const {
m_visited.reset();
m_fd_proc.reset();
for (unsigned i = r.get_uninterpreted_tail_size(); i < r.get_tail_size(); ++i) {
for_each_expr_core<fd_finder_proc,expr_sparse_mark, true, false>(m_fd_proc, m_visited, r.get_tail(i));
}
for (unsigned i = 0; i < r.get_uninterpreted_tail_size(); ++i) {
for (expr* arg : *r.get_tail(i)) {
for_each_expr_core<fd_finder_proc,expr_sparse_mark, true, false>(m_fd_proc, m_visited, arg);
}
}
for (expr* arg : *r.get_head()) {
for_each_expr_core<fd_finder_proc,expr_sparse_mark, true, false>(m_fd_proc, m_visited, arg);
}
return m_fd_proc.is_fd();
}
bool rule::has_negation() const {
for (unsigned i = 0; i < get_uninterpreted_tail_size(); ++i) {
if (is_neg_tail(i)) {

View file

@ -92,6 +92,20 @@ namespace datalog {
void reset() { m_exist = m_univ = false; }
};
struct fd_finder_proc {
ast_manager& m;
bv_util m_bv;
bool m_is_fd;
fd_finder_proc(ast_manager& m): m(m), m_bv(m), m_is_fd(true) {}
bool is_fd() const { return m_is_fd; }
bool is_fd(sort* s) { return m.is_bool(s) || m_bv.is_bv_sort(s); }
void operator()(var* n) { m_is_fd &= is_fd(n->get_sort()); }
void operator()(quantifier* ) { m_is_fd = false; }
void operator()(app* n) { m_is_fd &= is_fd(n->get_decl()->get_range()); }
void reset() { m_is_fd = true; }
};
/**
\brief Manager for the \c rule class
@ -117,6 +131,7 @@ namespace datalog {
mutable uninterpreted_function_finder_proc m_ufproc;
mutable quantifier_finder_proc m_qproc;
mutable expr_sparse_mark m_visited;
mutable fd_finder_proc m_fd_proc;
// only the context can create a rule_manager
@ -265,6 +280,7 @@ namespace datalog {
bool has_uninterpreted_non_predicates(rule const& r, func_decl*& f) const;
void has_quantifiers(rule const& r, bool& existential, bool& universal) const;
bool has_quantifiers(rule const& r) const;
bool is_finite_domain(rule const& r) const;
};

View file

@ -501,6 +501,14 @@ namespace datalog {
}
}
bool rule_set::is_finite_domain() const {
for (rule * r : *this) {
if (!get_rule_manager().is_finite_domain(*r))
return false;
}
return true;
}
void rule_set::display_deps( std::ostream & out ) const
{

View file

@ -253,6 +253,7 @@ namespace datalog {
const func_decl_set & get_output_predicates() const { return m_output_preds; }
func_decl* get_output_predicate() const { SASSERT(m_output_preds.size() == 1); return *m_output_preds.begin(); }
bool is_finite_domain() const;
void display(std::ostream & out) const;

View file

@ -1,8 +1,7 @@
def_module_params('fp',
description='fixedpoint parameters',
export=True,
params=(('timeout', UINT, UINT_MAX, 'set timeout'),
('engine', SYMBOL, 'auto-config',
params=(('engine', SYMBOL, 'auto-config',
'Select: auto-config, datalog, bmc, spacer'),
('datalog.default_table', SYMBOL, 'sparse',
'default table implementation: sparse, hashtable, bitvector, interval'),

View file

@ -17,22 +17,22 @@ Revision History:
--*/
#include "ast/datatype_decl_plugin.h"
#include "ast/dl_decl_plugin.h"
#include "ast/ast_smt_pp.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/bool_rewriter.h"
#include "ast/rewriter/rewriter_def.h"
#include "ast/scoped_proof.h"
#include "smt/smt_solver.h"
#include "tactic/portfolio/fd_solver.h"
#include "muz/base/dl_context.h"
#include "muz/base/dl_rule_transformer.h"
#include "muz/bmc/dl_bmc_engine.h"
#include "muz/transforms/dl_mk_slice.h"
#include "smt/smt_kernel.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/dl_decl_plugin.h"
#include "ast/rewriter/bool_rewriter.h"
#include "model/model_smt2_pp.h"
#include "ast/ast_smt_pp.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/rewriter_def.h"
#include "muz/transforms/dl_transforms.h"
#include "muz/transforms/dl_mk_rule_inliner.h"
#include "ast/scoped_proof.h"
#include "muz/base/fp_params.hpp"
namespace datalog {
@ -53,7 +53,7 @@ namespace datalog {
m_bit_width = 4;
lbool res = l_false;
while (res == l_false) {
b.m_solver.push();
b.m_solver->push();
IF_VERBOSE(1, verbose_stream() << "bit_width: " << m_bit_width << "\n";);
compile();
b.checkpoint();
@ -61,12 +61,12 @@ namespace datalog {
expr* T = m.mk_const(symbol("T"), mk_index_sort());
expr_ref fml(m.mk_app(q, T), m);
b.assert_expr(fml);
res = b.m_solver.check();
res = b.m_solver->check_sat(0, nullptr);
if (res == l_true) {
res = get_model();
}
b.m_solver.pop(1);
b.m_solver->pop(1);
++m_bit_width;
}
return res;
@ -141,10 +141,10 @@ namespace datalog {
}
void setup() {
b.m_fparams.m_relevancy_lvl = 2;
b.m_fparams.m_model = true;
b.m_fparams.m_model_compact = true;
b.m_fparams.m_mbqi = true;
params_ref p;
p.set_uint("smt.relevancy", 2ul);
p.set_bool("smt.mbqi", true);
b.m_solver->updt_params(p);
b.m_rule_trace.reset();
}
@ -252,7 +252,7 @@ namespace datalog {
rational num;
unsigned level, bv_size;
b.m_solver.get_model(md);
b.m_solver->get_model(md);
func_decl* pred = b.m_query_pred;
dl_decl_util util(m);
T = m.mk_const(symbol("T"), mk_index_sort());
@ -468,10 +468,9 @@ namespace datalog {
}
void setup() {
b.m_fparams.m_model = true;
b.m_fparams.m_model_compact = true;
// b.m_fparams.m_mbqi = true;
b.m_fparams.m_relevancy_lvl = 2;
params_ref p;
p.set_uint("smt.relevancy", 2ul);
b.m_solver->updt_params(p);
b.m_rule_trace.reset();
}
@ -482,7 +481,7 @@ namespace datalog {
q_at_level = m.mk_implies(q, p);
b.assert_expr(q_at_level);
expr* qr = q.get();
return b.m_solver.check(1, &qr);
return b.m_solver->check_sat(1, &qr);
}
proof_ref get_proof(model_ref& md, func_decl* pred, app* prop, unsigned level) {
@ -548,7 +547,7 @@ namespace datalog {
scoped_proof _sp(m);
expr_ref level_query = compile_query(b.m_query_pred, level);
model_ref md;
b.m_solver.get_model(md);
b.m_solver->get_model(md);
IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0););
proof_ref pr(m);
pr = get_proof(md, b.m_query_pred, to_app(level_query), level);
@ -755,11 +754,10 @@ namespace datalog {
m_pred2sort.reset();
m_pinned.reset();
m_sort2pred.reset();
b.m_fparams.m_relevancy_lvl = 0;
b.m_fparams.m_model = true;
b.m_fparams.m_model_compact = true;
b.m_fparams.m_mbqi = false;
b.m_fparams.m_relevancy_lvl = 2;
params_ref p;
p.set_uint("smt.relevancy", 2ul);
p.set_bool("smt.mbqi", false);
b.m_solver->updt_params(p);
b.m_rule_trace.reset();
}
@ -1096,12 +1094,12 @@ namespace datalog {
fml = m.mk_app(q, trace.get(), path.get());
b.assert_expr(fml);
while (true) {
lbool is_sat = b.m_solver.check();
lbool is_sat = b.m_solver->check_sat(0, nullptr);
model_ref md;
if (is_sat == l_false) {
return is_sat;
}
b.m_solver.get_model(md);
b.m_solver->get_model(md);
mk_answer(md, trace, path);
return l_true;
}
@ -1111,13 +1109,13 @@ namespace datalog {
expr_ref trace_val(m), eq(m);
trace_val = (*md)(trace);
eq = m.mk_eq(trace, trace_val);
b.m_solver.push();
b.m_solver.assert_expr(eq);
lbool is_sat = b.m_solver.check();
b.m_solver->push();
b.m_solver->assert_expr(eq);
lbool is_sat = b.m_solver->check_sat(0, nullptr);
if (is_sat != l_false) {
b.m_solver.get_model(md);
b.m_solver->get_model(md);
}
b.m_solver.pop(1);
b.m_solver->pop(1);
if (is_sat == l_false) {
IF_VERBOSE(1, verbose_stream() << "infeasible trace " << mk_pp(trace_val, m) << "\n";);
eq = m.mk_not(eq);
@ -1131,8 +1129,8 @@ namespace datalog {
trace = (*md)(trace);
path = (*md)(path);
IF_VERBOSE(2, verbose_stream() << mk_pp(trace, m) << "\n";
for (unsigned i = 0; i < b.m_solver.size(); ++i) {
verbose_stream() << mk_pp(b.m_solver.get_formula(i), m) << "\n";
for (unsigned i = 0; i < b.m_solver->get_num_assertions(); ++i) {
verbose_stream() << mk_pp(b.m_solver->get_assertion(i), m) << "\n";
});
scoped_proof _sp(m);
proof_ref pr(m);
@ -1183,7 +1181,7 @@ namespace datalog {
model_ref md;
proof_ref pr(m);
rule_unifier unifier(b.m_ctx);
b.m_solver.get_model(md);
b.m_solver->get_model(md);
func_decl* pred = b.m_query_pred;
SASSERT(m.is_true(md->get_const_interp(to_app(level_query)->get_decl())));
@ -1283,11 +1281,10 @@ namespace datalog {
void setup() {
b.m_fparams.m_relevancy_lvl = 0;
b.m_fparams.m_model = true;
b.m_fparams.m_model_compact = true;
b.m_fparams.m_mbqi = false;
// m_fparams.m_auto_config = false;
params_ref p;
p.set_uint("smt.relevancy", 0ul);
p.set_bool("smt.mbqi", false);
b.m_solver->updt_params(p);
b.m_rule_trace.reset();
}
@ -1295,7 +1292,7 @@ namespace datalog {
lbool check(unsigned level) {
expr_ref level_query = mk_level_predicate(b.m_query_pred, level);
expr* q = level_query.get();
return b.m_solver.check(1, &q);
return b.m_solver->check_sat(1, &q);
}
expr_ref mk_level_predicate(func_decl* p, unsigned level) {
@ -1428,7 +1425,7 @@ namespace datalog {
engine_base(ctx.get_manager(), "bmc"),
m_ctx(ctx),
m(ctx.get_manager()),
m_solver(m, m_fparams),
m_solver(nullptr),
m_rules(ctx),
m_query_pred(m),
m_answer(m),
@ -1438,7 +1435,7 @@ namespace datalog {
bmc::~bmc() {}
lbool bmc::query(expr* query) {
m_solver.reset();
m_solver = nullptr;
m_answer = nullptr;
m_ctx.ensure_opened();
m_rules.reset();
@ -1471,6 +1468,7 @@ namespace datalog {
IF_VERBOSE(2, m_ctx.display_rules(verbose_stream()););
params_ref p;
if (m_rules.get_num_rules() == 0) {
return l_false;
}
@ -1478,18 +1476,25 @@ namespace datalog {
return l_false;
}
if (is_linear()) {
if (m_ctx.get_engine() == QBMC_ENGINE) {
m_solver = mk_smt_solver(m, p, symbol::null);
qlinear ql(*this);
return ql.check();
}
else {
if (m_rules.is_finite_domain()) {
m_solver = mk_fd_solver(m, p);
}
else {
m_solver = mk_smt_solver(m, p, symbol::null);
}
linear lin(*this);
return lin.check();
}
}
else {
m_solver = mk_smt_solver(m, p, symbol::null);
IF_VERBOSE(0, verbose_stream() << "WARNING: non-linear BMC is highly inefficient\n";);
nonlinear nl(*this);
return nl.check();
@ -1498,7 +1503,7 @@ namespace datalog {
void bmc::assert_expr(expr* e) {
TRACE("bmc", tout << mk_pp(e, m) << "\n";);
m_solver.assert_expr(e);
m_solver->assert_expr(e);
}
bool bmc::is_linear() const {
@ -1525,11 +1530,11 @@ namespace datalog {
}
void bmc::collect_statistics(statistics& st) const {
m_solver.collect_statistics(st);
m_solver->collect_statistics(st);
}
void bmc::reset_statistics() {
m_solver.reset_statistics();
// m_solver->reset_statistics();
}
expr_ref bmc::get_answer() {

View file

@ -22,10 +22,8 @@ Revision History:
#include "util/params.h"
#include "util/statistics.h"
#include "smt/smt_kernel.h"
#include "ast/bv_decl_plugin.h"
#include "smt/params/smt_params.h"
#include "solver/solver.h"
namespace datalog {
class context;
@ -33,8 +31,7 @@ namespace datalog {
class bmc : public engine_base {
context& m_ctx;
ast_manager& m;
smt_params m_fparams;
smt::kernel m_solver;
solver_ref m_solver;
rule_set m_rules;
func_decl_ref m_query_pred;
expr_ref m_answer;

View file

@ -245,7 +245,8 @@ public:
datalog::context& dlctx = m_dl_ctx->dlctx();
set_background(ctx);
dlctx.updt_params(m_params);
unsigned timeout = m_dl_ctx->get_params().timeout();
unsigned timeout = ctx.params().m_timeout;
unsigned rlimit = ctx.params().rlimit();
cancel_eh<reslimit> eh(ctx.m().limit());
bool query_exn = false;
lbool status = l_undef;
@ -253,12 +254,14 @@ public:
IF_VERBOSE(10, verbose_stream() << "(query)\n";);
scoped_ctrl_c ctrlc(eh);
scoped_timer timer(timeout, &eh);
scoped_rlimit _rlimit(ctx.m().limit(), rlimit);
cmd_context::scoped_watch sw(ctx);
try {
status = dlctx.rel_query(1, &m_target);
}
catch (z3_error & ex) {
ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl;
print_statistics(ctx);
throw ex;
}
catch (z3_exception& ex) {