mirror of
https://github.com/Z3Prover/z3
synced 2025-06-20 04:43:39 +00:00
mk_extract
This commit is contained in:
parent
69e54b62c5
commit
73757e3fa4
3 changed files with 100 additions and 69 deletions
|
@ -157,6 +157,7 @@ namespace polysat {
|
||||||
switch (m_trail.back()) {
|
switch (m_trail.back()) {
|
||||||
case trail_item::add_var: undo_add_var(); break;
|
case trail_item::add_var: undo_add_var(); break;
|
||||||
case trail_item::split_core: undo_split_core(); break;
|
case trail_item::split_core: undo_split_core(); break;
|
||||||
|
case trail_item::mk_extract: undo_mk_extract(); break;
|
||||||
default: UNREACHABLE();
|
default: UNREACHABLE();
|
||||||
}
|
}
|
||||||
m_trail.pop_back();
|
m_trail.pop_back();
|
||||||
|
@ -644,49 +645,56 @@ namespace polysat {
|
||||||
get_base_core<true>(src, out_base);
|
get_base_core<true>(src, out_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
pvar slicing::mk_slice_extract(enode* src, unsigned hi, unsigned lo) {
|
pvar slicing::mk_extract(enode* src, unsigned hi, unsigned lo) {
|
||||||
enode_vector slices;
|
enode_vector& slices = m_tmp3;
|
||||||
|
SASSERT(slices.empty());
|
||||||
mk_slice(src, hi, lo, slices, false, true);
|
mk_slice(src, hi, lo, slices, false, true);
|
||||||
|
pvar v = null_var;
|
||||||
|
// try to re-use variable of an existing slice
|
||||||
|
if (slices.size() == 1)
|
||||||
|
v = slice2var(slices[0]);
|
||||||
|
// allocate new variable if we cannot reuse it
|
||||||
|
if (v == null_var)
|
||||||
|
v = m_solver.add_var(hi - lo + 1);
|
||||||
|
#if 0
|
||||||
|
// slice didn't have a variable yet; so we can re-use it for the new variable
|
||||||
|
// (we end up with a "phantom" enode that was first created for the variable)
|
||||||
if (slices.size() == 1) {
|
if (slices.size() == 1) {
|
||||||
enode* s = slices[0];
|
enode* s = slices[0];
|
||||||
if (slice2var(s) != null_var)
|
SASSERT_EQ(info(s).var, null_var);
|
||||||
return slice2var(s);
|
info(m_var2slice[v]).var = null_var; // disconnect the "phantom" enode
|
||||||
// TODO: optimization: could save a slice-tree by directly assigning slice2var(s) = v for new var v.
|
info(s).var = v;
|
||||||
|
m_var2slice[v] = s;
|
||||||
}
|
}
|
||||||
pvar v = m_solver.add_var(hi - lo + 1);
|
#endif
|
||||||
// TODO: can we use 'compressed' slice trees again if we store the source slice here as dependency?
|
// connect new variable
|
||||||
VERIFY(merge(slices, var2slice(v), dep_t()));
|
VERIFY(merge(slices, var2slice(v), dep_t()));
|
||||||
|
slices.reset();
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
pvar slicing::mk_extract_var(pvar src, unsigned hi, unsigned lo) {
|
pvar slicing::mk_extract(pvar src, unsigned hi, unsigned lo) {
|
||||||
return mk_slice_extract(var2slice(src), hi, lo);
|
extract_args args{src, hi, lo};
|
||||||
|
auto it = m_extract_dedup.find_iterator(args);
|
||||||
|
if (it != m_extract_dedup.end())
|
||||||
|
return it->m_value;
|
||||||
|
pvar const v = mk_extract(var2slice(src), hi, lo);
|
||||||
|
m_extract_dedup.insert(args, v);
|
||||||
|
m_extract_trail.push_back(args);
|
||||||
|
m_trail.push_back(trail_item::mk_extract);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdd slicing::mk_extract(pvar src, unsigned hi, unsigned lo) {
|
void slicing::undo_mk_extract() {
|
||||||
return m_solver.var(mk_extract_var(src, hi, lo));
|
extract_args args = m_extract_trail.back();
|
||||||
|
m_extract_trail.pop_back();
|
||||||
|
m_extract_dedup.remove(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdd slicing::mk_extract(pdd const& p, unsigned hi, unsigned lo) {
|
pvar slicing::mk_concat(unsigned num_args, pvar const* args) {
|
||||||
SASSERT(hi >= lo);
|
NOT_IMPLEMENTED_YET();
|
||||||
SASSERT(p.power_of_2() > hi);
|
return null_var;
|
||||||
if (p.is_val()) {
|
#if 0
|
||||||
// p[hi:lo] = (p >> lo) % 2^(hi - lo + 1)
|
|
||||||
rational q = mod2k(machine_div2k(p.val(), lo), hi - lo + 1);
|
|
||||||
return p.manager().mk_val(q);
|
|
||||||
}
|
|
||||||
if (!lo) {
|
|
||||||
// TODO: we could push the extract down into variables of the term instead of introducing a name.
|
|
||||||
}
|
|
||||||
return m_solver.var(mk_slice_extract(pdd2slice(p), hi, lo));
|
|
||||||
}
|
|
||||||
|
|
||||||
slicing::enode* slicing::pdd2slice(pdd const& p) {
|
|
||||||
pvar const v = m_solver.m_names.mk_name(p);
|
|
||||||
return var2slice(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdd slicing::mk_concat(pdd const& p, pdd const& q) {
|
|
||||||
// v := p ++ q (new variable of size |p| + |q|)
|
// v := p ++ q (new variable of size |p| + |q|)
|
||||||
// v[:|q|] = p
|
// v[:|q|] = p
|
||||||
// v[|q|:] = q
|
// v[|q|:] = q
|
||||||
|
@ -707,6 +715,11 @@ namespace polysat {
|
||||||
tmp.push_back(pdd2slice(q));
|
tmp.push_back(pdd2slice(q));
|
||||||
VERIFY(merge(tmp, var2slice(v), dep_t()));
|
VERIFY(merge(tmp, var2slice(v), dep_t()));
|
||||||
return m_solver.var(v);
|
return m_solver.var(v);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
pvar slicing::mk_concat(std::initializer_list<pvar> args) {
|
||||||
|
return mk_concat(args.size(), args.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
void slicing::add_constraint(signed_constraint c) {
|
void slicing::add_constraint(signed_constraint c) {
|
||||||
|
@ -838,9 +851,18 @@ namespace polysat {
|
||||||
// properties below only matter for representatives
|
// properties below only matter for representatives
|
||||||
if (!s->is_root())
|
if (!s->is_root())
|
||||||
continue;
|
continue;
|
||||||
|
enode_vector s_base;
|
||||||
|
get_base(s, s_base);
|
||||||
for (enode* n : euf::enode_class(s)) {
|
for (enode* n : euf::enode_class(s)) {
|
||||||
// equivalence class only contains slices of equal length
|
// equivalence class only contains slices of equal length
|
||||||
VERIFY_EQ(width(s), width(n));
|
VERIFY_EQ(width(s), width(n));
|
||||||
|
// bases of equivalent nodes are equivalent
|
||||||
|
enode_vector n_base;
|
||||||
|
get_base(n, n_base);
|
||||||
|
VERIFY_EQ(s_base.size(), n_base.size());
|
||||||
|
for (unsigned i = s_base.size(); i-- > 0; ) {
|
||||||
|
VERIFY_EQ(s_base[i]->get_root(), n_base[i]->get_root());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -189,16 +189,32 @@ namespace polysat {
|
||||||
// Check whether two slices are known to be equal
|
// Check whether two slices are known to be equal
|
||||||
bool is_equal(enode* x, enode* y);
|
bool is_equal(enode* x, enode* y);
|
||||||
|
|
||||||
enum class trail_item {
|
// deduplication of extract terms
|
||||||
|
struct extract_args {
|
||||||
|
pvar src;
|
||||||
|
unsigned hi;
|
||||||
|
unsigned lo;
|
||||||
|
bool operator==(extract_args const& other) const { return src == other.src && hi == other.hi && lo == other.lo; }
|
||||||
|
unsigned hash() const { return mk_mix(src, hi, lo); }
|
||||||
|
};
|
||||||
|
using extract_args_eq = default_eq<extract_args>;
|
||||||
|
using extract_args_hash = obj_hash<extract_args>;
|
||||||
|
using extract_map = map<extract_args, pvar, extract_args_hash, extract_args_eq>;
|
||||||
|
extract_map m_extract_dedup;
|
||||||
|
|
||||||
|
enum class trail_item : std::uint8_t {
|
||||||
add_var,
|
add_var,
|
||||||
split_core,
|
split_core,
|
||||||
|
mk_extract,
|
||||||
};
|
};
|
||||||
svector<trail_item> m_trail;
|
svector<trail_item> m_trail;
|
||||||
enode_vector m_split_trail;
|
enode_vector m_split_trail;
|
||||||
|
svector<extract_args> m_extract_trail;
|
||||||
unsigned_vector m_scopes;
|
unsigned_vector m_scopes;
|
||||||
|
|
||||||
void undo_add_var();
|
void undo_add_var();
|
||||||
void undo_split_core();
|
void undo_split_core();
|
||||||
|
void undo_mk_extract();
|
||||||
|
|
||||||
mutable enode_vector m_tmp1;
|
mutable enode_vector m_tmp1;
|
||||||
mutable enode_vector m_tmp2;
|
mutable enode_vector m_tmp2;
|
||||||
|
@ -207,18 +223,12 @@ namespace polysat {
|
||||||
sat::literal_set m_marked_lits;
|
sat::literal_set m_marked_lits;
|
||||||
uint_set m_marked_vars;
|
uint_set m_marked_vars;
|
||||||
|
|
||||||
// get a slice that is equivalent to the given pdd (may introduce new variable)
|
|
||||||
enode* pdd2slice(pdd const& p);
|
|
||||||
|
|
||||||
/** Get variable representing src[hi:lo] */
|
/** Get variable representing src[hi:lo] */
|
||||||
pvar mk_slice_extract(enode* src, unsigned hi, unsigned lo);
|
pvar mk_extract(enode* src, unsigned hi, unsigned lo);
|
||||||
|
|
||||||
bool invariant() const;
|
bool invariant() const;
|
||||||
bool invariant_needs_congruence() const;
|
bool invariant_needs_congruence() const;
|
||||||
|
|
||||||
/** Get variable representing x[hi:lo] */
|
|
||||||
pvar mk_extract_var(pvar x, unsigned hi, unsigned lo);
|
|
||||||
|
|
||||||
std::ostream& display(std::ostream& out, enode* s) const;
|
std::ostream& display(std::ostream& out, enode* s) const;
|
||||||
std::ostream& display_tree(std::ostream& out, enode* s, unsigned indent, unsigned hi, unsigned lo) const;
|
std::ostream& display_tree(std::ostream& out, enode* s, unsigned indent, unsigned hi, unsigned lo) const;
|
||||||
|
|
||||||
|
@ -230,14 +240,12 @@ namespace polysat {
|
||||||
|
|
||||||
void add_var(unsigned bit_width);
|
void add_var(unsigned bit_width);
|
||||||
|
|
||||||
/** Create expression for x[hi:lo] */
|
/** Get or create variable representing x[hi:lo] */
|
||||||
pdd mk_extract(pvar x, unsigned hi, unsigned lo);
|
pvar mk_extract(pvar x, unsigned hi, unsigned lo);
|
||||||
|
|
||||||
/** Create expression for p[hi:lo] */
|
/** Get or create variable representing x1 ++ x2 ++ ... ++ xn */
|
||||||
pdd mk_extract(pdd const& p, unsigned hi, unsigned lo);
|
pvar mk_concat(unsigned num_args, pvar const* args);
|
||||||
|
pvar mk_concat(std::initializer_list<pvar> args);
|
||||||
/** Create expression for p ++ q */
|
|
||||||
pdd mk_concat(pdd const& p, pdd const& q);
|
|
||||||
|
|
||||||
// Track value assignments to variables (and propagate to subslices)
|
// Track value assignments to variables (and propagate to subslices)
|
||||||
// (could generalize to fixed bits, then we need a way to merge interpreted enodes)
|
// (could generalize to fixed bits, then we need a way to merge interpreted enodes)
|
||||||
|
|
|
@ -82,13 +82,13 @@ namespace polysat {
|
||||||
pvar x = s.add_var(8);
|
pvar x = s.add_var(8);
|
||||||
pvar y = s.add_var(8);
|
pvar y = s.add_var(8);
|
||||||
|
|
||||||
pvar a = sl.mk_extract_var(x, 7, 3);
|
pvar a = sl.mk_extract(x, 7, 3);
|
||||||
std::cout << sl << "\n";
|
std::cout << sl << "\n";
|
||||||
|
|
||||||
VERIFY(sl.merge(sl.var2slice(x), sl.var2slice(y), sat::literal(1)));
|
VERIFY(sl.merge(sl.var2slice(x), sl.var2slice(y), sat::literal(1)));
|
||||||
std::cout << sl << "\n";
|
std::cout << sl << "\n";
|
||||||
|
|
||||||
pvar b = sl.mk_extract_var(y, 5, 0);
|
pvar b = sl.mk_extract(y, 5, 0);
|
||||||
std::cout << sl << "\n";
|
std::cout << sl << "\n";
|
||||||
|
|
||||||
sl.display_tree(std::cout);
|
sl.display_tree(std::cout);
|
||||||
|
@ -113,17 +113,17 @@ namespace polysat {
|
||||||
pvar y = s.add_var(8);
|
pvar y = s.add_var(8);
|
||||||
std::cout << sl << "\n";
|
std::cout << sl << "\n";
|
||||||
|
|
||||||
pvar a = sl.mk_extract_var(x, 7, 3);
|
pvar a = sl.mk_extract(x, 7, 3);
|
||||||
std::cout << "v" << a << " := v" << x << "[7:3]\n" << sl << "\n";
|
std::cout << "v" << a << " := v" << x << "[7:3]\n" << sl << "\n";
|
||||||
pvar b = sl.mk_extract_var(y, 5, 0);
|
pvar b = sl.mk_extract(y, 5, 0);
|
||||||
std::cout << "v" << b << " := v" << y << "[5:0]\n" << sl << "\n";
|
std::cout << "v" << b << " := v" << y << "[5:0]\n" << sl << "\n";
|
||||||
pvar c = sl.mk_extract_var(x, 5, 0);
|
pvar c = sl.mk_extract(x, 5, 0);
|
||||||
std::cout << "v" << c << " := v" << x << "[5:0]\n" << sl << "\n";
|
std::cout << "v" << c << " := v" << x << "[5:0]\n" << sl << "\n";
|
||||||
pdd d = sl.mk_concat(sl.mk_extract(x, 5, 4), sl.mk_extract(y, 3, 0));
|
pvar d = sl.mk_concat({sl.mk_extract(x, 5, 4), sl.mk_extract(y, 3, 0)});
|
||||||
std::cout << d << " := v" << x << "[5:4] ++ v" << y << "[3:0]\n" << sl << "\n";
|
std::cout << d << " := v" << x << "[5:4] ++ v" << y << "[3:0]\n" << sl << "\n";
|
||||||
|
|
||||||
std::cout << "v" << b << " = v" << c << "? " << sl.is_equal(sl.var2slice(b), sl.var2slice(c)) << "\n\n";
|
std::cout << "v" << b << " = v" << c << "? " << sl.is_equal(sl.var2slice(b), sl.var2slice(c)) << "\n\n";
|
||||||
std::cout << "v" << b << " = " << d << "? " << sl.is_equal(sl.var2slice(b), sl.pdd2slice(d)) << "\n\n";
|
std::cout << "v" << b << " = v" << d << "? " << sl.is_equal(sl.var2slice(b), sl.var2slice(d)) << "\n\n";
|
||||||
|
|
||||||
VERIFY(sl.merge(sl.var2slice(x), sl.var2slice(y), sat::literal(123)));
|
VERIFY(sl.merge(sl.var2slice(x), sl.var2slice(y), sat::literal(123)));
|
||||||
std::cout << "v" << x << " = v" << y << "\n" << sl << "\n";
|
std::cout << "v" << x << " = v" << y << "\n" << sl << "\n";
|
||||||
|
@ -137,13 +137,13 @@ namespace polysat {
|
||||||
sl.explain_equal(sl.var2slice(b), sl.var2slice(c), reason_lits, reason_vars);
|
sl.explain_equal(sl.var2slice(b), sl.var2slice(c), reason_lits, reason_vars);
|
||||||
std::cout << " Reason: " << reason_lits << " vars " << reason_vars << "\n";
|
std::cout << " Reason: " << reason_lits << " vars " << reason_vars << "\n";
|
||||||
|
|
||||||
std::cout << "v" << b << " = " << d << "? " << sl.is_equal(sl.var2slice(b), sl.pdd2slice(d))
|
std::cout << "v" << b << " = v" << d << "? " << sl.is_equal(sl.var2slice(b), sl.var2slice(d))
|
||||||
<< " root(v" << b << ") = " << sl.var2slice(b)->get_root_id()
|
<< " root(v" << b << ") = " << sl.var2slice(b)->get_root_id()
|
||||||
<< " root(" << d << ") = " << sl.pdd2slice(d)->get_root_id()
|
<< " root(v" << d << ") = " << sl.var2slice(d)->get_root_id()
|
||||||
<< "\n";
|
<< "\n";
|
||||||
reason_lits.reset();
|
reason_lits.reset();
|
||||||
reason_vars.reset();
|
reason_vars.reset();
|
||||||
sl.explain_equal(sl.var2slice(b), sl.pdd2slice(d), reason_lits, reason_vars);
|
sl.explain_equal(sl.var2slice(b), sl.var2slice(d), reason_lits, reason_vars);
|
||||||
std::cout << " Reason: " << reason_lits << " vars " << reason_vars << "\n";
|
std::cout << " Reason: " << reason_lits << " vars " << reason_vars << "\n";
|
||||||
|
|
||||||
sl.display_tree(std::cout);
|
sl.display_tree(std::cout);
|
||||||
|
@ -171,9 +171,13 @@ namespace polysat {
|
||||||
pvar e = s.add_var(2);
|
pvar e = s.add_var(2);
|
||||||
|
|
||||||
VERIFY(sl.merge(sl.var2slice(a), sl.var2slice(b), sat::literal(101)));
|
VERIFY(sl.merge(sl.var2slice(a), sl.var2slice(b), sat::literal(101)));
|
||||||
VERIFY(sl.merge(sl.var2slice(d), sl.var2slice(sl.mk_extract_var(c, 1, 0)), sat::literal(102)));
|
VERIFY(sl.merge(sl.var2slice(d), sl.var2slice(sl.mk_extract(c, 1, 0)), sat::literal(102)));
|
||||||
VERIFY(sl.merge(sl.var2slice(c), sl.var2slice(sl.mk_extract_var(b, 3, 0)), sat::literal(103)));
|
VERIFY(sl.merge(sl.var2slice(c), sl.var2slice(sl.mk_extract(b, 3, 0)), sat::literal(103)));
|
||||||
VERIFY(sl.merge(sl.var2slice(e), sl.var2slice(sl.mk_extract_var(a, 1, 0)), sat::literal(104)));
|
VERIFY(sl.merge(sl.var2slice(e), sl.var2slice(sl.mk_extract(a, 1, 0)), sat::literal(104)));
|
||||||
|
|
||||||
|
// sl.propagate();
|
||||||
|
sl.display_tree(std::cout);
|
||||||
|
VERIFY(sl.invariant());
|
||||||
|
|
||||||
std::cout << "v" << d << " = v" << e << "? " << sl.is_equal(sl.var2slice(d), sl.var2slice(e))
|
std::cout << "v" << d << " = v" << e << "? " << sl.is_equal(sl.var2slice(d), sl.var2slice(e))
|
||||||
<< " root(v" << d << ") = " << sl.var2slice(d)->get_root_id()
|
<< " root(v" << d << ") = " << sl.var2slice(d)->get_root_id()
|
||||||
|
@ -185,9 +189,6 @@ namespace polysat {
|
||||||
unsigned_vector reason_vars;
|
unsigned_vector reason_vars;
|
||||||
sl.explain_equal(sl.var2slice(d), sl.var2slice(e), reason_lits, reason_vars);
|
sl.explain_equal(sl.var2slice(d), sl.var2slice(e), reason_lits, reason_vars);
|
||||||
std::cout << " Reason: " << reason_lits << " vars " << reason_vars << "\n";
|
std::cout << " Reason: " << reason_lits << " vars " << reason_vars << "\n";
|
||||||
|
|
||||||
sl.display_tree(std::cout);
|
|
||||||
VERIFY(sl.invariant());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// x[5:2] = y
|
// x[5:2] = y
|
||||||
|
@ -201,9 +202,9 @@ namespace polysat {
|
||||||
pvar x = s.add_var(6);
|
pvar x = s.add_var(6);
|
||||||
std::cout << sl << "\n";
|
std::cout << sl << "\n";
|
||||||
|
|
||||||
pvar y = sl.mk_extract_var(x, 5, 2);
|
pvar y = sl.mk_extract(x, 5, 2);
|
||||||
std::cout << "v" << y << " := v" << x << "[5:2]\n" << sl << "\n";
|
std::cout << "v" << y << " := v" << x << "[5:2]\n" << sl << "\n";
|
||||||
pvar z = sl.mk_extract_var(x, 3, 0);
|
pvar z = sl.mk_extract(x, 3, 0);
|
||||||
std::cout << "v" << z << " := v" << x << "[3:0]\n" << sl << "\n";
|
std::cout << "v" << z << " := v" << x << "[3:0]\n" << sl << "\n";
|
||||||
|
|
||||||
slicing::enode* nine = sl.mk_value_slice(rational(9), 4);
|
slicing::enode* nine = sl.mk_value_slice(rational(9), 4);
|
||||||
|
@ -280,12 +281,12 @@ namespace polysat {
|
||||||
|
|
||||||
void tst_slicing() {
|
void tst_slicing() {
|
||||||
using namespace polysat;
|
using namespace polysat;
|
||||||
// test_slicing::test1();
|
test_slicing::test1();
|
||||||
// test_slicing::test2();
|
test_slicing::test2();
|
||||||
// test_slicing::test3();
|
// test_slicing::test3();
|
||||||
// test_slicing::test4();
|
test_slicing::test4();
|
||||||
// test_slicing::test5();
|
test_slicing::test5();
|
||||||
// test_slicing::test6();
|
test_slicing::test6();
|
||||||
test_slicing::test7();
|
test_slicing::test7();
|
||||||
std::cout << "ok\n";
|
std::cout << "ok\n";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue