3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-24 09:35:32 +00:00
This commit is contained in:
Jakob Rath 2023-07-17 19:04:17 +02:00
parent d1cb02b735
commit 11d9e5c862
3 changed files with 44 additions and 21 deletions

View file

@ -153,8 +153,8 @@ namespace polysat {
m_scopes.shrink(target_lvl);
while (m_trail.size() > target_size) {
switch (m_trail.back()) {
case trail_item::add_var: undo_add_var(); break;
case trail_item::split_core: undo_split_core(); break;
case trail_item::add_var: undo_add_var(); break;
case trail_item::split_core: undo_split_core(); break;
default: UNREACHABLE();
}
m_trail.pop_back();
@ -203,6 +203,7 @@ namespace polysat {
// split a single slice without updating any equivalences
void slicing::split_core(enode* s, unsigned cut) {
SASSERT(!has_sub(s));
SASSERT(info(s).sub_hi == nullptr && info(s).sub_lo == nullptr);
SASSERT(width(s) > cut + 1);
unsigned const width_hi = width(s) - cut - 1;
unsigned const width_lo = cut + 1;
@ -216,6 +217,8 @@ namespace polysat {
else {
sub_hi = alloc_slice(width_hi);
sub_lo = alloc_slice(width_lo);
// info(sub_hi).parent = s;
// info(sub_lo).parent = s;
}
info(s).set_cut(cut, sub_hi, sub_lo);
m_trail.push_back(trail_item::split_core);
@ -361,7 +364,6 @@ namespace polysat {
}
bool slicing::merge(enode_vector& xs, enode_vector& ys, dep_t dep) {
// LOG_H2("Merging " << xs << " with " << ys);
while (!xs.empty()) {
SASSERT(!ys.empty());
enode* x = xs.back();
@ -381,20 +383,17 @@ namespace polysat {
SASSERT(!has_sub(x));
SASSERT(!has_sub(y));
if (width(x) == width(y)) {
// LOG("Match " << x << " and " << y);
if (!merge_base(x, y, dep))
return false;
}
else if (width(x) > width(y)) {
// need to split x according to y
// LOG("Splitting " << x << " to fit " << y);
mk_slice(x, width(y) - 1, 0, xs, true);
ys.push_back(y);
}
else {
SASSERT(width(y) > width(x));
// need to split y according to x
// LOG("Splitting " << y << " to fit " << x);
mk_slice(y, width(x) - 1, 0, ys, true);
xs.push_back(x);
}
@ -442,6 +441,8 @@ namespace polysat {
ys.clear();
if (result) {
// TODO: merge equivalence class of x, y (on upper level)? but can we always combine the sub-trees?
// need to add a congruence to track justification.
// adding virtual concat terms for x,y will do that automatically.
}
return result;
}
@ -605,6 +606,7 @@ namespace polysat {
// TODO: evaluate under current assignment?
if (!c->is_eq())
return;
dep_t const d = c.blit();
pdd const& p = c->to_eq();
auto& m = p.manager();
for (auto& [a, x] : p.linear_monomials()) {
@ -616,7 +618,12 @@ namespace polysat {
enode* const sx = var2slice(x);
if (body.is_val()) {
// Simple assignment x = value
// TODO: set fixed bits
enode* const sval = mk_value_slice(body.val(), body.power_of_2());
if (!merge(sx, sval, d)) {
// TODO: conflict
NOT_IMPLEMENTED_YET();
return;
}
continue;
}
pvar const y = m_solver.m_names.get_name(body);
@ -626,8 +633,11 @@ namespace polysat {
}
enode* const sy = var2slice(y);
if (c.is_positive()) {
if (!merge(sx, sy, c.blit()))
if (!merge(sx, sy, d)) {
// TODO: conflict
NOT_IMPLEMENTED_YET();
return;
}
}
else {
SASSERT(c.is_negative());
@ -654,9 +664,8 @@ namespace polysat {
get_root_base(vs, base);
for (enode* s : base)
display(out << " ", s);
// if (has_value(vs)) {
// out << " -- (val:" << get_value(vs) << ")";
// }
if (has_value(vs->get_root()))
out << " [root_value: " << get_value(vs->get_root()) << "]";
out << "\n";
}
return out;
@ -690,10 +699,7 @@ namespace polysat {
}
std::ostream& slicing::display(std::ostream& out, enode* s) const {
out << "{id:" << s->get_id() << ",w:" << width(s);
// if (has_value(s))
// out << ",val:" << get_value(s);
out << "}";
out << "{id:" << s->get_id() << ",w:" << width(s) << "}";
return out;
}
@ -704,7 +710,17 @@ namespace polysat {
for (enode* s : m_egraph.nodes()) {
// if the slice is equivalent to a variable, then the variable's slice is in the equivalence class
pvar const v = slice2var(s);
VERIFY_EQ(v != null_var, var2slice(v)->get_root() == s->get_root());
if (v != null_var) {
VERIFY_EQ(var2slice(v)->get_root(), s->get_root());
}
// if slice has a value, it should be propagated to its sub-slices
if (has_value(s)) {
VERIFY(s->is_root());
if (has_sub(s)) {
VERIFY(has_value(sub_hi(s)));
VERIFY(has_value(sub_lo(s)));
}
}
// properties below only matter for representatives
if (!s->is_root())
continue;
@ -712,11 +728,6 @@ namespace polysat {
// equivalence class only contains slices of equal length
VERIFY_EQ(width(s), width(n));
}
// if slice has a value, it should be propagated to its sub-slices
// if (has_value(s)) {
// VERIFY(has_value(sub_hi(s)->get_root()));
// VERIFY(has_value(sub_lo(s)->get_root()));
// }
}
return true;
}

View file

@ -47,12 +47,17 @@ namespace polysat {
static constexpr unsigned null_cut = std::numeric_limits<unsigned>::max();
// Kinds of slices:
// - proper (from variables)
// - values
// - virtual concat(...) expressions
struct slice_info {
unsigned width = 0; // number of bits in the slice
// Cut point: if not null_cut, the slice s has been subdivided into s[|s|-1:cut+1] and s[cut:0].
// The cut point is relative to the parent slice (rather than a root variable, which might not be unique)
unsigned cut = null_cut; // cut point, or null_cut if no subslices
pvar var = null_var; // slice is equivalent to this variable, if any (without dependencies)
// enode* parent = nullptr; // parent slice, only for proper slices (if not null: s == sub_hi(parent(s)) || s == sub_lo(parent(s)))
enode* slice = nullptr; // if enode corresponds to a concat(...) expression, this field links to the represented slice.
enode* sub_hi = nullptr; // upper subslice s[|s|-1:cut+1]
enode* sub_lo = nullptr; // lower subslice s[cut:0]

View file

@ -51,6 +51,7 @@ namespace polysat {
std::cout << sl << "\n";
sl.display_tree(std::cout);
VERIFY(sl.invariant());
}
// x[7:3] = a
@ -73,6 +74,7 @@ namespace polysat {
std::cout << sl << "\n";
sl.display_tree(std::cout);
VERIFY(sl.invariant());
(void)a;
(void)b;
@ -123,6 +125,8 @@ namespace polysat {
reason.reset();
sl.explain_equal(sl.var2slice(b), sl.pdd2slice(d), reason);
std::cout << " Reason: " << reason << "\n\n";
VERIFY(sl.invariant());
}
// 1. a = b
@ -155,7 +159,9 @@ namespace polysat {
sat::literal_vector reason;
sl.explain_equal(sl.var2slice(d), sl.var2slice(e), reason);
std::cout << " Reason: " << reason << "\n";
sl.display_tree(std::cout);
VERIFY(sl.invariant());
}
// x[5:2] = y
@ -183,6 +189,7 @@ namespace polysat {
std::cout << "v" << z << " = 7\n" << sl << "\n";
sl.display_tree(std::cout);
VERIFY(sl.invariant());
}
};