3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-16 05:48:44 +00:00

more on #3858 elim_term_ite

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-04-09 10:31:21 -07:00
parent 21b7dc627e
commit cc794a19bc
2 changed files with 46 additions and 32 deletions

View file

@ -49,6 +49,8 @@ public:
Otherwise, (VAR 0) is stored in the first position, (VAR 1) in the second, and so on. Otherwise, (VAR 0) is stored in the first position, (VAR 1) in the second, and so on.
*/ */
expr_ref operator()(expr * n, unsigned num_args, expr * const * args); expr_ref operator()(expr * n, unsigned num_args, expr * const * args);
inline expr_ref operator()(expr * n, expr_ref_vector const& args) { return (*this)(n, args.size(), args.c_ptr()); }
inline expr_ref operator()(expr * n, ptr_vector<expr> const& args) { return (*this)(n, args.size(), args.c_ptr()); }
void reset() { m_reducer.reset(); } void reset() { m_reducer.reset(); }
}; };
@ -90,6 +92,8 @@ class expr_free_vars {
ptr_vector<sort> m_sorts; ptr_vector<sort> m_sorts;
ptr_vector<expr> m_todo; ptr_vector<expr> m_todo;
public: public:
expr_free_vars() {}
expr_free_vars(expr* e) { (*this)(e); }
void reset(); void reset();
void operator()(expr* e); void operator()(expr* e);
void accumulate(expr* e); void accumulate(expr* e);

View file

@ -17,27 +17,32 @@ Revision History:
--*/ --*/
#include "muz/transforms/dl_mk_elim_term_ite.h"
#include "tactic/core/blast_term_ite_tactic.h"
#include "ast/ast_util.h" #include "ast/ast_util.h"
#include "ast/expr_abstract.h" #include "ast/expr_abstract.h"
#include "tactic/core/blast_term_ite_tactic.h"
#include "tactic/tactic.h" #include "tactic/tactic.h"
#include "tactic/core/elim_term_ite_tactic.h" #include "tactic/core/elim_term_ite_tactic.h"
#include "muz/transforms/dl_mk_elim_term_ite.h"
namespace { namespace {
/**
* collect uninterpreted constants that are contained in ground
*/
struct uninterp_const_collector { struct uninterp_const_collector {
app_ref_vector &m_consts; app_ref_vector& m_consts;
uninterp_const_collector(app_ref_vector &v) : m_consts(v) {} expr_ref_vector const& m_ground;
uninterp_const_collector(app_ref_vector &v, expr_ref_vector const& g) : m_consts(v), m_ground(g) {}
void operator()(var *v) {} void operator()(var *v) {}
void operator()(quantifier *n) {} void operator()(quantifier *n) {}
void operator()(expr *a){} void operator()(expr *a){}
void operator()(app *a){ void operator()(app *a){
if (is_uninterp_const(a)) {m_consts.push_back(a);}; if (is_uninterp_const(a) && m_ground.contains(a))
m_consts.push_back(a);
} }
}; };
void collect_uninterp_consts(expr *e, app_ref_vector &v) { void collect_uninterp_consts(expr *e, app_ref_vector &v, expr_ref_vector const& g) {
uninterp_const_collector c(v); uninterp_const_collector c(v, g);
quick_for_each_expr(c, e); quick_for_each_expr(c, e);
} }
@ -47,9 +52,9 @@ namespace {
term_ite_proc(ast_manager &m) : m(m) {} term_ite_proc(ast_manager &m) : m(m) {}
void operator()(var *v) {} void operator()(var *v) {}
void operator()(quantifier *n) {} void operator()(quantifier *n) {}
void operator()(expr *a){} void operator()(expr *a) {
void operator()(app *a){ if (m.is_term_ite(a))
if (m.is_term_ite(a)) throw found(); throw found();
} }
}; };
@ -57,14 +62,16 @@ namespace {
term_ite_proc f(m); term_ite_proc f(m);
try { try {
quick_for_each_expr(f, e); quick_for_each_expr(f, e);
} catch (const term_ite_proc::found &) { }
catch (const term_ite_proc::found &) {
return true; return true;
} }
return false; return false;
} }
bool has_term_ite(expr_ref &e) { return has_term_ite(e, e.m());}
bool has_term_ite(expr_ref &e) { return has_term_ite(e, e.m());}
} }
namespace datalog { namespace datalog {
mk_elim_term_ite::mk_elim_term_ite(context & ctx, unsigned priority) : mk_elim_term_ite::mk_elim_term_ite(context & ctx, unsigned priority) :
rule_transformer::plugin(priority, false), rule_transformer::plugin(priority, false),
@ -75,18 +82,23 @@ namespace datalog {
mk_elim_term_ite::~mk_elim_term_ite() {} mk_elim_term_ite::~mk_elim_term_ite() {}
/**
\brief map free variables in e to ground, fresh, constants
m_ground is reset on every new rule so it is safe to assume
that the sorts in m_ground are consistent.
*/
expr_ref mk_elim_term_ite::ground(expr* e) { expr_ref mk_elim_term_ite::ground(expr* e) {
expr_free_vars fv; expr_free_vars fv(e);
fv(e); m_ground.reserve(fv.size());
if (m_ground.size() < fv.size())
m_ground.resize(fv.size());
for (unsigned i = 0, sz = fv.size(); i < sz; ++i) { for (unsigned i = 0, sz = fv.size(); i < sz; ++i) {
if (fv[i] && !m_ground.get(i)) if (!fv[i])
continue;
if (!m_ground.get(i))
m_ground[i] = m.mk_fresh_const("c", fv[i]); m_ground[i] = m.mk_fresh_const("c", fv[i]);
SASSERT(m.get_sort(m_ground.get(i)) == fv[i]);
} }
var_subst vsub(m, false); var_subst vsub(m, false);
return vsub(e, m_ground.size(), m_ground.c_ptr()); return vsub(e, m_ground);
} }
bool mk_elim_term_ite::elim(rule &r, rule_set &new_rules){ bool mk_elim_term_ite::elim(rule &r, rule_set &new_rules){
@ -96,13 +108,12 @@ namespace datalog {
unsigned utsz = r.get_uninterpreted_tail_size(); unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size(); unsigned tsz = r.get_tail_size();
expr_ref_vector new_conjs(m); expr_ref_vector new_conjs(m);
expr_ref tmp(m);
for (unsigned i = utsz; i < tsz; ++i) for (unsigned i = utsz; i < tsz; ++i)
new_conjs.push_back(r.get_tail(i)); new_conjs.push_back(r.get_tail(i));
flatten_and(new_conjs); flatten_and(new_conjs);
expr_ref fml1(m), fml2(m), body(m), head(m); expr_ref fml1(m), fml2(m), body(m);
// blast ite // blast ite
body = mk_and(new_conjs); body = mk_and(new_conjs);
@ -127,12 +138,11 @@ namespace datalog {
rule_ref new_rule(rm.mk(r.get_head(), tail.size(), tail.c_ptr(), nullptr, r.name(), false), rm); rule_ref new_rule(rm.mk(r.get_head(), tail.size(), tail.c_ptr(), nullptr, r.name(), false), rm);
rm.mk_rule_rewrite_proof(r, *new_rule.get()); rm.mk_rule_rewrite_proof(r, *new_rule.get());
new_rules.add_rule(new_rule); new_rules.add_rule(new_rule);
TRACE("dl_term_ite", tout << "No term-ite after blast_term_ite\n";); TRACE("dl", tout << "No term-ite after blast_term_ite\n";);
return true; return true;
} }
TRACE("dl_term_ite", TRACE("dl", tout << "Rule has term-ite after blasting, starting elimination\n";);
tout << "Rule has term-ite after blasting, starting elimination\n";);
body = ground(body); body = ground(body);
// elim ite // elim ite
tactic_ref elim_term_ite = mk_elim_term_ite_tactic(m); tactic_ref elim_term_ite = mk_elim_term_ite_tactic(m);
@ -145,6 +155,7 @@ namespace datalog {
unsigned sz = g->num_exprs(); unsigned sz = g->num_exprs();
(*elim_term_ite)(g, result); (*elim_term_ite)(g, result);
if (result.size() == 1) { if (result.size() == 1) {
// NSB code review: fragile test for effect
goal_ref new_goal = result[0]; goal_ref new_goal = result[0];
if (new_goal->num_exprs() != sz) { if (new_goal->num_exprs() != sz) {
new_conjs.reset(); new_conjs.reset();
@ -160,20 +171,20 @@ namespace datalog {
body = mk_and(new_conjs); body = mk_and(new_conjs);
rw(body); rw(body);
head = ground(r.get_head()); fml2 = m.mk_implies(body, ground(r.get_head()));
fml2 = m.mk_implies(body, head);
if (has_term_ite(fml2)) if (has_term_ite(fml2))
return false; return false;
app_ref_vector consts(m); app_ref_vector consts(m);
collect_uninterp_consts(fml2, consts); collect_uninterp_consts(fml2, consts, m_ground);
fml2 = mk_forall(m, consts.size(), consts.c_ptr(), fml2); fml2 = mk_forall(m, consts.size(), consts.c_ptr(), fml2);
proof_ref p(m); proof_ref p(m);
rm.mk_rule(fml2, p, new_rules, r.name()); rm.mk_rule(fml2, p, new_rules, r.name());
// TBD: breaks abstraction barrier: mk_rule could convert a single formula
// NSB code review: breaks abstraction barrier: mk_rule could convert a single formula
// into multiple rules // into multiple rules
rm.mk_rule_rewrite_proof(r, *new_rules.last()); rm.mk_rule_rewrite_proof(r, *new_rules.last());
TRACE("dl_term_ite", tout << "New rule: " << fml2 << "\n";); TRACE("dl", tout << "New rule: " << fml2 << "\n";);
return true; return true;
} }
@ -188,8 +199,7 @@ namespace datalog {
bool change = false; bool change = false;
for (auto *rule : source) { for (auto *rule : source) {
if (m_ctx.canceled()) { if (m_ctx.canceled()) {
change = false; return nullptr;
break;
} }
change |= elim(*rule, *rules); change |= elim(*rule, *rules);
} }