3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-15 13:28:47 +00:00

bug fixes, prepare for retaining blocked clauses

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-10-19 22:19:05 -07:00
parent 636f740b1a
commit 76eed064eb
16 changed files with 333 additions and 234 deletions

View file

@ -2761,8 +2761,8 @@ namespace sat {
} }
} }
unsigned ba_solver::get_num_non_learned_bin(literal l) { unsigned ba_solver::get_num_unblocked_bin(literal l) {
return s().m_simplifier.get_num_non_learned_bin(l); return s().m_simplifier.get_num_unblocked_bin(l);
} }
/* /*
@ -2831,8 +2831,8 @@ namespace sat {
value(lit) == l_undef && value(lit) == l_undef &&
use_count(lit) == 1 && use_count(lit) == 1 &&
use_count(~lit) == 1 && use_count(~lit) == 1 &&
get_num_non_learned_bin(lit) == 0 && get_num_unblocked_bin(lit) == 0 &&
get_num_non_learned_bin(~lit) == 0) { get_num_unblocked_bin(~lit) == 0) {
remove_constraint(c, "unused def"); remove_constraint(c, "unused def");
} }
break; break;
@ -2876,7 +2876,7 @@ namespace sat {
bool ba_solver::elim_pure(literal lit) { bool ba_solver::elim_pure(literal lit) {
if (value(lit) == l_undef && !m_cnstr_use_list[lit.index()].empty() && if (value(lit) == l_undef && !m_cnstr_use_list[lit.index()].empty() &&
use_count(~lit) == 0 && get_num_non_learned_bin(~lit) == 0) { use_count(~lit) == 0 && get_num_unblocked_bin(~lit) == 0) {
IF_VERBOSE(10, verbose_stream() << "pure literal: " << lit << "\n";); IF_VERBOSE(10, verbose_stream() << "pure literal: " << lit << "\n";);
s().assign(lit, justification()); s().assign(lit, justification());
return true; return true;
@ -3163,9 +3163,12 @@ namespace sat {
if (w.is_binary_clause() && is_marked(w.get_literal())) { if (w.is_binary_clause() && is_marked(w.get_literal())) {
++m_stats.m_num_bin_subsumes; ++m_stats.m_num_bin_subsumes;
// IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); // IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";);
if (!w.is_binary_non_learned_clause()) { if (w.is_learned()) {
c1.set_learned(false); c1.set_learned(false);
} }
else if (w.is_blocked()) {
w.set_unblocked();
}
} }
else { else {
if (it != it2) { if (it != it2) {

View file

@ -262,7 +262,7 @@ namespace sat {
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; } bool is_marked(literal l) const { return m_visited[l.index()] != 0; }
unsigned get_num_non_learned_bin(literal l); unsigned get_num_unblocked_bin(literal l);
literal get_min_occurrence_literal(card const& c); literal get_min_occurrence_literal(card const& c);
void init_use_lists(); void init_use_lists();
void remove_unused_defs(); void remove_unused_defs();

View file

@ -29,6 +29,7 @@ namespace sat {
m_capacity(sz), m_capacity(sz),
m_removed(false), m_removed(false),
m_learned(learned), m_learned(learned),
m_blocked(false),
m_used(false), m_used(false),
m_frozen(false), m_frozen(false),
m_reinit_stack(false), m_reinit_stack(false),

View file

@ -46,6 +46,7 @@ namespace sat {
unsigned m_used:1; unsigned m_used:1;
unsigned m_frozen:1; unsigned m_frozen:1;
unsigned m_reinit_stack:1; unsigned m_reinit_stack:1;
unsigned m_blocked;
unsigned m_inact_rounds:8; unsigned m_inact_rounds:8;
unsigned m_glue:8; unsigned m_glue:8;
unsigned m_psm:8; // transient field used during gc unsigned m_psm:8; // transient field used during gc
@ -86,6 +87,9 @@ namespace sat {
unsigned inact_rounds() const { return m_inact_rounds; } unsigned inact_rounds() const { return m_inact_rounds; }
bool frozen() const { return m_frozen; } bool frozen() const { return m_frozen; }
void freeze() { SASSERT(is_learned()); SASSERT(!frozen()); m_frozen = true; } void freeze() { SASSERT(is_learned()); SASSERT(!frozen()); m_frozen = true; }
bool is_blocked() const { return m_blocked; }
void block() { SASSERT(!m_blocked); SASSERT(!is_learned()); m_blocked = true; }
void unblock() { SASSERT(m_blocked); SASSERT(!is_learned()); m_blocked = false; }
void unfreeze() { SASSERT(is_learned()); SASSERT(frozen()); m_frozen = false; } void unfreeze() { SASSERT(is_learned()); SASSERT(frozen()); m_frozen = false; }
static var_approx_set approx(unsigned num, literal const * lits); static var_approx_set approx(unsigned num, literal const * lits);
void set_glue(unsigned glue) { m_glue = glue > 255 ? 255 : glue; } void set_glue(unsigned glue) { m_glue = glue > 255 ? 255 : glue; }

View file

@ -22,17 +22,20 @@ Revision History:
namespace sat { namespace sat {
bool clause_use_list::check_invariant() const { bool clause_use_list::check_invariant() const {
#ifdef LAZY_USE_LIST
unsigned sz = 0; unsigned sz = 0;
for (unsigned i = 0; i < m_clauses.size(); i++) for (clause* c : m_clauses)
if (!m_clauses[i]->was_removed()) if (!c->was_removed())
sz++; sz++;
SASSERT(sz == m_size); SASSERT(sz == m_size);
#endif unsigned blocked = 0;
for (clause* c : m_clauses)
if (c->is_blocked())
blocked++;
SASSERT(blocked == m_num_blocked);
return true; return true;
} }
#ifdef LAZY_USE_LIST
void clause_use_list::iterator::consume() { void clause_use_list::iterator::consume() {
while (true) { while (true) {
if (m_i == m_size) if (m_i == m_size)
@ -44,14 +47,11 @@ namespace sat {
m_i++; m_i++;
} }
} }
#endif
clause_use_list::iterator::~iterator() { clause_use_list::iterator::~iterator() {
#ifdef LAZY_USE_LIST
while (m_i < m_size) while (m_i < m_size)
next(); next();
m_clauses.shrink(m_j); m_clauses.shrink(m_j);
#endif
} }
}; };

View file

@ -24,30 +24,30 @@ Revision History:
namespace sat { namespace sat {
#define LAZY_USE_LIST
/** /**
\brief Clause use list with delayed deletion. \brief Clause use list with delayed deletion.
*/ */
class clause_use_list { class clause_use_list {
clause_vector m_clauses; clause_vector m_clauses;
#ifdef LAZY_USE_LIST
unsigned m_size; unsigned m_size;
#endif unsigned m_num_blocked;
public: public:
clause_use_list() { clause_use_list() {
STRACE("clause_use_list_bug", tout << "[cul_created] " << this << "\n";); STRACE("clause_use_list_bug", tout << "[cul_created] " << this << "\n";);
#ifdef LAZY_USE_LIST
m_size = 0; m_size = 0;
#endif m_num_blocked = 0;
} }
unsigned size() const { unsigned size() const {
#ifdef LAZY_USE_LIST
return m_size; return m_size;
#else }
return m_clauses.size();
#endif unsigned num_blocked() const {
return m_num_blocked;
}
unsigned non_blocked_size() const {
return m_size - m_num_blocked;
} }
bool empty() const { return size() == 0; } bool empty() const { return size() == 0; }
@ -57,58 +57,59 @@ namespace sat {
SASSERT(!m_clauses.contains(&c)); SASSERT(!m_clauses.contains(&c));
SASSERT(!c.was_removed()); SASSERT(!c.was_removed());
m_clauses.push_back(&c); m_clauses.push_back(&c);
#ifdef LAZY_USE_LIST
m_size++; m_size++;
#endif if (c.is_blocked()) ++m_num_blocked;
} }
void erase_not_removed(clause & c) { void erase_not_removed(clause & c) {
STRACE("clause_use_list_bug", tout << "[cul_erase_not_removed] " << this << " " << &c << "\n";); STRACE("clause_use_list_bug", tout << "[cul_erase_not_removed] " << this << " " << &c << "\n";);
#ifdef LAZY_USE_LIST
SASSERT(m_clauses.contains(&c)); SASSERT(m_clauses.contains(&c));
SASSERT(!c.was_removed()); SASSERT(!c.was_removed());
m_clauses.erase(&c); m_clauses.erase(&c);
m_size--; m_size--;
#else if (c.is_blocked()) --m_num_blocked;
m_clauses.erase(&c);
#endif
} }
void erase(clause & c) { void erase(clause & c) {
STRACE("clause_use_list_bug", tout << "[cul_erase] " << this << " " << &c << "\n";); STRACE("clause_use_list_bug", tout << "[cul_erase] " << this << " " << &c << "\n";);
#ifdef LAZY_USE_LIST
SASSERT(m_clauses.contains(&c)); SASSERT(m_clauses.contains(&c));
SASSERT(c.was_removed()); SASSERT(c.was_removed());
m_size--; m_size--;
#else if (c.is_blocked()) --m_num_blocked;
m_clauses.erase(&c); }
#endif
void block(clause const& c) {
SASSERT(c.is_blocked());
++m_num_blocked;
SASSERT(check_invariant());
}
void unblock(clause const& c) {
SASSERT(!c.is_blocked());
--m_num_blocked;
SASSERT(check_invariant());
} }
void reset() { void reset() {
m_clauses.finalize(); m_clauses.finalize();
#ifdef LAZY_USE_LIST
m_size = 0; m_size = 0;
#endif m_num_blocked = 0;
} }
bool check_invariant() const; bool check_invariant() const;
// iterate & compress // iterate & compress
class iterator { class iterator {
clause_vector & m_clauses; clause_vector & m_clauses;
unsigned m_size; unsigned m_size;
unsigned m_i; unsigned m_i;
#ifdef LAZY_USE_LIST
unsigned m_j; unsigned m_j;
void consume(); void consume();
#endif
public: public:
iterator(clause_vector & v):m_clauses(v), m_size(v.size()), m_i(0) { iterator(clause_vector & v):m_clauses(v), m_size(v.size()), m_i(0) {
#ifdef LAZY_USE_LIST
m_j = 0; m_j = 0;
consume(); consume();
#endif
} }
~iterator(); ~iterator();
bool at_end() const { return m_i == m_size; } bool at_end() const { return m_i == m_size; }
@ -117,10 +118,8 @@ namespace sat {
SASSERT(!at_end()); SASSERT(!at_end());
SASSERT(!m_clauses[m_i]->was_removed()); SASSERT(!m_clauses[m_i]->was_removed());
m_i++; m_i++;
#ifdef LAZY_USE_LIST
m_j++; m_j++;
consume(); consume();
#endif
} }
}; };

View file

@ -37,13 +37,13 @@ namespace sat{
literal pos_l(v, false); literal pos_l(v, false);
literal neg_l(v, true); literal neg_l(v, true);
unsigned num_bin_pos = simp.get_num_non_learned_bin(pos_l); unsigned num_bin_pos = simp.get_num_unblocked_bin(pos_l);
if (num_bin_pos > m_max_literals) return false; if (num_bin_pos > m_max_literals) return false;
unsigned num_bin_neg = simp.get_num_non_learned_bin(neg_l); unsigned num_bin_neg = simp.get_num_unblocked_bin(neg_l);
if (num_bin_neg > m_max_literals) return false; if (num_bin_neg > m_max_literals) return false;
clause_use_list & pos_occs = simp.m_use_list.get(pos_l); clause_use_list & pos_occs = simp.m_use_list.get(pos_l);
clause_use_list & neg_occs = simp.m_use_list.get(neg_l); clause_use_list & neg_occs = simp.m_use_list.get(neg_l);
unsigned clause_size = num_bin_pos + num_bin_neg + pos_occs.size() + neg_occs.size(); unsigned clause_size = num_bin_pos + num_bin_neg + pos_occs.non_blocked_size() + neg_occs.non_blocked_size();
if (clause_size == 0) { if (clause_size == 0) {
return false; return false;
} }
@ -85,8 +85,8 @@ namespace sat{
// eliminate variable // eliminate variable
simp.m_pos_cls.reset(); simp.m_pos_cls.reset();
simp.m_neg_cls.reset(); simp.m_neg_cls.reset();
simp.collect_clauses(pos_l, simp.m_pos_cls); simp.collect_clauses(pos_l, simp.m_pos_cls, false);
simp.collect_clauses(neg_l, simp.m_neg_cls); simp.collect_clauses(neg_l, simp.m_neg_cls, false);
model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v);
simp.save_clauses(mc_entry, simp.m_pos_cls); simp.save_clauses(mc_entry, simp.m_pos_cls);
simp.save_clauses(mc_entry, simp.m_neg_cls); simp.save_clauses(mc_entry, simp.m_neg_cls);
@ -122,13 +122,13 @@ namespace sat{
TRACE("elim_vars", TRACE("elim_vars",
tout << "eliminate " << v << "\n"; tout << "eliminate " << v << "\n";
for (watched const& w : simp.get_wlist(~pos_l)) { for (watched const& w : simp.get_wlist(~pos_l)) {
if (w.is_binary_non_learned_clause()) { if (w.is_binary_unblocked_clause()) {
tout << pos_l << " " << w.get_literal() << "\n"; tout << pos_l << " " << w.get_literal() << "\n";
} }
} }
m.display(tout, b1); m.display(tout, b1);
for (watched const& w : simp.get_wlist(~neg_l)) { for (watched const& w : simp.get_wlist(~neg_l)) {
if (w.is_binary_non_learned_clause()) { if (w.is_binary_unblocked_clause()) {
tout << neg_l << " " << w.get_literal() << "\n"; tout << neg_l << " " << w.get_literal() << "\n";
} }
} }
@ -294,7 +294,7 @@ namespace sat{
bool elim_vars::mark_literals(literal lit) { bool elim_vars::mark_literals(literal lit) {
watch_list& wl = simp.get_wlist(lit); watch_list& wl = simp.get_wlist(lit);
for (watched const& w : wl) { for (watched const& w : wl) {
if (w.is_binary_non_learned_clause()) { if (w.is_binary_unblocked_clause()) {
mark_var(w.get_literal().var()); mark_var(w.get_literal().var());
} }
} }
@ -306,6 +306,7 @@ namespace sat{
clause_use_list::iterator it = occs.mk_iterator(); clause_use_list::iterator it = occs.mk_iterator();
while (!it.at_end()) { while (!it.at_end()) {
clause const& c = it.curr(); clause const& c = it.curr();
if (c.is_blocked()) continue;
bdd cl = m.mk_false(); bdd cl = m.mk_false();
for (literal l : c) { for (literal l : c) {
cl |= mk_literal(l); cl |= mk_literal(l);
@ -320,7 +321,7 @@ namespace sat{
bdd result = m.mk_true(); bdd result = m.mk_true();
watch_list& wl = simp.get_wlist(~lit); watch_list& wl = simp.get_wlist(~lit);
for (watched const& w : wl) { for (watched const& w : wl) {
if (w.is_binary_non_learned_clause()) { if (w.is_binary_unblocked_clause()) {
result &= (mk_literal(lit) || mk_literal(w.get_literal())); result &= (mk_literal(lit) || mk_literal(w.get_literal()));
} }
} }

View file

@ -304,7 +304,7 @@ namespace sat {
watch_list::const_iterator it = wlist.begin(); watch_list::const_iterator it = wlist.begin();
watch_list::const_iterator end = wlist.end(); watch_list::const_iterator end = wlist.end();
for (; it != end; ++it) { for (; it != end; ++it) {
if (!it->is_binary_non_learned_clause()) if (!it->is_binary_unblocked_clause())
continue; continue;
literal l2 = it->get_literal(); literal l2 = it->get_literal();
if (l1.index() > l2.index()) if (l1.index() > l2.index())

View file

@ -965,7 +965,7 @@ namespace sat {
if (m_s.was_eliminated(l.var())) continue; if (m_s.was_eliminated(l.var())) continue;
watch_list const & wlist = m_s.m_watches[l_idx]; watch_list const & wlist = m_s.m_watches[l_idx];
for (auto& w : wlist) { for (auto& w : wlist) {
if (!w.is_binary_non_learned_clause()) if (!w.is_binary_clause())
continue; continue;
literal l2 = w.get_literal(); literal l2 = w.get_literal();
if (l.index() < l2.index() && !m_s.was_eliminated(l2.var())) if (l.index() < l2.index() && !m_s.was_eliminated(l2.var()))

View file

@ -34,26 +34,29 @@ namespace sat {
} }
void use_list::insert(clause & c) { void use_list::insert(clause & c) {
unsigned sz = c.size(); for (literal l : c)
for (unsigned i = 0; i < sz; i++) { m_use_list[l.index()].insert(c);
m_use_list[c[i].index()].insert(c);
}
} }
void use_list::erase(clause & c) { void use_list::erase(clause & c) {
unsigned sz = c.size(); for (literal l : c)
for (unsigned i = 0; i < sz; i++) { m_use_list[l.index()].erase(c);
m_use_list[c[i].index()].erase(c);
}
} }
void use_list::erase(clause & c, literal l) { void use_list::erase(clause & c, literal l) {
unsigned sz = c.size(); for (literal l2 : c)
for (unsigned i = 0; i < sz; i++) {
literal l2 = c[i];
if (l2 != l) if (l2 != l)
m_use_list[l2.index()].erase(c); m_use_list[l2.index()].erase(c);
} }
void use_list::block(clause& c) {
for (literal l : c)
m_use_list[l.index()].block(c);
}
void use_list::unblock(clause& c) {
for (literal l : c)
m_use_list[l.index()].unblock(c);
} }
simplifier::simplifier(solver & _s, params_ref const & p): simplifier::simplifier(solver & _s, params_ref const & p):
@ -99,9 +102,8 @@ namespace sat {
} }
inline void simplifier::remove_clause_core(clause & c) { inline void simplifier::remove_clause_core(clause & c) {
unsigned sz = c.size(); for (literal l : c)
for (unsigned i = 0; i < sz; i++) insert_elim_todo(l.var());
insert_elim_todo(c[i].var());
m_sub_todo.erase(c); m_sub_todo.erase(c);
c.set_removed(true); c.set_removed(true);
TRACE("resolution_bug", tout << "del_clause: " << c << "\n";); TRACE("resolution_bug", tout << "del_clause: " << c << "\n";);
@ -118,6 +120,20 @@ namespace sat {
m_use_list.erase(c, l); m_use_list.erase(c, l);
} }
inline void simplifier::block_clause(clause & c) {
#if 1
remove_clause(c);
#else
c.block();
m_use_list.block(c);
#endif
}
inline void simplifier::unblock_clause(clause & c) {
c.unblock();
m_use_list.unblock(c);
}
inline void simplifier::remove_bin_clause_half(literal l1, literal l2, bool learned) { inline void simplifier::remove_bin_clause_half(literal l1, literal l2, bool learned) {
SASSERT(s.get_wlist(~l1).contains(watched(l2, learned))); SASSERT(s.get_wlist(~l1).contains(watched(l2, learned)));
s.get_wlist(~l1).erase(watched(l2, learned)); s.get_wlist(~l1).erase(watched(l2, learned));
@ -238,10 +254,7 @@ namespace sat {
\brief Eliminate all ternary and clause watches. \brief Eliminate all ternary and clause watches.
*/ */
void simplifier::cleanup_watches() { void simplifier::cleanup_watches() {
vector<watch_list>::iterator it = s.m_watches.begin(); for (watch_list& wlist : s.m_watches) {
vector<watch_list>::iterator end = s.m_watches.end();
for (; it != end; ++it) {
watch_list & wlist = *it;
watch_list::iterator it2 = wlist.begin(); watch_list::iterator it2 = wlist.begin();
watch_list::iterator itprev = it2; watch_list::iterator itprev = it2;
watch_list::iterator end2 = wlist.end(); watch_list::iterator end2 = wlist.end();
@ -345,11 +358,9 @@ namespace sat {
\brief Return the variable in c with the minimal number positive+negative occurrences. \brief Return the variable in c with the minimal number positive+negative occurrences.
*/ */
bool_var simplifier::get_min_occ_var(clause const & c) const { bool_var simplifier::get_min_occ_var(clause const & c) const {
literal l_best = c[0]; literal l_best = null_literal;
unsigned best = m_use_list.get(l_best).size() + m_use_list.get(~l_best).size(); unsigned best = UINT_MAX;
unsigned sz = c.size(); for (literal l : c) {
for (unsigned i = 1; i < sz; i++) {
literal l = c[i];
unsigned num = m_use_list.get(l).size() + m_use_list.get(~l).size(); unsigned num = m_use_list.get(l).size() + m_use_list.get(~l).size();
if (num < best) { if (num < best) {
l_best = l; l_best = l;
@ -394,6 +405,7 @@ namespace sat {
*/ */
void simplifier::collect_subsumed1_core(clause const & c1, clause_vector & out, literal_vector & out_lits, void simplifier::collect_subsumed1_core(clause const & c1, clause_vector & out, literal_vector & out_lits,
literal target) { literal target) {
if (c1.is_blocked()) return;
clause_use_list const & cs = m_use_list.get(target); clause_use_list const & cs = m_use_list.get(target);
clause_use_list::iterator it = cs.mk_iterator(); clause_use_list::iterator it = cs.mk_iterator();
while (!it.at_end()) { while (!it.at_end()) {
@ -424,7 +436,7 @@ namespace sat {
} }
/** /**
\brief Perform backward subsumption and self-subsumption resolution using c. \brief Perform backward subsumption and self-subsumption resolution using c1.
*/ */
void simplifier::back_subsumption1(clause & c1) { void simplifier::back_subsumption1(clause & c1) {
m_bs_cs.reset(); m_bs_cs.reset();
@ -440,11 +452,13 @@ namespace sat {
// 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();
else if (c1.is_blocked() && !c2.is_learned() && !c2.is_blocked())
unblock_clause(c1);
TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";); TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";);
remove_clause(c2); remove_clause(c2);
m_num_subsumed++; m_num_subsumed++;
} }
else if (!c2.was_removed()) { else if (!c2.was_removed() && !c1.is_blocked()) {
// subsumption resolution // subsumption resolution
TRACE("subsumption_resolution", tout << c1 << " sub-ref(" << *l_it << ") " << c2 << "\n";); TRACE("subsumption_resolution", tout << c1 << " sub-ref(" << *l_it << ") " << c2 << "\n";);
elim_lit(c2, *l_it); elim_lit(c2, *l_it);
@ -466,11 +480,9 @@ namespace sat {
\brief Return the literal in c with the minimal number of occurrences. \brief Return the literal in c with the minimal number of occurrences.
*/ */
literal simplifier::get_min_occ_var0(clause const & c) const { literal simplifier::get_min_occ_var0(clause const & c) const {
literal l_best = c[0]; literal l_best = null_literal;
unsigned best = m_use_list.get(l_best).size(); unsigned best = UINT_MAX;
unsigned sz = c.size(); for (literal l : c) {
for (unsigned i = 1; i < sz; i++) {
literal l = c[i];
unsigned num = m_use_list.get(l).size(); unsigned num = m_use_list.get(l).size();
if (num < best) { if (num < best) {
l_best = l; l_best = l;
@ -485,21 +497,19 @@ namespace sat {
Otherwise return false Otherwise return false
*/ */
bool simplifier::subsumes0(clause const & c1, clause const & c2) { bool simplifier::subsumes0(clause const & c1, clause const & c2) {
unsigned sz2 = c2.size(); for (literal l : c2)
for (unsigned i = 0; i < sz2; i++) mark_visited(l);
mark_visited(c2[i]);
bool r = true; bool r = true;
unsigned sz1 = c1.size(); for (literal l : c1) {
for (unsigned i = 0; i < sz1; i++) { if (!is_marked(l)) {
if (!is_marked(c1[i])) {
r = false; r = false;
break; break;
} }
} }
for (unsigned i = 0; i < sz2; i++) for (literal l : c2)
unmark_visited(c2[i]); unmark_visited(l);
return r; return r;
} }
@ -508,6 +518,7 @@ namespace sat {
\brief Collect the clauses subsumed by c1 (using the occurrence list of target). \brief Collect the clauses subsumed by c1 (using the occurrence list of target).
*/ */
void simplifier::collect_subsumed0_core(clause const & c1, clause_vector & out, literal target) { void simplifier::collect_subsumed0_core(clause const & c1, clause_vector & out, literal target) {
if (c1.is_blocked()) return;
clause_use_list const & cs = m_use_list.get(target); clause_use_list const & cs = m_use_list.get(target);
clause_use_list::iterator it = cs.mk_iterator(); clause_use_list::iterator it = cs.mk_iterator();
while (!it.at_end()) { while (!it.at_end()) {
@ -540,10 +551,8 @@ namespace sat {
void simplifier::back_subsumption0(clause & c1) { void simplifier::back_subsumption0(clause & c1) {
m_bs_cs.reset(); m_bs_cs.reset();
collect_subsumed0(c1, m_bs_cs); collect_subsumed0(c1, m_bs_cs);
clause_vector::iterator it = m_bs_cs.begin(); for (clause* cp : m_bs_cs) {
clause_vector::iterator end = m_bs_cs.end(); clause & c2 = *cp;
for (; it != end; ++it) {
clause & c2 = *(*it);
// 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();
@ -951,13 +960,17 @@ namespace sat {
return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v); return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v);
} }
void operator()(unsigned num_vars) { void insert_queue(unsigned num_vars) {
for (bool_var v = 0; v < num_vars; v++) { for (bool_var v = 0; v < num_vars; v++) {
if (process_var(v)) { if (process_var(v)) {
insert(literal(v, false)); insert(literal(v, false));
insert(literal(v, true)); insert(literal(v, true));
} }
} }
}
void block_clauses(unsigned num_vars) {
insert_queue(num_vars);
while (!m_queue.empty()) { while (!m_queue.empty()) {
s.checkpoint(); s.checkpoint();
if (m_counter < 0) if (m_counter < 0)
@ -965,7 +978,73 @@ namespace sat {
literal l = m_queue.next(); literal l = m_queue.next();
process(l); process(l);
} }
cce(); }
void operator()(unsigned num_vars) {
block_clauses(num_vars);
if (s.m_elim_covered_clauses)
cce();
}
void process(literal l) {
TRACE("blocked_clause", tout << "processing: " << l << "\n";);
model_converter::entry * new_entry = 0;
if (!process_var(l.var())) {
return;
}
literal blocked = null_literal;
m_to_remove.reset();
{
clause_use_list & occs = s.m_use_list.get(l);
clause_use_list::iterator it = occs.mk_iterator();
while (!it.at_end()) {
clause & c = it.curr();
if (c.is_blocked()) continue;
m_counter -= c.size();
SASSERT(c.contains(l));
s.mark_all_but(c, l);
if (all_tautology(l)) {
block_clause(c, l, new_entry);
s.m_num_blocked_clauses++;
}
s.unmark_all(c);
it.next();
}
}
for (clause* c : m_to_remove)
s.block_clause(*c);
{
watch_list & wlist = s.get_wlist(~l);
m_counter -= wlist.size();
watch_list::iterator it = wlist.begin();
watch_list::iterator it2 = it;
watch_list::iterator end = wlist.end();
for (; it != end; ++it) {
if (!it->is_binary_clause() || it->is_blocked()) {
*it2 = *it;
it2++;
continue;
}
literal l2 = it->get_literal();
s.mark_visited(l2);
if (all_tautology(l)) {
block_binary(it, l, new_entry);
s.m_num_blocked_clauses++;
}
else if (s.m_elim_covered_clauses && cce(l, l2, blocked)) {
block_covered_binary(it, l, blocked);
s.m_num_covered_clauses++;
}
else {
*it2 = *it;
it2++;
}
s.unmark_visited(l2);
}
wlist.set_end(it2);
}
} }
// //
@ -976,7 +1055,7 @@ namespace sat {
if (!process_var(l.var())) return false; if (!process_var(l.var())) return false;
bool first = true; bool first = true;
for (watched & w : s.get_wlist(l)) { for (watched & w : s.get_wlist(l)) {
if (w.is_binary_non_learned_clause()) { if (w.is_binary_unblocked_clause()) {
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;
if (!first) { if (!first) {
@ -992,6 +1071,7 @@ namespace sat {
while (!it.at_end()) { while (!it.at_end()) {
bool tautology = false; bool tautology = false;
clause & c = it.curr(); clause & c = it.curr();
if (c.is_blocked()) continue;
for (literal lit : c) { for (literal lit : c) {
if (s.is_marked(~lit) && lit != ~l) { if (s.is_marked(~lit) && lit != ~l) {
tautology = true; tautology = true;
@ -1007,16 +1087,9 @@ namespace sat {
} }
else { else {
unsigned j = 0; unsigned j = 0;
unsigned sz = inter.size(); for (literal lit : inter)
for (unsigned i = 0; i < sz; ++i) { if (c.contains(lit))
literal lit1 = inter[i]; inter[j++] = lit;
for (literal lit2 : c) {
if (lit1 == lit2) {
inter[j++] = lit1;
break;
}
}
}
inter.shrink(j); inter.shrink(j);
if (j == 0) return false; if (j == 0) return false;
} }
@ -1052,6 +1125,14 @@ namespace sat {
} }
} }
/*
* C \/ l ~l \/ lit \/ D_i for i = 1...N all the clauses that have ~l
* -------------------------
* C \/ l \/ lit
*
*
*/
bool add_cla(literal& blocked) { bool add_cla(literal& blocked) {
for (unsigned i = 0; i < m_covered_clause.size(); ++i) { for (unsigned i = 0; i < m_covered_clause.size(); ++i) {
m_intersection.reset(); m_intersection.reset();
@ -1059,15 +1140,15 @@ namespace sat {
blocked = m_covered_clause[i]; blocked = m_covered_clause[i];
return true; return true;
} }
if (!m_intersection.empty()) {
m_elim_stack.push_back(std::make_pair(m_covered_clause.size(), m_covered_clause[i]));
}
for (literal l : m_intersection) { for (literal l : m_intersection) {
if (!s.is_marked(l)) { if (!s.is_marked(l)) {
s.mark_visited(l); s.mark_visited(l);
m_covered_clause.push_back(l); m_covered_clause.push_back(l);
} }
} }
if (!m_intersection.empty()) {
m_elim_stack.push_back(std::make_pair(m_covered_clause.size(), m_covered_clause[i]));
}
} }
return false; return false;
} }
@ -1085,14 +1166,18 @@ namespace sat {
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 1
break; break;
//if (is_tautology) break; #else
//sz = m_covered_clause.size(); // check for soundness?
// unsound? add_ala(); if (is_tautology) break;
sz = m_covered_clause.size();
add_ala();
#endif
} }
while (m_covered_clause.size() > sz); while (m_covered_clause.size() > sz);
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"; if (is_tautology) std::cout << "taut: " << num_iterations << " " << m_covered_clause.size() << " " << m_elim_stack.size() << "\n";
return is_tautology; return is_tautology;
} }
@ -1105,9 +1190,9 @@ namespace sat {
return cla(blocked); return cla(blocked);
} }
bool cce(literal lit, literal l2, literal& blocked) { bool cce(literal l1, literal l2, literal& blocked) {
m_covered_clause.reset(); m_covered_clause.reset();
m_covered_clause.push_back(lit); m_covered_clause.push_back(l1);
m_covered_clause.push_back(l2); m_covered_clause.push_back(l2);
return cla(blocked); return cla(blocked);
} }
@ -1117,79 +1202,17 @@ namespace sat {
literal blocked; literal blocked;
for (clause* cp : s.s.m_clauses) { for (clause* cp : s.s.m_clauses) {
clause& c = *cp; clause& c = *cp;
if (c.was_removed()) continue; if (!c.was_removed() && !c.is_blocked() && cce(c, blocked)) {
if (cce(c, blocked)) { block_covered_clause(c, blocked);
model_converter::entry * new_entry = 0;
block_covered_clause(c, blocked, new_entry);
s.m_num_covered_clauses++; s.m_num_covered_clauses++;
} }
} }
for (clause* c : m_to_remove) { for (clause* c : m_to_remove) {
s.remove_clause(*c); s.block_clause(*c);
} }
m_to_remove.reset(); m_to_remove.reset();
} }
void process(literal l) {
TRACE("blocked_clause", tout << "processing: " << l << "\n";);
model_converter::entry * new_entry = 0;
if (!process_var(l.var())) {
return;
}
literal blocked = null_literal;
m_to_remove.reset();
{
clause_use_list & occs = s.m_use_list.get(l);
clause_use_list::iterator it = occs.mk_iterator();
while (!it.at_end()) {
clause & c = it.curr();
m_counter -= c.size();
SASSERT(c.contains(l));
s.mark_all_but(c, l);
if (all_tautology(l)) {
block_clause(c, l, new_entry);
s.m_num_blocked_clauses++;
}
s.unmark_all(c);
it.next();
}
}
for (clause* c : m_to_remove) {
s.remove_clause(*c);
}
{
watch_list & wlist = s.get_wlist(~l);
m_counter -= wlist.size();
watch_list::iterator it = wlist.begin();
watch_list::iterator it2 = it;
watch_list::iterator end = wlist.end();
for (; it != end; ++it) {
if (!it->is_binary_clause()) {
*it2 = *it;
it2++;
continue;
}
literal l2 = it->get_literal();
s.mark_visited(l2);
if (all_tautology(l)) {
block_binary(it, l, new_entry);
s.m_num_blocked_clauses++;
}
else if (cce(l, l2, blocked)) {
model_converter::entry * blocked_entry = 0;
block_covered_binary(it, l, blocked, blocked_entry);
s.m_num_covered_clauses++;
}
else {
*it2 = *it;
it2++;
}
s.unmark_visited(l2);
}
wlist.set_end(it2);
}
}
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) {
TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";);
@ -1208,7 +1231,8 @@ namespace sat {
mc.insert(*new_entry, c); mc.insert(*new_entry, c);
} }
void block_covered_clause(clause& c, literal l, model_converter::entry *& new_entry) { void block_covered_clause(clause& c, literal l) {
model_converter::entry * new_entry = 0;
prepare_block_clause(c, l, new_entry); prepare_block_clause(c, l, new_entry);
mc.insert(*new_entry, m_covered_clause, m_elim_stack); mc.insert(*new_entry, m_covered_clause, m_elim_stack);
} }
@ -1227,7 +1251,8 @@ namespace sat {
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, model_converter::entry *& new_entry) { void block_covered_binary(watch_list::iterator it, literal l, literal blocked) {
model_converter::entry * new_entry = 0;
prepare_block_binary(it, l, blocked, new_entry); prepare_block_binary(it, l, blocked, new_entry);
mc.insert(*new_entry, m_covered_clause, m_elim_stack); mc.insert(*new_entry, m_covered_clause, m_elim_stack);
} }
@ -1236,7 +1261,7 @@ namespace sat {
watch_list & wlist = s.get_wlist(l); watch_list & wlist = s.get_wlist(l);
m_counter -= wlist.size(); m_counter -= wlist.size();
for (auto const& w : wlist) { for (auto const& w : wlist) {
if (w.is_binary_non_learned_clause() && if (w.is_binary_unblocked_clause() &&
!s.is_marked(~w.get_literal())) !s.is_marked(~w.get_literal()))
return false; return false;
} }
@ -1245,6 +1270,7 @@ namespace sat {
clause_use_list::iterator it = neg_occs.mk_iterator(); clause_use_list::iterator it = neg_occs.mk_iterator();
while (!it.at_end()) { while (!it.at_end()) {
clause & c = it.curr(); clause & c = it.curr();
if (c.is_blocked()) continue;
m_counter -= c.size(); m_counter -= c.size();
unsigned sz = c.size(); unsigned sz = c.size();
unsigned i; unsigned i;
@ -1300,11 +1326,11 @@ namespace sat {
elim(s.num_vars()); elim(s.num_vars());
} }
unsigned simplifier::get_num_non_learned_bin(literal l) const { unsigned simplifier::get_num_unblocked_bin(literal l) const {
unsigned r = 0; unsigned r = 0;
watch_list const & wlist = get_wlist(~l); watch_list const & wlist = get_wlist(~l);
for (auto & w : wlist) { for (auto & w : wlist) {
if (w.is_binary_non_learned_clause()) if (w.is_binary_unblocked_clause())
r++; r++;
} }
return r; return r;
@ -1315,8 +1341,8 @@ namespace sat {
literal neg_l(v, true); literal neg_l(v, true);
unsigned num_pos = m_use_list.get(pos_l).size(); unsigned num_pos = m_use_list.get(pos_l).size();
unsigned num_neg = m_use_list.get(neg_l).size(); unsigned num_neg = m_use_list.get(neg_l).size();
unsigned num_bin_pos = get_num_non_learned_bin(pos_l); unsigned num_bin_pos = get_num_unblocked_bin(pos_l);
unsigned num_bin_neg = get_num_non_learned_bin(neg_l); unsigned num_bin_neg = get_num_unblocked_bin(neg_l);
unsigned cost = 2 * num_pos * num_neg + num_pos * num_bin_neg + num_neg * num_bin_pos; unsigned cost = 2 * num_pos * num_neg + num_pos * num_bin_neg + num_neg * num_bin_pos;
CTRACE("elim_vars_detail", cost == 0, tout << v << " num_pos: " << num_pos << " num_neg: " << num_neg << " num_bin_pos: " << num_bin_pos CTRACE("elim_vars_detail", cost == 0, tout << v << " num_pos: " << num_pos << " num_neg: " << num_neg << " num_bin_pos: " << num_bin_pos
<< " num_bin_neg: " << num_bin_neg << " cost: " << cost << "\n";); << " num_bin_neg: " << num_bin_neg << " cost: " << cost << "\n";);
@ -1353,20 +1379,32 @@ namespace sat {
/** /**
\brief Collect clauses and binary clauses containing l. \brief Collect clauses and binary clauses containing l.
*/ */
void simplifier::collect_clauses(literal l, clause_wrapper_vector & r) { 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(); clause_use_list::iterator it = cs.mk_iterator();
while (!it.at_end()) { while (!it.at_end()) {
r.push_back(clause_wrapper(it.curr())); if (!it.curr().is_blocked() || include_blocked) {
SASSERT(r.back().size() == it.curr().size()); r.push_back(clause_wrapper(it.curr()));
SASSERT(r.back().size() == it.curr().size());
}
it.next(); it.next();
} }
watch_list & wlist = get_wlist(~l); watch_list & wlist = get_wlist(~l);
for (auto & w : wlist) { if (include_blocked) {
if (w.is_binary_non_learned_clause()) { for (auto & w : wlist) {
r.push_back(clause_wrapper(l, w.get_literal())); if (w.is_binary_non_learned_clause2()) {
SASSERT(r.back().size() == 2); r.push_back(clause_wrapper(l, w.get_literal()));
SASSERT(r.back().size() == 2);
}
}
}
else {
for (auto & w : wlist) {
if (w.is_binary_unblocked_clause()) {
r.push_back(clause_wrapper(l, w.get_literal()));
SASSERT(r.back().size() == 2);
}
} }
} }
} }
@ -1503,12 +1541,12 @@ namespace sat {
literal pos_l(v, false); literal pos_l(v, false);
literal neg_l(v, true); literal neg_l(v, true);
unsigned num_bin_pos = get_num_non_learned_bin(pos_l); unsigned num_bin_pos = get_num_unblocked_bin(pos_l);
unsigned num_bin_neg = get_num_non_learned_bin(neg_l); unsigned num_bin_neg = get_num_unblocked_bin(neg_l);
clause_use_list & pos_occs = m_use_list.get(pos_l); clause_use_list & pos_occs = m_use_list.get(pos_l);
clause_use_list & neg_occs = m_use_list.get(neg_l); clause_use_list & neg_occs = m_use_list.get(neg_l);
unsigned num_pos = pos_occs.size() + num_bin_pos; unsigned num_pos = pos_occs.non_blocked_size() + num_bin_pos;
unsigned num_neg = neg_occs.size() + num_bin_neg; unsigned num_neg = neg_occs.non_blocked_size() + num_bin_neg;
TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << "\n";); TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << "\n";);
@ -1520,7 +1558,8 @@ namespace sat {
{ {
clause_use_list::iterator it = pos_occs.mk_iterator(); clause_use_list::iterator it = pos_occs.mk_iterator();
while (!it.at_end()) { while (!it.at_end()) {
before_lits += it.curr().size(); if (!it.curr().is_blocked())
before_lits += it.curr().size();
it.next(); it.next();
} }
} }
@ -1528,7 +1567,8 @@ namespace sat {
{ {
clause_use_list::iterator it2 = neg_occs.mk_iterator(); clause_use_list::iterator it2 = neg_occs.mk_iterator();
while (!it2.at_end()) { while (!it2.at_end()) {
before_lits += it2.curr().size(); if (!it2.curr().is_blocked())
before_lits += it2.curr().size();
it2.next(); it2.next();
} }
} }
@ -1546,8 +1586,8 @@ namespace sat {
m_pos_cls.reset(); m_pos_cls.reset();
m_neg_cls.reset(); m_neg_cls.reset();
collect_clauses(pos_l, m_pos_cls); collect_clauses(pos_l, m_pos_cls, false);
collect_clauses(neg_l, m_neg_cls); collect_clauses(neg_l, m_neg_cls, false);
TRACE("resolution_detail", tout << "collecting number of after_clauses\n";); TRACE("resolution_detail", tout << "collecting number of after_clauses\n";);
@ -1676,6 +1716,7 @@ namespace sat {
void simplifier::updt_params(params_ref const & _p) { void simplifier::updt_params(params_ref const & _p) {
sat_simplifier_params p(_p); sat_simplifier_params p(_p);
m_elim_covered_clauses = p.elim_covered_clauses();
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_blocked_clause_limit = p.blocked_clause_limit(); m_blocked_clause_limit = p.blocked_clause_limit();
@ -1693,6 +1734,7 @@ namespace sat {
m_subsumption = p.subsumption(); m_subsumption = p.subsumption();
m_subsumption_limit = p.subsumption_limit(); m_subsumption_limit = p.subsumption_limit();
m_elim_vars = p.elim_vars(); m_elim_vars = p.elim_vars();
m_elim_vars_bdd = p.elim_vars_bdd();
} }
void simplifier::collect_param_descrs(param_descrs & r) { void simplifier::collect_param_descrs(param_descrs & r) {

View file

@ -40,6 +40,8 @@ namespace sat {
public: public:
void init(unsigned num_vars); void init(unsigned num_vars);
void insert(clause & c); void insert(clause & c);
void block(clause & c);
void unblock(clause & c);
void erase(clause & c); void erase(clause & c);
void erase(clause & c, literal l); void erase(clause & c, literal l);
clause_use_list & get(literal l) { return m_use_list[l.index()]; } clause_use_list & get(literal l) { return m_use_list[l.index()]; }
@ -69,6 +71,7 @@ namespace sat {
int m_elim_counter; int m_elim_counter;
// config // config
bool m_elim_covered_clauses;
bool m_elim_blocked_clauses; bool m_elim_blocked_clauses;
unsigned m_elim_blocked_clauses_at; unsigned m_elim_blocked_clauses_at;
unsigned m_blocked_clause_limit; unsigned m_blocked_clause_limit;
@ -87,6 +90,7 @@ namespace sat {
bool m_subsumption; bool m_subsumption;
unsigned m_subsumption_limit; unsigned m_subsumption_limit;
bool m_elim_vars; bool m_elim_vars;
bool m_elim_vars_bdd;
// stats // stats
unsigned m_num_blocked_clauses; unsigned m_num_blocked_clauses;
@ -119,6 +123,8 @@ namespace sat {
void remove_clause_core(clause & c); void remove_clause_core(clause & c);
void remove_clause(clause & c); void remove_clause(clause & c);
void remove_clause(clause & c, literal l); void remove_clause(clause & c, literal l);
void block_clause(clause & c);
void unblock_clause(clause & c);
void remove_bin_clause_half(literal l1, literal l2, bool learned); void remove_bin_clause_half(literal l1, literal l2, bool learned);
bool_var get_min_occ_var(clause const & c) const; bool_var get_min_occ_var(clause const & c) const;
@ -157,10 +163,10 @@ namespace sat {
struct blocked_clause_elim; struct blocked_clause_elim;
void elim_blocked_clauses(); void elim_blocked_clauses();
unsigned get_num_non_learned_bin(literal l) const; unsigned get_num_unblocked_bin(literal l) const;
unsigned get_to_elim_cost(bool_var v) const; unsigned get_to_elim_cost(bool_var v) const;
void order_vars_for_elim(bool_var_vector & r); void order_vars_for_elim(bool_var_vector & r);
void collect_clauses(literal l, clause_wrapper_vector & r); void collect_clauses(literal l, clause_wrapper_vector & r, bool include_blocked);
clause_wrapper_vector m_pos_cls; clause_wrapper_vector m_pos_cls;
clause_wrapper_vector m_neg_cls; clause_wrapper_vector m_neg_cls;
literal_vector m_new_cls; literal_vector m_new_cls;

View file

@ -2,6 +2,7 @@ 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'),
('elim_covered_clauses', BOOL, False, 'eliminate covered clauses'),
('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'),
('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', BOOL, True, 'eliminate boolean variables using resolution'), ('resolution', BOOL, True, 'eliminate boolean variables using resolution'),
@ -16,5 +17,6 @@ def_module_params(module_name='sat',
('resolution.cls_cutoff1', UINT, 100000000, 'limit1 - total number of problems clauses for the second cutoff of Boolean variable elimination'), ('resolution.cls_cutoff1', UINT, 100000000, 'limit1 - total number of problems clauses for the second cutoff of Boolean variable elimination'),
('resolution.cls_cutoff2', UINT, 700000000, 'limit2 - total number of problems clauses for the second cutoff of Boolean variable elimination'), ('resolution.cls_cutoff2', UINT, 700000000, 'limit2 - total number of problems clauses for the second cutoff of Boolean variable elimination'),
('elim_vars', BOOL, True, 'enable variable elimination during simplification'), ('elim_vars', BOOL, True, 'enable variable elimination during simplification'),
('elim_vars_bdd', BOOL, True, 'enable variable elimination using BDD recompilation during simplification'),
('subsumption', BOOL, True, 'eliminate subsumed clauses'), ('subsumption', BOOL, True, 'eliminate subsumed clauses'),
('subsumption.limit', UINT, 100000000, 'approx. maximum number of literals visited during subsumption (and subsumption resolution)'))) ('subsumption.limit', UINT, 100000000, 'approx. maximum number of literals visited during subsumption (and subsumption resolution)')))

View file

@ -117,7 +117,7 @@ namespace sat {
assign(src.m_trail[i], justification()); assign(src.m_trail[i], justification());
} }
// copy binary clauses // copy binary clauses that are unblocked.
{ {
unsigned sz = src.m_watches.size(); unsigned sz = src.m_watches.size();
for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { for (unsigned l_idx = 0; l_idx < sz; ++l_idx) {
@ -125,7 +125,7 @@ namespace sat {
if (src.was_eliminated(l.var())) continue; if (src.was_eliminated(l.var())) continue;
watch_list const & wlist = src.m_watches[l_idx]; watch_list const & wlist = src.m_watches[l_idx];
for (auto & wi : wlist) { for (auto & wi : wlist) {
if (!wi.is_binary_non_learned_clause()) if (!wi.is_binary_unblocked_clause())
continue; continue;
literal l2 = wi.get_literal(); literal l2 = wi.get_literal();
if (l.index() > l2.index() || if (l.index() > l2.index() ||
@ -142,7 +142,10 @@ namespace sat {
for (clause* c : src.m_clauses) { for (clause* c : src.m_clauses) {
buffer.reset(); buffer.reset();
for (literal l : *c) buffer.push_back(l); for (literal l : *c) buffer.push_back(l);
mk_clause_core(buffer); clause* c1 = mk_clause_core(buffer);
if (c1 && c->is_blocked()) {
c1->block();
}
} }
// copy high quality lemmas // copy high quality lemmas
for (clause* c : src.m_learned) { for (clause* c : src.m_learned) {
@ -1558,8 +1561,8 @@ namespace sat {
m_mc(m_model); m_mc(m_model);
TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";);
#ifndef _EXTERNAL_RELEASE // #ifndef _EXTERNAL_RELEASE
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model\"\n";); IF_VERBOSE(1, verbose_stream() << "\"checking model\"\n";);
if (!check_model(m_model)) if (!check_model(m_model))
throw solver_exception("check model failed"); throw solver_exception("check model failed");
@ -1568,7 +1571,7 @@ namespace sat {
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 // #endif
} }
bool solver::check_model(model const & m) const { bool solver::check_model(model const & m) const {
@ -3124,17 +3127,14 @@ namespace sat {
for (unsigned l_idx = 0; l_idx < sz; l_idx++) { for (unsigned l_idx = 0; l_idx < sz; l_idx++) {
literal l = to_literal(l_idx); literal l = to_literal(l_idx);
l.neg(); l.neg();
watch_list const & wlist = m_watches[l_idx]; for (watched const& w : m_watches[l_idx]) {
watch_list::const_iterator it = wlist.begin(); if (!w.is_binary_clause())
watch_list::const_iterator end = wlist.end();
for (; it != end; ++it) {
if (!it->is_binary_clause())
continue; continue;
if (!learned && it->is_learned()) if (!learned && w.is_learned())
continue; continue;
else if (learned && learned_only && !it->is_learned()) else if (learned && learned_only && !w.is_learned())
continue; continue;
literal l2 = it->get_literal(); literal l2 = w.get_literal();
if (l.index() > l2.index()) if (l.index() > l2.index())
continue; continue;
TRACE("cleanup_bug", tout << "collected: " << l << " " << l2 << "\n";); TRACE("cleanup_bug", tout << "collected: " << l << " " << l2 << "\n";);
@ -3168,13 +3168,10 @@ namespace sat {
for (unsigned l_idx = 0; l_idx < sz; l_idx++) { for (unsigned l_idx = 0; l_idx < sz; l_idx++) {
literal l = to_literal(l_idx); literal l = to_literal(l_idx);
l.neg(); l.neg();
watch_list const & wlist = m_watches[l_idx]; for (watched const& w : m_watches[l_idx]) {
watch_list::const_iterator it = wlist.begin(); if (!w.is_binary_clause())
watch_list::const_iterator end = wlist.end();
for (; it != end; ++it) {
if (!it->is_binary_clause())
continue; continue;
literal l2 = it->get_literal(); literal l2 = w.get_literal();
if (l.index() > l2.index()) if (l.index() > l2.index())
continue; continue;
out << "(" << l << " " << l2 << ")\n"; out << "(" << l << " " << l2 << ")\n";

View file

@ -220,8 +220,8 @@ namespace sat {
protected: protected:
void del_clause(clause & c); void del_clause(clause & c);
clause * mk_clause_core(unsigned num_lits, literal * lits, bool learned); clause * mk_clause_core(unsigned num_lits, literal * lits, bool learned);
void mk_clause_core(literal_vector const& lits) { mk_clause_core(lits.size(), lits.c_ptr()); } clause * mk_clause_core(literal_vector const& lits) { return mk_clause_core(lits.size(), lits.c_ptr()); }
void mk_clause_core(unsigned num_lits, literal * lits) { mk_clause_core(num_lits, lits, false); } clause * mk_clause_core(unsigned num_lits, literal * lits) { return mk_clause_core(num_lits, lits, false); }
void mk_clause_core(literal l1, literal l2) { literal lits[2] = { l1, l2 }; mk_clause_core(2, lits); } void mk_clause_core(literal l1, literal l2) { literal lits[2] = { l1, l2 }; mk_clause_core(2, lits); }
void mk_bin_clause(literal l1, literal l2, bool learned); void mk_bin_clause(literal l1, literal l2, bool learned);
bool propagate_bin_clause(literal l1, literal l2); bool propagate_bin_clause(literal l1, literal l2);

View file

@ -50,7 +50,7 @@ namespace sat {
SASSERT(is_binary_clause()); SASSERT(is_binary_clause());
SASSERT(get_literal() == l); SASSERT(get_literal() == l);
SASSERT(is_learned() == learned); SASSERT(is_learned() == learned);
SASSERT(learned || is_binary_non_learned_clause()); SASSERT(learned || is_binary_unblocked_clause());
} }
watched(literal l1, literal l2) { watched(literal l1, literal l2) {
@ -85,8 +85,15 @@ namespace sat {
literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(static_cast<unsigned>(m_val1)); } literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(static_cast<unsigned>(m_val1)); }
void set_literal(literal l) { SASSERT(is_binary_clause()); m_val1 = l.to_uint(); } void set_literal(literal l) { SASSERT(is_binary_clause()); m_val1 = l.to_uint(); }
bool is_learned() const { SASSERT(is_binary_clause()); return (m_val2 >> 2) == 1; } bool is_learned() const { SASSERT(is_binary_clause()); return (m_val2 >> 2) == 1; }
bool is_binary_non_learned_clause() const { return m_val2 == 0; }
bool is_binary_unblocked_clause() const { return m_val2 == 0; }
bool is_binary_learned_clause() const { return is_binary_clause() && is_learned(); }
bool is_binary_non_learned_clause2() const { return is_binary_clause() && !is_learned(); }
void mark_not_learned() { SASSERT(is_learned()); m_val2 = static_cast<unsigned>(BINARY); SASSERT(!is_learned()); } void mark_not_learned() { SASSERT(is_learned()); m_val2 = static_cast<unsigned>(BINARY); SASSERT(!is_learned()); }
void set_blocked() { SASSERT(is_binary_clause()); SASSERT(!is_learned()); m_val2 |= (1 << 3); }
bool is_blocked() const { SASSERT(is_binary_clause()); return 0 != (m_val2 & (1 << 3)); }
void set_unblocked() { SASSERT(is_binary_clause()); SASSERT(is_blocked()); m_val2 &= ~(1u << 3u); }
bool is_ternary_clause() const { return get_kind() == TERNARY; } bool is_ternary_clause() const { return get_kind() == TERNARY; }
literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(static_cast<unsigned>(m_val1)); } literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(static_cast<unsigned>(m_val1)); }

View file

@ -21,9 +21,9 @@ Revision History:
#include<signal.h> #include<signal.h>
#include "util/timeout.h" #include "util/timeout.h"
#include "util/rlimit.h" #include "util/rlimit.h"
#include "util/gparams.h"
#include "sat/dimacs.h" #include "sat/dimacs.h"
#include "sat/sat_solver.h" #include "sat/sat_solver.h"
#include "util/gparams.h"
extern bool g_display_statistics; extern bool g_display_statistics;
static sat::solver * g_solver = 0; static sat::solver * g_solver = 0;
@ -126,6 +126,42 @@ static void track_clauses(sat::solver const& src,
} }
} }
void verify_solution(char const * file_name) {
params_ref p = gparams::get_module("sat");
p.set_bool("produce_models", true);
reslimit limit;
sat::solver solver(p, limit);
std::ifstream in(file_name);
if (in.bad() || in.fail()) {
std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl;
exit(ERR_OPEN_FILE);
}
parse_dimacs(in, solver);
sat::model const & m = g_solver->get_model();
for (unsigned i = 1; i < m.size(); i++) {
sat::literal lit(i, false);
switch (m[i]) {
case l_false: lit.neg(); break;
case l_undef: break;
case l_true: break;
}
solver.mk_clause(1, &lit);
}
lbool r = solver.check();
switch (r) {
case l_false:
std::cout << "model checking failed\n";
break;
case l_true:
std::cout << "model validated\n";
break;
default:
std::cout << "inconclusive model\n";
break;
}
}
unsigned read_dimacs(char const * file_name) { unsigned read_dimacs(char const * file_name) {
g_start_time = clock(); g_start_time = clock();
register_on_timeout_proc(on_timeout); register_on_timeout_proc(on_timeout);
@ -164,6 +200,7 @@ unsigned read_dimacs(char const * file_name) {
switch (r) { switch (r) {
case l_true: case l_true:
std::cout << "sat\n"; std::cout << "sat\n";
if (file_name) verify_solution(file_name);
display_model(*g_solver); display_model(*g_solver);
break; break;
case l_undef: case l_undef: