mirror of
https://github.com/Z3Prover/z3
synced 2025-04-08 18:31:49 +00:00
fix transitive reduction bug, eliminate blocked tag on binary clauses, separate BIG structure from scc
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
commit
71c52396cb
|
@ -622,6 +622,9 @@ public:
|
|||
sort * const * get_domain() const { return m_domain; }
|
||||
sort * get_range() const { return m_range; }
|
||||
unsigned get_size() const { return get_obj_size(m_arity); }
|
||||
sort * const * begin() const { return get_domain(); }
|
||||
sort * const * end() const { return get_domain() + get_arity(); }
|
||||
|
||||
};
|
||||
|
||||
// -----------------------------------
|
||||
|
|
|
@ -20,20 +20,15 @@ Revision History:
|
|||
#include "ast/decl_collector.h"
|
||||
|
||||
void decl_collector::visit_sort(sort * n) {
|
||||
SASSERT(!m_visited.is_marked(n));
|
||||
family_id fid = n->get_family_id();
|
||||
if (m().is_uninterp(n))
|
||||
m_sorts.push_back(n);
|
||||
if (fid == m_dt_fid) {
|
||||
else if (fid == m_dt_fid) {
|
||||
m_sorts.push_back(n);
|
||||
|
||||
unsigned num_cnstr = m_dt_util.get_datatype_num_constructors(n);
|
||||
for (unsigned i = 0; i < num_cnstr; i++) {
|
||||
func_decl * cnstr = m_dt_util.get_datatype_constructors(n)->get(i);
|
||||
for (func_decl* cnstr : *m_dt_util.get_datatype_constructors(n)) {
|
||||
m_decls.push_back(cnstr);
|
||||
ptr_vector<func_decl> const & cnstr_acc = *m_dt_util.get_constructor_accessors(cnstr);
|
||||
unsigned num_cas = cnstr_acc.size();
|
||||
for (unsigned j = 0; j < num_cas; j++) {
|
||||
func_decl * accsr = cnstr_acc.get(j);
|
||||
for (func_decl * accsr : *m_dt_util.get_constructor_accessors(cnstr)) {
|
||||
m_decls.push_back(accsr);
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +48,7 @@ void decl_collector::visit_func(func_decl * n) {
|
|||
else
|
||||
m_decls.push_back(n);
|
||||
}
|
||||
m_visited.mark(n, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,11 +68,10 @@ void decl_collector::visit(ast* n) {
|
|||
if (!m_visited.is_marked(n)) {
|
||||
switch(n->get_kind()) {
|
||||
case AST_APP: {
|
||||
app * a = to_app(n);
|
||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||
m_todo.push_back(a->get_arg(i));
|
||||
for (expr * e : *to_app(n)) {
|
||||
m_todo.push_back(e);
|
||||
}
|
||||
m_todo.push_back(a->get_decl());
|
||||
m_todo.push_back(to_app(n)->get_decl());
|
||||
break;
|
||||
}
|
||||
case AST_QUANTIFIER: {
|
||||
|
@ -96,8 +91,8 @@ void decl_collector::visit(ast* n) {
|
|||
break;
|
||||
case AST_FUNC_DECL: {
|
||||
func_decl * d = to_func_decl(n);
|
||||
for (unsigned i = 0; i < d->get_arity(); ++i) {
|
||||
m_todo.push_back(d->get_domain(i));
|
||||
for (sort* srt : *d) {
|
||||
m_todo.push_back(srt);
|
||||
}
|
||||
m_todo.push_back(d->get_range());
|
||||
visit_func(d);
|
||||
|
|
|
@ -41,7 +41,7 @@ class decl_collector {
|
|||
|
||||
public:
|
||||
// if preds == true, then predicates are stored in a separate collection.
|
||||
decl_collector(ast_manager & m, bool preds=true);
|
||||
decl_collector(ast_manager & m, bool preds = true);
|
||||
ast_manager & m() { return m_manager; }
|
||||
|
||||
void visit_func(func_decl* n);
|
||||
|
|
|
@ -4,6 +4,7 @@ z3_add_component(sat
|
|||
dimacs.cpp
|
||||
sat_asymm_branch.cpp
|
||||
sat_bdd.cpp
|
||||
sat_big.cpp
|
||||
sat_clause.cpp
|
||||
sat_clause_set.cpp
|
||||
sat_clause_use_list.cpp
|
||||
|
|
|
@ -3158,12 +3158,9 @@ namespace sat {
|
|||
if (w.is_binary_clause() && is_marked(w.get_literal())) {
|
||||
++m_stats.m_num_bin_subsumes;
|
||||
// IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";);
|
||||
if (w.is_learned()) {
|
||||
if (!w.is_learned()) {
|
||||
c1.set_learned(false);
|
||||
}
|
||||
else if (w.is_blocked()) {
|
||||
w.set_unblocked();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (it != it2) {
|
||||
|
|
|
@ -19,7 +19,7 @@ Revision History:
|
|||
#include "sat/sat_asymm_branch.h"
|
||||
#include "sat/sat_asymm_branch_params.hpp"
|
||||
#include "sat/sat_solver.h"
|
||||
#include "sat/sat_scc.h"
|
||||
#include "sat/sat_big.h"
|
||||
#include "util/stopwatch.h"
|
||||
#include "util/trace.h"
|
||||
|
||||
|
@ -65,14 +65,14 @@ namespace sat {
|
|||
}
|
||||
};
|
||||
|
||||
bool asymm_branch::process(scc* scc) {
|
||||
bool asymm_branch::process(big* big) {
|
||||
unsigned elim0 = m_elim_literals;
|
||||
unsigned eliml0 = m_elim_learned_literals;
|
||||
for (unsigned i = 0; i < m_asymm_branch_rounds; ++i) {
|
||||
unsigned elim = m_elim_literals;
|
||||
if (scc) scc->init_big(true);
|
||||
process(scc, s.m_clauses);
|
||||
process(scc, s.m_learned);
|
||||
if (big) big->init_big(s, true);
|
||||
process(big, s.m_clauses);
|
||||
process(big, s.m_learned);
|
||||
s.propagate(false);
|
||||
if (s.m_inconsistent)
|
||||
break;
|
||||
|
@ -86,7 +86,7 @@ namespace sat {
|
|||
}
|
||||
|
||||
|
||||
void asymm_branch::process(scc* scc, clause_vector& clauses) {
|
||||
void asymm_branch::process(big* big, clause_vector& clauses) {
|
||||
int64 limit = -m_asymm_branch_limit;
|
||||
std::stable_sort(clauses.begin(), clauses.end(), clause_size_lt());
|
||||
m_counter -= clauses.size();
|
||||
|
@ -110,7 +110,7 @@ namespace sat {
|
|||
}
|
||||
s.checkpoint();
|
||||
clause & c = *(*it);
|
||||
if (scc ? !process_sampled(*scc, c) : !process(c)) {
|
||||
if (big ? !process_sampled(*big, c) : !process(c)) {
|
||||
continue; // clause was removed
|
||||
}
|
||||
*it2 = *it;
|
||||
|
@ -153,8 +153,8 @@ namespace sat {
|
|||
++counter;
|
||||
change = false;
|
||||
if (m_asymm_branch_sampled) {
|
||||
scc sc(s, m_params);
|
||||
if (process(&sc)) change = true;
|
||||
big big;
|
||||
if (process(&big)) change = true;
|
||||
}
|
||||
if (m_asymm_branch) {
|
||||
m_counter = 0;
|
||||
|
@ -188,40 +188,40 @@ namespace sat {
|
|||
}
|
||||
|
||||
struct asymm_branch::compare_left {
|
||||
scc& s;
|
||||
compare_left(scc& s): s(s) {}
|
||||
big& s;
|
||||
compare_left(big& s): s(s) {}
|
||||
bool operator()(literal u, literal v) const {
|
||||
return s.get_left(u) < s.get_left(v);
|
||||
}
|
||||
};
|
||||
|
||||
void asymm_branch::sort(scc& scc, clause const& c) {
|
||||
sort(scc, c.begin(), c.end());
|
||||
void asymm_branch::sort(big& big, clause const& c) {
|
||||
sort(big, c.begin(), c.end());
|
||||
}
|
||||
|
||||
void asymm_branch::sort(scc& scc, literal const* begin, literal const* end) {
|
||||
void asymm_branch::sort(big& big, literal const* begin, literal const* end) {
|
||||
m_pos.reset(); m_neg.reset();
|
||||
for (; begin != end; ++begin) {
|
||||
literal l = *begin;
|
||||
m_pos.push_back(l);
|
||||
m_neg.push_back(~l);
|
||||
}
|
||||
compare_left cmp(scc);
|
||||
compare_left cmp(big);
|
||||
std::sort(m_pos.begin(), m_pos.end(), cmp);
|
||||
std::sort(m_neg.begin(), m_neg.end(), cmp);
|
||||
}
|
||||
|
||||
bool asymm_branch::uhte(scc& scc, clause & c) {
|
||||
bool asymm_branch::uhte(big& big, clause & c) {
|
||||
unsigned pindex = 0, nindex = 0;
|
||||
literal lpos = m_pos[pindex++];
|
||||
literal lneg = m_neg[nindex++];
|
||||
while (true) {
|
||||
if (scc.get_left(lneg) > scc.get_left(lpos)) {
|
||||
if (big.get_left(lneg) > big.get_left(lpos)) {
|
||||
if (pindex == m_pos.size()) return false;
|
||||
lpos = m_pos[pindex++];
|
||||
}
|
||||
else if (scc.get_right(lneg) < scc.get_right(lpos) ||
|
||||
(m_pos.size() == 2 && (lpos == ~lneg || scc.get_parent(lpos) == lneg))) {
|
||||
else if (big.get_right(lneg) < big.get_right(lpos) ||
|
||||
(m_pos.size() == 2 && (lpos == ~lneg || big.get_parent(lpos) == lneg))) {
|
||||
if (nindex == m_neg.size()) return false;
|
||||
lneg = m_neg[nindex++];
|
||||
}
|
||||
|
@ -232,10 +232,10 @@ namespace sat {
|
|||
return false;
|
||||
}
|
||||
|
||||
void asymm_branch::minimize(scc& scc, literal_vector& lemma) {
|
||||
scc.ensure_big(true);
|
||||
sort(scc, lemma.begin(), lemma.end());
|
||||
uhle(scc);
|
||||
void asymm_branch::minimize(big& big, literal_vector& lemma) {
|
||||
big.ensure_big(s, true);
|
||||
sort(big, lemma.begin(), lemma.end());
|
||||
uhle(big);
|
||||
if (!m_to_delete.empty()) {
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < lemma.size(); ++i) {
|
||||
|
@ -249,14 +249,13 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
void asymm_branch::uhle(scc& scc) {
|
||||
void asymm_branch::uhle(big& big) {
|
||||
m_to_delete.reset();
|
||||
if (m_to_delete.empty()) {
|
||||
int right = scc.get_right(m_pos.back());
|
||||
int right = big.get_right(m_pos.back());
|
||||
for (unsigned i = m_pos.size() - 1; i-- > 0; ) {
|
||||
literal lit = m_pos[i];
|
||||
SASSERT(scc.get_left(lit) < scc.get_left(last));
|
||||
int right2 = scc.get_right(lit);
|
||||
int right2 = big.get_right(lit);
|
||||
if (right2 > right) {
|
||||
// lit => last, so lit can be deleted
|
||||
m_to_delete.push_back(lit);
|
||||
|
@ -267,10 +266,10 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
if (m_to_delete.empty()) {
|
||||
int right = scc.get_right(m_neg[0]);
|
||||
int right = big.get_right(m_neg[0]);
|
||||
for (unsigned i = 1; i < m_neg.size(); ++i) {
|
||||
literal lit = m_neg[i];
|
||||
int right2 = scc.get_right(lit);
|
||||
int right2 = big.get_right(lit);
|
||||
if (right > right2) {
|
||||
// ~first => ~lit
|
||||
m_to_delete.push_back(~lit);
|
||||
|
@ -282,8 +281,8 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
bool asymm_branch::uhle(scoped_detach& scoped_d, scc& scc, clause & c) {
|
||||
uhle(scc);
|
||||
bool asymm_branch::uhle(scoped_detach& scoped_d, big& big, clause & c) {
|
||||
uhle(big);
|
||||
if (!m_to_delete.empty()) {
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < c.size(); ++i) {
|
||||
|
@ -384,17 +383,17 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
bool asymm_branch::process_sampled(scc& scc, clause & c) {
|
||||
bool asymm_branch::process_sampled(big& big, clause & c) {
|
||||
scoped_detach scoped_d(s, c);
|
||||
sort(scc, c);
|
||||
sort(big, c);
|
||||
#if 0
|
||||
if (uhte(scc, c)) {
|
||||
if (uhte(big, c)) {
|
||||
++m_hidden_tautologies;
|
||||
scoped_d.del_clause();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return uhle(scoped_d, scc, c);
|
||||
return uhle(scoped_d, big, c);
|
||||
}
|
||||
|
||||
bool asymm_branch::process(clause & c) {
|
||||
|
|
|
@ -20,7 +20,7 @@ Revision History:
|
|||
#define SAT_ASYMM_BRANCH_H_
|
||||
|
||||
#include "sat/sat_types.h"
|
||||
#include "sat/sat_scc.h"
|
||||
#include "sat/sat_big.h"
|
||||
#include "util/statistics.h"
|
||||
#include "util/params.h"
|
||||
|
||||
|
@ -51,29 +51,29 @@ namespace sat {
|
|||
unsigned m_elim_learned_literals;
|
||||
unsigned m_hidden_tautologies;
|
||||
|
||||
literal_vector m_pos, m_neg; // literals (complements of literals) in clauses sorted by discovery time (m_left in scc).
|
||||
literal_vector m_pos, m_neg; // literals (complements of literals) in clauses sorted by discovery time (m_left in BIG).
|
||||
literal_vector m_to_delete;
|
||||
|
||||
struct compare_left;
|
||||
|
||||
void sort(scc& scc, literal const* begin, literal const* end);
|
||||
void sort(scc & scc, clause const& c);
|
||||
void sort(big& big, literal const* begin, literal const* end);
|
||||
void sort(big & big, clause const& c);
|
||||
|
||||
bool uhle(scoped_detach& scoped_d, scc & scc, clause & c);
|
||||
bool uhle(scoped_detach& scoped_d, big & big, clause & c);
|
||||
|
||||
void uhle(scc & scc);
|
||||
void uhle(big & big);
|
||||
|
||||
bool uhte(scc & scc, clause & c);
|
||||
bool uhte(big & big, clause & c);
|
||||
|
||||
bool re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz);
|
||||
|
||||
bool process(scc* scc);
|
||||
bool process(big* big);
|
||||
|
||||
bool process(clause & c);
|
||||
|
||||
bool process_sampled(scc& scc, clause & c);
|
||||
bool process_sampled(big& big, clause & c);
|
||||
|
||||
void process(scc* scc, clause_vector & c);
|
||||
void process(big* big, clause_vector & c);
|
||||
|
||||
bool process_all(clause & c);
|
||||
|
||||
|
@ -94,7 +94,7 @@ namespace sat {
|
|||
void collect_statistics(statistics & st) const;
|
||||
void reset_statistics();
|
||||
|
||||
void minimize(scc& scc, literal_vector& lemma);
|
||||
void minimize(big& big, literal_vector& lemma);
|
||||
|
||||
void init_search() { m_calls = 0; }
|
||||
|
||||
|
|
133
src/sat/sat_big.cpp
Normal file
133
src/sat/sat_big.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_big.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
binary implication graph structure.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2017-12-13.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "sat/sat_big.h"
|
||||
#include "sat/sat_solver.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
big::big() {}
|
||||
|
||||
void big::init_big(solver& s, bool learned) {
|
||||
m_num_vars = s.num_vars();
|
||||
unsigned num_lits = m_num_vars * 2;
|
||||
m_dag.reset();
|
||||
m_roots.reset();
|
||||
m_dag.resize(num_lits, 0);
|
||||
m_roots.resize(num_lits, true);
|
||||
literal_vector lits;
|
||||
SASSERT(num_lits == m_dag.size() && num_lits == m_roots.size());
|
||||
for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) {
|
||||
literal u = to_literal(l_idx);
|
||||
if (s.was_eliminated(u.var()))
|
||||
continue;
|
||||
auto& edges = m_dag[l_idx];
|
||||
for (watched const& w : s.get_wlist(l_idx)) {
|
||||
if (learned ? w.is_binary_clause() : w.is_binary_non_learned_clause()) {
|
||||
literal v = w.get_literal();
|
||||
m_roots[v.index()] = false;
|
||||
edges.push_back(v);
|
||||
}
|
||||
}
|
||||
shuffle<literal>(edges.size(), edges.c_ptr(), m_rand);
|
||||
}
|
||||
init_dfs_num(learned);
|
||||
}
|
||||
|
||||
struct big::pframe {
|
||||
literal m_parent;
|
||||
literal m_child;
|
||||
pframe(literal p, literal c):
|
||||
m_parent(p), m_child(c) {}
|
||||
literal child() const { return m_child; }
|
||||
literal parent() const { return m_parent; }
|
||||
};
|
||||
|
||||
void big::init_dfs_num(bool learned) {
|
||||
unsigned num_lits = m_num_vars * 2;
|
||||
m_left.reset();
|
||||
m_right.reset();
|
||||
m_root.reset();
|
||||
m_parent.reset();
|
||||
m_left.resize(num_lits, 0);
|
||||
m_right.resize(num_lits, -1);
|
||||
m_root.resize(num_lits, null_literal);
|
||||
m_parent.resize(num_lits, null_literal);
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
m_root[i] = to_literal(i);
|
||||
m_parent[i] = to_literal(i);
|
||||
}
|
||||
svector<pframe> todo;
|
||||
// retrieve literals that have no predecessors
|
||||
for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) {
|
||||
literal u(to_literal(l_idx));
|
||||
if (m_roots[u.index()]) {
|
||||
todo.push_back(pframe(null_literal, u));
|
||||
}
|
||||
}
|
||||
shuffle<pframe>(todo.size(), todo.c_ptr(), m_rand);
|
||||
int dfs_num = 0;
|
||||
while (!todo.empty()) {
|
||||
literal u = todo.back().child();
|
||||
if (m_left[u.index()] > 0) {
|
||||
// already visited
|
||||
if (m_right[u.index()] < 0) {
|
||||
m_right[u.index()] = ++dfs_num;
|
||||
}
|
||||
todo.pop_back();
|
||||
}
|
||||
else {
|
||||
SASSERT(m_left[u.index()] == 0);
|
||||
m_left[u.index()] = ++dfs_num;
|
||||
literal p = todo.back().parent();
|
||||
if (p != null_literal) {
|
||||
m_root[u.index()] = m_root[p.index()];
|
||||
m_parent[u.index()] = p;
|
||||
}
|
||||
for (literal v : m_dag[u.index()]) {
|
||||
if (m_left[v.index()] == 0) {
|
||||
todo.push_back(pframe(u, v));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
if (m_right[i] < 0) {
|
||||
VERIFY(m_left[i] == 0);
|
||||
m_left[i] = ++dfs_num;
|
||||
m_right[i] = ++dfs_num;
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
VERIFY(m_left[i] < m_right[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void big::display(std::ostream& out) const {
|
||||
unsigned idx = 0;
|
||||
for (auto& next : m_dag) {
|
||||
if (!next.empty()) {
|
||||
out << to_literal(idx) << " : " << m_left[idx] << ":" << m_right[idx] << " -> " << next << "\n";
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
55
src/sat/sat_big.h
Normal file
55
src/sat/sat_big.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_big.h
|
||||
|
||||
Abstract:
|
||||
|
||||
binary implication graph structure.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2017-12-13.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef SAT_BIG_H_
|
||||
#define SAT_BIG_H_
|
||||
|
||||
#include "sat/sat_types.h"
|
||||
#include "util/statistics.h"
|
||||
#include "util/params.h"
|
||||
|
||||
namespace sat {
|
||||
class solver;
|
||||
|
||||
class big {
|
||||
random_gen m_rand;
|
||||
unsigned m_num_vars;
|
||||
vector<literal_vector> m_dag;
|
||||
svector<bool> m_roots;
|
||||
svector<int> m_left, m_right;
|
||||
literal_vector m_root, m_parent;
|
||||
|
||||
void init_dfs_num(bool learned);
|
||||
struct pframe;
|
||||
|
||||
public:
|
||||
|
||||
big();
|
||||
void init_big(solver& s, bool learned);
|
||||
void ensure_big(solver& s, bool learned) { if (m_left.empty()) init_big(s, learned); }
|
||||
int get_left(literal l) const { return m_left[l.index()]; }
|
||||
int get_right(literal l) const { return m_right[l.index()]; }
|
||||
literal get_parent(literal l) const { return m_parent[l.index()]; }
|
||||
literal get_root(literal l) const { return m_root[l.index()]; }
|
||||
bool reaches(literal u, literal v) const { return m_left[u.index()] < m_left[v.index()] && m_right[v.index()] < m_right[u.index()]; }
|
||||
bool connected(literal u, literal v) const { return reaches(u, v) || reaches(~v, ~u); }
|
||||
void display(std::ostream& out) const;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
|
@ -87,8 +87,30 @@ namespace sat {
|
|||
else
|
||||
throw sat_param_exception("invalid reward type supplied: accepted heuristics are 'ternary', 'heuleu', 'unit' or 'heule_schur'");
|
||||
|
||||
if (p.lookahead_cube_cutoff() == symbol("depth")) {
|
||||
m_lookahead_cube_cutoff = depth_cutoff;
|
||||
}
|
||||
else if (p.lookahead_cube_cutoff() == symbol("freevars")) {
|
||||
m_lookahead_cube_cutoff = freevars_cutoff;
|
||||
}
|
||||
else if (p.lookahead_cube_cutoff() == symbol("psat")) {
|
||||
m_lookahead_cube_cutoff = psat_cutoff;
|
||||
}
|
||||
else if (p.lookahead_cube_cutoff() == symbol("adaptive_freevars")) {
|
||||
m_lookahead_cube_cutoff = adaptive_freevars_cutoff;
|
||||
}
|
||||
else if (p.lookahead_cube_cutoff() == symbol("adaptive_psat")) {
|
||||
m_lookahead_cube_cutoff = adaptive_psat_cutoff;
|
||||
}
|
||||
else {
|
||||
throw sat_param_exception("invalid cutoff type supplied: accepted cutoffs are 'depth', 'freevars', 'psat', 'adaptive_freevars' and 'adaptive_psat'");
|
||||
}
|
||||
m_lookahead_cube_fraction = p.lookahead_cube_fraction();
|
||||
m_lookahead_cube_cutoff = p.lookahead_cube_cutoff();
|
||||
m_lookahead_cube_depth = p.lookahead_cube_depth();
|
||||
m_lookahead_cube_freevars = p.lookahead_cube_freevars();
|
||||
m_lookahead_cube_psat_var_exp = p.lookahead_cube_psat_var_exp();
|
||||
m_lookahead_cube_psat_clause_base = p.lookahead_cube_psat_clause_base();
|
||||
m_lookahead_cube_psat_trigger = p.lookahead_cube_psat_trigger();
|
||||
m_lookahead_global_autarky = p.lookahead_global_autarky();
|
||||
|
||||
// These parameters are not exposed
|
||||
|
|
|
@ -65,6 +65,14 @@ namespace sat {
|
|||
march_cu_reward
|
||||
};
|
||||
|
||||
enum cutoff_t {
|
||||
depth_cutoff,
|
||||
freevars_cutoff,
|
||||
psat_cutoff,
|
||||
adaptive_freevars_cutoff,
|
||||
adaptive_psat_cutoff
|
||||
};
|
||||
|
||||
struct config {
|
||||
unsigned long long m_max_memory;
|
||||
phase_selection m_phase;
|
||||
|
@ -84,8 +92,13 @@ namespace sat {
|
|||
bool m_local_search;
|
||||
bool m_lookahead_simplify;
|
||||
bool m_lookahead_simplify_bca;
|
||||
unsigned m_lookahead_cube_cutoff;
|
||||
cutoff_t m_lookahead_cube_cutoff;
|
||||
double m_lookahead_cube_fraction;
|
||||
unsigned m_lookahead_cube_depth;
|
||||
double m_lookahead_cube_freevars;
|
||||
double m_lookahead_cube_psat_var_exp;
|
||||
double m_lookahead_cube_psat_clause_base;
|
||||
double m_lookahead_cube_psat_trigger;
|
||||
reward_t m_lookahead_reward;
|
||||
bool m_lookahead_global_autarky;
|
||||
|
||||
|
|
|
@ -85,8 +85,8 @@ namespace sat{
|
|||
// eliminate variable
|
||||
simp.m_pos_cls.reset();
|
||||
simp.m_neg_cls.reset();
|
||||
simp.collect_clauses(pos_l, simp.m_pos_cls, false);
|
||||
simp.collect_clauses(neg_l, simp.m_neg_cls, false);
|
||||
simp.collect_clauses(pos_l, simp.m_pos_cls);
|
||||
simp.collect_clauses(neg_l, simp.m_neg_cls);
|
||||
VERIFY(!s.is_external(v));
|
||||
model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v);
|
||||
simp.save_clauses(mc_entry, simp.m_pos_cls);
|
||||
|
@ -295,7 +295,7 @@ namespace sat{
|
|||
bool elim_vars::mark_literals(literal lit) {
|
||||
watch_list& wl = simp.get_wlist(lit);
|
||||
for (watched const& w : wl) {
|
||||
if (w.is_binary_unblocked_clause()) {
|
||||
if (w.is_binary_non_learned_clause()) {
|
||||
mark_var(w.get_literal().var());
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +321,7 @@ namespace sat{
|
|||
bdd result = m.mk_true();
|
||||
watch_list& wl = simp.get_wlist(~lit);
|
||||
for (watched const& w : wl) {
|
||||
if (w.is_binary_unblocked_clause()) {
|
||||
if (w.is_binary_non_learned_clause()) {
|
||||
result &= (mk_literal(lit) || mk_literal(w.get_literal()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,13 +34,11 @@ namespace sat {
|
|||
|
||||
// for nary clauses
|
||||
static bool contains_watched(watch_list const & wlist, clause const & c, clause_offset cls_off) {
|
||||
watch_list::const_iterator it = wlist.begin();
|
||||
watch_list::const_iterator end = wlist.end();
|
||||
for (; it != end; ++it) {
|
||||
if (it->is_clause()) {
|
||||
if (it->get_clause_offset() == cls_off) {
|
||||
for (watched const& w : wlist) {
|
||||
if (w.is_clause()) {
|
||||
if (w.get_clause_offset() == cls_off) {
|
||||
// the blocked literal must be in the clause.
|
||||
SASSERT(c.contains(it->get_blocked_literal()));
|
||||
SASSERT(c.contains(w.get_blocked_literal()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -96,13 +94,13 @@ namespace sat {
|
|||
}
|
||||
|
||||
// the first two literals must be watched.
|
||||
VERIFY(contains_watched(s.get_wlist(~c[0]), c, s.get_offset(c)));
|
||||
VERIFY(contains_watched(s.get_wlist(~c[0]), c, s.get_offset(c)));
|
||||
VERIFY(contains_watched(s.get_wlist(~c[1]), c, s.get_offset(c)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool integrity_checker::check_clauses(clause * const * begin, clause * const * end) const {
|
||||
bool integrity_checker::check_clauses(clause * const * begin, clause * const * end) const {
|
||||
for (clause * const * it = begin; it != end; ++it) {
|
||||
SASSERT(check_clause(*(*it)));
|
||||
}
|
||||
|
@ -152,49 +150,54 @@ namespace sat {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool integrity_checker::check_watches(literal l) const {
|
||||
return check_watches(l, s.get_wlist(~l));
|
||||
}
|
||||
|
||||
bool integrity_checker::check_watches(literal l, watch_list const& wlist) const {
|
||||
for (watched const& w : wlist) {
|
||||
switch (w.get_kind()) {
|
||||
case watched::BINARY:
|
||||
SASSERT(!s.was_eliminated(w.get_literal().var()));
|
||||
CTRACE("sat_watched_bug", !s.get_wlist(~(w.get_literal())).contains(watched(l, w.is_learned())),
|
||||
tout << "l: " << l << " l2: " << w.get_literal() << "\n";
|
||||
tout << "was_eliminated1: " << s.was_eliminated(l.var());
|
||||
tout << " was_eliminated2: " << s.was_eliminated(w.get_literal().var());
|
||||
tout << " learned: " << w.is_learned() << "\n";
|
||||
sat::display_watch_list(tout, s.m_cls_allocator, wlist);
|
||||
tout << "\n";
|
||||
sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~(w.get_literal())));
|
||||
tout << "\n";);
|
||||
VERIFY(find_binary_watch(s.get_wlist(~(w.get_literal())), l));
|
||||
break;
|
||||
case watched::TERNARY:
|
||||
VERIFY(!s.was_eliminated(w.get_literal1().var()));
|
||||
VERIFY(!s.was_eliminated(w.get_literal2().var()));
|
||||
VERIFY(w.get_literal1().index() < w.get_literal2().index());
|
||||
break;
|
||||
case watched::CLAUSE:
|
||||
SASSERT(!s.m_cls_allocator.get_clause(w.get_clause_offset())->was_removed());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool integrity_checker::check_watches() const {
|
||||
DEBUG_CODE(
|
||||
vector<watch_list>::const_iterator it = s.m_watches.begin();
|
||||
vector<watch_list>::const_iterator end = s.m_watches.end();
|
||||
for (unsigned l_idx = 0; it != end; ++it, ++l_idx) {
|
||||
literal l = ~to_literal(l_idx);
|
||||
watch_list const & wlist = *it;
|
||||
unsigned l_idx = 0;
|
||||
for (watch_list const& wlist : s.m_watches) {
|
||||
literal l = ~to_literal(l_idx++);
|
||||
CTRACE("sat_bug",
|
||||
s.was_eliminated(l.var()) && !wlist.empty(),
|
||||
tout << "l: " << l << "\n";
|
||||
s.display_watches(tout);
|
||||
s.display(tout););
|
||||
SASSERT(!s.was_eliminated(l.var()) || wlist.empty());
|
||||
watch_list::const_iterator it2 = wlist.begin();
|
||||
watch_list::const_iterator end2 = wlist.end();
|
||||
for (; it2 != end2; ++it2) {
|
||||
switch (it2->get_kind()) {
|
||||
case watched::BINARY:
|
||||
SASSERT(!s.was_eliminated(it2->get_literal().var()));
|
||||
CTRACE("sat_watched_bug", !s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned())),
|
||||
tout << "l: " << l << " l2: " << it2->get_literal() << "\n";
|
||||
tout << "was_eliminated1: " << s.was_eliminated(l.var());
|
||||
tout << " was_eliminated2: " << s.was_eliminated(it2->get_literal().var());
|
||||
tout << " learned: " << it2->is_learned() << "\n";
|
||||
sat::display_watch_list(tout, s.m_cls_allocator, wlist);
|
||||
tout << "\n";
|
||||
sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~(it2->get_literal())));
|
||||
tout << "\n";);
|
||||
SASSERT(s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned())));
|
||||
break;
|
||||
case watched::TERNARY:
|
||||
SASSERT(!s.was_eliminated(it2->get_literal1().var()));
|
||||
SASSERT(!s.was_eliminated(it2->get_literal2().var()));
|
||||
SASSERT(it2->get_literal1().index() < it2->get_literal2().index());
|
||||
break;
|
||||
case watched::CLAUSE:
|
||||
SASSERT(!s.m_cls_allocator.get_clause(it2->get_clause_offset())->was_removed());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!check_watches(l, wlist))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -211,16 +214,12 @@ namespace sat {
|
|||
|
||||
bool integrity_checker::check_disjoint_clauses() const {
|
||||
uint_set ids;
|
||||
clause_vector::const_iterator it = s.m_clauses.begin();
|
||||
clause_vector::const_iterator end = s.m_clauses.end();
|
||||
for (; it != end; ++it) {
|
||||
ids.insert((*it)->id());
|
||||
for (clause* cp : s.m_clauses) {
|
||||
ids.insert(cp->id());
|
||||
}
|
||||
it = s.m_learned.begin();
|
||||
end = s.m_learned.end();
|
||||
for (; it != end; ++it) {
|
||||
if (ids.contains((*it)->id())) {
|
||||
TRACE("sat", tout << "Repeated clause: " << (*it)->id() << "\n";);
|
||||
for (clause* cp : s.m_learned) {
|
||||
if (ids.contains(cp->id())) {
|
||||
TRACE("sat", tout << "Repeated clause: " << cp->id() << "\n";);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ Revision History:
|
|||
#define SAT_INTEGRITY_CHECKER_H_
|
||||
|
||||
#include "sat/sat_types.h"
|
||||
#include "sat/sat_watched.h"
|
||||
|
||||
namespace sat {
|
||||
class integrity_checker {
|
||||
|
@ -35,6 +36,8 @@ namespace sat {
|
|||
bool check_assignment() const;
|
||||
bool check_bool_vars() const;
|
||||
bool check_watches() const;
|
||||
bool check_watches(literal l, watch_list const& wlist) const;
|
||||
bool check_watches(literal l) const;
|
||||
bool check_reinit_stack() const;
|
||||
bool check_disjoint_clauses() const;
|
||||
bool operator()() const;
|
||||
|
|
|
@ -302,7 +302,7 @@ namespace sat {
|
|||
literal l1 = ~to_literal(l_idx);
|
||||
watch_list const & wlist = s.m_watches[l_idx];
|
||||
for (watched const& w : wlist) {
|
||||
if (!w.is_binary_unblocked_clause())
|
||||
if (!w.is_binary_non_learned_clause())
|
||||
continue;
|
||||
literal l2 = w.get_literal();
|
||||
if (l1.index() > l2.index())
|
||||
|
|
|
@ -683,7 +683,7 @@ namespace sat {
|
|||
// NB. u.index() > l.index() iff u.index() > (~l).index().
|
||||
// since indices for the same boolean variables occupy
|
||||
// two adjacent numbers.
|
||||
if (u.index() > l.index() && is_stamped(u)) {
|
||||
if (u.index() > l.index() && is_stamped(u) && ~l != u) {
|
||||
add_arc(~l, ~u);
|
||||
add_arc( u, l);
|
||||
}
|
||||
|
@ -692,7 +692,8 @@ namespace sat {
|
|||
lits.reset();
|
||||
if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) {
|
||||
for (literal u : lits) {
|
||||
if (u.index() > l.index() && is_stamped(u)) {
|
||||
// u is positive in lits, l is negative:
|
||||
if (~l != u && u.index() > l.index() && is_stamped(u)) {
|
||||
add_arc(~l, ~u);
|
||||
add_arc( u, l);
|
||||
}
|
||||
|
@ -1033,6 +1034,7 @@ namespace sat {
|
|||
}
|
||||
propagate();
|
||||
m_qhead = m_trail.size();
|
||||
m_init_freevars = m_freevars.size();
|
||||
TRACE("sat", m_s.display(tout); display(tout););
|
||||
}
|
||||
|
||||
|
@ -2018,6 +2020,35 @@ namespace sat {
|
|||
st.update("lh cube conflicts", m_cube_state.m_conflicts);
|
||||
}
|
||||
|
||||
double lookahead::psat_heur() {
|
||||
double h = 0.0;
|
||||
for (bool_var x : m_freevars) {
|
||||
literal l(x, false);
|
||||
for (literal lit : m_binary[l.index()]) {
|
||||
h += l.index() > lit.index() ? 1.0 / m_config.m_cube_psat_clause_base : 0.0;
|
||||
}
|
||||
for (literal lit : m_binary[(~l).index()]) {
|
||||
h += l.index() > lit.index() ? 1.0 / m_config.m_cube_psat_clause_base : 0.0;
|
||||
}
|
||||
for (binary b : m_ternary[l.index()]) {
|
||||
h += l.index() > b.m_u.index() && l.index() > b.m_v.index() ?
|
||||
1.0 / pow(m_config.m_cube_psat_clause_base, 2) :
|
||||
0.0;
|
||||
}
|
||||
for (binary b : m_ternary[(~l).index()]) {
|
||||
h += l.index() > b.m_u.index() && l.index() > b.m_v.index() ?
|
||||
1.0 / pow(m_config.m_cube_psat_clause_base, 2) :
|
||||
0.0;
|
||||
}
|
||||
}
|
||||
for (nary * n : m_nary_clauses) {
|
||||
h += 1.0 / pow(m_config.m_cube_psat_clause_base, n->size() - 1);
|
||||
}
|
||||
h /= pow(m_freevars.size(), m_config.m_cube_psat_var_exp);
|
||||
IF_VERBOSE(10, verbose_stream() << "(sat-cube-psat :val " << h << ")\n";);
|
||||
return h;
|
||||
}
|
||||
|
||||
lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level) {
|
||||
scoped_ext _scoped_ext(*this);
|
||||
lits.reset();
|
||||
|
@ -2062,9 +2093,14 @@ namespace sat {
|
|||
}
|
||||
backtrack_level = UINT_MAX;
|
||||
depth = m_cube_state.m_cube.size();
|
||||
if ((m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) ||
|
||||
(m_config.m_cube_cutoff == 0 && m_freevars.size() < m_cube_state.m_freevars_threshold)) {
|
||||
m_cube_state.m_freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth));
|
||||
if ((m_config.m_cube_cutoff == depth_cutoff && depth == m_config.m_cube_depth) ||
|
||||
(m_config.m_cube_cutoff == freevars_cutoff && m_freevars.size() <= m_init_freevars * m_config.m_cube_freevars) ||
|
||||
(m_config.m_cube_cutoff == psat_cutoff && psat_heur() >= m_config.m_cube_psat_trigger) ||
|
||||
(m_config.m_cube_cutoff == adaptive_freevars_cutoff && m_freevars.size() < m_cube_state.m_freevars_threshold) ||
|
||||
(m_config.m_cube_cutoff == adaptive_psat_cutoff && psat_heur() >= m_cube_state.m_psat_threshold)) {
|
||||
double dec = (1.0 - pow(m_config.m_cube_fraction, depth));
|
||||
m_cube_state.m_freevars_threshold *= dec;
|
||||
m_cube_state.m_psat_threshold *= dec;
|
||||
set_conflict();
|
||||
m_cube_state.inc_cutoff();
|
||||
#if 0
|
||||
|
@ -2077,10 +2113,12 @@ namespace sat {
|
|||
return l_undef;
|
||||
}
|
||||
int prev_nfreevars = m_freevars.size();
|
||||
double prev_psat = m_config.m_cube_cutoff == adaptive_psat_cutoff ? psat_heur() : DBL_MAX; // MN. only compute PSAT if enabled
|
||||
literal lit = choose();
|
||||
if (inconsistent()) {
|
||||
TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";);
|
||||
m_cube_state.m_freevars_threshold = prev_nfreevars;
|
||||
m_cube_state.m_psat_threshold = prev_psat;
|
||||
m_cube_state.inc_conflict();
|
||||
if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false;
|
||||
continue;
|
||||
|
@ -2332,8 +2370,8 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
scc scc(m_s, m_s.m_params);
|
||||
scc.init_big(true);
|
||||
big big;
|
||||
big.init_big(m_s, true);
|
||||
svector<std::pair<literal, literal>> candidates;
|
||||
|
||||
unsigned_vector bin_size(num_lits);
|
||||
|
@ -2350,14 +2388,14 @@ namespace sat {
|
|||
if (v == get_parent(v) &&
|
||||
!m_s.was_eliminated(v.var()) &&
|
||||
!imp.contains(std::make_pair(u.index(), v.index())) &&
|
||||
!scc.reaches(u, v)) {
|
||||
!big.connected(u, v)) {
|
||||
candidates.push_back(std::make_pair(u, v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned count = 0; count < 5; ++count) {
|
||||
scc.init_big(true);
|
||||
big.init_big(m_s, true);
|
||||
unsigned k = 0;
|
||||
union_find_default_ctx ufctx;
|
||||
union_find<union_find_default_ctx> uf(ufctx);
|
||||
|
@ -2365,7 +2403,7 @@ namespace sat {
|
|||
for (unsigned j = 0; j < candidates.size(); ++j) {
|
||||
literal u = candidates[j].first;
|
||||
literal v = candidates[j].second;
|
||||
if (!scc.reaches(u, v)) {
|
||||
if (!big.connected(u, v)) {
|
||||
if (uf.find(u.index()) != uf.find(v.index())) {
|
||||
++num_bins;
|
||||
uf.merge(u.index(), v.index());
|
||||
|
@ -2457,6 +2495,11 @@ namespace sat {
|
|||
m_config.m_reward_type = m_s.m_config.m_lookahead_reward;
|
||||
m_config.m_cube_cutoff = m_s.m_config.m_lookahead_cube_cutoff;
|
||||
m_config.m_cube_fraction = m_s.m_config.m_lookahead_cube_fraction;
|
||||
m_config.m_cube_depth = m_s.m_config.m_lookahead_cube_depth;
|
||||
m_config.m_cube_freevars = m_s.m_config.m_lookahead_cube_freevars;
|
||||
m_config.m_cube_psat_var_exp = m_s.m_config.m_lookahead_cube_psat_var_exp;
|
||||
m_config.m_cube_psat_clause_base = m_s.m_config.m_lookahead_cube_psat_clause_base;
|
||||
m_config.m_cube_psat_trigger = m_s.m_config.m_lookahead_cube_psat_trigger;
|
||||
}
|
||||
|
||||
void lookahead::collect_statistics(statistics& st) const {
|
||||
|
|
|
@ -80,8 +80,13 @@ namespace sat {
|
|||
unsigned m_dl_max_iterations;
|
||||
unsigned m_tc1_limit;
|
||||
reward_t m_reward_type;
|
||||
unsigned m_cube_cutoff;
|
||||
cutoff_t m_cube_cutoff;
|
||||
unsigned m_cube_depth;
|
||||
double m_cube_fraction;
|
||||
double m_cube_freevars;
|
||||
double m_cube_psat_var_exp;
|
||||
double m_cube_psat_clause_base;
|
||||
double m_cube_psat_trigger;
|
||||
|
||||
config() {
|
||||
memset(this, sizeof(*this), 0);
|
||||
|
@ -96,8 +101,13 @@ namespace sat {
|
|||
m_dl_max_iterations = 2;
|
||||
m_tc1_limit = 10000000;
|
||||
m_reward_type = ternary_reward;
|
||||
m_cube_cutoff = 0;
|
||||
m_cube_cutoff = adaptive_freevars_cutoff;
|
||||
m_cube_depth = 10;
|
||||
m_cube_fraction = 0.4;
|
||||
m_cube_freevars = 0.8;
|
||||
m_cube_psat_var_exp = 1.0;
|
||||
m_cube_psat_clause_base = 2.0;
|
||||
m_cube_psat_trigger = 5.0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -167,6 +177,7 @@ namespace sat {
|
|||
svector<bool> m_is_decision;
|
||||
literal_vector m_cube;
|
||||
double m_freevars_threshold;
|
||||
double m_psat_threshold;
|
||||
unsigned m_conflicts;
|
||||
unsigned m_cutoffs;
|
||||
cube_state() { reset(); }
|
||||
|
@ -175,6 +186,7 @@ namespace sat {
|
|||
m_is_decision.reset();
|
||||
m_cube.reset();
|
||||
m_freevars_threshold = 0;
|
||||
m_psat_threshold = DBL_MAX;
|
||||
reset_stats();
|
||||
}
|
||||
void reset_stats() { m_conflicts = 0; m_cutoffs = 0; }
|
||||
|
@ -228,11 +240,12 @@ namespace sat {
|
|||
svector<prefix> m_vprefix; // var: prefix where variable participates in propagation
|
||||
unsigned m_rating_throttle; // throttle to recompute rating
|
||||
indexed_uint_set m_freevars;
|
||||
unsigned m_init_freevars;
|
||||
lookahead_mode m_search_mode; // mode of search
|
||||
stats m_stats;
|
||||
model m_model;
|
||||
cube_state m_cube_state;
|
||||
scoped_ptr<extension> m_ext;
|
||||
scoped_ptr<extension> m_ext;
|
||||
|
||||
// ---------------------------------------
|
||||
// truth values
|
||||
|
@ -542,6 +555,8 @@ namespace sat {
|
|||
|
||||
void add_hyper_binary();
|
||||
|
||||
double psat_heur();
|
||||
|
||||
public:
|
||||
lookahead(solver& s) :
|
||||
m_s(s),
|
||||
|
|
|
@ -38,8 +38,14 @@ def_module_params('sat',
|
|||
('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'),
|
||||
('local_search', BOOL, False, 'use local search instead of CDCL'),
|
||||
('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'),
|
||||
('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead_cube is true'),
|
||||
('lookahead.cube.cutoff', UINT, 10, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'),
|
||||
('lookahead.cube.cutoff', SYMBOL, 'adaptive_freevars', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'),
|
||||
('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive_freevars or adaptive_psat'),
|
||||
('lookahead.cube.depth', UINT, 10, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth.'),
|
||||
('lookahead.cube.freevars', DOUBLE, 0.8, 'cube free fariable fraction. Used when lookahead.cube.cutoff is freevars'),
|
||||
('lookahead.cube.psat.var_exp', DOUBLE, 1, 'free variable exponent for PSAT cutoff'),
|
||||
('lookahead.cube.psat.clause_base', DOUBLE, 2, 'clause base for PSAT cutoff'),
|
||||
('lookahead.cube.psat.trigger', DOUBLE, 5, 'trigger value to create lookahead cubes for PSAT cutoff. Used when lookahead.cube.cutoff is psat'),
|
||||
('lookahead_search', BOOL, False, 'use lookahead solver'),
|
||||
('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'),
|
||||
('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'),
|
||||
('lookahead_simplify.bca', BOOL, False, 'add learned binary clauses as part of lookahead simplification'),
|
||||
|
|
|
@ -234,102 +234,10 @@ namespace sat {
|
|||
return to_elim.size();
|
||||
}
|
||||
|
||||
void scc::init_big(bool learned) {
|
||||
unsigned num_lits = m_solver.num_vars() * 2;
|
||||
m_dag.reset();
|
||||
m_roots.reset();
|
||||
m_dag.resize(num_lits, 0);
|
||||
m_roots.resize(num_lits, true);
|
||||
SASSERT(num_lits == m_dag.size() && num_lits == m_roots.size());
|
||||
for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) {
|
||||
literal u = to_literal(l_idx);
|
||||
if (m_solver.was_eliminated(u.var()))
|
||||
continue;
|
||||
auto& edges = m_dag[l_idx];
|
||||
for (watched const& w : m_solver.m_watches[l_idx]) {
|
||||
if (learned ? w.is_binary_clause() : w.is_binary_unblocked_clause()) {
|
||||
literal v = w.get_literal();
|
||||
m_roots[v.index()] = false;
|
||||
edges.push_back(v);
|
||||
}
|
||||
}
|
||||
shuffle<literal>(edges.size(), edges.c_ptr(), m_rand);
|
||||
}
|
||||
init_dfs_num(learned);
|
||||
}
|
||||
|
||||
struct scc::pframe {
|
||||
literal m_parent;
|
||||
literal m_child;
|
||||
pframe(literal p, literal c):
|
||||
m_parent(p), m_child(c) {}
|
||||
literal child() const { return m_child; }
|
||||
literal parent() const { return m_parent; }
|
||||
};
|
||||
|
||||
void scc::init_dfs_num(bool learned) {
|
||||
unsigned num_lits = m_solver.num_vars() * 2;
|
||||
m_left.reset();
|
||||
m_right.reset();
|
||||
m_root.reset();
|
||||
m_parent.reset();
|
||||
m_left.resize(num_lits, 0);
|
||||
m_right.resize(num_lits, -1);
|
||||
m_root.resize(num_lits, null_literal);
|
||||
m_parent.resize(num_lits, null_literal);
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
m_root[i] = to_literal(i);
|
||||
m_parent[i] = to_literal(i);
|
||||
}
|
||||
svector<pframe> todo;
|
||||
// retrieve literals that have no predecessors
|
||||
for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) {
|
||||
literal u(to_literal(l_idx));
|
||||
if (m_roots[u.index()]) {
|
||||
todo.push_back(pframe(null_literal, u));
|
||||
}
|
||||
}
|
||||
shuffle<pframe>(todo.size(), todo.c_ptr(), m_rand);
|
||||
int dfs_num = 0;
|
||||
while (!todo.empty()) {
|
||||
literal u = todo.back().child();
|
||||
if (m_left[u.index()] > 0) {
|
||||
// already visited
|
||||
if (m_right[u.index()] < 0) {
|
||||
m_right[u.index()] = ++dfs_num;
|
||||
}
|
||||
todo.pop_back();
|
||||
}
|
||||
else {
|
||||
SASSERT(m_left[u.index()] == 0);
|
||||
m_left[u.index()] = ++dfs_num;
|
||||
literal p = todo.back().parent();
|
||||
if (p != null_literal) {
|
||||
m_root[u.index()] = m_root[p.index()];
|
||||
m_parent[u.index()] = p;
|
||||
}
|
||||
for (literal v : m_dag[u.index()]) {
|
||||
if (m_left[v.index()] == 0) {
|
||||
todo.push_back(pframe(u, v));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
if (m_right[i] < 0) {
|
||||
VERIFY(m_left[i] == 0);
|
||||
m_left[i] = ++dfs_num;
|
||||
m_right[i] = ++dfs_num;
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
VERIFY(m_left[i] < m_right[i]);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned scc::reduce_tr(bool learned) {
|
||||
unsigned num_lits = m_solver.num_vars() * 2;
|
||||
init_big(learned);
|
||||
|
||||
unsigned idx = 0;
|
||||
unsigned elim = m_num_elim_bin;
|
||||
for (watch_list & wlist : m_solver.m_watches) {
|
||||
|
@ -343,6 +251,7 @@ namespace sat {
|
|||
literal v = w.get_literal();
|
||||
if (reaches(u, v) && u != get_parent(v)) {
|
||||
++m_num_elim_bin;
|
||||
m_solver.get_wlist(~v).erase(watched(~u, w.is_learned()));
|
||||
}
|
||||
else {
|
||||
*itprev = *it;
|
||||
|
|
|
@ -19,9 +19,10 @@ Revision History:
|
|||
#ifndef SAT_SCC_H_
|
||||
#define SAT_SCC_H_
|
||||
|
||||
#include "sat/sat_types.h"
|
||||
#include "util/statistics.h"
|
||||
#include "util/params.h"
|
||||
#include "sat/sat_types.h"
|
||||
#include "sat/sat_big.h"
|
||||
|
||||
namespace sat {
|
||||
class solver;
|
||||
|
@ -35,24 +36,12 @@ namespace sat {
|
|||
// stats
|
||||
unsigned m_num_elim;
|
||||
unsigned m_num_elim_bin;
|
||||
random_gen m_rand;
|
||||
|
||||
// BIG state:
|
||||
|
||||
vector<literal_vector> m_dag;
|
||||
svector<bool> m_roots;
|
||||
svector<int> m_left, m_right;
|
||||
literal_vector m_root, m_parent;
|
||||
big m_big;
|
||||
|
||||
void reduce_tr();
|
||||
unsigned reduce_tr(bool learned);
|
||||
|
||||
void init_dfs_num(bool learned);
|
||||
|
||||
struct pframe;
|
||||
|
||||
bool reaches_aux(literal u, literal v) const { return m_left[u.index()] < m_left[v.index()] && m_right[v.index()] < m_right[u.index()]; }
|
||||
|
||||
public:
|
||||
|
||||
scc(solver & s, params_ref const & p);
|
||||
|
@ -67,13 +56,14 @@ namespace sat {
|
|||
/*
|
||||
\brief create binary implication graph and associated data-structures to check transitivity.
|
||||
*/
|
||||
void init_big(bool learned);
|
||||
void ensure_big(bool learned) { if (m_left.empty()) init_big(learned); }
|
||||
int get_left(literal l) const { return m_left[l.index()]; }
|
||||
int get_right(literal l) const { return m_right[l.index()]; }
|
||||
literal get_parent(literal l) const { return m_parent[l.index()]; }
|
||||
literal get_root(literal l) const { return m_root[l.index()]; }
|
||||
bool reaches(literal u, literal v) const { return reaches_aux(u, v) || reaches_aux(~v, ~u); }
|
||||
void init_big(bool learned) { m_big.init_big(m_solver, learned); }
|
||||
void ensure_big(bool learned) { m_big.ensure_big(m_solver, learned); }
|
||||
int get_left(literal l) const { return m_big.get_left(l); }
|
||||
int get_right(literal l) const { return m_big.get_right(l); }
|
||||
literal get_parent(literal l) const { return m_big.get_parent(l); }
|
||||
literal get_root(literal l) const { return m_big.get_root(l); }
|
||||
bool reaches(literal u, literal v) const { return m_big.reaches(u, v); }
|
||||
bool connected(literal u, literal v) const { return m_big.connected(u, v); }
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ Revision History:
|
|||
#include "sat/sat_simplifier_params.hpp"
|
||||
#include "sat/sat_solver.h"
|
||||
#include "sat/sat_elim_vars.h"
|
||||
#include "sat/sat_integrity_checker.h"
|
||||
#include "util/stopwatch.h"
|
||||
#include "util/trace.h"
|
||||
|
||||
|
@ -99,16 +100,16 @@ namespace sat {
|
|||
(m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled());
|
||||
}
|
||||
bool simplifier::acce_enabled() const {
|
||||
return !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_acce;
|
||||
return !s.m_ext && !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_acce;
|
||||
}
|
||||
bool simplifier::cce_enabled() const {
|
||||
return !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled());
|
||||
return !s.m_ext && !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled());
|
||||
}
|
||||
bool simplifier::abce_enabled() const {
|
||||
return !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce;
|
||||
return !s.m_ext && !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce;
|
||||
}
|
||||
bool simplifier::bca_enabled() const {
|
||||
return !m_incremental_mode && !s.tracking_assumptions() && m_bca && m_learned_in_use_lists && single_threaded();
|
||||
return !s.m_ext && !m_incremental_mode && !s.tracking_assumptions() && m_bca && m_learned_in_use_lists && single_threaded();
|
||||
}
|
||||
bool simplifier::elim_vars_bdd_enabled() const {
|
||||
return !m_incremental_mode && !s.tracking_assumptions() && m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay && single_threaded();
|
||||
|
@ -164,23 +165,11 @@ namespace sat {
|
|||
}
|
||||
|
||||
inline void simplifier::remove_bin_clause_half(literal l1, literal l2, bool learned) {
|
||||
SASSERT(get_wlist(~l1).contains(watched(l2, learned)));
|
||||
get_wlist(~l1).erase(watched(l2, learned));
|
||||
m_sub_bin_todo.erase(bin_clause(l1, l2, learned));
|
||||
m_sub_bin_todo.erase(bin_clause(l2, l1, learned));
|
||||
}
|
||||
|
||||
inline void simplifier::block_bin_clause_half(literal l1, literal l2) {
|
||||
SASSERT(get_wlist(~l1).contains(watched(l2, false)));
|
||||
for (watched & w : get_wlist(~l1)) {
|
||||
if (w.get_literal() == l2) {
|
||||
w.set_blocked();
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sub_bin_todo.erase(bin_clause(l1, l2, false));
|
||||
}
|
||||
|
||||
void simplifier::init_visited() {
|
||||
m_visited.reset();
|
||||
m_visited.resize(2*s.num_vars(), false);
|
||||
|
@ -213,6 +202,9 @@ namespace sat {
|
|||
|
||||
void simplifier::operator()(bool learned) {
|
||||
|
||||
integrity_checker si(s);
|
||||
si.check_watches();
|
||||
|
||||
if (s.inconsistent())
|
||||
return;
|
||||
if (!m_subsumption && !bce_enabled() && !bca_enabled() && !elim_vars_enabled())
|
||||
|
@ -239,6 +231,7 @@ namespace sat {
|
|||
if (bce_enabled() || abce_enabled() || bca_enabled()) {
|
||||
elim_blocked_clauses();
|
||||
}
|
||||
si.check_watches();
|
||||
|
||||
if (!learned) {
|
||||
m_num_calls++;
|
||||
|
@ -260,7 +253,7 @@ namespace sat {
|
|||
if (s.inconsistent())
|
||||
return;
|
||||
if (!learned && elim_vars_enabled())
|
||||
elim_vars();
|
||||
elim_vars();
|
||||
if (s.inconsistent())
|
||||
return;
|
||||
if (!m_subsumption || m_sub_counter < 0)
|
||||
|
@ -276,12 +269,14 @@ namespace sat {
|
|||
cleanup_clauses(s.m_learned, true, vars_eliminated, m_learned_in_use_lists);
|
||||
cleanup_clauses(s.m_clauses, false, vars_eliminated, true);
|
||||
}
|
||||
si.check_watches();
|
||||
|
||||
CASSERT("sat_solver", s.check_invariant());
|
||||
TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout););
|
||||
|
||||
finalize();
|
||||
|
||||
si.check_watches();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -736,7 +731,7 @@ namespace sat {
|
|||
// should not traverse wlist using iterators, since back_subsumption1 may add new binary clauses there
|
||||
for (unsigned j = 0; j < wlist.size(); j++) {
|
||||
watched w = wlist[j];
|
||||
if (w.is_binary_unblocked_clause()) {
|
||||
if (w.is_binary_non_learned_clause()) {
|
||||
literal l2 = w.get_literal();
|
||||
if (l.index() < l2.index()) {
|
||||
m_dummy.set(l, l2, w.is_learned());
|
||||
|
@ -744,9 +739,9 @@ namespace sat {
|
|||
back_subsumption1(c);
|
||||
if (w.is_learned() && !c.is_learned()) {
|
||||
SASSERT(wlist[j] == w);
|
||||
TRACE("mark_not_learned_bug",
|
||||
TRACE("set_not_learned_bug",
|
||||
tout << "marking as not learned: " << l2 << " " << wlist[j].is_learned() << "\n";);
|
||||
wlist[j].mark_not_learned();
|
||||
wlist[j].set_not_learned();
|
||||
mark_as_not_learned_core(get_wlist(~l2), l);
|
||||
}
|
||||
if (s.inconsistent())
|
||||
|
@ -763,7 +758,7 @@ namespace sat {
|
|||
void simplifier::mark_as_not_learned_core(watch_list & wlist, literal l2) {
|
||||
for (watched & w : wlist) {
|
||||
if (w.is_binary_clause() && w.get_literal() == l2 && w.is_learned()) {
|
||||
w.mark_not_learned();
|
||||
w.set_not_learned();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -983,14 +978,20 @@ namespace sat {
|
|||
}
|
||||
|
||||
void operator()() {
|
||||
integrity_checker si(s.s);
|
||||
si.check_watches();
|
||||
if (s.bce_enabled())
|
||||
block_clauses();
|
||||
si.check_watches();
|
||||
if (s.abce_enabled())
|
||||
cce<false>();
|
||||
si.check_watches();
|
||||
if (s.cce_enabled())
|
||||
cce<true>();
|
||||
si.check_watches();
|
||||
if (s.bca_enabled())
|
||||
bca();
|
||||
si.check_watches();
|
||||
}
|
||||
|
||||
void block_clauses() {
|
||||
|
@ -1013,12 +1014,14 @@ namespace sat {
|
|||
|
||||
void process(literal l) {
|
||||
TRACE("blocked_clause", tout << "processing: " << l << "\n";);
|
||||
model_converter::entry * new_entry = 0;
|
||||
if (!process_var(l.var())) {
|
||||
return;
|
||||
}
|
||||
integrity_checker si(s.s);
|
||||
//si.check_watches();
|
||||
process_clauses(l);
|
||||
process_binary(l);
|
||||
//si.check_watches();
|
||||
}
|
||||
|
||||
void process_binary(literal l) {
|
||||
|
@ -1029,11 +1032,9 @@ namespace sat {
|
|||
watch_list::iterator it2 = it;
|
||||
watch_list::iterator end = wlist.end();
|
||||
|
||||
#define INC() if (!s.m_retain_blocked_clauses) { *it2 = *it; it2++; }
|
||||
|
||||
for (; it != end; ++it) {
|
||||
if (!it->is_binary_clause() || it->is_blocked()) {
|
||||
INC();
|
||||
if (!it->is_binary_non_learned_clause()) {
|
||||
*it2 = *it; it2++;
|
||||
continue;
|
||||
}
|
||||
literal l2 = it->get_literal();
|
||||
|
@ -1043,11 +1044,11 @@ namespace sat {
|
|||
s.m_num_blocked_clauses++;
|
||||
}
|
||||
else {
|
||||
INC();
|
||||
*it2 = *it; it2++;
|
||||
}
|
||||
s.unmark_visited(l2);
|
||||
}
|
||||
if (!s.m_retain_blocked_clauses) wlist.set_end(it2);
|
||||
wlist.set_end(it2);
|
||||
}
|
||||
|
||||
void process_clauses(literal l) {
|
||||
|
@ -1094,7 +1095,7 @@ namespace sat {
|
|||
for (watched & w : s.get_wlist(l)) {
|
||||
// when adding a blocked clause, then all non-learned clauses have to be considered for the
|
||||
// resolution intersection.
|
||||
bool process_bin = adding ? w.is_binary_clause() : w.is_binary_unblocked_clause();
|
||||
bool process_bin = adding ? w.is_binary_clause() : w.is_binary_non_learned_clause();
|
||||
if (process_bin) {
|
||||
literal lit = w.get_literal();
|
||||
if (s.is_marked(~lit) && lit != ~l) {
|
||||
|
@ -1146,7 +1147,7 @@ namespace sat {
|
|||
bool check_abce_tautology(literal l) {
|
||||
if (!process_var(l.var())) return false;
|
||||
for (watched & w : s.get_wlist(l)) {
|
||||
if (w.is_binary_unblocked_clause()) {
|
||||
if (w.is_binary_non_learned_clause()) {
|
||||
literal lit = w.get_literal();
|
||||
if (!s.is_marked(~lit) || lit == ~l) return false;
|
||||
}
|
||||
|
@ -1176,7 +1177,7 @@ namespace sat {
|
|||
for (; m_ala_qhead < m_covered_clause.size(); ++m_ala_qhead) {
|
||||
literal l = m_covered_clause[m_ala_qhead];
|
||||
for (watched & w : s.get_wlist(~l)) {
|
||||
if (w.is_binary_unblocked_clause()) {
|
||||
if (w.is_binary_non_learned_clause()) {
|
||||
literal lit = w.get_literal();
|
||||
if (!s.is_marked(lit) && !s.is_marked(~lit)) {
|
||||
m_covered_clause.push_back(~lit);
|
||||
|
@ -1318,8 +1319,9 @@ namespace sat {
|
|||
watch_list::iterator end = wlist.end();
|
||||
model_converter::kind k;
|
||||
for (; it != end; ++it) {
|
||||
if (!it->is_binary_clause() || it->is_blocked()) {
|
||||
INC();
|
||||
if (!it->is_binary_non_learned_clause()) {
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
continue;
|
||||
}
|
||||
literal l2 = it->get_literal();
|
||||
|
@ -1328,10 +1330,11 @@ namespace sat {
|
|||
s.m_num_covered_clauses++;
|
||||
}
|
||||
else {
|
||||
INC();
|
||||
*it2 = *it;
|
||||
it2++;
|
||||
}
|
||||
}
|
||||
if (!s.m_retain_blocked_clauses) wlist.set_end(it2);
|
||||
wlist.set_end(it2);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1357,7 +1360,7 @@ namespace sat {
|
|||
void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) {
|
||||
TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";);
|
||||
VERIFY(!s.is_external(l));
|
||||
if (new_entry == 0 && !s.m_retain_blocked_clauses)
|
||||
if (new_entry == 0)
|
||||
new_entry = &(mc.mk(k, l.var()));
|
||||
m_to_remove.push_back(&c);
|
||||
for (literal lit : c) {
|
||||
|
@ -1382,24 +1385,18 @@ namespace sat {
|
|||
|
||||
void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry, model_converter::kind k) {
|
||||
SASSERT(!s.is_external(blocked));
|
||||
VERIFY(!s.is_external(blocked));
|
||||
if (new_entry == 0)
|
||||
new_entry = &(mc.mk(k, blocked.var()));
|
||||
literal l2 = it->get_literal();
|
||||
TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";);
|
||||
if (s.m_retain_blocked_clauses && !it->is_learned()) {
|
||||
s.block_bin_clause_half(l2, l1);
|
||||
s.block_bin_clause_half(l1, l2);
|
||||
}
|
||||
else {
|
||||
s.remove_bin_clause_half(l2, l1, it->is_learned());
|
||||
}
|
||||
s.remove_bin_clause_half(l2, l1, it->is_learned());
|
||||
m_queue.decreased(~l2);
|
||||
}
|
||||
|
||||
void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) {
|
||||
literal l2 = it->get_literal();
|
||||
prepare_block_binary(it, l, l, new_entry, model_converter::BLOCK_LIT);
|
||||
mc.insert(*new_entry, l, it->get_literal());
|
||||
mc.insert(*new_entry, l, l2);
|
||||
}
|
||||
|
||||
void block_covered_binary(watch_list::iterator it, literal l, literal blocked, model_converter::kind k) {
|
||||
|
@ -1431,19 +1428,12 @@ namespace sat {
|
|||
}
|
||||
for (literal l2 : m_intersection) {
|
||||
l2.neg();
|
||||
bool found = false;
|
||||
for (watched w : s.get_wlist(~l)) {
|
||||
found = w.is_binary_clause() && l2 == w.get_literal();
|
||||
if (found) break;
|
||||
}
|
||||
if (!found) {
|
||||
watched* w = find_binary_watch(s.get_wlist(~l), l2);
|
||||
if (!w) {
|
||||
IF_VERBOSE(100, verbose_stream() << "bca " << l << " " << l2 << "\n";);
|
||||
watched w1(l2, false);
|
||||
w1.set_blocked();
|
||||
watched w2(l, false);
|
||||
w2.set_blocked();
|
||||
s.get_wlist(~l).push_back(w1);
|
||||
s.get_wlist(~l2).push_back(w2);
|
||||
s.get_wlist(~l).push_back(watched(l2, true));
|
||||
VERIFY(!find_binary_watch(s.get_wlist(~l2), l));
|
||||
s.get_wlist(~l2).push_back(watched(l, true));
|
||||
++s.m_num_bca;
|
||||
}
|
||||
}
|
||||
|
@ -1453,7 +1443,7 @@ namespace sat {
|
|||
watch_list & wlist = s.get_wlist(l);
|
||||
m_counter -= wlist.size();
|
||||
for (auto const& w : wlist) {
|
||||
if (w.is_binary_unblocked_clause() &&
|
||||
if (w.is_binary_non_learned_clause() &&
|
||||
!s.is_marked(~w.get_literal()))
|
||||
return false;
|
||||
}
|
||||
|
@ -1525,7 +1515,7 @@ namespace sat {
|
|||
unsigned r = 0;
|
||||
watch_list const & wlist = get_wlist(~l);
|
||||
for (auto & w : wlist) {
|
||||
if (w.is_binary_unblocked_clause())
|
||||
if (w.is_binary_non_learned_clause())
|
||||
r++;
|
||||
}
|
||||
return r;
|
||||
|
@ -1574,10 +1564,10 @@ namespace sat {
|
|||
/**
|
||||
\brief Collect clauses and binary clauses containing l.
|
||||
*/
|
||||
void simplifier::collect_clauses(literal l, clause_wrapper_vector & r, bool include_blocked) {
|
||||
void simplifier::collect_clauses(literal l, clause_wrapper_vector & r) {
|
||||
clause_use_list const & cs = m_use_list.get(l);
|
||||
for (auto it = cs.mk_iterator(); !it.at_end(); it.next()) {
|
||||
if (!it.curr().is_blocked() || include_blocked) {
|
||||
if (!it.curr().is_blocked()) {
|
||||
r.push_back(clause_wrapper(it.curr()));
|
||||
SASSERT(r.back().size() == it.curr().size());
|
||||
}
|
||||
|
@ -1585,7 +1575,7 @@ namespace sat {
|
|||
|
||||
watch_list & wlist = get_wlist(~l);
|
||||
for (auto & w : wlist) {
|
||||
if (include_blocked ? w.is_binary_non_learned_clause() : w.is_binary_unblocked_clause()) {
|
||||
if (w.is_binary_non_learned_clause()) {
|
||||
r.push_back(clause_wrapper(l, w.get_literal()));
|
||||
SASSERT(r.back().size() == 2);
|
||||
}
|
||||
|
@ -1643,27 +1633,26 @@ namespace sat {
|
|||
}
|
||||
|
||||
void simplifier::add_non_learned_binary_clause(literal l1, literal l2) {
|
||||
watched* w;
|
||||
watch_list & wlist1 = get_wlist(~l1);
|
||||
watch_list & wlist2 = get_wlist(~l2);
|
||||
bool found = false;
|
||||
for (watched& w : wlist1) {
|
||||
if (w.is_binary_clause() && w.get_literal() == l2) {
|
||||
if (w.is_learned()) w.mark_not_learned();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
w = find_binary_watch(wlist1, l2);
|
||||
if (w) {
|
||||
if (w->is_learned())
|
||||
w->set_not_learned();
|
||||
}
|
||||
else {
|
||||
wlist1.push_back(watched(l2, false));
|
||||
}
|
||||
if (!found) wlist1.push_back(watched(l2, false));
|
||||
|
||||
found = false;
|
||||
for (watched& w : wlist2) {
|
||||
if (w.is_binary_clause() && w.get_literal() == l1) {
|
||||
if (w.is_learned()) w.mark_not_learned();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
w = find_binary_watch(wlist2, l1);
|
||||
if (w) {
|
||||
if (w->is_learned())
|
||||
w->set_not_learned();
|
||||
}
|
||||
else {
|
||||
wlist2.push_back(watched(l1, false));
|
||||
}
|
||||
if (!found) wlist2.push_back(watched(l1, false));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1755,8 +1744,8 @@ namespace sat {
|
|||
|
||||
m_pos_cls.reset();
|
||||
m_neg_cls.reset();
|
||||
collect_clauses(pos_l, m_pos_cls, false);
|
||||
collect_clauses(neg_l, m_neg_cls, false);
|
||||
collect_clauses(pos_l, m_pos_cls);
|
||||
collect_clauses(neg_l, m_neg_cls);
|
||||
|
||||
TRACE("resolution_detail", tout << "collecting number of after_clauses\n";);
|
||||
unsigned before_clauses = num_pos + num_neg;
|
||||
|
@ -1782,7 +1771,7 @@ namespace sat {
|
|||
|
||||
// eliminate variable
|
||||
++s.m_stats.m_elim_var_res;
|
||||
VERIFY(!s.is_external(v));
|
||||
VERIFY(!is_external(v));
|
||||
model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v);
|
||||
save_clauses(mc_entry, m_pos_cls);
|
||||
save_clauses(mc_entry, m_neg_cls);
|
||||
|
|
|
@ -132,7 +132,6 @@ namespace sat {
|
|||
void remove_clause(clause & c);
|
||||
void remove_clause(clause & c, literal l);
|
||||
void block_clause(clause & c);
|
||||
void block_bin_clause_half(literal l1, literal l2);
|
||||
void unblock_clause(clause & c);
|
||||
void remove_bin_clause_half(literal l1, literal l2, bool learned);
|
||||
|
||||
|
@ -185,7 +184,7 @@ namespace sat {
|
|||
unsigned get_num_unblocked_bin(literal l) const;
|
||||
unsigned get_to_elim_cost(bool_var v) const;
|
||||
void order_vars_for_elim(bool_var_vector & r);
|
||||
void collect_clauses(literal l, clause_wrapper_vector & r, bool include_blocked);
|
||||
void collect_clauses(literal l, clause_wrapper_vector & r);
|
||||
clause_wrapper_vector m_pos_cls;
|
||||
clause_wrapper_vector m_neg_cls;
|
||||
literal_vector m_new_cls;
|
||||
|
|
|
@ -137,10 +137,6 @@ namespace sat {
|
|||
|
||||
watched w1(l2, wi.is_learned());
|
||||
watched w2(l, wi.is_learned());
|
||||
if (wi.is_blocked()) {
|
||||
w1.set_blocked();
|
||||
w2.set_blocked();
|
||||
}
|
||||
m_watches[(~l).index()].push_back(w1);
|
||||
m_watches[(~l2).index()].push_back(w2);
|
||||
}
|
||||
|
@ -315,6 +311,19 @@ namespace sat {
|
|||
}
|
||||
|
||||
void solver::mk_bin_clause(literal l1, literal l2, bool learned) {
|
||||
watched* w0 = find_binary_watch(get_wlist(~l1), l2);
|
||||
if (w0) {
|
||||
if (w0->is_learned() && !learned) {
|
||||
w0->set_not_learned();
|
||||
}
|
||||
w0 = find_binary_watch(get_wlist(~l2), l1);
|
||||
}
|
||||
if (w0) {
|
||||
if (w0->is_learned() && !learned) {
|
||||
w0->set_not_learned();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (m_config.m_drat)
|
||||
m_drat.add(l1, l2, learned);
|
||||
if (propagate_bin_clause(l1, l2)) {
|
||||
|
@ -324,8 +333,8 @@ namespace sat {
|
|||
m_clauses_to_reinit.push_back(clause_wrapper(l1, l2));
|
||||
}
|
||||
m_stats.m_mk_bin_clause++;
|
||||
m_watches[(~l1).index()].push_back(watched(l2, learned));
|
||||
m_watches[(~l2).index()].push_back(watched(l1, learned));
|
||||
get_wlist(~l1).push_back(watched(l2, learned));
|
||||
get_wlist(~l2).push_back(watched(l1, learned));
|
||||
}
|
||||
|
||||
bool solver::propagate_bin_clause(literal l1, literal l2) {
|
||||
|
@ -1331,6 +1340,7 @@ namespace sat {
|
|||
void solver::add_assumption(literal lit) {
|
||||
m_assumption_set.insert(lit);
|
||||
m_assumptions.push_back(lit);
|
||||
set_external(lit.var());
|
||||
VERIFY(is_external(lit.var()));
|
||||
}
|
||||
|
||||
|
@ -1419,6 +1429,8 @@ namespace sat {
|
|||
if (m_conflicts_since_init < m_next_simplify) {
|
||||
return;
|
||||
}
|
||||
integrity_checker si(*this);
|
||||
si.check_watches();
|
||||
m_simplifications++;
|
||||
IF_VERBOSE(2, verbose_stream() << "(sat.simplify :simplifications " << m_simplifications << ")\n";);
|
||||
|
||||
|
@ -1430,26 +1442,28 @@ namespace sat {
|
|||
|
||||
m_cleaner();
|
||||
CASSERT("sat_simplify_bug", check_invariant());
|
||||
si.check_watches();
|
||||
|
||||
m_scc();
|
||||
CASSERT("sat_simplify_bug", check_invariant());
|
||||
si.check_watches();
|
||||
|
||||
m_simplifier(false);
|
||||
CASSERT("sat_simplify_bug", check_invariant());
|
||||
CASSERT("sat_missed_prop", check_missed_propagation());
|
||||
|
||||
si.check_watches();
|
||||
if (!m_learned.empty()) {
|
||||
m_simplifier(true);
|
||||
CASSERT("sat_missed_prop", check_missed_propagation());
|
||||
CASSERT("sat_simplify_bug", check_invariant());
|
||||
}
|
||||
|
||||
si.check_watches();
|
||||
if (m_config.m_lookahead_simplify) {
|
||||
lookahead lh(*this);
|
||||
lh.simplify();
|
||||
lh.collect_statistics(m_aux_stats);
|
||||
}
|
||||
|
||||
si.check_watches();
|
||||
sort_watch_lits();
|
||||
CASSERT("sat_simplify_bug", check_invariant());
|
||||
|
||||
|
@ -1575,7 +1589,7 @@ namespace sat {
|
|||
literal l = ~to_literal(l_idx);
|
||||
if (value_at(l, m) != l_true) {
|
||||
for (watched const& w : wlist) {
|
||||
if (!w.is_binary_unblocked_clause())
|
||||
if (!w.is_binary_non_learned_clause())
|
||||
continue;
|
||||
literal l2 = w.get_literal();
|
||||
if (value_at(l2, m) != l_true) {
|
||||
|
|
|
@ -169,6 +169,7 @@ namespace sat {
|
|||
friend class cleaner;
|
||||
friend class simplifier;
|
||||
friend class scc;
|
||||
friend class big;
|
||||
friend class elim_eqs;
|
||||
friend class asymm_branch;
|
||||
friend class probing;
|
||||
|
|
|
@ -40,6 +40,38 @@ namespace sat {
|
|||
return false;
|
||||
}
|
||||
|
||||
watched* find_binary_watch(watch_list & wlist, literal l) {
|
||||
for (watched& w : wlist) {
|
||||
if (w.is_binary_clause() && w.get_literal() == l) return &w;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
watched const* find_binary_watch(watch_list const& wlist, literal l) {
|
||||
for (watched const& w : wlist) {
|
||||
if (w.is_binary_clause() && w.get_literal() == l) return &w;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void erase_binary_watch(watch_list& wlist, literal l) {
|
||||
watch_list::iterator it = wlist.begin(), end = wlist.end();
|
||||
watch_list::iterator it2 = it;
|
||||
bool found = false;
|
||||
for (; it != end; ++it) {
|
||||
if (it->is_binary_clause() && it->get_literal() == l && !found) {
|
||||
found = true;
|
||||
}
|
||||
else {
|
||||
*it2 = *it;
|
||||
++it2;
|
||||
}
|
||||
}
|
||||
wlist.set_end(it2);
|
||||
VERIFY(found);
|
||||
}
|
||||
|
||||
|
||||
std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist) {
|
||||
bool first = true;
|
||||
for (watched const& w : wlist) {
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace sat {
|
|||
SASSERT(is_binary_clause());
|
||||
SASSERT(get_literal() == l);
|
||||
SASSERT(is_learned() == learned);
|
||||
SASSERT(learned || is_binary_unblocked_clause());
|
||||
SASSERT(learned || is_binary_non_learned_clause());
|
||||
}
|
||||
|
||||
watched(literal l1, literal l2) {
|
||||
|
@ -88,15 +88,12 @@ namespace sat {
|
|||
void set_literal(literal l) { SASSERT(is_binary_clause()); m_val1 = l.to_uint(); }
|
||||
bool is_learned() const { SASSERT(is_binary_clause()); return (m_val2 >> 2) == 1; }
|
||||
|
||||
bool is_binary_unblocked_clause() const { return m_val2 == 0; }
|
||||
bool is_binary_learned_clause() const { return is_binary_clause() && is_learned(); }
|
||||
bool is_binary_non_learned_clause() const { return is_binary_clause() && !is_learned(); }
|
||||
|
||||
void mark_not_learned() { SASSERT(is_learned()); m_val2 = static_cast<unsigned>(BINARY); SASSERT(!is_learned()); }
|
||||
void set_blocked() { SASSERT(is_binary_clause()); SASSERT(!is_learned()); m_val2 |= (1 << 3); }
|
||||
bool is_blocked() const { SASSERT(is_binary_clause()); return 0 != (m_val2 & (1 << 3)); }
|
||||
void set_unblocked() { SASSERT(is_binary_clause()); SASSERT(is_blocked()); m_val2 &= ~(1u << 3u); }
|
||||
|
||||
void set_not_learned() { SASSERT(is_learned()); m_val2 = static_cast<unsigned>(BINARY); SASSERT(!is_learned()); }
|
||||
void set_learned() { SASSERT(!is_learned()); m_val2 = static_cast<unsigned>(BINARY) + (1u << 2); SASSERT(is_learned()); }
|
||||
|
||||
bool is_ternary_clause() const { return get_kind() == TERNARY; }
|
||||
literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(static_cast<unsigned>(m_val1)); }
|
||||
literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 2); }
|
||||
|
@ -135,6 +132,8 @@ namespace sat {
|
|||
|
||||
typedef vector<watched> watch_list;
|
||||
|
||||
watched* find_binary_watch(watch_list & wlist, literal l);
|
||||
watched const* find_binary_watch(watch_list const & wlist, literal l);
|
||||
bool erase_clause_watch(watch_list & wlist, clause_offset c);
|
||||
inline void erase_ternary_watch(watch_list & wlist, literal l1, literal l2) { wlist.erase(watched(l1, l2)); }
|
||||
|
||||
|
|
Loading…
Reference in a new issue