3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-06 01:24:08 +00:00

remove unused features related to weighted check-sat

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-01-13 20:53:22 -08:00
parent 9f49905582
commit bc6b3007de
16 changed files with 58 additions and 1656 deletions

View file

@ -2,7 +2,6 @@ z3_add_component(sat
SOURCES
dimacs.cpp
sat_asymm_branch.cpp
sat_bceq.cpp
sat_clause.cpp
sat_clause_set.cpp
sat_clause_use_list.cpp
@ -16,7 +15,6 @@ z3_add_component(sat
sat_probing.cpp
sat_scc.cpp
sat_simplifier.cpp
sat_sls.cpp
sat_solver.cpp
sat_watched.cpp
COMPONENT_DEPENDENCIES

View file

@ -302,17 +302,7 @@ public:
}
lbool check_sat(unsigned sz, expr* const* asms) {
if (m_st == s_primal_dual && m_c.sat_enabled()) {
rational max_weight = m_upper;
vector<rational> weights;
for (unsigned i = 0; i < sz; ++i) {
weights.push_back(get_weight(asms[i]));
}
return inc_sat_check_sat(s(), sz, asms, weights.c_ptr(), max_weight);
}
else {
return s().check_sat(sz, asms);
}
return s().check_sat(sz, asms);
}
void found_optimum() {

View file

@ -20,9 +20,49 @@ Notes:
#include "smt_literal.h"
#include "ast_pp.h"
#include "th_rewriter.h"
#include "sat_sls.h"
#include "sat_types.h"
namespace smt {
class index_set {
unsigned_vector m_elems;
unsigned_vector m_index;
public:
unsigned num_elems() const { return m_elems.size(); }
unsigned operator[](unsigned idx) const { return m_elems[idx]; }
void reset() { m_elems.reset(); m_index.reset(); }
bool empty() const { return m_elems.empty(); }
bool contains(unsigned idx) const {
return
(idx < m_index.size()) &&
(m_index[idx] < m_elems.size()) &&
(m_elems[m_index[idx]] == idx);
}
void insert(unsigned idx) {
m_index.reserve(idx+1);
if (!contains(idx)) {
m_index[idx] = m_elems.size();
m_elems.push_back(idx);
}
}
void remove(unsigned idx) {
if (!contains(idx)) return;
unsigned pos = m_index[idx];
m_elems[pos] = m_elems.back();
m_index[m_elems[pos]] = pos;
m_elems.pop_back();
}
unsigned choose(random_gen& rnd) const {
SASSERT(!empty());
return m_elems[rnd(num_elems())];
}
};
struct pb_sls::imp {
struct clause {
@ -73,8 +113,8 @@ namespace smt {
expr_ref_vector m_trail;
obj_map<expr, unsigned> m_decl2var; // map declarations to Boolean variables.
ptr_vector<expr> m_var2decl; // reverse map
sat::index_set m_hard_false; // list of hard clauses that are false.
sat::index_set m_soft_false; // list of soft clauses that are false.
index_set m_hard_false; // list of hard clauses that are false.
index_set m_soft_false; // list of soft clauses that are false.
unsigned m_max_flips; // maximal number of flips
unsigned m_non_greedy_percent; // percent of moves to do non-greedy style
random_gen m_rng;

View file

@ -1,530 +0,0 @@
/*++
Copyright (c) 2014 Microsoft Corporation
Module Name:
sat_bceq.cpp
Abstract:
Find equivalent literals based on blocked clause decomposition.
Author:
Nikolaj Bjorner (nbjorner) 2014-09-27.
Revision History:
--*/
#include"sat_bceq.h"
#include"sat_solver.h"
#include"trace.h"
#include"bit_vector.h"
#include"map.h"
#include"sat_elim_eqs.h"
namespace sat {
void bceq::use_list::init(unsigned num_vars) {
m_clauses.reset();
m_clauses.resize(2*num_vars);
}
void bceq::use_list::insert(clause& c) {
unsigned sz = c.size();
for (unsigned i = 0; i < sz; i++) {
m_clauses[c[i].index()].push_back(&c);
}
}
void bceq::use_list::erase(clause& c) {
unsigned sz = c.size();
for (unsigned i = 0; i < sz; i++) {
m_clauses[c[i].index()].erase(&c);
}
}
ptr_vector<clause>& bceq::use_list::get(literal lit) {
return m_clauses[lit.index()];
}
bceq::bceq(solver & s):
m_solver(s) {
}
void bceq::register_clause(clause* cls) {
m_clauses.setx(cls->id(), cls, 0);
}
void bceq::unregister_clause(clause* cls) {
m_clauses.setx(cls->id(), 0, 0);
}
void bceq::init() {
m_clauses.reset();
m_bin_clauses.reset();
m_L.reset();
m_R.reset();
m_L_blits.reset();
m_R_blits.reset();
m_bce_use_list.reset();
clause * const* it = m_solver.begin_clauses();
clause * const* end = m_solver.end_clauses();
for (; it != end; ++it) {
clause* cls = *it;
if (!cls->was_removed()) {
m_use_list->insert(*cls);
register_clause(cls);
}
}
bin_clauses bc;
m_solver.collect_bin_clauses(bc, false); // exclude roots.
literal lits[2];
for (unsigned i = 0; i < bc.size(); ++i) {
lits[0] = bc[i].first;
lits[1] = bc[i].second;
clause* cls = m_solver.m_cls_allocator.mk_clause(2, lits, false);
m_use_list->insert(*cls);
m_bin_clauses.push_back(cls);
register_clause(cls);
}
TRACE("sat",
for (unsigned i = 0; i < m_clauses.size(); ++i) {
clause const* cls = m_clauses[i];
if (cls) tout << *cls << "\n";
});
}
void bceq::pure_decompose() {
// while F != empty
// pick a clause and variable x in clause.
// get use list U1 of x and U2 of ~x
// assume |U1| >= |U2|
// add U1 to clause set.
for (unsigned i = 0; i < m_clauses.size(); ++i) {
clause* cls = m_clauses[i];
if (cls) {
SASSERT(i == cls->id());
pure_decompose((*cls)[0]);
SASSERT(!m_clauses[i]);
}
}
m_L.reverse();
m_L_blits.reverse();
}
void bceq::pure_decompose(literal lit) {
clause_use_list& pos = m_use_list->get(lit);
clause_use_list& neg = m_use_list->get(~lit);
unsigned sz1 = m_L.size();
unsigned sz2 = m_R.size();
pure_decompose(pos, m_L);
pure_decompose(neg, m_R);
unsigned delta1 = m_L.size() - sz1;
unsigned delta2 = m_R.size() - sz2;
if (delta1 < delta2) {
m_L_blits.resize(sz1+delta2, ~lit);
m_R_blits.resize(sz2+delta1, lit);
for (unsigned i = 0; i < delta1; ++i) {
std::swap(m_L[sz1 + i], m_R[sz2 + i]);
}
for (unsigned i = delta1; i < delta2; ++i) {
m_L.push_back(m_R[sz2 + i]);
}
m_R.resize(sz2 + delta1);
std::swap(delta1, delta2);
}
else {
m_L_blits.resize(sz1+delta1, lit);
m_R_blits.resize(sz2+delta2, ~lit);
}
TRACE("bceq", tout << lit << " " << "pos: " << delta1 << " " << "neg: " << delta2 << "\n";);
}
void bceq::pure_decompose(clause_use_list& uses, svector<clause*>& clauses) {
unsigned sz = uses.size();
for (unsigned i = 0; i < sz; ++i) {
clause& cls = *uses[i];
if (!cls.was_removed() && m_clauses[cls.id()]) {
clauses.push_back(&cls);
m_clauses[cls.id()] = 0;
}
}
}
void bceq::post_decompose() {
m_marked.reset();
m_marked.resize(2*m_solver.num_vars(), false);
use_list ul;
use_list* save = m_use_list;
m_use_list = &ul;
ul.init(m_solver.num_vars());
for (unsigned i = 0; i < m_L.size(); ++i) {
ul.insert(*m_L[i]);
}
// cheap pass: add clauses from R in order
// such that they are blocked with respect to
// predecessors.
m_removed.reset();
for (unsigned i = 0; i < m_R.size(); ++i) {
literal lit = find_blocked(*m_R[i]);
if (lit != null_literal) {
m_L.push_back(m_R[i]);
m_L_blits.push_back(lit);
ul.insert(*m_R[i]);
m_R[i] = m_R.back();
m_R_blits[i] = m_R_blits.back();
m_R.pop_back();
m_R_blits.pop_back();
--i;
}
}
// expensive pass: add clauses from R as long
// as BCE produces the empty set of clauses.
m_bce_use_list.init(m_solver.num_vars());
for (unsigned i = 0; i < m_L.size(); ++i) {
m_bce_use_list.insert(*m_L[i]);
}
for (unsigned i = 0; i < m_R.size(); ++i) {
if (bce(*m_R[i])) {
m_R[i] = m_R.back();
m_R_blits[i] = m_R_blits.back();
m_R.pop_back();
m_R_blits.pop_back();
--i;
}
}
m_use_list = save;
}
// Note: replay blocked clause elimination:
// Suppose C u { c1 } is blocked.
// annotate each clause by blocking literal.
// for new clause c2, check if C u { c2 } is blocked.
// For each c in C record which literal it is blocked.
// (Order the clauses in C by block ordering)
// l | c is blocked,
// -> c2 contains ~l => check if c c2 is blocked
//
bool bceq::bce(clause& cls0) {
IF_VERBOSE(1, verbose_stream() << "bce " << m_L.size() << " " << m_R.size() << " " << cls0 << "\n";);
unsigned_vector& live_clauses = m_live_clauses;
live_clauses.reset();
m_use_list = &m_bce_use_list;
m_bce_use_list.insert(cls0);
svector<clause*>& clauses = m_L;
literal_vector& blits = m_L_blits;
clauses.push_back(&cls0);
blits.push_back(null_literal);
bool removed = false;
m_removed.reset();
for (unsigned i = 0; i < clauses.size(); ++i) {
clause& cls1 = *clauses[i];
literal lit = find_blocked(cls1);
if (lit == null_literal) {
live_clauses.push_back(i);
}
else {
m_removed.setx(cls1.id(), true, false);
removed = true;
}
}
while (removed) {
removed = false;
//std::cout << live_clauses.size() << " ";
for (unsigned i = 0; i < live_clauses.size(); ++i) {
clause& cls1 = *clauses[live_clauses[i]];
literal lit = find_blocked(cls1);
if (lit != null_literal) {
m_removed.setx(cls1.id(), true, false);
removed = true;
live_clauses[i] = live_clauses.back();
live_clauses.pop_back();
--i;
}
}
}
//std::cout << "\n";
m_bce_use_list.erase(cls0);
clauses.pop_back();
blits.pop_back();
return live_clauses.empty();
}
literal bceq::find_blocked(clause const& cls) {
TRACE("bceq", tout << cls << "\n";);
unsigned sz = cls.size();
for (unsigned i = 0; i < sz; ++i) {
m_marked[(~cls[i]).index()] = true;
}
literal result = null_literal;
for (unsigned i = 0; i < sz; ++i) {
literal lit = cls[i];
if (is_blocked(lit)) {
TRACE("bceq", tout << "is blocked " << lit << " : " << cls << "\n";);
result = lit;
break;
}
}
for (unsigned i = 0; i < sz; ++i) {
m_marked[(~cls[i]).index()] = false;
}
return result;
}
bool bceq::is_blocked(literal lit) const {
clause_use_list& uses = m_use_list->get(~lit);
unsigned sz = uses.size();
for (unsigned i = 0; i < sz; ++i) {
clause const& cls = *uses[i];
unsigned sz = cls.size();
bool is_axiom = m_removed.get(cls.id(), false);
for (unsigned i = 0; !is_axiom && i < sz; ++i) {
is_axiom = m_marked[cls[i].index()] && cls[i] != ~lit;
}
TRACE("bceq", tout << "resolvent " << lit << " : " << cls << " " << (is_axiom?"axiom":"non-axiom") << "\n";);
if (!is_axiom) {
return false;
}
}
return true;
}
void bceq::init_rbits() {
m_rbits.reset();
for (unsigned i = 0; i < m_solver.num_vars(); ++i) {
uint64 lo = m_rand() + (m_rand() << 16);
uint64 hi = m_rand() + (m_rand() << 16);
m_rbits.push_back(lo + (hi << 32ULL));
}
}
void bceq::init_reconstruction_stack() {
m_rstack.reset();
m_bstack.reset();
// decomposition already creates a blocked stack in the proper order.
m_rstack.append(m_L);
m_bstack.append(m_L_blits);
}
uint64 bceq::eval_clause(clause const& cls) const {
uint64 b = 0;
unsigned sz = cls.size();
for (unsigned i = 0; i < sz; ++i) {
literal lit = cls[i];
uint64 val = m_rbits[lit.var()];
if (lit.sign()) {
val = ~val;
}
b |= val;
}
return b;
}
void bceq::sat_sweep() {
init_rbits();
init_reconstruction_stack();
for (unsigned i = 0; i < m_rstack.size(); ++i) {
clause const& cls = *m_rstack[i];
literal block_lit = m_bstack[i];
uint64 b = eval_clause(cls);
// v = 0, b = 0 -> v := 1
// v = 0, b = 1 -> v := 0
// v = 1, b = 0 -> v := 0
// v = 1, b = 1 -> v := 1
m_rbits[block_lit.var()] ^= ~b;
}
DEBUG_CODE(verify_sweep(););
}
void bceq::verify_sweep() {
DEBUG_CODE(
for (unsigned i = 0; i < m_L.size(); ++i) {
uint64 b = eval_clause(*m_L[i]);
SASSERT((~b) == 0);
});
}
struct u64_hash { unsigned operator()(uint64 u) const { return (unsigned)u; } };
struct u64_eq { bool operator()(uint64 u1, uint64 u2) const { return u1 == u2; } };
void bceq::extract_partition() {
unsigned num_vars = m_solver.num_vars();
map<uint64, unsigned, u64_hash, u64_eq> table;
union_find<> union_find(m_union_find_ctx);
for (unsigned i = 0; i < num_vars; ++i) {
m_s->mk_var(true, true);
union_find.mk_var();
}
for (unsigned i = 0; i < m_L.size(); ++i) {
m_s->mk_clause(m_L[i]->size(), m_L[i]->begin());
}
for (unsigned i = 0; i < num_vars; ++i) {
uint64 val = m_rbits[i];
unsigned index;
if (table.find(val, index)) {
union_find.merge(i, index);
}
else if (table.find(~val, index)) {
union_find.merge(i, index);
}
else {
table.insert(val, i);
}
}
TRACE("sat", union_find.display(tout););
//
// Preliminary version:
// A more appropriate is to walk each pair,
// and refine partition based on SAT results.
//
for (unsigned i = 0; i < num_vars; ++i) {
if (!union_find.is_root(i)) continue;
unsigned v = union_find.next(i);
unsigned last_v = UINT_MAX;
if (!m_solver.was_eliminated(i)) {
last_v = i;
}
while (v != i) {
if (!m_solver.was_eliminated(v)) {
if (last_v != UINT_MAX) {
if (check_equality(v, last_v)) {
// last_v was eliminated.
}
else {
// TBD: refine partition.
}
}
last_v = v;
}
v = union_find.next(v);
}
}
}
bool bceq::check_equality(unsigned v1, unsigned v2) {
TRACE("sat", tout << "check: " << v1 << " = " << v2 << "\n";);
uint64 val1 = m_rbits[v1];
uint64 val2 = m_rbits[v2];
literal l1 = literal(v1, false);
literal l2 = literal(v2, false);
if (val1 != val2) {
SASSERT(val1 == ~val2);
l2.neg();
}
if (is_already_equiv(l1, l2)) {
TRACE("sat", tout << "Already equivalent: " << l1 << " " << l2 << "\n";);
return false;
}
literal lits[2];
lits[0] = l1;
lits[1] = ~l2;
lbool is_sat = m_s->check(2, lits);
if (is_sat == l_false) {
lits[0] = ~l1;
lits[1] = l2;
is_sat = m_s->check(2, lits);
}
if (is_sat == l_false) {
TRACE("sat", tout << "Found equivalent: " << l1 << " " << l2 << "\n";);
assert_equality(l1, l2);
}
else {
TRACE("sat", tout << "Not equivalent: " << l1 << " " << l2 << "\n";);
// TBD: if is_sat == l_true, then refine partition.
}
return is_sat == l_false;
}
bool bceq::is_already_equiv(literal l1, literal l2) {
watch_list const& w1 = m_solver.get_wlist(l1);
bool found = false;
for (unsigned i = 0; !found && i < w1.size(); ++i) {
watched const& w = w1[i];
found = w.is_binary_clause() && w.get_literal() == ~l2;
}
if (!found) return false;
found = false;
watch_list const& w2 = m_solver.get_wlist(~l1);
for (unsigned i = 0; !found && i < w2.size(); ++i) {
watched const& w = w2[i];
found = w.is_binary_clause() && w.get_literal() == l2;
}
return found;
}
void bceq::assert_equality(literal l1, literal l2) {
if (l2.sign()) {
l1.neg();
l2.neg();
}
literal_vector roots;
bool_var_vector vars;
for (unsigned i = 0; i < m_solver.num_vars(); ++i) {
roots.push_back(literal(i, false));
}
roots[l2.var()] = l1;
vars.push_back(l2.var());
elim_eqs elim(m_solver);
IF_VERBOSE(1,
for (unsigned i = 0; i < vars.size(); ++i) {
verbose_stream() << "var: " << vars[i] << " root: " << roots[vars[i]] << "\n";
});
elim(roots, vars);
}
void bceq::cleanup() {
m_solver.del_clauses(m_bin_clauses.begin(), m_bin_clauses.end());
m_bin_clauses.reset();
}
void bceq::operator()() {
if (!m_solver.m_config.m_bcd) return;
flet<bool> _disable_bcd(m_solver.m_config.m_bcd, false);
flet<bool> _disable_min(m_solver.m_config.m_core_minimize, false);
flet<bool> _disable_opt(m_solver.m_config.m_optimize_model, false);
flet<unsigned> _bound_maxc(m_solver.m_config.m_max_conflicts, 1500);
use_list ul;
solver s(m_solver.m_params, m_solver.rlimit(), 0);
s.m_config.m_bcd = false;
s.m_config.m_core_minimize = false;
s.m_config.m_optimize_model = false;
s.m_config.m_max_conflicts = 1500;
m_use_list = &ul;
m_s = &s;
ul.init(m_solver.num_vars());
init();
pure_decompose();
post_decompose();
IF_VERBOSE(1, verbose_stream() << "Decomposed set " << m_L.size() << " rest: " << m_R.size() << "\n";);
TRACE("sat",
tout << "Decomposed set " << m_L.size() << "\n";
for (unsigned i = 0; i < m_L.size(); ++i) {
clause const* cls = m_L[i];
if (cls) tout << *cls << "\n";
}
tout << "remainder " << m_R.size() << "\n";
for (unsigned i = 0; i < m_R.size(); ++i) {
clause const* cls = m_R[i];
if (cls) tout << *cls << "\n";
}
);
sat_sweep();
extract_partition();
cleanup();
}
};

View file

@ -1,89 +0,0 @@
/*++
Copyright (c) 2014 Microsoft Corporation
Module Name:
sat_bceq.h
Abstract:
Find equivalent literals based on blocked clause decomposition.
Author:
Nikolaj Bjorner (nbjorner) 2014-09-27.
Revision History:
--*/
#ifndef SAT_BCEQ_H_
#define SAT_BCEQ_H_
#include"sat_types.h"
#include"union_find.h"
namespace sat {
class solver;
class bceq {
typedef ptr_vector<clause> clause_use_list;
class use_list {
vector<ptr_vector<clause> > m_clauses;
public:
use_list() {}
void init(unsigned num_vars);
void reset() { m_clauses.reset(); }
void erase(clause& c);
void insert(clause& c);
ptr_vector<clause>& get(literal lit);
};
typedef std::pair<literal, literal> bin_clause;
typedef svector<bin_clause> bin_clauses;
solver & m_solver;
use_list* m_use_list;
use_list m_bce_use_list;
solver* m_s;
random_gen m_rand;
svector<clause*> m_clauses;
svector<clause*> m_L;
svector<clause*> m_R;
literal_vector m_L_blits;
literal_vector m_R_blits;
svector<clause*> m_bin_clauses;
svector<uint64> m_rbits;
svector<clause*> m_rstack; // stack of blocked clauses
literal_vector m_bstack; // stack of blocking literals
svector<bool> m_marked;
svector<bool> m_removed; // set of clauses removed (not considered in clause set during BCE)
union_find_default_ctx m_union_find_ctx;
unsigned_vector m_live_clauses;
void init();
void register_clause(clause* cls);
void unregister_clause(clause* cls);
void pure_decompose();
void pure_decompose(literal lit);
void pure_decompose(ptr_vector<clause>& uses, svector<clause*>& clauses);
void post_decompose();
literal find_blocked(clause const& cls);
bool bce(clause& cls);
bool is_blocked(literal lit) const;
void init_rbits();
void init_reconstruction_stack();
void sat_sweep();
void cleanup();
uint64 eval_clause(clause const& cls) const;
void verify_sweep();
void extract_partition();
bool check_equality(unsigned v1, unsigned v2);
bool is_already_equiv(literal l1, literal l2);
void assert_equality(literal l1, literal l2);
public:
bceq(solver & s);
void operator()();
};
};
#endif

View file

@ -111,8 +111,6 @@ namespace sat {
m_minimize_lemmas = p.minimize_lemmas();
m_core_minimize = p.core_minimize();
m_core_minimize_partial = p.core_minimize_partial();
m_optimize_model = p.optimize_model();
m_bcd = p.bcd();
m_dyn_sub_res = p.dyn_sub_res();
}

View file

@ -72,8 +72,6 @@ namespace sat {
bool m_dyn_sub_res;
bool m_core_minimize;
bool m_core_minimize_partial;
bool m_optimize_model;
bool m_bcd;
symbol m_always_true;

View file

@ -20,11 +20,10 @@ Notes:
#include "sat_solver.h"
#include "sat_mus.h"
#include "sat_sls.h"
namespace sat {
mus::mus(solver& s):s(s), m_is_active(false), m_best_value(0), m_restart(0), m_max_restarts(0) {}
mus::mus(solver& s):s(s), m_is_active(false),m_restart(0), m_max_restarts(0) {}
mus::~mus() {}
@ -32,7 +31,6 @@ namespace sat {
m_core.reset();
m_mus.reset();
m_model.reset();
m_best_value = 0;
m_max_restarts = (s.m_stats.m_restart - m_restart) + 10;
m_restart = s.m_stats.m_restart;
}
@ -45,21 +43,13 @@ namespace sat {
}
void mus::update_model() {
double new_value = s.m_wsls.evaluate_model(s.m_model);
if (m_model.empty()) {
m_model.append(s.m_model);
m_best_value = new_value;
}
else if (m_best_value > new_value) {
m_model.reset();
m_model.append(s.m_model);
m_best_value = new_value;
}
}
lbool mus::operator()() {
flet<bool> _disable_min(s.m_config.m_core_minimize, false);
flet<bool> _disable_opt(s.m_config.m_optimize_model, false);
flet<bool> _is_active(m_is_active, true);
IF_VERBOSE(3, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";);
reset();
@ -120,9 +110,6 @@ namespace sat {
SASSERT(value_at(lit, s.get_model()) == l_false);
mus.push_back(lit);
update_model();
if (!core.empty()) {
// mr(); // TBD: measure
}
break;
}
case l_false:
@ -262,27 +249,5 @@ namespace sat {
IF_VERBOSE(3, verbose_stream() << "core verification: " << is_sat << " " << core << "\n";);
}
void mus::mr() {
sls sls(s);
literal_vector tabu;
tabu.append(m_mus);
tabu.append(m_core);
bool reuse_model = false;
for (unsigned i = m_mus.size(); i < tabu.size(); ++i) {
tabu[i] = ~tabu[i];
lbool is_sat = sls(tabu.size(), tabu.c_ptr(), reuse_model);
tabu[i] = ~tabu[i];
if (is_sat == l_true) {
m_mus.push_back(tabu[i]);
m_core.erase(tabu[i]);
IF_VERBOSE(3, verbose_stream() << "in core " << tabu[i] << "\n";);
reuse_model = true;
}
else {
IF_VERBOSE(3, verbose_stream() << "NOT in core " << tabu[i] << "\n";);
reuse_model = false;
}
}
}
}

View file

@ -26,7 +26,6 @@ namespace sat {
literal_vector m_mus;
bool m_is_active;
model m_model; // model obtained during minimal unsat core
double m_best_value;
unsigned m_restart;
unsigned m_max_restarts;
@ -41,7 +40,6 @@ namespace sat {
lbool mus1();
lbool mus2();
lbool qx(literal_set& assignment, literal_set& support, bool has_support);
void mr();
void reset();
void set_core();
void update_model();

View file

@ -22,6 +22,4 @@ def_module_params('sat',
('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'),
('core.minimize', BOOL, False, 'minimize computed core'),
('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'),
('optimize_model', BOOL, False, 'enable optimization of soft constraints'),
('bcd', BOOL, False, 'enable blocked clause decomposition for equality extraction'),
('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks')))

View file

@ -1,686 +0,0 @@
/*++
Copyright (c) 2014 Microsoft Corporation
Module Name:
sat_sls.cpp
Abstract:
SLS for clauses in SAT solver
Author:
Nikolaj Bjorner (nbjorner) 2014-12-8
Notes:
--*/
#include "sat_sls.h"
#include "sat_solver.h"
namespace sat {
bool index_set::contains(unsigned idx) const {
return
(idx < m_index.size()) &&
(m_index[idx] < m_elems.size()) &&
(m_elems[m_index[idx]] == idx);
}
void index_set::insert(unsigned idx) {
m_index.reserve(idx+1);
if (!contains(idx)) {
m_index[idx] = m_elems.size();
m_elems.push_back(idx);
}
}
void index_set::remove(unsigned idx) {
if (!contains(idx)) return;
unsigned pos = m_index[idx];
m_elems[pos] = m_elems.back();
m_index[m_elems[pos]] = pos;
m_elems.pop_back();
}
unsigned index_set::choose(random_gen& rnd) const {
SASSERT(!empty());
return m_elems[rnd(num_elems())];
}
sls::sls(solver& s): s(s) {
m_prob_choose_min_var = 43;
m_clause_generation = 0;
}
sls::~sls() {
for (unsigned i = 0; i < m_bin_clauses.size(); ++i) {
m_alloc.del_clause(m_bin_clauses[i]);
}
}
lbool sls::operator()(unsigned sz, literal const* tabu, bool reuse_model) {
init(sz, tabu, reuse_model);
unsigned i;
for (i = 0; !m_false.empty() && !s.canceled() && i < m_max_tries; ++i) {
flip();
}
IF_VERBOSE(2, verbose_stream() << "tries " << i << "\n";);
if (m_false.empty()) {
SASSERT(s.check_model(m_model));
return l_true;
}
return l_undef;
}
void sls::init(unsigned sz, literal const* tabu, bool reuse_model) {
bool same_generation = (m_clause_generation == s.m_stats.m_non_learned_generation);
if (!same_generation) {
init_clauses();
init_use();
IF_VERBOSE(0, verbose_stream() << s.m_stats.m_non_learned_generation << " " << m_clause_generation << "\n";);
}
if (!reuse_model) {
init_model();
}
init_tabu(sz, tabu);
m_clause_generation = s.m_stats.m_non_learned_generation;
m_max_tries = 10*(s.num_vars() + m_clauses.size());
}
void sls::init_clauses() {
for (unsigned i = 0; i < m_bin_clauses.size(); ++i) {
m_alloc.del_clause(m_bin_clauses[i]);
}
m_bin_clauses.reset();
m_clauses.reset();
clause * const * it = s.begin_clauses();
clause * const * end = s.end_clauses();
for (; it != end; ++it) {
m_clauses.push_back(*it);
}
svector<solver::bin_clause> bincs;
s.collect_bin_clauses(bincs, false);
literal lits[2];
for (unsigned i = 0; i < bincs.size(); ++i) {
lits[0] = bincs[i].first;
lits[1] = bincs[i].second;
clause* cl = m_alloc.mk_clause(2, lits, false);
m_clauses.push_back(cl);
m_bin_clauses.push_back(cl);
}
}
void sls::init_model() {
m_num_true.reset();
m_model.reset();
m_model.append(s.get_model());
unsigned sz = m_clauses.size();
for (unsigned i = 0; i < sz; ++i) {
clause const& c = *m_clauses[i];
unsigned n = 0;
unsigned csz = c.size();
for (unsigned j = 0; j < csz; ++j) {
lbool val = value_at(c[j], m_model);
switch (val) {
case l_true:
++n;
break;
case l_undef:
++n;
m_model[c[j].var()] = c[j].sign()?l_false:l_true;
SASSERT(value_at(c[j], m_model) == l_true);
break;
default:
break;
}
}
m_num_true.push_back(n);
if (n == 0) {
m_false.insert(i);
}
}
}
void sls::init_tabu(unsigned sz, literal const* tabu) {
// our main use is where m_model satisfies all the hard constraints.
// SASSERT(s.check_model(m_model));
// SASSERT(m_false.empty());
// ASSERT: m_num_true is correct count.
m_tabu.reset();
m_tabu.resize(s.num_vars(), false);
for (unsigned i = 0; i < sz; ++i) {
literal lit = tabu[i];
if (s.m_level[lit.var()] == 0) continue;
if (value_at(lit, m_model) == l_false) {
flip(lit);
}
m_tabu[lit.var()] = true;
}
for (unsigned i = 0; i < s.m_trail.size(); ++i) {
literal lit = s.m_trail[i];
if (s.m_level[lit.var()] > 0) break;
if (value_at(lit, m_model) != l_true) {
flip(lit);
}
m_tabu[lit.var()] = true;
}
}
void sls::init_use() {
m_use_list.reset();
m_use_list.resize(s.num_vars()*2);
unsigned sz = m_clauses.size();
for (unsigned i = 0; i < sz; ++i) {
clause const& c = *m_clauses[i];
unsigned csz = c.size();
for (unsigned j = 0; j < csz; ++j) {
m_use_list[c[j].index()].push_back(i);
}
}
DEBUG_CODE(check_use_list(););
}
unsigned_vector const& sls::get_use(literal lit) {
SASSERT(lit.index() < m_use_list.size());
return m_use_list[lit.index()];
}
unsigned sls::get_break_count(literal lit, unsigned min_break) {
SASSERT(value_at(lit, m_model) == l_false);
unsigned result = 0;
unsigned_vector const& uses = get_use(~lit);
unsigned sz = uses.size();
for (unsigned i = 0; i < sz; ++i) {
if (m_num_true[uses[i]] == 1) {
++result;
if (result > min_break) return result;
}
}
return result;
}
bool sls::pick_flip(literal& lit) {
unsigned clause_idx = m_false.choose(m_rand);
clause const& c = *m_clauses[clause_idx];
SASSERT(!c.satisfied_by(m_model));
unsigned min_break = UINT_MAX;
unsigned sz = c.size();
m_min_vars.reset();
for (unsigned i = 0; i < sz; ++i) {
lit = c[i];
if (m_tabu[lit.var()]) continue;
unsigned break_count = get_break_count(lit, min_break);
if (break_count < min_break) {
min_break = break_count;
m_min_vars.reset();
m_min_vars.push_back(lit);
}
else if (break_count == min_break) {
m_min_vars.push_back(lit);
}
}
if (min_break == 0 || (!m_min_vars.empty() && m_rand(100) >= m_prob_choose_min_var)) {
lit = m_min_vars[m_rand(m_min_vars.size())];
return true;
}
else if (min_break == UINT_MAX) {
return false;
}
else {
lit = c[m_rand(c.size())];
return !m_tabu[lit.var()];
}
}
void sls::flip() {
literal lit;
if (pick_flip(lit)) {
flip(lit);
}
}
void sls::flip(literal lit) {
//IF_VERBOSE(0, verbose_stream() << lit << " ";);
SASSERT(value_at(lit, m_model) == l_false);
SASSERT(!m_tabu[lit.var()]);
m_model[lit.var()] = lit.sign()?l_false:l_true;
SASSERT(value_at(lit, m_model) == l_true);
unsigned_vector const& use1 = get_use(lit);
unsigned sz = use1.size();
for (unsigned i = 0; i < sz; ++i) {
unsigned cl = use1[i];
m_num_true[cl]++;
SASSERT(m_num_true[cl] <= m_clauses[cl]->size());
if (m_num_true[cl] == 1) m_false.remove(cl);
}
unsigned_vector const& use2 = get_use(~lit);
sz = use2.size();
for (unsigned i = 0; i < sz; ++i) {
unsigned cl = use2[i];
SASSERT(m_num_true[cl] > 0);
m_num_true[cl]--;
if (m_num_true[cl] == 0) m_false.insert(cl);
}
}
void sls::check_invariant() {
DEBUG_CODE(
for (unsigned i = 0; i < m_clauses.size(); ++i) {
clause const& c = *m_clauses[i];
bool is_sat = c.satisfied_by(m_model);
SASSERT(is_sat != m_false.contains(i));
SASSERT(is_sat == (m_num_true[i] > 0));
});
}
void sls::check_use_list() {
DEBUG_CODE(
for (unsigned i = 0; i < m_clauses.size(); ++i) {
clause const& c = *m_clauses[i];
for (unsigned j = 0; j < c.size(); ++j) {
unsigned idx = c[j].index();
SASSERT(m_use_list[idx].contains(i));
}
}
for (unsigned i = 0; i < m_use_list.size(); ++i) {
literal lit = to_literal(i);
for (unsigned j = 0; j < m_use_list[i].size(); ++j) {
clause const& c = *m_clauses[m_use_list[i][j]];
bool found = false;
for (unsigned k = 0; !found && k < c.size(); ++k) {
found = c[k] == lit;
}
SASSERT(found);
}
});
}
void sls::display(std::ostream& out) const {
out << "Model\n";
for (bool_var v = 0; v < m_model.size(); ++v) {
out << v << ": " << m_model[v] << "\n";
}
out << "Clauses\n";
unsigned sz = m_false.num_elems();
for (unsigned i = 0; i < sz; ++i) {
out << *m_clauses[m_false[i]] << "\n";
}
for (unsigned i = 0; i < m_clauses.size(); ++i) {
if (m_false.contains(i)) continue;
clause const& c = *m_clauses[i];
out << c << " " << m_num_true[i] << "\n";
}
bool has_tabu = false;
for (unsigned i = 0; !has_tabu && i < m_tabu.size(); ++i) {
has_tabu = m_tabu[i];
}
if (has_tabu) {
out << "Tabu: ";
for (unsigned i = 0; i < m_tabu.size(); ++i) {
if (m_tabu[i]) {
literal lit(i, false);
if (value_at(lit, m_model) == l_false) lit.neg();
out << lit << " ";
}
}
out << "\n";
}
}
wsls::wsls(solver& s):
sls(s)
{
m_smoothing_probability = 1; // 1/1000
}
wsls::~wsls() {}
void wsls::set_soft(unsigned sz, literal const* lits, double const* weights) {
m_soft.reset();
m_weights.reset();
m_soft.append(sz, lits);
m_weights.append(sz, weights);
}
void wsls::opt(unsigned sz, literal const* tabu, bool reuse_model) {
init(sz, tabu, reuse_model);
//
// Initialize m_clause_weights, m_hscore, m_sscore.
//
m_best_value = m_false.empty()?evaluate_model(m_model):-1.0;
m_best_model.reset();
m_clause_weights.reset();
m_hscore.reset();
m_sscore.reset();
m_H.reset();
m_S.reset();
m_best_model.append(s.get_model());
m_clause_weights.resize(m_clauses.size(), 1);
m_sscore.resize(s.num_vars(), 0.0);
m_hscore.resize(s.num_vars(), 0);
for (unsigned i = 0; i < m_soft.size(); ++i) {
literal lit = m_soft[i];
m_sscore[lit.var()] = m_weights[i];
if (value_at(lit, m_model) == l_true) {
m_sscore[lit.var()] = -m_sscore[lit.var()];
}
}
for (bool_var i = 0; i < s.num_vars(); ++i) {
m_hscore[i] = compute_hscore(i);
refresh_scores(i);
}
DEBUG_CODE(check_invariant(););
unsigned i = 0;
for (; !s.canceled() && m_best_value > 0 && i < m_max_tries; ++i) {
wflip();
if (m_false.empty()) {
double val = evaluate_model(m_model);
if (val < m_best_value || m_best_value < 0.0) {
m_best_value = val;
m_best_model.reset();
m_best_model.append(m_model);
s.set_model(m_best_model);
IF_VERBOSE(1, verbose_stream() << "new value: " << val << " @ " << i << "\n";);
if (i*2 > m_max_tries) {
m_max_tries *= 2;
}
}
}
}
TRACE("sat", display(tout););
IF_VERBOSE(0, verbose_stream() << "tries " << i << "\n";);
}
void wsls::wflip() {
literal lit;
if (pick_wflip(lit)) {
// IF_VERBOSE(0, verbose_stream() << lit << " ";);
wflip(lit);
}
}
bool wsls::pick_wflip(literal & lit) {
unsigned idx;
if (!m_H.empty()) {
idx = m_H.choose(m_rand);
lit = literal(idx, false);
if (value_at(lit, m_model) == l_true) lit.neg();
SASSERT(value_at(lit, m_model) == l_false);
TRACE("sat", tout << "flip H(" << m_H.num_elems() << ") " << lit << "\n";);
}
else if (!m_S.empty()) {
double score = 0.0;
m_min_vars.reset();
for (unsigned i = 0; i < m_S.num_elems(); ++i) {
unsigned v = m_S[i];
SASSERT(m_sscore[v] > 0.0);
if (m_sscore[v] > score) {
m_min_vars.reset();
m_min_vars.push_back(literal(v, false));
score = m_sscore[v];
}
else if (m_sscore[v] == score) {
m_min_vars.push_back(literal(v, false));
}
}
lit = m_min_vars[m_rand(m_min_vars.size())]; // pick with largest sscore.
SASSERT(value_at(lit, m_model) == l_false);
TRACE("sat", tout << "flip S(" << m_min_vars.size() << "," << score << ") " << lit << "\n";);
}
else {
update_hard_weights();
if (!m_false.empty()) {
unsigned cls_idx = m_false.choose(m_rand);
clause const& c = *m_clauses[cls_idx];
lit = c[m_rand(c.size())];
TRACE("sat", tout << "flip hard(" << m_false.num_elems() << "," << c.size() << ") " << lit << "\n";);
}
else {
m_min_vars.reset();
for (unsigned i = 0; i < m_soft.size(); ++i) {
lit = m_soft[i];
if (value_at(lit, m_model) == l_false) {
m_min_vars.push_back(lit);
}
}
if (m_min_vars.empty()) {
SASSERT(m_best_value == 0.0);
UNREACHABLE(); // we should have exited the main loop before.
return false;
}
else {
lit = m_min_vars[m_rand(m_min_vars.size())];
}
TRACE("sat", tout << "flip soft(" << m_min_vars.size() << ", " << m_sscore[lit.var()] << ") " << lit << "\n";);
}
SASSERT(value_at(lit, m_model) == l_false);
}
return !m_tabu[lit.var()];
}
void wsls::wflip(literal lit) {
flip(lit);
unsigned v = lit.var();
m_sscore[v] = -m_sscore[v];
m_hscore[v] = compute_hscore(v);
refresh_scores(v);
recompute_hscores(lit);
}
void wsls::update_hard_weights() {
unsigned csz = m_clauses.size();
if (m_smoothing_probability >= m_rand(1000)) {
for (unsigned i = 0; i < csz; ++i) {
if (m_clause_weights[i] > 1 && !m_false.contains(i)) {
--m_clause_weights[i];
if (m_num_true[i] == 1) {
clause const& c = *m_clauses[i];
unsigned sz = c.size();
for (unsigned j = 0; j < sz; ++j) {
if (value_at(c[j], m_model) == l_true) {
++m_hscore[c[j].var()];
refresh_scores(c[j].var());
break;
}
}
}
}
}
}
else {
for (unsigned i = 0; i < csz; ++i) {
if (m_false.contains(i)) {
++m_clause_weights[i];
clause const& c = *m_clauses[i];
unsigned sz = c.size();
for (unsigned j = 0; j < sz; ++j) {
++m_hscore[c[j].var()];
refresh_scores(c[j].var());
}
}
}
}
DEBUG_CODE(check_invariant(););
}
double wsls::evaluate_model(model& mdl) {
SASSERT(m_false.empty());
double result = 0.0;
for (unsigned i = 0; i < m_soft.size(); ++i) {
literal lit = m_soft[i];
if (value_at(lit, mdl) != l_true) {
result += m_weights[i];
}
}
return result;
}
int wsls::compute_hscore(bool_var v) {
literal lit(v, false);
if (value_at(lit, m_model) == l_false) {
lit.neg();
}
SASSERT(value_at(lit, m_model) == l_true);
int hs = 0;
unsigned_vector const& use1 = get_use(~lit);
unsigned sz = use1.size();
for (unsigned i = 0; i < sz; ++i) {
unsigned cl = use1[i];
if (m_num_true[cl] == 0) {
SASSERT(m_false.contains(cl));
hs += m_clause_weights[cl];
}
else {
SASSERT(!m_false.contains(cl));
}
}
unsigned_vector const& use2 = get_use(lit);
sz = use2.size();
for (unsigned i = 0; i < sz; ++i) {
unsigned cl = use2[i];
if (m_num_true[cl] == 1) {
SASSERT(!m_false.contains(cl));
hs -= m_clause_weights[cl];
}
}
return hs;
}
void wsls::recompute_hscores(literal lit) {
SASSERT(value_at(lit, m_model) == l_true);
TRACE("sat", tout << lit.var() << " := " << m_hscore[lit.var()] << "\n";);
unsigned_vector const& use1 = get_use(lit);
unsigned sz = use1.size();
for (unsigned i = 0; i < sz; ++i) {
unsigned cl = use1[i];
TRACE("sat", tout << *m_clauses[cl] << " " << m_num_true[cl] << "\n";);
SASSERT(m_num_true[cl] > 0);
if (m_num_true[cl] == 1) {
// num_true 0 -> 1
// other literals don't have upside any more.
// subtract one from all other literals
adjust_all_values(lit, cl, -static_cast<int>(m_clause_weights[cl]));
}
else if (m_num_true[cl] == 2) {
// num_true 1 -> 2, previous critical literal is no longer critical
adjust_pivot_value(lit, cl, +m_clause_weights[cl]);
}
}
unsigned_vector const& use2 = get_use(~lit);
sz = use2.size();
for (unsigned i = 0; i < sz; ++i) {
unsigned cl = use2[i];
TRACE("sat", tout << *m_clauses[cl] << " " << m_num_true[cl] << "\n";);
if (m_num_true[cl] == 0) {
// num_true 1 -> 0
// all variables became critical.
adjust_all_values(~lit, cl, +m_clause_weights[cl]);
}
else if (m_num_true[cl] == 1) {
adjust_pivot_value(~lit, cl, -static_cast<int>(m_clause_weights[cl]));
}
// else n+1 -> n >= 2
}
}
void wsls::adjust_all_values(literal lit, unsigned cl, int delta) {
clause const& c = *m_clauses[cl];
unsigned sz = c.size();
TRACE("sat", tout << lit << " " << c << " delta: " << delta << " nt: " << m_num_true[cl] << "\n";);
for (unsigned i = 0; i < sz; ++i) {
literal lit2 = c[i];
if (lit2 != lit) {
TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";);
m_hscore[lit2.var()] += delta;
TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";);
refresh_scores(lit2.var());
}
}
}
void wsls::adjust_pivot_value(literal lit, unsigned cl, int delta) {
clause const& c = *m_clauses[cl];
unsigned csz = c.size();
for (unsigned j = 0; j < csz; ++j) {
literal lit2 = c[j];
if (lit2 != lit && value_at(lit2, m_model) == l_true) {
TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";);
m_hscore[lit2.var()] += delta;
TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";);
refresh_scores(lit2.var());
break;
}
}
}
void wsls::refresh_scores(bool_var v) {
if (m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) {
m_H.insert(v);
}
else {
m_H.remove(v);
}
if (m_sscore[v] > 0) {
if (m_hscore[v] == 0 && !m_tabu[v]) {
m_S.insert(v);
}
else {
m_S.remove(v);
}
}
else if (m_sscore[v] < 0) {
m_S.remove(v);
}
}
void wsls::check_invariant() {
sls::check_invariant();
// The hscore is the reward for flipping the truth value of variable v.
// hscore(v) = Sum weight(c) for num_true(c) = 0 and v in c
// - Sum weight(c) for num_true(c) = 1 and (v in c, M(v) or !v in c and !M(v))
DEBUG_CODE(
for (unsigned v = 0; v < s.num_vars(); ++v) {
int hs = compute_hscore(v);
CTRACE("sat", hs != m_hscore[v], display(tout << v << " - computed: " << hs << " - assigned: " << m_hscore[v] << "\n"););
SASSERT(m_hscore[v] == hs);
}
// The score(v) is the reward on soft clauses for flipping v.
for (unsigned j = 0; j < m_soft.size(); ++j) {
unsigned v = m_soft[j].var();
double ss = (l_true == value_at(m_soft[j], m_model))?(-m_weights[j]):m_weights[j];
SASSERT(m_sscore[v] == ss);
}
// m_H are values such that m_hscore > 0 and sscore = 0.
for (bool_var v = 0; v < m_hscore.size(); ++v) {
SASSERT((m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) == m_H.contains(v));
}
// m_S are values such that hscore = 0, sscore > 0
for (bool_var v = 0; v < m_sscore.size(); ++v) {
SASSERT((m_hscore[v] == 0 && m_sscore[v] > 0 && !m_tabu[v]) == m_S.contains(v));
});
}
void wsls::display(std::ostream& out) const {
sls::display(out);
out << "Best model\n";
for (bool_var v = 0; v < m_best_model.size(); ++v) {
out << v << ": " << m_best_model[v] << " h: " << m_hscore[v];
if (m_sscore[v] != 0.0) out << " s: " << m_sscore[v];
out << "\n";
}
}
};

View file

@ -1,115 +0,0 @@
/*++
Copyright (c) 2014 Microsoft Corporation
Module Name:
sat_sls.h
Abstract:
SLS for clauses in SAT solver
Author:
Nikolaj Bjorner (nbjorner) 2014-12-8
Notes:
--*/
#ifndef SAT_SLS_H_
#define SAT_SLS_H_
#include "util.h"
#include "sat_simplifier.h"
namespace sat {
class index_set {
unsigned_vector m_elems;
unsigned_vector m_index;
public:
unsigned num_elems() const { return m_elems.size(); }
unsigned operator[](unsigned idx) const { return m_elems[idx]; }
void reset() { m_elems.reset(); m_index.reset(); }
bool empty() const { return m_elems.empty(); }
bool contains(unsigned idx) const;
void insert(unsigned idx);
void remove(unsigned idx);
unsigned choose(random_gen& rnd) const;
};
class sls {
protected:
solver& s;
random_gen m_rand;
unsigned m_max_tries;
unsigned m_prob_choose_min_var; // number between 0 and 99.
unsigned m_clause_generation;
ptr_vector<clause const> m_clauses; // vector of all clauses.
index_set m_false; // clauses currently false
vector<unsigned_vector> m_use_list; // use lists for literals
unsigned_vector m_num_true; // per clause, count of # true literals
svector<literal> m_min_vars; // literals with smallest break count
model m_model; // current model
clause_allocator m_alloc; // clause allocator
clause_vector m_bin_clauses; // binary clauses
svector<bool> m_tabu; // variables that cannot be swapped
public:
sls(solver& s);
virtual ~sls();
lbool operator()(unsigned sz, literal const* tabu, bool reuse_model);
void set_max_tries(unsigned mx) { m_max_tries = mx; }
virtual void display(std::ostream& out) const;
protected:
void init(unsigned sz, literal const* tabu, bool reuse_model);
void init_tabu(unsigned sz, literal const* tabu);
void init_model();
void init_use();
void init_clauses();
unsigned_vector const& get_use(literal lit);
void flip(literal lit);
virtual void check_invariant();
void check_use_list();
private:
bool pick_flip(literal& lit);
void flip();
unsigned get_break_count(literal lit, unsigned min_break);
};
/**
\brief sls with weighted soft clauses.
*/
class wsls : public sls {
unsigned_vector m_clause_weights;
svector<int> m_hscore;
svector<double> m_sscore;
literal_vector m_soft;
svector<double> m_weights;
double m_best_value;
model m_best_model;
index_set m_H, m_S;
unsigned m_smoothing_probability;
public:
wsls(solver& s);
virtual ~wsls();
void set_soft(unsigned sz, literal const* lits, double const* weights);
bool has_soft() const { return !m_soft.empty(); }
void opt(unsigned sz, literal const* tabu, bool reuse_model);
virtual void display(std::ostream& out) const;
double evaluate_model(model& mdl);
private:
void wflip();
void wflip(literal lit);
void update_hard_weights();
bool pick_wflip(literal & lit);
virtual void check_invariant();
void refresh_scores(bool_var v);
int compute_hscore(bool_var v);
void recompute_hscores(literal lit);
void adjust_all_values(literal lit, unsigned cl, int delta);
void adjust_pivot_value(literal lit, unsigned cl, int delta);
};
};
#endif

View file

@ -20,7 +20,6 @@ Revision History:
#include"sat_integrity_checker.h"
#include"luby.h"
#include"trace.h"
#include"sat_bceq.h"
#include"max_cliques.h"
// define to update glue during propagation
@ -42,7 +41,6 @@ namespace sat {
m_asymm_branch(*this, p),
m_probing(*this, p),
m_mus(*this),
m_wsls(*this),
m_inconsistent(false),
m_num_frozen(0),
m_activity_inc(128),
@ -55,7 +53,6 @@ namespace sat {
m_conflicts = 0;
m_next_simplify = 0;
m_num_checkpoints = 0;
m_initializing_preferred = false;
}
solver::~solver() {
@ -713,7 +710,7 @@ namespace sat {
// Search
//
// -----------------------
lbool solver::check(unsigned num_lits, literal const* lits, double const* weights, double max_weight) {
lbool solver::check(unsigned num_lits, literal const* lits) {
pop_to_base_level();
IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";);
SASSERT(scope_lvl() == 0);
@ -728,7 +725,7 @@ namespace sat {
init_search();
propagate(false);
if (inconsistent()) return l_false;
init_assumptions(num_lits, lits, weights, max_weight);
init_assumptions(num_lits, lits);
propagate(false);
if (check_inconsistent()) return l_false;
cleanup();
@ -914,12 +911,11 @@ namespace sat {
}
}
void solver::init_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight) {
void solver::init_assumptions(unsigned num_lits, literal const* lits) {
if (num_lits == 0 && m_user_scope_literals.empty()) {
return;
}
retry_init_assumptions:
reset_assumptions();
push();
@ -943,16 +939,6 @@ namespace sat {
assign(nlit, justification());
}
if (weights && !inconsistent()) {
if (m_config.m_optimize_model) {
m_wsls.set_soft(num_lits, lits, weights);
}
if (!init_weighted_assumptions(num_lits, lits, weights, max_weight)) {
goto retry_init_assumptions;
}
return;
}
for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) {
literal lit = lits[i];
SASSERT(is_external(lit.var()));
@ -962,109 +948,6 @@ namespace sat {
}
bool solver::init_weighted_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight) {
flet<bool> _min1(m_config.m_core_minimize, false);
m_weight = 0;
m_blocker.reset();
svector<lbool> values;
unsigned num_cores = 0;
for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) {
literal lit = lits[i];
SASSERT(is_external(lit.var()));
TRACE("sat", tout << "propagate: " << lit << " " << value(lit) << "\n";);
SASSERT(m_scope_lvl == 1);
add_assumption(lit);
switch(value(lit)) {
case l_undef:
values.push_back(l_true);
assign(lit, justification());
if (num_cores*2 >= num_lits) {
break;
}
propagate(false);
if (inconsistent()) {
flet<bool> _init(m_initializing_preferred, true);
while (inconsistent()) {
if (!resolve_conflict()) {
return true;
}
propagate(true);
}
if (m_scope_lvl == 0) {
return false;
}
// backjump to last consistent assumption:
unsigned j;
m_weight = 0;
m_blocker.reset();
for (j = 0; j < i && value(lits[j]) == values[j]; ++j) {
if (values[j] == l_false) {
m_weight += weights[j];
m_blocker.push_back(lits[j]);
}
}
SASSERT(value(lits[j]) != values[j]);
SASSERT(j <= i);
SASSERT(j == 0 || value(lits[j-1]) == values[j-1]);
for (unsigned k = i; k >= j; --k) {
if (is_assumption(lits[k])) {
pop_assumption();
}
}
values.resize(j);
TRACE("sat", tout << "backjump " << (i - j + 1) << " steps " << num_cores << "\n";);
i = j - 1;
}
break;
case l_false:
++num_cores;
values.push_back(l_false);
SASSERT(!inconsistent());
set_conflict(justification(), ~lit);
m_conflict_lvl = scope_lvl();
resolve_conflict_for_unsat_core();
IF_VERBOSE(3, verbose_stream() << "(sat.core: " << m_core << ")\n";);
update_min_core();
SASSERT(m_min_core_valid);
m_weight += weights[i];
if (m_weight <= max_weight) {
m_blocker.push_back(lit);
}
TRACE("sat", tout << "core: " << m_core << "\nassumptions: " << m_assumptions << "\n";);
SASSERT(m_core.size() <= m_assumptions.size());
SASSERT(m_assumptions.size() <= i+1);
if (m_core.size() <= 3) {
m_inconsistent = true;
TRACE("opt", tout << "found small core: " << m_core << "\n";);
IF_VERBOSE(11, verbose_stream() << "(sat.core: " << m_core << ")\n";);
return true;
}
pop_assumption();
m_inconsistent = false;
break;
case l_true:
values.push_back(l_true);
SASSERT(m_justification[lit.var()].get_kind() != justification::NONE || lvl(lit) == 0);
break;
}
}
TRACE("sat", tout << "initialized\n";);
IF_VERBOSE(11, verbose_stream() << "(sat.blocker: " << m_blocker << "\nCore: " << m_min_core << ")\n";);
if (m_weight >= max_weight) {
// block the current correction set candidate.
++m_stats.m_blocked_corr_sets;
TRACE("opt", tout << "blocking soft correction set: " << m_blocker << "\n";);
IF_VERBOSE(11, verbose_stream() << "blocking " << m_blocker << "\n";);
pop_to_base_level();
mk_clause_core(m_blocker);
return false;
}
return true;
}
void solver::update_min_core() {
if (!m_min_core_valid || m_core.size() < m_min_core.size()) {
m_min_core.reset();
@ -1148,11 +1031,6 @@ namespace sat {
m_min_core_valid = false;
m_min_core.reset();
TRACE("sat", display(tout););
if (m_config.m_bcd) {
bceq bc(*this);
bc();
}
}
/**
@ -1244,9 +1122,6 @@ namespace sat {
m_model[v] = value(v);
}
TRACE("sat_mc_bug", m_mc.display(tout););
if (m_config.m_optimize_model) {
m_wsls.opt(0, 0, false);
}
m_mc(m_model);
TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";);
@ -1673,10 +1548,6 @@ namespace sat {
if (m_not_l == literal()) tout << "null literal\n";
else tout << m_not_l << "\n";);
if (m_initializing_preferred) {
SASSERT(m_conflict_lvl <= 1);
return resolve_conflict_for_init();
}
if (m_conflict_lvl <= 1 && tracking_assumptions()) {
resolve_conflict_for_unsat_core();
return false;
@ -3184,10 +3055,10 @@ namespace sat {
if (asms.empty()) {
bool_var v = mk_var(true, false);
literal lit(v, false);
init_assumptions(1, &lit, 0, 0);
init_assumptions(1, &lit);
}
else {
init_assumptions(asms.size(), asms.c_ptr(), 0, 0);
init_assumptions(asms.size(), asms.c_ptr());
}
propagate(false);
if (check_inconsistent()) return l_false;
@ -3249,10 +3120,10 @@ namespace sat {
if (asms.empty()) {
bool_var v = mk_var(true, false);
literal lit(v, false);
init_assumptions(1, &lit, 0, 0);
init_assumptions(1, &lit);
}
else {
init_assumptions(asms.size(), asms.c_ptr(), 0, 0);
init_assumptions(asms.size(), asms.c_ptr());
}
propagate(false);
if (check_inconsistent()) return l_false;

View file

@ -33,7 +33,6 @@ Revision History:
#include"sat_iff3_finder.h"
#include"sat_probing.h"
#include"sat_mus.h"
#include"sat_sls.h"
#include"params.h"
#include"statistics.h"
#include"stopwatch.h"
@ -86,7 +85,6 @@ namespace sat {
asymm_branch m_asymm_branch;
probing m_probing;
mus m_mus; // MUS for minimal core extraction
wsls m_wsls; // SLS facility for MaxSAT use
bool m_inconsistent;
// A conflict is usually a single justification. That is, a justification
// for false. If m_not_l is not null_literal, then m_conflict is a
@ -141,9 +139,6 @@ namespace sat {
friend class probing;
friend class iff3_finder;
friend class mus;
friend class sls;
friend class wsls;
friend class bceq;
friend struct mk_stat;
public:
solver(params_ref const & p, reslimit& l, extension * ext);
@ -280,10 +275,7 @@ namespace sat {
//
// -----------------------
public:
lbool check(unsigned num_lits = 0, literal const* lits = 0) {
return check(num_lits, lits, 0, 0);
}
lbool check(unsigned num_lits, literal const* lits, double const* weights, double max_weight);
lbool check(unsigned num_lits = 0, literal const* lits = 0);
model const & get_model() const { return m_model; }
bool model_is_current() const { return m_model_is_current; }
@ -311,11 +303,7 @@ namespace sat {
literal_vector m_min_core;
bool m_min_core_valid;
literal_vector m_blocker;
double m_weight;
bool m_initializing_preferred;
void init_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight);
bool init_weighted_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight);
void init_assumptions(unsigned num_lits, literal const* lits);
void reassert_min_core();
void update_min_core();
void resolve_weighted();

View file

@ -105,13 +105,8 @@ public:
virtual void set_progress_callback(progress_callback * callback) {}
virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) {
return check_sat(num_assumptions, assumptions, 0, 0);
}
void display_weighted(std::ostream& out, unsigned sz, expr * const * assumptions, unsigned const* weights) {
m_weights.reset();
if (weights != 0) {
for (unsigned i = 0; i < sz; ++i) m_weights.push_back(weights[i]);
}
@ -131,15 +126,11 @@ public:
for (unsigned i = 0; i < m_asms.size(); ++i) {
nweights.push_back((unsigned) m_weights[i]);
}
m_weights.reset();
m_solver.display_wcnf(out, m_asms.size(), m_asms.c_ptr(), nweights.c_ptr());
}
lbool check_sat(unsigned sz, expr * const * assumptions, double const* weights, double max_weight) {
m_weights.reset();
if (weights != 0) {
m_weights.append(sz, weights);
}
SASSERT(m_weights.empty() == (m_weights.c_ptr() == 0));
virtual lbool check_sat(unsigned sz, expr * const * assumptions) {
m_solver.pop_to_base_level();
dep2asm_t dep2asm;
m_model = 0;
@ -148,10 +139,10 @@ public:
r = internalize_assumptions(sz, assumptions, dep2asm);
if (r != l_true) return r;
r = m_solver.check(m_asms.size(), m_asms.c_ptr(), m_weights.c_ptr(), max_weight);
r = m_solver.check(m_asms.size(), m_asms.c_ptr());
switch (r) {
case l_true:
if (sz > 0 && !weights) {
if (sz > 0) {
check_assumptions(dep2asm);
}
break;
@ -675,18 +666,6 @@ solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p) {
}
lbool inc_sat_check_sat(solver& _s, unsigned sz, expr*const* soft, rational const* _weights, rational const& max_weight) {
inc_sat_solver& s = dynamic_cast<inc_sat_solver&>(_s);
vector<double> weights;
for (unsigned i = 0; _weights && i < sz; ++i) {
weights.push_back(_weights[i].get_double());
}
params_ref p;
p.set_bool("minimize_core", false);
s.updt_params(p);
return s.check_sat(sz, soft, weights.c_ptr(), max_weight.get_double());
}
void inc_sat_display(std::ostream& out, solver& _s, unsigned sz, expr*const* soft, rational const* _weights) {
inc_sat_solver& s = dynamic_cast<inc_sat_solver&>(_s);
vector<unsigned> weights;

View file

@ -24,7 +24,6 @@ Notes:
solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p);
lbool inc_sat_check_sat(solver& s, unsigned sz, expr*const* soft, rational const* weights, rational const& max_weight);
void inc_sat_display(std::ostream& out, solver& s, unsigned sz, expr*const* soft, rational const* _weights);