3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-06 17:44:08 +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_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_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:
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)

View file

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

View file

@ -41,6 +41,7 @@ Notes:
#include "model_smt2_pp.h"
#include "dl_mk_rule_inliner.h"
#include "ast_smt2_pp.h"
#include "qe_lite.h"
namespace pdr {
@ -124,7 +125,7 @@ namespace pdr {
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",
TRACE("pdr_verbose",
for (; it != end; ++it) {
expr* pred = it->m_key;
tout << mk_pp(pred, m) << ":\n";
@ -394,7 +395,7 @@ namespace pdr {
lbool is_sat = m_solver.check_conjunction_as_assumptions(n.state());
if (is_sat == l_true && core) {
core->reset();
model2cube(*model, *core);
model2cube(*model,*core);
n.set_model(model);
}
return is_sat;
@ -522,6 +523,7 @@ namespace pdr {
expr_ref_vector conj(m);
app_ref_vector& var_reprs = *(alloc(app_ref_vector, m));
qinst* qi = 0;
ptr_vector<app> aux_vars;
unsigned ut_size = rule.get_uninterpreted_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);
}
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));
expr_ref_vector tail(m);
@ -585,6 +587,7 @@ namespace pdr {
m_rule2qinst.insert(&rule, qi);
}
m_rule2inst.insert(&rule,&var_reprs);
m_rule2vars.insert(&rule, aux_vars);
}
bool pred_transformer::check_filled(app_ref_vector const& v) const {
@ -595,7 +598,7 @@ namespace pdr {
}
// 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;
get_free_vars(e, sorts);
while (vars.size() < sorts.size()) {
@ -604,6 +607,7 @@ namespace pdr {
for (unsigned i = 0; i < sorts.size(); ++i) {
if (sorts[i] && !vars[i].get()) {
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_cancel(false)
{
m_use_model_generalizer = m_params.get_bool("use-model-generalizer", false);
}
context::~context() {
@ -1296,19 +1301,9 @@ namespace pdr {
void context::init_model_generalizers(datalog::rule_set& rules) {
reset_model_generalizers();
classifier_proc classify(m, rules);
if (classify.is_bool_arith()) {
m_model_generalizers.push_back(alloc(bool_model_evaluation_generalizer, *this, m));
}
else {
if (m_use_model_generalizer) {
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() {
@ -1556,12 +1551,11 @@ namespace pdr {
close_node(n);
}
else {
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";);
TRACE("pdr", tout << "node: " << &n << "\n";);
for (unsigned i = 0; i < m_model_generalizers.size(); ++i) {
(*m_model_generalizers[i])(n, cube);
}
}
create_children(n, m_pm.mk_and(cube));
}
break;
@ -1634,7 +1628,11 @@ namespace pdr {
}
// 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 o_cube(m), n_cube(m);
datalog::flatten_and(model, literals);
@ -1652,6 +1650,7 @@ namespace pdr {
tout << preds[i]->get_name() << "\n";
}
);
for (unsigned i = 0; i < preds.size(); ++i) {
pred_transformer& pt = *m_rels.find(preds[i]);
SASSERT(pt.head() == preds[i]);
@ -1689,34 +1688,149 @@ namespace pdr {
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:
- Extract literals from T & phi using ternary simulation with M.
- resulting formula is Phi.
- 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)
- 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);
model_core const& M = n.model();
datalog::rule const& r = n.pt().find_rule(M);
expr* T = n.pt().get_transition(r);
pred_transformer& pt = n.pt();
model_ref M = n.model_ptr();
datalog::rule const& r = pt.find_rule(*M);
expr* T = pt.get_transition(r);
expr* phi = n.state();
expr_ref_vector Ts(m);
datalog::flatten_and(T, Ts);
IF_VERBOSE(2, verbose_stream() << "Model:\n";
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;
n.pt().find_predecessors(r, preds);
n.pt().remove_predecessors(Ts);
pt.find_predecessors(r, preds);
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););
}

View file

@ -60,6 +60,7 @@ namespace pdr {
};
typedef obj_map<datalog::rule const, expr*> rule2expr;
typedef obj_map<datalog::rule const, ptr_vector<app> > rule2apps;
manager& pm; // pdr-manager
ast_manager& m; // manager
@ -70,13 +71,14 @@ namespace pdr {
ptr_vector<datalog::rule> m_rules; // rules used to derive transformer
prop_solver m_solver; // solver context
vector<expr_ref_vector> m_levels; // level formulas
expr_ref_vector m_invariants; // properties that are invariant.
obj_map<expr, unsigned> m_prop2level; // map property to level where it occurs.
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, 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.
rule2inst m_rule2inst; // map rules to instantiations of indices
rule2expr m_rule2transition; // map rules to transition
rule2apps m_rule2vars; // map rule to auxiliary variables
expr_ref m_transition; // transition relation.
expr_ref m_initial_state; // initial state.
reachable_cache m_reachable;
@ -94,7 +96,7 @@ namespace pdr {
void init_rule(decl2rel const& pts, datalog::rule const& rule, expr_ref& init,
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 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(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;
datalog::rule const& find_rule(model_core const& model) const;
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);
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; }
pred_transformer& pt() const { return m_pt; }
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;
bool is_closed() const { return m_closed; }
@ -301,7 +305,6 @@ namespace pdr {
stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
};
front_end_params& m_fparams;
params_ref const& m_params;
@ -314,6 +317,7 @@ namespace pdr {
pred_transformer* m_query;
model_search m_search;
lbool m_last_result;
bool m_use_model_generalizer;
unsigned m_inductive_lvl;
ptr_vector<model_generalizer> m_model_generalizers;
ptr_vector<core_generalizer> m_core_generalizers;
@ -332,8 +336,8 @@ namespace pdr {
void check_pre_closed(model_node& n);
void expand_node(model_node& n);
lbool expand_state(model_node& n, expr_ref_vector& cube);
void create_children(model_node& n, expr* cube);
void create_children2(model_node& n, expr* cube);
void create_children(model_node& n, expr* model);
void create_children2(model_node& n);
expr_ref mk_sat_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(":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");
PRIVATE_PARAMS(p.insert(":use-farkas-model", CPK_BOOL, "PDR: (default false) enable using Farkas generalization through model propagation"););
PRIVATE_PARAMS(p.insert(":use-precondition-generalizer", CPK_BOOL, "PDR: (default false) enable generalizations from weakest pre-conditions"););
p.insert(":use-model-generalizer", CPK_BOOL, "PDR: (default false) use model for backwards propagation (instead of symbolic simulation)");
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-interpolants", CPK_BOOL, "PDR: (default false) use iZ3 interpolation for lemma generation"););

View file

@ -28,65 +28,18 @@ Revision History:
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.
//
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.pt().transition());
m_model_evaluator.minimize_model(forms, 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);
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);
}
//
@ -121,10 +74,6 @@ namespace pdr {
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) {
UNREACHABLE();
@ -207,31 +156,6 @@ namespace pdr {
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 >
@ -567,78 +491,4 @@ namespace pdr {
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 {
class bool_model_evaluation_generalizer : public model_generalizer {
ternary_model_evaluator m_model_evaluator;
class model_evaluation_generalizer : public model_generalizer {
model_evaluator m_model_evaluator;
public:
bool_model_evaluation_generalizer(context& ctx, ast_manager& m) : model_generalizer(ctx), m_model_evaluator(m) {}
virtual ~bool_model_evaluation_generalizer() {}
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);
};
@ -50,28 +50,6 @@ namespace pdr {
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 {
core_bool_inductive_generalizer m_gen;
public:

View file

@ -223,6 +223,20 @@ namespace pdr {
bool is_homogenous_formula(expr * e) const {
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.
@ -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_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
{ 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;
}
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 {
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
{
const sym_mux & m_parent;

View file

@ -86,6 +86,8 @@ private:
class hmg_checker;
class nonmodel_sym_checker;
class index_renamer_cfg;
class index_collector;
class variable_collector;
std::string get_suffix(unsigned i) const;
void ensure_tuple_size(func_decl * prim, unsigned sz) const;
@ -184,6 +186,15 @@ public:
*/
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.

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 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 {
class model_evaluator {
ast_manager& m;
arith_util m_arith;
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
//01 -- X
@ -209,13 +190,18 @@ class ternary_model_evaluator : public model_evaluator_base {
unsigned m_level2;
expr_mark m_visited;
void setup_model(expr_ref_vector const& model);
void add_model(expr* e);
void del_model(expr* e);
void reset();
void setup_model(model_ref& model);
void assign_value(expr* e, expr* v);
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_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
//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_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 rational const& get_value(expr* x) const { return m_values.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 rational const& get_number(expr* x) const { return m_numbers.find(x); }
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:
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:
ternary_model_evaluator(ast_manager& m) : m(m), m_arith(m), m_bv(m) {}
virtual void minimize_model(ptr_vector<expr> const & formulas, expr_ref_vector & model);
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, 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.
void operator()(expr* e) {}
@ -252,11 +245,6 @@ public:
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