Skip to content

Commit

Permalink
n/a
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolajBjorner committed Mar 5, 2024
1 parent ddf2d28 commit 388b2f5
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 200 deletions.
10 changes: 10 additions & 0 deletions src/ast/bv_decl_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -942,3 +942,13 @@ app* bv_util::mk_int2bv(unsigned sz, expr* e) {
parameter p(sz);
return m_manager.mk_app(get_fid(), OP_INT2BV, 1, &p, 1, &e);
}

app* bv_util::mk_bv_rotate_left(expr* arg, unsigned n) {
parameter p(n);
return m_manager.mk_app(get_fid(), OP_ROTATE_LEFT, 1, &p, 1, &arg);
}

app* bv_util::mk_bv_rotate_right(expr* arg, unsigned n) {
parameter p(n);
return m_manager.mk_app(get_fid(), OP_ROTATE_RIGHT, 1, &p, 1, &arg);
}
5 changes: 5 additions & 0 deletions src/ast/bv_decl_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,11 @@ class bv_util : public bv_recognizers {
app * mk_bv2int(expr* e);
app * mk_int2bv(unsigned sz, expr* e);

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); }
app* mk_bv_rotate_left(expr* arg, unsigned n);
app* mk_bv_rotate_right(expr* arg, unsigned n);

// TODO: all these binary ops commute (right?) but it'd be more logical to swap `n` & `m` in the `return`
app * mk_bvsmul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_OVFL, n, m); }
app * mk_bvsmul_no_udfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_UDFL, n, m); }
Expand Down
74 changes: 40 additions & 34 deletions src/ast/sls/bv_sls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,46 +46,53 @@ namespace bv {
m_eval.init_fixed(m_terms.assertions());
}

std::pair<bool, app*> sls::next_to_repair() {
app* e = nullptr;
if (!m_repair_down.empty()) {
unsigned index = m_rand(m_repair_down.size());
e = m_terms.term(m_repair_down.elem_at(index));
}
else if (m_repair_up.empty()) {
unsigned index = m_rand(m_repair_up.size());
e = m_terms.term(m_repair_up.elem_at(index));
}
return { !m_repair_down.empty(), e };
}

