mirror of
https://github.com/Z3Prover/z3
synced 2025-04-08 10:25:18 +00:00
358 lines
11 KiB
C++
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
|
|
|