mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
Update viable::propagate_from_containing_slice to use new get_fixed_sub_slices (wip)
This commit is contained in:
parent
9283b4169c
commit
85d3e266a4
2 changed files with 171 additions and 16 deletions
|
@ -645,18 +645,36 @@ namespace polysat {
|
|||
return result;
|
||||
}
|
||||
|
||||
dependency viable::propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps) {
|
||||
for (auto const& slice : m_overlaps)
|
||||
if (auto d = propagate_from_containing_slice(e, value, e_deps, slice); !d.is_null())
|
||||
dependency viable::propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps) {
|
||||
verbose_stream() << "\n\n\n\n\n\nNon-viable assignment for v" << m_var << " size " << c.size(m_var) << "\n";
|
||||
display_one(verbose_stream() << "entry: ", e) << "\n";
|
||||
verbose_stream() << "value " << value << "\n";
|
||||
|
||||
fixed_slice_extra_vector fixed;
|
||||
offset_slice_extra_vector subslices;
|
||||
#if 0
|
||||
verbose_stream() << "fixed subslices of v" << m_var << ":\n";
|
||||
c.s.get_fixed_sub_slices(m_var, fixed, subslices); // TODO: move into m_fixed bits?
|
||||
|
||||
// TODO: the conflict should be from the subslice with highest level. we might want to skip the others.
|
||||
for (auto const& slice : subslices)
|
||||
if (auto d = propagate_from_containing_slice(e, value, e_deps, fixed, slice); !d.is_null())
|
||||
return d;
|
||||
#else
|
||||
for (auto const& slice : m_overlaps)
|
||||
if (auto d = propagate_from_containing_slice(e, value, e_deps, fixed, {slice.v, slice.offset, 0}); !d.is_null())
|
||||
return d;
|
||||
#endif
|
||||
return null_dependency;
|
||||
}
|
||||
|
||||
dependency viable::propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps, offset_slice const& slice) {
|
||||
auto [w, offset] = slice;
|
||||
dependency viable::propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps, fixed_slice_extra_vector const& fixed, offset_slice_extra const& slice) {
|
||||
pvar w = slice.v;
|
||||
unsigned offset = slice.offset;
|
||||
unsigned w_level = slice.level; // level where value of w was fixed
|
||||
if (w == m_var)
|
||||
return null_dependency;
|
||||
verbose_stream() << "v" << m_var << " size " << c.size(m_var) << ", v" << w << " size " << c.size(w) << " offset " << offset << "\n";
|
||||
verbose_stream() << "v" << m_var << " size " << c.size(m_var) << ", v" << w << " size " << c.size(w) << " offset " << offset << " level " << w_level << "\n";
|
||||
|
||||
// Let:
|
||||
// v = m_var[e->bit_width-1:0]
|
||||
|
@ -685,12 +703,8 @@ namespace polysat {
|
|||
unsigned const z_sz = offset;
|
||||
unsigned const y_sz = std::min(w_sz, v_sz - z_sz);
|
||||
unsigned const x_sz = v_sz - y_sz;
|
||||
|
||||
rational const& w_shift = rational::power_of_two(w_sz - y_sz);
|
||||
|
||||
verbose_stream() << "v_sz " << v_sz << " w_sz " << w_sz << " / x_sz " << x_sz << " y_sz " << y_sz << " z_sz " << z_sz << "\n";
|
||||
display_one(verbose_stream() << "entry: ", e) << "\n";
|
||||
verbose_stream() << "value " << value << "\n";
|
||||
|
||||
SASSERT(!e->interval.is_full());
|
||||
rational const& lo = e->interval.lo_val();
|
||||
|
@ -699,6 +713,147 @@ namespace polysat {
|
|||
r_interval const v_ivl = r_interval::proper(lo, hi);
|
||||
verbose_stream() << "propagate interval " << v_ivl << " from v" << m_var << " to v" << w << "[" << y_sz << "]" << "\n";
|
||||
|
||||
#if 0
|
||||
|
||||
dependency_vector deps;
|
||||
deps.append(e_deps); // explains e
|
||||
deps.push_back(offset_claim{m_var, slice}); // explains m_var[...] = w
|
||||
|
||||
r_interval ivl = v_ivl;
|
||||
|
||||
// chop off x-part, taking fixed values into account whenever possible.
|
||||
unsigned const x_off = y_sz + z_sz;
|
||||
unsigned remaining_x_sz = x_sz;
|
||||
while (remaining_x_sz > 0 && !ivl.is_empty() && !ivl.is_full()) {
|
||||
unsigned remaining_x_end = remaining_x_sz + x_off;
|
||||
// find next fixed slice (prefer lower level)
|
||||
fixed_slice_extra best;
|
||||
unsigned best_end = 0;
|
||||
SASSERT(best_end < x_off); // because y_sz != 0
|
||||
for (auto const& f : fixed) {
|
||||
if (f.level >= w_level)
|
||||
continue;
|
||||
// ??????xxxxxxxyyyyyyzzzz
|
||||
// 1111 not useful at this point
|
||||
// 11111 OK
|
||||
// 1111 OK (has gap without fixed value)
|
||||
// 1111 NOT OK (overlaps y) ... although, why would that not be ok? it just restricts values of y too. maybe this can be used to improve interval for y further.
|
||||
// 111111 not useful at this point
|
||||
if (f.offset >= remaining_x_end)
|
||||
continue;
|
||||
if (f.end() <= x_off)
|
||||
continue;
|
||||
unsigned const f_end = std::min(remaining_x_end, f.end()); // for comparison, values beyond the current range don't matter
|
||||
if (f_end > best_end)
|
||||
best = f, best_end = f_end;
|
||||
else if (f_end == best_end && f.level < best.level)
|
||||
best = f, best_end = f_end;
|
||||
}
|
||||
|
||||
if (best_end < remaining_x_end) {
|
||||
// there is a gap without a fixed value
|
||||
unsigned const b = std::max(best_end, x_off);
|
||||
unsigned const a = remaining_x_end - b;
|
||||
SASSERT(remaining_x_sz >= a);
|
||||
ivl = chop_off_upper(ivl, a, b);
|
||||
remaining_x_sz -= a;
|
||||
remaining_x_end -= a;
|
||||
}
|
||||
|
||||
if (best_end > x_off) {
|
||||
verbose_stream() << " using fixed slice " << best.value << "[" << best.length << "]@" << best.offset << "\n";
|
||||
SASSERT(remaining_x_end == best_end);
|
||||
SASSERT(remaining_x_end <= best.end());
|
||||
// chop off portion with fixed value
|
||||
unsigned const b = std::max(x_off, best.offset);
|
||||
unsigned const a = remaining_x_end - b;
|
||||
rational value = best.value;
|
||||
if (b > best.offset)
|
||||
value = machine_div2k(value, b - best.offset);
|
||||
value = mod2k(value, a);
|
||||
|
||||
ivl = chop_off_upper(ivl, a, b, &value);
|
||||
remaining_x_sz -= a;
|
||||
remaining_x_end -= a;
|
||||
|
||||
deps.push_back(best.dep); // justification for the fixed value
|
||||
}
|
||||
}
|
||||
|
||||
if (ivl.is_empty())
|
||||
return null_dependency;
|
||||
|
||||
// chop off z-part
|
||||
unsigned remaining_z_sz = z_sz;
|
||||
while (remaining_z_sz > 0 && !ivl.is_empty() && !ivl.is_full()) {
|
||||
SASSERT(remaining_x_sz == 0);
|
||||
unsigned remaining_z_off = z_sz - remaining_z_sz;
|
||||
// find next fixed slice (prefer lower level)
|
||||
fixed_slice_extra best;
|
||||
unsigned best_off = UINT_MAX;
|
||||
for (auto const& f : fixed) {
|
||||
if (f.level >= w_level)
|
||||
continue;
|
||||
// ?????????????yyyyyyzzzzz???
|
||||
// 1111 not useful at this point
|
||||
// 1111 OK
|
||||
// 1111 OK (has gap without fixed value)
|
||||
// 111 not useful
|
||||
if (f.offset >= z_sz)
|
||||
continue;
|
||||
if (f.end() <= remaining_z_off)
|
||||
continue;
|
||||
unsigned const f_off = std::max(remaining_z_off, f.offset); // for comparison, values beyond the current range don't matter
|
||||
if (f_off < best_off)
|
||||
best = f, best_off = f_off;
|
||||
else if (f_off == best_off && f.level < best.level)
|
||||
best = f, best_off = f_off;
|
||||
}
|
||||
|
||||
if (best_off > remaining_z_off) {
|
||||
// there is a gap without a fixed value
|
||||
unsigned const b = best_off - remaining_z_off;
|
||||
unsigned const a = y_sz + z_sz - b;
|
||||
SASSERT(remaining_x_sz >= a);
|
||||
ivl = chop_off_lower(ivl, a, b);
|
||||
remaining_z_sz -= b;
|
||||
remaining_z_off += b;
|
||||
}
|
||||
|
||||
if (best_off < z_sz) {
|
||||
verbose_stream() << " using fixed slice " << best.value << "[" << best.length << "]@" << best.offset << "\n";
|
||||
SASSERT_EQ(best_off, remaining_z_off);
|
||||
unsigned const b = std::min(best.end(), z_sz) - remaining_z_off;
|
||||
unsigned const a = y_sz + z_sz - b;
|
||||
rational value = best.value;
|
||||
if (best.offset < best_off)
|
||||
value = machine_div2k(value, best_off - best.offset);
|
||||
value = mod2k(value, b);
|
||||
|
||||
ivl = chop_off_lower(ivl, a, b, &value);
|
||||
remaining_z_sz -= b;
|
||||
remaining_z_off += b;
|
||||
|
||||
deps.push_back(best.dep); // justification for the fixed value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ivl.is_empty())
|
||||
return null_dependency;
|
||||
|
||||
verbose_stream() << "=> v" << w << "[" << y_sz << "] not in " << ivl << "\n"; // << " using x=" << x_value << " z=" << z_value << "\n";
|
||||
if (ivl.is_full()) {
|
||||
// TODO: set conflict
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
else {
|
||||
// proper interval
|
||||
auto sc = ~cs.ult(w_shift * (c.var(w) - ivl.lo()), w_shift * (ivl.hi() - ivl.lo()));
|
||||
return c.propagate(sc, deps, "propagate from containing slice");
|
||||
}
|
||||
|
||||
#else
|
||||
// TODO: by the time we call viable::assign, m_fixed_bits only contains a single slice with 'value'.
|
||||
// if we had access to the actually fixed slices (not just fixed because of the latest assignment),
|
||||
// we could chop off fixed and non-fixed parts according to actually fixed slices;
|
||||
|
@ -762,13 +917,14 @@ namespace polysat {
|
|||
// y is unconstrained, nothing to do here
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return null_dependency;
|
||||
}
|
||||
|
||||
|
||||
/// Let x = concat(y, z) and x \not\in [lo;hi[.
|
||||
/// Returns an interval I such that z \not\in I.
|
||||
/// Let x = concat(y, z) and x not in [lo;hi[.
|
||||
/// Returns an interval I such that z not in I.
|
||||
r_interval viable::chop_off_upper(r_interval const& i, unsigned const Ny, unsigned const Nz, rational const* y_fixed_value) {
|
||||
if (i.is_full())
|
||||
return r_interval::full();
|
||||
|
@ -804,8 +960,8 @@ namespace polysat {
|
|||
UNREACHABLE();
|
||||
}
|
||||
|
||||
/// Let x = concat(y, z) and x \not\in [lo;hi[.
|
||||
/// Returns an interval I such that y \not\in I.
|
||||
/// Let x = concat(y, z) and x not in [lo;hi[.
|
||||
/// Returns an interval I such that y not in I.
|
||||
r_interval viable::chop_off_lower(r_interval const& i, unsigned const Ny, unsigned const Nz, rational const* z_fixed_value) {
|
||||
if (i.is_full())
|
||||
return r_interval::full();
|
||||
|
|
|
@ -116,13 +116,12 @@ namespace polysat {
|
|||
bool intersect(pvar v, entry* e);
|
||||
|
||||
dependency propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps);
|
||||
dependency propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps, offset_slice const& slice);
|
||||
dependency propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps, fixed_slice_extra_vector const& fixed, offset_slice_extra const& slice);
|
||||
static r_interval chop_off_upper(r_interval const& i, unsigned Ny, unsigned Nz, rational const* y_fixed_value = nullptr);
|
||||
static r_interval chop_off_lower(r_interval const& i, unsigned Ny, unsigned Nz, rational const* z_fixed_value = nullptr);
|
||||
|
||||
// find the first non-fixed entry that overlaps with val, if any.
|
||||
entry* find_overlap(rational& val);
|
||||
entry* find_overlap(pvar w, rational& val);
|
||||
entry* find_overlap(pvar w, layer& l, rational const& val);
|
||||
|
||||
void update_value_to_high(rational& val, entry* e);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue