mirror of
https://github.com/Z3Prover/z3
synced 2025-04-08 10:25:18 +00:00
testing lookahead
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
690689424d
commit
42deeb3498
|
@ -92,6 +92,7 @@ add_executable(test-z3
|
|||
rational.cpp
|
||||
rcf.cpp
|
||||
region.cpp
|
||||
sat_lookahead.cpp
|
||||
sat_user_scope.cpp
|
||||
simple_parser.cpp
|
||||
simplex.cpp
|
||||
|
|
|
@ -709,6 +709,37 @@ namespace sat {
|
|||
return result;
|
||||
}
|
||||
|
||||
void card_extension::find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes) {
|
||||
literal_set slits(lits);
|
||||
bool change = false;
|
||||
for (unsigned i = 0; i < m_constraints.size(); ++i) {
|
||||
card& c = *m_constraints[i];
|
||||
if (c.size() == c.k() + 1) {
|
||||
literal_vector mux;
|
||||
for (unsigned j = 0; j < c.size(); ++j) {
|
||||
literal lit = ~c[j];
|
||||
if (slits.contains(lit)) {
|
||||
mux.push_back(lit);
|
||||
}
|
||||
}
|
||||
if (mux.size() <= 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < mux.size(); ++j) {
|
||||
slits.remove(mux[j]);
|
||||
}
|
||||
change = true;
|
||||
mutexes.push_back(mux);
|
||||
}
|
||||
}
|
||||
if (!change) return;
|
||||
literal_set::iterator it = slits.begin(), end = slits.end();
|
||||
lits.reset();
|
||||
for (; it != end; ++it) {
|
||||
lits.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void card_extension::display_watch(std::ostream& out, bool_var v, bool sign) const {
|
||||
watch const* w = m_var_infos[v].m_lit_watch[sign];
|
||||
|
@ -957,7 +988,6 @@ namespace sat {
|
|||
tout << lits << "\n";);
|
||||
return value < p.m_k;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -163,6 +163,7 @@ namespace sat {
|
|||
virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const;
|
||||
virtual void collect_statistics(statistics& st) const;
|
||||
virtual extension* copy(solver* s);
|
||||
virtual void find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes);
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -113,9 +113,9 @@ namespace sat {
|
|||
m_minimize_lemmas = p.minimize_lemmas();
|
||||
m_core_minimize = p.core_minimize();
|
||||
m_core_minimize_partial = p.core_minimize_partial();
|
||||
m_drat = p.drat() && p.threads() == 1;
|
||||
m_drat_check = p.drat_check();
|
||||
m_drat_file = p.drat_file();
|
||||
m_drat = (m_drat_check || m_drat_file != symbol("")) && p.threads() == 1;
|
||||
m_dyn_sub_res = p.dyn_sub_res();
|
||||
}
|
||||
|
||||
|
|
|
@ -151,8 +151,6 @@ namespace sat {
|
|||
break;
|
||||
default:
|
||||
SASSERT(*it == &c);
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
if (j < sz) {
|
||||
if (m_solver.m_config.m_drat) m_solver.m_drat.del(c);
|
||||
c.shrink(j);
|
||||
|
@ -162,10 +160,12 @@ namespace sat {
|
|||
c.update_approx();
|
||||
|
||||
DEBUG_CODE({
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
for (unsigned i = 0; i < j; i++) {
|
||||
SASSERT(c[i] == norm(roots, c[i]));
|
||||
} });
|
||||
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
if (!c.frozen()) {
|
||||
m_solver.attach_clause(c);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ namespace sat {
|
|||
virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0;
|
||||
virtual void collect_statistics(statistics& st) const = 0;
|
||||
virtual extension* copy(solver* s) = 0;
|
||||
virtual void find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes) = 0;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
394
src/sat/sat_lookahead.h
Normal file
394
src/sat/sat_lookahead.h
Normal file
|
@ -0,0 +1,394 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_lookahead.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Lookahead SAT solver in the style of March.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2017-2-11
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _SAT_LOOKAHEAD_H_
|
||||
#define _SAT_LOOKAHEAD_H_
|
||||
|
||||
namespace sat {
|
||||
class lookahead {
|
||||
solver& s;
|
||||
|
||||
struct config {
|
||||
double m_dl_success;
|
||||
};
|
||||
|
||||
config m_config;
|
||||
double m_delta_trigger;
|
||||
literal_vector m_trail;
|
||||
literal_vector m_units;
|
||||
unsigned_vector m_units_lim;
|
||||
unsigned_vector m_learned_lim;
|
||||
|
||||
|
||||
void init() {
|
||||
m_delta_trigger = s.num_vars()/10;
|
||||
m_config.m_dl_success = 0.8;
|
||||
}
|
||||
|
||||
void push(literal lit) {
|
||||
m_learned_lim.push_back(s.m_learned.size());
|
||||
m_units_lim.push_back(m_units.size());
|
||||
m_trail.push_back(lit);
|
||||
s.push();
|
||||
assign(lit);
|
||||
}
|
||||
|
||||
void pop() {
|
||||
s.pop(1);
|
||||
unsigned old_sz = m_learned_lim.back();
|
||||
m_learned_lim.pop_back();
|
||||
for (unsigned i = old_sz; i < s.m_learned.size(); ++i) {
|
||||
clause* r = s.m_learned[i];
|
||||
s.dettach_clause(*r);
|
||||
s.m_cls_allocator.del_clause(r);
|
||||
}
|
||||
s.m_learned.shrink(old_sz);
|
||||
literal lits[2] = { m_trail.back(), null_literal };
|
||||
unsigned new_unit_sz = m_units_lim.back();
|
||||
for (unsigned i = m_units.size(); i > new_unit_sz; ) {
|
||||
--i;
|
||||
lits[1] = m_units[i];
|
||||
clause * r = s.m_cls_allocator.mk_clause(2, lits, true);
|
||||
s.m_learned.push_back(r);
|
||||
}
|
||||
m_units.shrink(new_unit_sz);
|
||||
m_units_lim.pop_back();
|
||||
m_trail.pop_back();
|
||||
}
|
||||
|
||||
unsigned diff(unsigned value0) const {
|
||||
unsigned value1 = get_state_value();
|
||||
SASSERT(value1 >= value0);
|
||||
return value1 - value0;
|
||||
}
|
||||
|
||||
unsigned mix_diff(unsigned l, unsigned r) const {
|
||||
return l + r + (1 << 10) * l * r;
|
||||
}
|
||||
|
||||
void get_resolvent_units(literal lit) {
|
||||
if (inconsistent()) return;
|
||||
for (unsigned i = s.m_trail.size(); i > 0; ) {
|
||||
--i;
|
||||
literal l = s.m_trail[i];
|
||||
if (l == lit) break;
|
||||
SASSERT(s.lvl(l) == s.scope_lvl());
|
||||
watch_list& wlist = s.m_watches[(~l).index()];
|
||||
watch_list::iterator it = wlist.begin(), end = wlist.end();
|
||||
for (; it != end; ++it) {
|
||||
switch (it->get_kind()) {
|
||||
case watched::TERNARY:
|
||||
if (s.value(it->get_literal1()) == l_false &&
|
||||
s.value(it->get_literal()) == l_false) {
|
||||
m_units.push_back(l);
|
||||
goto done_watch_list;
|
||||
}
|
||||
break;
|
||||
case watched::CLAUSE: {
|
||||
clause_offset cls_off = it->get_clause_offset();
|
||||
clause & c = *(s.m_cls_allocator.get_clause(cls_off));
|
||||
if (c.size() == 2) break;
|
||||
SASSERT(c.size() > 2);
|
||||
if (c[0] == l && s.value(c[1]) == l_false) {
|
||||
DEBUG_CODE(for (unsigned j = 2; j < c.size(); ++j) SASSERT(s.value(c[j]) == l_false););
|
||||
m_units.push_back(l);
|
||||
goto done_watch_list;
|
||||
}
|
||||
if (c[1] == l && s.value(c[0]) == l_false) {
|
||||
DEBUG_CODE(for (unsigned j = 2; j < c.size(); ++j) SASSERT(s.value(c[j]) == l_false););
|
||||
m_units.push_back(l);
|
||||
goto done_watch_list;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
done_watch_list:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
literal choose() {
|
||||
literal l;
|
||||
while (!choose1(l)) {};
|
||||
return l;
|
||||
}
|
||||
|
||||
unsigned get_state_value() const {
|
||||
return s.m_learned.size();
|
||||
}
|
||||
|
||||
bool choose1(literal& l) {
|
||||
literal_vector P;
|
||||
pre_select(P);
|
||||
l = null_literal;
|
||||
if (P.empty()) {
|
||||
return true;
|
||||
}
|
||||
unsigned value0 = get_state_value();
|
||||
unsigned h = 0, count = 1;
|
||||
literal_vector& units = m_units;;
|
||||
for (unsigned i = 0; i < P.size(); ++i) {
|
||||
literal lit = P[i];
|
||||
|
||||
push(lit);
|
||||
if (do_double(value0)) double_look();
|
||||
if (inconsistent()) {
|
||||
pop();
|
||||
assign(~lit);
|
||||
if (do_double(value0)) double_look();
|
||||
if (inconsistent()) return true;
|
||||
continue;
|
||||
}
|
||||
unsigned diff1 = diff(value0);
|
||||
pop();
|
||||
|
||||
push(~lit);
|
||||
if (do_double(value0)) double_look();
|
||||
bool unsat2 = inconsistent();
|
||||
unsigned diff2 = diff(value0);
|
||||
pop();
|
||||
|
||||
if (unsat2) {
|
||||
assign(lit);
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned mixd = mix_diff(diff1, diff2);
|
||||
|
||||
if (mixd > h || (mixd == h && s.m_rand(count) == 0)) {
|
||||
h = mixd;
|
||||
l = diff1 < diff2 ? lit : ~lit;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return l != null_literal;
|
||||
}
|
||||
|
||||
void double_look() {
|
||||
literal_vector P;
|
||||
pre_select(P);
|
||||
for (unsigned i = 0; !inconsistent() && i < P.size(); ++i) {
|
||||
literal lit = P[i];
|
||||
|
||||
push(lit);
|
||||
bool unsat = inconsistent();
|
||||
pop();
|
||||
if (unsat) {
|
||||
assign(~lit);
|
||||
continue;
|
||||
}
|
||||
|
||||
push(~lit);
|
||||
unsat = inconsistent();
|
||||
pop();
|
||||
if (unsat) {
|
||||
assign(lit);
|
||||
}
|
||||
|
||||
}
|
||||
update_delta_trigger();
|
||||
}
|
||||
|
||||
void assign(literal l) {
|
||||
s.assign(l, justification());
|
||||
s.propagate(false);
|
||||
get_resolvent_units(l);
|
||||
}
|
||||
|
||||
bool inconsistent() { return s.inconsistent(); }
|
||||
|
||||
void pre_select(literal_vector& P) {
|
||||
select_variables(P);
|
||||
order_by_implication_trees(P);
|
||||
}
|
||||
|
||||
void order_by_implication_trees(literal_vector& P) {
|
||||
literal_set roots;
|
||||
literal_vector nodes, parent;
|
||||
|
||||
//
|
||||
// Extract binary clauses in watch list.
|
||||
// Produce implication graph between literals in P.
|
||||
//
|
||||
|
||||
for (unsigned i = 0; i < P.size(); ++i) {
|
||||
literal lit1 = P[i], lit2;
|
||||
|
||||
//
|
||||
// lit2 => lit1, where lit2 is a root.
|
||||
// make lit1 a root instead of lit2
|
||||
//
|
||||
|
||||
watch_list& wlist = s.m_watches[(~lit1).index()];
|
||||
watch_list::iterator it = wlist.begin(), end = wlist.end();
|
||||
lit2 = null_literal;
|
||||
for (; it != end; ++it) {
|
||||
switch (it->get_kind()) {
|
||||
case watched::BINARY:
|
||||
lit2 = it->get_literal();
|
||||
break;
|
||||
case watched::CLAUSE: {
|
||||
clause_offset cls_off = it->get_clause_offset();
|
||||
clause & c = *(s.m_cls_allocator.get_clause(cls_off));
|
||||
if (c.size() == 2) {
|
||||
if (c[0] == ~lit1) {
|
||||
lit2 = c[1];
|
||||
}
|
||||
else {
|
||||
SASSERT(c[1] == ~lit1);
|
||||
lit2 = c[0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (lit2 != null_literal && roots.contains(lit2)) {
|
||||
// lit2 => lit1
|
||||
// if lit2 is a root, put it under lit2
|
||||
parent.setx(lit2.index(), lit1, null_literal);
|
||||
roots.remove(lit2);
|
||||
roots.insert(lit1);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// lit1 => lit2.
|
||||
// if lit2 is a node, put lit1 above lit2
|
||||
//
|
||||
|
||||
it = s.m_watches[lit1.index()].begin();
|
||||
end = s.m_watches[lit1.index()].end();
|
||||
for (; it != end; ++it) {
|
||||
lit2 = null_literal;
|
||||
switch (it->get_kind()) {
|
||||
case watched::BINARY:
|
||||
lit2 = it->get_literal();
|
||||
break;
|
||||
case watched::CLAUSE: {
|
||||
clause_offset cls_off = it->get_clause_offset();
|
||||
clause & c = *(s.m_cls_allocator.get_clause(cls_off));
|
||||
if (c.size() == 2) {
|
||||
if (c[0] == lit1) {
|
||||
lit2 = c[1];
|
||||
}
|
||||
else {
|
||||
SASSERT(c[1] == lit1);
|
||||
lit2 = c[0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (lit2 != null_literal && nodes.contains(lit2)) {
|
||||
// lit1 => lit2
|
||||
parent.setx(lit1.index(), lit2, null_literal);
|
||||
nodes.insert(lit1);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
std::cout << "no parents or children of literal " << lit1 << "\n";
|
||||
nodes.push_back(lit1);
|
||||
roots.insert(lit1);
|
||||
found:
|
||||
;
|
||||
}
|
||||
std::cout << "implication trees\n";
|
||||
for (unsigned i = 0; i < parent.size(); ++i) {
|
||||
literal p = parent[i];
|
||||
if (p != null_literal) {
|
||||
std::cout << to_literal(i) << " |-> " << p << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void select_variables(literal_vector& P) {
|
||||
for (unsigned i = 0; i < s.num_vars(); ++i) {
|
||||
if (s.value(i) == l_undef) {
|
||||
P.push_back(literal(i, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool do_double(unsigned value0) {
|
||||
unsigned value1 = get_state_value();
|
||||
return !inconsistent() && value1 - value0 > m_delta_trigger;
|
||||
}
|
||||
|
||||
void update_delta_trigger() {
|
||||
if (inconsistent()) {
|
||||
m_delta_trigger -= (1 - m_config.m_dl_success) / m_config.m_dl_success;
|
||||
}
|
||||
else {
|
||||
m_delta_trigger += 1;
|
||||
}
|
||||
if (m_delta_trigger >= s.num_vars()) {
|
||||
// reset it.
|
||||
}
|
||||
}
|
||||
|
||||
lbool search() {
|
||||
literal_vector trail;
|
||||
|
||||
#define BACKTRACK \
|
||||
if (inconsistent()) { \
|
||||
if (trail.empty()) return l_false; \
|
||||
pop(); \
|
||||
assign(~trail.back()); \
|
||||
trail.pop_back(); \
|
||||
continue; \
|
||||
} \
|
||||
|
||||
while (true) {
|
||||
s.checkpoint();
|
||||
BACKTRACK;
|
||||
literal l = choose();
|
||||
TRACE("sat", tout << l << "\n";);
|
||||
BACKTRACK;
|
||||
if (l == null_literal) {
|
||||
return l_true;
|
||||
}
|
||||
push(l);
|
||||
trail.push_back(l);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
lookahead(solver& s) : s(s) {
|
||||
init();
|
||||
}
|
||||
|
||||
lbool check() {
|
||||
return search();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -185,12 +185,17 @@ namespace sat {
|
|||
unsigned owner = s.m_par_id;
|
||||
while (m_pool.get_vector(owner, n, ptr)) {
|
||||
m_lits.reset();
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
m_lits.push_back(to_literal(ptr[i]));
|
||||
bool usable_clause = true;
|
||||
for (unsigned i = 0; usable_clause && i < n; ++i) {
|
||||
literal lit(to_literal(ptr[i]));
|
||||
m_lits.push_back(lit);
|
||||
usable_clause = lit.var() <= s.m_par_num_vars && !s.was_eliminated(lit.var());
|
||||
}
|
||||
IF_VERBOSE(3, verbose_stream() << s.m_par_id << ": retrieve " << m_lits << "\n";);
|
||||
SASSERT(n >= 2);
|
||||
s.mk_clause_core(m_lits.size(), m_lits.c_ptr(), true);
|
||||
if (usable_clause) {
|
||||
s.mk_clause_core(m_lits.size(), m_lits.c_ptr(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ def_module_params('sat',
|
|||
('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'),
|
||||
('threads', UINT, 1, 'number of parallel threads to use'),
|
||||
('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'),
|
||||
('drat', BOOL, False, 'produce DRAT proofs'),
|
||||
('drat.file', SYMBOL, '', 'file to dump DRAT proofs'),
|
||||
('drat.check', BOOL, False, 'build up internal proof and check'),
|
||||
))
|
||||
|
|
|
@ -35,6 +35,10 @@ namespace sat {
|
|||
void use_list::insert(clause & c) {
|
||||
unsigned sz = c.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if (m_use_list.size() <= c[i].index()) {
|
||||
std::cout << c[i] << "\n";
|
||||
std::cout << m_use_list.size() << "\n";
|
||||
}
|
||||
m_use_list[c[i].index()].insert(c);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -836,7 +836,7 @@ namespace sat {
|
|||
int num_threads = static_cast<int>(m_config.m_num_threads);
|
||||
int num_extra_solvers = num_threads - 1;
|
||||
sat::parallel par(*this);
|
||||
par.reserve(num_threads, 1 << 9);
|
||||
par.reserve(num_threads, 1 << 12);
|
||||
par.init_solvers(*this, num_extra_solvers);
|
||||
int finished_id = -1;
|
||||
std::string ex_msg;
|
||||
|
@ -3076,17 +3076,21 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
vector<unsigned_vector> _mutexes;
|
||||
literal_vector _lits(lits);
|
||||
if (m_ext) {
|
||||
m_ext->find_mutexes(_lits, mutexes);
|
||||
}
|
||||
unsigned_vector ps;
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
ps.push_back(lits[i].index());
|
||||
for (unsigned i = 0; i < _lits.size(); ++i) {
|
||||
ps.push_back(_lits[i].index());
|
||||
}
|
||||
mc.cliques(ps, _mutexes);
|
||||
for (unsigned i = 0; i < _mutexes.size(); ++i) {
|
||||
literal_vector lits;
|
||||
literal_vector clique;
|
||||
for (unsigned j = 0; j < _mutexes[i].size(); ++j) {
|
||||
lits.push_back(to_literal(_mutexes[i][j]));
|
||||
clique.push_back(to_literal(_mutexes[i][j]));
|
||||
}
|
||||
mutexes.push_back(lits);
|
||||
mutexes.push_back(clique);
|
||||
}
|
||||
return l_true;
|
||||
}
|
||||
|
|
|
@ -154,6 +154,7 @@ namespace sat {
|
|||
friend class drat;
|
||||
friend class card_extension;
|
||||
friend class parallel;
|
||||
friend class lookahead;
|
||||
friend struct mk_stat;
|
||||
public:
|
||||
solver(params_ref const & p, reslimit& l);
|
||||
|
|
|
@ -229,6 +229,7 @@ int main(int argc, char ** argv) {
|
|||
TST(model_evaluator);
|
||||
TST(get_consequences);
|
||||
TST(pb2bv);
|
||||
TST_ARGV(sat_lookahead);
|
||||
//TST_ARGV(hs);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue