mirror of
https://github.com/Z3Prover/z3
synced 2025-06-23 22:33:40 +00:00
testing / debugging arithmetic
This commit is contained in:
parent
ae55d30961
commit
5b0d49cd76
10 changed files with 269 additions and 139 deletions
|
@ -61,14 +61,21 @@ namespace sat {
|
||||||
m_steps_since_progress = 0;
|
m_steps_since_progress = 0;
|
||||||
unsigned steps = 0;
|
unsigned steps = 0;
|
||||||
save_best_values();
|
save_best_values();
|
||||||
|
try {
|
||||||
while (m_min_sz != 0 && m_steps_since_progress++ <= 1500000) {
|
while (m_min_sz != 0 && m_steps_since_progress++ <= 1500000) {
|
||||||
if (should_reinit_weights()) do_reinit_weights();
|
if (should_reinit_weights()) do_reinit_weights();
|
||||||
else if (steps % 5000 == 0) shift_weights(), m_plugin->on_rescale();
|
else if (steps % 5000 == 0) shift_weights(), m_plugin->on_rescale();
|
||||||
else if (should_restart()) do_restart(), m_plugin->on_restart();
|
else if (should_restart()) do_restart(), m_plugin->on_restart();
|
||||||
else if (do_flip<true>());
|
else if (do_flip<true>());
|
||||||
else shift_weights(), m_plugin->on_rescale();
|
else shift_weights(), m_plugin->on_rescale();
|
||||||
|
verbose_stream() << "steps: " << steps << " min_sz: " << m_min_sz << " unsat: " << m_unsat.size() << "\n";
|
||||||
++steps;
|
++steps;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (z3_exception& ex) {
|
||||||
|
IF_VERBOSE(0, verbose_stream() << "Exception: " << ex.msg() << "\n");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
m_plugin->finish_search();
|
m_plugin->finish_search();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -214,19 +214,20 @@ namespace sls {
|
||||||
// or flip on first non-negative score
|
// or flip on first non-negative score
|
||||||
template<typename num_t>
|
template<typename num_t>
|
||||||
void arith_base<num_t>::repair(sat::literal lit, ineq const& ineq) {
|
void arith_base<num_t>::repair(sat::literal lit, ineq const& ineq) {
|
||||||
num_t new_value;
|
num_t new_value, old_value;
|
||||||
if (UINT_MAX == ineq.m_var_to_flip)
|
if (UINT_MAX == ineq.m_var_to_flip)
|
||||||
dtt_reward(lit);
|
dtt_reward(lit);
|
||||||
auto v = ineq.m_var_to_flip;
|
auto v = ineq.m_var_to_flip;
|
||||||
|
|
||||||
if (v == UINT_MAX) {
|
if (v == UINT_MAX) {
|
||||||
IF_VERBOSE(1, verbose_stream() << "no var to flip\n");
|
IF_VERBOSE(0, verbose_stream() << "no var to flip\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// verbose_stream() << "var to flip " << v << "\n";
|
|
||||||
if (!cm(ineq, v, new_value)) {
|
if (!cm(ineq, v, new_value)) {
|
||||||
IF_VERBOSE(1, verbose_stream() << "no critical move for " << v << "\n");
|
IF_VERBOSE(0, verbose_stream() << "no critical move for " << v << "\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
verbose_stream() << "repair " << lit << ": " << ineq << " var: v" << v << " := " << value(v) << " -> " << new_value << "\n";
|
||||||
update(v, new_value);
|
update(v, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,9 +332,11 @@ namespace sls {
|
||||||
template<typename num_t>
|
template<typename num_t>
|
||||||
void arith_base<num_t>::update(var_t v, num_t const& new_value) {
|
void arith_base<num_t>::update(var_t v, num_t const& new_value) {
|
||||||
auto& vi = m_vars[v];
|
auto& vi = m_vars[v];
|
||||||
|
expr* e = vi.m_expr;
|
||||||
auto old_value = vi.m_value;
|
auto old_value = vi.m_value;
|
||||||
if (old_value == new_value)
|
if (old_value == new_value)
|
||||||
return;
|
return;
|
||||||
|
verbose_stream() << mk_bounded_pp(e, m) << " := " << new_value << "\n";
|
||||||
for (auto const& [coeff, bv] : vi.m_bool_vars) {
|
for (auto const& [coeff, bv] : vi.m_bool_vars) {
|
||||||
auto& ineq = *atom(bv);
|
auto& ineq = *atom(bv);
|
||||||
bool old_sign = sign(bv);
|
bool old_sign = sign(bv);
|
||||||
|
@ -354,7 +357,8 @@ namespace sls {
|
||||||
auto const& ad = m_adds[idx];
|
auto const& ad = m_adds[idx];
|
||||||
ctx.new_value_eh(m_vars[ad.m_var].m_expr);
|
ctx.new_value_eh(m_vars[ad.m_var].m_expr);
|
||||||
}
|
}
|
||||||
expr* e = vi.m_expr;
|
|
||||||
|
SASSERT(!m.is_value(e));
|
||||||
ctx.new_value_eh(e);
|
ctx.new_value_eh(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +378,7 @@ namespace sls {
|
||||||
template<>
|
template<>
|
||||||
bool arith_base<checked_int64<true>>::is_num(expr* e, checked_int64<true>& i) {
|
bool arith_base<checked_int64<true>>::is_num(expr* e, checked_int64<true>& i) {
|
||||||
rational r;
|
rational r;
|
||||||
if (a.is_numeral(e, r)) {
|
if (a.is_extended_numeral(e, r)) {
|
||||||
if (!r.is_int64())
|
if (!r.is_int64())
|
||||||
throw overflow_exception();
|
throw overflow_exception();
|
||||||
i = r.get_int64();
|
i = r.get_int64();
|
||||||
|
@ -385,7 +389,7 @@ namespace sls {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
bool arith_base<rational>::is_num(expr* e, rational& i) {
|
bool arith_base<rational>::is_num(expr* e, rational& i) {
|
||||||
return a.is_numeral(e, i);
|
return a.is_extended_numeral(e, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename num_t>
|
template<typename num_t>
|
||||||
|
@ -431,7 +435,7 @@ namespace sls {
|
||||||
unsigned_vector m;
|
unsigned_vector m;
|
||||||
num_t c = coeff;
|
num_t c = coeff;
|
||||||
for (expr* arg : *to_app(e))
|
for (expr* arg : *to_app(e))
|
||||||
if (is_num(x, i))
|
if (is_num(arg, i))
|
||||||
c *= i;
|
c *= i;
|
||||||
else
|
else
|
||||||
m.push_back(mk_term(arg));
|
m.push_back(mk_term(arg));
|
||||||
|
@ -621,13 +625,11 @@ namespace sls {
|
||||||
|
|
||||||
template<typename num_t>
|
template<typename num_t>
|
||||||
void arith_base<num_t>::propagate_literal(sat::literal lit) {
|
void arith_base<num_t>::propagate_literal(sat::literal lit) {
|
||||||
TRACE("sls", tout << "repair is-true: " << ctx.is_true(lit) << " lit: " << lit << "\n");
|
|
||||||
if (!ctx.is_true(lit))
|
if (!ctx.is_true(lit))
|
||||||
return;
|
return;
|
||||||
auto const* ineq = atom(lit.var());
|
auto const* ineq = atom(lit.var());
|
||||||
if (!ineq)
|
if (!ineq)
|
||||||
return;
|
return;
|
||||||
TRACE("sls", tout << "repair lit: " << lit << " ineq-is-true: " << ineq->is_true() << "\n");
|
|
||||||
if (ineq->is_true() != lit.sign())
|
if (ineq->is_true() != lit.sign())
|
||||||
return;
|
return;
|
||||||
repair(lit, *ineq);
|
repair(lit, *ineq);
|
||||||
|
@ -750,6 +752,9 @@ namespace sls {
|
||||||
auto const& coeffs = ad.m_args;
|
auto const& coeffs = ad.m_args;
|
||||||
num_t sum(ad.m_coeff);
|
num_t sum(ad.m_coeff);
|
||||||
num_t val = value(v);
|
num_t val = value(v);
|
||||||
|
|
||||||
|
verbose_stream() << mk_bounded_pp(m_vars[v].m_expr, m) << " := " << value(v) << "\n";
|
||||||
|
|
||||||
for (auto const& [c, w] : coeffs)
|
for (auto const& [c, w] : coeffs)
|
||||||
sum += c * value(w);
|
sum += c * value(w);
|
||||||
if (val == sum)
|
if (val == sum)
|
||||||
|
@ -771,13 +776,14 @@ namespace sls {
|
||||||
auto const& [v, coeff, monomial] = md;
|
auto const& [v, coeff, monomial] = md;
|
||||||
num_t product(coeff);
|
num_t product(coeff);
|
||||||
num_t val = value(v);
|
num_t val = value(v);
|
||||||
|
num_t new_value;
|
||||||
for (auto v : monomial)
|
for (auto v : monomial)
|
||||||
product *= value(v);
|
product *= value(v);
|
||||||
if (product == val)
|
if (product == val)
|
||||||
return;
|
return;
|
||||||
if (rand() % 20 == 0) {
|
verbose_stream() << "repair mul " << mk_bounded_pp(m_vars[v].m_expr, m) << " := " << val << "(" << product << ")\n";
|
||||||
|
if (rand() % 20 == 0)
|
||||||
update(v, product);
|
update(v, product);
|
||||||
}
|
|
||||||
else if (val == 0) {
|
else if (val == 0) {
|
||||||
auto v = monomial[ctx.rand(monomial.size())];
|
auto v = monomial[ctx.rand(monomial.size())];
|
||||||
num_t zero(0);
|
num_t zero(0);
|
||||||
|
@ -802,27 +808,29 @@ namespace sls {
|
||||||
// value1(v) = value(v) * val / product
|
// value1(v) = value(v) * val / product
|
||||||
auto w = monomial[ctx.rand(monomial.size())];
|
auto w = monomial[ctx.rand(monomial.size())];
|
||||||
auto old_value = value(w);
|
auto old_value = value(w);
|
||||||
num_t new_value;
|
|
||||||
if (m_vars[w].m_sort == var_sort::REAL)
|
|
||||||
new_value = old_value * val / product;
|
|
||||||
else
|
|
||||||
new_value = divide(w, old_value * val, product);
|
new_value = divide(w, old_value * val, product);
|
||||||
update(w, new_value);
|
update(w, new_value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
product = coeff;
|
auto w = monomial[ctx.rand(monomial.size())];
|
||||||
|
num_t prod(coeff);
|
||||||
for (auto v : monomial) {
|
for (auto v : monomial) {
|
||||||
num_t new_value{ 1 };
|
if (v == w)
|
||||||
|
continue;
|
||||||
|
num_t new_value(1);
|
||||||
if (rand() % 2 == 0)
|
if (rand() % 2 == 0)
|
||||||
new_value = -1;
|
new_value = -1;
|
||||||
product *= new_value;
|
prod *= new_value;
|
||||||
update(v, new_value);
|
update(v, new_value);
|
||||||
}
|
}
|
||||||
auto v = monomial[ctx.rand(monomial.size())];
|
|
||||||
if ((product < 0 && 0 < val) || (val < 0 && 0 < product))
|
verbose_stream() << "select random " << coeff << " " << val << " v" << w << "\n";
|
||||||
update(v, -val * value(v));
|
new_value = divide(w, val * value(w), coeff);
|
||||||
|
|
||||||
|
if ((product < 0 && 0 < new_value) || (new_value < 0 && 0 < product))
|
||||||
|
update(w, -new_value);
|
||||||
else
|
else
|
||||||
update(v, val * value(v));
|
update(w, new_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,6 +1084,19 @@ namespace sls {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sat)
|
||||||
|
continue;
|
||||||
|
verbose_stream() << clause << "\n";
|
||||||
|
for (auto lit : clause.m_clause) {
|
||||||
|
verbose_stream() << lit << " (" << ctx.is_true(lit) << ") ";
|
||||||
|
auto ineq = atom(lit.var());
|
||||||
|
if (!ineq)
|
||||||
|
continue;
|
||||||
|
verbose_stream() << *ineq << "\n";
|
||||||
|
for (auto const& [coeff, v] : ineq->m_args)
|
||||||
|
verbose_stream() << coeff << " " << v << " " << mk_bounded_pp(m_vars[v].m_expr, m) << " := " << value(v) << "\n";
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
if (!sat)
|
if (!sat)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,34 +21,35 @@ Author:
|
||||||
|
|
||||||
namespace sls {
|
namespace sls {
|
||||||
|
|
||||||
|
#define WITH_FALLBACK(_fn_) \
|
||||||
|
if (!m_arith) { \
|
||||||
|
try {\
|
||||||
|
return m_arith64->_fn_;\
|
||||||
|
}\
|
||||||
|
catch (overflow_exception&) {\
|
||||||
|
init_backup();\
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
return m_arith->_fn_; \
|
||||||
|
|
||||||
|
arith_plugin::arith_plugin(context& ctx) :
|
||||||
|
plugin(ctx), m_shared(ctx.get_manager()) {
|
||||||
|
m_arith64 = alloc(arith_base<checked_int64<true>>, ctx);
|
||||||
|
m_fid = m_arith64->fid();
|
||||||
|
init_backup();
|
||||||
|
}
|
||||||
|
|
||||||
void arith_plugin::init_backup() {
|
void arith_plugin::init_backup() {
|
||||||
m_arith = alloc(arith_base<rational>, ctx);
|
m_arith = alloc(arith_base<rational>, ctx);
|
||||||
m_arith->initialize();
|
m_arith->initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void arith_plugin::register_term(expr* e) {
|
void arith_plugin::register_term(expr* e) {
|
||||||
if (!m_arith) {
|
WITH_FALLBACK(register_term(e));
|
||||||
try {
|
|
||||||
m_arith64->register_term(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (overflow_exception&) {
|
|
||||||
init_backup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_arith->register_term(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_ref arith_plugin::get_value(expr* e) {
|
expr_ref arith_plugin::get_value(expr* e) {
|
||||||
if (!m_arith) {
|
WITH_FALLBACK(get_value(e));
|
||||||
try {
|
|
||||||
return m_arith64->get_value(e);
|
|
||||||
}
|
|
||||||
catch (overflow_exception&) {
|
|
||||||
init_backup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m_arith->get_value(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void arith_plugin::initialize() {
|
void arith_plugin::initialize() {
|
||||||
|
@ -59,28 +60,11 @@ namespace sls {
|
||||||
}
|
}
|
||||||
|
|
||||||
void arith_plugin::propagate_literal(sat::literal lit) {
|
void arith_plugin::propagate_literal(sat::literal lit) {
|
||||||
if (!m_arith) {
|
WITH_FALLBACK(propagate_literal(lit));
|
||||||
try {
|
|
||||||
m_arith64->propagate_literal(lit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (overflow_exception&) {
|
|
||||||
init_backup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_arith->propagate_literal(lit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool arith_plugin::propagate() {
|
bool arith_plugin::propagate() {
|
||||||
if (!m_arith) {
|
WITH_FALLBACK(propagate());
|
||||||
try {
|
|
||||||
return m_arith64->propagate();
|
|
||||||
}
|
|
||||||
catch (overflow_exception&) {
|
|
||||||
init_backup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m_arith->propagate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool arith_plugin::is_sat() {
|
bool arith_plugin::is_sat() {
|
||||||
|
@ -119,29 +103,14 @@ namespace sls {
|
||||||
}
|
}
|
||||||
|
|
||||||
void arith_plugin::repair_down(app* e) {
|
void arith_plugin::repair_down(app* e) {
|
||||||
if (m_arith)
|
WITH_FALLBACK(repair_down(e));
|
||||||
m_arith->repair_down(e);
|
|
||||||
else
|
|
||||||
m_arith64->repair_down(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void arith_plugin::repair_up(app* e) {
|
void arith_plugin::repair_up(app* e) {
|
||||||
if (m_arith)
|
WITH_FALLBACK(repair_up(e));
|
||||||
m_arith->repair_up(e);
|
|
||||||
else
|
|
||||||
m_arith64->repair_up(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void arith_plugin::set_value(expr* e, expr* v) {
|
void arith_plugin::set_value(expr* e, expr* v) {
|
||||||
if (!m_arith) {
|
WITH_FALLBACK(set_value(e, v));
|
||||||
try {
|
|
||||||
m_arith64->set_value(e, v);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (overflow_exception&) {
|
|
||||||
init_backup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_arith->set_value(e, v);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,11 +28,7 @@ namespace sls {
|
||||||
|
|
||||||
void init_backup();
|
void init_backup();
|
||||||
public:
|
public:
|
||||||
arith_plugin(context& ctx) :
|
arith_plugin(context& ctx);
|
||||||
plugin(ctx), m_shared(ctx.get_manager()) {
|
|
||||||
m_arith64 = alloc(arith_base<checked_int64<true>>,ctx);
|
|
||||||
m_fid = m_arith64->fid();
|
|
||||||
}
|
|
||||||
~arith_plugin() override {}
|
~arith_plugin() override {}
|
||||||
void register_term(expr* e) override;
|
void register_term(expr* e) override;
|
||||||
expr_ref get_value(expr* e) override;
|
expr_ref get_value(expr* e) override;
|
||||||
|
|
|
@ -17,6 +17,8 @@ Author:
|
||||||
|
|
||||||
#include "ast/sls/sls_basic_plugin.h"
|
#include "ast/sls/sls_basic_plugin.h"
|
||||||
#include "ast/ast_ll_pp.h"
|
#include "ast/ast_ll_pp.h"
|
||||||
|
#include "ast/ast_pp.h"
|
||||||
|
#include "ast/ast_util.h"
|
||||||
|
|
||||||
namespace sls {
|
namespace sls {
|
||||||
|
|
||||||
|
@ -24,50 +26,76 @@ namespace sls {
|
||||||
return expr_ref(m.mk_bool_val(bval0(e)), m);
|
return expr_ref(m.mk_bool_val(bval0(e)), m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool basic_plugin::is_basic(expr* e) const {
|
||||||
|
if (!e || !is_app(e))
|
||||||
|
return false;
|
||||||
|
if (to_app(e)->get_family_id() != basic_family_id)
|
||||||
|
return false;
|
||||||
|
if (!m.is_bool(e))
|
||||||
|
return false;
|
||||||
|
expr* x, * y;
|
||||||
|
if (m.is_eq(e, x, y) && !m.is_bool(x))
|
||||||
|
return false;
|
||||||
|
if (m.is_distinct(e) && !m.is_bool(to_app(e)->get_arg(0)))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void basic_plugin::propagate_literal(sat::literal lit) {
|
void basic_plugin::propagate_literal(sat::literal lit) {
|
||||||
auto a = ctx.atom(lit.var());
|
auto a = ctx.atom(lit.var());
|
||||||
if (!a || !is_app(a))
|
if (!is_basic(a))
|
||||||
return;
|
|
||||||
if (to_app(a)->get_family_id() != basic_family_id)
|
|
||||||
return;
|
return;
|
||||||
if (bval1(to_app(a)) != bval0(to_app(a)))
|
if (bval1(to_app(a)) != bval0(to_app(a)))
|
||||||
ctx.new_value_eh(a);
|
ctx.new_value_eh(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void basic_plugin::register_term(expr* e) {
|
void basic_plugin::register_term(expr* e) {
|
||||||
if (is_app(e) && m.is_bool(e) && to_app(e)->get_family_id() == basic_family_id)
|
if (is_basic(e))
|
||||||
m_values.setx(e->get_id(), bval1(to_app(e)), false);
|
m_values.setx(e->get_id(), bval1(to_app(e)), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void basic_plugin::initialize() {
|
void basic_plugin::initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool basic_plugin::propagate() {
|
||||||
|
for (auto t : ctx.subterms())
|
||||||
|
if (is_basic(t) && !m.is_not(t) &&
|
||||||
|
bval0(t) != bval1(to_app(t))) {
|
||||||
|
add_clause(to_app(t));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool basic_plugin::is_sat() {
|
bool basic_plugin::is_sat() {
|
||||||
for (auto t : ctx.subterms())
|
for (auto t : ctx.subterms())
|
||||||
if (is_app(t) &&
|
if (is_basic(t) && !m.is_not(t) &&
|
||||||
m.is_bool(t) &&
|
bval0(t) != bval1(to_app(t))) {
|
||||||
to_app(t)->get_family_id() == basic_family_id &&
|
verbose_stream() << mk_bounded_pp(t, m) << " := " << (bval0(t) ? "T" : "F") << " eval: " << (bval1(to_app(t)) ? "T" : "F") << "\n";
|
||||||
bval0(t) != bval1(to_app(t)))
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::ostream& basic_plugin::display(std::ostream& out) const {
|
std::ostream& basic_plugin::display(std::ostream& out) const {
|
||||||
for (auto t : ctx.subterms())
|
for (auto t : ctx.subterms())
|
||||||
if (is_app(t) && m.is_bool(t) && to_app(t)->get_family_id() == basic_family_id)
|
if (is_basic(t))
|
||||||
out << mk_bounded_pp(t, m) << " := " << (bval0(t)?"T":"F") << " eval: " << (bval1(to_app(t))?"T":"F") << "\n";
|
out << mk_bounded_pp(t, m) << " := " << (bval0(t)?"T":"F") << " eval: " << (bval1(to_app(t))?"T":"F") << "\n";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void basic_plugin::set_value(expr* e, expr* v) {
|
void basic_plugin::set_value(expr* e, expr* v) {
|
||||||
if (!m.is_bool(e))
|
if (!is_basic(e))
|
||||||
return;
|
return;
|
||||||
SASSERT(m.is_true(v) || m.is_false(v));
|
SASSERT(m.is_true(v) || m.is_false(v));
|
||||||
set_value(e, m.is_true(v));
|
set_value(e, m.is_true(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool basic_plugin::bval1(app* e) const {
|
bool basic_plugin::bval1(app* e) const {
|
||||||
|
if (m.is_not(e))
|
||||||
|
return bval1(to_app(e->get_arg(0)));
|
||||||
SASSERT(m.is_bool(e));
|
SASSERT(m.is_bool(e));
|
||||||
SASSERT(e->get_family_id() == basic_family_id);
|
SASSERT(e->get_family_id() == basic_family_id);
|
||||||
|
|
||||||
|
@ -103,6 +131,7 @@ namespace sls {
|
||||||
auto b = e->get_arg(1);
|
auto b = e->get_arg(1);
|
||||||
if (m.is_bool(a))
|
if (m.is_bool(a))
|
||||||
return bval0(a) == bval0(b);
|
return bval0(a) == bval0(b);
|
||||||
|
verbose_stream() << mk_bounded_pp(e, m) << " " << ctx.get_value(a) << " " << ctx.get_value(b) << "\n";
|
||||||
return ctx.get_value(a) == ctx.get_value(b);
|
return ctx.get_value(a) == ctx.get_value(b);
|
||||||
}
|
}
|
||||||
case OP_DISTINCT: {
|
case OP_DISTINCT: {
|
||||||
|
@ -123,11 +152,14 @@ namespace sls {
|
||||||
|
|
||||||
bool basic_plugin::bval0(expr* e) const {
|
bool basic_plugin::bval0(expr* e) const {
|
||||||
SASSERT(m.is_bool(e));
|
SASSERT(m.is_bool(e));
|
||||||
|
bool b = true;
|
||||||
|
while (m.is_not(e, e))
|
||||||
|
b = !b;
|
||||||
sat::bool_var v = ctx.atom2bool_var(e);
|
sat::bool_var v = ctx.atom2bool_var(e);
|
||||||
if (v == sat::null_bool_var)
|
if (v == sat::null_bool_var)
|
||||||
return m_values.get(e->get_id(), false);
|
return b == m_values.get(e->get_id(), false);
|
||||||
else
|
else
|
||||||
return ctx.is_true(v);
|
return b == ctx.is_true(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool basic_plugin::try_repair(app* e, unsigned i) {
|
bool basic_plugin::try_repair(app* e, unsigned i) {
|
||||||
|
@ -158,6 +190,56 @@ namespace sls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void basic_plugin::add_clause(app* e) {
|
||||||
|
expr_ref_vector es(m);
|
||||||
|
expr_ref fml(m);
|
||||||
|
expr* x, *y;
|
||||||
|
switch (e->get_decl_kind()) {
|
||||||
|
case OP_AND:
|
||||||
|
for (expr* arg : *e) {
|
||||||
|
ctx.add_constraint(m.mk_or(m.mk_not(e), arg));
|
||||||
|
es.push_back(mk_not(m, arg));
|
||||||
|
}
|
||||||
|
es.push_back(e);
|
||||||
|
ctx.add_constraint(m.mk_or(es));
|
||||||
|
break;
|
||||||
|
case OP_OR:
|
||||||
|
for (expr* arg : *e) {
|
||||||
|
ctx.add_constraint(m.mk_or(mk_not(m, arg), e));
|
||||||
|
es.push_back(arg);
|
||||||
|
}
|
||||||
|
es.push_back(m.mk_not(e));
|
||||||
|
ctx.add_constraint(m.mk_or(es));
|
||||||
|
break;
|
||||||
|
case OP_NOT:
|
||||||
|
break;
|
||||||
|
case OP_FALSE:
|
||||||
|
break;
|
||||||
|
case OP_TRUE:
|
||||||
|
break;
|
||||||
|
case OP_EQ:
|
||||||
|
VERIFY(m.is_eq(e, x, y));
|
||||||
|
ctx.add_constraint(m.mk_or(m.mk_not(e), mk_not(m, x), y));
|
||||||
|
ctx.add_constraint(m.mk_or(m.mk_not(e), mk_not(m, y), x));
|
||||||
|
ctx.add_constraint(m.mk_or(e, y, x));
|
||||||
|
ctx.add_constraint(m.mk_or(e, mk_not(m, x), mk_not(m, y)));
|
||||||
|
break;
|
||||||
|
case OP_IMPLIES:
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
case OP_XOR:
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
case OP_ITE:
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
case OP_DISTINCT:
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool basic_plugin::try_repair_and_or(app* e, unsigned i) {
|
bool basic_plugin::try_repair_and_or(app* e, unsigned i) {
|
||||||
auto b = bval0(e);
|
auto b = bval0(e);
|
||||||
if ((b && m.is_and(e)) || (!b && m.is_or(e))) {
|
if ((b && m.is_and(e)) || (!b && m.is_or(e))) {
|
||||||
|
@ -245,7 +327,7 @@ namespace sls {
|
||||||
}
|
}
|
||||||
|
|
||||||
void basic_plugin::repair_up(app* e) {
|
void basic_plugin::repair_up(app* e) {
|
||||||
if (!m.is_bool(e) || e->get_family_id() != basic_family_id)
|
if (!is_basic(e))
|
||||||
return;
|
return;
|
||||||
auto b = bval1(e);
|
auto b = bval1(e);
|
||||||
if (bval0(e) == b)
|
if (bval0(e) == b)
|
||||||
|
@ -256,7 +338,7 @@ namespace sls {
|
||||||
void basic_plugin::repair_down(app* e) {
|
void basic_plugin::repair_down(app* e) {
|
||||||
SASSERT(m.is_bool(e));
|
SASSERT(m.is_bool(e));
|
||||||
unsigned n = e->get_num_args();
|
unsigned n = e->get_num_args();
|
||||||
if (n == 0 || e->get_family_id() != m.get_basic_family_id())
|
if (n == 0 || !is_basic(e))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (bval0(e) == bval1(e))
|
if (bval0(e) == bval1(e))
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace sls {
|
||||||
bool_vector m_values;
|
bool_vector m_values;
|
||||||
bool m_initialized = false;
|
bool m_initialized = false;
|
||||||
|
|
||||||
|
bool is_basic(expr* e) const;
|
||||||
bool bval1(app* e) const;
|
bool bval1(app* e) const;
|
||||||
bool bval0(expr* e) const;
|
bool bval0(expr* e) const;
|
||||||
bool try_repair(app* e, unsigned i);
|
bool try_repair(app* e, unsigned i);
|
||||||
|
@ -32,6 +33,8 @@ namespace sls {
|
||||||
bool try_repair_distinct(app* e, unsigned i);
|
bool try_repair_distinct(app* e, unsigned i);
|
||||||
bool set_value(expr* e, bool b);
|
bool set_value(expr* e, bool b);
|
||||||
|
|
||||||
|
void add_clause(app* e);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
basic_plugin(context& ctx) :
|
basic_plugin(context& ctx) :
|
||||||
plugin(ctx) {
|
plugin(ctx) {
|
||||||
|
@ -42,7 +45,7 @@ namespace sls {
|
||||||
expr_ref get_value(expr* e) override;
|
expr_ref get_value(expr* e) override;
|
||||||
void initialize() override;
|
void initialize() override;
|
||||||
void propagate_literal(sat::literal lit) override;
|
void propagate_literal(sat::literal lit) override;
|
||||||
bool propagate() override { return false; }
|
bool propagate() override;
|
||||||
void repair_down(app* e) override;
|
void repair_down(app* e) override;
|
||||||
void repair_up(app* e) override;
|
void repair_up(app* e) override;
|
||||||
bool is_sat() override;
|
bool is_sat() override;
|
||||||
|
|
|
@ -59,15 +59,19 @@ namespace sls {
|
||||||
// Use timestamps to make it incremental.
|
// Use timestamps to make it incremental.
|
||||||
//
|
//
|
||||||
init();
|
init();
|
||||||
|
verbose_stream() << "check " << unsat().size() << "\n";
|
||||||
while (unsat().empty()) {
|
while (unsat().empty()) {
|
||||||
|
|
||||||
propagate_boolean_assignment();
|
propagate_boolean_assignment();
|
||||||
|
|
||||||
|
verbose_stream() << "propagate " << unsat().size() << " " << m_new_constraint << "\n";
|
||||||
// display(verbose_stream());
|
// display(verbose_stream());
|
||||||
|
|
||||||
if (m_new_constraint || !unsat().empty())
|
if (m_new_constraint || !unsat().empty())
|
||||||
return l_undef;
|
return l_undef;
|
||||||
|
|
||||||
|
verbose_stream() << unsat().size() << " " << m_new_constraint << "\n";
|
||||||
|
|
||||||
if (all_of(m_plugins, [&](auto* p) { return !p || p->is_sat(); })) {
|
if (all_of(m_plugins, [&](auto* p) { return !p || p->is_sat(); })) {
|
||||||
model_ref mdl = alloc(model, m);
|
model_ref mdl = alloc(model, m);
|
||||||
for (expr* e : subterms())
|
for (expr* e : subterms())
|
||||||
|
@ -98,7 +102,7 @@ namespace sls {
|
||||||
while (!m_repair_down.empty() && !m_new_constraint) {
|
while (!m_repair_down.empty() && !m_new_constraint) {
|
||||||
auto id = m_repair_down.erase_min();
|
auto id = m_repair_down.erase_min();
|
||||||
expr* e = term(id);
|
expr* e = term(id);
|
||||||
// verbose_stream() << "repair down " << mk_bounded_pp(e, m) << "\n";
|
TRACE("sls", tout << "repair down " << mk_bounded_pp(e, m) << "\n");
|
||||||
if (is_app(e)) {
|
if (is_app(e)) {
|
||||||
auto p = m_plugins.get(to_app(e)->get_family_id(), nullptr);
|
auto p = m_plugins.get(to_app(e)->get_family_id(), nullptr);
|
||||||
if (p)
|
if (p)
|
||||||
|
@ -108,7 +112,7 @@ namespace sls {
|
||||||
while (!m_repair_up.empty() && !m_new_constraint) {
|
while (!m_repair_up.empty() && !m_new_constraint) {
|
||||||
auto id = m_repair_up.erase_min();
|
auto id = m_repair_up.erase_min();
|
||||||
expr* e = term(id);
|
expr* e = term(id);
|
||||||
// verbose_stream() << "repair up " << mk_bounded_pp(e, m) << "\n";
|
TRACE("sls", tout << "repair up " << mk_bounded_pp(e, m) << "\n");
|
||||||
if (is_app(e)) {
|
if (is_app(e)) {
|
||||||
auto p = m_plugins.get(to_app(e)->get_family_id(), nullptr);
|
auto p = m_plugins.get(to_app(e)->get_family_id(), nullptr);
|
||||||
if (p)
|
if (p)
|
||||||
|
|
|
@ -108,32 +108,73 @@ namespace sls {
|
||||||
// send clauses to ddfw
|
// send clauses to ddfw
|
||||||
// send expression mapping to m_solver_ctx
|
// send expression mapping to m_solver_ctx
|
||||||
|
|
||||||
|
for (auto f : m_assertions)
|
||||||
|
add_clause(f);
|
||||||
|
|
||||||
|
IF_VERBOSE(10, m_solver_ctx->display(verbose_stream()));
|
||||||
|
return m_ddfw.check(0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void smt_solver::add_clause(expr* f) {
|
||||||
sat::literal_vector clause;
|
sat::literal_vector clause;
|
||||||
for (auto f : m_assertions) {
|
|
||||||
if (m.is_or(f)) {
|
if (m.is_or(f)) {
|
||||||
clause.reset();
|
clause.reset();
|
||||||
for (auto arg : *to_app(f))
|
for (auto arg : *to_app(f))
|
||||||
clause.push_back(mk_literal(arg));
|
clause.push_back(mk_literal(arg));
|
||||||
m_solver_ctx->add_clause(clause.size(), clause.data());
|
m_solver_ctx->add_clause(clause.size(), clause.data());
|
||||||
}
|
}
|
||||||
|
else if (m.is_and(f)) {
|
||||||
|
for (auto arg : *to_app(f))
|
||||||
|
add_clause(arg);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
sat::literal lit = mk_literal(f);
|
sat::literal lit = mk_literal(f);
|
||||||
m_solver_ctx->add_clause(1, &lit);
|
m_solver_ctx->add_clause(1, &lit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IF_VERBOSE(10, m_solver_ctx->display(verbose_stream()));
|
|
||||||
return m_ddfw.check(0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
sat::literal smt_solver::mk_literal(expr* e) {
|
sat::literal smt_solver::mk_literal(expr* e) {
|
||||||
bool neg = m.is_not(e, e);
|
sat::literal lit;
|
||||||
sat::bool_var v;
|
bool neg = false;
|
||||||
if (!m_expr2var.find(e, v)) {
|
while (m.is_not(e,e))
|
||||||
v = m_expr2var.size();
|
neg = !neg;
|
||||||
m_expr2var.insert(e, v);
|
if (m_expr2lit.find(e, lit))
|
||||||
m_solver_ctx->register_atom(v, e);
|
return neg ? ~lit : lit;
|
||||||
|
sat::literal_vector clause;
|
||||||
|
if (m.is_and(e)) {
|
||||||
|
lit = mk_literal();
|
||||||
|
for (expr* arg : *to_app(e)) {
|
||||||
|
auto lit2 = mk_literal(arg);
|
||||||
|
clause.push_back(~lit2);
|
||||||
|
sat::literal lits[2] = { ~lit, lit2 };
|
||||||
|
m_solver_ctx->add_clause(2, lits);
|
||||||
}
|
}
|
||||||
return sat::literal(v, neg);
|
clause.push_back(lit);
|
||||||
|
m_solver_ctx->add_clause(clause.size(), clause.data());
|
||||||
|
}
|
||||||
|
else if (m.is_or(e)) {
|
||||||
|
lit = mk_literal();
|
||||||
|
for (expr* arg : *to_app(e)) {
|
||||||
|
auto lit2 = mk_literal(arg);
|
||||||
|
clause.push_back(lit2);
|
||||||
|
sat::literal lits[2] = { lit, ~lit2 };
|
||||||
|
m_solver_ctx->add_clause(2, lits);
|
||||||
|
}
|
||||||
|
clause.push_back(~lit);
|
||||||
|
m_solver_ctx->add_clause(clause.size(), clause.data());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sat::bool_var v = m_num_vars++;
|
||||||
|
lit = sat::literal(v, false);
|
||||||
|
m_solver_ctx->register_atom(lit.var(), e);
|
||||||
|
}
|
||||||
|
m_expr2lit.insert(e, lit);
|
||||||
|
return neg ? ~lit : lit;
|
||||||
|
}
|
||||||
|
|
||||||
|
sat::literal smt_solver::mk_literal() {
|
||||||
|
sat::bool_var v = m_num_vars++;
|
||||||
|
return sat::literal(v, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
model_ref smt_solver::get_model() {
|
model_ref smt_solver::get_model() {
|
||||||
|
|
|
@ -29,9 +29,12 @@ namespace sls {
|
||||||
solver_ctx* m_solver_ctx = nullptr;
|
solver_ctx* m_solver_ctx = nullptr;
|
||||||
expr_ref_vector m_assertions;
|
expr_ref_vector m_assertions;
|
||||||
statistics m_st;
|
statistics m_st;
|
||||||
obj_map<expr, sat::bool_var> m_expr2var;
|
obj_map<expr, sat::literal> m_expr2lit;
|
||||||
|
unsigned m_num_vars = 0;
|
||||||
|
|
||||||
sat::literal mk_literal(expr* e);
|
sat::literal mk_literal(expr* e);
|
||||||
|
sat::literal mk_literal();
|
||||||
|
void add_clause(expr* f);
|
||||||
public:
|
public:
|
||||||
smt_solver(ast_manager& m, params_ref const& p);
|
smt_solver(ast_manager& m, params_ref const& p);
|
||||||
~smt_solver();
|
~smt_solver();
|
||||||
|
|
|
@ -32,6 +32,10 @@ namespace sat {
|
||||||
void add(literal lit) { ++m_num_trues; m_trues += lit.index(); }
|
void add(literal lit) { ++m_num_trues; m_trues += lit.index(); }
|
||||||
void del(literal lit) { SASSERT(m_num_trues > 0); --m_num_trues; m_trues -= lit.index(); }
|
void del(literal lit) { SASSERT(m_num_trues > 0); --m_num_trues; m_trues -= lit.index(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& out, clause_info const& ci) {
|
||||||
|
return out << ci.m_clause << " w: " << ci.m_weight << " nt: " << ci.m_num_trues;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue