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

inline propagation when adding new viable

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2024-01-08 20:31:14 -08:00
parent e26d597917
commit cc4ed602e5
5 changed files with 57 additions and 34 deletions

View file

@ -164,11 +164,7 @@ namespace polysat {
viable_conflict(m_var); viable_conflict(m_var);
return l_false; return l_false;
case find_t::singleton: { case find_t::singleton: {
auto p = var2pdd(m_var).mk_var(m_var); viable_propagate(m_var, var_value);
auto sc = m_constraints.eq(p, var_value);
TRACE("bv", tout << "check-propagate v" << m_var << " := " << var_value << " " << sc << "\n");
auto d = s.propagate(sc, m_viable.explain(), "viable-propagate");
propagate_assignment(m_var, var_value, d);
return l_false; return l_false;
} }
case find_t::multiple: { case find_t::multiple: {
@ -301,6 +297,14 @@ namespace polysat {
decay_activity(); decay_activity();
} }
void core::viable_propagate(pvar v, rational const& var_value) {
auto p = var2pdd(v).mk_var(v);
auto sc = m_constraints.eq(p, var_value);
TRACE("bv", tout << "check-propagate v" << v << " := " << var_value << " " << sc << "\n");
auto d = s.propagate(sc, m_viable.explain(), "viable-propagate");
propagate_assignment(v, var_value, d);
}
void core::propagate_assignment(constraint_id idx) { void core::propagate_assignment(constraint_id idx) {
auto [sc, dep, value] = m_constraint_index[idx.id]; auto [sc, dep, value] = m_constraint_index[idx.id];
@ -333,8 +337,18 @@ namespace polysat {
return; return;
v = w; v = w;
} }
if (v != null_var && !m_viable.add_unitary(v, idx, m_values[v])) if (v != null_var) {
switch (m_viable.add_unitary(v, idx, m_values[v])) {
case find_t::empty:
viable_conflict(v); viable_conflict(v);
break;
case find_t::singleton:
viable_propagate(v, m_values[v]);
break;
default:
break;
}
}
else if (v == null_var && weak_eval(sc) == l_false) { else if (v == null_var && weak_eval(sc) == l_false) {
auto ex = explain_weak_eval(sc); auto ex = explain_weak_eval(sc);
ex.push_back(dep); ex.push_back(dep);
@ -388,9 +402,18 @@ namespace polysat {
auto v1 = vars[1]; auto v1 = vars[1];
if (!is_assigned(v0) || is_assigned(v1)) if (!is_assigned(v0) || is_assigned(v1))
continue; continue;
// detect unitary, add to viable, detect conflict? if (value != l_undef) {
if (value != l_undef && !m_viable.add_unitary(v1, { idx }, m_values[v])) switch (m_viable.add_unitary(v1, { idx }, m_values[v1])) {
case find_t::empty:
viable_conflict(v1); viable_conflict(v1);
break;
case find_t::singleton:
viable_propagate(v1, m_values[v1]);
break;
default:
break;
}
}
} }
SASSERT(m_watch[v].size() == sz && "size of watch list was not changed"); SASSERT(m_watch[v].size() == sz && "size of watch list was not changed");
m_watch[v].shrink(j); m_watch[v].shrink(j);

View file

@ -79,6 +79,7 @@ namespace polysat {
void del_var(); void del_var();
void viable_conflict(pvar v); void viable_conflict(pvar v);
void viable_propagate(pvar v, rational const& var_value);
bool is_assigned(pvar v) { return !m_justification[v].is_null(); } bool is_assigned(pvar v) { return !m_justification[v].is_null(); }
void propagate_assignment(constraint_id idx); void propagate_assignment(constraint_id idx);

View file

@ -25,7 +25,7 @@ namespace polysat {
struct fi_record { struct fi_record {
eval_interval interval; eval_interval interval;
vector<signed_constraint> side_cond; vector<signed_constraint> side_cond;
vector<signed_constraint> src; // only units may have multiple src (as they can consist of contracted bit constraints) vector<signed_constraint> src; // there is either 0 or 1 src.
vector<dependency> deps; vector<dependency> deps;
rational coeff; rational coeff;
unsigned bit_width = 0; // number of lower bits; TODO: should move this to viable::entry; where the coeff/bit-width is adapted accordingly unsigned bit_width = 0; // number of lower bits; TODO: should move this to viable::entry; where the coeff/bit-width is adapted accordingly

View file

@ -103,10 +103,10 @@ namespace polysat {
if (n) if (n)
continue; continue;
++rounds;
if (!check_fixed_bits(v, lo)) if (!check_fixed_bits(v, lo))
continue; continue;
++rounds;
if (!check_disequal_lin(v, lo)) if (!check_disequal_lin(v, lo))
continue; continue;
if (!check_equal_lin(v, lo)) if (!check_equal_lin(v, lo))
@ -125,8 +125,6 @@ namespace polysat {
m_overlaps.reset(); m_overlaps.reset();
c.get_bitvector_suffixes(v, m_overlaps); c.get_bitvector_suffixes(v, m_overlaps);
std::sort(m_overlaps.begin(), m_overlaps.end(), [&](auto const& x, auto const& y) { return c.size(x.v) < c.size(y.v); }); std::sort(m_overlaps.begin(), m_overlaps.end(), [&](auto const& x, auto const& y) { return c.size(x.v) < c.size(y.v); });
//display_state(verbose_stream());
//display(verbose_stream());
} }
@ -518,18 +516,21 @@ namespace polysat {
*/ */
dependency_vector viable::explain() { dependency_vector viable::explain() {
dependency_vector result; dependency_vector result;
uint_set seen;
auto last = m_explain.back(); auto last = m_explain.back();
auto after = last; auto after = last;
TRACE("bv", display_explain(tout)); TRACE("bv", display_explain(tout));
auto unmark = [&]() {
for (auto e : m_explain)
e.e->marked = false;
};
auto explain_entry = [&](entry* e) { auto explain_entry = [&](entry* e) {
auto index = e->constraint_index; auto index = e->constraint_index;
if (!index.is_null() && seen.contains(index.id)) if (e->marked)
return; return;
if (!index.is_null()) e->marked = true;
seen.insert(index.id);
if (m_var != e->var) if (m_var != e->var)
result.push_back(offset_claim(m_var, { e->var, 0 })); result.push_back(offset_claim(m_var, { e->var, 0 }));
for (auto const& sc : e->side_cond) for (auto const& sc : e->side_cond)
@ -542,6 +543,7 @@ namespace polysat {
if (last.e->interval.is_full()) { if (last.e->interval.is_full()) {
explain_entry(last.e); explain_entry(last.e);
SASSERT(m_explain.size() == 1); SASSERT(m_explain.size() == 1);
unmark();
return result; return result;
} }
@ -564,6 +566,7 @@ namespace polysat {
auto sc = cs.eq(last.e->interval.hi() + 1, first.e->interval.lo()); auto sc = cs.eq(last.e->interval.hi() + 1, first.e->interval.lo());
result.push_back(c.propagate(sc, c.explain_weak_eval(sc))); result.push_back(c.propagate(sc, c.explain_weak_eval(sc)));
} }
unmark();
return result; return result;
} }
@ -638,29 +641,29 @@ namespace polysat {
/* /*
* Register constraint at index 'idx' as unitary in v. * Register constraint at index 'idx' as unitary in v.
*/ */
bool viable::add_unitary(pvar v, constraint_id idx, rational& var_value) { find_t viable::add_unitary(pvar v, constraint_id idx, rational& var_value) {
if (c.is_assigned(v)) if (c.is_assigned(v))
return true; return find_t::multiple;
auto [sc, d, truth_value] = c.m_constraint_index[idx.id]; auto [sc, d, truth_value] = c.m_constraint_index[idx.id];
SASSERT(truth_value != l_undef); SASSERT(truth_value != l_undef);
if (truth_value == l_false) if (truth_value == l_false)
sc = ~sc; sc = ~sc;
if (!sc.is_linear()) if (!sc.is_linear())
return true; return find_t::multiple;
entry* ne = alloc_entry(v, idx); entry* ne = alloc_entry(v, idx);
if (!m_forbidden_intervals.get_interval(sc, v, *ne)) { if (!m_forbidden_intervals.get_interval(sc, v, *ne)) {
m_alloc.push_back(ne); m_alloc.push_back(ne);
return true; return find_t::multiple;
} }
// verbose_stream() << "v" << v << " " << sc << " " << ne->interval << "\n"; // verbose_stream() << "v" << v << " " << sc << " " << ne->interval << "\n";
if (ne->interval.is_currently_empty()) { if (ne->interval.is_currently_empty()) {
m_alloc.push_back(ne); m_alloc.push_back(ne);
return true; return find_t::multiple;
} }
if (ne->coeff == 1) if (ne->coeff == 1)
@ -739,7 +742,7 @@ namespace polysat {
IF_VERBOSE(0, verbose_stream() << "Check: always true " << "x*" << ne->coeff << " not in " << ne->interval << " " << new_hi << "\n"); IF_VERBOSE(0, verbose_stream() << "Check: always true " << "x*" << ne->coeff << " not in " << ne->interval << " " << new_hi << "\n");
// empty // empty
m_alloc.push_back(ne); m_alloc.push_back(ne);
return true; return find_t::multiple;
} }
ne->coeff = 1; ne->coeff = 1;
@ -752,15 +755,9 @@ namespace polysat {
m_explain.push_back({ ne, rational::zero() }); m_explain.push_back({ ne, rational::zero() });
m_fixed_bits.reset(); m_fixed_bits.reset();
m_var = v; m_var = v;
return false; return find_t::empty;
} }
switch (find_viable(v, var_value)) { return find_viable(v, var_value);
case find_t::empty:
return false;
default:
break;
}
return true;
} }
void viable::ensure_var(pvar v) { void viable::ensure_var(pvar v) {

View file

@ -53,6 +53,7 @@ namespace polysat {
bool active = true; bool active = true;
pvar var = null_var; pvar var = null_var;
constraint_id constraint_index; constraint_id constraint_index;
bool marked = false;
void reset() { void reset() {
// dll_base<entry>::init(this); // we never did this in alloc_entry either // dll_base<entry>::init(this); // we never did this in alloc_entry either
@ -61,6 +62,7 @@ namespace polysat {
active = true; active = true;
var = null_var; var = null_var;
constraint_index = constraint_id::null(); constraint_index = constraint_id::null();
marked = false;
} }
}; };
@ -164,7 +166,7 @@ namespace polysat {
/* /*
* Register constraint at index 'idx' as unitary in v. * Register constraint at index 'idx' as unitary in v.
*/ */
bool add_unitary(pvar v, constraint_id, rational& value); find_t add_unitary(pvar v, constraint_id, rational& value);
/* /*
* Ensure data-structures tracking variable v. * Ensure data-structures tracking variable v.