mirror of
https://github.com/Z3Prover/z3
synced 2025-04-11 03:33:35 +00:00
237 lines
8.2 KiB
C++
237 lines
8.2 KiB
C++
/*++
|
|
Copyright (c) 2011 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sat_cleaner.h
|
|
|
|
Abstract:
|
|
|
|
Eliminate satisfied clauses, and literals assigned to false.
|
|
|
|
Author:
|
|
|
|
Leonardo de Moura (leonardo) 2011-05-24.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "sat/sat_cleaner.h"
|
|
#include "sat/sat_solver.h"
|
|
#include "util/trace.h"
|
|
#include "util/stopwatch.h"
|
|
|
|
namespace sat {
|
|
|
|
cleaner::cleaner(solver & _s):
|
|
s(_s),
|
|
m_last_num_units(0),
|
|
m_cleanup_counter(0) {
|
|
reset_statistics();
|
|
}
|
|
|
|
/**
|
|
- Delete watch lists of assigned literals.
|
|
- Delete satisfied binary watched binary clauses
|
|
- Delete watched clauses (they will be reinserted after they are cleaned).
|
|
*/
|
|
void cleaner::cleanup_watches() {
|
|
vector<watch_list>::iterator it = s.m_watches.begin();
|
|
vector<watch_list>::iterator end = s.m_watches.end();
|
|
unsigned l_idx = 0;
|
|
for (; it != end; ++it, ++l_idx) {
|
|
if (s.value(to_literal(l_idx)) != l_undef) {
|
|
it->finalize();
|
|
SASSERT(it->empty());
|
|
continue;
|
|
}
|
|
TRACE("cleanup_bug", tout << "processing wlist of " << to_literal(l_idx) << "\n";);
|
|
watch_list & wlist = *it;
|
|
watch_list::iterator it2 = wlist.begin();
|
|
watch_list::iterator it_prev = it2;
|
|
watch_list::iterator end2 = wlist.end();
|
|
for (; it2 != end2; ++it2) {
|
|
switch (it2->get_kind()) {
|
|
case watched::BINARY:
|
|
TRACE("cleanup_bug",
|
|
tout << ~to_literal(l_idx) << " " << it2->get_literal() << "\n";
|
|
tout << s.value(~to_literal(l_idx)) << " " << s.value(it2->get_literal()) << "\n";
|
|
tout << s.was_eliminated(it2->get_literal()) << " " << s.inconsistent() << "\n";);
|
|
SASSERT(s.value(it2->get_literal()) == l_true || s.value(it2->get_literal()) == l_undef);
|
|
if (s.value(it2->get_literal()) == l_undef) {
|
|
*it_prev = *it2;
|
|
++it_prev;
|
|
}
|
|
TRACE("cleanup_bug", tout << "keeping: " << ~to_literal(l_idx) << " " << it2->get_literal() << "\n";);
|
|
break;
|
|
#if ENABLE_TERNARY
|
|
case watched::TERNARY:
|
|
#endif
|
|
case watched::CLAUSE:
|
|
// skip
|
|
break;
|
|
case watched::EXT_CONSTRAINT:
|
|
*it_prev = *it2;
|
|
++it_prev;
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
break;
|
|
}
|
|
}
|
|
wlist.set_end(it_prev);
|
|
}
|
|
}
|
|
|
|
void cleaner::cleanup_clauses(clause_vector & cs) {
|
|
clause_vector::iterator it = cs.begin();
|
|
clause_vector::iterator it2 = it;
|
|
clause_vector::iterator end = cs.end();
|
|
for (; it != end; ++it) {
|
|
clause & c = *(*it);
|
|
TRACE("sat_cleaner_bug", tout << "cleaning: " << c << "\n";
|
|
for (unsigned i = 0; i < c.size(); i++) tout << c[i] << ": " << s.value(c[i]) << "\n";);
|
|
CTRACE("sat_cleaner_frozen", c.frozen(), tout << c << "\n";);
|
|
unsigned sz = c.size();
|
|
unsigned i = 0, j = 0;
|
|
m_cleanup_counter += sz;
|
|
for (; i < sz; i++) {
|
|
switch (s.value(c[i])) {
|
|
case l_true:
|
|
goto end_loop;
|
|
case l_false:
|
|
m_elim_literals++;
|
|
break;
|
|
case l_undef:
|
|
if (i != j) {
|
|
std::swap(c[j], c[i]);
|
|
}
|
|
j++;
|
|
break;
|
|
}
|
|
}
|
|
end_loop:
|
|
CTRACE("sat_cleaner_frozen", c.frozen(),
|
|
tout << "sat: " << (i < sz) << ", new_size: " << j << "\n";
|
|
tout << mk_lits_pp(j, c.begin()) << "\n";);
|
|
if (i < sz) {
|
|
m_elim_clauses++;
|
|
s.del_clause(c);
|
|
}
|
|
else {
|
|
unsigned new_sz = j;
|
|
CTRACE("sat_cleaner_bug", new_sz < 2, tout << "new_sz: " << new_sz << "\n";
|
|
if (c.size() > 0) tout << "unit: " << c[0] << "\n";
|
|
s.display_watches(tout););
|
|
switch (new_sz) {
|
|
case 0:
|
|
s.set_conflict();
|
|
s.del_clause(c);
|
|
break;
|
|
case 1:
|
|
s.assign_unit(c[0]);
|
|
s.del_clause(c);
|
|
break;
|
|
case 2:
|
|
SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef);
|
|
TRACE("cleanup_bug", tout << "clause became binary: " << c[0] << " " << c[1] << "\n";);
|
|
s.mk_bin_clause(c[0], c[1], c.is_learned());
|
|
s.del_clause(c);
|
|
break;
|
|
default:
|
|
s.shrink(c, sz, new_sz);
|
|
*it2 = *it;
|
|
it2++;
|
|
if (!c.frozen()) {
|
|
s.attach_clause(c);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
cs.set_end(it2);
|
|
}
|
|
|
|
struct cleaner::report {
|
|
cleaner & m_cleaner;
|
|
stopwatch m_watch;
|
|
unsigned m_elim_clauses;
|
|
unsigned m_elim_literals;
|
|
report(cleaner & c):
|
|
m_cleaner(c),
|
|
m_elim_clauses(c.m_elim_clauses),
|
|
m_elim_literals(c.m_elim_literals) {
|
|
m_watch.start();
|
|
}
|
|
~report() {
|
|
m_watch.stop();
|
|
IF_VERBOSE(2,
|
|
verbose_stream() << " (sat-cleaner";
|
|
verbose_stream() << " :elim-literals " << (m_cleaner.m_elim_literals - m_elim_literals);
|
|
verbose_stream() << " :elim-clauses " << (m_cleaner.m_elim_clauses - m_elim_clauses);
|
|
verbose_stream() << " :cost " << m_cleaner.m_cleanup_counter << m_watch << ")\n";);
|
|
}
|
|
};
|
|
|
|
bool cleaner::is_clean() const {
|
|
for (clause* cp : s.m_clauses) {
|
|
for (literal lit : *cp) {
|
|
if (s.value(lit) != l_undef && s.lvl(lit) == 0) return false;
|
|
}
|
|
}
|
|
for (clause* cp : s.m_learned) {
|
|
for (literal lit : *cp) {
|
|
if (s.value(lit) != l_undef && s.lvl(lit) == 0) return false;
|
|
}
|
|
}
|
|
unsigned idx = 0;
|
|
for (auto& wlist : s.m_watches) {
|
|
literal lit = to_literal(idx);
|
|
if (s.value(lit) != l_undef && s.lvl(lit) == 0 && !wlist.empty()) return false;
|
|
++idx;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
\brief Return true if cleaner executed.
|
|
*/
|
|
bool cleaner::operator()(bool force) {
|
|
CASSERT("cleaner_bug", s.check_invariant());
|
|
unsigned trail_sz = s.m_trail.size();
|
|
|
|
s.propagate(false); // make sure that everything was propagated.
|
|
TRACE("sat_cleaner_bug", s.display(tout); s.display_watches(tout););
|
|
if (s.m_inconsistent)
|
|
return false;
|
|
if (m_last_num_units == trail_sz)
|
|
return false; // there are no new assigned literals since last time... nothing to be done
|
|
if (!force && m_cleanup_counter > 0)
|
|
return false; // prevent simplifier from being executed over and over again.
|
|
report rpt(*this);
|
|
m_last_num_units = trail_sz;
|
|
m_cleanup_counter = 0;
|
|
do {
|
|
trail_sz = s.m_trail.size();
|
|
cleanup_watches();
|
|
cleanup_clauses(s.m_clauses);
|
|
cleanup_clauses(s.m_learned);
|
|
s.propagate(false);
|
|
}
|
|
while (trail_sz < s.m_trail.size() && !s.inconsistent());
|
|
CASSERT("cleaner_bug", s.check_invariant());
|
|
return true;
|
|
}
|
|
|
|
void cleaner::reset_statistics() {
|
|
m_elim_clauses = 0;
|
|
m_elim_literals = 0;
|
|
}
|
|
|
|
void cleaner::collect_statistics(statistics & st) const {
|
|
st.update("sat elim clauses", m_elim_clauses);
|
|
st.update("sat elim literals", m_elim_literals);
|
|
}
|
|
|
|
};
|