#pragma once
#include "muz/base/dl_context.h"
#include "muz/base/dl_rule_transformer.h"
#include "muz/transforms/dl_mk_interp_tail_simplifier.h"
#include "ast/substitution/unifier.h"
#include "ast/substitution/substitution.h"
#include "ast/substitution/substitution_tree.h"
namespace datalog {
class rule_unifier {
ast_manager& m;
rule_manager& m_rm;
context& m_context;
mk_interp_tail_simplifier m_interp_simplifier;
substitution m_subst;
unifier m_unif;
bool m_ready;
bool m_normalize;
unsigned m_deltas[2];
public:
rule_unifier(context& ctx)
: m(ctx.get_manager()), m_rm(ctx.get_rule_manager()), m_context(ctx),
m_interp_simplifier(ctx), m_subst(m), m_unif(m), m_ready(false), m_normalize(true) {}
bool unify_rules(rule const& tgt, unsigned tgt_idx, rule const& src);
bool apply(rule const& tgt, unsigned tgt_idx, rule const& src, rule_ref& result);
void display(std::ostream& stm) { m_subst.display(stm, 2, m_deltas); }
expr_ref_vector get_rule_subst(rule const& r, bool is_tgt);
void set_normalize(bool n) { m_normalize = n; }
private:
void apply(app * a, bool is_tgt, app_ref& res);
void apply(rule const& r, bool is_tgt, unsigned skipped_index, app_ref_vector& res,
bool_vector& res_neg);
};
class mk_rule_inliner : public rule_transformer::plugin {
struct has_new_quantifier {};
class visitor : public st_visitor {
context& m_context;
unsigned_vector m_unifiers;
bool_vector m_can_remove, m_can_expand;
obj_map<expr, unsigned_vector> m_positions;
public:
visitor(context& c, substitution & s): st_visitor(s), m_context(c) { (void) m_context; }
bool operator()(expr* e) override;
void reset() { m_unifiers.reset(); }
void reset(unsigned sz);
bool_vector& can_remove() { return m_can_remove; }
bool_vector& can_expand() { return m_can_expand; }
unsigned_vector const& add_position(expr* e, unsigned j);
unsigned_vector const& del_position(expr* e, unsigned j);
unsigned_vector const& get_unifiers() { return m_unifiers; }
};
typedef obj_map<func_decl, func_decl *> decl_map;
ast_manager & m;
rule_manager & m_rm;
context & m_context;
th_rewriter& m_simp;
rule_ref_vector m_pinned;
func_decl_set m_forbidden_preds;
func_decl_set m_preds_with_facts;
func_decl_set m_preds_with_neg_occurrence;
ast_counter m_head_pred_ctr;
ast_counter m_head_pred_non_empty_tails_ctr;
ast_counter m_tail_pred_ctr;
rule_set m_inlined_rules;
horn_subsume_model_converter* m_mc;
rule_unifier m_unifier;
substitution_tree m_head_index; substitution_tree m_tail_index;
substitution m_subst;
visitor m_head_visitor;
visitor m_tail_visitor;
bool tail_matches_head(app * tail, app* head);
bool try_to_inline_rule(rule& tgt, rule& src, unsigned tail_index, rule_ref& res);
bool inlining_allowed(rule_set const& orig, func_decl * pred);
void count_pred_occurrences(rule_set const & orig);
void plan_inlining(rule_set const & orig);
rule_set * create_allowed_rule_set(rule_set const & orig);
bool forbid_preds_from_cycles(rule_set const & r);
bool forbid_multiple_multipliers(const rule_set & orig, rule_set const & proposed_inlined_rules);
bool transform_rule(rule_set const& orig, rule * r, rule_set& tgt);
bool transform_rules(const rule_set & orig, rule_set & tgt);
bool is_oriented_rewriter(rule * r, rule_stratifier const& strat);
bool do_eager_inlining(rule * r, rule_set const& rules, rule_ref& res);
bool do_eager_inlining(scoped_ptr<rule_set> & rules);
bool has_quantifier(rule const& r) const;
bool inline_linear(scoped_ptr<rule_set>& rules);
void add_rule(rule_set const& rule_set, rule* r, unsigned i);
void del_rule(rule* r, unsigned i);
public:
mk_rule_inliner(context & ctx, unsigned priority=35000)
: plugin(priority),
m(ctx.get_manager()),
m_rm(ctx.get_rule_manager()),
m_context(ctx),
m_simp(m_context.get_rewriter()),
m_pinned(m_rm),
m_inlined_rules(m_context),
m_mc(nullptr),
m_unifier(ctx),
m_head_index(m),
m_tail_index(m),
m_subst(m),
m_head_visitor(ctx, m_subst),
m_tail_visitor(ctx, m_subst)
{}
rule_set * operator()(rule_set const & source) override;
};
};