3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-20 04:43:39 +00:00

add ite-finder, profile

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-01-05 13:35:14 -08:00
parent a6c3c18e74
commit e1fb74edc5
17 changed files with 321 additions and 168 deletions

View file

@ -102,7 +102,7 @@ namespace dd {
pdd pdd_manager::one() { return pdd(one_pdd, this); } pdd pdd_manager::one() { return pdd(one_pdd, this); }
pdd pdd_manager::mk_or(pdd const& p, pdd const& q) { return p + q - (p*q); } pdd pdd_manager::mk_or(pdd const& p, pdd const& q) { return p + q - (p*q); }
pdd pdd_manager::mk_xor(pdd const& p, pdd const& q) { return (p*q*2) - p - q; } pdd pdd_manager::mk_xor(pdd const& p, pdd const& q) { if (m_semantics == mod2_e) return p + q; return (p*q*2) - p - q; }
pdd pdd_manager::mk_not(pdd const& p) { return 1 - p; } pdd pdd_manager::mk_not(pdd const& p) { return 1 - p; }
pdd pdd_manager::subst_val(pdd const& p, vector<std::pair<unsigned, rational>> const& _s) { pdd pdd_manager::subst_val(pdd const& p, vector<std::pair<unsigned, rational>> const& _s) {
@ -152,7 +152,7 @@ namespace dd {
} }
} }
pdd_manager::PDD pdd_manager::apply_rec(PDD p, PDD q, pdd_op op) { pdd_manager::PDD pdd_manager::apply_rec(PDD p, PDD q, pdd_op op) {
switch (op) { switch (op) {
case pdd_sub_op: case pdd_sub_op:
if (is_zero(q)) return p; if (is_zero(q)) return p;

View file

@ -75,6 +75,7 @@ namespace dd {
} }
} }
catch (pdd_manager::mem_out) { catch (pdd_manager::mem_out) {
IF_VERBOSE(2, verbose_stream() << "simplifier memout\n");
// done reduce // done reduce
DEBUG_CODE(s.invariant();); DEBUG_CODE(s.invariant(););
} }
@ -400,6 +401,7 @@ namespace dd {
for (pdd const& p : simp_eqs) { for (pdd const& p : simp_eqs) {
s.add(p); s.add(p);
} }
IF_VERBOSE(10, verbose_stream() << "simp_linear " << simp_eqs.size() << "\n";);
return !simp_eqs.empty() && simplify_linear_step(false); return !simp_eqs.empty() && simplify_linear_step(false);
} }
@ -425,13 +427,14 @@ namespace dd {
*/ */
void simplifier::exlin_augment(vector<uint_set> const& orbits, vector<pdd>& eqs) { void simplifier::exlin_augment(vector<uint_set> const& orbits, vector<pdd>& eqs) {
IF_VERBOSE(10, verbose_stream() << "pdd-exlin augment\n";);
unsigned nv = s.m.num_vars(); unsigned nv = s.m.num_vars();
random_gen rand(s.m_config.m_random_seed); random_gen rand(s.m_config.m_random_seed);
unsigned modest_num_eqs = std::min(eqs.size(), 500u); unsigned modest_num_eqs = std::max(eqs.size(), 500u);
unsigned max_xlin_eqs = modest_num_eqs*modest_num_eqs + eqs.size(); unsigned max_xlin_eqs = modest_num_eqs;
unsigned max_degree = 5;
TRACE("dd.solver", tout << "augment " << nv << "\n"; TRACE("dd.solver", tout << "augment " << nv << "\n";
for (auto const& o : orbits) tout << o.num_elems() << "\n"; for (auto const& o : orbits) tout << o.num_elems() << "\n";);
);
vector<pdd> n_eqs; vector<pdd> n_eqs;
unsigned start = rand(); unsigned start = rand();
for (unsigned _v = 0; _v < nv; ++_v) { for (unsigned _v = 0; _v < nv; ++_v) {
@ -440,15 +443,16 @@ namespace dd {
if (orbitv.empty()) continue; if (orbitv.empty()) continue;
pdd pv = s.m.mk_var(v); pdd pv = s.m.mk_var(v);
for (pdd p : eqs) { for (pdd p : eqs) {
if (p.degree() > max_degree) continue;
for (unsigned w : p.free_vars()) { for (unsigned w : p.free_vars()) {
if (v != w && orbitv.contains(w)) { if (v != w && orbitv.contains(w)) {
n_eqs.push_back(pv * p); n_eqs.push_back(pv * p);
if (n_eqs.size() > max_xlin_eqs) {
goto end_of_new_eqs;
}
break; break;
} }
} }
if (n_eqs.size() > max_xlin_eqs) {
goto end_of_new_eqs;
}
} }
} }
@ -462,12 +466,13 @@ namespace dd {
if (v >= w) continue; if (v >= w) continue;
pdd pw = s.m.mk_var(w); pdd pw = s.m.mk_var(w);
for (pdd p : eqs) { for (pdd p : eqs) {
if (n_eqs.size() > max_xlin_eqs) { if (p.degree() + 1 > max_degree) continue;
goto end_of_new_eqs;
}
for (unsigned u : p.free_vars()) { for (unsigned u : p.free_vars()) {
if (orbits[w].contains(u) || orbits[v].contains(u)) { if (orbits[w].contains(u) || orbits[v].contains(u)) {
n_eqs.push_back(pw * pv * p); n_eqs.push_back(pw * pv * p);
if (n_eqs.size() > max_xlin_eqs) {
goto end_of_new_eqs;
}
break; break;
} }
} }
@ -481,22 +486,53 @@ namespace dd {
} }
void simplifier::simplify_exlin(vector<uint_set> const& orbits, vector<pdd> const& eqs, vector<pdd>& simp_eqs) { void simplifier::simplify_exlin(vector<uint_set> const& orbits, vector<pdd> const& eqs, vector<pdd>& simp_eqs) {
IF_VERBOSE(10, verbose_stream() << "pdd simplify-exlin\n";);
// index monomials
unsigned_vector vars;
struct mon {
unsigned sz;
unsigned offset;
unsigned index;
unsigned_vector* vars;
mon(unsigned sz, unsigned offset, unsigned_vector* vars): sz(sz), offset(offset), index(UINT_MAX), vars(vars) {}
mon(): sz(0), offset(0), index(UINT_MAX), vars(nullptr) {}
bool is_valid() const { return index != UINT_MAX; }
struct hash {
bool operator()(mon const& m) const {
if (!m.vars) return 0;
return string_hash((const char*)(m.vars->c_ptr() + m.offset), m.sz*4, 1);
};
};
struct eq {
bool operator()(mon const& a, mon const& b) const {
if (a.sz != b.sz) return false;
for (unsigned i = 0; i < a.sz; ++i)
if ((*a.vars)[a.offset+i] != (*b.vars)[b.offset+i]) return false;
return true;
}
};
};
hashtable<mon, mon::hash, mon::eq> mon2idx;
svector<mon> idx2mon;
// create variables for each non-constant monomial. auto insert_mon = [&,this](unsigned n, unsigned const* vs) {
u_map<unsigned> mon2idx; mon mm(n, vars.size(), &vars);
vector<pdd> idx2mon; vars.append(n, vs);
auto* e = mon2idx.insert_if_not_there2(mm);
if (!e->get_data().is_valid()) {
e->get_data().index = idx2mon.size();
idx2mon.push_back(e->get_data());
}
else {
vars.shrink(vars.size() - n);
}
};
// insert monomials of degree > 1 // insert monomials of degree > 1
for (pdd const& p : eqs) { for (pdd const& p : eqs) {
for (auto const& m : p) { for (auto const& m : p) {
if (m.vars.size() <= 1) continue; if (m.vars.size() <= 1) continue;
pdd r = s.m.mk_val(m.coeff); insert_mon(m.vars.size(), m.vars.c_ptr());
for (unsigned i = m.vars.size(); i-- > 0; )
r *= s.m.mk_var(m.vars[i]);
if (!mon2idx.contains(r.index())) {
mon2idx.insert(r.index(), idx2mon.size());
idx2mon.push_back(r);
}
} }
} }
@ -504,12 +540,13 @@ namespace dd {
unsigned nv = s.m.num_vars(); unsigned nv = s.m.num_vars();
for (unsigned v = 0; v < nv; ++v) { for (unsigned v = 0; v < nv; ++v) {
if (!orbits[v].empty()) { // not all variables are used. if (!orbits[v].empty()) { // not all variables are used.
pdd r = s.m.mk_var(v); insert_mon(1, &v);
mon2idx.insert(r.index(), idx2mon.size());
idx2mon.push_back(r);
} }
} }
IF_VERBOSE(10, verbose_stream() << "extracted monomials: " << idx2mon.size() << "\n";);
bit_matrix bm; bit_matrix bm;
unsigned const_idx = idx2mon.size(); unsigned const_idx = idx2mon.size();
bm.reset(const_idx + 1); bm.reset(const_idx + 1);
@ -526,19 +563,22 @@ namespace dd {
row.set(const_idx); row.set(const_idx);
continue; continue;
} }
pdd r = s.m.one(); unsigned n = m.vars.size();
for (unsigned i = m.vars.size(); i-- > 0; ) mon mm(n, vars.size(), &vars);
r *= s.m.mk_var(m.vars[i]); vars.append(n, m.vars.c_ptr());
unsigned v = mon2idx[r.index()]; VERIFY(mon2idx.find(mm, mm));
row.set(v); vars.shrink(vars.size() - n);
row.set(mm.index);
} }
} }
TRACE("dd.solver", tout << bm << "\n";); TRACE("dd.solver", tout << bm << "\n";);
IF_VERBOSE(10, verbose_stream() << "bit-matrix solving\n");
bm.solve(); bm.solve();
TRACE("dd.solver", tout << bm << "\n";); TRACE("dd.solver", tout << bm << "\n";);
IF_VERBOSE(10, verbose_stream() << "bit-matrix solved\n");
for (auto const& r : bm) { for (auto const& r : bm) {
bool is_linear = true; bool is_linear = true;
@ -547,8 +587,7 @@ namespace dd {
if (c == const_idx) { if (c == const_idx) {
break; break;
} }
pdd const& p = idx2mon[c]; if (idx2mon[c].sz != 1) {
if (!p.is_unary()) {
is_linear = false; is_linear = false;
break; break;
} }
@ -561,7 +600,8 @@ namespace dd {
p += s.m.one(); p += s.m.one();
} }
else { else {
p += idx2mon[c]; mon const& mm = idx2mon[c];
p += s.m.mk_var(vars[mm.offset]);
} }
} }
if (!p.is_zero()) { if (!p.is_zero()) {

View file

@ -14,6 +14,7 @@ Notes:
--*/ --*/
#include "math/simplex/bit_matrix.h" #include "math/simplex/bit_matrix.h"
#include "util/stopwatch.h"
bit_matrix::col_iterator bit_matrix::row::begin() const { bit_matrix::col_iterator bit_matrix::row::begin() const {
@ -68,11 +69,22 @@ bit_matrix::row& bit_matrix::row::operator+=(row const& other) {
return *this; return *this;
} }
struct bit_matrix::report {
bit_matrix& b;
stopwatch m_watch;
report(bit_matrix& b) : b(b) { m_watch.start(); }
~report() {
m_watch.stop();
IF_VERBOSE(10, verbose_stream() << "solve " << b.m_rows.size() << " " << b.m_num_columns << " " << m_watch << "\n");
}
};
void bit_matrix::solve() { void bit_matrix::solve() {
basic_solve(); basic_solve();
} }
void bit_matrix::basic_solve() { void bit_matrix::basic_solve() {
report _report(*this);
for (row& r : *this) { for (row& r : *this) {
auto ci = r.begin(); auto ci = r.begin();
if (ci != r.end()) { if (ci != r.end()) {

View file

@ -33,6 +33,8 @@ class bit_matrix {
unsigned m_num_chunks; unsigned m_num_chunks;
ptr_vector<uint64_t> m_rows; ptr_vector<uint64_t> m_rows;
struct report;
public: public:
class col_iterator; class col_iterator;

View file

@ -3802,7 +3802,8 @@ namespace sat {
xor_finder xf(s()); xor_finder xf(s());
std::function<void (literal_vector const&)> f = [this](literal_vector const& l) { add_xr(l, false); }; std::function<void (literal_vector const&)> f = [this](literal_vector const& l) { add_xr(l, false); };
xf.set(f); xf.set(f);
xf.extract_xors(s().m_clauses); clause_vector clauses(s().clauses());
xf(clauses);
for (clause* cp : xf.removed_clauses()) { for (clause* cp : xf.removed_clauses()) {
cp->set_removed(true); cp->set_removed(true);
m_clause_removed = true; m_clause_removed = true;

View file

@ -21,15 +21,10 @@
namespace sat { namespace sat {
void aig_finder::operator()(clause_vector const& clauses) { void aig_finder::operator()(clause_vector& clauses) {
m_big.init(s, true); m_big.init(s, true);
find_aigs(clauses);
for (clause* cp : clauses) { find_ifs(clauses);
clause& c = *cp;
if (c.size() <= 2) continue;
if (find_aig(c)) continue;
if (find_if(c)) continue;
}
} }
bool aig_finder::implies(literal a, literal b) { bool aig_finder::implies(literal a, literal b) {
@ -42,11 +37,29 @@ namespace sat {
return false; return false;
} }
void aig_finder::find_aigs(clause_vector& clauses) {
if (!m_on_aig) {
return;
}
unsigned j = 0;
for (clause* cp : clauses) {
clause& c = *cp;
if (!find_aig(c)) {
clauses[j++] = cp;
}
}
clauses.shrink(j);
}
// a = ~b & ~c // a = ~b & ~c
// if (~a | ~b) (~a | ~c), (b | c | a) // if (~a | ~b) (~a | ~c), (b | c | a)
bool aig_finder::find_aig(clause& c) { bool aig_finder::find_aig(clause& c) {
bool is_aig = false; bool is_aig = false;
if (c.size() <= 2) {
return false;
}
for (literal head : c) { for (literal head : c) {
is_aig = true; is_aig = true;
for (literal tail : c) { for (literal tail : c) {
@ -62,7 +75,7 @@ namespace sat {
for (literal tail : c) for (literal tail : c)
if (tail != head) if (tail != head)
m_ands.push_back(~tail); m_ands.push_back(~tail);
m_aig_def(head, m_ands, c); m_on_aig(head, m_ands);
break; break;
} }
} }
@ -76,78 +89,139 @@ namespace sat {
// y, z -> x // y, z -> x
// ~y, u -> x // ~y, u -> x
// //
// So there are clauses
// y -> (x = z)
// u -> (x = ~y)
//
// from clause x, y, z
// then ~x, ~y -> z
// look for ~y, z -> ~x - contains ternary(y, ~z, ~x)
// look for ~x, y -> u - u is used in a ternary claues (~y, x)
// look for y, u -> ~x - contains ternary(~u, ~x, ~y)
// then ~x = if ~y then z else u
bool aig_finder::find_if(clause& c) { void aig_finder::find_ifs(clause_vector& clauses) {
return false;
#if 0
if (c.size() != 3) return false;
literal x = c[0], y = c[1], z = c[2]; if (!m_on_if) {
if (find_if(~x, ~y, z, c)) return true; return;
if (find_if(~x, ~z, y, c)) return true;
if (find_if(~y, ~x, z, c)) return true;
if (find_if(~y, ~z, x, c)) return true;
if (find_if(~z, ~x, y, c)) return true;
if (find_if(~z, ~y, x, c)) return true;
return false;
#endif
}
#if 0
// x, y -> z
// x, ~y -> u
// y, z -> x
// ~y, u -> x
// x + yz + (1 + y)u = 0
bool aig_finder::check_if(literal x, literal y, literal z, clause& c) {
clause* c2 = find_clause(~y, ~z, x);
if (!c2) {
return false;
} }
for (clause* c3 : ternay_clauses_with(~x, y)) {
literal u = third_literal(~x, y, *c3); for (clause* cp : clauses) cp->unmark_used();
clause* c4 = find_clause(y, ~u, x);
if (c4) { typedef svector<std::pair<literal, clause*>> use_list_t;
m_if_def(x, y, z, u, c, *c2, *c3, *c4); struct binary {
literal x, y;
use_list_t* use_list;
binary(literal x, literal y, use_list_t* u): x(x), y(y), use_list(u) {
if (x.index() > y.index()) std::swap(x, y);
}
binary():x(null_literal), y(null_literal), use_list(nullptr) {}
struct hash {
unsigned operator()(binary const& t) const { return t.x.hash() + 2* t.y.hash(); }
};
struct eq {
bool operator()(binary const& a, binary const& b) const {
return a.x == b.x && a.y == b.y;
}
};
};
hashtable<binary, binary::hash, binary::eq> binaries;
scoped_ptr_vector<use_list_t> use_lists;
auto insert_binary = [&](literal x, literal y, literal z, clause* c) {
binary b(x, y, nullptr);
auto* e = binaries.insert_if_not_there2(b);
if (e->get_data().use_list == nullptr) {
use_list_t* use_list = alloc(use_list_t);
use_lists.push_back(use_list);
e->get_data().use_list = use_list;
}
e->get_data().use_list->push_back(std::make_pair(z, c));
};
struct ternary {
literal x, y, z;
clause* orig;
ternary(literal x, literal y, literal z, clause* c):
x(x), y(y), z(z), orig(c) {
if (x.index() > y.index()) std::swap(x, y);
if (y.index() > z.index()) std::swap(y, z);
if (x.index() > y.index()) std::swap(x, y);
}
ternary():x(null_literal), y(null_literal), z(null_literal), orig(nullptr) {}
struct hash {
unsigned operator()(ternary const& t) const { return mk_mix(t.x.hash(), t.y.hash(), t.z.hash()); }
};
struct eq {
bool operator()(ternary const& a, ternary const& b) const {
return a.x == b.x && a.y == b.y && a.z == b.z;
}
};
};
hashtable<ternary, ternary::hash, ternary::eq> ternaries;
auto has_ternary = [&](literal x, literal y, literal z, clause*& c) {
ternary t(x, y, z, nullptr);
if (ternaries.find(t, t)) {
c = t.orig;
return true; return true;
} }
if (implies(~y, z) || implies(~x, y) || implies(~x, z)) {
c = nullptr;
return true;
}
return false;
};
auto insert_ternary = [&](clause& c) {
if (c.size() == 3) {
ternaries.insert(ternary(c[0], c[1], c[2], &c));
insert_binary(c[0], c[1], c[2], &c);
insert_binary(c[0], c[2], c[1], &c);
insert_binary(c[2], c[1], c[0], &c);
}
};
for (clause* cp : s.learned()) {
insert_ternary(*cp);
} }
} for (clause* cp : s.clauses()) {
insert_ternary(*cp);
literal aig_finder::third_literal(literal a, literal b, clause const& c) { }
for (literal lit : c) auto try_ite = [&,this](literal x, literal y, literal z, clause& c) {
if (lit != a && lit != b) clause* c1, *c3;
return lit; if (has_ternary(y, ~z, ~x, c1)) {
return null_literal; binary b(~y, x, nullptr);
} if (!binaries.find(b, b)) {
return false;
clause* aig_finder::find_clause(literal a, literal b, literal c) { }
for (auto const& w : s.get_wlist(~a)) { for (auto p : *b.use_list) {
if (w.is_ternary() && literal u = p.first;
(b == w.get_literal1() && c == w.get_literal2()) || clause* c2 = p.second;
(c == w.get_literal1() && b == w.get_literal2())) { if (has_ternary(~u, ~x, ~y, c3)) {
for (clause* cp : s.clauses()) { c.mark_used();
clause& cl = *cp; if (c1) c1->mark_used();
if (c2) c2->mark_used();
#define pair_eq(a, b, x, y) ((a == x && b == y) || (a == y && b == x)) if (c3) c3->mark_used();
#define tern_eq(a, b, c, cl) \ m_on_if(~x, ~y, z, u);
cl.size() == 3 && \ return true;
((cl[0] == a && pair_eq(b, c, c1[1], c1[2])) || \ }
(cl[0] == b && pair_eq(a, c, cl[1], cl[2])) || \
(cl[0] == c && pair_eq(a, b, cl[1], cl[2]))))
if (tern_eq(a, b, c, *cp)) return cp;
} }
} }
if (w.is_clause() && tern_eq(a, b, c, s.get_clause(w))) return false;
return &s.get_clause(w); };
for (clause* cp : clauses) {
clause& c = *cp;
if (c.size() != 3 || c.was_used()) continue;
literal x = c[0], y = c[1], z = c[2];
if (try_ite(x, y, z, c)) continue;
if (try_ite(y, x, z, c)) continue;
if (try_ite(z, y, x, c)) continue;
} }
return nullptr;
std::function<bool(clause*)> not_used = [](clause* cp) { return !cp->was_used(); };
clauses.filter_update(not_used);
} }
#endif
} }

View file

@ -38,15 +38,18 @@ namespace sat {
solver& s; solver& s;
big m_big; big m_big;
literal_vector m_ands; literal_vector m_ands;
std::function<void (literal head, literal_vector const& ands, clause& orig)> m_aig_def; std::function<void (literal head, literal_vector const& ands)> m_on_aig;
std::function<void (literal head, literal cond, literal th, literal el)> m_on_if;
bool implies(literal a, literal b); bool implies(literal a, literal b);
bool find_aig(clause& c); bool find_aig(clause& c);
bool find_if(clause& c); void find_ifs(clause_vector& clauses);
void find_aigs(clause_vector& clauses);
public: public:
aig_finder(solver& s) : s(s), m_big(s.rand()) {} aig_finder(solver& s) : s(s), m_big(s.rand()) {}
~aig_finder() {} ~aig_finder() {}
void set(std::function<void (literal head, literal_vector const& ands, clause& orig)>& f) { m_aig_def = f; } void set(std::function<void (literal head, literal_vector const& ands)>& f) { m_on_aig = f; }
void operator()(clause_vector const& clauses); void set(std::function<void (literal head, literal cond, literal th, literal el)>& f) { m_on_if = f; }
void operator()(clause_vector& clauses);
}; };
} }

View file

@ -30,10 +30,11 @@ namespace sat {
~report() { ~report() {
m_watch.stop(); m_watch.stop();
IF_VERBOSE(2, IF_VERBOSE(2,
verbose_stream() << " (sat.anf.simplifier " verbose_stream() << " (sat.anf.simplifier"
<< " :num-units " << s.m_stats.m_num_units << " :num-units " << s.m_stats.m_num_units
<< " :num-eqs " << s.m_stats.m_num_eq << " :num-eqs " << s.m_stats.m_num_eq
<< mem_stat() << m_watch << ")\n"); << " :mb " << mem_stat()
<< m_watch << ")\n");
} }
}; };
@ -289,11 +290,7 @@ namespace sat {
}; };
xor_finder xf(s); xor_finder xf(s);
xf.set(f); xf.set(f);
xf.extract_xors(clauses); xf(clauses);
for (clause* cp : clauses) cp->unmark_used();
for (clause* cp : xf.removed_clauses()) cp->mark_used();
std::function<bool(clause*)> not_used = [](clause* cp) { return !cp->was_used(); };
clauses.filter_update(not_used);
} }
static solver::bin_clause normalize(solver::bin_clause const& b) { static solver::bin_clause normalize(solver::bin_clause const& b) {
@ -314,25 +311,28 @@ namespace sat {
if (!m_config.m_compile_aig) { if (!m_config.m_compile_aig) {
return; return;
} }
for (clause* cp : clauses) cp->unmark_used();
hashtable<solver::bin_clause, solver::bin_clause_hash, default_eq<solver::bin_clause>> seen_bin; hashtable<solver::bin_clause, solver::bin_clause_hash, default_eq<solver::bin_clause>> seen_bin;
std::function<void(literal head, literal_vector const& tail, clause& c)> f = std::function<void(literal head, literal_vector const& tail)> on_aig =
[&,this](literal head, literal_vector const& tail, clause& c) { [&,this](literal head, literal_vector const& tail) {
c.mark_used();
add_aig(head, tail, ps); add_aig(head, tail, ps);
for (literal l : tail) { for (literal l : tail) {
seen_bin.insert(normalize(solver::bin_clause(~l, head))); seen_bin.insert(normalize(solver::bin_clause(~l, head)));
} }
m_stats.m_num_aigs++; m_stats.m_num_aigs++;
}; };
std::function<void(literal head, literal c, literal th, literal el)> on_if =
[&,this](literal head, literal c, literal th, literal el) {
add_if(head, c, th, el, ps);
m_stats.m_num_ifs++;
};
aig_finder af(s); aig_finder af(s);
af.set(f); af.set(on_aig);
af.set(on_if);
af(clauses); af(clauses);
std::function<bool(clause*)> not_used = [](clause* cp) { return !cp->was_used(); }; std::function<bool(solver::bin_clause b)> not_seen =
std::function<bool(solver::bin_clause b)> not_seen = [&](solver::bin_clause b) { return !seen_bin.contains(normalize(b)); }; [&](solver::bin_clause b) { return !seen_bin.contains(normalize(b)); };
clauses.filter_update(not_used);
bins.filter_update(not_seen); bins.filter_update(not_seen);
} }
@ -361,14 +361,14 @@ namespace sat {
cfg.m_expr_size_limit = 1000; cfg.m_expr_size_limit = 1000;
cfg.m_max_steps = 1000; cfg.m_max_steps = 1000;
cfg.m_random_seed = s.rand()(); cfg.m_random_seed = s.rand()();
cfg.m_enable_exlin = true; cfg.m_enable_exlin = m_config.m_enable_exlin;
unsigned max_num_nodes = 1 << 18; unsigned max_num_nodes = 1 << 18;
ps.get_manager().set_max_num_nodes(max_num_nodes); ps.get_manager().set_max_num_nodes(max_num_nodes);
ps.set(cfg); ps.set(cfg);
} }
#define lit2pdd(_l_) _l_.sign() ? ~m.mk_var(_l_.var()) : m.mk_var(_l_.var()) #define lit2pdd(_l_) (_l_.sign() ? ~m.mk_var(_l_.var()) : m.mk_var(_l_.var()))
void anf_simplifier::add_bin(solver::bin_clause const& b, pdd_solver& ps) { void anf_simplifier::add_bin(solver::bin_clause const& b, pdd_solver& ps) {
auto& m = ps.get_manager(); auto& m = ps.get_manager();
@ -380,6 +380,7 @@ namespace sat {
} }
void anf_simplifier::add_clause(clause const& c, pdd_solver& ps) { void anf_simplifier::add_clause(clause const& c, pdd_solver& ps) {
if (c.size() > m_config.m_max_clause_size) return;
auto& m = ps.get_manager(); auto& m = ps.get_manager();
dd::pdd p = m.zero(); dd::pdd p = m.zero();
for (literal l : c) p |= lit2pdd(l); for (literal l : c) p |= lit2pdd(l);
@ -401,15 +402,23 @@ namespace sat {
for (literal l : ands) q &= lit2pdd(l); for (literal l : ands) q &= lit2pdd(l);
dd::pdd p = lit2pdd(head) ^ q; dd::pdd p = lit2pdd(head) ^ q;
ps.add(p); ps.add(p);
TRACE("anf_simplifier", tout << "aig: " << head << " == " << ands << " : " << p << "\n";); TRACE("anf_simplifier", tout << "aig: " << head << " == " << ands << " poly : " << p << "\n";);
}
void anf_simplifier::add_if(literal head, literal c, literal th, literal el, pdd_solver& ps) {
auto& m = ps.get_manager();
dd::pdd p = lit2pdd(head) ^ (lit2pdd(c) & lit2pdd(th)) ^ (~lit2pdd(c) & lit2pdd(el));
ps.add(p);
TRACE("anf_simplifier", tout << "ite: " << head << " == " << c << "?" << th << ":" << el << " poly : " << p << "\n";);
} }
void anf_simplifier::save_statistics(pdd_solver& solver) { void anf_simplifier::save_statistics(pdd_solver& solver) {
solver.collect_statistics(m_st); solver.collect_statistics(m_st);
m_st.update("anf.num-units", m_stats.m_num_units); m_st.update("sat-anf.units", m_stats.m_num_units);
m_st.update("anf.num-eqs", m_stats.m_num_eq); m_st.update("sat-anf.eqs", m_stats.m_num_eq);
m_st.update("anf.num-aigs", m_stats.m_num_aigs); m_st.update("sat-anf.ands", m_stats.m_num_aigs);
m_st.update("anf.num-xors", m_stats.m_num_xors); m_st.update("sat-anf.ites", m_stats.m_num_ifs);
m_st.update("sat-anf.xors", m_stats.m_num_xors);
} }
} }

View file

@ -42,12 +42,14 @@ namespace sat {
bool m_compile_xor; bool m_compile_xor;
bool m_compile_aig; bool m_compile_aig;
bool m_anf2phase; bool m_anf2phase;
bool m_enable_exlin;
config(): config():
m_max_clause_size(10), m_max_clause_size(3),
m_max_clauses(10000), m_max_clauses(10000),
m_compile_xor(true), m_compile_xor(true),
m_compile_aig(true), m_compile_aig(true),
m_anf2phase(false) m_anf2phase(false),
m_enable_exlin(false)
{} {}
}; };
@ -56,7 +58,7 @@ namespace sat {
struct stats { struct stats {
unsigned m_num_units, m_num_eq; unsigned m_num_units, m_num_eq;
unsigned m_num_aigs, m_num_xors; unsigned m_num_aigs, m_num_xors, m_num_ifs;
stats() { reset(); } stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); } void reset() { memset(this, 0, sizeof(*this)); }
}; };
@ -84,6 +86,7 @@ namespace sat {
void add_clause(clause const& c, pdd_solver& ps); void add_clause(clause const& c, pdd_solver& ps);
void add_bin(solver::bin_clause const& b, pdd_solver& ps); void add_bin(solver::bin_clause const& b, pdd_solver& ps);
void add_xor(literal_vector const& x, pdd_solver& ps); void add_xor(literal_vector const& x, pdd_solver& ps);
void add_if(literal head, literal c, literal t, literal e, pdd_solver& ps);
void add_aig(literal head, literal_vector const& ands, pdd_solver& ps); void add_aig(literal head, literal_vector const& ands, pdd_solver& ps);
void save_statistics(pdd_solver& ps); void save_statistics(pdd_solver& ps);

View file

@ -101,7 +101,10 @@ namespace sat {
m_unit_walk_threads = p.unit_walk_threads(); m_unit_walk_threads = p.unit_walk_threads();
m_binspr = p.binspr(); m_binspr = p.binspr();
m_anf_simplify = p.anf(); m_anf_simplify = p.anf();
m_anf_delay = p.anf_delay();
m_anf_exlin = p.anf_exlin();
m_aig_simplify = p.aig(); m_aig_simplify = p.aig();
m_aig_delay = p.aig_delay();
m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_simplify = p.lookahead_simplify();
m_lookahead_double = p.lookahead_double(); m_lookahead_double = p.lookahead_double();
m_lookahead_simplify_bca = p.lookahead_simplify_bca(); m_lookahead_simplify_bca = p.lookahead_simplify_bca();

View file

@ -121,7 +121,10 @@ namespace sat {
bool m_unit_walk; bool m_unit_walk;
bool m_binspr; bool m_binspr;
bool m_aig_simplify; bool m_aig_simplify;
unsigned m_aig_delay;
bool m_anf_simplify; bool m_anf_simplify;
unsigned m_anf_delay;
bool m_anf_exlin;
bool m_lookahead_simplify; bool m_lookahead_simplify;
bool m_lookahead_simplify_bca; bool m_lookahead_simplify_bca;
cutoff_t m_lookahead_cube_cutoff; cutoff_t m_lookahead_cube_cutoff;

View file

@ -71,7 +71,10 @@ def_module_params('sat',
('unit_walk_threads', UINT, 0, 'number of unit-walk search threads to find satisfiable solution'), ('unit_walk_threads', UINT, 0, 'number of unit-walk search threads to find satisfiable solution'),
('binspr', BOOL, False, 'enable SPR inferences of binary propagation redundant clauses. This inprocessing step eliminates models'), ('binspr', BOOL, False, 'enable SPR inferences of binary propagation redundant clauses. This inprocessing step eliminates models'),
('anf', BOOL, False, 'enable ANF based simplification in-processing'), ('anf', BOOL, False, 'enable ANF based simplification in-processing'),
('anf.delay', UINT, 2, 'delay ANF simplification by in-processing round'),
('anf.exlin', BOOL, False, 'enable extended linear simplification'),
('aig', BOOL, False, 'enable AIG based simplification in-processing'), ('aig', BOOL, False, 'enable AIG based simplification in-processing'),
('aig.delay', UINT, 2, 'delay AIG simplification by in-processing round'),
('lookahead.cube.cutoff', SYMBOL, 'depth', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), ('lookahead.cube.cutoff', SYMBOL, 'depth', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'),
# - depth: the maximal cutoff is fixed to the value of lookahead.cube.depth. # - depth: the maximal cutoff is fixed to the value of lookahead.cube.depth.
# So if the value is 10, at most 1024 cubes will be generated of length 10. # So if the value is 10, at most 1024 cubes will be generated of length 10.

View file

@ -1907,18 +1907,6 @@ namespace sat {
lh.collect_statistics(m_aux_stats); lh.collect_statistics(m_aux_stats);
} }
if (m_config.m_anf_simplify) {
anf_simplifier anf(*this);
anf();
anf.collect_statistics(m_aux_stats);
}
if (m_config.m_aig_simplify) {
aig_simplifier aig(*this);
aig();
aig.collect_statistics(m_aux_stats);
}
reinit_assumptions(); reinit_assumptions();
if (inconsistent()) return; if (inconsistent()) return;
@ -1942,18 +1930,21 @@ namespace sat {
m_binspr(); m_binspr();
} }
#if 0 if (m_config.m_anf_simplify && m_simplifications > m_config.m_anf_delay && !inconsistent()) {
static unsigned file_no = 0; anf_simplifier anf(*this);
#pragma omp critical (print_sat) anf_simplifier::config cfg;
{ cfg.m_enable_exlin = m_config.m_anf_exlin;
++file_no; anf();
std::ostringstream ostrm; anf.collect_statistics(m_aux_stats);
ostrm << "s" << file_no << ".txt"; // TBD: throttle anf_delay based on yield
std::ofstream ous(ostrm.str());
display(ous);
} }
#endif
if (m_config.m_aig_simplify && m_simplifications > m_config.m_aig_delay && !inconsistent()) {
aig_simplifier aig(*this);
aig();
aig.collect_statistics(m_aux_stats);
// TBD: throttle aig_delay based on yield
}
} }
bool solver::set_root(literal l, literal r) { bool solver::set_root(literal l, literal r) {

View file

@ -225,10 +225,6 @@ namespace sat {
return out << std::fixed << std::setprecision(2) << mem; return out << std::fixed << std::setprecision(2) << mem;
} }
inline std::ostream& operator<<(std::ostream& out, stopwatch const& sw) {
return out << " :time " << std::fixed << std::setprecision(2) << sw.get_seconds();
}
struct dimacs_lit { struct dimacs_lit {
literal m_lit; literal m_lit;
dimacs_lit(literal l):m_lit(l) {} dimacs_lit(literal l):m_lit(l) {}

View file

@ -24,7 +24,7 @@
namespace sat { namespace sat {
void xor_finder::extract_xors(clause_vector& clauses) { void xor_finder::operator()(clause_vector& clauses) {
m_removed_clauses.reset(); m_removed_clauses.reset();
if (!s.get_config().m_xor_solver) { if (!s.get_config().m_xor_solver) {
return; return;
@ -49,6 +49,11 @@ namespace sat {
} }
} }
m_clause_filters.clear(); m_clause_filters.clear();
for (clause* cp : clauses) cp->unmark_used();
for (clause* cp : m_removed_clauses) cp->mark_used();
std::function<bool(clause*)> not_used = [](clause* cp) { return !cp->was_used(); };
clauses.filter_update(not_used);
} }
void xor_finder::extract_xor(clause& c) { void xor_finder::extract_xor(clause& c) {
@ -108,7 +113,7 @@ namespace sat {
s.set_external(l.var()); s.set_external(l.var());
} }
if (parity) lits[0].neg(); if (parity) lits[0].neg();
m_add_xr(lits); m_on_xor(lits);
} }
bool xor_finder::extract_xor(bool parity, clause& c, literal l1, literal l2) { bool xor_finder::extract_xor(bool parity, clause& c, literal l1, literal l2) {

View file

@ -47,7 +47,7 @@ namespace sat {
literal_vector m_clause; // reference clause with literals sorted according to main clause literal_vector m_clause; // reference clause with literals sorted according to main clause
unsigned_vector m_missing; // set of indices not occurring in clause. unsigned_vector m_missing; // set of indices not occurring in clause.
clause_vector m_removed_clauses; clause_vector m_removed_clauses;
std::function<void (literal_vector const& lits)> m_add_xr; std::function<void (literal_vector const& lits)> m_on_xor;
inline void set_combination(unsigned mask) { m_combination |= (1 << mask); } inline void set_combination(unsigned mask) { m_combination |= (1 << mask); }
inline bool get_combination(unsigned mask) const { return (m_combination & (1 << mask)) != 0; } inline bool get_combination(unsigned mask) const { return (m_combination & (1 << mask)) != 0; }
@ -65,12 +65,12 @@ namespace sat {
xor_finder(solver& s) : s(s), m_max_xor_size(5) { init_parity(); } xor_finder(solver& s) : s(s), m_max_xor_size(5) { init_parity(); }
~xor_finder() {} ~xor_finder() {}
void set(std::function<void (literal_vector const& lits)>& f) { m_add_xr = f; } void set(std::function<void (literal_vector const& lits)>& f) { m_on_xor = f; }
bool parity(unsigned i, unsigned j) const { return m_parity[i][j]; } bool parity(unsigned i, unsigned j) const { return m_parity[i][j]; }
unsigned max_xor_size() const { return m_max_xor_size; } unsigned max_xor_size() const { return m_max_xor_size; }
void extract_xors(clause_vector& clauses); void operator()(clause_vector& clauses);
clause_vector& removed_clauses() { return m_removed_clauses; } clause_vector const& removed_clauses() const { return m_removed_clauses; }
}; };
} }

View file

@ -22,6 +22,9 @@ Revision History:
#include "util/debug.h" #include "util/debug.h"
#include <chrono> #include <chrono>
#include <iostream>
#include<iomanip>
class stopwatch class stopwatch
{ {
@ -89,4 +92,9 @@ struct scoped_watch {
} }
}; };
inline std::ostream& operator<<(std::ostream& out, stopwatch const& sw) {
return out << " :time " << std::fixed << std::setprecision(2) << sw.get_seconds();
}
#endif #endif