3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-12 12:08:18 +00:00
* arrays

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* arrays

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* arrays

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* fill

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* update drat and fix euf bugs

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* const qualifiers

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* reorg ba

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* reorg

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* build warnings

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-09-13 19:29:59 -07:00 committed by GitHub
parent d56dd1db7b
commit 796e2fd9eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
79 changed files with 2571 additions and 1850 deletions

View file

@ -1785,13 +1785,12 @@ bool ast_manager::slow_not_contains(ast const * n) {
} }
#endif #endif
#if 0
static unsigned s_count = 0; static unsigned s_count = 0;
#if 0
static void track_id(ast_manager& m, ast* n, unsigned id) { static void track_id(ast_manager& m, ast* n, unsigned id) {
if (n->get_id() != id) return; if (n->get_id() != id) return;
++s_count; ++s_count;
std::cout << &m << " " << s_count << "\n"; TRACE("ast", tout << s_count << "\n";);
SASSERT(s_count != 240);
} }
#endif #endif
@ -1825,9 +1824,9 @@ ast * ast_manager::register_node_core(ast * n) {
n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk();
// track_id(*this, n, 254); // track_id(*this, n, 3);
TRACE("ast", tout << "Object " << n->m_id << " was created.\n";); TRACE("ast", tout << (s_count++) << " Object " << n->m_id << " was created.\n";);
TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";); TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";);
// increment reference counters // increment reference counters
switch (n->get_kind()) { switch (n->get_kind()) {

View file

@ -81,8 +81,10 @@ 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_lits_qhead, update_record::new_lits_qhead()));
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()));
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());
} }
void egraph::update_children(enode* n) { void egraph::update_children(enode* n) {
@ -107,17 +109,23 @@ namespace euf {
return n; return n;
} }
enode_bool_pair p = m_table.insert(n); enode_bool_pair p = m_table.insert(n);
enode* r = p.first; enode* n2 = p.first;
if (r == n) { if (n2 == n) {
update_children(n); update_children(n);
} }
else { else {
SASSERT(r->get_expr() != n->get_expr()); merge(n, n2, justification::congruence(p.second));
merge_justification(n, r, justification::congruence(p.second)); #if 0
std::swap(n->m_next, r->m_next); SASSERT(n2->get_expr() != n->get_expr());
n->m_root = r; SASSERT(n->class_size() == 1);
r->inc_class_size(n->class_size()); SASSERT(n->is_root());
push_eq(n, n, r->num_parents()); merge_justification(n, n2, justification::congruence(p.second));
enode* r2 = n2->get_root();
std::swap(n->m_next, r2->m_next);
n->m_root = r2;
r2->inc_class_size(n->class_size());
push_eq(n, n, r2->num_parents());
#endif
} }
return n; return n;
} }
@ -128,12 +136,14 @@ namespace euf {
} }
void egraph::add_th_eq(theory_id id, theory_var v1, theory_var v2, enode* c, enode* r) { void egraph::add_th_eq(theory_id id, theory_var v1, theory_var v2, enode* c, enode* r) {
TRACE("euf_verbose", tout << "eq: " << v1 << " == " << v2 << "\n";);
m_new_th_eqs.push_back(th_eq(id, v1, v2, c, r)); m_new_th_eqs.push_back(th_eq(id, v1, v2, c, r));
m_updates.push_back(update_record(update_record::new_th_eq())); m_updates.push_back(update_record(update_record::new_th_eq()));
++m_stats.m_num_th_eqs; ++m_stats.m_num_th_eqs;
} }
void egraph::add_literal(enode* n, bool is_eq) { void egraph::add_literal(enode* n, bool is_eq) {
TRACE("euf_verbose", tout << "lit: " << n->get_expr_id() << "\n";);
m_new_lits.push_back(enode_bool_pair(n, is_eq)); m_new_lits.push_back(enode_bool_pair(n, is_eq));
m_updates.push_back(update_record(update_record::new_lit())); m_updates.push_back(update_record(update_record::new_lit()));
if (is_eq) ++m_stats.m_num_eqs; else ++m_stats.m_num_lits; if (is_eq) ++m_stats.m_num_eqs; else ++m_stats.m_num_lits;
@ -186,6 +196,9 @@ namespace euf {
return; return;
} }
num_scopes -= m_num_scopes; 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 old_lim = m_scopes.size() - num_scopes;
unsigned num_updates = m_scopes[old_lim]; unsigned num_updates = m_scopes[old_lim];
auto undo_node = [&](enode* n) { auto undo_node = [&](enode* n) {
@ -240,16 +253,19 @@ namespace euf {
m_scopes.shrink(old_lim); m_scopes.shrink(old_lim);
m_region.pop_scope(num_scopes); m_region.pop_scope(num_scopes);
m_worklist.reset(); m_worklist.reset();
SASSERT(m_new_lits_qhead <= m_new_lits.size());
SASSERT(m_new_th_eqs_qhead <= m_new_th_eqs.size());
} }
void egraph::merge(enode* n1, enode* n2, justification j) { void egraph::merge(enode* n1, enode* n2, justification j) {
SASSERT(m.get_sort(n1->get_expr()) == m.get_sort(n2->get_expr())); SASSERT(m.get_sort(n1->get_expr()) == m.get_sort(n2->get_expr()));
TRACE("euf", tout << n1->get_expr_id() << " == " << n2->get_expr_id() << "\n";);
force_push();
enode* r1 = n1->get_root(); enode* r1 = n1->get_root();
enode* r2 = n2->get_root(); enode* r2 = n2->get_root();
if (r1 == r2) if (r1 == r2)
return; return;
TRACE("euf", j.display(tout << n1->get_expr_id() << " == " << n2->get_expr_id() << " ", m_display_justification) << "\n";);
force_push();
SASSERT(m_num_scopes == 0);
++m_stats.m_num_merge; ++m_stats.m_num_merge;
if (r1->interpreted() && r2->interpreted()) { if (r1->interpreted() && r2->interpreted()) {
set_conflict(n1, n2, j); set_conflict(n1, n2, j);
@ -294,6 +310,7 @@ namespace euf {
} }
bool egraph::propagate() { bool egraph::propagate() {
SASSERT(m_new_lits_qhead <= m_new_lits.size());
SASSERT(m_num_scopes == 0 || m_worklist.empty()); SASSERT(m_num_scopes == 0 || m_worklist.empty());
unsigned head = 0, tail = m_worklist.size(); unsigned head = 0, tail = m_worklist.size();
while (head < tail && m.limit().inc() && !inconsistent()) { while (head < tail && m.limit().inc() && !inconsistent()) {
@ -311,6 +328,7 @@ namespace euf {
tail = m_worklist.size(); tail = m_worklist.size();
} }
m_worklist.reset(); m_worklist.reset();
force_push();
return return
(m_new_lits_qhead < m_new_lits.size()) || (m_new_lits_qhead < m_new_lits.size()) ||
(m_new_th_eqs_qhead < m_new_th_eqs.size()) || (m_new_th_eqs_qhead < m_new_th_eqs.size()) ||
@ -329,17 +347,27 @@ namespace euf {
} }
void egraph::merge_justification(enode* n1, enode* n2, justification j) { void egraph::merge_justification(enode* n1, enode* n2, justification j) {
SASSERT(!n1->get_root()->m_target);
SASSERT(!n2->get_root()->m_target);
SASSERT(n1->reaches(n1->get_root())); SASSERT(n1->reaches(n1->get_root()));
SASSERT(!n2->reaches(n1->get_root()));
SASSERT(!n2->reaches(n1));
n1->reverse_justification(); n1->reverse_justification();
n1->m_target = n2; n1->m_target = n2;
n1->m_justification = j; n1->m_justification = j;
SASSERT(n1->acyclic());
SASSERT(n2->acyclic());
SASSERT(n1->get_root()->reaches(n1)); SASSERT(n1->get_root()->reaches(n1));
SASSERT(!n2->get_root()->m_target);
TRACE("euf_verbose", tout << "merge " << n1->get_expr_id() << " " << n2->get_expr_id() << " updates: " << m_updates.size() << "\n";);
} }
void egraph::unmerge_justification(enode* n1) { void egraph::unmerge_justification(enode* n1) {
TRACE("euf_verbose", tout << "unmerge " << n1->get_expr_id() << " " << n1->m_target->get_expr_id() << "\n";);
// r1 -> .. -> n1 -> n2 -> ... -> r2 // r1 -> .. -> n1 -> n2 -> ... -> r2
// where n2 = n1->m_target // where n2 = n1->m_target
SASSERT(n1->get_root()->reaches(n1)); SASSERT(n1->get_root()->reaches(n1));
SASSERT(n1->m_target);
n1->m_target = nullptr; n1->m_target = nullptr;
n1->m_justification = justification::axiom(); n1->m_justification = justification::axiom();
n1->get_root()->reverse_justification(); n1->get_root()->reverse_justification();
@ -347,7 +375,7 @@ namespace euf {
// n1 -> ... -> r1 // n1 -> ... -> r1
// n2 -> ... -> r2 // n2 -> ... -> r2
SASSERT(n1->reaches(n1->get_root())); SASSERT(n1->reaches(n1->get_root()));
SASSERT(n1->get_root()->m_target == nullptr); SASSERT(!n1->get_root()->m_target);
} }
/** /**
@ -359,8 +387,9 @@ namespace euf {
void egraph::push_congruence(enode* n1, enode* n2, bool comm) { void egraph::push_congruence(enode* n1, enode* n2, bool comm) {
SASSERT(is_app(n1->get_expr())); SASSERT(is_app(n1->get_expr()));
SASSERT(n1->get_decl() == n2->get_decl()); SASSERT(n1->get_decl() == n2->get_decl());
if (m_used_cc) if (m_used_cc && !comm) {
m_used_cc(to_app(n1->get_expr()), to_app(n2->get_expr())); m_used_cc(to_app(n1->get_expr()), to_app(n2->get_expr()));
}
if (comm && if (comm &&
n1->get_arg(0)->get_root() == n2->get_arg(1)->get_root() && n1->get_arg(0)->get_root() == n2->get_arg(1)->get_root() &&
n1->get_arg(1)->get_root() == n2->get_arg(0)->get_root()) { n1->get_arg(1)->get_root() == n2->get_arg(0)->get_root()) {
@ -409,6 +438,7 @@ namespace euf {
void egraph::end_explain() { void egraph::end_explain() {
for (enode* n : m_todo) for (enode* n : m_todo)
n->unmark1(); n->unmark1();
DEBUG_CODE(for (enode* n : m_nodes) SASSERT(!n->is_marked1()););
m_todo.reset(); m_todo.reset();
} }
@ -424,7 +454,12 @@ namespace euf {
template <typename T> template <typename T>
void egraph::explain_eq(ptr_vector<T>& justifications, enode* a, enode* b) { void egraph::explain_eq(ptr_vector<T>& justifications, enode* a, enode* b) {
SASSERT(a->get_root() == b->get_root()); SASSERT(a->get_root() == b->get_root());
enode* lca = find_lca(a, b); enode* lca = find_lca(a, b);
TRACE("euf_verbose", tout << "explain-eq: " << a->get_expr_id() << " = " << b->get_expr_id()
<< ": " << mk_bounded_pp(a->get_expr(), m)
<< " == " << mk_bounded_pp(b->get_expr(), m)
<< " lca: " << mk_bounded_pp(lca->get_expr(), m) << "\n";);
push_to_lca(a, lca); push_to_lca(a, lca);
push_to_lca(b, lca); push_to_lca(b, lca);
if (m_used_eq) if (m_used_eq)
@ -438,6 +473,7 @@ namespace euf {
enode* n = m_todo[i]; enode* n = m_todo[i];
if (n->m_target && !n->is_marked1()) { if (n->m_target && !n->is_marked1()) {
n->mark1(); n->mark1();
CTRACE("euf", m_display_justification, n->m_justification.display(tout << n->get_expr_id() << " = " << n->m_target->get_expr_id() << " ", m_display_justification) << "\n";);
explain_eq(justifications, n, n->m_target, n->m_justification); explain_eq(justifications, n, n->m_target, n->m_justification);
} }
} }
@ -461,21 +497,26 @@ namespace euf {
out << "v:" << f->get_id(); out << "v:" << f->get_id();
out << "\n"; out << "\n";
if (!n->m_parents.empty()) { if (!n->m_parents.empty()) {
out << " "; out << " parents ";
for (enode* p : enode_parents(n)) for (enode* p : enode_parents(n))
out << p->get_expr_id() << " "; out << p->get_expr_id() << " ";
out << "\n"; out << "\n";
} }
if (n->has_th_vars()) { if (n->has_th_vars()) {
out << " "; out << " theories ";
for (auto v : enode_th_vars(n)) for (auto v : enode_th_vars(n))
out << v.get_id() << ":" << v.get_var() << " "; out << v.get_id() << ":" << v.get_var() << " ";
out << "\n"; out << "\n";
} }
if (n->m_target && m_display_justification)
n->m_justification.display(out << " = " << n->m_target->get_expr_id() << " j: ", m_display_justification) << "\n";
return out; return out;
} }
std::ostream& egraph::display(std::ostream& out) const { 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); m_table.display(out);
unsigned max_args = 0; unsigned max_args = 0;
for (enode* n : m_nodes) for (enode* n : m_nodes)

View file

@ -126,6 +126,7 @@ namespace euf {
stats m_stats; stats m_stats;
std::function<void(expr*,expr*,expr*)> m_used_eq; std::function<void(expr*,expr*,expr*)> m_used_eq;
std::function<void(app*,app*)> m_used_cc; std::function<void(app*,app*)> m_used_cc;
std::function<void(std::ostream&, void*)> m_display_justification;
void push_eq(enode* r1, enode* n1, unsigned r2_num_parents) { void push_eq(enode* r1, enode* n1, unsigned r2_num_parents) {
m_updates.push_back(update_record(r1, n1, r2_num_parents)); m_updates.push_back(update_record(r1, n1, r2_num_parents));
@ -151,6 +152,7 @@ namespace euf {
void push_to_lca(enode* a, enode* lca); void push_to_lca(enode* a, enode* lca);
void push_congruence(enode* n1, enode* n2, bool commutative); void push_congruence(enode* n1, enode* n2, bool commutative);
void push_todo(enode* n); void push_todo(enode* n);
template <typename T> template <typename T>
void explain_eq(ptr_vector<T>& justifications, enode* a, enode* b, justification const& j) { void explain_eq(ptr_vector<T>& justifications, enode* a, enode* b, justification const& j) {
if (j.is_external()) if (j.is_external())
@ -200,8 +202,8 @@ namespace euf {
bool has_th_eq() const { return m_new_th_eqs_qhead < m_new_th_eqs.size(); } bool has_th_eq() const { return m_new_th_eqs_qhead < m_new_th_eqs.size(); }
enode_bool_pair get_literal() const { return m_new_lits[m_new_lits_qhead]; } enode_bool_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]; } th_eq get_th_eq() const { return m_new_th_eqs[m_new_th_eqs_qhead]; }
void next_literal() { SASSERT(m_new_lits_qhead < m_new_lits.size()); m_new_lits_qhead++; } void next_literal() { force_push(); SASSERT(m_new_lits_qhead < m_new_lits.size()); m_new_lits_qhead++; }
void next_th_eq() { SASSERT(m_new_th_eqs_qhead < m_new_th_eqs.size()); m_new_th_eqs_qhead++; } void next_th_eq() { force_push(); SASSERT(m_new_th_eqs_qhead < m_new_th_eqs.size()); m_new_th_eqs_qhead++; }
void add_th_var(enode* n, theory_var v, theory_id id); void add_th_var(enode* n, theory_var v, theory_id id);
@ -209,6 +211,7 @@ namespace euf {
void set_used_eq(std::function<void(expr*,expr*,expr*)>& used_eq) { m_used_eq = used_eq; } 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; } void set_used_cc(std::function<void(app*,app*)>& used_cc) { m_used_cc = used_cc; }
void set_display_justification(std::function<void (std::ostream&, void*)> & d) { m_display_justification = d; }
void begin_explain(); void begin_explain();
void end_explain(); void end_explain();
@ -228,6 +231,8 @@ namespace euf {
e_pp pp(enode* n) const { return e_pp(*this, n); } e_pp pp(enode* n) const { return e_pp(*this, n); }
std::ostream& display(std::ostream& out) const; std::ostream& display(std::ostream& out) const;
void collect_statistics(statistics& st) const; void collect_statistics(statistics& st) const;
unsigned num_scopes() const { return m_scopes.size() + m_num_scopes; }
}; };
inline std::ostream& operator<<(std::ostream& out, egraph const& g) { return g.display(out); } inline std::ostream& operator<<(std::ostream& out, egraph const& g) { return g.display(out); }

View file

@ -31,7 +31,8 @@ namespace euf {
VERIFY(found_root); VERIFY(found_root);
VERIFY(found_this); VERIFY(found_this);
VERIFY(this != m_root || class_size == m_class_size); VERIFY(this != m_root || class_size == m_class_size);
if (this == m_root) { if (is_root()) {
VERIFY(!m_target);
for (enode* p : enode_parents(this)) { for (enode* p : enode_parents(this)) {
bool found = false; bool found = false;
for (enode* arg : enode_args(p)) { for (enode* arg : enode_args(p)) {
@ -69,8 +70,24 @@ namespace euf {
return true; return true;
} }
bool enode::acyclic() const {
enode const* n = this;
enode const* p = this;
while (n) {
n = n->m_target;
if (n) {
p = p->m_target;
n = n->m_target;
}
if (n == p)
return false;
}
return true;
}
bool enode::reaches(enode* n) const { bool enode::reaches(enode* n) const {
enode const* r = this; enode const* r = this;
SASSERT(acyclic());
while (r) { while (r) {
if (r == n) if (r == n)
return true; return true;

View file

@ -156,6 +156,7 @@ namespace euf {
void reverse_justification(); void reverse_justification();
bool reaches(enode* n) const; bool reaches(enode* n) const;
bool acyclic() const;
enode* const* begin_parents() const { return m_parents.begin(); } enode* const* begin_parents() const { return m_parents.begin(); }
enode* const* end_parents() const { return m_parents.end(); } enode* const* end_parents() const { return m_parents.end(); }

View file

@ -215,8 +215,6 @@ namespace euf {
return enode_bool_pair(n_prime, false); return enode_bool_pair(n_prime, false);
case BINARY: case BINARY:
n_prime = UNTAG(binary_table*, t)->insert_if_not_there(n); n_prime = UNTAG(binary_table*, t)->insert_if_not_there(n);
TRACE("euf", tout << "insert: " << n->get_expr_id() << " " << cg_binary_hash()(n) << " inserted: " << (n == n_prime) << " " << n_prime->get_expr_id() << "\n";
display_binary(tout, t); tout << "contains_ptr: " << contains_ptr(n) << "\n";);
return enode_bool_pair(n_prime, false); return enode_bool_pair(n_prime, false);
case BINARY_COMM: case BINARY_COMM:
m_commutativity = false; m_commutativity = false;
@ -236,7 +234,6 @@ namespace euf {
UNTAG(unary_table*, t)->erase(n); UNTAG(unary_table*, t)->erase(n);
break; break;
case BINARY: case BINARY:
TRACE("euf", tout << "erase: " << n->get_expr_id() << " " << cg_binary_hash()(n) << " contains: " << contains_ptr(n) << "\n";);
UNTAG(binary_table*, t)->erase(n); UNTAG(binary_table*, t)->erase(n);
break; break;
case BINARY_COMM: case BINARY_COMM:

View file

@ -20,7 +20,7 @@ Author:
namespace euf { namespace euf {
class justification { class justification {
enum kind_t { enum class kind_t {
axiom_t, axiom_t,
congruence_t, congruence_t,
external_t external_t
@ -29,20 +29,20 @@ namespace euf {
bool m_comm; bool m_comm;
void* m_external; void* m_external;
justification(bool comm): justification(bool comm):
m_kind(congruence_t), m_kind(kind_t::congruence_t),
m_comm(comm), m_comm(comm),
m_external(nullptr) m_external(nullptr)
{} {}
justification(void* ext): justification(void* ext):
m_kind(external_t), m_kind(kind_t::external_t),
m_comm(false), m_comm(false),
m_external(ext) m_external(ext)
{} {}
public: public:
justification(): justification():
m_kind(axiom_t), m_kind(kind_t::axiom_t),
m_comm(false), m_comm(false),
m_external(nullptr) m_external(nullptr)
{} {}
@ -51,24 +51,43 @@ namespace euf {
static justification congruence(bool c) { return justification(c); } static justification congruence(bool c) { return justification(c); }
static justification external(void* ext) { return justification(ext); } static justification external(void* ext) { return justification(ext); }
bool is_external() const { return m_kind == external_t; } bool is_external() const { return m_kind == kind_t::external_t; }
bool is_congruence() const { return m_kind == congruence_t; } bool is_congruence() const { return m_kind == kind_t::congruence_t; }
bool is_commutative() const { return m_comm; } bool is_commutative() const { return m_comm; }
template <typename T> template <typename T>
T* ext() const { SASSERT(is_external()); return static_cast<T*>(m_external); } T* ext() const { SASSERT(is_external()); return static_cast<T*>(m_external); }
justification copy(std::function<void*(void*)>& copy_justification) const { justification copy(std::function<void*(void*)>& copy_justification) const {
switch (m_kind) { switch (m_kind) {
case external_t: case kind_t::external_t:
return external(copy_justification(m_external)); return external(copy_justification(m_external));
case axiom_t: case kind_t::axiom_t:
return axiom(); return axiom();
case congruence_t: case kind_t::congruence_t:
return congruence(m_comm); return congruence(m_comm);
default: default:
UNREACHABLE(); UNREACHABLE();
return axiom(); return axiom();
} }
} }
std::ostream& display(std::ostream& out, std::function<void (std::ostream&, void*)> const& ext) const {
switch (m_kind) {
case kind_t::external_t:
if (ext)
ext(out, m_external);
else
out << "external";
return out;
case kind_t::axiom_t:
return out << "axiom";
case kind_t::congruence_t:
return out << "congruence";
default:
UNREACHABLE();
return out;
}
return out;
}
}; };
} }

View file

@ -287,13 +287,13 @@ namespace datalog {
class rule : public accounted_object { class rule : public accounted_object {
friend class rule_manager; friend class rule_manager;
app * m_head; app* m_head{ nullptr };
proof* m_proof; proof* m_proof{ nullptr };
unsigned m_tail_size:20; unsigned m_tail_size:20;
// unsigned m_reserve:12; // unsigned m_reserve:12;
unsigned m_ref_cnt; unsigned m_ref_cnt{ 0 };
unsigned m_positive_cnt; unsigned m_positive_cnt{ 0 };
unsigned m_uninterp_cnt; unsigned m_uninterp_cnt{ 0 };
symbol m_name; symbol m_name;
/** /**
The following field is an array of tagged pointers. The following field is an array of tagged pointers.

View file

@ -2613,7 +2613,7 @@ void context::init_global_smt_params() {
m.toggle_proof_mode(PGM_ENABLED); m.toggle_proof_mode(PGM_ENABLED);
params_ref p; params_ref p;
if (!m_use_eq_prop) { if (!m_use_eq_prop) {
p.set_uint("arith.propagation_mode", BP_NONE); p.set_uint("arith.propagation_mode", (unsigned)bound_prop_mode::BP_NONE);
p.set_bool("arith.auto_config_simplex", true); p.set_bool("arith.auto_config_simplex", true);
p.set_bool("arith.propagate_eqs", false); p.set_bool("arith.propagate_eqs", false);
p.set_bool("arith.eager_eq_axioms", false); p.set_bool("arith.eager_eq_axioms", false);

View file

@ -666,7 +666,7 @@ namespace opt {
opt_params p(m_params); opt_params p(m_params);
if (p.optsmt_engine() == symbol("symba") || if (p.optsmt_engine() == symbol("symba") ||
p.optsmt_engine() == symbol("farkas")) { p.optsmt_engine() == symbol("farkas")) {
auto str = std::to_string(AS_OPTINF); auto str = std::to_string((unsigned)(arith_solver_id::AS_OPTINF));
gparams::set("smt.arith.solver", str.c_str()); gparams::set("smt.arith.solver", str.c_str());
} }
} }

View file

@ -20,7 +20,6 @@ Revision History:
#undef max #undef max
#undef min #undef min
#include "sat/sat_solver.h" #include "sat/sat_solver.h"
#include "sat/sat_drat.h"
template<typename Buffer> template<typename Buffer>
static bool is_whitespace(Buffer & in) { static bool is_whitespace(Buffer & in) {
@ -147,13 +146,21 @@ bool parse_dimacs(std::istream & in, std::ostream& err, sat::solver & solver) {
namespace dimacs { namespace dimacs {
std::ostream& operator<<(std::ostream& out, drat_record const& r) { std::ostream& operator<<(std::ostream& out, drat_record const& r) {
std::function<symbol(int)> fn = [&](int th) { return symbol(th); };
drat_pp pp(r, fn);
return out << pp;
}
std::ostream& operator<<(std::ostream& out, drat_pp const& p) {
auto const& r = p.r;
sat::status_pp pp(r.m_status, p.th);
switch (r.m_tag) { switch (r.m_tag) {
case drat_record::tag_t::is_clause: case drat_record::tag_t::is_clause:
return out << r.m_status << " " << r.m_lits << "\n"; return out << pp << " " << r.m_lits << " 0\n";
case drat_record::tag_t::is_node: case drat_record::tag_t::is_node:
return out << "e " << r.m_node_id << " " << r.m_name << " " << r.m_args << "\n"; return out << "e " << r.m_node_id << " " << r.m_name << " " << r.m_args << "0\n";
case drat_record::is_bool_def: case drat_record::tag_t::is_bool_def:
return out << "b " << r.m_node_id << " " << r.m_args << "\n"; return out << "b " << r.m_node_id << " " << r.m_args << "0\n";
} }
return out; return out;
} }

View file

@ -53,23 +53,27 @@ namespace dimacs {
}; };
struct drat_record { struct drat_record {
enum tag_t { is_clause, is_node, is_bool_def }; enum class tag_t { is_clause, is_node, is_bool_def };
tag_t m_tag; tag_t m_tag{ tag_t::is_clause };
// a clause populates m_lits and m_status // a clause populates m_lits and m_status
// a node populates m_node_id, m_name, m_args // a node populates m_node_id, m_name, m_args
// a bool def populates m_node_id and one element in m_args // a bool def populates m_node_id and one element in m_args
sat::literal_vector m_lits; sat::literal_vector m_lits;
sat::status m_status; sat::status m_status{ sat::status::redundant() };
unsigned m_node_id; unsigned m_node_id{ 0 };
std::string m_name; std::string m_name;
unsigned_vector m_args; unsigned_vector m_args;
drat_record(): drat_record() {}
m_tag(is_clause), };
m_status(sat::status::redundant())
{} struct drat_pp {
drat_record const& r;
std::function<symbol(int)>& th;
drat_pp(drat_record const& r, std::function<symbol(int)>& th) : r(r), th(th) {}
}; };
std::ostream& operator<<(std::ostream& out, drat_record const& r); std::ostream& operator<<(std::ostream& out, drat_record const& r);
std::ostream& operator<<(std::ostream& out, drat_pp const& r);
class drat_parser { class drat_parser {
dimacs::stream_buffer in; dimacs::stream_buffer in;

View file

@ -92,7 +92,10 @@ namespace sat {
public: public:
binspr(solver& s): m_solver(s), m_stopped_at(0), m_limit1(1000), m_limit2(300) {} binspr(solver& s): m_solver(s), m_stopped_at(0), m_limit1(1000), m_limit2(300) {
memset(m_true, 0, sizeof(unsigned) * max_lits);
memset(m_false, 0, sizeof(unsigned) * max_lits);
}
~binspr() {} ~binspr() {}

View file

@ -35,7 +35,6 @@ namespace sat {
m_activity(false) m_activity(false)
{ {
if (s.get_config().m_drat && s.get_config().m_drat_file.is_non_empty_string()) { if (s.get_config().m_drat && s.get_config().m_drat_file.is_non_empty_string()) {
std::cout << "DRAT " << s.get_config().m_drat_file << "\n";
auto mode = s.get_config().m_drat_binary ? (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc) : std::ios_base::out; auto mode = s.get_config().m_drat_binary ? (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc) : std::ios_base::out;
m_out = alloc(std::ofstream, s.get_config().m_drat_file.str(), mode); m_out = alloc(std::ofstream, s.get_config().m_drat_file.str(), mode);
if (s.get_config().m_drat_binary) { if (s.get_config().m_drat_binary) {
@ -93,11 +92,8 @@ namespace sat {
char* lastd = digits + sizeof(digits); char* lastd = digits + sizeof(digits);
unsigned len = 0; unsigned len = 0;
if (st.is_asserted()) {
buffer[len++] = 'a'; if (st.is_deleted()) {
buffer[len++] = ' ';
}
else if (st.is_deleted()) {
buffer[len++] = 'd'; buffer[len++] = 'd';
buffer[len++] = ' '; buffer[len++] = ' ';
} }
@ -105,10 +101,16 @@ namespace sat {
buffer[len++] = 'i'; buffer[len++] = 'i';
buffer[len++] = ' '; buffer[len++] = ' ';
} }
else if (st.is_redundant() && !st.is_sat()) { else if (!st.is_sat()) {
if (st.is_redundant()) {
buffer[len++] = 'r'; buffer[len++] = 'r';
buffer[len++] = ' '; buffer[len++] = ' ';
} }
else if (st.is_asserted()) {
buffer[len++] = 'a';
buffer[len++] = ' ';
}
}
if (!st.is_sat()) { if (!st.is_sat()) {
for (char ch : m_theory[st.get_th()]) for (char ch : m_theory[st.get_th()])
@ -373,8 +375,33 @@ namespace sat {
} }
} }
bool drat::is_drup(unsigned n, literal const* c, literal_vector& units) {
if (m_inconsistent)
return true;
if (n == 0)
return false;
unsigned num_units = m_units.size();
for (unsigned i = 0; !m_inconsistent && i < n; ++i) {
declare(c[i]);
assign_propagate(~c[i]);
}
for (unsigned i = num_units; i < m_units.size(); ++i) {
m_assignment[m_units[i].var()] = l_undef;
}
units.append(m_units.size() - num_units, m_units.c_ptr() + num_units);
m_units.shrink(num_units);
bool ok = m_inconsistent;
m_inconsistent = false;
return ok;
}
bool drat::is_drup(unsigned n, literal const* c) { bool drat::is_drup(unsigned n, literal const* c) {
if (m_inconsistent || n == 0) return true; if (m_inconsistent)
return true;
if (n == 0)
return false;
unsigned num_units = m_units.size(); unsigned num_units = m_units.size();
for (unsigned i = 0; !m_inconsistent && i < n; ++i) { for (unsigned i = 0; !m_inconsistent && i < n; ++i) {
assign_propagate(~c[i]); assign_propagate(~c[i]);
@ -448,6 +475,7 @@ namespace sat {
} }
bool drat::is_drat(unsigned n, literal const* c) { bool drat::is_drat(unsigned n, literal const* c) {
return false;
if (m_inconsistent || n == 0) if (m_inconsistent || n == 0)
return true; return true;
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i)
@ -486,7 +514,7 @@ namespace sat {
clause& c = *m_proof[i]; clause& c = *m_proof[i];
unsigned j = 0; unsigned j = 0;
for (; j < c.size() && c[j] != ~l; ++j) {} for (; j < c.size() && c[j] != ~l; ++j) {}
if (st.is_sat() && j != c.size()) { if (j != c.size()) {
lits.append(j, c.begin()); lits.append(j, c.begin());
lits.append(c.size() - j - 1, c.begin() + j + 1); lits.append(c.size() - j - 1, c.begin() + j + 1);
if (!is_drup(lits.size(), lits.c_ptr())) if (!is_drup(lits.size(), lits.c_ptr()))
@ -520,6 +548,8 @@ namespace sat {
// s.display(std::cout); // s.display(std::cout);
std::string line; std::string line;
std::getline(std::cin, line); std::getline(std::cin, line);
exit(0);
#if 0
SASSERT(false); SASSERT(false);
INVOKE_DEBUGGER(); INVOKE_DEBUGGER();
exit(0); exit(0);
@ -530,6 +560,7 @@ namespace sat {
display(tout); display(tout);
s.display(tout);); s.display(tout););
UNREACHABLE(); UNREACHABLE();
#endif
} }
bool drat::contains(literal c, justification const& j) { bool drat::contains(literal c, justification const& j) {
@ -723,6 +754,7 @@ namespace sat {
if (m_out) (*m_out) << "0\n"; if (m_out) (*m_out) << "0\n";
if (m_bout) bdump(0, nullptr, status::redundant()); if (m_bout) bdump(0, nullptr, status::redundant());
if (m_check_unsat) { if (m_check_unsat) {
verify(0, nullptr);
SASSERT(m_inconsistent); SASSERT(m_inconsistent);
} }
} }
@ -756,24 +788,29 @@ namespace sat {
} }
} }
void drat::add(literal_vector const& lits, status st) { void drat::add(literal_vector const& lits, status st) {
add(lits.size(), lits.c_ptr(), st);
}
void drat::add(unsigned sz, literal const* lits, status st) {
if (st.is_deleted()) if (st.is_deleted())
++m_stats.m_num_del; ++m_stats.m_num_del;
else else
++m_stats.m_num_add; ++m_stats.m_num_add;
if (m_check) { if (m_check) {
switch (lits.size()) { switch (sz) {
case 0: add(); break; case 0: add(); break;
case 1: append(lits[0], st); break; case 1: append(lits[0], st); break;
default: { default: {
clause* c = m_alloc.mk_clause(lits.size(), lits.c_ptr(), st.is_redundant()); clause* c = m_alloc.mk_clause(sz, lits, st.is_redundant());
append(*c, st); append(*c, st);
break; break;
} }
} }
} }
if (m_out) if (m_out)
dump(lits.size(), lits.c_ptr(), st); dump(sz, lits, st);
} }
void drat::add(literal_vector const& c) { void drat::add(literal_vector const& c) {
++m_stats.m_num_add; ++m_stats.m_num_add;
if (m_out) dump(c.size(), c.begin(), status::redundant()); if (m_out) dump(c.size(), c.begin(), status::redundant());
@ -842,7 +879,21 @@ namespace sat {
void drat::check_model(model const& m) { void drat::check_model(model const& m) {
} }
std::ostream& operator<<(std::ostream& out, status const& st) { void drat::collect_statistics(statistics& st) const {
st.update("num-drup", m_stats.m_num_drup);
st.update("num-drat", m_stats.m_num_drat);
st.update("num-add", m_stats.m_num_add);
st.update("num-del", m_stats.m_num_del);
}
std::ostream& operator<<(std::ostream& out, sat::status const& st) {
std::function<symbol(int)> th = [&](int id) { return symbol(id); };
return out << sat::status_pp(st, th);
}
std::ostream& operator<<(std::ostream& out, sat::status_pp const& p) {
auto st = p.st;
if (st.is_deleted()) if (st.is_deleted())
out << "d"; out << "d";
else if (st.is_input()) else if (st.is_input())
@ -852,15 +903,8 @@ namespace sat {
else if (st.is_redundant() && !st.is_sat()) else if (st.is_redundant() && !st.is_sat())
out << "r"; out << "r";
if (!st.is_sat()) if (!st.is_sat())
out << " th" << st.m_orig; out << " " << p.th(st.get_th());
return out; return out;
} }
void drat::collect_statistics(statistics& st) const {
st.update("num-drup", m_stats.m_num_drup);
st.update("num-drat", m_stats.m_num_drat);
st.update("num-add", m_stats.m_num_add);
st.update("num-del", m_stats.m_num_del);
}
} }

View file

@ -123,6 +123,7 @@ namespace sat {
void add(clause& c, status st); void add(clause& c, status st);
void add(literal_vector const& c, status st); void add(literal_vector const& c, status st);
void add(literal_vector const& c); // add learned clause void add(literal_vector const& c); // add learned clause
void add(unsigned sz, literal const* lits, status st);
// support for SMT - connect Boolean variables with AST nodes // support for SMT - connect Boolean variables with AST nodes
// associate AST node id with Boolean variable v // associate AST node id with Boolean variable v
@ -156,9 +157,13 @@ namespace sat {
void check_model(model const& m); void check_model(model const& m);
void collect_statistics(statistics& st) const; void collect_statistics(statistics& st) const;
bool inconsistent() const { return m_inconsistent; }
literal_vector const& units() { return m_units; }
bool is_drup(unsigned n, literal const* c, literal_vector& units);
solver& get_solver() { return s; }
}; };
std::ostream& operator<<(std::ostream& out, status const& st); }
};

View file

@ -63,22 +63,14 @@ namespace sat {
// consume tautology // consume tautology
continue; continue;
} }
#if 0
if (l1 != r1) {
// add half r1 => r2, the other half ~r2 => ~r1 is added when traversing l2
m_solver.m_watches[(~r1).index()].push_back(watched(r2, it->is_learned()));
continue;
}
it->set_literal(r2); // keep it.
#else
if (l1 != r1 || l2 != r2) { if (l1 != r1 || l2 != r2) {
if (r1.index() < r2.index()) { if (r1.index() < r2.index()) {
TRACE("elim_eqs", tout << l1 << " " << l2 << " " << r1 << " " << r2 << "\n";);
m_new_bin.push_back(bin(r1, r2, it->is_learned())); m_new_bin.push_back(bin(r1, r2, it->is_learned()));
} }
continue; continue;
} }
// keep it // keep it
#endif
} }
*itprev = *it; *itprev = *it;
itprev++; itprev++;
@ -233,9 +225,10 @@ namespace sat {
if (m_solver.m_cut_simplifier) m_solver.m_cut_simplifier->set_root(v, r); if (m_solver.m_cut_simplifier) m_solver.m_cut_simplifier->set_root(v, r);
bool set_root = m_solver.set_root(l, r); bool set_root = m_solver.set_root(l, r);
bool root_ok = !m_solver.is_external(v) || set_root; bool root_ok = !m_solver.is_external(v) || set_root;
TRACE("elim_eqs", tout << l << " " << r << "\n";);
if (m_solver.is_assumption(v) || (m_solver.is_external(v) && (m_solver.is_incremental() || !root_ok))) { if (m_solver.is_assumption(v) || (m_solver.is_external(v) && (m_solver.is_incremental() || !root_ok))) {
// cannot really eliminate v, since we have to notify extension of future assignments // cannot really eliminate v, since we have to notify extension of future assignments
if (m_solver.m_config.m_drat && m_solver.m_config.m_drat_file.is_null()) { if (m_solver.m_config.m_drat) {
m_solver.m_drat.add(~l, r, sat::status::redundant()); m_solver.m_drat.add(~l, r, sat::status::redundant());
m_solver.m_drat.add(l, ~r, sat::status::redundant()); m_solver.m_drat.add(l, ~r, sat::status::redundant());
} }
@ -291,6 +284,7 @@ namespace sat {
} }
void elim_eqs::operator()(union_find<>& uf) { void elim_eqs::operator()(union_find<>& uf) {
TRACE("elim_eqs", tout << "before union-find bin\n";);
literal_vector roots(m_solver.num_vars(), null_literal); literal_vector roots(m_solver.num_vars(), null_literal);
bool_var_vector to_elim; bool_var_vector to_elim;
for (unsigned i = m_solver.num_vars(); i-- > 0; ) { for (unsigned i = m_solver.num_vars(); i-- > 0; ) {
@ -299,6 +293,7 @@ namespace sat {
if (idx != l1.index()) { if (idx != l1.index()) {
roots[i] = to_literal(idx); roots[i] = to_literal(idx);
to_elim.push_back(i); to_elim.push_back(i);
TRACE("elim_eqs", tout << "remove " << roots[i] << "\n";);
} }
else { else {
roots[i] = l1; roots[i] = l1;

View file

@ -25,7 +25,7 @@ Revision History:
namespace sat { namespace sat {
enum check_result { enum class check_result {
CR_DONE, CR_CONTINUE, CR_GIVEUP CR_DONE, CR_CONTINUE, CR_GIVEUP
}; };
@ -54,11 +54,21 @@ namespace sat {
}; };
class extension { class extension {
protected:
bool m_drating { false };
int m_id { 0 };
public: public:
extension(int id): m_id(id) {}
virtual ~extension() {} virtual ~extension() {}
virtual unsigned get_id() const { return 0; } virtual int get_id() const { return m_id; }
virtual void set_solver(solver* s) = 0; virtual void set_solver(solver* s) = 0;
virtual void set_lookahead(lookahead* s) {}; virtual void set_lookahead(lookahead* s) {};
class scoped_drating {
extension& ext;
public:
scoped_drating(extension& e) :ext(e) { ext.m_drating = true; }
~scoped_drating() { ext.m_drating = false; }
};
virtual void init_search() {} virtual void init_search() {}
virtual bool propagate(literal l, ext_constraint_idx idx) = 0; virtual bool propagate(literal l, ext_constraint_idx idx) = 0;
virtual bool unit_propagate() = 0; virtual bool unit_propagate() = 0;

View file

@ -1308,7 +1308,7 @@ namespace sat {
} }
} }
break; break;
case lookahead2: case lookahead_mode::lookahead2:
// this could create a conflict from propagation, but we complete the loop. // this could create a conflict from propagation, but we complete the loop.
for (binary const& b : m_ternary[(~l).index()]) { for (binary const& b : m_ternary[(~l).index()]) {
if (sz-- == 0) break; if (sz-- == 0) break;

View file

@ -42,7 +42,7 @@ namespace sat {
return out; return out;
} }
enum lookahead_mode { enum class lookahead_mode {
searching, // normal search searching, // normal search
lookahead1, // lookahead mode lookahead1, // lookahead mode
lookahead2 // double lookahead lookahead2 // double lookahead
@ -100,8 +100,8 @@ namespace sat {
m_delta_rho = (double)0.7; m_delta_rho = (double)0.7;
m_dl_max_iterations = 2; m_dl_max_iterations = 2;
m_tc1_limit = 10000000; m_tc1_limit = 10000000;
m_reward_type = ternary_reward; m_reward_type = reward_t::ternary_reward;
m_cube_cutoff = adaptive_freevars_cutoff; m_cube_cutoff = cutoff_t::adaptive_freevars_cutoff;
m_cube_depth = 10; m_cube_depth = 10;
m_cube_fraction = 0.4; m_cube_fraction = 0.4;
m_cube_freevars = 0.8; m_cube_freevars = 0.8;

View file

@ -66,7 +66,9 @@ namespace sat {
std::ostream& display_mask(std::ostream& out, uint64_t mask, unsigned sz) const; std::ostream& display_mask(std::ostream& out, uint64_t mask, unsigned sz) const;
public: public:
lut_finder(solver& s) : s(s), m_max_lut_size(5) { } lut_finder(solver& s) : s(s), m_max_lut_size(5) {
memset(m_masks, 0, sizeof(uint64_t)*7);
}
~lut_finder() {} ~lut_finder() {}
void set(std::function<void (uint64_t, bool_var_vector const&, bool_var)>& f) { m_on_lut = f; } void set(std::function<void (uint64_t, bool_var_vector const&, bool_var)>& f) { m_on_lut = f; }

View file

@ -32,8 +32,8 @@ namespace sat {
// shared pool of learned clauses. // shared pool of learned clauses.
class vector_pool { class vector_pool {
unsigned_vector m_vectors; unsigned_vector m_vectors;
unsigned m_size; unsigned m_size{ 0 };
unsigned m_tail; unsigned m_tail{ 0 };
unsigned_vector m_heads; unsigned_vector m_heads;
bool_vector m_at_end; bool_vector m_at_end;
void next(unsigned& index); void next(unsigned& index);

View file

@ -82,12 +82,15 @@ namespace sat {
else { else {
m_to_assert.reset(); m_to_assert.reset();
s.push(); s.push();
TRACE("sat", tout << "probing " << l << "\n";);
s.assign_scoped(l); s.assign_scoped(l);
m_counter--; m_counter--;
unsigned old_tr_sz = s.m_trail.size(); unsigned old_tr_sz = s.m_trail.size();
s.propagate(false); s.propagate(false);
if (s.inconsistent()) { if (s.inconsistent()) {
TRACE("sat", tout << "probe failed: " << ~l << "\n";);
// ~l must be true // ~l must be true
s.drat_explain_conflict();
s.pop(1); s.pop(1);
s.assign_scoped(~l); s.assign_scoped(~l);
s.propagate(false); s.propagate(false);
@ -125,10 +128,14 @@ namespace sat {
s.push(); s.push();
literal l(v, false); literal l(v, false);
s.assign_scoped(l); s.assign_scoped(l);
TRACE("sat", tout << "probing " << l << "\n";);
unsigned old_tr_sz = s.m_trail.size(); unsigned old_tr_sz = s.m_trail.size();
s.propagate(false); s.propagate(false);
if (s.inconsistent()) { if (s.inconsistent()) {
// ~l must be true // ~l must be true
TRACE("sat", tout << "probe failed: " << ~l << "\n";
s.display(tout););
s.drat_explain_conflict();
s.pop(1); s.pop(1);
s.assign_scoped(~l); s.assign_scoped(~l);
s.propagate(false); s.propagate(false);

View file

@ -126,7 +126,7 @@ namespace sat {
void init_visited(); void init_visited();
void mark_visited(literal l) { m_visited[l.index()] = true; } void mark_visited(literal l) { m_visited[l.index()] = true; }
void unmark_visited(literal l) { m_visited[l.index()] = false; } void unmark_visited(literal l) { m_visited[l.index()] = false; }
bool is_marked(literal l) const { return m_visited[l.index()] != 0; }
void mark_all_but(clause const & c, literal l); void mark_all_but(clause const & c, literal l);
void unmark_all(clause const & c); void unmark_all(clause const & c);
@ -239,6 +239,8 @@ namespace sat {
void propagate_unit(literal l); void propagate_unit(literal l);
void subsume(); void subsume();
bool is_marked(literal l) const { return m_visited[l.index()] != 0; }
}; };
}; };

View file

@ -249,7 +249,7 @@ namespace sat {
m_watches[2*v+1].reset(); m_watches[2*v+1].reset();
m_assignment[2*v] = l_undef; m_assignment[2*v] = l_undef;
m_assignment[2*v+1] = l_undef; m_assignment[2*v+1] = l_undef;
m_justification[2*v] = justification(UINT_MAX); m_justification[v] = justification(UINT_MAX);
m_decision[v] = dvar; m_decision[v] = dvar;
m_eliminated[v] = false; m_eliminated[v] = false;
m_external[v] = ext; m_external[v] = ext;
@ -337,6 +337,8 @@ namespace sat {
} }
void solver::set_eliminated(bool_var v, bool f) { void solver::set_eliminated(bool_var v, bool f) {
if (m_eliminated[v] && !f)
reset_var(v, m_external[v], m_decision[v]);
m_eliminated[v] = f; m_eliminated[v] = f;
} }
@ -386,6 +388,26 @@ namespace sat {
m_stats.m_del_clause++; m_stats.m_del_clause++;
} }
void solver::drat_explain_conflict() {
if (m_config.m_drat && m_ext) {
extension::scoped_drating _sd(*m_ext);
bool unique_max;
m_conflict_lvl = get_max_lvl(m_not_l, m_conflict, unique_max);
resolve_conflict_for_unsat_core();
}
}
void solver::drat_log_unit(literal lit, justification j) {
extension::scoped_drating _sd(*m_ext.get());
if (j.get_kind() == justification::EXT_JUSTIFICATION)
fill_ext_antecedents(lit, j, false);
m_drat.add(lit, m_searching);
}
void solver::drat_log_clause(unsigned num_lits, literal const* lits, sat::status st) {
m_drat.add(num_lits, lits, st);
}
clause * solver::mk_clause_core(unsigned num_lits, literal * lits, sat::status st) { clause * solver::mk_clause_core(unsigned num_lits, literal * lits, sat::status st) {
bool redundant = st.is_redundant(); bool redundant = st.is_redundant();
TRACE("sat", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << (redundant?" learned":" aux") << "\n";); TRACE("sat", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << (redundant?" learned":" aux") << "\n";);
@ -397,11 +419,9 @@ namespace sat {
return nullptr; // clause is equivalent to true. return nullptr; // clause is equivalent to true.
} }
// if an input clause is simplified, then log the simplified version as learned // if an input clause is simplified, then log the simplified version as learned
if (old_sz > num_lits && m_config.m_drat) { if (m_config.m_drat && old_sz > num_lits)
m_lemma.reset(); drat_log_clause(num_lits, lits, st);
m_lemma.append(num_lits, lits);
m_drat.add(m_lemma, st);
}
++m_stats.m_non_learned_generation; ++m_stats.m_non_learned_generation;
if (!m_searching) { if (!m_searching) {
m_mc.add_clause(num_lits, lits); m_mc.add_clause(num_lits, lits);
@ -413,6 +433,8 @@ namespace sat {
set_conflict(); set_conflict();
return nullptr; return nullptr;
case 1: case 1:
if (m_config.m_drat && (!st.is_sat() || st.is_input()))
drat_log_clause(num_lits, lits, st);
assign_unit(lits[0]); assign_unit(lits[0]);
return nullptr; return nullptr;
case 2: case 2:
@ -493,7 +515,7 @@ namespace sat {
VERIFY(ENABLE_TERNARY); VERIFY(ENABLE_TERNARY);
m_stats.m_mk_ter_clause++; m_stats.m_mk_ter_clause++;
clause * r = alloc_clause(3, lits, st.is_redundant()); clause * r = alloc_clause(3, lits, st.is_redundant());
bool reinit = attach_ter_clause(*r); bool reinit = attach_ter_clause(*r, st);
if (reinit && !st.is_redundant()) push_reinit_stack(*r); if (reinit && !st.is_redundant()) push_reinit_stack(*r);
if (st.is_redundant()) if (st.is_redundant())
m_learned.push_back(r); m_learned.push_back(r);
@ -505,10 +527,10 @@ namespace sat {
return r; return r;
} }
bool solver::attach_ter_clause(clause & c) { bool solver::attach_ter_clause(clause & c, sat::status st) {
VERIFY(ENABLE_TERNARY); VERIFY(ENABLE_TERNARY);
bool reinit = false; bool reinit = false;
if (m_config.m_drat) m_drat.add(c, c.is_learned() ? status::redundant() : status::asserted()); if (m_config.m_drat) m_drat.add(c, st);
TRACE("sat_verbose", tout << c << "\n";); TRACE("sat_verbose", tout << c << "\n";);
SASSERT(!c.was_removed()); SASSERT(!c.was_removed());
m_watches[(~c[0]).index()].push_back(watched(c[1], c[2])); m_watches[(~c[0]).index()].push_back(watched(c[1], c[2]));
@ -604,7 +626,7 @@ namespace sat {
SASSERT(c.size() > 2); SASSERT(c.size() > 2);
reinit = false; reinit = false;
if (ENABLE_TERNARY && c.size() == 3) if (ENABLE_TERNARY && c.size() == 3)
reinit = attach_ter_clause(c); reinit = attach_ter_clause(c, c.is_learned() ? sat::status::redundant() : sat::status::asserted());
else else
reinit = attach_nary_clause(c); reinit = attach_nary_clause(c);
} }
@ -890,7 +912,9 @@ namespace sat {
SASSERT(value(l) == l_undef); SASSERT(value(l) == l_undef);
TRACE("sat_assign_core", tout << l << " " << j << "\n";); TRACE("sat_assign_core", tout << l << " " << j << "\n";);
if (j.level() == 0) { if (j.level() == 0) {
if (m_config.m_drat) m_drat.add(l, m_searching); if (m_config.m_drat)
drat_log_unit(l, j);
j = justification(0); // erase justification for level 0 j = justification(0); // erase justification for level 0
} }
else { else {
@ -1666,12 +1690,12 @@ namespace sat {
lbool solver::final_check() { lbool solver::final_check() {
if (m_ext) { if (m_ext) {
switch (m_ext->check()) { switch (m_ext->check()) {
case CR_DONE: case check_result::CR_DONE:
mk_model(); mk_model();
return l_true; return l_true;
case CR_CONTINUE: case check_result::CR_CONTINUE:
break; break;
case CR_GIVEUP: case check_result::CR_GIVEUP:
throw abort_solver(); throw abort_solver();
} }
return l_undef; return l_undef;
@ -2630,8 +2654,9 @@ namespace sat {
} }
if (m_conflict_lvl == 0) { if (m_conflict_lvl == 0) {
if (m_config.m_drat && m_ext) drat_explain_conflict();
resolve_conflict_for_unsat_core(); if (m_config.m_drat)
drat_log_clause(0, nullptr, sat::status::redundant());
TRACE("sat", tout << "conflict level is 0\n";); TRACE("sat", tout << "conflict level is 0\n";);
return l_false; return l_false;
} }
@ -2883,7 +2908,7 @@ namespace sat {
break; break;
} }
case justification::EXT_JUSTIFICATION: { case justification::EXT_JUSTIFICATION: {
fill_ext_antecedents(consequent, js, true); fill_ext_antecedents(consequent, js, false);
for (literal l : m_ext_antecedents) { for (literal l : m_ext_antecedents) {
process_antecedent_for_unsat_core(l); process_antecedent_for_unsat_core(l);
} }
@ -2896,7 +2921,7 @@ namespace sat {
} }
void solver::resolve_conflict_for_unsat_core() { void solver::resolve_conflict_for_unsat_core() {
TRACE("sat", display(tout); TRACE("sat_verbose", display(tout);
unsigned level = 0; unsigned level = 0;
for (literal l : m_trail) { for (literal l : m_trail) {
if (level != lvl(l)) { if (level != lvl(l)) {
@ -2914,7 +2939,7 @@ namespace sat {
); );
m_core.reset(); m_core.reset();
if (m_conflict_lvl == 0) { if (!m_config.m_drat && m_conflict_lvl == 0) {
return; return;
} }
SASSERT(m_unmark.empty()); SASSERT(m_unmark.empty());
@ -3044,6 +3069,7 @@ namespace sat {
bool_var var = antecedent.var(); bool_var var = antecedent.var();
unsigned var_lvl = lvl(var); unsigned var_lvl = lvl(var);
SASSERT(var < num_vars()); SASSERT(var < num_vars());
TRACE("sat", tout << "process " << var << "@" << var_lvl << " marked " << is_marked(var) << " conflict " << m_conflict_lvl << "\n";);
if (!is_marked(var) && var_lvl > 0) { if (!is_marked(var) && var_lvl > 0) {
mark(var); mark(var);
switch (m_config.m_branching_heuristic) { switch (m_config.m_branching_heuristic) {
@ -3717,11 +3743,14 @@ namespace sat {
} }
for (literal lit : m_lemma) for (literal lit : m_lemma)
mark_visited(lit); mark_visited(lit);
auto is_active = [&](bool_var v) {
return value(v) != l_undef && lvl(v) <= new_lvl;
};
unsigned sz = m_active_vars.size(), j = old_num_vars; unsigned sz = m_active_vars.size(), j = old_num_vars;
for (unsigned i = old_num_vars; i < sz; ++i) { for (unsigned i = old_num_vars; i < sz; ++i) {
bool_var v = m_active_vars[i]; bool_var v = m_active_vars[i];
if (is_visited(v)) { if (is_visited(v) || is_active(v)) {
m_vars_to_reinit.push_back(v); m_vars_to_reinit.push_back(v);
m_active_vars[j++] = v; m_active_vars[j++] = v;
} }
@ -3731,7 +3760,9 @@ namespace sat {
} }
} }
m_active_vars.shrink(j); m_active_vars.shrink(j);
IF_VERBOSE(0, verbose_stream() << "vars to reinit: " << m_vars_to_reinit << " free vars " << m_free_vars << "\n"); IF_VERBOSE(11, verbose_stream() << "vars to reinit: " << m_vars_to_reinit << " free vars " << m_free_vars << "\n";
display(verbose_stream()););
} }
void solver::shrink_vars(unsigned v) { void solver::shrink_vars(unsigned v) {

View file

@ -284,7 +284,7 @@ namespace sat {
void mk_bin_clause(literal l1, literal l2, bool learned) { mk_bin_clause(l1, l2, learned ? sat::status::redundant() : sat::status::asserted()); } void mk_bin_clause(literal l1, literal l2, bool learned) { mk_bin_clause(l1, l2, learned ? sat::status::redundant() : sat::status::asserted()); }
bool propagate_bin_clause(literal l1, literal l2); bool propagate_bin_clause(literal l1, literal l2);
clause * mk_ter_clause(literal * lits, status st); clause * mk_ter_clause(literal * lits, status st);
bool attach_ter_clause(clause & c); bool attach_ter_clause(clause & c, status st);
clause * mk_nary_clause(unsigned num_lits, literal * lits, status st); clause * mk_nary_clause(unsigned num_lits, literal * lits, status st);
bool attach_nary_clause(clause & c); bool attach_nary_clause(clause & c);
void attach_clause(clause & c, bool & reinit); void attach_clause(clause & c, bool & reinit);
@ -296,6 +296,9 @@ namespace sat {
void add_ate(clause& c) { m_mc.add_ate(c); } void add_ate(clause& c) { m_mc.add_ate(c); }
void add_ate(literal l1, literal l2) { m_mc.add_ate(l1, l2); } void add_ate(literal l1, literal l2) { m_mc.add_ate(l1, l2); }
void add_ate(literal_vector const& lits) { m_mc.add_ate(lits); } void add_ate(literal_vector const& lits) { m_mc.add_ate(lits); }
void drat_log_unit(literal lit, justification j);
void drat_log_clause(unsigned sz, literal const* lits, status st);
void drat_explain_conflict();
class scoped_disable_checkpoint { class scoped_disable_checkpoint {
solver& s; solver& s;

View file

@ -26,6 +26,7 @@ Revision History:
#include "util/vector.h" #include "util/vector.h"
#include "util/uint_set.h" #include "util/uint_set.h"
#include "util/stopwatch.h" #include "util/stopwatch.h"
#include "util/symbol.h"
class params_ref; class params_ref;
class reslimit; class reslimit;
@ -278,5 +279,16 @@ namespace sat {
int get_th() const { return m_orig; } int get_th() const { return m_orig; }
}; };
struct status_pp {
status const& st;
std::function<symbol(int)>& th;
status_pp(status const& st, std::function<symbol(int)>& th) : st(st), th(th) {}
}; };
std::ostream& operator<<(std::ostream& out, sat::status const& st);
std::ostream& operator<<(std::ostream& out, sat::status_pp const& p);
};

View file

@ -5,8 +5,12 @@ z3_add_component(sat_smt
array_model.cpp array_model.cpp
array_solver.cpp array_solver.cpp
atom2bool_var.cpp atom2bool_var.cpp
ba_card.cpp
ba_constraint.cpp
ba_internalize.cpp ba_internalize.cpp
ba_pb.cpp
ba_solver.cpp ba_solver.cpp
ba_xor.cpp
bv_ackerman.cpp bv_ackerman.cpp
bv_internalize.cpp bv_internalize.cpp
bv_solver.cpp bv_solver.cpp

View file

@ -27,6 +27,8 @@ namespace array {
m_axiom_trail.push_back(r); m_axiom_trail.push_back(r);
if (m_axioms.contains(idx)) if (m_axioms.contains(idx))
m_axiom_trail.pop_back(); m_axiom_trail.pop_back();
else
ctx.push(push_back_vector<euf::solver, svector<axiom_record>>(m_axiom_trail));
} }
bool solver::assert_axiom(unsigned idx) { bool solver::assert_axiom(unsigned idx) {
@ -39,10 +41,16 @@ namespace array {
app* select; app* select;
switch (r.m_kind) { switch (r.m_kind) {
case axiom_record::kind_t::is_store: case axiom_record::kind_t::is_store:
TRACE("array", tout << "store-axiom: " << mk_bounded_pp(child, m, 2) << "\n";);
return assert_store_axiom(to_app(child)); return assert_store_axiom(to_app(child));
case axiom_record::kind_t::is_select: case axiom_record::kind_t::is_select:
select = r.select->get_app(); select = r.select->get_app();
SASSERT(a.is_select(select)); SASSERT(a.is_select(select));
SASSERT(can_beta_reduce(r.n));
TRACE("array", tout << "select-axiom: " << mk_bounded_pp(select, m, 2) << " " << mk_bounded_pp(child, m, 2) << "\n";);
if (r.select->get_arg(0)->get_root() != r.n->get_root()) {
IF_VERBOSE(0, verbose_stream() << "could delay " << mk_pp(select, m) << " " << mk_pp(child, m) << "\n");
}
if (a.is_const(child)) if (a.is_const(child))
return assert_select_const_axiom(select, to_app(child)); return assert_select_const_axiom(select, to_app(child));
else if (a.is_as_array(child)) else if (a.is_as_array(child))
@ -57,20 +65,22 @@ namespace array {
UNREACHABLE(); UNREACHABLE();
break; break;
case axiom_record::kind_t::is_default: case axiom_record::kind_t::is_default:
SASSERT(can_beta_reduce(r.n));
TRACE("array", tout << "default-axiom: " << mk_bounded_pp(child, m, 2) << "\n";);
if (a.is_const(child)) if (a.is_const(child))
return assert_default_const_axiom(to_app(child)); return assert_default_const_axiom(to_app(child));
else if (a.is_store(child)) else if (a.is_store(child))
return assert_default_store_axiom(to_app(child)); return assert_default_store_axiom(to_app(child));
else if (a.is_map(child)) else if (a.is_map(child))
return assert_default_map_axiom(to_app(child)); return assert_default_map_axiom(to_app(child));
else if (a.is_as_array(child))
return assert_default_as_array_axiom(to_app(child));
else else
UNREACHABLE(); return true;
break; break;
case axiom_record::kind_t::is_extensionality: case axiom_record::kind_t::is_extensionality:
TRACE("array", tout << "extensionality-axiom: " << mk_bounded_pp(child, m, 2) << "\n";);
return assert_extensionality(r.n->get_arg(0)->get_expr(), r.n->get_arg(1)->get_expr()); return assert_extensionality(r.n->get_arg(0)->get_expr(), r.n->get_arg(1)->get_expr());
case axiom_record::kind_t::is_congruence: case axiom_record::kind_t::is_congruence:
TRACE("array", tout << "congruence-axiom: " << mk_bounded_pp(child, m, 2) << " " << mk_bounded_pp(r.select->get_expr(), m, 2) << "\n";);
return assert_congruent_axiom(child, r.select->get_expr()); return assert_congruent_axiom(child, r.select->get_expr());
default: default:
UNREACHABLE(); UNREACHABLE();
@ -86,7 +96,7 @@ namespace array {
* n := store(a, i, v) * n := store(a, i, v)
*/ */
bool solver::assert_store_axiom(app* e) { bool solver::assert_store_axiom(app* e) {
m_stats.m_num_store_axiom++; ++m_stats.m_num_store_axiom;
SASSERT(a.is_store(e)); SASSERT(a.is_store(e));
unsigned num_args = e->get_num_args(); unsigned num_args = e->get_num_args();
ptr_vector<expr> sel_args(num_args - 1, e->get_args()); ptr_vector<expr> sel_args(num_args - 1, e->get_args());
@ -104,7 +114,7 @@ namespace array {
* where i = (i_1, ..., i_n), j = (j_1, .., j_n), k in 1..n * where i = (i_1, ..., i_n), j = (j_1, .., j_n), k in 1..n
*/ */
bool solver::assert_select_store_axiom(app* select, app* store) { bool solver::assert_select_store_axiom(app* select, app* store) {
m_stats.m_num_select_store_axiom++; ++m_stats.m_num_select_store_axiom;
SASSERT(a.is_store(store)); SASSERT(a.is_store(store));
SASSERT(a.is_select(select)); SASSERT(a.is_select(select));
SASSERT(store->get_num_args() == 1 + select->get_num_args()); SASSERT(store->get_num_args() == 1 + select->get_num_args());
@ -126,7 +136,10 @@ namespace array {
if (s1->get_root() == s2->get_root()) if (s1->get_root() == s2->get_root())
return false; return false;
sat::literal sel_eq = b_internalize(sel_eq_e); sat::literal sel_eq = b_internalize(sel_eq_e);
if (s().value(sel_eq) == l_true)
return false;
bool new_prop = false;
for (unsigned i = 1; i < num_args; i++) { for (unsigned i = 1; i < num_args; i++) {
expr* idx1 = store->get_arg(i); expr* idx1 = store->get_arg(i);
expr* idx2 = select->get_arg(i); expr* idx2 = select->get_arg(i);
@ -135,13 +148,15 @@ namespace array {
if (r1 == r2) if (r1 == r2)
continue; continue;
if (m.are_distinct(r1->get_expr(), r2->get_expr())) { if (m.are_distinct(r1->get_expr(), r2->get_expr())) {
new_prop = true;
add_clause(sel_eq); add_clause(sel_eq);
break; break;
} }
sat::literal idx_eq = b_internalize(m.mk_eq(idx1, idx2)); sat::literal idx_eq = b_internalize(m.mk_eq(idx1, idx2));
add_clause(idx_eq, sel_eq); if (add_clause(idx_eq, sel_eq))
new_prop = true;
} }
return true; return new_prop;
} }
/** /**
@ -149,7 +164,7 @@ namespace array {
* select(const(v), i) = v * select(const(v), i) = v
*/ */
bool solver::assert_select_const_axiom(app* select, app* cnst) { bool solver::assert_select_const_axiom(app* select, app* cnst) {
m_stats.m_num_select_const_axiom++; ++m_stats.m_num_select_const_axiom;
expr* val = nullptr; expr* val = nullptr;
VERIFY(a.is_const(cnst, val)); VERIFY(a.is_const(cnst, val));
SASSERT(a.is_select(select)); SASSERT(a.is_select(select));
@ -167,7 +182,7 @@ namespace array {
* e1 = e2 or select(e1, diff(e1,e2)) != select(e2, diff(e1, e2)) * e1 = e2 or select(e1, diff(e1,e2)) != select(e2, diff(e1, e2))
*/ */
bool solver::assert_extensionality(expr* e1, expr* e2) { bool solver::assert_extensionality(expr* e1, expr* e2) {
m_stats.m_num_extensionality_axiom++; ++m_stats.m_num_extensionality_axiom;
func_decl_ref_vector* funcs = nullptr; func_decl_ref_vector* funcs = nullptr;
VERIFY(m_sort2diff.find(m.get_sort(e1), funcs)); VERIFY(m_sort2diff.find(m.get_sort(e1), funcs));
expr_ref_vector args1(m), args2(m); expr_ref_vector args1(m), args2(m);
@ -184,10 +199,7 @@ namespace array {
expr_ref sel1_eq_sel2(m.mk_eq(sel1, sel2), m); expr_ref sel1_eq_sel2(m.mk_eq(sel1, sel2), m);
literal lit1 = b_internalize(n1_eq_n2); literal lit1 = b_internalize(n1_eq_n2);
literal lit2 = b_internalize(sel1_eq_sel2); literal lit2 = b_internalize(sel1_eq_sel2);
if (s().value(lit1) == l_true || s().value(lit2) == l_false) return add_clause(lit1, ~lit2);
return false;
add_clause(lit1, ~lit2);
return true;
} }
/** /**
@ -195,17 +207,12 @@ namespace array {
* select(map[f](a, ... d), i) = f(select(a,i),...,select(d,i)) * select(map[f](a, ... d), i) = f(select(a,i),...,select(d,i))
*/ */
bool solver::assert_select_map_axiom(app* select, app* map) { bool solver::assert_select_map_axiom(app* select, app* map) {
m_stats.m_num_select_map_axiom++; ++m_stats.m_num_select_map_axiom;
SASSERT(a.is_map(map)); SASSERT(a.is_map(map));
SASSERT(a.is_select(select)); SASSERT(a.is_select(select));
SASSERT(map->get_num_args() > 0); SASSERT(map->get_num_args() > 0);
func_decl* f = a.get_map_func_decl(map); func_decl* f = a.get_map_func_decl(map);
TRACE("array",
tout << mk_bounded_pp(map, m) << "\n";
tout << mk_bounded_pp(select, m) << "\n";);
unsigned num_args = select->get_num_args(); unsigned num_args = select->get_num_args();
unsigned num_arrays = map->get_num_args();
ptr_buffer<expr> args1, args2; ptr_buffer<expr> args1, args2;
vector<ptr_vector<expr> > args2l; vector<ptr_vector<expr> > args2l;
args1.push_back(map); args1.push_back(map);
@ -238,7 +245,7 @@ namespace array {
* select(as-array f, i_1, ..., i_n) = (f i_1 ... i_n) * select(as-array f, i_1, ..., i_n) = (f i_1 ... i_n)
*/ */
bool solver::assert_select_as_array_axiom(app* select, app* arr) { bool solver::assert_select_as_array_axiom(app* select, app* arr) {
m_stats.m_num_select_as_array_axiom++; ++m_stats.m_num_select_as_array_axiom;
SASSERT(a.is_as_array(arr)); SASSERT(a.is_as_array(arr));
SASSERT(a.is_select(select)); SASSERT(a.is_select(select));
unsigned num_args = select->get_num_args(); unsigned num_args = select->get_num_args();
@ -257,39 +264,31 @@ namespace array {
* default(map[f](a,..,d)) = f(default(a),..,default(d)) * default(map[f](a,..,d)) = f(default(a),..,default(d))
*/ */
bool solver::assert_default_map_axiom(app* map) { bool solver::assert_default_map_axiom(app* map) {
m_stats.m_num_default_map_axiom++; ++m_stats.m_num_default_map_axiom;
SASSERT(a.is_map(map)); SASSERT(a.is_map(map));
func_decl* f = a.get_map_func_decl(map); func_decl* f = a.get_map_func_decl(map);
SASSERT(map->get_num_args() == f->get_arity()); SASSERT(map->get_num_args() == f->get_arity());
ptr_buffer<expr> args2; expr_ref_vector args2(m);
for (expr* arg : *map) for (expr* arg : *map)
args2.push_back(a.mk_default(arg)); args2.push_back(a.mk_default(arg));
expr_ref def1(a.mk_default(map), m); expr_ref def1(a.mk_default(map), m);
expr_ref def2(m.mk_app(f, args2), m); expr_ref def2(m.mk_app(f, args2), m);
rewrite(def2); rewrite(def2);
return ctx.propagate(e_internalize(def1), e_internalize(def2), array_axiom()); return ctx.propagate(e_internalize(def1), e_internalize(def2), array_axiom());
} }
/** /**
* Assert: * Assert:
* default(const(e)) = e * default(const(e)) = e
*/ */
bool solver::assert_default_const_axiom(app* cnst) { bool solver::assert_default_const_axiom(app* cnst) {
m_stats.m_num_default_const_axiom++; ++m_stats.m_num_default_const_axiom;
expr* val = nullptr; expr* val = nullptr;
VERIFY(a.is_const(cnst, val)); VERIFY(a.is_const(cnst, val));
TRACE("array", tout << mk_bounded_pp(cnst, m) << "\n";);
expr_ref def(a.mk_default(cnst), m); expr_ref def(a.mk_default(cnst), m);
return ctx.propagate(expr2enode(val), e_internalize(def), array_axiom()); return ctx.propagate(expr2enode(val), e_internalize(def), array_axiom());
} }
bool solver::assert_default_as_array_axiom(app* as_array) {
// no-op
return false;
}
/** /**
* let n := store(a, i, v) * let n := store(a, i, v)
@ -303,19 +302,15 @@ namespace array {
* default(n) = default(a) * default(n) = default(a)
*/ */
bool solver::assert_default_store_axiom(app* store) { bool solver::assert_default_store_axiom(app* store) {
m_stats.m_num_default_store_axiom++; ++m_stats.m_num_default_store_axiom;
SASSERT(a.is_store(store)); SASSERT(a.is_store(store));
SASSERT(store->get_num_args() >= 3); SASSERT(store->get_num_args() >= 3);
expr_ref def1(m), def2(m); expr_ref def1(m), def2(m);
bool prop = false; bool prop = false;
unsigned num_args = store->get_num_args(); unsigned num_args = store->get_num_args();
def1 = a.mk_default(store); def1 = a.mk_default(store);
def2 = a.mk_default(store->get_arg(0)); def2 = a.mk_default(store->get_arg(0));
bool is_new = false;
if (has_unitary_domain(store)) { if (has_unitary_domain(store)) {
def2 = store->get_arg(num_args - 1); def2 = store->get_arg(num_args - 1);
} }
@ -357,6 +352,7 @@ namespace array {
* Assert select(lambda xs . M, N1,.., Nk) -> M[N1/x1, ..., Nk/xk] * Assert select(lambda xs . M, N1,.., Nk) -> M[N1/x1, ..., Nk/xk]
*/ */
bool solver::assert_select_lambda_axiom(app* select, expr* lambda) { bool solver::assert_select_lambda_axiom(app* select, expr* lambda) {
++m_stats.m_num_select_lambda_axiom;
SASSERT(is_lambda(lambda)); SASSERT(is_lambda(lambda));
SASSERT(a.is_select(select)); SASSERT(a.is_select(select));
SASSERT(m.get_sort(lambda) == m.get_sort(select->get_arg(0))); SASSERT(m.get_sort(lambda) == m.get_sort(select->get_arg(0)));
@ -373,8 +369,8 @@ namespace array {
*/ */
bool solver::assert_congruent_axiom(expr* e1, expr* e2) { bool solver::assert_congruent_axiom(expr* e1, expr* e2) {
++m_stats.m_num_congruence_axiom; ++m_stats.m_num_congruence_axiom;
sort* s = m.get_sort(e1); sort* srt = m.get_sort(e1);
unsigned dimension = get_array_arity(s); unsigned dimension = get_array_arity(srt);
expr_ref n1_eq_n2(m.mk_eq(e1, e2), m); expr_ref n1_eq_n2(m.mk_eq(e1, e2), m);
expr_ref_vector args1(m), args2(m); expr_ref_vector args1(m), args2(m);
args1.push_back(e1); args1.push_back(e1);
@ -382,10 +378,10 @@ namespace array {
svector<symbol> names; svector<symbol> names;
sort_ref_vector sorts(m); sort_ref_vector sorts(m);
for (unsigned i = 0; i < dimension; i++) { for (unsigned i = 0; i < dimension; i++) {
sort * srt = get_array_domain(s, i); sort * asrt = get_array_domain(srt, i);
sorts.push_back(srt); sorts.push_back(asrt);
names.push_back(symbol(i)); names.push_back(symbol(i));
expr * k = m.mk_var(dimension - i - 1, srt); expr * k = m.mk_var(dimension - i - 1, asrt);
args1.push_back(k); args1.push_back(k);
args2.push_back(k); args2.push_back(k);
} }
@ -395,8 +391,8 @@ namespace array {
expr_ref q(m.mk_forall(dimension, sorts.c_ptr(), names.c_ptr(), eq), m); expr_ref q(m.mk_forall(dimension, sorts.c_ptr(), names.c_ptr(), eq), m);
rewrite(q); rewrite(q);
sat::literal fa_eq = b_internalize(q); sat::literal fa_eq = b_internalize(q);
add_clause(~b_internalize(n1_eq_n2), fa_eq); sat::literal neq = b_internalize(n1_eq_n2);
return true; return add_clause(~neq, fa_eq);
} }
bool solver::has_unitary_domain(app* array_term) { bool solver::has_unitary_domain(app* array_term) {
@ -411,7 +407,7 @@ namespace array {
return true; return true;
} }
bool solver::has_large_domain(app* array_term) { bool solver::has_large_domain(expr* array_term) {
SASSERT(a.is_array(array_term)); SASSERT(a.is_array(array_term));
sort* s = m.get_sort(array_term); sort* s = m.get_sort(array_term);
unsigned dim = get_array_arity(s); unsigned dim = get_array_arity(s);
@ -429,7 +425,6 @@ namespace array {
return false; return false;
} }
std::pair<app*, func_decl*> solver::mk_epsilon(sort* s) { std::pair<app*, func_decl*> solver::mk_epsilon(sort* s) {
app* eps = nullptr; app* eps = nullptr;
func_decl* diag = nullptr; func_decl* diag = nullptr;
@ -444,24 +439,16 @@ namespace array {
return std::make_pair(eps, diag); return std::make_pair(eps, diag);
} }
void solver::push_parent_select_store_axioms(theory_var v) {
expr* e = var2expr(v);
if (!a.is_array(e))
return;
auto& d = get_var_data(v);
for (euf::enode* store : d.m_parents)
if (a.is_store(store->get_expr()))
for (euf::enode* sel : d.m_parents)
if (a.is_select(sel->get_expr()))
push_axiom(select_axiom(sel, store));
}
bool solver::add_delayed_axioms() { bool solver::add_delayed_axioms() {
if (!get_config().m_array_delay_exp_axiom) if (!get_config().m_array_delay_exp_axiom)
return false; return false;
unsigned num_vars = get_num_vars(); unsigned num_vars = get_num_vars();
for (unsigned v = 0; v < num_vars; v++) for (unsigned v = 0; v < num_vars; v++) {
push_parent_select_store_axioms(v); propagate_parent_select_axioms(v);
auto& d = get_var_data(v);
if (d.m_prop_upward)
propagate_parent_default(v);
}
return unit_propagate(); return unit_propagate();
} }
@ -471,13 +458,15 @@ namespace array {
bool prop = false; bool prop = false;
for (unsigned i = roots.size(); i-- > 0; ) { for (unsigned i = roots.size(); i-- > 0; ) {
theory_var v1 = roots[i]; theory_var v1 = roots[i];
euf::enode* n1 = var2enode(v1); expr* e1 = var2expr(v1);
for (unsigned j = i; j-- > 0; ) { for (unsigned j = i; j-- > 0; ) {
theory_var v2 = roots[j]; theory_var v2 = roots[j];
euf::enode* n2 = var2enode(v2); expr* e2 = var2expr(v2);
if (m.get_sort(n1->get_expr()) != m.get_sort(n2->get_expr())) if (m.get_sort(e1) != m.get_sort(e2))
continue; continue;
expr_ref eq(m.mk_eq(n1->get_expr(), n2->get_expr()), m); if (have_different_model_values(v1, v2))
continue;
expr_ref eq(m.mk_eq(e1, e2), m);
sat::literal lit = b_internalize(eq); sat::literal lit = b_internalize(eq);
if (s().value(lit) == l_undef) if (s().value(lit) == l_undef)
prop = true; prop = true;
@ -498,15 +487,10 @@ namespace array {
if (r->is_marked1()) { if (r->is_marked1()) {
continue; continue;
} }
// arrays used as indices in other arrays have to be treated as shared. // arrays used as indices in other arrays have to be treated as shared issue #3532, #3529
// issue #3532, #3529 if (ctx.is_shared(r) || is_select_arg(r))
// roots.push_back(r->get_th_var(get_id()));
if (ctx.is_shared(r) || is_select_arg(r)) {
TRACE("array", tout << "new shared var: #" << r->get_expr_id() << "\n";);
theory_var r_th_var = r->get_th_var(get_id());
SASSERT(r_th_var != euf::null_theory_var);
roots.push_back(r_th_var);
}
r->mark1(); r->mark1();
to_unmark.push_back(r); to_unmark.push_back(r);
} }
@ -516,6 +500,7 @@ namespace array {
} }
bool solver::is_select_arg(euf::enode* r) { bool solver::is_select_arg(euf::enode* r) {
SASSERT(r->is_root());
for (euf::enode* n : euf::enode_parents(r)) for (euf::enode* n : euf::enode_parents(r))
if (a.is_select(n->get_expr())) if (a.is_select(n->get_expr()))
for (unsigned i = 1; i < n->num_args(); ++i) for (unsigned i = 1; i < n->num_args(); ++i)

View file

@ -20,13 +20,15 @@ Author:
namespace array { namespace array {
sat::literal solver::internalize(expr* e, bool sign, bool root, bool learned) { sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) {
// TODO SASSERT(m.is_bool(e));
if (!visit_rec(m, e, sign, root, redundant))
return sat::null_literal; return sat::null_literal;
return expr2literal(e);
} }
void solver::internalize(expr* e, bool redundant) { void solver::internalize(expr* e, bool redundant) {
// TODO visit_rec(m, e, false, false, redundant);
} }
euf::theory_var solver::mk_var(euf::enode* n) { euf::theory_var solver::mk_var(euf::enode* n) {
@ -39,8 +41,11 @@ namespace array {
void solver::ensure_var(euf::enode* n) { void solver::ensure_var(euf::enode* n) {
theory_var v = n->get_th_var(get_id()); theory_var v = n->get_th_var(get_id());
if (v == euf::null_theory_var) if (v == euf::null_theory_var) {
mk_var(n); mk_var(n);
if (is_lambda(n->get_expr()))
internalize_lambda(n);
}
} }
void solver::apply_sort_cnstr(euf::enode * n, sort * s) { void solver::apply_sort_cnstr(euf::enode * n, sort * s) {
@ -48,19 +53,30 @@ namespace array {
} }
void solver::internalize_store(euf::enode* n) { void solver::internalize_store(euf::enode* n) {
if (get_config().m_array_laziness == 0) add_parent_lambda(n->get_arg(0)->get_th_var(get_id()), n);
add_parent(n->get_arg(0), n);
push_axiom(store_axiom(n)); push_axiom(store_axiom(n));
add_lambda(n->get_th_var(get_id()), n);
SASSERT(!get_var_data(n->get_th_var(get_id())).m_prop_upward);
}
void solver::internalize_map(euf::enode* n) {
for (auto* arg : euf::enode_args(n)) {
add_parent_lambda(arg->get_th_var(get_id()), n);
set_prop_upward(arg);
}
push_axiom(default_axiom(n));
add_lambda(n->get_th_var(get_id()), n);
SASSERT(!get_var_data(n->get_th_var(get_id())).m_prop_upward);
}
void solver::internalize_lambda(euf::enode* n) {
set_prop_upward(n);
push_axiom(default_axiom(n));
add_lambda(n->get_th_var(get_id()), n);
} }
void solver::internalize_select(euf::enode* n) { void solver::internalize_select(euf::enode* n) {
if (get_config().m_array_laziness == 0) add_parent_select(n->get_arg(0)->get_th_var(get_id()), n);
add_parent(n->get_arg(0), n);
}
void solver::internalize_const(euf::enode* n) {
push_axiom(default_axiom(n));
set_prop_upward(n);
} }
void solver::internalize_ext(euf::enode* n) { void solver::internalize_ext(euf::enode* n) {
@ -68,24 +84,10 @@ namespace array {
} }
void solver::internalize_default(euf::enode* n) { void solver::internalize_default(euf::enode* n) {
add_parent(n->get_arg(0), n); add_parent_default(n->get_arg(0)->get_th_var(get_id()), n);
set_prop_upward(n); set_prop_upward(n);
} }
void solver::internalize_map(euf::enode* n) {
for (auto* arg : euf::enode_args(n)) {
add_parent(arg, n);
set_prop_upward(arg);
}
push_axiom(default_axiom(n));
}
void solver::internalize_as_array(euf::enode* n) {
// TBD: delay verdict whether model is undetermined
ctx.unhandled_function(n->get_decl());
push_axiom(default_axiom(n));
}
bool solver::visited(expr* e) { bool solver::visited(expr* e) {
euf::enode* n = expr2enode(e); euf::enode* n = expr2enode(e);
return n && n->is_attached_to(get_id()); return n && n->is_attached_to(get_id());
@ -94,7 +96,8 @@ namespace array {
bool solver::visit(expr* e) { bool solver::visit(expr* e) {
if (!is_app(e) || to_app(e)->get_family_id() != get_id()) { if (!is_app(e) || to_app(e)->get_family_id() != get_id()) {
ctx.internalize(e, m_is_redundant); ctx.internalize(e, m_is_redundant);
ensure_var(expr2enode(e)); euf::enode* n = expr2enode(e);
ensure_var(n);
return true; return true;
} }
m_stack.push_back(sat::eframe(e)); m_stack.push_back(sat::eframe(e));
@ -108,7 +111,7 @@ namespace array {
if (!n) if (!n)
n = mk_enode(e, false); n = mk_enode(e, false);
SASSERT(!n->is_attached_to(get_id())); SASSERT(!n->is_attached_to(get_id()));
theory_var v = mk_var(n); mk_var(n);
for (auto* arg : euf::enode_args(n)) for (auto* arg : euf::enode_args(n))
ensure_var(arg); ensure_var(arg);
switch (a->get_decl_kind()) { switch (a->get_decl_kind()) {
@ -118,8 +121,9 @@ namespace array {
case OP_SELECT: case OP_SELECT:
internalize_select(n); internalize_select(n);
break; break;
case OP_AS_ARRAY:
case OP_CONST_ARRAY: case OP_CONST_ARRAY:
internalize_const(n); internalize_lambda(n);
break; break;
case OP_ARRAY_EXT: case OP_ARRAY_EXT:
internalize_ext(n); internalize_ext(n);
@ -130,9 +134,6 @@ namespace array {
case OP_ARRAY_MAP: case OP_ARRAY_MAP:
internalize_map(n); internalize_map(n);
break; break;
case OP_AS_ARRAY:
internalize_as_array(n);
break;
case OP_SET_UNION: case OP_SET_UNION:
case OP_SET_INTERSECT: case OP_SET_INTERSECT:
case OP_SET_DIFFERENCE: case OP_SET_DIFFERENCE:

View file

@ -53,7 +53,7 @@ namespace array {
mdl.register_decl(f, fi); mdl.register_decl(f, fi);
for (euf::enode* p : euf::enode_parents(n)) { for (euf::enode* p : euf::enode_parents(n)) {
if (!a.is_select(p->get_expr())) if (!a.is_select(p->get_expr()) || p->get_arg(0)->get_root() != n->get_root())
continue; continue;
args.reset(); args.reset();
for (unsigned i = 1; i < p->num_args(); ++i) for (unsigned i = 1; i < p->num_args(); ++i)
@ -74,4 +74,73 @@ namespace array {
values.set(n->get_root_id(), m.mk_app(get_id(), OP_AS_ARRAY, 1, &p)); values.set(n->get_root_id(), m.mk_app(get_id(), OP_AS_ARRAY, 1, &p));
} }
bool solver::have_different_model_values(theory_var v1, theory_var v2) {
euf::enode* else1 = nullptr, * else2 = nullptr;
euf::enode* n1 = var2enode(v1), *n2 = var2enode(v2);
euf::enode* r1 = n1->get_root(), * r2 = n2->get_root();
expr* e1 = n1->get_expr();
expr* e;
if (!a.is_array(e1))
return true;
auto find_else = [&](theory_var v, euf::enode* r) {
var_data& d = get_var_data(find(v));
for (euf::enode* c : d.m_lambdas)
if (a.is_const(c->get_expr(), e))
return expr2enode(e)->get_root();
for (euf::enode* p : euf::enode_parents(r))
for (euf::enode* pe : euf::enode_class(p))
if (a.is_default(pe->get_expr()))
return pe->get_root();
return (euf::enode*)nullptr;
};
else1 = find_else(v1, r1);
else2 = find_else(v2, r2);
if (else1 && else2 && else1->get_root() != else2->get_root() && has_large_domain(e1))
return true;
struct eq {
solver& s;
eq(solver& s) :s(s) {}
bool operator()(euf::enode* n1, euf::enode* n2) const {
SASSERT(s.a.is_select(n1->get_expr()));
SASSERT(s.a.is_select(n2->get_expr()));
for (unsigned i = n1->num_args(); i-- > 1; )
if (n1->get_arg(i)->get_root() != n2->get_arg(i)->get_root())
return false;
return true;
}
};
struct hash {
solver& s;
hash(solver& s) :s(s) {}
unsigned operator()(euf::enode* n) const {
SASSERT(s.a.is_select(n->get_expr()));
unsigned h = 33;
for (unsigned i = n->num_args(); i-- > 1; )
h = hash_u_u(h, n->get_arg(i)->get_root_id());
return h;
}
};
eq eq_proc(*this);
hash hash_proc(*this);
hashtable<euf::enode*, hash, eq> table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, hash_proc, eq_proc);
euf::enode* p2 = nullptr;
auto maps_diff = [&](euf::enode* p, euf::enode* else_, euf::enode* r) {
return table.find(p, p2) ? p2->get_root() != r : (else_ && else_ != r);
};
auto table_diff = [&](euf::enode* r1, euf::enode* r2, euf::enode* else1) {
table.reset();
for (euf::enode* p : euf::enode_parents(r1))
if (a.is_select(p->get_expr()) && r1 == p->get_arg(0)->get_root())
table.insert(p);
for (euf::enode* p : euf::enode_parents(r2))
if (a.is_select(p->get_expr()) && r2 == p->get_arg(0)->get_root())
if (maps_diff(p, else1, p->get_root()))
return true;
return false;
};
return table_diff(r1, r2, else1) || table_diff(r2, r1, else2);
}
} }

View file

@ -13,6 +13,54 @@ Author:
Nikolaj Bjorner (nbjorner) 2020-09-08 Nikolaj Bjorner (nbjorner) 2020-09-08
Notes:
A node n has attribtes:
parent_selects: { A[i] | A ~ n }
parent_lambdas: { store(A,i,v) | A ~ n } u { map(f, .., A, ..) | A ~ n }
lambdas: { const(v) | const(v) ~ n }
u { map(f,..) | map(f,..) ~ n }
u { store(A,i,v) | store(A,i,v) ~ n }
u { as-array(f) | as-array(f) ~ n }
The attributes are used for propagation.
When n1 is merged with n2, and n1 is the new root, the attributes from n2 are added to n1.
The merge also looks for new redexes.
Let A[j] in parent_selects(n2) :
lambda in parent_lambdas(n1)
-------------------------------
lambda[j] = beta-reduce(lambda[j])
lambda in lambdas(n1)
-------------------------------
lambda[j] = beta-reduce(lambda[j])
Beta reduction rules are:
beta-reduce(store(A,j,v)[i]) = if(i = j, v, A[j])
beta-reduce(map(f,A,B)[i]) = f(A[i],B[i])
beta-reduce(as-array(f)[i]) = f(i)
beta-reduce(const(v)[i]) = v
beta-reduce((lambda x M[x])[i]) = M[i]
For enforcing
store(A,j,v)[i] = beta-reduce(store(A,j,v)[i])
only the following axiom is instantiated:
- i = j or store(A,j,v)[i] = A[i]
The other required axiom, store(A,j,v)[j] = v
is added eagerly whenever store(A,j,v) is created.
Current setup: to enforce extensionality on lambdas,
also currently, as a base-line it is eager:
A ~ B, A = lambda x. M[x]
-------------------------------
A = B => forall i . M[i] = B[i]
--*/ --*/
#include "ast/ast_ll_pp.h" #include "ast/ast_ll_pp.h"
@ -36,20 +84,16 @@ namespace array {
} }
sat::check_result solver::check() { sat::check_result solver::check() {
flet<bool> _is_redundant(m_is_redundant, true); // flet<bool> _is_redundant(m_is_redundant, true);
bool turn[2] = { false, false }; bool turn[2] = { false, false };
turn[s().rand()(2)] = true; turn[s().rand()(2)] = true;
for (unsigned idx = 0; idx < 2; ++idx) { for (unsigned idx = 0; idx < 2; ++idx) {
if (turn[idx]) { if (turn[idx] && add_delayed_axioms())
if (add_delayed_axioms()) return sat::check_result::CR_CONTINUE;
return sat::CR_CONTINUE; else if (!turn[idx] && add_interface_equalities())
return sat::check_result::CR_CONTINUE;
} }
else { return sat::check_result::CR_DONE;
if (add_interface_equalities())
return sat::CR_CONTINUE;
}
}
return sat::CR_DONE;
} }
void solver::push() { void solver::push() {
@ -65,10 +109,23 @@ namespace array {
std::ostream& solver::display(std::ostream& out) const { std::ostream& solver::display(std::ostream& out) const {
for (unsigned i = 0; i < get_num_vars(); ++i) { for (unsigned i = 0; i < get_num_vars(); ++i) {
auto& d = get_var_data(i);
out << var2enode(i)->get_expr_id() << " " << mk_bounded_pp(var2expr(i), m, 2) << "\n"; out << var2enode(i)->get_expr_id() << " " << mk_bounded_pp(var2expr(i), m, 2) << "\n";
display_info(out, "parent beta", d.m_parent_lambdas);
display_info(out, "parent select", d.m_parent_selects);
display_info(out, "beta ", d.m_lambdas);
} }
return out; return out;
} }
std::ostream& solver::display_info(std::ostream& out, char const* id, euf::enode_vector const& v) const {
if (v.empty())
return out;
out << id << ": ";
for (euf::enode* p : v)
out << mk_bounded_pp(p->get_expr(), m, 2) << " ";
out << "\n";
return out;
}
std::ostream& solver::display_justification(std::ostream& out, sat::ext_justification_idx idx) const { return out; } std::ostream& solver::display_justification(std::ostream& out, sat::ext_justification_idx idx) const { return out; }
std::ostream& solver::display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const { return out; } std::ostream& solver::display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const { return out; }
@ -79,6 +136,7 @@ namespace array {
st.update("array sel/const", m_stats.m_num_select_const_axiom); st.update("array sel/const", m_stats.m_num_select_const_axiom);
st.update("array sel/map", m_stats.m_num_select_map_axiom); st.update("array sel/map", m_stats.m_num_select_map_axiom);
st.update("array sel/as array", m_stats.m_num_select_as_array_axiom); st.update("array sel/as array", m_stats.m_num_select_as_array_axiom);
st.update("array sel/lambda", m_stats.m_num_select_lambda_axiom);
st.update("array def/map", m_stats.m_num_default_map_axiom); st.update("array def/map", m_stats.m_num_default_map_axiom);
st.update("array def/const", m_stats.m_num_default_const_axiom); st.update("array def/const", m_stats.m_num_default_const_axiom);
st.update("array def/store", m_stats.m_num_default_store_axiom); st.update("array def/store", m_stats.m_num_default_store_axiom);
@ -121,77 +179,98 @@ namespace array {
SASSERT(n1->get_root() == n2->get_root()); SASSERT(n1->get_root() == n2->get_root());
SASSERT(n1->is_root() || n2->is_root()); SASSERT(n1->is_root() || n2->is_root());
SASSERT(v1 == find(v1)); SASSERT(v1 == find(v1));
expr* e1 = n1->get_expr(); expr* e1 = n1->get_expr();
expr* e2 = n2->get_expr(); expr* e2 = n2->get_expr();
auto& d1 = get_var_data(v1); auto& d1 = get_var_data(v1);
auto& d2 = get_var_data(v2); auto& d2 = get_var_data(v2);
if (d2.m_prop_upward && !d1.m_prop_upward) if (d2.m_prop_upward && !d1.m_prop_upward)
set_prop_upward(v1); set_prop_upward(v1);
if (a.is_array(e1)) for (euf::enode* lambda : d2.m_lambdas)
for (euf::enode* parent : d2.m_parents) { add_lambda(v1, lambda);
add_parent(v1, parent); for (euf::enode* lambda : d2.m_parent_lambdas)
if (a.is_store(parent->get_expr())) add_parent_lambda(v1, lambda);
add_store(v1, parent); for (euf::enode* select : d2.m_parent_selects)
} add_parent_select(v1, select);
if (is_lambda(e1) || is_lambda(e2)) if (is_lambda(e1) || is_lambda(e2))
push_axiom(congruence_axiom(n1, n2)); push_axiom(congruence_axiom(n1, n2));
} }
void solver::unmerge_eh(theory_var v1, theory_var v2) { void solver::tracked_push(euf::enode_vector& v, euf::enode* n) {
auto& p1 = get_var_data(v1).m_parents; v.push_back(n);
auto& p2 = get_var_data(v2).m_parents; ctx.push(push_back_trail<euf::solver, euf::enode*, false>(v));
p1.shrink(p1.size() - p2.size());
} }
void solver::add_store(theory_var v, euf::enode* store) { void solver::add_parent_select(theory_var v_child, euf::enode* select) {
SASSERT(a.is_store(store->get_expr())); SASSERT(a.is_select(select->get_expr()));
auto& d = get_var_data(v); SASSERT(m.get_sort(select->get_arg(0)->get_expr()) == m.get_sort(var2expr(v_child)));
unsigned lambda_equiv_class_size = get_lambda_equiv_size(d);
if (get_config().m_array_always_prop_upward || lambda_equiv_class_size >= 1)
set_prop_upward(d);
for (euf::enode* n : d.m_parents)
if (a.is_select(n->get_expr()))
push_axiom(select_axiom(n, store));
if (get_config().m_array_always_prop_upward || lambda_equiv_class_size >= 1)
set_prop_upward(store);
}
void solver::add_parent(theory_var v_child, euf::enode* parent) { v_child = find(v_child);
SASSERT(parent->is_root()); tracked_push(get_var_data(v_child).m_parent_selects, select);
get_var_data(v_child).m_parents.push_back(parent);
euf::enode* child = var2enode(v_child); euf::enode* child = var2enode(v_child);
euf::enode* r = child->get_root(); if (can_beta_reduce(child))
expr* p = parent->get_expr(); push_axiom(select_axiom(select, child));
expr* c = child->get_expr();
if (a.is_select(p) && parent->get_arg(0)->get_root() == r) {
if (a.is_const(c) || a.is_as_array(c) || a.is_store(c) || is_lambda(c))
push_axiom(select_axiom(parent, child));
#if 0
if (!get_config().m_array_delay_exp_axiom && d.m_prop_upward) {
auto& d = get_var_data(v_child);
for (euf::enode* p2 : d.m_parents)
if (a.is_store(p2->get_expr()))
push_axiom(select_axiom(parent, p2));
} }
#endif
void solver::add_lambda(theory_var v, euf::enode* lambda) {
SASSERT(can_beta_reduce(lambda));
auto& d = get_var_data(find(v));
if (should_set_prop_upward(d))
set_prop_upward(d);
tracked_push(d.m_lambdas, lambda);
if (should_set_prop_upward(d)) {
set_prop_upward(lambda);
propagate_select_axioms(d, lambda);
} }
else if (a.mk_default(p)) {
if (a.is_const(c) || a.is_store(c) || a.is_map(c) || a.is_as_array(c))
push_axiom(default_axiom(child));
} }
void solver::add_parent_lambda(theory_var v_child, euf::enode* lambda) {
SASSERT(can_beta_reduce(lambda));
auto& d = get_var_data(find(v_child));
tracked_push(d.m_parent_lambdas, lambda);
if (should_set_prop_upward(d))
propagate_select_axioms(d, lambda);
}
void solver::add_parent_default(theory_var v, euf::enode* def) {
SASSERT(a.is_default(def->get_expr()));
auto& d = get_var_data(find(v));
for (euf::enode* lambda : d.m_lambdas)
push_axiom(default_axiom(lambda));
if (should_prop_upward(d))
propagate_parent_default(v);
}
void solver::propagate_select_axioms(var_data const& d, euf::enode* lambda) {
for (euf::enode* select : d.m_parent_selects)
push_axiom(select_axiom(select, lambda));
}
void solver::propagate_parent_default(theory_var v) {
auto& d = get_var_data(find(v));
for (euf::enode* lambda : d.m_parent_lambdas)
push_axiom(default_axiom(lambda));
}
void solver::propagate_parent_select_axioms(theory_var v) {
v = find(v);
expr* e = var2expr(v);
if (!a.is_array(e))
return;
auto& d = get_var_data(v);
for (euf::enode* lambda : d.m_parent_lambdas)
propagate_select_axioms(d, lambda);
} }
void solver::set_prop_upward(theory_var v) { void solver::set_prop_upward(theory_var v) {
auto& d = get_var_data(find(v)); auto& d = get_var_data(find(v));
if (!d.m_prop_upward) { if (d.m_prop_upward)
return;
ctx.push(reset_flag_trail<euf::solver>(d.m_prop_upward)); ctx.push(reset_flag_trail<euf::solver>(d.m_prop_upward));
d.m_prop_upward = true; d.m_prop_upward = true;
if (!get_config().m_array_delay_exp_axiom) if (should_prop_upward(d))
push_parent_select_store_axioms(v); propagate_parent_select_axioms(v);
set_prop_upward(d); set_prop_upward(d);
} }
}
void solver::set_prop_upward(euf::enode* n) { void solver::set_prop_upward(euf::enode* n) {
if (a.is_store(n->get_expr())) if (a.is_store(n->get_expr()))
@ -199,7 +278,7 @@ namespace array {
} }
void solver::set_prop_upward(var_data& d) { void solver::set_prop_upward(var_data& d) {
for (auto* p : d.m_parents) for (auto* p : d.m_lambdas)
set_prop_upward(p); set_prop_upward(p);
} }
@ -207,14 +286,20 @@ namespace array {
\brief Return the size of the equivalence class for array terms \brief Return the size of the equivalence class for array terms
that can be expressed as \lambda i : Index . [.. (select a i) ..] that can be expressed as \lambda i : Index . [.. (select a i) ..]
*/ */
unsigned solver::get_lambda_equiv_size(var_data const& d) { unsigned solver::get_lambda_equiv_size(var_data const& d) const {
unsigned sz = 0; return d.m_parent_selects.size() + 2 * d.m_lambdas.size();
for (auto* p : d.m_parents)
if (a.is_store(p->get_expr()))
++sz;
return sz;
} }
bool solver::should_set_prop_upward(var_data const& d) const {
return get_config().m_array_always_prop_upward || get_lambda_equiv_size(d) >= 1;
}
bool solver::should_prop_upward(var_data const& d) const {
return !get_config().m_array_delay_exp_axiom && d.m_prop_upward;
}
bool solver::can_beta_reduce(euf::enode* n) const {
expr* c = n->get_expr();
return a.is_const(c) || a.is_as_array(c) || a.is_store(c) || is_lambda(c);
}
} }

View file

@ -42,6 +42,7 @@ namespace array {
unsigned m_num_select_const_axiom, m_num_select_store_axiom_delayed; unsigned m_num_select_const_axiom, m_num_select_store_axiom_delayed;
unsigned m_num_default_store_axiom, m_num_default_map_axiom; unsigned m_num_default_store_axiom, m_num_default_map_axiom;
unsigned m_num_default_const_axiom, m_num_default_as_array_axiom; unsigned m_num_default_const_axiom, m_num_default_as_array_axiom;
unsigned m_num_select_lambda_axiom;
void reset() { memset(this, 0, sizeof(*this)); } void reset() { memset(this, 0, sizeof(*this)); }
stats() { reset(); } stats() { reset(); }
}; };
@ -50,9 +51,9 @@ namespace array {
struct var_data { struct var_data {
bool m_prop_upward{ false }; bool m_prop_upward{ false };
bool m_is_array{ false }; euf::enode_vector m_lambdas; // equivalent nodes that have beta reduction properties
bool m_is_select{ false }; euf::enode_vector m_parent_lambdas; // parents that have beta reduction properties
ptr_vector<euf::enode> m_parents; euf::enode_vector m_parent_selects; // parents that use array in select position
var_data() {} var_data() {}
}; };
@ -76,11 +77,10 @@ namespace array {
void ensure_var(euf::enode* n); void ensure_var(euf::enode* n);
void internalize_store(euf::enode* n); void internalize_store(euf::enode* n);
void internalize_select(euf::enode* n); void internalize_select(euf::enode* n);
void internalize_const(euf::enode* n); void internalize_lambda(euf::enode* n);
void internalize_ext(euf::enode* n); void internalize_ext(euf::enode* n);
void internalize_default(euf::enode* n); void internalize_default(euf::enode* n);
void internalize_map(euf::enode* n); void internalize_map(euf::enode* n);
void internalize_as_array(euf::enode* n);
// axioms // axioms
struct axiom_record { struct axiom_record {
@ -144,33 +144,44 @@ namespace array {
bool assert_default_map_axiom(app* map); bool assert_default_map_axiom(app* map);
bool assert_default_const_axiom(app* cnst); bool assert_default_const_axiom(app* cnst);
bool assert_default_store_axiom(app* store); bool assert_default_store_axiom(app* store);
bool assert_default_as_array_axiom(app* as_array);
bool assert_congruent_axiom(expr* e1, expr* e2); bool assert_congruent_axiom(expr* e1, expr* e2);
bool add_delayed_axioms(); bool add_delayed_axioms();
bool has_unitary_domain(app* array_term); bool has_unitary_domain(app* array_term);
bool has_large_domain(app* array_term); bool has_large_domain(expr* array_term);
std::pair<app*, func_decl*> mk_epsilon(sort* s); std::pair<app*, func_decl*> mk_epsilon(sort* s);
void collect_shared_vars(sbuffer<theory_var>& roots); void collect_shared_vars(sbuffer<theory_var>& roots);
bool add_interface_equalities(); bool add_interface_equalities();
bool is_select_arg(euf::enode* r); bool is_select_arg(euf::enode* r);
// solving // solving
void add_parent(theory_var v_child, euf::enode* parent); void add_parent_select(theory_var v_child, euf::enode* select);
void add_parent(euf::enode* child, euf::enode* parent) { add_parent(child->get_th_var(get_id()), parent); } void add_parent_default(theory_var v_child, euf::enode* def);
void add_store(theory_var v, euf::enode* store); void add_lambda(theory_var v, euf::enode* lambda);
void add_parent_lambda(theory_var v_child, euf::enode* lambda);
void propagate_select_axioms(var_data const& d, euf::enode* a);
void propagate_parent_select_axioms(theory_var v);
void propagate_parent_default(theory_var v);
void set_prop_upward(theory_var v); void set_prop_upward(theory_var v);
void set_prop_upward(var_data& d); void set_prop_upward(var_data& d);
void set_prop_upward(euf::enode* n); void set_prop_upward(euf::enode* n);
void push_parent_select_store_axioms(theory_var v); unsigned get_lambda_equiv_size(var_data const& d) const;
unsigned get_lambda_equiv_size(var_data const& d); bool should_set_prop_upward(var_data const& d) const;
bool should_prop_upward(var_data const& d) const;
bool can_beta_reduce(euf::enode* n) const;
var_data& get_var_data(euf::enode* n) { return get_var_data(n->get_th_var(get_id())); } var_data& get_var_data(euf::enode* n) { return get_var_data(n->get_th_var(get_id())); }
var_data& get_var_data(theory_var v) { return *m_var_data[v]; } var_data& get_var_data(theory_var v) { return *m_var_data[v]; }
var_data const& get_var_data(theory_var v) const { return *m_var_data[v]; }
// models
bool have_different_model_values(theory_var v1, theory_var v2);
// invariants // diagnostics
std::ostream& display_info(std::ostream& out, char const* id, euf::enode_vector const& v) const;
public: public:
solver(euf::solver& ctx, theory_id id); solver(euf::solver& ctx, theory_id id);
~solver() override {} ~solver() override {}
@ -196,8 +207,10 @@ namespace array {
euf::theory_var mk_var(euf::enode* n) override; euf::theory_var mk_var(euf::enode* n) override;
void apply_sort_cnstr(euf::enode* n, sort* s) override; void apply_sort_cnstr(euf::enode* n, sort* s) override;
void tracked_push(euf::enode_vector& v, euf::enode* n);
void merge_eh(theory_var, theory_var, theory_var v1, theory_var v2); void merge_eh(theory_var, theory_var, theory_var v1, theory_var v2);
void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) {} void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) {}
void unmerge_eh(theory_var v1, theory_var v2); void unmerge_eh(theory_var v1, theory_var v2) {}
}; };
} }

290
src/sat/smt/ba_card.cpp Normal file
View file

@ -0,0 +1,290 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
ba_card.cpp
Abstract:
Interface for Cardinality constraints.
Author:
Nikolaj Bjorner (nbjorner) 2017-01-30
--*/
#include "sat/smt/ba_card.h"
#include "sat/smt/ba_solver.h"
#include "sat/sat_simplifier.h"
namespace ba {
// -----------------------
// pb_base
bool pb_base::well_formed() const {
uint_set vars;
if (lit() != sat::null_literal) vars.insert(lit().var());
for (unsigned i = 0; i < size(); ++i) {
bool_var v = get_lit(i).var();
if (vars.contains(v)) return false;
if (get_coeff(i) > k()) return false;
vars.insert(v);
}
return true;
}
// ----------------------
// card
card::card(unsigned id, literal lit, literal_vector const& lits, unsigned k) :
pb_base(tag_t::card_t, id, lit, lits.size(), get_obj_size(lits.size()), k) {
for (unsigned i = 0; i < size(); ++i) {
m_lits[i] = lits[i];
}
}
void card::negate() {
m_lit.neg();
for (unsigned i = 0; i < m_size; ++i) {
m_lits[i].neg();
}
m_k = m_size - m_k + 1;
SASSERT(m_size >= m_k && m_k > 0);
}
bool card::is_watching(literal l) const {
unsigned sz = std::min(k() + 1, size());
for (unsigned i = 0; i < sz; ++i) {
if ((*this)[i] == l) return true;
}
return false;
}
double card::get_reward(ba::solver_interface const& s, sat::literal_occs_fun& literal_occs) const {
unsigned k = this->k(), slack = 0;
bool do_add = s.get_config().m_lookahead_reward == sat::heule_schur_reward;
double to_add = do_add ? 0 : 1;
for (literal l : *this) {
switch (s.value(l)) {
case l_true: --k; if (k == 0) return 0;
case l_undef:
if (do_add) to_add += literal_occs(l);
++slack; break;
case l_false: break;
}
}
if (k >= slack) return 1;
return pow(0.5, slack - k + 1) * to_add;
}
std::ostream& card::display(std::ostream& out) const {
for (literal l : *this)
out << l << " ";
return out << " >= " << k();
}
void constraint::display_lit(std::ostream& out, solver_interface const& s, literal lit, unsigned sz, bool values) const {
if (lit != sat::null_literal) {
if (values) {
out << lit << "[" << sz << "]";
out << "@(" << s.value(lit);
if (s.value(lit) != l_undef) {
out << ":" << s.lvl(lit);
}
out << "): ";
}
else {
out << lit << " == ";
}
}
}
std::ostream& card::display(std::ostream& out, solver_interface const& s, bool values) const {
auto const& c = *this;
display_lit(out, s, c.lit(), c.size(), values);
for (unsigned i = 0; i < c.size(); ++i) {
literal l = c[i];
out << l;
if (values) {
out << "@(" << s.value(l);
if (s.value(l) != l_undef) {
out << ":" << s.lvl(l);
}
out << ") ";
}
else {
out << " ";
}
}
return out << ">= " << c.k() << "\n";
}
void card::clear_watch(solver_interface& s) {
if (is_clear()) return;
reset_watch();
unsigned sz = std::min(k() + 1, size());
for (unsigned i = 0; i < sz; ++i)
unwatch_literal(s, (*this)[i]);
}
bool card::init_watch(solver_interface& s) {
auto& c = *this;
literal root = c.lit();
if (root != sat::null_literal && s.value(root) == l_false) {
clear_watch(s);
negate();
root.neg();
}
if (root != sat::null_literal) {
if (!is_watched(s, root)) watch_literal(s, root);
if (!is_pure() && !is_watched(s, ~root)) watch_literal(s, ~root);
}
TRACE("ba", display(tout << "init watch: ", s, true););
SASSERT(root == sat::null_literal || s.value(root) == l_true);
unsigned j = 0, sz = c.size(), bound = c.k();
// put the non-false literals into the head.
if (bound == sz) {
for (literal l : c) s.assign(c, l);
return false;
}
for (unsigned i = 0; i < sz; ++i) {
if (s.value(c[i]) != l_false) {
if (j != i) {
if (c.is_watched() && j <= bound && i > bound) {
c.unwatch_literal(s, c[j]);
c.watch_literal(s, c[i]);
}
c.swap(i, j);
}
++j;
}
}
DEBUG_CODE(
bool is_false = false;
for (literal l : c) {
SASSERT(!is_false || s.value(l) == l_false);
is_false = s.value(l) == l_false;
});
// j is the number of non-false, sz - j the number of false.
if (j < bound) {
if (is_watched()) clear_watch(s);
SASSERT(0 < bound && bound < sz);
literal alit = c[j];
//
// we need the assignment level of the asserting literal to be maximal.
// such that conflict resolution can use the asserting literal as a starting
// point.
//
for (unsigned i = bound; i < sz; ++i) {
if (s.lvl(alit) < s.lvl(c[i])) {
c.swap(i, j);
alit = c[j];
}
}
s.set_conflict(c, alit);
return false;
}
else if (j == bound) {
for (unsigned i = 0; i < bound; ++i) {
s.assign(c, c[i]);
}
return false;
}
else {
if (c.is_watched()) return true;
clear_watch(s);
for (unsigned i = 0; i <= bound; ++i) {
c.watch_literal(s, c[i]);
}
c.set_watch();
return true;
}
}
card& constraint::to_card() {
SASSERT(is_card());
return static_cast<card&>(*this);
}
card const& constraint::to_card() const {
SASSERT(is_card());
return static_cast<card const&>(*this);
}
bool card::is_extended_binary(literal_vector& r) const {
auto const& ca = *this;
if (ca.size() == ca.k() + 1 && ca.lit() == sat::null_literal) {
r.reset();
for (literal l : ca) r.push_back(l);
return true;
}
else {
return false;
}
}
bool card::validate_unit_propagation(solver_interface const& s, literal alit) const {
(void) alit;
if (lit() != sat::null_literal && s.value(lit()) != l_true)
return false;
for (unsigned i = k(); i < size(); ++i)
if (s.value((*this)[i]) != l_false)
return false;
return true;
}
lbool card::eval(solver_interface const& s) const {
unsigned trues = 0, undefs = 0;
for (literal l : *this) {
switch (s.value(l)) {
case l_true: trues++; break;
case l_undef: undefs++; break;
default: break;
}
}
if (trues + undefs < k()) return l_false;
if (trues >= k()) return l_true;
return l_undef;
}
lbool card::eval(sat::model const& m) const {
unsigned trues = 0, undefs = 0;
for (literal l : *this) {
switch (ba::value(m, l)) {
case l_true: trues++; break;
case l_undef: undefs++; break;
default: break;
}
}
if (trues + undefs < k()) return l_false;
if (trues >= k()) return l_true;
return l_undef;
}
void card::init_use_list(sat::ext_use_list& ul) const {
auto idx = cindex();
for (auto l : *this)
ul.insert(l, idx);
}
bool card::is_blocked(sat::simplifier& sim, literal lit) const {
unsigned weight = 0;
for (literal l2 : *this)
if (sim.is_marked(~l2)) ++weight;
return weight >= k();
}
}

70
src/sat/smt/ba_card.h Normal file
View file

@ -0,0 +1,70 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
ba_card.h
Abstract:
Interface for Cardinality constraints.
Author:
Nikolaj Bjorner (nbjorner) 2017-01-30
--*/
#pragma once
#include "sat/sat_types.h"
#include "sat/smt/ba_constraint.h"
namespace ba {
// base class for pb and cardinality constraints
class pb_base : public constraint {
protected:
unsigned m_k;
public:
pb_base(ba::tag_t t, unsigned id, literal l, unsigned sz, size_t osz, unsigned k) :
constraint(t, id, l, sz, osz), m_k(k) {
VERIFY(k < 4000000000);
}
virtual void set_k(unsigned k) { VERIFY(k < 4000000000); m_k = k; }
virtual unsigned get_coeff(unsigned i) const { UNREACHABLE(); return 0; }
unsigned k() const { return m_k; }
bool well_formed() const override;
};
class card : public pb_base {
literal m_lits[0];
public:
static size_t get_obj_size(unsigned num_lits) { return sat::constraint_base::obj_size(sizeof(card) + num_lits * sizeof(literal)); }
card(unsigned id, literal lit, literal_vector const& lits, unsigned k);
literal operator[](unsigned i) const { return m_lits[i]; }
literal& operator[](unsigned i) { return m_lits[i]; }
literal const* begin() const { return m_lits; }
literal const* end() const { return static_cast<literal const*>(m_lits) + m_size; }
void negate() override;
void swap(unsigned i, unsigned j) override { std::swap(m_lits[i], m_lits[j]); }
literal_vector literals() const override { return literal_vector(m_size, m_lits); }
bool is_watching(literal l) const override;
literal get_lit(unsigned i) const override { return m_lits[i]; }
void set_lit(unsigned i, literal l) override { m_lits[i] = l; }
unsigned get_coeff(unsigned i) const override { return 1; }
double get_reward(ba::solver_interface const& s, sat::literal_occs_fun& occs) const override;
std::ostream& display(std::ostream& out) const override;
std::ostream& display(std::ostream& out, solver_interface const& s, bool values) const override;
void clear_watch(solver_interface& s) override;
bool init_watch(solver_interface& s) override;
bool is_extended_binary(literal_vector& r) const override;
bool validate_unit_propagation(solver_interface const& s, literal alit) const override;
lbool eval(sat::model const& m) const override;
lbool eval(solver_interface const& s) const override;
void init_use_list(sat::ext_use_list& ul) const override;
bool is_blocked(sat::simplifier& s, literal lit) const override;
};
}

View file

@ -0,0 +1,58 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
ba_constraint.cpp
Abstract:
Interface for constraints.
Author:
Nikolaj Bjorner (nbjorner) 2017-01-30
--*/
#include "sat/smt/ba_constraint.h"
namespace ba {
unsigned constraint::fold_max_var(unsigned w) const {
if (lit() != sat::null_literal) w = std::max(w, lit().var());
for (unsigned i = 0; i < size(); ++i) w = std::max(w, get_lit(i).var());
return w;
}
std::ostream& operator<<(std::ostream& out, constraint const& cnstr) {
if (cnstr.lit() != sat::null_literal) out << cnstr.lit() << " == ";
return cnstr.display(out);
}
bool constraint::is_watched(solver_interface const& s, literal lit) const {
return s.get_wlist(~lit).contains(sat::watched(cindex()));
}
void constraint::unwatch_literal(solver_interface& s, literal lit) {
sat::watched w(cindex());
s.get_wlist(~lit).erase(w);
SASSERT(!is_watched(s, lit));
}
void constraint::watch_literal(solver_interface& s, literal lit) {
if (is_pure() && lit == ~this->lit()) return;
SASSERT(!is_watched(s, lit));
sat::watched w(cindex());
s.get_wlist(~lit).push_back(w);
}
void constraint::nullify_tracking_literal(solver_interface& s) {
if (lit() != sat::null_literal) {
unwatch_literal(s, lit());
unwatch_literal(s, ~lit());
nullify_literal();
}
}
}

143
src/sat/smt/ba_constraint.h Normal file
View file

@ -0,0 +1,143 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
ba_constraint.h
Abstract:
Interface for Boolean constraints.
Author:
Nikolaj Bjorner (nbjorner) 2017-01-30
Revision History:
--*/
#pragma once
#include "sat/smt/ba_solver_interface.h"
namespace ba {
enum class tag_t {
card_t,
pb_t,
xr_t
};
class card;
class pb;
class xr;
class pb_base;
inline lbool value(sat::model const& m, literal l) { return l.sign() ? ~m[l.var()] : m[l.var()]; }
class constraint {
protected:
tag_t m_tag;
bool m_removed;
literal m_lit;
literal m_watch;
unsigned m_glue;
unsigned m_psm;
unsigned m_size;
size_t m_obj_size;
bool m_learned;
unsigned m_id;
bool m_pure; // is the constraint pure (only positive occurrences)
void display_lit(std::ostream& out, solver_interface const& s, literal lit, unsigned sz, bool values) const;
public:
constraint(tag_t t, unsigned id, literal l, unsigned sz, size_t osz):
m_tag(t), m_removed(false), m_lit(l), m_watch(sat::null_literal), m_glue(0), m_psm(0), m_size(sz), m_obj_size(osz), m_learned(false), m_id(id), m_pure(false) {
}
sat::ext_constraint_idx cindex() const { return sat::constraint_base::mem2base(this); }
void deallocate(small_object_allocator& a) { a.deallocate(obj_size(), sat::constraint_base::mem2base_ptr(this)); }
unsigned id() const { return m_id; }
tag_t tag() const { return m_tag; }
literal lit() const { return m_lit; }
unsigned size() const { return m_size; }
void set_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; }
void update_literal(literal l) { m_lit = l; }
bool was_removed() const { return m_removed; }
void set_removed() { m_removed = true; }
void nullify_literal() { m_lit = sat::null_literal; }
unsigned glue() const { return m_glue; }
void set_glue(unsigned g) { m_glue = g; }
unsigned psm() const { return m_psm; }
void set_psm(unsigned p) { m_psm = p; }
void set_learned(bool f) { m_learned = f; }
bool learned() const { return m_learned; }
bool is_watched() const { return m_watch == m_lit && m_lit != sat::null_literal; }
void set_watch() { m_watch = m_lit; }
void reset_watch() { m_watch = sat::null_literal; }
bool is_clear() const { return m_watch == sat::null_literal && m_lit != sat::null_literal; }
bool is_pure() const { return m_pure; }
void set_pure() { m_pure = true; }
unsigned fold_max_var(unsigned w) const;
size_t obj_size() const { return m_obj_size; }
card& to_card();
pb& to_pb();
xr& to_xr();
card const& to_card() const;
pb const& to_pb() const;
xr const& to_xr() const;
pb_base const& to_pb_base() const;
bool is_card() const { return m_tag == tag_t::card_t; }
bool is_pb() const { return m_tag == tag_t::pb_t; }
bool is_xr() const { return m_tag == tag_t::xr_t; }
bool is_watched(solver_interface const& s, literal lit) const;
void unwatch_literal(solver_interface& s, literal lit);
void nullify_tracking_literal(solver_interface& s);
void watch_literal(solver_interface& s, literal lit);
virtual void clear_watch(solver_interface& s) = 0;
virtual bool init_watch(solver_interface& s) = 0;
virtual lbool eval(sat::model const& m) const = 0;
virtual lbool eval(solver_interface const& s) const = 0;
virtual bool is_blocked(sat::simplifier& s, literal lit) const = 0;
virtual bool validate_unit_propagation(solver_interface const& s, literal alit) const = 0;
virtual bool is_watching(literal l) const { UNREACHABLE(); return false; };
virtual literal_vector literals() const { UNREACHABLE(); return literal_vector(); }
virtual void swap(unsigned i, unsigned j) { UNREACHABLE(); }
virtual literal get_lit(unsigned i) const { UNREACHABLE(); return sat::null_literal; }
virtual void set_lit(unsigned i, literal l) { UNREACHABLE(); }
virtual bool well_formed() const { return true; }
virtual void negate() { UNREACHABLE(); }
virtual bool is_extended_binary(literal_vector& r) const { return false; }
virtual double get_reward(solver_interface const& s, sat::literal_occs_fun& occs) const { return 0; }
virtual std::ostream& display(std::ostream& out) const = 0;
virtual std::ostream& display(std::ostream& out, solver_interface const& s, bool values) const = 0;
virtual void init_use_list(sat::ext_use_list& ul) const = 0;
class iterator {
constraint const& c;
unsigned idx;
public:
iterator(constraint const& c, unsigned idx) : c(c), idx(idx) {}
literal operator*() { return c.get_lit(idx); }
iterator& operator++() { ++idx; return *this; }
bool operator==(iterator const& other) const { SASSERT(&c == &other.c); return idx == other.idx; }
bool operator!=(iterator const& other) const { SASSERT(&c == &other.c); return idx != other.idx; }
};
class literal_iterator {
constraint const& c;
public:
literal_iterator(constraint const& c):c(c) {}
iterator begin() const { return iterator(c, 0); }
iterator end() const { return iterator(c, c.size()); }
};
};
std::ostream& operator<<(std::ostream& out, constraint const& c);
}

View file

@ -284,7 +284,7 @@ namespace sat {
} }
} }
expr_ref ba_solver::get_card(std::function<expr_ref(sat::literal)>& lit2expr, ba_solver::card const& c) { expr_ref ba_solver::get_card(std::function<expr_ref(sat::literal)>& lit2expr, ba::card const& c) {
ptr_buffer<expr> lits; ptr_buffer<expr> lits;
for (sat::literal l : c) { for (sat::literal l : c) {
lits.push_back(lit2expr(l)); lits.push_back(lit2expr(l));
@ -297,7 +297,7 @@ namespace sat {
return fml; return fml;
} }
expr_ref ba_solver::get_pb(std::function<expr_ref(sat::literal)>& lit2expr, ba_solver::pb const& p) { expr_ref ba_solver::get_pb(std::function<expr_ref(sat::literal)>& lit2expr, pb const& p) {
ptr_buffer<expr> lits; ptr_buffer<expr> lits;
vector<rational> coeffs; vector<rational> coeffs;
for (auto const& wl : p) { for (auto const& wl : p) {
@ -313,7 +313,7 @@ namespace sat {
return fml; return fml;
} }
expr_ref ba_solver::get_xor(std::function<expr_ref(sat::literal)>& lit2expr, ba_solver::xr const& x) { expr_ref ba_solver::get_xor(std::function<expr_ref(sat::literal)>& lit2expr, xr const& x) {
ptr_buffer<expr> lits; ptr_buffer<expr> lits;
for (sat::literal l : x) { for (sat::literal l : x) {
lits.push_back(lit2expr(l)); lits.push_back(lit2expr(l));
@ -329,13 +329,13 @@ namespace sat {
bool ba_solver::to_formulas(std::function<expr_ref(sat::literal)>& l2e, expr_ref_vector& fmls) { bool ba_solver::to_formulas(std::function<expr_ref(sat::literal)>& l2e, expr_ref_vector& fmls) {
for (auto* c : constraints()) { for (auto* c : constraints()) {
switch (c->tag()) { switch (c->tag()) {
case ba_solver::card_t: case ba::tag_t::card_t:
fmls.push_back(get_card(l2e, c->to_card())); fmls.push_back(get_card(l2e, c->to_card()));
break; break;
case ba_solver::pb_t: case ba::tag_t::pb_t:
fmls.push_back(get_pb(l2e, c->to_pb())); fmls.push_back(get_pb(l2e, c->to_pb()));
break; break;
case ba_solver::xr_t: case ba::tag_t::xr_t:
fmls.push_back(get_xor(l2e, c->to_xr())); fmls.push_back(get_xor(l2e, c->to_xr()));
break; break;
} }

308
src/sat/smt/ba_pb.cpp Normal file
View file

@ -0,0 +1,308 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
ba_pb.cpp
Abstract:
Interface for PB constraints.
Author:
Nikolaj Bjorner (nbjorner) 2017-01-30
--*/
#include "sat/smt/ba_pb.h"
namespace ba {
pb& constraint::to_pb() {
SASSERT(is_pb());
return static_cast<pb&>(*this);
}
pb const& constraint::to_pb() const {
SASSERT(is_pb());
return static_cast<pb const&>(*this);
}
pb_base const& constraint::to_pb_base() const {
SASSERT(is_pb() || is_card());
return static_cast<pb_base const&>(*this);
}
// -----------------------------------
// pb
pb::pb(unsigned id, literal lit, svector<wliteral> const& wlits, unsigned k) :
pb_base(tag_t::pb_t, id, lit, wlits.size(), get_obj_size(wlits.size()), k),
m_slack(0),
m_num_watch(0),
m_max_sum(0) {
for (unsigned i = 0; i < size(); ++i) {
m_wlits[i] = wlits[i];
}
update_max_sum();
}
void pb::update_max_sum() {
m_max_sum = 0;
for (unsigned i = 0; i < size(); ++i) {
m_wlits[i].first = std::min(k(), m_wlits[i].first);
if (m_max_sum + m_wlits[i].first < m_max_sum) {
throw default_exception("addition of pb coefficients overflows");
}
m_max_sum += m_wlits[i].first;
}
}
void pb::negate() {
m_lit.neg();
unsigned w = 0;
for (unsigned i = 0; i < m_size; ++i) {
m_wlits[i].second.neg();
VERIFY(w + m_wlits[i].first >= w);
w += m_wlits[i].first;
}
m_k = w - m_k + 1;
VERIFY(w >= m_k && m_k > 0);
}
bool pb::is_watching(literal l) const {
for (unsigned i = 0; i < m_num_watch; ++i) {
if ((*this)[i].second == l) return true;
}
return false;
}
bool pb::is_cardinality() const {
if (size() == 0) return false;
unsigned w = (*this)[0].first;
for (wliteral wl : *this) if (w != wl.first) return false;
return true;
}
double pb::get_reward(ba::solver_interface const& s, sat::literal_occs_fun& occs) const {
unsigned k = this->k(), slack = 0;
bool do_add = s.get_config().m_lookahead_reward == sat::heule_schur_reward;
double to_add = do_add ? 0 : 1;
double undefs = 0;
for (wliteral wl : *this) {
literal l = wl.second;
unsigned w = wl.first;
switch (s.value(l)) {
case l_true: if (k <= w) return 0;
case l_undef:
if (do_add) to_add += occs(l);
++undefs;
slack += w;
break; // TBD multiplier factor on this
case l_false: break;
}
}
if (k >= slack || 0 == undefs) return 0;
double avg = slack / undefs;
return pow(0.5, (slack - k + 1) / avg) * to_add;
}
void pb::clear_watch(solver_interface& s) {
reset_watch();
for (unsigned i = 0; i < num_watch(); ++i) {
unwatch_literal(s, (*this)[i].second);
}
set_num_watch(0);
DEBUG_CODE(for (wliteral wl : *this) VERIFY(!is_watched(s, wl.second)););
}
// watch a prefix of literals, such that the slack of these is >= k
bool pb::init_watch(solver_interface& s) {
auto& p = *this;
clear_watch(s);
if (lit() != sat::null_literal && s.value(p.lit()) == l_false) {
negate();
}
VERIFY(lit() == sat::null_literal || s.value(lit()) == l_true);
unsigned sz = size(), bound = k();
// put the non-false literals into the head.
unsigned slack = 0, slack1 = 0, num_watch = 0, j = 0;
for (unsigned i = 0; i < sz; ++i) {
if (s.value(p[i].second) != l_false) {
if (j != i) {
swap(i, j);
}
if (slack <= bound) {
slack += p[j].first;
++num_watch;
}
else {
slack1 += p[j].first;
}
++j;
}
}
DEBUG_CODE(
bool is_false = false;
for (unsigned k = 0; k < sz; ++k) {
SASSERT(!is_false || s.value(p[k].second) == l_false);
SASSERT((k < j) == (s.value(p[k].second) != l_false));
is_false = s.value(p[k].second) == l_false;
});
if (slack < bound) {
literal lit = p[j].second;
VERIFY(s.value(lit) == l_false);
for (unsigned i = j + 1; i < sz; ++i) {
if (s.lvl(lit) < s.lvl(p[i].second)) {
lit = p[i].second;
}
}
s.set_conflict(p, lit);
return false;
}
else {
for (unsigned i = 0; i < num_watch; ++i) {
p.watch_literal(s, p[i].second);
}
p.set_slack(slack);
p.set_num_watch(num_watch);
// SASSERT(validate_watch(p, sat::null_literal));
TRACE("ba", display(tout << "init watch: ", s, true););
// slack is tight:
if (slack + slack1 == bound) {
SASSERT(slack1 == 0);
SASSERT(j == num_watch);
for (unsigned i = 0; i < j; ++i) {
s.assign(p, p[i].second);
}
}
return true;
}
}
std::ostream& pb::display(std::ostream& out) const {
bool first = true;
for (wliteral wl : *this) {
if (!first) out << "+ ";
if (wl.first != 1) out << wl.first << " * ";
out << wl.second << " ";
first = false;
}
return out << " >= " << k();
}
std::ostream& pb::display(std::ostream& out, solver_interface const& s, bool values) const {
auto const& p = *this;
if (p.lit() != sat::null_literal) out << p.lit() << " == ";
if (values) {
out << "[watch: " << p.num_watch() << ", slack: " << p.slack() << "]";
}
if (p.lit() != sat::null_literal && values) {
out << "@(" << s.value(p.lit());
if (s.value(p.lit()) != l_undef) {
out << ":" << s.lvl(p.lit());
}
out << "): ";
}
unsigned i = 0;
for (wliteral wl : p) {
literal l = wl.second;
unsigned w = wl.first;
if (i > 0) out << "+ ";
if (i++ == p.num_watch()) out << " | ";
if (w > 1) out << w << " * ";
out << l;
if (values) {
out << "@(" << s.value(l);
if (s.value(l) != l_undef) {
out << ":" << s.lvl(l);
}
out << ") ";
}
else {
out << " ";
}
}
return out << ">= " << p.k() << "\n";
}
bool pb::validate_unit_propagation(solver_interface const& s, literal alit) const {
if (lit() != sat::null_literal && s.value(lit()) != l_true)
return false;
unsigned sum = 0;
TRACE("ba", display(tout << "validate: " << alit << "\n", s, true););
for (wliteral wl : *this) {
literal l = wl.second;
lbool val = s.value(l);
if (val != l_false && l != alit) {
sum += wl.first;
}
}
return sum < k();
}
lbool pb::eval(sat::model const& m) const {
auto const& p = *this;
unsigned trues = 0, undefs = 0;
for (wliteral wl : p) {
switch (ba::value(m, wl.second)) {
case l_true: trues += wl.first; break;
case l_undef: undefs += wl.first; break;
default: break;
}
}
if (trues + undefs < p.k()) return l_false;
if (trues >= p.k()) return l_true;
return l_undef;
}
lbool pb::eval(solver_interface const& s) const {
auto const& p = *this;
unsigned trues = 0, undefs = 0;
for (wliteral wl : p) {
switch (s.value(wl.second)) {
case l_true: trues += wl.first; break;
case l_undef: undefs += wl.first; break;
default: break;
}
}
if (trues + undefs < p.k()) return l_false;
if (trues >= p.k()) return l_true;
return l_undef;
}
void pb::init_use_list(sat::ext_use_list& ul) const {
auto idx = cindex();
for (auto l : *this)
ul.insert(l.second, idx);
}
bool pb::is_blocked(sat::simplifier& sim, literal lit) const {
unsigned weight = 0, offset = 0;
for (wliteral l2 : *this) {
if (~l2.second == lit) {
offset = l2.first;
break;
}
}
SASSERT(offset != 0);
for (wliteral l2 : *this) {
if (sim.is_marked(~l2.second)) {
weight += std::min(offset, l2.first);
}
}
return weight >= k();
}
}

67
src/sat/smt/ba_pb.h Normal file
View file

@ -0,0 +1,67 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
ba_pb.h
Abstract:
Interface for PB constraints.
Author:
Nikolaj Bjorner (nbjorner) 2017-01-30
--*/
#pragma once
#include "sat/sat_types.h"
#include "sat/smt/ba_card.h"
namespace ba {
class pb : public pb_base {
unsigned m_slack;
unsigned m_num_watch;
unsigned m_max_sum;
wliteral m_wlits[0];
public:
static size_t get_obj_size(unsigned num_lits) { return sat::constraint_base::obj_size(sizeof(pb) + num_lits * sizeof(wliteral)); }
pb(unsigned id, literal lit, svector<wliteral> const& wlits, unsigned k);
literal lit() const { return m_lit; }
wliteral operator[](unsigned i) const { return m_wlits[i]; }
wliteral& operator[](unsigned i) { return m_wlits[i]; }
wliteral const* begin() const { return m_wlits; }
wliteral const* end() const { return begin() + m_size; }
unsigned slack() const { return m_slack; }
void set_slack(unsigned s) { m_slack = s; }
unsigned num_watch() const { return m_num_watch; }
unsigned max_sum() const { return m_max_sum; }
void update_max_sum();
void set_num_watch(unsigned s) { m_num_watch = s; }
bool is_cardinality() const;
void negate() override;
void set_k(unsigned k) override { m_k = k; VERIFY(k < 4000000000); update_max_sum(); }
void swap(unsigned i, unsigned j) override { std::swap(m_wlits[i], m_wlits[j]); }
literal_vector literals() const override { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; }
bool is_watching(literal l) const override;
literal get_lit(unsigned i) const override { return m_wlits[i].second; }
void set_lit(unsigned i, literal l) override { m_wlits[i].second = l; }
unsigned get_coeff(unsigned i) const override { return m_wlits[i].first; }
double get_reward(ba::solver_interface const& s, sat::literal_occs_fun& occs) const override;
void clear_watch(solver_interface& s) override;
std::ostream& display(std::ostream& out) const override;
std::ostream& display(std::ostream& out, solver_interface const& s, bool values) const override;
bool init_watch(solver_interface& s) override;
bool validate_unit_propagation(solver_interface const& s, literal alit) const override;
lbool eval(sat::model const& m) const override;
lbool eval(solver_interface const& s) const override;
void init_use_list(sat::ext_use_list& ul) const override;
bool is_blocked(sat::simplifier& s, literal lit) const override;
};
}

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,10 @@ Revision History:
#include "sat/sat_big.h" #include "sat/sat_big.h"
#include "sat/smt/sat_smt.h" #include "sat/smt/sat_smt.h"
#include "sat/smt/sat_th.h" #include "sat/smt/sat_th.h"
#include "sat/smt/ba_constraint.h"
#include "sat/smt/ba_card.h"
#include "sat/smt/ba_pb.h"
#include "sat/smt/ba_xor.h"
#include "util/small_object_allocator.h" #include "util/small_object_allocator.h"
#include "util/scoped_ptr_vector.h" #include "util/scoped_ptr_vector.h"
#include "util/sorting_network.h" #include "util/sorting_network.h"
@ -33,9 +37,16 @@ Revision History:
namespace sat { namespace sat {
typedef ba::constraint constraint;
typedef ba::wliteral wliteral;
typedef ba::card card;
typedef ba::xr xr;
typedef ba::pb_base pb_base;
typedef ba::pb pb;
class xor_finder; class xor_finder;
class ba_solver : public euf::th_solver { class ba_solver : public euf::th_solver, public ba::solver_interface {
friend class local_search; friend class local_search;
@ -55,166 +66,6 @@ namespace sat {
void reset() { memset(this, 0, sizeof(*this)); } void reset() { memset(this, 0, sizeof(*this)); }
}; };
public:
enum tag_t {
card_t,
pb_t,
xr_t
};
class card;
class pb;
class xr;
class pb_base;
class constraint {
protected:
tag_t m_tag;
bool m_removed;
literal m_lit;
literal m_watch;
unsigned m_glue;
unsigned m_psm;
unsigned m_size;
size_t m_obj_size;
bool m_learned;
unsigned m_id;
bool m_pure; // is the constraint pure (only positive occurrences)
public:
constraint(tag_t t, unsigned id, literal l, unsigned sz, size_t osz):
m_tag(t), m_removed(false), m_lit(l), m_watch(null_literal), m_glue(0), m_psm(0), m_size(sz), m_obj_size(osz), m_learned(false), m_id(id), m_pure(false) {
}
ext_constraint_idx cindex() const { return constraint_base::mem2base(this); }
void deallocate(small_object_allocator& a) { a.deallocate(obj_size(), constraint_base::mem2base_ptr(this)); }
unsigned id() const { return m_id; }
tag_t tag() const { return m_tag; }
literal lit() const { return m_lit; }
unsigned size() const { return m_size; }
void set_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; }
void update_literal(literal l) { m_lit = l; }
bool was_removed() const { return m_removed; }
void set_removed() { m_removed = true; }
void nullify_literal() { m_lit = null_literal; }
unsigned glue() const { return m_glue; }
void set_glue(unsigned g) { m_glue = g; }
unsigned psm() const { return m_psm; }
void set_psm(unsigned p) { m_psm = p; }
void set_learned(bool f) { m_learned = f; }
bool learned() const { return m_learned; }
bool is_watched() const { return m_watch == m_lit && m_lit != null_literal; }
void set_watch() { m_watch = m_lit; }
void clear_watch() { m_watch = null_literal; }
bool is_clear() const { return m_watch == null_literal && m_lit != null_literal; }
bool is_pure() const { return m_pure; }
void set_pure() { m_pure = true; }
unsigned fold_max_var(unsigned w) const;
size_t obj_size() const { return m_obj_size; }
card& to_card();
pb& to_pb();
xr& to_xr();
card const& to_card() const;
pb const& to_pb() const;
xr const& to_xr() const;
pb_base const& to_pb_base() const;
bool is_card() const { return m_tag == card_t; }
bool is_pb() const { return m_tag == pb_t; }
bool is_xr() const { return m_tag == xr_t; }
virtual bool is_watching(literal l) const { UNREACHABLE(); return false; };
virtual literal_vector literals() const { UNREACHABLE(); return literal_vector(); }
virtual void swap(unsigned i, unsigned j) { UNREACHABLE(); }
virtual literal get_lit(unsigned i) const { UNREACHABLE(); return null_literal; }
virtual void set_lit(unsigned i, literal l) { UNREACHABLE(); }
virtual bool well_formed() const { return true; }
virtual void negate() { UNREACHABLE(); }
};
friend std::ostream& operator<<(std::ostream& out, constraint const& c);
// base class for pb and cardinality constraints
class pb_base : public constraint {
protected:
unsigned m_k;
public:
pb_base(tag_t t, unsigned id, literal l, unsigned sz, size_t osz, unsigned k):
constraint(t, id, l, sz, osz), m_k(k) { VERIFY(k < 4000000000); }
virtual void set_k(unsigned k) { VERIFY(k < 4000000000); m_k = k; }
virtual unsigned get_coeff(unsigned i) const { UNREACHABLE(); return 0; }
unsigned k() const { return m_k; }
bool well_formed() const override;
};
class card : public pb_base {
literal m_lits[0];
public:
static size_t get_obj_size(unsigned num_lits) { return constraint_base::obj_size(sizeof(card) + num_lits * sizeof(literal)); }
card(unsigned id, literal lit, literal_vector const& lits, unsigned k);
literal operator[](unsigned i) const { return m_lits[i]; }
literal& operator[](unsigned i) { return m_lits[i]; }
literal const* begin() const { return m_lits; }
literal const* end() const { return static_cast<literal const*>(m_lits) + m_size; }
void negate() override;
void swap(unsigned i, unsigned j) override { std::swap(m_lits[i], m_lits[j]); }
literal_vector literals() const override { return literal_vector(m_size, m_lits); }
bool is_watching(literal l) const override;
literal get_lit(unsigned i) const override { return m_lits[i]; }
void set_lit(unsigned i, literal l) override { m_lits[i] = l; }
unsigned get_coeff(unsigned i) const override { return 1; }
};
typedef std::pair<unsigned, literal> wliteral;
class pb : public pb_base {
unsigned m_slack;
unsigned m_num_watch;
unsigned m_max_sum;
wliteral m_wlits[0];
public:
static size_t get_obj_size(unsigned num_lits) { return constraint_base::obj_size(sizeof(pb) + num_lits * sizeof(wliteral)); }
pb(unsigned id, literal lit, svector<wliteral> const& wlits, unsigned k);
literal lit() const { return m_lit; }
wliteral operator[](unsigned i) const { return m_wlits[i]; }
wliteral& operator[](unsigned i) { return m_wlits[i]; }
wliteral const* begin() const { return m_wlits; }
wliteral const* end() const { return begin() + m_size; }
unsigned slack() const { return m_slack; }
void set_slack(unsigned s) { m_slack = s; }
unsigned num_watch() const { return m_num_watch; }
unsigned max_sum() const { return m_max_sum; }
void update_max_sum();
void set_num_watch(unsigned s) { m_num_watch = s; }
bool is_cardinality() const;
void negate() override;
void set_k(unsigned k) override { m_k = k; VERIFY(k < 4000000000); update_max_sum(); }
void swap(unsigned i, unsigned j) override { std::swap(m_wlits[i], m_wlits[j]); }
literal_vector literals() const override { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; }
bool is_watching(literal l) const override;
literal get_lit(unsigned i) const override { return m_wlits[i].second; }
void set_lit(unsigned i, literal l) override { m_wlits[i].second = l; }
unsigned get_coeff(unsigned i) const override { return m_wlits[i].first; }
};
class xr : public constraint {
literal m_lits[0];
public:
static size_t get_obj_size(unsigned num_lits) { return constraint_base::obj_size(sizeof(xr) + num_lits * sizeof(literal)); }
xr(unsigned id, literal_vector const& lits);
literal operator[](unsigned i) const { return m_lits[i]; }
literal const* begin() const { return m_lits; }
literal const* end() const { return begin() + m_size; }
void negate() override { m_lits[0].neg(); }
void swap(unsigned i, unsigned j) override { std::swap(m_lits[i], m_lits[j]); }
bool is_watching(literal l) const override;
literal_vector literals() const override { return literal_vector(size(), begin()); }
literal get_lit(unsigned i) const override { return m_lits[i]; }
void set_lit(unsigned i, literal l) override { m_lits[i] = l; }
bool well_formed() const override;
};
protected: protected:
struct ineq { struct ineq {
@ -235,29 +86,28 @@ namespace sat {
sat_internalizer& si; sat_internalizer& si;
pb_util m_pb; pb_util m_pb;
solver* m_solver; solver* m_solver{ nullptr };
lookahead* m_lookahead; lookahead* m_lookahead{ nullptr };
stats m_stats; stats m_stats;
small_object_allocator m_allocator; small_object_allocator m_allocator;
ptr_vector<ba::constraint> m_constraints;
ptr_vector<constraint> m_constraints; ptr_vector<ba::constraint> m_learned;
ptr_vector<constraint> m_learned; ptr_vector<ba::constraint> m_constraint_to_reinit;
ptr_vector<constraint> m_constraint_to_reinit;
unsigned_vector m_constraint_to_reinit_lim; unsigned_vector m_constraint_to_reinit_lim;
unsigned m_constraint_to_reinit_last_sz; unsigned m_constraint_to_reinit_last_sz{ 0 };
unsigned m_constraint_id; unsigned m_constraint_id{ 0 };
// conflict resolution // conflict resolution
unsigned m_num_marks; unsigned m_num_marks{ 0 };
unsigned m_conflict_lvl; unsigned m_conflict_lvl{ 0 };
svector<int64_t> m_coeffs; svector<int64_t> m_coeffs;
svector<bool_var> m_active_vars; svector<bool_var> m_active_vars;
unsigned m_bound; unsigned m_bound{ 0 };
tracked_uint_set m_active_var_set; tracked_uint_set m_active_var_set;
literal_vector m_lemma; literal_vector m_lemma;
literal_vector m_skipped; literal_vector m_skipped;
unsigned m_num_propagations_since_pop; unsigned m_num_propagations_since_pop{ 0 };
unsigned_vector m_parity_marks; unsigned_vector m_parity_marks;
literal_vector m_parity_trail; literal_vector m_parity_trail;
@ -297,9 +147,9 @@ namespace sat {
vector<svector<constraint*>> m_cnstr_use_list; vector<svector<constraint*>> m_cnstr_use_list;
use_list m_clause_use_list; use_list m_clause_use_list;
bool m_simplify_change; bool m_simplify_change{ false };
bool m_clause_removed; bool m_clause_removed{ false };
bool m_constraint_removed; bool m_constraint_removed{ false };
literal_vector m_roots; literal_vector m_roots;
bool_vector m_root_vars; bool_vector m_root_vars;
unsigned_vector m_weights; unsigned_vector m_weights;
@ -324,9 +174,9 @@ namespace sat {
unsigned elim_pure(); unsigned elim_pure();
bool elim_pure(literal lit); bool elim_pure(literal lit);
void unit_strengthen(); void unit_strengthen();
void unit_strengthen(big& big, constraint& cs); void unit_strengthen(big& big, ba::constraint& cs);
void unit_strengthen(big& big, pb_base& p); void unit_strengthen(big& big, pb_base& p);
void subsumption(constraint& c1); void subsumption(ba::constraint& c1);
void subsumption(card& c1); void subsumption(card& c1);
void gc_half(char const* _method); void gc_half(char const* _method);
void update_psm(constraint& c) const; void update_psm(constraint& c) const;
@ -345,10 +195,7 @@ namespace sat {
// constraints // constraints
constraint& index2constraint(size_t idx) const { return *reinterpret_cast<constraint*>(constraint_base::from_index(idx)->mem()); } constraint& index2constraint(size_t idx) const { return *reinterpret_cast<constraint*>(constraint_base::from_index(idx)->mem()); }
void pop_constraint(); void pop_constraint();
void unwatch_literal(literal w, constraint& c); // void watch_literal(wliteral w, pb& p);
void watch_literal(literal w, constraint& c);
void watch_literal(wliteral w, pb& p);
bool is_watched(literal l, constraint const& c) const;
void add_constraint(constraint* c); void add_constraint(constraint* c);
bool init_watch(constraint& c); bool init_watch(constraint& c);
void init_watch(bool_var v); void init_watch(bool_var v);
@ -357,9 +204,8 @@ namespace sat {
bool incremental_mode() const; bool incremental_mode() const;
void simplify(constraint& c); void simplify(constraint& c);
void pre_simplify(xor_finder& xu, constraint& c); void pre_simplify(xor_finder& xu, constraint& c);
void nullify_tracking_literal(constraint& c); void set_conflict(constraint& c, literal lit) override;
void set_conflict(constraint& c, literal lit); void assign(constraint& c, literal lit) override;
void assign(constraint& c, literal lit);
bool assigned_above(literal above, literal below); bool assigned_above(literal above, literal below);
void get_antecedents(literal l, constraint const& c, literal_vector & r, bool probing); void get_antecedents(literal l, constraint const& c, literal_vector & r, bool probing);
bool validate_conflict(constraint const& c) const; bool validate_conflict(constraint const& c) const;
@ -377,12 +223,10 @@ namespace sat {
void split_root(constraint& c); void split_root(constraint& c);
unsigned next_id() { return m_constraint_id++; } unsigned next_id() { return m_constraint_id++; }
void set_non_learned(constraint& c); void set_non_learned(constraint& c);
double get_reward(literal l, ext_justification_idx idx, literal_occs_fun& occs) const override;
// cardinality // cardinality
bool init_watch(card& c);
lbool add_assign(card& c, literal lit); lbool add_assign(card& c, literal lit);
void clear_watch(card& c);
void reset_coeffs(); void reset_coeffs();
void reset_marked_literals(); void reset_marked_literals();
void get_antecedents(literal l, card const& c, literal_vector & r); void get_antecedents(literal l, card const& c, literal_vector & r);
@ -392,13 +236,9 @@ namespace sat {
bool clausify(literal lit, unsigned n, literal const* lits, unsigned k); bool clausify(literal lit, unsigned n, literal const* lits, unsigned k);
lbool eval(card const& c) const; lbool eval(card const& c) const;
lbool eval(model const& m, card const& c) const; lbool eval(model const& m, card const& c) const;
double get_reward(card const& c, literal_occs_fun& occs) const;
// xr specific functionality // xr specific functionality
void clear_watch(xr& x);
bool init_watch(xr& x);
bool parity(xr const& x, unsigned offset) const;
lbool add_assign(xr& x, literal alit); lbool add_assign(xr& x, literal alit);
void get_xr_antecedents(literal l, unsigned index, justification js, literal_vector& r); void get_xr_antecedents(literal l, unsigned index, justification js, literal_vector& r);
void get_antecedents(literal l, xr const& x, literal_vector & r); void get_antecedents(literal l, xr const& x, literal_vector & r);
@ -411,11 +251,9 @@ namespace sat {
lbool eval(model const& m, xr const& x) const; lbool eval(model const& m, xr const& x) const;
// pb functionality // pb functionality
unsigned m_a_max; unsigned m_a_max{ 0 };
bool init_watch(pb& p);
lbool add_assign(pb& p, literal alit); lbool add_assign(pb& p, literal alit);
void add_index(pb& p, unsigned index, literal lit); void add_index(pb& p, unsigned index, literal lit);
void clear_watch(pb& p);
void get_antecedents(literal l, pb const& p, literal_vector & r); void get_antecedents(literal l, pb const& p, literal_vector & r);
void split_root(pb_base& p); void split_root(pb_base& p);
void simplify(pb_base& p); void simplify(pb_base& p);
@ -427,7 +265,6 @@ namespace sat {
bool is_cardinality(pb const& p, literal_vector& lits); bool is_cardinality(pb const& p, literal_vector& lits);
lbool eval(pb const& p) const; lbool eval(pb const& p) const;
lbool eval(model const& m, pb const& p) const; lbool eval(model const& m, pb const& p) const;
double get_reward(pb const& p, literal_occs_fun& occs) const;
// RoundingPb conflict resolution // RoundingPb conflict resolution
lbool resolve_conflict_rs(); lbool resolve_conflict_rs();
@ -449,31 +286,32 @@ namespace sat {
// access solver // access solver
inline lbool value(bool_var v) const { return value(literal(v, false)); } inline lbool value(bool_var v) const override { return value(literal(v, false)); }
inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } inline lbool value(literal lit) const override { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); }
inline lbool value(model const& m, literal l) const { return l.sign() ? ~m[l.var()] : m[l.var()]; } inline bool is_false(literal lit) const override { return l_false == value(lit); }
inline bool is_false(literal lit) const { return l_false == value(lit); }
inline unsigned lvl(literal lit) const { return m_lookahead ? 0 : m_solver->lvl(lit); } inline unsigned lvl(literal lit) const override { return m_lookahead ? 0 : m_solver->lvl(lit); }
inline unsigned lvl(bool_var v) const { return m_lookahead ? 0 : m_solver->lvl(v); } inline unsigned lvl(bool_var v) const override { return m_lookahead ? 0 : m_solver->lvl(v); }
inline bool inconsistent() const { inline bool inconsistent() const override {
if (m_lookahead) return m_lookahead->inconsistent(); if (m_lookahead) return m_lookahead->inconsistent();
return m_solver->inconsistent(); return m_solver->inconsistent();
} }
inline watch_list& get_wlist(literal l) { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } inline watch_list& get_wlist(literal l) override { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); }
inline watch_list const& get_wlist(literal l) const { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } inline watch_list const& get_wlist(literal l) const override { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); }
inline void assign(literal l, justification j) { inline void assign(literal l, justification j) override {
if (m_lookahead) m_lookahead->assign(l); if (m_lookahead) m_lookahead->assign(l);
else m_solver->assign(l, j); else m_solver->assign(l, j);
} }
inline void set_conflict(justification j, literal l) { inline void set_conflict(justification j, literal l) override {
if (m_lookahead) m_lookahead->set_conflict(); if (m_lookahead) m_lookahead->set_conflict();
else m_solver->set_conflict(j, l); else m_solver->set_conflict(j, l);
} }
inline config const& get_config() const { return m_lookahead ? m_lookahead->get_config() : m_solver->get_config(); } inline config const& get_config() const override {
return m_lookahead ? m_lookahead->get_config() : m_solver->get_config();
}
mutable bool m_overflow; mutable bool m_overflow{ false };
void reset_active_var_set(); void reset_active_var_set();
bool test_and_set_active(bool_var v); bool test_and_set_active(bool_var v);
void inc_coeff(literal l, unsigned offset); void inc_coeff(literal l, unsigned offset);
@ -499,10 +337,7 @@ namespace sat {
bool validate_assign(literal_vector const& lits, literal lit); bool validate_assign(literal_vector const& lits, literal lit);
bool validate_lemma(); bool validate_lemma();
bool validate_ineq(ineq const& ineq) const; bool validate_ineq(ineq const& ineq) const;
bool validate_unit_propagation(card const& c, literal alit) const;
bool validate_unit_propagation(pb const& p, literal alit) const;
bool validate_unit_propagation(pb const& p, literal_vector const& r, literal alit) const; bool validate_unit_propagation(pb const& p, literal_vector const& r, literal alit) const;
bool validate_unit_propagation(xr const& x, literal alit) const;
bool validate_conflict(literal_vector const& lits, ineq& p); bool validate_conflict(literal_vector const& lits, ineq& p);
bool validate_watch_literals() const; bool validate_watch_literals() const;
bool validate_watch_literal(literal lit) const; bool validate_watch_literal(literal lit) const;
@ -528,9 +363,6 @@ namespace sat {
unsigned get_coeff(ineq const& pb, literal lit); unsigned get_coeff(ineq const& pb, literal lit);
void display(std::ostream& out, ineq const& p, bool values = false) const; void display(std::ostream& out, ineq const& p, bool values = false) const;
void display(std::ostream& out, card const& c, bool values) const;
void display(std::ostream& out, pb const& p, bool values) const;
void display(std::ostream& out, xr const& c, bool values) const;
void display_lit(std::ostream& out, literal l, unsigned sz, bool values) const; void display_lit(std::ostream& out, literal l, unsigned sz, bool values) const;
constraint* add_at_least(literal l, literal_vector const& lits, unsigned k, bool learned); constraint* add_at_least(literal l, literal_vector const& lits, unsigned k, bool learned);
@ -560,9 +392,9 @@ namespace sat {
literal internalize_xor(expr* e, bool sign, bool root); literal internalize_xor(expr* e, bool sign, bool root);
// Decompile // Decompile
expr_ref get_card(std::function<expr_ref(sat::literal)>& l2e, ba_solver::card const& c); expr_ref get_card(std::function<expr_ref(sat::literal)>& l2e, card const& c);
expr_ref get_pb(std::function<expr_ref(sat::literal)>& l2e, ba_solver::pb const& p); expr_ref get_pb(std::function<expr_ref(sat::literal)>& l2e, pb const& p);
expr_ref get_xor(std::function<expr_ref(sat::literal)>& l2e, ba_solver::xr const& x); expr_ref get_xor(std::function<expr_ref(sat::literal)>& l2e, xr const& x);
public: public:
ba_solver(euf::solver& ctx, euf::theory_id id); ba_solver(euf::solver& ctx, euf::theory_id id);
@ -598,7 +430,6 @@ namespace sat {
void pop_reinit() override; void pop_reinit() override;
void gc() override; void gc() override;
unsigned max_var(unsigned w) const override; unsigned max_var(unsigned w) const override;
double get_reward(literal l, ext_justification_idx idx, literal_occs_fun& occs) const override;
bool is_extended_binary(ext_justification_idx idx, literal_vector & r) override; bool is_extended_binary(ext_justification_idx idx, literal_vector & r) override;
void init_use_list(ext_use_list& ul) override; void init_use_list(ext_use_list& ul) override;
bool is_blocked(literal l, ext_constraint_idx idx) override; bool is_blocked(literal l, ext_constraint_idx idx) override;

View file

@ -0,0 +1,52 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
ba_solver_interface.h
Abstract:
Abstract interface for a solver,
covers functionality exposed by the sat and lookahead solvers.
Author:
Nikolaj Bjorner (nbjorner) 2017-01-30
Revision History:
--*/
#pragma once
#include "sat/sat_types.h"
#include "sat/sat_solver.h"
#include "sat/smt/sat_smt.h"
namespace ba {
typedef sat::literal literal;
typedef sat::bool_var bool_var;
typedef sat::literal_vector literal_vector;
typedef std::pair<unsigned, literal> wliteral;
class constraint;
class solver_interface {
public:
virtual lbool value(bool_var v) const = 0;
virtual lbool value(literal lit) const = 0;
virtual bool is_false(literal lit) const = 0;
virtual unsigned lvl(literal lit) const = 0;
virtual unsigned lvl(bool_var v) const = 0;
virtual bool inconsistent() const = 0;
virtual sat::watch_list& get_wlist(literal l) = 0;
virtual sat::watch_list const& get_wlist(literal l) const = 0;
virtual void assign(literal l, sat::justification j) = 0;
virtual void set_conflict(sat::justification j, literal l) = 0;
virtual sat::config const& get_config() const = 0;
virtual void assign(constraint& c, literal lit) = 0;
virtual void set_conflict(constraint& c, literal lit) = 0;
};
}

192
src/sat/smt/ba_xor.cpp Normal file
View file

@ -0,0 +1,192 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
ba_xor.cpp
Abstract:
Interface for Xor constraints.
Author:
Nikolaj Bjorner (nbjorner) 2017-01-30
--*/
#include "sat/smt/ba_xor.h"
#include "sat/smt/ba_solver.h"
namespace ba {
xr& constraint::to_xr() {
SASSERT(is_xr());
return static_cast<xr&>(*this);
}
xr const& constraint::to_xr() const {
SASSERT(is_xr());
return static_cast<xr const&>(*this);
}
xr::xr(unsigned id, literal_vector const& lits) :
constraint(ba::tag_t::xr_t, id, sat::null_literal, lits.size(), get_obj_size(lits.size())) {
for (unsigned i = 0; i < size(); ++i) {
m_lits[i] = lits[i];
}
}
bool xr::is_watching(literal l) const {
return
l == (*this)[0] || l == (*this)[1] ||
~l == (*this)[0] || ~l == (*this)[1];
}
bool xr::well_formed() const {
uint_set vars;
if (lit() != sat::null_literal) vars.insert(lit().var());
for (literal l : *this) {
bool_var v = l.var();
if (vars.contains(v)) return false;
vars.insert(v);
}
return true;
}
std::ostream& xr::display(std::ostream& out) const {
for (unsigned i = 0; i < size(); ++i) {
out << (*this)[i] << " ";
if (i + 1 < size()) out << "x ";
}
return out;
}
void xr::clear_watch(solver_interface& s) {
auto& x = *this;
x.reset_watch();
x.unwatch_literal(s, x[0]);
x.unwatch_literal(s, x[1]);
x.unwatch_literal(s, ~x[0]);
x.unwatch_literal(s, ~x[1]);
}
bool xr::init_watch(solver_interface& s) {
auto& x = *this;
x.clear_watch(s);
VERIFY(x.lit() == sat::null_literal);
TRACE("ba", x.display(tout););
unsigned sz = x.size();
unsigned j = 0;
for (unsigned i = 0; i < sz && j < 2; ++i) {
if (s.value(x[i]) == l_undef) {
x.swap(i, j);
++j;
}
}
switch (j) {
case 0:
if (!parity(s, 0)) {
unsigned l = s.lvl(x[0]);
j = 1;
for (unsigned i = 1; i < sz; ++i) {
if (s.lvl(x[i]) > l) {
j = i;
l = s.lvl(x[i]);
}
}
s.set_conflict(x, x[j]);
}
return false;
case 1:
SASSERT(x.lit() == sat::null_literal || s.value(x.lit()) == l_true);
s.assign(x, parity(s, 1) ? ~x[0] : x[0]);
return false;
default:
SASSERT(j == 2);
x.watch_literal(s, x[0]);
x.watch_literal(s, x[1]);
x.watch_literal(s, ~x[0]);
x.watch_literal(s, ~x[1]);
return true;
}
}
bool xr::parity(solver_interface const& s, unsigned offset) const {
auto const& x = *this;
bool odd = false;
unsigned sz = x.size();
for (unsigned i = offset; i < sz; ++i) {
SASSERT(s.value(x[i]) != l_undef);
if (s.value(x[i]) == l_true) {
odd = !odd;
}
}
return odd;
}
std::ostream& xr::display(std::ostream& out, solver_interface const& s, bool values) const {
auto const& x = *this;
out << "xr: ";
for (literal l : x) {
out << l;
if (values) {
out << "@(" << s.value(l);
if (s.value(l) != l_undef) {
out << ":" << s.lvl(l);
}
out << ") ";
}
else {
out << " ";
}
}
return out << "\n";
}
bool xr::validate_unit_propagation(solver_interface const& s, literal alit) const {
if (s.value(lit()) != l_true) return false;
for (unsigned i = 1; i < size(); ++i) {
if (s.value((*this)[i]) == l_undef) return false;
}
return true;
}
lbool xr::eval(solver_interface const& s) const {
auto const& x = *this;
bool odd = false;
for (auto l : x) {
switch (s.value(l)) {
case l_true: odd = !odd; break;
case l_false: break;
default: return l_undef;
}
}
return odd ? l_true : l_false;
}
lbool xr::eval(sat::model const& m) const {
auto const& x = *this;
bool odd = false;
for (auto l : x) {
switch (ba::value(m, l)) {
case l_true: odd = !odd; break;
case l_false: break;
default: return l_undef;
}
}
return odd ? l_true : l_false;
}
void xr::init_use_list(sat::ext_use_list& ul) const {
auto idx = cindex();
for (auto l : *this) {
ul.insert(l, idx);
ul.insert(~l, idx);
}
}
}

53
src/sat/smt/ba_xor.h Normal file
View file

@ -0,0 +1,53 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
ba_xor.h
Abstract:
Interface for Xor constraints.
Author:
Nikolaj Bjorner (nbjorner) 2017-01-30
--*/
#pragma once
#include "sat/sat_types.h"
#include "sat/smt/ba_constraint.h"
namespace ba {
class xr : public constraint {
literal m_lits[0];
public:
static size_t get_obj_size(unsigned num_lits) { return sat::constraint_base::obj_size(sizeof(xr) + num_lits * sizeof(literal)); }
xr(unsigned id, literal_vector const& lits);
literal operator[](unsigned i) const { return m_lits[i]; }
literal const* begin() const { return m_lits; }
literal const* end() const { return begin() + m_size; }
void negate() override { m_lits[0].neg(); }
void swap(unsigned i, unsigned j) override { std::swap(m_lits[i], m_lits[j]); }
bool is_watching(literal l) const override;
literal_vector literals() const override { return literal_vector(size(), begin()); }
literal get_lit(unsigned i) const override { return m_lits[i]; }
void set_lit(unsigned i, literal l) override { m_lits[i] = l; }
bool well_formed() const override;
void clear_watch(solver_interface& s) override;
bool init_watch(solver_interface& s) override;
std::ostream& display(std::ostream& out) const override;
std::ostream& display(std::ostream& out, solver_interface const& s, bool values) const override;
bool parity(solver_interface const& s, unsigned offset) const;
bool validate_unit_propagation(solver_interface const& s, literal alit) const override;
lbool eval(sat::model const& m) const override;
lbool eval(solver_interface const& s) const override;
void init_use_list(sat::ext_use_list& ul) const override;
bool is_blocked(sat::simplifier& s, literal lit) const override { return false; }
};
}

View file

@ -362,7 +362,7 @@ namespace bv {
eq eq_proc(*this); eq eq_proc(*this);
hash hash_proc(*this); hash hash_proc(*this);
map<theory_var, theory_var, hash, eq> table(hash_proc, eq_proc); map<theory_var, theory_var, hash, eq> table(hash_proc, eq_proc);
for (unsigned v = 0; v < get_num_vars(); ++v) { for (theory_var v = 0; v < static_cast<theory_var>(get_num_vars()); ++v) {
if (!m_bits[v].empty()) { if (!m_bits[v].empty()) {
theory_var w = table.insert_if_not_there(v, v); theory_var w = table.insert_if_not_there(v, v);
if (v != w && m_find.find(v) != m_find.find(w)) if (v != w && m_find.find(v) != m_find.find(w))
@ -424,7 +424,7 @@ namespace bv {
result->m_bits[i].append(m_bits[i]); result->m_bits[i].append(m_bits[i]);
result->m_zero_one_bits[i].append(m_zero_one_bits[i]); result->m_zero_one_bits[i].append(m_zero_one_bits[i]);
} }
for (unsigned i = 0; i < get_num_vars(); ++i) for (theory_var i = 0; i < static_cast<theory_var>(get_num_vars()); ++i)
if (find(i) != i) if (find(i) != i)
result->m_find.merge(i, find(i)); result->m_find.merge(i, find(i));
result->m_prop_queue.append(m_prop_queue); result->m_prop_queue.append(m_prop_queue);

View file

@ -96,10 +96,12 @@ namespace euf {
void ackerman::cg_conflict_eh(expr * n1, expr * n2) { void ackerman::cg_conflict_eh(expr * n1, expr * n2) {
if (!is_app(n1) || !is_app(n2)) if (!is_app(n1) || !is_app(n2))
return; return;
SASSERT(!s.m_drating);
app* a = to_app(n1); app* a = to_app(n1);
app* b = to_app(n2); app* b = to_app(n2);
if (a->get_decl() != b->get_decl() || a->get_num_args() != b->get_num_args()) if (a->get_decl() != b->get_decl() || a->get_num_args() != b->get_num_args())
return; return;
TRACE("ack", tout << "conflict eh: " << mk_pp(a, m) << " == " << mk_pp(b, m) << "\n";);
insert(a, b); insert(a, b);
gc(); gc();
} }
@ -107,11 +109,17 @@ namespace euf {
void ackerman::used_eq_eh(expr* a, expr* b, expr* c) { void ackerman::used_eq_eh(expr* a, expr* b, expr* c) {
if (a == b || a == c || b == c) if (a == b || a == c || b == c)
return; return;
if (s.m_drating)
return;
TRACE("ack", tout << mk_pp(a, m) << " " << mk_pp(b, m) << " " << mk_pp(c, m) << "\n";);
insert(a, b, c); insert(a, b, c);
gc(); gc();
} }
void ackerman::used_cc_eh(app* a, app* b) { void ackerman::used_cc_eh(app* a, app* b) {
if (s.m_drating)
return;
TRACE("ack", tout << "used cc: " << mk_pp(a, m) << " == " << mk_pp(b, m) << "\n";);
SASSERT(a->get_decl() == b->get_decl()); SASSERT(a->get_decl() == b->get_decl());
SASSERT(a->get_num_args() == b->get_num_args()); SASSERT(a->get_num_args() == b->get_num_args());
insert(a, b); insert(a, b);
@ -156,12 +164,12 @@ namespace euf {
void ackerman::add_cc(expr* _a, expr* _b) { void ackerman::add_cc(expr* _a, expr* _b) {
app* a = to_app(_a); app* a = to_app(_a);
app* b = to_app(_b); app* b = to_app(_b);
TRACE("ack", tout << mk_pp(a, m) << " " << mk_pp(b, m) << "\n";);
sat::literal_vector lits; sat::literal_vector lits;
unsigned sz = a->get_num_args(); unsigned sz = a->get_num_args();
for (unsigned i = 0; i < sz; ++i) { for (unsigned i = 0; i < sz; ++i) {
expr_ref eq(m.mk_eq(a->get_arg(i), b->get_arg(i)), m); expr_ref eq(m.mk_eq(a->get_arg(i), b->get_arg(i)), m);
sat::literal lit = s.internalize(eq, true, false, true); lits.push_back(s.internalize(eq, true, false, true));
lits.push_back(~lit);
} }
expr_ref eq(m.mk_eq(a, b), m); expr_ref eq(m.mk_eq(a, b), m);
lits.push_back(s.internalize(eq, false, false, true)); lits.push_back(s.internalize(eq, false, false, true));
@ -173,6 +181,7 @@ namespace euf {
expr_ref eq1(m.mk_eq(a, c), m); expr_ref eq1(m.mk_eq(a, c), m);
expr_ref eq2(m.mk_eq(b, c), m); expr_ref eq2(m.mk_eq(b, c), m);
expr_ref eq3(m.mk_eq(a, b), m); expr_ref eq3(m.mk_eq(a, b), m);
TRACE("ack", tout << mk_pp(a, m) << " " << mk_pp(b, m) << " " << mk_pp(c, m) << "\n";);
lits[0] = s.internalize(eq1, true, false, true); lits[0] = s.internalize(eq1, true, false, true);
lits[1] = s.internalize(eq2, true, false, true); lits[1] = s.internalize(eq2, true, false, true);
lits[2] = s.internalize(eq3, false, false, true); lits[2] = s.internalize(eq3, false, false, true);

View file

@ -84,7 +84,7 @@ namespace euf {
void solver::attach_node(euf::enode* n) { void solver::attach_node(euf::enode* n) {
expr* e = n->get_expr(); expr* e = n->get_expr();
if (!m.is_bool(e)) if (!m.is_bool(e))
log_node(e); drat_log_node(e);
else else
attach_lit(literal(si.add_bool_var(e), false), e); attach_lit(literal(si.add_bool_var(e), false), e);
@ -98,20 +98,23 @@ namespace euf {
} }
sat::literal solver::attach_lit(literal lit, expr* e) { sat::literal solver::attach_lit(literal lit, expr* e) {
if (lit.sign()) { sat::bool_var v = lit.var();
sat::bool_var v = si.add_bool_var(e);
s().set_external(v); s().set_external(v);
s().set_eliminated(v, false);
if (lit.sign()) {
v = si.add_bool_var(e);
s().set_external(v);
s().set_eliminated(v, false);
sat::literal lit2 = literal(v, false); sat::literal lit2 = literal(v, false);
s().mk_clause(~lit, lit2, sat::status::asserted()); s().mk_clause(~lit, lit2, sat::status::th(m_is_redundant, m.get_basic_family_id()));
s().mk_clause(lit, ~lit2, sat::status::asserted()); s().mk_clause(lit, ~lit2, sat::status::th(m_is_redundant, m.get_basic_family_id()));
lit = lit2; lit = lit2;
} }
sat::bool_var v = lit.var();
m_var2expr.reserve(v + 1, nullptr); m_var2expr.reserve(v + 1, nullptr);
SASSERT(m_var2expr[v] == nullptr); SASSERT(m_var2expr[v] == nullptr);
m_var2expr[v] = e; m_var2expr[v] = e;
m_var_trail.push_back(v); m_var_trail.push_back(v);
s().set_external(v);
if (!m_egraph.find(e)) { if (!m_egraph.find(e)) {
enode* n = m_egraph.mk(e, 0, nullptr); enode* n = m_egraph.mk(e, 0, nullptr);
m_egraph.set_merge_enabled(n, false); m_egraph.set_merge_enabled(n, false);
@ -215,14 +218,11 @@ namespace euf {
void solver::axiomatize_basic(enode* n) { void solver::axiomatize_basic(enode* n) {
expr* e = n->get_expr(); expr* e = n->get_expr();
sat::status st = sat::status::th(m_is_redundant, m.get_basic_family_id()); sat::status st = sat::status::th(m_is_redundant, m.get_basic_family_id());
if (m.is_ite(e)) { expr* c = nullptr, * th = nullptr, * el = nullptr;
if (!m.is_bool(e) && m.is_ite(e, c, th, el)) {
app* a = to_app(e); app* a = to_app(e);
expr* c = a->get_arg(0);
expr* th = a->get_arg(1);
expr* el = a->get_arg(2);
sat::bool_var v = si.to_bool_var(c); sat::bool_var v = si.to_bool_var(c);
SASSERT(v != sat::null_bool_var); SASSERT(v != sat::null_bool_var);
SASSERT(!m.is_bool(e));
expr_ref eq_th(m.mk_eq(a, th), m); expr_ref eq_th(m.mk_eq(a, th), m);
expr_ref eq_el(m.mk_eq(a, el), m); expr_ref eq_el(m.mk_eq(a, el), m);
sat::literal lit_th = internalize(eq_th, false, false, m_is_redundant); sat::literal lit_th = internalize(eq_th, false, false, m_is_redundant);

View file

@ -44,5 +44,16 @@ namespace euf {
} }
} }
void solver::check_missing_eq_propagation() const {
if (s().inconsistent())
return;
for (enode* n : m_egraph.nodes())
if (m.is_false(n->get_root()->get_expr()) && m.is_eq(n->get_expr()) &&
n->get_arg(0)->get_root() == n->get_arg(1)->get_root()) {
TRACE("euf", display(tout << n->get_expr_id() << ": " << mk_pp(n->get_expr(), m) << "\n"););
UNREACHABLE();
}
}
} }

View file

@ -15,24 +15,32 @@ Author:
--*/ --*/
#include "ast/ast_ll_pp.h"
#include "sat/smt/euf_solver.h" #include "sat/smt/euf_solver.h"
namespace euf { namespace euf {
void solver::init_drat() { void solver::init_drat() {
if (!m_drat_initialized) if (!m_drat_initialized) {
get_drat().add_theory(m.get_basic_family_id(), symbol("euf")); get_drat().add_theory(get_id(), symbol("euf"));
get_drat().add_theory(m.get_basic_family_id(), symbol("bool"));
}
m_drat_initialized = true; m_drat_initialized = true;
} }
void solver::log_node(expr* e) { void solver::drat_log_node(expr* e) {
if (!use_drat()) if (!use_drat())
return; return;
if (is_app(e)) { if (is_app(e)) {
app* a = to_app(e);
if (a->get_num_parameters() == 0)
get_drat().def_begin(e->get_id(), a->get_decl()->get_name().str());
else {
std::stringstream strm; std::stringstream strm;
strm << mk_ismt2_func(to_app(e)->get_decl(), m); strm << mk_ismt2_func(a->get_decl(), m);
get_drat().def_begin(e->get_id(), strm.str()); get_drat().def_begin(e->get_id(), strm.str());
for (expr* arg : *to_app(e)) }
for (expr* arg : *a)
get_drat().def_add_arg(arg->get_id()); get_drat().def_add_arg(arg->get_id());
get_drat().def_end(); get_drat().def_end();
} }
@ -57,7 +65,7 @@ namespace euf {
for (literal lit : r) lits.push_back(~lit); for (literal lit : r) lits.push_back(~lit);
if (l != sat::null_literal) if (l != sat::null_literal)
lits.push_back(l); lits.push_back(l);
get_drat().add(lits, sat::status::th(true, m.get_basic_family_id())); get_drat().add(lits, sat::status::th(true, get_id()));
} }
void solver::log_antecedents(std::ostream& out, literal l, literal_vector const& r) { void solver::log_antecedents(std::ostream& out, literal l, literal_vector const& r) {
@ -65,14 +73,14 @@ namespace euf {
expr* n = m_var2expr[l.var()]; expr* n = m_var2expr[l.var()];
out << ~l << ": "; out << ~l << ": ";
if (!l.sign()) out << "! "; if (!l.sign()) out << "! ";
out << mk_pp(n, m) << "\n"; out << mk_bounded_pp(n, m) << "\n";
SASSERT(s().value(l) == l_true); SASSERT(s().value(l) == l_true);
} }
if (l != sat::null_literal) { if (l != sat::null_literal) {
out << l << ": "; out << l << ": ";
if (l.sign()) out << "! "; if (l.sign()) out << "! ";
expr* n = m_var2expr[l.var()]; expr* n = m_var2expr[l.var()];
out << mk_pp(n, m) << "\n"; out << mk_bounded_pp(n, m) << "\n";
} }
} }

View file

@ -25,6 +25,27 @@ Author:
namespace euf { namespace euf {
solver::solver(ast_manager& m, sat::sat_internalizer& si, params_ref const& p) :
extension(m.mk_family_id("euf")),
m(m),
si(si),
m_egraph(m),
m_trail(*this),
m_rewriter(m),
m_unhandled_functions(m),
m_solver(nullptr),
m_lookahead(nullptr),
m_to_m(&m),
m_to_si(&si),
m_reinit_exprs(m)
{
updt_params(p);
std::function<void(std::ostream&, void*)> disp =
[&](std::ostream& out, void* j) { display_justification_ptr(out, reinterpret_cast<size_t*>(j)); };
m_egraph.set_display_justification(disp);
}
void solver::updt_params(params_ref const& p) { void solver::updt_params(params_ref const& p) {
m_config.updt_params(p); m_config.updt_params(p);
} }
@ -130,6 +151,8 @@ namespace euf {
} }
} }
m_egraph.end_explain(); m_egraph.end_explain();
TRACE("euf", tout << "eplain " << l << " <- " << r << " " << probing << "\n";);
DEBUG_CODE(for (auto lit : r) SASSERT(s().value(lit) == l_true););
if (!probing) if (!probing)
log_antecedents(l, r); log_antecedents(l, r);
} }
@ -150,6 +173,7 @@ namespace euf {
expr* e = nullptr; expr* e = nullptr;
euf::enode* n = nullptr; euf::enode* n = nullptr;
if (!probing && !m_drating)
init_ackerman(); init_ackerman();
switch (j.kind()) { switch (j.kind()) {
@ -185,7 +209,7 @@ namespace euf {
} }
bool sign = l.sign(); bool sign = l.sign();
TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << " " << (sign ? "not ": " ") << e->get_id() << "\n";); TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << "\n";);
euf::enode* n = m_egraph.find(e); euf::enode* n = m_egraph.find(e);
if (!n) if (!n)
return; return;
@ -230,6 +254,7 @@ namespace euf {
break; break;
propagated = true; propagated = true;
} }
DEBUG_CODE(if (!s().inconsistent()) check_missing_eq_propagation(););
return propagated; return propagated;
} }
@ -255,11 +280,19 @@ namespace euf {
cnstr = lit_constraint().to_index(); cnstr = lit_constraint().to_index();
lit = literal(v, m.is_false(b)); lit = literal(v, m.is_false(b));
} }
unsigned lvl = s().scope_lvl();
CTRACE("euf", s().value(lit) != l_true, tout << lit << " " << s().value(lit) << "@" << lvl << " " << is_eq << " " << mk_bounded_pp(a, m) << " = " << mk_bounded_pp(b, m) << "\n";);
if (s().value(lit) == l_false && m_ackerman) if (s().value(lit) == l_false && m_ackerman)
m_ackerman->cg_conflict_eh(a, b); m_ackerman->cg_conflict_eh(a, b);
unsigned lvl = s().scope_lvl(); switch (s().value(lit)) {
if (s().value(lit) != l_true) case l_true:
break;
case l_undef:
case l_false:
s().assign(lit, sat::justification::mk_ext_justification(lvl, cnstr)); s().assign(lit, sat::justification::mk_ext_justification(lvl, cnstr));
break;
}
} }
} }
@ -295,15 +328,15 @@ namespace euf {
bool cont = false; bool cont = false;
for (auto* e : m_solvers) for (auto* e : m_solvers)
switch (e->check()) { switch (e->check()) {
case sat::CR_CONTINUE: cont = true; break; case sat::check_result::CR_CONTINUE: cont = true; break;
case sat::CR_GIVEUP: give_up = true; break; case sat::check_result::CR_GIVEUP: give_up = true; break;
default: break; default: break;
} }
if (cont) if (cont)
return sat::CR_CONTINUE; return sat::check_result::CR_CONTINUE;
if (give_up) if (give_up)
return sat::CR_GIVEUP; return sat::check_result::CR_GIVEUP;
return sat::CR_DONE; return sat::check_result::CR_DONE;
} }
void solver::push() { void solver::push() {
@ -329,6 +362,7 @@ namespace euf {
m_trail.pop_scope(n); m_trail.pop_scope(n);
m_scopes.shrink(m_scopes.size() - n); m_scopes.shrink(m_scopes.size() - n);
si.pop(n); si.pop(n);
SASSERT(m_egraph.num_scopes() == m_scopes.size());
} }
void solver::start_reinit(unsigned n) { void solver::start_reinit(unsigned n) {
@ -356,7 +390,7 @@ namespace euf {
return; return;
si.set_expr2var_replay(&expr2var_replay); si.set_expr2var_replay(&expr2var_replay);
for (auto const& kv : expr2var_replay) for (auto const& kv : expr2var_replay)
si.internalize(kv.m_key, true); attach_lit(si.internalize(kv.m_key, true), kv.m_key);
si.set_expr2var_replay(nullptr); si.set_expr2var_replay(nullptr);
} }
@ -397,6 +431,7 @@ namespace euf {
if (n && n->merge_enabled()) if (n && n->merge_enabled())
ok = false; ok = false;
} }
TRACE("euf", tout << ok << " " << l << " -> " << r << "\n";);
return ok; return ok;
} }
@ -417,6 +452,13 @@ namespace euf {
return out; return out;
} }
std::ostream& solver::display_justification_ptr(std::ostream& out, size_t* j) const {
if (is_literal(j))
return out << get_literal(j) << " ";
else
return display_justification(out, get_justification(j)) << " ";
}
std::ostream& solver::display_justification(std::ostream& out, ext_justification_idx idx) const { std::ostream& solver::display_justification(std::ostream& out, ext_justification_idx idx) const {
auto* ext = sat::constraint_base::to_extension(idx); auto* ext = sat::constraint_base::to_extension(idx);
if (ext != this) if (ext != this)
@ -480,6 +522,7 @@ namespace euf {
return false; return false;
check_eqc_bool_assignment(); check_eqc_bool_assignment();
check_missing_bool_enode_propagation(); check_missing_bool_enode_propagation();
check_missing_eq_propagation();
m_egraph.invariant(); m_egraph.invariant();
return true; return true;
} }
@ -531,7 +574,7 @@ namespace euf {
void solver::init_ackerman() { void solver::init_ackerman() {
if (m_ackerman) if (m_ackerman)
return; return;
if (m_config.m_dack == DACK_DISABLED) if (m_config.m_dack == dyn_ack_strategy::DACK_DISABLED)
return; return;
m_ackerman = alloc(ackerman, *this, m); m_ackerman = alloc(ackerman, *this, m);
std::function<void(expr*,expr*,expr*)> used_eq = [&](expr* a, expr* b, expr* lca) { std::function<void(expr*,expr*,expr*)> used_eq = [&](expr* a, expr* b, expr* lca) {

View file

@ -70,7 +70,7 @@ namespace euf {
size_t* to_ptr(size_t jst) { return TAG(size_t*, reinterpret_cast<size_t*>(jst), 2); } size_t* to_ptr(size_t jst) { return TAG(size_t*, reinterpret_cast<size_t*>(jst), 2); }
bool is_literal(size_t* p) const { return GET_TAG(p) == 1; } bool is_literal(size_t* p) const { return GET_TAG(p) == 1; }
bool is_justification(size_t* p) const { return GET_TAG(p) == 2; } bool is_justification(size_t* p) const { return GET_TAG(p) == 2; }
sat::literal get_literal(size_t* p) { sat::literal get_literal(size_t* p) const {
unsigned idx = static_cast<unsigned>(reinterpret_cast<size_t>(UNTAG(size_t*, p))); unsigned idx = static_cast<unsigned>(reinterpret_cast<size_t>(UNTAG(size_t*, p)));
return sat::to_literal(idx >> 4); return sat::to_literal(idx >> 4);
} }
@ -87,7 +87,6 @@ namespace euf {
th_rewriter m_rewriter; th_rewriter m_rewriter;
func_decl_ref_vector m_unhandled_functions; func_decl_ref_vector m_unhandled_functions;
sat::solver* m_solver { nullptr }; sat::solver* m_solver { nullptr };
sat::lookahead* m_lookahead { nullptr }; sat::lookahead* m_lookahead { nullptr };
ast_manager* m_to_m; ast_manager* m_to_m;
@ -148,13 +147,16 @@ namespace euf {
// proofs // proofs
void log_antecedents(std::ostream& out, literal l, literal_vector const& r); void log_antecedents(std::ostream& out, literal l, literal_vector const& r);
void log_antecedents(literal l, literal_vector const& r); void log_antecedents(literal l, literal_vector const& r);
void log_node(expr* n);
bool m_drat_initialized{ false }; bool m_drat_initialized{ false };
void init_drat(); void init_drat();
// invariant // invariant
void check_eqc_bool_assignment() const; void check_eqc_bool_assignment() const;
void check_missing_bool_enode_propagation() const; void check_missing_bool_enode_propagation() const;
void check_missing_eq_propagation() const;
std::ostream& display_justification_ptr(std::ostream& out, size_t* j) const;
constraint& mk_constraint(constraint*& c, constraint::kind_t k); constraint& mk_constraint(constraint*& c, constraint::kind_t k);
constraint& conflict_constraint() { return mk_constraint(m_conflict, constraint::kind_t::conflict); } constraint& conflict_constraint() { return mk_constraint(m_conflict, constraint::kind_t::conflict); }
@ -162,21 +164,7 @@ namespace euf {
constraint& lit_constraint() { return mk_constraint(m_lit, constraint::kind_t::lit); } constraint& lit_constraint() { return mk_constraint(m_lit, constraint::kind_t::lit); }
public: public:
solver(ast_manager& m, sat::sat_internalizer& si, params_ref const& p = params_ref()): solver(ast_manager& m, sat::sat_internalizer& si, params_ref const& p = params_ref());
m(m),
si(si),
m_egraph(m),
m_trail(*this),
m_rewriter(m),
m_unhandled_functions(m),
m_solver(nullptr),
m_lookahead(nullptr),
m_to_m(&m),
m_to_si(&si),
m_reinit_exprs(m)
{
updt_params(p);
}
~solver() override { ~solver() override {
if (m_conflict) dealloc(sat::constraint_base::mem2base_ptr(m_conflict)); if (m_conflict) dealloc(sat::constraint_base::mem2base_ptr(m_conflict));
@ -267,6 +255,7 @@ namespace euf {
void unhandled_function(func_decl* f); void unhandled_function(func_decl* f);
th_rewriter& get_rewriter() { return m_rewriter; } th_rewriter& get_rewriter() { return m_rewriter; }
bool is_shared(euf::enode* n) const; bool is_shared(euf::enode* n) const;
void drat_log_node(expr* n);
void update_model(model_ref& mdl); void update_model(model_ref& mdl);

View file

@ -31,17 +31,17 @@ namespace euf {
loop: loop:
if (!m.inc()) if (!m.inc())
throw tactic_exception(m.limit().get_cancel_msg()); throw tactic_exception(m.limit().get_cancel_msg());
sat::eframe& fr = m_stack.back(); unsigned fsz = m_stack.size();
expr* e = fr.m_e; expr* e = m_stack[fsz-1].m_e;
if (visited(e)) { if (visited(e)) {
m_stack.pop_back(); m_stack.pop_back();
continue; continue;
} }
unsigned num = is_app(e) ? to_app(e)->get_num_args() : 0; unsigned num = is_app(e) ? to_app(e)->get_num_args() : 0;
while (fr.m_idx < num) { while (m_stack[fsz - 1].m_idx < num) {
expr* arg = to_app(e)->get_arg(fr.m_idx); expr* arg = to_app(e)->get_arg(m_stack[fsz - 1].m_idx);
fr.m_idx++; m_stack[fsz - 1].m_idx++;
if (!visit(arg)) if (!visit(arg))
goto loop; goto loop;
} }
@ -120,25 +120,27 @@ namespace euf {
} }
} }
void th_euf_solver::add_unit(sat::literal lit) { bool th_euf_solver::add_unit(sat::literal lit) {
ctx.s().add_clause(1, &lit, sat::status::th(m_is_redundant, get_id())); return !is_true(lit) && (ctx.s().add_clause(1, &lit, sat::status::th(m_is_redundant, get_id())), true);
} }
void th_euf_solver::add_clause(sat::literal a, sat::literal b) { bool th_euf_solver::add_clause(sat::literal a, sat::literal b) {
sat::literal lits[2] = { a, b }; sat::literal lits[2] = { a, b };
ctx.s().add_clause(2, lits, sat::status::th(m_is_redundant, get_id())); return !is_true(a, b) && (ctx.s().add_clause(2, lits, sat::status::th(m_is_redundant, get_id())), true);
} }
void th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c) { bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c) {
sat::literal lits[3] = { a, b, c }; sat::literal lits[3] = { a, b, c };
ctx.s().add_clause(3, lits, sat::status::th(m_is_redundant, get_id())); return !is_true(a, b, c) && (ctx.s().add_clause(3, lits, sat::status::th(m_is_redundant, get_id())), true);
} }
void th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d) { bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d) {
sat::literal lits[4] = { a, b, c, d }; sat::literal lits[4] = { a, b, c, d };
ctx.s().add_clause(4, lits, sat::status::th(m_is_redundant, get_id())); return !is_true(a, b, c, d) && (ctx.s().add_clause(4, lits, sat::status::th(m_is_redundant, get_id())), true);
} }
bool th_euf_solver::is_true(sat::literal lit) { return ctx.s().value(lit) == l_true; }
euf::enode* th_euf_solver::mk_enode(expr* e, bool suppress_args) { euf::enode* th_euf_solver::mk_enode(expr* e, bool suppress_args) {
m_args.reset(); m_args.reset();
if (!suppress_args) if (!suppress_args)
@ -146,15 +148,9 @@ namespace euf {
m_args.push_back(expr2enode(arg)); m_args.push_back(expr2enode(arg));
euf::enode* n = ctx.mk_enode(e, m_args.size(), m_args.c_ptr()); euf::enode* n = ctx.mk_enode(e, m_args.size(), m_args.c_ptr());
ctx.attach_node(n); ctx.attach_node(n);
if (m.is_bool(e)) {
sat::bool_var v = ctx.get_si().add_bool_var(e);
NOT_IMPLEMENTED_YET();
// TODO: ctx.attach_lit(literal(v, false), e);
}
return n; return n;
} }
void th_euf_solver::rewrite(expr_ref& a) { void th_euf_solver::rewrite(expr_ref& a) {
ctx.get_rewriter()(a); ctx.get_rewriter()(a);
} }

View file

@ -86,11 +86,8 @@ namespace euf {
class th_solver : public sat::extension, public th_model_builder, public th_decompile, public th_internalizer { class th_solver : public sat::extension, public th_model_builder, public th_decompile, public th_internalizer {
protected: protected:
ast_manager & m; ast_manager & m;
theory_id m_id;
public: public:
th_solver(ast_manager& m, euf::theory_id id): m(m), m_id(id) {} th_solver(ast_manager& m, euf::theory_id id): extension(id), m(m) {}
unsigned get_id() const override { return m_id; }
virtual th_solver* fresh(sat::solver* s, euf::solver& ctx) = 0; virtual th_solver* fresh(sat::solver* s, euf::solver& ctx) = 0;
@ -115,11 +112,16 @@ namespace euf {
region& get_region(); region& get_region();
void add_unit(sat::literal lit); bool add_unit(sat::literal lit);
void add_clause(sat::literal lit) { add_unit(lit); } bool add_clause(sat::literal lit) { return add_unit(lit); }
void add_clause(sat::literal a, sat::literal b); bool add_clause(sat::literal a, sat::literal b);
void add_clause(sat::literal a, sat::literal b, sat::literal c); bool add_clause(sat::literal a, sat::literal b, sat::literal c);
void add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d); bool add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d);
bool is_true(sat::literal lit);
bool is_true(sat::literal a, sat::literal b) { return is_true(a) || is_true(b); }
bool is_true(sat::literal a, sat::literal b, sat::literal c) { return is_true(a) || is_true(b, c); }
bool is_true(sat::literal a, sat::literal b, sat::literal c, sat::literal d) { return is_true(a) || is_true(b, c, c); }
euf::enode* e_internalize(expr* e) { internalize(e, m_is_redundant); return expr2enode(e); } euf::enode* e_internalize(expr* e) { internalize(e, m_is_redundant); return expr2enode(e); }
euf::enode* mk_enode(expr* e, bool suppress_args); euf::enode* mk_enode(expr* e, bool suppress_args);

View file

@ -22,105 +22,12 @@ Revision History:
#include "sat/sat_simplifier_params.hpp" #include "sat/sat_simplifier_params.hpp"
#include "sat/sat_xor_finder.h" #include "sat/sat_xor_finder.h"
namespace sat { namespace sat {
ba_solver::xr& ba_solver::constraint::to_xr() {
SASSERT(is_xr());
return static_cast<xr&>(*this);
}
ba_solver::xr const& ba_solver::constraint::to_xr() const{
SASSERT(is_xr());
return static_cast<xr const&>(*this);
}
ba_solver::xr::xr(unsigned id, literal_vector const& lits):
constraint(xr_t, id, null_literal, lits.size(), get_obj_size(lits.size())) {
for (unsigned i = 0; i < size(); ++i) {
m_lits[i] = lits[i];
}
}
bool ba_solver::xr::is_watching(literal l) const {
return
l == (*this)[0] || l == (*this)[1] ||
~l == (*this)[0] || ~l == (*this)[1];
}
bool ba_solver::xr::well_formed() const {
uint_set vars;
if (lit() != null_literal) vars.insert(lit().var());
for (literal l : *this) {
bool_var v = l.var();
if (vars.contains(v)) return false;
vars.insert(v);
}
return true;
}
// -------------------- // --------------------
// xr: // xr:
void ba_solver::clear_watch(xr& x) {
x.clear_watch();
unwatch_literal(x[0], x);
unwatch_literal(x[1], x);
unwatch_literal(~x[0], x);
unwatch_literal(~x[1], x);
}
bool ba_solver::parity(xr const& x, unsigned offset) const {
bool odd = false;
unsigned sz = x.size();
for (unsigned i = offset; i < sz; ++i) {
SASSERT(value(x[i]) != l_undef);
if (value(x[i]) == l_true) {
odd = !odd;
}
}
return odd;
}
bool ba_solver::init_watch(xr& x) {
clear_watch(x);
VERIFY(x.lit() == null_literal);
TRACE("ba", display(tout, x, true););
unsigned sz = x.size();
unsigned j = 0;
for (unsigned i = 0; i < sz && j < 2; ++i) {
if (value(x[i]) == l_undef) {
x.swap(i, j);
++j;
}
}
switch (j) {
case 0:
if (!parity(x, 0)) {
unsigned l = lvl(x[0]);
j = 1;
for (unsigned i = 1; i < sz; ++i) {
if (lvl(x[i]) > l) {
j = i;
l = lvl(x[i]);
}
}
set_conflict(x, x[j]);
}
return false;
case 1:
SASSERT(x.lit() == null_literal || value(x.lit()) == l_true);
assign(x, parity(x, 1) ? ~x[0] : x[0]);
return false;
default:
SASSERT(j == 2);
watch_literal(x[0], x);
watch_literal(x[1], x);
watch_literal(~x[0], x);
watch_literal(~x[1], x);
return true;
}
}
lbool ba_solver::add_assign(xr& x, literal alit) { lbool ba_solver::add_assign(xr& x, literal alit) {
// literal is assigned // literal is assigned
unsigned sz = x.size(); unsigned sz = x.size();
@ -136,10 +43,10 @@ namespace sat {
literal lit = x[i]; literal lit = x[i];
if (value(lit) == l_undef) { if (value(lit) == l_undef) {
x.swap(index, i); x.swap(index, i);
unwatch_literal(~alit, x); x.unwatch_literal(*this, ~alit);
// alit gets unwatched by propagate_core because we return l_undef // alit gets unwatched by propagate_core because we return l_undef
watch_literal(lit, x); x.watch_literal(*this, lit);
watch_literal(~lit, x); x.watch_literal(*this, ~lit);
TRACE("ba", tout << "swap in: " << lit << " " << x << "\n";); TRACE("ba", tout << "swap in: " << lit << " " << x << "\n";);
return l_undef; return l_undef;
} }
@ -150,10 +57,10 @@ namespace sat {
// alit resides at index 1. // alit resides at index 1.
VERIFY(x[1].var() == alit.var()); VERIFY(x[1].var() == alit.var());
if (value(x[0]) == l_undef) { if (value(x[0]) == l_undef) {
bool p = parity(x, 1); bool p = x.parity(*this, 1);
assign(x, p ? ~x[0] : x[0]); assign(x, p ? ~x[0] : x[0]);
} }
else if (!parity(x, 0)) { else if (!x.parity(*this, 0)) {
set_conflict(x, ~x[1]); set_conflict(x, ~x[1]);
} }
return inconsistent() ? l_false : l_true; return inconsistent() ? l_false : l_true;
@ -232,7 +139,7 @@ namespace sat {
} }
ba_solver::constraint* ba_solver::add_xr(literal_vector const& _lits, bool learned) { constraint* ba_solver::add_xr(literal_vector const& _lits, bool learned) {
literal_vector lits; literal_vector lits;
u_map<bool> var2sign; u_map<bool> var2sign;
bool sign = false, odd = false; bool sign = false, odd = false;
@ -400,31 +307,6 @@ namespace sat {
} }
} }
lbool ba_solver::eval(xr const& x) const {
bool odd = false;
for (auto l : x) {
switch (value(l)) {
case l_true: odd = !odd; break;
case l_false: break;
default: return l_undef;
}
}
return odd ? l_true : l_false;
}
lbool ba_solver::eval(model const& m, xr const& x) const {
bool odd = false;
for (auto l : x) {
switch (value(m, l)) {
case l_true: odd = !odd; break;
case l_false: break;
default: return l_undef;
}
}
return odd ? l_true : l_false;
}
void ba_solver::pre_simplify(xor_finder& xf, constraint& c) { void ba_solver::pre_simplify(xor_finder& xf, constraint& c) {
if (c.is_xr() && c.size() <= xf.max_xor_size()) { if (c.is_xr() && c.size() <= xf.max_xor_size()) {
@ -532,30 +414,5 @@ namespace sat {
} }
} }
void ba_solver::display(std::ostream& out, xr const& x, bool values) const {
out << "xr: ";
for (literal l : x) {
out << l;
if (values) {
out << "@(" << value(l);
if (value(l) != l_undef) {
out << ":" << lvl(l);
}
out << ") ";
}
else {
out << " ";
}
}
out << "\n";
}
bool ba_solver::validate_unit_propagation(xr const& x, literal alit) const {
if (value(x.lit()) != l_true) return false;
for (unsigned i = 1; i < x.size(); ++i) {
if (value(x[i]) == l_undef) return false;
}
return true;
}
} }

View file

@ -102,7 +102,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
m_xor_solver = p.get_bool("xor_solver", false); m_xor_solver = p.get_bool("xor_solver", false);
m_euf = sp.euf(); m_euf = sp.euf();
m_drat = sp.drat_file() != symbol(); m_drat = sp.drat_file().is_non_empty_string();
} }
void throw_op_not_handled(std::string const& s) { void throw_op_not_handled(std::string const& s) {
@ -110,73 +110,73 @@ struct goal2sat::imp : public sat::sat_internalizer {
throw tactic_exception(std::move(s0)); throw tactic_exception(std::move(s0));
} }
sat::status mk_status() const {
return sat::status::th(m_is_redundant, m.get_basic_family_id());
}
void mk_clause(sat::literal l) { void mk_clause(sat::literal l) {
TRACE("goal2sat", tout << "mk_clause: " << l << "\n";); TRACE("goal2sat", tout << "mk_clause: " << l << "\n";);
m_solver.add_clause(1, &l, m_is_redundant ? sat::status::redundant() : sat::status::asserted()); m_solver.add_clause(1, &l, mk_status());
} }
void mk_clause(sat::literal l1, sat::literal l2) { void mk_clause(sat::literal l1, sat::literal l2) {
TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << "\n";); TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << "\n";);
m_solver.add_clause(l1, l2, m_is_redundant ? sat::status::redundant() : sat::status::asserted()); m_solver.add_clause(l1, l2, mk_status());
} }
void mk_clause(sat::literal l1, sat::literal l2, sat::literal l3) { void mk_clause(sat::literal l1, sat::literal l2, sat::literal l3) {
TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << " " << l3 << "\n";); TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << " " << l3 << "\n";);
m_solver.add_clause(l1, l2, l3, m_is_redundant ? sat::status::redundant() : sat::status::asserted()); m_solver.add_clause(l1, l2, l3, mk_status());
} }
void mk_clause(unsigned num, sat::literal * lits) { void mk_clause(unsigned num, sat::literal * lits) {
TRACE("goal2sat", tout << "mk_clause: "; for (unsigned i = 0; i < num; i++) tout << lits[i] << " "; tout << "\n";); TRACE("goal2sat", tout << "mk_clause: "; for (unsigned i = 0; i < num; i++) tout << lits[i] << " "; tout << "\n";);
m_solver.add_clause(num, lits, m_is_redundant ? sat::status::redundant() : sat::status::asserted()); m_solver.add_clause(num, lits, mk_status());
} }
void mk_root_clause(sat::literal l) { void mk_root_clause(sat::literal l) {
TRACE("goal2sat", tout << "mk_clause: " << l << "\n";); TRACE("goal2sat", tout << "mk_clause: " << l << "\n";);
m_solver.add_clause(1, &l, m_is_redundant ? sat::status::redundant() : sat::status::input()); m_solver.add_clause(1, &l, m_is_redundant ? mk_status() : sat::status::input());
} }
void mk_root_clause(sat::literal l1, sat::literal l2) { void mk_root_clause(sat::literal l1, sat::literal l2) {
TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << "\n";); TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << "\n";);
m_solver.add_clause(l1, l2, m_is_redundant ? sat::status::redundant() : sat::status::input()); m_solver.add_clause(l1, l2, m_is_redundant ? mk_status() : sat::status::input());
} }
void mk_root_clause(sat::literal l1, sat::literal l2, sat::literal l3) { void mk_root_clause(sat::literal l1, sat::literal l2, sat::literal l3) {
TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << " " << l3 << "\n";); TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << " " << l3 << "\n";);
m_solver.add_clause(l1, l2, l3, m_is_redundant ? sat::status::redundant() : sat::status::input()); m_solver.add_clause(l1, l2, l3, m_is_redundant ? mk_status() : sat::status::input());
} }
void mk_root_clause(unsigned num, sat::literal * lits) { void mk_root_clause(unsigned num, sat::literal * lits) {
TRACE("goal2sat", tout << "mk_clause: "; for (unsigned i = 0; i < num; i++) tout << lits[i] << " "; tout << "\n";); TRACE("goal2sat", tout << "mk_clause: "; for (unsigned i = 0; i < num; i++) tout << lits[i] << " "; tout << "\n";);
m_solver.add_clause(num, lits, m_is_redundant ? sat::status::redundant() : sat::status::input()); m_solver.add_clause(num, lits, m_is_redundant ? mk_status() : sat::status::input());
} }
sat::bool_var add_var(bool is_ext, expr* n) { sat::bool_var add_var(bool is_ext, expr* n) {
auto v = m_solver.add_var(is_ext); auto v = m_solver.add_var(is_ext);
log_node(v, n); log_node(n);
log_def(v, n);
return v; return v;
} }
void log_node(sat::bool_var v, expr* n) { void log_def(sat::bool_var v, expr* n) {
if (m_drat && m_solver.get_drat_ptr())
m_solver.get_drat_ptr()->bool_def(v, n->get_id());
}
void log_node(expr* n) {
if (m_drat && m_solver.get_drat_ptr()) { if (m_drat && m_solver.get_drat_ptr()) {
sat::drat* drat = m_solver.get_drat_ptr();
if (is_app(n)) { if (is_app(n)) {
app* a = to_app(n); for (expr* arg : *to_app(n))
std::stringstream strm; if (m.is_not(arg))
strm << mk_ismt2_func(a->get_decl(), m); log_node(arg);
drat->def_begin(n->get_id(), strm.str());
for (expr* arg : *a)
drat->def_add_arg(arg->get_id());
drat->def_end();
} }
else { ensure_euf()->drat_log_node(n);
IF_VERBOSE(0, verbose_stream() << "skipping DRAT of non-app\n");
}
drat->bool_def(v, n->get_id());
} }
} }
sat::literal mk_true() { sat::literal mk_true() {
if (m_true == sat::null_literal) { if (m_true == sat::null_literal) {
// create fake variable to represent true; // create fake variable to represent true;
@ -187,6 +187,9 @@ struct goal2sat::imp : public sat::sat_internalizer {
} }
sat::bool_var to_bool_var(expr* e) override { sat::bool_var to_bool_var(expr* e) override {
sat::literal l;
if (is_app(e) && m_cache.find(to_app(e), l) && !l.sign())
return l.var();
return m_map.to_bool_var(e); return m_map.to_bool_var(e);
} }
@ -264,9 +267,11 @@ struct goal2sat::imp : public sat::sat_internalizer {
else else
m_unhandled_funs.push_back(to_app(t)->get_decl()); m_unhandled_funs.push_back(to_app(t)->get_decl());
} }
bool ext = m_default_external || !is_uninterp_const(t) || m_interface_vars.contains(t);
v = mk_bool_var(t); v = mk_bool_var(t);
l = sat::literal(v, sign); l = sat::literal(v, sign);
bool ext = m_default_external || !is_uninterp_const(t) || m_interface_vars.contains(t);
if (ext)
m_solver.set_external(v);
TRACE("sat", tout << "new_var: " << v << ": " << mk_bounded_pp(t, m, 2) << " " << is_uninterp_const(t) << "\n";); TRACE("sat", tout << "new_var: " << v << ": " << mk_bounded_pp(t, m, 2) << " " << is_uninterp_const(t) << "\n";);
} }
} }
@ -275,8 +280,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
l = sat::literal(v, sign); l = sat::literal(v, sign);
m_solver.set_eliminated(v, false); m_solver.set_eliminated(v, false);
} }
if (root)
m_result_stack.reset();
SASSERT(l != sat::null_literal); SASSERT(l != sat::null_literal);
if (root) if (root)
mk_root_clause(l); mk_root_clause(l);
@ -354,8 +357,10 @@ struct goal2sat::imp : public sat::sat_internalizer {
} }
void convert_or(app * t, bool root, bool sign) { void convert_or(app * t, bool root, bool sign) {
TRACE("goal2sat", tout << "convert_or:\n" << mk_bounded_pp(t, m, 2) << "\n";); TRACE("goal2sat", tout << "convert_or:\n" << mk_bounded_pp(t, m, 2) << " root " << root << " stack " << m_result_stack.size() << "\n";);
unsigned num = t->get_num_args(); unsigned num = t->get_num_args();
SASSERT(num <= m_result_stack.size());
unsigned old_sz = m_result_stack.size() - num;
if (root) { if (root) {
SASSERT(num == m_result_stack.size()); SASSERT(num == m_result_stack.size());
if (sign) { if (sign) {
@ -369,7 +374,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
else { else {
mk_root_clause(m_result_stack.size(), m_result_stack.c_ptr()); mk_root_clause(m_result_stack.size(), m_result_stack.c_ptr());
} }
m_result_stack.reset(); m_result_stack.shrink(old_sz);
} }
else { else {
SASSERT(num <= m_result_stack.size()); SASSERT(num <= m_result_stack.size());
@ -393,7 +398,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
if (m_aig) { if (m_aig) {
m_aig->add_or(l, num, aig_lits.c_ptr()); m_aig->add_or(l, num, aig_lits.c_ptr());
} }
unsigned old_sz = m_result_stack.size() - num - 1;
m_result_stack.shrink(old_sz); m_result_stack.shrink(old_sz);
if (sign) if (sign)
l.neg(); l.neg();
@ -402,8 +406,11 @@ struct goal2sat::imp : public sat::sat_internalizer {
} }
void convert_and(app * t, bool root, bool sign) { void convert_and(app * t, bool root, bool sign) {
TRACE("goal2sat", tout << "convert_and:\n" << mk_ismt2_pp(t, m) << "\n";); TRACE("goal2sat", tout << "convert_and:\n" << mk_bounded_pp(t, m, 2) << " root: " << root << " result stack: " << m_result_stack.size() << "\n";);
unsigned num = t->get_num_args(); unsigned num = t->get_num_args();
unsigned old_sz = m_result_stack.size() - num;
SASSERT(num <= m_result_stack.size());
if (root) { if (root) {
if (sign) { if (sign) {
for (unsigned i = 0; i < num; ++i) { for (unsigned i = 0; i < num; ++i) {
@ -416,7 +423,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
mk_root_clause(m_result_stack[i]); mk_root_clause(m_result_stack[i]);
} }
} }
m_result_stack.reset(); m_result_stack.shrink(old_sz);
} }
else { else {
SASSERT(num <= m_result_stack.size()); SASSERT(num <= m_result_stack.size());
@ -445,7 +452,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
} }
if (sign) if (sign)
l.neg(); l.neg();
unsigned old_sz = m_result_stack.size() - num - 1;
m_result_stack.shrink(old_sz); m_result_stack.shrink(old_sz);
m_result_stack.push_back(l); m_result_stack.push_back(l);
TRACE("goal2sat", tout << m_result_stack << "\n";); TRACE("goal2sat", tout << m_result_stack << "\n";);
@ -458,6 +465,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
sat::literal c = m_result_stack[sz-3]; sat::literal c = m_result_stack[sz-3];
sat::literal t = m_result_stack[sz-2]; sat::literal t = m_result_stack[sz-2];
sat::literal e = m_result_stack[sz-1]; sat::literal e = m_result_stack[sz-1];
m_result_stack.shrink(sz - 3);
if (root) { if (root) {
SASSERT(sz == 3); SASSERT(sz == 3);
if (sign) { if (sign) {
@ -468,7 +476,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
mk_root_clause(~c, t); mk_root_clause(~c, t);
mk_root_clause(c, e); mk_root_clause(c, e);
} }
m_result_stack.reset();
} }
else { else {
sat::bool_var k = add_var(false, n); sat::bool_var k = add_var(false, n);
@ -485,7 +492,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
if (m_aig) m_aig->add_ite(l, c, t, e); if (m_aig) m_aig->add_ite(l, c, t, e);
if (sign) if (sign)
l.neg(); l.neg();
m_result_stack.shrink(sz-3);
m_result_stack.push_back(l); m_result_stack.push_back(l);
} }
} }
@ -496,6 +503,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
SASSERT(sz >= 2); SASSERT(sz >= 2);
sat::literal l2 = m_result_stack[sz - 1]; sat::literal l2 = m_result_stack[sz - 1];
sat::literal l1 = m_result_stack[sz - 2]; sat::literal l1 = m_result_stack[sz - 2];
m_result_stack.shrink(sz - 2);
if (root) { if (root) {
SASSERT(sz == 2); SASSERT(sz == 2);
if (sign) { if (sign) {
@ -505,7 +513,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
else { else {
mk_root_clause(~l1, l2); mk_root_clause(~l1, l2);
} }
m_result_stack.reset();
} }
else { else {
sat::bool_var k = add_var(false, t); sat::bool_var k = add_var(false, t);
@ -517,7 +524,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
mk_clause(~l2, l); mk_clause(~l2, l);
if (sign) if (sign)
l.neg(); l.neg();
m_result_stack.shrink(sz - 2);
m_result_stack.push_back(l); m_result_stack.push_back(l);
} }
} }
@ -528,6 +534,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
SASSERT(sz >= 2); SASSERT(sz >= 2);
sat::literal l1 = m_result_stack[sz-1]; sat::literal l1 = m_result_stack[sz-1];
sat::literal l2 = m_result_stack[sz-2]; sat::literal l2 = m_result_stack[sz-2];
m_result_stack.shrink(sz - 2);
if (root) { if (root) {
SASSERT(sz == 2); SASSERT(sz == 2);
if (sign) { if (sign) {
@ -538,7 +545,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
mk_root_clause(l1, ~l2); mk_root_clause(l1, ~l2);
mk_root_clause(~l1, l2); mk_root_clause(~l1, l2);
} }
m_result_stack.reset();
} }
else { else {
sat::bool_var k = add_var(false, t); sat::bool_var k = add_var(false, t);
@ -551,7 +557,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
if (m_aig) m_aig->add_iff(l, l1, l2); if (m_aig) m_aig->add_iff(l, l1, l2);
if (sign) if (sign)
l.neg(); l.neg();
m_result_stack.shrink(sz - 2);
m_result_stack.push_back(l); m_result_stack.push_back(l);
} }
} }
@ -570,7 +575,8 @@ struct goal2sat::imp : public sat::sat_internalizer {
return m_unhandled_funs; return m_unhandled_funs;
} }
void convert_euf(expr* e, bool root, bool sign) { euf::solver* ensure_euf() {
SASSERT(m_euf);
sat::extension* ext = m_solver.get_extension(); sat::extension* ext = m_solver.get_extension();
euf::solver* euf = nullptr; euf::solver* euf = nullptr;
if (!ext) { if (!ext) {
@ -584,9 +590,14 @@ struct goal2sat::imp : public sat::sat_internalizer {
} }
if (!euf) if (!euf)
throw default_exception("cannot convert to euf"); throw default_exception("cannot convert to euf");
return euf;
}
void convert_euf(expr* e, bool root, bool sign) {
SASSERT(m_euf);
TRACE("goal2sat", tout << "convert-euf " << mk_bounded_pp(e, m, 2) << " root " << root << "\n";);
euf::solver* euf = ensure_euf();
sat::literal lit = euf->internalize(e, sign, root, m_is_redundant); sat::literal lit = euf->internalize(e, sign, root, m_is_redundant);
if (root)
m_result_stack.reset();
if (lit == sat::null_literal) if (lit == sat::null_literal)
return; return;
if (root) if (root)
@ -597,7 +608,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
void convert_ba(app* t, bool root, bool sign) { void convert_ba(app* t, bool root, bool sign) {
SASSERT(!m_euf); SASSERT(!m_euf);
sat::extension* ext = m_solver.get_extension(); sat::extension* ext = dynamic_cast<sat::ba_solver*>(m_solver.get_extension());
euf::th_solver* th = nullptr; euf::th_solver* th = nullptr;
if (!ext) { if (!ext) {
th = alloc(sat::ba_solver, m, *this, pb.get_family_id()); th = alloc(sat::ba_solver, m, *this, pb.get_family_id());
@ -609,9 +620,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
SASSERT(th); SASSERT(th);
} }
auto lit = th->internalize(t, sign, root, m_is_redundant); auto lit = th->internalize(t, sign, root, m_is_redundant);
if (root)
m_result_stack.reset();
else
m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); m_result_stack.shrink(m_result_stack.size() - t->get_num_args());
if (lit == sat::null_literal) if (lit == sat::null_literal)
return; return;
@ -681,6 +689,10 @@ struct goal2sat::imp : public sat::sat_internalizer {
}; };
void process(expr* n, bool is_root, bool redundant) { void process(expr* n, bool is_root, bool redundant) {
TRACE("goal2sat", tout << "process-begin " << mk_bounded_pp(n, m, 3)
<< " root: " << is_root
<< " result-stack: " << m_result_stack.size()
<< " frame-stack: " << m_frame_stack.size() << "\n";);
flet<bool> _is_redundant(m_is_redundant, redundant); flet<bool> _is_redundant(m_is_redundant, redundant);
scoped_stack _sc(*this, is_root); scoped_stack _sc(*this, is_root);
unsigned sz = m_frame_stack.size(); unsigned sz = m_frame_stack.size();
@ -693,14 +705,16 @@ struct goal2sat::imp : public sat::sat_internalizer {
throw tactic_exception(m.limit().get_cancel_msg()); throw tactic_exception(m.limit().get_cancel_msg());
if (memory::get_allocation_size() > m_max_memory) if (memory::get_allocation_size() > m_max_memory)
throw tactic_exception(TACTIC_MAX_MEMORY_MSG); throw tactic_exception(TACTIC_MAX_MEMORY_MSG);
frame & fr = m_frame_stack.back(); unsigned fsz = m_frame_stack.size();
app * t = fr.m_t; frame const& _fr = m_frame_stack[fsz-1];
bool root = fr.m_root; app * t = _fr.m_t;
bool sign = fr.m_sign; bool root = _fr.m_root;
bool sign = _fr.m_sign;
TRACE("goal2sat_bug", tout << "result stack\n"; TRACE("goal2sat_bug", tout << "result stack\n";
tout << mk_ismt2_pp(t, m) << " root: " << root << " sign: " << sign << "\n"; tout << "ref-count: " << t->get_ref_count() << "\n";
tout << mk_bounded_pp(t, m, 3) << " root: " << root << " sign: " << sign << "\n";
tout << m_result_stack << "\n";); tout << m_result_stack << "\n";);
if (fr.m_idx == 0 && process_cached(t, root, sign)) { if (_fr.m_idx == 0 && process_cached(t, root, sign)) {
m_frame_stack.pop_back(); m_frame_stack.pop_back();
continue; continue;
} }
@ -715,27 +729,37 @@ struct goal2sat::imp : public sat::sat_internalizer {
continue; continue;
} }
unsigned num = t->get_num_args(); unsigned num = t->get_num_args();
while (fr.m_idx < num) { while (m_frame_stack[fsz-1].m_idx < num) {
expr * arg = t->get_arg(fr.m_idx); expr * arg = t->get_arg(m_frame_stack[fsz-1].m_idx);
fr.m_idx++; m_frame_stack[fsz - 1].m_idx++;
if (!visit(arg, false, false)) if (!visit(arg, false, false))
goto loop; goto loop;
TRACE("goal2sat_bug", tout << "visit " << mk_bounded_pp(t, m, 2) << " result stack: " << m_result_stack.size() << "\n";);
} }
TRACE("goal2sat_bug", tout << "converting\n"; TRACE("goal2sat_bug", tout << "converting\n";
tout << mk_ismt2_pp(t, m) << " root: " << root << " sign: " << sign << "\n"; tout << mk_bounded_pp(t, m, 2) << " root: " << root << " sign: " << sign << "\n";
tout << m_result_stack << "\n";); tout << m_result_stack << "\n";);
SASSERT(m_frame_stack.size() > sz);
convert(t, root, sign); convert(t, root, sign);
m_frame_stack.pop_back(); m_frame_stack.pop_back();
} }
TRACE("goal2sat", tout
<< "done process: " << mk_bounded_pp(n, m, 3)
<< " frame-stack: " << m_frame_stack.size()
<< " result-stack: " << m_result_stack.size() << "\n";);
} }
sat::literal internalize(expr* n, bool redundant) override { sat::literal internalize(expr* n, bool redundant) override {
unsigned sz = m_result_stack.size(); unsigned sz = m_result_stack.size();
(void)sz; (void)sz;
SASSERT(n->get_ref_count() > 0);
TRACE("goal2sat", tout << "internalize " << mk_bounded_pp(n, m, 2) << "\n";);
process(n, false, redundant); process(n, false, redundant);
SASSERT(m_result_stack.size() == sz + 1); SASSERT(m_result_stack.size() == sz + 1);
sat::literal result = m_result_stack.back(); sat::literal result = m_result_stack.back();
m_result_stack.pop_back(); m_result_stack.pop_back();
if (!result.sign() && m_map.to_bool_var(n) == sat::null_bool_var)
m_map.insert(n, result.var());
return result; return result;
} }
@ -766,8 +790,8 @@ struct goal2sat::imp : public sat::sat_internalizer {
} }
void process(expr * n) { void process(expr * n) {
m_result_stack.reset(); VERIFY(m_result_stack.empty());
TRACE("goal2sat", tout << "assert: "<< mk_pp(n, m) << "\n";); TRACE("goal2sat", tout << "assert: " << mk_bounded_pp(n, m, 3) << "\n";);
process(n, true, m_is_redundant); process(n, true, m_is_redundant);
CTRACE("goal2sat", !m_result_stack.empty(), tout << m_result_stack << "\n";); CTRACE("goal2sat", !m_result_stack.empty(), tout << m_result_stack << "\n";);
SASSERT(m_result_stack.empty()); SASSERT(m_result_stack.empty());

View file

@ -17,11 +17,14 @@ Copyright (c) 2020 Microsoft Corporation
class smt_checker { class smt_checker {
ast_manager& m; ast_manager& m;
sat::drat& m_drat;
expr_ref_vector const& m_b2e; expr_ref_vector const& m_b2e;
expr_ref_vector m_fresh_exprs; expr_ref_vector m_fresh_exprs;
expr_ref_vector m_core; expr_ref_vector m_core;
expr_ref_vector m_inputs;
params_ref m_params; params_ref m_params;
scoped_ptr<solver> m_solver; scoped_ptr<solver> m_lemma_solver, m_input_solver;
sat::literal_vector m_units;
expr* fresh(expr* e) { expr* fresh(expr* e) {
unsigned i = e->get_id(); unsigned i = e->get_id();
@ -59,29 +62,103 @@ class smt_checker {
m_core.push_back(fml); m_core.push_back(fml);
} }
} }
public:
smt_checker(expr_ref_vector const& b2e): expr_ref lit2expr(sat::literal lit) {
m(b2e.m()), m_b2e(b2e), m_fresh_exprs(m), m_core(m) { return expr_ref(lit.sign() ? m.mk_not(m_b2e[lit.var()]) : m_b2e[lit.var()], m);
m_solver = mk_smt_solver(m, m_params, symbol());
} }
void check_shallow(sat::literal_vector const& lits) { void add_units() {
unfold1(lits); auto const& units = m_drat.units();
m_solver->push(); for (unsigned i = m_units.size(); i < units.size(); ++i) {
for (auto* c : m_core) sat::literal lit = units[i];
m_solver->assert_expr(c); m_lemma_solver->assert_expr(lit2expr(lit));
lbool is_sat = m_solver->check_sat(); }
m_solver->pop(1); m_units.append(units.size() - m_units.size(), units.c_ptr() + m_units.size());
if (is_sat == l_true) { }
std::cout << "did not verify: " << lits << "\n" << m_core << "\n";
void check_assertion_redundant(sat::literal_vector const& input) {
expr_ref_vector args(m);
for (auto lit : input)
args.push_back(lit2expr(lit));
m_inputs.push_back(args.size() == 1 ? args.back() : m.mk_or(args));
m_input_solver->push();
for (auto lit : input) {
m_input_solver->assert_expr(lit2expr(~lit));
}
lbool is_sat = m_input_solver->check_sat();
if (is_sat != l_false) {
std::cout << "Failed to verify input\n";
exit(0);
}
m_input_solver->pop(1);
}
/**
* Validate a lemma using the following attempts:
* 1. check if it is propositional DRUP
* 2. establish the negation of literals is unsat using a limited unfolding.
* 3. check that it is DRUP modulo theories by taking propositional implicants from DRUP validation
*/
sat::literal_vector drup_units;
void check_clause(sat::literal_vector const& lits) {
add_units();
drup_units.reset();
if (m_drat.is_drup(lits.size(), lits.c_ptr(), drup_units)) {
std::cout << "drup\n";
return;
}
m_lemma_solver->push();
for (auto lit : drup_units)
m_lemma_solver->assert_expr(lit2expr(lit));
lbool is_sat = m_lemma_solver->check_sat();
if (is_sat != l_false) {
std::cout << "did not verify: " << lits << "\n";
for (sat::literal lit : lits) { for (sat::literal lit : lits) {
expr_ref e(m_b2e[lit.var()], m); std::cout << lit2expr(lit) << "\n";
if (lit.sign())
e = m.mk_not(e);
std::cout << e << " ";
} }
std::cout << "\n"; std::cout << "\n";
m_lemma_solver->display(std::cout);
exit(0);
} }
m_lemma_solver->pop(1);
std::cout << "smt\n";
check_assertion_redundant(lits);
}
public:
smt_checker(sat::drat& drat, expr_ref_vector const& b2e):
m(b2e.m()), m_drat(drat), m_b2e(b2e), m_fresh_exprs(m), m_core(m), m_inputs(m) {
m_lemma_solver = mk_smt_solver(m, m_params, symbol());
m_input_solver = mk_smt_solver(m, m_params, symbol());
}
void add(sat::literal_vector const& lits, sat::status const& st) {
for (sat::literal lit : lits)
while (lit.var() >= m_drat.get_solver().num_vars())
m_drat.get_solver().mk_var(true);
if (st.is_input())
check_assertion_redundant(lits);
else if (!st.is_sat() && !st.is_deleted())
check_clause(lits);
m_drat.add(lits, st);
}
/**
* Add an assertion from the source file
*/
void add_assertion(expr* a) {
m_input_solver->assert_expr(a);
}
void display_input() {
scoped_ptr<solver> s = mk_smt_solver(m, m_params, symbol());
for (auto* e : m_inputs)
s->assert_expr(e);
s->display(std::cout);
} }
}; };
@ -100,10 +177,12 @@ static void verify_smt(char const* drat_file, char const* smt_file) {
std::ifstream ins(drat_file); std::ifstream ins(drat_file);
dimacs::drat_parser drat(ins, std::cerr); dimacs::drat_parser drat(ins, std::cerr);
ast_manager& m = ctx.m();
std::function<int(char const* read_theory)> read_theory = [&](char const* r) { std::function<int(char const* read_theory)> read_theory = [&](char const* r) {
if (strcmp(r, "euf") == 0) return m.mk_family_id(symbol(r));
return ctx.m().get_basic_family_id(); };
return ctx.m().mk_family_id(symbol(r)); std::function<symbol(int)> write_theory = [&](int th) {
return m.get_family_name(th);
}; };
drat.set_read_theory(read_theory); drat.set_read_theory(read_theory);
params_ref p; params_ref p;
@ -113,43 +192,24 @@ static void verify_smt(char const* drat_file, char const* smt_file) {
sat::drat drat_checker(solver); sat::drat drat_checker(solver);
drat_checker.updt_config(); drat_checker.updt_config();
expr_ref_vector bool_var2expr(ctx.m()); expr_ref_vector bool_var2expr(m);
expr_ref_vector exprs(ctx.m()), args(ctx.m()); expr_ref_vector exprs(m), args(m), inputs(m);
func_decl* f = nullptr; func_decl* f = nullptr;
ptr_vector<sort> sorts; ptr_vector<sort> sorts;
smt_checker checker(bool_var2expr); smt_checker checker(drat_checker, bool_var2expr);
auto check_smt = [&](dimacs::drat_record const& r) { for (expr* a : ctx.assertions())
auto const& st = r.m_status; checker.add_assertion(a);
if (st.is_input())
;
else if (st.is_sat() && st.is_asserted()) {
std::cout << "Tseitin tautology " << r;
checker.check_shallow(r.m_lits);
}
else if (st.is_sat())
;
else if (st.is_deleted())
;
else {
std::cout << "check smt " << r;
checker.check_shallow(r.m_lits);
// TBD: shallow check may fail because it doesn't include
// all RUP units, whish are sometimes required.
}
};
for (auto const& r : drat) { for (auto const& r : drat) {
std::cout << r; std::cout << dimacs::drat_pp(r, write_theory);
std::cout.flush(); std::cout.flush();
switch (r.m_tag) { switch (r.m_tag) {
case dimacs::drat_record::tag_t::is_clause: case dimacs::drat_record::tag_t::is_clause:
for (sat::literal lit : r.m_lits) checker.add(r.m_lits, r.m_status);
while (lit.var() >= solver.num_vars()) if (drat_checker.inconsistent())
solver.mk_var(true); std::cout << "inconsistent\n";
drat_checker.add(r.m_lits, r.m_status);
check_smt(r);
break; break;
case dimacs::drat_record::tag_t::is_node: case dimacs::drat_record::tag_t::is_node:
args.reset(); args.reset();
@ -170,7 +230,7 @@ static void verify_smt(char const* drat_file, char const* smt_file) {
exprs.reserve(r.m_node_id+1); exprs.reserve(r.m_node_id+1);
exprs.set(r.m_node_id, ctx.m().mk_app(f, args.size(), args.c_ptr())); exprs.set(r.m_node_id, ctx.m().mk_app(f, args.size(), args.c_ptr()));
break; break;
case dimacs::drat_record::is_bool_def: case dimacs::drat_record::tag_t::is_bool_def:
bool_var2expr.reserve(r.m_node_id+1); bool_var2expr.reserve(r.m_node_id+1);
bool_var2expr.set(r.m_node_id, exprs.get(r.m_args[0])); bool_var2expr.set(r.m_node_id, exprs.get(r.m_args[0]));
break; break;
@ -182,6 +242,7 @@ static void verify_smt(char const* drat_file, char const* smt_file) {
statistics st; statistics st;
drat_checker.collect_statistics(st); drat_checker.collect_statistics(st);
std::cout << st << "\n"; std::cout << st << "\n";
} }

View file

@ -375,7 +375,7 @@ namespace smt {
} }
void dyn_ack_manager::propagate_eh() { void dyn_ack_manager::propagate_eh() {
if (m_params.m_dack == DACK_DISABLED) if (m_params.m_dack == dyn_ack_strategy::DACK_DISABLED)
return; return;
m_num_propagations_since_last_gc++; m_num_propagations_since_last_gc++;
if (m_num_propagations_since_last_gc > m_params.m_dack_gc) { if (m_num_propagations_since_last_gc > m_params.m_dack_gc) {
@ -407,7 +407,7 @@ namespace smt {
} }
void dyn_ack_manager::instantiate(app * n1, app * n2) { void dyn_ack_manager::instantiate(app * n1, app * n2) {
SASSERT(m_params.m_dack != DACK_DISABLED); SASSERT(m_params.m_dack != dyn_ack_strategy::DACK_DISABLED);
SASSERT(n1->get_decl() == n2->get_decl()); SASSERT(n1->get_decl() == n2->get_decl());
SASSERT(n1->get_num_args() == n2->get_num_args()); SASSERT(n1->get_num_args() == n2->get_num_args());
SASSERT(n1 != n2); SASSERT(n1 != n2);
@ -461,7 +461,7 @@ namespace smt {
void dyn_ack_manager::instantiate(app * n1, app * n2, app* r) { void dyn_ack_manager::instantiate(app * n1, app * n2, app* r) {
context& ctx = m_context; context& ctx = m_context;
SASSERT(m_params.m_dack != DACK_DISABLED); SASSERT(m_params.m_dack != dyn_ack_strategy::DACK_DISABLED);
SASSERT(n1 != n2 && n1 != r && n2 != r); SASSERT(n1 != n2 && n1 != r && n2 != r);
ctx.m_stats.m_num_dyn_ack++; ctx.m_stats.m_num_dyn_ack++;
TRACE("dyn_ack_inst", tout << "dyn_ack: " << n1->get_id() << " " << n2->get_id() << " " << r->get_id() << "\n";); TRACE("dyn_ack_inst", tout << "dyn_ack: " << n1->get_id() << " " << n2->get_id() << " " << r->get_id() << "\n";);

View file

@ -97,7 +97,7 @@ namespace smt {
\brief This method is invoked when the congruence rule was used during conflict resolution. \brief This method is invoked when the congruence rule was used during conflict resolution.
*/ */
void used_cg_eh(app * n1, app * n2) { void used_cg_eh(app * n1, app * n2) {
if (m_params.m_dack == DACK_CR) if (m_params.m_dack == dyn_ack_strategy::DACK_CR)
cg_eh(n1, n2); cg_eh(n1, n2);
} }
@ -105,7 +105,7 @@ namespace smt {
\brief This method is invoked when the congruence rule is the root of a conflict. \brief This method is invoked when the congruence rule is the root of a conflict.
*/ */
void cg_conflict_eh(app * n1, app * n2) { void cg_conflict_eh(app * n1, app * n2) {
if (m_params.m_dack == DACK_ROOT) if (m_params.m_dack == dyn_ack_strategy::DACK_ROOT)
cg_eh(n1, n2); cg_eh(n1, n2);
} }

View file

@ -25,11 +25,11 @@ namespace smt {
class fingerprint { class fingerprint {
protected: protected:
void * m_data; void* m_data{ nullptr };
unsigned m_data_hash; unsigned m_data_hash{ 0 };
expr* m_def; expr* m_def{ nullptr };
unsigned m_num_args; unsigned m_num_args{ 0 };
enode * * m_args; enode** m_args{ nullptr };
friend class fingerprint_set; friend class fingerprint_set;
fingerprint() {} fingerprint() {}

View file

@ -32,7 +32,7 @@ void dyn_ack_params::updt_params(params_ref const & _p) {
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; #define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
void dyn_ack_params::display(std::ostream & out) const { void dyn_ack_params::display(std::ostream & out) const {
DISPLAY_PARAM(m_dack); DISPLAY_PARAM((unsigned)m_dack);
DISPLAY_PARAM(m_dack_eq); DISPLAY_PARAM(m_dack_eq);
DISPLAY_PARAM(m_dack_factor); DISPLAY_PARAM(m_dack_factor);
DISPLAY_PARAM(m_dack_threshold); DISPLAY_PARAM(m_dack_threshold);

View file

@ -20,7 +20,7 @@ Revision History:
#include "util/params.h" #include "util/params.h"
enum dyn_ack_strategy { enum class dyn_ack_strategy {
DACK_DISABLED, DACK_DISABLED,
DACK_ROOT, // congruence is the root of the conflict DACK_ROOT, // congruence is the root of the conflict
DACK_CR // congruence used during conflict resolution DACK_CR // congruence used during conflict resolution
@ -36,7 +36,7 @@ struct dyn_ack_params {
public: public:
dyn_ack_params(params_ref const & p = params_ref()) : dyn_ack_params(params_ref const & p = params_ref()) :
m_dack(DACK_ROOT), m_dack(dyn_ack_strategy::DACK_ROOT),
m_dack_eq(false), m_dack_eq(false),
m_dack_factor(0.1), m_dack_factor(0.1),
m_dack_threshold(10), m_dack_threshold(10),

View file

@ -250,8 +250,8 @@ struct smt_params : public preprocessor_params,
m_random_var_freq(0.01), m_random_var_freq(0.01),
m_inv_decay(1.052), m_inv_decay(1.052),
m_clause_decay(1), m_clause_decay(1),
m_random_initial_activity(IA_RANDOM_WHEN_SEARCHING), m_random_initial_activity(initial_activity::IA_RANDOM_WHEN_SEARCHING),
m_phase_selection(PS_CACHING_CONSERVATIVE), m_phase_selection(phase_selection::PS_CACHING_CONSERVATIVE),
m_phase_caching_on(700), m_phase_caching_on(700),
m_phase_caching_off(100), m_phase_caching_off(100),
m_minimize_lemmas(true), m_minimize_lemmas(true),
@ -267,7 +267,7 @@ struct smt_params : public preprocessor_params,
m_ematching(true), m_ematching(true),
m_induction(false), m_induction(false),
m_clause_proof(false), m_clause_proof(false),
m_case_split_strategy(CS_ACTIVITY_DELAY_NEW), m_case_split_strategy(case_split_strategy::CS_ACTIVITY_DELAY_NEW),
m_rel_case_split_order(0), m_rel_case_split_order(0),
m_lookahead_diseq(false), m_lookahead_diseq(false),
m_theory_case_split(false), m_theory_case_split(false),
@ -275,13 +275,13 @@ struct smt_params : public preprocessor_params,
m_delay_units(false), m_delay_units(false),
m_delay_units_threshold(32), m_delay_units_threshold(32),
m_theory_resolve(false), m_theory_resolve(false),
m_restart_strategy(RS_IN_OUT_GEOMETRIC), m_restart_strategy(restart_strategy::RS_IN_OUT_GEOMETRIC),
m_restart_initial(100), m_restart_initial(100),
m_restart_factor(1.1), m_restart_factor(1.1),
m_restart_adaptive(true), m_restart_adaptive(true),
m_agility_factor(0.9999), m_agility_factor(0.9999),
m_restart_agility_threshold(0.18), m_restart_agility_threshold(0.18),
m_lemma_gc_strategy(LGC_FIXED), m_lemma_gc_strategy(lemma_gc_strategy::LGC_FIXED),
m_lemma_gc_half(false), m_lemma_gc_half(false),
m_recent_lemmas_size(100), m_recent_lemmas_size(100),
m_lemma_gc_initial(5000), m_lemma_gc_initial(5000),

View file

@ -50,11 +50,11 @@ void theory_arith_params::updt_params(params_ref const & _p) {
void theory_arith_params::display(std::ostream & out) const { void theory_arith_params::display(std::ostream & out) const {
DISPLAY_PARAM(m_arith_eq2ineq); DISPLAY_PARAM(m_arith_eq2ineq);
DISPLAY_PARAM(m_arith_process_all_eqs); DISPLAY_PARAM(m_arith_process_all_eqs);
DISPLAY_PARAM(m_arith_mode); DISPLAY_PARAM((unsigned)m_arith_mode);
DISPLAY_PARAM(m_arith_auto_config_simplex); //!< force simplex solver in auto_config DISPLAY_PARAM(m_arith_auto_config_simplex); //!< force simplex solver in auto_config
DISPLAY_PARAM(m_arith_blands_rule_threshold); DISPLAY_PARAM(m_arith_blands_rule_threshold);
DISPLAY_PARAM(m_arith_propagate_eqs); DISPLAY_PARAM(m_arith_propagate_eqs);
DISPLAY_PARAM(m_arith_bound_prop); DISPLAY_PARAM((unsigned)m_arith_bound_prop);
DISPLAY_PARAM(m_arith_stronger_lemmas); DISPLAY_PARAM(m_arith_stronger_lemmas);
DISPLAY_PARAM(m_arith_skip_rows_with_big_coeffs); DISPLAY_PARAM(m_arith_skip_rows_with_big_coeffs);
DISPLAY_PARAM(m_arith_max_lemma_size); DISPLAY_PARAM(m_arith_max_lemma_size);
@ -81,7 +81,7 @@ void theory_arith_params::display(std::ostream & out) const {
DISPLAY_PARAM(m_arith_pivot_strategy); DISPLAY_PARAM(m_arith_pivot_strategy);
DISPLAY_PARAM(m_arith_bounded_expansion); DISPLAY_PARAM(m_arith_bounded_expansion);
DISPLAY_PARAM(m_arith_add_binary_bounds); DISPLAY_PARAM(m_arith_add_binary_bounds);
DISPLAY_PARAM(m_arith_propagation_strategy); DISPLAY_PARAM((unsigned)m_arith_propagation_strategy);
DISPLAY_PARAM(m_arith_eq_bounds); DISPLAY_PARAM(m_arith_eq_bounds);
DISPLAY_PARAM(m_arith_lazy_adapter); DISPLAY_PARAM(m_arith_lazy_adapter);
DISPLAY_PARAM(m_arith_fixnum); DISPLAY_PARAM(m_arith_fixnum);

View file

@ -21,7 +21,7 @@ Revision History:
#include<climits> #include<climits>
#include "util/params.h" #include "util/params.h"
enum arith_solver_id { enum class arith_solver_id {
AS_NO_ARITH, // 0 AS_NO_ARITH, // 0
AS_DIFF_LOGIC, // 1 AS_DIFF_LOGIC, // 1
AS_OLD_ARITH, // 2 AS_OLD_ARITH, // 2
@ -31,13 +31,13 @@ enum arith_solver_id {
AS_NEW_ARITH // 6 AS_NEW_ARITH // 6
}; };
enum bound_prop_mode { enum class bound_prop_mode {
BP_NONE, BP_NONE,
BP_SIMPLE, // only used for implying literals BP_SIMPLE, // only used for implying literals
BP_REFINE // adds new literals, but only refines finite bounds BP_REFINE // adds new literals, but only refines finite bounds
}; };
enum arith_prop_strategy { enum class arith_prop_strategy {
ARITH_PROP_AGILITY, ARITH_PROP_AGILITY,
ARITH_PROP_PROPORTIONAL ARITH_PROP_PROPORTIONAL
}; };
@ -114,11 +114,11 @@ struct theory_arith_params {
theory_arith_params(params_ref const & p = params_ref()): theory_arith_params(params_ref const & p = params_ref()):
m_arith_eq2ineq(false), m_arith_eq2ineq(false),
m_arith_process_all_eqs(false), m_arith_process_all_eqs(false),
m_arith_mode(AS_NEW_ARITH), m_arith_mode(arith_solver_id::AS_NEW_ARITH),
m_arith_auto_config_simplex(false), m_arith_auto_config_simplex(false),
m_arith_blands_rule_threshold(1000), m_arith_blands_rule_threshold(1000),
m_arith_propagate_eqs(true), m_arith_propagate_eqs(true),
m_arith_bound_prop(BP_REFINE), m_arith_bound_prop(bound_prop_mode::BP_REFINE),
m_arith_stronger_lemmas(true), m_arith_stronger_lemmas(true),
m_arith_skip_rows_with_big_coeffs(true), m_arith_skip_rows_with_big_coeffs(true),
m_arith_max_lemma_size(128), m_arith_max_lemma_size(128),
@ -145,7 +145,7 @@ struct theory_arith_params {
m_arith_bounded_expansion(false), m_arith_bounded_expansion(false),
m_arith_pivot_strategy(arith_pivot_strategy::ARITH_PIVOT_SMALLEST), m_arith_pivot_strategy(arith_pivot_strategy::ARITH_PIVOT_SMALLEST),
m_arith_add_binary_bounds(false), m_arith_add_binary_bounds(false),
m_arith_propagation_strategy(ARITH_PROP_PROPORTIONAL), m_arith_propagation_strategy(arith_prop_strategy::ARITH_PROP_PROPORTIONAL),
m_arith_eq_bounds(false), m_arith_eq_bounds(false),
m_arith_lazy_adapter(false), m_arith_lazy_adapter(false),
m_arith_fixnum(false), m_arith_fixnum(false),

View file

@ -44,7 +44,7 @@ struct theory_array_params {
theory_array_params(): theory_array_params():
m_array_canonize_simplify(false), m_array_canonize_simplify(false),
m_array_simplify(true), m_array_simplify(true),
m_array_mode(AR_FULL), m_array_mode(array_solver_id::AR_FULL),
m_array_weak(false), m_array_weak(false),
m_array_extensional(true), m_array_extensional(true),
m_array_laziness(1), m_array_laziness(1),

View file

@ -36,7 +36,7 @@ struct theory_bv_params {
bool m_bv_enable_int2bv2int; bool m_bv_enable_int2bv2int;
bool m_bv_watch_diseq; bool m_bv_watch_diseq;
theory_bv_params(params_ref const & p = params_ref()): theory_bv_params(params_ref const & p = params_ref()):
m_bv_mode(BS_BLASTER), m_bv_mode(bv_solver_id::BS_BLASTER),
m_hi_div0(false), m_hi_div0(false),
m_bv_reflect(true), m_bv_reflect(true),
m_bv_lazy_le(false), m_bv_lazy_le(false),

View file

@ -111,9 +111,9 @@ namespace smt {
/* /*
state_graph for dead state detection, and associated methods state_graph for dead state detection, and associated methods
*/ */
state_graph m_state_graph;
ptr_addr_map<expr, unsigned> m_expr_to_state; ptr_addr_map<expr, unsigned> m_expr_to_state;
expr_ref_vector m_state_to_expr; expr_ref_vector m_state_to_expr;
state_graph m_state_graph;
/* map from uninterpreted regex constants to assigned regex expressions by EQ */ /* map from uninterpreted regex constants to assigned regex expressions by EQ */
// expr_map m_const_to_expr; // expr_map m_const_to_expr;
unsigned m_max_state_graph_size { 10000 }; unsigned m_max_state_graph_size { 10000 };

View file

@ -313,8 +313,8 @@ namespace smt {
// } // }
} }
else { else {
m_params.m_arith_bound_prop = BP_NONE; m_params.m_arith_bound_prop = bound_prop_mode::BP_NONE;
m_params.m_arith_propagation_strategy = ARITH_PROP_AGILITY; m_params.m_arith_propagation_strategy = arith_prop_strategy::ARITH_PROP_AGILITY;
m_params.m_arith_add_binary_bounds = true; m_params.m_arith_add_binary_bounds = true;
if (!st.m_has_rational && !m_params.m_model && st.arith_k_sum_is_small()) if (!st.m_has_rational && !m_params.m_model && st.arith_k_sum_is_small())
m_context.register_plugin(alloc(smt::theory_frdl, m_context)); m_context.register_plugin(alloc(smt::theory_frdl, m_context));
@ -524,7 +524,7 @@ namespace smt {
m_params.m_restart_factor = 1.5; m_params.m_restart_factor = 1.5;
} }
if (st.m_num_bin_clauses + st.m_num_units == st.m_num_clauses && st.m_cnf && st.m_arith_k_sum > rational(100000)) { if (st.m_num_bin_clauses + st.m_num_units == st.m_num_clauses && st.m_cnf && st.m_arith_k_sum > rational(100000)) {
m_params.m_arith_bound_prop = BP_NONE; m_params.m_arith_bound_prop = bound_prop_mode::BP_NONE;
m_params.m_arith_stronger_lemmas = false; m_params.m_arith_stronger_lemmas = false;
} }
setup_lra_arith(); setup_lra_arith();
@ -736,7 +736,7 @@ namespace smt {
} }
void setup::setup_i_arith() { void setup::setup_i_arith() {
if (AS_OLD_ARITH == m_params.m_arith_mode) { if (arith_solver_id::AS_OLD_ARITH == m_params.m_arith_mode) {
m_context.register_plugin(alloc(smt::theory_i_arith, m_context)); m_context.register_plugin(alloc(smt::theory_i_arith, m_context));
} }
else { else {
@ -745,7 +745,7 @@ namespace smt {
} }
void setup::setup_lra_arith() { void setup::setup_lra_arith() {
if (m_params.m_arith_mode == AS_OLD_ARITH) if (m_params.m_arith_mode == arith_solver_id::AS_OLD_ARITH)
m_context.register_plugin(alloc(smt::theory_mi_arith, m_context)); m_context.register_plugin(alloc(smt::theory_mi_arith, m_context));
else else
m_context.register_plugin(alloc(smt::theory_lra, m_context)); m_context.register_plugin(alloc(smt::theory_lra, m_context));
@ -753,10 +753,10 @@ namespace smt {
void setup::setup_mi_arith() { void setup::setup_mi_arith() {
switch (m_params.m_arith_mode) { switch (m_params.m_arith_mode) {
case AS_OPTINF: case arith_solver_id::AS_OPTINF:
m_context.register_plugin(alloc(smt::theory_inf_arith, m_context)); m_context.register_plugin(alloc(smt::theory_inf_arith, m_context));
break; break;
case AS_NEW_ARITH: case arith_solver_id::AS_NEW_ARITH:
setup_lra_arith(); setup_lra_arith();
break; break;
default: default:
@ -778,13 +778,13 @@ namespace smt {
bool int_only = !st.m_has_rational && !st.m_has_real && m_params.m_arith_int_only; bool int_only = !st.m_has_rational && !st.m_has_real && m_params.m_arith_int_only;
auto mode = m_params.m_arith_mode; auto mode = m_params.m_arith_mode;
if (m_logic == "QF_LIA") { if (m_logic == "QF_LIA") {
mode = AS_NEW_ARITH; mode = arith_solver_id::AS_NEW_ARITH;
} }
switch(mode) { switch(mode) {
case AS_NO_ARITH: case arith_solver_id::AS_NO_ARITH:
m_context.register_plugin(alloc(smt::theory_dummy, m_context, m_manager.mk_family_id("arith"), "no arithmetic")); m_context.register_plugin(alloc(smt::theory_dummy, m_context, m_manager.mk_family_id("arith"), "no arithmetic"));
break; break;
case AS_DIFF_LOGIC: case arith_solver_id::AS_DIFF_LOGIC:
m_params.m_arith_eq2ineq = true; m_params.m_arith_eq2ineq = true;
if (fixnum) { if (fixnum) {
if (int_only) if (int_only)
@ -799,7 +799,7 @@ namespace smt {
m_context.register_plugin(alloc(smt::theory_rdl, m_context)); m_context.register_plugin(alloc(smt::theory_rdl, m_context));
} }
break; break;
case AS_DENSE_DIFF_LOGIC: case arith_solver_id::AS_DENSE_DIFF_LOGIC:
m_params.m_arith_eq2ineq = true; m_params.m_arith_eq2ineq = true;
if (fixnum) { if (fixnum) {
if (int_only) if (int_only)
@ -814,23 +814,23 @@ namespace smt {
m_context.register_plugin(alloc(smt::theory_dense_mi, m_context)); m_context.register_plugin(alloc(smt::theory_dense_mi, m_context));
} }
break; break;
case AS_UTVPI: case arith_solver_id::AS_UTVPI:
m_params.m_arith_eq2ineq = true; m_params.m_arith_eq2ineq = true;
if (int_only) if (int_only)
m_context.register_plugin(alloc(smt::theory_iutvpi, m_context)); m_context.register_plugin(alloc(smt::theory_iutvpi, m_context));
else else
m_context.register_plugin(alloc(smt::theory_rutvpi, m_context)); m_context.register_plugin(alloc(smt::theory_rutvpi, m_context));
break; break;
case AS_OPTINF: case arith_solver_id::AS_OPTINF:
m_context.register_plugin(alloc(smt::theory_inf_arith, m_context)); m_context.register_plugin(alloc(smt::theory_inf_arith, m_context));
break; break;
case AS_OLD_ARITH: case arith_solver_id::AS_OLD_ARITH:
if (m_params.m_arith_int_only && int_only) if (m_params.m_arith_int_only && int_only)
m_context.register_plugin(alloc(smt::theory_i_arith, m_context)); m_context.register_plugin(alloc(smt::theory_i_arith, m_context));
else else
m_context.register_plugin(alloc(smt::theory_mi_arith, m_context)); m_context.register_plugin(alloc(smt::theory_mi_arith, m_context));
break; break;
case AS_NEW_ARITH: case arith_solver_id::AS_NEW_ARITH:
setup_lra_arith(); setup_lra_arith();
break; break;
default: default:

View file

@ -541,7 +541,7 @@ namespace smt {
int random_lower() const { return m_params.m_arith_random_lower; } int random_lower() const { return m_params.m_arith_random_lower; }
int random_upper() const { return m_params.m_arith_random_upper; } int random_upper() const { return m_params.m_arith_random_upper; }
unsigned blands_rule_threshold() const { return m_params.m_arith_blands_rule_threshold; } unsigned blands_rule_threshold() const { return m_params.m_arith_blands_rule_threshold; }
bound_prop_mode propagation_mode() const { return m_num_conflicts < m_params.m_arith_propagation_threshold ? m_params.m_arith_bound_prop : BP_NONE; } bound_prop_mode propagation_mode() const { return m_num_conflicts < m_params.m_arith_propagation_threshold ? m_params.m_arith_bound_prop : bound_prop_mode::BP_NONE; }
bool adaptive() const { return m_params.m_arith_adaptive; } bool adaptive() const { return m_params.m_arith_adaptive; }
double adaptive_assertion_threshold() const { return m_params.m_arith_adaptive_assertion_threshold; } double adaptive_assertion_threshold() const { return m_params.m_arith_adaptive_assertion_threshold; }
unsigned max_lemma_size() const { return m_params.m_arith_max_lemma_size; } unsigned max_lemma_size() const { return m_params.m_arith_max_lemma_size; }

View file

@ -1151,8 +1151,8 @@ namespace smt {
*/ */
template<typename Ext> template<typename Ext>
void theory_arith<Ext>::enable_record_conflict(expr* bound) { void theory_arith<Ext>::enable_record_conflict(expr* bound) {
m_params.m_arith_bound_prop = BP_NONE; m_params.m_arith_bound_prop = bound_prop_mode::BP_NONE;
SASSERT(propagation_mode() == BP_NONE); // bound propagation rules are not (yet) handled. SASSERT(propagation_mode() == bound_prop_mode::BP_NONE); // bound propagation rules are not (yet) handled.
if (bound) { if (bound) {
m_bound_watch = ctx.get_bool_var(bound); m_bound_watch = ctx.get_bool_var(bound);
} }

View file

@ -852,7 +852,7 @@ namespace smt {
SASSERT(!has_var_kind(get_var_row(s), BASE)); SASSERT(!has_var_kind(get_var_row(s), BASE));
} }
TRACE("init_row_bug", tout << "after:\n"; display_row_info(tout, r);); TRACE("init_row_bug", tout << "after:\n"; display_row_info(tout, r););
if (propagation_mode() != BP_NONE) if (propagation_mode() != bound_prop_mode::BP_NONE)
mark_row_for_bound_prop(r_id); mark_row_for_bound_prop(r_id);
SASSERT(r.is_coeff_of(s, numeral::one())); SASSERT(r.is_coeff_of(s, numeral::one()));
SASSERT(wf_row(r_id)); SASSERT(wf_row(r_id));
@ -1728,7 +1728,7 @@ namespace smt {
template<typename Ext> template<typename Ext>
void theory_arith<Ext>::add_row(unsigned rid1, const numeral & coeff, unsigned rid2, bool apply_gcd_test) { void theory_arith<Ext>::add_row(unsigned rid1, const numeral & coeff, unsigned rid2, bool apply_gcd_test) {
m_stats.m_add_rows++; m_stats.m_add_rows++;
if (propagation_mode() != BP_NONE) if (propagation_mode() != bound_prop_mode::BP_NONE)
mark_row_for_bound_prop(rid1); mark_row_for_bound_prop(rid1);
row & r1 = m_rows[rid1]; row & r1 = m_rows[rid1];
row & r2 = m_rows[rid2]; row & r2 = m_rows[rid2];
@ -2442,7 +2442,7 @@ namespace smt {
push_bound_trail(v, l, false); push_bound_trail(v, l, false);
set_bound(b, false); set_bound(b, false);
if (propagation_mode() != BP_NONE) if (propagation_mode() != bound_prop_mode::BP_NONE)
mark_rows_for_bound_prop(v); mark_rows_for_bound_prop(v);
return true; return true;
@ -2490,7 +2490,7 @@ namespace smt {
push_bound_trail(v, u, true); push_bound_trail(v, u, true);
set_bound(b, true); set_bound(b, true);
if (propagation_mode() != BP_NONE) if (propagation_mode() != bound_prop_mode::BP_NONE)
mark_rows_for_bound_prop(v); mark_rows_for_bound_prop(v);
return true; return true;

View file

@ -512,7 +512,7 @@ void theory_diff_logic<Ext>::propagate() {
switch (m_params.m_arith_propagation_strategy) { switch (m_params.m_arith_propagation_strategy) {
case ARITH_PROP_PROPORTIONAL: { case arith_prop_strategy::ARITH_PROP_PROPORTIONAL: {
++m_num_propagation_calls; ++m_num_propagation_calls;
if (m_num_propagation_calls * (m_stats.m_num_conflicts + 1) > if (m_num_propagation_calls * (m_stats.m_num_conflicts + 1) >
@ -526,7 +526,7 @@ void theory_diff_logic<Ext>::propagate() {
} }
break; break;
} }
case ARITH_PROP_AGILITY: { case arith_prop_strategy::ARITH_PROP_AGILITY: {
// update agility with factor generated by other conflicts. // update agility with factor generated by other conflicts.
double g = m_params.m_arith_adaptive_propagation_threshold; double g = m_params.m_arith_adaptive_propagation_threshold;

View file

@ -992,7 +992,7 @@ public:
smt_params_helper lpar(ctx().get_params()); smt_params_helper lpar(ctx().get_params());
lp().settings().set_resource_limit(m_resource_limit); lp().settings().set_resource_limit(m_resource_limit);
lp().settings().simplex_strategy() = static_cast<lp::simplex_strategy_enum>(lpar.arith_simplex_strategy()); lp().settings().simplex_strategy() = static_cast<lp::simplex_strategy_enum>(lpar.arith_simplex_strategy());
lp().settings().bound_propagation() = BP_NONE != propagation_mode(); lp().settings().bound_propagation() = bound_prop_mode::BP_NONE != propagation_mode();
lp().settings().enable_hnf() = lpar.arith_enable_hnf(); lp().settings().enable_hnf() = lpar.arith_enable_hnf();
lp().settings().print_external_var_name() = lpar.arith_print_ext_var_names(); lp().settings().print_external_var_name() = lpar.arith_print_ext_var_names();
lp().set_track_pivoted_rows(lpar.arith_bprop_on_pivoted_rows()); lp().set_track_pivoted_rows(lpar.arith_bprop_on_pivoted_rows());
@ -2320,11 +2320,11 @@ public:
} }
bool should_propagate() const { bool should_propagate() const {
return BP_NONE != propagation_mode(); return bound_prop_mode::BP_NONE != propagation_mode();
} }
bool should_refine_bounds() const { bool should_refine_bounds() const {
return BP_REFINE == propagation_mode() && ctx().at_search_level(); return bound_prop_mode::BP_REFINE == propagation_mode() && ctx().at_search_level();
} }
void consume(rational const& v, lp::constraint_index j) { void consume(rational const& v, lp::constraint_index j) {
@ -2807,7 +2807,7 @@ public:
// x <= hi -> ~(x >= hi') // x <= hi -> ~(x >= hi')
void propagate_bound(bool_var bv, bool is_true, lp_api::bound& b) { void propagate_bound(bool_var bv, bool is_true, lp_api::bound& b) {
if (BP_NONE == propagation_mode()) { if (bound_prop_mode::BP_NONE == propagation_mode()) {
return; return;
} }
lp_api::bound_kind k = b.get_bound_kind(); lp_api::bound_kind k = b.get_bound_kind();
@ -3113,7 +3113,7 @@ public:
bool propagate_eqs() const { return params().m_arith_propagate_eqs && m_num_conflicts < params().m_arith_propagation_threshold; } bool propagate_eqs() const { return params().m_arith_propagate_eqs && m_num_conflicts < params().m_arith_propagation_threshold; }
bound_prop_mode propagation_mode() const { return m_num_conflicts < params().m_arith_propagation_threshold ? params().m_arith_bound_prop : BP_NONE; } bound_prop_mode propagation_mode() const { return m_num_conflicts < params().m_arith_propagation_threshold ? params().m_arith_bound_prop : bound_prop_mode::BP_NONE; }
unsigned small_lemma_size() const { return params().m_arith_small_lemma_size; } unsigned small_lemma_size() const { return params().m_arith_small_lemma_size; }
@ -3568,10 +3568,10 @@ public:
struct scoped_arith_mode { struct scoped_arith_mode {
smt_params& p; smt_params& p;
scoped_arith_mode(smt_params& p) : p(p) { scoped_arith_mode(smt_params& p) : p(p) {
p.m_arith_mode = AS_OLD_ARITH; p.m_arith_mode = arith_solver_id::AS_OLD_ARITH;
} }
~scoped_arith_mode() { ~scoped_arith_mode() {
p.m_arith_mode = AS_NEW_ARITH; p.m_arith_mode = arith_solver_id::AS_NEW_ARITH;
} }
}; };
@ -3582,7 +3582,7 @@ public:
} }
bool validate_conflict(literal_vector const& core, svector<enode_pair> const& eqs) { bool validate_conflict(literal_vector const& core, svector<enode_pair> const& eqs) {
if (params().m_arith_mode != AS_NEW_ARITH) return true; if (params().m_arith_mode != arith_solver_id::AS_NEW_ARITH) return true;
scoped_arith_mode _sa(ctx().get_fparams()); scoped_arith_mode _sa(ctx().get_fparams());
context nctx(m, ctx().get_fparams(), ctx().get_params()); context nctx(m, ctx().get_fparams(), ctx().get_params());
add_background(nctx); add_background(nctx);
@ -3601,7 +3601,7 @@ public:
} }
bool validate_assign(literal lit, literal_vector const& core, svector<enode_pair> const& eqs) { bool validate_assign(literal lit, literal_vector const& core, svector<enode_pair> const& eqs) {
if (params().m_arith_mode != AS_NEW_ARITH) return true; if (params().m_arith_mode != arith_solver_id::AS_NEW_ARITH) return true;
scoped_arith_mode _sa(ctx().get_fparams()); scoped_arith_mode _sa(ctx().get_fparams());
context nctx(m, ctx().get_fparams(), ctx().get_params()); context nctx(m, ctx().get_fparams(), ctx().get_params());
m_core.push_back(~lit); m_core.push_back(~lit);
@ -3616,7 +3616,7 @@ public:
} }
bool validate_eq(enode* x, enode* y) { bool validate_eq(enode* x, enode* y) {
if (params().m_arith_mode == AS_NEW_ARITH) return true; if (params().m_arith_mode == arith_solver_id::AS_NEW_ARITH) return true;
context nctx(m, ctx().get_fparams(), ctx().get_params()); context nctx(m, ctx().get_fparams(), ctx().get_params());
add_background(nctx); add_background(nctx);
nctx.assert_expr(m.mk_not(m.mk_eq(x->get_owner(), y->get_owner()))); nctx.assert_expr(m.mk_not(m.mk_eq(x->get_owner(), y->get_owner())));

View file

@ -1791,7 +1791,7 @@ void theory_seq::collect_statistics(::statistics & st) const {
void theory_seq::init_search_eh() { void theory_seq::init_search_eh() {
auto as = get_fparams().m_arith_mode; auto as = get_fparams().m_arith_mode;
if (m_has_seq && as != AS_OLD_ARITH && as != AS_NEW_ARITH) { if (m_has_seq && as != arith_solver_id::AS_OLD_ARITH && as != arith_solver_id::AS_NEW_ARITH) {
throw default_exception("illegal arithmetic solver used with string solver"); throw default_exception("illegal arithmetic solver used with string solver");
} }
} }

View file

@ -20,11 +20,13 @@ static expr_ref mk_app(char const* name, expr_ref const& arg, sort* s) {
return expr_ref(m.mk_app(f, arg.get()), m); return expr_ref(m.mk_app(f, arg.get()), m);
} }
#if 0
static expr_ref mk_app(char const* name, expr_ref const& arg1, expr_ref const& arg2, sort* s) { static expr_ref mk_app(char const* name, expr_ref const& arg1, expr_ref const& arg2, sort* s) {
ast_manager& m = arg1.m(); ast_manager& m = arg1.m();
func_decl_ref f(m.mk_func_decl(symbol(name), m.get_sort(arg1), m.get_sort(arg2), s), m); func_decl_ref f(m.mk_func_decl(symbol(name), m.get_sort(arg1), m.get_sort(arg2), s), m);
return expr_ref(m.mk_app(f, arg1.get(), arg2.get()), m); return expr_ref(m.mk_app(f, arg1.get(), arg2.get()), m);
} }
#endif
static void test1() { static void test1() {
ast_manager m; ast_manager m;

View file

@ -74,10 +74,9 @@ static void tst2(unsigned num_bits) {
} }
} }
#if 0
// prints all don't care pareto fronts for 8-bit multiplier. // prints all don't care pareto fronts for 8-bit multiplier.
static void test_dc() { static void test_dc() {
unsigned a = 0;
unsigned b = 0;
unsigned num_bits = 8; unsigned num_bits = 8;
unsigned num_vals = 1 << num_bits; unsigned num_vals = 1 << num_bits;
tbv_manager m(num_bits*2); tbv_manager m(num_bits*2);
@ -134,6 +133,7 @@ static void test_dc() {
m.deallocate(t); m.deallocate(t);
} }
#endif
void tst_tbv() { void tst_tbv() {
// test_dc(); // test_dc();

View file

@ -97,7 +97,7 @@ public:
// command invocation // command invocation
void set_line_pos(int line, int pos) { m_line = line; m_pos = pos; } void set_line_pos(int line, int pos) { m_line = line; m_pos = pos; }
virtual void prepare(cmd_context & ctx) {} virtual void prepare(cmd_context & ctx) {}
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { UNREACHABLE(); return CPK_UINT; } virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { UNREACHABLE(); return cmd_arg_kind::CPK_UINT; }
virtual void set_next_arg(cmd_context & ctx, unsigned val) { UNREACHABLE(); } virtual void set_next_arg(cmd_context & ctx, unsigned val) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, bool val) { UNREACHABLE(); } virtual void set_next_arg(cmd_context & ctx, bool val) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, rational const & val) { UNREACHABLE(); } virtual void set_next_arg(cmd_context & ctx, rational const & val) { UNREACHABLE(); }

View file

@ -29,7 +29,7 @@ struct sexpr_composite : public sexpr {
unsigned m_num_chilren; unsigned m_num_chilren;
sexpr * m_children[0]; sexpr * m_children[0];
sexpr_composite(unsigned num_children, sexpr * const * children, unsigned line, unsigned pos): sexpr_composite(unsigned num_children, sexpr * const * children, unsigned line, unsigned pos):
sexpr(COMPOSITE, line, pos), sexpr(kind_t::COMPOSITE, line, pos),
m_num_chilren(num_children) { m_num_chilren(num_children) {
for (unsigned i = 0; i < num_children; i++) { for (unsigned i = 0; i < num_children; i++) {
m_children[i] = children[i]; m_children[i] = children[i];
@ -45,7 +45,7 @@ struct sexpr_numeral : public sexpr {
m_val(val) { m_val(val) {
} }
sexpr_numeral(rational const & val, unsigned line, unsigned pos): sexpr_numeral(rational const & val, unsigned line, unsigned pos):
sexpr(NUMERAL, line, pos), sexpr(kind_t::NUMERAL, line, pos),
m_val(val) { m_val(val) {
} }
}; };
@ -53,7 +53,7 @@ struct sexpr_numeral : public sexpr {
struct sexpr_bv : public sexpr_numeral { struct sexpr_bv : public sexpr_numeral {
unsigned m_size; unsigned m_size;
sexpr_bv(rational const & val, unsigned size, unsigned line, unsigned pos): sexpr_bv(rational const & val, unsigned size, unsigned line, unsigned pos):
sexpr_numeral(BV_NUMERAL, val, line, pos), sexpr_numeral(kind_t::BV_NUMERAL, val, line, pos),
m_size(size) { m_size(size) {
} }
}; };
@ -61,11 +61,11 @@ struct sexpr_bv : public sexpr_numeral {
struct sexpr_string : public sexpr { struct sexpr_string : public sexpr {
std::string m_val; std::string m_val;
sexpr_string(std::string const & val, unsigned line, unsigned pos): sexpr_string(std::string const & val, unsigned line, unsigned pos):
sexpr(STRING, line, pos), sexpr(kind_t::STRING, line, pos),
m_val(val) { m_val(val) {
} }
sexpr_string(char const * val, unsigned line, unsigned pos): sexpr_string(char const * val, unsigned line, unsigned pos):
sexpr(STRING, line, pos), sexpr(kind_t::STRING, line, pos),
m_val(val) { m_val(val) {
} }
}; };
@ -73,7 +73,7 @@ struct sexpr_string : public sexpr {
struct sexpr_symbol : public sexpr { struct sexpr_symbol : public sexpr {
symbol m_val; symbol m_val;
sexpr_symbol(bool keyword, symbol const & val, unsigned line, unsigned pos): sexpr_symbol(bool keyword, symbol const & val, unsigned line, unsigned pos):
sexpr(keyword ? KEYWORD : SYMBOL, line, pos), sexpr(keyword ? kind_t::KEYWORD : kind_t::SYMBOL, line, pos),
m_val(val) { m_val(val) {
} }
}; };
@ -122,12 +122,12 @@ sexpr * const * sexpr::get_children() const {
void sexpr::display_atom(std::ostream & out) const { void sexpr::display_atom(std::ostream & out) const {
switch (get_kind()) { switch (get_kind()) {
case sexpr::COMPOSITE: case sexpr::kind_t::COMPOSITE:
UNREACHABLE(); UNREACHABLE();
case sexpr::NUMERAL: case sexpr::kind_t::NUMERAL:
out << static_cast<sexpr_numeral const *>(this)->m_val; out << static_cast<sexpr_numeral const *>(this)->m_val;
break; break;
case sexpr::BV_NUMERAL: { case sexpr::kind_t::BV_NUMERAL: {
out << '#'; out << '#';
unsigned bv_size = static_cast<sexpr_bv const *>(this)->m_size; unsigned bv_size = static_cast<sexpr_bv const *>(this)->m_size;
rational val = static_cast<sexpr_bv const *>(this)->m_val; rational val = static_cast<sexpr_bv const *>(this)->m_val;
@ -172,11 +172,11 @@ void sexpr::display_atom(std::ostream & out) const {
out << buf.c_ptr(); out << buf.c_ptr();
break; break;
} }
case sexpr::STRING: case sexpr::kind_t::STRING:
out << "\"" << escaped(static_cast<sexpr_string const *>(this)->m_val.c_str()) << "\""; out << "\"" << escaped(static_cast<sexpr_string const *>(this)->m_val.c_str()) << "\"";
break; break;
case sexpr::SYMBOL: case sexpr::kind_t::SYMBOL:
case sexpr::KEYWORD: case sexpr::kind_t::KEYWORD:
out << static_cast<sexpr_symbol const *>(this)->m_val; out << static_cast<sexpr_symbol const *>(this)->m_val;
break; break;
default: default:
@ -220,7 +220,7 @@ void sexpr_manager::del(sexpr * n) {
sexpr * n = m_to_delete.back(); sexpr * n = m_to_delete.back();
m_to_delete.pop_back(); m_to_delete.pop_back();
switch (n->get_kind()) { switch (n->get_kind()) {
case sexpr::COMPOSITE: { case sexpr::kind_t::COMPOSITE: {
unsigned num = n->get_num_children(); unsigned num = n->get_num_children();
for (unsigned i = 0; i < num; i++) { for (unsigned i = 0; i < num; i++) {
sexpr * child = n->get_child(i); sexpr * child = n->get_child(i);
@ -233,20 +233,20 @@ void sexpr_manager::del(sexpr * n) {
m_allocator.deallocate(sizeof(sexpr_composite) + num * sizeof(sexpr*), n); m_allocator.deallocate(sizeof(sexpr_composite) + num * sizeof(sexpr*), n);
break; break;
} }
case sexpr::NUMERAL: case sexpr::kind_t::NUMERAL:
static_cast<sexpr_numeral*>(n)->~sexpr_numeral(); static_cast<sexpr_numeral*>(n)->~sexpr_numeral();
m_allocator.deallocate(sizeof(sexpr_numeral), n); m_allocator.deallocate(sizeof(sexpr_numeral), n);
break; break;
case sexpr::BV_NUMERAL: case sexpr::kind_t::BV_NUMERAL:
static_cast<sexpr_bv*>(n)->~sexpr_bv(); static_cast<sexpr_bv*>(n)->~sexpr_bv();
m_allocator.deallocate(sizeof(sexpr_bv), n); m_allocator.deallocate(sizeof(sexpr_bv), n);
break; break;
case sexpr::STRING: case sexpr::kind_t::STRING:
static_cast<sexpr_string*>(n)->~sexpr_string(); static_cast<sexpr_string*>(n)->~sexpr_string();
m_allocator.deallocate(sizeof(sexpr_string), n); m_allocator.deallocate(sizeof(sexpr_string), n);
break; break;
case sexpr::SYMBOL: case sexpr::kind_t::SYMBOL:
case sexpr::KEYWORD: case sexpr::kind_t::KEYWORD:
static_cast<sexpr_symbol*>(n)->~sexpr_symbol(); static_cast<sexpr_symbol*>(n)->~sexpr_symbol();
m_allocator.deallocate(sizeof(sexpr_symbol), n); m_allocator.deallocate(sizeof(sexpr_symbol), n);
break; break;

View file

@ -27,7 +27,7 @@ class sexpr_manager;
class sexpr { class sexpr {
public: public:
enum kind_t { enum class kind_t {
COMPOSITE, NUMERAL, BV_NUMERAL, STRING, KEYWORD, SYMBOL COMPOSITE, NUMERAL, BV_NUMERAL, STRING, KEYWORD, SYMBOL
}; };
protected: protected:
@ -44,12 +44,12 @@ public:
unsigned get_line() const { return m_line; } unsigned get_line() const { return m_line; }
unsigned get_pos() const { return m_pos; } unsigned get_pos() const { return m_pos; }
kind_t get_kind() const { return m_kind; } kind_t get_kind() const { return m_kind; }
bool is_composite() const { return get_kind() == COMPOSITE; } bool is_composite() const { return get_kind() == kind_t::COMPOSITE; }
bool is_numeral() const { return get_kind() == NUMERAL; } bool is_numeral() const { return get_kind() == kind_t::NUMERAL; }
bool is_bv_numeral() const { return get_kind() == BV_NUMERAL; } bool is_bv_numeral() const { return get_kind() == kind_t::BV_NUMERAL; }
bool is_string() const { return get_kind() == STRING; } bool is_string() const { return get_kind() == kind_t::STRING; }
bool is_keyword() const { return get_kind() == KEYWORD; } bool is_keyword() const { return get_kind() == kind_t::KEYWORD; }
bool is_symbol() const { return get_kind() == SYMBOL; } bool is_symbol() const { return get_kind() == kind_t::SYMBOL; }
rational const & get_numeral() const; rational const & get_numeral() const;
unsigned get_bv_size() const; unsigned get_bv_size() const;
symbol get_symbol() const; symbol get_symbol() const;