mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 13:28:47 +00:00
wip - local search - move to plugin model
This commit is contained in:
parent
a1f73d3805
commit
c1ecc49021
|
@ -27,6 +27,10 @@
|
||||||
#include "sat/sat_clause.h"
|
#include "sat/sat_clause.h"
|
||||||
#include "sat/sat_types.h"
|
#include "sat/sat_types.h"
|
||||||
|
|
||||||
|
namespace arith {
|
||||||
|
class sls;
|
||||||
|
}
|
||||||
|
|
||||||
namespace sat {
|
namespace sat {
|
||||||
class solver;
|
class solver;
|
||||||
class parallel;
|
class parallel;
|
||||||
|
@ -44,6 +48,7 @@ namespace sat {
|
||||||
};
|
};
|
||||||
|
|
||||||
class ddfw : public i_local_search {
|
class ddfw : public i_local_search {
|
||||||
|
friend class arith::sls;
|
||||||
public:
|
public:
|
||||||
struct clause_info {
|
struct clause_info {
|
||||||
clause_info(clause* cl, double init_weight): m_weight(init_weight), m_clause(cl) {}
|
clause_info(clause* cl, double init_weight): m_weight(init_weight), m_clause(cl) {}
|
||||||
|
@ -126,7 +131,7 @@ namespace sat {
|
||||||
stopwatch m_stopwatch;
|
stopwatch m_stopwatch;
|
||||||
|
|
||||||
parallel* m_par;
|
parallel* m_par;
|
||||||
scoped_ptr< local_search_plugin> m_plugin;
|
local_search_plugin* m_plugin = nullptr;
|
||||||
|
|
||||||
void flatten_use_list();
|
void flatten_use_list();
|
||||||
|
|
||||||
|
@ -148,7 +153,7 @@ namespace sat {
|
||||||
|
|
||||||
inline double reward(bool_var v) const { return m_vars[v].m_reward; }
|
inline double reward(bool_var v) const { return m_vars[v].m_reward; }
|
||||||
|
|
||||||
inline double plugin_reward(bool_var v) const { return m_plugin->reward(v); }
|
inline double plugin_reward(bool_var v) const { return is_external(v) ? m_plugin->reward(v) : reward(v); }
|
||||||
|
|
||||||
void set_external(bool_var v) { m_vars[v].m_external = true; }
|
void set_external(bool_var v) { m_vars[v].m_external = true; }
|
||||||
|
|
||||||
|
|
90
src/sat/sat_solver/sat_smt_setup.h
Normal file
90
src/sat/sat_solver/sat_smt_setup.h
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2006 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
sat_smt_setup.h
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2023-01-17
|
||||||
|
|
||||||
|
--*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ast/ast.h"
|
||||||
|
#include "smt/params/smt_params.h"
|
||||||
|
#include "sat/sat_config.h"
|
||||||
|
#include "ast/simplifiers/dependent_expr_state.h"
|
||||||
|
|
||||||
|
struct static_features;
|
||||||
|
|
||||||
|
namespace sat_smt {
|
||||||
|
|
||||||
|
void setup_sat_config(smt_params const& p, sat::config& config);
|
||||||
|
|
||||||
|
class setup {
|
||||||
|
ast_manager& m;
|
||||||
|
dependent_expr_state& m_st;
|
||||||
|
smt_params& m_params;
|
||||||
|
symbol m_logic;
|
||||||
|
bool m_already_configured = false;
|
||||||
|
|
||||||
|
void setup_auto_config();
|
||||||
|
void setup_default();
|
||||||
|
//
|
||||||
|
// setup_<logic>() methods do not depend on static features of the formula. So, they are safe to use
|
||||||
|
// even in an incremental setting.
|
||||||
|
//
|
||||||
|
// setup_<logic>(static_features & st) can only be used if the logical context will perform a single
|
||||||
|
// check.
|
||||||
|
//
|
||||||
|
void setup_QF_DT();
|
||||||
|
void setup_QF_UF();
|
||||||
|
void setup_QF_UF(static_features const & st);
|
||||||
|
void setup_QF_RDL();
|
||||||
|
void setup_QF_RDL(static_features & st);
|
||||||
|
void setup_QF_IDL();
|
||||||
|
void setup_QF_IDL(static_features & st);
|
||||||
|
void setup_QF_UFIDL();
|
||||||
|
void setup_QF_UFIDL(static_features & st);
|
||||||
|
void setup_QF_LRA();
|
||||||
|
void setup_QF_LRA(static_features const & st);
|
||||||
|
void setup_QF_LIA();
|
||||||
|
void setup_QF_LIRA(static_features const& st);
|
||||||
|
void setup_QF_LIA(static_features const & st);
|
||||||
|
void setup_QF_UFLIA();
|
||||||
|
void setup_QF_UFLIA(static_features & st);
|
||||||
|
void setup_QF_UFLRA();
|
||||||
|
void setup_QF_BV();
|
||||||
|
void setup_QF_AUFBV();
|
||||||
|
void setup_QF_AX();
|
||||||
|
void setup_QF_AX(static_features const & st);
|
||||||
|
void setup_QF_AUFLIA();
|
||||||
|
void setup_QF_AUFLIA(static_features const & st);
|
||||||
|
void setup_QF_FP();
|
||||||
|
void setup_QF_FPBV();
|
||||||
|
void setup_QF_S();
|
||||||
|
void setup_LRA();
|
||||||
|
void setup_CSP();
|
||||||
|
void setup_AUFLIA(bool simple_array = true);
|
||||||
|
void setup_AUFLIA(static_features const & st);
|
||||||
|
void setup_AUFLIRA(bool simple_array = true);
|
||||||
|
void setup_UFNIA();
|
||||||
|
void setup_UFLRA();
|
||||||
|
void setup_AUFLIAp();
|
||||||
|
void setup_AUFNIRA();
|
||||||
|
void setup_QF_BVRE();
|
||||||
|
void setup_unknown();
|
||||||
|
void setup_unknown(static_features & st);
|
||||||
|
|
||||||
|
public:
|
||||||
|
setup(ast_manager& m, dependent_expr_state& st, smt_params & params);
|
||||||
|
void setk_already_configured() { m_already_configured = true; }
|
||||||
|
bool already_configured() const { return m_already_configured; }
|
||||||
|
symbol const & get_logic() const { return m_logic; }
|
||||||
|
void operator()();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*++
|
/*++
|
||||||
Copyright (c) 2020 Microsoft Corporation
|
Copyright (c) 2023 Microsoft Corporation
|
||||||
|
|
||||||
Module Name:
|
Module Name:
|
||||||
|
|
||||||
|
@ -112,6 +112,8 @@ namespace arith {
|
||||||
for (unsigned v = 0; v < s.s().num_vars(); ++v)
|
for (unsigned v = 0; v < s.s().num_vars(); ++v)
|
||||||
init_bool_var_assignment(v);
|
init_bool_var_assignment(v);
|
||||||
m_best_min_unsat = std::numeric_limits<unsigned>::max();
|
m_best_min_unsat = std::numeric_limits<unsigned>::max();
|
||||||
|
|
||||||
|
d->set(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sls::set_bounds_begin() {
|
void sls::set_bounds_begin() {
|
||||||
|
@ -209,14 +211,13 @@ namespace arith {
|
||||||
unsigned start = s.random();
|
unsigned start = s.random();
|
||||||
unsigned sz = unsat().size();
|
unsigned sz = unsat().size();
|
||||||
for (unsigned i = sz; i-- > 0; )
|
for (unsigned i = sz; i-- > 0; )
|
||||||
if (flip(unsat().elem_at((i + start) % sz)))
|
if (flip_clause(unsat().elem_at((i + start) % sz)))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sls::flip(unsigned cl) {
|
bool sls::flip_clause(unsigned cl) {
|
||||||
auto const& clause = get_clause(cl);
|
auto const& clause = get_clause(cl);
|
||||||
int64_t new_value;
|
|
||||||
for (literal lit : clause) {
|
for (literal lit : clause) {
|
||||||
if (is_true(lit))
|
if (is_true(lit))
|
||||||
continue;
|
continue;
|
||||||
|
@ -224,20 +225,32 @@ namespace arith {
|
||||||
if (!ineq)
|
if (!ineq)
|
||||||
continue;
|
continue;
|
||||||
SASSERT(!ineq->is_true());
|
SASSERT(!ineq->is_true());
|
||||||
for (auto const& [coeff, v] : ineq->m_args) {
|
if (flip(*ineq))
|
||||||
if (!cm(*ineq, v, new_value))
|
|
||||||
continue;
|
|
||||||
int score = cm_score(v, new_value);
|
|
||||||
if (score <= 0)
|
|
||||||
continue;
|
|
||||||
unsigned num_unsat = unsat().size();
|
|
||||||
update(v, new_value);
|
|
||||||
IF_VERBOSE(2,
|
|
||||||
verbose_stream() << "v" << v << " score " << score << " "
|
|
||||||
<< num_unsat << " -> " << unsat().size() << "\n");
|
|
||||||
SASSERT(num_unsat > unsat().size());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flip on the first positive score
|
||||||
|
// it could be changed to flip on maximal positive score
|
||||||
|
// or flip on maximal non-negative score
|
||||||
|
// or flip on first non-negative score
|
||||||
|
bool sls::flip(ineq const& ineq) {
|
||||||
|
int64_t new_value;
|
||||||
|
for (auto const& [coeff, v] : ineq.m_args) {
|
||||||
|
if (!cm(ineq, v, new_value))
|
||||||
|
continue;
|
||||||
|
int score = cm_score(v, new_value);
|
||||||
|
if (score <= 0)
|
||||||
|
continue;
|
||||||
|
unsigned num_unsat = unsat().size();
|
||||||
|
update(v, new_value);
|
||||||
|
IF_VERBOSE(2,
|
||||||
|
verbose_stream() << "v" << v << " score " << score << " "
|
||||||
|
<< num_unsat << " -> " << unsat().size() << "\n");
|
||||||
|
SASSERT(num_unsat > unsat().size());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -246,7 +259,7 @@ namespace arith {
|
||||||
unsigned start = s.random();
|
unsigned start = s.random();
|
||||||
unsigned sz = m_bool_search->num_clauses();
|
unsigned sz = m_bool_search->num_clauses();
|
||||||
for (unsigned i = sz; i-- > 0; )
|
for (unsigned i = sz; i-- > 0; )
|
||||||
if (flip((i + start) % sz))
|
if (flip_clause((i + start) % sz))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -541,9 +554,85 @@ namespace arith {
|
||||||
|
|
||||||
void sls::init_literal_assignment(sat::literal lit) {
|
void sls::init_literal_assignment(sat::literal lit) {
|
||||||
auto* ineq = m_literals.get(lit.index(), nullptr);
|
auto* ineq = m_literals.get(lit.index(), nullptr);
|
||||||
|
|
||||||
if (ineq && is_true(lit) != (dtt(*ineq) == 0))
|
if (ineq && is_true(lit) != (dtt(*ineq) == 0))
|
||||||
m_bool_search->flip(lit.var());
|
m_bool_search->flip(lit.var());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sls::init_search() {
|
||||||
|
on_restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sls::finish_search() {
|
||||||
|
store_best_values();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sls::flip(sat::bool_var v) {
|
||||||
|
sat::literal lit(v, m_bool_search->get_value(v));
|
||||||
|
SASSERT(!is_true(lit));
|
||||||
|
auto const* ineq = atom(lit);
|
||||||
|
if (!ineq)
|
||||||
|
IF_VERBOSE(0, verbose_stream() << "no inequality for variable " << v << "\n");
|
||||||
|
if (!ineq)
|
||||||
|
return;
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "flip " << lit << "\n");
|
||||||
|
SASSERT(!ineq->is_true());
|
||||||
|
flip(*ineq);
|
||||||
|
}
|
||||||
|
|
||||||
|
double sls::reward(sat::bool_var v) {
|
||||||
|
if (m_dscore_mode)
|
||||||
|
return dscore_reward(v);
|
||||||
|
else
|
||||||
|
return dtt_reward(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
double sls::dtt_reward(sat::bool_var v) {
|
||||||
|
sat::literal litv(v, m_bool_search->get_value(v));
|
||||||
|
auto const* ineq = atom(litv);
|
||||||
|
if (!ineq)
|
||||||
|
return 0;
|
||||||
|
int64_t new_value;
|
||||||
|
double result = 0;
|
||||||
|
for (auto const & [coeff, x] : ineq->m_args) {
|
||||||
|
if (!cm(*ineq, x, new_value))
|
||||||
|
continue;
|
||||||
|
for (auto const [coeff, lit] : m_vars[x].m_literals) {
|
||||||
|
auto dtt_old = dtt(*atom(lit));
|
||||||
|
auto dtt_new = dtt(*atom(lit), x, new_value);
|
||||||
|
if ((dtt_new == 0) != (dtt_old == 0))
|
||||||
|
result += m_bool_search->reward(lit.var());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
double sls::dscore_reward(sat::bool_var x) {
|
||||||
|
m_dscore_mode = false;
|
||||||
|
sat::literal litv(x, m_bool_search->get_value(x));
|
||||||
|
auto const* ineq = atom(litv);
|
||||||
|
if (!ineq)
|
||||||
|
return 0;
|
||||||
|
SASSERT(!ineq->is_true());
|
||||||
|
int64_t new_value;
|
||||||
|
double result = 0;
|
||||||
|
for (auto const& [coeff, v] : ineq->m_args)
|
||||||
|
if (cm(*ineq, v, new_value))
|
||||||
|
result += dscore(v, new_value);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch to dscore mode
|
||||||
|
void sls::on_rescale() {
|
||||||
|
m_dscore_mode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sls::on_save_model() {
|
||||||
|
save_best_values();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sls::on_restart() {
|
||||||
|
for (unsigned v = 0; v < s.s().num_vars(); ++v)
|
||||||
|
init_bool_var_assignment(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace arith {
|
||||||
class solver;
|
class solver;
|
||||||
|
|
||||||
// local search portion for arithmetic
|
// local search portion for arithmetic
|
||||||
class sls {
|
class sls : public sat::local_search_plugin {
|
||||||
enum class ineq_kind { EQ, LE, LT, NE };
|
enum class ineq_kind { EQ, LE, LT, NE };
|
||||||
enum class var_kind { INT, REAL };
|
enum class var_kind { INT, REAL };
|
||||||
typedef unsigned var_t;
|
typedef unsigned var_t;
|
||||||
|
@ -78,7 +78,7 @@ namespace arith {
|
||||||
std::ostream& display(std::ostream& out) const {
|
std::ostream& display(std::ostream& out) const {
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto const& [c, v] : m_args)
|
for (auto const& [c, v] : m_args)
|
||||||
out << (first? "": " + ") << c << " * v" << v, first = false;
|
out << (first ? "" : " + ") << c << " * v" << v, first = false;
|
||||||
switch (m_op) {
|
switch (m_op) {
|
||||||
case ineq_kind::LE:
|
case ineq_kind::LE:
|
||||||
return out << " <= " << m_bound << "(" << m_args_value << ")";
|
return out << " <= " << m_bound << "(" << m_args_value << ")";
|
||||||
|
@ -97,7 +97,7 @@ namespace arith {
|
||||||
int64_t m_value;
|
int64_t m_value;
|
||||||
int64_t m_best_value;
|
int64_t m_best_value;
|
||||||
var_kind m_kind = var_kind::INT;
|
var_kind m_kind = var_kind::INT;
|
||||||
vector<std::pair<int64_t, sat::literal>> m_literals;
|
svector<std::pair<int64_t, sat::literal>> m_literals;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct clause {
|
struct clause {
|
||||||
|
@ -116,6 +116,7 @@ namespace arith {
|
||||||
vector<var_info> m_vars;
|
vector<var_info> m_vars;
|
||||||
vector<clause> m_clauses;
|
vector<clause> m_clauses;
|
||||||
svector<std::pair<lp::tv, euf::theory_var>> m_terms;
|
svector<std::pair<lp::tv, euf::theory_var>> m_terms;
|
||||||
|
bool m_dscore_mode = false;
|
||||||
|
|
||||||
|
|
||||||
indexed_uint_set& unsat() { return m_bool_search->unsat_set(); }
|
indexed_uint_set& unsat() { return m_bool_search->unsat_set(); }
|
||||||
|
@ -136,7 +137,8 @@ namespace arith {
|
||||||
bool flip_clauses();
|
bool flip_clauses();
|
||||||
bool flip_dscore();
|
bool flip_dscore();
|
||||||
bool flip_dscore(unsigned cl);
|
bool flip_dscore(unsigned cl);
|
||||||
bool flip(unsigned cl);
|
bool flip_clause(unsigned cl);
|
||||||
|
bool flip(ineq const& ineq);
|
||||||
int64_t dtt(ineq const& ineq) const { return dtt(ineq.m_args_value, ineq); }
|
int64_t dtt(ineq const& ineq) const { return dtt(ineq.m_args_value, ineq); }
|
||||||
int64_t dtt(int64_t args, ineq const& ineq) const;
|
int64_t dtt(int64_t args, ineq const& ineq) const;
|
||||||
int64_t dtt(ineq const& ineq, var_t v, int64_t new_value) const;
|
int64_t dtt(ineq const& ineq, var_t v, int64_t new_value) const;
|
||||||
|
@ -145,6 +147,8 @@ namespace arith {
|
||||||
bool cm(ineq const& ineq, var_t v, int64_t& new_value);
|
bool cm(ineq const& ineq, var_t v, int64_t& new_value);
|
||||||
int cm_score(var_t v, int64_t new_value);
|
int cm_score(var_t v, int64_t new_value);
|
||||||
void update(var_t v, int64_t new_value);
|
void update(var_t v, int64_t new_value);
|
||||||
|
double dscore_reward(sat::bool_var v);
|
||||||
|
double dtt_reward(sat::bool_var v);
|
||||||
void paws();
|
void paws();
|
||||||
int64_t dscore(var_t v, int64_t new_value) const;
|
int64_t dscore(var_t v, int64_t new_value) const;
|
||||||
void save_best_values();
|
void save_best_values();
|
||||||
|
@ -163,11 +167,20 @@ namespace arith {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
sls(solver& s);
|
sls(solver& s);
|
||||||
|
~sls() override {}
|
||||||
lbool operator ()(bool_vector& phase);
|
lbool operator ()(bool_vector& phase);
|
||||||
void set_bounds_begin();
|
void set_bounds_begin();
|
||||||
void set_bounds_end(unsigned num_literals);
|
void set_bounds_end(unsigned num_literals);
|
||||||
void set_bounds(euf::enode* n);
|
void set_bounds(euf::enode* n);
|
||||||
void set(sat::ddfw* d);
|
void set(sat::ddfw* d);
|
||||||
|
|
||||||
|
void init_search() override;
|
||||||
|
void finish_search() override;
|
||||||
|
void flip(sat::bool_var v) override;
|
||||||
|
double reward(sat::bool_var v) override;
|
||||||
|
void on_rescale() override;
|
||||||
|
void on_save_model() override;
|
||||||
|
void on_restart() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& out, sls::ineq const& ineq) {
|
inline std::ostream& operator<<(std::ostream& out, sls::ineq const& ineq) {
|
||||||
|
|
|
@ -29,44 +29,13 @@ namespace euf {
|
||||||
bool_search.set_seed(rand());
|
bool_search.set_seed(rand());
|
||||||
scoped_rl.push_child(&(bool_search.rlimit()));
|
scoped_rl.push_child(&(bool_search.rlimit()));
|
||||||
|
|
||||||
unsigned max_rounds = 30;
|
|
||||||
|
|
||||||
for (auto* th : m_solvers)
|
for (auto* th : m_solvers)
|
||||||
th->set_bool_search(&bool_search);
|
th->set_bool_search(&bool_search);
|
||||||
|
|
||||||
for (unsigned rounds = 0; m.inc() && rounds < max_rounds; ++rounds) {
|
bool_search.rlimit().push(m_max_bool_steps);
|
||||||
|
lbool r = bool_search.check(0, nullptr, nullptr);
|
||||||
|
bool_search.rlimit().pop();
|
||||||
|
|
||||||
setup_bounds(bool_search, phase);
|
|
||||||
|
|
||||||
// Non-boolean literals are assumptions to Boolean search
|
|
||||||
literal_vector assumptions;
|
|
||||||
#if 0
|
|
||||||
for (unsigned v = 0; v < phase.size(); ++v)
|
|
||||||
if (!is_propositional(literal(v)))
|
|
||||||
assumptions.push_back(literal(v, !bool_search.get_value(v)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
verbose_stream() << "assumptions " << assumptions.size() << "\n";
|
|
||||||
|
|
||||||
bool_search.rlimit().push(m_max_bool_steps);
|
|
||||||
|
|
||||||
lbool r = bool_search.check(assumptions.size(), assumptions.data(), nullptr);
|
|
||||||
bool_search.rlimit().pop();
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// restore state to optimal model
|
|
||||||
auto const& mdl = bool_search.get_model();
|
|
||||||
for (unsigned i = 0; i < mdl.size(); ++i)
|
|
||||||
if ((mdl[i] == l_true) != bool_search.get_value(i))
|
|
||||||
bool_search.flip(i);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (auto* th : m_solvers)
|
|
||||||
th->local_search(phase);
|
|
||||||
|
|
||||||
if (bool_search.unsat_set().empty())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto const& mdl = bool_search.get_model();
|
auto const& mdl = bool_search.get_model();
|
||||||
for (unsigned i = 0; i < mdl.size(); ++i)
|
for (unsigned i = 0; i < mdl.size(); ++i)
|
||||||
phase[i] = mdl[i] == l_true;
|
phase[i] = mdl[i] == l_true;
|
||||||
|
|
Loading…
Reference in a new issue