3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-11 19:53:34 +00:00
z3/lib/dl_mk_rule_inliner.h
Leonardo de Moura e9eab22e5c Z3 sources
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2012-10-02 11:35:25 -07:00

199 lines
6.6 KiB
C++

/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
dl_mk_interp_tail_simplifier.h
Abstract:
Rule transformer which inlines some of the rules
Author:
Krystof Hoder (t-khoder) 2011-10-02.
Revision History:
--*/
#ifndef _DL_MK_RULE_INLINER_H_
#define _DL_MK_RULE_INLINER_H_
#include "dl_context.h"
#include "dl_rule_transformer.h"
#include "dl_mk_interp_tail_simplifier.h"
#include "unifier.h"
#include "substitution.h"
#include "substitution_tree.h"
namespace datalog {
class rule_unifier {
ast_manager& m;
rule_manager& m_rm;
context& m_context;
/** We use this simplifier after inlining to get nicer intermediate rules */
mk_interp_tail_simplifier m_interp_simplifier;
substitution m_subst;
unifier m_unif;
bool m_ready;
unsigned m_deltas[2];
public:
rule_unifier(rule_manager& rm, context& ctx, ast_manager& m)
: m(m), m_rm(rm), m_context(ctx), m_interp_simplifier(ctx), m_subst(m), m_unif(m), m_ready(false) {}
/** Reset subtitution and unify tail tgt_idx of the target rule and the head of the src rule */
bool unify_rules(const rule& tgt, unsigned tgt_idx, const rule& src);
/**
\brief Apply unifier to rules.
Return false if the resulting rule is a tautology (the interpreted tail is unsat).
*/
bool apply(rule& tgt, unsigned tgt_idx, rule& src, rule_ref& result);
void display(std::ostream& stm) { m_subst.display(stm, 2, m_deltas); }
/**
Retrieve substitutions for src/tgt. (second argument of unify_rules).
*/
expr_ref_vector get_rule_subst(const rule& r, bool is_tgt);
private:
void apply(app * a, bool is_tgt, app_ref& res);
/**
Apply substitution to a rule tail. Tail with skipped_index is skipped,
unless skipped_index is equal to UINT_MAX
*/
void apply(rule& r, bool is_tgt, unsigned skipped_index, app_ref_vector& res,
svector<bool>& res_neg);
};
class mk_rule_inliner : public rule_transformer::plugin {
class visitor : public st_visitor {
context& m_context;
unsigned_vector m_unifiers;
svector<bool> 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) {}
virtual bool operator()(expr* e);
void reset() { m_unifiers.reset(); }
void reset(unsigned sz);
svector<bool>& can_remove() { return m_can_remove; }
svector<bool>& 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;
decl_set m_forbidden_preds;
decl_set m_preds_with_facts;
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;
replace_proof_converter* m_pc;
//used in try_to_inline_rule and do_eager_inlining
rule_unifier m_unifier;
substitution_tree m_head_index; // for straight-line relation inlining.
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(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);
/** Ensure we don't inline two multi-head rules that would appear together in some tail */
bool forbid_multiple_multipliers(const rule_set & orig, rule_set const & proposed_inlined_rules);
/** Return true if the rule was modified */
bool transform_rule(rule * r, rule_set& tgt);
/** Return true if some transformation was performed */
bool transform_rules(const rule_set & orig, rule_set & tgt);
bool is_oriented_rewriter(rule * r, rule_stratifier const& strat);
/**
Return false if nothing was done with the rule.
res may be set to zero if we managed to prove the rule unsatisfiable.
*/
bool do_eager_inlining(rule * r, rule_set const& rules, rule_ref& res);
/**
Inline rules even if it doesn't lead to elimination of the whole predicate.
The inlining is done as long as it doesn't increase the number of rules
(i.e. when only one rule defining a predicate can replace tail atom).
The original rule-set must be closed before passing t this function
*/
bool do_eager_inlining(scoped_ptr<rule_set> & rules);
bool has_quantifier(rule const& r) const;
/**
Inline predicates that are known to not be join-points.
*/
bool inline_linear(scoped_ptr<rule_set>& rules);
void add_rule(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_unifier(ctx.get_rule_manager(), ctx, m),
m_mc(0),
m_pc(0),
m_head_index(m),
m_tail_index(m),
m_subst(m),
m_head_visitor(ctx, m_subst),
m_tail_visitor(ctx, m_subst)
{}
virtual ~mk_rule_inliner() { }
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
};
};
#endif /* _DL_MK_INTERP_TAIL_SIMPLIFIER_H_ */