mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-03 21:09:11 +00:00 
			
		
		
		
	removing dependency on simplifier in pattern_inference
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									e5826b957f
								
							
						
					
					
						commit
						655b3d9c19
					
				
					 8 changed files with 861 additions and 167 deletions
				
			
		| 
						 | 
					@ -298,104 +298,6 @@ struct macro_manager::macro_expander_rw : public rewriter_tpl<macro_manager::mac
 | 
				
			||||||
    {}
 | 
					    {}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro_manager::macro_expander::macro_expander(ast_manager & m, macro_manager & mm):
 | 
					 | 
				
			||||||
    simplifier(m),
 | 
					 | 
				
			||||||
    m_macro_manager(mm) {
 | 
					 | 
				
			||||||
    // REMARK: theory simplifier should not be used by macro_expander...
 | 
					 | 
				
			||||||
    // is_arith_macro rewrites a quantifer such as:
 | 
					 | 
				
			||||||
    //   forall (x Int) (= (+ x (+ (f x) 1)) 2)
 | 
					 | 
				
			||||||
    // into
 | 
					 | 
				
			||||||
    //   forall (x Int) (= (f x) (+ 1 (* -1 x)))
 | 
					 | 
				
			||||||
    // The goal is to make simple macro detection detect the arith macro.
 | 
					 | 
				
			||||||
    // The arith simplifier will undo this transformation.
 | 
					 | 
				
			||||||
    // borrow_plugins(s);
 | 
					 | 
				
			||||||
    enable_ac_support(false);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
macro_manager::macro_expander::~macro_expander() {
 | 
					 | 
				
			||||||
    // release_plugins();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void macro_manager::macro_expander::reduce1_quantifier(quantifier * q) {
 | 
					 | 
				
			||||||
    simplifier::reduce1_quantifier(q);
 | 
					 | 
				
			||||||
    // If a macro was expanded in a pattern, we must erase it since it may not be a valid pattern anymore.
 | 
					 | 
				
			||||||
    // The MAM assumes valid patterns, and it crashes if invalid patterns are provided.
 | 
					 | 
				
			||||||
    // For example, it will crash if the pattern does not contain all variables.
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Alternative solution: use pattern_validation to check if the pattern is still valid.
 | 
					 | 
				
			||||||
    // I'm not sure if this is a good solution, since the pattern may be meaningless after the macro expansion.
 | 
					 | 
				
			||||||
    // So, I'm just erasing them.
 | 
					 | 
				
			||||||
    expr *  new_q_expr = 0;
 | 
					 | 
				
			||||||
    proof * new_q_pr = 0;
 | 
					 | 
				
			||||||
    get_cached(q, new_q_expr, new_q_pr);
 | 
					 | 
				
			||||||
    if (!is_quantifier(new_q_expr))
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    quantifier * new_q = to_quantifier(new_q_expr);
 | 
					 | 
				
			||||||
    bool erase_patterns = false;
 | 
					 | 
				
			||||||
    if (q->get_num_patterns() != new_q->get_num_patterns() ||
 | 
					 | 
				
			||||||
        q->get_num_no_patterns() != new_q->get_num_no_patterns()) {
 | 
					 | 
				
			||||||
        erase_patterns = true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
        for (unsigned i = 0; !erase_patterns && i < q->get_num_patterns(); i++) {
 | 
					 | 
				
			||||||
            if (q->get_pattern(i) != new_q->get_pattern(i))
 | 
					 | 
				
			||||||
                erase_patterns = true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        for (unsigned i = 0; !erase_patterns && i < q->get_num_no_patterns(); i++) {
 | 
					 | 
				
			||||||
            if (q->get_no_pattern(i) != new_q->get_no_pattern(i))
 | 
					 | 
				
			||||||
                erase_patterns = true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (erase_patterns) {
 | 
					 | 
				
			||||||
        ast_manager & m = get_manager();
 | 
					 | 
				
			||||||
        expr * new_new_q = m.update_quantifier(new_q, 0, 0, 0, 0, new_q->get_expr());
 | 
					 | 
				
			||||||
        // we can use the same proof since new_new_q and new_q are identical modulo patterns/annotations
 | 
					 | 
				
			||||||
        cache_result(q, new_new_q, new_q_pr);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref & p) {
 | 
					 | 
				
			||||||
    if (!is_app(_n))
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    app * n = to_app(_n);
 | 
					 | 
				
			||||||
    quantifier * q = 0;
 | 
					 | 
				
			||||||
    func_decl * d  = n->get_decl();
 | 
					 | 
				
			||||||
    TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";);
 | 
					 | 
				
			||||||
    if (m_macro_manager.m_decl2macro.find(d, q)) {
 | 
					 | 
				
			||||||
        TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";);
 | 
					 | 
				
			||||||
        app * head = 0;
 | 
					 | 
				
			||||||
        expr * def = 0;
 | 
					 | 
				
			||||||
        m_macro_manager.get_head_def(q, d, head, def);
 | 
					 | 
				
			||||||
        unsigned num = n->get_num_args();
 | 
					 | 
				
			||||||
        SASSERT(head && def);
 | 
					 | 
				
			||||||
        ptr_buffer<expr> subst_args;
 | 
					 | 
				
			||||||
        subst_args.resize(num, 0);
 | 
					 | 
				
			||||||
        for (unsigned i = 0; i < num; i++) {
 | 
					 | 
				
			||||||
            var * v = to_var(head->get_arg(i));
 | 
					 | 
				
			||||||
            SASSERT(v->get_idx() < num);
 | 
					 | 
				
			||||||
            unsigned nidx = num - v->get_idx() - 1;
 | 
					 | 
				
			||||||
            SASSERT(subst_args[nidx] == 0);
 | 
					 | 
				
			||||||
            subst_args[nidx] = n->get_arg(i);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        var_subst s(m);
 | 
					 | 
				
			||||||
        s(def, num, subst_args.c_ptr(), r);
 | 
					 | 
				
			||||||
        if (m.proofs_enabled()) {
 | 
					 | 
				
			||||||
            expr_ref instance(m);
 | 
					 | 
				
			||||||
            s(q->get_expr(), num, subst_args.c_ptr(), instance);
 | 
					 | 
				
			||||||
            proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr());
 | 
					 | 
				
			||||||
            proof * q_pr  = 0;
 | 
					 | 
				
			||||||
            m_macro_manager.m_decl2macro_pr.find(d, q_pr);
 | 
					 | 
				
			||||||
            SASSERT(q_pr != 0);
 | 
					 | 
				
			||||||
            proof * prs[2] = { qi_pr, q_pr };
 | 
					 | 
				
			||||||
            p = m.mk_unit_resolution(2, prs);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            p = 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void macro_manager::expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref & new_pr) {
 | 
					void macro_manager::expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref & new_pr) {
 | 
				
			||||||
    if (has_macros()) {
 | 
					    if (has_macros()) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,17 +60,6 @@ class macro_manager {
 | 
				
			||||||
    struct macro_expander_cfg;
 | 
					    struct macro_expander_cfg;
 | 
				
			||||||
    struct macro_expander_rw;
 | 
					    struct macro_expander_rw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class macro_expander : public simplifier {
 | 
					 | 
				
			||||||
    protected:
 | 
					 | 
				
			||||||
        macro_manager &   m_macro_manager;
 | 
					 | 
				
			||||||
        virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p);
 | 
					 | 
				
			||||||
        virtual void reduce1_quantifier(quantifier * q);
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        macro_expander(ast_manager & m, macro_manager & mm);
 | 
					 | 
				
			||||||
        ~macro_expander();
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    friend class macro_expander;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    macro_manager(ast_manager & m);
 | 
					    macro_manager(ast_manager & m);
 | 
				
			||||||
    ~macro_manager();
 | 
					    ~macro_manager();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,15 +16,17 @@ Author:
 | 
				
			||||||
Revision History:
 | 
					Revision History:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--*/
 | 
					--*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "util/warning.h"
 | 
				
			||||||
#include "ast/pattern/pattern_inference.h"
 | 
					#include "ast/pattern/pattern_inference.h"
 | 
				
			||||||
#include "ast/ast_ll_pp.h"
 | 
					#include "ast/ast_ll_pp.h"
 | 
				
			||||||
#include "ast/ast_pp.h"
 | 
					#include "ast/ast_pp.h"
 | 
				
			||||||
#include "ast/ast_util.h"
 | 
					#include "ast/ast_util.h"
 | 
				
			||||||
#include "util/warning.h"
 | 
					 | 
				
			||||||
#include "ast/arith_decl_plugin.h"
 | 
					#include "ast/arith_decl_plugin.h"
 | 
				
			||||||
#include "ast/normal_forms/pull_quant.h"
 | 
					#include "ast/normal_forms/pull_quant.h"
 | 
				
			||||||
#include "ast/well_sorted.h"
 | 
					#include "ast/well_sorted.h"
 | 
				
			||||||
#include "ast/for_each_expr.h"
 | 
					#include "ast/for_each_expr.h"
 | 
				
			||||||
 | 
					#include "ast/rewriter/rewriter_def.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void smaller_pattern::save(expr * p1, expr * p2) {
 | 
					void smaller_pattern::save(expr * p1, expr * p2) {
 | 
				
			||||||
    expr_pair e(p1, p2);
 | 
					    expr_pair e(p1, p2);
 | 
				
			||||||
| 
						 | 
					@ -87,7 +89,7 @@ bool smaller_pattern::operator()(unsigned num_bindings, expr * p1, expr * p2) {
 | 
				
			||||||
    return process(p1, p2);
 | 
					    return process(p1, p2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params & params):
 | 
					pattern_inference_old::pattern_inference_old(ast_manager & m, pattern_inference_params & params):
 | 
				
			||||||
    simplifier(m),
 | 
					    simplifier(m),
 | 
				
			||||||
    m_params(params),
 | 
					    m_params(params),
 | 
				
			||||||
    m_bfid(m.get_basic_family_id()),
 | 
					    m_bfid(m.get_basic_family_id()),
 | 
				
			||||||
| 
						 | 
					@ -105,7 +107,7 @@ pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params &
 | 
				
			||||||
    enable_ac_support(false);
 | 
					    enable_ac_support(false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) {
 | 
					void pattern_inference_old::collect::operator()(expr * n, unsigned num_bindings) {
 | 
				
			||||||
    SASSERT(m_info.empty());
 | 
					    SASSERT(m_info.empty());
 | 
				
			||||||
    SASSERT(m_todo.empty());
 | 
					    SASSERT(m_todo.empty());
 | 
				
			||||||
    SASSERT(m_cache.empty());
 | 
					    SASSERT(m_cache.empty());
 | 
				
			||||||
| 
						 | 
					@ -125,7 +127,7 @@ void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) {
 | 
				
			||||||
    reset();
 | 
					    reset();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void pattern_inference::collect::visit(expr * n, unsigned delta, bool & visited) {
 | 
					inline void pattern_inference_old::collect::visit(expr * n, unsigned delta, bool & visited) {
 | 
				
			||||||
    entry e(n, delta);
 | 
					    entry e(n, delta);
 | 
				
			||||||
    if (!m_cache.contains(e)) {
 | 
					    if (!m_cache.contains(e)) {
 | 
				
			||||||
        m_todo.push_back(e);
 | 
					        m_todo.push_back(e);
 | 
				
			||||||
| 
						 | 
					@ -133,7 +135,7 @@ inline void pattern_inference::collect::visit(expr * n, unsigned delta, bool & v
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool pattern_inference::collect::visit_children(expr * n, unsigned delta) {
 | 
					bool pattern_inference_old::collect::visit_children(expr * n, unsigned delta) {
 | 
				
			||||||
    bool visited = true;
 | 
					    bool visited = true;
 | 
				
			||||||
    unsigned i;
 | 
					    unsigned i;
 | 
				
			||||||
    switch (n->get_kind()) {
 | 
					    switch (n->get_kind()) {
 | 
				
			||||||
| 
						 | 
					@ -153,13 +155,13 @@ bool pattern_inference::collect::visit_children(expr * n, unsigned delta) {
 | 
				
			||||||
    return visited;
 | 
					    return visited;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void pattern_inference::collect::save(expr * n, unsigned delta, info * i) {
 | 
					inline void pattern_inference_old::collect::save(expr * n, unsigned delta, info * i) {
 | 
				
			||||||
    m_cache.insert(entry(n, delta), i);
 | 
					    m_cache.insert(entry(n, delta), i);
 | 
				
			||||||
    if (i != 0)
 | 
					    if (i != 0)
 | 
				
			||||||
        m_info.push_back(i);
 | 
					        m_info.push_back(i);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
 | 
					void pattern_inference_old::collect::save_candidate(expr * n, unsigned delta) {
 | 
				
			||||||
    switch (n->get_kind()) {
 | 
					    switch (n->get_kind()) {
 | 
				
			||||||
    case AST_VAR: {
 | 
					    case AST_VAR: {
 | 
				
			||||||
        unsigned idx = to_var(n)->get_idx();
 | 
					        unsigned idx = to_var(n)->get_idx();
 | 
				
			||||||
| 
						 | 
					@ -247,14 +249,14 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pattern_inference::collect::reset() {
 | 
					void pattern_inference_old::collect::reset() {
 | 
				
			||||||
    m_cache.reset();
 | 
					    m_cache.reset();
 | 
				
			||||||
    std::for_each(m_info.begin(), m_info.end(), delete_proc<info>());
 | 
					    std::for_each(m_info.begin(), m_info.end(), delete_proc<info>());
 | 
				
			||||||
    m_info.reset();
 | 
					    m_info.reset();
 | 
				
			||||||
    SASSERT(m_todo.empty());
 | 
					    SASSERT(m_todo.empty());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsigned size) {
 | 
					void pattern_inference_old::add_candidate(app * n, uint_set const & free_vars, unsigned size) {
 | 
				
			||||||
    for (unsigned i = 0; i < m_num_no_patterns; i++) {
 | 
					    for (unsigned i = 0; i < m_num_no_patterns; i++) {
 | 
				
			||||||
        if (n == m_no_patterns[i])
 | 
					        if (n == m_no_patterns[i])
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
| 
						 | 
					@ -271,7 +273,7 @@ void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsig
 | 
				
			||||||
   \brief Copy the non-looping patterns in m_candidates to result when m_params.m_pi_block_loop_patterns = true.
 | 
					   \brief Copy the non-looping patterns in m_candidates to result when m_params.m_pi_block_loop_patterns = true.
 | 
				
			||||||
   Otherwise, copy m_candidates to result.
 | 
					   Otherwise, copy m_candidates to result.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
void pattern_inference::filter_looping_patterns(ptr_vector<app> & result) {
 | 
					void pattern_inference_old::filter_looping_patterns(ptr_vector<app> & result) {
 | 
				
			||||||
    unsigned num = m_candidates.size();
 | 
					    unsigned num = m_candidates.size();
 | 
				
			||||||
    for (unsigned i1 = 0; i1 < num; i1++) {
 | 
					    for (unsigned i1 = 0; i1 < num; i1++) {
 | 
				
			||||||
        app * n1 = m_candidates.get(i1);
 | 
					        app * n1 = m_candidates.get(i1);
 | 
				
			||||||
| 
						 | 
					@ -310,7 +312,7 @@ void pattern_inference::filter_looping_patterns(ptr_vector<app> & result) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void pattern_inference::contains_subpattern::save(expr * n) {
 | 
					inline void pattern_inference_old::contains_subpattern::save(expr * n) {
 | 
				
			||||||
    unsigned id = n->get_id();
 | 
					    unsigned id = n->get_id();
 | 
				
			||||||
    m_already_processed.assure_domain(id);
 | 
					    m_already_processed.assure_domain(id);
 | 
				
			||||||
    if (!m_already_processed.contains(id)) {
 | 
					    if (!m_already_processed.contains(id)) {
 | 
				
			||||||
| 
						 | 
					@ -319,7 +321,7 @@ inline void pattern_inference::contains_subpattern::save(expr * n) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool pattern_inference::contains_subpattern::operator()(expr * n) {
 | 
					bool pattern_inference_old::contains_subpattern::operator()(expr * n) {
 | 
				
			||||||
    m_already_processed.reset();
 | 
					    m_already_processed.reset();
 | 
				
			||||||
    m_todo.reset();
 | 
					    m_todo.reset();
 | 
				
			||||||
    expr2info::obj_map_entry * _e = m_owner.m_candidates_info.find_core(n);
 | 
					    expr2info::obj_map_entry * _e = m_owner.m_candidates_info.find_core(n);
 | 
				
			||||||
| 
						 | 
					@ -360,7 +362,7 @@ bool pattern_inference::contains_subpattern::operator()(expr * n) {
 | 
				
			||||||
   Return true if n contains a direct/indirect child that is also a
 | 
					   Return true if n contains a direct/indirect child that is also a
 | 
				
			||||||
   pattern, and contains the same number of free variables.
 | 
					   pattern, and contains the same number of free variables.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
inline bool pattern_inference::contains_subpattern(expr * n) {
 | 
					inline bool pattern_inference_old::contains_subpattern(expr * n) {
 | 
				
			||||||
    return m_contains_subpattern(n);
 | 
					    return m_contains_subpattern(n);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -372,18 +374,15 @@ inline bool pattern_inference::contains_subpattern(expr * n) {
 | 
				
			||||||
   Remark: Every pattern p in patterns is also a member of
 | 
					   Remark: Every pattern p in patterns is also a member of
 | 
				
			||||||
   m_pattern_map.
 | 
					   m_pattern_map.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
void pattern_inference::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) {
 | 
					void pattern_inference_old::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) {
 | 
				
			||||||
    ptr_vector<app>::const_iterator it  = patterns.begin();
 | 
					    for (app * curr : patterns) {
 | 
				
			||||||
    ptr_vector<app>::const_iterator end = patterns.end();
 | 
					 | 
				
			||||||
    for (; it != end; ++it) {
 | 
					 | 
				
			||||||
        app * curr = *it;
 | 
					 | 
				
			||||||
        if (!contains_subpattern(curr))
 | 
					        if (!contains_subpattern(curr))
 | 
				
			||||||
            result.push_back(curr);
 | 
					            result.push_back(curr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) const {
 | 
					bool pattern_inference_old::pattern_weight_lt::operator()(expr * n1, expr * n2) const {
 | 
				
			||||||
    expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1);
 | 
					    expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1);
 | 
				
			||||||
    expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2);
 | 
					    expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2);
 | 
				
			||||||
    SASSERT(e1 != 0);
 | 
					    SASSERT(e1 != 0);
 | 
				
			||||||
| 
						 | 
					@ -401,13 +400,10 @@ bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) cons
 | 
				
			||||||
   variables, then it is copied to remaining_candidate_patterns.  The
 | 
					   variables, then it is copied to remaining_candidate_patterns.  The
 | 
				
			||||||
   new patterns are stored in result.
 | 
					   new patterns are stored in result.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
void pattern_inference::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
 | 
					void pattern_inference_old::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
 | 
				
			||||||
                                                  ptr_vector<app> & remaining_candidate_patterns,
 | 
					                                                  ptr_vector<app> & remaining_candidate_patterns,
 | 
				
			||||||
                                                  app_ref_buffer  & result) {
 | 
					                                                  app_ref_buffer  & result) {
 | 
				
			||||||
    ptr_vector<app>::const_iterator it  = candidate_patterns.begin();
 | 
					    for (app * candidate : candidate_patterns) {
 | 
				
			||||||
    ptr_vector<app>::const_iterator end = candidate_patterns.end();
 | 
					 | 
				
			||||||
    for (; it != end; ++it) {
 | 
					 | 
				
			||||||
        app * candidate = *it;
 | 
					 | 
				
			||||||
        expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
 | 
					        expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
 | 
				
			||||||
        info const & i = e->get_data().m_value;
 | 
					        info const & i = e->get_data().m_value;
 | 
				
			||||||
        if (i.m_free_vars.num_elems() == m_num_bindings) {
 | 
					        if (i.m_free_vars.num_elems() == m_num_bindings) {
 | 
				
			||||||
| 
						 | 
					@ -425,7 +421,7 @@ void pattern_inference::candidates2unary_patterns(ptr_vector<app> const & candid
 | 
				
			||||||
// HACK: limit the number of case-splits:
 | 
					// HACK: limit the number of case-splits:
 | 
				
			||||||
#define MAX_SPLITS 32
 | 
					#define MAX_SPLITS 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns,
 | 
					void pattern_inference_old::candidates2multi_patterns(unsigned max_num_patterns,
 | 
				
			||||||
                                                  ptr_vector<app> const & candidate_patterns,
 | 
					                                                  ptr_vector<app> const & candidate_patterns,
 | 
				
			||||||
                                                  app_ref_buffer & result) {
 | 
					                                                  app_ref_buffer & result) {
 | 
				
			||||||
    SASSERT(!candidate_patterns.empty());
 | 
					    SASSERT(!candidate_patterns.empty());
 | 
				
			||||||
| 
						 | 
					@ -469,21 +465,19 @@ void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pattern_inference::reset_pre_patterns() {
 | 
					void pattern_inference_old::reset_pre_patterns() {
 | 
				
			||||||
    std::for_each(m_pre_patterns.begin(), m_pre_patterns.end(), delete_proc<pre_pattern>());
 | 
					    std::for_each(m_pre_patterns.begin(), m_pre_patterns.end(), delete_proc<pre_pattern>());
 | 
				
			||||||
    m_pre_patterns.reset();
 | 
					    m_pre_patterns.reset();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _TRACE
 | 
					#ifdef _TRACE
 | 
				
			||||||
static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) {
 | 
					static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) {
 | 
				
			||||||
    ptr_vector<app>::const_iterator it  = v.begin();
 | 
					    for (app * e : v) 
 | 
				
			||||||
    ptr_vector<app>::const_iterator end = v.end();
 | 
					        out << mk_pp(e, m) << "\n";
 | 
				
			||||||
    for (; it != end; ++it)
 | 
					 | 
				
			||||||
        out << mk_pp(*it, m) << "\n";
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool pattern_inference::is_forbidden(app * n) const {
 | 
					bool pattern_inference_old::is_forbidden(app * n) const {
 | 
				
			||||||
    func_decl const * decl = n->get_decl();
 | 
					    func_decl const * decl = n->get_decl();
 | 
				
			||||||
    if (is_ground(n))
 | 
					    if (is_ground(n))
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
| 
						 | 
					@ -499,14 +493,11 @@ bool pattern_inference::is_forbidden(app * n) const {
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool pattern_inference::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) {
 | 
					bool pattern_inference_old::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) {
 | 
				
			||||||
    if (m_preferred.empty())
 | 
					    if (m_preferred.empty())
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    bool found = false;
 | 
					    bool found = false;
 | 
				
			||||||
    ptr_vector<app>::const_iterator it  = candidate_patterns.begin();
 | 
					    for (app * candidate : candidate_patterns) {
 | 
				
			||||||
    ptr_vector<app>::const_iterator end = candidate_patterns.end();
 | 
					 | 
				
			||||||
    for (; it != end; ++it) {
 | 
					 | 
				
			||||||
        app * candidate = *it;
 | 
					 | 
				
			||||||
        if (m_preferred.contains(to_app(candidate)->get_decl())) {
 | 
					        if (m_preferred.contains(to_app(candidate)->get_decl())) {
 | 
				
			||||||
            expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
 | 
					            expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
 | 
				
			||||||
            info const & i = e->get_data().m_value;
 | 
					            info const & i = e->get_data().m_value;
 | 
				
			||||||
| 
						 | 
					@ -521,7 +512,7 @@ bool pattern_inference::has_preferred_patterns(ptr_vector<app> & candidate_patte
 | 
				
			||||||
    return found;
 | 
					    return found;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pattern_inference::mk_patterns(unsigned num_bindings,
 | 
					void pattern_inference_old::mk_patterns(unsigned num_bindings,
 | 
				
			||||||
                                    expr *   n,
 | 
					                                    expr *   n,
 | 
				
			||||||
                                    unsigned num_no_patterns,
 | 
					                                    unsigned num_no_patterns,
 | 
				
			||||||
                                    expr * const * no_patterns,
 | 
					                                    expr * const * no_patterns,
 | 
				
			||||||
| 
						 | 
					@ -578,7 +569,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ast/pattern/database.h"
 | 
					#include "ast/pattern/database.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pattern_inference::reduce1_quantifier(quantifier * q) {
 | 
					void pattern_inference_old::reduce1_quantifier(quantifier * q) {
 | 
				
			||||||
    TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";);
 | 
					    TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";);
 | 
				
			||||||
    if (!q->is_forall()) {
 | 
					    if (!q->is_forall()) {
 | 
				
			||||||
        simplifier::reduce1_quantifier(q);
 | 
					        simplifier::reduce1_quantifier(q);
 | 
				
			||||||
| 
						 | 
					@ -739,13 +730,626 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
// unused
 | 
					 | 
				
			||||||
static void dump_expr_vector(std::ostream & out, ptr_vector<expr> const & v, ast_manager & m) {
 | 
					 | 
				
			||||||
    ptr_vector<expr>::const_iterator it  = v.begin();
 | 
					 | 
				
			||||||
    ptr_vector<expr>::const_iterator end = v.end();
 | 
					 | 
				
			||||||
    for (; it != end; ++it)
 | 
					 | 
				
			||||||
        out << mk_pp(*it, m) << "\n";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pattern_inference_cfg::pattern_inference_cfg(ast_manager & m, pattern_inference_params & params):
 | 
				
			||||||
 | 
					    m(m),
 | 
				
			||||||
 | 
					    m_params(params),
 | 
				
			||||||
 | 
					    m_bfid(m.get_basic_family_id()),
 | 
				
			||||||
 | 
					    m_afid(m.mk_family_id("arith")),
 | 
				
			||||||
 | 
					    m_le(m),
 | 
				
			||||||
 | 
					    m_nested_arith_only(true),
 | 
				
			||||||
 | 
					    m_block_loop_patterns(params.m_pi_block_loop_patterns),
 | 
				
			||||||
 | 
					    m_candidates(m),
 | 
				
			||||||
 | 
					    m_pattern_weight_lt(m_candidates_info),
 | 
				
			||||||
 | 
					    m_collect(m, *this),
 | 
				
			||||||
 | 
					    m_contains_subpattern(*this),
 | 
				
			||||||
 | 
					    m_database(m) {
 | 
				
			||||||
 | 
					    if (params.m_pi_arith == AP_NO)
 | 
				
			||||||
 | 
					        register_forbidden_family(m_afid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pattern_inference_cfg::collect::operator()(expr * n, unsigned num_bindings) {
 | 
				
			||||||
 | 
					    SASSERT(m_info.empty());
 | 
				
			||||||
 | 
					    SASSERT(m_todo.empty());
 | 
				
			||||||
 | 
					    SASSERT(m_cache.empty());
 | 
				
			||||||
 | 
					    m_num_bindings = num_bindings;
 | 
				
			||||||
 | 
					    m_todo.push_back(entry(n, 0));
 | 
				
			||||||
 | 
					    while (!m_todo.empty()) {
 | 
				
			||||||
 | 
					        entry & e      = m_todo.back();
 | 
				
			||||||
 | 
					        n              = e.m_node;
 | 
				
			||||||
 | 
					        unsigned delta = e.m_delta;
 | 
				
			||||||
 | 
					        TRACE("collect", tout << "processing: " << n->get_id() << " " << delta << " kind: " << n->get_kind() << "\n";);
 | 
				
			||||||
 | 
					        TRACE("collect_info", tout << mk_pp(n, m) << "\n";);
 | 
				
			||||||
 | 
					        if (visit_children(n, delta)) {
 | 
				
			||||||
 | 
					            m_todo.pop_back();
 | 
				
			||||||
 | 
					            save_candidate(n, delta);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    reset();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline void pattern_inference_cfg::collect::visit(expr * n, unsigned delta, bool & visited) {
 | 
				
			||||||
 | 
					    entry e(n, delta);
 | 
				
			||||||
 | 
					    if (!m_cache.contains(e)) {
 | 
				
			||||||
 | 
					        m_todo.push_back(e);
 | 
				
			||||||
 | 
					        visited = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool pattern_inference_cfg::collect::visit_children(expr * n, unsigned delta) {
 | 
				
			||||||
 | 
					    bool visited = true;
 | 
				
			||||||
 | 
					    unsigned i;
 | 
				
			||||||
 | 
					    switch (n->get_kind()) {
 | 
				
			||||||
 | 
					    case AST_APP:
 | 
				
			||||||
 | 
					        i = to_app(n)->get_num_args();
 | 
				
			||||||
 | 
					        while (i > 0) {
 | 
				
			||||||
 | 
					            --i;
 | 
				
			||||||
 | 
					            visit(to_app(n)->get_arg(i), delta, visited);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case AST_QUANTIFIER:
 | 
				
			||||||
 | 
					        visit(to_quantifier(n)->get_expr(), delta + to_quantifier(n)->get_num_decls(), visited);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return visited;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline void pattern_inference_cfg::collect::save(expr * n, unsigned delta, info * i) {
 | 
				
			||||||
 | 
					    m_cache.insert(entry(n, delta), i);
 | 
				
			||||||
 | 
					    if (i != 0)
 | 
				
			||||||
 | 
					        m_info.push_back(i);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) {
 | 
				
			||||||
 | 
					    switch (n->get_kind()) {
 | 
				
			||||||
 | 
					    case AST_VAR: {
 | 
				
			||||||
 | 
					        unsigned idx = to_var(n)->get_idx();
 | 
				
			||||||
 | 
					        if (idx >= delta) {
 | 
				
			||||||
 | 
					            idx = idx - delta;
 | 
				
			||||||
 | 
					            uint_set free_vars;
 | 
				
			||||||
 | 
					            if (idx < m_num_bindings)
 | 
				
			||||||
 | 
					                free_vars.insert(idx);
 | 
				
			||||||
 | 
					            info * i = 0;
 | 
				
			||||||
 | 
					            if (delta == 0)
 | 
				
			||||||
 | 
					                i = alloc(info, m, n, free_vars, 1);
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                i = alloc(info, m, m.mk_var(idx, to_var(n)->get_sort()), free_vars, 1);
 | 
				
			||||||
 | 
					            save(n, delta, i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            save(n, delta, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case AST_APP: {
 | 
				
			||||||
 | 
					        app *       c    = to_app(n);
 | 
				
			||||||
 | 
					        func_decl * decl = c->get_decl();
 | 
				
			||||||
 | 
					        if (m_owner.is_forbidden(c)) {
 | 
				
			||||||
 | 
					            save(n, delta, 0);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (c->get_num_args() == 0) {
 | 
				
			||||||
 | 
					            save(n, delta, alloc(info, m, n, uint_set(), 1));
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ptr_buffer<expr> buffer;
 | 
				
			||||||
 | 
					        bool changed   = false; // false if none of the children is mapped to a node different from itself.
 | 
				
			||||||
 | 
					        uint_set free_vars;
 | 
				
			||||||
 | 
					        unsigned size  = 1;
 | 
				
			||||||
 | 
					        unsigned num   = c->get_num_args();
 | 
				
			||||||
 | 
					        for (unsigned i = 0; i < num; i++) {
 | 
				
			||||||
 | 
					            expr * child      = c->get_arg(i);
 | 
				
			||||||
 | 
					            info * child_info = 0;
 | 
				
			||||||
 | 
					#ifdef Z3DEBUG
 | 
				
			||||||
 | 
					            bool found =
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					            m_cache.find(entry(child, delta), child_info);
 | 
				
			||||||
 | 
					            SASSERT(found);
 | 
				
			||||||
 | 
					            if (child_info == 0) {
 | 
				
			||||||
 | 
					                save(n, delta, 0);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            buffer.push_back(child_info->m_node.get());
 | 
				
			||||||
 | 
					            free_vars |= child_info->m_free_vars;
 | 
				
			||||||
 | 
					            size      += child_info->m_size;
 | 
				
			||||||
 | 
					            if (child != child_info->m_node.get())
 | 
				
			||||||
 | 
					                changed = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        app * new_node = 0;
 | 
				
			||||||
 | 
					        if (changed)
 | 
				
			||||||
 | 
					            new_node = m.mk_app(decl, buffer.size(), buffer.c_ptr());
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            new_node = to_app(n);
 | 
				
			||||||
 | 
					        save(n, delta, alloc(info, m, new_node, free_vars, size));
 | 
				
			||||||
 | 
					        // Remark: arithmetic patterns are only used if they are nested inside other terms.
 | 
				
			||||||
 | 
					        // That is, we never consider x + 1 as pattern. On the other hand, f(x+1) can be a pattern
 | 
				
			||||||
 | 
					        // if arithmetic is not in the forbidden list.
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // Remark: The rule above has an exception. The operators (div, idiv, mod) are allowed to be
 | 
				
			||||||
 | 
					        // used as patterns even when they are not nested in other terms. The motivation is that
 | 
				
			||||||
 | 
					        // Z3 currently doesn't implement them (i.e., they are uninterpreted). So, some users add axioms
 | 
				
			||||||
 | 
					        // stating properties about these operators.
 | 
				
			||||||
 | 
					        family_id fid = c->get_family_id();
 | 
				
			||||||
 | 
					        decl_kind k   = c->get_decl_kind();
 | 
				
			||||||
 | 
					        if (!free_vars.empty() &&
 | 
				
			||||||
 | 
					            (fid != m_afid || (fid == m_afid && !m_owner.m_nested_arith_only && (k == OP_DIV || k == OP_IDIV || k == OP_MOD || k == OP_REM || k == OP_MUL)))) {
 | 
				
			||||||
 | 
					            TRACE("pattern_inference", tout << "potential candidate: \n" << mk_pp(new_node, m) << "\n";);
 | 
				
			||||||
 | 
					            m_owner.add_candidate(new_node, free_vars, size);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        save(n, delta, 0);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pattern_inference_cfg::collect::reset() {
 | 
				
			||||||
 | 
					    m_cache.reset();
 | 
				
			||||||
 | 
					    std::for_each(m_info.begin(), m_info.end(), delete_proc<info>());
 | 
				
			||||||
 | 
					    m_info.reset();
 | 
				
			||||||
 | 
					    SASSERT(m_todo.empty());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pattern_inference_cfg::add_candidate(app * n, uint_set const & free_vars, unsigned size) {
 | 
				
			||||||
 | 
					    for (unsigned i = 0; i < m_num_no_patterns; i++) {
 | 
				
			||||||
 | 
					        if (n == m_no_patterns[i])
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!m_candidates_info.contains(n)) {
 | 
				
			||||||
 | 
					        m_candidates_info.insert(n, info(free_vars, size));
 | 
				
			||||||
 | 
					        m_candidates.push_back(n);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					   \brief Copy the non-looping patterns in m_candidates to result when m_params.m_pi_block_loop_patterns = true.
 | 
				
			||||||
 | 
					   Otherwise, copy m_candidates to result.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void pattern_inference_cfg::filter_looping_patterns(ptr_vector<app> & result) {
 | 
				
			||||||
 | 
					    unsigned num = m_candidates.size();
 | 
				
			||||||
 | 
					    for (unsigned i1 = 0; i1 < num; i1++) {
 | 
				
			||||||
 | 
					        app * n1 = m_candidates.get(i1);
 | 
				
			||||||
 | 
					        expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1);
 | 
				
			||||||
 | 
					        SASSERT(e1);
 | 
				
			||||||
 | 
					        uint_set const & s1 = e1->get_data().m_value.m_free_vars;
 | 
				
			||||||
 | 
					        if (m_block_loop_patterns) {
 | 
				
			||||||
 | 
					            bool smaller = false;
 | 
				
			||||||
 | 
					            for (unsigned i2 = 0; i2 < num; i2++) {
 | 
				
			||||||
 | 
					                if (i1 != i2) {
 | 
				
			||||||
 | 
					                    app * n2 = m_candidates.get(i2);
 | 
				
			||||||
 | 
					                    expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2);
 | 
				
			||||||
 | 
					                    if (e2) {
 | 
				
			||||||
 | 
					                        uint_set const & s2 = e2->get_data().m_value.m_free_vars;
 | 
				
			||||||
 | 
					                        // Remark: the comparison operator only makes sense if both AST nodes
 | 
				
			||||||
 | 
					                        // contain the same number of variables.
 | 
				
			||||||
 | 
					                        // Example:
 | 
				
			||||||
 | 
					                        // (f X Y) <: (f (g X Z W) Y)
 | 
				
			||||||
 | 
					                        if (s1 == s2 && m_le(m_num_bindings, n1, n2) && !m_le(m_num_bindings, n2, n1)) {
 | 
				
			||||||
 | 
					                            smaller = true;
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!smaller)
 | 
				
			||||||
 | 
					                result.push_back(n1);
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                m_candidates_info.erase(n1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            result.push_back(n1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline void pattern_inference_cfg::contains_subpattern::save(expr * n) {
 | 
				
			||||||
 | 
					    unsigned id = n->get_id();
 | 
				
			||||||
 | 
					    m_already_processed.assure_domain(id);
 | 
				
			||||||
 | 
					    if (!m_already_processed.contains(id)) {
 | 
				
			||||||
 | 
					        m_todo.push_back(n);
 | 
				
			||||||
 | 
					        m_already_processed.insert(id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool pattern_inference_cfg::contains_subpattern::operator()(expr * n) {
 | 
				
			||||||
 | 
					    m_already_processed.reset();
 | 
				
			||||||
 | 
					    m_todo.reset();
 | 
				
			||||||
 | 
					    expr2info::obj_map_entry * _e = m_owner.m_candidates_info.find_core(n);
 | 
				
			||||||
 | 
					    SASSERT(_e);
 | 
				
			||||||
 | 
					    uint_set const & s1 = _e->get_data().m_value.m_free_vars;
 | 
				
			||||||
 | 
					    save(n);
 | 
				
			||||||
 | 
					    unsigned num;
 | 
				
			||||||
 | 
					    while (!m_todo.empty()) {
 | 
				
			||||||
 | 
					        expr * curr = m_todo.back();
 | 
				
			||||||
 | 
					        m_todo.pop_back();
 | 
				
			||||||
 | 
					        switch (curr->get_kind()) {
 | 
				
			||||||
 | 
					        case AST_APP:
 | 
				
			||||||
 | 
					            if (curr != n) {
 | 
				
			||||||
 | 
					                expr2info::obj_map_entry * e = m_owner.m_candidates_info.find_core(curr);
 | 
				
			||||||
 | 
					                if (e) {
 | 
				
			||||||
 | 
					                    uint_set const & s2 = e->get_data().m_value.m_free_vars;
 | 
				
			||||||
 | 
					                    SASSERT(s2.subset_of(s1));
 | 
				
			||||||
 | 
					                    if (s1 == s2) {
 | 
				
			||||||
 | 
					                        TRACE("pattern_inference", tout << mk_pp(n, m_owner.m) << "\nis bigger than\n" << mk_pp(to_app(curr), m_owner.m) << "\n";);
 | 
				
			||||||
 | 
					                        return true;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            num = to_app(curr)->get_num_args();
 | 
				
			||||||
 | 
					            for (unsigned i = 0; i < num; i++)
 | 
				
			||||||
 | 
					                save(to_app(curr)->get_arg(i));
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case AST_VAR:
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            UNREACHABLE();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					   Return true if n contains a direct/indirect child that is also a
 | 
				
			||||||
 | 
					   pattern, and contains the same number of free variables.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					inline bool pattern_inference_cfg::contains_subpattern(expr * n) {
 | 
				
			||||||
 | 
					    return m_contains_subpattern(n);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					   \brief Copy a pattern p in patterns to result, if there is no
 | 
				
			||||||
 | 
					   direct/indirect child of p in patterns which contains the same set
 | 
				
			||||||
 | 
					   of variables.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Remark: Every pattern p in patterns is also a member of
 | 
				
			||||||
 | 
					   m_pattern_map.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void pattern_inference_cfg::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) {
 | 
				
			||||||
 | 
					    for (app * curr : patterns) {
 | 
				
			||||||
 | 
					        if (!contains_subpattern(curr))
 | 
				
			||||||
 | 
					            result.push_back(curr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool pattern_inference_cfg::pattern_weight_lt::operator()(expr * n1, expr * n2) const {
 | 
				
			||||||
 | 
					    expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1);
 | 
				
			||||||
 | 
					    expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2);
 | 
				
			||||||
 | 
					    SASSERT(e1 != 0);
 | 
				
			||||||
 | 
					    SASSERT(e2 != 0);
 | 
				
			||||||
 | 
					    info const & i1 = e1->get_data().m_value;
 | 
				
			||||||
 | 
					    info const & i2 = e2->get_data().m_value;
 | 
				
			||||||
 | 
					    unsigned num_free_vars1 = i1.m_free_vars.num_elems();
 | 
				
			||||||
 | 
					    unsigned num_free_vars2 = i2.m_free_vars.num_elems();
 | 
				
			||||||
 | 
					    return num_free_vars1 > num_free_vars2 || (num_free_vars1 == num_free_vars2 && i1.m_size < i2.m_size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					   \brief Create unary patterns (single expressions that contain all
 | 
				
			||||||
 | 
					   bound variables).  If a candidate does not contain all bound
 | 
				
			||||||
 | 
					   variables, then it is copied to remaining_candidate_patterns.  The
 | 
				
			||||||
 | 
					   new patterns are stored in result.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void pattern_inference_cfg::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
 | 
				
			||||||
 | 
					                                                  ptr_vector<app> & remaining_candidate_patterns,
 | 
				
			||||||
 | 
					                                                  app_ref_buffer  & result) {
 | 
				
			||||||
 | 
					    for (app * candidate : candidate_patterns) {
 | 
				
			||||||
 | 
					        expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
 | 
				
			||||||
 | 
					        info const & i = e->get_data().m_value;
 | 
				
			||||||
 | 
					        if (i.m_free_vars.num_elems() == m_num_bindings) {
 | 
				
			||||||
 | 
					            app * new_pattern = m.mk_pattern(candidate);
 | 
				
			||||||
 | 
					            result.push_back(new_pattern);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            remaining_candidate_patterns.push_back(candidate);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: this code is too inefficient when the number of candidate
 | 
				
			||||||
 | 
					// patterns is too big.
 | 
				
			||||||
 | 
					// HACK: limit the number of case-splits:
 | 
				
			||||||
 | 
					#define MAX_SPLITS 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pattern_inference_cfg::candidates2multi_patterns(unsigned max_num_patterns,
 | 
				
			||||||
 | 
					                                                  ptr_vector<app> const & candidate_patterns,
 | 
				
			||||||
 | 
					                                                  app_ref_buffer & result) {
 | 
				
			||||||
 | 
					    SASSERT(!candidate_patterns.empty());
 | 
				
			||||||
 | 
					    m_pre_patterns.push_back(alloc(pre_pattern));
 | 
				
			||||||
 | 
					    unsigned sz = candidate_patterns.size();
 | 
				
			||||||
 | 
					    unsigned num_splits = 0;
 | 
				
			||||||
 | 
					    for (unsigned j = 0; j < m_pre_patterns.size(); j++) {
 | 
				
			||||||
 | 
					        pre_pattern * curr = m_pre_patterns[j];
 | 
				
			||||||
 | 
					        if (curr->m_free_vars.num_elems() == m_num_bindings) {
 | 
				
			||||||
 | 
					            app * new_pattern = m.mk_pattern(curr->m_exprs.size(), curr->m_exprs.c_ptr());
 | 
				
			||||||
 | 
					            result.push_back(new_pattern);
 | 
				
			||||||
 | 
					            if (result.size() >= max_num_patterns)
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (curr->m_idx < sz) {
 | 
				
			||||||
 | 
					            app * n                     = candidate_patterns[curr->m_idx];
 | 
				
			||||||
 | 
					            expr2info::obj_map_entry * e = m_candidates_info.find_core(n);
 | 
				
			||||||
 | 
					            uint_set const & s           = e->get_data().m_value.m_free_vars;
 | 
				
			||||||
 | 
					            if (!s.subset_of(curr->m_free_vars)) {
 | 
				
			||||||
 | 
					                pre_pattern * new_p = alloc(pre_pattern,*curr);
 | 
				
			||||||
 | 
					                new_p->m_exprs.push_back(n);
 | 
				
			||||||
 | 
					                new_p->m_free_vars |= s;
 | 
				
			||||||
 | 
					                new_p->m_idx++;
 | 
				
			||||||
 | 
					                m_pre_patterns.push_back(new_p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (num_splits < MAX_SPLITS) {
 | 
				
			||||||
 | 
					                    m_pre_patterns[j] = 0;
 | 
				
			||||||
 | 
					                    curr->m_idx++;
 | 
				
			||||||
 | 
					                    m_pre_patterns.push_back(curr);
 | 
				
			||||||
 | 
					                    num_splits++;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                m_pre_patterns[j] = 0;
 | 
				
			||||||
 | 
					                curr->m_idx++;
 | 
				
			||||||
 | 
					                m_pre_patterns.push_back(curr);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        TRACE("pattern_inference", tout << "m_pre_patterns.size(): " << m_pre_patterns.size() <<
 | 
				
			||||||
 | 
					              "\nnum_splits: " << num_splits << "\n";);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pattern_inference_cfg::reset_pre_patterns() {
 | 
				
			||||||
 | 
					    std::for_each(m_pre_patterns.begin(), m_pre_patterns.end(), delete_proc<pre_pattern>());
 | 
				
			||||||
 | 
					    m_pre_patterns.reset();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool pattern_inference_cfg::is_forbidden(app * n) const {
 | 
				
			||||||
 | 
					    func_decl const * decl = n->get_decl();
 | 
				
			||||||
 | 
					    if (is_ground(n))
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    // Remark: skolem constants should not be used in patterns, since they do not
 | 
				
			||||||
 | 
					    // occur outside of the quantifier. That is, Z3 will never match this kind of
 | 
				
			||||||
 | 
					    // pattern.
 | 
				
			||||||
 | 
					    if (m_params.m_pi_avoid_skolems && decl->is_skolem()) {
 | 
				
			||||||
 | 
					        CTRACE("pattern_inference_skolem", decl->is_skolem(), tout << "ignoring: " << mk_pp(n, m) << "\n";);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (is_forbidden(decl))
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool pattern_inference_cfg::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) {
 | 
				
			||||||
 | 
					    if (m_preferred.empty())
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    bool found = false;
 | 
				
			||||||
 | 
					    for (app * candidate : candidate_patterns) {
 | 
				
			||||||
 | 
					        if (m_preferred.contains(to_app(candidate)->get_decl())) {
 | 
				
			||||||
 | 
					            expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
 | 
				
			||||||
 | 
					            info const & i = e->get_data().m_value;
 | 
				
			||||||
 | 
					            if (i.m_free_vars.num_elems() == m_num_bindings) {
 | 
				
			||||||
 | 
					                TRACE("pattern_inference", tout << "found preferred pattern:\n" << mk_pp(candidate, m) << "\n";);
 | 
				
			||||||
 | 
					                app * p = m.mk_pattern(candidate);
 | 
				
			||||||
 | 
					                result.push_back(p);
 | 
				
			||||||
 | 
					                found = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return found;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pattern_inference_cfg::mk_patterns(unsigned num_bindings,
 | 
				
			||||||
 | 
					                                    expr *   n,
 | 
				
			||||||
 | 
					                                    unsigned num_no_patterns,
 | 
				
			||||||
 | 
					                                    expr * const * no_patterns,
 | 
				
			||||||
 | 
					                                    app_ref_buffer & result) {
 | 
				
			||||||
 | 
					    m_num_bindings    = num_bindings;
 | 
				
			||||||
 | 
					    m_num_no_patterns = num_no_patterns;
 | 
				
			||||||
 | 
					    m_no_patterns     = no_patterns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_collect(n, num_bindings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TRACE("pattern_inference",
 | 
				
			||||||
 | 
					          tout << mk_pp(n, m);
 | 
				
			||||||
 | 
					          tout << "\ncandidates:\n";
 | 
				
			||||||
 | 
					          unsigned num = m_candidates.size();
 | 
				
			||||||
 | 
					          for (unsigned i = 0; i < num; i++) {
 | 
				
			||||||
 | 
					              tout << mk_pp(m_candidates.get(i), m) << "\n";
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!m_candidates.empty()) {
 | 
				
			||||||
 | 
					        m_tmp1.reset();
 | 
				
			||||||
 | 
					        filter_looping_patterns(m_tmp1);
 | 
				
			||||||
 | 
					        TRACE("pattern_inference",
 | 
				
			||||||
 | 
					              tout << "candidates after removing looping-patterns:\n";
 | 
				
			||||||
 | 
					              dump_app_vector(tout, m_tmp1, m););
 | 
				
			||||||
 | 
					        SASSERT(!m_tmp1.empty());
 | 
				
			||||||
 | 
					        if (!has_preferred_patterns(m_tmp1, result)) {
 | 
				
			||||||
 | 
					            // continue if there are no preferred patterns
 | 
				
			||||||
 | 
					            m_tmp2.reset();
 | 
				
			||||||
 | 
					            filter_bigger_patterns(m_tmp1, m_tmp2);
 | 
				
			||||||
 | 
					            SASSERT(!m_tmp2.empty());
 | 
				
			||||||
 | 
					            TRACE("pattern_inference",
 | 
				
			||||||
 | 
					                  tout << "candidates after removing bigger patterns:\n";
 | 
				
			||||||
 | 
					                  dump_app_vector(tout, m_tmp2, m););
 | 
				
			||||||
 | 
					            m_tmp1.reset();
 | 
				
			||||||
 | 
					            candidates2unary_patterns(m_tmp2, m_tmp1, result);
 | 
				
			||||||
 | 
					            unsigned num_extra_multi_patterns = m_params.m_pi_max_multi_patterns;
 | 
				
			||||||
 | 
					            if (result.empty())
 | 
				
			||||||
 | 
					                num_extra_multi_patterns++;
 | 
				
			||||||
 | 
					            if (num_extra_multi_patterns > 0 && !m_tmp1.empty()) {
 | 
				
			||||||
 | 
					                // m_pattern_weight_lt is not a total order
 | 
				
			||||||
 | 
					                std::stable_sort(m_tmp1.begin(), m_tmp1.end(), m_pattern_weight_lt);
 | 
				
			||||||
 | 
					                TRACE("pattern_inference",
 | 
				
			||||||
 | 
					                      tout << "candidates after sorting:\n";
 | 
				
			||||||
 | 
					                      dump_app_vector(tout, m_tmp1, m););
 | 
				
			||||||
 | 
					                candidates2multi_patterns(num_extra_multi_patterns, m_tmp1, result);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reset_pre_patterns();
 | 
				
			||||||
 | 
					    m_candidates_info.reset();
 | 
				
			||||||
 | 
					    m_candidates.reset();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool pattern_inference_cfg::reduce_quantifier(
 | 
				
			||||||
 | 
					    quantifier * q, 
 | 
				
			||||||
 | 
					    expr * new_body, 
 | 
				
			||||||
 | 
					    expr * const *, // new_patterns 
 | 
				
			||||||
 | 
					    expr * const * new_no_patterns,
 | 
				
			||||||
 | 
					    expr_ref & result,
 | 
				
			||||||
 | 
					    proof_ref & result_pr) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";);
 | 
				
			||||||
 | 
					    if (!q->is_forall()) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int weight = q->get_weight();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (m_params.m_pi_use_database) {
 | 
				
			||||||
 | 
					        app_ref_vector new_patterns(m);
 | 
				
			||||||
 | 
					        m_database.initialize(g_pattern_database);
 | 
				
			||||||
 | 
					        unsigned new_weight;
 | 
				
			||||||
 | 
					        if (m_database.match_quantifier(q, new_patterns, new_weight)) {
 | 
				
			||||||
 | 
					            DEBUG_CODE(for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); });
 | 
				
			||||||
 | 
					            quantifier_ref new_q(m);
 | 
				
			||||||
 | 
					            if (q->get_num_patterns() > 0) {
 | 
				
			||||||
 | 
					                // just update the weight...
 | 
				
			||||||
 | 
					                TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m) << "\n";);
 | 
				
			||||||
 | 
					                result = m.update_quantifier_weight(q, new_weight);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                quantifier_ref tmp(m);
 | 
				
			||||||
 | 
					                tmp    = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr());
 | 
				
			||||||
 | 
					                result = m.update_quantifier_weight(tmp, new_weight);
 | 
				
			||||||
 | 
					                TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (m.fine_grain_proofs())
 | 
				
			||||||
 | 
					                result_pr = m.mk_rewrite(q, new_q);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (q->get_num_patterns() > 0) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (m_params.m_pi_nopat_weight >= 0)
 | 
				
			||||||
 | 
					        weight = m_params.m_pi_nopat_weight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SASSERT(q->get_num_patterns() == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (m_params.m_pi_arith == AP_CONSERVATIVE)
 | 
				
			||||||
 | 
					        m_forbidden.push_back(m_afid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    app_ref_buffer new_patterns(m);
 | 
				
			||||||
 | 
					    unsigned num_no_patterns = q->get_num_no_patterns();
 | 
				
			||||||
 | 
					    mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (new_patterns.empty() && num_no_patterns > 0) {
 | 
				
			||||||
 | 
					        if (new_patterns.empty()) {
 | 
				
			||||||
 | 
					            mk_patterns(q->get_num_decls(), new_body, 0, 0, new_patterns);
 | 
				
			||||||
 | 
					            if (m_params.m_pi_warnings && !new_patterns.empty()) {
 | 
				
			||||||
 | 
					                warning_msg("ignoring nopats annotation because Z3 couldn't find any other pattern (quantifier id: %s)", q->get_qid().str().c_str());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (m_params.m_pi_arith == AP_CONSERVATIVE) {
 | 
				
			||||||
 | 
					        m_forbidden.pop_back();
 | 
				
			||||||
 | 
					        if (new_patterns.empty()) {
 | 
				
			||||||
 | 
					            flet<bool> l1(m_block_loop_patterns, false); // allow looping patterns
 | 
				
			||||||
 | 
					            mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns);
 | 
				
			||||||
 | 
					            if (!new_patterns.empty()) {
 | 
				
			||||||
 | 
					                weight = std::max(weight, static_cast<int>(m_params.m_pi_arith_weight));
 | 
				
			||||||
 | 
					                if (m_params.m_pi_warnings) {
 | 
				
			||||||
 | 
					                    warning_msg("using arith. in pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_ARITH_WEIGHT=<val>).",
 | 
				
			||||||
 | 
					                                q->get_qid().str().c_str(), weight);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (m_params.m_pi_arith != AP_NO && new_patterns.empty()) {
 | 
				
			||||||
 | 
					        if (new_patterns.empty()) {
 | 
				
			||||||
 | 
					            flet<bool> l1(m_nested_arith_only, false); // try to find a non-nested arith pattern
 | 
				
			||||||
 | 
					            flet<bool> l2(m_block_loop_patterns, false); // allow looping patterns
 | 
				
			||||||
 | 
					            mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns);
 | 
				
			||||||
 | 
					            if (!new_patterns.empty()) {
 | 
				
			||||||
 | 
					                weight = std::max(weight, static_cast<int>(m_params.m_pi_non_nested_arith_weight));
 | 
				
			||||||
 | 
					                if (m_params.m_pi_warnings) {
 | 
				
			||||||
 | 
					                    warning_msg("using non nested arith. pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=<val>).",
 | 
				
			||||||
 | 
					                                q->get_qid().str().c_str(), weight);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // verbose_stream() << mk_pp(q, m) << "\n";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    quantifier_ref new_q(m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body), m);
 | 
				
			||||||
 | 
					    if (weight != q->get_weight())
 | 
				
			||||||
 | 
					        new_q = m.update_quantifier_weight(new_q, weight);
 | 
				
			||||||
 | 
					    if (m.fine_grain_proofs()) {
 | 
				
			||||||
 | 
					        proof* new_body_pr = m.mk_reflexivity(new_body);
 | 
				
			||||||
 | 
					        result_pr = m.mk_quant_intro(q, new_q, new_body_pr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (new_patterns.empty() && m_params.m_pi_pull_quantifiers) {
 | 
				
			||||||
 | 
					        pull_quant pull(m);
 | 
				
			||||||
 | 
					        expr_ref   new_expr(m);
 | 
				
			||||||
 | 
					        proof_ref  new_pr(m);
 | 
				
			||||||
 | 
					        pull(new_q, new_expr, new_pr);
 | 
				
			||||||
 | 
					        quantifier * result2 = to_quantifier(new_expr);
 | 
				
			||||||
 | 
					        if (result2 != new_q) {
 | 
				
			||||||
 | 
					            mk_patterns(result2->get_num_decls(), result2->get_expr(), 0, 0, new_patterns);
 | 
				
			||||||
 | 
					            if (!new_patterns.empty()) {
 | 
				
			||||||
 | 
					                if (m_params.m_pi_warnings) {
 | 
				
			||||||
 | 
					                    warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr());
 | 
				
			||||||
 | 
					                if (m.fine_grain_proofs()) {
 | 
				
			||||||
 | 
					                    result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_reflexivity(new_q->get_expr())));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (new_patterns.empty()) {
 | 
				
			||||||
 | 
					        if (m_params.m_pi_warnings) {
 | 
				
			||||||
 | 
					            warning_msg("failed to find a pattern for quantifier (quantifier id: %s)", q->get_qid().str().c_str());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        TRACE("pi_failed", tout << mk_pp(q, m) << "\n";);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (new_patterns.empty() && new_body == q->get_expr()) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    result = new_q;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    IF_IVERBOSE(10,
 | 
				
			||||||
 | 
					        verbose_stream() << "(smt.inferred-patterns :qid " << q->get_qid() << "\n";
 | 
				
			||||||
 | 
					        for (unsigned i = 0; i < new_patterns.size(); i++)
 | 
				
			||||||
 | 
					            verbose_stream() << "  " << mk_ismt2_pp(new_patterns[i], m, 2) << "\n";
 | 
				
			||||||
 | 
					        verbose_stream() << ")\n"; );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pattern_inference_rw::pattern_inference_rw(ast_manager& m, pattern_inference_params & params):
 | 
				
			||||||
 | 
					    rewriter_tpl<pattern_inference_cfg>(m, m.proofs_enabled(), m_cfg),
 | 
				
			||||||
 | 
					    m_cfg(m, params)
 | 
				
			||||||
 | 
					{}    
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@ Revision History:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ast/ast.h"
 | 
					#include "ast/ast.h"
 | 
				
			||||||
#include "ast/simplifier/simplifier.h"
 | 
					#include "ast/simplifier/simplifier.h"
 | 
				
			||||||
 | 
					#include "ast/rewriter/rewriter.h"
 | 
				
			||||||
#include "ast/pattern/pattern_inference_params.h"
 | 
					#include "ast/pattern/pattern_inference_params.h"
 | 
				
			||||||
#include "util/vector.h"
 | 
					#include "util/vector.h"
 | 
				
			||||||
#include "util/uint_set.h"
 | 
					#include "util/uint_set.h"
 | 
				
			||||||
| 
						 | 
					@ -60,7 +61,7 @@ public:
 | 
				
			||||||
    bool operator()(unsigned num_bindings, expr * p1, expr * p2);
 | 
					    bool operator()(unsigned num_bindings, expr * p1, expr * p2);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class pattern_inference : public simplifier {
 | 
					class pattern_inference_old : public simplifier {
 | 
				
			||||||
    pattern_inference_params & m_params;
 | 
					    pattern_inference_params & m_params;
 | 
				
			||||||
    family_id                  m_bfid;
 | 
					    family_id                  m_bfid;
 | 
				
			||||||
    family_id                  m_afid;
 | 
					    family_id                  m_afid;
 | 
				
			||||||
| 
						 | 
					@ -136,7 +137,7 @@ class pattern_inference : public simplifier {
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        ast_manager &            m;
 | 
					        ast_manager &            m;
 | 
				
			||||||
        pattern_inference &      m_owner;
 | 
					        pattern_inference_old &      m_owner;
 | 
				
			||||||
        family_id                m_afid;
 | 
					        family_id                m_afid;
 | 
				
			||||||
        unsigned                 m_num_bindings;
 | 
					        unsigned                 m_num_bindings;
 | 
				
			||||||
        typedef map<entry, info *, obj_hash<entry>, default_eq<entry> > cache;
 | 
					        typedef map<entry, info *, obj_hash<entry>, default_eq<entry> > cache;
 | 
				
			||||||
| 
						 | 
					@ -150,7 +151,7 @@ class pattern_inference : public simplifier {
 | 
				
			||||||
        void save_candidate(expr * n, unsigned delta);
 | 
					        void save_candidate(expr * n, unsigned delta);
 | 
				
			||||||
        void reset();
 | 
					        void reset();
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        collect(ast_manager & m, pattern_inference & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
 | 
					        collect(ast_manager & m, pattern_inference_old & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
 | 
				
			||||||
        void operator()(expr * n, unsigned num_bindings);
 | 
					        void operator()(expr * n, unsigned num_bindings);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,12 +166,12 @@ class pattern_inference : public simplifier {
 | 
				
			||||||
    void filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result);
 | 
					    void filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class contains_subpattern {
 | 
					    class contains_subpattern {
 | 
				
			||||||
        pattern_inference &  m_owner;
 | 
					        pattern_inference_old &  m_owner;
 | 
				
			||||||
        nat_set              m_already_processed; 
 | 
					        nat_set              m_already_processed; 
 | 
				
			||||||
        ptr_vector<expr>     m_todo;
 | 
					        ptr_vector<expr>     m_todo;
 | 
				
			||||||
        void save(expr * n);
 | 
					        void save(expr * n);
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        contains_subpattern(pattern_inference & owner):
 | 
					        contains_subpattern(pattern_inference_old & owner):
 | 
				
			||||||
            m_owner(owner) {}
 | 
					            m_owner(owner) {}
 | 
				
			||||||
        bool operator()(expr * n);
 | 
					        bool operator()(expr * n);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					@ -217,7 +218,7 @@ class pattern_inference : public simplifier {
 | 
				
			||||||
    virtual void reduce1_quantifier(quantifier * q);
 | 
					    virtual void reduce1_quantifier(quantifier * q);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    pattern_inference(ast_manager & m, pattern_inference_params & params);
 | 
					    pattern_inference_old(ast_manager & m, pattern_inference_params & params);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    void register_forbidden_family(family_id fid) {
 | 
					    void register_forbidden_family(family_id fid) {
 | 
				
			||||||
        SASSERT(fid != m_bfid);
 | 
					        SASSERT(fid != m_bfid);
 | 
				
			||||||
| 
						 | 
					@ -244,5 +245,201 @@ public:
 | 
				
			||||||
    bool is_forbidden(app * n) const;
 | 
					    bool is_forbidden(app * n) const;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class pattern_inference_cfg :  public default_rewriter_cfg {
 | 
				
			||||||
 | 
					    ast_manager&               m;
 | 
				
			||||||
 | 
					    pattern_inference_params & m_params;
 | 
				
			||||||
 | 
					    family_id                  m_bfid;
 | 
				
			||||||
 | 
					    family_id                  m_afid;
 | 
				
			||||||
 | 
					    svector<family_id>         m_forbidden;
 | 
				
			||||||
 | 
					    obj_hashtable<func_decl>   m_preferred;        
 | 
				
			||||||
 | 
					    smaller_pattern            m_le;
 | 
				
			||||||
 | 
					    unsigned                   m_num_bindings;
 | 
				
			||||||
 | 
					    unsigned                   m_num_no_patterns;
 | 
				
			||||||
 | 
					    expr * const *             m_no_patterns;
 | 
				
			||||||
 | 
					    bool                       m_nested_arith_only;
 | 
				
			||||||
 | 
					    bool                       m_block_loop_patterns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct info {
 | 
				
			||||||
 | 
					        uint_set m_free_vars;
 | 
				
			||||||
 | 
					        unsigned m_size;
 | 
				
			||||||
 | 
					        info(uint_set const & vars, unsigned size):
 | 
				
			||||||
 | 
					            m_free_vars(vars),
 | 
				
			||||||
 | 
					            m_size(size) {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        info():
 | 
				
			||||||
 | 
					            m_free_vars(),
 | 
				
			||||||
 | 
					            m_size(0) {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    typedef obj_map<expr, info> expr2info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expr2info                 m_candidates_info; // candidate -> set of free vars + size
 | 
				
			||||||
 | 
					    app_ref_vector            m_candidates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptr_vector<app>           m_tmp1;
 | 
				
			||||||
 | 
					    ptr_vector<app>           m_tmp2;
 | 
				
			||||||
 | 
					    ptr_vector<app>           m_todo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Compare candidates patterns based on their usefulness
 | 
				
			||||||
 | 
					    // p1 < p2 if
 | 
				
			||||||
 | 
					    //  - p1 has more free variables than p2
 | 
				
			||||||
 | 
					    //  - p1 and p2 has the same number of free variables,
 | 
				
			||||||
 | 
					    //    and p1 is smaller than p2.
 | 
				
			||||||
 | 
					    struct pattern_weight_lt {
 | 
				
			||||||
 | 
					        expr2info & m_candidates_info;
 | 
				
			||||||
 | 
					        pattern_weight_lt(expr2info & i):
 | 
				
			||||||
 | 
					            m_candidates_info(i) {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        bool operator()(expr * n1, expr * n2) const;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pattern_weight_lt          m_pattern_weight_lt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // Functor for collecting candidates.
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    class collect {
 | 
				
			||||||
 | 
					        struct entry {
 | 
				
			||||||
 | 
					            expr *    m_node;
 | 
				
			||||||
 | 
					            unsigned  m_delta;
 | 
				
			||||||
 | 
					            entry():m_node(0), m_delta(0) {}
 | 
				
			||||||
 | 
					            entry(expr * n, unsigned d):m_node(n), m_delta(d) {}
 | 
				
			||||||
 | 
					            unsigned hash() const { 
 | 
				
			||||||
 | 
					                return hash_u_u(m_node->get_id(), m_delta);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            bool operator==(entry const & e) const { 
 | 
				
			||||||
 | 
					                return m_node == e.m_node && m_delta == e.m_delta; 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        struct info {
 | 
				
			||||||
 | 
					            expr_ref    m_node;
 | 
				
			||||||
 | 
					            uint_set    m_free_vars;
 | 
				
			||||||
 | 
					            unsigned    m_size;
 | 
				
			||||||
 | 
					            info(ast_manager & m, expr * n, uint_set const & vars, unsigned sz):
 | 
				
			||||||
 | 
					                m_node(n, m), m_free_vars(vars), m_size(sz) {}
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        ast_manager &            m;
 | 
				
			||||||
 | 
					        pattern_inference_cfg &     m_owner;
 | 
				
			||||||
 | 
					        family_id                m_afid;
 | 
				
			||||||
 | 
					        unsigned                 m_num_bindings;
 | 
				
			||||||
 | 
					        typedef map<entry, info *, obj_hash<entry>, default_eq<entry> > cache;
 | 
				
			||||||
 | 
					        cache                    m_cache;
 | 
				
			||||||
 | 
					        ptr_vector<info>         m_info;
 | 
				
			||||||
 | 
					        svector<entry>           m_todo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void visit(expr * n, unsigned delta, bool & visited);
 | 
				
			||||||
 | 
					        bool visit_children(expr * n, unsigned delta);
 | 
				
			||||||
 | 
					        void save(expr * n, unsigned delta, info * i);
 | 
				
			||||||
 | 
					        void save_candidate(expr * n, unsigned delta);
 | 
				
			||||||
 | 
					        void reset();
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        collect(ast_manager & m, pattern_inference_cfg & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
 | 
				
			||||||
 | 
					        void operator()(expr * n, unsigned num_bindings);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    collect                    m_collect;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    void add_candidate(app * n, uint_set const & s, unsigned size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void filter_looping_patterns(ptr_vector<app> & result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class contains_subpattern {
 | 
				
			||||||
 | 
					        pattern_inference_cfg & m_owner;
 | 
				
			||||||
 | 
					        nat_set              m_already_processed; 
 | 
				
			||||||
 | 
					        ptr_vector<expr>     m_todo;
 | 
				
			||||||
 | 
					        void save(expr * n);
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        contains_subpattern(pattern_inference_cfg & owner):
 | 
				
			||||||
 | 
					            m_owner(owner) {}
 | 
				
			||||||
 | 
					        bool operator()(expr * n);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    contains_subpattern        m_contains_subpattern;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    bool contains_subpattern(expr * n);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    struct pre_pattern {
 | 
				
			||||||
 | 
					        ptr_vector<app>  m_exprs;     // elements of the pattern.
 | 
				
			||||||
 | 
					        uint_set         m_free_vars; // set of free variables in m_exprs
 | 
				
			||||||
 | 
					        unsigned         m_idx;       // idx of the next candidate to process.
 | 
				
			||||||
 | 
					        pre_pattern():
 | 
				
			||||||
 | 
					            m_idx(0) {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptr_vector<pre_pattern>      m_pre_patterns;
 | 
				
			||||||
 | 
					    expr_pattern_match           m_database;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
 | 
				
			||||||
 | 
					                                   ptr_vector<app> & remaining_candidate_patterns,
 | 
				
			||||||
 | 
					                                   app_ref_buffer & result);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    void candidates2multi_patterns(unsigned max_num_patterns, 
 | 
				
			||||||
 | 
					                                   ptr_vector<app> const & candidate_patterns, 
 | 
				
			||||||
 | 
					                                   app_ref_buffer & result);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    void reset_pre_patterns();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					       \brief All minimal unary patterns (i.e., expressions that
 | 
				
			||||||
 | 
					       contain all bound variables) are copied to result.  If there
 | 
				
			||||||
 | 
					       are unary patterns, then at most num_extra_multi_patterns multi
 | 
				
			||||||
 | 
					       patterns are created.  If there are no unary pattern, then at
 | 
				
			||||||
 | 
					       most 1 + num_extra_multi_patterns multi_patterns are created.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    void mk_patterns(unsigned num_bindings,              // IN number of bindings.
 | 
				
			||||||
 | 
					                     expr * n,                           // IN node where the patterns are going to be extracted.
 | 
				
			||||||
 | 
					                     unsigned num_no_patterns,           // IN num. patterns that should not be used.
 | 
				
			||||||
 | 
					                     expr * const * no_patterns,         // IN patterns that should not be used.
 | 
				
			||||||
 | 
					                     app_ref_buffer & result);           // OUT result
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    pattern_inference_cfg(ast_manager & m, pattern_inference_params & params);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    void register_forbidden_family(family_id fid) {
 | 
				
			||||||
 | 
					        SASSERT(fid != m_bfid);
 | 
				
			||||||
 | 
					        m_forbidden.push_back(fid);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					       \brief Register f as a preferred function symbol. The inference algorithm
 | 
				
			||||||
 | 
					       gives preference to patterns rooted by this kind of function symbol.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    void register_preferred(func_decl * f) {
 | 
				
			||||||
 | 
					        m_preferred.insert(f);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool reduce_quantifier(quantifier * old_q, 
 | 
				
			||||||
 | 
					                           expr * new_body, 
 | 
				
			||||||
 | 
					                           expr * const * new_patterns, 
 | 
				
			||||||
 | 
					                           expr * const * new_no_patterns,
 | 
				
			||||||
 | 
					                           expr_ref & result,
 | 
				
			||||||
 | 
					                           proof_ref & result_pr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void register_preferred(unsigned num, func_decl * const * fs) { for (unsigned i = 0; i < num; i++) register_preferred(fs[i]); }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    bool is_forbidden(func_decl const * decl) const {
 | 
				
			||||||
 | 
					        family_id fid = decl->get_family_id();
 | 
				
			||||||
 | 
					        if (fid == m_bfid && decl->get_decl_kind() != OP_TRUE && decl->get_decl_kind() != OP_FALSE) 
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        return std::find(m_forbidden.begin(), m_forbidden.end(), fid) != m_forbidden.end();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool is_forbidden(app * n) const;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class pattern_inference_rw : public rewriter_tpl<pattern_inference_cfg> {
 | 
				
			||||||
 | 
					    pattern_inference_cfg m_cfg;
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    pattern_inference_rw(ast_manager& m, pattern_inference_params & params);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* PATTERN_INFERENCE_H_ */
 | 
					#endif /* PATTERN_INFERENCE_H_ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,7 +70,7 @@ namespace datalog {
 | 
				
			||||||
        if (q->get_num_patterns() == 0) {
 | 
					        if (q->get_num_patterns() == 0) {
 | 
				
			||||||
            proof_ref new_pr(m);
 | 
					            proof_ref new_pr(m);
 | 
				
			||||||
            pattern_inference_params params;
 | 
					            pattern_inference_params params;
 | 
				
			||||||
            pattern_inference infer(m, params);
 | 
					            pattern_inference_old infer(m, params);
 | 
				
			||||||
            infer(q, qe, new_pr);
 | 
					            infer(q, qe, new_pr);
 | 
				
			||||||
            q = to_quantifier(qe);
 | 
					            q = to_quantifier(qe);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@ Revision History:
 | 
				
			||||||
#include "ast/ast_pp.h"
 | 
					#include "ast/ast_pp.h"
 | 
				
			||||||
#include "ast/for_each_expr.h"
 | 
					#include "ast/for_each_expr.h"
 | 
				
			||||||
#include "ast/well_sorted.h"
 | 
					#include "ast/well_sorted.h"
 | 
				
			||||||
 | 
					#include "ast/rewriter/rewriter_def.h"
 | 
				
			||||||
#include "ast/simplifier/arith_simplifier_plugin.h"
 | 
					#include "ast/simplifier/arith_simplifier_plugin.h"
 | 
				
			||||||
#include "ast/simplifier/array_simplifier_plugin.h"
 | 
					#include "ast/simplifier/array_simplifier_plugin.h"
 | 
				
			||||||
#include "ast/simplifier/datatype_simplifier_plugin.h"
 | 
					#include "ast/simplifier/datatype_simplifier_plugin.h"
 | 
				
			||||||
| 
						 | 
					@ -517,7 +518,7 @@ void asserted_formulas::reduce_and_solve() {
 | 
				
			||||||
void asserted_formulas::infer_patterns() {
 | 
					void asserted_formulas::infer_patterns() {
 | 
				
			||||||
    IF_IVERBOSE(10, verbose_stream() << "(smt.pattern-inference)\n";);
 | 
					    IF_IVERBOSE(10, verbose_stream() << "(smt.pattern-inference)\n";);
 | 
				
			||||||
    TRACE("before_pattern_inference", display(tout););
 | 
					    TRACE("before_pattern_inference", display(tout););
 | 
				
			||||||
    pattern_inference infer(m, m_params);
 | 
					    pattern_inference_rw infer(m, m_params);
 | 
				
			||||||
    expr_ref_vector  new_exprs(m);
 | 
					    expr_ref_vector  new_exprs(m);
 | 
				
			||||||
    proof_ref_vector new_prs(m);
 | 
					    proof_ref_vector new_prs(m);
 | 
				
			||||||
    unsigned i  = m_asserted_qhead;
 | 
					    unsigned i  = m_asserted_qhead;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -207,8 +207,10 @@ void proto_model::remove_aux_decls_not_in_set(ptr_vector<func_decl> & decls, fun
 | 
				
			||||||
   by their interpretations.
 | 
					   by their interpretations.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
void proto_model::cleanup() {
 | 
					void proto_model::cleanup() {
 | 
				
			||||||
 | 
					    TRACE("model_bug", model_v2_pp(tout, *this););
 | 
				
			||||||
    func_decl_set found_aux_fs;
 | 
					    func_decl_set found_aux_fs;
 | 
				
			||||||
    for (auto const& kv : m_finterp) {
 | 
					    for (auto const& kv : m_finterp) {
 | 
				
			||||||
 | 
					        TRACE("model_bug", tout << kv.m_key->get_name() << "\n";);
 | 
				
			||||||
        func_interp * fi = kv.m_value;
 | 
					        func_interp * fi = kv.m_value;
 | 
				
			||||||
        cleanup_func_interp(fi, found_aux_fs);
 | 
					        cleanup_func_interp(fi, found_aux_fs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -365,7 +367,7 @@ void proto_model::complete_partial_funcs() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
model * proto_model::mk_model() {
 | 
					model * proto_model::mk_model() {
 | 
				
			||||||
    TRACE("proto_model", tout << "mk_model\n"; model_v2_pp(tout, *this););
 | 
					    TRACE("proto_model", model_v2_pp(tout << "mk_model\n", *this););
 | 
				
			||||||
    model * m = alloc(model, m_manager);
 | 
					    model * m = alloc(model, m_manager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (auto const& kv : m_interp) {
 | 
					    for (auto const& kv : m_interp) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,6 @@ Revision History:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "util/ref_util.h"
 | 
					#include "util/ref_util.h"
 | 
				
			||||||
#include "ast/for_each_expr.h"
 | 
					#include "ast/for_each_expr.h"
 | 
				
			||||||
#include "ast/ast_ll_pp.h"
 | 
					 | 
				
			||||||
#include "ast/ast_pp.h"
 | 
					#include "ast/ast_pp.h"
 | 
				
			||||||
#include "ast/ast_smt2_pp.h"
 | 
					#include "ast/ast_smt2_pp.h"
 | 
				
			||||||
#include "smt/smt_context.h"
 | 
					#include "smt/smt_context.h"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue