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

ensure that bca takes also lemmas into account

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-10-27 15:40:25 -07:00
parent 0919fd4075
commit 829c140087
21 changed files with 384 additions and 149 deletions

View file

@ -1776,6 +1776,7 @@ void cmd_context::validate_model() {
continue; continue;
} }
TRACE("model_validate", model_smt2_pp(tout, *this, *(md.get()), 0);); TRACE("model_validate", model_smt2_pp(tout, *this, *(md.get()), 0););
IF_VERBOSE(10, verbose_stream() << "model check failed on: " << mk_pp(a, m()) << "\n";);
invalid_model = true; invalid_model = true;
} }
} }

View file

@ -115,6 +115,7 @@ namespace sat {
} }
bool asymm_branch::process(clause & c) { bool asymm_branch::process(clause & c) {
if (c.is_blocked()) return true;
TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";); TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";);
SASSERT(s.scope_lvl() == 0); SASSERT(s.scope_lvl() == 0);
SASSERT(s.m_qhead == s.m_trail.size()); SASSERT(s.m_qhead == s.m_trail.size());

View file

@ -60,15 +60,15 @@ namespace sat {
} }
bool clause::contains(literal l) const { bool clause::contains(literal l) const {
for (unsigned i = 0; i < m_size; i++) for (literal l2 : *this)
if (m_lits[i] == l) if (l2 == l)
return true; return true;
return false; return false;
} }
bool clause::contains(bool_var v) const { bool clause::contains(bool_var v) const {
for (unsigned i = 0; i < m_size; i++) for (literal l : *this)
if (m_lits[i].var() == v) if (l.var() == v)
return true; return true;
return false; return false;
} }
@ -87,8 +87,7 @@ namespace sat {
} }
bool clause::satisfied_by(model const & m) const { bool clause::satisfied_by(model const & m) const {
for (unsigned i = 0; i < m_size; i++) { for (literal l : *this) {
literal l = m_lits[i];
if (l.sign()) { if (l.sign()) {
if (m[l.var()] == l_false) if (m[l.var()] == l_false)
return true; return true;
@ -197,14 +196,13 @@ namespace sat {
if (c.was_removed()) out << "x"; if (c.was_removed()) out << "x";
if (c.strengthened()) out << "+"; if (c.strengthened()) out << "+";
if (c.is_learned()) out << "*"; if (c.is_learned()) out << "*";
if (c.is_blocked()) out << "b";
return out; return out;
} }
std::ostream & operator<<(std::ostream & out, clause_vector const & cs) { std::ostream & operator<<(std::ostream & out, clause_vector const & cs) {
clause_vector::const_iterator it = cs.begin(); for (clause *cp : cs) {
clause_vector::const_iterator end = cs.end(); out << *cp << "\n";
for (; it != end; ++it) {
out << *(*it) << "\n";
} }
return out; return out;
} }
@ -226,12 +224,12 @@ namespace sat {
} }
std::ostream & operator<<(std::ostream & out, clause_wrapper const & c) { std::ostream & operator<<(std::ostream & out, clause_wrapper const & c) {
out << "("; if (c.is_binary()) {
for (unsigned i = 0; i < c.size(); i++) { out << "(" << c[0] << " " << c[1] << ")";
if (i > 0) out << " "; }
out << c[i]; else {
out << c.get_clause()->id() << ": " << *c.get_clause();
} }
out << ")";
return out; return out;
} }

View file

@ -33,6 +33,10 @@ namespace sat {
class clause_allocator; class clause_allocator;
class clause;
std::ostream & operator<<(std::ostream & out, clause const & c);
class clause { class clause {
friend class clause_allocator; friend class clause_allocator;
friend class tmp_clause; friend class tmp_clause;
@ -61,8 +65,8 @@ namespace sat {
literal & operator[](unsigned idx) { SASSERT(idx < m_size); return m_lits[idx]; } literal & operator[](unsigned idx) { SASSERT(idx < m_size); return m_lits[idx]; }
literal const & operator[](unsigned idx) const { SASSERT(idx < m_size); return m_lits[idx]; } literal const & operator[](unsigned idx) const { SASSERT(idx < m_size); return m_lits[idx]; }
bool is_learned() const { return m_learned; } bool is_learned() const { return m_learned; }
void unset_learned() { SASSERT(is_learned()); m_learned = false; } void unset_learned() { if (id() == 642277) std::cout << "unlearn " << *this << "\n"; SASSERT(is_learned()); m_learned = false; }
void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; mark_strengthened(); } } void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; mark_strengthened(); if (id() == 642277) std::cout << "shrink " << *this << "\n"; } }
bool strengthened() const { return m_strengthened; } bool strengthened() const { return m_strengthened; }
void mark_strengthened() { m_strengthened = true; update_approx(); } void mark_strengthened() { m_strengthened = true; update_approx(); }
void unmark_strengthened() { m_strengthened = false; } void unmark_strengthened() { m_strengthened = false; }
@ -101,7 +105,6 @@ namespace sat {
void set_reinit_stack(bool f) { m_reinit_stack = f; } void set_reinit_stack(bool f) { m_reinit_stack = f; }
}; };
std::ostream & operator<<(std::ostream & out, clause const & c);
std::ostream & operator<<(std::ostream & out, clause_vector const & cs); std::ostream & operator<<(std::ostream & out, clause_vector const & cs);
class bin_clause { class bin_clause {
@ -180,6 +183,7 @@ namespace sat {
bool contains(literal l) const; bool contains(literal l) const;
bool contains(bool_var v) const; bool contains(bool_var v) const;
clause * get_clause() const { SASSERT(!is_binary()); return m_cls; } clause * get_clause() const { SASSERT(!is_binary()); return m_cls; }
bool was_removed() const { return !is_binary() && get_clause()->was_removed(); }
}; };
typedef svector<clause_wrapper> clause_wrapper_vector; typedef svector<clause_wrapper> clause_wrapper_vector;

View file

@ -137,6 +137,7 @@ namespace sat {
SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef);
if (new_sz == 2) { if (new_sz == 2) {
TRACE("cleanup_bug", tout << "clause became binary: " << c[0] << " " << c[1] << "\n";); TRACE("cleanup_bug", tout << "clause became binary: " << c[0] << " " << c[1] << "\n";);
if (!c.is_blocked())
s.mk_bin_clause(c[0], c[1], c.is_learned()); s.mk_bin_clause(c[0], c[1], c.is_learned());
s.del_clause(c); s.del_clause(c);
} }

View file

@ -146,9 +146,10 @@ namespace sat {
m_minimize_lemmas = p.minimize_lemmas(); m_minimize_lemmas = p.minimize_lemmas();
m_core_minimize = p.core_minimize(); m_core_minimize = p.core_minimize();
m_core_minimize_partial = p.core_minimize_partial(); m_core_minimize_partial = p.core_minimize_partial();
m_drat_check = p.drat_check(); m_drat_check_unsat = p.drat_check_unsat();
m_drat_check_sat = p.drat_check_sat();
m_drat_file = p.drat_file(); m_drat_file = p.drat_file();
m_drat = (m_drat_check || m_drat_file != symbol("")) && p.threads() == 1; m_drat = (m_drat_check_unsat || m_drat_file != symbol("") || m_drat_check_sat) && p.threads() == 1;
m_dyn_sub_res = p.dyn_sub_res(); m_dyn_sub_res = p.dyn_sub_res();
// Parameters used in Liang, Ganesh, Poupart, Czarnecki AAAI 2016. // Parameters used in Liang, Ganesh, Poupart, Czarnecki AAAI 2016.

View file

@ -105,7 +105,8 @@ namespace sat {
bool m_core_minimize_partial; bool m_core_minimize_partial;
bool m_drat; bool m_drat;
symbol m_drat_file; symbol m_drat_file;
bool m_drat_check; bool m_drat_check_unsat;
bool m_drat_check_sat;
bool m_dimacs_display; bool m_dimacs_display;
bool m_dimacs_inprocess_display; bool m_dimacs_inprocess_display;

View file

@ -27,7 +27,10 @@ namespace sat {
drat::drat(solver& s): drat::drat(solver& s):
s(s), s(s),
m_out(0), m_out(0),
m_inconsistent(false) m_inconsistent(false),
m_check_unsat(false),
m_check_sat(false),
m_check(false)
{ {
if (s.m_config.m_drat && s.m_config.m_drat_file != symbol()) { if (s.m_config.m_drat && s.m_config.m_drat_file != symbol()) {
m_out = alloc(std::ofstream, s.m_config.m_drat_file.str().c_str()); m_out = alloc(std::ofstream, s.m_config.m_drat_file.str().c_str());
@ -44,6 +47,12 @@ namespace sat {
} }
} }
void drat::updt_config() {
m_check_unsat = s.m_config.m_drat_check_unsat;
m_check_sat = s.m_config.m_drat_check_sat;
m_check = m_check_unsat || m_check_sat;
}
std::ostream& operator<<(std::ostream& out, drat::status st) { std::ostream& operator<<(std::ostream& out, drat::status st) {
switch (st) { switch (st) {
case drat::status::learned: return out << "l"; case drat::status::learned: return out << "l";
@ -88,7 +97,7 @@ namespace sat {
} }
void drat::append(literal l, status st) { void drat::append(literal l, status st) {
IF_VERBOSE(10, trace(verbose_stream(), 1, &l, st);); IF_VERBOSE(20, trace(verbose_stream(), 1, &l, st););
if (st == status::learned) { if (st == status::learned) {
verify(1, &l); verify(1, &l);
} }
@ -100,7 +109,7 @@ namespace sat {
void drat::append(literal l1, literal l2, status st) { void drat::append(literal l1, literal l2, status st) {
literal lits[2] = { l1, l2 }; literal lits[2] = { l1, l2 };
IF_VERBOSE(10, trace(verbose_stream(), 2, lits, st);); IF_VERBOSE(20, trace(verbose_stream(), 2, lits, st););
if (st == status::deleted) { if (st == status::deleted) {
// noop // noop
// don't record binary as deleted. // don't record binary as deleted.
@ -131,7 +140,7 @@ namespace sat {
void drat::append(clause& c, status st) { void drat::append(clause& c, status st) {
unsigned n = c.size(); unsigned n = c.size();
IF_VERBOSE(10, trace(verbose_stream(), n, c.begin(), st);); IF_VERBOSE(20, trace(verbose_stream(), n, c.begin(), st););
if (st == status::learned) { if (st == status::learned) {
verify(n, c.begin()); verify(n, c.begin());
@ -270,7 +279,7 @@ namespace sat {
} }
void drat::verify(unsigned n, literal const* c) { void drat::verify(unsigned n, literal const* c) {
if (!is_drup(n, c) && !is_drat(n, c)) { if (m_check_unsat && !is_drup(n, c) && !is_drat(n, c)) {
std::cout << "Verification failed\n"; std::cout << "Verification failed\n";
UNREACHABLE(); UNREACHABLE();
//display(std::cout); //display(std::cout);
@ -412,7 +421,7 @@ namespace sat {
void drat::add() { void drat::add() {
if (m_out) (*m_out) << "0\n"; if (m_out) (*m_out) << "0\n";
if (s.m_config.m_drat_check) { if (m_check_unsat) {
SASSERT(m_inconsistent); SASSERT(m_inconsistent);
} }
} }
@ -420,7 +429,7 @@ namespace sat {
declare(l); declare(l);
status st = get_status(learned); status st = get_status(learned);
if (m_out) dump(1, &l, st); if (m_out) dump(1, &l, st);
if (s.m_config.m_drat_check) append(l, st); if (m_check) append(l, st);
} }
void drat::add(literal l1, literal l2, bool learned) { void drat::add(literal l1, literal l2, bool learned) {
declare(l1); declare(l1);
@ -428,17 +437,17 @@ namespace sat {
literal ls[2] = {l1, l2}; literal ls[2] = {l1, l2};
status st = get_status(learned); status st = get_status(learned);
if (m_out) dump(2, ls, st); if (m_out) dump(2, ls, st);
if (s.m_config.m_drat_check) append(l1, l2, st); if (m_check) append(l1, l2, st);
} }
void drat::add(clause& c, bool learned) { void drat::add(clause& c, bool learned) {
TRACE("sat", tout << "add: " << c << "\n";); TRACE("sat", tout << "add: " << c << "\n";);
for (unsigned i = 0; i < c.size(); ++i) declare(c[i]); for (unsigned i = 0; i < c.size(); ++i) declare(c[i]);
status st = get_status(learned); status st = get_status(learned);
if (m_out) dump(c.size(), c.begin(), st); if (m_out) dump(c.size(), c.begin(), st);
if (s.m_config.m_drat_check) append(c, get_status(learned)); if (m_check_unsat) append(c, get_status(learned));
} }
void drat::add(literal_vector const& lits, svector<premise> const& premises) { void drat::add(literal_vector const& lits, svector<premise> const& premises) {
if (s.m_config.m_drat_check) { if (m_check) {
switch (lits.size()) { switch (lits.size()) {
case 0: add(); break; case 0: add(); break;
case 1: append(lits[0], status::external); break; case 1: append(lits[0], status::external); break;
@ -453,7 +462,7 @@ namespace sat {
void drat::add(literal_vector const& c) { void drat::add(literal_vector const& c) {
for (unsigned i = 0; i < c.size(); ++i) declare(c[i]); for (unsigned i = 0; i < c.size(); ++i) declare(c[i]);
if (m_out) dump(c.size(), c.begin(), status::learned); if (m_out) dump(c.size(), c.begin(), status::learned);
if (s.m_config.m_drat_check) { if (m_check) {
switch (c.size()) { switch (c.size()) {
case 0: add(); break; case 0: add(); break;
case 1: append(c[0], status::learned); break; case 1: append(c[0], status::learned); break;
@ -469,20 +478,25 @@ namespace sat {
void drat::del(literal l) { void drat::del(literal l) {
if (m_out) dump(1, &l, status::deleted); if (m_out) dump(1, &l, status::deleted);
if (s.m_config.m_drat_check) append(l, status::deleted); if (m_check_unsat) append(l, status::deleted);
} }
void drat::del(literal l1, literal l2) { void drat::del(literal l1, literal l2) {
literal ls[2] = {l1, l2}; literal ls[2] = {l1, l2};
if (m_out) dump(2, ls, status::deleted); if (m_out) dump(2, ls, status::deleted);
if (s.m_config.m_drat_check) if (m_check)
append(l1, l2, status::deleted); append(l1, l2, status::deleted);
} }
void drat::del(clause& c) { void drat::del(clause& c) {
TRACE("sat", tout << "del: " << c << "\n";); TRACE("sat", tout << "del: " << c << "\n";);
if (m_out) dump(c.size(), c.begin(), status::deleted); if (m_out) dump(c.size(), c.begin(), status::deleted);
if (s.m_config.m_drat_check) { if (m_check) {
clause* c1 = s.m_cls_allocator.mk_clause(c.size(), c.begin(), c.is_learned()); clause* c1 = s.m_cls_allocator.mk_clause(c.size(), c.begin(), c.is_learned());
append(*c1, status::deleted); append(*c1, status::deleted);
} }
} }
void drat::check_model(model const& m) {
std::cout << "check model on " << m_proof.size() << "\n";
}
} }

View file

@ -52,6 +52,7 @@ namespace sat {
vector<watch> m_watches; vector<watch> m_watches;
svector<lbool> m_assignment; svector<lbool> m_assignment;
bool m_inconsistent; bool m_inconsistent;
bool m_check_unsat, m_check_sat, m_check;
void dump(unsigned n, literal const* c, status st); void dump(unsigned n, literal const* c, status st);
void append(literal l, status st); void append(literal l, status st);
@ -78,6 +79,8 @@ namespace sat {
public: public:
drat(solver& s); drat(solver& s);
~drat(); ~drat();
void updt_config();
void add(); void add();
void add(literal l, bool learned); void add(literal l, bool learned);
void add(literal l1, literal l2, bool learned); void add(literal l1, literal l2, bool learned);
@ -89,6 +92,8 @@ namespace sat {
void del(literal l); void del(literal l);
void del(literal l1, literal l2); void del(literal l1, literal l2);
void del(clause& c); void del(clause& c);
void check_model(model const& m);
}; };
}; };

View file

@ -246,8 +246,8 @@ namespace sat {
inline bool is_true(literal l) const { return is_true_at(l, m_level); } inline bool is_true(literal l) const { return is_true_at(l, m_level); }
inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); } inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); }
inline void set_undef(literal l) { m_stamp[l.var()] = 0; } inline void set_undef(literal l) { m_stamp[l.var()] = 0; }
inline unsigned get_level(literal l) const { return m_stamp[l.var()] & UINT_MAX - 1; } inline unsigned get_level(literal l) const { return m_stamp[l.var()] & ~0x1; }
void set_level(literal d, literal s) { m_stamp[d.var()] = (m_stamp[s.var()] & ~0x1) + d.sign(); } void set_level(literal d, literal s) { m_stamp[d.var()] = get_level(s) + d.sign(); }
lbool value(literal l) const { return is_undef(l) ? l_undef : is_true(l) ? l_true : l_false; } lbool value(literal l) const { return is_undef(l) ? l_undef : is_true(l) ? l_true : l_false; }
// set the level within a scope of the search. // set the level within a scope of the search.

View file

@ -18,11 +18,12 @@ Revision History:
--*/ --*/
#include "sat/sat_model_converter.h" #include "sat/sat_model_converter.h"
#include "sat/sat_clause.h" #include "sat/sat_clause.h"
#include "sat/sat_solver.h"
#include "util/trace.h" #include "util/trace.h"
namespace sat { namespace sat {
model_converter::model_converter() { model_converter::model_converter(): m_solver(nullptr) {
} }
model_converter::~model_converter() { model_converter::~model_converter() {
@ -50,7 +51,6 @@ namespace sat {
} }
if (!sat) { if (!sat) {
m[lit.var()] = lit.sign() ? l_false : l_true; m[lit.var()] = lit.sign() ? l_false : l_true;
// if (lit.var() == 258007) std::cout << "flip " << lit << " " << m[lit.var()] << " @ " << i << " of " << c << " from overall size " << sz << "\n";
} }
} }
} }
@ -58,6 +58,8 @@ namespace sat {
void model_converter::operator()(model & m) const { void model_converter::operator()(model & m) const {
vector<entry>::const_iterator begin = m_entries.begin(); vector<entry>::const_iterator begin = m_entries.begin();
vector<entry>::const_iterator it = m_entries.end(); vector<entry>::const_iterator it = m_entries.end();
bool first = true;
VERIFY(!m_solver || m_solver->check_clauses(m));
while (it != begin) { while (it != begin) {
--it; --it;
SASSERT(it->get_kind() != ELIM_VAR || m[it->var()] == l_undef); SASSERT(it->get_kind() != ELIM_VAR || m[it->var()] == l_undef);
@ -70,14 +72,18 @@ namespace sat {
for (literal l : it->m_clauses) { for (literal l : it->m_clauses) {
if (l == null_literal) { if (l == null_literal) {
// end of clause // end of clause
elim_stack* s = it->m_elim_stack[index]; elim_stack* st = it->m_elim_stack[index];
if (!sat) { if (!sat) {
m[it->var()] = var_sign ? l_false : l_true; m[it->var()] = var_sign ? l_false : l_true;
} }
if (s) { if (st) {
process_stack(m, clause, s->stack()); process_stack(m, clause, st->stack());
} }
sat = false; sat = false;
if (first && m_solver && !m_solver->check_clauses(m)) {
display(std::cout, *it) << "\n";
first = false;
}
++index; ++index;
clause.reset(); clause.reset();
continue; continue;
@ -95,8 +101,12 @@ namespace sat {
else if (!sat && v != it->var() && m[v] == l_undef) { else if (!sat && v != it->var() && m[v] == l_undef) {
// clause can be satisfied by assigning v. // clause can be satisfied by assigning v.
m[v] = sign ? l_false : l_true; m[v] = sign ? l_false : l_true;
// if (v == 258007) std::cout << "set undef " << v << " to " << m[v] << " in " << clause << "\n"; // if (first) std::cout << "set: " << l << "\n";
sat = true; sat = true;
if (first && m_solver && !m_solver->check_clauses(m)) {
display(std::cout, *it) << "\n";;
first = false;
}
} }
} }
DEBUG_CODE({ DEBUG_CODE({
@ -217,10 +227,12 @@ namespace sat {
it2++; it2++;
for (; it2 != end; ++it2) { for (; it2 != end; ++it2) {
SASSERT(it2->var() != it->var()); SASSERT(it2->var() != it->var());
if (it2->var() == it->var()) return false;
for (literal l : it2->m_clauses) { for (literal l : it2->m_clauses) {
CTRACE("sat_model_converter", l.var() == it->var(), tout << "var: " << it->var() << "\n"; display(tout);); CTRACE("sat_model_converter", l.var() == it->var(), tout << "var: " << it->var() << "\n"; display(tout););
SASSERT(l.var() != it->var()); SASSERT(l.var() != it->var());
SASSERT(l == null_literal || l.var() < num_vars); SASSERT(l == null_literal || l.var() < num_vars);
if (it2->var() == it->var()) return false;
} }
} }
} }
@ -229,10 +241,26 @@ namespace sat {
} }
void model_converter::display(std::ostream & out) const { void model_converter::display(std::ostream & out) const {
out << "(sat::model-converter"; out << "(sat::model-converter\n";
bool first = true;
for (auto & entry : m_entries) { for (auto & entry : m_entries) {
out << "\n (" << (entry.get_kind() == ELIM_VAR ? "elim" : "blocked") << " " << entry.var(); if (first) first = false; else out << "\n";
display(out, entry);
}
out << ")\n";
}
std::ostream& model_converter::display(std::ostream& out, entry const& entry) const {
out << " (";
switch (entry.get_kind()) {
case ELIM_VAR: out << "elim"; break;
case BLOCK_LIT: out << "blocked"; break;
case CCE: out << "cce"; break;
case ACCE: out << "acce"; break;
}
out << " " << entry.var();
bool start = true; bool start = true;
unsigned index = 0;
for (literal l : entry.m_clauses) { for (literal l : entry.m_clauses) {
if (start) { if (start) {
out << "\n ("; out << "\n (";
@ -245,13 +273,71 @@ namespace sat {
if (l == null_literal) { if (l == null_literal) {
out << ")"; out << ")";
start = true; start = true;
elim_stack* st = entry.m_elim_stack[index];
if (st) {
elim_stackv const& stack = st->stack();
unsigned sz = stack.size();
for (unsigned i = sz; i-- > 0; ) {
out << "\n " << stack[i].first << " " << stack[i].second;
}
}
++index;
continue; continue;
} }
out << l; out << l;
} }
out << ")"; out << ")";
for (literal l : entry.m_clauses) {
if (l != null_literal) {
if (m_solver && m_solver->was_eliminated(l.var())) out << "\neliminated: " << l;
}
}
return out;
}
void model_converter::validate_is_blocked(entry const& e, clause const& c) {
if (c.is_blocked() || c.is_learned()) return;
unsigned index = 0;
literal lit = null_literal;
bool_var v = e.var();
for (literal l : c) {
if (l.var() == v) {
lit = l;
break;
}
}
if (lit == null_literal) return;
bool sat = false;
for (literal l : e.m_clauses) {
if (l == null_literal) {
if (!sat) {
display(std::cout << "clause is not blocked\n", e) << "\n";
std::cout << c << "\n";
}
sat = false;
elim_stack* st = e.m_elim_stack[index];
if (st) {
elim_stackv const& stack = st->stack();
unsigned sz = stack.size();
for (unsigned i = sz; i-- > 0; ) {
// verify ...
}
}
++index;
continue;
}
if (sat) {
continue;
}
if (l.var() == v) {
sat = l == lit;
}
else {
sat = c.contains(~l);
}
} }
out << ")\n";
} }
void model_converter::copy(model_converter const & src) { void model_converter::copy(model_converter const & src) {

View file

@ -36,6 +36,9 @@ namespace sat {
This is a low-level model_converter. Given a mapping from bool_var to expr, This is a low-level model_converter. Given a mapping from bool_var to expr,
it can be converted into a general Z3 model_converter it can be converted into a general Z3 model_converter
*/ */
class solver;
class model_converter { class model_converter {
public: public:
@ -55,11 +58,11 @@ namespace sat {
elim_stackv const& stack() const { return m_stack; } elim_stackv const& stack() const { return m_stack; }
}; };
enum kind { ELIM_VAR = 0, BLOCK_LIT }; enum kind { ELIM_VAR = 0, BLOCK_LIT, CCE, ACCE };
class entry { class entry {
friend class model_converter; friend class model_converter;
unsigned m_var:31; unsigned m_var:30;
unsigned m_kind:1; unsigned m_kind:2;
literal_vector m_clauses; // the different clauses are separated by null_literal literal_vector m_clauses; // the different clauses are separated by null_literal
sref_vector<elim_stack> m_elim_stack; sref_vector<elim_stack> m_elim_stack;
entry(kind k, bool_var v):m_var(v), m_kind(k) {} entry(kind k, bool_var v):m_var(v), m_kind(k) {}
@ -75,12 +78,18 @@ namespace sat {
}; };
private: private:
vector<entry> m_entries; vector<entry> m_entries;
solver const* m_solver;
void process_stack(model & m, literal_vector const& clause, elim_stackv const& stack) const; void process_stack(model & m, literal_vector const& clause, elim_stackv const& stack) const;
std::ostream& display(std::ostream & out, entry const& entry) const;
void validate_is_blocked(entry const& e, clause const& c);
public: public:
model_converter(); model_converter();
~model_converter(); ~model_converter();
void set_solver(solver const* s) { m_solver = s; }
void operator()(model & m) const; void operator()(model & m) const;
model_converter& operator=(model_converter const& other); model_converter& operator=(model_converter const& other);

View file

@ -28,7 +28,8 @@ def_module_params('sat',
('threads', UINT, 1, 'number of parallel threads to use'), ('threads', UINT, 1, 'number of parallel threads to use'),
('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'),
('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'),
('drat.check', BOOL, False, 'build up internal proof and check'), ('drat.check_unsat', BOOL, False, 'build up internal proof and check'),
('drat.check_sat', BOOL, False, 'build up internal trace, check satisfying model'),
('cardinality.solver', BOOL, False, 'use cardinality solver'), ('cardinality.solver', BOOL, False, 'use cardinality solver'),
('pb.solver', SYMBOL, 'circuit', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use SMT solver)'), ('pb.solver', SYMBOL, 'circuit', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use SMT solver)'),
('xor.solver', BOOL, False, 'use xor solver'), ('xor.solver', BOOL, False, 'use xor solver'),

View file

@ -107,7 +107,7 @@ namespace sat {
frame & fr = frames.back(); frame & fr = frames.back();
unsigned l_idx = fr.m_lidx; unsigned l_idx = fr.m_lidx;
if (!fr.m_first) { if (!fr.m_first) {
SASSERT(fr.m_it->is_binary_clause()); SASSERT(fr.m_it->is_binary_unblocked_clause());
// after visiting child // after visiting child
literal l2 = fr.m_it->get_literal(); literal l2 = fr.m_it->get_literal();
unsigned l2_idx = l2.index(); unsigned l2_idx = l2.index();
@ -118,7 +118,7 @@ namespace sat {
} }
fr.m_first = false; fr.m_first = false;
while (fr.m_it != fr.m_end) { while (fr.m_it != fr.m_end) {
if (!fr.m_it->is_binary_clause()) { if (!fr.m_it->is_binary_unblocked_clause()) {
fr.m_it++; fr.m_it++;
continue; continue;
} }

View file

@ -201,18 +201,19 @@ namespace sat {
CASSERT("sat_solver", s.check_invariant()); CASSERT("sat_solver", s.check_invariant());
m_need_cleanup = false; m_need_cleanup = false;
m_use_list.init(s.num_vars()); m_use_list.init(s.num_vars());
m_learned_in_use_lists = false; m_learned_in_use_lists = learned;
if (learned) { if (learned) {
register_clauses(s.m_learned); register_clauses(s.m_learned);
m_learned_in_use_lists = true;
} }
register_clauses(s.m_clauses); register_clauses(s.m_clauses);
if (!learned && (bce_enabled() || bca_enabled())) if (bce_enabled() || abce_enabled() || bca_enabled()) {
elim_blocked_clauses(); elim_blocked_clauses();
}
if (!learned) if (!learned) {
m_num_calls++; m_num_calls++;
}
m_sub_counter = m_subsumption_limit; m_sub_counter = m_subsumption_limit;
m_elim_counter = m_res_limit; m_elim_counter = m_res_limit;
@ -457,7 +458,7 @@ namespace sat {
literal_vector::iterator l_it = m_bs_ls.begin(); literal_vector::iterator l_it = m_bs_ls.begin();
for (; it != end; ++it, ++l_it) { for (; it != end; ++it, ++l_it) {
clause & c2 = *(*it); clause & c2 = *(*it);
if (!c2.was_removed() && *l_it == null_literal) { if (!c2.was_removed() && !c1.is_blocked() && *l_it == null_literal) {
// c2 was subsumed // c2 was subsumed
if (c1.is_learned() && !c2.is_learned()) if (c1.is_learned() && !c2.is_learned())
c1.unset_learned(); c1.unset_learned();
@ -713,7 +714,7 @@ namespace sat {
// should not traverse wlist using iterators, since back_subsumption1 may add new binary clauses there // should not traverse wlist using iterators, since back_subsumption1 may add new binary clauses there
for (unsigned j = 0; j < wlist.size(); j++) { for (unsigned j = 0; j < wlist.size(); j++) {
watched w = wlist[j]; watched w = wlist[j];
if (w.is_binary_clause()) { if (w.is_binary_unblocked_clause()) {
literal l2 = w.get_literal(); literal l2 = w.get_literal();
if (l.index() < l2.index()) { if (l.index() < l2.index()) {
m_dummy.set(l, l2, w.is_learned()); m_dummy.set(l, l2, w.is_learned());
@ -959,8 +960,10 @@ namespace sat {
void operator()() { void operator()() {
if (s.bce_enabled()) if (s.bce_enabled())
block_clauses(); block_clauses();
if (s.abce_enabled())
cce<false>();
if (s.cce_enabled()) if (s.cce_enabled())
cce(); cce<true>();
if (s.bca_enabled()) if (s.bca_enabled())
bca(); bca();
} }
@ -1053,21 +1056,22 @@ namespace sat {
for (watched & w : s.get_wlist(l)) { for (watched & w : s.get_wlist(l)) {
// when adding a blocked clause, then all non-learned clauses have to be considered for the // when adding a blocked clause, then all non-learned clauses have to be considered for the
// resolution intersection. // resolution intersection.
bool process_bin = adding ? (w.is_binary_clause() && !w.is_learned()) : w.is_binary_unblocked_clause(); bool process_bin = adding ? w.is_binary_clause() : w.is_binary_unblocked_clause();
if (process_bin) { if (process_bin) {
literal lit = w.get_literal(); literal lit = w.get_literal();
if (s.is_marked(~lit) && lit != ~l) continue; if (s.is_marked(~lit) && lit != ~l) {
continue; // tautology
}
if (!first || s.is_marked(lit)) { if (!first || s.is_marked(lit)) {
inter.reset(); inter.reset();
return false; return false; // intersection is empty or does not add anything new.
} }
first = false; first = false;
inter.push_back(lit); inter.push_back(lit);
} }
} }
clause_use_list & neg_occs = s.m_use_list.get(~l); clause_use_list & neg_occs = s.m_use_list.get(~l);
clause_use_list::iterator it = neg_occs.mk_iterator(); for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) {
for (; !it.at_end(); it.next()) {
bool tautology = false; bool tautology = false;
clause & c = it.curr(); clause & c = it.curr();
if (c.is_blocked() && !adding) continue; if (c.is_blocked() && !adding) continue;
@ -1098,6 +1102,30 @@ namespace sat {
return first; return first;
} }
bool check_abce_tautology(literal l) {
if (!process_var(l.var())) return false;
for (watched & w : s.get_wlist(l)) {
if (w.is_binary_unblocked_clause()) {
literal lit = w.get_literal();
if (!s.is_marked(~lit) || lit == ~l) return false;
}
}
clause_use_list & neg_occs = s.m_use_list.get(~l);
for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) {
clause & c = it.curr();
if (c.is_blocked()) continue;
bool tautology = false;
for (literal lit : c) {
if (s.is_marked(~lit) && lit != ~l) {
tautology = true;
break;
}
}
if (!tautology) return false;
}
return true;
}
/* /*
* C \/ l l \/ lit * C \/ l l \/ lit
* ------------------- * -------------------
@ -1146,59 +1174,101 @@ namespace sat {
return false; return false;
} }
bool cla(literal& blocked) { bool above_threshold(unsigned sz0) const {
return sz0 * 10 < m_covered_clause.size();
}
template<bool use_ri>
bool cla(literal& blocked, model_converter::kind& k) {
bool is_tautology = false; bool is_tautology = false;
for (literal l : m_covered_clause) s.mark_visited(l); for (literal l : m_covered_clause) s.mark_visited(l);
unsigned num_iterations = 0, sz; unsigned num_iterations = 0, sz;
m_elim_stack.reset(); m_elim_stack.reset();
m_ala_qhead = 0; m_ala_qhead = 0;
k = model_converter::CCE;
unsigned sz0 = m_covered_clause.size();
/*
* For blocked clause elimination with asymmetric literal addition (ABCE)
* it suffices to check if one of the original
* literals in the clause is blocked modulo the additional literals added to the clause.
* So we record sz0, the original set of literals in the clause, mark additional literals,
* and then check if any of the first sz0 literals are blocked.
*/
if (s.abce_enabled() && !use_ri) {
add_ala();
for (unsigned i = 0; i < sz0; ++i) {
if (check_abce_tautology(m_covered_clause[i])) {
blocked = m_covered_clause[i];
is_tautology = true;
break;
}
}
k = model_converter::BLOCK_LIT; // actually ABCE
for (literal l : m_covered_clause) s.unmark_visited(l);
m_covered_clause.shrink(sz0);
return is_tautology;
}
/*
* For CCE we add the resolution intersection while checking if the clause becomes a tautology.
* For ACCE, in addition, we add literals.
*/
do { do {
do { do {
if (above_threshold(sz0)) break;
++num_iterations; ++num_iterations;
sz = m_covered_clause.size(); sz = m_covered_clause.size();
is_tautology = add_cla(blocked); is_tautology = add_cla(blocked);
} }
while (m_covered_clause.size() > sz && !is_tautology); while (m_covered_clause.size() > sz && !is_tautology);
if (above_threshold(sz0)) break;
if (s.acce_enabled() && !is_tautology) { if (s.acce_enabled() && !is_tautology) {
sz = m_covered_clause.size(); sz = m_covered_clause.size();
add_ala(); add_ala();
k = model_converter::ACCE;
} }
} }
while (m_covered_clause.size() > sz && !is_tautology); while (m_covered_clause.size() > sz && !is_tautology);
// if (is_tautology) std::cout << num_iterations << " " << m_covered_clause.size() << " " << sz0 << " " << is_tautology << " " << m_elim_stack.size() << "\n";
for (literal l : m_covered_clause) s.unmark_visited(l); for (literal l : m_covered_clause) s.unmark_visited(l);
// if (is_tautology) std::cout << "taut: " << num_iterations << " " << m_covered_clause.size() << " " << m_elim_stack.size() << "\n"; return is_tautology && !above_threshold(sz0);
return is_tautology;
} }
// perform covered clause elimination. // perform covered clause elimination.
// first extract the covered literal addition (CLA). // first extract the covered literal addition (CLA).
// then check whether the CLA is blocked. // then check whether the CLA is blocked.
bool cce(clause& c, literal& blocked) { template<bool use_ri>
bool cce(clause& c, literal& blocked, model_converter::kind& k) {
m_covered_clause.reset(); m_covered_clause.reset();
for (literal l : c) m_covered_clause.push_back(l); for (literal l : c) m_covered_clause.push_back(l);
return cla(blocked); return cla<use_ri>(blocked, k);
} }
bool cce(literal l1, literal l2, literal& blocked) { template<bool use_ri>
bool cce(literal l1, literal l2, literal& blocked, model_converter::kind& k) {
m_covered_clause.reset(); m_covered_clause.reset();
m_covered_clause.push_back(l1); m_covered_clause.push_back(l1);
m_covered_clause.push_back(l2); m_covered_clause.push_back(l2);
return cla(blocked); return cla<use_ri>(blocked, k);
} }
template<bool use_ri>
void cce() { void cce() {
insert_queue(); insert_queue();
cce_clauses(); cce_clauses<use_ri>();
cce_binary(); cce_binary<use_ri>();
} }
template<bool use_ri>
void cce_binary() { void cce_binary() {
while (!m_queue.empty() && m_counter >= 0) { while (!m_queue.empty() && m_counter >= 0) {
s.checkpoint(); s.checkpoint();
process_cce_binary(m_queue.next()); process_cce_binary<use_ri>(m_queue.next());
} }
} }
template<bool use_ri>
void process_cce_binary(literal l) { void process_cce_binary(literal l) {
literal blocked = null_literal; literal blocked = null_literal;
watch_list & wlist = s.get_wlist(~l); watch_list & wlist = s.get_wlist(~l);
@ -1206,15 +1276,15 @@ namespace sat {
watch_list::iterator it = wlist.begin(); watch_list::iterator it = wlist.begin();
watch_list::iterator it2 = it; watch_list::iterator it2 = it;
watch_list::iterator end = wlist.end(); watch_list::iterator end = wlist.end();
model_converter::kind k;
for (; it != end; ++it) { for (; it != end; ++it) {
if (!it->is_binary_clause() || it->is_blocked()) { if (!it->is_binary_clause() || it->is_blocked()) {
INC(); INC();
continue; continue;
} }
literal l2 = it->get_literal(); literal l2 = it->get_literal();
if (cce(l, l2, blocked)) { if (cce<use_ri>(l, l2, blocked, k)) {
block_covered_binary(it, l, blocked); block_covered_binary(it, l, blocked, k);
s.m_num_covered_clauses++; s.m_num_covered_clauses++;
} }
else { else {
@ -1225,13 +1295,15 @@ namespace sat {
} }
template<bool use_ri>
void cce_clauses() { void cce_clauses() {
m_to_remove.reset(); m_to_remove.reset();
literal blocked; literal blocked;
model_converter::kind k;
for (clause* cp : s.s.m_clauses) { for (clause* cp : s.s.m_clauses) {
clause& c = *cp; clause& c = *cp;
if (!c.was_removed() && !c.is_blocked() && cce(c, blocked)) { if (!c.was_removed() && !c.is_blocked() && cce<use_ri>(c, blocked, k)) {
block_covered_clause(c, blocked); block_covered_clause(c, blocked, k);
s.m_num_covered_clauses++; s.m_num_covered_clauses++;
} }
} }
@ -1242,10 +1314,10 @@ namespace sat {
} }
void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry) { void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) {
TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";);
if (new_entry == 0) if (new_entry == 0)
new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); new_entry = &(mc.mk(k, l.var()));
m_to_remove.push_back(&c); m_to_remove.push_back(&c);
for (literal lit : c) { for (literal lit : c) {
if (lit != l && process_var(lit.var())) { if (lit != l && process_var(lit.var())) {
@ -1255,19 +1327,19 @@ namespace sat {
} }
void block_clause(clause& c, literal l, model_converter::entry *& new_entry) { void block_clause(clause& c, literal l, model_converter::entry *& new_entry) {
prepare_block_clause(c, l, new_entry); prepare_block_clause(c, l, new_entry, model_converter::BLOCK_LIT);
mc.insert(*new_entry, c); mc.insert(*new_entry, c);
} }
void block_covered_clause(clause& c, literal l) { void block_covered_clause(clause& c, literal l, model_converter::kind k) {
model_converter::entry * new_entry = 0; model_converter::entry * new_entry = 0;
prepare_block_clause(c, l, new_entry); prepare_block_clause(c, l, new_entry, k);
mc.insert(*new_entry, m_covered_clause, m_elim_stack); mc.insert(*new_entry, m_covered_clause, m_elim_stack);
} }
void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry) { void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry, model_converter::kind k) {
if (new_entry == 0) if (new_entry == 0)
new_entry = &(mc.mk(model_converter::BLOCK_LIT, blocked.var())); new_entry = &(mc.mk(k, blocked.var()));
literal l2 = it->get_literal(); literal l2 = it->get_literal();
TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";);
if (s.m_retain_blocked_clauses && !it->is_learned()) { if (s.m_retain_blocked_clauses && !it->is_learned()) {
@ -1281,13 +1353,13 @@ namespace sat {
} }
void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) {
prepare_block_binary(it, l, l, new_entry); prepare_block_binary(it, l, l, new_entry, model_converter::BLOCK_LIT);
mc.insert(*new_entry, l, it->get_literal()); mc.insert(*new_entry, l, it->get_literal());
} }
void block_covered_binary(watch_list::iterator it, literal l, literal blocked) { void block_covered_binary(watch_list::iterator it, literal l, literal blocked, model_converter::kind k) {
model_converter::entry * new_entry = 0; model_converter::entry * new_entry = 0;
prepare_block_binary(it, l, blocked, new_entry); prepare_block_binary(it, l, blocked, new_entry, k);
mc.insert(*new_entry, m_covered_clause, m_elim_stack); mc.insert(*new_entry, m_covered_clause, m_elim_stack);
} }
@ -1375,10 +1447,12 @@ namespace sat {
stopwatch m_watch; stopwatch m_watch;
unsigned m_num_blocked_clauses; unsigned m_num_blocked_clauses;
unsigned m_num_covered_clauses; unsigned m_num_covered_clauses;
unsigned m_num_added_clauses;
blocked_cls_report(simplifier & s): blocked_cls_report(simplifier & s):
m_simplifier(s), m_simplifier(s),
m_num_blocked_clauses(s.m_num_blocked_clauses), m_num_blocked_clauses(s.m_num_blocked_clauses),
m_num_covered_clauses(s.m_num_covered_clauses) { m_num_covered_clauses(s.m_num_covered_clauses),
m_num_added_clauses(s.m_num_bca) {
m_watch.start(); m_watch.start();
} }
@ -1389,6 +1463,8 @@ namespace sat {
<< (m_simplifier.m_num_blocked_clauses - m_num_blocked_clauses) << (m_simplifier.m_num_blocked_clauses - m_num_blocked_clauses)
<< " :elim-covered-clauses " << " :elim-covered-clauses "
<< (m_simplifier.m_num_covered_clauses - m_num_covered_clauses) << (m_simplifier.m_num_covered_clauses - m_num_covered_clauses)
<< " :added-clauses "
<< (m_simplifier.m_num_bca - m_num_added_clauses)
<< mem_stat() << mem_stat()
<< " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
} }
@ -1456,8 +1532,7 @@ namespace sat {
*/ */
void simplifier::collect_clauses(literal l, clause_wrapper_vector & r, bool include_blocked) { void simplifier::collect_clauses(literal l, clause_wrapper_vector & r, bool include_blocked) {
clause_use_list const & cs = m_use_list.get(l); clause_use_list const & cs = m_use_list.get(l);
clause_use_list::iterator it = cs.mk_iterator(); for (auto it = cs.mk_iterator(); !it.at_end(); it.next()) {
for (; !it.at_end(); it.next()) {
if (!it.curr().is_blocked() || include_blocked) { if (!it.curr().is_blocked() || include_blocked) {
r.push_back(clause_wrapper(it.curr())); r.push_back(clause_wrapper(it.curr()));
SASSERT(r.back().size() == it.curr().size()); SASSERT(r.back().size() == it.curr().size());
@ -1703,6 +1778,7 @@ namespace sat {
else else
s.m_stats.m_mk_clause++; s.m_stats.m_mk_clause++;
clause * new_c = s.m_cls_allocator.mk_clause(m_new_cls.size(), m_new_cls.c_ptr(), false); clause * new_c = s.m_cls_allocator.mk_clause(m_new_cls.size(), m_new_cls.c_ptr(), false);
if (s.m_config.m_drat) s.m_drat.add(*new_c, true); if (s.m_config.m_drat) s.m_drat.add(*new_c, true);
s.m_clauses.push_back(new_c); s.m_clauses.push_back(new_c);
m_use_list.insert(*new_c); m_use_list.insert(*new_c);
@ -1769,6 +1845,7 @@ namespace sat {
m_cce = p.cce(); m_cce = p.cce();
m_acce = p.acce(); m_acce = p.acce();
m_bca = p.bca(); m_bca = p.bca();
m_bce_delay = p.bce_delay();
m_elim_blocked_clauses = p.elim_blocked_clauses(); m_elim_blocked_clauses = p.elim_blocked_clauses();
m_elim_blocked_clauses_at = p.elim_blocked_clauses_at(); m_elim_blocked_clauses_at = p.elim_blocked_clauses_at();
m_retain_blocked_clauses = p.retain_blocked_clauses(); m_retain_blocked_clauses = p.retain_blocked_clauses();

View file

@ -71,9 +71,11 @@ namespace sat {
int m_elim_counter; int m_elim_counter;
// config // config
bool m_abce; // block clauses using asymmetric added literals
bool m_cce; // covered clause elimination bool m_cce; // covered clause elimination
bool m_acce; // cce with asymetric literal addition bool m_acce; // cce with asymetric literal addition
bool m_bca; // blocked (binary) clause addition. bool m_bca; // blocked (binary) clause addition.
unsigned m_bce_delay;
bool m_elim_blocked_clauses; bool m_elim_blocked_clauses;
unsigned m_elim_blocked_clauses_at; unsigned m_elim_blocked_clauses_at;
bool m_retain_blocked_clauses; bool m_retain_blocked_clauses;
@ -169,10 +171,11 @@ namespace sat {
struct blocked_clause_elim; struct blocked_clause_elim;
void elim_blocked_clauses(); void elim_blocked_clauses();
bool bce_enabled() const { return m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled(); } bool bce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled()); }
bool acce_enabled() const { return m_acce; } bool acce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_acce; }
bool cce_enabled() const { return m_cce || acce_enabled(); } bool cce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled()); }
bool bca_enabled() const { return m_bca; } bool abce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce; }
bool bca_enabled() const { return m_bca && m_learned_in_use_lists; }
bool elim_vars_bdd_enabled() const { return m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay; } bool elim_vars_bdd_enabled() const { return m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay; }
bool elim_vars_enabled() const { return m_elim_vars; } bool elim_vars_enabled() const { return m_elim_vars; }

View file

@ -2,10 +2,12 @@ def_module_params(module_name='sat',
class_name='sat_simplifier_params', class_name='sat_simplifier_params',
export=True, export=True,
params=(('elim_blocked_clauses', BOOL, False, 'eliminate blocked clauses'), params=(('elim_blocked_clauses', BOOL, False, 'eliminate blocked clauses'),
('abce', BOOL, BOOL, False, 'eliminate blocked clauses using asymmmetric literals'),
('cce', BOOL, False, 'eliminate covered clauses'), ('cce', BOOL, False, 'eliminate covered clauses'),
('acce', BOOL, False, 'eliminate covered clauses using asymmetric added literals'), ('acce', BOOL, False, 'eliminate covered clauses using asymmetric added literals'),
('elim_blocked_clauses_at', UINT, 2, 'eliminate blocked clauses only once at the given simplification round'), ('elim_blocked_clauses_at', UINT, 2, 'eliminate blocked clauses only once at the given simplification round'),
('bca', BOOL, False, 'blocked clause addition - add blocked binary clauses'), ('bca', BOOL, False, 'blocked clause addition - add blocked binary clauses'),
('bce_delay', UINT, 0, 'delay eliminate blocked clauses until simplification round'),
('retain_blocked_clauses', BOOL, False, 'retain blocked clauses for propagation, hide them from variable elimination'), ('retain_blocked_clauses', BOOL, False, 'retain blocked clauses for propagation, hide them from variable elimination'),
('blocked_clause_limit', UINT, 100000000, 'maximum number of literals visited during blocked clause elimination'), ('blocked_clause_limit', UINT, 100000000, 'maximum number of literals visited during blocked clause elimination'),
('resolution.limit', UINT, 500000000, 'approx. maximum number of literals visited during variable elimination'), ('resolution.limit', UINT, 500000000, 'approx. maximum number of literals visited during variable elimination'),

View file

@ -23,14 +23,11 @@ Revision History:
#include "util/luby.h" #include "util/luby.h"
#include "util/trace.h" #include "util/trace.h"
#include "util/max_cliques.h" #include "util/max_cliques.h"
#include "util/gparams.h"
// define to update glue during propagation // define to update glue during propagation
#define UPDATE_GLUE #define UPDATE_GLUE
// define to create a copy of the solver before starting the search
// useful for checking models
// #define CLONE_BEFORE_SOLVING
namespace sat { namespace sat {
solver::solver(params_ref const & p, reslimit& l): solver::solver(params_ref const & p, reslimit& l):
@ -734,15 +731,13 @@ namespace sat {
case watched::CLAUSE: { case watched::CLAUSE: {
if (value(it->get_blocked_literal()) == l_true) { if (value(it->get_blocked_literal()) == l_true) {
TRACE("propagate_clause_bug", tout << "blocked literal " << it->get_blocked_literal() << "\n"; TRACE("propagate_clause_bug", tout << "blocked literal " << it->get_blocked_literal() << "\n";
clause_offset cls_off = it->get_clause_offset(); tout << get_clause(it) << "\n";);
clause & c = *(m_cls_allocator.get_clause(cls_off));
tout << c << "\n";);
*it2 = *it; *it2 = *it;
it2++; it2++;
break; break;
} }
clause_offset cls_off = it->get_clause_offset(); clause_offset cls_off = it->get_clause_offset();
clause & c = *(m_cls_allocator.get_clause(cls_off)); clause & c = get_clause(cls_off);
TRACE("propagate_clause_bug", tout << "processing... " << c << "\nwas_removed: " << c.was_removed() << "\n";); TRACE("propagate_clause_bug", tout << "processing... " << c << "\nwas_removed: " << c.was_removed() << "\n";);
if (c[0] == not_l) if (c[0] == not_l)
std::swap(c[0], c[1]); std::swap(c[0], c[1]);
@ -886,12 +881,10 @@ namespace sat {
return check_par(num_lits, lits); return check_par(num_lits, lits);
} }
flet<bool> _searching(m_searching, true); flet<bool> _searching(m_searching, true);
#ifdef CLONE_BEFORE_SOLVING if (m_mc.empty() && gparams::get().get_bool("model_validate", false)) {
if (m_mc.empty()) { m_clone = alloc(solver, m_params, m_rlimit);
m_clone = alloc(solver, m_params); m_clone->copy(*this);
SASSERT(m_clone);
} }
#endif
try { try {
init_search(); init_search();
if (inconsistent()) return l_false; if (inconsistent()) return l_false;
@ -1548,30 +1541,40 @@ namespace sat {
m_model[v] = value(v); m_model[v] = value(v);
} }
TRACE("sat_mc_bug", m_mc.display(tout);); TRACE("sat_mc_bug", m_mc.display(tout););
m_mc(m_model);
TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";);
// #ifndef _EXTERNAL_RELEASE
IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";); IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";);
if (!check_model(m_model)) { if (!check_clauses(m_model)) {
UNREACHABLE(); UNREACHABLE();
throw solver_exception("check model failed"); throw solver_exception("check model failed");
} }
if (m_config.m_drat) m_drat.check_model(m_model);
// m_mc.set_solver(this);
m_mc(m_model);
if (!check_clauses(m_model)) {
std::cout << "failure checking clauses on transformed model\n";
UNREACHABLE();
throw solver_exception("check model failed");
}
TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";);
if (m_clone) { if (m_clone) {
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model (on original set of clauses)\"\n";); IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model (on original set of clauses)\"\n";);
if (!m_clone->check_model(m_model)) if (!m_clone->check_model(m_model))
throw solver_exception("check model failed (for cloned solver)"); throw solver_exception("check model failed (for cloned solver)");
} }
// #endif
} }
bool solver::check_model(model const & m) const { bool solver::check_clauses(model const& m) const {
bool ok = true; bool ok = true;
for (clause const* cp : m_clauses) { for (clause const* cp : m_clauses) {
clause const & c = *cp; clause const & c = *cp;
if (!c.satisfied_by(m) && !c.is_blocked()) { if (!c.satisfied_by(m) && !c.is_blocked()) {
IF_VERBOSE(0, verbose_stream() << "model check failed: " << c << "\n";); IF_VERBOSE(0, verbose_stream() << "failed clause " << c.id() << ": " << c << "\n";);
TRACE("sat", tout << "failed: " << c << "\n"; TRACE("sat", tout << "failed: " << c << "\n";
tout << "assumptions: " << m_assumptions << "\n"; tout << "assumptions: " << m_assumptions << "\n";
tout << "trail: " << m_trail << "\n"; tout << "trail: " << m_trail << "\n";
@ -1612,10 +1615,16 @@ namespace sat {
ok = false; ok = false;
} }
} }
return ok;
}
bool solver::check_model(model const & m) const {
bool ok = check_clauses(m);
if (ok && !m_mc.check_model(m)) { if (ok && !m_mc.check_model(m)) {
ok = false; ok = false;
TRACE("sat", tout << "model: " << m << "\n"; m_mc.display(tout);); TRACE("sat", tout << "model: " << m << "\n"; m_mc.display(tout););
} }
IF_VERBOSE(1, verbose_stream() << "model check " << (ok?"OK":"failed") << "\n";);
return ok; return ok;
} }
@ -2034,7 +2043,7 @@ namespace sat {
process_antecedent(~(js.get_literal2()), num_marks); process_antecedent(~(js.get_literal2()), num_marks);
break; break;
case justification::CLAUSE: { case justification::CLAUSE: {
clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); clause & c = get_clause(js);
unsigned i = 0; unsigned i = 0;
if (consequent != null_literal) { if (consequent != null_literal) {
SASSERT(c[0] == consequent || c[1] == consequent); SASSERT(c[0] == consequent || c[1] == consequent);
@ -2153,7 +2162,7 @@ namespace sat {
process_antecedent_for_unsat_core(~(js.get_literal2())); process_antecedent_for_unsat_core(~(js.get_literal2()));
break; break;
case justification::CLAUSE: { case justification::CLAUSE: {
clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); clause & c = get_clause(js);
unsigned i = 0; unsigned i = 0;
if (consequent != null_literal) { if (consequent != null_literal) {
SASSERT(c[0] == consequent || c[1] == consequent); SASSERT(c[0] == consequent || c[1] == consequent);
@ -2497,7 +2506,7 @@ namespace sat {
} }
break; break;
case justification::CLAUSE: { case justification::CLAUSE: {
clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); clause & c = get_clause(js);
unsigned i = 0; unsigned i = 0;
if (c[0].var() == var) { if (c[0].var() == var) {
i = 1; i = 1;
@ -2624,8 +2633,7 @@ namespace sat {
unsigned sz = m_lemma.size(); unsigned sz = m_lemma.size();
SASSERT(!is_marked(m_lemma[0].var())); SASSERT(!is_marked(m_lemma[0].var()));
mark(m_lemma[0].var()); mark(m_lemma[0].var());
for (unsigned i = m_lemma.size(); i > 0; ) { for (unsigned i = m_lemma.size(); i-- > 0; ) {
--i;
justification js = m_justification[m_lemma[i].var()]; justification js = m_justification[m_lemma[i].var()];
switch (js.get_kind()) { switch (js.get_kind()) {
case justification::NONE: case justification::NONE:
@ -2638,9 +2646,9 @@ namespace sat {
update_lrb_reasoned(js.get_literal2()); update_lrb_reasoned(js.get_literal2());
break; break;
case justification::CLAUSE: { case justification::CLAUSE: {
clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); clause & c = get_clause(js);
for (unsigned i = 0; i < c.size(); ++i) { for (literal l : c) {
update_lrb_reasoned(c[i]); update_lrb_reasoned(l);
} }
break; break;
} }
@ -3045,6 +3053,7 @@ namespace sat {
m_scc.updt_params(p); m_scc.updt_params(p);
m_rand.set_seed(m_config.m_random_seed); m_rand.set_seed(m_config.m_random_seed);
m_step_size = m_config.m_step_size_init; m_step_size = m_config.m_step_size_init;
m_drat.updt_config();
} }
void solver::collect_param_descrs(param_descrs & d) { void solver::collect_param_descrs(param_descrs & d) {
@ -3199,7 +3208,7 @@ namespace sat {
std::ostream& solver::display_justification(std::ostream & out, justification const& js) const { std::ostream& solver::display_justification(std::ostream & out, justification const& js) const {
out << js; out << js;
if (js.is_clause()) { if (js.is_clause()) {
out << *(m_cls_allocator.get_clause(js.get_clause_offset())); out << get_clause(js);
} }
else if (js.is_ext_justification() && m_ext) { else if (js.is_ext_justification() && m_ext) {
m_ext->display_justification(out << " ", js.get_ext_justification_idx()); m_ext->display_justification(out << " ", js.get_ext_justification_idx());
@ -3845,11 +3854,11 @@ namespace sat {
s |= m_antecedents.find(js.get_literal2().var()); s |= m_antecedents.find(js.get_literal2().var());
break; break;
case justification::CLAUSE: { case justification::CLAUSE: {
clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); clause & c = get_clause(js);
for (unsigned i = 0; i < c.size(); ++i) { for (literal l : c) {
if (c[i] != lit) { if (l != lit) {
if (check_domain(lit, ~c[i]) && all_found) { if (check_domain(lit, ~l) && all_found) {
s |= m_antecedents.find(c[i].var()); s |= m_antecedents.find(l.var());
} }
else { else {
all_found = false; all_found = false;

View file

@ -366,6 +366,7 @@ namespace sat {
model_converter const & get_model_converter() const { return m_mc; } model_converter const & get_model_converter() const { return m_mc; }
void set_model(model const& mdl); void set_model(model const& mdl);
char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } char const* get_reason_unknown() const { return m_reason_unknown.c_str(); }
bool check_clauses(model const& m) const;
literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars);
lbool cube(bool_var_vector const& vars, literal_vector& lits); lbool cube(bool_var_vector const& vars, literal_vector& lits);
@ -443,6 +444,20 @@ namespace sat {
return !jst.is_clause() || m_cls_allocator.get_clause(jst.get_clause_offset()) != &c; return !jst.is_clause() || m_cls_allocator.get_clause(jst.get_clause_offset()) != &c;
} }
clause& get_clause(watch_list::iterator it) const {
SASSERT(it->get_kind() == watched::CLAUSE);
return get_clause(it->get_clause_offset());
}
clause& get_clause(justification const& j) const {
SASSERT(j.is_clause());
return get_clause(j.get_clause_offset());
}
clause& get_clause(clause_offset cls_off) const {
return *(m_cls_allocator.get_clause(cls_off));
}
// ----------------------- // -----------------------
// //
// Conflict resolution // Conflict resolution

View file

@ -180,7 +180,13 @@ public:
m_internalized_converted = false; m_internalized_converted = false;
init_reason_unknown(); init_reason_unknown();
try {
r = m_solver.check(m_asms.size(), m_asms.c_ptr()); r = m_solver.check(m_asms.size(), m_asms.c_ptr());
}
catch (z3_exception& ex) {
IF_VERBOSE(10, verbose_stream() << "exception: " << ex.msg() << "\n";);
r = l_undef;
}
if (r == l_undef && m_solver.get_config().m_dimacs_display) { if (r == l_undef && m_solver.get_config().m_dimacs_display) {
for (auto const& kv : m_map) { for (auto const& kv : m_map) {
std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, m) << "\n"; std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, m) << "\n";

View file

@ -896,6 +896,7 @@ struct sat2goal::imp {
public: public:
sat_model_converter(ast_manager & m, sat::solver const & s):m_var2expr(m) { sat_model_converter(ast_manager & m, sat::solver const & s):m_var2expr(m) {
m_mc.copy(s.get_model_converter()); m_mc.copy(s.get_model_converter());
m_mc.set_solver(&s);
m_fmc = alloc(filter_model_converter, m); m_fmc = alloc(filter_model_converter, m);
} }