mirror of
https://github.com/Z3Prover/z3
synced 2025-06-20 12:53:38 +00:00
working on lookahead
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
388b025d9e
commit
88e7c240b7
4 changed files with 280 additions and 87 deletions
|
@ -219,6 +219,10 @@ namespace sat {
|
||||||
|
|
||||||
lbool operator()();
|
lbool operator()();
|
||||||
|
|
||||||
|
lbool check(unsigned sz, literal const* assumptions) { return l_undef; } // TBD
|
||||||
|
|
||||||
|
void cancel() {} // TBD
|
||||||
|
|
||||||
local_search_config& config() { return m_config; }
|
local_search_config& config() { return m_config; }
|
||||||
|
|
||||||
local_search_config m_config;
|
local_search_config m_config;
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace sat {
|
||||||
unsigned m_max_hlevel;
|
unsigned m_max_hlevel;
|
||||||
unsigned m_min_cutoff;
|
unsigned m_min_cutoff;
|
||||||
unsigned m_level_cand;
|
unsigned m_level_cand;
|
||||||
|
float m_delta_rho;
|
||||||
|
|
||||||
config() {
|
config() {
|
||||||
m_max_hlevel = 50;
|
m_max_hlevel = 50;
|
||||||
|
@ -38,15 +39,39 @@ namespace sat {
|
||||||
m_max_score = 20.0;
|
m_max_score = 20.0;
|
||||||
m_min_cutoff = 30;
|
m_min_cutoff = 30;
|
||||||
m_level_cand = 600;
|
m_level_cand = 600;
|
||||||
|
m_delta_rho = (float)0.9995;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct prefix {
|
||||||
|
unsigned m_prefix;
|
||||||
|
unsigned m_length;
|
||||||
|
prefix(): m_prefix(0), m_length(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lit_info {
|
||||||
|
float m_wnb;
|
||||||
|
unsigned m_double_lookahead;
|
||||||
|
lit_info(): m_wnb(0), m_double_lookahead(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct statistics {
|
struct statistics {
|
||||||
unsigned m_propagations;
|
unsigned m_propagations;
|
||||||
statistics() { reset(); }
|
statistics() { reset(); }
|
||||||
void reset() { memset(this, 0, sizeof(*this)); }
|
void reset() { memset(this, 0, sizeof(*this)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum search_mode {
|
||||||
|
searching, // normal search
|
||||||
|
lookahead1, // lookahead mode
|
||||||
|
lookahead2 // double lookahead
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ternary {
|
||||||
|
ternary(literal u, literal v, literal w): m_u(u), m_v(v), m_w(w) {}
|
||||||
|
literal m_u, m_v, m_w;
|
||||||
|
};
|
||||||
|
|
||||||
config m_config;
|
config m_config;
|
||||||
double m_delta_trigger;
|
double m_delta_trigger;
|
||||||
|
|
||||||
|
@ -60,15 +85,25 @@ namespace sat {
|
||||||
unsigned m_qhead; // propagation queue head
|
unsigned m_qhead; // propagation queue head
|
||||||
unsigned_vector m_qhead_lim;
|
unsigned_vector m_qhead_lim;
|
||||||
clause_vector m_clauses; // non-binary clauses
|
clause_vector m_clauses; // non-binary clauses
|
||||||
|
clause_vector m_retired_clauses; // clauses that were removed during search
|
||||||
|
svector<ternary> m_retired_ternary; //
|
||||||
|
unsigned_vector m_retired_clause_lim;
|
||||||
clause_allocator m_cls_allocator;
|
clause_allocator m_cls_allocator;
|
||||||
bool m_inconsistent;
|
bool m_inconsistent;
|
||||||
unsigned_vector m_bstamp; // literal: timestamp for binary implication
|
unsigned_vector m_bstamp; // literal: timestamp for binary implication
|
||||||
vector<svector<float> > m_H; // literal: fitness score
|
vector<svector<float> > m_H; // literal: fitness score
|
||||||
|
svector<float>* m_heur; // current fitness
|
||||||
svector<float> m_rating; // var: pre-selection rating
|
svector<float> m_rating; // var: pre-selection rating
|
||||||
unsigned m_bstamp_id; // unique id for binary implication.
|
unsigned m_bstamp_id; // unique id for binary implication.
|
||||||
|
unsigned m_istamp_id; // unique id for managing double lookaheads
|
||||||
char_vector m_assignment; // literal: assignment
|
char_vector m_assignment; // literal: assignment
|
||||||
vector<watch_list> m_watches; // literal: watch structure
|
vector<watch_list> m_watches; // literal: watch structure
|
||||||
|
svector<lit_info> m_lits; // literal: attributes.
|
||||||
|
float m_weighted_new_binaries; // metric associated with current lookahead1 literal.
|
||||||
|
svector<prefix> m_prefix; // var: prefix where variable participates in propagation
|
||||||
indexed_uint_set m_freevars;
|
indexed_uint_set m_freevars;
|
||||||
|
svector<search_mode> m_search_modes; // stack of modes
|
||||||
|
search_mode m_search_mode; // mode of search
|
||||||
statistics m_stats;
|
statistics m_stats;
|
||||||
|
|
||||||
void add_binary(literal l1, literal l2) {
|
void add_binary(literal l1, literal l2) {
|
||||||
|
@ -97,6 +132,15 @@ namespace sat {
|
||||||
m_bstamp.fill(0);
|
m_bstamp.fill(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void inc_istamp() {
|
||||||
|
++m_istamp_id;
|
||||||
|
if (m_istamp_id == 0) {
|
||||||
|
++m_istamp_id;
|
||||||
|
for (unsigned i = 0; i < m_lits.size(); ++i) {
|
||||||
|
m_lits[i].m_double_lookahead = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
void set_bstamp(literal l) {
|
void set_bstamp(literal l) {
|
||||||
m_bstamp[l.index()] = m_bstamp_id;
|
m_bstamp[l.index()] = m_bstamp_id;
|
||||||
}
|
}
|
||||||
|
@ -159,6 +203,15 @@ namespace sat {
|
||||||
// pre-selection
|
// pre-selection
|
||||||
// see also 91 - 102 sat11.w
|
// see also 91 - 102 sat11.w
|
||||||
|
|
||||||
|
void pre_select() {
|
||||||
|
m_lookahead.reset();
|
||||||
|
if (select(scope_lvl())) {
|
||||||
|
get_scc();
|
||||||
|
find_heights();
|
||||||
|
construct_lookahead_table();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct candidate {
|
struct candidate {
|
||||||
bool_var m_var;
|
bool_var m_var;
|
||||||
float m_rating;
|
float m_rating;
|
||||||
|
@ -169,7 +222,7 @@ namespace sat {
|
||||||
float get_rating(bool_var v) const { return m_rating[v]; }
|
float get_rating(bool_var v) const { return m_rating[v]; }
|
||||||
float get_rating(literal l) const { return get_rating(l.var()); }
|
float get_rating(literal l) const { return get_rating(l.var()); }
|
||||||
|
|
||||||
bool_var select(unsigned level) {
|
bool select(unsigned level) {
|
||||||
init_pre_selection(level);
|
init_pre_selection(level);
|
||||||
unsigned max_num_cand = level == 0 ? m_freevars.size() : m_config.m_level_cand / level;
|
unsigned max_num_cand = level == 0 ? m_freevars.size() : m_config.m_level_cand / level;
|
||||||
max_num_cand = std::max(m_config.m_min_cutoff, max_num_cand);
|
max_num_cand = std::max(m_config.m_min_cutoff, max_num_cand);
|
||||||
|
@ -179,7 +232,7 @@ namespace sat {
|
||||||
sum = init_candidates(level, newbies);
|
sum = init_candidates(level, newbies);
|
||||||
if (!m_candidates.empty()) break;
|
if (!m_candidates.empty()) break;
|
||||||
if (is_sat()) {
|
if (is_sat()) {
|
||||||
return null_bool_var;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SASSERT(!m_candidates.empty());
|
SASSERT(!m_candidates.empty());
|
||||||
|
@ -218,6 +271,7 @@ namespace sat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SASSERT(!m_candidates.empty() && m_candidates.size() <= max_num_cand);
|
SASSERT(!m_candidates.empty() && m_candidates.size() <= max_num_cand);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sift_up(unsigned j) {
|
void sift_up(unsigned j) {
|
||||||
|
@ -238,6 +292,7 @@ namespace sat {
|
||||||
m_candidates.reset();
|
m_candidates.reset();
|
||||||
float sum = 0;
|
float sum = 0;
|
||||||
for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) {
|
for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) {
|
||||||
|
SASSERT(l_undef == value(*it));
|
||||||
bool_var x = *it;
|
bool_var x = *it;
|
||||||
if (!newbies) {
|
if (!newbies) {
|
||||||
// TBD filter out candidates based on prefix strings or similar method
|
// TBD filter out candidates based on prefix strings or similar method
|
||||||
|
@ -277,17 +332,17 @@ namespace sat {
|
||||||
h_scores(m_H[i + 1], m_H[(i + 2) % 3]);
|
h_scores(m_H[i + 1], m_H[(i + 2) % 3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// heur = m_H[1];
|
m_heur = &m_H[1];
|
||||||
}
|
}
|
||||||
else if (level < max_level) {
|
else if (level < max_level) {
|
||||||
ensure_H(level);
|
ensure_H(level);
|
||||||
h_scores(m_H[level-1], m_H[level]);
|
h_scores(m_H[level-1], m_H[level]);
|
||||||
// heur = m_H[level];
|
m_heur = &m_H[level];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ensure_H(max_level);
|
ensure_H(max_level);
|
||||||
h_scores(m_H[max_level-1], m_H[max_level]);
|
h_scores(m_H[max_level-1], m_H[max_level]);
|
||||||
// heur = m_H[max_level];
|
m_heur = &m_H[max_level];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,9 +470,7 @@ namespace sat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void add_arc(literal u, literal v) { m_dfs[u.index()].m_next.push_back(v); }
|
void add_arc(literal u, literal v) { m_dfs[u.index()].m_next.push_back(v); }
|
||||||
bool has_arc(literal v) const {
|
bool has_arc(literal v) const { return m_dfs[v.index()].m_next.size() > m_dfs[v.index()].m_nextp; }
|
||||||
return m_dfs[v.index()].m_next.size() > m_dfs[v.index()].m_nextp;
|
|
||||||
}
|
|
||||||
literal pop_arc(literal u) { return m_dfs[u.index()].m_next[m_dfs[u.index()].m_nextp++]; }
|
literal pop_arc(literal u) { return m_dfs[u.index()].m_next[m_dfs[u.index()].m_nextp++]; }
|
||||||
unsigned num_next(literal u) const { return m_dfs[u.index()].m_next.size(); }
|
unsigned num_next(literal u) const { return m_dfs[u.index()].m_next.size(); }
|
||||||
literal get_next(literal u, unsigned i) const { return m_dfs[u.index()].m_next[i]; }
|
literal get_next(literal u, unsigned i) const { return m_dfs[u.index()].m_next[i]; }
|
||||||
|
@ -512,10 +565,6 @@ namespace sat {
|
||||||
else m_dfs[v.index()].m_min = u;
|
else m_dfs[v.index()].m_min = u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void construct_forest() {
|
|
||||||
find_heights();
|
|
||||||
construct_lookahead_table();
|
|
||||||
}
|
|
||||||
void find_heights() {
|
void find_heights() {
|
||||||
literal pp = null_literal;
|
literal pp = null_literal;
|
||||||
set_child(pp, null_literal);
|
set_child(pp, null_literal);
|
||||||
|
@ -562,7 +611,7 @@ namespace sat {
|
||||||
void construct_lookahead_table() {
|
void construct_lookahead_table() {
|
||||||
literal u = get_child(null_literal), v = null_literal;
|
literal u = get_child(null_literal), v = null_literal;
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
m_lookahead.reset();
|
SASSERT(m_lookahead.empty());
|
||||||
while (u != null_literal) {
|
while (u != null_literal) {
|
||||||
set_rank(u, m_lookahead.size());
|
set_rank(u, m_lookahead.size());
|
||||||
set_lookahead(get_vcomp(u));
|
set_lookahead(get_vcomp(u));
|
||||||
|
@ -592,6 +641,40 @@ namespace sat {
|
||||||
tout << m_lookahead[i].m_lit << " : " << m_lookahead[i].m_offset << "\n";);
|
tout << m_lookahead[i].m_lit << " : " << m_lookahead[i].m_offset << "\n";);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------
|
||||||
|
// clause management
|
||||||
|
|
||||||
|
void attach_clause(clause& c) {
|
||||||
|
if (false && c.size() == 3) { // disable ternary clauses
|
||||||
|
m_watches[(~c[0]).index()].push_back(watched(c[1], c[2]));
|
||||||
|
m_watches[(~c[1]).index()].push_back(watched(c[0], c[2]));
|
||||||
|
m_watches[(~c[2]).index()].push_back(watched(c[0], c[1]));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
literal block_lit = c[c.size() >> 2];
|
||||||
|
clause_offset cls_off = m_cls_allocator.get_offset(&c);
|
||||||
|
m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off));
|
||||||
|
m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off));
|
||||||
|
SASSERT(value(c[0]) == l_undef);
|
||||||
|
SASSERT(value(c[1]) == l_undef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void detach_clause(clause& c) {
|
||||||
|
clause_offset cls_off = m_cls_allocator.get_offset(&c);
|
||||||
|
m_retired_clauses.push_back(&c);
|
||||||
|
erase_clause_watch(get_wlist(~c[0]), cls_off);
|
||||||
|
erase_clause_watch(get_wlist(~c[1]), cls_off);
|
||||||
|
}
|
||||||
|
|
||||||
|
void detach_ternary(literal l1, literal l2, literal l3) {
|
||||||
|
m_retired_ternary.push_back(ternary(l1, l2, l3));
|
||||||
|
erase_ternary_watch(get_wlist(~l1), l2, l3);
|
||||||
|
erase_ternary_watch(get_wlist(~l2), l1, l3);
|
||||||
|
erase_ternary_watch(get_wlist(~l3), l1, l2);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch_list& get_wlist(literal l) { return m_watches[l.index()]; }
|
||||||
|
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
// initialization
|
// initialization
|
||||||
|
@ -608,6 +691,10 @@ namespace sat {
|
||||||
m_rating.push_back(0);
|
m_rating.push_back(0);
|
||||||
m_dfs.push_back(dfs_info());
|
m_dfs.push_back(dfs_info());
|
||||||
m_dfs.push_back(dfs_info());
|
m_dfs.push_back(dfs_info());
|
||||||
|
m_lits.push_back(lit_info());
|
||||||
|
m_lits.push_back(lit_info());
|
||||||
|
m_prefix.push_back(prefix());
|
||||||
|
m_freevars.insert(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
|
@ -642,8 +729,9 @@ namespace sat {
|
||||||
clause_vector::const_iterator end = s.m_clauses.end();
|
clause_vector::const_iterator end = s.m_clauses.end();
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
clause& c = *(*it);
|
clause& c = *(*it);
|
||||||
m_clauses.push_back(m_cls_allocator.mk_clause(c.size(), c.begin(), false));
|
clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false);
|
||||||
// TBD: add watch
|
m_clauses.push_back(c1);
|
||||||
|
attach_clause(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy units
|
// copy units
|
||||||
|
@ -655,17 +743,37 @@ namespace sat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void push(literal lit) {
|
// ------------------------------------
|
||||||
|
// search
|
||||||
|
|
||||||
|
void push(literal lit, search_mode mode) {
|
||||||
m_binary_trail_lim.push_back(m_binary_trail.size());
|
m_binary_trail_lim.push_back(m_binary_trail.size());
|
||||||
m_units_lim.push_back(m_units.size());
|
m_units_lim.push_back(m_units.size());
|
||||||
m_trail_lim.push_back(m_trail.size());
|
m_trail_lim.push_back(m_trail.size());
|
||||||
|
m_retired_clause_lim.push_back(m_retired_clauses.size());
|
||||||
m_qhead_lim.push_back(m_qhead);
|
m_qhead_lim.push_back(m_qhead);
|
||||||
m_trail.push_back(lit);
|
m_trail.push_back(lit);
|
||||||
|
m_search_modes.push_back(m_search_mode);
|
||||||
|
m_search_mode = mode;
|
||||||
assign(lit);
|
assign(lit);
|
||||||
propagate();
|
propagate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop() {
|
void pop() {
|
||||||
|
m_inconsistent = false;
|
||||||
|
|
||||||
|
// search mode
|
||||||
|
m_search_mode = m_search_modes.back();
|
||||||
|
m_search_modes.pop_back();
|
||||||
|
|
||||||
|
// unretire clauses
|
||||||
|
unsigned rsz = m_retired_clause_lim.back();
|
||||||
|
for (unsigned i = rsz; i < m_retired_clauses.size(); ++i) {
|
||||||
|
attach_clause(*m_retired_clauses[i]);
|
||||||
|
}
|
||||||
|
m_retired_clauses.resize(rsz);
|
||||||
|
m_retired_clause_lim.pop_back();
|
||||||
|
|
||||||
// remove local binary clauses
|
// remove local binary clauses
|
||||||
unsigned old_sz = m_binary_trail_lim.back();
|
unsigned old_sz = m_binary_trail_lim.back();
|
||||||
m_binary_trail_lim.pop_back();
|
m_binary_trail_lim.pop_back();
|
||||||
|
@ -673,24 +781,31 @@ namespace sat {
|
||||||
del_binary(m_binary_trail[i]);
|
del_binary(m_binary_trail[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// undo assignments
|
||||||
|
for (unsigned i = m_trail.size(); i > m_trail_lim.size(); ) {
|
||||||
|
--i;
|
||||||
|
literal l = m_trail[i];
|
||||||
|
m_freevars.insert(l.var());
|
||||||
|
m_assignment[l.index()] = l_undef;
|
||||||
|
m_assignment[(~l).index()] = l_undef;
|
||||||
|
}
|
||||||
|
m_trail.shrink(m_trail_lim.size()); // reset assignment.
|
||||||
|
m_trail_lim.pop_back();
|
||||||
|
|
||||||
// add implied binary clauses
|
// add implied binary clauses
|
||||||
unsigned new_unit_sz = m_units_lim.back();
|
unsigned new_unit_sz = m_units_lim.back();
|
||||||
for (unsigned i = new_unit_sz; i < m_units.size(); ++i) {
|
for (unsigned i = new_unit_sz; i < m_units.size(); ++i) {
|
||||||
add_binary(~m_trail.back(), m_units[i]);
|
try_add_binary(~m_trail.back(), m_units[i]);
|
||||||
}
|
}
|
||||||
m_units.shrink(new_unit_sz);
|
m_units.shrink(new_unit_sz);
|
||||||
m_units_lim.pop_back();
|
m_units_lim.pop_back();
|
||||||
m_trail.shrink(m_trail_lim.size()); // reset assignment.
|
|
||||||
m_trail_lim.pop_back();
|
// reset propagation queue
|
||||||
m_qhead_lim.pop_back();
|
m_qhead_lim.pop_back();
|
||||||
m_qhead = m_qhead_lim.back();
|
m_qhead = m_qhead_lim.back();
|
||||||
|
|
||||||
m_inconsistent = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned diff() const { return m_units.size() - m_units_lim.back(); }
|
float mix_diff(float l, float r) const { return l + r + (1 << 10) * l * r; }
|
||||||
|
|
||||||
unsigned mix_diff(unsigned l, unsigned r) const { return l + r + (1 << 10) * l * r; }
|
|
||||||
|
|
||||||
clause const& get_clause(watch_list::iterator it) const {
|
clause const& get_clause(watch_list::iterator it) const {
|
||||||
clause_offset cls_off = it->get_clause_offset();
|
clause_offset cls_off = it->get_clause_offset();
|
||||||
|
@ -715,6 +830,7 @@ namespace sat {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
case watched::TERNARY: {
|
case watched::TERNARY: {
|
||||||
|
UNREACHABLE(); // we avoid adding ternary clauses for now.
|
||||||
literal l1 = it->get_literal1();
|
literal l1 = it->get_literal1();
|
||||||
literal l2 = it->get_literal2();
|
literal l2 = it->get_literal2();
|
||||||
lbool val1 = value(l1);
|
lbool val1 = value(l1);
|
||||||
|
@ -731,7 +847,17 @@ namespace sat {
|
||||||
set_conflict();
|
set_conflict();
|
||||||
}
|
}
|
||||||
else if (val1 == l_undef && val2 == l_undef) {
|
else if (val1 == l_undef && val2 == l_undef) {
|
||||||
// TBD: the clause has become binary.
|
switch (m_search_mode) {
|
||||||
|
case searching:
|
||||||
|
detach_ternary(l, l1, l2);
|
||||||
|
try_add_binary(l1, l2);
|
||||||
|
break;
|
||||||
|
case lookahead1:
|
||||||
|
m_weighted_new_binaries += (*m_heur)[l1.index()] * (*m_heur)[l2.index()];
|
||||||
|
break;
|
||||||
|
case lookahead2:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*it2 = *it;
|
*it2 = *it;
|
||||||
it2++;
|
it2++;
|
||||||
|
@ -750,29 +876,37 @@ namespace sat {
|
||||||
}
|
}
|
||||||
literal * l_it = c.begin() + 2;
|
literal * l_it = c.begin() + 2;
|
||||||
literal * l_end = c.end();
|
literal * l_end = c.end();
|
||||||
unsigned found = 0;
|
bool found = false;
|
||||||
for (; l_it != l_end && found < 2; ++l_it) {
|
for (; l_it != l_end && !found; ++l_it) {
|
||||||
if (value(*l_it) != l_false) {
|
if (value(*l_it) != l_false) {
|
||||||
++found;
|
found = true;
|
||||||
if (found == 2) {
|
c[1] = *l_it;
|
||||||
break;
|
*l_it = ~l;
|
||||||
}
|
m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off));
|
||||||
else {
|
|
||||||
c[1] = *l_it;
|
|
||||||
*l_it = ~l;
|
|
||||||
m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found == 1) {
|
if (found) {
|
||||||
// TBD: clause has become binary
|
found = false;
|
||||||
|
for (; l_it != l_end && !found; ++l_it) {
|
||||||
|
found = value(*l_it) != l_false;
|
||||||
|
}
|
||||||
|
// normal clause was converted to a binary clause.
|
||||||
|
if (!found && value(c[1]) == l_undef && value(c[0]) == l_undef) {
|
||||||
|
switch (m_search_mode) {
|
||||||
|
case searching:
|
||||||
|
detach_clause(c);
|
||||||
|
try_add_binary(c[0], c[1]);
|
||||||
|
break;
|
||||||
|
case lookahead1:
|
||||||
|
m_weighted_new_binaries += (*m_heur)[c[0].index()]* (*m_heur)[c[1].index()];
|
||||||
|
break;
|
||||||
|
case lookahead2:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (found > 1) {
|
if (value(c[0]) == l_false) {
|
||||||
// not a binary clause
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (value(c[0]) == l_false) {
|
|
||||||
set_conflict();
|
set_conflict();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -829,41 +963,57 @@ namespace sat {
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TBD:
|
||||||
|
// Handle scope properly for nested implications.
|
||||||
|
// Suppose u -> v, and u -> w and we process v first, then the
|
||||||
|
// consequences of v should remain when processing u.
|
||||||
|
// March and sat11.w solve this by introducing timestamps on truth values.
|
||||||
|
// regular push/pop doesn't really work here: we basically need a traversal of the
|
||||||
|
// lookahead tree and push/pop according to that (or adapt timestamps)
|
||||||
|
//
|
||||||
bool choose1(literal& l) {
|
bool choose1(literal& l) {
|
||||||
|
pre_select();
|
||||||
l = null_literal;
|
l = null_literal;
|
||||||
if (m_lookahead.empty()) {
|
if (m_lookahead.empty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
unsigned h = 0, count = 1;
|
float h = 0;
|
||||||
for (unsigned i = 0; i < m_lookahead.size(); ++i) {
|
unsigned count = 1;
|
||||||
|
for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) {
|
||||||
literal lit = m_lookahead[i].m_lit;
|
literal lit = m_lookahead[i].m_lit;
|
||||||
|
if (value(lit) != l_undef) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SASSERT(value(lit) == l_undef);
|
||||||
|
SASSERT(!inconsistent());
|
||||||
|
|
||||||
push(lit);
|
reset_wnb(lit);
|
||||||
if (do_double()) double_look();
|
push(lit, lookahead1);
|
||||||
|
do_double(lit);
|
||||||
if (inconsistent()) {
|
if (inconsistent()) {
|
||||||
pop();
|
pop();
|
||||||
assign(~lit);
|
assign(~lit);
|
||||||
if (do_double()) double_look();
|
propagate();
|
||||||
if (inconsistent()) return true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
unsigned diff1 = diff();
|
update_wnb(lit);
|
||||||
|
float diff1 = m_weighted_new_binaries;
|
||||||
pop();
|
pop();
|
||||||
|
|
||||||
push(~lit);
|
reset_wnb(~lit);
|
||||||
if (do_double()) double_look();
|
push(~lit, lookahead1);
|
||||||
bool unsat2 = inconsistent();
|
do_double(~lit);
|
||||||
unsigned diff2 = diff();
|
if (inconsistent()) {
|
||||||
pop();
|
pop();
|
||||||
|
|
||||||
if (unsat2) {
|
|
||||||
assign(lit);
|
assign(lit);
|
||||||
|
propagate();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
update_wnb(~lit);
|
||||||
|
float diff2 = m_weighted_new_binaries;
|
||||||
|
pop();
|
||||||
|
|
||||||
unsigned mixd = mix_diff(diff1, diff2);
|
float mixd = mix_diff(diff1, diff2);
|
||||||
|
|
||||||
|
|
||||||
if (mixd > h || (mixd == h && s.m_rand(count) == 0)) {
|
if (mixd > h || (mixd == h && s.m_rand(count) == 0)) {
|
||||||
CTRACE("sat", l != null_literal, tout << lit << " diff1: " << diff1 << " diff2: " << diff2 << "\n";);
|
CTRACE("sat", l != null_literal, tout << lit << " diff1: " << diff1 << " diff2: " << diff2 << "\n";);
|
||||||
|
@ -872,7 +1022,30 @@ namespace sat {
|
||||||
l = diff1 < diff2 ? lit : ~lit;
|
l = diff1 < diff2 ? lit : ~lit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return l != null_literal;
|
return l != null_literal || inconsistent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_wnb(literal l, float f) { m_lits[l.index()].m_wnb = f; }
|
||||||
|
void inc_wnb(literal l, float f) { m_lits[l.index()].m_wnb += f; }
|
||||||
|
float get_wnb(literal l) const { return m_lits[l.index()].m_wnb; }
|
||||||
|
bool dl_enabled(literal l) const { return m_lits[l.index()].m_double_lookahead != m_istamp_id; }
|
||||||
|
void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; }
|
||||||
|
|
||||||
|
void reset_wnb(literal l) {
|
||||||
|
m_weighted_new_binaries = 0;
|
||||||
|
|
||||||
|
// inherit propagation effect from parent.
|
||||||
|
literal p = get_parent(l);
|
||||||
|
set_wnb(l, p == null_literal ? 0 : get_wnb(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_wnb(literal l) {
|
||||||
|
if (m_weighted_new_binaries == 0) {
|
||||||
|
// TBD autarky
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
inc_wnb(l, m_weighted_new_binaries);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void double_look() {
|
void double_look() {
|
||||||
|
@ -881,7 +1054,7 @@ namespace sat {
|
||||||
literal lit = m_lookahead[i].m_lit;
|
literal lit = m_lookahead[i].m_lit;
|
||||||
if (value(lit) != l_undef) continue;
|
if (value(lit) != l_undef) continue;
|
||||||
|
|
||||||
push(lit);
|
push(lit, lookahead2);
|
||||||
unsat = inconsistent();
|
unsat = inconsistent();
|
||||||
pop();
|
pop();
|
||||||
if (unsat) {
|
if (unsat) {
|
||||||
|
@ -890,7 +1063,7 @@ namespace sat {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
push(~lit);
|
push(~lit, lookahead2);
|
||||||
unsat = inconsistent();
|
unsat = inconsistent();
|
||||||
pop();
|
pop();
|
||||||
if (unsat) {
|
if (unsat) {
|
||||||
|
@ -898,7 +1071,6 @@ namespace sat {
|
||||||
assign(lit);
|
assign(lit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update_delta_trigger();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_fixed(literal l) const { return value(l) != l_undef; }
|
bool is_fixed(literal l) const { return value(l) != l_undef; }
|
||||||
|
@ -906,6 +1078,7 @@ namespace sat {
|
||||||
bool is_true(literal l) const { return value(l) == l_true; }
|
bool is_true(literal l) const { return value(l) == l_true; }
|
||||||
void set_conflict() { m_inconsistent = true; }
|
void set_conflict() { m_inconsistent = true; }
|
||||||
lbool value(literal l) const { return static_cast<lbool>(m_assignment[l.index()]); }
|
lbool value(literal l) const { return static_cast<lbool>(m_assignment[l.index()]); }
|
||||||
|
lbool value(bool_var v) const { return value(literal(v, false)); }
|
||||||
unsigned scope_lvl() const { return m_trail_lim.size(); }
|
unsigned scope_lvl() const { return m_trail_lim.size(); }
|
||||||
|
|
||||||
void assign(literal l) {
|
void assign(literal l) {
|
||||||
|
@ -919,14 +1092,13 @@ namespace sat {
|
||||||
m_assignment[l.index()] = l.sign() ? l_false : l_true;
|
m_assignment[l.index()] = l.sign() ? l_false : l_true;
|
||||||
m_assignment[(~l).index()] = l.sign() ? l_false : l_true;
|
m_assignment[(~l).index()] = l.sign() ? l_false : l_true;
|
||||||
m_trail.push_back(l);
|
m_trail.push_back(l);
|
||||||
|
m_freevars.remove(l.var());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_inconsistent() { m_inconsistent = true; }
|
|
||||||
bool inconsistent() { return m_inconsistent; }
|
bool inconsistent() { return m_inconsistent; }
|
||||||
|
|
||||||
|
|
||||||
void select_variables(literal_vector& P) {
|
void select_variables(literal_vector& P) {
|
||||||
for (unsigned i = 0; i < s.num_vars(); ++i) {
|
for (unsigned i = 0; i < s.num_vars(); ++i) {
|
||||||
if (value(literal(i,false)) == l_undef) {
|
if (value(literal(i,false)) == l_undef) {
|
||||||
|
@ -935,19 +1107,16 @@ namespace sat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool do_double() {
|
void do_double(literal l) {
|
||||||
return !inconsistent() && diff() > m_delta_trigger;
|
if (!inconsistent() && scope_lvl() > 0 && dl_enabled(l)) {
|
||||||
}
|
if (get_wnb(l) > m_delta_trigger) {
|
||||||
|
double_look();
|
||||||
void update_delta_trigger() {
|
m_delta_trigger = get_wnb(l);
|
||||||
if (inconsistent()) {
|
dl_disable(l);
|
||||||
m_delta_trigger -= (1 - m_config.m_dl_success) / m_config.m_dl_success;
|
}
|
||||||
}
|
else {
|
||||||
else {
|
m_delta_trigger *= m_config.m_delta_rho;
|
||||||
m_delta_trigger += 1;
|
}
|
||||||
}
|
|
||||||
if (m_delta_trigger >= s.num_vars()) {
|
|
||||||
// reset it.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -961,8 +1130,9 @@ namespace sat {
|
||||||
|
|
||||||
lbool search() {
|
lbool search() {
|
||||||
literal_vector trail;
|
literal_vector trail;
|
||||||
|
m_search_mode = searching;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
inc_istamp();
|
||||||
s.checkpoint();
|
s.checkpoint();
|
||||||
literal l = choose();
|
literal l = choose();
|
||||||
if (inconsistent()) {
|
if (inconsistent()) {
|
||||||
|
@ -973,7 +1143,7 @@ namespace sat {
|
||||||
return l_true;
|
return l_true;
|
||||||
}
|
}
|
||||||
TRACE("sat", tout << "choose: " << l << " " << trail << "\n";);
|
TRACE("sat", tout << "choose: " << l << " " << trail << "\n";);
|
||||||
push(l);
|
push(l, searching);
|
||||||
trail.push_back(l);
|
trail.push_back(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -782,7 +782,7 @@ namespace sat {
|
||||||
pop_to_base_level();
|
pop_to_base_level();
|
||||||
IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";);
|
IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";);
|
||||||
SASSERT(at_base_lvl());
|
SASSERT(at_base_lvl());
|
||||||
if (m_config.m_num_threads > 1 && !m_par) {
|
if ((m_config.m_num_threads > 1 || m_local_search) && !m_par) {
|
||||||
return check_par(num_lits, lits);
|
return check_par(num_lits, lits);
|
||||||
}
|
}
|
||||||
flet<bool> _searching(m_searching, true);
|
flet<bool> _searching(m_searching, true);
|
||||||
|
@ -854,9 +854,17 @@ namespace sat {
|
||||||
ERROR_EX
|
ERROR_EX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
local_search& solver::init_local_search() {
|
||||||
|
if (!m_local_search) {
|
||||||
|
m_local_search = alloc(local_search, *this);
|
||||||
|
}
|
||||||
|
return *m_local_search.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
lbool solver::check_par(unsigned num_lits, literal const* lits) {
|
lbool solver::check_par(unsigned num_lits, literal const* lits) {
|
||||||
int num_threads = static_cast<int>(m_config.m_num_threads);
|
int num_threads = static_cast<int>(m_config.m_num_threads);
|
||||||
int num_extra_solvers = num_threads - 1;
|
int num_extra_solvers = num_threads - 1 + (m_local_search ? 1 : 0);
|
||||||
sat::parallel par(*this);
|
sat::parallel par(*this);
|
||||||
par.reserve(num_threads, 1 << 12);
|
par.reserve(num_threads, 1 << 12);
|
||||||
par.init_solvers(*this, num_extra_solvers);
|
par.init_solvers(*this, num_extra_solvers);
|
||||||
|
@ -870,7 +878,10 @@ namespace sat {
|
||||||
for (int i = 0; i < num_threads; ++i) {
|
for (int i = 0; i < num_threads; ++i) {
|
||||||
try {
|
try {
|
||||||
lbool r = l_undef;
|
lbool r = l_undef;
|
||||||
if (i < num_extra_solvers) {
|
if (m_local_search && i + 1 == num_extra_solvers) {
|
||||||
|
r = m_local_search->check(num_lits, lits);
|
||||||
|
}
|
||||||
|
else if (i < num_extra_solvers) {
|
||||||
r = par.get_solver(i).check(num_lits, lits);
|
r = par.get_solver(i).check(num_lits, lits);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -886,6 +897,9 @@ namespace sat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (first) {
|
if (first) {
|
||||||
|
if (m_local_search) {
|
||||||
|
m_local_search->cancel();
|
||||||
|
}
|
||||||
for (int j = 0; j < num_extra_solvers; ++j) {
|
for (int j = 0; j < num_extra_solvers; ++j) {
|
||||||
if (i != j) {
|
if (i != j) {
|
||||||
par.cancel_solver(j);
|
par.cancel_solver(j);
|
||||||
|
|
|
@ -35,6 +35,7 @@ Revision History:
|
||||||
#include"sat_mus.h"
|
#include"sat_mus.h"
|
||||||
#include"sat_drat.h"
|
#include"sat_drat.h"
|
||||||
#include"sat_parallel.h"
|
#include"sat_parallel.h"
|
||||||
|
#include"sat_local_search.h"
|
||||||
#include"params.h"
|
#include"params.h"
|
||||||
#include"statistics.h"
|
#include"statistics.h"
|
||||||
#include"stopwatch.h"
|
#include"stopwatch.h"
|
||||||
|
@ -89,6 +90,7 @@ namespace sat {
|
||||||
probing m_probing;
|
probing m_probing;
|
||||||
mus m_mus; // MUS for minimal core extraction
|
mus m_mus; // MUS for minimal core extraction
|
||||||
drat m_drat; // DRAT for generating proofs
|
drat m_drat; // DRAT for generating proofs
|
||||||
|
scoped_ptr<local_search> m_local_search;
|
||||||
bool m_inconsistent;
|
bool m_inconsistent;
|
||||||
bool m_searching;
|
bool m_searching;
|
||||||
// A conflict is usually a single justification. That is, a justification
|
// A conflict is usually a single justification. That is, a justification
|
||||||
|
@ -460,6 +462,9 @@ namespace sat {
|
||||||
|
|
||||||
lbool get_consequences(literal_vector const& assms, bool_var_vector const& vars, vector<literal_vector>& conseq);
|
lbool get_consequences(literal_vector const& assms, bool_var_vector const& vars, vector<literal_vector>& conseq);
|
||||||
|
|
||||||
|
// initialize and retrieve local search.
|
||||||
|
local_search& init_local_search();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
typedef hashtable<unsigned, u_hash, u_eq> index_set;
|
typedef hashtable<unsigned, u_hash, u_eq> index_set;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue