mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
updates to seq and bug fixes (#4056)
* na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix #4037 * nicer output for skolem functions * more overhaul of seq, some bug fixes * na * added offset_eq file * na * fix #4044 * fix #4040 * fix #4045 * updated ignore * new rewrites for indexof based on #4036 * add shortcuts * updated ne solver for seq, fix #4025 * use pair vectors for equalities that are reduced by seq_rewriter * use erase_and_swap * remove unit-walk * na * add check for #3200 * nits Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * name a type Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * remove fp check Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * remove unsound axiom instantiation for non-contains Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix rewrites Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix #4053 Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix #4052 Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
53c14bd554
commit
95a78b2450
39 changed files with 1516 additions and 1654 deletions
|
@ -33,7 +33,6 @@ z3_add_component(sat
|
|||
sat_scc.cpp
|
||||
sat_simplifier.cpp
|
||||
sat_solver.cpp
|
||||
sat_unit_walk.cpp
|
||||
sat_watched.cpp
|
||||
sat_xor_finder.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
|
|
|
@ -1865,7 +1865,7 @@ namespace sat {
|
|||
}
|
||||
|
||||
ba_solver::ba_solver()
|
||||
: m_solver(nullptr), m_lookahead(nullptr), m_unit_walk(nullptr),
|
||||
: m_solver(nullptr), m_lookahead(nullptr),
|
||||
m_constraint_id(0), m_ba(*this), m_sort(m_ba) {
|
||||
TRACE("ba", tout << this << "\n";);
|
||||
m_num_propagations_since_pop = 0;
|
||||
|
|
|
@ -24,7 +24,6 @@ Revision History:
|
|||
#include "sat/sat_extension.h"
|
||||
#include "sat/sat_solver.h"
|
||||
#include "sat/sat_lookahead.h"
|
||||
#include "sat/sat_unit_walk.h"
|
||||
#include "sat/sat_big.h"
|
||||
#include "util/small_object_allocator.h"
|
||||
#include "util/scoped_ptr_vector.h"
|
||||
|
@ -230,7 +229,6 @@ namespace sat {
|
|||
|
||||
solver* m_solver;
|
||||
lookahead* m_lookahead;
|
||||
unit_walk* m_unit_walk;
|
||||
stats m_stats;
|
||||
small_object_allocator m_allocator;
|
||||
|
||||
|
@ -445,23 +443,20 @@ namespace sat {
|
|||
inline lbool value(model const& m, literal l) const { return l.sign() ? ~m[l.var()] : m[l.var()]; }
|
||||
inline bool is_false(literal lit) const { return l_false == value(lit); }
|
||||
|
||||
inline unsigned lvl(literal lit) const { return m_lookahead || m_unit_walk ? 0 : m_solver->lvl(lit); }
|
||||
inline unsigned lvl(bool_var v) const { return m_lookahead || m_unit_walk ? 0 : m_solver->lvl(v); }
|
||||
inline unsigned lvl(literal lit) const { return m_lookahead ? 0 : m_solver->lvl(lit); }
|
||||
inline unsigned lvl(bool_var v) const { return m_lookahead ? 0 : m_solver->lvl(v); }
|
||||
inline bool inconsistent() const {
|
||||
if (m_lookahead) return m_lookahead->inconsistent();
|
||||
if (m_unit_walk) return m_unit_walk->inconsistent();
|
||||
return m_solver->inconsistent();
|
||||
}
|
||||
inline watch_list& get_wlist(literal l) { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); }
|
||||
inline watch_list const& get_wlist(literal l) const { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); }
|
||||
inline void assign(literal l, justification j) {
|
||||
if (m_lookahead) m_lookahead->assign(l);
|
||||
else if (m_unit_walk) m_unit_walk->assign(l);
|
||||
else m_solver->assign(l, j);
|
||||
}
|
||||
inline void set_conflict(justification j, literal l) {
|
||||
if (m_lookahead) m_lookahead->set_conflict();
|
||||
else if (m_unit_walk) m_unit_walk->set_conflict();
|
||||
else m_solver->set_conflict(j, l);
|
||||
}
|
||||
inline config const& get_config() const { return m_lookahead ? m_lookahead->get_config() : m_solver->get_config(); }
|
||||
|
@ -544,7 +539,6 @@ namespace sat {
|
|||
~ba_solver() override;
|
||||
void set_solver(solver* s) override { m_solver = s; }
|
||||
void set_lookahead(lookahead* l) override { m_lookahead = l; }
|
||||
void set_unit_walk(unit_walk* u) override { m_unit_walk = u; }
|
||||
void add_at_least(bool_var v, literal_vector const& lits, unsigned k);
|
||||
void add_pb_ge(bool_var v, svector<wliteral> const& wlits, unsigned k);
|
||||
void add_xr(literal_vector const& lits);
|
||||
|
|
|
@ -98,8 +98,6 @@ namespace sat {
|
|||
else
|
||||
m_local_search_mode = local_search_mode::wsat;
|
||||
m_local_search_dbg_flips = p.local_search_dbg_flips();
|
||||
m_unit_walk = p.unit_walk();
|
||||
m_unit_walk_threads = p.unit_walk_threads();
|
||||
m_binspr = p.binspr();
|
||||
m_binspr = false; // prevent adventurous users from trying feature that isn't ready
|
||||
m_anf_simplify = p.anf();
|
||||
|
|
|
@ -117,8 +117,6 @@ namespace sat {
|
|||
bool m_local_search;
|
||||
local_search_mode m_local_search_mode;
|
||||
bool m_local_search_dbg_flips;
|
||||
unsigned m_unit_walk_threads;
|
||||
bool m_unit_walk;
|
||||
bool m_binspr;
|
||||
bool m_cut_simplify;
|
||||
unsigned m_cut_delay;
|
||||
|
|
|
@ -52,7 +52,6 @@ namespace sat {
|
|||
virtual ~extension() {}
|
||||
virtual void set_solver(solver* s) = 0;
|
||||
virtual void set_lookahead(lookahead* s) = 0;
|
||||
virtual void set_unit_walk(unit_walk* u) = 0;
|
||||
virtual bool propagate(literal l, ext_constraint_idx idx) = 0;
|
||||
virtual double get_reward(literal l, ext_constraint_idx idx, literal_occs_fun& occs) const = 0;
|
||||
virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) = 0;
|
||||
|
|
|
@ -67,8 +67,6 @@ def_module_params('sat',
|
|||
('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'),
|
||||
('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'),
|
||||
('local_search_dbg_flips', BOOL, False, 'write debug information for number of flips'),
|
||||
('unit_walk', BOOL, False, 'use unit-walk search instead of CDCL'),
|
||||
('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'),
|
||||
('anf.delay', UINT, 2, 'delay ANF simplification by in-processing round'),
|
||||
|
|
|
@ -27,7 +27,6 @@ Revision History:
|
|||
#include "sat/sat_solver.h"
|
||||
#include "sat/sat_integrity_checker.h"
|
||||
#include "sat/sat_lookahead.h"
|
||||
#include "sat/sat_unit_walk.h"
|
||||
#include "sat/sat_ddfw.h"
|
||||
#include "sat/sat_prob.h"
|
||||
#include "sat/sat_anf_simplifier.h"
|
||||
|
@ -1194,7 +1193,7 @@ namespace sat {
|
|||
return do_local_search(num_lits, lits);
|
||||
}
|
||||
if ((m_config.m_num_threads > 1 || m_config.m_local_search_threads > 0 ||
|
||||
m_config.m_ddfw_threads > 0 || m_config.m_unit_walk_threads > 0) && !m_par) {
|
||||
m_config.m_ddfw_threads > 0) && !m_par) {
|
||||
SASSERT(scope_lvl() == 0);
|
||||
return check_par(num_lits, lits);
|
||||
}
|
||||
|
@ -1214,10 +1213,6 @@ namespace sat {
|
|||
if (check_inconsistent()) return l_false;
|
||||
if (m_config.m_force_cleanup) do_cleanup(true);
|
||||
|
||||
if (m_config.m_unit_walk) {
|
||||
return do_unit_walk();
|
||||
}
|
||||
|
||||
if (m_config.m_gc_burst) {
|
||||
// force gc
|
||||
m_conflicts_since_gc = m_gc_threshold + 1;
|
||||
|
@ -1326,19 +1321,6 @@ namespace sat {
|
|||
return invoke_local_search(num_lits, lits);
|
||||
}
|
||||
|
||||
lbool solver::do_unit_walk() {
|
||||
unit_walk srch(*this);
|
||||
lbool r = srch();
|
||||
if (r == l_true) {
|
||||
m_model.reset();
|
||||
for (bool_var v = 0; v < num_vars(); ++v) {
|
||||
m_model.push_back(m_assignment[literal(v,false).index()]);
|
||||
}
|
||||
m_model_is_current = true;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
lbool solver::check_par(unsigned num_lits, literal const* lits) {
|
||||
if (!rlimit().inc()) {
|
||||
return l_undef;
|
||||
|
@ -1347,9 +1329,8 @@ namespace sat {
|
|||
scoped_ptr_vector<solver> uw;
|
||||
int num_extra_solvers = m_config.m_num_threads - 1;
|
||||
int num_local_search = static_cast<int>(m_config.m_local_search_threads);
|
||||
int num_unit_walk = static_cast<int>(m_config.m_unit_walk_threads);
|
||||
int num_ddfw = m_ext ? 0 : static_cast<int>(m_config.m_ddfw_threads);
|
||||
int num_threads = num_extra_solvers + 1 + num_local_search + num_unit_walk + num_ddfw;
|
||||
int num_threads = num_extra_solvers + 1 + num_local_search + num_ddfw;
|
||||
for (int i = 0; i < num_local_search; ++i) {
|
||||
local_search* l = alloc(local_search);
|
||||
l->updt_params(m_params);
|
||||
|
@ -1357,6 +1338,8 @@ namespace sat {
|
|||
l->set_seed(m_config.m_random_seed + i);
|
||||
ls.push_back(l);
|
||||
}
|
||||
|
||||
vector<reslimit> lims(num_ddfw);
|
||||
// set up ddfw search
|
||||
for (int i = 0; i < num_ddfw; ++i) {
|
||||
ddfw* d = alloc(ddfw);
|
||||
|
@ -1365,23 +1348,11 @@ namespace sat {
|
|||
d->add(*this);
|
||||
ls.push_back(d);
|
||||
}
|
||||
|
||||
// set up unit walk
|
||||
vector<reslimit> lims(num_unit_walk + num_ddfw);
|
||||
for (int i = 0; i < num_unit_walk; ++i) {
|
||||
solver* s = alloc(solver, m_params, lims[i]);
|
||||
s->copy(*this);
|
||||
s->m_config.m_unit_walk = true;
|
||||
uw.push_back(s);
|
||||
}
|
||||
|
||||
int local_search_offset = num_extra_solvers;
|
||||
int unit_walk_offset = num_extra_solvers + num_local_search + num_ddfw;
|
||||
int main_solver_offset = unit_walk_offset + num_unit_walk;
|
||||
int main_solver_offset = num_extra_solvers + num_local_search + num_ddfw;
|
||||
|
||||
#define IS_AUX_SOLVER(i) (0 <= i && i < num_extra_solvers)
|
||||
#define IS_LOCAL_SEARCH(i) (local_search_offset <= i && i < unit_walk_offset)
|
||||
#define IS_UNIT_WALK(i) (unit_walk_offset <= i && i < main_solver_offset)
|
||||
#define IS_LOCAL_SEARCH(i) (local_search_offset <= i && i < main_solver_offset)
|
||||
#define IS_MAIN_SOLVER(i) (i == main_solver_offset)
|
||||
|
||||
sat::parallel par(*this);
|
||||
|
@ -1413,9 +1384,6 @@ namespace sat {
|
|||
else if (IS_LOCAL_SEARCH(i)) {
|
||||
r = ls[i-local_search_offset]->check(num_lits, lits, &par);
|
||||
}
|
||||
else if (IS_UNIT_WALK(i)) {
|
||||
r = uw[i-unit_walk_offset]->check(num_lits, lits);
|
||||
}
|
||||
else {
|
||||
r = check(num_lits, lits);
|
||||
}
|
||||
|
@ -1484,9 +1452,6 @@ namespace sat {
|
|||
if (result == l_true && IS_LOCAL_SEARCH(finished_id)) {
|
||||
set_model(ls[finished_id - local_search_offset]->get_model(), true);
|
||||
}
|
||||
if (result == l_true && IS_UNIT_WALK(finished_id)) {
|
||||
set_model(uw[finished_id - unit_walk_offset]->get_model(), true);
|
||||
}
|
||||
if (!canceled) {
|
||||
rlimit().reset_cancel();
|
||||
}
|
||||
|
|
|
@ -1,514 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_unit_walk.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
unit walk local search procedure.
|
||||
|
||||
A variant of UnitWalk. Hirsch and Kojevinkov, SAT 2001.
|
||||
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
|
||||
pending units as a multi-set.
|
||||
|
||||
It uses standard DPLL approach for backracking, flipping the last decision literal that
|
||||
lead to a conflict. It restarts after evern 100 conflicts.
|
||||
|
||||
It does not attempt to add conflict clauses
|
||||
|
||||
It can receive conflict clauses from a concurrent CDCL solver
|
||||
|
||||
The phase of variables is optionally sticky between rounds. We use a decay rate
|
||||
to compute stickiness of a variable.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2017-12-15.
|
||||
|
||||
Revision History:
|
||||
|
||||
2018-11-5:
|
||||
change reinitialization to use local search with limited timeouts to find phase and ordering of variables.
|
||||
|
||||
--*/
|
||||
|
||||
#include "sat/sat_unit_walk.h"
|
||||
#include "util/luby.h"
|
||||
|
||||
|
||||
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) {
|
||||
// IF_VERBOSE(0, verbose_stream() << "pop " << v << "\n");
|
||||
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() << "#vars: " << m_vars.size() << "\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();
|
||||
s.pop_to_base_level();
|
||||
|
||||
for (unsigned v = 0; v < s.num_vars(); ++v) {
|
||||
if (!s.was_eliminated(v) && s.value(v) == l_undef) {
|
||||
add(v);
|
||||
}
|
||||
}
|
||||
IF_VERBOSE(0, verbose_stream() << "num vars " << m_vars.size() << "\n";);
|
||||
}
|
||||
|
||||
bool_var unit_walk::var_priority::next(solver& s) {
|
||||
bool_var v = peek(s);
|
||||
++m_head;
|
||||
return v;
|
||||
}
|
||||
|
||||
unit_walk::unit_walk(solver& s):
|
||||
s(s) {
|
||||
m_max_conflicts = 10000;
|
||||
m_flips = 0;
|
||||
}
|
||||
|
||||
class scoped_set_unit_walk {
|
||||
solver& s;
|
||||
public:
|
||||
scoped_set_unit_walk(unit_walk* u, solver& s): s(s) {
|
||||
if (s.get_extension()) s.get_extension()->set_unit_walk(u);
|
||||
}
|
||||
~scoped_set_unit_walk() {
|
||||
if (s.get_extension()) s.get_extension()->set_unit_walk(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
lbool unit_walk::operator()() {
|
||||
m_inconsistent = false;
|
||||
scoped_set_unit_walk _scoped_set(this, s);
|
||||
if (init_runs())
|
||||
return l_true;
|
||||
init_propagation();
|
||||
init_phase();
|
||||
lbool st = l_undef;
|
||||
while (s.rlimit().inc() && st == l_undef) {
|
||||
if (inconsistent() && !m_decisions.empty()) do_pop();
|
||||
else if (inconsistent()) st = l_false;
|
||||
else if (should_restart()) restart();
|
||||
else if (should_backjump()) st = do_backjump();
|
||||
else st = decide();
|
||||
}
|
||||
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);
|
||||
lbool st = update_priority(backjump_level);
|
||||
switch (st) {
|
||||
case l_true: return l_true;
|
||||
case l_false: break; // TBD
|
||||
default: break;
|
||||
}
|
||||
if (refresh_solver())
|
||||
return l_true;
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
void unit_walk::pop() {
|
||||
SASSERT (!m_decisions.empty());
|
||||
literal dlit = m_decisions.back();
|
||||
pop_decision();
|
||||
assign(~dlit);
|
||||
}
|
||||
|
||||
void unit_walk::pop_decision() {
|
||||
SASSERT (!m_decisions.empty());
|
||||
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_trail.pop_back();
|
||||
}
|
||||
while (lit != dlit);
|
||||
m_qhead = m_trail.size();
|
||||
m_decisions.pop_back();
|
||||
pqueue().pop();
|
||||
m_inconsistent = false;
|
||||
}
|
||||
|
||||
bool unit_walk::init_runs() {
|
||||
m_luby_index = 0;
|
||||
m_restart_threshold = 1000;
|
||||
m_max_trail = 0;
|
||||
m_trail.reset();
|
||||
m_decisions.reset();
|
||||
m_phase.resize(s.num_vars());
|
||||
m_phase_tf.resize(s.num_vars(), ema(1e-5));
|
||||
pqueue().reset();
|
||||
pqueue().set_vars(s);
|
||||
for (unsigned v = 0; v < s.num_vars(); ++v) {
|
||||
m_phase_tf[v].update(50);
|
||||
}
|
||||
m_ls.import(s, true);
|
||||
m_rand.set_seed(s.rand()());
|
||||
return l_true == update_priority(0);
|
||||
}
|
||||
|
||||
lbool unit_walk::do_local_search(unsigned num_rounds) {
|
||||
unsigned prefix_length = (0*m_trail.size())/10;
|
||||
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(num_rounds);
|
||||
lbool is_sat = m_ls.check(prefix_length, m_trail.c_ptr(), nullptr);
|
||||
m_ls.rlimit().pop();
|
||||
return is_sat;
|
||||
}
|
||||
|
||||
lbool unit_walk::update_priority(unsigned level) {
|
||||
|
||||
while (m_decisions.size() > level) {
|
||||
pop_decision();
|
||||
}
|
||||
IF_VERBOSE(1, verbose_stream() << "(sat.unit-walk :update-priority " << m_decisions.size() << ")\n");
|
||||
|
||||
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_model()[v];
|
||||
}
|
||||
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 {
|
||||
return ls.get_priority(v) > ls.get_priority(w);
|
||||
}
|
||||
};
|
||||
|
||||
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] = l_true == m_ls.cur_solution(v);
|
||||
}
|
||||
pqueue().rewind();
|
||||
}
|
||||
|
||||
void unit_walk::init_phase() {
|
||||
for (bool_var v : pqueue()) {
|
||||
m_phase[v] = s.m_phase[v];
|
||||
}
|
||||
}
|
||||
|
||||
bool unit_walk::refresh_solver() {
|
||||
m_max_conflicts += m_conflict_offset ;
|
||||
m_conflict_offset += 10000;
|
||||
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);
|
||||
if (init_runs())
|
||||
return true;
|
||||
init_phase();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void unit_walk::restart() {
|
||||
while (!m_decisions.empty()) {
|
||||
pop_decision();
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
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();
|
||||
}
|
||||
for (literal lit : m_trail) {
|
||||
s.m_assignment[lit.index()] = l_undef;
|
||||
s.m_assignment[(~lit).index()] = l_undef;
|
||||
}
|
||||
m_flips = 0;
|
||||
m_trail.reset();
|
||||
s.m_stats.m_conflict = 0;
|
||||
m_conflict_offset = 10000;
|
||||
m_decisions.reset();
|
||||
m_qhead = 0;
|
||||
m_inconsistent = false;
|
||||
}
|
||||
|
||||
void unit_walk::propagate() {
|
||||
while (m_qhead < m_trail.size() && !inconsistent()) {
|
||||
propagate(m_trail[m_qhead++]);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
++s.m_stats.m_propagate;
|
||||
literal not_l = ~l;
|
||||
literal l1, l2;
|
||||
lbool val1, val2;
|
||||
bool keep;
|
||||
watch_list & wlist = s.get_wlist(l);
|
||||
watch_list::iterator it = wlist.begin();
|
||||
watch_list::iterator it2 = it;
|
||||
watch_list::iterator end = wlist.end();
|
||||
for (; it != end; ++it) {
|
||||
switch (it->get_kind()) {
|
||||
case watched::BINARY:
|
||||
l1 = it->get_literal();
|
||||
switch (value(l1)) {
|
||||
case l_false:
|
||||
conflict_cleanup(it, it2, wlist);
|
||||
set_conflict(l,l1);
|
||||
return;
|
||||
case l_undef:
|
||||
assign(l1);
|
||||
break;
|
||||
case l_true:
|
||||
break; // skip
|
||||
}
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
break;
|
||||
case watched::TERNARY:
|
||||
l1 = it->get_literal1();
|
||||
l2 = it->get_literal2();
|
||||
val1 = value(l1);
|
||||
val2 = value(l2);
|
||||
if (val1 == l_false && val2 == l_undef) {
|
||||
assign(l2);
|
||||
}
|
||||
else if (val1 == l_undef && val2 == l_false) {
|
||||
assign(l1);
|
||||
}
|
||||
else if (val1 == l_false && val2 == l_false) {
|
||||
conflict_cleanup(it, it2, wlist);
|
||||
set_conflict(l,l1,l2);
|
||||
return;
|
||||
}
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
break;
|
||||
case watched::CLAUSE: {
|
||||
if (value(it->get_blocked_literal()) == l_true) {
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
break;
|
||||
}
|
||||
clause_offset cls_off = it->get_clause_offset();
|
||||
clause & c = s.get_clause(cls_off);
|
||||
if (c[0] == not_l)
|
||||
std::swap(c[0], c[1]);
|
||||
if (c[1] != not_l) {
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
break;
|
||||
}
|
||||
if (value(c[0]) == l_true) {
|
||||
it2->set_clause(c[0], cls_off);
|
||||
it2++;
|
||||
break;
|
||||
}
|
||||
SASSERT(c[1] == not_l);
|
||||
literal * l_it = c.begin() + 2;
|
||||
literal * l_end = c.end();
|
||||
for (; l_it != l_end; ++l_it) {
|
||||
if (value(*l_it) != l_false) {
|
||||
c[1] = *l_it;
|
||||
*l_it = not_l;
|
||||
s.get_wlist((~c[1]).index()).push_back(watched(c[0], cls_off));
|
||||
goto end_clause_case;
|
||||
}
|
||||
}
|
||||
SASSERT(value(c[0]) == l_false || value(c[0]) == l_undef);
|
||||
if (value(c[0]) == l_false) {
|
||||
c.mark_used();
|
||||
conflict_cleanup(it, it2, wlist);
|
||||
set_conflict(c);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
assign(c[0]);
|
||||
}
|
||||
end_clause_case:
|
||||
break;
|
||||
}
|
||||
case watched::EXT_CONSTRAINT:
|
||||
SASSERT(s.get_extension());
|
||||
keep = s.get_extension()->propagate(l, it->get_ext_constraint_idx());
|
||||
if (inconsistent()) {
|
||||
if (!keep) {
|
||||
++it;
|
||||
}
|
||||
set_conflict(l, l);
|
||||
conflict_cleanup(it, it2, wlist);
|
||||
return;
|
||||
}
|
||||
if (keep) {
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
wlist.set_end(it2);
|
||||
}
|
||||
|
||||
void unit_walk::assign(literal lit) {
|
||||
VERIFY(value(lit) == l_undef);
|
||||
s.m_assignment[lit.index()] = l_true;
|
||||
s.m_assignment[(~lit).index()] = l_false;
|
||||
m_trail.push_back(lit);
|
||||
if (s.get_extension() && s.is_external(lit.var())) {
|
||||
s.get_extension()->asserted(lit);
|
||||
}
|
||||
if (m_phase[lit.var()] == lit.sign()) {
|
||||
++m_flips;
|
||||
flip_phase(lit);
|
||||
m_phase_tf[lit.var()].update(m_phase[lit.var()] ? 100 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void unit_walk::flip_phase(literal l) {
|
||||
bool_var v = l.var();
|
||||
m_phase[v] = !m_phase[v];
|
||||
}
|
||||
|
||||
void unit_walk::log_status() {
|
||||
IF_VERBOSE(1, verbose_stream()
|
||||
<< "(sat.unit-walk"
|
||||
<< " :trail " << m_trail.size()
|
||||
<< " :depth " << m_decisions.size()
|
||||
<< " :decisions " << s.m_stats.m_decision
|
||||
<< " :propagations " << s.m_stats.m_propagate
|
||||
<< " :conflicts " << s.m_stats.m_conflict
|
||||
<< ")\n";);
|
||||
}
|
||||
|
||||
void unit_walk::set_conflict(literal l1, literal l2) {
|
||||
set_conflict();
|
||||
}
|
||||
|
||||
void unit_walk::set_conflict(literal l1, literal l2, literal l3) {
|
||||
set_conflict();
|
||||
}
|
||||
|
||||
void unit_walk::set_conflict(clause const& c) {
|
||||
set_conflict();
|
||||
}
|
||||
|
||||
void unit_walk::set_conflict() {
|
||||
m_inconsistent = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_unit_walk.h
|
||||
|
||||
Abstract:
|
||||
|
||||
unit walk local search procedure.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2017-12-15.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef SAT_UNIT_WALK_H_
|
||||
#define SAT_UNIT_WALK_H_
|
||||
|
||||
#include "sat/sat_solver.h"
|
||||
#include "sat/sat_local_search.h"
|
||||
#include "util/ema.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
class unit_walk {
|
||||
#if 0
|
||||
struct double2 {
|
||||
double t, f;
|
||||
};
|
||||
#endif
|
||||
class var_priority {
|
||||
svector<bool_var> m_vars;
|
||||
unsigned_vector m_lim;
|
||||
unsigned m_head;
|
||||
public:
|
||||
var_priority() { m_head = 0; }
|
||||
void reset() { m_lim.reset(); m_head = 0;}
|
||||
void rewind() { for (unsigned& l : m_lim) l = 0; m_head = 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;
|
||||
local_search m_ls;
|
||||
random_gen m_rand;
|
||||
bool_vector m_phase;
|
||||
svector<ema> m_phase_tf;
|
||||
var_priority m_priorities;
|
||||
unsigned m_luby_index;
|
||||
unsigned m_restart_threshold;
|
||||
|
||||
// settings
|
||||
unsigned m_max_conflicts;
|
||||
|
||||
unsigned m_flips;
|
||||
unsigned m_max_trail;
|
||||
unsigned m_qhead;
|
||||
literal_vector m_trail;
|
||||
bool m_inconsistent;
|
||||
literal_vector m_decisions;
|
||||
unsigned m_conflict_offset;
|
||||
svector<lbool> m_model;
|
||||
|
||||
bool should_restart();
|
||||
void do_pop();
|
||||
bool should_backjump();
|
||||
lbool do_backjump();
|
||||
lbool do_local_search(unsigned num_rounds);
|
||||
lbool decide();
|
||||
void restart();
|
||||
void pop();
|
||||
void pop_decision();
|
||||
bool init_runs();
|
||||
lbool update_priority(unsigned level);
|
||||
void update_pqueue();
|
||||
void init_phase();
|
||||
void init_propagation();
|
||||
bool refresh_solver();
|
||||
void update_max_trail();
|
||||
void flip_phase(literal l);
|
||||
void propagate();
|
||||
void propagate(literal lit);
|
||||
void set_conflict(literal l1, literal l2);
|
||||
void set_conflict(literal l1, literal l2, literal l3);
|
||||
void set_conflict(clause const& c);
|
||||
inline lbool value(literal lit) { return s.value(lit); }
|
||||
void log_status();
|
||||
var_priority& pqueue() { return m_priorities; }
|
||||
public:
|
||||
|
||||
unit_walk(solver& s);
|
||||
lbool operator()();
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
bool inconsistent() const { return m_inconsistent; }
|
||||
void set_conflict();
|
||||
void assign(literal lit);
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue