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

bug fixes and cleanup in projection functions

spacer would drop variables of sorts not handled by main loop.
- projection with witness needs to disable qel style preprocessing to ensure witnesses are returned.
- add euf plugin to handle uninterpreted sorts (and then uninterpreted functions)
This commit is contained in:
Nikolaj Bjorner 2025-02-15 14:11:20 -08:00
parent 0cf2b5f515
commit eee96ec312
12 changed files with 249 additions and 108 deletions

4
genaisrc/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
# auto-generated
genaiscript.d.ts
tsconfig.json
jsconfig.json

View file

@ -152,6 +152,7 @@ void qe_project_z3(ast_manager &m, app_ref_vector &vars, expr_ref &fml,
params_ref p; params_ref p;
p.set_bool("reduce_all_selects", reduce_all_selects); p.set_bool("reduce_all_selects", reduce_all_selects);
p.set_bool("dont_sub", dont_sub); p.set_bool("dont_sub", dont_sub);
TRACE("qe", tout << "qe-project-z3\n");
qe::mbproj mbp(m, p); qe::mbproj mbp(m, p);
mbp.spacer(vars, mdl, fml); mbp.spacer(vars, mdl, fml);
@ -167,8 +168,7 @@ void qe_project_spacer(ast_manager &m, app_ref_vector &vars, expr_ref &fml,
bool dont_sub) { bool dont_sub) {
th_rewriter rw(m); th_rewriter rw(m);
TRACE("spacer_mbp", tout << "Before projection:\n"; tout << fml << "\n"; TRACE("spacer_mbp", tout << "Before projection:\n"; tout << fml << "\n";
tout << "Vars:\n" tout << "Vars:" << vars << "\n";);
<< vars;);
{ {
// Ensure that top-level AND of fml is flat // Ensure that top-level AND of fml is flat
@ -182,6 +182,7 @@ void qe_project_spacer(ast_manager &m, app_ref_vector &vars, expr_ref &fml,
app_ref_vector arith_vars(m); app_ref_vector arith_vars(m);
app_ref_vector array_vars(m); app_ref_vector array_vars(m);
app_ref_vector other_vars(m);
array_util arr_u(m); array_util arr_u(m);
arith_util ari_u(m); arith_util ari_u(m);
expr_safe_replace bool_sub(m); expr_safe_replace bool_sub(m);
@ -194,8 +195,7 @@ void qe_project_spacer(ast_manager &m, app_ref_vector &vars, expr_ref &fml,
rw(fml); rw(fml);
TRACE("spacer_mbp", tout << "After qe_lite:\n"; TRACE("spacer_mbp", tout << "After qe_lite:\n";
tout << mk_pp(fml, m) << "\n"; tout << "Vars:\n" tout << mk_pp(fml, m) << "\nVars:" << vars << "\n";);
<< vars;);
SASSERT(!m.is_false(fml)); SASSERT(!m.is_false(fml));
@ -206,12 +206,13 @@ void qe_project_spacer(ast_manager &m, app_ref_vector &vars, expr_ref &fml,
// using model completion // using model completion
model::scoped_model_completion _sc_(mdl, true); model::scoped_model_completion _sc_(mdl, true);
bool_sub.insert(v, mdl(v)); bool_sub.insert(v, mdl(v));
} else if (arr_u.is_array(v)) {
array_vars.push_back(v);
} else {
SASSERT(ari_u.is_int(v) || ari_u.is_real(v));
arith_vars.push_back(v);
} }
else if (arr_u.is_array(v))
array_vars.push_back(v);
else if (ari_u.is_int(v) || ari_u.is_real(v))
arith_vars.push_back(v);
else
other_vars.push_back(v);
} }
// substitute Booleans // substitute Booleans
@ -220,8 +221,7 @@ void qe_project_spacer(ast_manager &m, app_ref_vector &vars, expr_ref &fml,
// -- bool_sub is not simplifying // -- bool_sub is not simplifying
rw(fml); rw(fml);
SASSERT(!m.is_false(fml)); SASSERT(!m.is_false(fml));
TRACE("spacer_mbp", tout << "Projected Booleans:\n" TRACE("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n";);
<< fml << "\n";);
bool_sub.reset(); bool_sub.reset();
} }
@ -230,7 +230,7 @@ void qe_project_spacer(ast_manager &m, app_ref_vector &vars, expr_ref &fml,
vars.reset(); vars.reset();
// project arrays // project arrays
{ if (!array_vars.empty()) {
scoped_no_proof _sp(m); scoped_no_proof _sp(m);
// -- local rewriter that is aware of current proof mode // -- local rewriter that is aware of current proof mode
th_rewriter srw(m); th_rewriter srw(m);
@ -243,14 +243,15 @@ void qe_project_spacer(ast_manager &m, app_ref_vector &vars, expr_ref &fml,
TRACE("spacer_mbp", tout << "extended model:\n"; model_pp(tout, mdl); TRACE("spacer_mbp", tout << "extended model:\n"; model_pp(tout, mdl);
tout << "Auxiliary variables of index and value sorts:\n"; tout << "Auxiliary variables of index and value sorts:\n";
tout << vars;); tout << vars << "\n";);
if (vars.empty()) { break; } if (vars.empty())
break;
} }
// project reals and ints // project reals and ints
if (!arith_vars.empty()) { if (!arith_vars.empty()) {
TRACE("spacer_mbp", tout << "Arith vars:\n" << arith_vars;); TRACE("spacer_mbp", tout << "Arith vars:" << arith_vars << "\n";);
if (use_native_mbp) { if (use_native_mbp) {
qe::mbproj mbp(m); qe::mbproj mbp(m);
@ -260,19 +261,19 @@ void qe_project_spacer(ast_manager &m, app_ref_vector &vars, expr_ref &fml,
mbp(true, arith_vars, mdl, fmls); mbp(true, arith_vars, mdl, fmls);
fml = mk_and(fmls); fml = mk_and(fmls);
SASSERT(arith_vars.empty()); SASSERT(arith_vars.empty());
} else { }
else {
scoped_no_proof _sp(m); scoped_no_proof _sp(m);
spacer_qe::arith_project(mdl, arith_vars, fml); spacer_qe::arith_project(mdl, arith_vars, fml);
} }
TRACE("spacer_mbp", tout << "Projected arith vars:\n" TRACE("spacer_mbp", tout << "Projected arith vars: "<< fml << "\n";
<< fml << "\n"; tout << "Remaining arith vars:" << arith_vars << "\n";);
tout << "Remaining arith vars:\n"
<< arith_vars << "\n";);
SASSERT(!m.is_false(fml)); SASSERT(!m.is_false(fml));
} }
if (!arith_vars.empty()) { mbqi_project(mdl, arith_vars, fml); } if (!arith_vars.empty())
mbqi_project(mdl, arith_vars, fml);
// substitute any remaining arith vars // substitute any remaining arith vars
if (!dont_sub && !arith_vars.empty()) { if (!dont_sub && !arith_vars.empty()) {
@ -289,26 +290,30 @@ void qe_project_spacer(ast_manager &m, app_ref_vector &vars, expr_ref &fml,
SASSERT(mev.is_true(fml));); SASSERT(mev.is_true(fml)););
vars.reset(); vars.reset();
if (dont_sub && !arith_vars.empty()) { vars.append(arith_vars); } vars.append(other_vars);
if (dont_sub && !arith_vars.empty())
vars.append(arith_vars);
TRACE("qe", tout << "after projection: " << fml << ": " << vars << "\n");
} }
static expr *apply_accessor(ast_manager &m, ptr_vector<func_decl> const &acc, static expr *apply_accessor(ast_manager &m, ptr_vector<func_decl> const &acc,
unsigned j, func_decl *f, expr *c) { unsigned j, func_decl *f, expr *c) {
if (is_app(c) && to_app(c)->get_decl() == f) { if (is_app(c) && to_app(c)->get_decl() == f)
return to_app(c)->get_arg(j); return to_app(c)->get_arg(j);
} else { else
return m.mk_app(acc[j], c); return m.mk_app(acc[j], c);
}
} }
void qe_project(ast_manager &m, app_ref_vector &vars, expr_ref &fml, model &mdl, void qe_project(ast_manager &m, app_ref_vector &vars, expr_ref &fml, model &mdl,
bool reduce_all_selects, bool use_native_mbp, bool dont_sub) { bool reduce_all_selects, bool use_native_mbp, bool dont_sub) {
if (use_native_mbp) if (!use_native_mbp)
qe_project_z3(m, vars, fml, mdl, reduce_all_selects, use_native_mbp,
dont_sub);
else
qe_project_spacer(m, vars, fml, mdl, reduce_all_selects, use_native_mbp, qe_project_spacer(m, vars, fml, mdl, reduce_all_selects, use_native_mbp,
dont_sub); dont_sub);
if (!vars.empty())
qe_project_z3(m, vars, fml, mdl, reduce_all_selects, use_native_mbp,
dont_sub);
} }
void expand_literals(ast_manager &m, expr_ref_vector &conjs) { void expand_literals(ast_manager &m, expr_ref_vector &conjs) {
@ -329,12 +334,14 @@ void expand_literals(ast_manager &m, expr_ref_vector &conjs) {
conjs[i] = arith.mk_le(e1, e2); conjs[i] = arith.mk_le(e1, e2);
if (i + 1 == conjs.size()) { if (i + 1 == conjs.size()) {
conjs.push_back(arith.mk_ge(e1, e2)); conjs.push_back(arith.mk_ge(e1, e2));
} else { }
else {
conjs.push_back(conjs[i + 1].get()); conjs.push_back(conjs[i + 1].get());
conjs[i + 1] = arith.mk_ge(e1, e2); conjs[i + 1] = arith.mk_ge(e1, e2);
} }
++i; ++i;
} else if ((m.is_eq(e, c, val) && is_app(val) && }
else if ((m.is_eq(e, c, val) && is_app(val) &&
dt.is_constructor(to_app(val))) || dt.is_constructor(to_app(val))) ||
(m.is_eq(e, val, c) && is_app(val) && (m.is_eq(e, val, c) && is_app(val) &&
dt.is_constructor(to_app(val)))) { dt.is_constructor(to_app(val)))) {
@ -346,8 +353,9 @@ void expand_literals(ast_manager &m, expr_ref_vector &conjs) {
conjs.push_back(m.mk_eq(apply_accessor(m, acc, j, f, c), conjs.push_back(m.mk_eq(apply_accessor(m, acc, j, f, c),
to_app(val)->get_arg(j))); to_app(val)->get_arg(j)));
} }
} else if ((m.is_eq(e, c, val) && bv.is_numeral(val, r, bv_size)) || }
(m.is_eq(e, val, c) && bv.is_numeral(val, r, bv_size))) { else if ((m.is_eq(e, c, val) && bv.is_numeral(val, r, bv_size)) ||
(m.is_eq(e, val, c) && bv.is_numeral(val, r, bv_size))) {
rational two(2); rational two(2);
for (unsigned j = 0; j < bv_size; ++j) { for (unsigned j = 0; j < bv_size; ++j) {
parameter p(j); parameter p(j);
@ -355,11 +363,10 @@ void expand_literals(ast_manager &m, expr_ref_vector &conjs) {
bv.mk_extract(j, j, c)); bv.mk_extract(j, j, c));
if ((r % two).is_zero()) { e = m.mk_not(e); } if ((r % two).is_zero()) { e = m.mk_not(e); }
r = div(r, two); r = div(r, two);
if (j == 0) { if (j == 0)
conjs[i] = e; conjs[i] = e;
} else { else
conjs.push_back(e); conjs.push_back(e);
}
} }
} }
} }

View file

@ -6,6 +6,7 @@ z3_add_component(mbp
mbp_basic_tg.cpp mbp_basic_tg.cpp
mbp_datatypes.cpp mbp_datatypes.cpp
mbp_dt_tg.cpp mbp_dt_tg.cpp
mbp_euf.cpp
mbp_qel.cpp mbp_qel.cpp
mbp_qel_util.cpp mbp_qel_util.cpp
mbp_plugin.cpp mbp_plugin.cpp

View file

@ -27,7 +27,7 @@ class mbp_basic_tg : public mbp_tg_plugin {
struct impl; struct impl;
impl *m_impl; impl *m_impl;
public: public:
mbp_basic_tg(ast_manager &man, mbp::term_graph &tg, model &mdl, mbp_basic_tg(ast_manager &man, mbp::term_graph &tg, model &mdl,
obj_hashtable<app> &vars_set, expr_sparse_mark &seen); obj_hashtable<app> &vars_set, expr_sparse_mark &seen);
// iterate through all terms in m_tg and apply all basic MBP rules once // iterate through all terms in m_tg and apply all basic MBP rules once

85
src/qe/mbp/mbp_euf.cpp Normal file
View file

@ -0,0 +1,85 @@
/*++
Copyright (c) 2025 Microsoft Corporation
--*/
#include "ast/ast_util.h"
#include "ast/for_each_expr.h"
#include "qe/mbp/mbp_euf.h"
#include "qe/mbp/mbp_term_graph.h"
namespace mbp {
euf_project_plugin::euf_project_plugin(ast_manager& m): project_plugin(m) {
}
euf_project_plugin::~euf_project_plugin() {
}
bool euf_project_plugin::project1(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) {
return false;
}
family_id euf_project_plugin::get_family_id() {
return basic_family_id;
}
bool euf_project_plugin::operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
return false;
}
bool euf_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits, vector<def>& defs) {
if (vars.empty())
return false;
flatten_and(lits);
expr_mark var_set;
auto is_pure = [&](expr_mark& var_set, expr* v) {
return all_of(subterms::all(expr_ref(v, m)), [&](expr* w) { return !var_set.is_marked(w); });
};
for (auto v : vars)
var_set.mark(v, true);
unsigned has_def = false;
#if 1
// solve trivial equations
for (auto e : lits) {
expr* x = nullptr, *y = nullptr;
if (m.is_eq(e, x, y) && var_set.is_marked(x) && is_pure(var_set, y)) {
vars.erase(to_app(x));
defs.push_back({ expr_ref(x, m), expr_ref(y, m) });
has_def = true;
}
else if (m.is_eq(e, y, x) && var_set.is_marked(x) && is_pure(var_set, y)) {
vars.erase(to_app(x));
defs.push_back({ expr_ref(x, m), expr_ref(y, m) });
has_def = true;
}
}
if (has_def)
return true;
#endif
// check if there is a variable of uninterp sort
if (all_of(vars, [&](expr* v) { return !m.is_uninterp(v->get_sort()); }))
return has_def;
term_graph tg(m);
tg.add_lits(lits);
for (auto v : vars)
if (m.is_uninterp(v->get_sort()))
tg.add_var(v);
//
// now what:
/// walk all subterms of lits.
// push in partitions by value.
// add equations from model
// compute repr from tg.
//
return has_def;
}
}

30
src/qe/mbp/mbp_euf.h Normal file
View file

@ -0,0 +1,30 @@
/*++
Copyright (c) 2025 Microsoft Corporation
--*/
#pragma once
#include "model/model.h"
#include "qe/mbp/mbp_plugin.h"
namespace mbp {
class euf_project_plugin : public project_plugin {
public:
euf_project_plugin(ast_manager& m);
~euf_project_plugin() override;
bool project1(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) override;
bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override { return false; }
family_id get_family_id() override;
bool operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) override;
bool project(model& model, app_ref_vector& vars, expr_ref_vector& lits, vector<def>& defs) override;
void saturate(model& model, func_decl_ref_vector const& shared, expr_ref_vector& lits) override { UNREACHABLE(); }
};
};

