mirror of
https://github.com/Z3Prover/z3
synced 2025-06-18 11:58:31 +00:00
hoist out fixed-bits reasoning into self-contained module
without dependencies on viable entries
This commit is contained in:
parent
658f079efd
commit
b1072d0a1c
8 changed files with 183 additions and 158 deletions
|
@ -145,7 +145,7 @@ namespace polysat {
|
||||||
* Viable
|
* Viable
|
||||||
*/
|
*/
|
||||||
void get_bitvector_suffixes(pvar v, offset_slices& out);
|
void get_bitvector_suffixes(pvar v, offset_slices& out);
|
||||||
void get_fixed_bits(pvar v, fixed_bits_vector& fixed_bits);
|
void get_fixed_bits(pvar v, fixed_bits_vector& fixed_slice);
|
||||||
void get_subslices(pvar v, offset_slices& out);
|
void get_subslices(pvar v, offset_slices& out);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -13,14 +13,95 @@ Author:
|
||||||
|
|
||||||
#include "sat/smt/polysat/fixed_bits.h"
|
#include "sat/smt/polysat/fixed_bits.h"
|
||||||
#include "sat/smt/polysat/ule_constraint.h"
|
#include "sat/smt/polysat/ule_constraint.h"
|
||||||
|
#include "sat/smt/polysat/core.h"
|
||||||
|
|
||||||
namespace polysat {
|
namespace polysat {
|
||||||
|
|
||||||
|
// reset with fixed bits information for variable v
|
||||||
|
void fixed_bits::reset(pvar v) {
|
||||||
|
m_fixed_slices.reset();
|
||||||
|
m_var = v;
|
||||||
|
m_fixed.reset();
|
||||||
|
m_fixed.resize(c.size(v), l_undef);
|
||||||
|
m_bits.reserve(c.size(v));
|
||||||
|
fixed_bits_vector fbs;
|
||||||
|
c.get_fixed_bits(v, fbs);
|
||||||
|
for (auto const& fb : fbs)
|
||||||
|
for (unsigned i = fb.lo; i <= fb.hi; ++i)
|
||||||
|
m_fixed[i] = to_lbool(fb.value.get_bit(i - fb.lo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// find then next value >= val that agrees with fixed bits, or false if none exists within the maximal value for val.
|
||||||
|
// examples
|
||||||
|
// fixed bits: 1?0 (least significant bit is last)
|
||||||
|
// val: 101
|
||||||
|
// next: 110
|
||||||
|
|
||||||
|
// fixed bits ?1?0
|
||||||
|
// val 1011
|
||||||
|
// next 1100
|
||||||
|
|
||||||
|
// algorith: Let i be the most significant index where fixed bits disagree with val.
|
||||||
|
// If m_fixed[i] == l_true; then updating val to mask by fixed bits sufficies.
|
||||||
|
// Otherwise, the range above the disagreement has to be incremented.
|
||||||
|
// Increment the non-fixed bits by 1
|
||||||
|
// The first non-fixed 0 position is set to 1, non-fixed positions below are set to 0.s
|
||||||
|
// If there are none, then the value is maximal and we return false.
|
||||||
|
|
||||||
|
bool fixed_bits::next(rational& val) {
|
||||||
|
if (m_fixed_slices.empty())
|
||||||
|
return true;
|
||||||
|
unsigned sz = c.size(m_var);
|
||||||
|
for (unsigned i = 0; i < sz; ++i)
|
||||||
|
m_bits[i] = val.get_bit(i);
|
||||||
|
unsigned i = sz;
|
||||||
|
for (; i-- > 0; )
|
||||||
|
if (m_fixed[i] != l_undef && m_fixed[i] != to_lbool(m_bits[i]))
|
||||||
|
break;
|
||||||
|
if (i == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (unsigned j = 0; j < sz; ++j) {
|
||||||
|
if (m_fixed[j] != l_undef)
|
||||||
|
m_bits[j] = m_fixed[j] == l_true;
|
||||||
|
else if (j < i)
|
||||||
|
m_bits[j] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_fixed[i] == l_false) {
|
||||||
|
for (; i < sz; ++i) {
|
||||||
|
if (m_fixed[i] != l_undef)
|
||||||
|
continue;
|
||||||
|
if (m_bits[i])
|
||||||
|
m_bits[i] = false;
|
||||||
|
else {
|
||||||
|
m_bits[i] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// overflow
|
||||||
|
if (i == sz)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
val = 0;
|
||||||
|
for (unsigned i = sz; i-- > 0;)
|
||||||
|
val = val * 2 + rational(m_bits[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// explain the fixed bits ranges.
|
||||||
|
dependency_vector fixed_bits::explain() {
|
||||||
|
dependency_vector result;
|
||||||
|
for (auto const& slice : m_fixed_slices)
|
||||||
|
result.push_back(dependency({ m_var, slice }));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 2^k * x = 2^k * b
|
* 2^k * x = 2^k * b
|
||||||
* ==> x[N-k-1:0] = b[N-k-1:0]
|
* ==> x[N-k-1:0] = b[N-k-1:0]
|
||||||
*/
|
*/
|
||||||
bool get_eq_fixed_lsb(pdd const& p, fixed_bits& out) {
|
bool get_eq_fixed_lsb(pdd const& p, fixed_slice& out) {
|
||||||
SASSERT(!p.is_val());
|
SASSERT(!p.is_val());
|
||||||
unsigned const N = p.power_of_2();
|
unsigned const N = p.power_of_2();
|
||||||
// Recognize p = 2^k * a * x - 2^k * b
|
// Recognize p = 2^k * a * x - 2^k * b
|
||||||
|
@ -39,7 +120,7 @@ namespace polysat {
|
||||||
if (d.parity(N) < k)
|
if (d.parity(N) < k)
|
||||||
return false;
|
return false;
|
||||||
rational const b = machine_div2k(d, k);
|
rational const b = machine_div2k(d, k);
|
||||||
out = fixed_bits(N - k - 1, 0, b);
|
out = fixed_slice(N - k - 1, 0, b);
|
||||||
SASSERT_EQ(d, b * rational::power_of_two(k));
|
SASSERT_EQ(d, b * rational::power_of_two(k));
|
||||||
SASSERT_EQ(p, (p.manager().mk_var(p.var()) - out.value) * rational::power_of_two(k));
|
SASSERT_EQ(p, (p.manager().mk_var(p.var()) - out.value) * rational::power_of_two(k));
|
||||||
return true;
|
return true;
|
||||||
|
@ -66,7 +147,7 @@ namespace polysat {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_eq_fixed_bits(pdd const& p, fixed_bits& out) {
|
bool get_eq_fixed_slice(pdd const& p, fixed_slice& out) {
|
||||||
if (get_eq_fixed_lsb(p, out))
|
if (get_eq_fixed_lsb(p, out))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
|
@ -80,7 +161,7 @@ namespace polysat {
|
||||||
* ==> x[1:0] = 1
|
* ==> x[1:0] = 1
|
||||||
* -- TODO: Generalize [the obvious solution does not work]
|
* -- TODO: Generalize [the obvious solution does not work]
|
||||||
*/
|
*/
|
||||||
bool get_ule_fixed_lsb(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_bits& out) {
|
bool get_ule_fixed_lsb(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_slice& out) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +171,7 @@ namespace polysat {
|
||||||
* x <= 2^k - 1 ==> x[N-1:k] = 0
|
* x <= 2^k - 1 ==> x[N-1:k] = 0
|
||||||
* x < 2^k ==> x[N-1:k] = 0
|
* x < 2^k ==> x[N-1:k] = 0
|
||||||
*/
|
*/
|
||||||
bool get_ule_fixed_msb(pdd const& p, pdd const& q, bool is_positive, fixed_bits& out) {
|
bool get_ule_fixed_msb(pdd const& p, pdd const& q, bool is_positive, fixed_slice& out) {
|
||||||
SASSERT(!q.is_zero()); // equalities are handled elsewhere
|
SASSERT(!q.is_zero()); // equalities are handled elsewhere
|
||||||
unsigned const N = p.power_of_2();
|
unsigned const N = p.power_of_2();
|
||||||
pdd const& lhs = is_positive ? p : q;
|
pdd const& lhs = is_positive ? p : q;
|
||||||
|
@ -117,14 +198,14 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2^(N-1) <= 2^(N-1-i) * x
|
// 2^(N-1) <= 2^(N-1-i) * x
|
||||||
bool get_ule_fixed_bit(pdd const& p, pdd const& q, bool is_positive, fixed_bits& out) {
|
bool get_ule_fixed_bit(pdd const& p, pdd const& q, bool is_positive, fixed_slice& out) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_ule_fixed_bits(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_bits& out) {
|
bool get_ule_fixed_slice(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_slice& out) {
|
||||||
SASSERT(ule_constraint::is_simplified(lhs, rhs));
|
SASSERT(ule_constraint::is_simplified(lhs, rhs));
|
||||||
if (rhs.is_zero())
|
if (rhs.is_zero())
|
||||||
return is_positive ? get_eq_fixed_bits(lhs, out) : false;
|
return is_positive ? get_eq_fixed_slice(lhs, out) : false;
|
||||||
if (get_ule_fixed_msb(lhs, rhs, is_positive, out))
|
if (get_ule_fixed_msb(lhs, rhs, is_positive, out))
|
||||||
return true;
|
return true;
|
||||||
if (get_ule_fixed_lsb(lhs, rhs, is_positive, out))
|
if (get_ule_fixed_lsb(lhs, rhs, is_positive, out))
|
||||||
|
@ -134,10 +215,10 @@ namespace polysat {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_fixed_bits(signed_constraint c, fixed_bits& out) {
|
bool get_fixed_slice(signed_constraint c, fixed_slice& out) {
|
||||||
SASSERT_EQ(c.vars().size(), 1); // this only makes sense for univariate constraints
|
SASSERT_EQ(c.vars().size(), 1); // this only makes sense for univariate constraints
|
||||||
if (c.is_ule())
|
if (c.is_ule())
|
||||||
return get_ule_fixed_bits(c.to_ule().lhs(), c.to_ule().rhs(), c.is_positive(), out);
|
return get_ule_fixed_slice(c.to_ule().lhs(), c.to_ule().rhs(), c.is_positive(), out);
|
||||||
// if (c->is_op())
|
// if (c->is_op())
|
||||||
// ; // TODO: x & constant = constant ==> bitmask ... but we have trouble recognizing that because we introduce a new variable for '&' before we see the equality.
|
// ; // TODO: x & constant = constant ==> bitmask ... but we have trouble recognizing that because we introduce a new variable for '&' before we see the equality.
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -17,13 +17,33 @@ Author:
|
||||||
|
|
||||||
namespace polysat {
|
namespace polysat {
|
||||||
|
|
||||||
bool get_eq_fixed_lsb(pdd const& p, fixed_bits& out);
|
class core;
|
||||||
bool get_eq_fixed_bits(pdd const& p, fixed_bits& out);
|
|
||||||
|
|
||||||
bool get_ule_fixed_lsb(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_bits& out);
|
bool get_eq_fixed_lsb(pdd const& p, fixed_slice& out);
|
||||||
bool get_ule_fixed_msb(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_bits& out);
|
bool get_eq_fixed_slice(pdd const& p, fixed_slice& out);
|
||||||
bool get_ule_fixed_bit(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_bits& out);
|
|
||||||
bool get_ule_fixed_bits(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_bits& out);
|
|
||||||
bool get_fixed_bits(signed_constraint c, fixed_bits& out);
|
|
||||||
|
|
||||||
|
bool get_ule_fixed_lsb(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_slice& out);
|
||||||
|
bool get_ule_fixed_msb(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_slice& out);
|
||||||
|
bool get_ule_fixed_bit(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_slice& out);
|
||||||
|
bool get_ule_fixed_slice(pdd const& lhs, pdd const& rhs, bool is_positive, fixed_slice& out);
|
||||||
|
bool get_fixed_slice(signed_constraint c, fixed_slice& out);
|
||||||
|
|
||||||
|
class fixed_bits {
|
||||||
|
core& c;
|
||||||
|
pvar m_var = null_var;
|
||||||
|
vector<fixed_slice> m_fixed_slices;
|
||||||
|
svector<lbool> m_fixed;
|
||||||
|
bool_vector m_bits;
|
||||||
|
public:
|
||||||
|
fixed_bits(core& c) : c(c) {}
|
||||||
|
|
||||||
|
// reset with fixed bits information for variable v
|
||||||
|
void reset(pvar v);
|
||||||
|
|
||||||
|
// find then next value >= val that agrees with fixed bits, or false if none exists within the maximal value for val.
|
||||||
|
bool next(rational& val);
|
||||||
|
|
||||||
|
// explain the fixed bits ranges.
|
||||||
|
dependency_vector explain();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,24 +34,46 @@ namespace polysat {
|
||||||
|
|
||||||
class signed_constraint;
|
class signed_constraint;
|
||||||
|
|
||||||
|
struct fixed_slice {
|
||||||
|
unsigned hi = 0;
|
||||||
|
unsigned lo = 0;
|
||||||
|
rational value;
|
||||||
|
fixed_slice() = default;
|
||||||
|
fixed_slice(unsigned hi, unsigned lo, rational value) : hi(hi), lo(lo), value(value) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fixed_claim : public fixed_slice {
|
||||||
|
pvar v;
|
||||||
|
fixed_claim() = default;
|
||||||
|
fixed_claim(pvar v, unsigned hi, unsigned lo, rational value) : fixed_slice(hi, lo, value), v(v) {}
|
||||||
|
fixed_claim(pvar, fixed_slice const& s) : fixed_slice(s), v(v) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct offset_slice {
|
||||||
|
pvar v;
|
||||||
|
unsigned offset;
|
||||||
|
};
|
||||||
|
|
||||||
class dependency {
|
class dependency {
|
||||||
struct axiom_t {};
|
struct axiom_t {};
|
||||||
std::variant<axiom_t, sat::bool_var, theory_var_pair, offset_claim> m_data;
|
std::variant<axiom_t, sat::bool_var, theory_var_pair, offset_claim, fixed_claim> m_data;
|
||||||
dependency(): m_data(axiom_t()) {}
|
dependency(): m_data(axiom_t()) {}
|
||||||
public:
|
public:
|
||||||
dependency(sat::bool_var v) : m_data(v){}
|
dependency(sat::bool_var v) : m_data(v){}
|
||||||
dependency(theory_var v1, theory_var v2) : m_data(std::make_pair(v1, v2)) {}
|
dependency(theory_var v1, theory_var v2) : m_data(std::make_pair(v1, v2)) {}
|
||||||
dependency(offset_claim const& c) : m_data(c) {}
|
dependency(offset_claim const& c) : m_data(c) {}
|
||||||
|
dependency(fixed_claim const& c): m_data(c) {}
|
||||||
static dependency axiom() { return dependency(); }
|
static dependency axiom() { return dependency(); }
|
||||||
bool is_null() const { return is_bool_var() && *std::get_if<sat::bool_var>(&m_data) == sat::null_bool_var; }
|
bool is_null() const { return is_bool_var() && *std::get_if<sat::bool_var>(&m_data) == sat::null_bool_var; }
|
||||||
bool is_axiom() const { return std::holds_alternative<axiom_t>(m_data); }
|
bool is_axiom() const { return std::holds_alternative<axiom_t>(m_data); }
|
||||||
bool is_eq() const { return std::holds_alternative<theory_var_pair>(m_data); }
|
bool is_eq() const { return std::holds_alternative<theory_var_pair>(m_data); }
|
||||||
bool is_bool_var() const { return std::holds_alternative<sat::bool_var>(m_data); }
|
bool is_bool_var() const { return std::holds_alternative<sat::bool_var>(m_data); }
|
||||||
bool is_offset_claim() const { return std::holds_alternative<offset_claim>(m_data); }
|
bool is_offset_claim() const { return std::holds_alternative<offset_claim>(m_data); }
|
||||||
|
bool is_fixed_claim() const { return std::holds_alternative<fixed_claim>(m_data); }
|
||||||
sat::bool_var bool_var() const { SASSERT(is_bool_var()); return *std::get_if<sat::bool_var>(&m_data); }
|
sat::bool_var bool_var() const { SASSERT(is_bool_var()); return *std::get_if<sat::bool_var>(&m_data); }
|
||||||
theory_var_pair eq() const { SASSERT(is_eq()); return *std::get_if<theory_var_pair>(&m_data); }
|
theory_var_pair eq() const { SASSERT(is_eq()); return *std::get_if<theory_var_pair>(&m_data); }
|
||||||
offset_claim offset() const { return *std::get_if<offset_claim>(&m_data); }
|
offset_claim offset() const { return *std::get_if<offset_claim>(&m_data); }
|
||||||
|
fixed_claim fixed() const { return *std::get_if<fixed_claim>(&m_data); }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const dependency null_dependency = dependency(sat::null_bool_var);
|
inline const dependency null_dependency = dependency(sat::null_bool_var);
|
||||||
|
@ -72,24 +94,12 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct fixed_bits {
|
|
||||||
unsigned hi = 0;
|
|
||||||
unsigned lo = 0;
|
|
||||||
rational value;
|
|
||||||
fixed_bits() = default;
|
|
||||||
fixed_bits(unsigned hi, unsigned lo, rational value) : hi(hi), lo(lo), value(value) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct offset_slice {
|
|
||||||
pvar v;
|
|
||||||
unsigned offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& out, offset_slice const& js) {
|
inline std::ostream& operator<<(std::ostream& out, offset_slice const& js) {
|
||||||
return out << "v" << js.v << "[" << js.offset << "[ @";
|
return out << "v" << js.v << "[" << js.offset << "[ @";
|
||||||
}
|
}
|
||||||
|
|
||||||
using fixed_bits_vector = svector<fixed_bits>;
|
using fixed_bits_vector = svector<fixed_slice>;
|
||||||
|
|
||||||
using dependency_vector = vector<dependency>;
|
using dependency_vector = vector<dependency>;
|
||||||
using constraint_or_dependency = std::variant<signed_constraint, dependency>;
|
using constraint_or_dependency = std::variant<signed_constraint, dependency>;
|
||||||
|
@ -118,7 +128,7 @@ namespace polysat {
|
||||||
virtual void get_bitvector_suffixes(pvar v, offset_slices& out) = 0;
|
virtual void get_bitvector_suffixes(pvar v, offset_slices& out) = 0;
|
||||||
virtual void get_bitvector_sub_slices(pvar v, offset_slices& out) = 0;
|
virtual void get_bitvector_sub_slices(pvar v, offset_slices& out) = 0;
|
||||||
virtual void get_bitvector_super_slices(pvar v, offset_slices& out) = 0;
|
virtual void get_bitvector_super_slices(pvar v, offset_slices& out) = 0;
|
||||||
virtual void get_fixed_bits(pvar v, fixed_bits_vector& fixed_bits) = 0;
|
virtual void get_fixed_bits(pvar v, fixed_bits_vector& fixed_slice) = 0;
|
||||||
virtual unsigned level(dependency const& d) = 0;
|
virtual unsigned level(dependency const& d) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace polysat {
|
||||||
|
|
||||||
using dd::val_pp;
|
using dd::val_pp;
|
||||||
|
|
||||||
viable::viable(core& c) : c(c), cs(c.cs()), m_forbidden_intervals(c) {}
|
viable::viable(core& c) : c(c), cs(c.cs()), m_forbidden_intervals(c), m_fixed_bits(c) {}
|
||||||
|
|
||||||
viable::~viable() {
|
viable::~viable() {
|
||||||
for (auto* e : m_alloc)
|
for (auto* e : m_alloc)
|
||||||
|
@ -123,7 +123,7 @@ namespace polysat {
|
||||||
|
|
||||||
lbool viable::find_viable(pvar v, rational& lo, rational& hi) {
|
lbool viable::find_viable(pvar v, rational& lo, rational& hi) {
|
||||||
m_explain.reset();
|
m_explain.reset();
|
||||||
init_fixed_bits(v);
|
m_fixed_bits.reset(v);
|
||||||
init_overlays(v);
|
init_overlays(v);
|
||||||
return l_undef;
|
return l_undef;
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ namespace polysat {
|
||||||
rational const& max_value = c.var2pdd(v).max_value();
|
rational const& max_value = c.var2pdd(v).max_value();
|
||||||
|
|
||||||
|
|
||||||
lbool r = find_on_layers(v, m_widths, m_overlaps, m_fbi, rational::zero(), max_value, lo);
|
lbool r = find_on_layers(v, m_widths, m_overlaps, rational::zero(), max_value, lo);
|
||||||
if (r != l_true)
|
if (r != l_true)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ namespace polysat {
|
||||||
return l_true;
|
return l_true;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = find_on_layers(v, m_widths, m_overlaps, m_fbi, lo + 1, max_value, hi);
|
r = find_on_layers(v, m_widths, m_overlaps, lo + 1, max_value, hi);
|
||||||
|
|
||||||
if (r != l_false)
|
if (r != l_false)
|
||||||
return r;
|
return r;
|
||||||
|
@ -156,7 +156,6 @@ namespace polysat {
|
||||||
pvar const v,
|
pvar const v,
|
||||||
unsigned_vector const& widths,
|
unsigned_vector const& widths,
|
||||||
offset_slices const& overlaps,
|
offset_slices const& overlaps,
|
||||||
fixed_bits_info const& fbi,
|
|
||||||
rational const& to_cover_lo,
|
rational const& to_cover_lo,
|
||||||
rational const& to_cover_hi,
|
rational const& to_cover_hi,
|
||||||
rational& val) {
|
rational& val) {
|
||||||
|
@ -169,7 +168,7 @@ namespace polysat {
|
||||||
|
|
||||||
while (refinements--) {
|
while (refinements--) {
|
||||||
m_explain.shrink(explain_size);
|
m_explain.shrink(explain_size);
|
||||||
lbool result = find_on_layer(v, widths.size() - 1, widths, overlaps, fbi, to_cover_lo, to_cover_hi, val, refine_todo);
|
lbool result = find_on_layer(v, widths.size() - 1, widths, overlaps, to_cover_lo, to_cover_hi, val, refine_todo);
|
||||||
|
|
||||||
// store bit-intervals we have used
|
// store bit-intervals we have used
|
||||||
for (entry* e : refine_todo)
|
for (entry* e : refine_todo)
|
||||||
|
@ -183,6 +182,7 @@ namespace polysat {
|
||||||
// start refinement on smallest variable
|
// start refinement on smallest variable
|
||||||
// however, we probably should rotate to avoid getting stuck in refinement loop on a 'bad' constraint
|
// however, we probably should rotate to avoid getting stuck in refinement loop on a 'bad' constraint
|
||||||
bool refined = false;
|
bool refined = false;
|
||||||
|
#if 0
|
||||||
for (unsigned i = overlaps.size(); i-- > 0; ) {
|
for (unsigned i = overlaps.size(); i-- > 0; ) {
|
||||||
pvar x = overlaps[i].v;
|
pvar x = overlaps[i].v;
|
||||||
rational const& mod_value = c.var2pdd(x).two_to_N();
|
rational const& mod_value = c.var2pdd(x).two_to_N();
|
||||||
|
@ -192,6 +192,7 @@ namespace polysat {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!refined)
|
if (!refined)
|
||||||
return l_true;
|
return l_true;
|
||||||
|
@ -210,7 +211,6 @@ namespace polysat {
|
||||||
unsigned const w_idx,
|
unsigned const w_idx,
|
||||||
unsigned_vector const& widths,
|
unsigned_vector const& widths,
|
||||||
offset_slices const& overlaps,
|
offset_slices const& overlaps,
|
||||||
fixed_bits_info const& fbi,
|
|
||||||
rational const& to_cover_lo,
|
rational const& to_cover_lo,
|
||||||
rational const& to_cover_hi,
|
rational const& to_cover_hi,
|
||||||
rational& val,
|
rational& val,
|
||||||
|
@ -283,6 +283,7 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
// when we cannot make progress by existing intervals any more, try interval from fixed bits
|
// when we cannot make progress by existing intervals any more, try interval from fixed bits
|
||||||
if (!e) {
|
if (!e) {
|
||||||
e = refine_bits<true>(v, val, w, fbi);
|
e = refine_bits<true>(v, val, w, fbi);
|
||||||
|
@ -291,6 +292,7 @@ namespace polysat {
|
||||||
display_one(std::cerr << "found entry by bits: ", 0, e) << "\n";
|
display_one(std::cerr << "found entry by bits: ", 0, e) << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// no more progress on current layer
|
// no more progress on current layer
|
||||||
if (!e)
|
if (!e)
|
||||||
|
@ -346,6 +348,7 @@ namespace polysat {
|
||||||
if (distance(val, n, mod_value) < distance(val, next_val, mod_value))
|
if (distance(val, n, mod_value) < distance(val, next_val, mod_value))
|
||||||
next_val = n;
|
next_val = n;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
if (entry* e = refine_bits<false>(v, next_val, w, fbi)) {
|
if (entry* e = refine_bits<false>(v, next_val, w, fbi)) {
|
||||||
refine_todo.push_back(e);
|
refine_todo.push_back(e);
|
||||||
rational const& n = e->interval.lo_val();
|
rational const& n = e->interval.lo_val();
|
||||||
|
@ -353,6 +356,7 @@ namespace polysat {
|
||||||
next_val = n;
|
next_val = n;
|
||||||
}
|
}
|
||||||
SASSERT(!refine_bits<true>(v, val, w, fbi));
|
SASSERT(!refine_bits<true>(v, val, w, fbi));
|
||||||
|
#endif
|
||||||
SASSERT(val != next_val);
|
SASSERT(val != next_val);
|
||||||
|
|
||||||
unsigned const lower_w = widths[w_idx - 1];
|
unsigned const lower_w = widths[w_idx - 1];
|
||||||
|
@ -366,7 +370,7 @@ namespace polysat {
|
||||||
lower_cover_lo = 0;
|
lower_cover_lo = 0;
|
||||||
lower_cover_hi = lower_mod_value;
|
lower_cover_hi = lower_mod_value;
|
||||||
rational a;
|
rational a;
|
||||||
lbool result = find_on_layer(v, w_idx - 1, widths, overlaps, fbi, lower_cover_lo, lower_cover_hi, a, refine_todo);
|
lbool result = find_on_layer(v, w_idx - 1, widths, overlaps, lower_cover_lo, lower_cover_hi, a, refine_todo);
|
||||||
VERIFY(result != l_undef);
|
VERIFY(result != l_undef);
|
||||||
if (result == l_false) {
|
if (result == l_false) {
|
||||||
SASSERT(c.inconsistent());
|
SASSERT(c.inconsistent());
|
||||||
|
@ -388,7 +392,7 @@ namespace polysat {
|
||||||
lower_cover_hi = mod(next_val, lower_mod_value);
|
lower_cover_hi = mod(next_val, lower_mod_value);
|
||||||
|
|
||||||
rational a;
|
rational a;
|
||||||
lbool result = find_on_layer(v, w_idx - 1, widths, overlaps, fbi, lower_cover_lo, lower_cover_hi, a, refine_todo);
|
lbool result = find_on_layer(v, w_idx - 1, widths, overlaps, lower_cover_lo, lower_cover_hi, a, refine_todo);
|
||||||
if (result == l_false) {
|
if (result == l_false) {
|
||||||
SASSERT(c.inconsistent());
|
SASSERT(c.inconsistent());
|
||||||
return l_false; // conflict
|
return l_false; // conflict
|
||||||
|
@ -431,38 +435,6 @@ namespace polysat {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true iff no conflict was encountered
|
|
||||||
bool viable::collect_bit_information(pvar v, bool add_conflict, fixed_bits_info& out_fbi) {
|
|
||||||
|
|
||||||
pdd p = c.var(v);
|
|
||||||
unsigned const v_sz = c.size(v);
|
|
||||||
out_fbi.reset(v_sz);
|
|
||||||
auto& [fixed, just_src, just_side_cond, just_slice] = out_fbi;
|
|
||||||
|
|
||||||
fixed_bits_vector fbs;
|
|
||||||
c.get_fixed_bits(v, fbs);
|
|
||||||
|
|
||||||
for (auto const& fb : fbs) {
|
|
||||||
LOG("slicing fixed bits: v" << v << "[" << fb.hi << ":" << fb.lo << "] = " << fb.value);
|
|
||||||
for (unsigned i = fb.lo; i <= fb.hi; ++i) {
|
|
||||||
SASSERT(out_fbi.just_src[i].empty()); // since we don't get overlapping ranges from collect_fixed.
|
|
||||||
SASSERT(out_fbi.just_side_cond[i].empty());
|
|
||||||
SASSERT(out_fbi.just_slicing[i].empty());
|
|
||||||
out_fbi.fixed[i] = to_lbool(fb.value.get_bit(i - fb.lo));
|
|
||||||
out_fbi.just_slicing[i].push_back(fb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entry* e1 = m_equal_lin[v];
|
|
||||||
entry* e2 = m_units[v].get_entries(c.size(v)); // TODO: take other widths into account (will be done automatically by tracking fixed bits in the slicing egraph)
|
|
||||||
entry* first = e1;
|
|
||||||
if (!e1 && !e2)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Explain why the current variable is not viable or signleton.
|
* Explain why the current variable is not viable or signleton.
|
||||||
*/
|
*/
|
||||||
|
@ -474,7 +446,7 @@ namespace polysat {
|
||||||
result.push_back(d);
|
result.push_back(d);
|
||||||
result.append(c.explain_eval(sc));
|
result.append(c.explain_eval(sc));
|
||||||
}
|
}
|
||||||
// TODO: explaination for fixed bits
|
result.append(m_fixed_bits.explain());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@ Author:
|
||||||
|
|
||||||
#include "sat/smt/polysat/types.h"
|
#include "sat/smt/polysat/types.h"
|
||||||
#include "sat/smt/polysat/forbidden_intervals.h"
|
#include "sat/smt/polysat/forbidden_intervals.h"
|
||||||
|
#include "sat/smt/polysat/fixed_bits.h"
|
||||||
|
|
||||||
|
|
||||||
namespace polysat {
|
namespace polysat {
|
||||||
|
|
||||||
|
@ -103,56 +105,6 @@ namespace polysat {
|
||||||
entry* get_entries(unsigned bit_width) const { layer const* l = get_layer(bit_width); return l ? l->entries : nullptr; }
|
entry* get_entries(unsigned bit_width) const { layer const* l = get_layer(bit_width); return l ? l->entries : nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fixed_bits_info {
|
|
||||||
svector<lbool> fixed;
|
|
||||||
vector<vector<signed_constraint>> just_src;
|
|
||||||
vector<vector<signed_constraint>> just_side_cond;
|
|
||||||
vector<fixed_bits_vector> just_slicing;
|
|
||||||
|
|
||||||
bool is_empty() const {
|
|
||||||
SASSERT_EQ(fixed.empty(), just_src.empty());
|
|
||||||
SASSERT_EQ(fixed.empty(), just_side_cond.empty());
|
|
||||||
return fixed.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_empty_at(unsigned i) const {
|
|
||||||
return fixed[i] == l_undef && just_src[i].empty() && just_side_cond[i].empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset(unsigned num_bits) {
|
|
||||||
fixed.reset();
|
|
||||||
fixed.resize(num_bits, l_undef);
|
|
||||||
just_src.reset();
|
|
||||||
just_src.resize(num_bits);
|
|
||||||
just_side_cond.reset();
|
|
||||||
just_side_cond.resize(num_bits);
|
|
||||||
just_slicing.reset();
|
|
||||||
just_slicing.resize(num_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset_just(unsigned i) {
|
|
||||||
just_src[i].reset();
|
|
||||||
just_side_cond[i].reset();
|
|
||||||
just_slicing[i].reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_just(unsigned i, entry* e) {
|
|
||||||
reset_just(i);
|
|
||||||
push_just(i, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_just(unsigned i, entry* e) {
|
|
||||||
just_src[i].append(e->src);
|
|
||||||
just_side_cond[i].append(e->side_cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_from_bit(unsigned i, unsigned src) {
|
|
||||||
just_src[i].append(just_src[src]);
|
|
||||||
just_side_cond[i].append(just_side_cond[src]);
|
|
||||||
just_slicing[i].append(just_slicing[src]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
ptr_vector<entry> m_alloc;
|
ptr_vector<entry> m_alloc;
|
||||||
vector<layers> m_units; // set of viable values based on unit multipliers, layered by bit-width in descending order
|
vector<layers> m_units; // set of viable values based on unit multipliers, layered by bit-width in descending order
|
||||||
|
@ -187,7 +139,6 @@ namespace polysat {
|
||||||
pvar v,
|
pvar v,
|
||||||
unsigned_vector const& widths,
|
unsigned_vector const& widths,
|
||||||
offset_slices const& overlaps,
|
offset_slices const& overlaps,
|
||||||
fixed_bits_info const& fbi,
|
|
||||||
rational const& to_cover_lo,
|
rational const& to_cover_lo,
|
||||||
rational const& to_cover_hi,
|
rational const& to_cover_hi,
|
||||||
rational& out_val);
|
rational& out_val);
|
||||||
|
@ -197,39 +148,14 @@ namespace polysat {
|
||||||
unsigned w_idx,
|
unsigned w_idx,
|
||||||
unsigned_vector const& widths,
|
unsigned_vector const& widths,
|
||||||
offset_slices const& overlaps,
|
offset_slices const& overlaps,
|
||||||
fixed_bits_info const& fbi,
|
|
||||||
rational const& to_cover_lo,
|
rational const& to_cover_lo,
|
||||||
rational const& to_cover_hi,
|
rational const& to_cover_hi,
|
||||||
rational& out_val,
|
rational& out_val,
|
||||||
ptr_vector<entry>& refine_todo);
|
ptr_vector<entry>& refine_todo);
|
||||||
|
|
||||||
|
|
||||||
template <bool FORWARD>
|
|
||||||
bool refine_viable(pvar v, rational const& val, fixed_bits_info const& fbi) {
|
|
||||||
throw default_exception("refine nyi");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool refine_viable(pvar v, rational const& val) {
|
|
||||||
throw default_exception("refine nyi");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool FORWARD>
|
|
||||||
bool refine_bits(pvar v, rational const& val, fixed_bits_info const& fbi) {
|
|
||||||
throw default_exception("refine nyi");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool FORWARD>
|
|
||||||
entry* refine_bits(pvar v, rational const& val, unsigned num_bits, fixed_bits_info const& fbi) {
|
|
||||||
throw default_exception("refine nyi");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool refine_equal_lin(pvar v, rational const& val) {
|
|
||||||
throw default_exception("refine nyi");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool refine_disequal_lin(pvar v, rational const& val) {
|
|
||||||
throw default_exception("refine nyi");
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_conflict_by_interval(pvar v, unsigned w, ptr_vector<entry>& intervals, unsigned first_interval);
|
void set_conflict_by_interval(pvar v, unsigned w, ptr_vector<entry>& intervals, unsigned first_interval);
|
||||||
bool set_conflict_by_interval_rec(pvar v, unsigned w, entry** intervals, unsigned num_intervals, bool& create_lemma, uint_set& vars_to_explain);
|
bool set_conflict_by_interval_rec(pvar v, unsigned w, entry** intervals, unsigned num_intervals, bool& create_lemma, uint_set& vars_to_explain);
|
||||||
|
@ -238,10 +164,7 @@ namespace polysat {
|
||||||
throw default_exception("fine_value nyi");
|
throw default_exception("fine_value nyi");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool collect_bit_information(pvar v, bool add_conflict, fixed_bits_info& out_fbi);
|
fixed_bits m_fixed_bits;
|
||||||
|
|
||||||
|
|
||||||
fixed_bits_info m_fbi;
|
|
||||||
void init_fixed_bits(pvar v);
|
void init_fixed_bits(pvar v);
|
||||||
|
|
||||||
unsigned_vector m_widths;
|
unsigned_vector m_widths;
|
||||||
|
@ -259,7 +182,7 @@ namespace polysat {
|
||||||
find_t find_viable(pvar v, rational& out_val);
|
find_t find_viable(pvar v, rational& out_val);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Explain why the current variable is not viable or signleton.
|
* Explain the current variable is not viable or signleton.
|
||||||
*/
|
*/
|
||||||
dependency_vector explain();
|
dependency_vector explain();
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ namespace polysat {
|
||||||
unsigned lo = offset, hi = bv.get_bv_size(n->get_expr());
|
unsigned lo = offset, hi = bv.get_bv_size(n->get_expr());
|
||||||
rational value;
|
rational value;
|
||||||
VERIFY(bv.is_numeral(n->get_expr(), value));
|
VERIFY(bv.is_numeral(n->get_expr(), value));
|
||||||
out.push_back({ fixed_bits(lo, hi, value) });
|
out.push_back({ fixed_slice(lo, hi, value) });
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
theory_var v = m_pddvar2var[pv];
|
theory_var v = m_pddvar2var[pv];
|
||||||
|
|
|
@ -223,6 +223,18 @@ namespace polysat {
|
||||||
level = std::max(level, s().lvl(lit));
|
level = std::max(level, s().lvl(lit));
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
else if (d.is_fixed_claim()) {
|
||||||
|
auto const& f = d.fixed();
|
||||||
|
sat::literal_vector lits;
|
||||||
|
std::function<void(euf::enode*, euf::enode*)> consume = [&](auto* a, auto* b) {
|
||||||
|
ctx.get_eq_antecedents(a, b, lits);
|
||||||
|
};
|
||||||
|
explain_fixed(f.v, f.lo, f.hi, f.value, consume);
|
||||||
|
unsigned level = 0;
|
||||||
|
for (auto lit : lits)
|
||||||
|
level = std::max(level, s().lvl(lit));
|
||||||
|
return level;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
SASSERT(d.is_axiom());
|
SASSERT(d.is_axiom());
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -281,6 +293,13 @@ namespace polysat {
|
||||||
};
|
};
|
||||||
explain_slice(v, w, offset, consume);
|
explain_slice(v, w, offset, consume);
|
||||||
}
|
}
|
||||||
|
else if (d.is_fixed_claim()) {
|
||||||
|
auto const& f = d.fixed();
|
||||||
|
std::function<void(euf::enode*, euf::enode*)> consume = [&](auto* a, auto* b) {
|
||||||
|
lits.push_back(~eq_internalize(a, b));
|
||||||
|
};
|
||||||
|
explain_fixed(f.v, f.lo, f.hi, f.value, consume);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
SASSERT(d.is_axiom());
|
SASSERT(d.is_axiom());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue