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

358 lines
11 KiB
C++

/*++
Copyright (c) 2010 Microsoft Corporation
Module Name:
qe.h
Abstract:
Quantifier-elimination procedures
Author:
Nikolaj Bjorner (nbjorner) 2010-02-19
Revision History:
--*/
#ifndef __QE_H__
#define __QE_H__
#include "ast.h"
#include "front_end_params.h"
#include "statistics.h"
#include "lbool.h"
#include "expr_functors.h"
#include "simplifier.h"
#include "rewriter.h"
#include "model.h"
#include "params.h"
namespace qe {
class i_nnf_atom {
public:
virtual void operator()(expr* e, bool pol, expr_ref& result) = 0;
};
typedef obj_hashtable<app> atom_set;
class qe_solver_plugin;
class i_solver_context {
protected:
class is_relevant : public i_expr_pred {
i_solver_context& m_s;
public:
is_relevant(i_solver_context& s):m_s(s) {}
virtual bool operator()(expr* e);
};
class mk_atom_fn : public i_nnf_atom {
i_solver_context& m_s;
public:
mk_atom_fn(i_solver_context& s) : m_s(s) {}
void operator()(expr* e, bool p, expr_ref& result);
};
is_relevant m_is_relevant;
mk_atom_fn m_mk_atom;
ptr_vector<qe_solver_plugin> m_plugins; // fid -> plugin
public:
i_solver_context():m_is_relevant(*this), m_mk_atom(*this) {}
virtual ~i_solver_context();
void add_plugin(qe_solver_plugin* p);
bool has_plugin(app* x);
qe_solver_plugin& plugin(app* x);
qe_solver_plugin& plugin(unsigned fid) { return *m_plugins[fid]; }
void mk_atom(expr* e, bool p, expr_ref& result);
virtual ast_manager& get_manager() = 0;
// set of atoms in current formula.
virtual atom_set const& pos_atoms() const = 0;
virtual atom_set const& neg_atoms() const = 0;
// Access current set of variables to solve
virtual unsigned get_num_vars() const = 0;
virtual app* get_var(unsigned idx) const = 0;
virtual app*const* get_vars() const = 0;
virtual bool is_var(expr* e, unsigned& idx) const;
virtual contains_app& contains(unsigned idx) = 0;
// callback to replace variable at index 'idx' with definition 'def' and updated formula 'fml'
virtual void elim_var(unsigned idx, expr* fml, expr* def) = 0;
// callback to add new variable to branch.
virtual void add_var(app* x) = 0;
// callback to add constraints in branch.
virtual void add_constraint(bool use_var, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) = 0;
// eliminate finite domain variable 'var' from fml.
virtual void blast_or(app* var, expr_ref& fml) = 0;
i_expr_pred& get_is_relevant() { return m_is_relevant; }
i_nnf_atom& get_mk_atom() { return m_mk_atom; }
};
class conj_enum {
ast_manager& m;
expr_ref_vector m_conjs;
public:
conj_enum(ast_manager& m, expr* e);
class iterator {
conj_enum* m_super;
unsigned m_index;
public:
iterator(conj_enum& c, bool first) : m_super(&c), m_index(first?0:c.m_conjs.size()) {}
expr* operator*() { return m_super->m_conjs[m_index].get(); }
iterator& operator++() { m_index++; return *this; }
bool operator==(iterator const& it) const { return m_index == it.m_index; }
bool operator!=(iterator const& it) const { return m_index != it.m_index; }
};
void extract_equalities(expr_ref_vector& eqs);
iterator begin() { return iterator(*this, true); }
iterator end() { return iterator(*this, false); }
};
//
// interface for plugins to eliminate quantified variables.
//
class qe_solver_plugin {
protected:
ast_manager& m;
family_id m_fid;
i_solver_context& m_ctx;
public:
qe_solver_plugin(ast_manager& m, family_id fid, i_solver_context& ctx) :
m(m),
m_fid(fid),
m_ctx(ctx)
{}
virtual ~qe_solver_plugin() {}
family_id get_family_id() { return m_fid; }
/**
\brief Return number of case splits for variable x in fml.
*/
virtual bool get_num_branches(contains_app& x, expr* fml, rational& num_branches) = 0;
/**
\brief Given a case split index 'vl' assert the constraints associated with it.
*/
virtual void assign(contains_app& x, expr* fml, rational const& vl) = 0;
/**
\brief The case splits associated with 'vl' are satisfiable.
Apply the elimination for fml corresponding to case split.
If def is non-null, then retrieve the realizer corresponding to the case split.
*/
virtual void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) = 0;
/**
\brief solve quantified variable.
*/
virtual bool solve(conj_enum& conjs, expr* fml) = 0;
/**
\brief project variable x for fml given model.
Assumption: model |= fml[x]
Projection updates fml to fml', such that:
- fml' -> fml
- model |= fml'
- fml' does not contain x
return false if the method is not implemented.
*/
virtual bool project(contains_app& x, model_ref& model, expr_ref& fml) { return false; }
/**
\brief assign branching penalty to variable x for 'fml'.
*/
virtual unsigned get_weight(contains_app& x, expr* fml) { return UINT_MAX; }
/**
\brief simplify formula.
*/
virtual bool simplify(expr_ref& fml) { return false; }
/**
\brief Normalize literal during NNF conversion.
*/
virtual bool mk_atom(expr* e, bool p, expr_ref& result) { return false; }
/**
\brief Determine whether sub-term is uninterpreted with respect to quantifier elimination.
*/
virtual bool is_uninterpreted(app* f) { return true; }
};
qe_solver_plugin* mk_datatype_plugin(i_solver_context& ctx);
qe_solver_plugin* mk_bool_plugin(i_solver_context& ctx);
qe_solver_plugin* mk_bv_plugin(i_solver_context& ctx);
qe_solver_plugin* mk_dl_plugin(i_solver_context& ctx);
qe_solver_plugin* mk_array_plugin(i_solver_context& ctx);
qe_solver_plugin* mk_arith_plugin(i_solver_context& ctx, bool produce_models, front_end_params& p);
class def_vector {
func_decl_ref_vector m_vars;
expr_ref_vector m_defs;
public:
def_vector(ast_manager& m): m_vars(m), m_defs(m) {}
void push_back(func_decl* v, expr* e) {
m_vars.push_back(v);
m_defs.push_back(e);
}
void reset() { m_vars.reset(); m_defs.reset(); }
void append(def_vector const& o) { m_vars.append(o.m_vars); m_defs.append(o.m_defs); }
unsigned size() const { return m_defs.size(); }
void shrink(unsigned sz) { m_vars.shrink(sz); m_defs.shrink(sz); }
bool empty() const { return m_defs.empty(); }
func_decl* var(unsigned i) const { return m_vars[i]; }
expr* def(unsigned i) const { return m_defs[i]; }
expr_ref_vector::element_ref def_ref(unsigned i) { return m_defs[i]; }
};
class quant_elim;
class expr_quant_elim {
ast_manager& m;
front_end_params const& m_fparams;
params_ref m_params;
expr_ref_vector m_trail;
obj_map<expr,expr*> m_visited;
quant_elim* m_qe;
expr* m_assumption;
bool m_use_new_qe;
public:
expr_quant_elim(ast_manager& m, front_end_params const& fp, params_ref const& p = params_ref());
~expr_quant_elim();
void operator()(expr* assumption, expr* fml, expr_ref& result);
void collect_statistics(statistics & st) const;
void updt_params(params_ref const& p);
void collect_param_descrs(param_descrs& r);
/**
\brief try to eliminate 'vars' and find first satisfying assignment.
return l_true if satisfiable, l_false if unsatisfiable, l_undef if
the formula could not be satisfied modulo eliminating the quantified variables.
*/
lbool first_elim(unsigned num_vars, app* const* vars, expr_ref& fml, def_vector& defs);
/**
\brief solve for (exists (var) fml).
Return false if operation failed.
Return true and list of pairs (t_i, fml_i) in <terms, fmls>
such that fml[t_1] \/ ... \/ fml[t_n] == (exists (var) fml)
and fml_i == fml[t_1]
*/
bool solve_for_var(app* var, expr* fml, expr_ref_vector& terms, expr_ref_vector& fmls);
void set_cancel(bool f);
private:
void instantiate_expr(expr_ref_vector& bound, expr_ref& fml);
void abstract_expr(unsigned sz, expr* const* bound, expr_ref& fml);
void elim(expr_ref& result);
void init_qe();
};
class expr_quant_elim_star1 : public simplifier {
protected:
expr_quant_elim m_quant_elim;
expr* m_assumption;
virtual bool visit_quantifier(quantifier * q);
virtual void reduce1_quantifier(quantifier * q);
virtual bool is_target(quantifier * q) const { return q->get_num_patterns() == 0 && q->get_num_no_patterns() == 0; }
public:
expr_quant_elim_star1(ast_manager & m, front_end_params const& p);
virtual ~expr_quant_elim_star1() {}
void collect_statistics(statistics & st) const {
m_quant_elim.collect_statistics(st);
}
void reduce_with_assumption(expr* ctx, expr* fml, expr_ref& result);
lbool first_elim(unsigned num_vars, app* const* vars, expr_ref& fml, def_vector& defs) {
return m_quant_elim.first_elim(num_vars, vars, fml, defs);
}
void set_cancel(bool f) {} // TBD: replace simplifier by rewriter
};
void hoist_exists(expr_ref& fml, app_ref_vector& vars);
void mk_exists(unsigned num_vars, app* const* vars, expr_ref& fml);
void get_nnf(expr_ref& fml, i_expr_pred& pred, i_nnf_atom& mk_atom, atom_set& pos, atom_set& neg);
class simplify_rewriter_cfg : public default_rewriter_cfg {
class impl;
impl* imp;
public:
simplify_rewriter_cfg(ast_manager& m);
~simplify_rewriter_cfg();
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);
bool pre_visit(expr* e);
};
class simplify_rewriter_star : public rewriter_tpl<simplify_rewriter_cfg> {
simplify_rewriter_cfg m_cfg;
public:
simplify_rewriter_star(ast_manager& m):
rewriter_tpl<simplify_rewriter_cfg>(m, false, m_cfg),
m_cfg(m) {}
};
};
#endif