3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-22 05:43:39 +00:00

debug projection

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2014-09-18 20:45:13 -07:00
commit 0d5b1637ba
7 changed files with 447 additions and 268 deletions

View file

@ -22,7 +22,7 @@ Revision History:
#include "doc.h" #include "doc.h"
doc_manager::doc_manager(unsigned n): m(n) { doc_manager::doc_manager(unsigned n): m(n), m_alloc("doc") {
m_full = m.allocateX(); m_full = m.allocateX();
} }
@ -30,39 +30,43 @@ doc_manager::~doc_manager() {
m.deallocate(m_full); m.deallocate(m_full);
} }
void doc_manager::reset() {
// m.reset(); - not until docs are in small object allocator.
}
doc* doc_manager::allocate() { doc* doc_manager::allocate() {
return alloc(doc, m.allocate()); return allocate(m.allocate());
} }
doc* doc_manager::allocate1() { doc* doc_manager::allocate1() {
return alloc(doc, m.allocate1()); return allocate(m.allocate1());
} }
doc* doc_manager::allocate0() { doc* doc_manager::allocate0() {
return alloc(doc, m.allocate0()); return allocate(m.allocate0());
} }
doc* doc_manager::allocateX() { doc* doc_manager::allocateX() {
return alloc(doc, m.allocateX()); return allocate(m.allocateX());
} }
doc* doc_manager::allocate(doc const& src) { doc* doc_manager::allocate(doc const& src) {
doc* r = alloc(doc, m.allocate(src.pos())); doc* r = allocate(m.allocate(src.pos()));
for (unsigned i = 0; i < src.neg().size(); ++i) { for (unsigned i = 0; i < src.neg().size(); ++i) {
r->neg().push_back(m.allocate(src.neg()[i])); r->neg().push_back(m.allocate(src.neg()[i]));
} }
return r; return r;
} }
doc* doc_manager::allocate(tbv* t) {
void* mm = m_alloc.allocate(sizeof(doc));
return new (mm) doc(t);
}
doc* doc_manager::allocate(tbv const& src) {
return allocate(m.allocate(src));
}
doc* doc_manager::allocate(uint64 n) { doc* doc_manager::allocate(uint64 n) {
return alloc(doc, m.allocate(n)); return allocate(m.allocate(n));
} }
doc* doc_manager::allocate(rational const& r) { doc* doc_manager::allocate(rational const& r) {
return alloc(doc, m.allocate(r)); return allocate(m.allocate(r));
} }
doc* doc_manager::allocate(uint64 n, unsigned hi, unsigned lo) { doc* doc_manager::allocate(uint64 n, unsigned hi, unsigned lo) {
return alloc(doc, m.allocate(n, hi, lo)); return allocate(m.allocate(n, hi, lo));
} }
doc* doc_manager::allocate(doc const& src, unsigned const* permutation) { doc* doc_manager::allocate(doc const& src, unsigned const* permutation) {
doc* r = alloc(doc, m.allocate(src.pos(), permutation)); doc* r = allocate(m.allocate(src.pos(), permutation));
for (unsigned i = 0; i < src.neg().size(); ++i) { for (unsigned i = 0; i < src.neg().size(); ++i) {
r->neg().push_back(m.allocate(src.neg()[i], permutation)); r->neg().push_back(m.allocate(src.neg()[i], permutation));
} }
@ -72,7 +76,8 @@ void doc_manager::deallocate(doc* src) {
if (!src) return; if (!src) return;
m.deallocate(&src->pos()); m.deallocate(&src->pos());
src->neg().reset(m); src->neg().reset(m);
dealloc(src); m_alloc.deallocate(sizeof(doc), src);
// dealloc(src);
} }
void doc_manager::copy(doc& dst, doc const& src) { void doc_manager::copy(doc& dst, doc const& src) {
m.copy(dst.pos(), src.pos()); m.copy(dst.pos(), src.pos());
@ -105,11 +110,31 @@ doc& doc_manager::fillX(doc& src) {
bool doc_manager::set_and(doc& dst, doc const& src) { bool doc_manager::set_and(doc& dst, doc const& src) {
// (A \ B) & (C \ D) = (A & C) \ (B u D) // (A \ B) & (C \ D) = (A & C) \ (B u D)
if (!m.set_and(dst.pos(), src.pos())) return false; if (!m.set_and(dst.pos(), src.pos())) return false;
for (unsigned i = 0; i < dst.neg().size(); ++i) {
if (!m.set_and(dst.neg()[i], dst.pos())) {
dst.neg().erase(m, i);
--i;
}
}
tbv_ref t(m);
for (unsigned i = 0; i < src.neg().size(); ++i) { for (unsigned i = 0; i < src.neg().size(); ++i) {
dst.neg().insert(m, m.allocate(src.neg()[i])); t = m.allocate(src.neg()[i]);
if (m.set_and(*t, dst.pos())) {
dst.neg().insert(m, t.detach());
}
} }
return (src.neg().is_empty() || fold_neg(dst)); return (src.neg().is_empty() || fold_neg(dst));
} }
bool doc_manager::well_formed(doc const& d) const {
if (!m.is_well_formed(d.pos())) return false;
for (unsigned i = 0; i < d.neg().size(); ++i) {
if (!m.is_well_formed(d.neg()[i])) return false;
if (!m.contains(d.pos(), d.neg()[i])) return false;
}
return true;
}
bool doc_manager::fold_neg(doc& dst) { bool doc_manager::fold_neg(doc& dst) {
start_over: start_over:
for (unsigned i = 0; i < dst.neg().size(); ++i) { for (unsigned i = 0; i < dst.neg().size(); ++i) {
@ -153,143 +178,239 @@ unsigned doc_manager::diff_by_012(tbv const& pos, tbv const& neg, unsigned& inde
} }
return count; return count;
} }
doc* doc_manager::project(unsigned n, bool const* to_delete, doc const& src) {
tbv* p = tbvm().project(n, to_delete, src.pos()); void doc_manager::set(doc& d, unsigned idx, tbit value) {
if (src.neg().is_empty()) { d.pos().set(idx, value);
// build doc from p. for (unsigned i = 0; i < d.neg().size(); ++i) {
return 0; d.neg()[i].set(idx, value);
} }
NOT_IMPLEMENTED_YET(); }
ptr_vector<tbv> todo;
#if 0 //
// tbv & ~tbv1 & ~tbv2 & .. // merge range from [lo:lo+length-1] with each index in equivalence class.
// Semantics of ~tbv1 is that it is a clause of literals. // under assumption of equalities and columns that are discarded.
// indices where BIT_1 is set are negative. //
// indices where BIT_0 is set are positive. bool doc_manager::merge(doc& d, unsigned lo, unsigned length, subset_ints& equalities, bit_vector const& discard_cols) {
// The first loop is supposed to project tbv_i directly for (unsigned i = 0; i < length; ++i) {
// when some safety condition is met. unsigned idx = lo + i;
// The second loop handles the remaining tbv_i that if (!merge(d, lo + i, equalities, discard_cols)) return false;
// don't meet the safety condition.
for (unsigned i = 0; i < src.neg().size(); ++i) {
if (can_project_neg(n, to_delete, src.neg()[i])) {
}
} }
#endif return true;
#if 0 }
// REVIEW: what is the spec for this code? bool doc_manager::merge(doc& d, unsigned idx, subset_ints& equalities, bit_vector const& discard_cols) {
ternary_diff_bitvector TBV(*this); unsigned root = equalities.find(idx);
if (!TBV.fold_neg()) idx = root;
return false; unsigned num_x = 0;
unsigned root1;
std::set<ternary_bitvector*> todo; tbit value = BIT_x;
cpy_bits_t cpy_bits; do {
ternary_bitvector newneg; switch (d[idx]) {
for (union_ternary_bitvector<ternary_bitvector>::iterator I = TBV.m_neg.begin(), case BIT_0:
E = TBV.m_neg.end(); I != E; ++I) { if (value == BIT_1) return false;
// check if subtract TBV should be skiped value = BIT_0;
for (unsigned i = 0; i < delcols.size()-1; ++i) { break;
unsigned idx = delcols[i]; case BIT_1:
if (I->get(idx) != TBV.m_pos.get(idx)) { // xx \ 1x if (value == BIT_0) return false;
if (analyze_copy_bit(TBV.m_pos, *I, delcols, cpy_bits)) value = BIT_1;
todo.insert(&*I); break;
goto skip_row; case BIT_x:
if (!discard_cols.get(idx)) {
++num_x;
root1 = idx;
} }
break;
default:
break;
} }
idx = equalities.next(idx);
newneg.reset(); }
I->project(delcols, new_size, newneg); while (idx != root);
result.m_neg.add_fact(newneg);
skip_row: ; if (num_x == 0) {
// nothing to do.
}
else if (value != BIT_x) {
do {
if (d[idx] == BIT_x) {
set(d, idx, value);
}
idx = equalities.next(idx);
}
while (idx != root);
}
else {
do {
if (!discard_cols.get(idx) && idx != root1) {
tbv* t = tbvm().allocate(d.pos());
t->set(idx, BIT_0);
t->set(root1, BIT_1);
d.neg().insert(tbvm(), t);
t = tbvm().allocate(d.pos());
t->set(idx, BIT_1);
t->set(root1, BIT_0);
d.neg().insert(tbvm(), t);
}
idx = equalities.next(idx);
}
while (idx != root);
}
return true;
}
//
// 1. If n = 0,1: can project directly.
// 2. If tbv_i uses X in all positions with vars or constant where tbv is constant: can project directly.
// 3. Perform resolution on remaining tbv_i
//
// tbv & ~tbv1 & ~tbv2 & .. & ~tbv_n
// Semantics of ~tbv1 is that it is a clause of literals.
// indices where BIT_1 is set are negative.
// indices where BIT_0 is set are positive.
//
doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, doc const& src) {
tbv_manager& dstt = dstm.m;
doc* r = dstm.allocate(dstt.project(n, to_delete, src.pos()));
if (src.neg().is_empty()) {
return r;
}
if (src.neg().size() == 1) {
r->neg().push_back(dstt.project(n, to_delete, src.neg()[0]));
return r;
} }
if (!todo.empty()) { //
for (std::set<ternary_bitvector*>::iterator I = todo.begin(), // All negations can be projected if they are sign compatible.
E = todo.end(); I != E; ++I) { //
for (unsigned i = 0; i < delcols.size()-1; ++i) { tbv_ref bits(tbvm(), tbvm().allocateX());
unsigned idx = delcols[i]; for (unsigned i = 0; i < src.neg().size(); ++i) {
if ((*I)->get(idx) != TBV.m_pos.get(idx)) { tbvm().set_and(*bits, src.neg()[i]);
cpy_bits_t::iterator II = cpy_bits.find(idx); }
if (II == cpy_bits.end()) bool can_project_const = true;
goto skip_bv; for (unsigned i = 0; can_project_const && i < n; ++i) {
can_project_const = !to_delete[i] || (*bits)[i] == BIT_x;
unsigned idx_keep = II->second.first; }
unsigned cpy_val = II->second.second; if (can_project_const) {
for (unsigned i = 0; i < src.neg().size(); ++i) {
if (!((*I)->get(idx) & cpy_val) || (*I)->get(idx_keep) != BIT_x) r->neg().push_back(dstt.project(n, to_delete, src.neg()[i]));
goto skip_bv; }
return r;
(*I)->set(idx_keep, (*I)->get(idx)); }
//
// A negation can be projected directly if it does not constrain
// deleted variables.
//
ptr_vector<tbv> todo;
for (unsigned i = 0; i < src.neg().size(); ++i) {
if (can_project_neg(src.pos(), n, to_delete, src.neg()[i])) {
r->neg().push_back(dstt.project(n, to_delete, src.neg()[i]));
}
else {
todo.push_back(tbvm().allocate(src.neg()[i]));
}
}
if (todo.empty()) {
return r;
}
ptr_vector<tbv> pos, neg, new_todo;
tbv_ref t1(tbvm()), t2(tbvm());
for (unsigned i = 0; i < n; ++i) {
if (to_delete[i] && (*bits)[i] != BIT_x) {
TRACE("doc", tout << "delete " << i << " ";
for (unsigned j = 0; j < todo.size(); ++j) {
tbvm().display(tout, *todo[j]) << " ";
}
tout << "\n";);
new_todo.reset();
pos.reset();
neg.reset();
for (unsigned j = 0; j < todo.size(); ++j) {
tbv& t = *todo[j];
switch(t[i]) {
case BIT_x: new_todo.push_back(&t); break;
case BIT_0: neg.push_back(&t); break;
case BIT_1: pos.push_back(&t); break;
default: UNREACHABLE(); break;
} }
} }
if (pos.empty() || neg.empty()) {
newneg.reset(); std::swap(new_todo, todo);
(*I)->project(delcols, new_size, newneg); continue;
result.m_neg.add_fact(newneg); }
skip_bv: ; TRACE("doc",
tout << "pos: ";
for (unsigned i = 0; i < pos.size(); ++i) {
tbvm().display(tout, *pos[i]) << " ";
}
tout << "\nneg: ";
for (unsigned i = 0; i < neg.size(); ++i) {
tbvm().display(tout, *neg[i]) << " ";
}
tout << "\n";
);
for (unsigned j = 0; j < pos.size(); ++j) {
for (unsigned k = 0; k < neg.size(); ++k) {
t1 = tbvm().allocate(*pos[j]);
(*t1).set(i, BIT_x);
if (tbvm().set_and(*t1, *neg[k])) {
(*t1).set(i, BIT_x);
new_todo.push_back(t1.detach());
}
}
}
for (unsigned i = 0; i < pos.size(); ++i) {
tbvm().deallocate(pos[i]);
}
for (unsigned i = 0; i < neg.size(); ++i) {
tbvm().deallocate(neg[i]);
}
std::swap(todo, new_todo);
} }
} }
for (unsigned i = 0; i < todo.size(); ++i) {
return !result.is_empty(); r->neg().push_back(dstt.project(n, to_delete, *todo[i]));
tbvm().deallocate(todo[i]);
// idx_del -> <idx_keep, val>
// val -> BIT_*
typedef std::map<unsigned, std::pair<unsigned, unsigned char> > cpy_bits_t;
static bool analyze_copy_bit(const ternary_bitvector& pos, const ternary_bitvector& neg,
const unsigned_vector& delcols, cpy_bits_t& cpy_bits) {
unsigned *del = delcols.c_ptr();
bool got_del_col = false, got_keep_col = false;
unsigned del_col = 0, keep_col = 0;
for (unsigned i = 0; i < pos.size(); ++i) {
if (pos.get(i) != neg.get(i)) {
if (*del == i) {
if (got_del_col)
return true;
del_col = i;
got_del_col = true;
} else {
if (got_keep_col)
return true;
keep_col = i;
got_keep_col = true;
}
}
if (i == *del)
++del;
}
if (!got_del_col || !got_keep_col)
return true;
if (neg.get(keep_col) == neg.get(del_col))
return false;
unsigned char val = neg.get(del_col);
cpy_bits_t::iterator I = cpy_bits.find(del_col);
if (I == cpy_bits.end())
cpy_bits[del_col] = std::make_pair(keep_col, val);
else {
// FIXME: eq classes with size > 1 not supported for now
SASSERT(I->second.first == keep_col);
I->second.second |= val;
}
return false;
} }
return r;
#endif
return 0;
} }
bool doc_manager::can_project_neg(tbv const& pos, unsigned n, bool const* to_delete, tbv const& neg) {
for (unsigned i = 0; i < n; ++i) {
if (to_delete[i] && BIT_x != neg[i] && BIT_x == pos[i]) return false;
}
return true;
}
void doc_manager::complement(doc const& src, ptr_vector<doc>& result) { void doc_manager::complement(doc const& src, ptr_vector<doc>& result) {
NOT_IMPLEMENTED_YET(); result.reset();
if (is_full(src)) {
return;
}
doc* r = allocateX();
r->neg().push_back(m.allocate(src.pos()));
result.push_back(r);
for (unsigned i = 0; i < src.neg().size(); ++i) {
result.push_back(allocate(src.neg()[i]));
}
} }
void doc_manager::subtract(doc const& A, doc const& B, ptr_vector<doc>& result) { void doc_manager::subtract(doc const& A, doc const& B, ptr_vector<doc>& result) {
NOT_IMPLEMENTED_YET(); doc_ref r(*this), r2(*this);
r = allocate(A);
if (r->neg().insert(m, m.allocate(B.pos()))) {
result.push_back(r.detach());
r = allocate(A);
}
for (unsigned i = 0; i < B.neg().size(); ++i) {
r2 = allocate(B.neg()[i]);
if (set_and(*r, *r2)) {
result.push_back(r.detach());
r = allocate(A);
}
}
} }
bool doc_manager::equals(doc const& a, doc const& b) const { bool doc_manager::equals(doc const& a, doc const& b) const {
if (!m.equals(a.pos(), b.pos())) return false; if (!m.equals(a.pos(), b.pos())) return false;

View file

@ -29,20 +29,23 @@ Revision History:
class doc; class doc;
template<typename M, typename T> class union_bvec; template<typename M, typename T> class union_bvec;
typedef union_find<> subset_ints;
class doc_manager { class doc_manager {
tbv_manager m; tbv_manager m;
tbv* m_full; tbv* m_full;
small_object_allocator m_alloc;
public: public:
doc_manager(unsigned num_bits); doc_manager(unsigned num_bits);
~doc_manager(); ~doc_manager();
tbv_manager& tbvm() { return m; } tbv_manager& tbvm() { return m; }
void reset();
doc* allocate(); doc* allocate();
doc* allocate1(); doc* allocate1();
doc* allocate0(); doc* allocate0();
doc* allocateX(); doc* allocateX();
doc* allocate(doc const& src); doc* allocate(doc const& src);
doc* allocate(tbv const& src);
doc* allocate(tbv * src);
doc* allocate(uint64 n); doc* allocate(uint64 n);
doc* allocate(rational const& r); doc* allocate(rational const& r);
doc* allocate(uint64 n, unsigned hi, unsigned lo); doc* allocate(uint64 n, unsigned hi, unsigned lo);
@ -64,12 +67,16 @@ public:
bool contains(doc const& a, doc const& b) const; bool contains(doc const& a, doc const& b) const;
std::ostream& display(std::ostream& out, doc const& b) const; std::ostream& display(std::ostream& out, doc const& b) const;
unsigned num_tbits() const { return m.num_tbits(); } unsigned num_tbits() const { return m.num_tbits(); }
doc* project(unsigned n, bool const* to_delete, doc const& src); doc* project(doc_manager& dstm, unsigned n, bool const* to_delete, doc const& src);
bool well_formed(doc const& d) const;
bool merge(doc& d, unsigned lo, unsigned length, subset_ints& equalities, bit_vector const& discard_cols);
void set(doc& d, unsigned idx, tbit value);
private: private:
unsigned diff_by_012(tbv const& pos, tbv const& neg, unsigned& index); unsigned diff_by_012(tbv const& pos, tbv const& neg, unsigned& index);
bool merge(doc& d, unsigned idx, subset_ints& equalities, bit_vector const& discard_cols);
bool can_project_neg(tbv const& pos, unsigned n, bool const* to_delete, tbv const& neg);
}; };
typedef union_find<> subset_ints;
// union of tbv*, union of doc* // union of tbv*, union of doc*
template<typename M, typename T> template<typename M, typename T>
@ -210,98 +217,31 @@ public:
push_back(m.allocate(other[i])); push_back(m.allocate(other[i]));
} }
} }
void fix_eq_bits(unsigned idx1, tbv* BV, unsigned idx2, unsigned length,
subset_ints& equalities, const bit_vector& discard_cols) {
for (unsigned i = 0; i < length; ++i) {
unsigned k = 0;
for (unsigned j = 0; j < size(); ++j, ++k) {
NOT_IMPLEMENTED_YET();
#if 0 void merge(M& m, unsigned lo, unsigned length, subset_ints & equalities, bit_vector const& discard_cols) {
T *eqBV = BV ? const_cast<T*>(BV) : &*I; for (unsigned i = 0; i < size(); ++i) {
bool discard_col = discard_cols.get(idx1+i) || (!BV && discard_cols.get(idx2+i)); if (!m.merge(*m_elems[i], lo, length, equalities, discard_cols)) {
erase(m, i);
switch (fix_single_bit(*I, idx1+i, eqBV, idx2+i, equalities, discard_col)) { --i;
case 1:
// remove row
I = m_bitvectors.erase(I);
break;
case 2: {
// don't care column equality. try subtraction first.
union_ternary_bitvector diff(I->size()), result(I->size());
T BV(I->size(), true);
BV.set(idx1+i, BIT_0);
BV.set(idx2+i, BIT_1);
diff.add_new_fact(BV);
BV.set(idx1+i, BIT_1);
BV.set(idx2+i, BIT_0);
diff.add_new_fact(BV);
I->subtract(diff, result);
*I = *result.begin();
++I;
break;
}
default:
if (I->is_empty()) {
I = m_bitvectors.erase(I);
} else {
// bits fixed
++I;
}
}
#endif
} }
} }
} }
void merge(M& m, unsigned lo1, unsigned lo2, unsigned length, bit_vector const& discard_cols) {
union_find_default_ctx union_ctx;
subset_ints equalities(union_ctx);
for (unsigned i = 0; i < discard_cols.size(); ++i) {
equalities.mk_var();
}
for (unsigned j = 0; j < length; ++j) {
equalities.merge(lo1 + j, lo2 + j);
}
merge(m, lo1, length, equalities, discard_cols);
}
private: private:
fix_bit_result_t fix_single_bit(tbv& bv, unsigned idx, unsigned value, const subset_ints& equalities) {
unsigned root = equalities.find(idx);
idx = root;
do {
unsigned bitval = bv.get(idx);
if (bitval == tbv::BIT_x) {
bv.set(idx, value);
}
else if (bitval != value) {
return e_row_removed;
}
idx = equalities.next(idx);
}
while (idx != root);
return e_fixed;
}
fix_bit_result_t fix_single_bit(tbv & BV1, unsigned idx1, tbv & BV2, unsigned idx2,
subset_ints& equalities, bool discard_col) {
unsigned A = BV1.get(idx1);
unsigned B = BV2.get(idx2);
if (A == tbv::BIT_x) {
if (B == tbv::BIT_x) {
// Both are don't cares.
if (!discard_col)
return e_duplicate_row;
equalities.merge(idx1, idx2);
return e_fixed;
} else {
// only A is don't care.
return fix_single_bit(BV1, idx1, B, equalities);
}
} else if (B == tbv::BIT_x) {
// Only B is don't care.
return fix_single_bit(BV2, idx2, A, equalities);
} else if (A == B) {
return e_fixed;
} else {
return e_row_removed;
}
}
}; };
@ -335,7 +275,7 @@ public:
utbv& neg() { return m_neg; } utbv& neg() { return m_neg; }
tbv const& pos() const { return *m_pos; } tbv const& pos() const { return *m_pos; }
utbv const& neg() const { return m_neg; } utbv const& neg() const { return m_neg; }
tbit operator[](unsigned idx) const { return pos()[idx]; }
}; };
typedef union_bvec<doc_manager, doc> udoc; typedef union_bvec<doc_manager, doc> udoc;
@ -356,6 +296,7 @@ public:
} }
doc& operator*() { return *d; } doc& operator*() { return *d; }
doc* operator->() { return d; } doc* operator->() { return d; }
doc* detach() { doc* r = d; d = 0; return r; }
}; };
#endif /* _DOC_H_ */ #endif /* _DOC_H_ */

View file

@ -19,12 +19,26 @@ Revision History:
--*/ --*/
#include "tbv.h" #include "tbv.h"
#include "hashtable.h"
tbv_manager::~tbv_manager() {
#if 0
ptr_vector<tbv>::iterator it = allocated_tbvs.begin(), end = allocated_tbvs.end();
for (; it != end; ++it) {
std::cout << "dangling: " << (*it) << "\n";
}
#endif
}
void tbv_manager::reset() { void tbv_manager::reset() {
m.reset(); m.reset();
} }
tbv* tbv_manager::allocate() { tbv* tbv_manager::allocate() {
return reinterpret_cast<tbv*>(m.allocate()); tbv* r = reinterpret_cast<tbv*>(m.allocate());
//std::cout << allocated_tbvs.size() << " " << r << "\n";
//allocated_tbvs.insert(r);
return r;
} }
tbv* tbv_manager::allocate1() { tbv* tbv_manager::allocate1() {
tbv* v = allocate(); tbv* v = allocate();
@ -42,7 +56,9 @@ tbv* tbv_manager::allocateX() {
return v; return v;
} }
tbv* tbv_manager::allocate(tbv const& bv) { tbv* tbv_manager::allocate(tbv const& bv) {
return reinterpret_cast<tbv*>(m.allocate(bv)); tbv* r = allocate();
copy(*r, bv);
return r;
} }
tbv* tbv_manager::allocate(uint64 val) { tbv* tbv_manager::allocate(uint64 val) {
tbv* v = allocate0(); tbv* v = allocate0();
@ -124,6 +140,13 @@ tbv* tbv_manager::allocate(rational const& r) {
return v; return v;
} }
void tbv_manager::deallocate(tbv* bv) { void tbv_manager::deallocate(tbv* bv) {
#if 0
if (!allocated_tbvs.contains(bv)) {
std::cout << "double deallocate: " << bv << "\n";
UNREACHABLE();
}
allocated_tbvs.erase(bv);
#endif
m.deallocate(bv); m.deallocate(bv);
} }
void tbv_manager::copy(tbv& dst, tbv const& src) const { void tbv_manager::copy(tbv& dst, tbv const& src) const {
@ -150,8 +173,12 @@ tbv& tbv_manager::set_or(tbv& dst, tbv const& src) const {
} }
bool tbv_manager::set_and(tbv& dst, tbv const& src) const { bool tbv_manager::set_and(tbv& dst, tbv const& src) const {
m.set_and(dst, src); m.set_and(dst, src);
return is_well_formed(dst);
}
bool tbv_manager::is_well_formed(tbv const& dst) const {
for (unsigned i = 0; i < num_tbits(); ++i) { for (unsigned i = 0; i < num_tbits(); ++i) {
if (dst.get(i) == BIT_z) return false; if (dst[i] == BIT_z) return false;
} }
return true; return true;
} }

View file

@ -40,8 +40,10 @@ inline tbit neg(tbit t) {
class tbv_manager { class tbv_manager {
friend class tbv; friend class tbv;
fixed_bit_vector_manager m; fixed_bit_vector_manager m;
// ptr_vector<tbv> allocated_tbvs;
public: public:
tbv_manager(unsigned n): m(2*n) {} tbv_manager(unsigned n): m(2*n) {}
~tbv_manager();
void reset(); void reset();
tbv* allocate(); tbv* allocate();
tbv* allocate1(); tbv* allocate1();
@ -70,6 +72,7 @@ public:
bool intersect(tbv const& a, tbv const& b, tbv& result); bool intersect(tbv const& a, tbv const& b, tbv& result);
std::ostream& display(std::ostream& out, tbv const& b) const; std::ostream& display(std::ostream& out, tbv const& b) const;
tbv* project(unsigned n, bool const* to_delete, tbv const& src); tbv* project(unsigned n, bool const* to_delete, tbv const& src);
bool is_well_formed(tbv const& b) const; // - does not contain BIT_z;
}; };
class tbv: private fixed_bit_vector { class tbv: private fixed_bit_vector {
@ -130,6 +133,7 @@ public:
} }
tbv& operator*() { return *d; } tbv& operator*() { return *d; }
tbv* get() { return d; } tbv* get() { return d; }
tbv* detach() { tbv* result = d; d = 0; return result; }
}; };

View file

@ -461,14 +461,18 @@ namespace datalog {
for (unsigned i = 0, e = m_empty_bv.size(); i < e; ++i) { for (unsigned i = 0, e = m_empty_bv.size(); i < e; ++i) {
m_equalities.mk_var(); m_equalities.mk_var();
} }
for (unsigned i = 1; i < col_cnt; ++i) {
for (unsigned j = 0; j < m_size; ++j) {
m_equalities.merge(m_cols[0]+j ,m_cols[i]+j);
}
}
} }
virtual void operator()(relation_base & _r) { virtual void operator()(relation_base & _r) {
udoc_relation& r = get(_r); udoc_relation& r = get(_r);
udoc& d = r.get_udoc(); udoc& d = r.get_udoc();
for (unsigned i = 1; i < m_cols.size(); ++i) { doc_manager& dm = r.get_dm();
d.fix_eq_bits(m_cols[0], 0, m_cols[i], m_size, m_equalities, m_empty_bv); d.merge(dm, m_cols[0], m_size, m_equalities, m_empty_bv);
}
TRACE("dl", tout << "final size: " << r.get_size_estimate_rows() << '\n';); TRACE("dl", tout << "final size: " << r.get_size_estimate_rows() << '\n';);
} }
}; };
@ -624,10 +628,10 @@ namespace datalog {
SASSERT(m.is_bool(g)); SASSERT(m.is_bool(g));
unsigned v = to_var(g)->get_idx(); unsigned v = to_var(g)->get_idx();
unsigned idx = column_idx(v); unsigned idx = column_idx(v);
doc_manager& dm1 = get_plugin().dm(1); doc_ref d(dm);
tbv_ref bit1(dm1.tbvm()); d = dm.allocateX();
bit1 = dm1.tbvm().allocate1(); dm.set(*d, idx, BIT_1);
result.fix_eq_bits(idx, bit1.get(), 0, 1, equalities, discard_cols); result.intersect(dm, *d);
} }
else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) {
unsigned hi, lo; unsigned hi, lo;
@ -650,7 +654,7 @@ namespace datalog {
unsigned idx1 = column_idx(v1->get_idx()); unsigned idx1 = column_idx(v1->get_idx());
unsigned idx2 = column_idx(v2->get_idx()); unsigned idx2 = column_idx(v2->get_idx());
unsigned length = column_num_bits(v1->get_idx()); unsigned length = column_num_bits(v1->get_idx());
result.fix_eq_bits(idx1, 0, idx2, length, equalities, discard_cols); result.merge(dm, idx1, idx2, length, discard_cols);
} }
else { else {
goto failure_case; goto failure_case;

View file

@ -9,14 +9,13 @@
#include "model_smt2_pp.h" #include "model_smt2_pp.h"
#include "smt_params.h" #include "smt_params.h"
#include "ast_util.h" #include "ast_util.h"
#include "expr_safe_replace.h"
#include "th_rewriter.h"
static void tst_doc1(unsigned n) { static void tst_doc1(unsigned n) {
doc_manager m(n); doc_manager m(n);
m.allocate();
m.reset();
doc_ref d(m, m.allocate()); doc_ref d(m, m.allocate());
doc_ref d1(m, m.allocate1()); doc_ref d1(m, m.allocate1());
doc_ref d0(m, m.allocate0()); doc_ref d0(m, m.allocate0());
@ -74,17 +73,25 @@ static void tst_doc1(unsigned n) {
m.display(std::cout, *d1) << "\n"; m.display(std::cout, *d1) << "\n";
#if 0
svector<bool> to_delete(n, false); svector<bool> to_delete(n, false);
to_delete[1] = true; to_delete[1] = true;
to_delete[3] = true; to_delete[3] = true;
doc_manager m1(n-2); doc_manager m1(n-2);
doc_ref d1_1(m1, m1.project(n, to_delete.c_ptr(), *d0)); doc_ref d1_1(m1, m.project(m1, n, to_delete.c_ptr(), *d1));
doc_ref d1_2(m1, m1.allocate1()); doc_ref d1_2(m1, m1.allocate1());
m.display(std::cout, *d1) << " -> "; m.display(std::cout, *d1) << " -> ";
m1.display(std::cout, *d1_1) << "\n"; m1.display(std::cout, *d1_1) << "\n";
SASSERT(m1.equals(*d1_1,*d1_2)); SASSERT(m1.equals(*d1_1,*d1_2));
#endif m.set(*d1,2,BIT_x);
m.set(*d1,4,BIT_x);
d1_1 = m.project(m1, n, to_delete.c_ptr(), *d1);
m.display(std::cout, *d1) << " -> ";
m1.display(std::cout, *d1_1) << "\n";
d1->neg().push_back(m.tbvm().allocate1());
SASSERT(m.well_formed(*d1));
d1_1 = m.project(m1, n, to_delete.c_ptr(), *d1);
m.display(std::cout, *d1) << " -> ";
m1.display(std::cout, *d1_1) << "\n";
} }
@ -106,48 +113,113 @@ class test_doc_project {
default : return BIT_x; default : return BIT_x;
} }
} }
void mk_clause(expr_ref& result, tbv& t) { expr_ref mk_conj(tbv& t) {
expr_ref_vector clause(m); expr_ref result(m);
expr_ref_vector conjs(m);
for (unsigned i = 0; i < m_vars.size(); ++i) { for (unsigned i = 0; i < m_vars.size(); ++i) {
tbit b = choose_tbit(); tbit b = choose_tbit();
t.set(i, b); t.set(i, b);
switch (b) { switch (b) {
case BIT_0: clause.push_back(m.mk_not(m_vars[i].get())); break; case BIT_1: conjs.push_back(m_vars[i].get()); break;
case BIT_1: clause.push_back(m_vars[i].get()); break; case BIT_0: conjs.push_back(m.mk_not(m_vars[i].get())); break;
default: break; default: break;
} }
} }
result = mk_or(m, clause.size(), clause.c_ptr()); result = mk_and(m, conjs.size(), conjs.c_ptr());
return result;
} }
expr_ref to_formula(tbv const& t, doc_manager& m2, bool const* to_delete) {
expr_ref result(m);
expr_ref_vector conjs(m);
unsigned n = m2.num_tbits();
tbv_manager& tm = m2.tbvm();
for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) {
if (!to_delete[i]) {
switch (t[j]) {
case BIT_x:
break;
case BIT_1:
conjs.push_back(m_vars[i].get());
break;
case BIT_0:
conjs.push_back(m.mk_not(m_vars[i].get()));
break;
default:
UNREACHABLE();
break;
}
++j;
}
}
result = mk_and(m, conjs.size(), conjs.c_ptr());
return result;
}
expr_ref to_formula(doc const& d, doc_manager& m2, bool const* to_delete) {
expr_ref result(m);
expr_ref_vector conjs(m);
conjs.push_back(to_formula(d.pos(), m2, to_delete));
for (unsigned i = 0; i < d.neg().size(); ++i) {
conjs.push_back(m.mk_not(to_formula(d.neg()[i], m2, to_delete)));
}
result = mk_and(m, conjs.size(), conjs.c_ptr());
return result;
}
void project(doc const& d, doc_manager& m2, bool const* to_delete, doc_ref& result) {
result = dm.project(m2, m_vars.size(), to_delete, d);
TRACE("doc",
for (unsigned i = 0; i < m_vars.size(); ++i) {
tout << (to_delete[i]?"0":"1");
}
tout << " ";
dm.display(tout, d) << " -> ";
m2.display(tout, *result) << "\n";
);
}
void test_clauses(unsigned num_clauses) { void test_clauses(unsigned num_clauses) {
doc_ref d(dm, dm.allocateX()); doc_ref d(dm, dm.allocateX());
expr_ref_vector fmls(m); expr_ref_vector fmls(m);
expr_ref fml(m); th_rewriter rw(m);
expr_ref fml1(m), fml2(m), fml3(m), tmp1(m), tmp2(m), fml(m);
for (unsigned i = 0; i < num_clauses; ++i) { for (unsigned i = 0; i < num_clauses; ++i) {
expr_ref clause(m);
tbv* t = dm.tbvm().allocate(); tbv* t = dm.tbvm().allocate();
mk_clause(clause, *t); fmls.push_back(m.mk_not(mk_conj(*t)));
d->neg().push_back(t); d->neg().push_back(t);
fmls.push_back(clause);
} }
fml = mk_and(m, fmls.size(), fmls.c_ptr()); fml1 = mk_and(m, fmls.size(), fmls.c_ptr());
dm.display(std::cout, *d) << "\n";
std::cout << fml << "\n";
for (unsigned i = 0; i < m_vars.size(); ++i) {
//test_project(i, fml, *d);
}
}
void test_project(unsigned i, expr* fml, doc& d) {
svector<bool> to_delete(m_vars.size(), false); svector<bool> to_delete(m_vars.size(), false);
to_delete[i] = true; unsigned num_bits = 1;
doc_manager dm1(m_vars.size()-1); for (unsigned i = 1; i < to_delete.size(); ++i) {
doc_ref d1(dm1, dm1.project(m_vars.size(), to_delete.c_ptr(), d)); to_delete[i] = (m_ran(2) == 0);
expr_ref fml1(m); if (!to_delete[i]) ++num_bits;
// fml1 = m.mk_exists(); }
// extrac formula fml2 from d1, doc_manager m2(num_bits);
// check that fml1 is equivalent to fml2 doc_ref result(m2);
project(*d, m2, to_delete.c_ptr(), result);
fml2 = to_formula(*result, m2, to_delete.c_ptr());
rw(fml2);
for (unsigned i = 0; i < m_vars.size(); ++i) {
if (to_delete[i]) {
expr_safe_replace rep1(m), rep2(m);
rep1.insert(m_vars[i].get(), m.mk_true());
rep1(fml1, tmp1);
rep2.insert(m_vars[i].get(), m.mk_false());
rep2(fml1, tmp2);
fml1 = m.mk_or(tmp1, tmp2);
}
}
rw(fml1);
smt_params fp;
smt::kernel solver(m, fp);
TRACE("doc", tout << "manual project:\n" << fml1 << "\nautomatic project: \n" << fml2 << "\n";);
fml = m.mk_not(m.mk_eq(fml1, fml2));
solver.assert_expr(fml);
lbool res = solver.check();
SASSERT(res == l_false);
} }
public: public:
@ -171,5 +243,5 @@ void tst_doc() {
tst_doc1(70); tst_doc1(70);
test_doc_project tp(4); test_doc_project tp(4);
tp(5,7); tp(200,7);
} }

View file

@ -24,6 +24,16 @@ static void tst1(unsigned num_bits) {
VERIFY(m.intersect(*bX,*b0,*bN)); VERIFY(m.intersect(*bX,*b0,*bN));
SASSERT(m.equals(*b0, *bN)); SASSERT(m.equals(*b0, *bN));
VERIFY(!m.intersect(*b0,*b1,*bN)); VERIFY(!m.intersect(*b0,*b1,*bN));
m.fill1(*b1);
svector<bool> to_delete(num_bits, false);
tbv_manager m2(num_bits-2);
to_delete[1] = true;
to_delete[3] = true;
(*b1).set(2, BIT_0);
(*b1).set(4, BIT_x);
tbv_ref b2(m2, m2.project(num_bits, to_delete.c_ptr(), *b1));
m.display(std::cout, *b1) << " -> ";
m2.display(std::cout, *b2) << "\n";
m.deallocate(b0); m.deallocate(b0);
m.deallocate(b1); m.deallocate(b1);
m.deallocate(bX); m.deallocate(bX);