3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-08 15:13:23 +00:00

working on viable explanations

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2024-01-02 16:20:13 -08:00
parent b706434282
commit 21236dc80a
5 changed files with 53 additions and 23 deletions

View file

@ -1860,14 +1860,11 @@ namespace dd {
return (*this) * rational::power_of_two(n); return (*this) * rational::power_of_two(n);
} }
bool pdd::has_unit(pdd& x, pdd& rest) const { bool pdd::has_unit(pdd& x) const {
if (is_val())
return false;
pdd r = *this; pdd r = *this;
while (!r.is_val()) { while (!r.is_val()) {
if (r.hi().is_one()) { if (r.hi().is_one()) {
x = m->mk_var(r.var()); x = m->mk_var(r.var());
rest = *this - x;
return true; return true;
} }
r = r.lo(); r = r.lo();

View file

@ -441,7 +441,7 @@ namespace dd {
bool is_unary() const { return !is_val() && lo().is_zero() && hi().is_val(); } bool is_unary() const { return !is_val() && lo().is_zero() && hi().is_val(); }
bool is_offset() const { return !is_val() && lo().is_val() && hi().is_one(); } bool is_offset() const { return !is_val() && lo().is_val() && hi().is_one(); }
bool is_binary() const { return m->is_binary(root); } bool is_binary() const { return m->is_binary(root); }
bool has_unit(pdd& x, pdd& rest) const; bool has_unit(pdd& x) const;
bool is_monomial() const { return m->is_monomial(root); } bool is_monomial() const { return m->is_monomial(root); }
bool is_univariate() const { return m->is_univariate(root); } bool is_univariate() const { return m->is_univariate(root); }
bool is_univariate_in(unsigned v) const { return m->is_univariate_in(root, v); } bool is_univariate_in(unsigned v) const { return m->is_univariate_in(root, v); }

View file

@ -84,6 +84,7 @@ namespace polysat {
} }
find_t viable::find_viable(pvar v, rational& lo) { find_t viable::find_viable(pvar v, rational& lo) {
verbose_stream() << "find viable v" << v << " starting with " << lo << "\n";
rational hi; rational hi;
switch (find_viable(v, lo, hi)) { switch (find_viable(v, lo, hi)) {
case l_true: case l_true:
@ -103,7 +104,9 @@ namespace polysat {
lbool viable::find_viable(pvar v, rational& val1, rational& val2) { lbool viable::find_viable(pvar v, rational& val1, rational& val2) {
m_explain.reset(); m_explain.reset();
m_ineqs.reset();
m_var = v; m_var = v;
m_value = nullptr;
m_num_bits = c.size(v); m_num_bits = c.size(v);
m_fixed_bits.reset(v); m_fixed_bits.reset(v);
init_overlaps(v); init_overlaps(v);
@ -129,6 +132,9 @@ namespace polysat {
else else
val2 = val1 + 1; val2 = val1 + 1;
// instead of m_value use linked list of entries?
m_value = alloc(pdd, c.value(val2, m_num_bits));
r = next_viable(val2); r = next_viable(val2);
if (r != l_false) if (r != l_false)
@ -231,14 +237,29 @@ namespace polysat {
break; break;
// TODO check if admitted: layer.entries = e; // TODO check if admitted: layer.entries = e;
m_explain.push_back(e); m_explain.push_back(e);
if (e->interval.is_full()) if (e->interval.is_full())
return l_false; return l_false;
auto hi = e->interval.hi_val();
if (wrapped && start <= hi) auto hi_val = e->interval.hi_val();
auto lo_val = e->interval.lo_val();
auto hi = e->interval.hi();
auto lo = e->interval.lo();
if (!m_value)
m_value = alloc(pdd, lo);
m_ineqs.push_back({ *m_value, lo, hi });
if (wrapped && start <= hi_val) {
verbose_stream() << "WRAPPED\n";
return l_false; return l_false;
if (hi < e->interval.lo_val()) }
if (hi_val < lo_val)
wrapped = true; wrapped = true;
val1 = hi; val1 = hi_val;
m_value = alloc(pdd, hi);
SASSERT(val1 < p2b); SASSERT(val1 < p2b);
} }
SASSERT(val1 < p2b); SASSERT(val1 < p2b);
@ -537,6 +558,13 @@ namespace polysat {
auto const& [sc, d, value] = c.m_constraint_index[index.id]; auto const& [sc, d, value] = c.m_constraint_index[index.id];
result.push_back(d); result.push_back(d);
} }
for (auto [t, lo, hi] : m_ineqs) {
auto sc = cs.ult(t - lo, hi - lo);
verbose_stream() << "Overlap " << t << " in [" << lo << ", " << hi << "[: " << sc << "\n";
if (!sc.is_always_true())
result.push_back(c.propagate(sc, c.explain_eval(sc)));
}
result.append(m_fixed_bits.explain()); result.append(m_fixed_bits.explain());
TRACE("bv", tout << "viable-explain v" << m_var << " - " << result.size() << "\n"); TRACE("bv", tout << "viable-explain v" << m_var << " - " << result.size() << "\n");
return result; return result;
@ -656,6 +684,7 @@ namespace polysat {
} }
if (ne->interval.is_full()) { if (ne->interval.is_full()) {
m_explain.reset(); m_explain.reset();
m_ineqs.reset();
m_explain.push_back(ne); m_explain.push_back(ne);
m_fixed_bits.reset(); m_fixed_bits.reset();
m_var = v; m_var = v;

View file

@ -85,11 +85,15 @@ 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; }
}; };
// short for t in [lo,hi[
struct interval_member {
pdd t, lo, hi;
};
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
ptr_vector<entry> m_equal_lin; // entries that have non-unit multipliers, but are equal ptr_vector<entry> m_equal_lin; // entries that have non-unit multipliers, but are equal
ptr_vector<entry> m_diseq_lin; // entries that have distinct non-zero multipliers ptr_vector<entry> m_diseq_lin; // entries that have distinct non-zero multipliers
vector<interval_member> m_ineqs; // inequalities to justify that values are not viable.
ptr_vector<entry> m_explain; // entries that explain the current propagation or conflict ptr_vector<entry> m_explain; // entries that explain the current propagation or conflict
bool well_formed(entry* e); bool well_formed(entry* e);
@ -126,6 +130,7 @@ namespace polysat {
bool refine_equal_lin(pvar v, rational const& val); bool refine_equal_lin(pvar v, rational const& val);
pvar m_var = null_var; pvar m_var = null_var;
scoped_ptr<pdd> m_value; // the current symbolid value being checked for viability.
unsigned m_num_bits = 0; unsigned m_num_bits = 0;
fixed_bits m_fixed_bits; fixed_bits m_fixed_bits;
offset_slices m_overlaps; offset_slices m_overlaps;

View file

@ -384,24 +384,23 @@ namespace polysat {
expr_ref result(m); expr_ref result(m);
switch (sc.op()) { switch (sc.op()) {
case ckind_t::ule_t: { case ckind_t::ule_t: {
auto p = sc.to_ule().lhs(); auto p = sc.to_ule().lhs();
auto q = sc.to_ule().rhs(); auto q = sc.to_ule().rhs();
pdd x = p, r = p; pdd x = p;
if (q.is_zero() && p.has_unit(x, r)) { if (q.is_zero() && p.has_unit(x)) {
auto l = pdd2expr(x); auto l = pdd2expr(x);
auto h = pdd2expr(-r); auto r = pdd2expr(x - p);
result = m.mk_eq(l, h); result = m.mk_eq(l, r);
} }
else { else {
auto l = pdd2expr(p); auto l = pdd2expr(p);
auto h = pdd2expr(q); auto r = pdd2expr(q);
if (p == q) if (p == q)
result = m.mk_true(); result = m.mk_true();
else if (q.is_zero()) else if (q.is_zero())
result = m.mk_eq(l, h); result = m.mk_eq(l, r);
else else
result = bv.mk_ule(l, h); result = bv.mk_ule(l, r);
} }
if (sc.sign()) if (sc.sign())
result = m.mk_not(result); result = m.mk_not(result);