lbool sls::operator()() {
// init and init_eval were invoked.
unsigned& n = m_stats.m_moves;
n = 0;
for (; n < m_config.m_max_repairs && m.inc(); ++n) {
if (!m_repair_down.empty()) {
unsigned index = m_rand(m_repair_down.size());
unsigned expr_id = m_repair_down.elem_at(index);
auto e = m_terms.term(expr_id);
IF_VERBOSE(20, verbose_stream() << "d " << mk_bounded_pp(e, m, 1) << "\n");
if (eval_is_correct(e))
m_repair_down.remove(expr_id);
auto [down, e] = next_to_repair();
if (!e)
return l_true;
IF_VERBOSE(20, verbose_stream() << (down?"d ":"u ") << mk_bounded_pp(e, m, 1) << "\n");
if (eval_is_correct(e)) {
if (down)
m_repair_down.remove(e->get_id());
else
try_repair_down(e);
m_repair_up.remove(e->get_id());
}
else if (!m_repair_up.empty()) {
unsigned index = m_rand(m_repair_up.size());
unsigned expr_id = m_repair_up.elem_at(index);
auto e = m_terms.term(expr_id);
IF_VERBOSE(20, verbose_stream() << "u " << mk_bounded_pp(e, m, 1) << "\n");
if (eval_is_correct(e))
m_repair_up.remove(expr_id);
else
try_repair_up(e);
else if (down) {
try_repair_down(e);
}
else
return l_true;
else
try_repair_up(e);
}
return l_undef;
}

bool sls::try_repair_down(app* e) {
void sls::try_repair_down(app* e) {
unsigned n = e->get_num_args();
if (n == 0)
return false;
unsigned s = m_rand(n);
for (unsigned i = 0; i < n; ++i)
if (try_repair_down(e, (i + s) % n))
return true;
return false;
if (n > 0) {
unsigned s = m_rand(n);
for (unsigned i = 0; i < n; ++i)
if (try_repair_down(e, (i + s) % n))
return;
}
m_repair_down.remove(e->get_id());
m_repair_up.insert(e->get_id());
}

bool sls::try_repair_down(app* e, unsigned i) {
Expand All @@ -99,17 +106,16 @@ namespace bv {
return was_repaired;
}

bool sls::try_repair_up(app* e) {
void sls::try_repair_up(app* e) {
m_repair_up.remove(e->get_id());
if (m_terms.is_assertion(e)) {
m_repair_down.insert(e->get_id());
return false;
}
m_eval.repair_up(e);
for (auto p : m_terms.parents(e))
m_repair_up.insert(p->get_id());

return true;
else {
m_eval.repair_up(e);
for (auto p : m_terms.parents(e))
m_repair_up.insert(p->get_id());
}
}

bool sls::eval_is_correct(app* e) {
Expand Down
5 changes: 3 additions & 2 deletions src/ast/sls/bv_sls.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ namespace bv {
random_gen m_rand;
config m_config;

std::pair<bool, app*> next_to_repair();

bool eval_is_correct(app* e);
bool try_repair_down(app* e);
bool try_repair_up(app* e);
void try_repair_down(app* e);
void try_repair_up(app* e);

bool try_repair_down(app* e, unsigned i);

Expand Down
37 changes: 20 additions & 17 deletions src/ast/sls/bv_sls_eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,16 +343,9 @@ namespace bv {
}
};

auto mk_rotate_left = [&](unsigned n) {
auto mk_rotate_left = [&](unsigned n) {
auto& a = wval0(e->get_arg(0));
if (n == 0 || a.bw == 1)
val.set(a.bits);
else {
for (unsigned i = a.bw - n; i < a.bw; ++i)
val.set(val.bits, i + n - a.bw, a.get(a.bits, i));
for (unsigned i = 0; i < a.bw - n; ++i)
val.set(val.bits, i + a.bw - n, a.get(a.bits, i));
}
VERIFY(try_repair_rotate_left(a, val, a.bw - n));
};

SASSERT(e->get_family_id() == bv.get_fid());
Expand Down Expand Up @@ -853,6 +846,7 @@ namespace bv {
auto child = e->get_arg(i);
auto ev = bval0(e);
if (m.is_bool(child)) {
SASSERT(!is_fixed0(child));
auto bv = bval0(e->get_arg(1 - i));
m_eval[child->get_id()] = ev == bv;
return true;
Expand All @@ -863,12 +857,21 @@ namespace bv {
if (ev)
return a.try_set(b.bits);
else {
// pick random bit to differ
for (unsigned i = 0; i < a.nw; ++i)
m_tmp[i] = a.bits[i];
unsigned idx = m_rand(a.bw);
a.set(m_tmp, idx, !b.get(b.bits, idx));
return a.try_set(m_tmp);
// pick random bit to differ
a.get(m_tmp);
unsigned start = m_rand(a.bw);
for (unsigned idx = 0; idx < a.bw; ++idx) {
unsigned j = (idx + start) % a.bw;
if (!a.get(a.fixed, j)) {
a.set(m_tmp, idx, !b.get(b.bits, j));
bool r = a.try_set(m_tmp);
if (r)
return true;
a.set(m_tmp, j, b.get(b.bits, j));
}
}
// could be due to bounds?
return false;
}
}
return false;
Expand Down Expand Up @@ -1107,9 +1110,9 @@ namespace bv {
return false;
}

bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) {
bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) const {
// a := rotate_right(e, n)
n = (n % a.bw) - n;
n = (a.bw - n) % a.bw;
for (unsigned i = a.bw - n; i < a.bw; ++i)
a.set(m_tmp, i + n - a.bw, e.get(e.bits, i));
for (unsigned i = 0; i < a.bw - n; ++i)
Expand Down
3 changes: 1 addition & 2 deletions src/ast/sls/bv_sls_eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,9 @@ namespace bv {
bool try_repair_smod(bvval const& e, bvval& a, bvval& b, unsigned i);
bool try_repair_urem(bvval const& e, bvval& a, bvval& b, unsigned i);
bool try_repair_srem(bvval const& e, bvval& a, bvval& b, unsigned i);
bool try_repair_rotate_left(bvval const& e, bvval& a, unsigned n);
bool try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) const;
bool try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i);


sls_valuation& wval0(app* e, unsigned i) { return wval0(e->get_arg(i)); }

void wval1(app* e, sls_valuation& val) const;
Expand Down
72 changes: 53 additions & 19 deletions src/ast/sls/sls_valuation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,27 @@ namespace bv {
for (unsigned i = 0; i < nw; ++i)
lo[i] = 0, hi[i] = 0, bits[i] = 0, fixed[i] = 0;
for (unsigned i = bw; i < 8 * sizeof(digit_t) * nw; ++i)
set(fixed, i, true);
set(fixed, i, false);
}

sls_valuation::~sls_valuation() {
}

bool sls_valuation::is_feasible() const {
return true;
mpn_manager m;
unsigned nb = (bw + 7) / 8;
auto c = m.compare(lo.data(), nb, hi.data(), nb);
bool sls_valuation::in_range(svector<digit_t> const& bits) const {
mpn_manager m;
auto c = m.compare(lo.data(), nw, hi.data(), nw);
// full range
if (c == 0)
return true;
// lo < hi: then lo <= bits & bits < hi
if (c < 0)
return
m.compare(lo.data(), nb, bits.data(), nb) <= 0 &&
m.compare(bits.data(), nb, hi.data(), nb) < 0;
return
m.compare(lo.data(), nb, bits.data(), nb) <= 0 ||
m.compare(bits.data(), nb, hi.data(), nb) < 0;
return
m.compare(lo.data(), nw, bits.data(), nw) <= 0 &&
m.compare(bits.data(), nw, hi.data(), nw) < 0;
// hi < lo: bits < hi or lo <= bits
return
m.compare(lo.data(), nw, bits.data(), nw) <= 0 ||
m.compare(bits.data(), nw, hi.data(), nw) < 0;
}

bool sls_valuation::eq(svector<digit_t> const& other) const {
Expand All @@ -65,11 +66,34 @@ namespace bv {
return true;
}

bool sls_valuation::gt(svector<digit_t> const& a, svector<digit_t> const& b) const {
mpn_manager m;
return m.compare(a.data(), nw, b.data(), nw) > 0;
}

void sls_valuation::clear_overflow_bits(svector<digit_t>& bits) const {
for (unsigned i = bw; i < nw * sizeof(digit_t) * 8; ++i)
set(bits, i, false);
}

bool sls_valuation::get_below(svector<digit_t> const& src, svector<digit_t>& dst) {
for (unsigned i = 0; i < nw; ++i)
dst[i] = (src[i] & ~fixed[i]) | (fixed[i] & bits[i]);
for (unsigned i = 0; i < nw; ++i)
dst[i] = fixed[i] & bits[i];
if (gt(dst, src))
return false;
if (!in_range(dst)) {
// lo < hi:
// set dst to lo, except for fixed bits
//
if (gt(hi, lo)) {

}
}
return true;
}

void sls_valuation::set_value(svector<digit_t>& bits, rational const& n) {
for (unsigned i = 0; i < bw; ++i)
set(bits, i, n.get_bit(i));
Expand All @@ -94,11 +118,16 @@ namespace bv {
set(bits, i, true);
}

bool sls_valuation::can_set(svector<digit_t> const& new_bits) const {
//
// new_bits != bits => ~fixed
// 0 = (new_bits ^ bits) & fixed
// also check that new_bits are in range
//
bool sls_valuation::can_set(svector<digit_t> const& new_bits) const {
for (unsigned i = 0; i < nw; ++i)
if (bits[i] != ((new_bits[i] & ~fixed[i]) | (bits[i] & fixed[i])))
return true;
return false;
if (0 != ((new_bits[i] ^ bits[i]) & fixed[i]))
return false;
return in_range(new_bits);
}

unsigned sls_valuation::to_nat(svector<digit_t> const& d, unsigned max_n) {
Expand All @@ -124,10 +153,15 @@ namespace bv {
h = mod(h, rational::power_of_two(bw));
if (h == l)
return;
set_value(this->lo, l);
set_value(this->hi, h);
if (eq(lo, hi)) {
set_value(lo, l);
set_value(hi, h);
return;
}

// TODO: intersect with previous range, if any

set_value(lo, l);
set_value(hi, h);
}

}
21 changes: 11 additions & 10 deletions src/ast/sls/sls_valuation.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ Module Name:
namespace bv {

struct sls_valuation {
unsigned bw; // bit-width
unsigned nw; // num words
svector<digit_t> lo, hi; // range assignment to bit-vector, as wrap-around interval
unsigned bw; // bit-width
unsigned nw; // num words
svector<digit_t> lo, hi; // range assignment to bit-vector, as wrap-around interval
svector<digit_t> bits, fixed; // bit assignment and don't care bit
bool is_feasible() const; // the current bit-evaluation is between lo and hi.
sls_valuation(unsigned bw);
~sls_valuation();

Expand All @@ -44,17 +43,15 @@ namespace bv {
void add_range(rational lo, rational hi);
void set1(svector<digit_t>& bits);


void clear_overflow_bits(svector<digit_t>& bits) const;
bool in_range(svector<digit_t> const& bits) const;
bool can_set(svector<digit_t> const& bits) const;

bool eq(sls_valuation const& other) const { return eq(other.bits); }

bool eq(svector<digit_t> const& other) const;

bool gt(svector<digit_t> const& a, svector<digit_t> const& b) const {
return 0 > memcmp(a.data(), b.data(), num_bytes());
}
bool eq(svector<digit_t> const& other) const { return eq(other, bits); }
bool eq(svector<digit_t> const& a, svector<digit_t> const& b) const;
bool gt(svector<digit_t> const& a, svector<digit_t> const& b) const;

bool is_zero() const { return is_zero(bits); }
bool is_zero(svector<digit_t> const& a) const {
Expand All @@ -79,6 +76,10 @@ namespace bv {
return i;
}

// retrieve number at or below src which is feasible
// with respect to fixed, lo, hi.
bool get_below(svector<digit_t> const& src, svector<digit_t>& dst);

bool try_set(svector<digit_t> const& src) {
if (!can_set(src))
return false;
Expand Down
Loading

0 comments on commit 388b2f5

Please sign in to comment.