mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
na
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
8357ac1cfc
commit
586343ce64
24 changed files with 708 additions and 513 deletions
|
@ -932,13 +932,13 @@ unsigned bv_util::get_int2bv_size(parameter const& p) {
|
|||
return static_cast<unsigned>(sz);
|
||||
}
|
||||
|
||||
app * bv_util::mk_bv2int(expr* e) {
|
||||
app * bv_util::mk_bv2int(expr* e) const {
|
||||
sort* s = m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT);
|
||||
parameter p(s);
|
||||
return m_manager.mk_app(get_fid(), OP_BV2INT, 1, &p, 1, &e);
|
||||
}
|
||||
|
||||
app* bv_util::mk_int2bv(unsigned sz, expr* e) {
|
||||
app* bv_util::mk_int2bv(unsigned sz, expr* e) const {
|
||||
parameter p(sz);
|
||||
return m_manager.mk_app(get_fid(), OP_INT2BV, 1, &p, 1, &e);
|
||||
}
|
||||
|
|
|
@ -549,8 +549,8 @@ public:
|
|||
app * mk_bv_ashr(expr* arg1, expr* arg2) { return m_manager.mk_app(get_fid(), OP_BASHR, arg1, arg2); }
|
||||
app * mk_bv_lshr(expr* arg1, expr* arg2) { return m_manager.mk_app(get_fid(), OP_BLSHR, arg1, arg2); }
|
||||
|
||||
app * mk_bv2int(expr* e);
|
||||
app * mk_int2bv(unsigned sz, expr* e);
|
||||
app * mk_bv2int(expr* e) const;
|
||||
app * mk_int2bv(unsigned sz, expr* e) const;
|
||||
|
||||
app* mk_bv_rotate_left(expr* arg1, expr* arg2) { return m_manager.mk_app(get_fid(), OP_EXT_ROTATE_LEFT, arg1, arg2); }
|
||||
app* mk_bv_rotate_right(expr* arg1, expr* arg2) { return m_manager.mk_app(get_fid(), OP_EXT_ROTATE_RIGHT, arg1, arg2); }
|
||||
|
|
|
@ -10,8 +10,9 @@ z3_add_component(ast_sls
|
|||
sls_basic_plugin.cpp
|
||||
sls_bv_plugin.cpp
|
||||
sls_cc.cpp
|
||||
sls_context.cpp
|
||||
sls_engine.cpp
|
||||
sls_smt.cpp
|
||||
sls_smt_solver.cpp
|
||||
sls_valuation.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
ast
|
||||
|
|
|
@ -14,6 +14,7 @@ Author:
|
|||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/sls/bv_sls.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
|
||||
namespace bv {
|
||||
|
||||
|
@ -25,29 +26,28 @@ namespace bv {
|
|||
m_fix(*this, terms, ctx)
|
||||
{}
|
||||
|
||||
void sls_eval::init_eval(std::function<bool(expr*, unsigned)> const& eval) {
|
||||
for (expr* e : ctx.subterms()) {
|
||||
if (!is_app(e))
|
||||
continue;
|
||||
app* a = to_app(e);
|
||||
if (!bv.is_bv(e))
|
||||
continue;
|
||||
add_bit_vector(a);
|
||||
if (a->get_family_id() == bv.get_family_id())
|
||||
init_eval_bv(a);
|
||||
else if (is_uninterp(e)) {
|
||||
auto& v = wval(e);
|
||||
for (unsigned i = 0; i < v.bw; ++i)
|
||||
m_tmp.set(i, eval(e, i));
|
||||
v.set_repair(random_bool(), m_tmp);
|
||||
}
|
||||
|
||||
void sls_eval::register_term(expr* e) {
|
||||
if (!is_app(e))
|
||||
return;
|
||||
app* a = to_app(e);
|
||||
add_bit_vector(a);
|
||||
if (a->get_family_id() == bv.get_family_id())
|
||||
init_eval_bv(a);
|
||||
else if (bv.is_bv(e)) {
|
||||
auto& v = wval(e);
|
||||
for (unsigned i = 0; i < v.bw; ++i)
|
||||
m_tmp.set(i, false);
|
||||
v.set_repair(random_bool(), m_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
bool sls_eval::add_bit_vector(app* e) {
|
||||
void sls_eval::add_bit_vector(app* e) {
|
||||
if (!bv.is_bv(e))
|
||||
return;
|
||||
m_values.reserve(e->get_id() + 1);
|
||||
if (m_values.get(e->get_id()))
|
||||
return false;
|
||||
return;
|
||||
auto v = alloc_valuation(e);
|
||||
m_values.set(e->get_id(), v);
|
||||
expr* x, * y;
|
||||
|
@ -57,7 +57,7 @@ namespace bv {
|
|||
else if (bv.is_bv_ashr(e, x, y) && bv.is_numeral(y, val) &&
|
||||
val.is_unsigned() && val.get_unsigned() <= bv.get_bv_size(e))
|
||||
v->set_signed(val.get_unsigned());
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
sls_valuation* sls_eval::alloc_valuation(app* e) {
|
||||
|
@ -575,11 +575,19 @@ namespace bv {
|
|||
val.set(val.eval, 0);
|
||||
break;
|
||||
}
|
||||
case OP_INT2BV: {
|
||||
expr_ref v = ctx.get_value(e->get_arg(0));
|
||||
th_rewriter rw(m);
|
||||
v = bv.mk_int2bv(bv.get_bv_size(e), v);
|
||||
rw(v);
|
||||
rational r;
|
||||
VERIFY(bv.is_numeral(v, r));
|
||||
val.set_value(m_tmp, r);
|
||||
break;
|
||||
}
|
||||
case OP_BREDAND:
|
||||
case OP_BREDOR:
|
||||
case OP_BXNOR:
|
||||
case OP_INT2BV:
|
||||
|
||||
verbose_stream() << mk_bounded_pp(e, m) << "\n";
|
||||
NOT_IMPLEMENTED_YET();
|
||||
break;
|
||||
|
@ -672,7 +680,7 @@ namespace bv {
|
|||
case OP_BV2INT:
|
||||
return false;
|
||||
case OP_INT2BV:
|
||||
return false;
|
||||
return try_repair_int2bv(eval_value(e), e->get_arg(0));
|
||||
case OP_ULEQ:
|
||||
if (i == 0)
|
||||
return try_repair_ule(bval0(e), wval(e, i), wval(e, 1 - i));
|
||||
|
@ -1804,6 +1812,16 @@ namespace bv {
|
|||
return a.set_random(m_rand);
|
||||
}
|
||||
|
||||
bool sls_eval::try_repair_int2bv(bvect const& e, expr* arg) {
|
||||
expr_ref intval(m);
|
||||
intval = bv.mk_bv2int(bv.mk_numeral(e.get_value(e.nw), e.bw));
|
||||
th_rewriter rw(m);
|
||||
rw(intval);
|
||||
verbose_stream() << "repair " << mk_pp(arg, m) << " " << intval << "\n";
|
||||
ctx.set_value(arg, intval);
|
||||
return true;
|
||||
}
|
||||
|
||||
void sls_eval::set_div(bvect const& a, bvect const& b, unsigned bw,
|
||||
bvect& quot, bvect& rem) const {
|
||||
unsigned nw = (bw + 8 * sizeof(digit_t) - 1) / (8 * sizeof(digit_t));
|
||||
|
@ -1853,8 +1871,10 @@ namespace bv {
|
|||
}
|
||||
|
||||
void sls_eval::commit_eval(app* e) {
|
||||
if (bv.is_bv(e))
|
||||
VERIFY(wval(e).commit_eval());
|
||||
if (!bv.is_bv(e))
|
||||
return;
|
||||
VERIFY(wval(e).commit_eval());
|
||||
// todo: if e is shared, then ctx.set_value().
|
||||
}
|
||||
|
||||
void sls_eval::set_random(app* e) {
|
||||
|
@ -1899,7 +1919,7 @@ namespace bv {
|
|||
return expr_ref(m);
|
||||
}
|
||||
|
||||
std::ostream& sls_eval::display(std::ostream& out) {
|
||||
std::ostream& sls_eval::display(std::ostream& out) const {
|
||||
auto& terms = ctx.subterms();
|
||||
for (expr* e : terms) {
|
||||
if (!bv.is_bv(e))
|
||||
|
@ -1912,7 +1932,7 @@ namespace bv {
|
|||
return out;
|
||||
}
|
||||
|
||||
std::ostream& sls_eval::display_value(std::ostream& out, expr* e) {
|
||||
std::ostream& sls_eval::display_value(std::ostream& out, expr* e) const {
|
||||
if (bv.is_bv(e))
|
||||
return out << wval(e);
|
||||
return out << "?";
|
||||
|
|
|
@ -19,7 +19,7 @@ Author:
|
|||
#include "ast/ast.h"
|
||||
#include "ast/sls/sls_valuation.h"
|
||||
#include "ast/sls/bv_sls_fixed.h"
|
||||
#include "ast/sls/sls_smt.h"
|
||||
#include "ast/sls/sls_context.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
|
||||
namespace bv {
|
||||
|
@ -58,7 +58,7 @@ namespace bv {
|
|||
* Register e as a bit-vector.
|
||||
* Return true if not already registered, false if already registered.
|
||||
*/
|
||||
bool add_bit_vector(app* e);
|
||||
void add_bit_vector(app* e);
|
||||
sls_valuation* alloc_valuation(app* e);
|
||||
|
||||
//bool bval1_basic(app* e) const;
|
||||
|
@ -109,6 +109,7 @@ namespace bv {
|
|||
bool try_repair_extract(bvect const& e, bvval& a, unsigned lo);
|
||||
bool try_repair_comp(bvect const& e, bvval& a, bvval& b, unsigned i);
|
||||
bool try_repair_eq(bool is_true, bvval& a, bvval const& b);
|
||||
bool try_repair_int2bv(bvect const& e, expr* arg);
|
||||
void add_p2_1(bvval const& a, bvect& t) const;
|
||||
|
||||
bool add_overflow_on_fixed(bvval const& a, bvect const& t);
|
||||
|
@ -136,10 +137,12 @@ namespace bv {
|
|||
public:
|
||||
sls_eval(sls_terms& terms, sls::context& ctx);
|
||||
|
||||
void init_eval(std::function<bool(expr*, unsigned)> const& eval);
|
||||
// void init_eval(std::function<bool(expr*, unsigned)> const& eval);
|
||||
|
||||
void tighten_range() { m_fix.init(); }
|
||||
|
||||
void register_term(expr* e);
|
||||
|
||||
/**
|
||||
* Retrieve evaluation based on cache.
|
||||
* bval - Boolean values
|
||||
|
@ -178,8 +181,8 @@ namespace bv {
|
|||
bool repair_up(expr* e);
|
||||
|
||||
|
||||
std::ostream& display(std::ostream& out);
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
|
||||
std::ostream& display_value(std::ostream& out, expr* e);
|
||||
std::ostream& display_value(std::ostream& out, expr* e) const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ Author:
|
|||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/sls/sls_valuation.h"
|
||||
#include "ast/sls/sls_smt.h"
|
||||
#include "ast/sls/sls_context.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
|
||||
namespace bv {
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace bv {
|
|||
ctx(ctx),
|
||||
m(ctx.get_manager()),
|
||||
bv(m),
|
||||
m_axioms(m) {}
|
||||
m_axioms(m) {}
|
||||
|
||||
void sls_terms::register_term(expr* e) {
|
||||
auto r = ensure_binary(e);
|
||||
|
|
|
@ -24,7 +24,7 @@ Author:
|
|||
#include "ast/sls/sls_stats.h"
|
||||
#include "ast/sls/sls_powers.h"
|
||||
#include "ast/sls/sls_valuation.h"
|
||||
#include "ast/sls/sls_smt.h"
|
||||
#include "ast/sls/sls_context.h"
|
||||
|
||||
namespace bv {
|
||||
|
||||
|
|
|
@ -243,10 +243,14 @@ namespace sat {
|
|||
// access clause information and state of Boolean search
|
||||
indexed_uint_set& unsat_set() { return m_unsat; }
|
||||
|
||||
indexed_uint_set const& unsat_set() const { return m_unsat; }
|
||||
|
||||
vector<clause_info> const& clauses() const { return m_clauses; }
|
||||
|
||||
clause_info& get_clause_info(unsigned idx) { return m_clauses[idx]; }
|
||||
|
||||
clause_info const& get_clause_info(unsigned idx) const { return m_clauses[idx]; }
|
||||
|
||||
void remove_assumptions();
|
||||
|
||||
void flip(bool_var v);
|
||||
|
|
|
@ -317,32 +317,16 @@ namespace sls {
|
|||
SASSERT(dtt(sign(bv), ineq) == 0);
|
||||
}
|
||||
vi.m_value = new_value;
|
||||
if (vi.m_shared) {
|
||||
sort* s = vi.m_sort == var_sort::INT ? a.mk_int() : a.mk_real();
|
||||
expr_ref num = from_num(s, new_value);
|
||||
ctx.set_value(vi.m_expr, num);
|
||||
}
|
||||
for (auto idx : vi.m_muls) {
|
||||
auto const& [v, monomial] = m_muls[idx];
|
||||
num_t prod(1);
|
||||
for (auto w : monomial)
|
||||
prod *= value(w);
|
||||
if (value(v) != prod)
|
||||
m_vars_to_update.push_back({ v, prod });
|
||||
auto const& [w, coeff, monomial] = m_muls[idx];
|
||||
ctx.new_value_eh(m_vars[w].m_expr);
|
||||
}
|
||||
for (auto const& idx : vi.m_adds) {
|
||||
for (auto idx : vi.m_adds) {
|
||||
auto const& ad = m_adds[idx];
|
||||
auto const& args = ad.m_args;
|
||||
auto v = ad.m_var;
|
||||
num_t sum(ad.m_coeff);
|
||||
for (auto [c, w] : args)
|
||||
sum += c * value(w);
|
||||
if (value(v) != sum)
|
||||
m_vars_to_update.push_back({ v, sum });
|
||||
ctx.new_value_eh(m_vars[ad.m_var].m_expr);
|
||||
}
|
||||
if (vi.m_def_idx != UINT_MAX)
|
||||
// add repair actions for additions and multiplications
|
||||
m_defs_to_update.push_back(v);
|
||||
expr* e = vi.m_expr;
|
||||
ctx.new_value_eh(e);
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
|
@ -375,10 +359,10 @@ namespace sls {
|
|||
|
||||
template<typename num_t>
|
||||
bool arith_base<num_t>::is_num(expr* e, num_t& i) {
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
expr_ref arith_base<rational>::from_num(sort* s, rational const& n) {
|
||||
return expr_ref(a.mk_numeral(n, s), m);
|
||||
}
|
||||
|
@ -389,6 +373,7 @@ namespace sls {
|
|||
|
||||
template<typename num_t>
|
||||
expr_ref arith_base<num_t>::from_num(sort* s, num_t const& n) {
|
||||
UNREACHABLE();
|
||||
return expr_ref(m);
|
||||
}
|
||||
|
||||
|
@ -427,14 +412,14 @@ namespace sls {
|
|||
default: {
|
||||
v = mk_var(e);
|
||||
unsigned idx = m_muls.size();
|
||||
m_muls.push_back({ v, m });
|
||||
num_t prod(1);
|
||||
m_muls.push_back({ v, c, m });
|
||||
num_t prod(c);
|
||||
for (auto w : m)
|
||||
m_vars[w].m_muls.push_back(idx), prod *= value(w);
|
||||
m_vars[v].m_def_idx = idx;
|
||||
m_vars[v].m_op = arith_op_kind::OP_MUL;
|
||||
m_vars[v].m_value = prod;
|
||||
add_arg(term, c, v);
|
||||
add_arg(term, num_t(1), v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -473,22 +458,21 @@ namespace sls {
|
|||
num_t val;
|
||||
switch (k) {
|
||||
case arith_op_kind::OP_MOD:
|
||||
if (value(v) != 0)
|
||||
val = mod(value(w), value(v));
|
||||
val = value(v) == 0 ? num_t(0) : mod(value(w), value(v));
|
||||
break;
|
||||
case arith_op_kind::OP_REM:
|
||||
if (value(v) != 0) {
|
||||
if (value(v) == 0)
|
||||
val = 0;
|
||||
else {
|
||||
val = value(w);
|
||||
val %= value(v);
|
||||
}
|
||||
break;
|
||||
case arith_op_kind::OP_IDIV:
|
||||
if (value(v) != 0)
|
||||
val = div(value(w), value(v));
|
||||
val = value(v) == 0 ? num_t(0): div(value(w), value(v));
|
||||
break;
|
||||
case arith_op_kind::OP_DIV:
|
||||
if (value(v) != 0)
|
||||
val = value(w) / value(v);
|
||||
val = value(v) == 0? num_t(0) : value(w) / value(v);
|
||||
break;
|
||||
case arith_op_kind::OP_ABS:
|
||||
val = abs(value(w));
|
||||
|
@ -511,7 +495,7 @@ namespace sls {
|
|||
return v;
|
||||
linear_term t;
|
||||
add_args(t, e, num_t(1));
|
||||
if (t.m_coeff == 1 && t.m_args.size() == 1 && t.m_args[0].first == 1)
|
||||
if (t.m_coeff == 0 && t.m_args.size() == 1 && t.m_args[0].first == 1)
|
||||
return t.m_args[0].second;
|
||||
v = mk_var(e);
|
||||
auto idx = m_adds.size();
|
||||
|
@ -531,7 +515,7 @@ namespace sls {
|
|||
if (v == UINT_MAX) {
|
||||
v = m_vars.size();
|
||||
m_expr2var.setx(e->get_id(), v, UINT_MAX);
|
||||
m_vars.push_back(var_info(e, a.is_int(e) ? var_sort::INT : var_sort::REAL));
|
||||
m_vars.push_back(var_info(e, a.is_int(e) ? var_sort::INT : var_sort::REAL));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
@ -541,7 +525,7 @@ namespace sls {
|
|||
if (m_bool_vars.get(bv, nullptr))
|
||||
return;
|
||||
expr* e = ctx.atom(bv);
|
||||
// verbose_stream() << "bool var " << bv << " " << mk_bounded_pp(e, m) << "\n";
|
||||
verbose_stream() << "bool var " << bv << " " << mk_bounded_pp(e, m) << "\n";
|
||||
if (!e)
|
||||
return;
|
||||
expr* x, * y;
|
||||
|
@ -570,6 +554,9 @@ namespace sls {
|
|||
add_args(ineq, y, num_t(-1));
|
||||
init_ineq(bv, ineq);
|
||||
}
|
||||
else if (m.is_distinct(e) && a.is_int_real(e->get_arg(0))) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
else if (a.is_is_int(e, x))
|
||||
{
|
||||
NOT_IMPLEMENTED_YET();
|
||||
|
@ -601,77 +588,127 @@ namespace sls {
|
|||
}
|
||||
|
||||
template<typename num_t>
|
||||
void arith_base<num_t>::repair(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))
|
||||
return;
|
||||
auto const* ineq = atom(lit.var());
|
||||
if (!ineq)
|
||||
return;
|
||||
TRACE("sls", tout << "repair lit: " << lit << " ineq-is-true: " << ineq->is_true() << "\n");
|
||||
if (ineq->is_true() != lit.sign())
|
||||
return;
|
||||
TRACE("sls", tout << "repair " << lit << "\n");
|
||||
return;
|
||||
repair(lit, *ineq);
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
void arith_base<num_t>::repair_defs_and_updates() {
|
||||
while (!m_defs_to_update.empty() || !m_vars_to_update.empty()) {
|
||||
repair_updates();
|
||||
repair_defs();
|
||||
bool arith_base<num_t>::propagate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
void arith_base<num_t>::repair_up(app* e) {
|
||||
auto v = m_expr2var.get(e->get_id(), UINT_MAX);
|
||||
if (v == UINT_MAX)
|
||||
return;
|
||||
auto const& vi = m_vars[v];
|
||||
if (vi.m_def_idx == UINT_MAX)
|
||||
return;
|
||||
m_ops.reserve(vi.m_def_idx + 1);
|
||||
auto const& od = m_ops[vi.m_def_idx];
|
||||
num_t v1, v2;
|
||||
switch (vi.m_op) {
|
||||
case LAST_ARITH_OP:
|
||||
break;
|
||||
case OP_ADD: {
|
||||
auto const& ad = m_adds[vi.m_def_idx];
|
||||
auto const& args = ad.m_args;
|
||||
num_t sum(ad.m_coeff);
|
||||
for (auto [c, w] : args)
|
||||
sum += c * value(w);
|
||||
update(v, sum);
|
||||
break;
|
||||
}
|
||||
case OP_MUL: {
|
||||
auto const& [w, coeff, monomial] = m_muls[vi.m_def_idx];
|
||||
num_t prod(coeff);
|
||||
for (auto w : monomial)
|
||||
prod *= value(w);
|
||||
update(v, prod);
|
||||
break;
|
||||
}
|
||||
case OP_MOD:
|
||||
v1 = value(od.m_arg1);
|
||||
v2 = value(od.m_arg2);
|
||||
update(v, v2 == 0 ? num_t(0) : mod(v1, v2));
|
||||
break;
|
||||
case OP_DIV:
|
||||
v1 = value(od.m_arg1);
|
||||
v2 = value(od.m_arg2);
|
||||
update(v, v2 == 0 ? num_t(0) : v1 / v2);
|
||||
break;
|
||||
case OP_IDIV:
|
||||
v1 = value(od.m_arg1);
|
||||
v2 = value(od.m_arg2);
|
||||
update(v, v2 == 0 ? num_t(0) : div(v1, v2));
|
||||
break;
|
||||
case OP_REM:
|
||||
v1 = value(od.m_arg1);
|
||||
v2 = value(od.m_arg2);
|
||||
update(v, v2 == 0 ? num_t(0) : v1 %= v2);
|
||||
break;
|
||||
case OP_ABS:
|
||||
update(v, abs(value(od.m_arg1)));
|
||||
break;
|
||||
default:
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
void arith_base<num_t>::repair_updates() {
|
||||
while (!m_vars_to_update.empty()) {
|
||||
auto [w, new_value1] = m_vars_to_update.back();
|
||||
m_vars_to_update.pop_back();
|
||||
update(w, new_value1);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
void arith_base<num_t>::repair_defs() {
|
||||
while (!m_defs_to_update.empty()) {
|
||||
auto v = m_defs_to_update.back();
|
||||
m_defs_to_update.pop_back();
|
||||
auto const& vi = m_vars[v];
|
||||
switch (vi.m_op) {
|
||||
case arith_op_kind::LAST_ARITH_OP:
|
||||
break;
|
||||
case arith_op_kind::OP_ADD:
|
||||
repair_add(m_adds[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_MUL:
|
||||
repair_mul(m_muls[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_MOD:
|
||||
repair_mod(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_REM:
|
||||
repair_rem(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_POWER:
|
||||
repair_power(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_IDIV:
|
||||
repair_idiv(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_DIV:
|
||||
repair_div(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_ABS:
|
||||
repair_abs(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_TO_INT:
|
||||
repair_to_int(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_TO_REAL:
|
||||
repair_to_real(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
default:
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
void arith_base<num_t>::repair_down(app* e) {
|
||||
auto v = m_expr2var.get(e->get_id(), UINT_MAX);
|
||||
if (v == UINT_MAX)
|
||||
return;
|
||||
auto const& vi = m_vars[v];
|
||||
if (vi.m_def_idx == UINT_MAX)
|
||||
return;
|
||||
TRACE("sls", tout << "repair def " << mk_bounded_pp(vi.m_expr, m) << "\n");
|
||||
switch (vi.m_op) {
|
||||
case arith_op_kind::LAST_ARITH_OP:
|
||||
break;
|
||||
case arith_op_kind::OP_ADD:
|
||||
repair_add(m_adds[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_MUL:
|
||||
repair_mul(m_muls[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_MOD:
|
||||
repair_mod(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_REM:
|
||||
repair_rem(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_POWER:
|
||||
repair_power(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_IDIV:
|
||||
repair_idiv(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_DIV:
|
||||
repair_div(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_ABS:
|
||||
repair_abs(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_TO_INT:
|
||||
repair_to_int(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
case arith_op_kind::OP_TO_REAL:
|
||||
repair_to_real(m_ops[vi.m_def_idx]);
|
||||
break;
|
||||
default:
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -699,23 +736,24 @@ namespace sls {
|
|||
|
||||
template<typename num_t>
|
||||
void arith_base<num_t>::repair_mul(mul_def const& md) {
|
||||
num_t product(1);
|
||||
num_t val = value(md.m_var);
|
||||
for (auto v : md.m_monomial)
|
||||
auto const& [v, coeff, monomial] = md;
|
||||
num_t product(coeff);
|
||||
num_t val = value(v);
|
||||
for (auto v : monomial)
|
||||
product *= value(v);
|
||||
if (product == val)
|
||||
return;
|
||||
if (rand() % 20 == 0) {
|
||||
update(md.m_var, product);
|
||||
update(v, product);
|
||||
}
|
||||
else if (val == 0) {
|
||||
auto v = md.m_monomial[rand() % md.m_monomial.size()];
|
||||
auto v = monomial[ctx.rand(monomial.size())];
|
||||
num_t zero(0);
|
||||
update(v, zero);
|
||||
}
|
||||
else if (val == 1 || val == -1) {
|
||||
product = 1;
|
||||
for (auto v : md.m_monomial) {
|
||||
product = coeff;
|
||||
for (auto v : monomial) {
|
||||
num_t new_value(1);
|
||||
if (rand() % 2 == 0)
|
||||
new_value = -1;
|
||||
|
@ -723,14 +761,14 @@ namespace sls {
|
|||
update(v, new_value);
|
||||
}
|
||||
if (product != val) {
|
||||
auto last = md.m_monomial.back();
|
||||
auto last = monomial.back();
|
||||
update(last, -value(last));
|
||||
}
|
||||
}
|
||||
else if (rand() % 2 == 0 && product != 0) {
|
||||
// value1(v) * product / value(v) = val
|
||||
// value1(v) = value(v) * val / product
|
||||
auto w = md.m_monomial[rand() % md.m_monomial.size()];
|
||||
auto w = monomial[ctx.rand(monomial.size())];
|
||||
auto old_value = value(w);
|
||||
num_t new_value;
|
||||
if (m_vars[w].m_sort == var_sort::REAL)
|
||||
|
@ -740,15 +778,15 @@ namespace sls {
|
|||
update(w, new_value);
|
||||
}
|
||||
else {
|
||||
product = 1;
|
||||
for (auto v : md.m_monomial) {
|
||||
product = coeff;
|
||||
for (auto v : monomial) {
|
||||
num_t new_value{ 1 };
|
||||
if (rand() % 2 == 0)
|
||||
new_value = -1;
|
||||
product *= new_value;
|
||||
update(v, new_value);
|
||||
}
|
||||
auto v = md.m_monomial[rand() % md.m_monomial.size()];
|
||||
auto v = monomial[ctx.rand(monomial.size())];
|
||||
if ((product < 0 && 0 < val) || (val < 0 && 0 < product))
|
||||
update(v, -val * value(v));
|
||||
else
|
||||
|
@ -761,8 +799,10 @@ namespace sls {
|
|||
auto val = value(od.m_var);
|
||||
auto v1 = value(od.m_arg1);
|
||||
auto v2 = value(od.m_arg2);
|
||||
if (v2 == 0)
|
||||
if (v2 == 0) {
|
||||
update(od.m_var, num_t(0));
|
||||
return;
|
||||
}
|
||||
|
||||
IF_VERBOSE(0, verbose_stream() << "todo repair rem");
|
||||
// bail
|
||||
|
@ -784,7 +824,11 @@ namespace sls {
|
|||
|
||||
template<typename num_t>
|
||||
void arith_base<num_t>::repair_to_int(op_def const& od) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
auto val = value(od.m_var);
|
||||
auto v1 = value(od.m_arg1);
|
||||
if (val - 1 < v1 && v1 <= val)
|
||||
return;
|
||||
update(od.m_arg1, val);
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
|
@ -800,8 +844,10 @@ namespace sls {
|
|||
auto val = value(od.m_var);
|
||||
auto v1 = value(od.m_arg1);
|
||||
auto v2 = value(od.m_arg2);
|
||||
if (v1 == 0 && v2 == 0)
|
||||
if (v1 == 0 && v2 == 0) {
|
||||
update(od.m_var, num_t(0));
|
||||
return;
|
||||
}
|
||||
IF_VERBOSE(0, verbose_stream() << "todo repair ^");
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
|
@ -832,10 +878,7 @@ namespace sls {
|
|||
update(od.m_arg1, v1);
|
||||
return;
|
||||
}
|
||||
if (v2 == 0)
|
||||
return;
|
||||
// bail
|
||||
update(od.m_var, mod(v1, v2));
|
||||
update(od.m_var, v2 == 0 ? num_t(0) : mod(v1, v2));
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
|
@ -843,11 +886,9 @@ namespace sls {
|
|||
auto val = value(od.m_var);
|
||||
auto v1 = value(od.m_arg1);
|
||||
auto v2 = value(od.m_arg2);
|
||||
if (v2 == 0)
|
||||
return;
|
||||
IF_VERBOSE(0, verbose_stream() << "todo repair div");
|
||||
// bail
|
||||
update(od.m_var, div(v1, v2));
|
||||
update(od.m_var, v2 == 0 ? num_t(0) : div(v1, v2));
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
|
@ -855,11 +896,9 @@ namespace sls {
|
|||
auto val = value(od.m_var);
|
||||
auto v1 = value(od.m_arg1);
|
||||
auto v2 = value(od.m_arg2);
|
||||
if (v2 == 0)
|
||||
return;
|
||||
IF_VERBOSE(0, verbose_stream() << "todo repair /");
|
||||
// bail
|
||||
update(od.m_var, v1 / v2);
|
||||
update(od.m_var, v2 == 0 ? num_t(0) : v1 / v2);
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
|
@ -956,27 +995,31 @@ namespace sls {
|
|||
}
|
||||
|
||||
template<typename num_t>
|
||||
void arith_base<num_t>::register_term(expr* e) {
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
void arith_base<num_t>::set_shared(expr* e) {
|
||||
if (!a.is_int_real(e))
|
||||
void arith_base<num_t>::register_term(expr* _e) {
|
||||
if (!is_app(_e))
|
||||
return;
|
||||
var_t v = m_expr2var.get(e->get_id(), UINT_MAX);
|
||||
if (v == UINT_MAX)
|
||||
v = mk_term(e);
|
||||
m_vars[v].m_shared = true;
|
||||
app* e = to_app(_e);
|
||||
auto v = ctx.atom2bool_var(e);
|
||||
if (v != sat::null_bool_var)
|
||||
init_bool_var(v);
|
||||
if (!a.is_arith_expr(e) && !m.is_eq(e) && !m.is_distinct(e))
|
||||
for (auto arg : *e)
|
||||
if (a.is_int_real(arg))
|
||||
mk_term(arg);
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
void arith_base<num_t>::set_value(expr* e, expr* v) {
|
||||
auto w = m_expr2var.get(e->get_id(), UINT_MAX);
|
||||
if (w == UINT_MAX)
|
||||
if (!a.is_int_real(e))
|
||||
return;
|
||||
var_t w = m_expr2var.get(e->get_id(), UINT_MAX);
|
||||
if (w == UINT_MAX)
|
||||
w = mk_term(e);
|
||||
|
||||
num_t n;
|
||||
if (!is_num(v, n))
|
||||
return;
|
||||
verbose_stream() << "set value " << w << " " << mk_bounded_pp(e, m) << " " << n << " " << value(w) << "\n";
|
||||
if (n == value(w))
|
||||
return;
|
||||
update(w, n);
|
||||
|
@ -988,21 +1031,6 @@ namespace sls {
|
|||
return expr_ref(a.mk_numeral(rational(m_vars[v].m_value.get_int64(), rational::i64()), a.is_int(e)), m);
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
lbool arith_base<num_t>::check() {
|
||||
// repair each root literal
|
||||
for (sat::literal lit : ctx.root_literals())
|
||||
repair(lit);
|
||||
|
||||
repair_defs_and_updates();
|
||||
|
||||
// update literal assignment based on current model
|
||||
for (unsigned v = 0; v < ctx.num_bool_vars(); ++v)
|
||||
init_bool_var_assignment(v);
|
||||
|
||||
return ctx.unsat().empty() ? l_true : l_undef;
|
||||
}
|
||||
|
||||
template<typename num_t>
|
||||
bool arith_base<num_t>::is_sat() {
|
||||
for (auto const& clause : ctx.clauses()) {
|
||||
|
@ -1035,8 +1063,8 @@ namespace sls {
|
|||
}
|
||||
for (unsigned v = 0; v < m_vars.size(); ++v) {
|
||||
auto const& vi = m_vars[v];
|
||||
out << "v" << v << " := " << vi.m_value << " " << vi.m_best_value << " ";
|
||||
out << mk_bounded_pp(vi.m_expr, m) << " - ";
|
||||
out << "v" << v << " := " << vi.m_value << " (best " << vi.m_best_value << ") ";
|
||||
out << mk_bounded_pp(vi.m_expr, m) << " : ";
|
||||
for (auto [c, bv] : vi.m_bool_vars)
|
||||
out << c << "@" << bv << " ";
|
||||
out << "\n";
|
||||
|
@ -1049,9 +1077,11 @@ namespace sls {
|
|||
}
|
||||
for (auto ad : m_adds) {
|
||||
out << "v" << ad.m_var << " := ";
|
||||
bool first = true;
|
||||
for (auto [c, w] : ad.m_args)
|
||||
out << c << "* v" << w << " + ";
|
||||
out << ad.m_coeff;
|
||||
out << (first?"":" + ") << c << "* v" << w;
|
||||
if (ad.m_coeff != 0)
|
||||
out << " + " << ad.m_coeff;
|
||||
out << "\n";
|
||||
}
|
||||
for (auto od : m_ops) {
|
||||
|
|
|
@ -20,7 +20,7 @@ Author:
|
|||
#include "util/checked_int64.h"
|
||||
#include "ast/ast_trail.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/sls/sls_smt.h"
|
||||
#include "ast/sls/sls_context.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
|
@ -75,11 +75,11 @@ namespace sls {
|
|||
out << " + " << m_coeff;
|
||||
switch (m_op) {
|
||||
case ineq_kind::LE:
|
||||
return out << " <= " << 0 << "(" << m_args_value << ")";
|
||||
return out << " <= " << 0 << "(" << m_args_value + m_coeff << ")";
|
||||
case ineq_kind::EQ:
|
||||
return out << " == " << 0 << "(" << m_args_value << ")";
|
||||
return out << " == " << 0 << "(" << m_args_value + m_coeff << ")";
|
||||
default:
|
||||
return out << " < " << 0 << "(" << m_args_value << ")";
|
||||
return out << " < " << 0 << "(" << m_args_value + m_coeff << ")";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -101,6 +101,7 @@ namespace sls {
|
|||
|
||||
struct mul_def {
|
||||
unsigned m_var;
|
||||
num_t m_coeff;
|
||||
unsigned_vector m_monomial;
|
||||
};
|
||||
|
||||
|
@ -109,8 +110,8 @@ namespace sls {
|
|||
};
|
||||
|
||||
struct op_def {
|
||||
unsigned m_var;
|
||||
arith_op_kind m_op;
|
||||
unsigned m_var = UINT_MAX;
|
||||
arith_op_kind m_op = LAST_ARITH_OP;
|
||||
unsigned m_arg1, m_arg2;
|
||||
};
|
||||
|
||||
|
@ -124,8 +125,6 @@ namespace sls {
|
|||
unsigned_vector m_expr2var;
|
||||
bool m_dscore_mode = false;
|
||||
arith_util a;
|
||||
unsigned_vector m_defs_to_update;
|
||||
vector<std::pair<var_t, num_t>> m_vars_to_update;
|
||||
|
||||
unsigned get_num_vars() const { return m_vars.size(); }
|
||||
|
||||
|
@ -139,10 +138,6 @@ namespace sls {
|
|||
void repair_abs(op_def const& od);
|
||||
void repair_to_int(op_def const& od);
|
||||
void repair_to_real(op_def const& od);
|
||||
void repair_defs_and_updates();
|
||||
void repair_defs();
|
||||
void repair_updates();
|
||||
void repair(sat::literal lit);
|
||||
void repair(sat::literal lit, ineq const& ineq);
|
||||
|
||||
double reward(sat::literal lit);
|
||||
|
@ -179,15 +174,18 @@ namespace sls {
|
|||
bool is_num(expr* e, num_t& i);
|
||||
expr_ref from_num(sort* s, num_t const& n);
|
||||
void check_ineqs();
|
||||
void init_bool_var(sat::bool_var v);
|
||||
public:
|
||||
arith_base(context& ctx);
|
||||
~arith_base() override {}
|
||||
void init_bool_var(sat::bool_var v) override;
|
||||
~arith_base() override {}
|
||||
void register_term(expr* e) override;
|
||||
void set_shared(expr* e) override;
|
||||
void set_value(expr* e, expr* v) override;
|
||||
expr_ref get_value(expr* e) override;
|
||||
lbool check() override;
|
||||
void initialize() override {}
|
||||
void propagate_literal(sat::literal lit) override;
|
||||
bool propagate() override;
|
||||
void repair_up(app* e) override;
|
||||
void repair_down(app* e) override;
|
||||
bool is_sat() override;
|
||||
void on_rescale() override;
|
||||
void on_restart() override;
|
||||
|
|
|
@ -21,21 +21,9 @@ Author:
|
|||
|
||||
namespace sls {
|
||||
|
||||
void arith_plugin::init_bool_var(sat::bool_var v) {
|
||||
if (!m_arith) {
|
||||
try {
|
||||
m_arith64->init_bool_var(v);
|
||||
return;
|
||||
}
|
||||
catch (overflow_exception&) {
|
||||
m_arith = alloc(arith_base<rational>, ctx);
|
||||
for (auto e : m_shared)
|
||||
m_arith->set_shared(e);
|
||||
return; // initialization happens on check-sat calls
|
||||
}
|
||||
}
|
||||
m_arith->init_bool_var(v);
|
||||
|
||||
void arith_plugin::init_backup() {
|
||||
m_arith = alloc(arith_base<rational>, ctx);
|
||||
m_arith->initialize();
|
||||
}
|
||||
|
||||
void arith_plugin::register_term(expr* e) {
|
||||
|
@ -45,9 +33,7 @@ namespace sls {
|
|||
return;
|
||||
}
|
||||
catch (overflow_exception&) {
|
||||
m_arith = alloc(arith_base<rational>, ctx);
|
||||
for (auto e : m_shared)
|
||||
m_arith->set_shared(e);
|
||||
init_backup();
|
||||
}
|
||||
}
|
||||
m_arith->register_term(e);
|
||||
|
@ -59,32 +45,49 @@ namespace sls {
|
|||
return m_arith64->get_value(e);
|
||||
}
|
||||
catch (overflow_exception&) {
|
||||
m_arith = alloc(arith_base<rational>, ctx);
|
||||
for (auto e : m_shared)
|
||||
m_arith->set_shared(e);
|
||||
init_backup();
|
||||
}
|
||||
}
|
||||
return m_arith->get_value(e);
|
||||
}
|
||||
|
||||
lbool arith_plugin::check() {
|
||||
void arith_plugin::initialize() {
|
||||
if (m_arith)
|
||||
m_arith->initialize();
|
||||
else
|
||||
m_arith64->initialize();
|
||||
}
|
||||
|
||||
void arith_plugin::propagate_literal(sat::literal lit) {
|
||||
if (!m_arith) {
|
||||
try {
|
||||
return m_arith64->check();
|
||||
m_arith64->propagate_literal(lit);
|
||||
return;
|
||||
}
|
||||
catch (overflow_exception&) {
|
||||
m_arith = alloc(arith_base<rational>, ctx);
|
||||
for (auto e : m_shared)
|
||||
m_arith->set_shared(e);
|
||||
init_backup();
|
||||
}
|
||||
}
|
||||
return m_arith->check();
|
||||
}
|
||||
m_arith->propagate_literal(lit);
|
||||
}
|
||||
|
||||
bool arith_plugin::propagate() {
|
||||
if (!m_arith) {
|
||||
try {
|
||||
return m_arith64->propagate();
|
||||
}
|
||||
catch (overflow_exception&) {
|
||||
init_backup();
|
||||
}
|
||||
}
|
||||
return m_arith->propagate();
|
||||
}
|
||||
|
||||
bool arith_plugin::is_sat() {
|
||||
if (!m_arith)
|
||||
if (m_arith)
|
||||
return m_arith->is_sat();
|
||||
else
|
||||
return m_arith64->is_sat();
|
||||
return m_arith->is_sat();
|
||||
}
|
||||
|
||||
void arith_plugin::on_rescale() {
|
||||
|
@ -115,19 +118,30 @@ namespace sls {
|
|||
m_arith64->mk_model(mdl);
|
||||
}
|
||||
|
||||
void arith_plugin::set_shared(expr* e) {
|
||||
void arith_plugin::repair_down(app* e) {
|
||||
if (m_arith)
|
||||
m_arith->repair_down(e);
|
||||
else
|
||||
m_arith64->repair_down(e);
|
||||
}
|
||||
|
||||
void arith_plugin::repair_up(app* e) {
|
||||
if (m_arith)
|
||||
m_arith->set_shared(e);
|
||||
else {
|
||||
m_arith64->set_shared(e);
|
||||
m_shared.push_back(e);
|
||||
}
|
||||
m_arith->repair_up(e);
|
||||
else
|
||||
m_arith64->repair_up(e);
|
||||
}
|
||||
|
||||
void arith_plugin::set_value(expr* e, expr* v) {
|
||||
if (m_arith)
|
||||
m_arith->set_value(e, v);
|
||||
else
|
||||
m_arith->set_value(e, v);
|
||||
if (!m_arith) {
|
||||
try {
|
||||
m_arith64->set_value(e, v);
|
||||
return;
|
||||
}
|
||||
catch (overflow_exception&) {
|
||||
init_backup();
|
||||
}
|
||||
}
|
||||
m_arith->set_value(e, v);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ Author:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "ast/sls/sls_smt.h"
|
||||
#include "ast/sls/sls_context.h"
|
||||
#include "ast/sls/sls_arith_base.h"
|
||||
|
||||
namespace sls {
|
||||
|
@ -25,23 +25,28 @@ namespace sls {
|
|||
scoped_ptr<arith_base<checked_int64<true>>> m_arith64;
|
||||
scoped_ptr<arith_base<rational>> m_arith;
|
||||
expr_ref_vector m_shared;
|
||||
|
||||
void init_backup();
|
||||
public:
|
||||
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 {}
|
||||
void init_bool_var(sat::bool_var v) override;
|
||||
void register_term(expr* e) override;
|
||||
expr_ref get_value(expr* e) override;
|
||||
lbool check() override;
|
||||
void initialize() override;
|
||||
void propagate_literal(sat::literal lit) override;
|
||||
bool propagate() override;
|
||||
void repair_down(app* e) override;
|
||||
void repair_up(app* e) override;
|
||||
bool is_sat() override;
|
||||
|
||||
void on_rescale() override;
|
||||
void on_restart() override;
|
||||
std::ostream& display(std::ostream& out) const override;
|
||||
void mk_model(model& mdl) override;
|
||||
void set_shared(expr* e) override;
|
||||
void set_value(expr* e, expr* v) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -24,24 +24,21 @@ namespace sls {
|
|||
return expr_ref(m.mk_bool_val(bval0(e)), m);
|
||||
}
|
||||
|
||||
lbool basic_plugin::check() {
|
||||
init();
|
||||
for (sat::literal lit : ctx.root_literals())
|
||||
repair_literal(lit);
|
||||
repair_defs_and_updates();
|
||||
return ctx.unsat().empty() ? l_true : l_undef;
|
||||
void basic_plugin::propagate_literal(sat::literal lit) {
|
||||
auto a = ctx.atom(lit.var());
|
||||
if (!a || !is_app(a))
|
||||
return;
|
||||
SASSERT(to_app(a)->get_family_id() != basic_family_id);
|
||||
if (bval1(to_app(a)) != bval0(to_app(a)))
|
||||
ctx.new_value_eh(a);
|
||||
}
|
||||
|
||||
void basic_plugin::init() {
|
||||
m_repair_down = UINT_MAX;
|
||||
m_repair_roots.reset();
|
||||
m_repair_up.reset();
|
||||
if (m_initialized)
|
||||
return;
|
||||
m_initialized = true;
|
||||
for (auto t : ctx.subterms())
|
||||
if (is_app(t) && m.is_bool(t) && to_app(t)->get_family_id() == basic_family_id)
|
||||
m_values.setx(t->get_id(), bval1(to_app(t)), false);
|
||||
void basic_plugin::register_term(expr* e) {
|
||||
if (is_app(e) && m.is_bool(e) && to_app(e)->get_family_id() == basic_family_id)
|
||||
m_values.setx(e->get_id(), bval1(to_app(e)), false);
|
||||
}
|
||||
|
||||
void basic_plugin::initialize() {
|
||||
}
|
||||
|
||||
bool basic_plugin::is_sat() {
|
||||
|
@ -70,7 +67,6 @@ namespace sls {
|
|||
if (bval0(e) != m.is_true(v))
|
||||
return;
|
||||
set_value(e, m.is_true(v));
|
||||
m_repair_roots.insert(e->get_id());
|
||||
}
|
||||
|
||||
bool basic_plugin::bval1(app* e) const {
|
||||
|
@ -133,7 +129,7 @@ namespace sls {
|
|||
if (v == sat::null_bool_var)
|
||||
return m_values.get(e->get_id(), false);
|
||||
else
|
||||
return ctx.is_true(sat::literal(v, false));
|
||||
return ctx.is_true(v);
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair(app* e, unsigned i) {
|
||||
|
@ -157,8 +153,7 @@ namespace sls {
|
|||
case OP_ITE:
|
||||
return try_repair_ite(e, i);
|
||||
case OP_DISTINCT:
|
||||
NOT_IMPLEMENTED_YET();
|
||||
return false;
|
||||
return try_repair_distinct(e, i);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
|
@ -167,17 +162,21 @@ namespace sls {
|
|||
|
||||
bool basic_plugin::try_repair_and_or(app* e, unsigned i) {
|
||||
auto b = bval0(e);
|
||||
if ((b && m.is_and(e)) || (!b && m.is_or(e))) {
|
||||
for (auto arg : *e)
|
||||
if (!set_value(arg, b))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
auto child = e->get_arg(i);
|
||||
if (b == bval0(child))
|
||||
return false;
|
||||
set_value(child, b);
|
||||
return true;
|
||||
return set_value(child, b);
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_not(app* e) {
|
||||
auto child = e->get_arg(0);
|
||||
set_value(child, !bval0(e));
|
||||
return true;
|
||||
return set_value(child, !bval0(e));
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_eq(app* e, unsigned i) {
|
||||
|
@ -185,129 +184,111 @@ namespace sls {
|
|||
auto sibling = e->get_arg(1 - i);
|
||||
if (!m.is_bool(child))
|
||||
return false;
|
||||
set_value(child, bval0(e) == bval0(sibling));
|
||||
return true;
|
||||
return set_value(child, bval0(e) == bval0(sibling));
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_xor(app* e, unsigned i) {
|
||||
bool ev = bval0(e);
|
||||
bool bv = bval0(e->get_arg(1 - i));
|
||||
auto child = e->get_arg(i);
|
||||
set_value(child, ev != bv);
|
||||
return true;
|
||||
bool bv = false;
|
||||
for (unsigned j = 0; j < e->get_num_args(); ++j)
|
||||
if (j != i)
|
||||
bv ^= bval0(e->get_arg(j));
|
||||
bool ev = bval0(e);
|
||||
return set_value(child, ev != bv);
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_ite(app* e, unsigned i) {
|
||||
auto child = e->get_arg(i);
|
||||
bool c = bval0(e->get_arg(0));
|
||||
if (i == 0) {
|
||||
set_value(child, !c);
|
||||
return true;
|
||||
}
|
||||
if (i == 0)
|
||||
return set_value(child, !c);
|
||||
|
||||
if (c != (i == 1))
|
||||
return false;
|
||||
if (m.is_bool(e)) {
|
||||
set_value(child, bval0(e));
|
||||
return true;
|
||||
}
|
||||
if (m.is_bool(e))
|
||||
return set_value(child, bval0(e));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_implies(app* e, unsigned i) {
|
||||
auto child = e->get_arg(i);
|
||||
auto sibling = e->get_arg(1 - i);
|
||||
bool ev = bval0(e);
|
||||
bool av = bval0(child);
|
||||
bool bv = bval0(e->get_arg(1 - i));
|
||||
if (i == 0) {
|
||||
if (ev == (!av || bv))
|
||||
return false;
|
||||
}
|
||||
else if (ev != (!bv || av))
|
||||
bool bv = bval0(sibling);
|
||||
if (ev) {
|
||||
|
||||
if (i == 0 && (!av || bv))
|
||||
return true;
|
||||
if (i == 1 && (!bv || av))
|
||||
return true;
|
||||
if (i == 0) {
|
||||
return set_value(child, false);
|
||||
}
|
||||
if (i == 1) {
|
||||
return set_value(child, true);
|
||||
}
|
||||
return false;
|
||||
set_value(child, ev);
|
||||
return true;
|
||||
}
|
||||
if (i == 0 && av && !bv)
|
||||
return true;
|
||||
if (i == 1 && bv && !av)
|
||||
return true;
|
||||
if (i == 0) {
|
||||
return set_value(child, true) && set_value(sibling, false);
|
||||
}
|
||||
if (i == 1) {
|
||||
return set_value(child, false) && set_value(sibling, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool basic_plugin::repair_up(expr* e) {
|
||||
if (!m.is_bool(e))
|
||||
return false;
|
||||
auto b = bval1(to_app(e));
|
||||
void basic_plugin::repair_up(app* e) {
|
||||
if (!m.is_bool(e) || e->get_family_id() != basic_family_id)
|
||||
return;
|
||||
auto b = bval1(e);
|
||||
if (bval0(e) == b)
|
||||
return;
|
||||
set_value(e, b);
|
||||
return true;
|
||||
}
|
||||
|
||||
void basic_plugin::repair_down(app* e) {
|
||||
SASSERT(m.is_bool(e));
|
||||
unsigned n = e->get_num_args();
|
||||
if (n == 0 || e->get_family_id() != m.get_basic_family_id()) {
|
||||
for (auto p : ctx.parents(e))
|
||||
m_repair_up.insert(p->get_id());
|
||||
ctx.set_value(e, m.mk_bool_val(bval0(e)));
|
||||
if (n == 0 || e->get_family_id() != m.get_basic_family_id())
|
||||
return;
|
||||
}
|
||||
|
||||
if (bval0(e) == bval1(e))
|
||||
return;
|
||||
unsigned s = ctx.rand(n);
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
auto j = (i + s) % n;
|
||||
if (try_repair(e, j)) {
|
||||
m_repair_down = e->get_arg(j)->get_id();
|
||||
return;
|
||||
}
|
||||
if (try_repair(e, j))
|
||||
return;
|
||||
}
|
||||
m_repair_up.insert(e->get_id());
|
||||
set_value(e, bval1(e));
|
||||
}
|
||||
|
||||
|
||||
void basic_plugin::repair_defs_and_updates() {
|
||||
if (!m_repair_roots.empty() ||
|
||||
!m_repair_up.empty() ||
|
||||
m_repair_down != UINT_MAX) {
|
||||
|
||||
while (m_repair_down != UINT_MAX) {
|
||||
auto e = ctx.term(m_repair_down);
|
||||
repair_down(to_app(e));
|
||||
}
|
||||
|
||||
while (!m_repair_up.empty()) {
|
||||
auto id = m_repair_up.elem_at(rand() % m_repair_up.size());
|
||||
auto e = ctx.term(id);
|
||||
m_repair_up.remove(id);
|
||||
repair_up(to_app(e));
|
||||
}
|
||||
|
||||
if (!m_repair_roots.empty()) {
|
||||
auto id = m_repair_roots.elem_at(rand() % m_repair_roots.size());
|
||||
m_repair_roots.remove(id);
|
||||
m_repair_down = id;
|
||||
}
|
||||
}
|
||||
bool basic_plugin::try_repair_distinct(app* e, unsigned i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void basic_plugin::set_value(expr* e, bool b) {
|
||||
bool basic_plugin::set_value(expr* e, bool b) {
|
||||
if (m.is_true(e) && !b)
|
||||
return false;
|
||||
if (m.is_false(e) && b)
|
||||
return false;
|
||||
sat::bool_var v = ctx.atom2bool_var(e);
|
||||
if (v == sat::null_bool_var) {
|
||||
if (m_values.get(e->get_id(), b) != b) {
|
||||
m_values.set(e->get_id(), b);
|
||||
ctx.set_value(e, m.mk_bool_val(b));
|
||||
ctx.new_value_eh(e);
|
||||
}
|
||||
}
|
||||
else if (ctx.is_true(sat::literal(v, false)) != b) {
|
||||
else if (ctx.is_true(v) != b) {
|
||||
ctx.flip(v);
|
||||
ctx.set_value(e, m.mk_bool_val(b));
|
||||
ctx.new_value_eh(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void basic_plugin::repair_literal(sat::literal lit) {
|
||||
if (!ctx.is_true(lit))
|
||||
return;
|
||||
auto a = ctx.atom(lit.var());
|
||||
if (!a || !is_app(a))
|
||||
return;
|
||||
if (to_app(a)->get_family_id() != basic_family_id)
|
||||
return;
|
||||
if (bval1(to_app(a)) != bval0(to_app(a)))
|
||||
m_repair_roots.insert(a->get_id());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,20 +12,16 @@ Author:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "ast/sls/sls_smt.h"
|
||||
#include "ast/sls/sls_context.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
class basic_plugin : public plugin {
|
||||
bool_vector m_values;
|
||||
indexed_uint_set m_repair_up, m_repair_roots;
|
||||
unsigned m_repair_down = UINT_MAX;
|
||||
bool m_initialized = false;
|
||||
|
||||
void init();
|
||||
bool bval1(app* e) const;
|
||||
bool bval0(expr* e) const;
|
||||
bool repair_up(expr* e);
|
||||
bool try_repair(app* e, unsigned i);
|
||||
bool try_repair_and_or(app* e, unsigned i);
|
||||
bool try_repair_not(app* e);
|
||||
|
@ -33,28 +29,28 @@ namespace sls {
|
|||
bool try_repair_xor(app* e, unsigned i);
|
||||
bool try_repair_ite(app* e, unsigned i);
|
||||
bool try_repair_implies(app* e, unsigned i);
|
||||
void set_value(expr* e, bool b);
|
||||
|
||||
void repair_down(app* e);
|
||||
void repair_defs_and_updates();
|
||||
void repair_literal(sat::literal lit);
|
||||
bool try_repair_distinct(app* e, unsigned i);
|
||||
bool set_value(expr* e, bool b);
|
||||
|
||||
public:
|
||||
basic_plugin(context& ctx) :
|
||||
plugin(ctx) {
|
||||
m_fid = basic_family_id;
|
||||
}
|
||||
~basic_plugin() override {}
|
||||
void init_bool_var(sat::bool_var v) override {}
|
||||
void register_term(expr* e) override {}
|
||||
void register_term(expr* e) override;
|
||||
expr_ref get_value(expr* e) override;
|
||||
lbool check() override;
|
||||
void initialize() override;
|
||||
void propagate_literal(sat::literal lit) override;
|
||||
bool propagate() override { return false; }
|
||||
void repair_down(app* e) override;
|
||||
void repair_up(app* e) override;
|
||||
bool is_sat() override;
|
||||
|
||||
void on_rescale() override {}
|
||||
void on_restart() override {}
|
||||
std::ostream& display(std::ostream& out) const override;
|
||||
void mk_model(model& mdl) override {}
|
||||
void set_shared(expr* e) override {}
|
||||
void set_value(expr* e, expr* v) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,80 +23,44 @@ namespace sls {
|
|||
plugin(ctx),
|
||||
bv(m),
|
||||
m_terms(ctx),
|
||||
m_eval(m_terms, ctx)
|
||||
{}
|
||||
m_eval(m_terms, ctx) {
|
||||
m_fid = bv.get_family_id();
|
||||
}
|
||||
|
||||
void bv_plugin::register_term(expr* e) {
|
||||
m_terms.register_term(e);
|
||||
}
|
||||
|
||||
expr_ref bv_plugin::get_value(expr* e) {
|
||||
return expr_ref(m);
|
||||
SASSERT(bv.is_bv(e));
|
||||
auto const & val = m_eval.wval(e);
|
||||
return expr_ref(bv.mk_numeral(val.get_value(), e->get_sort()), m);
|
||||
}
|
||||
|
||||
lbool bv_plugin::check() {
|
||||
|
||||
if (!m_initialized) {
|
||||
auto eval = [&](expr* e, unsigned idx) { return false; };
|
||||
m_eval.init_eval(eval);
|
||||
m_initialized = true;
|
||||
}
|
||||
void bv_plugin::propagate_literal(sat::literal lit) {
|
||||
SASSERT(ctx.is_true(lit));
|
||||
auto a = ctx.atom(lit.var());
|
||||
if (!a || !is_app(a))
|
||||
return;
|
||||
if (!m_eval.eval_is_correct(to_app(a)))
|
||||
ctx.new_value_eh(a);
|
||||
}
|
||||
|
||||
bool bv_plugin::propagate() {
|
||||
auto& axioms = m_terms.axioms();
|
||||
if (!axioms.empty()) {
|
||||
for (auto* e : axioms)
|
||||
ctx.add_constraint(e);
|
||||
axioms.reset();
|
||||
return l_undef;
|
||||
return true;
|
||||
}
|
||||
|
||||
// repair each root literal
|
||||
for (sat::literal lit : ctx.root_literals())
|
||||
repair_literal(lit);
|
||||
|
||||
repair_defs_and_updates();
|
||||
|
||||
// update literal assignment based on current model
|
||||
for (unsigned v = 0; v < ctx.num_bool_vars(); ++v)
|
||||
init_bool_var_assignment(v);
|
||||
|
||||
return ctx.unsat().empty() ? l_true : l_undef;
|
||||
return false;
|
||||
}
|
||||
|
||||
void bv_plugin::repair_literal(sat::literal lit) {
|
||||
if (!ctx.is_true(lit))
|
||||
return;
|
||||
auto a = ctx.atom(lit.var());
|
||||
if (!a || !is_app(a))
|
||||
return;
|
||||
if (to_app(a)->get_family_id() != bv.get_family_id())
|
||||
return;
|
||||
if (!m_eval.eval_is_correct(to_app(a)))
|
||||
m_repair_roots.insert(a->get_id());
|
||||
}
|
||||
|
||||
void bv_plugin::repair_defs_and_updates() {
|
||||
if (!m_repair_roots.empty() ||
|
||||
!m_repair_up.empty() ||
|
||||
m_repair_down != UINT_MAX) {
|
||||
|
||||
while (m_repair_down != UINT_MAX) {
|
||||
auto e = ctx.term(m_repair_down);
|
||||
try_repair_down(to_app(e));
|
||||
}
|
||||
|
||||
while (!m_repair_up.empty()) {
|
||||
auto id = m_repair_up.elem_at(rand() % m_repair_up.size());
|
||||
auto e = ctx.term(id);
|
||||
m_repair_up.remove(id);
|
||||
try_repair_up(to_app(e));
|
||||
}
|
||||
|
||||
if (!m_repair_roots.empty()) {
|
||||
auto id = m_repair_roots.elem_at(rand() % m_repair_roots.size());
|
||||
m_repair_roots.remove(id);
|
||||
m_repair_down = id;
|
||||
}
|
||||
void bv_plugin::initialize() {
|
||||
if (!m_initialized) {
|
||||
// compute fixed ranges
|
||||
m_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,38 +72,35 @@ namespace sls {
|
|||
return;
|
||||
bool is_true = m_eval.bval1(to_app(a));
|
||||
|
||||
if (is_true != ctx.is_true(sat::literal(v, false)))
|
||||
if (is_true != ctx.is_true(v))
|
||||
ctx.flip(v);
|
||||
}
|
||||
|
||||
bool bv_plugin::is_sat() {
|
||||
return false;
|
||||
for (auto t : ctx.subterms())
|
||||
if (is_app(t) && bv.is_bv(t) && !m_eval.eval_is_correct(to_app(t)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::ostream& bv_plugin::display(std::ostream& out) const {
|
||||
// m_eval.display(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void bv_plugin::set_shared(expr* e) {
|
||||
return m_eval.display(out);
|
||||
}
|
||||
|
||||
void bv_plugin::set_value(expr* e, expr* v) {
|
||||
if (!bv.is_bv(e))
|
||||
return;
|
||||
rational val;
|
||||
VERIFY(bv.is_numeral(v, val));
|
||||
NOT_IMPLEMENTED_YET();
|
||||
// set value of e to val,
|
||||
}
|
||||
|
||||
void bv_plugin::try_repair_down(app* e) {
|
||||
void bv_plugin::repair_down(app* e) {
|
||||
|
||||
unsigned n = e->get_num_args();
|
||||
if (n == 0 || m_eval.eval_is_correct(e)) {
|
||||
m_eval.commit_eval(e);
|
||||
if (!m.is_bool(e))
|
||||
for (auto p : ctx.parents(e))
|
||||
m_repair_up.insert(p->get_id());
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.is_bool(e)) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -148,15 +109,15 @@ namespace sls {
|
|||
auto d2 = get_depth(e->get_arg(1));
|
||||
unsigned s = ctx.rand(d1 + d2 + 2);
|
||||
if (s <= d1 && m_eval.try_repair(e, 0)) {
|
||||
set_repair_down(e->get_arg(0));
|
||||
ctx.new_value_eh(e->get_arg(0));
|
||||
return;
|
||||
}
|
||||
if (m_eval.try_repair(e, 1)) {
|
||||
set_repair_down(e->get_arg(1));
|
||||
ctx.new_value_eh(e->get_arg(1));
|
||||
return;
|
||||
}
|
||||
if (m_eval.try_repair(e, 0)) {
|
||||
set_repair_down(e->get_arg(0));
|
||||
ctx.new_value_eh(e->get_arg(0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -165,18 +126,16 @@ namespace sls {
|
|||
for (unsigned i = 0; i < n; ++i) {
|
||||
auto j = (i + s) % n;
|
||||
if (m_eval.try_repair(e, j)) {
|
||||
set_repair_down(e->get_arg(j));
|
||||
ctx.new_value_eh(e->get_arg(j));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
IF_VERBOSE(3, verbose_stream() << "init-repair " << mk_bounded_pp(e, m) << "\n");
|
||||
// repair was not successful, so reset the state to find a different way to repair
|
||||
m_repair_down = UINT_MAX;
|
||||
}
|
||||
|
||||
void bv_plugin::try_repair_up(app* e) {
|
||||
if (m.is_bool(e))
|
||||
void bv_plugin::repair_up(app* e) {
|
||||
if (!bv.is_bv(e))
|
||||
;
|
||||
else if (m_eval.repair_up(e)) {
|
||||
if (!m_eval.eval_is_correct(e)) {
|
||||
|
@ -184,12 +143,12 @@ namespace sls {
|
|||
}
|
||||
SASSERT(m_eval.eval_is_correct(e));
|
||||
for (auto p : ctx.parents(e))
|
||||
m_repair_up.insert(p->get_id());
|
||||
ctx.new_value_eh(p);
|
||||
}
|
||||
else if (ctx.rand(10) != 0) {
|
||||
IF_VERBOSE(2, verbose_stream() << "repair-up "; trace_repair(true, e));
|
||||
m_eval.set_random(e);
|
||||
m_repair_roots.insert(e->get_id());
|
||||
ctx.new_value_eh(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,9 +161,7 @@ namespace sls {
|
|||
|
||||
void bv_plugin::trace() {
|
||||
IF_VERBOSE(2, verbose_stream()
|
||||
<< "(bvsls :restarts " << m_stats.m_restarts
|
||||
<< " :repair-up " << m_repair_up.size()
|
||||
<< " :repair-roots " << m_repair_roots.size() << ")\n");
|
||||
<< "(bvsls :restarts " << m_stats.m_restarts << ")\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ Author:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "ast/sls/sls_smt.h"
|
||||
#include "ast/sls/sls_context.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/sls/bv_sls_terms.h"
|
||||
#include "ast/sls/bv_sls_eval.h"
|
||||
|
@ -28,38 +28,29 @@ namespace sls {
|
|||
bv::sls_terms m_terms;
|
||||
bv::sls_eval m_eval;
|
||||
bv::sls_stats m_stats;
|
||||
|
||||
indexed_uint_set m_repair_up, m_repair_roots;
|
||||
unsigned m_repair_down = UINT_MAX;
|
||||
bool m_initialized = false;
|
||||
|
||||
void repair_literal(sat::literal lit);
|
||||
|
||||
void repair_defs_and_updates();
|
||||
|
||||
void init_bool_var_assignment(sat::bool_var v);
|
||||
|
||||
void try_repair_down(app* e);
|
||||
void set_repair_down(expr* e) { m_repair_down = e->get_id(); }
|
||||
void try_repair_up(app* e);
|
||||
|
||||
std::ostream& bv_plugin::trace_repair(bool down, expr* e);
|
||||
std::ostream& trace_repair(bool down, expr* e);
|
||||
void trace();
|
||||
bool can_propagate();
|
||||
|
||||
public:
|
||||
bv_plugin(context& ctx);
|
||||
~bv_plugin() override {}
|
||||
void init_bool_var(sat::bool_var v) override {}
|
||||
void register_term(expr* e) override;
|
||||
expr_ref get_value(expr* e) override;
|
||||
lbool check() override;
|
||||
void initialize() override;
|
||||
void propagate_literal(sat::literal lit) override;
|
||||
bool propagate() override;
|
||||
void repair_down(app* e) override;
|
||||
void repair_up(app* e) override;
|
||||
bool is_sat() override;
|
||||
|
||||
void on_rescale() override {}
|
||||
void on_restart() override {}
|
||||
std::ostream& display(std::ostream& out) const override;
|
||||
void mk_model(model& mdl) override {}
|
||||
void set_shared(expr* e) override;
|
||||
void set_value(expr* e, expr* v) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace sls {
|
|||
return true;
|
||||
}
|
||||
|
||||
lbool cc_plugin::check() {
|
||||
bool cc_plugin::propagate() {
|
||||
bool new_constraint = false;
|
||||
for (auto & [f, ts] : m_app) {
|
||||
if (ts.size() <= 1)
|
||||
|
@ -108,7 +108,7 @@ namespace sls {
|
|||
m_values.insert(t);
|
||||
}
|
||||
}
|
||||
return new_constraint ? l_undef : l_true;
|
||||
return new_constraint;
|
||||
}
|
||||
|
||||
std::ostream& cc_plugin::display(std::ostream& out) const {
|
||||
|
|
|
@ -17,7 +17,7 @@ Author:
|
|||
#pragma once
|
||||
|
||||
#include "util/hashtable.h"
|
||||
#include "ast/sls/sls_smt.h"
|
||||
#include "ast/sls/sls_context.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
|
@ -39,14 +39,16 @@ namespace sls {
|
|||
~cc_plugin() override;
|
||||
family_id fid() { return m_fid; }
|
||||
expr_ref get_value(expr* e) override;
|
||||
lbool check() override;
|
||||
void initialize() override {}
|
||||
void propagate_literal(sat::literal lit) override {}
|
||||
bool propagate() override;
|
||||
bool is_sat() override;
|
||||
void register_term(expr* e) override;
|
||||
void init_bool_var(sat::bool_var v) override {}
|
||||
std::ostream& display(std::ostream& out) const override;
|
||||
void mk_model(model& mdl) override;
|
||||
void set_value(expr* e, expr* v) override {}
|
||||
void set_shared(expr* e) override {}
|
||||
void repair_up(app* e) override {}
|
||||
void repair_down(app* e) override {}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -16,11 +16,12 @@ Author:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "ast/sls/sls_smt.h"
|
||||
#include "ast/sls/sls_context.h"
|
||||
#include "ast/sls/sls_cc.h"
|
||||
#include "ast/sls/sls_arith_plugin.h"
|
||||
#include "ast/sls/sls_bv_plugin.h"
|
||||
#include "ast/sls/sls_basic_plugin.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
|
@ -30,7 +31,11 @@ namespace sls {
|
|||
}
|
||||
|
||||
context::context(ast_manager& m, sat_solver_context& s) :
|
||||
m(m), s(s), m_atoms(m), m_allterms(m) {
|
||||
m(m), s(s), m_atoms(m), m_allterms(m),
|
||||
m_gd(*this),
|
||||
m_ld(*this),
|
||||
m_repair_down(m.get_num_asts(), m_gd),
|
||||
m_repair_up(m.get_num_asts(), m_ld) {
|
||||
register_plugin(alloc(cc_plugin, *this));
|
||||
register_plugin(alloc(arith_plugin, *this));
|
||||
register_plugin(alloc(bv_plugin, *this));
|
||||
|
@ -56,14 +61,12 @@ namespace sls {
|
|||
//
|
||||
init();
|
||||
while (unsat().empty()) {
|
||||
reinit_relevant();
|
||||
for (auto p : m_plugins) {
|
||||
lbool r;
|
||||
if (p && (r = p->check()) != l_true)
|
||||
return r;
|
||||
}
|
||||
if (m_new_constraint)
|
||||
|
||||
propagate_boolean_assignment();
|
||||
|
||||
if (m_new_constraint || !unsat().empty())
|
||||
return l_undef;
|
||||
|
||||
if (all_of(m_plugins, [&](auto* p) { return !p || p->is_sat(); })) {
|
||||
model_ref mdl = alloc(model, m);
|
||||
for (expr* e : subterms())
|
||||
|
@ -74,17 +77,72 @@ namespace sls {
|
|||
p->mk_model(*mdl);
|
||||
s.on_model(mdl);
|
||||
verbose_stream() << *mdl << "\n";
|
||||
TRACE("sls", display(tout));
|
||||
return l_true;
|
||||
}
|
||||
}
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
void context::propagate_boolean_assignment() {
|
||||
reinit_relevant();
|
||||
|
||||
for (sat::literal lit : root_literals()) {
|
||||
if (m_new_constraint)
|
||||
break;
|
||||
propagate_literal(lit);
|
||||
}
|
||||
|
||||
while (!m_new_constraint && (!m_repair_up.empty() || !m_repair_down.empty())) {
|
||||
while (!m_repair_down.empty() && !m_new_constraint) {
|
||||
auto id = m_repair_down.erase_min();
|
||||
expr* e = term(id);
|
||||
if (is_app(e)) {
|
||||
auto p = m_plugins.get(to_app(e)->get_family_id(), nullptr);
|
||||
if (p)
|
||||
p->repair_down(to_app(e));
|
||||
}
|
||||
}
|
||||
while (!m_repair_up.empty() && !m_new_constraint) {
|
||||
auto id = m_repair_up.erase_min();
|
||||
expr* e = term(id);
|
||||
if (is_app(e)) {
|
||||
auto p = m_plugins.get(to_app(e)->get_family_id(), nullptr);
|
||||
if (p)
|
||||
p->repair_up(to_app(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
// propagate "final checks"
|
||||
bool propagated = true;
|
||||
while (propagated && !m_new_constraint) {
|
||||
propagated = false;
|
||||
for (auto p : m_plugins)
|
||||
propagated |= p && !m_new_constraint && p->propagate();
|
||||
}
|
||||
}
|
||||
|
||||
void context::propagate_literal(sat::literal lit) {
|
||||
if (!is_true(lit))
|
||||
return;
|
||||
auto a = atom(lit.var());
|
||||
if (!a || !is_app(a))
|
||||
return;
|
||||
family_id fid = to_app(a)->get_family_id();
|
||||
if (m.is_eq(a) || m.is_distinct(a))
|
||||
fid = to_app(a)->get_arg(0)->get_sort()->get_family_id();
|
||||
auto p = m_plugins.get(fid, nullptr);
|
||||
if (p)
|
||||
p->propagate_literal(lit);
|
||||
}
|
||||
|
||||
bool context::is_true(expr* e) {
|
||||
SASSERT(m.is_bool(e));
|
||||
auto v = m_atom2bool_var.get(e->get_id(), sat::null_bool_var);
|
||||
SASSERT(v != sat::null_bool_var);
|
||||
return is_true(sat::literal(v, false));
|
||||
if (v != sat::null_bool_var)
|
||||
return m.is_true(m_plugins[basic_family_id]->get_value(e));
|
||||
else
|
||||
return is_true(v);
|
||||
}
|
||||
|
||||
bool context::is_fixed(expr* e) {
|
||||
|
@ -101,11 +159,11 @@ namespace sls {
|
|||
UNREACHABLE();
|
||||
return expr_ref(e, m);
|
||||
}
|
||||
|
||||
void context::set_value(expr* e, expr* v) {
|
||||
|
||||
void context::set_value(expr * e, expr * v) {
|
||||
for (auto p : m_plugins)
|
||||
if (p)
|
||||
p->set_value(e, v);
|
||||
p->set_value(e, v);
|
||||
}
|
||||
|
||||
bool context::is_relevant(expr* e) {
|
||||
|
@ -148,31 +206,21 @@ namespace sls {
|
|||
v = s.add_var();
|
||||
register_terms(e);
|
||||
register_atom(v, e);
|
||||
init_bool_var(v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void context::init_bool_var(sat::bool_var v) {
|
||||
for (auto p : m_plugins)
|
||||
if (p)
|
||||
p->init_bool_var(v);
|
||||
}
|
||||
|
||||
void context::init() {
|
||||
m_new_constraint = false;
|
||||
if (m_initialized)
|
||||
return;
|
||||
m_initialized = true;
|
||||
register_terms();
|
||||
for (sat::bool_var v = 0; v < num_bool_vars(); ++v)
|
||||
init_bool_var(v);
|
||||
}
|
||||
|
||||
void context::register_terms() {
|
||||
for (auto a : m_atoms)
|
||||
if (a)
|
||||
register_terms(a);
|
||||
for (auto p : m_plugins)
|
||||
if (p)
|
||||
p->initialize();
|
||||
}
|
||||
|
||||
void context::register_terms(expr* e) {
|
||||
|
@ -213,6 +261,23 @@ namespace sls {
|
|||
}
|
||||
}
|
||||
|
||||
void context::new_value_eh(expr* e) {
|
||||
DEBUG_CODE(
|
||||
if (m.is_bool(e)) {
|
||||
auto v = m_atom2bool_var.get(e->get_id(), sat::null_bool_var);
|
||||
if (v != sat::null_bool_var) {
|
||||
SASSERT(m.is_true(get_value(e)) == is_true(v));
|
||||
}
|
||||
}
|
||||
);
|
||||
m_repair_down.reserve(e->get_id() + 1);
|
||||
m_repair_down.insert(e->get_id());
|
||||
for (auto p : parents(e)) {
|
||||
m_repair_up.reserve(p->get_id() + 1);
|
||||
m_repair_up.insert(p->get_id());
|
||||
}
|
||||
}
|
||||
|
||||
void context::register_term(expr* e) {
|
||||
for (auto p : m_plugins)
|
||||
if (p)
|
||||
|
@ -261,10 +326,14 @@ namespace sls {
|
|||
}
|
||||
|
||||
std::ostream& context::display(std::ostream& out) const {
|
||||
for (auto p : m_plugins) {
|
||||
for (auto id : m_repair_down)
|
||||
out << "d " << mk_bounded_pp(term(id), m) << "\n";
|
||||
for (auto id : m_repair_up)
|
||||
out << "u " << mk_bounded_pp(term(id), m) << "\n";
|
||||
for (auto p : m_plugins)
|
||||
if (p)
|
||||
p->display(out);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ Copyright (c) 2024 Microsoft Corporation
|
|||
|
||||
Module Name:
|
||||
|
||||
smt_sls.h
|
||||
sls_context.h
|
||||
|
||||
Abstract:
|
||||
|
||||
|
@ -22,6 +22,7 @@ Author:
|
|||
#include "model/model.h"
|
||||
#include "util/scoped_ptr_vector.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
#include "util/heap.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
|
@ -38,14 +39,16 @@ namespace sls {
|
|||
virtual family_id fid() { return m_fid; }
|
||||
virtual void register_term(expr* e) = 0;
|
||||
virtual expr_ref get_value(expr* e) = 0;
|
||||
virtual void init_bool_var(sat::bool_var v) = 0;
|
||||
virtual lbool check() = 0;
|
||||
virtual void initialize() = 0;
|
||||
virtual bool propagate() = 0;
|
||||
virtual void propagate_literal(sat::literal lit) = 0;
|
||||
virtual void repair_down(app* e) = 0;
|
||||
virtual void repair_up(app* e) = 0;
|
||||
virtual bool is_sat() = 0;
|
||||
virtual void on_rescale() {};
|
||||
virtual void on_restart() {};
|
||||
virtual std::ostream& display(std::ostream& out) const = 0;
|
||||
virtual void mk_model(model& mdl) = 0;
|
||||
virtual void set_shared(expr* e) = 0;
|
||||
virtual void set_value(expr* e, expr* v) = 0;
|
||||
};
|
||||
|
||||
|
@ -68,6 +71,22 @@ namespace sls {
|
|||
};
|
||||
|
||||
class context {
|
||||
struct greater_depth {
|
||||
context& c;
|
||||
greater_depth(context& c) : c(c) {}
|
||||
bool operator()(unsigned x, unsigned y) const {
|
||||
return get_depth(c.term(x)) > get_depth(c.term(y));
|
||||
}
|
||||
};
|
||||
|
||||
struct less_depth {
|
||||
context& c;
|
||||
less_depth(context& c) : c(c) {}
|
||||
bool operator()(unsigned x, unsigned y) const {
|
||||
return get_depth(c.term(x)) < get_depth(c.term(y));
|
||||
}
|
||||
};
|
||||
|
||||
ast_manager& m;
|
||||
sat_solver_context& s;
|
||||
scoped_ptr_vector<plugin> m_plugins;
|
||||
|
@ -81,23 +100,27 @@ namespace sls {
|
|||
bool m_new_constraint = false;
|
||||
expr_ref_vector m_allterms;
|
||||
ptr_vector<expr> m_subterms;
|
||||
greater_depth m_gd;
|
||||
less_depth m_ld;
|
||||
heap<greater_depth> m_repair_down;
|
||||
heap<less_depth> m_repair_up;
|
||||
|
||||
void register_plugin(plugin* p);
|
||||
|
||||
void init();
|
||||
void init_bool_var(sat::bool_var v);
|
||||
void register_terms();
|
||||
ptr_vector<expr> m_todo;
|
||||
void register_terms(expr* e);
|
||||
void register_term(expr* e);
|
||||
sat::bool_var mk_atom(expr* e);
|
||||
|
||||
void propagate_boolean_assignment();
|
||||
void propagate_literal(sat::literal lit);
|
||||
|
||||
public:
|
||||
context(ast_manager& m, sat_solver_context& s);
|
||||
|
||||
// Between SAT/SMT solver and context.
|
||||
void register_atom(sat::bool_var v, expr* e);
|
||||
// void reset();
|
||||
lbool check();
|
||||
|
||||
// expose sat_solver to plugins
|
||||
|
@ -107,6 +130,7 @@ namespace sls {
|
|||
double get_weight(unsigned clause_idx) { return s.get_weigth(clause_idx); }
|
||||
unsigned num_bool_vars() const { return s.num_vars(); }
|
||||
bool is_true(sat::literal lit) { return s.is_true(lit); }
|
||||
bool is_true(sat::bool_var v) { return s.is_true(sat::literal(v, false)); }
|
||||
expr* atom(sat::bool_var v) { return m_atoms.get(v, nullptr); }
|
||||
expr* term(unsigned id) const { return m_allterms.get(id); }
|
||||
sat::bool_var atom2bool_var(expr* e) const { return m_atom2bool_var.get(e->get_id(), sat::null_bool_var); }
|
||||
|
@ -126,13 +150,15 @@ namespace sls {
|
|||
|
||||
// Between plugin solvers
|
||||
expr_ref get_value(expr* e);
|
||||
bool is_true(expr* e);
|
||||
bool is_fixed(expr* e);
|
||||
void set_value(expr* e, expr* v);
|
||||
void new_value_eh(expr* e);
|
||||
bool is_true(expr* e);
|
||||
bool is_fixed(expr* e);
|
||||
bool is_relevant(expr* e);
|
||||
void add_constraint(expr* e);
|
||||
ptr_vector<expr> const& subterms();
|
||||
ast_manager& get_manager() { return m; }
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
|
||||
};
|
||||
}
|
|
@ -17,7 +17,7 @@ Author:
|
|||
|
||||
#include "sat/smt/sls_solver.h"
|
||||
#include "sat/smt/euf_solver.h"
|
||||
#include "ast/sls/sls_smt.h"
|
||||
#include "ast/sls/sls_context.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
|
|
|
@ -29,7 +29,103 @@ Notes:
|
|||
#include "tactic/sls/sls_tactic.h"
|
||||
#include "params/sls_params.hpp"
|
||||
#include "ast/sls/sls_engine.h"
|
||||
#include "ast/sls/bv_sls.h"
|
||||
#include "ast/sls/sls_smt_solver.h"
|
||||
|
||||
class sls_smt_tactic : public tactic {
|
||||
ast_manager& m;
|
||||
params_ref m_params;
|
||||
sls::smt_solver* m_sls;
|
||||
statistics m_st;
|
||||
|
||||
public:
|
||||
sls_smt_tactic(ast_manager& _m, params_ref const& p) :
|
||||
m(_m),
|
||||
m_params(p) {
|
||||
m_sls = alloc(sls::smt_solver, m, p);
|
||||
}
|
||||
|
||||
tactic* translate(ast_manager& m) override {
|
||||
return alloc(sls_smt_tactic, m, m_params);
|
||||
}
|
||||
|
||||
~sls_smt_tactic() override {
|
||||
dealloc(m_sls);
|
||||
}
|
||||
|
||||
char const* name() const override { return "sls-smt"; }
|
||||
|
||||
void updt_params(params_ref const& p) override {
|
||||
m_params.append(p);
|
||||
m_sls->updt_params(m_params);
|
||||
}
|
||||
|
||||
void collect_param_descrs(param_descrs& r) override {
|
||||
sls_params::collect_param_descrs(r);
|
||||
}
|
||||
|
||||
void run(goal_ref const& g, model_converter_ref& mc) {
|
||||
if (g->inconsistent()) {
|
||||
mc = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < g->size(); i++)
|
||||
m_sls->assert_expr(g->form(i));
|
||||
|
||||
|
||||
lbool res = m_sls->check();
|
||||
m_st.reset();
|
||||
m_sls->collect_statistics(m_st);
|
||||
// report_tactic_progress("Number of flips:", m_sls->get_num_moves());
|
||||
IF_VERBOSE(10, verbose_stream() << res << "\n");
|
||||
IF_VERBOSE(10, m_sls->display(verbose_stream()));
|
||||
|
||||
if (res == l_true) {
|
||||
if (g->models_enabled()) {
|
||||
model_ref mdl = m_sls->get_model();
|
||||
mc = model2model_converter(mdl.get());
|
||||
TRACE("sls_model", mc->display(tout););
|
||||
}
|
||||
g->reset();
|
||||
}
|
||||
else
|
||||
mc = nullptr;
|
||||
|
||||
}
|
||||
|
||||
void operator()(goal_ref const& g,
|
||||
goal_ref_buffer& result) override {
|
||||
result.reset();
|
||||
|
||||
TRACE("sls", g->display(tout););
|
||||
tactic_report report("sls", *g);
|
||||
|
||||
model_converter_ref mc;
|
||||
run(g, mc);
|
||||
g->add(mc.get());
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
}
|
||||
|
||||
void cleanup() override {
|
||||
auto* d = alloc(sls::smt_solver, m, m_params);
|
||||
std::swap(d, m_sls);
|
||||
dealloc(d);
|
||||
}
|
||||
|
||||
void collect_statistics(statistics& st) const override {
|
||||
st.copy(m_st);
|
||||
}
|
||||
|
||||
void reset_statistics() override {
|
||||
m_sls->reset_statistics();
|
||||
m_st.reset();
|
||||
}
|
||||
};
|
||||
|
||||
tactic* mk_sls_smt_tactic(ast_manager& m, params_ref const& p) {
|
||||
return alloc(sls_smt_tactic, m, p);
|
||||
}
|
||||
|
||||
class sls_tactic : public tactic {
|
||||
ast_manager & m;
|
||||
|
|
|
@ -23,9 +23,11 @@ class ast_manager;
|
|||
class tactic;
|
||||
|
||||
tactic * mk_qfbv_sls_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
tactic * mk_sls_smt_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
/*
|
||||
ADD_TACTIC("qfbv-sls", "(try to) solve using stochastic local search for QF_BV.", "mk_qfbv_sls_tactic(m, p)")
|
||||
ADD_TACTIC("sls-smt", "(try to) solve SMT formulas using local search.", "mk_sls_smt_tactic(m, p)")
|
||||
|
||||
*/
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue