/*++ Copyright (c) 2015 Microsoft Corporation --*/ #include "muz/rel/check_relation.h" #include "muz/rel/dl_relation_manager.h" #include "ast/ast_util.h" #include "smt/smt_kernel.h" #include namespace datalog { check_relation::check_relation(check_relation_plugin& p, relation_signature const& sig, relation_base* r): relation_base(p, sig), m(p.get_ast_manager()), m_relation(r), m_fml(m) { m_relation->to_formula(m_fml); } check_relation::~check_relation() { m_relation->deallocate(); } void check_relation::check_equiv(char const* objective, expr* f1, expr* f2) const { get_plugin().check_equiv(objective, f1, f2); } void check_relation::consistent_formula() { expr_ref fml(m); m_relation->to_formula(fml); if (m_fml != fml) { IF_VERBOSE(0, display(verbose_stream() << "relation does not have a consistent formula");); } } expr_ref check_relation::mk_eq(relation_fact const& f) const { relation_signature const& sig = get_signature(); expr_ref_vector conjs(m); for (unsigned i = 0; i < sig.size(); ++i) { conjs.push_back(m.mk_eq(m.mk_var(i, sig[i]), f[i])); } return expr_ref(mk_and(m, conjs.size(), conjs.data()), m); } expr_ref check_relation::ground(expr* fml) const { return get_plugin().ground(*this, fml); } expr_ref check_relation_plugin::ground(relation_base const& dst) const { expr_ref fml(m); dst.to_formula(fml); return ground(dst, fml); } expr_ref check_relation_plugin::ground(relation_base const& dst, expr* fml) const { relation_signature const& sig = dst.get_signature(); var_subst sub(m, false); expr_ref_vector vars(m); for (unsigned i = 0; i < sig.size(); ++i) { vars.push_back(m.mk_const(symbol(i), sig[i])); } return sub(fml, vars.size(), vars.data()); } void check_relation::add_fact(const relation_fact & f) { expr_ref fml1(m); m_relation->add_fact(f); m_relation->to_formula(fml1); m_fml = m.mk_or(m_fml, mk_eq(f)); check_equiv("add_fact", ground(m_fml), ground(fml1)); m_fml = fml1; } void check_relation::add_new_fact(const relation_fact & f) { expr_ref fml1(m); m_relation->add_new_fact(f); m_relation->to_formula(fml1); m_fml = m.mk_or(m_fml, mk_eq(f)); check_equiv("add_fact", ground(m_fml), ground(fml1)); m_fml = fml1; } bool check_relation::empty() const { bool result = m_relation->empty(); if (result && !m.is_false(m_fml)) { check_equiv("empty", m.mk_false(), ground(m_fml)); } return result; } bool check_relation::fast_empty() const { bool result = m_relation->fast_empty(); if (result && !m.is_false(m_fml)) { check_equiv("fast_empty", m.mk_false(), ground(m_fml)); } return result; } void check_relation::reset() { m_relation->reset(); m_fml = m.mk_false(); } bool check_relation::contains_fact(const relation_fact & f) const { bool result = m_relation->contains_fact(f); expr_ref fml1(m), fml2(m); fml1 = mk_eq(f); fml2 = m.mk_and(m_fml, fml1); if (result) { check_equiv("contains fact", ground(fml1), ground(fml2)); } else if (!m.is_false(m_fml)) { check_equiv("contains fact", ground(fml2), m.mk_false()); } return result; } check_relation * check_relation::clone() const { check_relation* result = check_relation_plugin::get(get_plugin().mk_empty(get_signature())); result->m_relation->deallocate(); result->m_relation = m_relation->clone(); result->m_relation->to_formula(result->m_fml); if (m_fml != result->m_fml) { check_equiv("clone", ground(m_fml), ground(result->m_fml)); } return result; } check_relation * check_relation::complement(func_decl* f) const { check_relation* result = check_relation_plugin::get(get_plugin().mk_empty(get_signature())); result->m_relation->deallocate(); result->m_relation = m_relation->complement(f); result->m_relation->to_formula(result->m_fml); expr_ref fml(m); fml = m.mk_not(m_fml); check_equiv("complement", ground(fml), ground(result->m_fml)); return result; } void check_relation::to_formula(expr_ref& fml) const { fml = m_fml; } check_relation_plugin& check_relation::get_plugin() const { return static_cast(relation_base::get_plugin()); } void check_relation::display(std::ostream& out) const { m_relation->display(out); out << m_fml << "\n"; } // ------------- check_relation_plugin::check_relation_plugin(relation_manager& rm): relation_plugin(check_relation_plugin::get_name(), rm), m(rm.get_context().get_manager()), m_base(nullptr) { } check_relation_plugin::~check_relation_plugin() { } check_relation& check_relation_plugin::get(relation_base& r) { return dynamic_cast(r); } check_relation* check_relation_plugin::get(relation_base* r) { return r?dynamic_cast(r):nullptr; } check_relation const & check_relation_plugin::get(relation_base const& r) { return dynamic_cast(r); } bool check_relation_plugin::can_handle_signature(const relation_signature & sig) { return m_base && m_base->can_handle_signature(sig); } relation_base * check_relation_plugin::mk_empty(const relation_signature & sig) { relation_base* r = m_base->mk_empty(sig); check_relation* result = alloc(check_relation, *this, sig, r); if (result->m_fml != m.mk_false()) { check_equiv("mk_empty", result->ground(result->m_fml), m.mk_false()); } return result; } relation_base * check_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { relation_base* r = m_base->mk_full(p, s); check_relation* result = alloc(check_relation, *this, s, r); if (result->m_fml != m.mk_true()) { check_equiv("mk_full", result->ground(result->m_fml), m.mk_true()); } return result; } class check_relation_plugin::join_fn : public convenient_relation_join_fn { scoped_ptr m_join; public: join_fn(relation_join_fn* j, const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) : convenient_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2), m_join(j) {} ~join_fn() override {} relation_base * operator()(const relation_base & r1, const relation_base & r2) override { check_relation const& t1 = get(r1); check_relation const& t2 = get(r2); check_relation_plugin& p = t1.get_plugin(); relation_base* r = (*m_join)(t1.rb(), t2.rb()); p.verify_join(r1, r2, *r, m_cols1, m_cols2); return alloc(check_relation, p, r->get_signature(), r); } }; relation_join_fn * check_relation_plugin::mk_join_fn( const relation_base & t1, const relation_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { relation_join_fn* j = m_base->mk_join_fn(get(t1).rb(), get(t2).rb(), col_cnt, cols1, cols2); return j?alloc(join_fn, j, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2):nullptr; } class check_relation_plugin::join_project_fn : public convenient_relation_join_project_fn { scoped_ptr m_join; public: join_project_fn( relation_join_fn* j, const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned* removed_cols) : convenient_join_project_fn(o1_sig, o2_sig, col_cnt, cols1, cols2, removed_col_cnt, removed_cols), m_join(j) {} ~join_project_fn() override {} relation_base * operator()(const relation_base & r1, const relation_base & r2) override { check_relation const& t1 = get(r1); check_relation const& t2 = get(r2); check_relation_plugin& p = t1.get_plugin(); relation_base* r = (*m_join)(t1.rb(), t2.rb()); p.verify_join_project(r1, r2, *r, m_cols1, m_cols2, m_removed_cols); return alloc(check_relation, p, r->get_signature(), r); } }; relation_join_fn * check_relation_plugin::mk_join_project_fn( const relation_base & t1, const relation_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols) { relation_join_fn* j = m_base->mk_join_project_fn(get(t1).rb(), get(t2).rb(), col_cnt, cols1, cols2, removed_col_cnt, removed_cols); return j?alloc(join_project_fn, j, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, removed_col_cnt, removed_cols):nullptr; } void check_relation_plugin::verify_filter_project( relation_base const& src, relation_base const& dst, app* cond, unsigned_vector const& removed_cols) { expr_ref fml1(m), fml2(m); src.to_formula(fml1); dst.to_formula(fml2); fml1 = m.mk_and(cond, fml1); verify_project(src, fml1, dst, fml2, removed_cols); } void check_relation_plugin::verify_project( relation_base const& src, relation_base const& dst, unsigned_vector const& removed_cols) { expr_ref fml1(m), fml2(m); src.to_formula(fml1); dst.to_formula(fml2); verify_project(src, fml1, dst, fml2, removed_cols); } void check_relation_plugin::verify_project( relation_base const& src, expr* f1, relation_base const& dst, expr* f2, unsigned_vector const& removed_cols) { expr_ref fml1 = ground(dst, mk_project(src.get_signature(), f1, removed_cols)); expr_ref fml2 = ground(dst, f2); check_equiv("project", fml1, fml2); } expr_ref check_relation_plugin::mk_project( relation_signature const& sig, expr* fml, unsigned_vector const& removed_cols) { expr_ref fml1(m); ptr_vector bound; svector names; expr_ref_vector vars(m); unsigned rm_cnt = removed_cols.size(); for (unsigned i = 0, j = 0, k = 0; i < sig.size(); ++i) { if (j < rm_cnt && removed_cols[j] == i) { std::ostringstream strm; strm << "x" << j; bound.push_back(sig[i]); names.push_back(symbol(strm.str())); vars.push_back(m.mk_var(j, sig[i])); ++j; } else { vars.push_back(m.mk_var(k + rm_cnt, sig[i])); ++k; } } var_subst sub(m, false); fml1 = sub(fml, vars.size(), vars.data()); bound.reverse(); fml1 = m.mk_exists(bound.size(), bound.data(), names.data(), fml1); return fml1; } void check_relation_plugin::verify_join_project( relation_base const& t1, relation_base const& t2, relation_base const& t, unsigned_vector const& cols1, unsigned_vector const& cols2, unsigned_vector const& rm_cols) { ast_manager& m = get_ast_manager(); relation_signature const& sigA = t1.get_signature(); relation_signature const& sigB = t2.get_signature(); relation_signature sig1; sig1.append(sigA); sig1.append(sigB); expr_ref fml1 = mk_join(t1, t2, cols1, cols2); fml1 = mk_project(sig1, fml1, rm_cols); fml1 = ground(t, fml1); expr_ref fml2(m); t.to_formula(fml2); fml2 = ground(t, fml2); check_equiv("join_project", fml1, fml2); } expr_ref check_relation_plugin::mk_join( relation_base const& t1, relation_base const& t2, unsigned_vector const& cols1, unsigned_vector const& cols2) { ast_manager& m = get_ast_manager(); expr_ref fml1(m), fml2(m), fml3(m); relation_signature const& sig1 = t1.get_signature(); relation_signature const& sig2 = t2.get_signature(); var_ref var1(m), var2(m); t1.to_formula(fml1); t2.to_formula(fml2); var_subst sub(m, false); expr_ref_vector vars(m); for (unsigned i = 0; i < sig2.size(); ++i) { vars.push_back(m.mk_var(i + sig1.size(), sig2[i])); } fml2 = sub(fml2, vars.size(), vars.data()); fml1 = m.mk_and(fml1, fml2); for (unsigned i = 0; i < cols1.size(); ++i) { unsigned v1 = cols1[i]; unsigned v2 = cols2[i]; var1 = m.mk_var(v1, sig1[v1]); var2 = m.mk_var(v2 + sig1.size(), sig2[v2]); fml1 = m.mk_and(m.mk_eq(var1, var2), fml1); } return fml1; } void check_relation_plugin::verify_permutation( relation_base const& src, relation_base const& dst, unsigned_vector const& cycle) { unsigned_vector perm; relation_signature const& sig1 = src.get_signature(); relation_signature const& sig2 = dst.get_signature(); for (unsigned i = 0; i < sig1.size(); ++i) { perm.push_back(i); } for (unsigned i = 0; i < cycle.size(); ++i) { unsigned j = (i + 1)%cycle.size(); unsigned col1 = cycle[i]; unsigned col2 = cycle[j]; perm[col2] = col1; } for (unsigned i = 0; i < perm.size(); ++i) { SASSERT(sig2[perm[i]] == sig1[i]); } expr_ref_vector sub(m); for (unsigned i = 0; i < perm.size(); ++i) { sub.push_back(m.mk_var(perm[i], sig1[i])); } var_subst subst(m, false); expr_ref fml1(m), fml2(m); src.to_formula(fml1); dst.to_formula(fml2); fml1 = subst(fml1, sub.size(), sub.data()); expr_ref_vector vars(m); for (unsigned i = 0; i < sig2.size(); ++i) { vars.push_back(m.mk_const(symbol(i), sig2[i])); } fml1 = subst(fml1, vars.size(), vars.data()); fml2 = subst(fml2, vars.size(), vars.data()); check_equiv("permutation", fml1, fml2); } void check_relation_plugin::verify_join( relation_base const& t1, relation_base const& t2, relation_base const& t, unsigned_vector const& cols1, unsigned_vector const& cols2) { expr_ref fml1 = ground(t, mk_join(t1, t2, cols1, cols2)); expr_ref fml2 = ground(t); check_equiv("join", fml1, fml2); } void check_relation_plugin::verify_filter(expr* fml0, relation_base const& t, expr* cond) { expr_ref fml1(m), fml2(m); fml1 = m.mk_and(fml0, cond); t.to_formula(fml2); relation_signature const& sig = t.get_signature(); expr_ref_vector vars(m); var_subst sub(m, false); for (unsigned i = 0; i < sig.size(); ++i) { std::stringstream strm; strm << 'x' << i; vars.push_back(m.mk_const(symbol(strm.str()), sig[i])); } fml1 = sub(fml1, vars.size(), vars.data()); fml2 = sub(fml2, vars.size(), vars.data()); 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) { TRACE("doc", tout << mk_pp(fml1, m) << "\n"; tout << mk_pp(fml2, m) << "\n";); smt_params fp; smt::kernel solver(m, fp); expr_ref tmp(m); tmp = m.mk_not(m.mk_eq(fml1, fml2)); solver.assert_expr(tmp); lbool res = solver.check(); if (res == l_false) { IF_VERBOSE(3, verbose_stream() << objective << " verified\n";); } else if (res == l_true) { IF_VERBOSE(0, verbose_stream() << "NOT verified " << res << "\n"; verbose_stream() << mk_pp(fml1, m) << "\n"; verbose_stream() << mk_pp(fml2, m) << "\n"; verbose_stream().flush(); ); throw default_exception("operation was not verified"); } } void check_relation_plugin::verify_union(expr* dst0, relation_base const& src, relation_base const& dst, expr* delta0, relation_base const* delta) { expr_ref fml1(m), fml2(m); src.to_formula(fml1); dst.to_formula(fml2); fml1 = m.mk_or(fml1, dst0); relation_signature const& sig = dst.get_signature(); expr_ref_vector vars(m); var_subst sub(m, false); for (unsigned i = 0; i < sig.size(); ++i) { std::stringstream strm; strm << 'x' << i; vars.push_back(m.mk_const(symbol(strm.str()), sig[i])); } fml1 = sub(fml1, vars.size(), vars.data()); fml2 = sub(fml2, vars.size(), vars.data()); check_equiv("union", fml1, fml2); if (delta) { expr_ref d0(m), d(m); delta->to_formula(d); IF_VERBOSE(3, verbose_stream() << "verify delta " << d << "\n";); // delta >= dst \ dst0 // dst \ dst0 == delta & dst & \ dst0 expr_ref fml4(m), fml5(m); fml4 = m.mk_and(fml2, m.mk_not(dst0)); fml4 = sub(fml4, vars.size(), vars.data()); d = sub(d, vars.size(), vars.data()); check_contains("union_delta low", d, fml4); // // delta >= delta0 // d0 = sub(delta0, vars.size(), vars.data()); check_contains("union delta0", d, d0); // // dst u delta0 = delta u dst0 // fml4 = m.mk_or(fml2, delta0); fml5 = m.mk_or(d, dst0); fml4 = sub(fml4, vars.size(), vars.data()); fml5 = sub(fml5, vars.size(), vars.data()); check_equiv("union no overflow", fml4, fml5); } } class check_relation_plugin::union_fn : public relation_union_fn { scoped_ptr m_union; public: union_fn(relation_union_fn* m): m_union(m) {} void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) override { TRACE("doc", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); check_relation& r = get(_r); check_relation const& src = get(_src); check_relation* d = get(_delta); 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()):nullptr); r.get_plugin().verify_union(fml0, src.rb(), r.rb(), delta0, d?(&d->rb()):nullptr); r.rb().to_formula(r.m_fml); if (d) d->rb().to_formula(d->m_fml); } }; relation_union_fn * check_relation_plugin::mk_union_fn( const relation_base & tgt, const relation_base & src, const relation_base * delta) { relation_base const* d1 = delta?(&(get(*delta).rb())):nullptr; relation_union_fn* u = m_base->mk_union_fn(get(tgt).rb(), get(src).rb(), d1); return u?alloc(union_fn, u):nullptr; } relation_union_fn * check_relation_plugin::mk_widen_fn( const relation_base & tgt, const relation_base & src, const relation_base * delta) { relation_base const* d1 = delta?(&(get(*delta).rb())):nullptr; relation_union_fn* u = m_base->mk_widen_fn(get(tgt).rb(), get(src).rb(), d1); return u?alloc(union_fn, u):nullptr; } class check_relation_plugin::filter_identical_fn : public relation_mutator_fn { unsigned_vector m_cols; scoped_ptr m_filter; public: filter_identical_fn(relation_mutator_fn* f, unsigned col_cnt, const unsigned *identical_cols) : m_cols(col_cnt, identical_cols), m_filter(f) { } ~filter_identical_fn() override {} void operator()(relation_base & _r) override { check_relation& r = get(_r); check_relation_plugin& p = r.get_plugin(); ast_manager& m = p.m; expr_ref cond(m); relation_signature const& sig = r.get_signature(); expr_ref_vector conds(m); unsigned c1 = m_cols[0]; for (unsigned i = 1; i < m_cols.size(); ++i) { unsigned c2 = m_cols[i]; conds.push_back(m.mk_eq(m.mk_var(c1, sig[c1]), m.mk_var(c2, sig[c2]))); } cond = mk_and(m, conds.size(), conds.data()); r.consistent_formula(); (*m_filter)(r.rb()); p.verify_filter(r.m_fml, r.rb(), cond); r.rb().to_formula(r.m_fml); } }; relation_mutator_fn * check_relation_plugin::mk_filter_identical_fn( const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { relation_mutator_fn* r = m_base->mk_filter_identical_fn(get(t).rb(), col_cnt, identical_cols); return r?alloc(filter_identical_fn, r, col_cnt, identical_cols):nullptr; } class check_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { scoped_ptr m_mutator; app_ref m_condition; public: filter_interpreted_fn(relation_mutator_fn* r, app_ref& condition) : m_mutator(r), m_condition(condition) { } ~filter_interpreted_fn() override {} void operator()(relation_base & tb) override { check_relation& r = get(tb); check_relation_plugin& p = r.get_plugin(); expr_ref fml = r.m_fml; (*m_mutator)(r.rb()); p.verify_filter(fml, r.rb(), m_condition); r.rb().to_formula(r.m_fml); } }; relation_mutator_fn * check_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { relation_mutator_fn* r = m_base->mk_filter_interpreted_fn(get(t).rb(), condition); app_ref cond(condition, m); return r?alloc(filter_interpreted_fn, r, cond):nullptr; } class check_relation_plugin::project_fn : public convenient_relation_project_fn { scoped_ptr m_project; public: project_fn(relation_transformer_fn* p, relation_base const & t, unsigned removed_col_cnt, const unsigned * removed_cols) : convenient_relation_project_fn(t.get_signature(), removed_col_cnt, removed_cols), m_project(p) { } ~project_fn() override {} relation_base * operator()(const relation_base & tb) override { check_relation const& t = get(tb); check_relation_plugin& p = t.get_plugin(); relation_base* r = (*m_project)(t.rb()); p.verify_project(tb, *r, m_removed_cols); return alloc(check_relation, p, r->get_signature(), r); } }; relation_transformer_fn * check_relation_plugin::mk_project_fn( const relation_base & t, unsigned col_cnt, const unsigned * removed_cols) { relation_transformer_fn* p = m_base->mk_project_fn(get(t).rb(), col_cnt, removed_cols); return p?alloc(project_fn, p, t, col_cnt, removed_cols):nullptr; } class check_relation_plugin::rename_fn : public convenient_relation_rename_fn { scoped_ptr m_permute; public: rename_fn(relation_transformer_fn* permute, relation_base const& t, unsigned cycle_len, const unsigned * cycle) : convenient_relation_rename_fn(t.get_signature(), cycle_len, cycle), m_permute(permute) { } ~rename_fn() override {} relation_base * operator()(const relation_base & _t) override { check_relation const& t = get(_t); check_relation_plugin& p = t.get_plugin(); relation_signature const& sig = get_result_signature(); relation_base* r = (*m_permute)(t.rb()); p.verify_permutation(t.rb(), *r, m_cycle); return alloc(check_relation, p, sig, r); } }; relation_transformer_fn * check_relation_plugin::mk_rename_fn( const relation_base & r, unsigned cycle_len, const unsigned * permutation_cycle) { relation_transformer_fn* p = m_base->mk_rename_fn(get(r).rb(), cycle_len, permutation_cycle); return p?alloc(rename_fn, p, r, cycle_len, permutation_cycle):nullptr; } class check_relation_plugin::filter_equal_fn : public relation_mutator_fn { scoped_ptr m_filter; relation_element m_val; unsigned m_col; public: filter_equal_fn(relation_mutator_fn* filter, relation_base const& t, const relation_element val, unsigned col): m_filter(filter), m_val(val), m_col(col) {} ~filter_equal_fn() override { } void operator()(relation_base & tb) override { check_relation & t = get(tb); check_relation_plugin& p = t.get_plugin(); (*m_filter)(t.rb()); expr_ref fml = t.m_fml; t.rb().to_formula(t.m_fml); fml = p.m.mk_and(fml, p.m.mk_eq(p.m.mk_var(m_col, t.get_signature()[m_col]), m_val)); p.check_equiv("filter_equal", t.ground(fml), t.ground(t.m_fml)); } }; relation_mutator_fn * check_relation_plugin::mk_filter_equal_fn( const relation_base & t, const relation_element & value, unsigned col) { relation_mutator_fn* r = m_base->mk_filter_equal_fn(get(t).rb(), value, col); return r?alloc(filter_equal_fn, r, t, value, col):nullptr; } class check_relation_plugin::negation_filter_fn : public relation_intersection_filter_fn { scoped_ptr m_filter; const unsigned_vector m_t_cols; const unsigned_vector m_neg_cols; public: negation_filter_fn( relation_intersection_filter_fn* filter, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *neg_cols) : m_filter(filter), m_t_cols(joined_col_cnt, t_cols), m_neg_cols(joined_col_cnt, neg_cols) { SASSERT(joined_col_cnt > 0); } void operator()(relation_base& tb, const relation_base& negb) override { check_relation& t = get(tb); check_relation const& n = get(negb); 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()); t.rb().to_formula(t.m_fml); p.verify_filter_by_negation(dst0, t.rb(), n.rb(), m_t_cols, m_neg_cols); } }; relation_intersection_filter_fn * check_relation_plugin::mk_filter_by_negation_fn( const relation_base& t, const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *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):nullptr; } /* 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, relation_base const& dst, relation_base 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"; neg.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.data()); ptr_vector rev_sig2(sig2.size(), sig2.data()); rev_sig2.reverse(); svector names; for (unsigned i = 0; i < sig2.size(); ++i) { names.push_back(symbol(i)); } negf = m.mk_exists(rev_sig2.size(), rev_sig2.data(), names.data(), negf); negf = m.mk_and(dst0, m.mk_not(negf)); negf = ground(dst, negf); dstf = ground(dst, 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 { app_ref m_cond; scoped_ptr m_xform; public: filter_proj_fn(relation_transformer_fn* xform, relation_base const& t, app_ref& cond, unsigned col_cnt, const unsigned * removed_cols) : convenient_relation_project_fn(t.get_signature(), col_cnt, removed_cols), m_cond(cond), m_xform(xform) {} ~filter_proj_fn() override {} relation_base* operator()(const relation_base & tb) override { check_relation const & t = get(tb); check_relation_plugin& p = t.get_plugin(); relation_base* r = (*m_xform)(t.rb()); p.verify_filter_project(t.rb(), *r, m_cond, m_removed_cols); relation_signature const& sig = get_result_signature(); return alloc(check_relation, p, sig, r); } }; relation_transformer_fn * check_relation_plugin::mk_filter_interpreted_and_project_fn( const relation_base & t, app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { relation_transformer_fn* r = m_base->mk_filter_interpreted_and_project_fn(get(t).rb(), condition, removed_col_cnt, removed_cols); app_ref cond(condition, m); return r?alloc(filter_proj_fn, r, t, cond, removed_col_cnt, removed_cols):nullptr; } }