3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-26 07:43:41 +00:00

perf improvements to solve-eqs and euf-completion

This commit is contained in:
Nikolaj Bjorner 2022-11-16 22:15:02 -08:00
parent 2c7799939e
commit 6662afdd26
4 changed files with 129 additions and 51 deletions

View file

@ -58,31 +58,43 @@ namespace euf {
}
void completion::reduce() {
unsigned rounds = 0;
do {
++m_epoch;
++rounds;
m_has_new_eq = false;
add_egraph();
map_canonical();
read_egraph();
IF_VERBOSE(11, verbose_stream() << "(euf.completion :rounds " << rounds << ")\n");
}
while (m_has_new_eq);
while (m_has_new_eq && rounds <= 3);
}
void completion::add_egraph() {
m_nodes.reset();
m_nodes_to_canonize.reset();
unsigned sz = m_fmls.size();
auto add_children = [&](enode* n) {
for (auto* ch : enode_args(n))
m_nodes_to_canonize.push_back(ch);
};
for (unsigned i = m_qhead; i < sz; ++i) {
auto [f,d] = m_fmls[i]();
auto* n = mk_enode(f);
if (m.is_eq(f)) {
m_egraph.merge(n->get_arg(0), n->get_arg(1), d);
m_nodes.push_back(n->get_arg(0));
m_nodes.push_back(n->get_arg(1));
add_children(n->get_arg(0));
add_children(n->get_arg(1));
}
if (m.is_not(f))
if (m.is_not(f)) {
m_egraph.merge(n->get_arg(0), m_ff, d);
else
add_children(n->get_arg(0));
}
else {
m_egraph.merge(n, m_tt, d);
add_children(n);
}
}
m_egraph.propagate();
}
@ -106,15 +118,7 @@ namespace euf {
m_fmls.update(i, dependent_expr(m, g, dep));
m_stats.m_num_rewrites++;
IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n");
expr* x, * y;
if (m.is_eq(g, x, y) && new_eq(x, y))
m_has_new_eq = true;
if (m.is_and(g) && !m_has_new_eq)
for (expr* arg : *to_app(g))
if (m.is_eq(arg, x, y))
m_has_new_eq |= new_eq(x, y);
else if (!m.is_true(arg))
m_has_new_eq = true;
update_has_new_eq(g);
}
CTRACE("euf_completion", g != f, tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n");
}
@ -122,12 +126,34 @@ namespace euf {
advance_qhead(m_fmls.size());
}
bool completion::new_eq(expr* a, expr* b) {
bool completion::is_new_eq(expr* a, expr* b) {
enode* na = m_egraph.find(a);
enode* nb = m_egraph.find(b);
if (!na)
IF_VERBOSE(11, verbose_stream() << "not internalied " << mk_bounded_pp(a, m) << "\n");
if (!nb)
IF_VERBOSE(11, verbose_stream() << "not internalied " << mk_bounded_pp(b, m) << "\n");
if (na && nb && na->get_root() != nb->get_root())
IF_VERBOSE(11, verbose_stream() << m_egraph.bpp(na) << " " << m_egraph.bpp(nb) << "\n");
return !na || !nb || na->get_root() != nb->get_root();
}
void completion::update_has_new_eq(expr* g) {
expr* x, * y;
if (m_has_new_eq)
return;
else if (m.is_eq(g, x, y))
m_has_new_eq |= is_new_eq(x, y);
else if (m.is_and(g)) {
for (expr* arg : *to_app(g))
update_has_new_eq(arg);
}
else if (m.is_not(g, g))
m_has_new_eq |= is_new_eq(g, m.mk_false());
else
m_has_new_eq |= is_new_eq(g, m.mk_true());
}
enode* completion::mk_enode(expr* e) {
m_todo.push_back(e);
enode* n;
@ -138,7 +164,7 @@ namespace euf {
continue;
}
if (!is_app(e)) {
m_nodes.push_back(m_egraph.mk(e, 0, 0, nullptr));
m_nodes_to_canonize.push_back(m_egraph.mk(e, 0, 0, nullptr));
m_todo.pop_back();
continue;
}
@ -152,7 +178,7 @@ namespace euf {
m_todo.push_back(arg);
}
if (sz == m_todo.size()) {
m_nodes.push_back(m_egraph.mk(e, 0, m_args.size(), m_args.data()));
m_nodes_to_canonize.push_back(m_egraph.mk(e, 0, m_args.size(), m_args.data()));
m_todo.pop_back();
}
}
@ -314,10 +340,10 @@ namespace euf {
void completion::map_canonical() {
m_todo.reset();
enode_vector roots;
if (m_nodes.empty())
if (m_nodes_to_canonize.empty())
return;
for (unsigned i = 0; i < m_nodes.size(); ++i) {
enode* n = m_nodes[i]->get_root();
for (unsigned i = 0; i < m_nodes_to_canonize.size(); ++i) {
enode* n = m_nodes_to_canonize[i]->get_root();
if (n->is_marked1())
continue;
n->mark1();
@ -334,7 +360,7 @@ namespace euf {
for (enode* arg : enode_args(n)) {
arg = arg->get_root();
if (!arg->is_marked1())
m_nodes.push_back(arg);
m_nodes_to_canonize.push_back(arg);
}
}
for (enode* r : roots)