View file

@ -205,7 +205,7 @@ namespace mbp {
else else
extract_bools(eval, fmls, i, fml, true); extract_bools(eval, fmls, i, fml, true);
} }
TRACE("qe", tout << fmls << "\n";); TRACE("qe", tout << "fmls: " << fmls << "\n";);
} }
void project_plugin::extract_bools(model_evaluator& eval, expr_ref_vector& fmls, unsigned idx, expr* fml, bool is_true) { void project_plugin::extract_bools(model_evaluator& eval, expr_ref_vector& fmls, unsigned idx, expr* fml, bool is_true) {

View file

@ -21,6 +21,7 @@ Revision History:
#pragma once #pragma once
#include "ast/ast.h" #include "ast/ast.h"
#include "ast/ast_pp.h"
#include "util/params.h" #include "util/params.h"
#include "model/model.h" #include "model/model.h"
#include "math/simplex/model_based_opt.h" #include "math/simplex/model_based_opt.h"
@ -32,11 +33,12 @@ namespace mbp {
struct def { struct def {
expr_ref var, term; expr_ref var, term;
def(const expr_ref& v, expr_ref& t): var(v), term(t) {}
}; };
class project_plugin { class project_plugin {
protected:
ast_manager& m; ast_manager& m;
private:
expr_mark m_visited; expr_mark m_visited;
ptr_vector<expr> m_to_visit; ptr_vector<expr> m_to_visit;
expr_mark m_bool_visited; expr_mark m_bool_visited;
@ -110,3 +112,6 @@ namespace mbp {
}; };
} }
inline std::ostream& operator<<(std::ostream& out, mbp::def const& d) {
return out << d.var << " -> " << d.term << "\n";
}

View file

@ -1018,8 +1018,7 @@ void term_graph::to_lits(expr_ref_vector &lits, bool all_equalities,
void term_graph::to_lits_qe_lite(expr_ref_vector &lits, void term_graph::to_lits_qe_lite(expr_ref_vector &lits,
std::function<bool(expr *)> *non_core) { std::function<bool(expr *)> *non_core) {
DEBUG_CODE(for (auto t : m_terms) SASSERT(t->get_repr());); DEBUG_CODE(for (auto t : m_terms) SASSERT(t->get_repr()););
DEBUG_CODE(for (auto t DEBUG_CODE(for (auto t : m_terms)
: m_terms)
SASSERT(!t->is_cgr() || t->get_repr()->is_cgr());); SASSERT(!t->is_cgr() || t->get_repr()->is_cgr()););
is_non_core not_in_core(non_core); is_non_core not_in_core(non_core);
check_pred contains_nc(not_in_core, m, false); check_pred contains_nc(not_in_core, m, false);

View file

@ -32,10 +32,10 @@ Notes:
#include "util/plugin_manager.h" #include "util/plugin_manager.h"
namespace mbp { namespace mbp {
namespace is_ground_ns { namespace is_ground_ns {
struct proc; struct proc;
struct found; struct found;
} // namespace is_ground_ns } // namespace is_ground_ns
class term; class term;
class term_graph { class term_graph {
@ -246,16 +246,16 @@ private:
bool makes_cycle(term *t); bool makes_cycle(term *t);
}; };
namespace is_ground_ns { namespace is_ground_ns {
struct found {}; struct found {};
struct proc { struct proc {
term_graph::is_variable_proc &m_is_var; term_graph::is_variable_proc &m_is_var;
proc(term_graph::is_variable_proc &is_var) : m_is_var(is_var) {} proc(term_graph::is_variable_proc &is_var) : m_is_var(is_var) {}
void operator()(var *n) const {} void operator()(var *n) const {}
void operator()(app const *n) const { void operator()(app const *n) const {
if (m_is_var.contains(n->get_decl())) throw found(); if (m_is_var.contains(n->get_decl())) throw found();
} }
void operator()(quantifier *n) const {} void operator()(quantifier *n) const {}
}; };
} // namespace is_ground_ns } // namespace is_ground_ns
} // namespace mbp } // namespace mbp

View file

@ -23,12 +23,12 @@ Revision History:
#include "util/obj_hashtable.h" #include "util/obj_hashtable.h"
class mbp_tg_plugin { class mbp_tg_plugin {
public: public:
// iterate through all terms in m_tg and apply all theory MBP rules once // iterate through all terms in m_tg and apply all theory MBP rules once
// returns true if any rules were applied // returns true if any rules were applied
virtual bool apply() { return false; }; virtual bool apply() { return false; };
virtual ~mbp_tg_plugin() = default; virtual ~mbp_tg_plugin() = default;
virtual void use_model() { }; virtual void use_model() { };
virtual void get_new_vars(app_ref_vector*&) { }; virtual void get_new_vars(app_ref_vector*&) { };
virtual family_id get_family_id() const { return null_family_id; }; virtual family_id get_family_id() const { return null_family_id; };
}; };

View file

@ -37,6 +37,7 @@ Revision History:
#include "qe/lite/qel.h" #include "qe/lite/qel.h"
#include "qe/mbp/mbp_arith.h" #include "qe/mbp/mbp_arith.h"
#include "qe/mbp/mbp_arrays.h" #include "qe/mbp/mbp_arrays.h"
#include "qe/mbp/mbp_euf.h"
#include "qe/mbp/mbp_qel.h" #include "qe/mbp/mbp_qel.h"
#include "qe/mbp/mbp_datatypes.h" #include "qe/mbp/mbp_datatypes.h"
@ -352,6 +353,7 @@ public:
add_plugin(alloc(mbp::arith_project_plugin, m)); add_plugin(alloc(mbp::arith_project_plugin, m));
add_plugin(alloc(mbp::datatype_project_plugin, m)); add_plugin(alloc(mbp::datatype_project_plugin, m));
add_plugin(alloc(mbp::array_project_plugin, m)); add_plugin(alloc(mbp::array_project_plugin, m));
add_plugin(alloc(mbp::euf_project_plugin, m));
updt_params(p); updt_params(p);
} }
@ -392,18 +394,18 @@ public:
flatten_and(fml, fmls); flatten_and(fml, fmls);
} }
else { else {
extract_literals(model, vars, fmls); extract_literals(model, vars, fmls);
bool change = true; bool change = true;
while (change && !vars.empty()) { while (change && !vars.empty()) {
change = solve(model, vars, fmls); change = solve(model, vars, fmls);
for (auto* p : m_plugins) { for (auto* p : m_plugins) {
if (p && p->solve(model, vars, fmls)) { if (p && p->solve(model, vars, fmls)) {
change = true; change = true;
}
} }
} }
} }
} }
}
bool validate_model(model& model, expr_ref_vector const& fmls) { bool validate_model(model& model, expr_ref_vector const& fmls) {
for (expr* f : fmls) { for (expr* f : fmls) {
@ -419,24 +421,27 @@ public:
return any_of(subterms::all(e), [&](expr* c) { return seq.is_char(c) || seq.is_seq(c); }); return any_of(subterms::all(e), [&](expr* c) { return seq.is_char(c) || seq.is_seq(c); });
} }
void operator()(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls, vector<mbp::def>* defs = nullptr) { void operator()(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls, vector<mbp::def>* defs = nullptr) {
//don't use mbp_qel on some theories where model evaluation is //don't use mbp_qel on some theories where model evaluation is
//incomplete This is not a limitation of qel. Fix this either by //incomplete This is not a limitation of qel. Fix this either by
//making mbp choices less dependent on the model evaluation methods //making mbp choices less dependent on the model evaluation methods
//or fix theory rewriters to make terms evaluation complete //or fix theory rewriters to make terms evaluation complete
if (m_use_qel && !has_unsupported_th(fmls) && !defs) { if (m_use_qel && !has_unsupported_th(fmls) && !defs) {
bool dsub = m_dont_sub; bool dsub = m_dont_sub;
m_dont_sub = !force_elim; m_dont_sub = !force_elim;
expr_ref fml(m); expr_ref fml(m);
fml = mk_and(fmls); fml = mk_and(fmls);
spacer_qel(vars, model, fml); spacer_qel(vars, model, fml);
fmls.reset(); fmls.reset();
flatten_and(fml, fmls); flatten_and(fml, fmls);
m_dont_sub = dsub; m_dont_sub = dsub;
} TRACE("qe", tout << "spacer-qel " << vars << " " << fml << "\n");
else {
mbp(force_elim, vars, model, fmls, defs);
}
} }
else {
mbp(force_elim, vars, model, fmls, defs);
TRACE("qe", tout << "mbp " << vars << " " << fmls << "\n";
if (defs) { tout << "defs: "; for (auto const& d : *defs) tout << d << "\n"; tout << "\n";});
}
}
void mbp(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls, vector<mbp::def>* defs) { void mbp(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls, vector<mbp::def>* defs) {
SASSERT(validate_model(model, fmls)); SASSERT(validate_model(model, fmls));
@ -444,9 +449,12 @@ public:
app_ref var(m); app_ref var(m);
expr_ref_vector unused_fmls(m); expr_ref_vector unused_fmls(m);
bool progress = true; bool progress = true;
preprocess_solve(model, vars, fmls); TRACE("qe", tout << "eliminate vars: " << vars << "fmls: " << fmls << "\n");
if (!defs)
preprocess_solve(model, vars, fmls);
filter_variables(model, vars, fmls, unused_fmls); filter_variables(model, vars, fmls, unused_fmls);
project_bools(model, vars, fmls); project_bools(model, vars, fmls);
TRACE("qe", tout << "eliminate vars: " << vars << "\nfmls: " << fmls << "\nunused: " << unused_fmls <<"\n");
while (progress && !vars.empty() && !fmls.empty() && m.limit().inc()) { while (progress && !vars.empty() && !fmls.empty() && m.limit().inc()) {
app_ref_vector new_vars(m); app_ref_vector new_vars(m);
progress = false; progress = false;
@ -455,10 +463,12 @@ public:
unsigned sz = defs->size(); unsigned sz = defs->size();
p->project(model, vars, fmls, *defs); p->project(model, vars, fmls, *defs);
progress |= sz < defs->size(); progress |= sz < defs->size();
TRACE("qe", tout << "after project " << m.get_family_name(p->get_family_id()) << ": " << vars << "\n");
} }
else if (p) else if (p)
(*p)(model, vars, fmls); (*p)(model, vars, fmls);
} }
TRACE("qe", tout << "projecting " << vars << "\n");
while (!vars.empty() && !fmls.empty() && !defs && m.limit().inc()) { while (!vars.empty() && !fmls.empty() && !defs && m.limit().inc()) {
var = vars.back(); var = vars.back();
vars.pop_back(); vars.pop_back();
@ -491,16 +501,17 @@ public:
if (!m.limit().inc()) if (!m.limit().inc())
return; return;
vars.append(new_vars); vars.append(new_vars);
if (progress) { if (progress && !defs)
preprocess_solve(model, vars, fmls); preprocess_solve(model, vars, fmls);
} TRACE("qe", tout << "looping " << vars << "\n");
} }
if (fmls.empty()) { if (fmls.empty()) {
vars.reset(); vars.reset();
} }
fmls.append(unused_fmls); fmls.append(unused_fmls);
SASSERT(validate_model(model, fmls)); SASSERT(validate_model(model, fmls));
TRACE("qe", tout << vars << " " << fmls << "\n";); TRACE("qe", tout << "vars: " << vars << "\nfmls: " << fmls << "\n";);
} }
void do_qe_lite(app_ref_vector& vars, expr_ref& fml) { void do_qe_lite(app_ref_vector& vars, expr_ref& fml) {
@ -529,16 +540,16 @@ public:
fml = mk_and(fmls); fml = mk_and(fmls);
} }
void qel_project(app_ref_vector &vars, model &mdl, expr_ref &fml, bool reduce_all_selects) { void qel_project(app_ref_vector &vars, model &mdl, expr_ref &fml, bool reduce_all_selects) {
flatten_and(fml); flatten_and(fml);
mbp::mbp_qel mbptg(m, m_params); mbp::mbp_qel mbptg(m, m_params);
mbptg(vars, fml, mdl); mbptg(vars, fml, mdl);
if (reduce_all_selects) rewrite_read_over_write(fml, mdl, fml); if (reduce_all_selects) rewrite_read_over_write(fml, mdl, fml);
m_rw(fml); m_rw(fml);
TRACE("qe", tout << "After mbp_tg:\n" TRACE("qe", tout << "After mbp_tg:\n"
<< fml << " models " << mdl.is_true(fml) << "\n" << fml << " models " << mdl.is_true(fml) << "\n"
<< "Vars: " << vars << "\n";); << "Vars: " << vars << "\n";);
} }
void spacer_qel(app_ref_vector& vars, model& mdl, expr_ref& fml) { void spacer_qel(app_ref_vector& vars, model& mdl, expr_ref& fml) {
TRACE("qe", tout << "Before projection:\n" << fml << "\n" << "Vars: " << vars << "\n";); TRACE("qe", tout << "Before projection:\n" << fml << "\n" << "Vars: " << vars << "\n";);
@ -600,12 +611,11 @@ public:
} }
void spacer(app_ref_vector& vars, model& mdl, expr_ref& fml) { void spacer(app_ref_vector& vars, model& mdl, expr_ref& fml) {
if (m_use_qel) { TRACE("qe", tout << "spacer " << m_use_qel << " " << fml << " " << vars << "\n");
if (m_use_qel)
spacer_qel(vars, mdl, fml); spacer_qel(vars, mdl, fml);
} else
else {
spacer_qe_lite(vars, mdl, fml); spacer_qe_lite(vars, mdl, fml);
}
} }
void spacer_qe_lite(app_ref_vector& vars, model& mdl, expr_ref& fml) { void spacer_qe_lite(app_ref_vector& vars, model& mdl, expr_ref& fml) {