3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-15 13:28:47 +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 = (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_binary = p.drat_binary();
m_drat_activity = p.drat_activity(); m_drat_activity = p.drat_activity();
m_drup_trim = p.drup_trim();
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

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

View file

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

View file

@ -50,6 +50,7 @@ def_module_params('sat',
('drat.binary', BOOL, False, 'use Binary DRAT output format'), ('drat.binary', BOOL, False, 'use Binary DRAT output format'),
('drat.check_unsat', 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'), ('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'), ('drat.activity', BOOL, False, 'dump variable activities'),
('cardinality.solver', BOOL, True, 'use cardinality solver'), ('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)'), ('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)'),