mirror of
https://github.com/Z3Prover/z3
synced 2025-04-28 19:35:50 +00:00
increase build version, better propagation in euf-egraph, handle assumptions in sat.smt
- increase build version to 4.12.1. This prepares updated release for MacOs-11 build on x86 - move literal propagation mode in euf-egraph to a callback and traversal of equivalence class. Track antecedent by newest equality instead of root. This makes equality propagation to literals have similar behavior as in legacy solver and appears to result in a speedup (10% fewer conflicts on QF_UF/QG-classification/qg5/iso_icl478.smt2 in preliminary testing) - fix interaction of pre-processing and assumptions. Pre-processing has to freeze assumption literals so they don't get eliminated. This is similar to dependencies that are already frozen.
This commit is contained in:
parent
c8f197d0ca
commit
7368f9f7d3
22 changed files with 201 additions and 162 deletions
|
@ -91,9 +91,7 @@ namespace euf {
|
|||
m_scopes.push_back(m_updates.size());
|
||||
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_lits_qhead, update_record::new_lits_qhead()));
|
||||
}
|
||||
SASSERT(m_new_lits_qhead <= m_new_lits.size());
|
||||
SASSERT(m_new_th_eqs_qhead <= m_new_th_eqs.size());
|
||||
}
|
||||
|
||||
|
@ -156,12 +154,29 @@ namespace euf {
|
|||
}
|
||||
|
||||
void egraph::add_literal(enode* n, enode* ante) {
|
||||
/*
|
||||
if (n->bool_var() == sat::null_bool_var)
|
||||
return;
|
||||
TRACE("euf_verbose", tout << "lit: " << n->get_expr_id() << "\n";);
|
||||
m_new_lits.push_back(enode_pair(n, ante));
|
||||
m_updates.push_back(update_record(update_record::new_lit()));
|
||||
*/
|
||||
if (!ante) ++m_stats.m_num_eqs; else ++m_stats.m_num_lits;
|
||||
if (!ante)
|
||||
m_on_propagate_literal(n, ante);
|
||||
else if (m.is_true(ante->get_expr()) || m.is_false(ante->get_expr())) {
|
||||
for (enode* k : enode_class(n)) {
|
||||
if (k != ante) {
|
||||
//verbose_stream() << "eq: " << k->value() << " " <<ante->value() << "\n";
|
||||
m_on_propagate_literal(k, ante);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (enode* k : enode_class(n)) {
|
||||
if (k->value() != ante->value()) {
|
||||
//verbose_stream() << "eq: " << k->value() << " " <<ante->value() << "\n";
|
||||
m_on_propagate_literal(k, ante);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void egraph::new_diseq(enode* n) {
|
||||
|
@ -339,7 +354,6 @@ namespace euf {
|
|||
num_scopes -= m_num_scopes;
|
||||
m_num_scopes = 0;
|
||||
|
||||
SASSERT(m_new_lits_qhead <= m_new_lits.size());
|
||||
unsigned old_lim = m_scopes.size() - num_scopes;
|
||||
unsigned num_updates = m_scopes[old_lim];
|
||||
auto undo_node = [&]() {
|
||||
|
@ -378,18 +392,12 @@ namespace euf {
|
|||
SASSERT(p.r1->get_th_var(p.m_th_id) != null_theory_var);
|
||||
p.r1->replace_th_var(p.m_old_th_var, p.m_th_id);
|
||||
break;
|
||||
case update_record::tag_t::is_new_lit:
|
||||
m_new_lits.pop_back();
|
||||
break;
|
||||
case update_record::tag_t::is_new_th_eq:
|
||||
m_new_th_eqs.pop_back();
|
||||
break;
|
||||
case update_record::tag_t::is_new_th_eq_qhead:
|
||||
m_new_th_eqs_qhead = p.qhead;
|
||||
break;
|
||||
case update_record::tag_t::is_new_lits_qhead:
|
||||
m_new_lits_qhead = p.qhead;
|
||||
break;
|
||||
case update_record::tag_t::is_inconsistent:
|
||||
m_inconsistent = p.m_inconsistent;
|
||||
break;
|
||||
|
@ -424,7 +432,6 @@ namespace euf {
|
|||
m_region.pop_scope(num_scopes);
|
||||
m_to_merge.reset();
|
||||
|
||||
SASSERT(m_new_lits_qhead <= m_new_lits.size());
|
||||
SASSERT(m_new_th_eqs_qhead <= m_new_th_eqs.size());
|
||||
|
||||
// DEBUG_CODE(invariant(););
|
||||
|
@ -461,12 +468,6 @@ namespace euf {
|
|||
std::swap(n1, n2);
|
||||
}
|
||||
|
||||
if (j.is_congruence() && (m.is_false(r2->get_expr()) || m.is_true(r2->get_expr())))
|
||||
add_literal(n1, r2);
|
||||
if (r2->value() != l_undef && n1->value() == l_undef)
|
||||
add_literal(n1, r2);
|
||||
else if (r1->value() != l_undef && n2->value() == l_undef)
|
||||
add_literal(n2, r1);
|
||||
remove_parents(r1);
|
||||
push_eq(r1, n1, r2->num_parents());
|
||||
merge_justification(n1, n2, j);
|
||||
|
@ -476,6 +477,13 @@ namespace euf {
|
|||
r2->inc_class_size(r1->class_size());
|
||||
merge_th_eq(r1, r2);
|
||||
reinsert_parents(r1, r2);
|
||||
if (j.is_congruence() && (m.is_false(r2->get_expr()) || m.is_true(r2->get_expr())))
|
||||
add_literal(n1, r2);
|
||||
else if (n2->value() != l_undef && n1->value() != n2->value())
|
||||
add_literal(n1, n2);
|
||||
else if (n1->value() != l_undef && n2->value() != n1->value())
|
||||
add_literal(n2, n1);
|
||||
|
||||
for (auto& cb : m_on_merge)
|
||||
cb(r2, r1);
|
||||
}
|
||||
|
@ -565,7 +573,6 @@ namespace euf {
|
|||
|
||||
|
||||
bool egraph::propagate() {
|
||||
SASSERT(m_new_lits_qhead <= m_new_lits.size());
|
||||
SASSERT(m_num_scopes == 0 || m_to_merge.empty());
|
||||
force_push();
|
||||
for (unsigned i = 0; i < m_to_merge.size() && m.limit().inc() && !inconsistent(); ++i) {
|
||||
|
@ -574,7 +581,6 @@ namespace euf {
|
|||
}
|
||||
m_to_merge.reset();
|
||||
return
|
||||
(m_new_lits_qhead < m_new_lits.size()) ||
|
||||
(m_new_th_eqs_qhead < m_new_th_eqs.size()) ||
|
||||
inconsistent();
|
||||
}
|
||||
|
@ -851,7 +857,6 @@ namespace euf {
|
|||
|
||||
std::ostream& egraph::display(std::ostream& out) const {
|
||||
out << "updates " << m_updates.size() << "\n";
|
||||
out << "newlits " << m_new_lits.size() << " qhead: " << m_new_lits_qhead << "\n";
|
||||
out << "neweqs " << m_new_th_eqs.size() << " qhead: " << m_new_th_eqs_qhead << "\n";
|
||||
m_table.display(out);
|
||||
unsigned max_args = 0;
|
||||
|
|
|
@ -105,10 +105,8 @@ namespace euf {
|
|||
struct toggle_merge_tf {};
|
||||
struct add_th_var {};
|
||||
struct replace_th_var {};
|
||||
struct new_lit {};
|
||||
struct new_th_eq {};
|
||||
struct new_th_eq_qhead {};
|
||||
struct new_lits_qhead {};
|
||||
struct inconsistent {};
|
||||
struct value_assignment {};
|
||||
struct lbl_hash {};
|
||||
|
@ -116,8 +114,8 @@ namespace euf {
|
|||
struct update_children {};
|
||||
struct set_relevant {};
|
||||
enum class tag_t { is_set_parent, is_add_node, is_toggle_cgc, is_toggle_merge_tf, is_update_children,
|
||||
is_add_th_var, is_replace_th_var, is_new_lit, is_new_th_eq,
|
||||
is_lbl_hash, is_new_th_eq_qhead, is_new_lits_qhead,
|
||||
is_add_th_var, is_replace_th_var, is_new_th_eq,
|
||||
is_lbl_hash, is_new_th_eq_qhead,
|
||||
is_inconsistent, is_value_assignment, is_lbl_set, is_set_relevant };
|
||||
tag_t tag;
|
||||
enode* r1;
|
||||
|
@ -145,14 +143,10 @@ namespace euf {
|
|||
tag(tag_t::is_add_th_var), r1(n), n1(nullptr), r2_num_parents(id) {}
|
||||
update_record(enode* n, theory_id id, theory_var v, replace_th_var) :
|
||||
tag(tag_t::is_replace_th_var), r1(n), n1(nullptr), m_th_id(id), m_old_th_var(v) {}
|
||||
update_record(new_lit) :
|
||||
tag(tag_t::is_new_lit), r1(nullptr), n1(nullptr), r2_num_parents(0) {}
|
||||
update_record(new_th_eq) :
|
||||
tag(tag_t::is_new_th_eq), r1(nullptr), n1(nullptr), r2_num_parents(0) {}
|
||||
update_record(unsigned qh, new_th_eq_qhead):
|
||||
tag(tag_t::is_new_th_eq_qhead), r1(nullptr), n1(nullptr), qhead(qh) {}
|
||||
update_record(unsigned qh, new_lits_qhead):
|
||||
tag(tag_t::is_new_lits_qhead), r1(nullptr), n1(nullptr), qhead(qh) {}
|
||||
update_record(bool inc, inconsistent) :
|
||||
tag(tag_t::is_inconsistent), r1(nullptr), n1(nullptr), m_inconsistent(inc) {}
|
||||
update_record(enode* n, value_assignment) :
|
||||
|
@ -187,9 +181,7 @@ namespace euf {
|
|||
enode *m_n1 = nullptr;
|
||||
enode *m_n2 = nullptr;
|
||||
justification m_justification;
|
||||
unsigned m_new_lits_qhead = 0;
|
||||
unsigned m_new_th_eqs_qhead = 0;
|
||||
svector<enode_pair> m_new_lits;
|
||||
svector<th_eq> m_new_th_eqs;
|
||||
bool_vector m_th_propagates_diseqs;
|
||||
enode_vector m_todo;
|
||||
|
@ -198,7 +190,8 @@ namespace euf {
|
|||
bool m_default_relevant = true;
|
||||
uint64_t m_congruence_timestamp = 0;
|
||||
|
||||
std::vector<std::function<void(enode*,enode*)>> m_on_merge;
|
||||
std::vector<std::function<void(enode*,enode*)>> m_on_merge;
|
||||
std::function<void(enode*, enode*)> m_on_propagate_literal;
|
||||
std::function<void(enode*)> m_on_make;
|
||||
std::function<void(expr*,expr*,expr*)> m_used_eq;
|
||||
std::function<void(app*,app*)> m_used_cc;
|
||||
|
@ -290,11 +283,8 @@ namespace euf {
|
|||
is an equality consequence.
|
||||
*/
|
||||
void add_th_diseq(theory_id id, theory_var v1, theory_var v2, expr* eq);
|
||||
bool has_literal() const { return m_new_lits_qhead < m_new_lits.size(); }
|
||||
bool has_th_eq() const { return m_new_th_eqs_qhead < m_new_th_eqs.size(); }
|
||||
enode_pair get_literal() const { return m_new_lits[m_new_lits_qhead]; }
|
||||
th_eq get_th_eq() const { return m_new_th_eqs[m_new_th_eqs_qhead]; }
|
||||
void next_literal() { force_push(); SASSERT(m_new_lits_qhead < m_new_lits.size()); m_new_lits_qhead++; }
|
||||
void next_th_eq() { force_push(); SASSERT(m_new_th_eqs_qhead < m_new_th_eqs.size()); m_new_th_eqs_qhead++; }
|
||||
|
||||
void set_lbl_hash(enode* n);
|
||||
|
@ -311,6 +301,7 @@ namespace euf {
|
|||
void set_default_relevant(bool b) { m_default_relevant = b; }
|
||||
|
||||
void set_on_merge(std::function<void(enode* root,enode* other)>& on_merge) { m_on_merge.push_back(on_merge); }
|
||||
void set_on_propagate(std::function<void(enode* lit,enode* ante)>& on_propagate) { m_on_propagate_literal = on_propagate; }
|
||||
void set_on_make(std::function<void(enode* n)>& on_make) { m_on_make = on_make; }
|
||||
void set_used_eq(std::function<void(expr*,expr*,expr*)>& used_eq) { m_used_eq = used_eq; }
|
||||
void set_used_cc(std::function<void(app*,app*)>& used_cc) { m_used_cc = used_cc; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue