3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 10:25:18 +00:00

add anf and aig simplifier modules, cut-set enumeration, aig_finder, hoist out xor_finder from ba_solver

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-01-04 13:28:15 -08:00
parent 12e727e49a
commit d27a949ae9
15 changed files with 545 additions and 142 deletions

View file

@ -310,6 +310,7 @@ namespace dd {
unsigned var() const { return m.var(root); }
rational const& val() const { SASSERT(is_val()); return m.val(root); }
bool is_val() const { return m.is_val(root); }
bool is_one() const { return m.is_one(root); }
bool is_zero() const { return m.is_zero(root); }
bool is_linear() const { return m.is_linear(root); }
bool is_unary() const { return !is_val() && lo().is_zero() && hi().is_val(); }

View file

@ -2,6 +2,8 @@ z3_add_component(sat
SOURCES
ba_solver.cpp
dimacs.cpp
sat_aig_finder.cpp
sat_aig_simplifier.cpp
sat_anf_simplifier.cpp
sat_asymm_branch.cpp
sat_big.cpp
@ -11,6 +13,7 @@ z3_add_component(sat
sat_clause_use_list.cpp
sat_cleaner.cpp
sat_config.cpp
sat_cutset.cpp
sat_ddfw.cpp
sat_drat.cpp
sat_elim_eqs.cpp
@ -29,7 +32,7 @@ z3_add_component(sat
sat_solver.cpp
sat_unit_walk.cpp
sat_watched.cpp
sat_xor_util.cpp
sat_xor_finder.cpp
COMPONENT_DEPENDENCIES
util
dd

View file

@ -22,7 +22,7 @@ Revision History:
#include "sat/sat_types.h"
#include "util/mpz.h"
#include "sat/sat_simplifier_params.hpp"
#include "sat/sat_xor_util.h"
#include "sat/sat_xor_finder.h"
namespace sat {
@ -2911,9 +2911,9 @@ namespace sat {
void ba_solver::pre_simplify() {
VERIFY(s().at_base_lvl());
m_constraint_removed = false;
xor_util xu(s());
for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) pre_simplify(xu, *m_constraints[i]);
for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) pre_simplify(xu, *m_learned[i]);
xor_finder xf(s());
for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) pre_simplify(xf, *m_constraints[i]);
for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) pre_simplify(xf, *m_learned[i]);
bool change = m_constraint_removed;
cleanup_constraints();
if (change) {
@ -2924,8 +2924,8 @@ namespace sat {
}
}
void ba_solver::pre_simplify(xor_util& xu, constraint& c) {
if (c.is_xr() && c.size() <= xu.max_xor_size()) {
void ba_solver::pre_simplify(xor_finder& xf, constraint& c) {
if (c.is_xr() && c.size() <= xf.max_xor_size()) {
unsigned sz = c.size();
literal_vector lits;
bool parity = false;
@ -2936,7 +2936,7 @@ namespace sat {
// IF_VERBOSE(0, verbose_stream() << "blast: " << c << "\n");
for (unsigned i = 0; i < (1ul << sz); ++i) {
if (xu.parity(sz, i) == parity) {
if (xf.parity(sz, i) == parity) {
lits.reset();
for (unsigned j = 0; j < sz; ++j) {
lits.push_back(literal(x[j].var(), (0 != (i & (1 << j)))));
@ -3799,11 +3799,11 @@ namespace sat {
}
void ba_solver::extract_xor() {
xor_util xu(s());
std::function<void (literal_vector const&, bool)> f = [this](literal_vector const& l, bool b) { add_xr(l,b); };
xu.set(f);
xu.extract_xors();
for (clause* cp : xu.removed_clauses()) {
xor_finder xf(s());
std::function<void (literal_vector const&)> f = [this](literal_vector const& l) { add_xr(l, false); };
xf.set(f);
xf.extract_xors(s().m_clauses);
for (clause* cp : xf.removed_clauses()) {
cp->set_removed(true);
m_clause_removed = true;
}

View file

@ -32,7 +32,7 @@ Revision History:
namespace sat {
class xor_util;
class xor_finder;
class ba_solver : public extension {
@ -347,7 +347,7 @@ namespace sat {
lbool add_assign(constraint& c, literal l);
bool incremental_mode() const;
void simplify(constraint& c);
void pre_simplify(xor_util& xu, constraint& c);
void pre_simplify(xor_finder& xu, constraint& c);
void nullify_tracking_literal(constraint& c);
void set_conflict(constraint& c, literal lit);
void assign(constraint& c, literal lit);

153
src/sat/sat_aig_finder.cpp Normal file
View file

@ -0,0 +1,153 @@
/*++
Copyright (c) 2020 Microsoft Corporation
Module Name:
sat_aig_finder.cpp
Author:
Nikolaj Bjorner 2020-01-02
Notes:
AIG finder
--*/
#pragma once;
#include "sat/sat_aig_finder.h"
namespace sat {
void aig_finder::operator()(clause_vector const& clauses) {
m_big.init(s, true);
for (clause* cp : 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) {
if (m_big.connected(a, b))
return true;
for (auto const& w : s.get_wlist(a)) {
if (w.is_binary_clause() && b == w.get_literal())
return true;
}
return false;
}
// a = ~b & ~c
// if (~a | ~b) (~a | ~c), (b | c | a)
bool aig_finder::find_aig(clause& c) {
bool is_aig = false;
for (literal head : c) {
is_aig = true;
for (literal tail : c) {
if (head == tail)
continue;
if (!implies(head, ~tail)) {
is_aig = false;
break;
}
}
if (is_aig) {
m_ands.reset();
for (literal tail : c)
if (tail != head)
m_ands.push_back(~tail);
m_aig_def(head, m_ands, c);
break;
}
}
return is_aig;
}
//
// x = if y then z else u
// if x, y -> z
// x, ~y -> u
// y, z -> x
// ~y, u -> x
//
bool aig_finder::find_if(clause& c) {
return false;
#if 0
if (c.size() != 3) return false;
literal x = c[0], y = c[1], z = c[2];
if (find_if(~x, ~y, z, c)) return true;
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);
clause* c4 = find_clause(y, ~u, x);
if (c4) {
m_if_def(x, y, z, u, c, *c2, *c3, *c4);
return true;
}
}
}
literal aig_finder::third_literal(literal a, literal b, clause const& c) {
for (literal lit : c)
if (lit != a && lit != b)
return lit;
return null_literal;
}
clause* aig_finder::find_clause(literal a, literal b, literal c) {
for (auto const& w : s.get_wlist(~a)) {
if (w.is_ternary() &&
(b == w.get_literal1() && c == w.get_literal2()) ||
(c == w.get_literal1() && b == w.get_literal2())) {
for (clause* cp : s.clauses()) {
clause& cl = *cp;
#define pair_eq(a, b, x, y) ((a == x && b == y) || (a == y && b == x))
#define tern_eq(a, b, c, cl) \
cl.size() == 3 && \
((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 &s.get_clause(w);
}
return nullptr;
}
#endif
}

52
src/sat/sat_aig_finder.h Normal file
View file

@ -0,0 +1,52 @@
/*++
Copyright (c) 2020 Microsoft Corporation
Module Name:
sat_aig_finder.h
Abstract:
extract AIG definitions from clauses.
An example AIG clause is:
head \/ l1 \/ l2
such that
~l1 /\ ~l2 => head
head => ~l1, head => ~l2
Author:
Nikolaj Bjorner 2020-01-02
Notes:
AIG finder
--*/
#pragma once;
#include "util/params.h"
#include "util/statistics.h"
#include "sat/sat_clause.h"
#include "sat/sat_types.h"
#include "sat/sat_solver.h"
#include "sat/sat_big.h"
namespace sat {
class aig_finder {
solver& s;
big m_big;
literal_vector m_ands;
std::function<void (literal head, literal_vector const& ands, clause& orig)> m_aig_def;
bool implies(literal a, literal b);
bool find_aig(clause& c);
bool find_if(clause& c);
public:
aig_finder(solver& s) : s(s), m_big(s.rand()) {}
~aig_finder() {}
void set(std::function<void (literal head, literal_vector const& ands, clause& orig)>& f) { m_aig_def = f; }
void operator()(clause_vector const& clauses);
};
}

View file

@ -17,128 +17,195 @@
#include "sat/sat_anf_simplifier.h"
#include "sat/sat_solver.h"
#include "sat/sat_xor_util.h"
#include "sat/sat_xor_finder.h"
#include "sat/sat_aig_finder.h"
#include "math/grobner/pdd_solver.h"
namespace sat {
class pdd_solver : public dd::solver {
public:
pdd_solver(reslimit& lim, dd::pdd_manager& m): dd::solver(lim, m) {}
struct anf_simplifier::report {
anf_simplifier& s;
stopwatch m_watch;
report(anf_simplifier& s): s(s) { m_watch.start(); }
~report() {
m_watch.stop();
IF_VERBOSE(2,
verbose_stream() << " (sat.anf.simplifier "
<< " :num-units " << s.m_stats.m_num_units
<< " :num-eqs " << s.m_stats.m_num_eq
<< mem_stat() << m_watch << ")\n");
}
};
void anf_simplifier::operator()() {
vector<literal_vector> xors;
clause_vector clauses;
svector<solver::bin_clause> bins;
m_relevant.reset();
m_relevant.resize(s.num_vars(), false);
for (clause* cp : s.m_clauses) cp->unmark_used();
collect_xors(xors);
collect_clauses(clauses, bins);
dd::pdd_manager m(20, dd::pdd_manager::semantics::mod2_e);
report _report(*this);
pdd_solver solver(s.rlimit(), m);
configure_solver(solver);
try {
for (literal_vector const& x : xors) {
add_xor(x, solver);
}
for (clause* cp : clauses) {
add_clause(*cp, solver);
}
for (auto const& b : bins) {
add_bin(b, solver);
}
}
catch (dd::pdd_manager::mem_out) {
IF_VERBOSE(2, verbose_stream() << "(sat.anf memout)\n");
return;
}
TRACE("anf_simplifier", solver.display(tout););
clauses2anf(solver);
TRACE("anf_simplifier", solver.display(tout); s.display(tout););
solver.simplify();
TRACE("anf_simplifier", solver.display(tout););
anf2clauses(solver);
anf2phase(solver);
save_statistics(solver);
IF_VERBOSE(10, m_st.display(verbose_stream() << "(sat.anf.simplifier\n"); verbose_stream() << ")\n");
}
unsigned num_units = 0, num_eq = 0;
/**
\brief extract learned units and equivalences from processed anf.
TBD: could learn binary clauses
TBD: could try simplify equations using BIG subsumption similar to asymm_branch
*/
void anf_simplifier::anf2clauses(pdd_solver& solver) {
for (auto* e : solver.equations()) {
auto const& p = e->poly();
if (p.is_zero()) {
continue;
}
else if (p.is_val()) {
if (p.is_one()) {
s.set_conflict();
break;
}
else if (p.is_unary()) {
// unit
literal lit(p.var(), p.lo().val().is_zero());
SASSERT(!p.is_val() && p.lo().is_val() && p.hi().is_val());
literal lit(p.var(), p.lo().is_zero());
s.assign_unit(lit);
++num_units;
++m_stats.m_num_units;
TRACE("anf_simplifier", tout << "unit " << p << " : " << lit << "\n";);
}
else if (p.is_binary()) {
// equivalence
// x + y + c = 0
SASSERT(!p.is_val() && p.hi().is_one() && !p.lo().is_val() && p.lo().hi().is_one() && p.lo().lo().is_val());
literal x(p.var(), false);
literal y(p.lo().var(), p.lo().lo().val().is_zero());
literal y(p.lo().var(), p.lo().lo().is_zero());
s.mk_clause(x, y, true);
s.mk_clause(~x, ~y, true);
++num_eq;
++m_stats.m_num_eq;
TRACE("anf_simplifier", tout << "equivalence " << p << " : " << x << " == " << y << "\n";);
}
// TBD: could learn binary clauses
// TBD: could try simplify equations using BIG subsumption similar to asymm_branch
}
}
IF_VERBOSE(10, solver.display_statistics(verbose_stream() << "(sat.anf\n" )
<< "\n"
<< " :num-unit " << num_units
<< " :num-eq " << num_eq
<< " :num-xor " << xors.size()
<< " :num-cls " << clauses.size()
<< " :num-bin " << bins.size()
<< ")\n");
/**
\brief update best phase using solved equations
polynomials that are not satisfied evaluate to true.
In a satisfying assignment, all polynomials should evaluate to false.
assume that solutions are provided in reverse order.
As a simplifying assumption it relies on the property
that if an equation is of the form v + p, where v does not occur in p,
then all equations that come after it do not contain p.
In this way we can flip the assignment to v without
invalidating the evaluation cache.
*/
void anf_simplifier::anf2phase(pdd_solver& solver) {
if (!m_config.m_anf2phase)
return;
m_eval_ts = 0;
reset_eval();
auto const& eqs = solver.equations();
for (unsigned i = eqs.size(); i-- > 0; ) {
dd::pdd const& p = eqs[i]->poly();
if (!p.is_val() && p.hi().is_one() && s.m_best_phase[p.var()] != eval(p.lo())) {
s.m_best_phase[p.var()] = !s.m_best_phase[p.var()];
}
}
}
bool anf_simplifier::eval(dd::pdd const& p) {
if (p.is_one()) return true;
if (p.is_zero()) return false;
unsigned index = p.index();
if (index < m_eval_cache.size()) {
if (m_eval_cache[index] == m_eval_ts) return false;
if (m_eval_cache[index] == m_eval_ts + 1) return true;
}
SASSERT(!p.is_val());
bool hi = eval(p.hi());
bool lo = eval(p.lo());
bool v = (hi && s.m_best_phase[p.var()]) ^ lo;
m_eval_cache.reserve(index + 1, 0);
m_eval_cache[index] = m_eval_ts + v;
return v;
}
void anf_simplifier::reset_eval() {
if (m_eval_ts + 2 < m_eval_ts) {
m_eval_cache.reset();
m_eval_ts = 0;
}
m_eval_ts += 2;
}
void anf_simplifier::clauses2anf(pdd_solver& solver) {
svector<solver::bin_clause> bins;
m_relevant.reset();
m_relevant.resize(s.num_vars(), false);
clause_vector clauses(s.clauses());
s.collect_bin_clauses(bins, false, false);
collect_clauses(clauses, bins);
try {
compile_xors(clauses, solver);
compile_aigs(clauses, bins, solver);
for (auto const& b : bins) {
add_bin(b, solver);
}
for (clause* cp : clauses) {
add_clause(*cp, solver);
}
}
catch (dd::pdd_manager::mem_out) {
IF_VERBOSE(1, verbose_stream() << "(sat.anf memout)\n");
}
}
void anf_simplifier::collect_clauses(clause_vector & clauses, svector<solver::bin_clause>& bins) {
clause_vector oclauses;
for (clause* cp : s.clauses()) {
svector<solver::bin_clause> obins;
unsigned j = 0;
for (clause* cp : clauses) {
clause const& c = *cp;
if (c.was_used() || is_too_large(c))
if (is_too_large(c))
continue;
else if (is_pre_satisfied(c)) {
oclauses.push_back(cp);
}
else {
clauses.push_back(cp);
clauses[j++] = cp;
}
}
svector<solver::bin_clause> obins;
s.collect_bin_clauses(obins, false, false);
unsigned j = 0;
for (auto const& b : obins) {
clauses.shrink(j);
j = 0;
for (auto const& b : bins) {
if (is_pre_satisfied(b)) {
obins[j++] = b;
obins.push_back(b);
}
else {
bins.push_back(b);
bins[j++] = b;
}
}
obins.shrink(j);
bins.shrink(j);
while (bins.size() + clauses.size() < m_config.m_max_clauses) {
unsigned rounds = 0, max_rounds = 3;
bool added = true;
while (bins.size() + clauses.size() < m_config.m_max_clauses &&
(!obins.empty() || !oclauses.empty()) &&
added &&
rounds < max_rounds) {
added = false;
for (auto const& b : bins) set_relevant(b);
for (clause* cp : clauses) set_relevant(*cp);
j = 0;
for (auto const& b : obins) {
if (has_relevant_var(b)) {
added = true;
bins.push_back(b);
}
else {
@ -153,16 +220,24 @@ namespace sat {
j = 0;
for (clause* cp : oclauses) {
clause& c = *cp;
if (has_relevant_var(c)) {
if (has_relevant_var(*cp)) {
added = true;
clauses.push_back(cp);
}
else {
oclauses.push_back(cp);
oclauses[j++] = cp;
}
}
oclauses.shrink(j);
}
TRACE("anf_simplifier",
tout << "kept:\n";
for (clause* cp : clauses) tout << *cp << "\n";
for (auto b : bins) tout << b.first << " " << b.second << "\n";
tout << "removed:\n";
for (clause* cp : oclauses) tout << *cp << "\n";
for (auto b : obins) tout << b.first << " " << b.second << "\n";);
}
void anf_simplifier::set_relevant(solver::bin_clause const& b) {
@ -197,23 +272,77 @@ namespace sat {
return is_relevant(b.first) || is_relevant(b.second);
}
void anf_simplifier::collect_xors(vector<literal_vector>& xors) {
std::function<void(literal_vector const&, bool)> f =
[&](literal_vector const& l, bool) { xors.push_back(l); };
xor_util xu(s);
xu.set(f);
xu.extract_xors();
for (clause* cp : s.m_clauses) cp->unmark_used();
for (clause* cp : s.m_learned) cp->unmark_used();
for (clause* cp : xu.removed_clauses()) cp->mark_used();
/**
\brief extract xors from all s.clauses()
(could be just filtered clauses, or clauses with relevant variables).
Add the extracted xors to pdd_solver.
Remove clauses from list that correspond to extracted xors
*/
void anf_simplifier::compile_xors(clause_vector& clauses, pdd_solver& ps) {
if (!m_config.m_compile_xor) {
return;
}
std::function<void(literal_vector const&)> f =
[&,this](literal_vector const& x) {
add_xor(x, ps);
m_stats.m_num_xors++;
};
xor_finder xf(s);
xf.set(f);
xf.extract_xors(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) {
if (b.first.index() > b.second.index()) {
return solver::bin_clause(b.second, b.first);
}
else {
return b;
}
}
/**
\brief extract AIGs from clauses.
Add the extracted AIGs to pdd_solver.
Remove clauses from list that correspond to extracted AIGs
Remove binary clauses that correspond to extracted AIGs.
*/
void anf_simplifier::compile_aigs(clause_vector& clauses, svector<solver::bin_clause>& bins, pdd_solver& ps) {
if (!m_config.m_compile_aig) {
return;
}
for (clause* cp : clauses) cp->unmark_used();
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 =
[&,this](literal head, literal_vector const& tail, clause& c) {
c.mark_used();
add_aig(head, tail, ps);
for (literal l : tail) {
seen_bin.insert(normalize(solver::bin_clause(~l, head)));
}
m_stats.m_num_aigs++;
};
aig_finder af(s);
af.set(f);
af(clauses);
std::function<bool(clause*)> not_used = [](clause* cp) { return !cp->was_used(); };
std::function<bool(solver::bin_clause b)> not_seen = [&](solver::bin_clause b) { return !seen_bin.contains(normalize(b)); };
clauses.filter_update(not_used);
bins.filter_update(not_seen);
}
/**
assign levels to variables.
use s.def_level as a primary source for the level of a variable.
secondarily, sort variables randomly (each variable is assigned
a random, unique, id).
*/
void anf_simplifier::configure_solver(pdd_solver& ps) {
// assign levels to variables.
// use s.def_level as a primary source for the level of a variable.
// secondarily, sort variables randomly (each variable is assigned
// a random, unique, id).
unsigned nv = s.num_vars();
unsigned_vector l2v(nv), var2id(nv), id2var(nv);
svector<std::pair<unsigned, unsigned>> vl(nv);
@ -239,36 +368,48 @@ namespace sat {
ps.set(cfg);
}
#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) {
auto& m = ps.get_manager();
auto v = m.mk_var(b.first.var());
auto w = m.mk_var(b.second.var());
if (b.first.sign()) v = ~v;
if (b.second.sign()) w = ~w;
auto v = lit2pdd(b.first);
auto w = lit2pdd(b.second);
dd::pdd p = v | w;
ps.add(p);
TRACE("anf_simplifier", tout << "bin: " << b.first << " " << b.second << " : " << p << "\n";);
}
void anf_simplifier::add_clause(clause const& c, pdd_solver& ps) {
auto& m = ps.get_manager();
dd::pdd p = m.zero();
for (literal l : c) {
auto v = m.mk_var(l.var());
if (l.sign()) v = ~v;
p |= v;
}
for (literal l : c) p |= lit2pdd(l);
ps.add(p);
TRACE("anf_simplifier", tout << "clause: " << c << " : " << p << "\n";);
}
void anf_simplifier::add_xor(literal_vector const& x, pdd_solver& ps) {
auto& m = ps.get_manager();
dd::pdd p = m.zero();
for (literal l : x) {
auto v = m.mk_var(l.var());
if (l.sign()) v = ~v;
p ^= v;
}
for (literal l : x) p ^= lit2pdd(l);
ps.add(p);
TRACE("anf_simplifier", tout << "xor: " << x << " : " << p << "\n";);
}
void anf_simplifier::add_aig(literal head, literal_vector const& ands, pdd_solver& ps) {
auto& m = ps.get_manager();
dd::pdd q = m.one();
for (literal l : ands) q &= lit2pdd(l);
dd::pdd p = lit2pdd(head) ^ q;
ps.add(p);
TRACE("anf_simplifier", tout << "aig: " << head << " == " << ands << " : " << p << "\n";);
}
void anf_simplifier::save_statistics(pdd_solver& solver) {
solver.collect_statistics(m_st);
m_st.update("anf.num-units", m_stats.m_num_units);
m_st.update("anf.num-eqs", m_stats.m_num_eq);
m_st.update("anf.num-aigs", m_stats.m_num_aigs);
m_st.update("anf.num-xors", m_stats.m_num_xors);
}
}

View file

@ -25,31 +25,70 @@
#include "sat/sat_types.h"
#include "sat/sat_solver.h"
namespace dd {
class pdd;
class solver;
};
namespace sat {
class pdd_solver;
typedef dd::solver pdd_solver;
class anf_simplifier {
public:
struct config {
unsigned m_max_clause_size;
unsigned m_max_clauses;
bool m_compile_xor;
bool m_compile_aig;
bool m_anf2phase;
config():
m_max_clause_size(10),
m_max_clauses(10000)
m_max_clauses(10000),
m_compile_xor(true),
m_compile_aig(true),
m_anf2phase(false)
{}
};
private:
solver& s;
config m_config;
svector<bool> m_relevant;
struct report;
struct stats {
unsigned m_num_units, m_num_eq;
unsigned m_num_aigs, m_num_xors;
stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
};
solver& s;
config m_config;
svector<bool> m_relevant;
stats m_stats;
statistics m_st;
unsigned_vector m_eval_cache;
unsigned m_eval_ts;
svector<bool> m_used_for_evaluation;
void clauses2anf(pdd_solver& solver);
void anf2clauses(pdd_solver& solver);
void anf2phase(pdd_solver& solver);
void collect_clauses(clause_vector & clauses, svector<solver::bin_clause>& bins);
void compile_xors(clause_vector& clauses, pdd_solver& ps);
void compile_aigs(clause_vector& clauses, svector<solver::bin_clause>& bins, pdd_solver& ps);
void collect_xors(vector<literal_vector>& xors);
void configure_solver(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_xor(literal_vector const& x, pdd_solver& ps);
void add_aig(literal head, literal_vector const& ands, pdd_solver& ps);
void save_statistics(pdd_solver& ps);
bool eval(dd::pdd const& p);
void reset_eval();
bool is_pre_satisfied(clause const& c);
bool is_pre_satisfied(solver::bin_clause const& b);
@ -65,11 +104,13 @@ namespace sat {
void set_relevant(literal l) { set_relevant(l.var()); }
void set_relevant(bool_var v) { m_relevant[v] = true; }
public:
anf_simplifier(solver& s) : s(s) {}
~anf_simplifier() {}
void operator()();
void set(config const& cfg) { m_config = cfg; }
void collect_statistics(statistics& st) const { st.copy(m_st); }
};
}

View file

@ -101,6 +101,7 @@ namespace sat {
m_unit_walk_threads = p.unit_walk_threads();
m_binspr = p.binspr();
m_anf_simplify = p.anf();
m_aig_simplify = p.aig();
m_lookahead_simplify = p.lookahead_simplify();
m_lookahead_double = p.lookahead_double();
m_lookahead_simplify_bca = p.lookahead_simplify_bca();

View file

@ -120,6 +120,7 @@ namespace sat {
unsigned m_unit_walk_threads;
bool m_unit_walk;
bool m_binspr;
bool m_aig_simplify;
bool m_anf_simplify;
bool m_lookahead_simplify;
bool m_lookahead_simplify_bca;

View file

@ -71,6 +71,7 @@ def_module_params('sat',
('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'),
('anf', BOOL, False, 'enable ANF based simplification in-processing'),
('aig', BOOL, False, 'enable AIG based simplification in-processing'),
('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.
# So if the value is 10, at most 1024 cubes will be generated of length 10.

View file

@ -31,6 +31,7 @@ Revision History:
#include "sat/sat_ddfw.h"
#include "sat/sat_prob.h"
#include "sat/sat_anf_simplifier.h"
#include "sat/sat_aig_simplifier.h"
#if defined(_MSC_VER) && !defined(_M_ARM) && !defined(_M_ARM64)
# include <xmmintrin.h>
#endif
@ -1909,6 +1910,13 @@ namespace sat {
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();

View file

@ -216,7 +216,8 @@ namespace sat {
friend struct mk_stat;
friend class elim_vars;
friend class scoped_detach;
friend class xor_util;
friend class xor_finder;
friend class aig_finder;
public:
solver(params_ref const & p, reslimit& l);
~solver() override;
@ -402,6 +403,7 @@ namespace sat {
bool set_root(literal l, literal r);
void flush_roots();
typedef std::pair<literal, literal> bin_clause;
struct bin_clause_hash { unsigned operator()(bin_clause const& b) const { return b.first.hash() + 2*b.second.hash(); } };
protected:
watch_list & get_wlist(literal l) { return m_watches[l.index()]; }
watch_list const & get_wlist(literal l) const { return m_watches[l.index()]; }

View file

@ -3,11 +3,11 @@
Module Name:
sat_xor_util.cpp
sat_xor_finder.cpp
Abstract:
xor utilities
xor finderities
Author:
@ -19,12 +19,12 @@
--*/
#pragma once;
#include "sat/sat_xor_util.h"
#include "sat/sat_xor_finder.h"
#include "sat/sat_solver.h"
namespace sat {
void xor_util::extract_xors() {
void xor_finder::extract_xors(clause_vector& clauses) {
m_removed_clauses.reset();
if (!s.get_config().m_xor_solver) {
return;
@ -37,11 +37,11 @@ namespace sat {
SASSERT(sizeof(m_combination)*8 <= (1ull << static_cast<uint64_t>(max_size)));
init_clause_filter();
m_var_position.resize(s.num_vars());
for (clause* cp : s.m_clauses) {
for (clause* cp : clauses) {
cp->unmark_used();
}
for (; max_size > 2; --max_size) {
for (clause* cp : s.m_clauses) {
for (clause* cp : clauses) {
clause& c = *cp;
if (c.size() == max_size && !c.was_removed() && !c.is_learned() && !c.was_used()) {
extract_xor(c);
@ -51,7 +51,7 @@ namespace sat {
m_clause_filters.clear();
}
void xor_util::extract_xor(clause& c) {
void xor_finder::extract_xor(clause& c) {
SASSERT(c.size() > 2);
unsigned filter = get_clause_filter(c);
s.init_visited();
@ -99,20 +99,19 @@ namespace sat {
}
}
void xor_util::add_xor(bool parity, clause& c) {
void xor_finder::add_xor(bool parity, clause& c) {
DEBUG_CODE(for (clause* cp : m_clauses_to_remove) VERIFY(cp->was_used()););
m_removed_clauses.append(m_clauses_to_remove);
bool learned = false;
literal_vector lits;
for (literal l : c) {
lits.push_back(literal(l.var(), false));
s.set_external(l.var());
}
if (parity) lits[0].neg();
m_add_xr(lits, learned);
m_add_xr(lits);
}
bool xor_util::extract_xor(bool parity, clause& c, literal l1, literal l2) {
bool xor_finder::extract_xor(bool parity, clause& c, literal l1, literal l2) {
SASSERT(s.is_visited(l1.var()));
SASSERT(s.is_visited(l2.var()));
m_missing.reset();
@ -131,7 +130,7 @@ namespace sat {
return update_combinations(c, parity, mask);
}
bool xor_util::extract_xor(bool parity, clause& c, clause& c2) {
bool xor_finder::extract_xor(bool parity, clause& c, clause& c2) {
bool parity2 = false;
for (literal l : c2) {
if (!s.is_visited(l.var())) return false;
@ -168,7 +167,7 @@ namespace sat {
return update_combinations(c, parity, mask);
}
bool xor_util::update_combinations(clause& c, bool parity, unsigned mask) {
bool xor_finder::update_combinations(clause& c, bool parity, unsigned mask) {
unsigned num_missing = m_missing.size();
for (unsigned k = 0; k < (1ul << num_missing); ++k) {
unsigned mask2 = mask;
@ -189,7 +188,7 @@ namespace sat {
return true;
}
void xor_util::init_parity() {
void xor_finder::init_parity() {
for (unsigned i = m_parity.size(); i <= m_max_xor_size; ++i) {
bool_vector bv;
for (unsigned j = 0; j < (1ul << i); ++j) {
@ -203,14 +202,14 @@ namespace sat {
}
}
void xor_util::init_clause_filter() {
void xor_finder::init_clause_filter() {
m_clause_filters.reset();
m_clause_filters.resize(s.num_vars());
init_clause_filter(s.m_clauses);
init_clause_filter(s.m_learned);
}
void xor_util::init_clause_filter(clause_vector& clauses) {
void xor_finder::init_clause_filter(clause_vector& clauses) {
for (clause* cp : clauses) {
clause& c = *cp;
if (c.size() <= m_max_xor_size && s.all_distinct(c)) {
@ -222,7 +221,7 @@ namespace sat {
}
}
unsigned xor_util::get_clause_filter(clause& c) {
unsigned xor_finder::get_clause_filter(clause& c) {
unsigned filter = 0;
for (literal l : c) {
filter |= 1 << ((l.var() % 32));

View file

@ -3,11 +3,11 @@
Module Name:
sat_xor.h
sat_xor_finder.h
Abstract:
xor utilities
xor finderities
Author:
@ -29,7 +29,7 @@
namespace sat {
class xor_util {
class xor_finder {
solver& s;
struct clause_filter {
unsigned m_filter;
@ -47,7 +47,7 @@ namespace sat {
literal_vector m_clause; // reference clause with literals sorted according to main clause
unsigned_vector m_missing; // set of indices not occurring in clause.
clause_vector m_removed_clauses;
std::function<void (literal_vector const& lits, bool learned)> m_add_xr;
std::function<void (literal_vector const& lits)> m_add_xr;
inline void set_combination(unsigned mask) { m_combination |= (1 << mask); }
inline bool get_combination(unsigned mask) const { return (m_combination & (1 << mask)) != 0; }
@ -62,15 +62,15 @@ namespace sat {
unsigned get_clause_filter(clause& c);
public:
xor_util(solver& s) : s(s), m_max_xor_size(5) { init_parity(); }
~xor_util() {}
xor_finder(solver& s) : s(s), m_max_xor_size(5) { init_parity(); }
~xor_finder() {}
void set(std::function<void (literal_vector const& lits, bool learned)>& f) { m_add_xr = f; }
void set(std::function<void (literal_vector const& lits)>& f) { m_add_xr = f; }
bool parity(unsigned i, unsigned j) const { return m_parity[i][j]; }
unsigned max_xor_size() const { return m_max_xor_size; }
void extract_xors();
void extract_xors(clause_vector& clauses);
clause_vector& removed_clauses() { return m_removed_clauses; }
};
}