mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
Z3 sources
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
3f9edad676
commit
e9eab22e5c
1186 changed files with 381859 additions and 0 deletions
357
lib/qe.h
Normal file
357
lib/qe.h
Normal file
|
@ -0,0 +1,357 @@
|
|||
/*++
|
||||
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
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue