/*++ Copyright (c) 2006 Microsoft Corporation Module Name: dl_table_relation.cpp Abstract: Author: Krystof Hoder (t-khoder) 2010-09-14. Revision History: --*/ #include #include"dl_context.h" #include"dl_relation_manager.h" #include"dl_table_relation.h" namespace datalog { // ----------------------------------- // // table_relation_plugin // // ----------------------------------- symbol table_relation_plugin::create_plugin_name(const table_plugin &p) { std::string name = std::string("tr_") + p.get_name().bare_str(); return symbol(name.c_str()); } bool table_relation_plugin::can_handle_signature(const relation_signature & s) { table_signature tsig; if(!get_manager().relation_signature_to_table(s, tsig)) { return false; } return m_table_plugin.can_handle_signature(tsig); } relation_base * table_relation_plugin::mk_empty(const relation_signature & s) { table_signature tsig; if(!get_manager().relation_signature_to_table(s, tsig)) { return 0; } table_base * t = m_table_plugin.mk_empty(tsig); return alloc(table_relation, *this, s, t); } relation_base * table_relation_plugin::mk_full(const relation_signature & s, func_decl* p, family_id kind) { table_signature tsig; if(!get_manager().relation_signature_to_table(s, tsig)) { return 0; } table_base * t = m_table_plugin.mk_full(p, tsig, kind); return alloc(table_relation, *this, s, t); } relation_base * table_relation_plugin::mk_from_table(const relation_signature & s, table_base * t) { if (&t->get_plugin() == &m_table_plugin) return alloc(table_relation, *this, s, t); table_relation_plugin& other = t->get_manager().get_table_relation_plugin(t->get_plugin()); return alloc(table_relation, other, s, t); } class table_relation_plugin::tr_join_project_fn : public convenient_relation_join_project_fn { scoped_ptr m_tfun; public: tr_join_project_fn(const relation_signature & s1, const relation_signature & s2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols, table_join_fn * tfun) : convenient_relation_join_project_fn(s1, s2, col_cnt, cols1, cols2, removed_col_cnt, removed_cols), m_tfun(tfun) {} virtual relation_base * operator()(const relation_base & t1, const relation_base & t2) { SASSERT(t1.from_table()); SASSERT(t2.from_table()); table_relation_plugin & plugin = static_cast(t1.get_plugin()); const table_relation & tr1 = static_cast(t1); const table_relation & tr2 = static_cast(t2); table_base * tres = (*m_tfun)(tr1.get_table(), tr2.get_table()); TRACE("dl_table_relation", tout << "# join => "; tres->display(tout);); if(&tres->get_plugin()!=&plugin.m_table_plugin) { //Operation returned a table of different type than the one which is associated with //this plugin. We need to get a correct table_relation_plugin and create the relation //using it. return plugin.get_manager().get_table_relation_plugin(tres->get_plugin()) .mk_from_table(get_result_signature(), tres); } return plugin.mk_from_table(get_result_signature(), tres); } }; relation_join_fn * table_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if(!r1.from_table() || !r2.from_table()) { return 0; } const table_relation & tr1 = static_cast(r1); const table_relation & tr2 = static_cast(r2); table_join_fn * tfun = get_manager().mk_join_fn(tr1.get_table(), tr2.get_table(), col_cnt, cols1, cols2); if(!tfun) { return 0; } return alloc(tr_join_project_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2, 0, static_cast(0), tfun); } relation_join_fn * table_relation_plugin::mk_join_project_fn(const relation_base & r1, const relation_base & r2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols) { if(!r1.from_table() || !r2.from_table()) { return 0; } const table_relation & tr1 = static_cast(r1); const table_relation & tr2 = static_cast(r2); table_join_fn * tfun = get_manager().mk_join_project_fn(tr1.get_table(), tr2.get_table(), joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols); SASSERT(tfun); return alloc(tr_join_project_fn, r1.get_signature(), r2.get_signature(), joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols, tfun); } class table_relation_plugin::tr_transformer_fn : public convenient_relation_transformer_fn { scoped_ptr m_tfun; public: tr_transformer_fn(const relation_signature & rsig, table_transformer_fn * tfun) : m_tfun(tfun) { get_result_signature() = rsig; } virtual relation_base * operator()(const relation_base & t) { SASSERT(t.from_table()); table_relation_plugin & plugin = static_cast(t.get_plugin()); const table_relation & tr = static_cast(t); table_base * tres = (*m_tfun)(tr.get_table()); TRACE("dl_table_relation", tout << "# transform => "; tres->display(tout);); if(&tres->get_plugin()!=&plugin.m_table_plugin) { //Transformation returned a table of different type than the one which is associated with this plugin. //We need to get a correct table_relation_plugin and create the relation using it. return plugin.get_manager().get_table_relation_plugin(tres->get_plugin()) .mk_from_table(get_result_signature(), tres); } return plugin.mk_from_table(get_result_signature(), tres); } }; relation_transformer_fn * table_relation_plugin::mk_project_fn(const relation_base & t, unsigned col_cnt, const unsigned * removed_cols) { if(!t.from_table()) { return 0; } const table_relation & tr = static_cast(t); table_transformer_fn * tfun = get_manager().mk_project_fn(tr.get_table(), col_cnt, removed_cols); SASSERT(tfun); relation_signature sig; relation_signature::from_project(t.get_signature(), col_cnt, removed_cols, sig); return alloc(tr_transformer_fn, sig, tfun); } relation_transformer_fn * table_relation_plugin::mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, const unsigned * permutation_cycle) { if(!t.from_table()) { return 0; } const table_relation & tr = static_cast(t); table_transformer_fn * tfun = get_manager().mk_rename_fn(tr.get_table(), permutation_cycle_len, permutation_cycle); SASSERT(tfun); relation_signature sig; relation_signature::from_rename(t.get_signature(), permutation_cycle_len, permutation_cycle, sig); return alloc(tr_transformer_fn, sig, tfun); } relation_transformer_fn * table_relation_plugin::mk_permutation_rename_fn(const relation_base & t, const unsigned * permutation) { if(!t.from_table()) { return 0; } const table_relation & tr = static_cast(t); table_transformer_fn * tfun = get_manager().mk_permutation_rename_fn(tr.get_table(), permutation); SASSERT(tfun); relation_signature sig; relation_signature::from_permutation_rename(t.get_signature(), permutation, sig); return alloc(tr_transformer_fn, sig, tfun); } relation_transformer_fn * table_relation_plugin::mk_select_equal_and_project_fn(const relation_base & t, const relation_element & value, unsigned col) { if(!t.from_table()) { return 0; } const table_relation & tr = static_cast(t); table_element tvalue; get_manager().relation_to_table(tr.get_signature()[col], value, tvalue); table_transformer_fn * tfun = get_manager().mk_select_equal_and_project_fn(tr.get_table(), tvalue, col); SASSERT(tfun); relation_signature res_sig; relation_signature::from_project(t.get_signature(), 1, &col, res_sig); return alloc(tr_transformer_fn, res_sig, tfun); } /** Union functor that can unite table relation into any other relation (using any delta relation) by iterating through the table and calling \c add_fact of the target relation. */ class table_relation_plugin::universal_target_union_fn : public relation_union_fn { virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { SASSERT(src.from_table()); const table_relation & tr_src = static_cast(src); relation_manager & rmgr = tr_src.get_manager(); relation_signature sig = tr_src.get_signature(); SASSERT(tgt.get_signature()==sig); SASSERT(!delta || delta->get_signature()==sig); table_base::iterator it = tr_src.get_table().begin(); table_base::iterator end = tr_src.get_table().end(); table_fact tfact; relation_fact rfact(rmgr.get_context()); for (; it != end; ++it) { it->get_fact(tfact); rmgr.table_fact_to_relation(sig, tfact, rfact); if(delta) { if(!tgt.contains_fact(rfact)) { tgt.add_new_fact(rfact); delta->add_fact(rfact); } } else { tgt.add_fact(rfact); } } TRACE("dl_table_relation", tout << "# universal union => "; tgt.display(tout);); } }; class table_relation_plugin::tr_union_fn : public relation_union_fn { scoped_ptr m_tfun; public: tr_union_fn(table_union_fn * tfun) : m_tfun(tfun) {} virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { SASSERT(tgt.from_table()); SASSERT(src.from_table()); SASSERT(!delta || delta->from_table()); table_relation & tr_tgt = static_cast(tgt); const table_relation & tr_src = static_cast(src); table_relation * tr_delta = static_cast(delta); (*m_tfun)(tr_tgt.get_table(), tr_src.get_table(), tr_delta ? &tr_delta->get_table() : 0); TRACE("dl_table_relation", tout << "# union => "; tr_tgt.get_table().display(tout);); } }; relation_union_fn * table_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { if(!src.from_table()) { return 0; } if(!tgt.from_table() || (delta && !delta->from_table())) { return alloc(universal_target_union_fn); } const table_relation & tr_tgt = static_cast(tgt); const table_relation & tr_src = static_cast(src); const table_relation * tr_delta = static_cast(delta); table_union_fn * tfun = get_manager().mk_union_fn(tr_tgt.get_table(), tr_src.get_table(), tr_delta ? &tr_delta->get_table() : 0); SASSERT(tfun); return alloc(tr_union_fn, tfun); } class table_relation_plugin::tr_mutator_fn : public relation_mutator_fn { scoped_ptr m_tfun; public: tr_mutator_fn(table_mutator_fn * tfun) : m_tfun(tfun) {} virtual void operator()(relation_base & r) { SASSERT(r.from_table()); table_relation & tr = static_cast(r); (*m_tfun)(tr.get_table()); TRACE("dl_table_relation", tout << "# mutator => "; tr.get_table().display(tout);); } }; relation_mutator_fn * table_relation_plugin::mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { if(!t.from_table()) { return 0; } const table_relation & tr = static_cast(t); table_mutator_fn * tfun = get_manager().mk_filter_identical_fn(tr.get_table(), col_cnt, identical_cols); SASSERT(tfun); return alloc(tr_mutator_fn, tfun); } relation_mutator_fn * table_relation_plugin::mk_filter_equal_fn(const relation_base & t, const relation_element & value, unsigned col) { if(!t.from_table()) { return 0; } const table_relation & tr = static_cast(t); table_element tvalue; get_manager().relation_to_table(tr.get_signature()[col], value, tvalue); table_mutator_fn * tfun = get_manager().mk_filter_equal_fn(tr.get_table(), tvalue, col); SASSERT(tfun); return alloc(tr_mutator_fn, tfun); } relation_mutator_fn * table_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { bool condition_needs_transforming = false; if(!t.from_table() || condition_needs_transforming) { return 0; } const table_relation & tr = static_cast(t); table_mutator_fn * tfun = get_manager().mk_filter_interpreted_fn(tr.get_table(), condition); SASSERT(tfun); return alloc(tr_mutator_fn, tfun); } class table_relation_plugin::tr_intersection_filter_fn : public relation_intersection_filter_fn { scoped_ptr m_tfun; public: tr_intersection_filter_fn(table_intersection_filter_fn * tfun) : m_tfun(tfun) {} virtual void operator()(relation_base & r, const relation_base & src) { SASSERT(r.from_table()); SASSERT(src.from_table()); table_relation & tr = static_cast(r); const table_relation & tr_src = static_cast(src); (*m_tfun)(tr.get_table(), tr_src.get_table()); TRACE("dl_table_relation", tout << "# negation_filter => "; tr.get_table().display(tout);); } }; relation_intersection_filter_fn * table_relation_plugin::mk_filter_by_intersection_fn(const relation_base & r, const relation_base & src, unsigned joined_col_cnt, const unsigned * r_cols, const unsigned * src_cols) { if(!r.from_table() || !src.from_table()) { return 0; } const table_relation & tr = static_cast(r); const table_relation & tr_neg = static_cast(src); table_intersection_filter_fn * tfun = get_manager().mk_filter_by_intersection_fn(tr.get_table(), tr_neg.get_table(), joined_col_cnt, r_cols, src_cols); if(!tfun) { return 0; } return alloc(tr_intersection_filter_fn, tfun); } relation_intersection_filter_fn * table_relation_plugin::mk_filter_by_negation_fn(const relation_base & r, const relation_base & negated_rel, unsigned joined_col_cnt, const unsigned * r_cols, const unsigned * negated_cols) { if(!r.from_table() || !negated_rel.from_table()) { return 0; } const table_relation & tr = static_cast(r); const table_relation & tr_neg = static_cast(negated_rel); table_intersection_filter_fn * tfun = get_manager().mk_filter_by_negation_fn(tr.get_table(), tr_neg.get_table(), joined_col_cnt, r_cols, negated_cols); SASSERT(tfun); return alloc(tr_intersection_filter_fn, tfun); } // ----------------------------------- // // table_relation // // ----------------------------------- void table_relation::add_table_fact(const table_fact & f) { get_table().add_fact(f); } void table_relation::add_fact(const relation_fact & f) { SASSERT(f.size()==get_signature().size()); table_fact vals; get_manager().relation_fact_to_table(get_signature(), f, vals); get_table().add_fact(vals); TRACE("dl_table_relation", tout << "# add fact => "; get_table().display(tout);); } bool table_relation::contains_fact(const relation_fact & f) const { table_fact vals; get_manager().relation_fact_to_table(get_signature(), f, vals); return get_table().contains_fact(vals); } relation_base * table_relation::clone() const { table_base * tres = get_table().clone(); return get_plugin().mk_from_table(get_signature(), tres); } relation_base * table_relation::complement(func_decl* p) const { table_base * tres = get_table().complement(p); return get_plugin().mk_from_table(get_signature(), tres); } void table_relation::display_tuples(func_decl & pred, std::ostream & out) const { context & ctx = get_manager().get_context(); unsigned arity = pred.get_arity(); out << "Tuples in " << pred.get_name() << ": \n"; table_base::iterator it = get_table().begin(); table_base::iterator end = get_table().end(); table_fact fact; for (; it != end; ++it) { it->get_fact(fact); out << "\t("; for(unsigned i=0;i