mirror of
https://github.com/Z3Prover/z3
synced 2025-06-03 21:01:22 +00:00
revise unit walk
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
5fe40a25dc
commit
6d893e0599
3 changed files with 308 additions and 104 deletions
|
@ -226,6 +226,8 @@ namespace sat {
|
||||||
void mk_clause(literal l1, literal l2, bool learned = false);
|
void mk_clause(literal l1, literal l2, bool learned = false);
|
||||||
void mk_clause(literal l1, literal l2, literal l3, bool learned = false);
|
void mk_clause(literal l1, literal l2, literal l3, bool learned = false);
|
||||||
|
|
||||||
|
random_gen& rand() { return m_rand; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline clause_allocator& cls_allocator() { return m_cls_allocator[m_cls_allocator_idx]; }
|
inline clause_allocator& cls_allocator() { return m_cls_allocator[m_cls_allocator_idx]; }
|
||||||
inline clause_allocator const& cls_allocator() const { return m_cls_allocator[m_cls_allocator_idx]; }
|
inline clause_allocator const& cls_allocator() const { return m_cls_allocator[m_cls_allocator_idx]; }
|
||||||
|
|
|
@ -8,6 +8,7 @@ Module Name:
|
||||||
Abstract:
|
Abstract:
|
||||||
|
|
||||||
unit walk local search procedure.
|
unit walk local search procedure.
|
||||||
|
|
||||||
A variant of UnitWalk. Hirsch and Kojevinkov, SAT 2001.
|
A variant of UnitWalk. Hirsch and Kojevinkov, SAT 2001.
|
||||||
This version uses a trail to reset assignments and integrates directly with the
|
This version uses a trail to reset assignments and integrates directly with the
|
||||||
watch list structure. Thus, assignments are not delayed and we avoid treating
|
watch list structure. Thus, assignments are not delayed and we avoid treating
|
||||||
|
@ -16,11 +17,9 @@ Abstract:
|
||||||
It uses standard DPLL approach for backracking, flipping the last decision literal that
|
It uses standard DPLL approach for backracking, flipping the last decision literal that
|
||||||
lead to a conflict. It restarts after evern 100 conflicts.
|
lead to a conflict. It restarts after evern 100 conflicts.
|
||||||
|
|
||||||
It does not attempt to add conflict clauses or alternate with
|
It does not attempt to add conflict clauses
|
||||||
walksat.
|
|
||||||
|
|
||||||
It can receive conflict clauses from a concurrent CDCL solver and does not
|
It can receive conflict clauses from a concurrent CDCL solver
|
||||||
create its own conflict clauses.
|
|
||||||
|
|
||||||
The phase of variables is optionally sticky between rounds. We use a decay rate
|
The phase of variables is optionally sticky between rounds. We use a decay rate
|
||||||
to compute stickiness of a variable.
|
to compute stickiness of a variable.
|
||||||
|
@ -31,20 +30,52 @@ Author:
|
||||||
|
|
||||||
Revision History:
|
Revision History:
|
||||||
|
|
||||||
|
2018-11-5:
|
||||||
|
change reinitialization to use local search with limited timeouts to find phase and ordering of variables.
|
||||||
|
|
||||||
--*/
|
--*/
|
||||||
|
|
||||||
#include "sat_unit_walk.h"
|
#include "sat/sat_unit_walk.h"
|
||||||
|
#include "util/luby.h"
|
||||||
|
|
||||||
|
|
||||||
namespace sat {
|
namespace sat {
|
||||||
|
|
||||||
|
bool_var unit_walk::var_priority::peek(solver& s) {
|
||||||
|
while (m_head < m_vars.size()) {
|
||||||
|
bool_var v = m_vars[m_head];
|
||||||
|
unsigned idx = literal(v, false).index();
|
||||||
|
if (s.m_assignment[idx] == l_undef)
|
||||||
|
return v;
|
||||||
|
++m_head;
|
||||||
|
}
|
||||||
|
for (bool_var v : m_vars) {
|
||||||
|
if (s.m_assignment[literal(v, false).index()] == l_undef) {
|
||||||
|
IF_VERBOSE(0, verbose_stream() << "unassigned: " << v << "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IF_VERBOSE(0, verbose_stream() << "(sat.unit-walk sat)\n");
|
||||||
|
return null_bool_var;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unit_walk::var_priority::set_vars(solver& s) {
|
||||||
|
m_vars.reset();
|
||||||
|
for (unsigned v = 0; v < s.num_vars(); ++v) {
|
||||||
|
if (!s.was_eliminated(v) && s.m_assignment[v] == l_undef) {
|
||||||
|
add(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_var unit_walk::var_priority::next(solver& s) {
|
||||||
|
bool_var v = peek(s);
|
||||||
|
++m_head;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
unit_walk::unit_walk(solver& s):
|
unit_walk::unit_walk(solver& s):
|
||||||
s(s)
|
s(s) {
|
||||||
{
|
m_max_conflicts = 10000;
|
||||||
m_runs = 0;
|
|
||||||
m_periods = 0;
|
|
||||||
m_max_runs = UINT_MAX;
|
|
||||||
m_max_periods = 5000; // UINT_MAX; // TBD configure
|
|
||||||
m_max_conflicts = 100;
|
|
||||||
m_sticky_phase = s.get_config().m_phase_sticky;
|
m_sticky_phase = s.get_config().m_phase_sticky;
|
||||||
m_flips = 0;
|
m_flips = 0;
|
||||||
}
|
}
|
||||||
|
@ -63,67 +94,177 @@ namespace sat {
|
||||||
lbool unit_walk::operator()() {
|
lbool unit_walk::operator()() {
|
||||||
scoped_set_unit_walk _scoped_set(this, s);
|
scoped_set_unit_walk _scoped_set(this, s);
|
||||||
init_runs();
|
init_runs();
|
||||||
for (m_runs = 0; m_runs < m_max_runs || m_max_runs == UINT_MAX; ++m_runs) {
|
init_propagation();
|
||||||
init_propagation();
|
init_phase();
|
||||||
init_phase();
|
while (true) {
|
||||||
for (m_periods = 0; m_periods < m_max_periods || m_max_periods == UINT_MAX; ++m_periods) {
|
if (!s.rlimit().inc()) {
|
||||||
if (!s.rlimit().inc()) return l_undef;
|
log_status();
|
||||||
lbool r = unit_propagation();
|
return l_undef;
|
||||||
if (r != l_undef) return r;
|
}
|
||||||
}
|
bool_var v = pqueue().next(s);
|
||||||
}
|
if (v == null_bool_var) {
|
||||||
return l_undef;
|
log_status();
|
||||||
}
|
return l_true;
|
||||||
|
}
|
||||||
lbool unit_walk::unit_propagation() {
|
|
||||||
init_propagation();
|
|
||||||
while (!m_freevars.empty() && !inconsistent()) {
|
|
||||||
bool_var v = m_freevars.begin()[m_rand(m_freevars.size())];
|
|
||||||
literal lit(v, !m_phase[v]);
|
literal lit(v, !m_phase[v]);
|
||||||
++s.m_stats.m_decision;
|
++s.m_stats.m_decision;
|
||||||
m_decisions.push_back(lit);
|
m_decisions.push_back(lit);
|
||||||
|
// IF_VERBOSE(0, verbose_stream() << "push " << lit << " " << m_decisions.size() << "\n");
|
||||||
|
pqueue().push();
|
||||||
assign(lit);
|
assign(lit);
|
||||||
propagate();
|
propagate();
|
||||||
while (inconsistent() && !m_decisions.empty()) {
|
while (inconsistent() && !m_decisions.empty()) {
|
||||||
++m_conflicts;
|
update_max_trail();
|
||||||
backtrack();
|
++s.m_stats.m_conflict;
|
||||||
|
pop();
|
||||||
|
pqueue().pop();
|
||||||
propagate();
|
propagate();
|
||||||
}
|
}
|
||||||
if (m_conflicts >= m_max_conflicts && !m_freevars.empty()) {
|
if (inconsistent()) {
|
||||||
set_conflict();
|
log_status();
|
||||||
break;
|
return l_false;
|
||||||
|
}
|
||||||
|
bool do_reinit = s.m_stats.m_conflict >= m_max_conflicts;
|
||||||
|
if (do_reinit || pqueue().depth() > m_decisions.size()) { // || pqueue().depth() <= 10
|
||||||
|
switch (update_priority()) {
|
||||||
|
case l_true: return l_true;
|
||||||
|
case l_false: break; // TBD
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (do_reinit) {
|
||||||
|
refresh_solver();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!inconsistent()) {
|
}
|
||||||
log_status();
|
|
||||||
IF_VERBOSE(1, verbose_stream() << "(sat-unit-walk sat)\n";);
|
void unit_walk::pop() {
|
||||||
s.mk_model();
|
SASSERT (!m_decisions.empty());
|
||||||
return l_true;
|
literal dlit = m_decisions.back();
|
||||||
|
pop_decision();
|
||||||
|
m_inconsistent = false;
|
||||||
|
assign(~dlit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unit_walk::pop_decision() {
|
||||||
|
SASSERT (!m_decisions.empty());
|
||||||
|
literal dlit = m_decisions.back();
|
||||||
|
// IF_VERBOSE(0, verbose_stream() << "pop " << dlit << " " << m_decisions.size() << "\n");
|
||||||
|
literal lit;
|
||||||
|
do {
|
||||||
|
SASSERT(!m_trail.empty());
|
||||||
|
lit = m_trail.back();
|
||||||
|
s.m_assignment[lit.index()] = l_undef;
|
||||||
|
s.m_assignment[(~lit).index()] = l_undef;
|
||||||
|
m_trail.pop_back();
|
||||||
}
|
}
|
||||||
return l_undef;
|
while (lit != dlit);
|
||||||
|
m_qhead = m_trail.size();
|
||||||
|
m_decisions.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_walk::init_runs() {
|
void unit_walk::init_runs() {
|
||||||
m_freevars.reset();
|
m_luby_index = 0;
|
||||||
|
m_restart_threshold = 1000;
|
||||||
|
m_max_trail = 0;
|
||||||
m_trail.reset();
|
m_trail.reset();
|
||||||
m_decisions.reset();
|
m_decisions.reset();
|
||||||
m_phase.resize(s.num_vars());
|
m_phase.resize(s.num_vars());
|
||||||
double2 d2;
|
m_phase_tf.resize(s.num_vars(), ema(1e-5));
|
||||||
d2.t = 1.0;
|
pqueue().reset();
|
||||||
d2.f = 1.0;
|
pqueue().set_vars(s);
|
||||||
m_phase_tf.resize(s.num_vars(), d2);
|
for (unsigned v = 0; v < s.num_vars(); ++v) {
|
||||||
for (unsigned i = 0; i < s.num_vars(); ++i) {
|
m_phase_tf[v].update(50);
|
||||||
literal l(i, false);
|
|
||||||
if (!s.was_eliminated(l.var()) && s.m_assignment[l.index()] == l_undef)
|
|
||||||
m_freevars.insert(l.var());
|
|
||||||
}
|
}
|
||||||
IF_VERBOSE(1, verbose_stream() << "num vars: " << s.num_vars() << " free vars: " << m_freevars.size() << "\n";);
|
m_ls.import(s, true);
|
||||||
|
m_rand.set_seed(s.rand()());
|
||||||
|
update_priority();
|
||||||
|
}
|
||||||
|
|
||||||
|
lbool unit_walk::update_priority() {
|
||||||
|
unsigned prefix_length = 0;
|
||||||
|
if (pqueue().depth() > m_decisions.size()) {
|
||||||
|
while (pqueue().depth() > m_decisions.size()) {
|
||||||
|
pqueue().dec_depth();
|
||||||
|
}
|
||||||
|
prefix_length = m_trail.size();
|
||||||
|
SASSERT(pqueue().depth() == m_decisions.size());
|
||||||
|
}
|
||||||
|
else if (pqueue().depth() == m_decisions.size()) {
|
||||||
|
prefix_length = m_trail.size();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
literal last = m_decisions[pqueue().depth()];
|
||||||
|
while (m_trail[prefix_length++] != last) {}
|
||||||
|
pqueue().inc_depth();
|
||||||
|
}
|
||||||
|
log_status();
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "(sat.unit-walk :update-priority " << pqueue().depth() << ")\n");
|
||||||
|
for (unsigned v = 0; v < s.num_vars(); ++v) {
|
||||||
|
m_ls.set_bias(v, m_phase_tf[v] >= 50 ? l_true : l_false);
|
||||||
|
}
|
||||||
|
for (literal lit : m_trail) {
|
||||||
|
m_ls.set_bias(lit.var(), lit.sign() ? l_false : l_true);
|
||||||
|
}
|
||||||
|
m_ls.rlimit().push(std::max(1u, pqueue().depth()));
|
||||||
|
lbool is_sat = m_ls.check(0, m_trail.c_ptr(), nullptr);
|
||||||
|
m_ls.rlimit().pop();
|
||||||
|
|
||||||
|
TRACE("sat", tout << "result of running bounded local search " << is_sat << "\n";);
|
||||||
|
IF_VERBOSE(0, verbose_stream() << "result of running local search " << is_sat << "\n";);
|
||||||
|
if (is_sat != l_undef) {
|
||||||
|
restart();
|
||||||
|
}
|
||||||
|
if (is_sat == l_true) {
|
||||||
|
for (unsigned v = 0; v < s.num_vars(); ++v) {
|
||||||
|
s.m_assignment[v] = m_ls.get_phase(v) ? l_true : l_false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compare_break {
|
||||||
|
local_search& ls;
|
||||||
|
compare_break(local_search& ls): ls(ls) {}
|
||||||
|
int operator()(bool_var v, bool_var w) const {
|
||||||
|
double diff = ls.break_count(v) - ls.break_count(w);
|
||||||
|
return diff > 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
compare_break cb(m_ls);
|
||||||
|
std::sort(pqueue().begin(), pqueue().end(), cb);
|
||||||
|
pqueue().rewind();
|
||||||
|
// assert variables are sorted from highest to lowest value.
|
||||||
|
|
||||||
|
for (bool_var v : pqueue()) {
|
||||||
|
if (m_ls.cur_solution(v))
|
||||||
|
m_phase_tf[v].update(100);
|
||||||
|
else
|
||||||
|
m_phase_tf[v].update(0);
|
||||||
|
}
|
||||||
|
init_phase();
|
||||||
|
|
||||||
|
// restart
|
||||||
|
bool_var v = pqueue().peek(s);
|
||||||
|
if (is_sat == l_undef && v != null_bool_var && false) {
|
||||||
|
unsigned num_levels = 0;
|
||||||
|
while (m_decisions.size() > 0 && num_levels <= 50) {
|
||||||
|
bool_var w = m_decisions.back().var();
|
||||||
|
if (num_levels >= 15 && m_ls.break_count(w) >= m_ls.break_count(v)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++num_levels;
|
||||||
|
pop_decision();
|
||||||
|
if (pqueue().depth() > m_decisions.size()) {
|
||||||
|
pqueue().pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IF_VERBOSE(0, verbose_stream() << "backtrack levels " << num_levels << "\n");
|
||||||
|
}
|
||||||
|
return is_sat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_walk::init_phase() {
|
void unit_walk::init_phase() {
|
||||||
m_max_trail = 0;
|
|
||||||
if (m_sticky_phase) {
|
if (m_sticky_phase) {
|
||||||
for (bool_var v : m_freevars) {
|
for (bool_var v : pqueue()) {
|
||||||
if (s.m_phase[v] == POS_PHASE) {
|
if (s.m_phase[v] == POS_PHASE) {
|
||||||
m_phase[v] = true;
|
m_phase[v] = true;
|
||||||
}
|
}
|
||||||
|
@ -131,35 +272,73 @@ namespace sat {
|
||||||
m_phase[v] = false;
|
m_phase[v] = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_phase[v] = m_rand(100 * static_cast<unsigned>(m_phase_tf[v].t + m_phase_tf[v].f)) <= 100 * m_phase_tf[v].t;
|
m_phase[v] = m_rand(100) <= m_phase_tf[v];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (bool_var v : m_freevars)
|
for (bool_var v : pqueue())
|
||||||
m_phase[v] = (m_rand(2) == 0);
|
m_phase[v] = (m_rand(2) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unit_walk::refresh_solver() {
|
||||||
|
m_max_conflicts += m_conflict_offset ;
|
||||||
|
m_conflict_offset += 100; // 00;
|
||||||
|
if (s.m_par && s.m_par->copy_solver(s)) {
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "(sat.unit-walk fresh copy)\n";);
|
||||||
|
if (s.get_extension()) s.get_extension()->set_unit_walk(this);
|
||||||
|
init_runs();
|
||||||
|
init_phase();
|
||||||
|
}
|
||||||
|
if (should_restart()) {
|
||||||
|
restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unit_walk::should_restart() {
|
||||||
|
if (s.m_stats.m_conflict >= m_restart_threshold) {
|
||||||
|
m_restart_threshold = s.get_config().m_restart_initial * get_luby(m_luby_index);
|
||||||
|
++m_luby_index;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unit_walk::restart() {
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "restart\n");
|
||||||
|
while (!m_decisions.empty()) {
|
||||||
|
pop_decision();
|
||||||
|
}
|
||||||
|
pqueue().reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void unit_walk::update_max_trail() {
|
||||||
|
if (m_max_trail == 0 || m_trail.size() > m_max_trail) {
|
||||||
|
m_max_trail = m_trail.size();
|
||||||
|
m_restart_threshold += 10000;
|
||||||
|
m_max_conflicts = s.m_stats.m_conflict + 20000;
|
||||||
|
log_status();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void unit_walk::init_propagation() {
|
void unit_walk::init_propagation() {
|
||||||
if (s.m_par && s.m_par->copy_solver(s)) {
|
if (s.m_par && s.m_par->copy_solver(s)) {
|
||||||
IF_VERBOSE(1, verbose_stream() << "(sat-unit-walk fresh copy)\n";);
|
IF_VERBOSE(1, verbose_stream() << "(sat.unit-walk fresh copy)\n";);
|
||||||
if (s.get_extension()) s.get_extension()->set_unit_walk(this);
|
if (s.get_extension()) s.get_extension()->set_unit_walk(this);
|
||||||
init_runs();
|
init_runs();
|
||||||
init_phase();
|
init_phase();
|
||||||
}
|
}
|
||||||
if (m_max_trail == 0 || m_trail.size() > m_max_trail) {
|
|
||||||
m_max_trail = m_trail.size();
|
|
||||||
log_status();
|
|
||||||
}
|
|
||||||
for (literal lit : m_trail) {
|
for (literal lit : m_trail) {
|
||||||
s.m_assignment[lit.index()] = l_undef;
|
s.m_assignment[lit.index()] = l_undef;
|
||||||
s.m_assignment[(~lit).index()] = l_undef;
|
s.m_assignment[(~lit).index()] = l_undef;
|
||||||
m_freevars.insert(lit.var());
|
|
||||||
}
|
}
|
||||||
m_flips = 0;
|
m_flips = 0;
|
||||||
m_trail.reset();
|
m_trail.reset();
|
||||||
m_conflicts = 0;
|
s.m_stats.m_conflict = 0;
|
||||||
|
m_conflict_offset = 10000;
|
||||||
m_decisions.reset();
|
m_decisions.reset();
|
||||||
m_qhead = 0;
|
m_qhead = 0;
|
||||||
m_inconsistent = false;
|
m_inconsistent = false;
|
||||||
|
@ -171,6 +350,20 @@ namespace sat {
|
||||||
// IF_VERBOSE(1, verbose_stream() << m_trail.size() << " " << inconsistent() << "\n";);
|
// IF_VERBOSE(1, verbose_stream() << m_trail.size() << " " << inconsistent() << "\n";);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& unit_walk::display(std::ostream& out) const {
|
||||||
|
unsigned i = 0;
|
||||||
|
out << "num decisions: " << m_decisions.size() << "\n";
|
||||||
|
for (literal lit : m_trail) {
|
||||||
|
if (i < m_decisions.size() && m_decisions[i] == lit) {
|
||||||
|
out << "d " << i << ": ";
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
out << lit << "\n";
|
||||||
|
}
|
||||||
|
s.display(verbose_stream());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
void unit_walk::propagate(literal l) {
|
void unit_walk::propagate(literal l) {
|
||||||
++s.m_stats.m_propagate;
|
++s.m_stats.m_propagate;
|
||||||
literal not_l = ~l;
|
literal not_l = ~l;
|
||||||
|
@ -289,11 +482,12 @@ namespace sat {
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_walk::assign(literal lit) {
|
void unit_walk::assign(literal lit) {
|
||||||
SASSERT(value(lit) == l_undef);
|
VERIFY(value(lit) == l_undef);
|
||||||
|
//VERIFY(!m_trail.contains(lit));
|
||||||
|
//VERIFY(!m_trail.contains(~lit));
|
||||||
s.m_assignment[lit.index()] = l_true;
|
s.m_assignment[lit.index()] = l_true;
|
||||||
s.m_assignment[(~lit).index()] = l_false;
|
s.m_assignment[(~lit).index()] = l_false;
|
||||||
m_trail.push_back(lit);
|
m_trail.push_back(lit);
|
||||||
m_freevars.remove(lit.var());
|
|
||||||
if (s.get_extension() && s.is_external(lit.var())) {
|
if (s.get_extension() && s.is_external(lit.var())) {
|
||||||
s.get_extension()->asserted(lit);
|
s.get_extension()->asserted(lit);
|
||||||
}
|
}
|
||||||
|
@ -307,28 +501,23 @@ namespace sat {
|
||||||
bool_var v = l.var();
|
bool_var v = l.var();
|
||||||
m_phase[v] = !m_phase[v];
|
m_phase[v] = !m_phase[v];
|
||||||
if (m_sticky_phase) {
|
if (m_sticky_phase) {
|
||||||
m_phase_tf[v].f *= 0.98;
|
if (m_phase[v]) m_phase_tf[v].update(100); else m_phase_tf[v].update(0);
|
||||||
m_phase_tf[v].t *= 0.98;
|
|
||||||
if (m_phase[v]) m_phase_tf[v].t += 1; else m_phase_tf[v].f += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_walk::log_status() {
|
void unit_walk::log_status() {
|
||||||
IF_VERBOSE(1, verbose_stream() << "(sat-unit-walk :trail " << m_max_trail
|
IF_VERBOSE(1, verbose_stream()
|
||||||
<< " :branches " << m_decisions.size()
|
<< "(sat.unit-walk"
|
||||||
<< " :free " << m_freevars.size()
|
<< " :trail " << m_trail.size()
|
||||||
<< " :periods " << m_periods
|
<< " :depth " << m_decisions.size()
|
||||||
<< " :decisions " << s.m_stats.m_decision
|
<< " :decisions " << s.m_stats.m_decision
|
||||||
<< " :propagations " << s.m_stats.m_propagate
|
<< " :propagations " << s.m_stats.m_propagate
|
||||||
|
<< " :conflicts " << s.m_stats.m_conflict
|
||||||
<< ")\n";);
|
<< ")\n";);
|
||||||
}
|
}
|
||||||
|
|
||||||
literal unit_walk::choose_literal() {
|
literal unit_walk::choose_literal() {
|
||||||
SASSERT(m_qhead < m_trail.size());
|
return m_trail[m_qhead++];
|
||||||
unsigned idx = m_rand(m_trail.size() - m_qhead);
|
|
||||||
std::swap(m_trail[m_qhead], m_trail[m_qhead + idx]);
|
|
||||||
literal lit = m_trail[m_qhead++];
|
|
||||||
return lit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_walk::set_conflict(literal l1, literal l2) {
|
void unit_walk::set_conflict(literal l1, literal l2) {
|
||||||
|
@ -346,25 +535,6 @@ namespace sat {
|
||||||
void unit_walk::set_conflict() {
|
void unit_walk::set_conflict() {
|
||||||
m_inconsistent = true;
|
m_inconsistent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_walk::backtrack() {
|
|
||||||
if (m_decisions.empty()) return;
|
|
||||||
literal dlit = m_decisions.back();
|
|
||||||
literal lit;
|
|
||||||
do {
|
|
||||||
SASSERT(!m_trail.empty());
|
|
||||||
lit = m_trail.back();
|
|
||||||
s.m_assignment[lit.index()] = l_undef;
|
|
||||||
s.m_assignment[(~lit).index()] = l_undef;
|
|
||||||
m_freevars.insert(lit.var());
|
|
||||||
m_trail.pop_back();
|
|
||||||
}
|
|
||||||
while (lit != dlit);
|
|
||||||
m_inconsistent = false;
|
|
||||||
m_decisions.pop_back();
|
|
||||||
m_qhead = m_trail.size();
|
|
||||||
assign(~dlit);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,43 +20,74 @@ Revision History:
|
||||||
#define SAT_UNIT_WALK_H_
|
#define SAT_UNIT_WALK_H_
|
||||||
|
|
||||||
#include "sat/sat_solver.h"
|
#include "sat/sat_solver.h"
|
||||||
|
#include "sat/sat_local_search.h"
|
||||||
|
#include "util/ema.h"
|
||||||
|
|
||||||
namespace sat {
|
namespace sat {
|
||||||
|
|
||||||
class unit_walk {
|
class unit_walk {
|
||||||
|
#if 0
|
||||||
struct double2 {
|
struct double2 {
|
||||||
double t, f;
|
double t, f;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
class var_priority {
|
||||||
|
svector<bool_var> m_vars;
|
||||||
|
unsigned_vector m_lim;
|
||||||
|
unsigned m_head;
|
||||||
|
unsigned m_depth;
|
||||||
|
public:
|
||||||
|
var_priority() { m_depth = 0; m_head = 0; }
|
||||||
|
void rewind() { m_head = 0; for (unsigned& l : m_lim) l = 0; }
|
||||||
|
unsigned depth() const { return m_depth; }
|
||||||
|
void inc_depth() { ++m_depth; }
|
||||||
|
void dec_depth() { --m_depth; }
|
||||||
|
void reset() { m_lim.reset(); m_head = 0; m_depth = 0; }
|
||||||
|
void add(bool_var v) { m_vars.push_back(v); }
|
||||||
|
bool_var next(solver& s);
|
||||||
|
bool_var peek(solver& s);
|
||||||
|
void set_vars(solver& s);
|
||||||
|
void push() { m_lim.push_back(m_head); }
|
||||||
|
void pop() { m_head = m_lim.back(); m_lim.pop_back(); }
|
||||||
|
bool empty() const { return m_lim.empty(); }
|
||||||
|
bool_var const* begin() const { return m_vars.begin(); }
|
||||||
|
bool_var const* end() const { return m_vars.end(); }
|
||||||
|
bool_var* begin() { return m_vars.begin(); }
|
||||||
|
bool_var* end() { return m_vars.end(); }
|
||||||
|
};
|
||||||
|
|
||||||
solver& s;
|
solver& s;
|
||||||
|
local_search m_ls;
|
||||||
random_gen m_rand;
|
random_gen m_rand;
|
||||||
svector<bool> m_phase;
|
svector<bool> m_phase;
|
||||||
svector<double2> m_phase_tf;
|
svector<ema> m_phase_tf;
|
||||||
indexed_uint_set m_freevars;
|
var_priority m_priorities;
|
||||||
unsigned m_runs;
|
unsigned m_luby_index;
|
||||||
unsigned m_periods;
|
unsigned m_restart_threshold;
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
unsigned m_max_runs;
|
|
||||||
unsigned m_max_periods;
|
|
||||||
unsigned m_max_conflicts;
|
unsigned m_max_conflicts;
|
||||||
bool m_sticky_phase;
|
bool m_sticky_phase;
|
||||||
|
|
||||||
unsigned m_propagations;
|
|
||||||
unsigned m_flips;
|
unsigned m_flips;
|
||||||
unsigned m_max_trail;
|
unsigned m_max_trail;
|
||||||
unsigned m_qhead;
|
unsigned m_qhead;
|
||||||
literal_vector m_trail;
|
literal_vector m_trail;
|
||||||
bool m_inconsistent;
|
bool m_inconsistent;
|
||||||
literal_vector m_decisions;
|
literal_vector m_decisions;
|
||||||
unsigned m_conflicts;
|
unsigned m_conflict_offset;
|
||||||
|
|
||||||
void push();
|
bool should_restart();
|
||||||
void backtrack();
|
void restart();
|
||||||
|
void pop();
|
||||||
|
void pop_decision();
|
||||||
void init_runs();
|
void init_runs();
|
||||||
|
lbool update_priority();
|
||||||
void init_phase();
|
void init_phase();
|
||||||
void init_propagation();
|
void init_propagation();
|
||||||
|
void refresh_solver();
|
||||||
|
void update_max_trail();
|
||||||
void flip_phase(literal l);
|
void flip_phase(literal l);
|
||||||
lbool unit_propagation();
|
|
||||||
void propagate();
|
void propagate();
|
||||||
void propagate(literal lit);
|
void propagate(literal lit);
|
||||||
literal choose_literal();
|
literal choose_literal();
|
||||||
|
@ -65,6 +96,7 @@ namespace sat {
|
||||||
void set_conflict(clause const& c);
|
void set_conflict(clause const& c);
|
||||||
inline lbool value(literal lit) { return s.value(lit); }
|
inline lbool value(literal lit) { return s.value(lit); }
|
||||||
void log_status();
|
void log_status();
|
||||||
|
var_priority& pqueue() { return m_priorities; }
|
||||||
public:
|
public:
|
||||||
|
|
||||||
unit_walk(solver& s);
|
unit_walk(solver& s);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue