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

working on symbolic execution for PDR

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2012-10-18 21:01:28 -07:00
parent 3a837037d4
commit 8f5fc3716e
13 changed files with 847 additions and 1014 deletions

View file

@ -832,6 +832,7 @@ inline bool is_app(ast const * n) { return n->get_kind() == AST_APP; }
inline bool is_var(ast const * n) { return n->get_kind() == AST_VAR; } inline bool is_var(ast const * n) { return n->get_kind() == AST_VAR; }
inline bool is_quantifier(ast const * n) { return n->get_kind() == AST_QUANTIFIER; } inline bool is_quantifier(ast const * n) { return n->get_kind() == AST_QUANTIFIER; }
inline bool is_forall(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->is_forall(); } inline bool is_forall(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->is_forall(); }
inline bool is_exists(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->is_exists(); }
// ----------------------------------- // -----------------------------------
// //

View file

@ -20,8 +20,8 @@ Notes:
Implements proof rule of the form: Implements proof rule of the form:
a(x) & q(x) -> p(x) b(y) & q(y) -> p(y) a(x) & q(x) -> p(x), b(y) & q(y) -> p(y)
--------------------------------------------- ----------------------------------------------
(a(z) \/ b(z)) & q(z) -> p(z) (a(z) \/ b(z)) & q(z) -> p(z)

View file

@ -753,6 +753,7 @@
<ClCompile Include="qe_bv_plugin.cpp" /> <ClCompile Include="qe_bv_plugin.cpp" />
<ClCompile Include="qe_datatype_plugin.cpp" /> <ClCompile Include="qe_datatype_plugin.cpp" />
<ClCompile Include="qe_dl_plugin.cpp" /> <ClCompile Include="qe_dl_plugin.cpp" />
<ClCompile Include="qe_lite.cpp" />
<ClCompile Include="qe_sat_tactic.cpp" /> <ClCompile Include="qe_sat_tactic.cpp" />
<ClCompile Include="qe_tactic.cpp" /> <ClCompile Include="qe_tactic.cpp" />
<ClCompile Include="qffpa_tactic.cpp" /> <ClCompile Include="qffpa_tactic.cpp" />
@ -1160,6 +1161,7 @@
<ClInclude Include="pull_ite_tree.h" /> <ClInclude Include="pull_ite_tree.h" />
<ClInclude Include="pull_quant.h" /> <ClInclude Include="pull_quant.h" />
<ClInclude Include="push_app_ite.h" /> <ClInclude Include="push_app_ite.h" />
<ClInclude Include="qe_lite.h" />
<ClInclude Include="qe_sat_tactic.h" /> <ClInclude Include="qe_sat_tactic.h" />
<ClInclude Include="qfnra_sign.h" /> <ClInclude Include="qfnra_sign.h" />
<ClInclude Include="qfuf_strategy.h" /> <ClInclude Include="qfuf_strategy.h" />

View file

