3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-27 16:38:45 +00:00

variations on unit-walk

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2019-02-13 17:43:15 -08:00
parent 83f0fd5cc2
commit 5cdfa7cd1c
9 changed files with 163 additions and 154 deletions

View file

@ -90,6 +90,7 @@ namespace sat {
m_unit_walk = p.unit_walk(); m_unit_walk = p.unit_walk();
m_unit_walk_threads = p.unit_walk_threads(); m_unit_walk_threads = p.unit_walk_threads();
m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_simplify = p.lookahead_simplify();
m_lookahead_double = p.lookahead_double();
m_lookahead_simplify_bca = p.lookahead_simplify_bca(); m_lookahead_simplify_bca = p.lookahead_simplify_bca();
if (p.lookahead_reward() == symbol("heule_schur")) if (p.lookahead_reward() == symbol("heule_schur"))
m_lookahead_reward = heule_schur_reward; m_lookahead_reward = heule_schur_reward;

View file

@ -128,6 +128,7 @@ namespace sat {
double m_lookahead_cube_psat_clause_base; double m_lookahead_cube_psat_clause_base;
double m_lookahead_cube_psat_trigger; double m_lookahead_cube_psat_trigger;
reward_t m_lookahead_reward; reward_t m_lookahead_reward;
bool m_lookahead_double;
bool m_lookahead_global_autarky; bool m_lookahead_global_autarky;
double m_lookahead_delta_fraction; double m_lookahead_delta_fraction;
bool m_lookahead_use_learned; bool m_lookahead_use_learned;

View file

@ -591,18 +591,40 @@ namespace sat {
m_unsat_stack.push_back(c); m_unsat_stack.push_back(c);
} }
void local_search::pick_flip_lookahead() {
unsigned num_unsat = m_unsat_stack.size();
constraint const& c = m_constraints[m_unsat_stack[m_rand() % num_unsat]];
literal best = null_literal;
unsigned best_make = UINT_MAX;
for (literal lit : c.m_literals) {
if (!is_unit(lit) && is_true(lit)) {
flip_walksat(lit.var());
if (propagate(~lit) && best_make > m_unsat_stack.size()) {
best = lit;
best_make = m_unsat_stack.size();
}
flip_walksat(lit.var());
propagate(lit);
}
}
if (best != null_literal) {
flip_walksat(best.var());
propagate(~best);
}
else {
std::cout << "no best\n";
}
}
void local_search::pick_flip_walksat() { void local_search::pick_flip_walksat() {
reflip: reflip:
bool_var best_var = null_bool_var; bool_var best_var = null_bool_var;
unsigned n = 1; unsigned n = 1;
bool_var v = null_bool_var; bool_var v = null_bool_var;
unsigned num_unsat = m_unsat_stack.size(); unsigned num_unsat = m_unsat_stack.size();
constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; constraint const& c = m_constraints[m_unsat_stack[m_rand() % num_unsat]];
// VERIFY(c.m_k < constraint_value(c));
unsigned reflipped = 0; unsigned reflipped = 0;
bool is_core = m_unsat_stack.size() <= 10; bool is_core = m_unsat_stack.size() <= 10;
// TBD: dynamic noise strategy
//if (m_rand() % 100 < 98) {
if (m_rand() % 10000 <= m_noise) { if (m_rand() % 10000 <= m_noise) {
// take this branch with 98% probability. // take this branch with 98% probability.
// find the first one, to fast break the rest // find the first one, to fast break the rest

View file

@ -202,6 +202,7 @@ namespace sat {
void init_slack(); void init_slack();
void init_scores(); void init_scores();
void init_goodvars(); void init_goodvars();
void pick_flip_lookahead();
void pick_flip_walksat(); void pick_flip_walksat();
void flip_walksat(bool_var v); void flip_walksat(bool_var v);
bool propagate(literal lit); bool propagate(literal lit);

View file

@ -1812,7 +1812,7 @@ namespace sat {
unsigned lookahead::do_double(literal l, unsigned& base) { unsigned lookahead::do_double(literal l, unsigned& base) {
unsigned num_units = 0; unsigned num_units = 0;
if (!inconsistent() && dl_enabled(l)) { if (!inconsistent() && dl_enabled(l) && get_config().m_lookahead_double) {
if (get_lookahead_reward(l) > m_delta_trigger) { if (get_lookahead_reward(l) > m_delta_trigger) {
if (dl_no_overflow(base)) { if (dl_no_overflow(base)) {
++m_stats.m_double_lookahead_rounds; ++m_stats.m_double_lookahead_rounds;
@ -2013,6 +2013,7 @@ namespace sat {
} }
bool lookahead::backtrack(literal_vector& trail, svector<bool> & is_decision) { bool lookahead::backtrack(literal_vector& trail, svector<bool> & is_decision) {
m_cube_state.m_backtracks++;
while (inconsistent()) { while (inconsistent()) {
if (trail.empty()) return false; if (trail.empty()) return false;
if (is_decision.back()) { if (is_decision.back()) {
@ -2033,6 +2034,7 @@ namespace sat {
void lookahead::update_cube_statistics(statistics& st) { void lookahead::update_cube_statistics(statistics& st) {
st.update("lh cube cutoffs", m_cube_state.m_cutoffs); st.update("lh cube cutoffs", m_cube_state.m_cutoffs);
st.update("lh cube conflicts", m_cube_state.m_conflicts); st.update("lh cube conflicts", m_cube_state.m_conflicts);
st.update("lh cube backtracks", m_cube_state.m_backtracks);
} }
double lookahead::psat_heur() { double lookahead::psat_heur() {

View file

@ -181,6 +181,7 @@ namespace sat {
double m_psat_threshold; double m_psat_threshold;
unsigned m_conflicts; unsigned m_conflicts;
unsigned m_cutoffs; unsigned m_cutoffs;
unsigned m_backtracks;
cube_state() { reset(); } cube_state() { reset(); }
void reset() { void reset() {
m_first = true; m_first = true;
@ -190,7 +191,7 @@ namespace sat {
m_psat_threshold = dbl_max; m_psat_threshold = dbl_max;
reset_stats(); reset_stats();
} }
void reset_stats() { m_conflicts = 0; m_cutoffs = 0; } void reset_stats() { m_conflicts = 0; m_cutoffs = 0; m_backtracks = 0;}
void inc_conflict() { ++m_conflicts; } void inc_conflict() { ++m_conflicts; }
void inc_cutoff() { ++m_cutoffs; } void inc_cutoff() { ++m_cutoffs; }
}; };

View file

@ -72,6 +72,7 @@ def_module_params('sat',
('lookahead.cube.psat.trigger', DOUBLE, 5, 'trigger value to create lookahead cubes for PSAT cutoff. Used when lookahead.cube.cutoff is psat'), ('lookahead.cube.psat.trigger', DOUBLE, 5, 'trigger value to create lookahead cubes for PSAT cutoff. Used when lookahead.cube.cutoff is psat'),
('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'),
('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'),
('lookahead.double', BOOL, True, 'enable doubld lookahead'),
('lookahead.use_learned', BOOL, False, 'use learned clauses when selecting lookahead literal'), ('lookahead.use_learned', BOOL, False, 'use learned clauses when selecting lookahead literal'),
('lookahead_simplify.bca', BOOL, True, 'add learned binary clauses as part of lookahead simplification'), ('lookahead_simplify.bca', BOOL, True, 'add learned binary clauses as part of lookahead simplification'),
('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'), ('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'),

View file

@ -76,7 +76,6 @@ namespace sat {
unit_walk::unit_walk(solver& s): unit_walk::unit_walk(solver& s):
s(s) { s(s) {
m_max_conflicts = 10000; m_max_conflicts = 10000;
m_sticky_phase = s.get_config().m_phase_sticky;
m_flips = 0; m_flips = 0;
} }
@ -96,60 +95,64 @@ namespace sat {
init_runs(); init_runs();
init_propagation(); init_propagation();
init_phase(); init_phase();
while (true) { lbool st = l_undef;
if (!s.rlimit().inc()) { while (s.rlimit().inc() && st == l_undef) {
log_status(); if (inconsistent() && !m_decisions.empty()) do_pop();
return l_undef; else if (inconsistent()) st = l_false;
} else if (should_backjump()) st = do_backjump();
bool_var v = pqueue().next(s); else st = decide();
if (v == null_bool_var) {
log_status();
return l_true;
}
literal lit(v, !m_phase[v]);
++s.m_stats.m_decision;
m_decisions.push_back(lit);
// IF_VERBOSE(0, verbose_stream() << "push " << lit << " " << m_decisions.size() << "\n");
pqueue().push();
assign(lit);
propagate();
while (inconsistent() && !m_decisions.empty()) {
update_max_trail();
++s.m_stats.m_conflict;
pop();
pqueue().pop();
propagate();
}
if (inconsistent()) {
log_status();
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();
}
} }
log_status();
return st;
}
void unit_walk::do_pop() {
update_max_trail();
++s.m_stats.m_conflict;
pop();
propagate();
}
lbool unit_walk::decide() {
bool_var v = pqueue().next(s);
if (v == null_bool_var) {
return l_true;
}
literal lit(v, !m_phase[v]);
++s.m_stats.m_decision;
m_decisions.push_back(lit);
pqueue().push();
assign(lit);
propagate();
return l_undef;
}
bool unit_walk::should_backjump() {
return
s.m_stats.m_conflict >= m_max_conflicts && m_decisions.size() > 20;
}
lbool unit_walk::do_backjump() {
unsigned backjump_level = m_decisions.size(); // - (m_decisions.size()/20);
switch (update_priority(backjump_level)) {
case l_true: return l_true;
case l_false: break; // TBD
default: break;
}
refresh_solver();
return l_undef;
} }
void unit_walk::pop() { void unit_walk::pop() {
SASSERT (!m_decisions.empty()); SASSERT (!m_decisions.empty());
literal dlit = m_decisions.back(); literal dlit = m_decisions.back();
pop_decision(); pop_decision();
m_inconsistent = false;
assign(~dlit); assign(~dlit);
} }
void unit_walk::pop_decision() { void unit_walk::pop_decision() {
SASSERT (!m_decisions.empty()); SASSERT (!m_decisions.empty());
literal dlit = m_decisions.back(); literal dlit = m_decisions.back();
// IF_VERBOSE(0, verbose_stream() << "pop " << dlit << " " << m_decisions.size() << "\n");
literal lit; literal lit;
do { do {
SASSERT(!m_trail.empty()); SASSERT(!m_trail.empty());
@ -161,6 +164,8 @@ namespace sat {
while (lit != dlit); while (lit != dlit);
m_qhead = m_trail.size(); m_qhead = m_trail.size();
m_decisions.pop_back(); m_decisions.pop_back();
pqueue().pop();
m_inconsistent = false;
} }
void unit_walk::init_runs() { void unit_walk::init_runs() {
@ -178,120 +183,100 @@ namespace sat {
} }
m_ls.import(s, true); m_ls.import(s, true);
m_rand.set_seed(s.rand()()); m_rand.set_seed(s.rand()());
update_priority(); update_priority(0);
} }
lbool unit_walk::update_priority() { lbool unit_walk::do_local_search(unsigned num_rounds) {
unsigned prefix_length = 0; unsigned prefix_length = (0*m_trail.size())/10;
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) { for (unsigned v = 0; v < s.num_vars(); ++v) {
m_ls.set_bias(v, m_phase_tf[v] >= 50 ? l_true : l_false); m_ls.set_bias(v, m_phase_tf[v] >= 50 ? l_true : l_false);
} }
for (literal lit : m_trail) { for (literal lit : m_trail) {
m_ls.set_bias(lit.var(), lit.sign() ? l_false : l_true); m_ls.set_bias(lit.var(), lit.sign() ? l_false : l_true);
} }
m_ls.rlimit().push(std::max(1u, pqueue().depth())); m_ls.rlimit().push(num_rounds);
lbool is_sat = m_ls.check(0, m_trail.c_ptr(), nullptr); lbool is_sat = m_ls.check(prefix_length, m_trail.c_ptr(), nullptr);
m_ls.rlimit().pop(); 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; return is_sat;
} }
void unit_walk::init_phase() { lbool unit_walk::update_priority(unsigned level) {
if (m_sticky_phase) {
for (bool_var v : pqueue()) { while (m_decisions.size() > level) {
if (s.m_phase[v] == POS_PHASE) { pop_decision();
m_phase[v] = true;
}
else if (s.m_phase[v] == NEG_PHASE) {
m_phase[v] = false;
}
else {
m_phase[v] = m_rand(100) <= m_phase_tf[v];
}
}
} }
else { IF_VERBOSE(1, verbose_stream() << "(sat.unit-walk :update-priority " << m_decisions.size() << "\n");
for (bool_var v : pqueue())
m_phase[v] = (m_rand(2) == 0); unsigned num_rounds = 50;
log_status();
lbool is_sat = do_local_search(num_rounds);
switch (is_sat) {
case l_true:
for (unsigned v = 0; v < s.num_vars(); ++v) {
s.m_assignment[v] = m_ls.get_phase(v) ? l_true : l_false;
}
return l_true;
case l_false:
if (m_decisions.empty()) {
return l_false;
}
else {
pop();
return l_undef;
}
default:
update_pqueue();
return l_undef;
}
}
/**
* \brief Reshuffle variables in the priority queue using the break counts from local search.
*/
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;
}
};
void unit_walk::update_pqueue() {
compare_break cb(m_ls);
std::sort(pqueue().begin(), pqueue().end(), cb);
for (bool_var v : pqueue()) {
m_phase_tf[v].update(m_ls.cur_solution(v) ? 100 : 0);
m_phase[v] = m_ls.cur_solution(v);
}
pqueue().rewind();
}
void unit_walk::init_phase() {
for (bool_var v : pqueue()) {
if (s.m_phase[v] == POS_PHASE) {
m_phase[v] = true;
}
else if (s.m_phase[v] == NEG_PHASE) {
m_phase[v] = false;
}
else {
m_phase[v] = m_rand(100) < m_phase_tf[v];
}
} }
} }
void unit_walk::refresh_solver() { void unit_walk::refresh_solver() {
m_max_conflicts += m_conflict_offset ; m_max_conflicts += m_conflict_offset ;
m_conflict_offset += 100; // 00; m_conflict_offset += 10000;
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 (should_restart()) { if (false && should_restart()) {
restart(); restart();
} }
} }
@ -308,11 +293,9 @@ namespace sat {
} }
void unit_walk::restart() { void unit_walk::restart() {
IF_VERBOSE(1, verbose_stream() << "restart\n");
while (!m_decisions.empty()) { while (!m_decisions.empty()) {
pop_decision(); pop_decision();
} }
pqueue().reset();
} }
void unit_walk::update_max_trail() { void unit_walk::update_max_trail() {
@ -483,8 +466,6 @@ namespace sat {
void unit_walk::assign(literal lit) { void unit_walk::assign(literal lit) {
VERIFY(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);
@ -494,15 +475,13 @@ namespace sat {
if (m_phase[lit.var()] == lit.sign()) { if (m_phase[lit.var()] == lit.sign()) {
++m_flips; ++m_flips;
flip_phase(lit); flip_phase(lit);
m_phase_tf[lit.var()].update(m_phase[lit.var()] ? 100 : 0);
} }
} }
void unit_walk::flip_phase(literal l) { void unit_walk::flip_phase(literal l) {
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_phase[v]) m_phase_tf[v].update(100); else m_phase_tf[v].update(0);
}
} }
void unit_walk::log_status() { void unit_walk::log_status() {

View file

@ -35,14 +35,10 @@ namespace sat {
svector<bool_var> m_vars; svector<bool_var> m_vars;
unsigned_vector m_lim; unsigned_vector m_lim;
unsigned m_head; unsigned m_head;
unsigned m_depth;
public: public:
var_priority() { m_depth = 0; m_head = 0; } var_priority() { m_head = 0; }
void rewind() { m_head = 0; for (unsigned& l : m_lim) l = 0; } void reset() { m_lim.reset(); m_head = 0;}
unsigned depth() const { return m_depth; } void rewind() { for (unsigned& l : m_lim) l = 0; m_head = 0;}
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); } void add(bool_var v) { m_vars.push_back(v); }
bool_var next(solver& s); bool_var next(solver& s);
bool_var peek(solver& s); bool_var peek(solver& s);
@ -67,7 +63,6 @@ namespace sat {
// settings // settings
unsigned m_max_conflicts; unsigned m_max_conflicts;
bool m_sticky_phase;
unsigned m_flips; unsigned m_flips;
unsigned m_max_trail; unsigned m_max_trail;
@ -78,11 +73,17 @@ namespace sat {
unsigned m_conflict_offset; unsigned m_conflict_offset;
bool should_restart(); bool should_restart();
void do_pop();
bool should_backjump();
lbool do_backjump();
lbool do_local_search(unsigned num_rounds);
lbool decide();
void restart(); void restart();
void pop(); void pop();
void pop_decision(); void pop_decision();
void init_runs(); void init_runs();
lbool update_priority(); lbool update_priority(unsigned level);
void update_pqueue();
void init_phase(); void init_phase();
void init_propagation(); void init_propagation();
void refresh_solver(); void refresh_solver();