#pragma once
#include "ast/ast.h"
#include "params/smt_params.h"
#include "util/statistics.h"
#include "util/lbool.h"
#include "ast/expr_functors.h"
#include "ast/rewriter/rewriter.h"
#include "model/model.h"
#include "util/params.h"
namespace qe {
class i_nnf_atom {
public:
virtual ~i_nnf_atom() = default;
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) {}
bool operator()(expr* e) override;
};
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) override;
};
is_relevant m_is_relevant;
mk_atom_fn m_mk_atom;
ptr_vector<qe_solver_plugin> m_plugins;
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;
virtual atom_set const& pos_atoms() const = 0;
virtual atom_set const& neg_atoms() const = 0;
virtual unsigned get_num_vars() const = 0;
virtual app* get_var(unsigned idx) const = 0;
virtual app_ref_vector const& get_vars() const = 0;
virtual bool is_var(expr* e, unsigned& idx) const;
virtual contains_app& contains(unsigned idx) = 0;
virtual void elim_var(unsigned idx, expr* fml, expr* def) = 0;
virtual void add_var(app* x) = 0;
virtual void add_constraint(bool use_var, expr* l1 = nullptr, expr* l2 = nullptr, expr* l3 = nullptr) = 0;
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; }
void collect_statistics(statistics & st) const;
};
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; }
};
void extract_equalities(expr_ref_vector& eqs);
iterator begin() { return iterator(*this, true); }
iterator end() { return iterator(*this, false); }
};
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() = default;
family_id get_family_id() { return m_fid; }
virtual bool get_num_branches(contains_app& x, expr* fml, rational& num_branches) = 0;
virtual void assign(contains_app& x, expr* fml, rational const& vl) = 0;
virtual void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) = 0;
virtual bool solve(conj_enum& conjs, expr* fml) = 0;
virtual bool project(contains_app& x, model_ref& model, expr_ref& fml) { return false; }
virtual unsigned get_weight(contains_app& x, expr* fml) { return UINT_MAX; }
virtual bool simplify(expr_ref& fml) { return false; }
virtual bool mk_atom(expr* e, bool p, expr_ref& result) { return false; }
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, smt_params& p);
void extract_vars(quantifier* q, expr_ref& new_body, app_ref_vector& vars);
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]; }
void normalize();
void project(unsigned num_vars, app* const* vars);
};
class guarded_defs {
expr_ref_vector m_guards;
vector<def_vector> m_defs;
bool inv();
public:
guarded_defs(ast_manager& m): m_guards(m) { SASSERT(inv()); }
void add(expr* guard, def_vector const& defs);
unsigned size() const { return m_guards.size(); }
def_vector const& defs(unsigned i) const { return m_defs[i]; }
expr* guard(unsigned i) const { return m_guards[i]; }
std::ostream& display(std::ostream& out) const;
void project(unsigned num_vars, app* const* vars);
};
class quant_elim;
class expr_quant_elim {
ast_manager& m;
smt_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;
public:
expr_quant_elim(ast_manager& m, smt_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);
lbool first_elim(unsigned num_vars, app* const* vars, expr_ref& fml, def_vector& defs);
bool solve_for_var(app* var, expr* fml, guarded_defs& defs);
bool solve_for_vars(unsigned num_vars, app* const* vars, expr* fml, guarded_defs& defs);
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();
};
void hoist_exists(expr_ref& fml, app_ref_vector& vars);
void mk_exists(unsigned num_vars, app* const* vars, expr_ref& fml);
bool has_quantified_uninterpreted(ast_manager& m, expr* 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);
void updt_params(params_ref const& p);
void collect_statistics(statistics & st) const;
};
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) {}
void updt_params(params_ref const& p) { m_cfg.updt_params(p); }
void collect_statistics(statistics & st) const {
m_cfg.collect_statistics(st);
}
};
}