@ -41,6 +41,7 @@ Notes:
#include "model_smt2_pp.h" #include "model_smt2_pp.h"
#include "dl_mk_rule_inliner.h" #include "dl_mk_rule_inliner.h"
#include "ast_smt2_pp.h" #include "ast_smt2_pp.h"
#include "qe_lite.h"
namespace pdr { namespace pdr {
@ -124,7 +125,7 @@ namespace pdr {
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(); obj_map<expr, datalog::rule const*>::iterator it = m_tag2rule.begin(), end = m_tag2rule.end();
TRACE("pdr", TRACE("pdr_verbose",
for (; it != end; ++it) { for (; it != end; ++it) {
expr* pred = it->m_key; expr* pred = it->m_key;
tout << mk_pp(pred, m) << ":\n"; tout << mk_pp(pred, m) << ":\n";
@ -394,7 +395,7 @@ namespace pdr {
lbool is_sat = m_solver.check_conjunction_as_assumptions(n.state()); lbool is_sat = m_solver.check_conjunction_as_assumptions(n.state());
if (is_sat == l_true && core) { if (is_sat == l_true && core) {
core->reset(); core->reset();
model2cube(*model, *core); model2cube(*model,*core);
n.set_model(model); n.set_model(model);
} }
return is_sat; return is_sat;
@ -522,6 +523,7 @@ namespace pdr {
expr_ref_vector conj(m); expr_ref_vector conj(m);
app_ref_vector& var_reprs = *(alloc(app_ref_vector, m)); app_ref_vector& var_reprs = *(alloc(app_ref_vector, m));
qinst* qi = 0; qinst* qi = 0;
ptr_vector<app> aux_vars;
unsigned ut_size = rule.get_uninterpreted_tail_size(); unsigned ut_size = rule.get_uninterpreted_tail_size();
unsigned t_size = rule.get_tail_size(); unsigned t_size = rule.get_tail_size();
@ -534,7 +536,7 @@ namespace pdr {
init_atom(pts, rule.get_tail(i), var_reprs, conj, i); init_atom(pts, rule.get_tail(i), var_reprs, conj, i);
} }
for (unsigned i = ut_size; i < t_size; ++i) { for (unsigned i = ut_size; i < t_size; ++i) {
ground_free_vars(rule.get_tail(i), var_reprs); ground_free_vars(rule.get_tail(i), var_reprs, aux_vars);
} }
SASSERT(check_filled(var_reprs)); SASSERT(check_filled(var_reprs));
expr_ref_vector tail(m); expr_ref_vector tail(m);
@ -585,6 +587,7 @@ namespace pdr {
m_rule2qinst.insert(&rule, qi); m_rule2qinst.insert(&rule, qi);
} }
m_rule2inst.insert(&rule,&var_reprs); m_rule2inst.insert(&rule,&var_reprs);
m_rule2vars.insert(&rule, aux_vars);
} }
bool pred_transformer::check_filled(app_ref_vector const& v) const { bool pred_transformer::check_filled(app_ref_vector const& v) const {
@ -595,7 +598,7 @@ namespace pdr {
} }
// create constants for free variables in tail. // create constants for free variables in tail.
void pred_transformer::ground_free_vars(expr* e, app_ref_vector& vars) { void pred_transformer::ground_free_vars(expr* e, app_ref_vector& vars, ptr_vector<app>& aux_vars) {
ptr_vector<sort> sorts; ptr_vector<sort> sorts;
get_free_vars(e, sorts); get_free_vars(e, sorts);
while (vars.size() < sorts.size()) { while (vars.size() < sorts.size()) {
@ -604,6 +607,7 @@ namespace pdr {
for (unsigned i = 0; i < sorts.size(); ++i) { for (unsigned i = 0; i < sorts.size(); ++i) {
if (sorts[i] && !vars[i].get()) { if (sorts[i] && !vars[i].get()) {
vars[i] = m.mk_fresh_const("aux", sorts[i]); vars[i] = m.mk_fresh_const("aux", sorts[i]);
aux_vars.push_back(vars[i].get());
} }
} }
} }
@ -1099,6 +1103,7 @@ namespace pdr {
m_inductive_lvl(0), m_inductive_lvl(0),
m_cancel(false) m_cancel(false)
{ {
m_use_model_generalizer = m_params.get_bool("use-model-generalizer", false);
} }
context::~context() { context::~context() {
@ -1296,19 +1301,9 @@ namespace pdr {
void context::init_model_generalizers(datalog::rule_set& rules) { void context::init_model_generalizers(datalog::rule_set& rules) {
reset_model_generalizers(); reset_model_generalizers();
classifier_proc classify(m, rules); if (m_use_model_generalizer) {
if (classify.is_bool_arith()) {
m_model_generalizers.push_back(alloc(bool_model_evaluation_generalizer, *this, m));
}
else {
m_model_generalizers.push_back(alloc(model_evaluation_generalizer, *this, m)); m_model_generalizers.push_back(alloc(model_evaluation_generalizer, *this, m));
} }
if (m_params.get_bool(":use-farkas-model", false)) {
m_model_generalizers.push_back(alloc(model_farkas_generalizer, *this));
}
if (m_params.get_bool(":use-precondition-generalizer", false)) {
m_model_generalizers.push_back(alloc(model_precond_generalizer, *this));
}
} }
void context::reset_core_generalizers() { void context::reset_core_generalizers() {
@ -1556,12 +1551,11 @@ namespace pdr {
close_node(n); close_node(n);
} }
else { else {
TRACE("pdr", tout << "node: " << &n << "\n"; TRACE("pdr", tout << "node: " << &n << "\n";);
expr_ref cb(m.mk_and(cube.size(),cube.c_ptr()), m);
tout << mk_pp(cb.get(), m) << "\n";);
for (unsigned i = 0; i < m_model_generalizers.size(); ++i) { for (unsigned i = 0; i < m_model_generalizers.size(); ++i) {
(*m_model_generalizers[i])(n, cube); (*m_model_generalizers[i])(n, cube);
} }
create_children(n, m_pm.mk_and(cube)); create_children(n, m_pm.mk_and(cube));
} }
break; break;
@ -1634,7 +1628,11 @@ namespace pdr {
} }
// create children states from model cube. // create children states from model cube.
void context::create_children(model_node& n, expr* model) { void context::create_children(model_node& n, expr* model) {
if (!m_use_model_generalizer) {
create_children2(n);
return;
}
expr_ref_vector literals(m), sub_lits(m); expr_ref_vector literals(m), sub_lits(m);
expr_ref o_cube(m), n_cube(m); expr_ref o_cube(m), n_cube(m);
datalog::flatten_and(model, literals); datalog::flatten_and(model, literals);
@ -1652,6 +1650,7 @@ namespace pdr {
tout << preds[i]->get_name() << "\n"; tout << preds[i]->get_name() << "\n";
} }
); );
for (unsigned i = 0; i < preds.size(); ++i) { for (unsigned i = 0; i < preds.size(); ++i) {
pred_transformer& pt = *m_rels.find(preds[i]); pred_transformer& pt = *m_rels.find(preds[i]);
SASSERT(pt.head() == preds[i]); SASSERT(pt.head() == preds[i]);
@ -1689,34 +1688,149 @@ namespace pdr {
Goal is to find phi0(x0), phi1(x1) such that: Goal is to find phi0(x0), phi1(x1) such that:
phi(x) & phi0(x0) & phi1(x1) => psi(x0, x1, x) phi(x) & phi0(x0) & phi1(x1) => psi(x0, x1, x)
or at least (ignoring psi alltogether):
phi(x) & phi0(x0) & phi1(x1) => T(x0, x1, x)
Strategy: Strategy:
- Extract literals from T & phi using ternary simulation with M.
- resulting formula is Phi.
- perform cheap existential quantifier elimination on - perform cheap existential quantifier elimination on
exists x . T(x0,x1,x) & phi(x) Phi <- exists x . Phi(x0,x1,x)
(e.g., destructive equality resolution) (e.g., destructive equality resolution)
- Sub-strategy 1: rename remaining x to fresh variables.
- Sub-strategy 2: replace remaining x to M(x).
- For each literal L in result:
- if L is x0 pure, add L to L0
- if L is x1 pure, add L to L1
- if L mixes x0, x1, add x1 = M(x1) to L1, add L(x1 |-> M(x1)) to L0
- Create sub-goals for L0 and L1.
- pull equalities that use
*/ */
void context::create_children2(model_node& n, expr* psi) { void context::create_children2(model_node& n) {
SASSERT(n.level() > 0); SASSERT(n.level() > 0);
model_core const& M = n.model(); pred_transformer& pt = n.pt();
datalog::rule const& r = n.pt().find_rule(M); model_ref M = n.model_ptr();
expr* T = n.pt().get_transition(r); datalog::rule const& r = pt.find_rule(*M);
expr* T = pt.get_transition(r);
expr* phi = n.state(); expr* phi = n.state();
expr_ref_vector Ts(m); IF_VERBOSE(2, verbose_stream() << "Model:\n";
datalog::flatten_and(T, Ts); model_smt2_pp(verbose_stream(), m, *M, 0);
verbose_stream() << "\n";
verbose_stream() << "Transition:\n" << mk_pp(T, m) << "\n";
verbose_stream() << "Phi:\n" << mk_pp(phi, m) << "\n";);
model_evaluator mev(m);
expr_ref_vector mdl(m), forms(m);
forms.push_back(T);
forms.push_back(phi);
datalog::flatten_and(forms);
ptr_vector<expr> forms1(forms.size(), forms.c_ptr());
expr_ref_vector Phi = mev.minimize_literals(forms1, M);
ptr_vector<func_decl> preds; ptr_vector<func_decl> preds;
n.pt().find_predecessors(r, preds); pt.find_predecessors(r, preds);
n.pt().remove_predecessors(Ts); pt.remove_predecessors(Phi);
app_ref_vector vars(m);
unsigned sig_size = pt.head()->get_arity();
for (unsigned i = 0; i < sig_size; ++i) {
vars.push_back(m.mk_const(m_pm.o2n(pt.sig(i), 0)));
}
ptr_vector<app> aux_vars;
pt.get_aux_vars(r, aux_vars);
vars.append(aux_vars.size(), aux_vars.c_ptr());
qe_lite qe(m);
expr_ref phi1 = m_pm.mk_and(Phi);
qe(vars, phi1);
IF_VERBOSE(2,
verbose_stream() << "Vars:\n";
for (unsigned i = 0; i < vars.size(); ++i) {
verbose_stream() << mk_pp(vars[i].get(), m) << "\n";
}
verbose_stream() << "Literals\n";
verbose_stream() << mk_pp(m_pm.mk_and(Phi), m) << "\n";
verbose_stream() << "Reduced\n" << mk_pp(phi1, m) << "\n";);
if (!vars.empty()) {
// also fresh names for auxiliary variables in body?
expr_substitution sub(m);
expr_ref tmp(m);
proof_ref pr(m);
pr = m.mk_asserted(m.mk_true());
for (unsigned i = 0; i < vars.size(); ++i) {
M->eval(vars[i]->get_decl(), tmp);
sub.insert(vars[i].get(), tmp, pr);
}
scoped_ptr<expr_replacer> rep = mk_default_expr_replacer(m);
rep->set_substitution(&sub);
(*rep)(phi1);
IF_VERBOSE(2, verbose_stream() << "Projected:\n" << mk_pp(phi1, m) << "\n";);
}
Phi.reset();
datalog::flatten_and(phi1, Phi);
unsigned_vector indices;
vector<expr_ref_vector> child_states;
child_states.resize(preds.size(), expr_ref_vector(m));
for (unsigned i = 0; i < Phi.size(); ++i) {
m_pm.collect_indices(Phi[i].get(), indices);
if (indices.size() == 0) {
IF_VERBOSE(2, verbose_stream() << "Skipping " << mk_pp(Phi[i].get(), m) << "\n";);
}
else if (indices.size() == 1) {
child_states[indices.back()].push_back(Phi[i].get());
}
else {
expr_substitution sub(m);
expr_ref tmp(m);
proof_ref pr(m);
pr = m.mk_asserted(m.mk_true());
vector<ptr_vector<app> > vars;
m_pm.collect_variables(Phi[i].get(), vars);
SASSERT(vars.size() == indices.back()+1);
for (unsigned j = 1; j < indices.size(); ++j) {
ptr_vector<app> const& vs = vars[indices[j]];
for (unsigned k = 0; k < vs.size(); ++k) {
M->eval(vs[k]->get_decl(), tmp);
sub.insert(vs[k], tmp, pr);
child_states[indices[j]].push_back(m.mk_eq(vs[k], tmp));
}
}
tmp = Phi[i].get();
scoped_ptr<expr_replacer> rep = mk_default_expr_replacer(m);
rep->set_substitution(&sub);
(*rep)(tmp);
child_states[indices[0]].push_back(tmp);
}
}
expr_ref n_cube(m);
for (unsigned i = 0; i < preds.size(); ++i) {
pred_transformer& pt = *m_rels.find(preds[i]);
SASSERT(pt.head() == preds[i]);
expr_ref o_cube = m_pm.mk_and(child_states[i]);
m_pm.formula_o2n(o_cube, n_cube, i);
model_node* child = alloc(model_node, &n, n_cube, pt, n.level()-1);
++m_stats.m_num_nodes;
m_search.add_leaf(*child);
IF_VERBOSE(2, verbose_stream() << "Predecessor: " << mk_pp(o_cube, m) << "\n";);
}
check_pre_closed(n);
// TBD ...
TRACE("pdr", m_search.display(tout);); TRACE("pdr", m_search.display(tout););
} }

View file

@ -60,6 +60,7 @@ namespace pdr {
}; };
typedef obj_map<datalog::rule const, expr*> rule2expr; typedef obj_map<datalog::rule const, expr*> rule2expr;
typedef obj_map<datalog::rule const, ptr_vector<app> > rule2apps;
manager& pm; // pdr-manager manager& pm; // pdr-manager
ast_manager& m; // manager ast_manager& m; // manager
@ -70,13 +71,14 @@ namespace pdr {
ptr_vector<datalog::rule> m_rules; // rules used to derive transformer ptr_vector<datalog::rule> m_rules; // rules used to derive transformer
prop_solver m_solver; // solver context prop_solver m_solver; // solver context
vector<expr_ref_vector> m_levels; // level formulas vector<expr_ref_vector> m_levels; // level formulas
expr_ref_vector m_invariants; // properties that are invariant. expr_ref_vector m_invariants; // properties that are invariant.
obj_map<expr, unsigned> m_prop2level; // map property to level where it occurs. obj_map<expr, unsigned> m_prop2level; // map property to level where it occurs.
obj_map<expr, datalog::rule const*> m_tag2rule; // map tag predicate to rule. obj_map<expr, datalog::rule const*> m_tag2rule; // map tag predicate to rule.
rule2expr m_rule2tag; // map rule to predicate tag. rule2expr m_rule2tag; // map rule to predicate tag.
qinst_map m_rule2qinst; // map tag to quantifier instantiation. qinst_map m_rule2qinst; // map tag to quantifier instantiation.
rule2inst m_rule2inst; // map rules to instantiations of indices rule2inst m_rule2inst; // map rules to instantiations of indices
rule2expr m_rule2transition; // map rules to transition rule2expr m_rule2transition; // map rules to transition
rule2apps m_rule2vars; // map rule to auxiliary variables
expr_ref m_transition; // transition relation. expr_ref m_transition; // transition relation.
expr_ref m_initial_state; // initial state. expr_ref m_initial_state; // initial state.
reachable_cache m_reachable; reachable_cache m_reachable;
@ -94,7 +96,7 @@ namespace pdr {
void init_rule(decl2rel const& pts, datalog::rule const& rule, expr_ref& init, void init_rule(decl2rel const& pts, datalog::rule const& rule, expr_ref& init,
ptr_vector<datalog::rule const>& rules, expr_ref_vector& transition); ptr_vector<datalog::rule const>& rules, expr_ref_vector& transition);
void init_atom(decl2rel const& pts, app * atom, app_ref_vector& var_reprs, expr_ref_vector& conj, unsigned tail_idx); void init_atom(decl2rel const& pts, app * atom, app_ref_vector& var_reprs, expr_ref_vector& conj, unsigned tail_idx);
void ground_free_vars(expr* e, app_ref_vector& vars); void ground_free_vars(expr* e, app_ref_vector& vars, ptr_vector<app>& aux_vars);
void model2cube(const model_core& md, func_decl * d, expr_ref_vector& res) const; void model2cube(const model_core& md, func_decl * d, expr_ref_vector& res) const;
void model2cube(app* c, expr* val, expr_ref_vector& res) const; void model2cube(app* c, expr* val, expr_ref_vector& res) const;
@ -137,6 +139,7 @@ namespace pdr {
void find_predecessors(model_core const& model, ptr_vector<func_decl>& preds) const; void find_predecessors(model_core const& model, ptr_vector<func_decl>& preds) const;
datalog::rule const& find_rule(model_core const& model) const; datalog::rule const& find_rule(model_core const& model) const;
expr* get_transition(datalog::rule const& r) { return m_rule2transition.find(&r); } expr* get_transition(datalog::rule const& r) { return m_rule2transition.find(&r); }
void get_aux_vars(datalog::rule const& r, ptr_vector<app>& vs) { m_rule2vars.find(&r, vs); }
bool propagate_to_next_level(unsigned level); bool propagate_to_next_level(unsigned level);
void add_property(expr * lemma, unsigned lvl); // add property 'p' to state at level. void add_property(expr * lemma, unsigned lvl); // add property 'p' to state at level.
@ -194,7 +197,8 @@ namespace pdr {
ptr_vector<model_node> const& children() { return m_children; } ptr_vector<model_node> const& children() { return m_children; }
pred_transformer& pt() const { return m_pt; } pred_transformer& pt() const { return m_pt; }
model_node* parent() const { return m_parent; } model_node* parent() const { return m_parent; }
model_core const& model() const { return *m_model; } model* model_ptr() const { return m_model.get(); }
model const& model() const { return *m_model; }
unsigned index() const; unsigned index() const;
bool is_closed() const { return m_closed; } bool is_closed() const { return m_closed; }
@ -301,7 +305,6 @@ namespace pdr {
stats() { reset(); } stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); } void reset() { memset(this, 0, sizeof(*this)); }
}; };
front_end_params& m_fparams; front_end_params& m_fparams;
params_ref const& m_params; params_ref const& m_params;
@ -314,6 +317,7 @@ namespace pdr {
pred_transformer* m_query; pred_transformer* m_query;
model_search m_search; model_search m_search;
lbool m_last_result; lbool m_last_result;
bool m_use_model_generalizer;
unsigned m_inductive_lvl; unsigned m_inductive_lvl;
ptr_vector<model_generalizer> m_model_generalizers; ptr_vector<model_generalizer> m_model_generalizers;
ptr_vector<core_generalizer> m_core_generalizers; ptr_vector<core_generalizer> m_core_generalizers;
@ -332,8 +336,8 @@ namespace pdr {
void check_pre_closed(model_node& n); void check_pre_closed(model_node& n);
void expand_node(model_node& n); void expand_node(model_node& n);
lbool expand_state(model_node& n, expr_ref_vector& cube); lbool expand_state(model_node& n, expr_ref_vector& cube);
void create_children(model_node& n, expr* cube); void create_children(model_node& n, expr* model);
void create_children2(model_node& n, expr* cube); void create_children2(model_node& n);
expr_ref mk_sat_answer() const; expr_ref mk_sat_answer() const;
expr_ref mk_unsat_answer() const; expr_ref mk_unsat_answer() const;

View file

@ -202,8 +202,7 @@ void dl_interface::collect_params(param_descrs& p) {
p.insert(":inline-proofs", CPK_BOOL, "PDR: (default true) run PDR with proof mode turned on and extract Farkas coefficients directly (instead of creating a separate proof object when extracting coefficients)"); p.insert(":inline-proofs", CPK_BOOL, "PDR: (default true) run PDR with proof mode turned on and extract Farkas coefficients directly (instead of creating a separate proof object when extracting coefficients)");
p.insert(":flexible-trace", CPK_BOOL, "PDR: (default false) allow PDR generate long counter-examples by extending candidate trace within search area"); p.insert(":flexible-trace", CPK_BOOL, "PDR: (default false) allow PDR generate long counter-examples by extending candidate trace within search area");
p.insert(":unfold-rules", CPK_UINT, "PDR: (default 0) unfold rules statically using iterative squarring"); p.insert(":unfold-rules", CPK_UINT, "PDR: (default 0) unfold rules statically using iterative squarring");
PRIVATE_PARAMS(p.insert(":use-farkas-model", CPK_BOOL, "PDR: (default false) enable using Farkas generalization through model propagation");); p.insert(":use-model-generalizer", CPK_BOOL, "PDR: (default false) use model for backwards propagation (instead of symbolic simulation)");
PRIVATE_PARAMS(p.insert(":use-precondition-generalizer", CPK_BOOL, "PDR: (default false) enable generalizations from weakest pre-conditions"););
PRIVATE_PARAMS(p.insert(":use-multicore-generalizer", CPK_BOOL, "PDR: (default false) extract multiple cores for blocking states");); PRIVATE_PARAMS(p.insert(":use-multicore-generalizer", CPK_BOOL, "PDR: (default false) extract multiple cores for blocking states"););
PRIVATE_PARAMS(p.insert(":use-inductive-generalizer", CPK_BOOL, "PDR: (default true) generalize lemmas using induction strengthening");); PRIVATE_PARAMS(p.insert(":use-inductive-generalizer", CPK_BOOL, "PDR: (default true) generalize lemmas using induction strengthening"););
PRIVATE_PARAMS(p.insert(":use-interpolants", CPK_BOOL, "PDR: (default false) use iZ3 interpolation for lemma generation");); PRIVATE_PARAMS(p.insert(":use-interpolants", CPK_BOOL, "PDR: (default false) use iZ3 interpolation for lemma generation"););

View file

@ -28,65 +28,18 @@ Revision History:
namespace pdr { namespace pdr {
static void solve_for_next_vars(expr_ref& F, model_node& n, expr_substitution& sub) {
ast_manager& m = F.get_manager();
manager& pm = n.pt().get_pdr_manager();
const model_core & mdl = n.model();
unsigned sz = mdl.get_num_constants();
expr_ref_vector refs(m);
for (unsigned i = 0; i < sz; i++) {
func_decl * d = mdl.get_constant(i);
expr_ref interp(m);
ptr_vector<app> cs;
if (m.is_bool(d->get_range())) {
get_value_from_model(mdl, d, interp);
app* c = m.mk_const(d);
refs.push_back(c);
refs.push_back(interp);
sub.insert(c, interp);
}
}
scoped_ptr<expr_replacer> rep = mk_default_expr_replacer(m);
rep->set_substitution(&sub);
(*rep)(F);
th_rewriter rw(m);
rw(F);
ptr_vector<expr> todo;
todo.push_back(F);
expr* e1, *e2;
while (!todo.empty()) {
expr* e = todo.back();
todo.pop_back();
if (m.is_and(e)) {
todo.append(to_app(e)->get_num_args(), to_app(e)->get_args());
}
else if ((m.is_eq(e, e1, e2) && pm.is_n(e1) && pm.is_o_formula(e2)) ||
(m.is_eq(e, e2, e1) && pm.is_n(e1) && pm.is_o_formula(e2))) {
sub.insert(e1, e2);
TRACE("pdr", tout << mk_pp(e1, m) << " |-> " << mk_pp(e2, m) << "\n";);
}
}
}
// //
// eliminate conjuncts from cube as long as state is satisfied. // eliminate conjuncts from cube as long as state is satisfied.
// //
void model_evaluation_generalizer::operator()(model_node& n, expr_ref_vector& cube) { void model_evaluation_generalizer::operator()(model_node& n, expr_ref_vector& cube) {
ptr_vector<expr> forms; expr_ref_vector forms(cube.get_manager());
forms.push_back(n.state()); forms.push_back(n.state());
forms.push_back(n.pt().transition()); forms.push_back(n.pt().transition());
m_model_evaluator.minimize_model(forms, cube); datalog::flatten_and(forms);
} ptr_vector<expr> forms1(forms.size(), forms.c_ptr());
model_ref mdl = n.model_ptr();
// m_model_evaluator.minimize_model(forms1, mdl, cube);
// eliminate conjuncts from cube as long as state is satisfied.
//
void bool_model_evaluation_generalizer::operator()(model_node& n, expr_ref_vector& cube) {
ptr_vector<expr> forms;
forms.push_back(n.state());
forms.push_back(n.pt().transition());
m_model_evaluator.minimize_model(forms, cube);
} }
// //
@ -121,10 +74,6 @@ namespace pdr {
TRACE("pdr", tout << "old size: " << old_core_size << " new size: " << core.size() << "\n";); TRACE("pdr", tout << "old size: " << old_core_size << " new size: " << core.size() << "\n";);
} }
//
// extract multiple cores from unreachable state.
//
void core_multi_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { void core_multi_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) {
UNREACHABLE(); UNREACHABLE();
@ -207,31 +156,6 @@ namespace pdr {
m_farkas_learner.collect_statistics(st); m_farkas_learner.collect_statistics(st);
} }
void model_precond_generalizer::operator()(model_node& n, expr_ref_vector& cube) {
ast_manager& m = n.pt().get_manager();
manager& pm = n.pt().get_pdr_manager();
expr_ref A(m), state(m);
expr_ref_vector states(m);
A = n.pt().get_formulas(n.level(), true);
// extract substitution for next-state variables.
expr_substitution sub(m);
solve_for_next_vars(A, n, sub);
scoped_ptr<expr_replacer> rep = mk_default_expr_replacer(m);
rep->set_substitution(&sub);
A = m.mk_and(A, n.state());
(*rep)(A);
datalog::flatten_and(A, states);
for (unsigned i = 0; i < states.size(); ++i) {
expr* s = states[i].get();
if (pm.is_o_formula(s) && pm.is_homogenous_formula(s)) {
cube.push_back(s);
}
}
TRACE("pdr", for (unsigned i = 0; i < cube.size(); ++i) tout << mk_pp(cube[i].get(), m) << "\n";);
}
/** /**
< F, phi, i + 1 > < F, phi, i + 1 >
@ -567,78 +491,4 @@ namespace pdr {
uses_level = true; uses_level = true;
} }
} }
//
// cube => n.state() & formula
// so n.state() & cube & ~formula is unsat
// so weaken cube while result is still unsat.
//
void model_farkas_generalizer::operator()(model_node& n, expr_ref_vector& cube) {
ast_manager& m = n.pt().get_manager();
manager& pm = n.pt().get_pdr_manager();
front_end_params& p = m_ctx.get_fparams();
farkas_learner learner(p, m);
expr_ref A0(m), A(m), B(m), state(m);
expr_ref_vector states(m);
A0 = n.pt().get_formulas(n.level(), true);
// extract substitution for next-state variables.
expr_substitution sub(m);
solve_for_next_vars(A0, n, sub);
scoped_ptr<expr_replacer> rep = mk_default_expr_replacer(m);
rep->set_substitution(&sub);
(*rep)(A0);
A0 = m.mk_not(A0);
state = n.state();
(*rep)(state);
datalog::flatten_and(state, states);
ptr_vector<func_decl> preds;
n.pt().find_predecessors(n.model(), preds);
TRACE("pdr", for (unsigned i = 0; i < cube.size(); ++i) tout << mk_pp(cube[i].get(), m) << "\n";);
for (unsigned i = 0; i < preds.size(); ++i) {
pred_transformer& pt = m_ctx.get_pred_transformer(preds[i]);
SASSERT(pt.head() == preds[i]);
expr_ref_vector lemmas(m), o_cube(m), other(m), o_state(m), other_state(m);
pm.partition_o_atoms(cube, o_cube, other, i);
pm.partition_o_atoms(states, o_state, other_state, i);
TRACE("pdr",
tout << "cube:\n";
for (unsigned i = 0; i < cube.size(); ++i) tout << mk_pp(cube[i].get(), m) << "\n";
tout << "o_cube:\n";
for (unsigned i = 0; i < o_cube.size(); ++i) tout << mk_pp(o_cube[i].get(), m) << "\n";
tout << "other:\n";
for (unsigned i = 0; i < other.size(); ++i) tout << mk_pp(other[i].get(), m) << "\n";
tout << "o_state:\n";
for (unsigned i = 0; i < o_state.size(); ++i) tout << mk_pp(o_state[i].get(), m) << "\n";
tout << "other_state:\n";
for (unsigned i = 0; i < other_state.size(); ++i) tout << mk_pp(other_state[i].get(), m) << "\n";
);
A = m.mk_and(A0, pm.mk_and(other), pm.mk_and(other_state));
B = m.mk_and(pm.mk_and(o_cube), pm.mk_and(o_state));
TRACE("pdr",
tout << "A: " << mk_pp(A, m) << "\n";
tout << "B: " << mk_pp(B, m) << "\n";);
if (learner.get_lemma_guesses(A, B, lemmas)) {
cube.append(lemmas);
cube.append(o_state);
TRACE("pdr",
tout << "New lemmas:\n";
for (unsigned i = 0; i < lemmas.size(); ++i) {
tout << mk_pp(lemmas[i].get(), m) << "\n";
}
);
}
}
TRACE("pdr", for (unsigned i = 0; i < cube.size(); ++i) tout << mk_pp(cube[i].get(), m) << "\n";);
}
}; };

View file

@ -25,11 +25,11 @@ Revision History:
namespace pdr { namespace pdr {
class bool_model_evaluation_generalizer : public model_generalizer { class model_evaluation_generalizer : public model_generalizer {
ternary_model_evaluator m_model_evaluator; model_evaluator m_model_evaluator;
public: public:
bool_model_evaluation_generalizer(context& ctx, ast_manager& m) : model_generalizer(ctx), m_model_evaluator(m) {} model_evaluation_generalizer(context& ctx, ast_manager& m) : model_generalizer(ctx), m_model_evaluator(m) {}
virtual ~bool_model_evaluation_generalizer() {} virtual ~model_evaluation_generalizer() {}
virtual void operator()(model_node& n, expr_ref_vector& cube); virtual void operator()(model_node& n, expr_ref_vector& cube);
}; };
@ -50,28 +50,6 @@ namespace pdr {
virtual void collect_statistics(statistics& st) const; virtual void collect_statistics(statistics& st) const;
}; };
class model_precond_generalizer : public model_generalizer {
public:
model_precond_generalizer(context& ctx): model_generalizer(ctx) {}
virtual ~model_precond_generalizer() {}
virtual void operator()(model_node& n, expr_ref_vector& cube);
};
class model_farkas_generalizer : public model_generalizer {
public:
model_farkas_generalizer(context& ctx) : model_generalizer(ctx) {}
virtual ~model_farkas_generalizer() {}
virtual void operator()(model_node& n, expr_ref_vector& cube);
};
class model_evaluation_generalizer : public model_generalizer {
th_rewriter_model_evaluator m_model_evaluator;
public:
model_evaluation_generalizer(context& ctx, ast_manager& m) : model_generalizer(ctx), m_model_evaluator(m) {}
virtual ~model_evaluation_generalizer() {}
virtual void operator()(model_node& n, expr_ref_vector& cube);
};
class core_multi_generalizer : public core_generalizer { class core_multi_generalizer : public core_generalizer {
core_bool_inductive_generalizer m_gen; core_bool_inductive_generalizer m_gen;
public: public:

View file

@ -223,6 +223,20 @@ namespace pdr {
bool is_homogenous_formula(expr * e) const { bool is_homogenous_formula(expr * e) const {
return m_mux.is_homogenous_formula(e); return m_mux.is_homogenous_formula(e);
} }
/**
Collect indices used in expression.
*/
void collect_indices(expr* e, unsigned_vector& indices) const {
m_mux.collect_indices(e, indices);
}
/**
Collect used variables of each index.
*/
void collect_variables(expr* e, vector<ptr_vector<app> >& vars) const {
m_mux.collect_variables(e, vars);
}
/** /**
Return true iff both s1 and s2 are either "n" or "o" of the same index. Return true iff both s1 and s2 are either "n" or "o" of the same index.
@ -275,8 +289,6 @@ namespace pdr {
bool try_get_state_and_value_from_atom(expr * atom, app *& state, app_ref& value); bool try_get_state_and_value_from_atom(expr * atom, app *& state, app_ref& value);
bool try_get_state_decl_from_atom(expr * atom, func_decl *& state); bool try_get_state_decl_from_atom(expr * atom, func_decl *& state);
void get_state_cube_from_model(const model_core & mdl, expr_ref_vector & cube) const
{ return m_mux.get_muxed_cube_from_model(mdl, cube); }
std::string pp_model(const model_core & mdl) const std::string pp_model(const model_core & mdl) const
{ return m_mux.pp_model(mdl); } { return m_mux.pp_model(mdl); }

View file

@ -228,6 +228,76 @@ bool sym_mux::is_homogenous(const expr_ref_vector & vect, unsigned idx) const
return true; return true;
} }
class sym_mux::index_collector {
sym_mux const& m_parent;
svector<bool> m_indices;
public:
index_collector(sym_mux const& s):
m_parent(s) {}
void operator()(expr * e) {
if (is_app(e)) {
func_decl * sym = to_app(e)->get_decl();
unsigned idx;
if (m_parent.try_get_index(sym, idx)) {
SASSERT(idx > 0);
--idx;
if (m_indices.size() <= idx) {
m_indices.resize(idx+1, false);
}
m_indices[idx] = true;
}
}
}
void extract(unsigned_vector& indices) {
for (unsigned i = 0; i < m_indices.size(); ++i) {
if (m_indices[i]) {
indices.push_back(i);
}
}
}
};
void sym_mux::collect_indices(expr* e, unsigned_vector& indices) const {
indices.reset();
index_collector collector(*this);
for_each_expr(collector, m_visited, e);
m_visited.reset();
collector.extract(indices);
}
class sym_mux::variable_collector {
sym_mux const& m_parent;
vector<ptr_vector<app> >& m_vars;
public:
variable_collector(sym_mux const& s, vector<ptr_vector<app> >& vars):
m_parent(s), m_vars(vars) {}
void operator()(expr * e) {
if (is_app(e)) {
func_decl * sym = to_app(e)->get_decl();
unsigned idx;
if (m_parent.try_get_index(sym, idx)) {
SASSERT(idx > 0);
--idx;
if (m_vars.size() <= idx) {
m_vars.resize(idx+1, ptr_vector<app>());
}
m_vars[idx].push_back(to_app(e));
}
}
}
};
void sym_mux::collect_variables(expr* e, vector<ptr_vector<app> >& vars) const {
vars.reset();
variable_collector collector(*this, vars);
for_each_expr(collector, m_visited, e);
m_visited.reset();
}
class sym_mux::hmg_checker { class sym_mux::hmg_checker {
const sym_mux & m_parent; const sym_mux & m_parent;
@ -445,38 +515,6 @@ void sym_mux::filter_non_model_lits(expr_ref_vector & vect) const {
} }
} }
void sym_mux::get_muxed_cube_from_model(const model_core & mdl, expr_ref_vector & res) const
{
res.reset();
unsigned sz = mdl.get_num_constants();
for (unsigned i = 0; i < sz; i++) {
func_decl * d = mdl.get_constant(i);
if(!is_muxed(d) || m_non_model_syms.contains(get_primary(d))) { continue; }
SASSERT(d->get_arity()==0);
expr_ref interp(m);
get_value_from_model(mdl, d, interp);
app_ref constant(m.mk_const(d), m);
app_ref lit(m);
if(m.is_bool(d->get_range())) {
if(m.is_true(interp)) {
lit = constant;
}
else {
SASSERT(m.is_false(interp));
lit = m.mk_not(constant);
}
}
else {
lit = m.mk_eq(constant, interp);
}
res.push_back(lit);
}
//LOGV(5, " got cube "<<pp_cube(res, m));
}
class sym_mux::decl_idx_comparator class sym_mux::decl_idx_comparator
{ {
const sym_mux & m_parent; const sym_mux & m_parent;

View file

@ -86,6 +86,8 @@ private:
class hmg_checker; class hmg_checker;
class nonmodel_sym_checker; class nonmodel_sym_checker;
class index_renamer_cfg; class index_renamer_cfg;
class index_collector;
class variable_collector;
std::string get_suffix(unsigned i) const; std::string get_suffix(unsigned i) const;
void ensure_tuple_size(func_decl * prim, unsigned sz) const; void ensure_tuple_size(func_decl * prim, unsigned sz) const;
@ -184,6 +186,15 @@ public:
*/ */
bool contains(expr * e, unsigned idx) const; bool contains(expr * e, unsigned idx) const;
/**
Collect indices used in expression.
*/
void collect_indices(expr* e, unsigned_vector& indices) const;
/**
Collect used variables of each index.
*/
void collect_variables(expr* e, vector<ptr_vector<app> >& vars) const;
/** /**
Convert symbol sym which has to be of src_idx variant into variant tgt_idx. Convert symbol sym which has to be of src_idx variant into variant tgt_idx.

File diff suppressed because it is too large Load diff

View file

@ -170,34 +170,15 @@ void vect_set_union(ref_vector<Type,Mgr> & tgt, ref_vector<Type,Mgr> & src, Comp
} }
class model_evaluator_base {
protected:
virtual void check_model(ptr_vector<expr> const & formulas,
expr_ref_vector & model, bool & has_unknown, bool & has_false) = 0;
public:
virtual void minimize_model(ptr_vector<expr> const & formulas, expr_ref_vector & model);
};
class th_rewriter_model_evaluator : public model_evaluator_base { class model_evaluator {
class expr_rewriter_cfg;
ast_manager& m;
th_rewriter m_rewriter;
void setup_assignment(expr_ref_vector const& model, obj_map<expr,expr*>& assignment);
protected:
virtual void check_model(ptr_vector<expr> const & formulas,
expr_ref_vector & model, bool & has_unknown,
bool & has_false);
public:
th_rewriter_model_evaluator(ast_manager& m) : m(m), m_rewriter(m) {}
};
class ternary_model_evaluator : public model_evaluator_base {
ast_manager& m; ast_manager& m;
arith_util m_arith; arith_util m_arith;
bv_util m_bv; bv_util m_bv;
obj_map<expr,rational> m_values; obj_map<expr,rational> m_numbers;
expr_ref_vector m_refs;
obj_map<expr, expr*> m_values;
model_ref m_model;
//00 -- non-visited //00 -- non-visited
//01 -- X //01 -- X
@ -209,13 +190,18 @@ class ternary_model_evaluator : public model_evaluator_base {
unsigned m_level2; unsigned m_level2;
expr_mark m_visited; expr_mark m_visited;
void setup_model(expr_ref_vector const& model);
void add_model(expr* e); void reset();
void del_model(expr* e); void setup_model(model_ref& model);
void assign_value(expr* e, expr* v);
bool get_assignment(expr* e, expr*& var, expr*& val); bool get_assignment(expr* e, expr*& var, expr*& val);
void collect(ptr_vector<expr> const& formulas, ptr_vector<expr>& tocollect);
void process_formula(app* e, ptr_vector<expr>& todo, ptr_vector<expr>& tocollect);
void prune_by_cone_of_influence(ptr_vector<expr> const & formulas, expr_ref_vector& model); void prune_by_cone_of_influence(ptr_vector<expr> const & formulas, expr_ref_vector& model);
void prune_by_probing(ptr_vector<expr> const & formulas, expr_ref_vector& model); void eval_arith(app* e);
void eval_basic(app* e);
void eval_iff(app* e, expr* arg1, expr* arg2);
void inherit_value(expr* e, expr* v);
//00 -- non-visited //00 -- non-visited
//01 -- X //01 -- X
@ -231,20 +217,27 @@ class ternary_model_evaluator : public model_evaluator_base {
inline void set_false(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); } inline void set_false(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); }
inline void set_true(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); m2.mark(x); } inline void set_true(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); m2.mark(x); }
inline void set_bool(expr* x, bool v) { if (v) { set_true(x); } else { set_false(x); } } inline void set_bool(expr* x, bool v) { if (v) { set_true(x); } else { set_false(x); } }
inline rational const& get_value(expr* x) const { return m_values.find(x); } inline rational const& get_number(expr* x) const { return m_numbers.find(x); }
inline void set_value(expr* x, rational const& v) { set_v(x); TRACE("pdr_verbose", tout << mk_pp(x,m) << " " << v << "\n";); m_values.insert(x,v); } inline void set_number(expr* x, rational const& v) { set_v(x); TRACE("pdr_verbose", tout << mk_pp(x,m) << " " << v << "\n";); m_numbers.insert(x,v); }
inline expr* get_value(expr* x) { return m_values.find(x); }
inline void set_value(expr* x, expr* v) { set_v(x); m_refs.push_back(v); m_values.insert(x, v); }
protected: protected:
bool check_model(ptr_vector<expr> const & formulas); bool check_model(ptr_vector<expr> const & formulas);
virtual void check_model(ptr_vector<expr> const & formulas, expr_ref_vector & model,
bool & has_unknown, bool & has_false) {
UNREACHABLE();
}
public: public:
ternary_model_evaluator(ast_manager& m) : m(m), m_arith(m), m_bv(m) {} model_evaluator(ast_manager& m) : m(m), m_arith(m), m_bv(m), m_refs(m) {}
virtual void minimize_model(ptr_vector<expr> const & formulas, expr_ref_vector & model);
virtual void minimize_model(ptr_vector<expr> const & formulas, model_ref& mdl, expr_ref_vector& model);
/**
\brief extract literals from formulas that satisfy formulas.
\pre model satisfies formulas
*/
expr_ref_vector minimize_literals(ptr_vector<expr> const & formulas, model_ref& mdl);
// for_each_expr visitor. // for_each_expr visitor.
void operator()(expr* e) {} void operator()(expr* e) {}
@ -252,11 +245,6 @@ public:
void get_value_from_model(const model_core & mdl, func_decl * f, expr_ref& res); void get_value_from_model(const model_core & mdl, func_decl * f, expr_ref& res);
/**
If the solver argument is non-zero, we will exclude its auxiliary symbols from the generated cube.
*/
void get_cube_from_model(const model_core & mdl, expr_ref_vector & res, pdr::prop_solver& solver);
} }
#endif #endif