3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-14 04:48:45 +00:00

prepare for trim

This commit is contained in:
Nikolaj Bjorner 2022-06-09 10:08:57 -07:00
parent c5847504ff
commit 828850f298
5 changed files with 128 additions and 139 deletions

View file

@ -197,6 +197,7 @@ namespace sat {
m_drat = (m_drat_check_unsat || m_drat_file.is_non_empty_string() || m_drat_check_sat) && p.threads() == 1;
m_drat_binary = p.drat_binary();
m_drat_activity = p.drat_activity();
m_drup_trim = p.drup_trim();
m_dyn_sub_res = p.dyn_sub_res();
// Parameters used in Liang, Ganesh, Poupart, Czarnecki AAAI 2016.

View file

@ -179,6 +179,7 @@ namespace sat {
symbol m_drat_file;
bool m_drat_check_unsat;
bool m_drat_check_sat;
bool m_drup_trim;
bool m_drat_activity;
bool m_card_solver;

View file

@ -7,7 +7,7 @@ Module Name:
Abstract:
Produce DRAT proofs.
Produce DRUP/DRAT proofs.
Check them using a very simple forward checker
that interacts with external plugins.
@ -24,17 +24,10 @@ Notes:
#include "sat/sat_solver.h"
#include "sat/sat_drat.h"
namespace sat {
drat::drat(solver& s) :
s(s),
m_out(nullptr),
m_bout(nullptr),
m_inconsistent(false),
m_check_unsat(false),
m_check_sat(false),
m_check(false),
m_activity(false)
s(s)
{
if (s.get_config().m_drat && s.get_config().m_drat_file.is_non_empty_string()) {
auto mode = s.get_config().m_drat_binary ? (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc) : std::ios_base::out;
@ -49,11 +42,8 @@ namespace sat {
if (m_bout) m_bout->flush();
dealloc(m_out);
dealloc(m_bout);
for (unsigned i = 0; i < m_proof.size(); ++i) {
clause* c = m_proof[i];
if (c)
m_alloc.del_clause(c);
}
for (auto & [c, st] : m_proof)
m_alloc.del_clause(&c);
m_proof.reset();
m_out = nullptr;
m_bout = nullptr;
@ -61,9 +51,10 @@ namespace sat {
void drat::updt_config() {
m_check_unsat = s.get_config().m_drat_check_unsat;
m_check_sat = s.get_config().m_drat_check_sat;
m_check = m_check_unsat || m_check_sat;
m_activity = s.get_config().m_drat_activity;
m_check_sat = s.get_config().m_drat_check_sat;
m_trim = s.get_config().m_drup_trim;
m_check = m_check_unsat || m_check_sat || m_trim;
m_activity = s.get_config().m_drat_activity;
}
std::ostream& drat::pp(std::ostream& out, status st) const {
@ -149,14 +140,12 @@ namespace sat {
}
buffer[len++] = '\n';
m_out->write(buffer, len);
}
void drat::dump_activity() {
(*m_out) << "c activity ";
for (unsigned v = 0; v < s.num_vars(); ++v) {
for (unsigned v = 0; v < s.num_vars(); ++v)
(*m_out) << s.m_activity[v] << " ";
}
(*m_out) << "\n";
}
@ -183,7 +172,8 @@ namespace sat {
m_bout->write(buffer, len);
len = 0;
}
} while (v);
}
while (v);
}
buffer[len++] = 0;
m_bout->write(buffer, len);
@ -193,7 +183,8 @@ namespace sat {
literal last = null_literal;
unsigned n = c.size();
for (unsigned i = 0; i < n; ++i) {
if (c[i] == last) return true;
if (c[i] == last)
return true;
last = c[i];
}
return false;
@ -243,12 +234,12 @@ namespace sat {
if (st.is_redundant() && st.is_sat())
verify(2, lits);
clause* c = m_alloc.mk_clause(2, lits, st.is_redundant());
m_proof.push_back(c);
m_status.push_back(st);
if (!m_check_unsat) return;
clause& c = mk_clause(2, lits, st.is_redundant());
m_proof.push_back({c, st});
if (!m_check_unsat)
return;
unsigned idx = m_watched_clauses.size();
m_watched_clauses.push_back(watched_clause(c, l1, l2));
m_watched_clauses.push_back(watched_clause(&c, l1, l2));
m_watches[(~l1).index()].push_back(idx);
m_watches[(~l2).index()].push_back(idx);
@ -286,40 +277,16 @@ namespace sat {
fn(*m_out);
}
#if 0
// debugging code
bool drat::is_clause(clause& c, literal l1, literal l2, literal l3, drat::status st1, drat::status st2) {
//if (st1 != st2) return false;
if (c.size() != 3) return false;
if (l1 == c[0]) {
if (l2 == c[1] && l3 == c[2]) return true;
if (l2 == c[2] && l3 == c[1]) return true;
}
if (l2 == c[0]) {
if (l1 == c[1] && l3 == c[2]) return true;
if (l1 == c[2] && l3 == c[1]) return true;
}
if (l3 == c[0]) {
if (l1 == c[1] && l2 == c[2]) return true;
if (l1 == c[2] && l2 == c[1]) return true;
}
return false;
}
#endif
void drat::append(clause& c, status st) {
TRACE("sat_drat", pp(tout, st) << " " << c << "\n";);
for (literal lit : c) declare(lit);
unsigned n = c.size();
IF_VERBOSE(20, trace(verbose_stream(), n, c.begin(), st););
if (st.is_redundant() && st.is_sat()) {
if (st.is_redundant() && st.is_sat())
verify(c);
}
m_status.push_back(st);
m_proof.push_back(&c);
m_proof.push_back({c, st});
if (st.is_deleted()) {
if (n > 0) del_watch(c, c[0]);
if (n > 1) del_watch(c, c[1]);
@ -370,7 +337,8 @@ namespace sat {
}
void drat::declare(literal l) {
if (!m_check) return;
if (!m_check)
return;
unsigned n = static_cast<unsigned>(l.var());
while (m_assignment.size() <= n) {
m_assignment.push_back(l_undef);
@ -391,9 +359,9 @@ namespace sat {
assign_propagate(~c[i]);
}
for (unsigned i = num_units; i < m_units.size(); ++i) {
for (unsigned i = num_units; i < m_units.size(); ++i)
m_assignment[m_units[i].var()] = l_undef;
}
units.append(m_units.size() - num_units, m_units.data() + num_units);
m_units.shrink(num_units);
bool ok = m_inconsistent;
@ -487,10 +455,8 @@ namespace sat {
}
void drat::validate_propagation() const {
for (unsigned i = 0; i < m_proof.size(); ++i) {
status st = m_status[i];
if (m_proof[i] && m_proof[i]->size() > 1 && !st.is_deleted()) {
clause& c = *m_proof[i];
for (auto const& [c, st] : m_proof) {
if (c.size() > 1 && !st.is_deleted()) {
unsigned num_undef = 0, num_true = 0;
for (unsigned j = 0; j < c.size(); ++j) {
switch (value(c[j])) {
@ -510,10 +476,8 @@ namespace sat {
literal l = c[pos];
literal_vector lits(n, c);
SASSERT(lits.size() == n);
for (unsigned i = 0; i < m_proof.size(); ++i) {
status st = m_status[i];
if (m_proof[i] && m_proof[i]->size() > 1 && st.is_asserted()) {
clause& c = *m_proof[i];
for (auto const& [c, st] : m_proof) {
if (c.size() > 1 && st.is_asserted()) {
unsigned j = 0;
for (; j < c.size() && c[j] != ~l; ++j) {}
if (j != c.size()) {
@ -530,12 +494,10 @@ namespace sat {
}
void drat::verify(unsigned n, literal const* c) {
if (!m_check_unsat) {
if (!m_check_unsat)
return;
}
for (unsigned i = 0; i < n; ++i) {
for (unsigned i = 0; i < n; ++i)
declare(c[i]);
}
if (is_drup(n, c)) {
++m_stats.m_num_drup;
return;
@ -584,12 +546,12 @@ namespace sat {
}
bool drat::contains(unsigned n, literal const* lits) {
if (!m_check) return true;
if (!m_check)
return true;
unsigned num_add = 0;
unsigned num_del = 0;
for (unsigned i = m_proof.size(); i-- > 0; ) {
clause& c = *m_proof[i];
status st = m_status[i];
auto const & [c, st] = m_proof[i];
if (match(n, lits, c)) {
if (st.is_deleted()) {
num_del++;
@ -603,52 +565,53 @@ namespace sat {
}
bool drat::match(unsigned n, literal const* lits, clause const& c) const {
if (n == c.size()) {
for (unsigned i = 0; i < n; ++i) {
literal lit1 = lits[i];
bool found = false;
for (literal lit2 : c) {
if (lit1 == lit2) {
found = true;
break;
}
}
if (!found) {
return false;
if (n != c.size())
return false;
for (unsigned i = 0; i < n; ++i) {
literal lit1 = lits[i];
bool found = false;
for (literal lit2 : c) {
if (lit1 == lit2) {
found = true;
break;
}
}
return true;
if (!found)
return false;
}
return false;
return true;
}
void drat::display(std::ostream& out) const {
out << "units: " << m_units << "\n";
for (unsigned i = 0; i < m_assignment.size(); ++i) {
lbool v = value(literal(i, false));
if (v != l_undef) out << i << ": " << v << "\n";
if (v != l_undef)
out << i << ": " << v << "\n";
}
for (unsigned i = 0; i < m_proof.size(); ++i) {
clause* c = m_proof[i];
if (!m_status[i].is_deleted() && c) {
unsigned num_true = 0;
unsigned num_undef = 0;
for (unsigned j = 0; j < c->size(); ++j) {
switch (value((*c)[j])) {
case l_true: num_true++; break;
case l_undef: num_undef++; break;
default: break;
}
unsigned i = 0;
for (auto const& [c, st] : m_proof) {
++i;
if (st.is_deleted())
continue;
unsigned num_true = 0;
unsigned num_undef = 0;
for (unsigned j = 0; j < c.size(); ++j) {
switch (value(c[j])) {
case l_true: num_true++; break;
case l_undef: num_undef++; break;
default: break;
}
if (num_true == 0 && num_undef == 0) {
out << "False ";
}
if (num_true == 0 && num_undef == 1) {
out << "Unit ";
}
pp(out, m_status[i]) << " " << i << ": " << *c << "\n";
}
if (num_true == 0 && num_undef == 0)
out << "False ";
if (num_true == 0 && num_undef == 1)
out << "Unit ";
pp(out, st) << " " << i << ": " << c << "\n";
}
for (unsigned i = 0; i < m_assignment.size(); ++i) {
watch const& w1 = m_watches[2 * i];
watch const& w2 = m_watches[2 * i + 1];
@ -690,9 +653,8 @@ namespace sat {
void drat::assign_propagate(literal l) {
unsigned num_units = m_units.size();
assign(l);
for (unsigned i = num_units; !m_inconsistent && i < m_units.size(); ++i) {
propagate(m_units[i]);
}
for (unsigned i = num_units; !m_inconsistent && i < m_units.size(); ++i)
propagate(m_units[i]);
}
void drat::propagate(literal l) {
@ -784,11 +746,9 @@ namespace sat {
++m_stats.m_num_add;
if (m_out) dump(c.size(), c.begin(), st);
if (m_bout) bdump(c.size(), c.begin(), st);
if (m_check) {
clause* cl = m_alloc.mk_clause(c.size(), c.begin(), st.is_redundant());
append(*cl, st);
}
if (m_check) append(mk_clause(c), st);
}
void drat::add(literal_vector const& lits, status st) {
add(lits.size(), lits.data(), st);
}
@ -802,11 +762,7 @@ namespace sat {
switch (sz) {
case 0: add(); break;
case 1: append(lits[0], st); break;
default: {
clause* c = m_alloc.mk_clause(sz, lits, st.is_redundant());
append(*c, st);
break;
}
default: append(mk_clause(sz, lits, st.is_redundant()), st); break;
}
}
if (m_out)
@ -818,14 +774,14 @@ namespace sat {
if (m_out) dump(c.size(), c.begin(), status::redundant());
if (m_bout) bdump(c.size(), c.begin(), status::redundant());
if (m_check) {
for (literal lit : c) declare(lit);
for (literal lit : c)
declare(lit);
switch (c.size()) {
case 0: add(); break;
case 1: append(c[0], status::redundant()); break;
default: {
verify(c.size(), c.begin());
clause* cl = m_alloc.mk_clause(c.size(), c.data(), true);
append(*cl, status::redundant());
append(mk_clause(c.size(), c.data(), true), status::redundant());
break;
}
}
@ -836,7 +792,7 @@ namespace sat {
++m_stats.m_num_del;
if (m_out) dump(1, &l, status::deleted());
if (m_bout) bdump(1, &l, status::deleted());
if (m_check_unsat) append(l, status::deleted());
if (m_check) append(l, status::deleted());
}
void drat::del(literal l1, literal l2) {
@ -862,20 +818,22 @@ namespace sat {
++m_stats.m_num_del;
if (m_out) dump(c.size(), c.begin(), status::deleted());
if (m_bout) bdump(c.size(), c.begin(), status::deleted());
if (m_check) {
clause* c1 = m_alloc.mk_clause(c.size(), c.begin(), c.is_learned());
append(*c1, status::deleted());
}
if (m_check) append(mk_clause(c), status::deleted());
}
clause& drat::mk_clause(clause& c) {
return mk_clause(c.size(), c.begin(), c.is_learned());
}
clause& drat::mk_clause(unsigned n, literal const* lits, bool is_learned) {
return *m_alloc.mk_clause(n, lits, is_learned);
}
void drat::del(literal_vector const& c) {
++m_stats.m_num_del;
if (m_out) dump(c.size(), c.begin(), status::deleted());
if (m_bout) bdump(c.size(), c.begin(), status::deleted());
if (m_check) {
clause* c1 = m_alloc.mk_clause(c.size(), c.begin(), true);
append(*c1, status::deleted());
}
if (m_check) append(mk_clause(c.size(), c.begin(), true), status::deleted());
}
void drat::check_model(model const& m) {
@ -1028,4 +986,25 @@ namespace sat {
}
}
#if 0
// debugging code
bool drat::is_clause(clause& c, literal l1, literal l2, literal l3, drat::status st1, drat::status st2) {
//if (st1 != st2) return false;
if (c.size() != 3) return false;
if (l1 == c[0]) {
if (l2 == c[1] && l3 == c[2]) return true;
if (l2 == c[2] && l3 == c[1]) return true;
}
if (l2 == c[0]) {
if (l1 == c[1] && l3 == c[2]) return true;
if (l1 == c[2] && l3 == c[1]) return true;
}
if (l3 == c[0]) {
if (l1 == c[1] && l2 == c[2]) return true;
if (l1 == c[2] && l2 == c[1]) return true;
}
return false;
}
#endif
}

View file

@ -62,10 +62,10 @@ namespace sat {
class drat {
struct stats {
unsigned m_num_drup { 0 };
unsigned m_num_drat { 0 };
unsigned m_num_add { 0 };
unsigned m_num_del { 0 };
unsigned m_num_drup = 0;
unsigned m_num_drat = 0;
unsigned m_num_add = 0;
unsigned m_num_del = 0;
};
struct watched_clause {
clause* m_clause;
@ -77,16 +77,19 @@ namespace sat {
typedef svector<unsigned> watch;
solver& s;
clause_allocator m_alloc;
std::ostream* m_out;
std::ostream* m_bout;
ptr_vector<clause> m_proof;
svector<status> m_status;
std::ostream* m_out = nullptr;
std::ostream* m_bout = nullptr;
svector<std::pair<clause&, status>> m_proof;
literal_vector m_units;
vector<watch> m_watches;
svector<lbool> m_assignment;
vector<std::string> m_theory;
bool m_inconsistent;
bool m_check_unsat, m_check_sat, m_check, m_activity;
bool m_inconsistent = false;
bool m_check_unsat = false;
bool m_check_sat = false;
bool m_check = false;
bool m_activity = false;
bool m_trim = false;
stats m_stats;
void dump_activity();
@ -115,6 +118,10 @@ namespace sat {
void validate_propagation() const;
bool match(unsigned n, literal const* lits, clause const& c) const;
clause& mk_clause(clause& c);
clause& mk_clause(unsigned n, literal const* lits, bool is_learned);
public:
drat(solver& s);

View file

@ -50,6 +50,7 @@ def_module_params('sat',
('drat.binary', BOOL, False, 'use Binary DRAT output format'),
('drat.check_unsat', BOOL, False, 'build up internal proof and check'),
('drat.check_sat', BOOL, False, 'build up internal trace, check satisfying model'),
('drup.trim', BOOL, False, 'build and trim drup proof'),
('drat.activity', BOOL, False, 'dump variable activities'),
('cardinality.solver', BOOL, True, 'use cardinality solver'),
('pb.solver', SYMBOL, 'solver', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), binary_merge, segmented, solver (use native solver)'),