3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 02:15:19 +00:00

elaborating on local-search rephase strategy

This commit is contained in:
Nikolaj Bjorner 2023-02-07 03:17:52 -08:00
parent f3ae7692ca
commit 90a75866fb
9 changed files with 131 additions and 56 deletions

View file

@ -57,11 +57,11 @@ namespace sat {
double sec = m_stopwatch.get_current_seconds();
double kflips_per_sec = (m_flips - m_last_flips) / (1000.0 * sec);
if (m_last_flips == 0) {
IF_VERBOSE(0, verbose_stream() << "(sat.ddfw :unsat :models :kflips/sec :flips :restarts :reinits :unsat_vars :shifts";
IF_VERBOSE(1, verbose_stream() << "(sat.ddfw :unsat :models :kflips/sec :flips :restarts :reinits :unsat_vars :shifts";
if (m_par) verbose_stream() << " :par";
verbose_stream() << ")\n");
}
IF_VERBOSE(0, verbose_stream() << "(sat.ddfw "
IF_VERBOSE(1, verbose_stream() << "(sat.ddfw "
<< std::setw(07) << m_min_sz
<< std::setw(07) << m_models.size()
<< std::setw(10) << kflips_per_sec
@ -106,7 +106,6 @@ namespace sat {
if (r > 0) {
lim_pos -= score(r);
if (lim_pos <= 0) {
if (m_par) update_reward_avg(v);
return v;
}
}
@ -139,9 +138,8 @@ namespace sat {
}
void ddfw::add(solver const& s) {
for (auto& ci : m_clauses) {
for (auto& ci : m_clauses)
m_alloc.del_clause(ci.m_clause);
}
m_clauses.reset();
m_use_list.reset();
m_num_non_binary_clauses = 0;
@ -281,6 +279,7 @@ namespace sat {
ci.add(nlit);
}
value(v) = !value(v);
update_reward_avg(v);
}
bool ddfw::should_reinit_weights() {
@ -379,36 +378,35 @@ namespace sat {
return m_par != nullptr && m_flips >= m_parsync_next;
}
void ddfw::save_priorities() {
m_probs.reset();
for (unsigned v = 0; v < num_vars(); ++v)
m_probs.push_back(-m_vars[v].m_reward_avg);
}
void ddfw::do_parallel_sync() {
if (m_par->from_solver(*this)) {
// Sum exp(xi) / exp(a) = Sum exp(xi - a)
double max_avg = 0;
for (unsigned v = 0; v < num_vars(); ++v) {
max_avg = std::max(max_avg, (double)m_vars[v].m_reward_avg);
}
double sum = 0;
for (unsigned v = 0; v < num_vars(); ++v) {
sum += exp(m_config.m_itau * (m_vars[v].m_reward_avg - max_avg));
}
if (sum == 0) {
sum = 0.01;
}
m_probs.reset();
for (unsigned v = 0; v < num_vars(); ++v) {
m_probs.push_back(exp(m_config.m_itau * (m_vars[v].m_reward_avg - max_avg)) / sum);
}
if (m_par->from_solver(*this))
m_par->to_solver(*this);
}
++m_parsync_count;
m_parsync_next *= 3;
m_parsync_next /= 2;
}
void ddfw::save_model() {
m_model.reserve(num_vars());
for (unsigned i = 0; i < num_vars(); ++i)
m_model[i] = to_lbool(value(i));
save_priorities();
}
void ddfw::save_best_values() {
if (m_unsat.empty()) {
m_model.reserve(num_vars());
for (unsigned i = 0; i < num_vars(); ++i)
m_model[i] = to_lbool(value(i));
if (m_unsat.empty())
save_model();
else if (m_unsat.size() < m_min_sz) {
if (m_unsat.size() < 50 || m_min_sz * 10 > m_unsat.size() * 11)
save_model();
}
if (m_unsat.size() < m_min_sz) {
m_models.reset();

View file

@ -164,6 +164,8 @@ namespace sat {
bool_var pick_var();
void flip(bool_var v);
void save_best_values();
void save_model();
void save_priorities();
// shift activity
void shift_weights();

View file

@ -214,14 +214,17 @@ namespace sat {
}
bool parallel::_to_solver(solver& s) {
if (m_priorities.empty()) {
return false;
}
void parallel::_to_solver(solver& s) {
return;
#if 0
if (m_priorities.empty())
return;
for (bool_var v = 0; v < m_priorities.size(); ++v) {
s.update_activity(v, m_priorities[v]);
}
return true;
s.m_activity_inc = 128;
#endif
}
void parallel::from_solver(solver& s) {
@ -229,16 +232,19 @@ namespace sat {
_from_solver(s);
}
bool parallel::to_solver(solver& s) {
void parallel::to_solver(solver& s) {
lock_guard lock(m_mux);
return _to_solver(s);
_to_solver(s);
}
void parallel::_to_solver(i_local_search& s) {
return;
#if 0
m_priorities.reset();
for (bool_var v = 0; m_solver_copy && v < m_solver_copy->num_vars(); ++v) {
m_priorities.push_back(s.get_priority(v));
}
#endif
}
bool parallel::_from_solver(i_local_search& s) {

View file

@ -51,7 +51,7 @@ namespace sat {
bool enable_add(clause const& c) const;
void _get_clauses(solver& s);
void _from_solver(solver& s);
bool _to_solver(solver& s);
void _to_solver(solver& s);
bool _from_solver(i_local_search& s);
void _to_solver(i_local_search& s);
@ -102,7 +102,7 @@ namespace sat {
// exchange from solver state to local search and back.
void from_solver(solver& s);
bool to_solver(solver& s);
void to_solver(solver& s);
bool from_solver(i_local_search& s);
void to_solver(i_local_search& s);

View file

@ -2,7 +2,7 @@ def_module_params('sat',
export=True,
description='propositional SAT solver',
params=(max_memory_param(),
('phase', SYMBOL, 'caching', 'phase selection strategy: always_false, always_true, basic_caching, random, caching'),
('phase', SYMBOL, 'caching', 'phase selection strategy: always_false, always_true, basic_caching, random, caching, local_search'),
('phase.sticky', BOOL, True, 'use sticky phase caching'),
('search.unsat.conflicts', UINT, 400, 'period for solving for unsat (in number of conflicts)'),
('search.sat.conflicts', UINT, 400, 'period for solving for sat (in number of conflicts)'),

View file

@ -58,7 +58,7 @@ namespace sat {
clause_vector m_clause_db;
svector<clause_info> m_clauses;
bool_vector m_values, m_best_values;
unsigned m_best_min_unsat{ 0 };
unsigned m_best_min_unsat = 0;
vector<unsigned_vector> m_use_list;
unsigned_vector m_flat_use_list;
unsigned_vector m_use_list_index;
@ -67,9 +67,9 @@ namespace sat {
indexed_uint_set m_unsat;
random_gen m_rand;
unsigned_vector m_breaks;
uint64_t m_flips{ 0 };
uint64_t m_next_restart{ 0 };
unsigned m_restart_count{ 0 };
uint64_t m_flips = 0;
uint64_t m_next_restart = 0;
unsigned m_restart_count = 0;
stopwatch m_stopwatch;
model m_model;
@ -139,6 +139,8 @@ namespace sat {
void add(solver const& s) override;
model const& get_model() const override { return m_model; }
double get_priority(bool_var v) const { return 0; }
std::ostream& display(std::ostream& out) const;

View file

@ -40,6 +40,26 @@ Revision History:
namespace sat {
/**
* Special cases of kissat style general backoff calculation.
* The version here calculates
* limit := value*log(C)^2*n*log(n)
* (effort calculation in kissat is based on ticks not clauses)
*
* respectively
* limit := conflicts + value*log(C)^2*n*log(n)
*/
void backoff::delta_effort(solver& s) {
count++;
unsigned d = value * count * log2(count + 1);
unsigned cl = log2(s.num_clauses() + 2);
limit = cl * cl * d;
}
void backoff::delta_conflicts(solver& s) {
delta_effort(s);
limit += s.m_conflicts_since_init;
}
solver::solver(params_ref const & p, reslimit& l):
solver_core(l),
@ -1349,16 +1369,43 @@ namespace sat {
m_local_search->updt_params(m_params);
m_local_search->set_seed(m_rand());
scoped_rl.push_child(&(m_local_search->rlimit()));
m_local_search->rlimit().push(500000);
m_backoffs.m_local_search.delta_effort(*this);
m_local_search->rlimit().push(m_backoffs.m_local_search.limit);
m_local_search->reinit(*this);
lbool r = m_local_search->check(_lits.size(), _lits.data(), nullptr);
for (unsigned i = 0; i < m_phase.size(); ++i)
m_best_phase[i] = m_local_search->get_value(i);
if (r == l_true) {
m_conflicts_since_restart = 0;
m_conflicts_since_gc = 0;
m_next_simplify = std::max(m_next_simplify, m_conflicts_since_init + 1);
auto const& mdl = m_local_search->get_model();
if (mdl.size() == m_best_phase.size()) {
for (unsigned i = 0; i < m_best_phase.size(); ++i)
m_best_phase[i] = l_true == mdl[i];
if (r == l_true) {
m_conflicts_since_restart = 0;
m_conflicts_since_gc = 0;
m_next_simplify = std::max(m_next_simplify, m_conflicts_since_init + 1);
}
do_restart(true);
#if 0
// move higher priority variables to front
// eg., move the first 10% variables to front
svector<std::pair<double, bool_var>> priorities(mdl.size());
for (unsigned i = 0; i < mdl.size(); ++i)
priorities[i] = { m_local_search->get_priority(i), i };
std::sort(priorities.begin(), priorities.end(), [](auto& x, auto& y) { return x.first > y.first; });
for (unsigned i = priorities.size() / 10; i-- > 0; )
move_to_front(priorities[i].second);
#endif
if (l_true == r) {
for (clause const* cp : m_clauses) {
bool is_true = any_of(*cp, [&](auto lit) { return lit.sign() != m_best_phase[lit.var()]; });
if (!is_true) {
verbose_stream() << "clause is false " << *cp << "\n";
}
}
}
}
}
@ -1693,7 +1740,7 @@ namespace sat {
if (!is_pos)
next_lit.neg();
TRACE("sat_decide", tout << scope_lvl() << ": next-case-split: " << next_lit << "\n";);
assign_scoped(next_lit);
return true;
@ -1913,6 +1960,7 @@ namespace sat {
m_rephase_lim = 0;
m_rephase_inc = 0;
m_reorder_lim = m_config.m_reorder_base;
m_backoffs.m_local_search.value = 500;
m_reorder_inc = 0;
m_conflicts_since_restart = 0;
m_force_conflict_analysis = false;
@ -1928,6 +1976,7 @@ namespace sat {
m_next_simplify = m_config.m_simplify_delay;
m_min_d_tk = 1.0;
m_search_lvl = 0;
if (m_learned.size() <= 2*m_clauses.size())
m_conflicts_since_gc = 0;
m_restart_next_out = 0;
@ -2030,9 +2079,7 @@ namespace sat {
if (m_par) {
m_par->from_solver(*this);
if (m_par->to_solver(*this)) {
m_activity_inc = 128;
}
m_par->to_solver(*this);
}
if (m_config.m_binspr && !inconsistent()) {
@ -2944,14 +2991,19 @@ namespace sat {
case PS_SAT_CACHING:
if (m_search_state == s_sat)
for (unsigned i = 0; i < m_phase.size(); ++i)
m_phase[i] = m_best_phase[i];
m_phase[i] = m_best_phase[i];
break;
case PS_RANDOM:
for (auto& p : m_phase) p = (m_rand() % 2) == 0;
break;
case PS_LOCAL_SEARCH:
if (m_search_state == s_sat)
bounded_local_search();
if (m_search_state == s_sat) {
if (m_rand() % 2 == 0)
bounded_local_search();
for (unsigned i = 0; i < m_phase.size(); ++i)
m_phase[i] = m_best_phase[i];
}
break;
default:
UNREACHABLE();

View file

@ -87,10 +87,23 @@ namespace sat {
struct no_drat_params : public params_ref {
no_drat_params() { set_bool("drat.disable", true); }
};
struct backoff {
unsigned value = 1;
unsigned lo = 0;
unsigned hi = 0;
unsigned limit = 0;
unsigned count = 0;
void delta_effort(solver& s);
void delta_conflicts(solver& s);
};
class solver : public solver_core {
public:
struct abort_solver {};
struct backoffs {
backoff m_local_search;
};
protected:
enum search_state { s_sat, s_unsat };
@ -159,6 +172,7 @@ namespace sat {
unsigned m_search_next_toggle;
unsigned m_phase_counter;
unsigned m_best_phase_size;
backoffs m_backoffs;
unsigned m_rephase_lim;
unsigned m_rephase_inc;
unsigned m_reorder_lim;
@ -237,6 +251,7 @@ namespace sat {
friend class lut_finder;
friend class npn3_finder;
friend class proof_trim;
friend struct backoff;
public:
solver(params_ref const & p, reslimit& l);
~solver() override;

View file

@ -90,7 +90,7 @@ namespace sat {
virtual reslimit& rlimit() = 0;
virtual model const& get_model() const = 0;
virtual void collect_statistics(statistics& st) const = 0;
virtual double get_priority(bool_var v) const { return 0; }
virtual double get_priority(bool_var v) const = 0;
virtual bool get_value(bool_var v) const { return true; }
};