3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-04 02:10:23 +00:00

working on symbolic execution trace unfolding

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2012-10-16 16:54:03 -07:00
parent 6b414ba5cf
commit 3a837037d4
8 changed files with 165 additions and 206 deletions

View file

@ -69,6 +69,10 @@ namespace pdr {
for (; it2 != end2; ++it2) {
dealloc(it2->m_value);
}
rule2expr::iterator it3 = m_rule2transition.begin(), end3 = m_rule2transition.end();
for (; it3 != end3; ++it3) {
m.dec_ref(it3->m_value);
}
}
std::ostream& pred_transformer::display(std::ostream& out) const {
@ -118,7 +122,7 @@ namespace pdr {
return m_reachable.is_reachable(state);
}
datalog::rule const* pred_transformer::find_rule(model_core const& model) const {
datalog::rule const& pred_transformer::find_rule(model_core const& model) const {
obj_map<expr, datalog::rule const*>::iterator it = m_tag2rule.begin(), end = m_tag2rule.end();
TRACE("pdr",
for (; it != end; ++it) {
@ -130,7 +134,7 @@ namespace pdr {
it = m_tag2rule.begin();
if (m_tag2rule.size() == 1) {
return it->m_value;
return *it->m_value;
}
expr_ref vl(m);
@ -138,11 +142,11 @@ namespace pdr {
expr* pred = it->m_key;
TRACE("pdr", tout << mk_pp(pred, m) << "\n";);
if (model.eval(to_app(pred)->get_decl(), vl) && m.is_true(vl)) {
return it->m_value;
return *it->m_value;
}
}
UNREACHABLE();
return 0;
return *((datalog::rule*)0);
}
void pred_transformer::find_predecessors(datalog::rule const& r, ptr_vector<func_decl>& preds) const {
@ -154,10 +158,7 @@ namespace pdr {
}
void pred_transformer::find_predecessors(model_core const& model, ptr_vector<func_decl>& preds) const {
datalog::rule const* r = find_rule(model);
if (r) {
find_predecessors(*r, preds);
}
find_predecessors(find_rule(model), preds);
}
void pred_transformer::remove_predecessors(expr_ref_vector& literals) {
@ -562,6 +563,8 @@ namespace pdr {
SASSERT(is_ground(tmp));
}
expr_ref fml = pm.mk_and(conj);
th_rewriter rw(m);
rw(fml);
TRACE("pdr", tout << mk_pp(fml, m) << "\n";);
SASSERT(is_ground(fml));
if (m.is_false(fml)) {
@ -574,6 +577,8 @@ namespace pdr {
init = m.mk_or(init, fml);
}
transitions.push_back(fml);
m.inc_ref(fml);
m_rule2transition.insert(&rule, fml.get());
rules.push_back(&rule);
}
if (qi) {
@ -715,81 +720,6 @@ namespace pdr {
}
}
void pred_transformer::model2properties(
const model_core & mdl,
unsigned index,
model_node const& n,
expr_ref_vector & res) const {
expr_ref tr1(transition(), m), tr2(m);
expr_ref_vector trs(m), refs(m);
expr_substitution sub(m);
unsigned sz = mdl.get_num_constants();
obj_map<expr,ptr_vector<app> > equivs;
for (unsigned i = 0; i < sz; i++) {
func_decl * d = mdl.get_constant(i);
expr_ref interp(m);
ptr_vector<app> cs;
obj_map<expr,ptr_vector<app> >::obj_map_entry* e;
get_value_from_model(mdl, d, interp);
app* c = m.mk_const(d);
refs.push_back(c);
refs.push_back(interp);
if (m.is_bool(d->get_range())) {
sub.insert(c, interp);
}
else {
e = equivs.insert_if_not_there2(interp, cs);
e->get_data().m_value.push_back(c);
}
}
obj_map<expr,ptr_vector<app> >::iterator it = equivs.begin(), end = equivs.end();
for (; it != end; ++it) {
//
// determine equivalence class representative.
// it is either one of the indexed variables, or it
// is the constant evaluated by the model.
//
ptr_vector<app> const& cs = it->m_value;
expr* rep = 0;
for (unsigned i = 0; !rep && i < cs.size(); ++i) {
if (pm.is_o(cs[i]->get_decl(), index)) {
rep = cs[i];
}
}
if (!rep) {
rep = it->m_key;
}
for (unsigned i = 0; i < cs.size(); ++i) {
if (!pm.is_o(cs[i]->get_decl(), index)) {
sub.insert(cs[i], rep);
}
}
}
scoped_ptr<expr_replacer> rep = mk_default_expr_replacer(m);
rep->set_substitution(&sub);
(*rep)(tr1);
th_rewriter rw(m);
rw(tr1);
TRACE("pdr", tout << "Transition:\n" << mk_pp(tr1, m) << "\n";);
pm.formula_o2n(tr1, tr2, index);
datalog::flatten_and(tr2, trs);
res.append(trs);
TRACE("pdr", tout << "Reduced transition:\n" << mk_pp(tr2, m) << "\n";);
//
// Take state-invariant for indexed formula and select the literals
// that are true under the assignment.
//
//
#if 0
IF_VERBOSE(2, verbose_stream() << "index: " << index << "\n"
<< "level: " << n.level() << "\n"
<< mk_pp(n.pt().get_propagation_formula(m_rels, n.level()), m) << "\n"
<< "propagation formula\n"
<< mk_pp(n.parent()->pt().get_propagation_formula(m_rels, n.level()+1), m) << "\n";);
#endif
}
// ----------------
// model_node
@ -844,8 +774,7 @@ namespace pdr {
model.insert(e, m.mk_true());
}
}
r0 = const_cast<datalog::rule*>(pt().find_rule(*m_model.get()));
SASSERT(r0);
r0 = const_cast<datalog::rule*>(&pt().find_rule(*m_model.get()));
app_ref_vector& inst = pt().get_inst(r0);
TRACE("pdr", tout << mk_pp(state(), m) << "\n";);
for (unsigned i = 0; i < inst.size(); ++i) {
@ -886,12 +815,6 @@ namespace pdr {
return 0;
}
void model_node::get_properties(expr_ref_vector& props) const {
model_node* p = parent();
if (p) {
p->pt().model2properties(p->model(), index(), *this, props);
}
}
// ----------------
// model_search
@ -1256,7 +1179,6 @@ namespace pdr {
for (; it != end; ++it) {
m_rels.insert(it->m_key, it->m_value);
}
VERIFY(m_rels.find(m_query_pred, m_query));
}
unsigned context::get_num_levels(func_decl* p) {
@ -1397,8 +1319,9 @@ namespace pdr {
void context::init_core_generalizers(datalog::rule_set& rules) {
reset_core_generalizers();
classifier_proc classify(m, rules);
if (m_params.get_bool(":use-multicore-generalizer", false)) {
m_core_generalizers.push_back(alloc(core_multi_generalizer, *this));
bool use_mc = m_params.get_bool(":use-multicore-generalizer", false);
if (use_mc) {
m_core_generalizers.push_back(alloc(core_multi_generalizer, *this, 0));
}
if (m_params.get_bool(":use-farkas", true) && !classify.is_bool()) {
if (m_params.get_bool(":inline-proof-mode", true)) {
@ -1414,10 +1337,7 @@ namespace pdr {
m_core_generalizers.push_back(alloc(core_farkas_generalizer, *this, m, m_fparams));
}
}
if (m_params.get_bool(":use-farkas-properties", false)) {
m_core_generalizers.push_back(alloc(core_farkas_properties_generalizer, *this));
}
if (m_params.get_bool(":use-inductive-generalizer", true)) {
if (!use_mc && m_params.get_bool(":use-inductive-generalizer", true)) {
m_core_generalizers.push_back(alloc(core_bool_inductive_generalizer, *this, 0));
}
if (m_params.get_bool(":use-interpolants", false)) {
@ -1540,6 +1460,9 @@ namespace pdr {
}
void context::solve_impl() {
if (!m_rels.find(m_query_pred, m_query)) {
throw inductive_exception();
}
unsigned lvl = 0;
bool reachable;
while (true) {
@ -1643,15 +1566,28 @@ namespace pdr {
}
break;
case l_false: {
bool uses_level = true;
for (unsigned i = 0; !cube.empty() && i < m_core_generalizers.size(); ++i) {
(*m_core_generalizers[i])(n, cube, uses_level);
core_generalizer::cores cores;
cores.push_back(std::make_pair(cube, true));
for (unsigned i = 0; !cores.empty() && i < m_core_generalizers.size(); ++i) {
core_generalizer::cores new_cores;
for (unsigned j = 0; j < cores.size(); ++j) {
(*m_core_generalizers[i])(n, cores[j].first, cores[j].second, new_cores);
}
cores.reset();
cores.append(new_cores);
}
bool found_invariant = false;
for (unsigned i = 0; i < cores.size(); ++i) {
expr_ref_vector const& core = cores[i].first;
bool uses_level = cores[i].second;
found_invariant = !uses_level || found_invariant;
expr_ref ncore(m_pm.mk_not_and(core), m);
TRACE("pdr", tout << "invariant state: " << (uses_level?"":"(inductive) ") << mk_pp(ncore, m) << "\n";);
n.pt().add_property(ncore, uses_level?n.level():infty_level);
}
expr_ref ncube(m_pm.mk_not_and(cube), m);
TRACE("pdr", tout << "invariant state: " << (uses_level?"":"(inductive) ") << mk_pp(ncube, m) << "\n";);
n.pt().add_property(ncube, uses_level?n.level():infty_level);
CASSERT("pdr",n.level() == 0 || check_invariant(n.level()-1));
m_search.backtrack_level(uses_level && m_params.get_bool(":flexible-trace", false), n);
m_search.backtrack_level(!found_invariant && m_params.get_bool(":flexible-trace", false), n);
break;
}
case l_undef: {
@ -1707,10 +1643,13 @@ namespace pdr {
SASSERT(level > 0);
n.pt().find_predecessors(n.model(), preds);
n.pt().remove_predecessors(literals);
TRACE("pdr", tout << mk_pp(model, m) << "\n";
TRACE("pdr",
model_v2_pp(tout, n.model());
tout << "Model cube\n";
tout << mk_pp(model, m) << "\n";
tout << "Predecessors\n";
for (unsigned i = 0; i < preds.size(); ++i) {
tout << mk_pp(preds[i], m) << "\n";
tout << preds[i]->get_name() << "\n";
}
);
for (unsigned i = 0; i < preds.size(); ++i) {
@ -1729,6 +1668,58 @@ namespace pdr {
TRACE("pdr", m_search.display(tout););
}
/**
\brief create children states from model cube.
Introduce the shorthands:
- T(x0,x1,x) for transition
- phi(x) for n.state()
- psi(x0,x1,x) for psi
- M(x0,x1,x) for n.model()
Assumptions:
M => psi
psi => phi & T
psi & M agree on which rules are taken.
In other words,
1. psi is a weakening of M
2. phi & T is implied by psi
Goal is to find phi0(x0), phi1(x1) such that:
phi(x) & phi0(x0) & phi1(x1) => psi(x0, x1, x)
Strategy:
- perform cheap existential quantifier elimination on
exists x . T(x0,x1,x) & phi(x)
(e.g., destructive equality resolution)
- pull equalities that use
*/
void context::create_children2(model_node& n, expr* psi) {
SASSERT(n.level() > 0);
model_core const& M = n.model();
datalog::rule const& r = n.pt().find_rule(M);
expr* T = n.pt().get_transition(r);
expr* phi = n.state();
expr_ref_vector Ts(m);
datalog::flatten_and(T, Ts);
ptr_vector<func_decl> preds;
n.pt().find_predecessors(r, preds);
n.pt().remove_predecessors(Ts);
// TBD ...
TRACE("pdr", m_search.display(tout););
}
void context::collect_statistics(statistics& st) const {
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
for (it = m_rels.begin(); it != end; ++it) {