mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 17:45:32 +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()) {
|
||||
case trail_item::add_var: undo_add_var(); break;
|
||||
case trail_item::split_core: undo_split_core(); break;
|
||||
case trail_item::mk_extract: undo_mk_extract(); break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
m_trail.pop_back();
|
||||
|
@ -644,49 +645,56 @@ namespace polysat {
|
|||
get_base_core<true>(src, out_base);
|
||||
}
|
||||
|
||||
pvar slicing::mk_slice_extract(enode* src, unsigned hi, unsigned lo) {
|
||||
enode_vector slices;
|
||||
pvar slicing::mk_extract(enode* src, unsigned hi, unsigned lo) {
|
||||
enode_vector& slices = m_tmp3;
|
||||
SASSERT(slices.empty());
|
||||
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) {
|
||||
enode* s = slices[0];
|
||||
if (slice2var(s) != null_var)
|
||||
return slice2var(s);
|
||||
// TODO: optimization: could save a slice-tree by directly assigning slice2var(s) = v for new var v.
|
||||
SASSERT_EQ(info(s).var, null_var);
|
||||
info(m_var2slice[v]).var = null_var; // disconnect the "phantom" enode
|
||||
info(s).var = v;
|
||||
m_var2slice[v] = s;
|
||||
}
|
||||
pvar v = m_solver.add_var(hi - lo + 1);
|
||||
// TODO: can we use 'compressed' slice trees again if we store the source slice here as dependency?
|
||||
#endif
|
||||
// connect new variable
|
||||
VERIFY(merge(slices, var2slice(v), dep_t()));
|
||||
slices.reset();
|
||||
return v;
|
||||
}
|
||||
|
||||
pvar slicing::mk_extract_var(pvar src, unsigned hi, unsigned lo) {
|
||||
return mk_slice_extract(var2slice(src), hi, lo);
|
||||
pvar slicing::mk_extract(pvar src, unsigned hi, unsigned 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) {
|
||||
return m_solver.var(mk_extract_var(src, hi, lo));
|
||||
void slicing::undo_mk_extract() {
|
||||
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) {
|
||||
SASSERT(hi >= lo);
|
||||
SASSERT(p.power_of_2() > hi);
|
||||
if (p.is_val()) {
|
||||
// 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) {
|
||||
pvar slicing::mk_concat(unsigned num_args, pvar const* args) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
return null_var;
|
||||
#if 0
|
||||
// v := p ++ q (new variable of size |p| + |q|)
|
||||
// v[:|q|] = p
|
||||
// v[|q|:] = q
|
||||
|
@ -707,6 +715,11 @@ namespace polysat {
|
|||
tmp.push_back(pdd2slice(q));
|
||||
VERIFY(merge(tmp, var2slice(v), dep_t()));
|
||||
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) {
|
||||
|
@ -838,9 +851,18 @@ namespace polysat {
|
|||
// properties below only matter for representatives
|
||||
if (!s->is_root())
|
||||
continue;
|
||||
enode_vector s_base;
|
||||
get_base(s, s_base);
|
||||
for (enode* n : euf::enode_class(s)) {
|
||||
// equivalence class only contains slices of equal length
|
||||
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;
|
||||
|
|
|
@ -189,16 +189,32 @@ namespace polysat {
|
|||
// Check whether two slices are known to be equal
|
||||
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,
|
||||
split_core,
|
||||
mk_extract,
|
||||
};
|
||||
svector<trail_item> m_trail;
|
||||
enode_vector m_split_trail;
|
||||
svector<extract_args> m_extract_trail;
|
||||
unsigned_vector m_scopes;
|
||||
|
||||
void undo_add_var();
|
||||
void undo_split_core();
|
||||
void undo_mk_extract();
|
||||
|
||||
mutable enode_vector m_tmp1;
|
||||
mutable enode_vector m_tmp2;
|
||||
|
@ -207,18 +223,12 @@ namespace polysat {
|
|||
sat::literal_set m_marked_lits;
|
||||
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] */
|
||||
pvar mk_slice_extract(enode* src, unsigned hi, unsigned lo);
|
||||
pvar mk_extract(enode* src, unsigned hi, unsigned lo);
|
||||
|
||||
bool invariant() 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_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);
|
||||
|
||||
/** Create expression for x[hi:lo] */
|
||||
pdd mk_extract(pvar x, unsigned hi, unsigned lo);
|
||||
/** Get or create variable representing x[hi:lo] */
|
||||
pvar mk_extract(pvar x, unsigned hi, unsigned lo);
|
||||
|
||||
/** Create expression for p[hi:lo] */
|
||||
pdd mk_extract(pdd const& p, unsigned hi, unsigned lo);
|
||||
|
||||
/** Create expression for p ++ q */
|
||||
pdd mk_concat(pdd const& p, pdd const& q);
|
||||
/** Get or create variable representing x1 ++ x2 ++ ... ++ xn */
|
||||
pvar mk_concat(unsigned num_args, pvar const* args);
|
||||
pvar mk_concat(std::initializer_list<pvar> args);
|
||||
|
||||
// Track value assignments to variables (and propagate to subslices)
|
||||
// (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 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";
|
||||
|
||||
VERIFY(sl.merge(sl.var2slice(x), sl.var2slice(y), sat::literal(1)));
|
||||
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";
|
||||
|
||||
sl.display_tree(std::cout);
|
||||
|
@ -113,17 +113,17 @@ namespace polysat {
|
|||
pvar y = s.add_var(8);
|
||||
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";
|
||||
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";
|
||||
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";
|
||||
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 << "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)));
|
||||
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);
|
||||
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(" << d << ") = " << sl.pdd2slice(d)->get_root_id()
|
||||
<< " root(v" << d << ") = " << sl.var2slice(d)->get_root_id()
|
||||
<< "\n";
|
||||
reason_lits.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";
|
||||
|
||||
sl.display_tree(std::cout);
|
||||
|
@ -171,9 +171,13 @@ namespace polysat {
|
|||
pvar e = s.add_var(2);
|
||||
|
||||
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(c), sl.var2slice(sl.mk_extract_var(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(d), sl.var2slice(sl.mk_extract(c, 1, 0)), sat::literal(102)));
|
||||
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(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))
|
||||
<< " root(v" << d << ") = " << sl.var2slice(d)->get_root_id()
|
||||
|
@ -185,9 +189,6 @@ namespace polysat {
|
|||
unsigned_vector reason_vars;
|
||||
sl.explain_equal(sl.var2slice(d), sl.var2slice(e), reason_lits, reason_vars);
|
||||
std::cout << " Reason: " << reason_lits << " vars " << reason_vars << "\n";
|
||||
|
||||
sl.display_tree(std::cout);
|
||||
VERIFY(sl.invariant());
|
||||
}
|
||||
|
||||
// x[5:2] = y
|
||||
|
@ -201,9 +202,9 @@ namespace polysat {
|
|||
pvar x = s.add_var(6);
|
||||
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";
|
||||
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";
|
||||
|
||||
slicing::enode* nine = sl.mk_value_slice(rational(9), 4);
|
||||
|
@ -280,12 +281,12 @@ namespace polysat {
|
|||
|
||||
void tst_slicing() {
|
||||
using namespace polysat;
|
||||
// test_slicing::test1();
|
||||
// test_slicing::test2();
|
||||
test_slicing::test1();
|
||||
test_slicing::test2();
|
||||
// test_slicing::test3();
|
||||
// test_slicing::test4();
|
||||
// test_slicing::test5();
|
||||
// test_slicing::test6();
|
||||
test_slicing::test4();
|
||||
test_slicing::test5();
|
||||
test_slicing::test6();
|
||||
test_slicing::test7();
|
||||
std::cout << "ok\n";
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue