z3-z3-4.13.0.src.muz.rel.dl_sieve_relation.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
dl_mk_explanations.cpp
Abstract:
Author:
Krystof Hoder (t-khoder) 2010-11-08.
Revision History:
--*/
#include
#include "ast/ast_pp.h"
#include "muz/rel/dl_sieve_relation.h"
namespace datalog {
// -----------------------------------
//
// sieve_relation
//
// -----------------------------------
sieve_relation::sieve_relation(sieve_relation_plugin & p, const relation_signature & s,
const bool * inner_columns, relation_base * inner)
: relation_base(p, s), m_inner_cols(s.size(), inner_columns), m_inner(inner) {
unsigned n = s.size();
for(unsigned i=0; i 0; ) {
--i;
unsigned idx = m_inner2sig[i];
s.push_back(m.mk_var(idx, sig[i]));
}
get_inner().to_formula(tmp);
fml = get_plugin().get_context().get_var_subst()(tmp, sz, s.data());
}
void sieve_relation::display(std::ostream & out) const {
out << "Sieve relation ";
print_container(m_inner_cols, out);
out <<"\n";
get_inner().display(out);
}
// -----------------------------------
//
// sieve_relation_plugin
//
// -----------------------------------
sieve_relation_plugin & sieve_relation_plugin::get_plugin(relation_manager & rmgr) {
sieve_relation_plugin * res = static_cast(rmgr.get_relation_plugin(get_name()));
if(!res) {
res = alloc(sieve_relation_plugin, rmgr);
rmgr.register_plugin(res);
}
return *res;
}
sieve_relation& sieve_relation_plugin::get(relation_base& r) {
return dynamic_cast(r);
}
sieve_relation const & sieve_relation_plugin::get(relation_base const& r) {
return dynamic_cast(r);
}
sieve_relation* sieve_relation_plugin::get(relation_base* r) {
return dynamic_cast(r);
}
sieve_relation const* sieve_relation_plugin::get(relation_base const* r) {
return dynamic_cast(r);
}
sieve_relation_plugin::sieve_relation_plugin(relation_manager & manager)
: relation_plugin(get_name(), manager, ST_SIEVE_RELATION),
m_spec_store(*this) {}
void sieve_relation_plugin::initialize(family_id fid) {
relation_plugin::initialize(fid);
m_spec_store.add_available_kind(get_kind());
}
family_id sieve_relation_plugin::get_relation_kind(const relation_signature & sig,
const bool * inner_columns, family_id inner_kind) {
rel_spec spec(sig.size(), inner_columns, inner_kind);
return m_spec_store.get_relation_kind(sig, spec);
}
family_id sieve_relation_plugin::get_relation_kind(sieve_relation & r, const bool * inner_columns) {
const relation_signature & sig = r.get_signature();
return get_relation_kind(sig, inner_columns, r.get_inner().get_kind());
}
void sieve_relation_plugin::extract_inner_columns(const relation_signature & s, relation_plugin & inner,
bool_vector & inner_columns) {
SASSERT(inner_columns.size()==s.size());
unsigned n = s.size();
relation_signature inner_sig_singleton;
for(unsigned i=0; iget_plugin().is_sieve_relation()); //it does not make sense to make a sieve of a sieve
return alloc(sieve_relation, *this, s, inner_columns, inner_rel);
}
sieve_relation * sieve_relation_plugin::mk_empty(const sieve_relation & original) {
return static_cast(mk_empty(original.get_signature(), original.get_kind()));
}
relation_base * sieve_relation_plugin::mk_empty(const relation_base & original) {
return mk_empty(static_cast(original));
}
relation_base * sieve_relation_plugin::mk_empty(const relation_signature & s, family_id kind) {
rel_spec spec;
m_spec_store.get_relation_spec(s, kind, spec);
relation_signature inner_sig;
collect_inner_signature(s, spec.m_inner_cols, inner_sig);
relation_base * inner = get_manager().mk_empty_relation(inner_sig, spec.m_inner_kind);
return mk_from_inner(s, spec.m_inner_cols.data(), inner);
}
relation_base * sieve_relation_plugin::mk_empty(const relation_signature & s) {
UNREACHABLE();
return nullptr;
#if 0
bool_vector inner_cols(s.size());
extract_inner_columns(s, inner_cols.c_ptr());
return mk_empty(s, inner_cols.c_ptr());
#endif
}
sieve_relation * sieve_relation_plugin::mk_empty(const relation_signature & s, relation_plugin & inner_plugin) {
SASSERT(!inner_plugin.is_sieve_relation()); //it does not make sense to make a sieve of a sieve
bool_vector inner_cols(s.size());
extract_inner_columns(s, inner_plugin, inner_cols);
relation_signature inner_sig;
collect_inner_signature(s, inner_cols, inner_sig);
relation_base * inner_rel = inner_plugin.mk_empty(inner_sig);
return mk_from_inner(s, inner_cols, inner_rel);
}
relation_base * sieve_relation_plugin::mk_full(func_decl* p, const relation_signature & s) {
relation_signature empty_sig;
relation_plugin& plugin = get_manager().get_appropriate_plugin(s);
relation_base * inner = plugin.mk_full(p, empty_sig, null_family_id);
bool_vector inner_cols;
inner_cols.resize(s.size(), false);
return mk_from_inner(s, inner_cols, inner);
}
sieve_relation * sieve_relation_plugin::full(func_decl* p, const relation_signature & s, relation_plugin & inner_plugin) {
SASSERT(!inner_plugin.is_sieve_relation()); //it does not make sense to make a sieve of a sieve
bool_vector inner_cols(s.size());
extract_inner_columns(s, inner_plugin, inner_cols);
relation_signature inner_sig;
collect_inner_signature(s, inner_cols, inner_sig);
relation_base * inner_rel = inner_plugin.mk_full(p, inner_sig, null_family_id);
return mk_from_inner(s, inner_cols, inner_rel);
}
class sieve_relation_plugin::join_fn : public convenient_relation_join_fn {
sieve_relation_plugin & m_plugin;
unsigned_vector m_inner_cols_1;
unsigned_vector m_inner_cols_2;
bool_vector m_result_inner_cols;
scoped_ptr m_inner_join_fun;
public:
join_fn(sieve_relation_plugin & p, const relation_base & r1, const relation_base & r2, unsigned col_cnt,
const unsigned * cols1, const unsigned * cols2, relation_join_fn * inner_join_fun)
: convenient_relation_join_fn(r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2),
m_plugin(p),
m_inner_join_fun(inner_join_fun) {
bool r1_sieved = r1.get_plugin().is_sieve_relation();
bool r2_sieved = r2.get_plugin().is_sieve_relation();
const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : nullptr;
const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : nullptr;
if(r1_sieved) {
m_result_inner_cols.append(sr1->m_inner_cols);
}
else {
m_result_inner_cols.resize(r1.get_signature().size(), true);
}
if(r2_sieved) {
m_result_inner_cols.append(sr2->m_inner_cols);
}
else {
m_result_inner_cols.resize(m_result_inner_cols.size() + r2.get_signature().size(), true);
}
}
relation_base * operator()(const relation_base & r1, const relation_base & r2) override {
bool r1_sieved = r1.get_plugin().is_sieve_relation();
bool r2_sieved = r2.get_plugin().is_sieve_relation();
SASSERT(r1_sieved || r2_sieved);
const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : nullptr;
const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : nullptr;
const relation_base & inner1 = r1_sieved ? sr1->get_inner() : r1;
const relation_base & inner2 = r2_sieved ? sr2->get_inner() : r2;
relation_base * inner_res = (*m_inner_join_fun)(inner1, inner2);
return m_plugin.mk_from_inner(get_result_signature(), m_result_inner_cols.data(), inner_res);
}
};
relation_join_fn * sieve_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2,
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) {
if( &r1.get_plugin()!=this && &r2.get_plugin()!=this ) {
//we create just operations that involve the current plugin
return nullptr;
}
bool r1_sieved = r1.get_plugin().is_sieve_relation();
bool r2_sieved = r2.get_plugin().is_sieve_relation();
const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : nullptr;
const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : nullptr;
const relation_base & inner1 = r1_sieved ? sr1->get_inner() : r1;
const relation_base & inner2 = r2_sieved ? sr2->get_inner() : r2;
unsigned_vector inner_cols1;
unsigned_vector inner_cols2;
for(unsigned i=0; iis_inner_col(cols1[i])) {
continue;
}
if(r2_sieved && !sr2->is_inner_col(cols2[i])) {
continue;
}
inner_cols1.push_back( r1_sieved ? sr1->get_inner_col(cols1[i]) : cols1[i] );
inner_cols2.push_back( r2_sieved ? sr2->get_inner_col(cols2[i]) : cols2[i] );
}
relation_join_fn * inner_join_fun = get_manager().mk_join_fn(inner1, inner2, inner_cols1, inner_cols2, false);
if(!inner_join_fun) {
return nullptr;
}
return alloc(join_fn, *this, r1, r2, col_cnt, cols1, cols2, inner_join_fun);
}
class sieve_relation_plugin::transformer_fn : public convenient_relation_transformer_fn {
bool_vector m_result_inner_cols;
scoped_ptr m_inner_fun;
public:
transformer_fn(relation_transformer_fn * inner_fun, const relation_signature & result_sig,
const bool * result_inner_cols)
: m_result_inner_cols(result_sig.size(), result_inner_cols), m_inner_fun(inner_fun) {
get_result_signature() = result_sig;
}
relation_base * operator()(const relation_base & r0) override {
SASSERT(r0.get_plugin().is_sieve_relation());
const sieve_relation & r = static_cast(r0);
sieve_relation_plugin & plugin = r.get_plugin();
relation_base * inner_res = (*m_inner_fun)(r.get_inner());
return plugin.mk_from_inner(get_result_signature(), m_result_inner_cols.data(), inner_res);
}
};
relation_transformer_fn * sieve_relation_plugin::mk_project_fn(const relation_base & r0, unsigned col_cnt,
const unsigned * removed_cols) {
if(&r0.get_plugin()!=this) {
return nullptr;
}
const sieve_relation & r = static_cast(r0);
unsigned_vector inner_removed_cols;
for(unsigned i=0; i(r0);
unsigned sig_sz = r.get_signature().size();
unsigned_vector permutation;
add_sequence(0, sig_sz, permutation);
permute_by_cycle(permutation, cycle_len, permutation_cycle);
bool inner_identity;
unsigned_vector inner_permutation;
collect_sub_permutation(permutation, r.m_sig2inner, inner_permutation, inner_identity);
bool_vector result_inner_cols = r.m_inner_cols;
permute_by_cycle(result_inner_cols, cycle_len, permutation_cycle);
relation_signature result_sig;
relation_signature::from_rename(r.get_signature(), cycle_len, permutation_cycle, result_sig);
relation_transformer_fn * inner_fun =
get_manager().mk_permutation_rename_fn(r.get_inner(), inner_permutation);
if(!inner_fun) {
return nullptr;
}
return alloc(transformer_fn, inner_fun, result_sig, result_inner_cols.data());
}
class sieve_relation_plugin::union_fn : public relation_union_fn {
scoped_ptr m_union_fun;
public:
union_fn(relation_union_fn * union_fun) : m_union_fun(union_fun) {}
void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) override {
bool tgt_sieved = tgt.get_plugin().is_sieve_relation();
bool src_sieved = src.get_plugin().is_sieve_relation();
bool delta_sieved = delta && delta->get_plugin().is_sieve_relation();
sieve_relation * stgt = tgt_sieved ? static_cast(&tgt) : nullptr;
const sieve_relation * ssrc = src_sieved ? static_cast(&src) : nullptr;
sieve_relation * sdelta = delta_sieved ? static_cast(delta) : nullptr;
relation_base & itgt = tgt_sieved ? stgt->get_inner() : tgt;
const relation_base & isrc = src_sieved ? ssrc->get_inner() : src;
relation_base * idelta = delta_sieved ? &sdelta->get_inner() : delta;
(*m_union_fun)(itgt, isrc, idelta);
}
};
relation_union_fn * sieve_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src,
const relation_base * delta) {
if(&tgt.get_plugin()!=this && &src.get_plugin()!=this && (delta && &delta->get_plugin()!=this)) {
//we create the operation only if it involves this plugin
return nullptr;
}
bool tgt_sieved = tgt.get_plugin().is_sieve_relation();
bool src_sieved = src.get_plugin().is_sieve_relation();
bool delta_sieved = delta && delta->get_plugin().is_sieve_relation();
const sieve_relation * stgt = tgt_sieved ? static_cast(&tgt) : nullptr;
const sieve_relation * ssrc = src_sieved ? static_cast(&src) : nullptr;
const sieve_relation * sdelta = delta_sieved ? static_cast(delta) : nullptr;
const relation_base & itgt = tgt_sieved ? stgt->get_inner() : tgt;
const relation_base & isrc = src_sieved ? ssrc->get_inner() : src;
const relation_base * idelta = delta_sieved ? &sdelta->get_inner() : delta;
//Now we require that the sieved and inner columns must match on all relations.
//We may want to allow for some cases of misalignment even though it could introcude imprecision
if( tgt_sieved && src_sieved && (!delta || delta_sieved) ) {
if( !vectors_equal(stgt->m_inner_cols, ssrc->m_inner_cols)
|| (delta && !vectors_equal(stgt->m_inner_cols, sdelta->m_inner_cols)) ) {
return nullptr;
}
}
else {
if( (stgt && !stgt->no_sieved_columns())
|| (ssrc && !ssrc->no_sieved_columns())
|| (sdelta && !sdelta->no_sieved_columns()) ) {
//We have an unsieved relation and then some relation with some sieved columns,
//which means there is an misalignment.
return nullptr;
}
}
relation_union_fn * union_fun = get_manager().mk_union_fn(itgt, isrc, idelta);
if(!union_fun) {
return nullptr;
}
return alloc(union_fn, union_fun);
}
class sieve_relation_plugin::filter_fn : public relation_mutator_fn {
scoped_ptr m_inner_fun;
public:
filter_fn(relation_mutator_fn * inner_fun)
: m_inner_fun(inner_fun) {}
void operator()(relation_base & r0) override {
SASSERT(r0.get_plugin().is_sieve_relation());
sieve_relation & r = static_cast(r0);
(*m_inner_fun)(r.get_inner());
}
};
relation_mutator_fn * sieve_relation_plugin::mk_filter_identical_fn(const relation_base & r0,
unsigned col_cnt, const unsigned * identical_cols) {
if(&r0.get_plugin()!=this) {
return nullptr;
}
const sieve_relation & r = static_cast(r0);
unsigned_vector inner_icols;
//we ignore the columns which do not belong to the inner relation (which introduces imprecision)
for(unsigned i=0; i(r0);
if(!r.is_inner_col(col)) {
//if the column which do not belong to the inner relation, we do nothing (which introduces imprecision)
return alloc(identity_relation_mutator_fn);
}
unsigned inner_col = r.get_inner_col(col);
relation_mutator_fn * inner_fun = get_manager().mk_filter_equal_fn(r.get_inner(), value, inner_col);
if(!inner_fun) {
return nullptr;
}
return alloc(filter_fn, inner_fun);
}
relation_mutator_fn * sieve_relation_plugin::mk_filter_interpreted_fn(const relation_base & rb,
app * condition) {
if(&rb.get_plugin()!=this) {
return nullptr;
}
ast_manager & m = get_ast_manager();
const sieve_relation & r = static_cast(rb);
const relation_signature sig = r.get_signature();
unsigned sz = sig.size();
var_idx_set& cond_vars = get_context().get_rule_manager().collect_vars(condition);
expr_ref_vector subst_vect(m);
subst_vect.resize(sz);
unsigned subst_ofs = sz-1;
for(unsigned i=0; i m_inner_fun;
public:
negation_filter_fn(relation_intersection_filter_fn * inner_fun)
: m_inner_fun(inner_fun) {}
void operator()(relation_base & r, const relation_base & neg) override {
bool r_sieved = r.get_plugin().is_sieve_relation();
bool neg_sieved = neg.get_plugin().is_sieve_relation();
SASSERT(r_sieved || neg_sieved);
sieve_relation * sr = r_sieved ? static_cast(&r) : nullptr;
const sieve_relation * sneg = neg_sieved ? static_cast(&neg) : nullptr;
relation_base & inner_r = r_sieved ? sr->get_inner() : r;
const relation_base & inner_neg = neg_sieved ? sneg->get_inner() : neg;
(*m_inner_fun)(inner_r, inner_neg);
}
};
relation_intersection_filter_fn * sieve_relation_plugin::mk_filter_by_negation_fn(const relation_base & r,
const relation_base & neg, unsigned col_cnt, const unsigned * r_cols,
const unsigned * neg_cols) {
if(&r.get_plugin()!=this && &neg.get_plugin()!=this) {
//we create just operations that involve the current plugin
return nullptr;
}
bool r_sieved = r.get_plugin().is_sieve_relation();
bool neg_sieved = neg.get_plugin().is_sieve_relation();
SASSERT(r_sieved || neg_sieved);
const sieve_relation * sr = r_sieved ? static_cast(&r) : nullptr;
const sieve_relation * sneg = neg_sieved ? static_cast(&neg) : nullptr;
const relation_base & inner_r = r_sieved ? sr->get_inner() : r;
const relation_base & inner_neg = neg_sieved ? sneg->get_inner() : neg;
unsigned_vector ir_cols;
unsigned_vector ineg_cols;
for(unsigned i=0; iis_inner_col(r_cols[i]);
bool neg_col_inner = neg_sieved && !sneg->is_inner_col(neg_cols[i]);
if(r_col_inner && neg_col_inner) {
ir_cols.push_back( r_sieved ? sr->get_inner_col(i) : i );
ineg_cols.push_back( neg_sieved ? sneg->get_inner_col(i) : i );
}
else if(!r_col_inner && neg_col_inner) {
//Sieved (i.e. full) column in r is matched on an inner column in neg.
//If we assume the column in neg is not full, no rows from the inner relation of
//r would be removed. So in this case we perform no operation at cost of a little
//impresicion.
return alloc(identity_relation_intersection_filter_fn);
}
else {
//Inner or sieved column in r must match a sieved column in neg.
//Since sieved columns are full, this is always true so we can skip the equality.
continue;
}
}
relation_intersection_filter_fn * inner_fun =
get_manager().mk_filter_by_negation_fn(inner_r, inner_neg, ir_cols, ineg_cols);
if(!inner_fun) {
return nullptr;
}
return alloc(negation_filter_fn, inner_fun);
}
};