/*++ Copyright (c) 2006 Microsoft Corporation Module Name: dl_relation_manager.cpp Abstract: Author: Krystof Hoder (t-khoder) 2010-09-14. Revision History: --*/ #include #include"ast_pp.h" #include"dl_check_table.h" #include"dl_context.h" #include"dl_finite_product_relation.h" #include"dl_product_relation.h" #include"dl_sieve_relation.h" #include"dl_table_relation.h" #include"dl_relation_manager.h" namespace datalog { relation_manager::~relation_manager() { reset(); } void relation_manager::reset_relations() { relation_map::iterator it=m_relations.begin(); relation_map::iterator end=m_relations.end(); for(;it!=end;++it) { func_decl * pred = it->m_key; get_context().get_manager().dec_ref(pred); //inc_ref in get_relation relation_base * r=(*it).m_value; r->deallocate(); } m_relations.reset(); } void relation_manager::reset() { reset_relations(); m_favourite_table_plugin = static_cast(0); m_favourite_relation_plugin = static_cast(0); dealloc_ptr_vector_content(m_table_plugins); m_table_plugins.reset(); dealloc_ptr_vector_content(m_relation_plugins); m_relation_plugins.reset(); m_next_table_fid = 0; m_next_relation_fid = 0; } dl_decl_util & relation_manager::get_decl_util() const { return get_context().get_decl_util(); } family_id relation_manager::get_next_relation_fid(relation_plugin & claimer) { unsigned res = m_next_relation_fid++; m_kind2plugin.insert(res, &claimer); return res; } void relation_manager::set_predicate_kind(func_decl * pred, family_id kind) { SASSERT(!m_relations.contains(pred)); m_pred_kinds.insert(pred, kind); } family_id relation_manager::get_requested_predicate_kind(func_decl * pred) { family_id res; if(m_pred_kinds.find(pred, res)) { return res; } //This is commented out as the favourite relation might not be suitable for all //signatures. In the cases where it is suitable, it will be used anyway if we //now return null_family_id. //else if (m_favourite_relation_plugin) { // return m_favourite_relation_plugin->get_kind(); //} else { return null_family_id; } } relation_base & relation_manager::get_relation(func_decl * pred) { relation_base * res = try_get_relation(pred); if(!res) { relation_signature sig; from_predicate(pred, sig); family_id rel_kind = get_requested_predicate_kind(pred); res = mk_empty_relation(sig, rel_kind); store_relation(pred, res); } return *res; } relation_base * relation_manager::try_get_relation(func_decl * pred) const { relation_base * res = 0; if(!m_relations.find(pred, res)) { return 0; } SASSERT(res); return res; } void relation_manager::store_relation(func_decl * pred, relation_base * rel) { SASSERT(rel); relation_map::entry * e = m_relations.insert_if_not_there2(pred, 0); if(e->get_data().m_value) { e->get_data().m_value->deallocate(); } else { get_context().get_manager().inc_ref(pred); //dec_ref in reset } e->get_data().m_value = rel; } void relation_manager::collect_predicates(decl_set & res) const { relation_map::iterator it = m_relations.begin(); relation_map::iterator end = m_relations.end(); for(; it!=end; ++it) { res.insert(it->m_key); } } void relation_manager::collect_non_empty_predicates(decl_set & res) const { relation_map::iterator it = m_relations.begin(); relation_map::iterator end = m_relations.end(); for(; it!=end; ++it) { if(!it->m_value->empty()) { res.insert(it->m_key); } } } void relation_manager::restrict_predicates(const decl_set & preds) { typedef ptr_vector fd_vector; fd_vector to_remove; relation_map::iterator rit = m_relations.begin(); relation_map::iterator rend = m_relations.end(); for(; rit!=rend; ++rit) { func_decl * pred = rit->m_key; if(!preds.contains(pred)) { to_remove.insert(pred); } } fd_vector::iterator pit = to_remove.begin(); fd_vector::iterator pend = to_remove.end(); for(; pit!=pend; ++pit) { func_decl * pred = *pit; relation_base * rel; TRUSTME( m_relations.find(pred, rel) ); rel->deallocate(); m_relations.remove(pred); get_context().get_manager().dec_ref(pred); } set_intersection(m_saturated_rels, preds); } void relation_manager::register_plugin(table_plugin * plugin) { plugin->initialize(get_next_table_fid()); m_table_plugins.push_back(plugin); if(plugin->get_name()==get_context().default_table()) { m_favourite_table_plugin = plugin; } table_relation_plugin * tr_plugin = alloc(table_relation_plugin, *plugin, *this); register_relation_plugin_impl(tr_plugin); m_table_relation_plugins.insert(plugin, tr_plugin); symbol checker_name = get_context().default_table_checker(); if(get_context().default_table_checked() && get_table_plugin(checker_name)) { if( m_favourite_table_plugin && (plugin==m_favourite_table_plugin || plugin->get_name()==checker_name) ) { symbol checked_name = get_context().default_table(); //the plugins we need to create the checking plugin were just added SASSERT(m_favourite_table_plugin->get_name()==get_context().default_table()); table_plugin * checking_plugin = alloc(check_table_plugin, *this, checker_name, checked_name); register_plugin(checking_plugin); m_favourite_table_plugin = checking_plugin; } if(m_favourite_relation_plugin && m_favourite_relation_plugin->from_table()) { table_relation_plugin * fav_rel_plugin = static_cast(m_favourite_relation_plugin); if(&fav_rel_plugin->get_table_plugin()==plugin || plugin->get_name()==checker_name) { //the plugins we need to create the checking table_relation_plugin were just added SASSERT(m_favourite_relation_plugin->get_name() == get_context().default_relation()); symbol checked_name = fav_rel_plugin->get_table_plugin().get_name(); table_plugin * checking_plugin = alloc(check_table_plugin, *this, checker_name, checked_name); register_plugin(checking_plugin); table_relation_plugin * checking_tr_plugin = alloc(table_relation_plugin, *checking_plugin, *this); register_relation_plugin_impl(checking_tr_plugin); m_table_relation_plugins.insert(checking_plugin, checking_tr_plugin); m_favourite_relation_plugin = checking_tr_plugin; } } } } void relation_manager::register_relation_plugin_impl(relation_plugin * plugin) { m_relation_plugins.push_back(plugin); plugin->initialize(get_next_relation_fid(*plugin)); if (plugin->get_name() == get_context().default_relation()) { m_favourite_relation_plugin = plugin; } if(plugin->is_finite_product_relation()) { finite_product_relation_plugin * fprp = static_cast(plugin); relation_plugin * inner = &fprp->get_inner_plugin(); m_finite_product_relation_plugins.insert(inner, fprp); } } relation_plugin * relation_manager::try_get_appropriate_plugin(const relation_signature & s) { if(m_favourite_relation_plugin && m_favourite_relation_plugin->can_handle_signature(s)) { return m_favourite_relation_plugin; } relation_plugin_vector::iterator rpit = m_relation_plugins.begin(); relation_plugin_vector::iterator rpend = m_relation_plugins.end(); for(; rpit!=rpend; ++rpit) { if((*rpit)->can_handle_signature(s)) { return *rpit; } } return 0; } relation_plugin & relation_manager::get_appropriate_plugin(const relation_signature & s) { relation_plugin * res = try_get_appropriate_plugin(s); if(!res) { throw default_exception("no suitable plugin found for given relation signature"); throw 0; } return *res; } table_plugin * relation_manager::try_get_appropriate_plugin(const table_signature & t) { if(m_favourite_table_plugin && m_favourite_table_plugin->can_handle_signature(t)) { return m_favourite_table_plugin; } table_plugin_vector::iterator tpit = m_table_plugins.begin(); table_plugin_vector::iterator tpend = m_table_plugins.end(); for(; tpit!=tpend; ++tpit) { if((*tpit)->can_handle_signature(t)) { return *tpit; } } return 0; } table_plugin & relation_manager::get_appropriate_plugin(const table_signature & t) { table_plugin * res = try_get_appropriate_plugin(t); if(!res) { throw default_exception("no suitable plugin found for given table signature"); } return *res; } relation_plugin * relation_manager::get_relation_plugin(symbol const& s) { relation_plugin_vector::iterator rpit = m_relation_plugins.begin(); relation_plugin_vector::iterator rpend = m_relation_plugins.end(); for(; rpit!=rpend; ++rpit) { if((*rpit)->get_name()==s) { return *rpit; } } return 0; } relation_plugin & relation_manager::get_relation_plugin(family_id kind) { SASSERT(kind>=0); SASSERT(kindget_name()==k) { return *tpit; } } return 0; } table_relation_plugin & relation_manager::get_table_relation_plugin(table_plugin & tp) { table_relation_plugin * res; TRUSTME( m_table_relation_plugins.find(&tp, res) ); return *res; } bool relation_manager::try_get_finite_product_relation_plugin(const relation_plugin & inner, finite_product_relation_plugin * & res) { return m_finite_product_relation_plugins.find(&inner, res); } table_base * relation_manager::mk_empty_table(const table_signature & s) { return get_appropriate_plugin(s).mk_empty(s); } bool relation_manager::is_non_explanation(relation_signature const& s) const { dl_decl_util & decl_util = get_context().get_decl_util(); unsigned n = s.size(); for(unsigned i = 0; i < n; i++) { if(decl_util.is_rule_sort(s[i])) { return false; } } return true; } relation_base * relation_manager::mk_empty_relation(const relation_signature & s, func_decl* pred) { return mk_empty_relation(s, get_requested_predicate_kind(pred)); } relation_base * relation_manager::mk_empty_relation(const relation_signature & s, family_id kind) { if (kind != null_family_id) { relation_plugin & plugin = get_relation_plugin(kind); if (plugin.can_handle_signature(s, kind)) return plugin.mk_empty(s, kind); } relation_base * res; relation_plugin* p = m_favourite_relation_plugin; if (p && p->can_handle_signature(s)) { return p->mk_empty(s); } if(mk_empty_table_relation(s, res)) { return res; } for (unsigned i = 0; i < m_relation_plugins.size(); ++i) { p = m_relation_plugins[i]; if (p->can_handle_signature(s)) { return p->mk_empty(s); } } //If there is no plugin to handle the signature, we just create an empty product relation and //stuff will be added to it by later operations. return product_relation_plugin::get_plugin(*this).mk_empty(s); } relation_base * relation_manager::mk_table_relation(const relation_signature & s, table_base * table) { SASSERT(s.size()==table->get_signature().size()); return get_table_relation_plugin(table->get_plugin()).mk_from_table(s, table); } bool relation_manager::mk_empty_table_relation(const relation_signature & s, relation_base * & result) { table_signature tsig; if(!relation_signature_to_table(s, tsig)) { return false; } table_base * table = mk_empty_table(tsig); result = mk_table_relation(s, table); return true; } relation_base * relation_manager::mk_full_relation(const relation_signature & s, func_decl* p, family_id kind) { if (kind != null_family_id) { relation_plugin & plugin = get_relation_plugin(kind); if (plugin.can_handle_signature(s, kind)) { return plugin.mk_full(p, s, kind); } } return get_appropriate_plugin(s).mk_full(p, s, null_family_id); } relation_base * relation_manager::mk_full_relation(const relation_signature & s, func_decl* pred) { family_id kind = get_requested_predicate_kind(pred); return mk_full_relation(s, pred, kind); } void relation_manager::relation_to_table(const relation_sort & sort, const relation_element & from, table_element & to) { SASSERT(from->get_num_args()==0); TRUSTME(get_context().get_decl_util().is_numeral_ext(from, to)); } void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from, relation_element & to) { to = get_decl_util().mk_numeral(from, sort); } void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from, relation_element_ref & to) { relation_element rel_el; table_to_relation(sort, from, rel_el); to = rel_el; } void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from, const relation_fact::el_proxy & to) { relation_element rel_el; table_to_relation(sort, from, rel_el); to = rel_el; } bool relation_manager::relation_sort_to_table(const relation_sort & from, table_sort & to) { return get_context().get_decl_util().try_get_size(from, to); } void relation_manager::from_predicate(func_decl * pred, unsigned arg_index, relation_sort & result) { result = pred->get_domain(arg_index); } void relation_manager::from_predicate(func_decl * pred, relation_signature & result) { result.reset(); unsigned arg_num=pred->get_arity(); for(unsigned i=0;iget_name().bare_str()); } std::string relation_manager::to_nice_string(const relation_signature & s) const { std::string res("["); bool first = true; relation_signature::const_iterator it = s.begin(); relation_signature::const_iterator end = s.end(); for(; it!=end; ++it) { if(first) { first = false; } else { res+=','; } res+=to_nice_string(*it); } res+=']'; return res; } void relation_manager::display(std::ostream & out) const { relation_map::iterator it=m_relations.begin(); relation_map::iterator end=m_relations.end(); for(;it!=end;++it) { out << "Table " << it->m_key->get_name() << "\n"; it->m_value->display(out); } } void relation_manager::display_relation_sizes(std::ostream & out) const { relation_map::iterator it=m_relations.begin(); relation_map::iterator end=m_relations.end(); for(;it!=end;++it) { out << "Relation " << it->m_key->get_name() << " has size " << it->m_value->get_size_estimate_rows() << "\n"; } } void relation_manager::display_output_tables(std::ostream & out) const { const decl_set & output_preds = get_context().get_output_predicates(); decl_set::iterator it=output_preds.begin(); decl_set::iterator end=output_preds.end(); for(; it!=end; ++it) { func_decl * pred = *it; relation_base * rel = try_get_relation(pred); if(!rel) { out << "Tuples in " << pred->get_name() << ": \n"; continue; } rel->display_tuples(*pred, out); } } // ----------------------------------- // // relation operations // // ----------------------------------- class relation_manager::empty_signature_relation_join_fn : public relation_join_fn { public: virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { TRACE("dl", tout << r1.get_plugin().get_name() << " " << r2.get_plugin().get_name() << "\n";); if(r1.get_signature().empty()) { if(r1.empty()) { return r2.get_manager().mk_empty_relation(r2.get_signature(), r2.get_kind()); } else { return r2.clone(); } } else { SASSERT(r2.get_signature().empty()); if(r2.empty()) { return r1.get_manager().mk_empty_relation(r1.get_signature(), r1.get_kind()); } else { return r1.clone(); } } } }; relation_join_fn * relation_manager::mk_join_fn(const relation_base & t1, const relation_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, bool allow_product_relation) { relation_plugin * p1 = &t1.get_plugin(); relation_plugin * p2 = &t2.get_plugin(); relation_join_fn * res = p1->mk_join_fn(t1, t2, col_cnt, cols1, cols2); if(!res && p1!=p2) { res = p2->mk_join_fn(t1, t2, col_cnt, cols1, cols2); } if(!res && (t1.get_signature().empty() || t2.get_signature().empty())) { res = alloc(empty_signature_relation_join_fn); } finite_product_relation_plugin * fprp; if(!res && p1->from_table() && try_get_finite_product_relation_plugin(*p2, fprp)) { //we downcast here to relation_plugin so that we don't have to declare //relation_manager as a friend class of finite_product_relation_plugin res = static_cast(fprp)->mk_join_fn(t1, t2, col_cnt, cols1, cols2); } if(!res && p2->from_table() && try_get_finite_product_relation_plugin(*p1, fprp)) { res = static_cast(fprp)->mk_join_fn(t1, t2, col_cnt, cols1, cols2); } if(!res && allow_product_relation) { relation_plugin & product_plugin = product_relation_plugin::get_plugin(*this); res = product_plugin.mk_join_fn(t1, t2, col_cnt, cols1, cols2); } return res; } relation_transformer_fn * relation_manager::mk_project_fn(const relation_base & t, unsigned col_cnt, const unsigned * removed_cols) { return t.get_plugin().mk_project_fn(t, col_cnt, removed_cols); } class relation_manager::default_relation_join_project_fn : public relation_join_fn { scoped_ptr m_join; scoped_ptr m_project; unsigned_vector m_removed_cols; public: /** This constructor should be used only if we know that the projection operation exists for the result of the join. */ default_relation_join_project_fn(join_fn * join, unsigned removed_col_cnt, const unsigned * removed_cols) : m_join(join), m_project(0), m_removed_cols(removed_col_cnt, removed_cols) {} virtual relation_base * operator()(const relation_base & t1, const relation_base & t2) { scoped_rel aux = (*m_join)(t1, t2); if(!m_project) { relation_manager & rmgr = aux->get_plugin().get_manager(); m_project = rmgr.mk_project_fn(*aux, m_removed_cols.size(), m_removed_cols.c_ptr()); if(!m_project) { throw default_exception("projection does not exist"); } } relation_base * res = (*m_project)(*aux); return res; } }; relation_join_fn * relation_manager::mk_join_project_fn(const relation_base & t1, const relation_base & t2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols, bool allow_product_relation_join) { relation_join_fn * res = t1.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols); if(!res && &t1.get_plugin()!=&t2.get_plugin()) { res = t2.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols); } if(!res) { relation_join_fn * join = mk_join_fn(t1, t2, joined_col_cnt, cols1, cols2, allow_product_relation_join); if(join) { res = alloc(default_relation_join_project_fn, join, removed_col_cnt, removed_cols); } } return res; } relation_transformer_fn * relation_manager::mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, const unsigned * permutation_cycle) { return t.get_plugin().mk_rename_fn(t, permutation_cycle_len, permutation_cycle); } relation_transformer_fn * relation_manager::mk_permutation_rename_fn(const relation_base & t, const unsigned * permutation) { relation_transformer_fn * res = t.get_plugin().mk_permutation_rename_fn(t, permutation); if(!res) { res = alloc(default_relation_permutation_rename_fn, t, permutation); } return res; } relation_union_fn * relation_manager::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { relation_union_fn * res = tgt.get_plugin().mk_union_fn(tgt, src, delta); if(!res && &tgt.get_plugin()!=&src.get_plugin()) { res = src.get_plugin().mk_union_fn(tgt, src, delta); } if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { res = delta->get_plugin().mk_union_fn(tgt, src, delta); } return res; } relation_union_fn * relation_manager::mk_widen_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { relation_union_fn * res = tgt.get_plugin().mk_widen_fn(tgt, src, delta); if(!res && &tgt.get_plugin()!=&src.get_plugin()) { res = src.get_plugin().mk_widen_fn(tgt, src, delta); } if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { res = delta->get_plugin().mk_widen_fn(tgt, src, delta); } if(!res) { res = mk_union_fn(tgt, src, delta); } return res; } relation_mutator_fn * relation_manager::mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { return t.get_plugin().mk_filter_identical_fn(t, col_cnt, identical_cols); } relation_mutator_fn * relation_manager::mk_filter_equal_fn(const relation_base & t, const relation_element & value, unsigned col) { return t.get_plugin().mk_filter_equal_fn(t, value, col); } relation_mutator_fn * relation_manager::mk_filter_interpreted_fn(const relation_base & t, app * condition) { return t.get_plugin().mk_filter_interpreted_fn(t, condition); } class relation_manager::default_relation_select_equal_and_project_fn : public relation_transformer_fn { scoped_ptr m_filter; scoped_ptr m_project; public: default_relation_select_equal_and_project_fn(relation_mutator_fn * filter, relation_transformer_fn * project) : m_filter(filter), m_project(project) {} virtual relation_base * operator()(const relation_base & t1) { TRACE("dl", tout << t1.get_plugin().get_name() << "\n";); scoped_rel aux = t1.clone(); (*m_filter)(*aux); relation_base * res = (*m_project)(*aux); return res; } }; relation_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const relation_base & t, const relation_element & value, unsigned col) { relation_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col); TRACE("dl", tout << t.get_plugin().get_name() << " " << value << " " << col << "\n";); if(!res) { relation_mutator_fn * selector = mk_filter_equal_fn(t, value, col); if(selector) { relation_transformer_fn * projector = mk_project_fn(t, 1, &col); if(projector) { res = alloc(default_relation_select_equal_and_project_fn, selector, projector); } else { dealloc(selector); } } } return res; } class relation_manager::default_relation_intersection_filter_fn : public relation_intersection_filter_fn { scoped_ptr m_join_fun; scoped_ptr m_union_fun; public: default_relation_intersection_filter_fn(relation_join_fn * join_fun, relation_union_fn * union_fun) : m_join_fun(join_fun), m_union_fun(union_fun) {} virtual void operator()(relation_base & tgt, const relation_base & intersected_obj) { scoped_rel filtered_rel = (*m_join_fun)(tgt, intersected_obj); TRACE("dl", tgt.display(tout << "tgt:\n"); intersected_obj.display(tout << "intersected:\n"); filtered_rel->display(tout << "filtered:\n"); ); if(!m_union_fun) { SASSERT(tgt.can_swap(*filtered_rel)); tgt.swap(*filtered_rel); } tgt.reset(); TRACE("dl", tgt.display(tout << "target reset:\n"); ); (*m_union_fun)(tgt, *filtered_rel); TRACE("dl", tgt.display(tout << "intersected target:\n"); ); } }; relation_intersection_filter_fn * relation_manager::try_mk_default_filter_by_intersection_fn( const relation_base & tgt, const relation_base & src, unsigned joined_col_cnt, const unsigned * tgt_cols, const unsigned * src_cols) { TRACE("dl_verbose", tout << tgt.get_plugin().get_name() << "\n";); unsigned_vector join_removed_cols; add_sequence(tgt.get_signature().size(), src.get_signature().size(), join_removed_cols); scoped_rel join_fun = mk_join_project_fn(tgt, src, joined_col_cnt, tgt_cols, src_cols, join_removed_cols.size(), join_removed_cols.c_ptr(), false); if(!join_fun) { return 0; } //we perform the join operation here to see what the result is scoped_rel join_res = (*join_fun)(tgt, src); if(tgt.can_swap(*join_res)) { return alloc(default_relation_intersection_filter_fn, join_fun.release(), 0); } if(join_res->get_plugin().is_product_relation()) { //we cannot have the product relation here, since it uses the intersection operation //for unions and therefore we would get into an infinite recursion return 0; } scoped_rel union_fun = mk_union_fn(tgt, *join_res); if(!union_fun) { return 0; } return alloc(default_relation_intersection_filter_fn, join_fun.release(), union_fun.release()); } relation_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const relation_base & t, const relation_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) { TRACE("dl_verbose", tout << t.get_plugin().get_name() << "\n";); relation_intersection_filter_fn * res = t.get_plugin().mk_filter_by_intersection_fn(t, src, joined_col_cnt, t_cols, src_cols); if(!res && &t.get_plugin()!=&src.get_plugin()) { res = src.get_plugin().mk_filter_by_intersection_fn(t, src, joined_col_cnt, t_cols, src_cols); } if(!res) { res = try_mk_default_filter_by_intersection_fn(t, src, joined_col_cnt, t_cols, src_cols); } return res; } relation_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const relation_base & tgt, const relation_base & src) { TRACE("dl_verbose", tout << tgt.get_plugin().get_name() << "\n";); SASSERT(tgt.get_signature()==src.get_signature()); unsigned sz = tgt.get_signature().size(); unsigned_vector cols; add_sequence(0, sz, cols); return mk_filter_by_intersection_fn(tgt, src, cols, cols); } relation_intersection_filter_fn * relation_manager::mk_filter_by_negation_fn(const relation_base & t, const relation_base & negated_obj, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) { TRACE("dl", tout << t.get_plugin().get_name() << "\n";); relation_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, t_cols, negated_cols); if(!res && &t.get_plugin()!=&negated_obj.get_plugin()) { res = negated_obj.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, t_cols, negated_cols); } return res; } // ----------------------------------- // // table operations // // ----------------------------------- class relation_manager::default_table_join_fn : public convenient_table_join_fn { unsigned m_col_cnt; public: default_table_join_fn(const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) : convenient_table_join_fn(t1_sig, t2_sig, col_cnt, cols1, cols2), m_col_cnt(col_cnt) {} virtual table_base * operator()(const table_base & t1, const table_base & t2) { table_plugin * plugin = &t1.get_plugin(); const table_signature & res_sign = get_result_signature(); if (!plugin->can_handle_signature(res_sign)) { plugin = &t2.get_plugin(); if (!plugin->can_handle_signature(res_sign)) { plugin = &t1.get_manager().get_appropriate_plugin(res_sign); } } SASSERT(plugin->can_handle_signature(res_sign)); table_base * res = plugin->mk_empty(res_sign); unsigned t1cols=t1.get_signature().size(); unsigned t2cols=t2.get_signature().size(); unsigned t1first_func=t1.get_signature().first_functional(); unsigned t2first_func=t2.get_signature().first_functional(); table_base::iterator els1it = t1.begin(); table_base::iterator els1end = t1.end(); table_base::iterator els2end = t2.end(); table_fact acc; for(; els1it!=els1end; ++els1it) { const table_base::row_interface & row1 = *els1it; table_base::iterator els2it = t2.begin(); for(; els2it!=els2end; ++els2it) { const table_base::row_interface & row2 = *els2it; bool match=true; for(unsigned i=0; iadd_fact(acc); } } return res; } }; table_join_fn * relation_manager::mk_join_fn(const table_base & t1, const table_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { table_join_fn * res = t1.get_plugin().mk_join_fn(t1, t2, col_cnt, cols1, cols2); if(!res && &t1.get_plugin()!=&t2.get_plugin()) { res = t2.get_plugin().mk_join_fn(t1, t2, col_cnt, cols1, cols2); } if(!res) { table_signature sig; table_signature::from_join(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, sig); res = alloc(default_table_join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); } return res; } class relation_manager::auxiliary_table_transformer_fn { table_fact m_row; public: virtual ~auxiliary_table_transformer_fn() {} virtual const table_signature & get_result_signature() const = 0; virtual void modify_fact(table_fact & f) const = 0; table_base * operator()(const table_base & t) { table_plugin & plugin = t.get_plugin(); const table_signature & res_sign = get_result_signature(); SASSERT(plugin.can_handle_signature(res_sign)); table_base * res = plugin.mk_empty(res_sign); table_base::iterator it = t.begin(); table_base::iterator end = t.end(); for(; it!=end; ++it) { it->get_fact(m_row); modify_fact(m_row); res->add_fact(m_row); } return res; } }; class relation_manager::default_table_project_fn : public convenient_table_project_fn, auxiliary_table_transformer_fn { public: default_table_project_fn(const table_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) : convenient_table_project_fn(orig_sig, removed_col_cnt, removed_cols) { SASSERT(removed_col_cnt>0); } virtual const table_signature & get_result_signature() const { return convenient_table_project_fn::get_result_signature(); } virtual void modify_fact(table_fact & f) const { project_out_vector_columns(f, m_removed_cols); } virtual table_base * operator()(const table_base & t) { return auxiliary_table_transformer_fn::operator()(t); } }; class relation_manager::null_signature_table_project_fn : public table_transformer_fn { const table_signature m_empty_sig; public: null_signature_table_project_fn() : m_empty_sig() {} virtual table_base * operator()(const table_base & t) { relation_manager & m = t.get_plugin().get_manager(); table_base * res = m.mk_empty_table(m_empty_sig); if(!t.empty()) { table_fact el; res->add_fact(el); } return res; } }; table_transformer_fn * relation_manager::mk_project_fn(const table_base & t, unsigned col_cnt, const unsigned * removed_cols) { table_transformer_fn * res = t.get_plugin().mk_project_fn(t, col_cnt, removed_cols); if(!res && col_cnt==t.get_signature().size()) { //all columns are projected out res = alloc(null_signature_table_project_fn); } if(!res) { res = alloc(default_table_project_fn, t.get_signature(), col_cnt, removed_cols); } return res; } class relation_manager::default_table_join_project_fn : public convenient_table_join_project_fn { scoped_ptr m_join; scoped_ptr m_project; unsigned_vector m_removed_cols; public: default_table_join_project_fn(join_fn * join, const table_base & t1, const table_base & t2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols) : convenient_table_join_project_fn(t1.get_signature(), t2.get_signature(), joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols), m_join(join), m_removed_cols(removed_col_cnt, removed_cols) {} class unreachable_reducer : public table_row_pair_reduce_fn { virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { //we do project_with_reduce only if we are sure there will be no reductions //(see code of the table_signature::from_join_project function) UNREACHABLE(); } }; virtual table_base * operator()(const table_base & t1, const table_base & t2) { table_base * aux = (*m_join)(t1, t2); if(m_project==0) { relation_manager & rmgr = aux->get_plugin().get_manager(); if(get_result_signature().functional_columns()!=0) { //to preserve functional columns we need to do the project_with_reduction unreachable_reducer * reducer = alloc(unreachable_reducer); m_project = rmgr.mk_project_with_reduce_fn(*aux, m_removed_cols.size(), m_removed_cols.c_ptr(), reducer); } else { m_project = rmgr.mk_project_fn(*aux, m_removed_cols); } if(!m_project) { throw default_exception("projection for table does not exist"); } } table_base * res = (*m_project)(*aux); aux->deallocate(); return res; } }; table_join_fn * relation_manager::mk_join_project_fn(const table_base & t1, const table_base & t2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols) { table_join_fn * res = t1.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols); if(!res && &t1.get_plugin()!=&t2.get_plugin()) { res = t2.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols); } if(!res) { table_join_fn * join = mk_join_fn(t1, t2, joined_col_cnt, cols1, cols2); if(join) { res = alloc(default_table_join_project_fn, join, t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols); } } return res; } class relation_manager::default_table_rename_fn : public convenient_table_rename_fn, auxiliary_table_transformer_fn { const unsigned m_cycle_len; public: default_table_rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len, const unsigned * permutation_cycle) : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle), m_cycle_len(permutation_cycle_len) { SASSERT(permutation_cycle_len>=2); } virtual const table_signature & get_result_signature() const { return convenient_table_rename_fn::get_result_signature(); } virtual void modify_fact(table_fact & f) const { permutate_by_cycle(f, m_cycle); } virtual table_base * operator()(const table_base & t) { return auxiliary_table_transformer_fn::operator()(t); } }; table_transformer_fn * relation_manager::mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, const unsigned * permutation_cycle) { table_transformer_fn * res = t.get_plugin().mk_rename_fn(t, permutation_cycle_len, permutation_cycle); if(!res) { res = alloc(default_table_rename_fn, t.get_signature(), permutation_cycle_len, permutation_cycle); } return res; } table_transformer_fn * relation_manager::mk_permutation_rename_fn(const table_base & t, const unsigned * permutation) { table_transformer_fn * res = t.get_plugin().mk_permutation_rename_fn(t, permutation); if(!res) { res = alloc(default_table_permutation_rename_fn, t, permutation); } return res; } class relation_manager::default_table_union_fn : public table_union_fn { table_fact m_row; public: virtual void operator()(table_base & tgt, const table_base & src, table_base * delta) { table_base::iterator it = src.begin(); table_base::iterator iend = src.end(); for(; it!=iend; ++it) { it->get_fact(m_row); if(delta) { if(!tgt.contains_fact(m_row)) { tgt.add_new_fact(m_row); delta->add_fact(m_row); } } else { //if there's no delta, we don't need to know whether we are actually adding a new fact tgt.add_fact(m_row); } } } }; table_union_fn * relation_manager::mk_union_fn(const table_base & tgt, const table_base & src, const table_base * delta) { table_union_fn * res = tgt.get_plugin().mk_union_fn(tgt, src, delta); if(!res && &tgt.get_plugin()!=&src.get_plugin()) { res = src.get_plugin().mk_union_fn(tgt, src, delta); } if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { res = delta->get_plugin().mk_union_fn(tgt, src, delta); } if(!res) { res = alloc(default_table_union_fn); } return res; } table_union_fn * relation_manager::mk_widen_fn(const table_base & tgt, const table_base & src, const table_base * delta) { table_union_fn * res = tgt.get_plugin().mk_widen_fn(tgt, src, delta); if(!res && &tgt.get_plugin()!=&src.get_plugin()) { res = src.get_plugin().mk_widen_fn(tgt, src, delta); } if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { res = delta->get_plugin().mk_widen_fn(tgt, src, delta); } if(!res) { res = mk_union_fn(tgt, src, delta); } return res; } /** An auixiliary class for functors that perform filtering. It performs the table traversal and only asks for each individual row whether it should be removed. When using this class in multiple inheritance, this class should not be inherited publicly and should be mentioned as last. This should ensure that deteletion of the object will go well when initiated from a pointer to the first ancestor. */ class relation_manager::auxiliary_table_filter_fn { table_fact m_row; svector m_to_remove; public: virtual ~auxiliary_table_filter_fn() {} virtual bool should_remove(const table_fact & f) const = 0; void operator()(table_base & r) { m_to_remove.reset(); unsigned sz = 0; table_base::iterator it = r.begin(); table_base::iterator iend = r.end(); for(; it!=iend; ++it) { it->get_fact(m_row); if(should_remove(m_row)) { m_to_remove.append(m_row.size(), m_row.c_ptr()); ++sz; } } r.remove_facts(sz, m_to_remove.c_ptr()); } }; class relation_manager::default_table_filter_identical_fn : public table_mutator_fn, auxiliary_table_filter_fn { const unsigned m_col_cnt; const unsigned_vector m_identical_cols; public: default_table_filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) : m_col_cnt(col_cnt), m_identical_cols(col_cnt, identical_cols) { SASSERT(col_cnt>=2); } virtual bool should_remove(const table_fact & f) const { table_element val=f[m_identical_cols[0]]; for(unsigned i=1; iget_arg(0); if (!m.is_eq(condition)) { return 0; } expr* x = to_app(condition)->get_arg(0); expr* y = to_app(condition)->get_arg(1); if (!is_var(x)) { std::swap(x, y); } if (!is_var(x)) { return 0; } dl_decl_util decl_util(m); uint64 value = 0; if (!decl_util.is_numeral_ext(y, value)) { return 0; } return alloc(default_table_filter_not_equal_fn, ctx, to_var(x)->get_idx(), value); } }; class relation_manager::default_table_filter_interpreted_fn : public table_mutator_fn, auxiliary_table_filter_fn { ast_manager & m_ast_manager; var_subst & m_vs; dl_decl_util & m_decl_util; th_rewriter & m_simp; app_ref m_condition; ptr_vector m_var_sorts; expr_ref_vector m_args; public: default_table_filter_interpreted_fn(context & ctx, unsigned col_cnt, app* condition) : m_ast_manager(ctx.get_manager()), m_vs(ctx.get_var_subst()), m_decl_util(ctx.get_decl_util()), m_simp(ctx.get_rewriter()), m_condition(condition, ctx.get_manager()), m_args(ctx.get_manager()) { m_var_sorts.resize(col_cnt); get_free_vars(m_condition, m_var_sorts); } virtual bool should_remove(const table_fact & f) const { expr_ref_vector& args = const_cast(m_args); args.reset(); //arguments need to be in reverse order for the substitution unsigned col_cnt = f.size(); for(int i=col_cnt-1;i>=0;i--) { sort * var_sort = m_var_sorts[i]; if(!var_sort) { args.push_back(0); continue; //this variable does not occur in the condition; } table_element el = f[i]; args.push_back(m_decl_util.mk_numeral(el, var_sort)); } expr_ref ground(m_ast_manager); m_vs(m_condition.get(), args.size(), args.c_ptr(), ground); m_simp(ground); return m_ast_manager.is_false(ground); } virtual void operator()(table_base & t) { auxiliary_table_filter_fn::operator()(t); } }; table_mutator_fn * relation_manager::mk_filter_interpreted_fn(const table_base & t, app * condition) { context & ctx = get_context(); table_mutator_fn * res = t.get_plugin().mk_filter_interpreted_fn(t, condition); if (!res) { res = default_table_filter_not_equal_fn::mk(ctx, condition); } if(!res) { res = alloc(default_table_filter_interpreted_fn, ctx, t.get_signature().size(), condition); } return res; } table_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const table_base & t, const table_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) { table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt, t_cols, src_cols); if(!res && &t.get_plugin()!=&src.get_plugin()) { res = src.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt, t_cols, src_cols); } return res; } class relation_manager::default_table_negation_filter_fn : public convenient_table_negation_filter_fn, auxiliary_table_filter_fn { const table_base * m_negated_table; mutable table_fact m_aux_fact; public: default_table_negation_filter_fn(const table_base & tgt, const table_base & neg_t, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) : convenient_table_negation_filter_fn(tgt, neg_t, joined_col_cnt, t_cols, negated_cols), m_negated_table(0) { m_aux_fact.resize(neg_t.get_signature().size()); } virtual bool should_remove(const table_fact & f) const { if(!m_all_neg_bound || m_overlap) { table_base::iterator nit = m_negated_table->begin(); table_base::iterator nend = m_negated_table->end(); for(; nit!=nend; ++nit) { const table_base::row_interface & nrow = *nit; if(bindings_match(nrow, f)) { return true; } } return false; } else { make_neg_bindings(m_aux_fact, f); return m_negated_table->contains_fact(m_aux_fact); } } virtual void operator()(table_base & tgt, const table_base & negated_table) { SASSERT(m_negated_table==0); flet flet_neg_table(m_negated_table, &negated_table); auxiliary_table_filter_fn::operator()(tgt); } }; table_intersection_filter_fn * relation_manager::mk_filter_by_negation_fn(const table_base & t, const table_base & negated_obj, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) { table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, t_cols, negated_cols); if(!res && &t.get_plugin()!=&negated_obj.get_plugin()) { res = negated_obj.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, t_cols, negated_cols); } if(!res) { res = alloc(default_table_negation_filter_fn, t, negated_obj, joined_col_cnt, t_cols, negated_cols); } return res; } class relation_manager::default_table_select_equal_and_project_fn : public table_transformer_fn { scoped_ptr m_filter; scoped_ptr m_project; public: default_table_select_equal_and_project_fn(table_mutator_fn * filter, table_transformer_fn * project) : m_filter(filter), m_project(project) {} virtual table_base * operator()(const table_base & t1) { TRACE("dl", tout << t1.get_plugin().get_name() << "\n";); scoped_rel aux = t1.clone(); (*m_filter)(*aux); table_base * res = (*m_project)(*aux); return res; } }; table_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const table_base & t, const table_element & value, unsigned col) { table_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col); if(!res) { table_mutator_fn * selector = mk_filter_equal_fn(t, value, col); SASSERT(selector); table_transformer_fn * projector = mk_project_fn(t, 1, &col); SASSERT(projector); res = alloc(default_table_select_equal_and_project_fn, selector, projector); } return res; } class relation_manager::default_table_map_fn : public table_mutator_fn { scoped_ptr m_mapper; unsigned m_first_functional; scoped_rel m_aux_table; scoped_ptr m_union_fn; table_fact m_curr_fact; public: default_table_map_fn(const table_base & t, table_row_mutator_fn * mapper) : m_mapper(mapper), m_first_functional(t.get_signature().first_functional()) { SASSERT(t.get_signature().functional_columns()>0); table_plugin & plugin = t.get_plugin(); m_aux_table = plugin.mk_empty(t.get_signature()); m_union_fn = plugin.mk_union_fn(t, *m_aux_table, static_cast(0)); } virtual void operator()(table_base & t) { SASSERT(t.get_signature()==m_aux_table->get_signature()); if(!m_aux_table->empty()) { m_aux_table->reset(); } table_base::iterator it = t.begin(); table_base::iterator iend = t.end(); for(; it!=iend; ++it) { it->get_fact(m_curr_fact); if((*m_mapper)(m_curr_fact.c_ptr()+m_first_functional)) { m_aux_table->add_fact(m_curr_fact); } } t.reset(); (*m_union_fn)(t, *m_aux_table, static_cast(0)); } }; table_mutator_fn * relation_manager::mk_map_fn(const table_base & t, table_row_mutator_fn * mapper) { SASSERT(t.get_signature().functional_columns()>0); table_mutator_fn * res = t.get_plugin().mk_map_fn(t, mapper); if(!res) { res = alloc(default_table_map_fn, t, mapper); } return res; } class relation_manager::default_table_project_with_reduce_fn : public convenient_table_transformer_fn { unsigned_vector m_removed_cols; const unsigned m_inp_col_cnt; const unsigned m_removed_col_cnt; const unsigned m_result_col_cnt; scoped_ptr m_reducer; unsigned m_res_first_functional; table_fact m_row; table_fact m_former_row; public: default_table_project_with_reduce_fn(const table_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) : m_removed_cols(removed_col_cnt, removed_cols), m_inp_col_cnt(orig_sig.size()), m_removed_col_cnt(removed_col_cnt), m_result_col_cnt(orig_sig.size()-removed_col_cnt), m_reducer(reducer) { SASSERT(removed_col_cnt>0); table_signature::from_project_with_reduce(orig_sig, removed_col_cnt, removed_cols, get_result_signature()); m_res_first_functional = get_result_signature().first_functional(); m_row.resize(get_result_signature().size()); m_former_row.resize(get_result_signature().size()); } virtual void modify_fact(table_fact & f) const { unsigned ofs=1; unsigned r_i=1; for(unsigned i=m_removed_cols[0]+1; isuggest_fact(m_former_row)) { (*m_reducer)(m_former_row.c_ptr()+m_res_first_functional, m_row.c_ptr()+m_res_first_functional); res->ensure_fact(m_former_row); } } return res; } }; table_transformer_fn * relation_manager::mk_project_with_reduce_fn(const table_base & t, unsigned col_cnt, const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) { SASSERT(t.get_signature().functional_columns()>0); table_transformer_fn * res = t.get_plugin().mk_project_with_reduce_fn(t, col_cnt, removed_cols, reducer); if(!res) { res = alloc(default_table_project_with_reduce_fn, t.get_signature(), col_cnt, removed_cols, reducer); } return res; } };