mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
refactor sat/sls interface. Remove wpm2 and bvsls dependencies
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
a02cab2194
commit
ee1a1b1135
43 changed files with 609 additions and 891 deletions
|
@ -105,6 +105,7 @@ namespace sat {
|
|||
}
|
||||
m_minimize_lemmas = p.minimize_lemmas();
|
||||
m_minimize_core = p.minimize_core();
|
||||
m_optimize_model = p.optimize_model();
|
||||
m_dyn_sub_res = p.dyn_sub_res();
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace sat {
|
|||
bool m_minimize_lemmas;
|
||||
bool m_dyn_sub_res;
|
||||
bool m_minimize_core;
|
||||
bool m_optimize_model;
|
||||
|
||||
|
||||
symbol m_always_true;
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace sat {
|
|||
|
||||
lbool mus::operator()() {
|
||||
flet<bool> _disable_min(s.m_config.m_minimize_core, false);
|
||||
flet<bool> _disable_opt(s.m_config.m_optimize_model, false);
|
||||
TRACE("sat", tout << "old core: " << s.get_core() << "\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";);
|
||||
reset();
|
||||
|
|
|
@ -19,4 +19,5 @@ def_module_params('sat',
|
|||
('minimize_lemmas', BOOL, True, 'minimize learned clauses'),
|
||||
('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'),
|
||||
('minimize_core', BOOL, False, 'minimize computed core'),
|
||||
('optimize_model', BOOL, False, 'enable optimization of soft constraints'),
|
||||
('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks')))
|
||||
|
|
|
@ -50,8 +50,8 @@ namespace sat {
|
|||
return m_elems[rnd(num_elems())];
|
||||
}
|
||||
|
||||
sls::sls(solver& s): s(s) {
|
||||
m_max_tries = 10000;
|
||||
sls::sls(solver& s): s(s), m_cancel(false) {
|
||||
m_max_tries = 1000000;
|
||||
m_prob_choose_min_var = 43;
|
||||
m_clause_generation = 0;
|
||||
}
|
||||
|
@ -180,6 +180,7 @@ namespace sat {
|
|||
m_use_list[c[j].index()].push_back(i);
|
||||
}
|
||||
}
|
||||
DEBUG_CODE(check_use_list(););
|
||||
}
|
||||
|
||||
unsigned_vector const& sls::get_use(literal lit) {
|
||||
|
@ -242,7 +243,7 @@ namespace sat {
|
|||
}
|
||||
|
||||
void sls::flip(literal lit) {
|
||||
// IF_VERBOSE(0, verbose_stream() << 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;
|
||||
|
@ -266,9 +267,70 @@ namespace sat {
|
|||
}
|
||||
|
||||
void sls::check_invariant() {
|
||||
|
||||
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() {
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -277,7 +339,7 @@ namespace sat {
|
|||
|
||||
wsls::~wsls() {}
|
||||
|
||||
void wsls::set_soft(unsigned sz, double const* weights, literal const* lits) {
|
||||
void wsls::set_soft(unsigned sz, literal const* lits, double const* weights) {
|
||||
m_soft.reset();
|
||||
m_weights.reset();
|
||||
m_soft.append(sz, lits);
|
||||
|
@ -291,14 +353,17 @@ namespace sat {
|
|||
// Initialize m_clause_weights, m_hscore, m_sscore.
|
||||
//
|
||||
m_best_value = m_false.empty()?evaluate_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);
|
||||
unsigned num_violated = 0;
|
||||
for (unsigned i = 0; i < m_soft.size(); ++i) {
|
||||
literal lit = m_soft[i];
|
||||
m_sscore[lit.var()] = m_weights[i];
|
||||
|
@ -310,16 +375,19 @@ namespace sat {
|
|||
m_hscore[i] = compute_hscore(i);
|
||||
refresh_scores(i);
|
||||
}
|
||||
DEBUG_CODE(check_invariant(););
|
||||
unsigned i = 0;
|
||||
for (; !m_cancel && i < m_max_tries; ++i) {
|
||||
for (; !m_cancel && m_best_value > 0 && i < m_max_tries; ++i) {
|
||||
wflip();
|
||||
}
|
||||
IF_VERBOSE(2, verbose_stream() << "tries " << i << "\n";);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -328,8 +396,10 @@ namespace sat {
|
|||
if (m_false.empty()) {
|
||||
double val = evaluate_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);
|
||||
IF_VERBOSE(0, verbose_stream() << "new value:" << val << "\n";);
|
||||
}
|
||||
}
|
||||
unsigned idx;
|
||||
|
@ -337,6 +407,8 @@ namespace sat {
|
|||
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;
|
||||
|
@ -353,16 +425,38 @@ namespace sat {
|
|||
m_min_vars.push_back(literal(v, false));
|
||||
}
|
||||
}
|
||||
idx = m_min_vars[m_rand(m_min_vars.size())].var(); // pick with largest sscore.
|
||||
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 {
|
||||
lit = m_soft[m_rand(m_soft.size())];
|
||||
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() << ") " << lit << "\n";);
|
||||
|
||||
}
|
||||
SASSERT(value_at(lit, m_model) == l_false);
|
||||
}
|
||||
return !m_tabu[lit.var()];
|
||||
}
|
||||
|
@ -408,7 +502,6 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_CODE(check_invariant(););
|
||||
}
|
||||
|
||||
|
@ -488,9 +581,29 @@ namespace sat {
|
|||
// 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 = value_at(m_soft[j], m_model)?(-m_weights[j]):m_weights[j];
|
||||
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.
|
||||
for (bool_var v = 0; v < m_hscore.size(); ++v) {
|
||||
SASSERT(m_hscore[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_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";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -60,6 +60,8 @@ namespace sat {
|
|||
virtual ~sls();
|
||||
lbool operator()(unsigned sz, literal const* tabu, bool reuse_model);
|
||||
void set_cancel(bool f) { m_cancel = f; }
|
||||
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);
|
||||
|
@ -69,6 +71,7 @@ namespace sat {
|
|||
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();
|
||||
|
@ -91,9 +94,11 @@ namespace sat {
|
|||
public:
|
||||
wsls(solver& s);
|
||||
virtual ~wsls();
|
||||
void set_soft(unsigned sz, double const* weights, literal const* lits);
|
||||
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);
|
||||
model const& get_model() { return m_best_model; }
|
||||
virtual void display(std::ostream& out) const;
|
||||
private:
|
||||
void wflip();
|
||||
void wflip(literal lit);
|
||||
|
|
|
@ -40,6 +40,7 @@ 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),
|
||||
|
@ -528,6 +529,10 @@ namespace sat {
|
|||
return found_undef ? l_undef : l_false;
|
||||
}
|
||||
|
||||
void solver::initialize_soft(unsigned sz, literal const* lits, double const* weights) {
|
||||
m_wsls.set_soft(sz, lits, weights);
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Propagation
|
||||
|
@ -1003,6 +1008,11 @@ 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_model.reset();
|
||||
m_model.append(m_wsls.get_model());
|
||||
}
|
||||
m_mc(m_model);
|
||||
TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";);
|
||||
|
||||
|
@ -2305,6 +2315,7 @@ namespace sat {
|
|||
|
||||
void solver::set_cancel(bool f) {
|
||||
m_cancel = f;
|
||||
m_wsls.set_cancel(f);
|
||||
}
|
||||
|
||||
void solver::collect_statistics(statistics & st) const {
|
||||
|
|
|
@ -33,6 +33,7 @@ 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"
|
||||
|
@ -82,6 +83,7 @@ namespace sat {
|
|||
asymm_branch m_asymm_branch;
|
||||
probing m_probing;
|
||||
mus m_mus;
|
||||
wsls m_wsls;
|
||||
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
|
||||
|
@ -224,13 +226,14 @@ namespace sat {
|
|||
void assign_core(literal l, justification jst);
|
||||
void set_conflict(justification c, literal not_l);
|
||||
void set_conflict(justification c) { set_conflict(c, null_literal); }
|
||||
lbool status(clause const & c) const;
|
||||
lbool status(clause const & c) const;
|
||||
clause_offset get_offset(clause const & c) const { return m_cls_allocator.get_offset(&c); }
|
||||
void checkpoint() {
|
||||
if (m_cancel) throw solver_exception(Z3_CANCELED_MSG);
|
||||
if (memory::get_allocation_size() > m_config.m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG);
|
||||
}
|
||||
typedef std::pair<literal, literal> bin_clause;
|
||||
void initialize_soft(unsigned sz, literal const* lits, double const* weights);
|
||||
protected:
|
||||
watch_list & get_wlist(literal l) { return m_watches[l.index()]; }
|
||||
watch_list const & get_wlist(literal l) const { return m_watches[l.index()]; }
|
||||
|
|
|
@ -36,6 +36,7 @@ Notes:
|
|||
#include"model_v2_pp.h"
|
||||
#include"tactic.h"
|
||||
#include"ast_pp.h"
|
||||
#include<strstream>
|
||||
|
||||
struct goal2sat::imp {
|
||||
struct frame {
|
||||
|
@ -78,8 +79,9 @@ struct goal2sat::imp {
|
|||
m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
|
||||
}
|
||||
|
||||
void throw_op_not_handled() {
|
||||
throw tactic_exception("operator not supported, apply simplifier before invoking translator");
|
||||
void throw_op_not_handled(std::string const& s) {
|
||||
std::string s0 = "operator " + s + " not supported, apply simplifier before invoking translator";
|
||||
throw tactic_exception(s0.c_str());
|
||||
}
|
||||
|
||||
void mk_clause(sat::literal l) {
|
||||
|
@ -183,9 +185,12 @@ struct goal2sat::imp {
|
|||
case OP_AND:
|
||||
case OP_XOR:
|
||||
case OP_IMPLIES:
|
||||
case OP_DISTINCT:
|
||||
case OP_DISTINCT: {
|
||||
TRACE("goal2sat_not_handled", tout << mk_ismt2_pp(t, m) << "\n";);
|
||||
throw_op_not_handled();
|
||||
std::ostringstream strm;
|
||||
strm << mk_ismt2_pp(t, m);
|
||||
throw_op_not_handled(strm.str());
|
||||
}
|
||||
default:
|
||||
convert_atom(t, root, sign);
|
||||
return true;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue