3
0
Fork 0
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:
Nikolaj Bjorner 2017-02-12 11:49:07 -08:00
parent 690689424d
commit 42deeb3498
13 changed files with 456 additions and 15 deletions

View file

@ -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

View file

@ -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;
}
};

View file

@ -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);
};
};

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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
View 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

View file

@ -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);
}
}
}

View file

@ -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'),
))

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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);
}