3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 17:15:31 +00:00

Merge remote-tracking branch 'origin/master' into poly

This commit is contained in:
Jakob Rath 2024-05-11 23:30:53 +02:00
commit 94955e3fae
67 changed files with 2698 additions and 806 deletions

View file

@ -438,6 +438,7 @@ public:
MATCH_BINARY(is_bv_xor);
MATCH_BINARY(is_bv_nand);
MATCH_BINARY(is_bv_nor);
MATCH_BINARY(is_concat);
MATCH_BINARY(is_bv_uremi);

View file

@ -17,6 +17,7 @@ Notes:
--*/
#include "params/rewriter_params.hpp"
#include "params/poly_rewriter_params.hpp"
#include "ast/rewriter/th_rewriter.h"
#include "ast/rewriter/bool_rewriter.h"
#include "ast/rewriter/arith_rewriter.h"
@ -83,7 +84,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
void updt_local_params(params_ref const & _p) {
rewriter_params p(_p);
m_flat = true;
poly_rewriter_params pp(_p);
m_flat = pp.flat();
m_max_memory = megabytes_to_bytes(p.max_memory());
m_max_steps = p.max_steps();
m_pull_cheap_ite = p.pull_cheap_ite();

View file

@ -288,7 +288,8 @@ void bound_simplifier::tighten_bound(dependent_expr const& de) {
void bound_simplifier::assert_upper(expr* x, rational const& n, bool strict) {
scoped_mpq c(nm);
nm.set(c, n.to_mpq());
nm.set(c, n.to_mpq());
TRACE("propagate-ineqs", tout << to_var(x) << ": " << mk_pp(x, m) << (strict ? " < " : " <= ") << n << "\n");
bp.assert_upper(to_var(x), c, strict);
}
@ -296,6 +297,7 @@ void bound_simplifier::assert_upper(expr* x, rational const& n, bool strict) {
void bound_simplifier::assert_lower(expr* x, rational const& n, bool strict) {
scoped_mpq c(nm);
nm.set(c, n.to_mpq());
TRACE("propagate-ineqs", tout << to_var(x) << ": " << mk_pp(x, m) << (strict ? " > " : " >= ") << n << "\n");
bp.assert_lower(to_var(x), c, strict);
}
@ -306,6 +308,7 @@ bool bound_simplifier::has_lower(expr* x, rational& n, bool& strict) {
return false;
strict = m_interval.lower_is_open(i);
n = m_interval.lower(i);
TRACE("propagate-ineqs", tout << to_var(x) << ": " << mk_pp(x, m) << (strict ? " > " : " >= ") << n << "\n");
return true;
}
@ -316,6 +319,7 @@ bool bound_simplifier::has_upper(expr* x, rational& n, bool& strict) {
return false;
strict = m_interval.upper_is_open(i);
n = m_interval.upper(i);
TRACE("propagate-ineqs", tout << to_var(x) << ": " << mk_pp(x, m) << (strict ? " < " : " <= ") << n << "\n");
return true;
}

View file

@ -31,8 +31,9 @@ namespace euf {
expr* orig; // original expression that encoded equation
app* var; // isolated variable
expr_ref term; // defined term
expr_dependency* dep;
dependent_eq(expr* orig, app* var, expr_ref const& term, expr_dependency* d) : orig(orig), var(var), term(term), dep(d) {}
expr_dependency_ref dep;
dependent_eq(expr* orig, app* var, expr_ref const& term, expr_dependency* d) :
orig(orig), var(var), term(term), dep(d, term.get_manager()) {}
};
typedef vector<dependent_eq> dep_eq_vector;

View file

@ -329,6 +329,7 @@ namespace euf {
m_config.m_context_solve = p.get_bool("context_solve", tp.solve_eqs_context_solve());
for (auto* ex : m_extract_plugins)
ex->updt_params(p);
m_rewriter.updt_params(p);
}
void solve_eqs::collect_param_descrs(param_descrs& r) {

View file

@ -25,12 +25,15 @@ Author:
namespace bv {
sls::sls(ast_manager& m):
sls::sls(ast_manager& m, params_ref const& p):
m(m),
bv(m),
m_terms(m),
m_eval(m)
{}
m_eval(m),
m_engine(m, p)
{
updt_params(p);
}
void sls::init() {
m_terms.init();
@ -53,38 +56,96 @@ namespace bv {
}
}
for (auto* t : m_terms.terms()) {
if (t && !re_eval_is_correct(t))
if (t && !m_eval.re_eval_is_correct(t))
m_repair_roots.insert(t->get_id());
}
}
void sls::set_model() {
if (!m_set_model)
return;
if (m_repair_roots.size() >= m_min_repair_size)
return;
m_min_repair_size = m_repair_roots.size();
IF_VERBOSE(2, verbose_stream() << "(sls-update-model :num-unsat " << m_min_repair_size << ")\n");
m_set_model(*get_model());
}
void sls::init_repair_goal(app* t) {
if (m.is_bool(t))
m_eval.set(t, m_eval.bval1(t));
else if (bv.is_bv(t)) {
auto& v = m_eval.wval(t);
v.bits().copy_to(v.nw, v.eval);
m_eval.init_eval(t);
}
void sls::init_repair_candidates() {
m_to_repair.reset();
ptr_vector<expr> todo;
expr_fast_mark1 mark;
for (auto index : m_repair_roots)
todo.push_back(m_terms.term(index));
for (unsigned i = 0; i < todo.size(); ++i) {
expr* e = todo[i];
if (mark.is_marked(e))
continue;
mark.mark(e);
if (!is_app(e))
continue;
for (expr* arg : *to_app(e))
todo.push_back(arg);
if (is_uninterp_const(e))
m_to_repair.insert(e->get_id());
}
}
void sls::reinit_eval() {
init_repair_candidates();
if (m_to_repair.empty())
return;
// refresh the best model so far to a callback
set_model();
// add fresh units, if any
bool new_assertion = false;
while (m_get_unit) {
auto e = m_get_unit();
if (!e)
break;
new_assertion = true;
assert_expr(e);
}
if (new_assertion)
init();
std::function<bool(expr*, unsigned)> eval = [&](expr* e, unsigned i) {
auto should_keep = [&]() {
return m_rand() % 100 <= 92;
};
unsigned id = e->get_id();
bool keep = !m_to_repair.contains(id);
if (m.is_bool(e)) {
if (m_eval.is_fixed0(e) || should_keep())
if (m_eval.is_fixed0(e) || keep)
return m_eval.bval0(e);
if (m_engine_init) {
auto const& z = m_engine.get_value(e);
return rational(z).get_bit(0);
}
}
else if (bv.is_bv(e)) {
auto& w = m_eval.wval(e);
if (w.fixed.get(i) || should_keep())
return w.get_bit(i);
if (w.fixed.get(i) || keep)
return w.get_bit(i);
if (m_engine_init) {
auto const& z = m_engine.get_value(e);
return rational(z).get_bit(i);
}
}
return m_rand() % 2 == 0;
};
m_eval.init_eval(m_terms.assertions(), eval);
init_repair();
// m_engine_init = false;
}
std::pair<bool, app*> sls::next_to_repair() {
@ -109,7 +170,7 @@ namespace bv {
SASSERT(m_eval.bval0(e));
return { true, e };
}
if (!re_eval_is_correct(e)) {
if (!m_eval.re_eval_is_correct(e)) {
init_repair_goal(e);
return { true, e };
}
@ -119,37 +180,54 @@ namespace bv {
return { false, nullptr };
}
lbool sls::search() {
lbool sls::search1() {
// init and init_eval were invoked
unsigned n = 0;
for (; n++ < m_config.m_max_repairs && m.inc(); ) {
for (; n < m_config.m_max_repairs && m.inc(); ++n) {
auto [down, e] = next_to_repair();
if (!e)
return l_true;
trace_repair(down, e);
IF_VERBOSE(20, trace_repair(down, e));
++m_stats.m_moves;
if (down)
try_repair_down(e);
try_repair_down(e);
else
try_repair_up(e);
}
return l_undef;
}
lbool sls::search2() {
lbool res = l_undef;
if (m_stats.m_restarts == 0)
res = m_engine(),
m_engine_init = true;
else if (m_stats.m_restarts % 1000 == 0)
res = m_engine.search_loop(),
m_engine_init = true;
if (res != l_undef)
m_engine_model = true;
return res;
}
lbool sls::operator()() {
lbool res = l_undef;
m_stats.reset();
m_stats.m_restarts = 0;
m_engine_model = false;
m_engine_init = false;
do {
res = search();
res = search1();
if (res != l_undef)
break;
trace();
//res = search2();
if (res != l_undef)
break;
reinit_eval();
}
while (m.inc() && m_stats.m_restarts++ < m_config.m_max_restarts);
@ -158,93 +236,84 @@ namespace bv {
}
void sls::try_repair_down(app* e) {
unsigned n = e->get_num_args();
if (n == 0) {
if (m.is_bool(e))
m_eval.set(e, m_eval.bval1(e));
else
VERIFY(m_eval.wval(e).commit_eval());
m_eval.commit_eval(e);
for (auto p : m_terms.parents(e))
m_repair_up.insert(p->get_id());
return;
}
unsigned s = m_rand(n);
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));
if (n == 2) {
auto d1 = get_depth(e->get_arg(0));
auto d2 = get_depth(e->get_arg(1));
unsigned s = m_rand(d1 + d2 + 2);
if (s <= d1 && m_eval.try_repair(e, 0)) {
set_repair_down(e->get_arg(0));
return;
}
if (m_eval.try_repair(e, 1)) {
set_repair_down(e->get_arg(1));
return;
}
if (m_eval.try_repair(e, 0)) {
set_repair_down(e->get_arg(0));
return;
}
}
// search a new root / random walk to repair
else {
unsigned s = m_rand(n);
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));
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
init_repair();
}
void sls::try_repair_up(app* e) {
if (m_terms.is_assertion(e) || !m_eval.repair_up(e))
m_repair_roots.insert(e->get_id());
if (m_terms.is_assertion(e))
m_repair_roots.insert(e->get_id());
else if (!m_eval.repair_up(e)) {
IF_VERBOSE(2, verbose_stream() << "repair-up "; trace_repair(true, e));
if (m_rand(10) != 0) {
m_eval.set_random(e);
m_repair_roots.insert(e->get_id());
}
else
init_repair();
}
else {
if (!eval_is_correct(e)) {
if (!m_eval.eval_is_correct(e)) {
verbose_stream() << "incorrect eval #" << e->get_id() << " " << mk_bounded_pp(e, m) << "\n";
}
SASSERT(eval_is_correct(e));
SASSERT(m_eval.eval_is_correct(e));
for (auto p : m_terms.parents(e))
m_repair_up.insert(p->get_id());
}
}
bool sls::eval_is_correct(app* e) {
if (!m_eval.can_eval1(e))
return false;
if (m.is_bool(e))
return m_eval.bval0(e) == m_eval.bval1(e);
if (bv.is_bv(e)) {
auto const& v = m_eval.wval(e);
return v.eval == v.bits();
}
UNREACHABLE();
return false;
}
bool sls::re_eval_is_correct(app* e) {
if (!m_eval.can_eval1(e))
return false;
if (m.is_bool(e))
return m_eval.bval0(e) == m_eval.bval1(e);
if (bv.is_bv(e)) {
auto const& v = m_eval.eval(e);
return v.eval == v.bits();
}
UNREACHABLE();
return false;
}
model_ref sls::get_model() {
model_ref mdl = alloc(model, m);
if (m_engine_model)
return m_engine.get_model();
model_ref mdl = alloc(model, m);
auto& terms = m_eval.sort_assertions(m_terms.assertions());
for (expr* e : terms) {
if (!re_eval_is_correct(to_app(e))) {
verbose_stream() << "missed evaluation #" << e->get_id() << " " << mk_bounded_pp(e, m) << "\n";
if (bv.is_bv(e)) {
auto const& v = m_eval.wval(e);
verbose_stream() << v << "\n" << v.eval << "\n";
}
}
if (!is_uninterp_const(e))
continue;
auto f = to_app(e)->get_decl();
if (m.is_bool(e))
mdl->register_decl(f, m.mk_bool_val(m_eval.bval0(e)));
else if (bv.is_bv(e)) {
auto const& v = m_eval.wval(e);
rational n = v.get_value();
mdl->register_decl(f, bv.mk_numeral(n, v.bw));
}
auto v = m_eval.get_value(to_app(e));
if (v)
mdl->register_decl(f, v);
}
terms.reset();
return mdl;
@ -260,10 +329,7 @@ namespace bv {
out << "u ";
if (m_repair_roots.contains(e->get_id()))
out << "r ";
if (bv.is_bv(e))
out << m_eval.wval(e);
else if (m.is_bool(e))
out << (m_eval.bval0(e)?"T":"F");
m_eval.display_value(out, e);
out << "\n";
}
terms.reset();
@ -273,17 +339,20 @@ namespace bv {
void sls::updt_params(params_ref const& _p) {
sls_params p(_p);
m_config.m_max_restarts = p.max_restarts();
m_config.m_max_repairs = p.max_repairs();
m_rand.set_seed(p.random_seed());
m_terms.updt_params(_p);
params_ref q = _p;
q.set_uint("max_restarts", 10);
m_engine.updt_params(q);
}
void sls::trace_repair(bool down, expr* e) {
IF_VERBOSE(20,
verbose_stream() << (down ? "d #" : "u #")
std::ostream& sls::trace_repair(bool down, expr* e) {
verbose_stream() << (down ? "d #" : "u #")
<< e->get_id() << ": "
<< mk_bounded_pp(e, m, 1) << " ";
if (bv.is_bv(e)) verbose_stream() << m_eval.wval(e) << " " << (m_eval.is_fixed0(e) ? "fixed " : " ");
if (m.is_bool(e)) verbose_stream() << m_eval.bval0(e) << " ";
verbose_stream() << "\n");
m_eval.display_value(verbose_stream(), e) << "\n";
return verbose_stream();
}
void sls::trace() {

View file

@ -26,6 +26,7 @@ Author:
#include "ast/sls/sls_valuation.h"
#include "ast/sls/bv_sls_terms.h"
#include "ast/sls/bv_sls_eval.h"
#include "ast/sls/sls_engine.h"
#include "ast/bv_decl_plugin.h"
#include "model/model.h"
@ -49,33 +50,41 @@ namespace bv {
ptr_vector<expr> m_todo;
random_gen m_rand;
config m_config;
sls_engine m_engine;
bool m_engine_model = false;
bool m_engine_init = false;
std::function<expr_ref()> m_get_unit;
std::function<void(model& mdl)> m_set_model;
unsigned m_min_repair_size = UINT_MAX;
std::pair<bool, app*> next_to_repair();
bool eval_is_correct(app* e);
bool re_eval_is_correct(app* e);
void init_repair_goal(app* e);
void set_model();
void try_repair_down(app* e);
void try_repair_up(app* e);
void set_repair_down(expr* e) { m_repair_down = e->get_id(); }
lbool search();
lbool search1();
lbool search2();
void reinit_eval();
void init_repair();
void trace();
void trace_repair(bool down, expr* e);
std::ostream& trace_repair(bool down, expr* e);
indexed_uint_set m_to_repair;
void init_repair_candidates();
public:
sls(ast_manager& m);
sls(ast_manager& m, params_ref const& p);
/**
* Add constraints
*/
void assert_expr(expr* e) { m_terms.assert_expr(e); }
void assert_expr(expr* e) { m_terms.assert_expr(e); m_engine.assert_expr(e); }
/*
* Invoke init after all expressions are asserted.
* No other expressions can be asserted after init.
*/
void init();
@ -85,16 +94,26 @@ namespace bv {
*/
void init_eval(std::function<bool(expr*, unsigned)>& eval);
/**
* add callback to retrieve new units
*/
void init_unit(std::function<expr_ref()> get_unit) { m_get_unit = get_unit; }
/**
* Add callback to set model
*/
void set_model(std::function<void(model& mdl)> f) { m_set_model = f; }
/**
* Run (bounded) local search to find feasible assignments.
*/
lbool operator()();
void updt_params(params_ref const& p);
void collect_statistics(statistics & st) const { m_stats.collect_statistics(st); }
void reset_statistics() { m_stats.reset(); }
void collect_statistics(statistics& st) const { m_stats.collect_statistics(st); m_engine.collect_statistics(st); }
void reset_statistics() { m_stats.reset(); m_engine.reset_statistics(); }
sls_stats const& get_stats() const { return m_stats; }
unsigned get_num_moves() { return m_stats.m_moves + m_engine.get_stats().m_moves; }
std::ostream& display(std::ostream& out);

View file

@ -24,8 +24,8 @@ namespace bv {
{}
void sls_eval::init_eval(expr_ref_vector const& es, std::function<bool(expr*, unsigned)> const& eval) {
sort_assertions(es);
for (expr* e : m_todo) {
auto& terms = sort_assertions(es);
for (expr* e : terms) {
if (!is_app(e))
continue;
app* a = to_app(e);
@ -49,7 +49,7 @@ namespace bv {
TRACE("sls", tout << "Unhandled expression " << mk_pp(e, m) << "\n");
}
}
m_todo.reset();
terms.reset();
}
/**
@ -84,10 +84,13 @@ namespace bv {
return false;
auto v = alloc_valuation(e);
m_values.set(e->get_id(), v);
if (bv.is_sign_ext(e)) {
unsigned p = e->get_parameter(0).get_int();
v->set_signed(p);
}
expr* x, * y;
rational val;
if (bv.is_sign_ext(e))
v->set_signed(e->get_parameter(0).get_int());
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;
}
@ -911,26 +914,25 @@ namespace bv {
bool sls_eval::try_repair_eq(bool is_true, bvval& a, bvval const& b) {
if (is_true) {
if (m_rand() % 20 != 0)
if (m_rand(20) != 0)
if (a.try_set(b.bits()))
return true;
a.get_variant(m_tmp, m_rand);
return a.set_repair(random_bool(), m_tmp);
return a.set_random(m_rand);
}
else {
bool try_above = m_rand() % 2 == 0;
bool try_above = m_rand(2) == 0;
if (try_above) {
a.set_add(m_tmp, b.bits(), m_one);
if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_tmp2, m_rand))
if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_rand))
return true;
}
a.set_sub(m_tmp, b.bits(), m_one);
if (!a.is_zero(m_tmp) && a.set_random_at_most(m_tmp, m_tmp2, m_rand))
if (!a.is_zero(m_tmp) && a.set_random_at_most(m_tmp, m_rand))
return true;
if (!try_above) {
a.set_add(m_tmp, b.bits(), m_one);
if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_tmp2, m_rand))
if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_rand))
return true;
}
return false;
@ -1005,7 +1007,6 @@ namespace bv {
bool sls_eval::try_repair_bxor(bvect const& e, bvval& a, bvval const& b) {
for (unsigned i = 0; i < a.nw; ++i)
m_tmp[i] = e[i] ^ b.bits()[i];
a.clear_overflow_bits(m_tmp);
return a.set_repair(random_bool(), m_tmp);
}
@ -1015,17 +1016,16 @@ namespace bv {
// If this fails, set a to a random value
//
bool sls_eval::try_repair_add(bvect const& e, bvval& a, bvval const& b) {
if (m_rand() % 20 != 0) {
if (m_rand(20) != 0) {
a.set_sub(m_tmp, e, b.bits());
if (a.try_set(m_tmp))
return true;
}
a.get_variant(m_tmp, m_rand);
return a.set_repair(random_bool(), m_tmp);
return a.set_random(m_rand);
}
bool sls_eval::try_repair_sub(bvect const& e, bvval& a, bvval & b, unsigned i) {
if (m_rand() % 20 != 0) {
if (m_rand(20) != 0) {
if (i == 0)
// e = a - b -> a := e + b
a.set_add(m_tmp, e, b.bits());
@ -1036,8 +1036,7 @@ namespace bv {
return true;
}
// fall back to a random value
a.get_variant(m_tmp, m_rand);
return a.set_repair(random_bool(), m_tmp);
return a.set_random(m_rand);
}
/**
@ -1055,15 +1054,11 @@ namespace bv {
return a.set_repair(random_bool(), m_tmp);
}
if (b.is_zero()) {
a.get_variant(m_tmp, m_rand);
return a.set_repair(random_bool(), m_tmp);
}
if (m_rand() % 20 == 0) {
a.get_variant(m_tmp, m_rand);
return a.set_repair(random_bool(), m_tmp);
}
if (b.is_zero())
return a.set_random(m_rand);
if (m_rand(20) == 0)
return a.set_random(m_rand);
#if 0
verbose_stream() << "solve for " << e << "\n";
@ -1093,7 +1088,7 @@ namespace bv {
b.shift_right(y, parity_b);
#if 0
for (unsigned i = parity_b; i < b.bw; ++i)
y.set(i, m_rand() % 2 == 0);
y.set(i, m_rand(2) == 0);
#endif
}
@ -1148,13 +1143,12 @@ namespace bv {
if (a.set_repair(random_bool(), m_tmp))
return true;
a.get_variant(m_tmp, m_rand);
return a.set_repair(random_bool(), m_tmp);
return a.set_random(m_rand);
}
bool sls_eval::try_repair_bnot(bvect const& e, bvval& a) {
for (unsigned i = 0; i < a.nw; ++i)
m_tmp[i] = ~e[i];
m_tmp[i] = ~e[i];
a.clear_overflow_bits(m_tmp);
return a.try_set(m_tmp);
}
@ -1233,16 +1227,16 @@ namespace bv {
bool sls_eval::try_repair_sle(bvval& a, bvect const& b, bvect const& p2) {
bool r = false;
if (b < p2) {
bool coin = m_rand() % 2 == 0;
bool coin = m_rand(2) == 0;
if (coin)
r = a.set_random_at_least(p2, m_tmp3, m_rand);
r = a.set_random_at_least(p2, m_rand);
if (!r)
r = a.set_random_at_most(b, m_tmp3, m_rand);
r = a.set_random_at_most(b, m_rand);
if (!coin && !r)
r = a.set_random_at_least(p2, m_tmp3, m_rand);
r = a.set_random_at_least(p2, m_rand);
}
else
r = a.set_random_in_range(p2, b, m_tmp3, m_rand);
r = a.set_random_in_range(p2, b, m_rand);
return r;
}
@ -1262,16 +1256,16 @@ namespace bv {
bool r = false;
if (p2 < b)
// random b <= x < p2
r = a.set_random_in_range(b, p2_1, m_tmp3, m_rand);
r = a.set_random_in_range(b, p2_1, m_rand);
else {
// random b <= x or x < p2
bool coin = m_rand() % 2 == 0;
bool coin = m_rand(2) == 0;
if (coin)
r = a.set_random_at_most(p2_1, m_tmp3, m_rand);
r = a.set_random_at_most(p2_1,m_rand);
if (!r)
r = a.set_random_at_least(b, m_tmp3, m_rand);
r = a.set_random_at_least(b, m_rand);
if (!r && !coin)
r = a.set_random_at_most(p2_1, m_tmp3, m_rand);
r = a.set_random_at_most(p2_1, m_rand);
}
p2_1.set_bw(0);
return r;
@ -1287,28 +1281,28 @@ namespace bv {
bool sls_eval::try_repair_ule(bool e, bvval& a, bvval const& b) {
if (e) {
// a <= t
return a.set_random_at_most(b.bits(), m_tmp, m_rand);
return a.set_random_at_most(b.bits(), m_rand);
}
else {
// a > t
a.set_add(m_tmp, b.bits(), m_one);
if (a.is_zero(m_tmp))
return false;
return a.set_random_at_least(m_tmp, m_tmp2, m_rand);
return a.set_random_at_least(m_tmp, m_rand);
}
}
bool sls_eval::try_repair_uge(bool e, bvval& a, bvval const& b) {
if (e) {
// a >= t
return a.set_random_at_least(b.bits(), m_tmp, m_rand);
return a.set_random_at_least(b.bits(), m_rand);
}
else {
// a < t
if (b.is_zero())
return false;
a.set_sub(m_tmp, b.bits(), m_one);
return a.set_random_at_most(m_tmp, m_tmp2, m_rand);
return a.set_random_at_most(m_tmp, m_rand);
}
}
@ -1348,41 +1342,261 @@ namespace bv {
return false;
}
bool sls_eval::try_repair_ashr(bvect const& e, bvval & a, bvval& b, unsigned i) {
if (i == 0) {
unsigned sh = b.to_nat(b.bw);
if (sh == 0)
return a.try_set(e);
else if (sh >= b.bw) {
if (e.get(a.bw - 1))
return a.try_set_bit(a.bw - 1, true);
else
return a.try_set_bit(a.bw - 1, false);
}
else {
// e = a >> sh
// a[bw-1:sh] = e[bw-sh-1:0]
// a[sh-1:0] = a[sh-1:0]
// ignore sign
for (unsigned i = sh; i < a.bw; ++i)
m_tmp.set(i, e.get(i - sh));
for (unsigned i = 0; i < sh; ++i)
m_tmp.set(i, a.get_bit(i));
a.clear_overflow_bits(m_tmp);
return a.try_set(m_tmp);
}
}
else {
// NB. blind sub-range of possible values for b
SASSERT(i == 1);
unsigned sh = m_rand(a.bw + 1);
b.set(m_tmp, sh);
return b.try_set(m_tmp);
}
bool sls_eval::try_repair_ashr(bvect const& e, bvval & a, bvval& b, unsigned i) {
if (i == 0)
return try_repair_ashr0(e, a, b);
else
return try_repair_ashr1(e, a, b);
}
bool sls_eval::try_repair_lshr(bvect const& e, bvval& a, bvval& b, unsigned i) {
return try_repair_ashr(e, a, b, i);
if (i == 0)
return try_repair_lshr0(e, a, b);
else
return try_repair_lshr1(e, a, b);
}
/**
* strong:
* - e = (e << b) >> b -> a := e << b, upper b bits set random
* weak:
* - e = 0 -> a := random
* - e > 0 -> a := random with msb(a) >= msb(e)
*/
bool sls_eval::try_repair_lshr0(bvect const& e, bvval& a, bvval const& b) {
auto& t = m_tmp;
// t := e << b
// t := t >> b
t.set_shift_left(e, b.bits());
t.set_shift_right(t, b.bits());
bool use_strong = m_rand(10) != 0;
if (t == e && use_strong) {
t.set_shift_left(e, b.bits());
unsigned n = b.bits().to_nat(e.bw);
for (unsigned i = e.bw; i-- > e.bw - n;)
t.set(i, a.get_bit(i));
if (a.set_repair(random_bool(), t))
return true;
}
unsigned sh = b.to_nat(b.bw);
if (m_rand(20) != 0) {
if (sh == 0 && a.try_set(e))
return true;
else if (sh >= b.bw)
return true;
else if (sh < b.bw && m_rand(20) != 0) {
// e = a >> sh
// a[bw-1:sh] = e[bw-sh-1:0]
// a[sh-1:0] = a[sh-1:0]
for (unsigned i = sh; i < a.bw; ++i)
t.set(i, e.get(i - sh));
for (unsigned i = 0; i < sh; ++i)
t.set(i, a.get_bit(i));
a.clear_overflow_bits(t);
if (a.try_set(t))
return true;
}
}
//bool r = try_repair_ashr(e, a, const_cast<bvval&>(b), 0);
//verbose_stream() << "repair lshr0 " << e << " b: " << b << " a: " << a << "\n";
//return r;
a.get_variant(t, m_rand);
unsigned msb = a.msb(e);
if (msb > a.msb(t)) {
unsigned num_flex = 0;
for (unsigned i = e.bw; i-- >= msb;)
if (!a.fixed.get(i))
++num_flex;
if (num_flex == 0)
return false;
unsigned n = m_rand(num_flex);
for (unsigned i = e.bw; i-- >= msb;) {
if (!a.fixed.get(i)) {
if (n == 0) {
t.set(i, true);
break;
}
else
n--;
}
}
}
return a.set_repair(random_bool(), t);
}
/**
* strong:
* - clz(a) <= clz(e), e = 0 or (a >> (clz(e) - clz(a)) = e
* - e = 0 and a = 0: b := random
* - e = 0 and a != 0: b := random, such that shift <= b
* - e != 0: b := shift
* where shift := clz(e) - clz(a)
*
* weak:
* - e = 0: b := random
* - e > 0: b := random >= clz(e)
*/
bool sls_eval::try_repair_lshr1(bvect const& e, bvval const& a, bvval& b) {
auto& t = m_tmp;
auto clza = a.clz(a.bits());
auto clze = a.clz(e);
t.set_bw(a.bw);
// strong
if (m_rand(10) != 0 && clza <= clze && (a.is_zero(e) || t.set_shift_right(a.bits(), clze - clza) == e)) {
if (a.is_zero(e) && a.is_zero())
return true;
unsigned shift = clze - clza;
if (a.is_zero(e))
shift = m_rand(a.bw + 1 - shift) + shift;
b.set(t, shift);
if (b.try_set(t))
return true;
}
// no change
if (m_rand(10) != 0) {
if (a.is_zero(e))
return true;
if (b.bits() <= clze)
return true;
}
// weak
b.get_variant(t, m_rand);
if (a.is_zero(e))
return b.set_repair(random_bool(), t);
else {
for (unsigned i = 0; i < 4; ++i) {
for (unsigned i = a.bw; !(t <= clze) && i-- > 0; )
if (!b.fixed.get(i))
t.set(i, false);
if (t <= clze && b.set_repair(random_bool(), t))
return true;
b.get_variant(t, m_rand);
}
return false;
}
}
/**
* strong:
* b < |b| => (e << b) >>a b = e)
* b >= |b| => (e = ones || e = 0)
* - if b < |b|: a := e << b
* - if b >= |b|: a[bw-1] := e = ones
* weak:
*
*/
bool sls_eval::try_repair_ashr0(bvect const& e, bvval& a, bvval const& b) {
auto& t = m_tmp;
t.set_bw(b.bw);
auto n = b.msb(b.bits());
bool use_strong = m_rand(20) != 0;
if (use_strong && n < b.bw) {
t.set_shift_left(e, b.bits());
bool sign = t.get(b.bw-1);
t.set_shift_right(t, b.bits());
if (sign) {
for (unsigned i = b.bw; i-- > b.bw - n; )
t.set(i, true);
}
use_strong &= t == e;
}
else {
use_strong &= a.is_zero(e) || a.is_ones(e);
}
if (use_strong) {
if (n < b.bw) {
t.set_shift_left(e, b.bits());
for (unsigned i = 0; i < n; ++i)
t.set(i, a.get_bit(i));
}
else {
for (unsigned i = 0; i < b.nw; ++i)
t[i] = a.bits()[i];
t.set(b.bw - 1, a.is_ones(e));
}
if (a.set_repair(random_bool(), t))
return true;
}
if (m_rand(10) != 0) {
if (n < b.bw) {
t.set_shift_left(e, b.bits());
for (unsigned i = 0; i < n; ++i)
t.set(i, random_bool());
}
else {
a.get_variant(t, m_rand);
t.set(b.bw - 1, a.is_ones(e));
}
if (a.set_repair(random_bool(), t))
return true;
}
return a.set_random(m_rand);
}
/*
* strong:
* - clz(a) <= clz(e), e = 0 or (a >>a (clz(e) - clz(a)) = e
* - e = 0 and a = 0: b := random
* - e = 0 and a != 0: b := random, such that shift <= b
* - e != 0: b := shift
* where shift := clz(e) - clz(a)
*
* weak:
* - e = 0: b := random
* - e > 0: b := random >= clz(e)
*/
bool sls_eval::try_repair_ashr1(bvect const& e, bvval const& a, bvval& b) {
auto& t = m_tmp;
auto clza = a.clz(a.bits());
auto clze = a.clz(e);
t.set_bw(a.bw);
// strong unsigned
if (!a.get_bit(a.bw - 1) && m_rand(10) != 0 && clza <= clze && (a.is_zero(e) || t.set_shift_right(a.bits(), clze - clza) == e)) {
if (a.is_zero(e) && a.is_zero())
return true;
unsigned shift = clze - clza;
if (a.is_zero(e))
shift = m_rand(a.bw + 1 - shift) + shift;
b.set(t, shift);
if (b.try_set(t))
return true;
}
// strong signed
if (a.get_bit(a.bw - 1) && m_rand(10) != 0 && clza >= clze) {
t.set_shift_right(a.bits(), clza - clze);
for (unsigned i = a.bw; i-- > a.bw - clza + clze; )
t.set(i, true);
if (e == t) {
if (a.is_zero(e) && a.is_zero())
return true;
unsigned shift = clze - clza;
if (a.is_zero(e))
shift = m_rand(a.bw + 1 - shift) + shift;
b.set(t, shift);
if (b.try_set(t))
return true;
}
}
// weak
b.get_variant(t, m_rand);
return b.set_repair(random_bool(), t);
}
bool sls_eval::try_repair_comp(bvect const& e, bvval& a, bvval& b, unsigned i) {
@ -1425,16 +1639,12 @@ namespace bv {
m_tmp2.set(b.msb(m_tmp2), false);
while (a.set_add(m_tmp3, m_tmp, m_tmp2))
m_tmp2.set(b.msb(m_tmp2), false);
a.clear_overflow_bits(m_tmp3);
return a.set_repair(true, m_tmp3);
}
else {
if (a.is_one(e) && a.is_zero()) {
for (unsigned i = 0; i < a.nw; ++i)
m_tmp[i] = random_bits();
a.clear_overflow_bits(m_tmp);
return b.set_repair(true, m_tmp);
}
if (a.is_one(e) && a.is_zero())
return b.set_random(m_rand);
if (a.is_one(e)) {
a.set(m_tmp, a.bits());
return b.set_repair(true, m_tmp);
@ -1506,7 +1716,6 @@ namespace bv {
m_tmp[i] = random_bits();
a.set_sub(m_tmp2, a.bits(), e);
set_div(m_tmp2, m_tmp, a.bw, m_tmp3, m_tmp4);
a.clear_overflow_bits(m_tmp3);
return b.set_repair(random_bool(), m_tmp3);
}
}
@ -1630,8 +1839,7 @@ namespace bv {
m_tmp.set(i, e.get(i));
b.clear_overflow_bits(m_tmp);
r = b.try_set(m_tmp);
}
//verbose_stream() << e << " := " << a << " " << b << "\n";
}
return r;
}
@ -1641,15 +1849,15 @@ namespace bv {
// set a outside of [hi:lo] to random values with preference to 0 or 1 bits
//
bool sls_eval::try_repair_extract(bvect const& e, bvval& a, unsigned lo) {
if (m_rand() % m_config.m_prob_randomize_extract <= 100) {
if (m_rand(m_config.m_prob_randomize_extract) <= 100) {
a.get_variant(m_tmp, m_rand);
if (0 == (m_rand() % 2)) {
auto bit = 0 == (m_rand() % 2);
if (0 == (m_rand(2))) {
auto bit = 0 == (m_rand(2));
if (!a.try_set_range(m_tmp, 0, lo, bit))
a.try_set_range(m_tmp, 0, lo, !bit);
}
if (0 == (m_rand() % 2)) {
auto bit = 0 == (m_rand() % 2);
if (0 == (m_rand(2))) {
auto bit = 0 == (m_rand(2));
if (!a.try_set_range(m_tmp, lo + e.bw, a.bw, bit))
a.try_set_range(m_tmp, lo + e.bw, a.bw, !bit);
}
@ -1660,10 +1868,7 @@ namespace bv {
m_tmp.set(i + lo, e.get(i));
if (a.try_set(m_tmp))
return true;
a.get_variant(m_tmp, m_rand);
bool res = a.set_repair(random_bool(), m_tmp);
// verbose_stream() << "try set " << res << " " << m_tmp[0] << " " << a << "\n";
return res;
return a.set_random(m_rand);
}
void sls_eval::set_div(bvect const& a, bvect const& b, unsigned bw,
@ -1698,7 +1903,7 @@ namespace bv {
}
if (bv.is_bv(e)) {
auto& v = eval(to_app(e));
// verbose_stream() << "committing: " << v << "\n";
for (unsigned i = 0; i < v.nw; ++i)
if (0 != (v.fixed[i] & (v.bits()[i] ^ v.eval[i]))) {
v.bits().copy_to(v.nw, v.eval);
@ -1717,19 +1922,83 @@ namespace bv {
return *m_values[e->get_id()];
}
void sls_eval::init_eval(app* t) {
if (m.is_bool(t))
set(t, bval1(t));
else if (bv.is_bv(t)) {
auto& v = wval(t);
v.bits().copy_to(v.nw, v.eval);
}
}
void sls_eval::commit_eval(app* e) {
if (m.is_bool(e)) {
set(e, bval1(e));
}
else {
VERIFY(wval(e).commit_eval());
}
}
void sls_eval::set_random(app* e) {
if (bv.is_bv(e))
eval(e).set_random(m_rand);
}
bool sls_eval::eval_is_correct(app* e) {
if (!can_eval1(e))
return false;
if (m.is_bool(e))
return bval0(e) == bval1(e);
if (bv.is_bv(e)) {
auto const& v = wval(e);
return v.eval == v.bits();
}
UNREACHABLE();
return false;
}
bool sls_eval::re_eval_is_correct(app* e) {
if (!can_eval1(e))
return false;
if (m.is_bool(e))
return bval0(e) ==bval1(e);
if (bv.is_bv(e)) {
auto const& v = eval(e);
return v.eval == v.bits();
}
UNREACHABLE();
return false;
}
expr_ref sls_eval::get_value(app* e) {
if (m.is_bool(e))
return expr_ref(m.mk_bool_val(bval0(e)), m);
else if (bv.is_bv(e)) {
auto const& v = wval(e);
rational n = v.get_value();
return expr_ref(bv.mk_numeral(n, v.bw), m);
}
return expr_ref(m);
}
std::ostream& sls_eval::display(std::ostream& out, expr_ref_vector const& es) {
auto& terms = sort_assertions(es);
for (expr* e : terms) {
out << e->get_id() << ": " << mk_bounded_pp(e, m, 1) << " ";
if (is_fixed0(e))
out << "f ";
if (bv.is_bv(e))
out << wval(e);
else if (m.is_bool(e))
out << (bval0(e) ? "T" : "F");
out << "\n";
display_value(out, e) << "\n";
}
terms.reset();
return out;
}
std::ostream& sls_eval::display_value(std::ostream& out, expr* e) {
if (bv.is_bv(e))
return out << wval(e);
if (m.is_bool(e))
return out << (bval0(e)?"T":"F");
return out << "?";
}
}

View file

@ -25,6 +25,12 @@ namespace bv {
class sls_fixed;
class sls_eval_plugin {
public:
virtual ~sls_eval_plugin() {}
};
class sls_eval {
struct config {
unsigned m_prob_randomize_extract = 50;
@ -40,6 +46,8 @@ namespace bv {
random_gen m_rand;
config m_config;
scoped_ptr_vector<sls_eval_plugin> m_plugins;
scoped_ptr_vector<sls_valuation> m_values; // expr-id -> bv valuation
@ -93,6 +101,10 @@ namespace bv {
bool try_repair_shl(bvect const& e, bvval& a, bvval& b, unsigned i);
bool try_repair_ashr(bvect const& e, bvval& a, bvval& b, unsigned i);
bool try_repair_lshr(bvect const& e, bvval& a, bvval& b, unsigned i);
bool try_repair_lshr0(bvect const& e, bvval& a, bvval const& b);
bool try_repair_lshr1(bvect const& e, bvval const& a, bvval& b);
bool try_repair_ashr0(bvect const& e, bvval& a, bvval const& b);
bool try_repair_ashr1(bvect const& e, bvval const& a, bvval& b);
bool try_repair_bit2bool(bvval& a, unsigned idx);
bool try_repair_udiv(bvect const& e, bvval& a, bvval& b, unsigned i);
bool try_repair_urem(bvect const& e, bvval& a, bvval& b, unsigned i);
@ -153,6 +165,18 @@ namespace bv {
sls_valuation& eval(app* e) const;
void commit_eval(app* e);
void init_eval(app* e);
void set_random(app* e);
bool eval_is_correct(app* e);
bool re_eval_is_correct(app* e);
expr_ref get_value(app* e);
/**
* Override evaluaton.
*/
@ -174,5 +198,7 @@ namespace bv {
std::ostream& display(std::ostream& out, expr_ref_vector const& es);
std::ostream& display_value(std::ostream& out, expr* e);
};
}

View file

@ -38,8 +38,8 @@ namespace bv {
else
;
}
ev.m_todo.reset();
init_ranges(es);
ev.m_todo.reset();
}
@ -49,11 +49,49 @@ namespace bv {
if (is_app(e))
init_range(to_app(e), sign);
}
for (expr* e : ev.m_todo)
propagate_range_up(e);
}
void sls_fixed::propagate_range_up(expr* e) {
expr* t, * s;
rational v;
if (bv.is_concat(e, t, s)) {
auto& vals = wval(s);
if (vals.lo() != vals.hi() && (vals.lo() < vals.hi() || vals.hi() == 0))
// lo <= e
add_range(e, vals.lo(), rational::zero(), false);
auto valt = wval(t);
if (valt.lo() != valt.hi() && (valt.lo() < valt.hi() || valt.hi() == 0)) {
// (2^|s|) * lo <= e < (2^|s|) * hi
auto p = rational::power_of_two(bv.get_bv_size(s));
add_range(e, valt.lo() * p, valt.hi() * p, false);
}
}
else if (bv.is_bv_add(e, s, t) && bv.is_numeral(s, v)) {
auto& val = wval(t);
if (val.lo() != val.hi())
add_range(e, v + val.lo(), v + val.hi(), false);
}
else if (bv.is_bv_add(e, t, s) && bv.is_numeral(s, v)) {
auto& val = wval(t);
if (val.lo() != val.hi())
add_range(e, v + val.lo(), v + val.hi(), false);
}
// x in [1, 4[ => -x in [-3, 0[
// x in [lo, hi[ => -x in [-hi + 1, -lo + 1[
else if (bv.is_bv_mul(e, s, t) && bv.is_numeral(s, v) &&
v + 1 == rational::power_of_two(bv.get_bv_size(e))) {
auto& val = wval(t);
if (val.lo() != val.hi())
add_range(e, -val.hi() + 1, - val.lo() + 1, false);
}
}
// s <=s t <=> s + K <= t + K, K = 2^{bw-1}
void sls_fixed::init_range(app* e, bool sign) {
bool sls_fixed::init_range(app* e, bool sign) {
expr* s, * t, * x, * y;
rational a, b;
unsigned idx;
@ -64,56 +102,116 @@ namespace bv {
if (bv.is_ule(e, s, t)) {
get_offset(s, x, a);
get_offset(t, y, b);
init_range(x, a, y, b, sign);
return init_range(x, a, y, b, sign);
}
else if (bv.is_ult(e, s, t)) {
get_offset(s, x, a);
get_offset(t, y, b);
init_range(y, b, x, a, !sign);
return init_range(y, b, x, a, !sign);
}
else if (bv.is_uge(e, s, t)) {
get_offset(s, x, a);
get_offset(t, y, b);
init_range(y, b, x, a, sign);
return init_range(y, b, x, a, sign);
}
else if (bv.is_ugt(e, s, t)) {
get_offset(s, x, a);
get_offset(t, y, b);
init_range(x, a, y, b, !sign);
return init_range(x, a, y, b, !sign);
}
else if (bv.is_sle(e, s, t)) {
get_offset(s, x, a);
get_offset(t, y, b);
init_range(x, a + N(s), y, b + N(s), sign);
return init_range(x, a + N(s), y, b + N(s), sign);
}
else if (bv.is_slt(e, s, t)) {
get_offset(s, x, a);
get_offset(t, y, b);
init_range(y, b + N(s), x, a + N(s), !sign);
return init_range(y, b + N(s), x, a + N(s), !sign);
}
else if (bv.is_sge(e, s, t)) {
get_offset(s, x, a);
get_offset(t, y, b);
init_range(y, b + N(s), x, a + N(s), sign);
return init_range(y, b + N(s), x, a + N(s), sign);
}
else if (bv.is_sgt(e, s, t)) {
get_offset(s, x, a);
get_offset(t, y, b);
init_range(x, a + N(s), y, b + N(s), !sign);
return init_range(x, a + N(s), y, b + N(s), !sign);
}
else if (!sign && m.is_eq(e, s, t)) {
else if (m.is_eq(e, s, t)) {
if (bv.is_numeral(s, a))
// t - a <= 0
init_range(t, -a, nullptr, rational(0), false);
init_eq(t, a, sign);
else if (bv.is_numeral(t, a))
init_range(s, -a, nullptr, rational(0), false);
init_eq(s, a, sign);
else
return false;
return true;
}
else if (bv.is_bit2bool(e, s, idx)) {
auto& val = wval(s);
val.try_set_bit(idx, !sign);
val.fixed.set(idx, true);
val.tighten_range();
return true;
}
return false;
}
bool sls_fixed::init_eq(expr* t, rational const& a, bool sign) {
unsigned lo, hi;
rational b(0);
// verbose_stream() << mk_bounded_pp(t, m) << " == " << a << "\n";
expr* s = nullptr;
if (sign)
// 1 <= t - a
init_range(nullptr, rational(1), t, -a, false);
else
// t - a <= 0
init_range(t, -a, nullptr, rational::zero(), false);
if (!sign && bv.is_bv_not(t, s)) {
for (unsigned i = 0; i < bv.get_bv_size(s); ++i)
if (!a.get_bit(i))
b += rational::power_of_two(i);
init_eq(s, b, false);
return true;
}
expr* x, * y;
if (!sign && bv.is_concat(t, x, y)) {
auto sz = bv.get_bv_size(y);
auto k = rational::power_of_two(sz);
init_eq(y, mod(a, k), false);
init_eq(x, div(a + k - 1, k), false);
return true;
}
if (bv.is_extract(t, lo, hi, s)) {
if (hi == lo) {
sign = sign ? a == 1 : a == 0;
auto& val = wval(s);
if (val.try_set_bit(lo, !sign))
val.fixed.set(lo, true);
val.tighten_range();
}
else if (!sign) {
auto& val = wval(s);
for (unsigned i = lo; i <= hi; ++i)
if (val.try_set_bit(i, a.get_bit(i - lo)))
val.fixed.set(i, true);
val.tighten_range();
// verbose_stream() << lo << " " << hi << " " << val << " := " << a << "\n";
}
if (!sign && hi + 1 == bv.get_bv_size(s)) {
// s < 2^lo * (a + 1)
rational b = rational::power_of_two(lo) * (a + 1) - 1;
rational offset;
get_offset(s, t, offset);
// t + offset <= b
init_range(t, offset, nullptr, b, false);
}
}
return true;
}
//
@ -125,52 +223,65 @@ namespace bv {
// a < x + b <=> ! (x + b <= a) <=> x not in [-a, b - a [ <=> x in [b - a, -a [ a != -1
// x + a < x + b <=> ! (x + b <= x + a) <=> x in [-a, -b [ a != b
//
void sls_fixed::init_range(expr* x, rational const& a, expr* y, rational const& b, bool sign) {
bool sls_fixed::init_range(expr* x, rational const& a, expr* y, rational const& b, bool sign) {
if (!x && !y)
return;
if (!x) {
// a <= y + b
if (a == 0)
return;
auto& v = wval(y);
if (!sign)
v.add_range(a - b, -b);
else
v.add_range(-b, a - b);
}
else if (!y) {
return false;
if (!x)
return add_range(y, a - b, -b, sign);
else if (!y)
return add_range(x, -a, b - a + 1, sign);
else if (x == y)
return add_range(x, -a, -b, sign);
return false;
}
if (mod(b + 1, rational::power_of_two(bv.get_bv_size(x))) == 0)
return;
auto& v = wval(x);
if (!sign)
v.add_range(-a, b - a + 1);
else
v.add_range(b - a + 1, -a);
bool sls_fixed::add_range(expr* e, rational lo, rational hi, bool sign) {
auto& v = wval(e);
lo = mod(lo, rational::power_of_two(bv.get_bv_size(e)));
hi = mod(hi, rational::power_of_two(bv.get_bv_size(e)));
if (lo == hi)
return false;
if (sign)
std::swap(lo, hi);
v.add_range(lo, hi);
expr* x, * y;
if (v.lo() == 0 && bv.is_concat(e, x, y)) {
auto sz = bv.get_bv_size(y);
auto k = rational::power_of_two(sz);
lo = v.lo();
hi = v.hi();
if (hi <= k) {
add_range(y, lo, hi, false);
init_eq(x, lo, false);
}
else {
hi = div(hi + k - 1, k);
add_range(x, lo, hi, false);
}
}
else if (x == y) {
if (a == b)
return;
auto& v = wval(x);
if (!sign)
v.add_range(-a, -b);
else
v.add_range(-b, -a);
}
return true;
}
void sls_fixed::get_offset(expr* e, expr*& x, rational& offset) {
expr* s, * t;
x = e;
offset = 0;
if (bv.is_bv_add(e, s, t)) {
if (bv.is_numeral(s, offset))
rational n;
while (true) {
if (bv.is_bv_add(x, s, t) && bv.is_numeral(s, n)) {
x = t;
else if (bv.is_numeral(t, offset))
offset += n;
continue;
}
if (bv.is_bv_add(x, s, t) && bv.is_numeral(t, n)) {
x = s;
offset += n;
continue;
}
break;
}
else if (bv.is_numeral(e, offset))
if (bv.is_numeral(e, n))
offset += n,
x = nullptr;
}
@ -258,11 +369,6 @@ namespace bv {
case OP_BADD: {
auto& a = wval(e->get_arg(0));
auto& b = wval(e->get_arg(1));
rational r;
if (bv.is_numeral(e->get_arg(0), r) && b.has_range())
v.add_range(r + b.lo(), r + b.hi());
else if (bv.is_numeral(e->get_arg(1), r) && a.has_range())
v.add_range(r + a.lo(), r + a.hi());
bool pfixed = true;
for (unsigned i = 0; i < v.bw; ++i) {
if (pfixed && a.fixed.get(i) && b.fixed.get(i))
@ -277,7 +383,6 @@ namespace bv {
v.fixed.set(i, false);
}
}
break;
}
case OP_BMUL: {

View file

@ -30,9 +30,12 @@ namespace bv {
bv_util& bv;
void init_ranges(expr_ref_vector const& es);
void init_range(app* e, bool sign);
void init_range(expr* x, rational const& a, expr* y, rational const& b, bool sign);
bool init_range(app* e, bool sign);
void propagate_range_up(expr* e);
bool init_range(expr* x, rational const& a, expr* y, rational const& b, bool sign);
void get_offset(expr* e, expr*& x, rational& offset);
bool init_eq(expr* e, rational const& v, bool sign);
bool add_range(expr* e, rational lo, rational hi, bool sign);
void init_fixed_basic(app* e);
void init_fixed_bv(app* e);

View file

@ -20,12 +20,14 @@ Author:
#include "ast/ast_ll_pp.h"
#include "ast/sls/bv_sls.h"
#include "ast/rewriter/th_rewriter.h"
namespace bv {
sls_terms::sls_terms(ast_manager& m):
m(m),
bv(m),
m_rewriter(m),
m_assertions(m),
m_pinned(m),
m_translated(m),
@ -40,18 +42,20 @@ namespace bv {
expr* top = e;
m_pinned.push_back(e);
m_todo.push_back(e);
expr_fast_mark1 mark;
for (unsigned i = 0; i < m_todo.size(); ++i) {
expr* e = m_todo[i];
if (!is_app(e))
continue;
if (m_translated.get(e->get_id(), nullptr))
continue;
if (mark.is_marked(e))
continue;
mark.mark(e);
for (auto arg : *to_app(e))
m_todo.push_back(arg);
{
expr_fast_mark1 mark;
for (unsigned i = 0; i < m_todo.size(); ++i) {
expr* e = m_todo[i];
if (!is_app(e))
continue;
if (m_translated.get(e->get_id(), nullptr))
continue;
if (mark.is_marked(e))
continue;
mark.mark(e);
for (auto arg : *to_app(e))
m_todo.push_back(arg);
}
}
std::stable_sort(m_todo.begin(), m_todo.end(), [&](expr* a, expr* b) { return get_depth(a) < get_depth(b); });
for (expr* e : m_todo)
@ -127,7 +131,7 @@ namespace bv {
m_translated.setx(e->get_id(), r);
}
expr* sls_terms::mk_sdiv(expr* x, expr* y) {
expr_ref sls_terms::mk_sdiv(expr* x, expr* y) {
// d = udiv(abs(x), abs(y))
// y = 0, x >= 0 -> -1
// y = 0, x < 0 -> 1
@ -141,17 +145,18 @@ namespace bv {
expr_ref z(bv.mk_zero(sz), m);
expr* signx = bv.mk_ule(bv.mk_numeral(N / 2, sz), x);
expr* signy = bv.mk_ule(bv.mk_numeral(N / 2, sz), y);
expr* absx = m.mk_ite(signx, bv.mk_bv_sub(bv.mk_numeral(N - 1, sz), x), x);
expr* absy = m.mk_ite(signy, bv.mk_bv_sub(bv.mk_numeral(N - 1, sz), y), y);
expr* absx = m.mk_ite(signx, bv.mk_bv_neg(x), x);
expr* absy = m.mk_ite(signy, bv.mk_bv_neg(y), y);
expr* d = bv.mk_bv_udiv(absx, absy);
expr* r = m.mk_ite(m.mk_eq(signx, signy), d, bv.mk_bv_neg(d));
expr_ref r(m.mk_ite(m.mk_eq(signx, signy), d, bv.mk_bv_neg(d)), m);
r = m.mk_ite(m.mk_eq(z, y),
m.mk_ite(signx, bv.mk_one(sz), bv.mk_numeral(N - 1, sz)),
m.mk_ite(m.mk_eq(x, z), z, r));
m.mk_ite(signx, bv.mk_one(sz), bv.mk_numeral(N - 1, sz)),
m.mk_ite(m.mk_eq(x, z), z, r));
m_rewriter(r);
return r;
}
expr* sls_terms::mk_smod(expr* x, expr* y) {
expr_ref sls_terms::mk_smod(expr* x, expr* y) {
// u := umod(abs(x), abs(y))
// u = 0 -> 0
// y = 0 -> x
@ -164,21 +169,24 @@ namespace bv {
expr_ref abs_x(m.mk_ite(bv.mk_sle(z, x), x, bv.mk_bv_neg(x)), m);
expr_ref abs_y(m.mk_ite(bv.mk_sle(z, y), y, bv.mk_bv_neg(y)), m);
expr_ref u(bv.mk_bv_urem(abs_x, abs_y), m);
return
m.mk_ite(m.mk_eq(u, z), z,
expr_ref r(m);
r = m.mk_ite(m.mk_eq(u, z), z,
m.mk_ite(m.mk_eq(y, z), x,
m.mk_ite(m.mk_and(bv.mk_sle(z, x), bv.mk_sle(z, x)), u,
m.mk_ite(bv.mk_sle(z, x), bv.mk_bv_add(y, u),
m.mk_ite(bv.mk_sle(z, y), bv.mk_bv_sub(y, u), bv.mk_bv_neg(u))))));
m_rewriter(r);
return r;
}
expr* sls_terms::mk_srem(expr* x, expr* y) {
expr_ref sls_terms::mk_srem(expr* x, expr* y) {
// y = 0 -> x
// else x - sdiv(x, y) * y
return
m.mk_ite(m.mk_eq(y, bv.mk_zero(bv.get_bv_size(x))),
expr_ref r(m);
r = m.mk_ite(m.mk_eq(y, bv.mk_zero(bv.get_bv_size(x))),
x, bv.mk_bv_sub(x, bv.mk_bv_mul(y, mk_sdiv(x, y))));
m_rewriter(r);
return r;
}
@ -198,6 +206,7 @@ namespace bv {
m_todo.push_back(arg);
}
// populate parents
m_parents.reset();
m_parents.reserve(m_terms.size());
for (expr* e : m_terms) {
if (!e || !is_app(e))
@ -205,8 +214,16 @@ namespace bv {
for (expr* arg : *to_app(e))
m_parents[arg->get_id()].push_back(e);
}
m_assertion_set.reset();
for (auto a : m_assertions)
m_assertion_set.insert(a->get_id());
}
void sls_terms::updt_params(params_ref const& p) {
params_ref q = p;
q.set_bool("flat", false);
m_rewriter.updt_params(q);
}
}

View file

@ -21,6 +21,7 @@ Author:
#include "util/scoped_ptr_vector.h"
#include "util/uint_set.h"
#include "ast/ast.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/sls/sls_stats.h"
#include "ast/sls/sls_powers.h"
#include "ast/sls/sls_valuation.h"
@ -31,6 +32,7 @@ namespace bv {
class sls_terms {
ast_manager& m;
bv_util bv;
th_rewriter m_rewriter;
ptr_vector<expr> m_todo, m_args;
expr_ref_vector m_assertions, m_pinned, m_translated;
app_ref_vector m_terms;
@ -40,12 +42,14 @@ namespace bv {
expr* ensure_binary(expr* e);
void ensure_binary_core(expr* e);
expr* mk_sdiv(expr* x, expr* y);
expr* mk_smod(expr* x, expr* y);
expr* mk_srem(expr* x, expr* y);
expr_ref mk_sdiv(expr* x, expr* y);
expr_ref mk_smod(expr* x, expr* y);
expr_ref mk_srem(expr* x, expr* y);
public:
sls_terms(ast_manager& m);
void updt_params(params_ref const& p);
/**
* Add constraints

View file

@ -421,6 +421,7 @@ lbool sls_engine::search() {
// get candidate variables
ptr_vector<func_decl> & to_evaluate = m_tracker.get_unsat_constants(m_assertions);
if (to_evaluate.empty())
{
res = l_true;
@ -514,6 +515,12 @@ lbool sls_engine::operator()() {
if (m_restart_init)
m_tracker.randomize(m_assertions);
return search_loop();
}
lbool sls_engine::search_loop() {
lbool res = l_undef;
do {
@ -533,7 +540,6 @@ lbool sls_engine::operator()() {
} while (res != l_true && m_stats.m_restarts++ < m_max_restarts);
verbose_stream() << "(restarts: " << m_stats.m_restarts << " flips: " << m_stats.m_moves << " fps: " << (m_stats.m_moves / m_stats.m_stopwatch.get_current_seconds()) << ")" << std::endl;
return res;
}

View file

@ -79,7 +79,11 @@ public:
void mk_inv(unsigned bv_sz, const mpz & old_value, mpz & inverted);
void mk_flip(sort * s, const mpz & old_value, unsigned bit, mpz & flipped);
lbool search();
lbool search();
lbool search_loop();
lbool operator()();

View file

@ -56,6 +56,20 @@ namespace bv {
return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) >= 0;
}
bool operator<=(digit_t a, bvect const& b) {
for (unsigned i = 1; i < b.nw; ++i)
if (0 != b[i])
return true;
return mpn_manager().compare(&a, 1, b.data(), 1) <= 0;
}
bool operator<=(bvect const& a, digit_t b) {
for (unsigned i = 1; i < a.nw; ++i)
if (0 != a[i])
return false;
return mpn_manager().compare(a.data(), 1, &b, 1) <= 0;
}
std::ostream& operator<<(std::ostream& out, bvect const& v) {
out << std::hex;
bool nz = false;
@ -83,11 +97,63 @@ namespace bv {
return r;
}
unsigned bvect::to_nat(unsigned max_n) const {
SASSERT(max_n < UINT_MAX / 2);
unsigned p = 1;
unsigned value = 0;
for (unsigned i = 0; i < bw; ++i) {
if (p >= max_n) {
for (unsigned j = i; j < bw; ++j)
if (get(j))
return max_n;
return value;
}
if (get(i))
value += p;
p <<= 1;
}
return value;
}
bvect& bvect::set_shift_right(bvect const& a, bvect const& b) {
SASSERT(a.bw == b.bw);
unsigned shift = b.to_nat(b.bw);
return set_shift_right(a, shift);
}
bvect& bvect::set_shift_right(bvect const& a, unsigned shift) {
set_bw(a.bw);
if (shift == 0)
a.copy_to(a.nw, *this);
else if (shift >= a.bw)
set_zero();
else
for (unsigned i = 0; i < bw; ++i)
set(i, i + shift < bw ? a.get(i + shift) : false);
return *this;
}
bvect& bvect::set_shift_left(bvect const& a, bvect const& b) {
set_bw(a.bw);
SASSERT(a.bw == b.bw);
unsigned shift = b.to_nat(b.bw);
if (shift == 0)
a.copy_to(a.nw, *this);
else if (shift >= a.bw)
set_zero();
else
for (unsigned i = bw; i-- > 0; )
set(i, i >= shift ? a.get(i - shift) : false);
return *this;
}
sls_valuation::sls_valuation(unsigned bw) {
set_bw(bw);
m_lo.set_bw(bw);
m_hi.set_bw(bw);
m_bits.set_bw(bw);
m_tmp.set_bw(bw);
fixed.set_bw(bw);
eval.set_bw(bw);
// have lo, hi bits, fixed point to memory allocated within this of size num_bytes each allocated
@ -106,10 +172,12 @@ namespace bv {
bool sls_valuation::commit_eval() {
for (unsigned i = 0; i < nw; ++i)
if (0 != (fixed[i] & (m_bits[i] ^ eval[i])))
return false;
if (!in_range(eval))
if (0 != (fixed[i] & (m_bits[i] ^ eval[i])))
return false;
if (!in_range(eval))
return false;
for (unsigned i = 0; i < nw; ++i)
m_bits[i] = eval[i];
SASSERT(well_formed());
@ -137,143 +205,75 @@ namespace bv {
//
// largest dst <= src and dst is feasible
// set dst := src & (~fixed | bits)
//
// increment dst if dst < src by setting bits below msb(src & ~dst) to 1
//
// if dst < lo < hi:
// return false
// if lo < hi <= dst:
// set dst := hi - 1
// if hi <= dst < lo
// set dst := hi - 1
//
//
bool sls_valuation::get_at_most(bvect const& src, bvect& dst) const {
SASSERT(!has_overflow(src));
for (unsigned i = 0; i < nw; ++i)
dst[i] = src[i] & (~fixed[i] | m_bits[i]);
//
// If dst < src, then find the most significant
// bit where src[idx] = 1, dst[idx] = 0
// set dst[j] = bits_j | ~fixed_j for j < idx
//
for (unsigned i = nw; i-- > 0; ) {
if (0 != (~dst[i] & src[i])) {
auto idx = log2(~dst[i] & src[i]);
auto mask = (1 << idx) - 1;
dst[i] = (~fixed[i] & mask) | dst[i];
for (unsigned j = i; j-- > 0; )
dst[j] = (~fixed[j] | m_bits[j]);
break;
}
}
SASSERT(!has_overflow(dst));
return round_down(dst);
src.copy_to(nw, dst);
sup_feasible(dst);
if (in_range(dst)) {
SASSERT(can_set(dst));
return true;
}
if (dst < m_lo && m_lo < m_hi) // dst < lo < hi
return false;
if (is_zero(m_hi))
return false;
m_hi.copy_to(nw, dst); // hi <= dst < lo or lo < hi <= dst
sub1(dst);
SASSERT(can_set(dst));
return true;
}
//
// smallest dst >= src and dst is feasible with respect to this.
// set dst := (src & ~fixed) | (fixed & bits)
//
// decrement dst if dst > src by setting bits below msb to 0 unless fixed
//
// if lo < hi <= dst
// return false
// if dst < lo < hi:
// set dst := lo
// if hi <= dst < lo
// set dst := lo
//
bool sls_valuation::get_at_least(bvect const& src, bvect& dst) const {
SASSERT(!has_overflow(src));
for (unsigned i = 0; i < nw; ++i)
dst[i] = (~fixed[i] & src[i]) | (fixed[i] & m_bits[i]);
//
// If dst > src, then find the most significant
// bit where src[idx] = 0, dst[idx] = 1
// set dst[j] = dst[j] & fixed_j for j < idx
//
for (unsigned i = nw; i-- > 0; ) {
if (0 != (dst[i] & ~src[i])) {
auto idx = log2(dst[i] & ~src[i]);
auto mask = (1 << idx);
dst[i] = dst[i] & (fixed[i] | mask);
for (unsigned j = i; j-- > 0; )
dst[j] = dst[j] & fixed[j];
break;
}
src.copy_to(nw, dst);
dst.set_bw(bw);
inf_feasible(dst);
if (in_range(dst)) {
SASSERT(can_set(dst));
return true;
}
SASSERT(!has_overflow(dst));
return round_up(dst);
}
bool sls_valuation::round_up(bvect& dst) const {
if (m_lo < m_hi) {
if (m_hi <= dst)
return false;
if (m_lo > dst)
set(dst, m_lo);
}
else if (m_hi <= dst && m_lo > dst)
set(dst, m_lo);
SASSERT(!has_overflow(dst));
return true;
}
bool sls_valuation::round_down(bvect& dst) const {
if (m_lo < m_hi) {
if (m_lo > dst)
return false;
if (m_hi <= dst) {
set(dst, m_hi);
sub1(dst);
}
}
else if (m_hi <= dst && m_lo > dst) {
set(dst, m_hi);
sub1(dst);
}
SASSERT(well_formed());
return true;
}
bool sls_valuation::set_random_at_most(bvect const& src, bvect& tmp, random_gen& r) {
if (!get_at_most(src, tmp))
if (dst > m_lo)
return false;
if (is_zero(tmp) || (0 == r() % 2))
return try_set(tmp);
m_lo.copy_to(nw, dst);
SASSERT(can_set(dst));
return true;
}
bool sls_valuation::set_random_at_most(bvect const& src, random_gen& r) {
m_tmp.set_bw(bw);
if (!get_at_most(src, m_tmp))
return false;
if (is_zero(m_tmp) || (0 != r(10)))
return try_set(m_tmp);
set_random_below(tmp, r);
// random value below tmp
if (m_lo == m_hi || is_zero(m_lo) || m_lo <= tmp)
return try_set(tmp);
// for simplicity, bail out if we were not lucky
return get_at_most(src, tmp) && try_set(tmp);
set_random_below(m_tmp, r);
return (can_set(m_tmp) || get_at_most(src, m_tmp)) && try_set(m_tmp);
}
bool sls_valuation::set_random_at_least(bvect const& src, bvect& tmp, random_gen& r) {
if (!get_at_least(src, tmp))
bool sls_valuation::set_random_at_least(bvect const& src, random_gen& r) {
if (!get_at_least(src, m_tmp))
return false;
if (is_ones(tmp) || (0 == r() % 2))
return try_set(tmp);
if (is_ones(m_tmp) || (0 != r(10)))
return try_set(m_tmp);
// random value at least tmp
set_random_above(tmp, r);
if (m_lo == m_hi || is_zero(m_hi) || m_hi > tmp)
return try_set(tmp);
set_random_above(m_tmp, r);
// for simplicity, bail out if we were not lucky
return get_at_least(src, tmp) && try_set(tmp);
return (can_set(m_tmp) || get_at_least(src, m_tmp)) && try_set(m_tmp);
}
bool sls_valuation::set_random_in_range(bvect const& lo, bvect const& hi, bvect& tmp, random_gen& r) {
if (0 == r() % 2) {
bool sls_valuation::set_random_in_range(bvect const& lo, bvect const& hi, random_gen& r) {
bvect& tmp = m_tmp;
if (0 == r(2)) {
if (!get_at_least(lo, tmp))
return false;
SASSERT(in_range(tmp));
@ -344,7 +344,7 @@ namespace bv {
bool sls_valuation::set_repair(bool try_down, bvect& dst) {
for (unsigned i = 0; i < nw; ++i)
dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & m_bits[i]);
clear_overflow_bits(dst);
repair_sign_bits(dst);
if (in_range(dst)) {
set(eval, dst);
@ -409,6 +409,16 @@ namespace bv {
return bw;
}
unsigned sls_valuation::clz(bvect const& src) const {
SASSERT(!has_overflow(src));
unsigned i = bw;
for (; i-- > 0; )
if (!src.get(i))
return bw - 1 - i;
return bw;
}
void sls_valuation::set_value(bvect& bits, rational const& n) {
for (unsigned i = 0; i < bw; ++i)
bits.set(i, n.get_bit(i));
@ -433,14 +443,22 @@ namespace bv {
clear_overflow_bits(dst);
}
bool sls_valuation::set_random(random_gen& r) {
get_variant(m_tmp, r);
return set_repair(r(2) == 0, m_tmp);
}
void sls_valuation::repair_sign_bits(bvect& dst) const {
if (m_signed_prefix == 0)
return;
bool sign = dst.get(bw - 1);
for (unsigned i = bw; i-- >= bw - m_signed_prefix; ) {
bool sign = m_signed_prefix == bw ? dst.get(bw - 1) : dst.get(bw - m_signed_prefix - 1);
for (unsigned i = bw; i-- > bw - m_signed_prefix; ) {
if (dst.get(i) != sign) {
if (fixed.get(i)) {
for (unsigned i = bw; i-- >= bw - m_signed_prefix; )
unsigned j = bw - m_signed_prefix;
if (j > 0 && !fixed.get(j - 1))
dst.set(j - 1, !sign);
for (unsigned i = bw; i-- > bw - m_signed_prefix; )
if (!fixed.get(i))
dst.set(i, !sign);
return;
@ -453,7 +471,7 @@ namespace bv {
//
// new_bits != bits => ~fixed
// 0 = (new_bits ^ bits) & fixed
// 0 = (new_bits ^ bits) & fixedf
// also check that new_bits are in range
//
bool sls_valuation::can_set(bvect const& new_bits) const {
@ -464,24 +482,11 @@ namespace bv {
return in_range(new_bits);
}
unsigned sls_valuation::to_nat(unsigned max_n) {
unsigned sls_valuation::to_nat(unsigned max_n) const {
bvect const& d = m_bits;
SASSERT(!has_overflow(d));
SASSERT(max_n < UINT_MAX / 2);
unsigned p = 1;
unsigned value = 0;
for (unsigned i = 0; i < bw; ++i) {
if (p >= max_n) {
for (unsigned j = i; j < bw; ++j)
if (d.get(j))
return max_n;
return value;
}
if (d.get(i))
value += p;
p <<= 1;
}
return value;
return d.to_nat(max_n);
}
void sls_valuation::shift_right(bvect& out, unsigned shift) const {
@ -491,15 +496,16 @@ namespace bv {
SASSERT(well_formed());
}
void sls_valuation::add_range(rational l, rational h) {
void sls_valuation::add_range(rational l, rational h) {
//return;
//verbose_stream() << *this << " " << l << " " << h << " --> \n";
l = mod(l, rational::power_of_two(bw));
h = mod(h, rational::power_of_two(bw));
if (h == l)
return;
//verbose_stream() << "[" << l << ", " << h << "[\n";
//verbose_stream() << *this << "\n";
// verbose_stream() << *this << " " << l << " " << h << " --> ";
if (m_lo == m_hi) {
set_value(m_lo, l);
@ -509,32 +515,42 @@ namespace bv {
auto old_lo = lo();
auto old_hi = hi();
if (old_lo < old_hi) {
if (old_lo < l && l < old_hi)
if (old_lo < l && l < old_hi && old_hi <= h)
set_value(m_lo, l),
old_lo = l;
if (old_hi < h && h < old_hi)
if (l <= old_lo && old_lo < h && h < old_hi)
set_value(m_hi, h);
}
else {
SASSERT(old_hi < old_lo);
if (old_lo < l || l < old_hi)
set_value(m_lo, l),
old_lo = l;
if (old_lo < h && h < old_hi)
if (h <= old_hi && old_lo <= l) {
set_value(m_lo, l);
set_value(m_hi, h);
else if (old_hi < old_lo && (h < old_hi || old_lo < h))
}
else if (old_lo <= l && l <= h) {
set_value(m_lo, l);
set_value(m_hi, h);
}
else if (old_lo + 1 == l)
set_value(m_lo, l);
else if (old_hi == h + 1)
set_value(m_hi, h);
else if (old_hi == h && old_lo < l)
set_value(m_lo, l);
else if (old_lo == l && h < old_hi)
set_value(m_hi, h);
}
}
SASSERT(!has_overflow(m_lo));
SASSERT(!has_overflow(m_hi));
//verbose_stream() << *this << " --> ";
tighten_range();
//verbose_stream() << *this << "\n";
SASSERT(well_formed());
// verbose_stream() << *this << "\n";
}
//
@ -551,68 +567,88 @@ namespace bv {
// lo + 1 = hi -> set bits = lo
// lo < hi, set most significant bits based on hi
//
void sls_valuation::tighten_range() {
// verbose_stream() << "tighten " << *this << "\n";
unsigned sls_valuation::diff_index(bvect const& a) const {
unsigned index = 0;
for (unsigned i = nw; i-- > 0; ) {
auto diff = fixed[i] & (m_bits[i] ^ a[i]);
if (diff != 0 && index == 0)
index = 1 + i * 8 * sizeof(digit_t) + log2(diff);
}
return index;
}
void sls_valuation::inf_feasible(bvect& a) const {
unsigned lo_index = diff_index(a);
if (lo_index != 0) {
lo_index--;
SASSERT(a.get(lo_index) != m_bits.get(lo_index));
SASSERT(fixed.get(lo_index));
for (unsigned i = 0; i <= lo_index; ++i) {
if (!fixed.get(i))
a.set(i, false);
else if (fixed.get(i))
a.set(i, m_bits.get(i));
}
if (!a.get(lo_index)) {
for (unsigned i = lo_index + 1; i < bw; ++i)
if (!fixed.get(i) && !a.get(i)) {
a.set(i, true);
break;
}
}
}
}
void sls_valuation::sup_feasible(bvect& a) const {
unsigned hi_index = diff_index(a);
if (hi_index != 0) {
hi_index--;
SASSERT(a.get(hi_index) != m_bits.get(hi_index));
SASSERT(fixed.get(hi_index));
for (unsigned i = 0; i <= hi_index; ++i) {
if (!fixed.get(i))
a.set(i, true);
else if (fixed.get(i))
a.set(i, m_bits.get(i));
}
if (a.get(hi_index)) {
for (unsigned i = hi_index + 1; i < bw; ++i)
if (!fixed.get(i) && a.get(i)) {
a.set(i, false);
break;
}
}
}
}
void sls_valuation::tighten_range() {
if (m_lo == m_hi)
return;
if (!in_range(m_bits)) {
// verbose_stream() << "not in range\n";
bool compatible = true;
for (unsigned i = 0; i < nw && compatible; ++i)
compatible = 0 == (fixed[i] & (m_bits[i] ^ m_lo[i]));
//verbose_stream() << (fixed[0] & (m_bits[0] ^ m_lo[0])) << "\n";
//verbose_stream() << bw << " " << m_lo[0] << " " << m_bits[0] << "\n";
if (compatible) {
//verbose_stream() << "compatible\n";
set(m_bits, m_lo);
}
else {
bvect tmp(m_bits.nw);
tmp.set_bw(bw);
set(tmp, m_lo);
unsigned max_diff = bw;
for (unsigned i = 0; i < bw; ++i) {
if (fixed.get(i) && (m_bits.get(i) ^ m_lo.get(i)))
max_diff = i;
}
SASSERT(max_diff != bw);
inf_feasible(m_lo);
for (unsigned i = 0; i <= max_diff; ++i)
tmp.set(i, fixed.get(i) && m_bits.get(i));
bvect& hi1 = m_tmp;
hi1.set_bw(bw);
m_hi.copy_to(nw, hi1);
sub1(hi1);
sup_feasible(hi1);
add1(hi1);
hi1.copy_to(nw, m_hi);
bool found0 = false;
for (unsigned i = max_diff + 1; i < bw; ++i) {
if (found0 || m_lo.get(i) || fixed.get(i))
tmp.set(i, m_lo.get(i) && fixed.get(i));
else {
tmp.set(i, true);
found0 = true;
}
}
set(m_bits, tmp);
}
}
// update lo, hi to be feasible.
if (has_range() && !in_range(m_bits))
m_bits = m_lo;
if (mod(lo() + 1, rational::power_of_two(bw)) == hi())
for (unsigned i = 0; i < nw; ++i)
fixed[i] = ~0;
if (lo() < hi() && hi() < rational::power_of_two(bw - 1))
for (unsigned i = 0; i < bw; ++i)
if (hi() < rational::power_of_two(i))
fixed.set(i, true);
for (unsigned i = bw; i-- > 0; ) {
if (!fixed.get(i))
continue;
if (m_bits.get(i) == m_lo.get(i))
continue;
if (m_bits.get(i)) {
m_lo.set(i, true);
for (unsigned j = i; j-- > 0; )
m_lo.set(j, fixed.get(j) && m_bits.get(j));
}
else {
for (unsigned j = bw; j-- > 0; )
m_lo.set(j, fixed.get(j) && m_bits.get(j));
}
break;
}
SASSERT(well_formed());
}
@ -648,6 +684,4 @@ namespace bv {
c += get_num_1bits(src[i]);
return c == 1;
}
}

View file

@ -60,13 +60,27 @@ namespace bv {
return bw;
}
void set_zero() {
for (unsigned i = 0; i < nw; ++i)
(*this)[i] = 0;
}
bvect& set_shift_right(bvect const& a, bvect const& b);
bvect& set_shift_right(bvect const& a, unsigned shift);
bvect& set_shift_left(bvect const& a, bvect const& b);
rational get_value(unsigned nw) const;
unsigned to_nat(unsigned max_n) const;
friend bool operator==(bvect const& a, bvect const& b);
friend bool operator<(bvect const& a, bvect const& b);
friend bool operator>(bvect const& a, bvect const& b);
friend bool operator<=(bvect const& a, bvect const& b);
friend bool operator>=(bvect const& a, bvect const& b);
friend bool operator<=(digit_t a, bvect const& b);
friend bool operator<=(bvect const& a, digit_t b);
friend std::ostream& operator<<(std::ostream& out, bvect const& v);
private:
@ -96,11 +110,10 @@ namespace bv {
protected:
bvect m_bits;
bvect m_lo, m_hi; // range assignment to bit-vector, as wrap-around interval
bvect m_tmp;
unsigned m_signed_prefix = 0;
unsigned mask;
bool round_up(bvect& dst) const;
bool round_down(bvect& dst) const;
void repair_sign_bits(bvect& dst) const;
@ -111,6 +124,7 @@ namespace bv {
bvect fixed; // bit assignment and don't care bit
bvect eval; // current evaluation
sls_valuation(unsigned bw);
void set_bw(unsigned bw);
@ -127,9 +141,11 @@ namespace bv {
SASSERT(in_range(m_bits));
if (fixed.get(i) && get_bit(i) != b)
return false;
m_bits.set(i, b);
eval.set(i, b);
if (in_range(m_bits))
return true;
m_bits.set(i, !b);
eval.set(i, !b);
return false;
}
@ -141,6 +157,9 @@ namespace bv {
rational lo() const { return m_lo.get_value(nw); }
rational hi() const { return m_hi.get_value(nw); }
unsigned diff_index(bvect const& a) const;
void inf_feasible(bvect& a) const;
void sup_feasible(bvect& a) const;
void get(bvect& dst) const;
void add_range(rational lo, rational hi);
@ -198,6 +217,8 @@ namespace bv {
// most significant bit or bw if src = 0
unsigned msb(bvect const& src) const;
unsigned clz(bvect const& src) const;
bool is_power_of2(bvect const& src) const;
// retrieve largest number at or below (above) src which is feasible
@ -205,19 +226,21 @@ namespace bv {
bool get_at_most(bvect const& src, bvect& dst) const;
bool get_at_least(bvect const& src, bvect& dst) const;
bool set_random_at_most(bvect const& src, bvect& tmp, random_gen& r);
bool set_random_at_least(bvect const& src, bvect& tmp, random_gen& r);
bool set_random_in_range(bvect const& lo, bvect const& hi, bvect& tmp, random_gen& r);
bool set_random_at_most(bvect const& src, random_gen& r);
bool set_random_at_least(bvect const& src, random_gen& r);
bool set_random_in_range(bvect const& lo, bvect const& hi, random_gen& r);
bool set_repair(bool try_down, bvect& dst);
void set_random_above(bvect& dst, random_gen& r);
void set_random_below(bvect& dst, random_gen& r);
bool set_random(random_gen& r);
void round_down(bvect& dst, std::function<bool(bvect const&)> const& is_feasible);
void round_up(bvect& dst, std::function<bool(bvect const&)> const& is_feasible);
static digit_t random_bits(random_gen& r);
void get_variant(bvect& dst, random_gen& r) const;
bool try_set(bvect const& src) {
if (!can_set(src))
@ -232,7 +255,7 @@ namespace bv {
clear_overflow_bits(eval);
}
void set_zero(bvect& out) const {
void set_zero(bvect& out) const {
for (unsigned i = 0; i < nw; ++i)
out[i] = 0;
}
@ -258,6 +281,17 @@ namespace bv {
}
}
void add1(bvect& out) const {
for (unsigned i = 0; i < bw; ++i) {
if (!out.get(i)) {
out.set(i, true);
return;
}
else
out.set(i, false);
}
}
void set_sub(bvect& out, bvect const& a, bvect const& b) const;
bool set_add(bvect& out, bvect const& a, bvect const& b) const;
bool set_mul(bvect& out, bvect const& a, bvect const& b, bool check_overflow = true) const;
@ -288,7 +322,7 @@ namespace bv {
dst[i] = src[i];
}
unsigned to_nat(unsigned max_n);
unsigned to_nat(unsigned max_n) const;
std::ostream& display(std::ostream& out) const {
out << m_bits;