mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
add way to unit test mbp from command line
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
402234757e
commit
e281f85586
4 changed files with 54 additions and 174 deletions
|
@ -30,6 +30,7 @@ Notes:
|
|||
#include "ast/used_vars.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "util/gparams.h"
|
||||
#include "qe/qe_mbp.h"
|
||||
|
||||
|
||||
BINARY_SYM_CMD(get_quantifier_body_cmd,
|
||||
|
@ -352,6 +353,43 @@ public:
|
|||
void execute(cmd_context & ctx) override { ctx.display_dimacs(); }
|
||||
};
|
||||
|
||||
class mbp_cmd : public cmd {
|
||||
expr* m_fml;
|
||||
ptr_vector<expr> m_vars;
|
||||
public:
|
||||
mbp_cmd():cmd("mbp") {}
|
||||
char const * get_usage() const override { return "<expr>"; }
|
||||
char const * get_descr(cmd_context & ctx) const override { return "perform model based projection"; }
|
||||
unsigned get_arity() const override { return 2; }
|
||||
cmd_arg_kind next_arg_kind(cmd_context& ctx) const override {
|
||||
if (m_fml == nullptr) return CPK_EXPR;
|
||||
return CPK_EXPR_LIST;
|
||||
}
|
||||
void set_next_arg(cmd_context& ctx, expr * arg) { m_fml = arg; }
|
||||
void set_next_arg(cmd_context & ctx, unsigned num, expr * const * ts) override {
|
||||
m_vars.append(num, ts);
|
||||
}
|
||||
void prepare(cmd_context & ctx) override { m_fml = nullptr; }
|
||||
void execute(cmd_context & ctx) override {
|
||||
ast_manager& m = ctx.m();
|
||||
app_ref_vector vars(m);
|
||||
model_ref mdl;
|
||||
if (!ctx.is_model_available(mdl) || !ctx.get_check_sat_result()) {
|
||||
throw cmd_exception("model is not available");
|
||||
}
|
||||
for (expr* v : m_vars) {
|
||||
if (!is_uninterp_const(v)) {
|
||||
throw cmd_exception("invalid variable argument. Uninterpreted variable expected");
|
||||
}
|
||||
vars.push_back(to_app(v));
|
||||
}
|
||||
qe::mbp mbp(m);
|
||||
expr_ref fml(m_fml, m);
|
||||
mbp.spacer(vars, *mdl.get(), fml);
|
||||
ctx.regular_stream() << fml << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void install_dbg_cmds(cmd_context & ctx) {
|
||||
ctx.insert(alloc(print_dimacs_cmd));
|
||||
|
@ -377,4 +415,5 @@ void install_dbg_cmds(cmd_context & ctx) {
|
|||
ctx.insert(alloc(instantiate_cmd));
|
||||
ctx.insert(alloc(instantiate_nested_cmd));
|
||||
ctx.insert(alloc(set_next_id));
|
||||
ctx.insert(alloc(mbp_cmd));
|
||||
}
|
||||
|
|
|
@ -631,13 +631,13 @@ namespace qe {
|
|||
m_v = arr_vars.get (i);
|
||||
if (!m_arr_u.is_array (m_v)) {
|
||||
TRACE ("qe",
|
||||
tout << "not an array variable: " << mk_pp (m_v, m) << "\n";
|
||||
tout << "not an array variable: " << m_v << "\n";
|
||||
);
|
||||
aux_vars.push_back (m_v);
|
||||
continue;
|
||||
}
|
||||
TRACE ("qe",
|
||||
tout << "projecting equalities on variable: " << mk_pp (m_v, m) << "\n";
|
||||
tout << "projecting equalities on variable: " << m_v << "\n";
|
||||
);
|
||||
|
||||
if (project (fml)) {
|
||||
|
@ -653,8 +653,8 @@ namespace qe {
|
|||
);
|
||||
}
|
||||
else {
|
||||
IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(m_v, m) << "\n";);
|
||||
TRACE ("qe", tout << "Failed to project: " << mk_pp (m_v, m) << "\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "can't project:" << m_v << "\n";);
|
||||
TRACE ("qe", tout << "Failed to project: " << m_v << "\n";);
|
||||
arr_vars[j++] = m_v;
|
||||
}
|
||||
}
|
||||
|
@ -1196,67 +1196,6 @@ 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())) {
|
||||
|
@ -1275,113 +1214,7 @@ namespace qe {
|
|||
for (unsigned j = 0; j < n; ++j) {
|
||||
lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j]));
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
if (m.is_eq(lits[i].get(), s, t)) {
|
||||
vector<indices> idxs;
|
||||
expr_ref save(m), back(m);
|
||||
save = lits[i].get();
|
||||
back = lits.back();
|
||||
lits[i] = back;
|
||||
lits.pop_back();
|
||||
unsigned sz = lits.size();
|
||||
if (contains_x(s) && !contains_x(t) && is_app(s)) {
|
||||
if (solve(model, to_app(s), t, idxs, vars, lits)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (contains_x(t) && !contains_x(s) && is_app(t)) {
|
||||
if (solve(model, to_app(t), s, idxs, vars, lits)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// put back the equality literal.
|
||||
lits.resize(sz);
|
||||
lits.push_back(back);
|
||||
lits[i] = save;
|
||||
}
|
||||
// TBD: not distinct?
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool solve(model& model, app* s, expr* t, vector<indices>& idxs, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
SASSERT(contains_x(s));
|
||||
|
@ -1502,7 +1335,13 @@ namespace qe {
|
|||
}
|
||||
|
||||
bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
return (*m_imp)(model, var, vars, 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;
|
||||
}
|
||||
|
||||
bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
|
|
|
@ -99,6 +99,7 @@ void project_plugin::partition_values(model& model, expr_ref_vector const& vals,
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
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;
|
||||
|
@ -111,6 +112,7 @@ void project_plugin::partition_args(model& model, app_ref_vector const& selects,
|
|||
project_plugin::partition_values(model, args, lits);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void project_plugin::erase(expr_ref_vector& lits, unsigned& i) {
|
||||
lits[i] = lits.back();
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace qe {
|
|||
|
||||
static expr_ref pick_equality(ast_manager& m, model& model, expr* t);
|
||||
static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits);
|
||||
static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits);
|
||||
//static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits);
|
||||
static void erase(expr_ref_vector& lits, unsigned& i);
|
||||
static void push_back(expr_ref_vector& lits, expr* lit);
|
||||
static void mark_rec(expr_mark& visited, expr* e);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue