mirror of
https://github.com/Z3Prover/z3
synced 2025-06-27 00:18:45 +00:00
last? bug-fix to new udoc_relation for feature parity
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
979d1f913a
commit
9cea3a1c02
7 changed files with 240 additions and 63 deletions
|
@ -3,6 +3,7 @@
|
||||||
#include "qe_util.h"
|
#include "qe_util.h"
|
||||||
#include "ast_util.h"
|
#include "ast_util.h"
|
||||||
#include "smt_kernel.h"
|
#include "smt_kernel.h"
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
|
|
||||||
namespace datalog {
|
namespace datalog {
|
||||||
|
@ -343,6 +344,12 @@ namespace datalog {
|
||||||
check_equiv("filter", fml1, fml2);
|
check_equiv("filter", fml1, fml2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void check_relation_plugin::check_contains(char const* objective, expr* fml1, expr* fml2) {
|
||||||
|
expr_ref fml0(m);
|
||||||
|
fml0 = m.mk_and(fml1, fml2);
|
||||||
|
check_equiv(objective, fml0, fml2);
|
||||||
|
}
|
||||||
|
|
||||||
void check_relation_plugin::check_equiv(char const* objective, expr* fml1, expr* fml2) {
|
void check_relation_plugin::check_equiv(char const* objective, expr* fml1, expr* fml2) {
|
||||||
TRACE("doc", tout << mk_pp(fml1, m) << "\n";
|
TRACE("doc", tout << mk_pp(fml1, m) << "\n";
|
||||||
tout << mk_pp(fml2, m) << "\n";);
|
tout << mk_pp(fml2, m) << "\n";);
|
||||||
|
@ -358,16 +365,20 @@ namespace datalog {
|
||||||
else {
|
else {
|
||||||
IF_VERBOSE(3, verbose_stream() << "NOT verified " << res << "\n";
|
IF_VERBOSE(3, verbose_stream() << "NOT verified " << res << "\n";
|
||||||
verbose_stream() << mk_pp(fml1, m) << "\n";
|
verbose_stream() << mk_pp(fml1, m) << "\n";
|
||||||
verbose_stream() << mk_pp(fml2, m) << "\n";);
|
verbose_stream() << mk_pp(fml2, m) << "\n";
|
||||||
|
verbose_stream().flush();
|
||||||
|
);
|
||||||
throw 0;
|
throw 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_relation_plugin::verify_union(expr* fml0, relation_base const& src, relation_base const& dst, relation_base const* delta) {
|
void check_relation_plugin::verify_union(expr* dst0, relation_base const& src,
|
||||||
expr_ref fml1(m), fml2(m), fml3(m);
|
relation_base const& dst,
|
||||||
|
expr* delta0, relation_base const* delta) {
|
||||||
|
expr_ref fml1(m), fml2(m);
|
||||||
src.to_formula(fml1);
|
src.to_formula(fml1);
|
||||||
dst.to_formula(fml2);
|
dst.to_formula(fml2);
|
||||||
fml1 = m.mk_or(fml1, fml0);
|
fml1 = m.mk_or(fml1, dst0);
|
||||||
relation_signature const& sig = dst.get_signature();
|
relation_signature const& sig = dst.get_signature();
|
||||||
expr_ref_vector vars(m);
|
expr_ref_vector vars(m);
|
||||||
var_subst sub(m, false);
|
var_subst sub(m, false);
|
||||||
|
@ -382,21 +393,30 @@ namespace datalog {
|
||||||
check_equiv("union", fml1, fml2);
|
check_equiv("union", fml1, fml2);
|
||||||
|
|
||||||
if (delta) {
|
if (delta) {
|
||||||
delta->to_formula(fml3);
|
expr_ref d0(m), d(m);
|
||||||
IF_VERBOSE(3, verbose_stream() << "verify delta\n";
|
delta->to_formula(d);
|
||||||
verbose_stream() << fml3 << "\n";);
|
IF_VERBOSE(3, verbose_stream() << "verify delta " << d << "\n";);
|
||||||
// delta >= dst \ fml0
|
// delta >= dst \ dst0
|
||||||
// dst \ fml0 == delta & dst & \ fml0
|
// dst \ dst0 == delta & dst & \ dst0
|
||||||
expr_ref fml4(m), fml5(m);
|
expr_ref fml4(m), fml5(m);
|
||||||
fml4 = m.mk_and(fml2, m.mk_not(fml0));
|
fml4 = m.mk_and(fml2, m.mk_not(dst0));
|
||||||
fml5 = m.mk_and(fml3, fml4);
|
sub(fml4, vars.size(), vars.c_ptr(), fml4);
|
||||||
|
sub(d, vars.size(), vars.c_ptr(), d);
|
||||||
|
check_contains("union_delta low", d, fml4);
|
||||||
|
//
|
||||||
|
// delta >= delta0
|
||||||
|
//
|
||||||
|
sub(delta0, vars.size(), vars.c_ptr(), d0);
|
||||||
|
check_contains("union delta0", d, d0);
|
||||||
|
|
||||||
|
//
|
||||||
|
// dst u delta0 = delta u dst0
|
||||||
|
//
|
||||||
|
fml4 = m.mk_or(fml2, delta0);
|
||||||
|
fml5 = m.mk_or(d, dst0);
|
||||||
sub(fml4, vars.size(), vars.c_ptr(), fml4);
|
sub(fml4, vars.size(), vars.c_ptr(), fml4);
|
||||||
sub(fml5, vars.size(), vars.c_ptr(), fml5);
|
sub(fml5, vars.size(), vars.c_ptr(), fml5);
|
||||||
check_equiv("union delta low", fml4, fml5);
|
check_equiv("union no overflow", fml4, fml5);
|
||||||
//fml4 = m.mk_and(fml3, fml2);
|
|
||||||
//sub(fml3, vars.size(), vars.c_ptr(), fml3);
|
|
||||||
//sub(fml4, vars.size(), vars.c_ptr(), fml4);
|
|
||||||
//check_equiv("union delta high", fml3, fml4);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,8 +431,10 @@ namespace datalog {
|
||||||
check_relation const& src = get(_src);
|
check_relation const& src = get(_src);
|
||||||
check_relation* d = get(_delta);
|
check_relation* d = get(_delta);
|
||||||
expr_ref fml0 = r.m_fml;
|
expr_ref fml0 = r.m_fml;
|
||||||
|
expr_ref delta0(r.m_fml.get_manager());
|
||||||
|
if (d) d->to_formula(delta0);
|
||||||
(*m_union)(r.rb(), src.rb(), d?(&d->rb()):0);
|
(*m_union)(r.rb(), src.rb(), d?(&d->rb()):0);
|
||||||
r.get_plugin().verify_union(fml0, src.rb(), r.rb(), d?(&d->rb()):0);
|
r.get_plugin().verify_union(fml0, src.rb(), r.rb(), delta0, d?(&d->rb()):0);
|
||||||
r.rb().to_formula(r.m_fml);
|
r.rb().to_formula(r.m_fml);
|
||||||
if (d) d->rb().to_formula(d->m_fml);
|
if (d) d->rb().to_formula(d->m_fml);
|
||||||
}
|
}
|
||||||
|
@ -595,12 +617,15 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void operator()(relation_base& tb, const relation_base& negb) {
|
virtual void operator()(relation_base& tb, const relation_base& negb) {
|
||||||
IF_VERBOSE(0, verbose_stream() << "TBD: verify filter_negation\n";);
|
|
||||||
check_relation& t = get(tb);
|
check_relation& t = get(tb);
|
||||||
check_relation const& n = get(negb);
|
check_relation const& n = get(negb);
|
||||||
check_relation_plugin& p = t.get_plugin();
|
check_relation_plugin& p = t.get_plugin();
|
||||||
|
ast_manager& m = p.get_ast_manager();
|
||||||
|
expr_ref dst0(m);
|
||||||
|
t.to_formula(dst0);
|
||||||
(*m_filter)(t.rb(), n.rb());
|
(*m_filter)(t.rb(), n.rb());
|
||||||
t.rb().to_formula(t.m_fml);
|
t.rb().to_formula(t.m_fml);
|
||||||
|
p.verify_filter_by_negation(dst0, t, n, m_t_cols, m_neg_cols);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -608,10 +633,57 @@ namespace datalog {
|
||||||
const relation_base& t,
|
const relation_base& t,
|
||||||
const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols,
|
const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols,
|
||||||
const unsigned *negated_cols) {
|
const unsigned *negated_cols) {
|
||||||
relation_intersection_filter_fn* f = mk_filter_by_negation_fn(get(t).rb(), get(neg).rb(), joined_col_cnt, t_cols, negated_cols);
|
relation_intersection_filter_fn* f = m_base->mk_filter_by_negation_fn(get(t).rb(), get(neg).rb(), joined_col_cnt, t_cols, negated_cols);
|
||||||
return f?alloc(negation_filter_fn, f, joined_col_cnt, t_cols, negated_cols):0;
|
return f?alloc(negation_filter_fn, f, joined_col_cnt, t_cols, negated_cols):0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The filter_by_negation postcondition:
|
||||||
|
filter_by_negation(tgt, neg, columns in tgt: c1,...,cN,
|
||||||
|
corresponding columns in neg: d1,...,dN):
|
||||||
|
tgt_1:={x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) }
|
||||||
|
*/
|
||||||
|
|
||||||
|
void check_relation_plugin::verify_filter_by_negation(
|
||||||
|
expr* dst0,
|
||||||
|
check_relation const& dst,
|
||||||
|
check_relation const& neg,
|
||||||
|
unsigned_vector const& cols1,
|
||||||
|
unsigned_vector const& cols2) {
|
||||||
|
relation_signature const& sig1 = dst.get_signature();
|
||||||
|
relation_signature const& sig2 = neg.get_signature();
|
||||||
|
expr_ref dstf(m), negf(m);
|
||||||
|
std::cout << mk_pp(dst0, m) << "\n";
|
||||||
|
expr_ref_vector eqs(m);
|
||||||
|
dst.to_formula(dstf);
|
||||||
|
std::cout << mk_pp(dstf, m) << "\n";
|
||||||
|
dst.to_formula(negf);
|
||||||
|
std::cout << mk_pp(negf, m) << "\n";
|
||||||
|
eqs.push_back(negf);
|
||||||
|
for (unsigned i = 0; i < cols1.size(); ++i) {
|
||||||
|
var_ref v1(m), v2(m);
|
||||||
|
unsigned c1 = cols1[i];
|
||||||
|
unsigned c2 = cols2[i];
|
||||||
|
SASSERT(sig1[c1] == sig2[c2]);
|
||||||
|
v1 = m.mk_var(sig2.size() + c1, sig1[c1]);
|
||||||
|
v2 = m.mk_var(c2, sig2[c2]);
|
||||||
|
eqs.push_back(m.mk_eq(v1, v2));
|
||||||
|
}
|
||||||
|
negf = mk_and(m, eqs.size(), eqs.c_ptr());
|
||||||
|
ptr_vector<sort> rev_sig2(sig2.size(), sig2.c_ptr());
|
||||||
|
rev_sig2.reverse();
|
||||||
|
svector<symbol> names;
|
||||||
|
for (unsigned i = 0; i < sig2.size(); ++i) {
|
||||||
|
names.push_back(symbol(i));
|
||||||
|
}
|
||||||
|
negf = m.mk_exists(rev_sig2.size(), rev_sig2.c_ptr(), names.c_ptr(), negf);
|
||||||
|
negf = m.mk_and(dst0, m.mk_not(negf));
|
||||||
|
negf = dst.ground(negf);
|
||||||
|
dstf = dst.ground(dstf);
|
||||||
|
std::cout << negf << "\n";
|
||||||
|
std::cout << dstf << "\n";
|
||||||
|
check_equiv("filter by negation", dstf, negf);
|
||||||
|
}
|
||||||
|
|
||||||
class check_relation_plugin::filter_proj_fn : public convenient_relation_project_fn {
|
class check_relation_plugin::filter_proj_fn : public convenient_relation_project_fn {
|
||||||
app_ref m_cond;
|
app_ref m_cond;
|
||||||
|
|
|
@ -115,7 +115,7 @@ namespace datalog {
|
||||||
void verify_filter(expr* fml0, relation_base const& t, expr* cond);
|
void verify_filter(expr* fml0, relation_base const& t, expr* cond);
|
||||||
|
|
||||||
void verify_union(expr* fml0, relation_base const& src, relation_base const& dst,
|
void verify_union(expr* fml0, relation_base const& src, relation_base const& dst,
|
||||||
relation_base const* delta);
|
expr* delta0, relation_base const* delta);
|
||||||
|
|
||||||
void verify_permutation(
|
void verify_permutation(
|
||||||
relation_base const& src, relation_base const& dst,
|
relation_base const& src, relation_base const& dst,
|
||||||
|
@ -135,11 +135,16 @@ namespace datalog {
|
||||||
relation_base const& src, relation_base const& dst,
|
relation_base const& src, relation_base const& dst,
|
||||||
app* cond, unsigned_vector const& removed_cols);
|
app* cond, unsigned_vector const& removed_cols);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void check_equiv(char const* objective, expr* f1, expr* f2);
|
void check_equiv(char const* objective, expr* f1, expr* f2);
|
||||||
|
|
||||||
|
void check_contains(char const* objective, expr* f1, expr* f2);
|
||||||
|
|
||||||
|
void verify_filter_by_negation(
|
||||||
|
expr* dst0,
|
||||||
|
check_relation const& dst,
|
||||||
|
check_relation const& neg,
|
||||||
|
unsigned_vector const& dst_eq,
|
||||||
|
unsigned_vector const& neg_eq);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -552,11 +552,33 @@ bool doc_manager::contains(doc const& a, doc const& b) const {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool doc_manager::contains(
|
||||||
|
unsigned offset_a, doc const& a,
|
||||||
|
doc_manager const& dm_b,
|
||||||
|
unsigned offset_b, doc const& b,
|
||||||
|
unsigned length) const {
|
||||||
|
if (!m.contains(offset_a, a.pos(), dm_b.tbvm(), offset_b, b.pos(), length)) return false;
|
||||||
|
for (unsigned i = 0; i < a.neg().size(); ++i) {
|
||||||
|
bool found = false;
|
||||||
|
for (unsigned j = 0; !found && j < b.neg().size(); ++j) {
|
||||||
|
found = dm_b.tbvm().contains(offset_b, b.neg()[j], tbvm(), offset_a, a.neg()[i], length);
|
||||||
|
}
|
||||||
|
if (!found) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream& doc_manager::display(std::ostream& out, doc const& b) const {
|
std::ostream& doc_manager::display(std::ostream& out, doc const& b) const {
|
||||||
m.display(out, b.pos());
|
if (num_tbits() == 0) return out << "[]";
|
||||||
|
return display(out, b, num_tbits()-1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& doc_manager::display(std::ostream& out, doc const& b, unsigned hi, unsigned lo) const {
|
||||||
|
m.display(out, b.pos(), hi, lo);
|
||||||
if (b.neg().is_empty()) return out;
|
if (b.neg().is_empty()) return out;
|
||||||
out << " \\ ";
|
out << " \\ ";
|
||||||
b.neg().display(m, out);
|
b.neg().display(m, out, hi, lo);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ 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; }
|
||||||
|
tbv_manager const& tbvm() const { return m; }
|
||||||
doc* allocate();
|
doc* allocate();
|
||||||
doc* allocate1();
|
doc* allocate1();
|
||||||
doc* allocate0();
|
doc* allocate0();
|
||||||
|
@ -81,7 +82,11 @@ public:
|
||||||
bool equals(doc const& a, doc const& b) const;
|
bool equals(doc const& a, doc const& b) const;
|
||||||
unsigned hash(doc const& src) const;
|
unsigned hash(doc const& src) const;
|
||||||
bool contains(doc const& a, doc const& b) const;
|
bool contains(doc const& a, doc const& b) const;
|
||||||
|
bool contains(unsigned offset_a, doc const& a,
|
||||||
|
doc_manager const& dm_b, unsigned offset_b, doc const& b,
|
||||||
|
unsigned length) const;
|
||||||
std::ostream& display(std::ostream& out, doc const& b) const;
|
std::ostream& display(std::ostream& out, doc const& b) const;
|
||||||
|
std::ostream& display(std::ostream& out, doc const& b, unsigned hi, unsigned lo) const;
|
||||||
unsigned num_tbits() const { return m.num_tbits(); }
|
unsigned num_tbits() const { return m.num_tbits(); }
|
||||||
doc* project(doc_manager& dstm, 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 well_formed(doc const& d) const;
|
||||||
|
@ -123,10 +128,16 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::ostream& display(M const& m, std::ostream& out) const {
|
std::ostream& display(M const& m, std::ostream& out) const {
|
||||||
|
if (m.num_tbits() == 0) return out << "[]";
|
||||||
|
return display(m, out, m.num_tbits()-1, 0);
|
||||||
|
}
|
||||||
|
std::ostream& display(M const& m, std::ostream& out, unsigned hi, unsigned lo) const {
|
||||||
out << "{";
|
out << "{";
|
||||||
|
if (size() + m.num_tbits() > 10) out << "\n ";
|
||||||
for (unsigned i = 0; i < size(); ++i) {
|
for (unsigned i = 0; i < size(); ++i) {
|
||||||
m.display(out, *m_elems[i]);
|
m.display(out, *m_elems[i], hi, lo);
|
||||||
if (i + 1 < size()) out << ", ";
|
if (i + 1 < size()) out << ", ";
|
||||||
|
if (i + 1 < size() && m.num_tbits() > 10) out << "\n ";
|
||||||
}
|
}
|
||||||
return out << "}";
|
return out << "}";
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,13 +244,31 @@ unsigned tbv_manager::hash(tbv const& src) const {
|
||||||
bool tbv_manager::contains(tbv const& a, tbv const& b) const {
|
bool tbv_manager::contains(tbv const& a, tbv const& b) const {
|
||||||
return m.contains(a, b);
|
return m.contains(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tbv_manager::contains(unsigned offset_a, tbv const& a,
|
||||||
|
tbv_manager const& dm_b, unsigned offset_b, tbv const& b,
|
||||||
|
unsigned length) const {
|
||||||
|
if (this == &dm_b && length == num_tbits()) {
|
||||||
|
SASSERT(offset_a == 0);
|
||||||
|
SASSERT(offset_b == 0);
|
||||||
|
return m.contains(a, b);
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < length; ++i) {
|
||||||
|
tbit bit_a = a[offset_a + i];
|
||||||
|
if (bit_a == BIT_x) continue;
|
||||||
|
if (bit_a != b[offset_b + i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool tbv_manager::intersect(tbv const& a, tbv const& b, tbv& result) {
|
bool tbv_manager::intersect(tbv const& a, tbv const& b, tbv& result) {
|
||||||
copy(result, a);
|
copy(result, a);
|
||||||
return set_and(result, b);
|
return set_and(result, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& tbv_manager::display(std::ostream& out, tbv const& b) const {
|
std::ostream& tbv_manager::display(std::ostream& out, tbv const& b, unsigned hi, unsigned lo) const {
|
||||||
for (unsigned i = 0; i < num_tbits(); ++i) {
|
SASSERT(lo <= hi && hi < num_tbits());
|
||||||
|
for (unsigned i = lo; i <= hi; ++i) {
|
||||||
switch (b.get(i)) {
|
switch (b.get(i)) {
|
||||||
case BIT_0:
|
case BIT_0:
|
||||||
out << '0';
|
out << '0';
|
||||||
|
@ -271,6 +289,11 @@ std::ostream& tbv_manager::display(std::ostream& out, tbv const& b) const {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& tbv_manager::display(std::ostream& out, tbv const& b) const {
|
||||||
|
if (num_tbits() == 0) return out << "[]";
|
||||||
|
return display(out, b, num_tbits()-1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
expr_ref tbv_manager::to_formula(ast_manager& m, tbv const& src) {
|
expr_ref tbv_manager::to_formula(ast_manager& m, tbv const& src) {
|
||||||
expr_ref result(m);
|
expr_ref result(m);
|
||||||
expr_ref_vector conj(m);
|
expr_ref_vector conj(m);
|
||||||
|
|
|
@ -70,8 +70,12 @@ public:
|
||||||
bool equals(tbv const& a, tbv const& b) const;
|
bool equals(tbv const& a, tbv const& b) const;
|
||||||
unsigned hash(tbv const& src) const;
|
unsigned hash(tbv const& src) const;
|
||||||
bool contains(tbv const& a, tbv const& b) const;
|
bool contains(tbv const& a, tbv const& b) const;
|
||||||
|
bool contains(unsigned offset_a, tbv const& a,
|
||||||
|
tbv_manager const& dm_b, unsigned offset_b, tbv const& b,
|
||||||
|
unsigned length) const;
|
||||||
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;
|
||||||
|
std::ostream& display(std::ostream& out, tbv const& b, unsigned hi, unsigned lo) 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;
|
bool is_well_formed(tbv const& b) const; // - does not contain BIT_z;
|
||||||
void set(tbv& dst, uint64 n, unsigned hi, unsigned lo);
|
void set(tbv& dst, uint64 n, unsigned hi, unsigned lo);
|
||||||
|
|
|
@ -1003,9 +1003,18 @@ namespace datalog {
|
||||||
return check_kind(t)?alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition):0;
|
return check_kind(t)?alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition):0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// 1. this code could use some cleanup and simplification.
|
||||||
|
// 2. It is also not very efficient in the copy routines.
|
||||||
|
// They fall back to copying each bit instead of a chunk.
|
||||||
|
// 3. Argument about correctness is needed as comments.
|
||||||
|
// 4. Unit/stress test cases are needed.
|
||||||
|
//
|
||||||
class udoc_plugin::negation_filter_fn : public relation_intersection_filter_fn {
|
class udoc_plugin::negation_filter_fn : public relation_intersection_filter_fn {
|
||||||
const unsigned_vector m_t_cols;
|
const unsigned_vector m_t_cols;
|
||||||
const unsigned_vector m_neg_cols;
|
const unsigned_vector m_neg_cols;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
negation_filter_fn(const udoc_relation & r, const udoc_relation & neg, unsigned joined_col_cnt,
|
negation_filter_fn(const udoc_relation & r, const udoc_relation & neg, unsigned joined_col_cnt,
|
||||||
const unsigned *t_cols, const unsigned *neg_cols)
|
const unsigned *t_cols, const unsigned *neg_cols)
|
||||||
|
@ -1018,72 +1027,103 @@ namespace datalog {
|
||||||
udoc_relation const& n = get(negb);
|
udoc_relation const& n = get(negb);
|
||||||
udoc & dst = t.get_udoc();
|
udoc & dst = t.get_udoc();
|
||||||
udoc const & neg = n.get_udoc();
|
udoc const & neg = n.get_udoc();
|
||||||
doc_manager& dm = t.get_dm();
|
doc_manager& dmt = t.get_dm();
|
||||||
|
doc_manager& dmn = n.get_dm();
|
||||||
|
IF_VERBOSE(3, t.display(verbose_stream() << "dst:"););
|
||||||
|
IF_VERBOSE(3, n.display(verbose_stream() << "neg:"););
|
||||||
|
|
||||||
udoc result;
|
udoc result;
|
||||||
for (unsigned i = 0; i < dst.size(); ++i) {
|
for (unsigned i = 0; i < dst.size(); ++i) {
|
||||||
bool done_i = false;
|
for (unsigned j = 0; j < neg.size(); ++j) {
|
||||||
for (unsigned j = 0; !done_i && j < neg.size(); ++j) {
|
for (unsigned c = 0; c < m_t_cols.size(); ++c) {
|
||||||
bool done_j = false;
|
|
||||||
for (unsigned c = 0; !done_j && c < m_t_cols.size(); ++c) {
|
|
||||||
unsigned t_col = m_t_cols[c];
|
unsigned t_col = m_t_cols[c];
|
||||||
unsigned n_col = m_neg_cols[c];
|
unsigned n_col = m_neg_cols[c];
|
||||||
unsigned num_bits = t.column_num_bits(t_col);
|
unsigned num_bits = t.column_num_bits(t_col);
|
||||||
SASSERT(num_bits == n.column_num_bits(n_col));
|
SASSERT(num_bits == n.column_num_bits(n_col));
|
||||||
unsigned t_idx = t.column_idx(t_col);
|
unsigned t_idx = t.column_idx(t_col);
|
||||||
unsigned n_idx = n.column_idx(n_col);
|
unsigned n_idx = n.column_idx(n_col);
|
||||||
for (unsigned k = 0; !done_j && k < num_bits; ++k) {
|
bool cont = dmn.contains(n_idx, neg[j], dmt, t_idx, dst[i], num_bits);
|
||||||
tbit n_bit = neg[j][n_idx + k];
|
IF_VERBOSE(
|
||||||
tbit d_bit = dst[i][t_idx + k];
|
3,
|
||||||
// neg does not contain dst.
|
dmt.display(verbose_stream() << "dst:", dst[i], t_idx+num_bits-1,t_idx) << "\n";
|
||||||
done_j = (n_bit != BIT_x && n_bit != d_bit);
|
dmn.display(verbose_stream() << "neg:", neg[j], n_idx+num_bits-1,n_idx) << "\n";
|
||||||
|
verbose_stream() << "contains: " << (cont?"true":"false") << "\n";);
|
||||||
|
if (!cont) {
|
||||||
|
goto next_neg_disj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (done_j) {
|
dmt.deallocate(&dst[i]);
|
||||||
result.push_back(&dst[i]);
|
goto next_disj;
|
||||||
done_i = true;
|
next_neg_disj:;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!done_i) {
|
|
||||||
dm.deallocate(&dst[i]);
|
|
||||||
}
|
}
|
||||||
|
result.push_back(&dst[i]);
|
||||||
|
next_disj:;
|
||||||
}
|
}
|
||||||
std::swap(dst, result);
|
std::swap(dst, result);
|
||||||
if (dst.is_empty()) {
|
if (dst.is_empty()) {
|
||||||
IF_VERBOSE(3, tb.display(verbose_stream()););
|
IF_VERBOSE(3, tb.display(verbose_stream() << "fast empty"););
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// slow case
|
// slow case
|
||||||
udoc renamed_neg;
|
udoc renamed_neg;
|
||||||
for (unsigned i = 0; i < neg.size(); ++i) {
|
for (unsigned i = 0; i < neg.size(); ++i) {
|
||||||
doc_ref newD(dm, dm.allocateX());
|
doc& neg_i = neg[i];
|
||||||
for (unsigned j = 0; j < m_neg_cols.size(); ++j) {
|
doc_ref newD(dmt, dmt.allocateX());
|
||||||
copy_column(*newD, neg[i], m_t_cols[j], m_neg_cols[j], t, n);
|
copy_columns(newD->pos(), neg_i.pos(), t, n);
|
||||||
|
bool is_empty = false;
|
||||||
|
for (unsigned j = 0; !is_empty && j < neg_i.neg().size(); ++j) {
|
||||||
|
tbv_ref newT(dmt.tbvm(), dmt.tbvm().allocateX());
|
||||||
|
copy_columns(*newT, neg_i.neg()[j], t, n);
|
||||||
|
if (dmt.tbvm().equals(newD->pos(), *newT)) {
|
||||||
|
is_empty = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newD->neg().push_back(newT.detach());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!is_empty) {
|
||||||
|
IF_VERBOSE(3,
|
||||||
|
dmn.display(verbose_stream() << "copy neg: ", neg_i) << "\n";
|
||||||
|
dmt.display(verbose_stream() << "to dst: ", *newD) << "\n";);
|
||||||
|
renamed_neg.push_back(newD.detach());
|
||||||
}
|
}
|
||||||
renamed_neg.push_back(newD.detach());
|
|
||||||
}
|
}
|
||||||
TRACE("doc", dst.display(dm, tout) << "\n";
|
TRACE("doc", dst.display(dmt, tout) << "\n";
|
||||||
renamed_neg.display(dm, tout) << "\n";
|
renamed_neg.display(dmt, tout) << "\n";
|
||||||
);
|
);
|
||||||
dst.subtract(dm, renamed_neg);
|
dst.subtract(dmt, renamed_neg);
|
||||||
TRACE("doc", dst.display(dm, tout) << "\n";);
|
// TBD: double check semantics
|
||||||
SASSERT(dst.well_formed(dm));
|
TRACE("doc", dst.display(dmt, tout) << "\n";);
|
||||||
renamed_neg.reset(t.get_dm());
|
SASSERT(dst.well_formed(dmt));
|
||||||
IF_VERBOSE(3, tb.display(verbose_stream()););
|
renamed_neg.reset(dmt);
|
||||||
|
IF_VERBOSE(3, tb.display(verbose_stream() << "slow case:"););
|
||||||
|
}
|
||||||
|
void copy_columns(
|
||||||
|
tbv& dst, tbv const& src,
|
||||||
|
udoc_relation const& dstt,
|
||||||
|
udoc_relation const& srct)
|
||||||
|
{
|
||||||
|
unsigned num_cols = m_t_cols.size();
|
||||||
|
for (unsigned i = 0; i < num_cols; ++i) {
|
||||||
|
copy_column(dst, src, m_t_cols[i], m_neg_cols[i], dstt, srct);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void copy_column(
|
void copy_column(
|
||||||
doc& dst, doc const& src,
|
tbv& dst, tbv const& src,
|
||||||
unsigned col_dst, unsigned col_src,
|
unsigned col_dst, unsigned col_src,
|
||||||
udoc_relation const& dstt,
|
udoc_relation const& dstt,
|
||||||
udoc_relation const& srct) {
|
udoc_relation const& srct) {
|
||||||
doc_manager& dm = dstt.get_dm();
|
tbv_manager& dm = dstt.get_dm().tbvm();
|
||||||
unsigned idx_dst = dstt.column_idx(col_dst);
|
unsigned idx_dst = dstt.column_idx(col_dst);
|
||||||
unsigned idx_src = srct.column_idx(col_src);
|
unsigned idx_src = srct.column_idx(col_src);
|
||||||
unsigned num_bits = dstt.column_num_bits(col_dst);
|
unsigned num_tbits = dstt.column_num_bits(col_dst);
|
||||||
SASSERT(num_bits == srct.column_num_bits(col_src));
|
SASSERT(num_bits == srct.column_num_bits(col_src));
|
||||||
for (unsigned i = 0; i < num_bits; ++i) {
|
IF_VERBOSE(3, verbose_stream() << "copy column " << idx_src
|
||||||
dm.set(dst, idx_dst+i, src[idx_src+i]);
|
<< " to " << idx_dst << " " << num_tbits << "\n";);
|
||||||
}
|
for (unsigned i = 0; i < num_tbits; ++i) {
|
||||||
|
dm.set(dst, idx_dst + i, src[idx_src + i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue