3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-19 10:52:02 +00:00

updates to mbqi

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2018-05-17 13:06:47 -07:00 committed by Arie Gurfinkel
parent 80c39eb037
commit 20300bbf94
3 changed files with 237 additions and 62 deletions

View file

@ -1196,6 +1196,67 @@ namespace qe {
return false;
}
bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) {
TRACE("qe", tout << mk_pp(var, m) << "\n" << lits;);
m_var = alloc(contains_app, m, var);
// reduce select-store redeces based on model.
// rw_cfg rw(m);
// rw(lits);
// try first to solve for var.
if (solve_eq(model, vars, lits)) {
return true;
}
app_ref_vector selects(m);
// check that only non-select occurrences are in disequalities.
if (!check_diseqs(lits, selects)) {
TRACE("qe", tout << "Could not project " << mk_pp(var, m) << " for:\n" << lits << "\n";);
return false;
}
// remove disequalities.
elim_diseqs(lits);
// Ackerman reduction on remaining select occurrences
// either replace occurrences by model value or other node
// that is congruent to model value.
ackermanize_select(model, selects, vars, lits);
TRACE("qe", tout << selects << "\n" << lits << "\n";);
return true;
}
void ackermanize_select(model& model, app_ref_vector const& selects, app_ref_vector& vars, expr_ref_vector& lits) {
expr_ref_vector vals(m), reps(m);
expr_ref val(m);
expr_safe_replace sub(m);
if (selects.empty()) {
return;
}
app_ref sel(m);
for (unsigned i = 0; i < selects.size(); ++i) {
sel = m.mk_fresh_const("sel", m.get_sort(selects[i]));
VERIFY (model.eval(selects[i], val));
model.register_decl(sel->get_decl(), val);
vals.push_back(to_app(val));
reps.push_back(val); // TODO: direct pass could handle nested selects.
vars.push_back(sel);
sub.insert(selects[i], val);
}
sub(lits);
remove_true(lits);
project_plugin::partition_args(model, selects, lits);
project_plugin::partition_values(model, reps, lits);
}
void remove_true(expr_ref_vector& lits) {
for (unsigned i = 0; i < lits.size(); ++i) {
if (m.is_true(lits[i].get())) {
@ -1216,6 +1277,80 @@ namespace qe {
}
}
// check that x occurs only under selects or in disequalities.
bool check_diseqs(expr_ref_vector const& lits, app_ref_vector& selects) {
expr_mark mark;
ptr_vector<app> todo;
app* e;
for (unsigned i = 0; i < lits.size(); ++i) {
e = to_app(lits[i]);
if (is_diseq_x(e)) {
continue;
}
if (contains_x(e)) {
todo.push_back(e);
}
}
while (!todo.empty()) {
e = todo.back();
todo.pop_back();
if (mark.is_marked(e)) {
continue;
}
mark.mark(e);
if (m_var->x() == e) {
return false;
}
unsigned start = 0;
if (a.is_select(e)) {
if (e->get_arg(0) == m_var->x()) {
start = 1;
selects.push_back(e);
}
}
for (unsigned i = start; i < e->get_num_args(); ++i) {
todo.push_back(to_app(e->get_arg(i)));
}
}
return true;
}
void elim_diseqs(expr_ref_vector& lits) {
for (unsigned i = 0; i < lits.size(); ++i) {
if (is_diseq_x(lits[i].get())) {
project_plugin::erase(lits, i);
}
}
}
bool is_update_x(app* e) {
do {
if (m_var->x() == e) {
return true;
}
if (a.is_store(e) && contains_x(e->get_arg(0))) {
for (unsigned i = 1; i < e->get_num_args(); ++i) {
if (contains_x(e->get_arg(i))) {
return false;
}
}
e = to_app(e->get_arg(0));
continue;
}
}
while (false);
return false;
}
bool is_diseq_x(expr* e) {
expr *f, * s, *t;
if (m.is_not(e, f) && m.is_eq(f, s, t)) {
if (contains_x(s) && !contains_x(t) && is_update_x(to_app(s))) return true;
if (contains_x(t) && !contains_x(s) && is_update_x(to_app(t))) return true;
}
return false;
}
bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
// find an equality to solve for.
expr* s, *t;
@ -1367,13 +1502,7 @@ namespace qe {
}
bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) {
ast_manager& m = vars.get_manager();
app_ref_vector vvars(m, 1, &var);
expr_ref fml = mk_and(lits);
(*this)(model, vvars, fml, vars, false);
lits.reset();
flatten_and(fml, lits);
return true;
return (*m_imp)(model, var, vars, lits);
}
bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
@ -1390,9 +1519,9 @@ namespace qe {
array_project_eqs_util pe (m);
pe (mdl, arr_vars, fml, aux_vars);
TRACE ("qe",
tout << "Projected array eqs: " << fml << "\n";
tout << "Remaining array vars: " << arr_vars << "\n";
tout << "Aux vars: " << aux_vars << "\n";
tout << "Projected array eqs:\n" << fml << "\n";
tout << "Remaining array vars:\n" << arr_vars;
tout << "Aux vars:\n" << aux_vars;
);
// 2. reduce selects
@ -1406,8 +1535,8 @@ namespace qe {
ps (mdl, arr_vars, fml, aux_vars);
TRACE ("qe",
tout << "Projected array selects: " << fml << "\n";
tout << "All aux vars: " << aux_vars << "\n";
tout << "Projected array selects:\n" << fml << "\n";
tout << "All aux vars:\n" << aux_vars;
);
}

View file

@ -77,6 +77,40 @@ expr_ref project_plugin::pick_equality(ast_manager& m, model& model, expr* t) {
return expr_ref(nullptr, m);
}
void project_plugin::partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits) {
ast_manager& m = vals.get_manager();
expr_ref val(m);
expr_ref_vector trail(m), reps(m);
obj_map<expr, expr*> roots;
for (unsigned i = 0; i < vals.size(); ++i) {
expr* v = vals[i], *root;
VERIFY (model.eval(v, val));
if (roots.find(val, root)) {
lits.push_back(m.mk_eq(v, root));
}
else {
roots.insert(val, v);
trail.push_back(val);
reps.push_back(v);
}
}
if (reps.size() > 1) {
lits.push_back(mk_distinct(reps));
}
}
void project_plugin::partition_args(model& model, app_ref_vector const& selects, expr_ref_vector& lits) {
ast_manager& m = selects.get_manager();
if (selects.empty()) return;
unsigned num_args = selects[0]->get_decl()->get_arity();
for (unsigned j = 1; j < num_args; ++j) {
expr_ref_vector args(m);
for (unsigned i = 0; i < selects.size(); ++i) {
args.push_back(selects[i]->get_arg(j));
}
project_plugin::partition_values(model, args, lits);
}
}
void project_plugin::erase(expr_ref_vector& lits, unsigned& i) {
lits[i] = lits.back();
@ -100,6 +134,7 @@ class mbp::impl {
// parameters
bool m_reduce_all_selects;
bool m_native_mbp;
bool m_dont_sub;
void add_plugin(project_plugin* p) {
@ -287,7 +322,8 @@ class mbp::impl {
void operator() (app *n) {
expr *e1, *e2;
if (m_array.is_select (n)) {
for (expr * arg : *n) {
for (unsigned i = 1; i < n->get_num_args(); ++i) {
expr * arg = n->get_arg(i);
if (m.get_sort(arg) == m.get_sort(m_var) && arg != m_var)
m_res.push_back (arg);
}
@ -340,7 +376,8 @@ class mbp::impl {
// -- evaluate to initialize eval cache
(void) eval (fml);
unsigned j = 0;
for (app * v : vars) {
for (unsigned i = 0; i < vars.size (); ++i) {
app* v = vars.get(i);
if (!project_var (eval, v, fml)) {
vars[j++] = v;
}
@ -350,6 +387,7 @@ class mbp::impl {
public:
opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) {
arith_project_plugin arith(m);
return arith.maximize(fmls, mdl, t, ge, gt);
@ -490,6 +528,7 @@ public:
void updt_params(params_ref const& p) {
m_params.append(p);
m_reduce_all_selects = m_params.get_bool("reduce_all_selects", false);
m_native_mbp = m_params.get_bool("native_mbp", false);
m_dont_sub = m_params.get_bool("dont_sub", false);
}
@ -508,7 +547,6 @@ public:
bool validate_model(model& model, expr_ref_vector const& fmls) {
expr_ref val(m);
model_evaluator eval(model);
for (expr * f : fmls) {
VERIFY(model.eval(f, val) && m.is_true(val));
}
@ -637,19 +675,26 @@ public:
tout << "extended model:\n";
model_pp (tout, mdl);
tout << "Auxiliary variables of index and value sorts:\n";
tout << vars << "\n";
tout << vars;
);
}
// project reals and ints
if (!arith_vars.empty ()) {
TRACE ("qe", tout << "Arith vars: " << arith_vars << "\n";);
TRACE ("qe", tout << "Arith vars:\n" << arith_vars;);
if (m_native_mbp) {
expr_ref_vector fmls(m);
flatten_and (fml, fmls);
(*this)(true, arith_vars, mdl, fmls);
fml = mk_and (fmls);
SASSERT (arith_vars.empty ());
}
else {
NOT_IMPLEMENTED_YET();
// qe::arith_project (mdl, arith_vars, fml);
}
TRACE ("qe",
tout << "Projected arith vars:\n" << fml << "\n";
@ -693,6 +738,7 @@ void mbp::updt_params(params_ref const& p) {
void mbp::get_param_descrs(param_descrs & r) {
r.insert("reduce_all_selects", CPK_BOOL, "(default: false) reduce selects");
r.insert("native_mbp", CPK_BOOL, "(default: false) switch between native and spacer tailored mbp");
r.insert("dont_sub", CPK_BOOL, "(default: false) disable substitution of values for free variables");
}