3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-14 23:05:26 +00:00

updates to ac-plugin

fix incrementality bugs by allowing destructive updates during saturation at the cost of redoing saturation after a pop.
This commit is contained in:
Nikolaj Bjorner 2025-07-27 13:38:24 -07:00
parent 07613942da
commit 67695b4cd6
5 changed files with 263 additions and 195 deletions

View file

@ -136,15 +136,13 @@ namespace euf {
// unit -> {} // unit -> {}
void ac_plugin::add_unit(enode* u) { void ac_plugin::add_unit(enode* u) {
m_units.push_back(u); push_equation(u, nullptr);
mk_node(u);
auto m_id = to_monomial(u, {});
init_equation(eq(to_monomial(u), m_id, justification::axiom(get_id())));
} }
// zero x -> zero // zero x -> zero
void ac_plugin::add_zero(enode* z) { void ac_plugin::add_zero(enode* z) {
mk_node(z)->is_zero = true; mk_node(z)->is_zero = true;
// zeros persist
} }
void ac_plugin::register_shared(enode* n) { void ac_plugin::register_shared(enode* n) {
@ -165,12 +163,16 @@ namespace euf {
push_undo(is_register_shared); push_undo(is_register_shared);
} }
void ac_plugin::push_scope_eh() {
push_undo(is_push_scope);
}
void ac_plugin::undo() { void ac_plugin::undo() {
auto k = m_undo.back(); auto k = m_undo.back();
m_undo.pop_back(); m_undo.pop_back();
switch (k) { switch (k) {
case is_add_eq: { case is_queue_eq: {
m_active.pop_back(); m_queued.pop_back();
break; break;
} }
case is_add_node: { case is_add_node: {
@ -180,14 +182,15 @@ namespace euf {
n->~node(); n->~node();
break; break;
} }
case is_add_monomial: { case is_push_scope: {
m_monomials.pop_back(); m_active.reset();
m_passive.reset();
m_units.reset();
m_queue_head = 0;
break; break;
} }
case is_update_eq: { case is_add_monomial: {
auto const& [idx, eq] = m_update_eq_trail.back(); m_monomials.pop_back();
m_active[idx] = eq;
m_update_eq_trail.pop_back();
break; break;
} }
case is_add_shared_index: { case is_add_shared_index: {
@ -316,14 +319,24 @@ namespace euf {
} }
void ac_plugin::merge_eh(enode* l, enode* r) { void ac_plugin::merge_eh(enode* l, enode* r) {
if (l == r) push_equation(l, r);
return; }
void ac_plugin::pop_equation(enode* l, enode* r) {
m_fuel += m_fuel_inc; m_fuel += m_fuel_inc;
auto j = justification::equality(l, r); if (!r) {
auto m1 = to_monomial(l); m_units.push_back(l);
auto m2 = to_monomial(r); mk_node(l);
TRACE(plugin, tout << "merge: " << m_name << " " << g.bpp(l) << " == " << g.bpp(r) << " " << m_pp_ll(*this, monomial(m1)) << " == " << m_pp_ll(*this, monomial(m2)) << "\n"); auto m_id = to_monomial(l, {});
init_equation(eq(m1, m2, j)); init_equation(eq(to_monomial(l), m_id, justification::axiom(get_id())), true);
}
else {
auto j = justification::equality(l, r);
auto m1 = to_monomial(l);
auto m2 = to_monomial(r);
TRACE(plugin, tout << "merge: " << m_name << " " << g.bpp(l) << " == " << g.bpp(r) << " " << m_pp_ll(*this, monomial(m1)) << " == " << m_pp_ll(*this, monomial(m2)) << "\n");
init_equation(eq(m1, m2, j), true);
}
} }
void ac_plugin::diseq_eh(enode* eq) { void ac_plugin::diseq_eh(enode* eq) {
@ -336,64 +349,83 @@ namespace euf {
register_shared(b); register_shared(b);
} }
bool ac_plugin::init_equation(eq const& e) { void ac_plugin::push_equation(enode* l, enode* r) {
m_active.push_back(e); if (l == r)
auto& eq = m_active.back(); return;
deduplicate(monomial(eq.l).m_nodes, monomial(eq.r).m_nodes); m_queued.push_back({ l, r });
push_undo(is_queue_eq);
}
if (orient_equation(eq)) { bool ac_plugin::init_equation(eq eq, bool is_active) {
auto& ml = monomial(eq.l); deduplicate(monomial(eq.l), monomial(eq.r));
auto& mr = monomial(eq.r); if (!orient_equation(eq))
return false;
unsigned eq_id = m_active.size() - 1; #if 0
if (is_reducing(eq))
is_active = true;
#endif
if (ml.size() == 1 && mr.size() == 1) is_active = true; // set to active because forward reduction is not implemented yet.
push_merge(ml[0]->n, mr[0]->n, eq.j); // we will have to forward reduce a passive equation before it can be activated.
// this means that we have to iterate over all overlaps of variables in equation with
for (auto n : ml) { // reducing eqations. Otherwise, we will not have the invariant that reducing variables
if (!n->n->is_marked2()) { // are eliminated from all equations.
n->eqs.push_back(eq_id);
n->n->mark2();
push_undo(is_add_eq_index);
m_node_trail.push_back(n);
for (auto s : n->shared)
m_shared_todo.insert(s);
}
}
for (auto n : mr) {
if (!n->n->is_marked2()) {
n->eqs.push_back(eq_id);
n->n->mark2();
push_undo(is_add_eq_index);
m_node_trail.push_back(n);
for (auto s : n->shared)
m_shared_todo.insert(s);
}
}
for (auto n : ml)
n->n->unmark2();
for (auto n : mr)
n->n->unmark2();
SASSERT(well_formed(eq));
TRACE(plugin, display_equation_ll(tout, eq) << " shared: " << m_shared_todo << "\n");
m_to_simplify_todo.insert(eq_id);
m_new_eqs.push_back(eq_id);
//display_equation_ll(verbose_stream() << "init " << eq_id << ": ", eq) << "\n";
if (!is_active) {
m_passive.push_back(eq);
return true; return true;
} }
else {
m_active.pop_back(); m_active.push_back(eq);
return false; auto& ml = monomial(eq.l);
auto& mr = monomial(eq.r);
unsigned eq_id = m_active.size() - 1;
if (ml.size() == 1 && mr.size() == 1)
push_merge(ml[0]->n, mr[0]->n, eq.j);
for (auto n : ml) {
if (!n->n->is_marked2()) {
n->eqs.push_back(eq_id);
n->n->mark2();
push_undo(is_add_eq_index);
m_node_trail.push_back(n);
for (auto s : n->shared)
m_shared_todo.insert(s);
}
} }
for (auto n : mr) {
if (!n->n->is_marked2()) {
n->eqs.push_back(eq_id);
n->n->mark2();
push_undo(is_add_eq_index);
m_node_trail.push_back(n);
for (auto s : n->shared)
m_shared_todo.insert(s);
}
}
for (auto n : ml)
n->n->unmark2();
for (auto n : mr)
n->n->unmark2();
SASSERT(well_formed(eq));
TRACE(plugin, display_equation_ll(tout, eq) << " shared: " << m_shared_todo << "\n");
m_to_simplify_todo.insert(eq_id);
m_new_eqs.push_back(eq_id);
//display_equation_ll(verbose_stream() << "init " << eq_id << ": ", eq) << "\n";
return true;
} }
bool ac_plugin::orient_equation(eq& e) { bool ac_plugin::orient_equation(eq& e) {
auto& ml = monomial(e.l); auto& ml = monomial(e.l);
auto& mr = monomial(e.r); auto& mr = monomial(e.r);
@ -429,7 +461,7 @@ namespace euf {
return false; return false;
if (!is_sorted(mr)) if (!is_sorted(mr))
return false; return false;
for (unsigned i = 0; i < ml.size(); ++i) { for (unsigned i = 0; i < ml.size(); ++i) {
if (ml[i]->id() == mr[i]->id()) if (ml[i]->id() == mr[i]->id())
continue; continue;
if (ml[i]->id() < mr[i]->id()) if (ml[i]->id() < mr[i]->id())
@ -455,15 +487,21 @@ namespace euf {
uint64_t ac_plugin::filter(monomial_t& m) { uint64_t ac_plugin::filter(monomial_t& m) {
auto& bloom = m.m_bloom; auto& bloom = m.m_bloom;
if (bloom.m_tick == m_tick)
if (bloom.m_tick == m_tick) {
uint64_t f = 0;
for (auto n : m)
f |= (1ull << (n->id() % 64ull));
SASSERT(f == bloom.m_filter);
return bloom.m_filter; return bloom.m_filter;
}
bloom.m_filter = 0; bloom.m_filter = 0;
for (auto n : m) for (auto n : m)
bloom.m_filter |= (1ull << (n->id() % 64ull)); bloom.m_filter |= (1ull << (n->id() % 64ull));
if (!is_sorted(m)) if (!is_sorted(m))
sort(m); sort(m);
bloom.m_tick = m_tick; bloom.m_tick = m_tick;
return bloom.m_filter; return bloom.m_filter;
} }
bool ac_plugin::can_be_subset(monomial_t& subset, monomial_t& superset) { bool ac_plugin::can_be_subset(monomial_t& subset, monomial_t& superset) {
@ -562,6 +600,10 @@ namespace euf {
} }
void ac_plugin::propagate() { void ac_plugin::propagate() {
while (m_queue_head < m_queued.size()) {
auto [l, r] = m_queued[m_queue_head++];
pop_equation(l, r);
}
while (true) { while (true) {
loop_start: loop_start:
if (m_fuel == 0) if (m_fuel == 0)
@ -576,14 +618,14 @@ namespace euf {
// simplify eq using processed // simplify eq using processed
TRACE(plugin, TRACE(plugin,
for (auto other_eq : forward_iterator(eq_id)) for (auto other_eq : forward_iterator(eq_id))
tout << "forward iterator " << eq_id << " vs " << other_eq << " " << is_processed(other_eq) << "\n"); tout << "forward iterator " << eq_id << " vs " << other_eq << " " << is_processed(other_eq) << "\n");
for (auto other_eq : forward_iterator(eq_id)) for (auto other_eq : forward_iterator(eq_id))
if (is_processed(other_eq) && forward_simplify(eq_id, other_eq)) if (is_processed(other_eq) && forward_simplify(eq_id, other_eq))
goto loop_start; goto loop_start;
auto& eq = m_active[eq_id]; auto& eq = m_active[eq_id];
deduplicate(monomial(eq.l).m_nodes, monomial(eq.r).m_nodes); deduplicate(monomial(eq.l), monomial(eq.r));
if (monomial(eq.l).size() == 0) { if (monomial(eq.l).size() == 0) {
set_status(eq_id, eq_status::is_dead_eq); set_status(eq_id, eq_status::is_dead_eq);
continue; continue;
@ -623,12 +665,20 @@ namespace euf {
} }
unsigned ac_plugin::pick_next_eq() { unsigned ac_plugin::pick_next_eq() {
init_pick:
while (!m_to_simplify_todo.empty()) { while (!m_to_simplify_todo.empty()) {
unsigned id = *m_to_simplify_todo.begin(); unsigned id = *m_to_simplify_todo.begin();
if (id < m_active.size() && is_to_simplify(id)) if (id < m_active.size() && is_to_simplify(id))
return id; return id;
m_to_simplify_todo.remove(id); m_to_simplify_todo.remove(id);
} }
if (!m_passive.empty()) {
auto eq = m_passive.back();
verbose_stream() << "pick passive " << eq_pp_ll(*this, eq) << "\n";
m_passive.pop_back();
init_equation(eq, true);
goto init_pick;
}
return UINT_MAX; return UINT_MAX;
} }
@ -640,11 +690,7 @@ namespace euf {
if (are_equal(monomial(eq.l), monomial(eq.r))) if (are_equal(monomial(eq.l), monomial(eq.r)))
s = eq_status::is_dead_eq; s = eq_status::is_dead_eq;
if (eq.status != s) { eq.status = s;
m_update_eq_trail.push_back({ id, eq });
eq.status = s;
push_undo(is_update_eq);
}
switch (s) { switch (s) {
case eq_status::is_processed_eq: case eq_status::is_processed_eq:
case eq_status::is_reducing_eq: case eq_status::is_reducing_eq:
@ -673,7 +719,7 @@ namespace euf {
} }
// //
// backward iterator allows simplification of eq // forward iterator allows simplification of eq
// The rhs of eq is a super-set of lhs of other eq. // The rhs of eq is a super-set of lhs of other eq.
// //
unsigned_vector const& ac_plugin::forward_iterator(unsigned eq_id) { unsigned_vector const& ac_plugin::forward_iterator(unsigned eq_id) {
@ -749,7 +795,7 @@ namespace euf {
} }
// //
// forward iterator simplifies other eqs where their rhs is a superset of lhs of eq // backward iterator simplifies other eqs where their rhs is a superset of lhs of eq
// //
unsigned_vector const& ac_plugin::backward_iterator(unsigned eq_id) { unsigned_vector const& ac_plugin::backward_iterator(unsigned eq_id) {
auto& eq = m_active[eq_id]; auto& eq = m_active[eq_id];
@ -786,7 +832,7 @@ namespace euf {
init_ref_counts(m, check); init_ref_counts(m, check);
return return
all_of(counts, [&](unsigned i) { return check[i] == counts[i]; }) && all_of(counts, [&](unsigned i) { return check[i] == counts[i]; }) &&
all_of(check, [&](unsigned i) { return check[i] == counts[i]; }); all_of(check, [&](unsigned i) { return check[i] == counts[i]; });
} }
void ac_plugin::backward_simplify(unsigned src_eq, unsigned dst_eq) { void ac_plugin::backward_simplify(unsigned src_eq, unsigned dst_eq) {
@ -843,10 +889,8 @@ namespace euf {
reduce(m_src_r, j); reduce(m_src_r, j);
auto new_r = to_monomial(m_src_r); auto new_r = to_monomial(m_src_r);
index_new_r(dst_eq, monomial(m_active[dst_eq].r), monomial(new_r)); index_new_r(dst_eq, monomial(m_active[dst_eq].r), monomial(new_r));
m_update_eq_trail.push_back({ dst_eq, m_active[dst_eq] });
m_active[dst_eq].r = new_r; m_active[dst_eq].r = new_r;
m_active[dst_eq].j = j; m_active[dst_eq].j = j;
push_undo(is_update_eq);
m_src_r.reset(); m_src_r.reset();
m_src_r.append(monomial(src.r).m_nodes); m_src_r.append(monomial(src.r).m_nodes);
TRACE(plugin_verbose, tout << "rewritten to " << m_pp_ll(*this, monomial(new_r)) << "\n"); TRACE(plugin_verbose, tout << "rewritten to " << m_pp_ll(*this, monomial(new_r)) << "\n");
@ -862,7 +906,7 @@ namespace euf {
// //
// dst_ids, dst_count contain rhs of dst_eq // dst_ids, dst_count contain rhs of dst_eq
// //
TRACE(plugin, tout << "backward simplify " << eq_pp_ll(*this, src) << " " << eq_pp_ll(*this, dst) << " can-be-subset: " << can_be_subset(monomial(src.l), monomial(dst.r)) << "\n"); TRACE(plugin, tout << "forward simplify " << eq_pp_ll(*this, src) << " " << eq_pp_ll(*this, dst) << " can-be-subset: " << can_be_subset(monomial(src.l), monomial(dst.r)) << "\n");
if (forward_subsumes(src_eq, dst_eq)) { if (forward_subsumes(src_eq, dst_eq)) {
set_status(dst_eq, eq_status::is_dead_eq); set_status(dst_eq, eq_status::is_dead_eq);
@ -891,11 +935,9 @@ namespace euf {
reduce(m, j); reduce(m, j);
auto new_r = to_monomial(m); auto new_r = to_monomial(m);
index_new_r(dst_eq, monomial(m_active[dst_eq].r), monomial(new_r)); index_new_r(dst_eq, monomial(m_active[dst_eq].r), monomial(new_r));
m_update_eq_trail.push_back({ dst_eq, m_active[dst_eq] });
m_active[dst_eq].r = new_r; m_active[dst_eq].r = new_r;
m_active[dst_eq].j = j; m_active[dst_eq].j = j;
TRACE(plugin, tout << "rewritten to " << m_pp(*this, monomial(new_r)) << "\n"); TRACE(plugin, tout << "rewritten to " << m_pp(*this, monomial(new_r)) << "\n");
push_undo(is_update_eq);
return true; return true;
} }
@ -913,7 +955,7 @@ namespace euf {
m_new_eqs.reset(); m_new_eqs.reset();
} }
bool ac_plugin::is_forward_subsumed(unsigned eq_id) { bool ac_plugin::is_forward_subsumed(unsigned eq_id) {
return any_of(forward_iterator(eq_id), [&](unsigned other_eq) { return forward_subsumes(other_eq, eq_id); }); return any_of(forward_iterator(eq_id), [&](unsigned other_eq) { return forward_subsumes(other_eq, eq_id); });
} }
@ -975,7 +1017,9 @@ namespace euf {
SASSERT(!are_equal(m_active[src_eq], m_active[dst_eq])); SASSERT(!are_equal(m_active[src_eq], m_active[dst_eq]));
return false; return false;
} }
return all_of(monomial(dst.r), [&](node* n) { unsigned id = n->id(); return m_src_r_counts[id] == m_dst_r_counts[id]; }); bool r = all_of(monomial(dst.r), [&](node* n) { unsigned id = n->id(); return m_src_r_counts[id] == m_dst_r_counts[id]; });
SASSERT(r || !are_equal(m_active[src_eq], m_active[dst_eq]));
return r;
} }
// src_l_counts, src_r_counts are initialized for src.l, src.r // src_l_counts, src_r_counts are initialized for src.l, src.r
@ -1079,8 +1123,7 @@ namespace euf {
goto init_loop; goto init_loop;
} }
} }
} } while (false);
while (false);
VERIFY(sz >= m.size()); VERIFY(sz >= m.size());
return change; return change;
} }
@ -1122,7 +1165,7 @@ namespace euf {
auto& src = m_active[src_eq]; auto& src = m_active[src_eq];
auto& dst = m_active[dst_eq]; auto& dst = m_active[dst_eq];
unsigned max_left = std::max(monomial(src.l).size(), monomial(dst.l).size()); unsigned max_left = std::max(monomial(src.l).size(), monomial(dst.l).size());
unsigned min_right = std::max(monomial(src.r).size(), monomial(dst.r).size()); unsigned min_right = std::max(monomial(src.r).size(), monomial(dst.r).size());
@ -1177,11 +1220,11 @@ namespace euf {
unsigned max_left_new = std::max(m_src_r.size(), m_dst_r.size()); unsigned max_left_new = std::max(m_src_r.size(), m_dst_r.size());
unsigned min_right_new = std::min(m_src_r.size(), m_dst_r.size()); unsigned min_right_new = std::min(m_src_r.size(), m_dst_r.size());
if (max_left_new <= max_left && min_right_new <= min_right) if (max_left_new <= max_left && min_right_new <= min_right)
added_eq = init_equation(eq(to_monomial(m_src_r), to_monomial(m_dst_r), j)); added_eq = init_equation(eq(to_monomial(m_src_r), to_monomial(m_dst_r), j), false);
CTRACE(plugin, added_eq, CTRACE(plugin, added_eq,
tout << "superpose: " << m_name << " " << eq_pp_ll(*this, src) << " " << eq_pp_ll(*this, dst) << " --> "; tout << "superpose: " << m_name << " " << eq_pp_ll(*this, src) << " " << eq_pp_ll(*this, dst) << " --> ";
tout << m_pp_ll(*this, m_src_r) << "== " << m_pp_ll(*this, m_dst_r) << "\n";); tout << m_pp_ll(*this, m_src_r) << "== " << m_pp_ll(*this, m_dst_r) << "\n";);
m_src_r.reset(); m_src_r.reset();
m_src_r.append(monomial(src_r).m_nodes); m_src_r.append(monomial(src_r).m_nodes);
@ -1204,21 +1247,24 @@ namespace euf {
} }
} }
// TODO: this is destructive. It breaks reversibility.
// TODO: also need justifications from eq if there is a change.
void ac_plugin::backward_reduce(eq const& eq, unsigned other_eq_id) { void ac_plugin::backward_reduce(eq const& eq, unsigned other_eq_id) {
auto& other_eq = m_active[other_eq_id]; auto& other_eq = m_active[other_eq_id];
TRACE(plugin_verbose,
tout << "backward reduce " << eq_pp_ll(*this, eq) << " " << eq_pp_ll(*this, other_eq) << "\n");
bool change = false; bool change = false;
if (backward_reduce_monomial(eq, monomial(other_eq.l))) if (backward_reduce_monomial(eq, other_eq, monomial(other_eq.l)))
change = true; change = true;
if (backward_reduce_monomial(eq, monomial(other_eq.r))) if (backward_reduce_monomial(eq, other_eq, monomial(other_eq.r)))
change = true; change = true;
if (change) CTRACE(plugin, change,
tout << "backward reduce " << eq_pp_ll(*this, eq) << " " << eq_pp_ll(*this, other_eq) << "\n");
if (change) {
set_status(other_eq_id, eq_status::is_to_simplify_eq); set_status(other_eq_id, eq_status::is_to_simplify_eq);
}
} }
bool ac_plugin::backward_reduce_monomial(eq const& eq, monomial_t& m) { bool ac_plugin::backward_reduce_monomial(eq const& src, eq& dst, monomial_t& m) {
auto const& r = monomial(eq.r); auto const& r = monomial(src.r);
unsigned j = 0; unsigned j = 0;
bool change = false; bool change = false;
for (auto n : m) { for (auto n : m) {
@ -1241,6 +1287,10 @@ namespace euf {
m.m_nodes[j++] = r[0]; m.m_nodes[j++] = r[0];
} }
m.m_nodes.shrink(j); m.m_nodes.shrink(j);
if (change) {
m.m_bloom.m_tick = 0;
dst.j = join(dst.j, src);
}
return change; return change;
} }
@ -1277,21 +1327,29 @@ namespace euf {
return true; return true;
} }
void ac_plugin::deduplicate(monomial_t& a, monomial_t& b) {
unsigned sza = a.size(), szb = b.size();
deduplicate(a.m_nodes, b.m_nodes);
if (sza != a.size())
a.m_bloom.m_tick = 0;
if (szb != b.size())
b.m_bloom.m_tick = 0;
}
void ac_plugin::deduplicate(ptr_vector<node>& a, ptr_vector<node>& b) { void ac_plugin::deduplicate(ptr_vector<node>& a, ptr_vector<node>& b) {
{ for (auto n : a) {
for (auto n : a) { if (n->is_zero) {
if (n->is_zero) { a[0] = n;
a[0] = n; a.shrink(1);
a.shrink(1); break;
break;
}
} }
for (auto n : b) { }
if (n->is_zero) { for (auto n : b) {
b[0] = n; if (n->is_zero) {
b.shrink(1); b[0] = n;
break; b.shrink(1);
} break;
} }
} }
@ -1385,9 +1443,7 @@ namespace euf {
push_undo(is_update_shared); push_undo(is_update_shared);
m_shared[idx].m = new_m; m_shared[idx].m = new_m;
m_shared[idx].j = j; m_shared[idx].j = j;
TRACE(plugin_verbose, tout << "shared simplified to " << m_pp_ll(*this, monomial(new_m)) << "\n"); TRACE(plugin_verbose, tout << "shared simplified to " << m_pp_ll(*this, monomial(new_m)) << "\n");
push_merge(old_n, new_n, j); push_merge(old_n, new_n, j);
} }
@ -1397,19 +1453,15 @@ namespace euf {
} }
justification::dependency* ac_plugin::justify_equation(unsigned eq) { justification::dependency* ac_plugin::justify_equation(unsigned eq) {
auto const& e = m_active[eq]; return m_dep_manager.mk_leaf(m_active[eq].j);
auto* j = m_dep_manager.mk_leaf(e.j);
j = justify_monomial(j, monomial(e.l));
j = justify_monomial(j, monomial(e.r));
return j;
}
justification::dependency* ac_plugin::justify_monomial(justification::dependency* j, monomial_t const& m) {
return j;
} }
justification ac_plugin::join(justification j, unsigned eq) { justification ac_plugin::join(justification j, unsigned eq) {
return justification::dependent(m_dep_manager.mk_join(m_dep_manager.mk_leaf(j), justify_equation(eq))); return justification::dependent(m_dep_manager.mk_join(m_dep_manager.mk_leaf(j), justify_equation(eq)));
} }
justification ac_plugin::join(justification j, eq const& eq) {
return justification::dependent(m_dep_manager.mk_join(m_dep_manager.mk_leaf(j), m_dep_manager.mk_leaf(eq.j)));
}
} }

View file

@ -123,6 +123,7 @@ namespace euf {
func_decl* m_decl = nullptr; func_decl* m_decl = nullptr;
bool m_is_injective = false; bool m_is_injective = false;
vector<eq> m_active, m_passive; vector<eq> m_active, m_passive;
enode_pair_vector m_queued;
ptr_vector<node> m_nodes; ptr_vector<node> m_nodes;
bool_vector m_shared_nodes; bool_vector m_shared_nodes;
vector<monomial_t> m_monomials; vector<monomial_t> m_monomials;
@ -146,21 +147,21 @@ namespace euf {
// backtrackable state // backtrackable state
enum undo_kind { enum undo_kind {
is_add_eq, is_queue_eq,
is_add_monomial, is_add_monomial,
is_add_node, is_add_node,
is_update_eq,
is_add_shared_index, is_add_shared_index,
is_add_eq_index, is_add_eq_index,
is_register_shared, is_register_shared,
is_update_shared is_update_shared,
is_push_scope
}; };
svector<undo_kind> m_undo; svector<undo_kind> m_undo;
ptr_vector<node> m_node_trail; ptr_vector<node> m_node_trail;
unsigned m_queue_head = 0;
svector<std::pair<unsigned, shared>> m_update_shared_trail; svector<std::pair<unsigned, shared>> m_update_shared_trail;
svector<std::tuple<node*, unsigned, unsigned>> m_merge_trail; svector<std::tuple<node*, unsigned, unsigned>> m_merge_trail;
svector<std::pair<unsigned, eq>> m_update_eq_trail;
@ -191,8 +192,8 @@ namespace euf {
bool well_formed(eq const& e) const; bool well_formed(eq const& e) const;
bool is_reducing(eq const& e) const; bool is_reducing(eq const& e) const;
void backward_reduce(unsigned eq_id); void backward_reduce(unsigned eq_id);
void backward_reduce(eq const& src, unsigned dst); void backward_reduce(eq const& eq, unsigned dst);
bool backward_reduce_monomial(eq const& eq, monomial_t& m); bool backward_reduce_monomial(eq const& src, eq & dst, monomial_t& m);
void forward_subsume_new_eqs(); void forward_subsume_new_eqs();
bool is_forward_subsumed(unsigned dst_eq); bool is_forward_subsumed(unsigned dst_eq);
bool forward_subsumes(unsigned src_eq, unsigned dst_eq); bool forward_subsumes(unsigned src_eq, unsigned dst_eq);
@ -208,7 +209,9 @@ namespace euf {
return nullptr; return nullptr;
} }
bool init_equation(eq const& e); bool init_equation(eq e, bool is_active);
void push_equation(enode* l, enode* r);
void pop_equation(enode* l, enode* r);
bool orient_equation(eq& e); bool orient_equation(eq& e);
void set_status(unsigned eq_id, eq_status s); void set_status(unsigned eq_id, eq_status s);
unsigned pick_next_eq(); unsigned pick_next_eq();
@ -217,6 +220,7 @@ namespace euf {
void backward_simplify(unsigned eq_id, unsigned using_eq); void backward_simplify(unsigned eq_id, unsigned using_eq);
bool forward_simplify(unsigned eq_id, unsigned using_eq); bool forward_simplify(unsigned eq_id, unsigned using_eq);
bool superpose(unsigned src_eq, unsigned dst_eq); bool superpose(unsigned src_eq, unsigned dst_eq);
void deduplicate(monomial_t& a, monomial_t& b);
void deduplicate(ptr_vector<node>& a, ptr_vector<node>& b); void deduplicate(ptr_vector<node>& a, ptr_vector<node>& b);
ptr_vector<node> m_src_r, m_src_l, m_dst_r, m_dst_l; ptr_vector<node> m_src_r, m_src_l, m_dst_r, m_dst_l;
@ -260,8 +264,8 @@ namespace euf {
justification justify_rewrite(unsigned eq1, unsigned eq2); justification justify_rewrite(unsigned eq1, unsigned eq2);
justification::dependency* justify_equation(unsigned eq); justification::dependency* justify_equation(unsigned eq);
justification::dependency* justify_monomial(justification::dependency* d, monomial_t const& m);
justification join(justification j1, unsigned eq); justification join(justification j1, unsigned eq);
justification join(justification j1, eq const& eq);
bool is_correct_ref_count(monomial_t const& m, ref_counts const& counts) const; bool is_correct_ref_count(monomial_t const& m, ref_counts const& counts) const;
bool is_correct_ref_count(ptr_vector<node> const& m, ref_counts const& counts) const; bool is_correct_ref_count(ptr_vector<node> const& m, ref_counts const& counts) const;
@ -301,6 +305,8 @@ namespace euf {
void undo() override; void undo() override;
void push_scope_eh() override;
void propagate() override; void propagate() override;
std::ostream& display(std::ostream& out) const override; std::ostream& display(std::ostream& out) const override;

View file

@ -43,6 +43,11 @@ namespace euf {
void undo() override; void undo() override;
void push_scope_eh() override {
m_add.push_scope_eh();
m_mul.push_scope_eh();
}
void propagate() override; void propagate() override;
std::ostream& display(std::ostream& out) const override; std::ostream& display(std::ostream& out) const override;

View file

@ -103,6 +103,9 @@ namespace euf {
m_scopes.push_back(m_updates.size()); m_scopes.push_back(m_updates.size());
m_region.push_scope(); m_region.push_scope();
m_updates.push_back(update_record(m_new_th_eqs_qhead, update_record::new_th_eq_qhead())); m_updates.push_back(update_record(m_new_th_eqs_qhead, update_record::new_th_eq_qhead()));
for (auto p : m_plugins)
if (p)
p->push_scope_eh();
} }
SASSERT(m_new_th_eqs_qhead <= m_new_th_eqs.size()); SASSERT(m_new_th_eqs_qhead <= m_new_th_eqs.size());
} }

View file

@ -53,6 +53,8 @@ namespace euf {
virtual void undo() = 0; virtual void undo() = 0;
virtual void push_scope_eh() {}
virtual std::ostream& display(std::ostream& out) const = 0; virtual std::ostream& display(std::ostream& out) const = 0;
virtual void collect_statistics(statistics& st) const {} virtual void collect_statistics(statistics& st) const {}