/*++ Copyright (c) 2012 Microsoft Corporation Module Name: dl_mk_partial_equiv.cpp Abstract: Rule transformer which identifies predicates that are partial equivalence relations. Author: Nikolaj Bjorner (nbjorner) 2012-05-14 Revision History: --*/ #include "dl_mk_partial_equiv.h" #include "ast_pp.h" namespace datalog { bool mk_partial_equivalence_transformer::is_symmetry(rule const* r) { func_decl* p = r->get_head()->get_decl(); return p->get_arity() == 2 && p->get_domain(0) == p->get_domain(1) && r->get_tail_size() == 1 && r->get_tail(0)->get_decl() == p && r->get_head()->get_arg(0) == r->get_tail(0)->get_arg(1) && r->get_head()->get_arg(1) == r->get_tail(0)->get_arg(0) && is_var(r->get_head()->get_arg(0)) && is_var(r->get_head()->get_arg(1)) && r->get_head()->get_arg(0) != r->get_head()->get_arg(1); } bool mk_partial_equivalence_transformer::is_transitivity(rule const* r) { func_decl* p = r->get_head()->get_decl(); if (p->get_arity() != 2 || p->get_domain(0) != p->get_domain(1) || r->get_tail_size() != 2 || r->get_tail(0)->get_decl() != p || r->get_tail(1)->get_decl() != p) { return false; } app* h = r->get_head(); app* a = r->get_tail(0); app* b = r->get_tail(1); expr* x1 = h->get_arg(0); expr* x2 = h->get_arg(1); expr* a1 = a->get_arg(0); expr* a2 = a->get_arg(1); expr* b1 = b->get_arg(0); expr* b2 = b->get_arg(1); if (!(is_var(x1) && is_var(x2) && is_var(a1) && is_var(a2) && is_var(b1) && is_var(b2))) { return false; } if (x1 == x2 || a1 == a2 || b1 == b2) { return false; } if (a2 == b1) { if (x1 == b2 && x2 == a1) { return true; } if (x1 == a1 && x2 == b2) { return true; } return false; } if (a1 == b2) { if (x1 == b1 && x2 == a2) { return true; } if (x1 == a2 && x2 == b1) { return true; } return false; } return false; ; } rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { // TODO mc, pc if (source.get_num_rules() == 0) { return 0; } if (m_context.get_engine() != DATALOG_ENGINE) { return 0; } relation_manager & rm = m_context.get_rmanager(); rule_set::decl2rules::iterator it = source.begin_grouped_rules(); rule_set::decl2rules::iterator end = source.end_grouped_rules(); rule_set* res = alloc(rule_set, m_context); for (; it != end; ++it) { func_decl* p = it->m_key; rule_vector const& rv = *(it->m_value); bool has_symmetry = false; bool has_transitivity = false; unsigned i_symmetry, i_transitivity; family_id kind = rm.get_requested_predicate_kind(p); for (unsigned i = 0; i < rv.size(); ++i) { if (kind != null_family_id) { res->add_rule(rv[i]); } else if (is_symmetry(rv[i])) { i_symmetry = i; has_symmetry = true; } else if (is_transitivity(rv[i])) { i_transitivity = i; has_transitivity = true; } else { res->add_rule(rv[i]); } } if (has_symmetry && !has_transitivity) { res->add_rule(rv[i_symmetry]); } else if (!has_symmetry && has_transitivity) { res->add_rule(rv[i_transitivity]); } else if (has_symmetry && has_transitivity) { TRACE("dl", tout << "updating predicate " << mk_pp(p, m) << " to partial equivalence\n";); SASSERT(kind == null_family_id); rm.set_predicate_kind(p, rm.get_table_plugin(symbol("equivalence"))->get_kind()); } } if (res->get_num_rules() == source.get_num_rules()) { dealloc(res); return 0; } return res; } };