mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 20:18:18 +00:00
tune euf-completion
This commit is contained in:
parent
22353c2d6c
commit
9a2693bb72
|
@ -780,6 +780,10 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (m_order_eq && lhs->get_id() > rhs->get_id()) {
|
||||||
|
result = m().mk_eq(rhs, lhs);
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
return BR_FAILED;
|
return BR_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,10 +52,11 @@ Notes:
|
||||||
class bool_rewriter {
|
class bool_rewriter {
|
||||||
ast_manager & m_manager;
|
ast_manager & m_manager;
|
||||||
hoist_rewriter m_hoist;
|
hoist_rewriter m_hoist;
|
||||||
bool m_flat_and_or;
|
bool m_flat_and_or = false;
|
||||||
bool m_local_ctx;
|
bool m_local_ctx = false;
|
||||||
bool m_elim_and;
|
bool m_elim_and = false;
|
||||||
bool m_blast_distinct;
|
bool m_blast_distinct = false;
|
||||||
|
bool m_order_eq = false;
|
||||||
unsigned m_blast_distinct_threshold;
|
unsigned m_blast_distinct_threshold;
|
||||||
bool m_ite_extra_rules;
|
bool m_ite_extra_rules;
|
||||||
unsigned m_local_ctx_limit;
|
unsigned m_local_ctx_limit;
|
||||||
|
@ -90,6 +91,7 @@ public:
|
||||||
bool elim_and() const { return m_elim_and; }
|
bool elim_and() const { return m_elim_and; }
|
||||||
void set_elim_and(bool f) { m_elim_and = f; }
|
void set_elim_and(bool f) { m_elim_and = f; }
|
||||||
void reset_local_ctx_cost() { m_local_ctx_cost = 0; }
|
void reset_local_ctx_cost() { m_local_ctx_cost = 0; }
|
||||||
|
void set_order_eq(bool f) { m_order_eq = f; }
|
||||||
|
|
||||||
void updt_params(params_ref const & p);
|
void updt_params(params_ref const & p);
|
||||||
|
|
||||||
|
|
|
@ -707,9 +707,10 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
||||||
|
|
||||||
expr_ref mk_eq(expr* a, expr* b) {
|
expr_ref mk_eq(expr* a, expr* b) {
|
||||||
expr_ref result(m());
|
expr_ref result(m());
|
||||||
if (a->get_id() > b->get_id())
|
br_status st = reduce_eq(a, b, result);
|
||||||
std::swap(a, b);
|
if (BR_FAILED == st)
|
||||||
if (BR_FAILED == reduce_eq(a, b, result))
|
st = m_b_rw.mk_eq_core(a, b, result);
|
||||||
|
if (BR_FAILED == st)
|
||||||
result = m().mk_eq(a, b);
|
result = m().mk_eq(a, b);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -945,6 +946,10 @@ void th_rewriter::set_flat_and_or(bool f) {
|
||||||
m_imp->cfg().m_b_rw.set_flat_and_or(f);
|
m_imp->cfg().m_b_rw.set_flat_and_or(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void th_rewriter::set_order_eq(bool f) {
|
||||||
|
m_imp->cfg().m_b_rw.set_order_eq(f);
|
||||||
|
}
|
||||||
|
|
||||||
th_rewriter::~th_rewriter() {
|
th_rewriter::~th_rewriter() {
|
||||||
dealloc(m_imp);
|
dealloc(m_imp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ public:
|
||||||
static void get_param_descrs(param_descrs & r);
|
static void get_param_descrs(param_descrs & r);
|
||||||
|
|
||||||
void set_flat_and_or(bool f);
|
void set_flat_and_or(bool f);
|
||||||
|
void set_order_eq(bool f);
|
||||||
|
|
||||||
unsigned get_cache_size() const;
|
unsigned get_cache_size() const;
|
||||||
unsigned get_num_steps() const;
|
unsigned get_num_steps() const;
|
||||||
|
|
|
@ -43,6 +43,7 @@ Algorithm for extracting canonical form from an E-graph:
|
||||||
#include "ast/ast_util.h"
|
#include "ast/ast_util.h"
|
||||||
#include "ast/euf/euf_egraph.h"
|
#include "ast/euf/euf_egraph.h"
|
||||||
#include "ast/simplifiers/euf_completion.h"
|
#include "ast/simplifiers/euf_completion.h"
|
||||||
|
#include "ast/shared_occs.h"
|
||||||
|
|
||||||
namespace euf {
|
namespace euf {
|
||||||
|
|
||||||
|
@ -55,20 +56,99 @@ namespace euf {
|
||||||
m_rewriter(m) {
|
m_rewriter(m) {
|
||||||
m_tt = m_egraph.mk(m.mk_true(), 0, 0, nullptr);
|
m_tt = m_egraph.mk(m.mk_true(), 0, 0, nullptr);
|
||||||
m_ff = m_egraph.mk(m.mk_false(), 0, 0, nullptr);
|
m_ff = m_egraph.mk(m.mk_false(), 0, 0, nullptr);
|
||||||
|
m_rewriter.set_order_eq(true);
|
||||||
|
m_rewriter.set_flat_and_or(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void completion::reduce() {
|
void completion::reduce() {
|
||||||
unsigned rounds = 0;
|
|
||||||
do {
|
propagate_values();
|
||||||
|
if (m_fmls.inconsistent())
|
||||||
|
return;
|
||||||
|
m_has_new_eq = true;
|
||||||
|
for (unsigned rounds = 0; m_has_new_eq && rounds <= 3 && !m_fmls.inconsistent(); ++rounds) {
|
||||||
++m_epoch;
|
++m_epoch;
|
||||||
++rounds;
|
|
||||||
m_has_new_eq = false;
|
m_has_new_eq = false;
|
||||||
add_egraph();
|
add_egraph();
|
||||||
map_canonical();
|
map_canonical();
|
||||||
read_egraph();
|
read_egraph();
|
||||||
IF_VERBOSE(11, verbose_stream() << "(euf.completion :rounds " << rounds << ")\n");
|
IF_VERBOSE(11, verbose_stream() << "(euf.completion :rounds " << rounds << ")\n");
|
||||||
}
|
}
|
||||||
while (m_has_new_eq && rounds <= 3);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Propagate writes into values first. It is cheaper to propagate values directly than using
|
||||||
|
* the E-graph. The E-graph suffers from the following overhead: it prefers interpreted nodes
|
||||||
|
* as roots and therefore the "merge" function ignores the heuristic of choosing the node to appoint root
|
||||||
|
* as the one with the fewest parents. Merging a constant value with multiple terms then has a compounding
|
||||||
|
* quadratic time overhead since the parents of the value are removed and re-inserted into the congruence
|
||||||
|
* table repeatedly and with growing size (exceeding the n*log(n) overhead when choosing the root to
|
||||||
|
* have the fewest parents).
|
||||||
|
*/
|
||||||
|
void completion::propagate_values() {
|
||||||
|
shared_occs shared(m, true);
|
||||||
|
expr_substitution subst(m, true, false);
|
||||||
|
expr* x, * y;
|
||||||
|
expr_ref_buffer args(m);
|
||||||
|
auto add_shared = [&]() {
|
||||||
|
shared_occs_mark visited;
|
||||||
|
shared.reset();
|
||||||
|
for (unsigned i = 0; i < m_fmls.size(); ++i)
|
||||||
|
shared(m_fmls[i].fml(), visited);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto add_sub = [&](dependent_expr const& de) {
|
||||||
|
auto const& [f, dep] = de();
|
||||||
|
if (m.is_not(f, x) && shared.is_shared(x))
|
||||||
|
subst.insert(x, m.mk_false(), dep);
|
||||||
|
else if (shared.is_shared(f))
|
||||||
|
subst.insert(f, m.mk_true(), dep);
|
||||||
|
if (m.is_eq(f, x, y) && m.is_value(x) && shared.is_shared(y))
|
||||||
|
subst.insert(y, x, dep);
|
||||||
|
else if (m.is_eq(f, x, y) && m.is_value(y) && shared.is_shared(x))
|
||||||
|
subst.insert(x, y, dep);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto process_fml = [&](unsigned i) {
|
||||||
|
expr* f = m_fmls[i].fml();
|
||||||
|
expr_dependency* dep = m_fmls[i].dep();
|
||||||
|
expr_ref fml(m);
|
||||||
|
proof_ref pr(m);
|
||||||
|
m_rewriter(f, fml, pr);
|
||||||
|
if (fml != f) {
|
||||||
|
dep = m.mk_join(dep, m_rewriter.get_used_dependencies());
|
||||||
|
m_fmls.update(i, dependent_expr(m, fml, dep));
|
||||||
|
++m_stats.m_num_rewrites;
|
||||||
|
}
|
||||||
|
m_rewriter.reset_used_dependencies();
|
||||||
|
add_sub(m_fmls[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned rw = m_stats.m_num_rewrites + 1;
|
||||||
|
for (unsigned r = 0; r < 4 && rw != m_stats.m_num_rewrites; ++r) {
|
||||||
|
rw = m_stats.m_num_rewrites;
|
||||||
|
add_shared();
|
||||||
|
subst.reset();
|
||||||
|
m_rewriter.reset();
|
||||||
|
m_rewriter.set_substitution(&subst);
|
||||||
|
for (unsigned i = 0; i < m_qhead; ++i)
|
||||||
|
add_sub(m_fmls[i]);
|
||||||
|
for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i)
|
||||||
|
process_fml(i);
|
||||||
|
add_shared();
|
||||||
|
subst.reset();
|
||||||
|
m_rewriter.reset();
|
||||||
|
m_rewriter.set_substitution(&subst);
|
||||||
|
for (unsigned i = 0; i < m_qhead; ++i)
|
||||||
|
add_sub(m_fmls[i]);
|
||||||
|
for (unsigned i = m_fmls.size(); i-- > m_qhead && !m_fmls.inconsistent();)
|
||||||
|
process_fml(i);
|
||||||
|
if (subst.empty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rewriter.set_substitution(nullptr);
|
||||||
|
m_rewriter.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void completion::add_egraph() {
|
void completion::add_egraph() {
|
||||||
|
|
|
@ -46,6 +46,7 @@ namespace euf {
|
||||||
bool is_new_eq(expr* a, expr* b);
|
bool is_new_eq(expr* a, expr* b);
|
||||||
void update_has_new_eq(expr* g);
|
void update_has_new_eq(expr* g);
|
||||||
expr_ref mk_and(expr* a, expr* b);
|
expr_ref mk_and(expr* a, expr* b);
|
||||||
|
void propagate_values();
|
||||||
void add_egraph();
|
void add_egraph();
|
||||||
void map_canonical();
|
void map_canonical();
|
||||||
void read_egraph();
|
void read_egraph();
|
||||||
|
|
Loading…
Reference in a new issue