/*++ Copyright (c) 2011 Microsoft Corporation Module Name: pdr_manager.cpp Abstract: A manager class for PDR, taking care of creating of AST objects and conversions between them. Author: Krystof Hoder (t-khoder) 2011-8-25. Revision History: --*/ #include #include "pdr_manager.h" #include "ast_smt2_pp.h" #include "for_each_expr.h" #include "has_free_vars.h" #include "expr_replacer.h" #include "expr_abstract.h" #include "model2expr.h" #include "model_smt2_pp.h" #include "model_converter.h" namespace pdr { class collect_decls_proc { func_decl_set& m_bound_decls; func_decl_set& m_aux_decls; public: collect_decls_proc(func_decl_set& bound_decls, func_decl_set& aux_decls): m_bound_decls(bound_decls), m_aux_decls(aux_decls) { } void operator()(app* a) { if (a->get_family_id() == null_family_id) { func_decl* f = a->get_decl(); if (!m_bound_decls.contains(f)) { m_aux_decls.insert(f); } } } void operator()(var* v) {} void operator()(quantifier* q) {} }; typedef hashtable symbol_set; expr_ref inductive_property::fixup_clause(expr* fml) const { expr_ref_vector disjs(m); datalog::flatten_or(fml, disjs); switch(disjs.size()) { case 0: return expr_ref(m.mk_false(), m); case 1: return expr_ref(disjs[0].get(), m); default: return expr_ref(m.mk_or(disjs.size(), disjs.c_ptr()), m); } } expr_ref inductive_property::fixup_clauses(expr* fml) const { expr_ref_vector conjs(m); datalog::flatten_and(fml, conjs); for (unsigned i = 0; i < conjs.size(); ++i) { conjs[i] = fixup_clause(conjs[i].get()); } switch(conjs.size()) { case 0: return expr_ref(m.mk_true(), m); case 1: return expr_ref(conjs[0].get(), m); default: return expr_ref(m.mk_and(conjs.size(), conjs.c_ptr()), m); } } std::string inductive_property::to_string() const { std::stringstream stm; model_ref md; expr_ref result(m); to_model(md); model_smt2_pp(stm, m, *md.get(), 0); return stm.str(); } void inductive_property::to_model(model_ref& md) const { md = alloc(model, m); vector const& rs = m_relation_info; expr_ref_vector conjs(m); for (unsigned i = 0; i < rs.size(); ++i) { relation_info ri(rs[i]); func_decl * pred = ri.m_pred; expr_ref prop = fixup_clauses(ri.m_body); func_decl_ref_vector const& sig = ri.m_vars; expr_ref q(m); expr_ref_vector sig_vars(m); for (unsigned j = 0; j < sig.size(); ++j) { sig_vars.push_back(m.mk_const(sig[sig.size()-j-1])); } expr_abstract(m, 0, sig_vars.size(), sig_vars.c_ptr(), prop, q); if (sig.empty()) { md->register_decl(pred, q); } else { func_interp* fi = alloc(func_interp, m, sig.size()); fi->set_else(q); md->register_decl(pred, fi); } } apply(const_cast(m_mc), md, 0); } expr_ref inductive_property::to_expr() const { model_ref md; expr_ref result(m); to_model(md); model2expr(md, result); return result; } void inductive_property::display(ptr_vector const& rules, std::ostream& out) const { func_decl_set bound_decls, aux_decls; collect_decls_proc collect_decls(bound_decls, aux_decls); for (unsigned i = 0; i < m_relation_info.size(); ++i) { bound_decls.insert(m_relation_info[i].m_pred); func_decl_ref_vector const& sig = m_relation_info[i].m_vars; for (unsigned j = 0; j < sig.size(); ++j) { bound_decls.insert(sig[j]); } for_each_expr(collect_decls, m_relation_info[i].m_body); } for (unsigned i = 0; i < rules.size(); ++i) { bound_decls.insert(rules[i]->get_head()->get_decl()); } for (unsigned i = 0; i < rules.size(); ++i) { unsigned u_sz = rules[i]->get_uninterpreted_tail_size(); unsigned t_sz = rules[i]->get_tail_size(); for (unsigned j = u_sz; j < t_sz; ++j) { for_each_expr(collect_decls, rules[i]->get_tail(j)); } } smt2_pp_environment_dbg env(m); pp_params params; func_decl_set::iterator it = aux_decls.begin(), end = aux_decls.end(); for (; it != end; ++it) { func_decl* f = *it; ast_smt2_pp(out, f, env, params); out << "\n"; } out << to_string() << "\n"; for (unsigned i = 0; i < rules.size(); ++i) { out << "(push)\n"; out << "(assert (not\n"; rules[i]->display_smt2(m, out); out << "))\n"; out << "(check-sat)\n"; out << "(pop)\n"; } } vector manager::get_state_suffixes() { vector res; res.push_back("_n"); return res; } manager::manager(front_end_params& fparams, params_ref const& params, ast_manager& manager) : m(manager), m_fparams(fparams), m_params(params), m_brwr(m), m_mux(m, get_state_suffixes()), m_background(m.mk_true(), m), m_contexts(fparams, params, m), m_next_unique_num(0) { } void manager::add_new_state(func_decl * s) { SASSERT(s->get_arity()==0); //we currently don't support non-constant states decl_vector vect; SASSERT(o_index(0)==1); //we assume this in the number of retrieved symbols m_mux.create_tuple(s, s->get_arity(), s->get_domain(), s->get_range(), 2, vect); m_o0_preds.push_back(vect[o_index(0)]); } func_decl * manager::get_o_pred(func_decl* s, unsigned idx) { func_decl * res = m_mux.try_get_by_prefix(s, o_index(idx)); if(res) { return res; } add_new_state(s); res = m_mux.try_get_by_prefix(s, o_index(idx)); SASSERT(res); return res; } func_decl * manager::get_n_pred(func_decl* s) { func_decl * res = m_mux.try_get_by_prefix(s, n_index()); if(res) { return res; } add_new_state(s); res = m_mux.try_get_by_prefix(s, n_index()); SASSERT(res); return res; } void manager::mk_model_into_cube(const expr_ref_vector & mdl, expr_ref & res) { m_brwr.mk_and(mdl.size(), mdl.c_ptr(), res); } void manager::mk_core_into_cube(const expr_ref_vector & core, expr_ref & res) { m_brwr.mk_and(core.size(), core.c_ptr(), res); } void manager::mk_cube_into_lemma(expr * cube, expr_ref & res) { m_brwr.mk_not(cube, res); } void manager::mk_lemma_into_cube(expr * lemma, expr_ref & res) { m_brwr.mk_not(lemma, res); } expr_ref manager::mk_and(unsigned sz, expr* const* exprs) { expr_ref result(m); m_brwr.mk_and(sz, exprs, result); return result; } expr_ref manager::mk_or(unsigned sz, expr* const* exprs) { expr_ref result(m); m_brwr.mk_or(sz, exprs, result); return result; } expr_ref manager::mk_not_and(expr_ref_vector const& conjs) { expr_ref result(m), e(m); expr_ref_vector es(conjs); datalog::flatten_and(es); for (unsigned i = 0; i < es.size(); ++i) { m_brwr.mk_not(es[i].get(), e); es[i] = e; } m_brwr.mk_or(es.size(), es.c_ptr(), result); return result; } void manager::get_or(expr* e, expr_ref_vector& result) { result.push_back(e); for (unsigned i = 0; i < result.size(); ) { e = result[i].get(); if (m.is_or(e)) { result.append(to_app(e)->get_num_args(), to_app(e)->get_args()); result[i] = result.back(); result.pop_back(); } else { ++i; } } } bool manager::try_get_state_and_value_from_atom(expr * atom0, app *& state, app_ref& value) { if(!is_app(atom0)) { return false; } app * atom = to_app(atom0); expr * arg1; expr * arg2; app * candidate_state; app_ref candidate_value(m); if(m.is_not(atom, arg1)) { if(!is_app(arg1)) { return false; } candidate_state = to_app(arg1); candidate_value = m.mk_false(); } else if(m.is_eq(atom, arg1, arg2)) { if(!is_app(arg1) || !is_app(arg2)) { return false; } if(!m_mux.is_muxed(to_app(arg1)->get_decl())) { std::swap(arg1, arg2); } candidate_state = to_app(arg1); candidate_value = to_app(arg2); } else { candidate_state = atom; candidate_value = m.mk_true(); } if(!m_mux.is_muxed(candidate_state->get_decl())) { return false; } state = candidate_state; value = candidate_value; return true; } bool manager::try_get_state_decl_from_atom(expr * atom, func_decl *& state) { app_ref dummy_value_holder(m); app * s; if(try_get_state_and_value_from_atom(atom, s, dummy_value_holder)) { state = s->get_decl(); return true; } else { return false; } } interpolant_provider& manager::get_interpolator() { if(!m_interpolator) { m_interpolator = interpolant_provider::mk(m, get_params()); } return *m_interpolator; } bool manager::implication_surely_holds(expr * lhs, expr * rhs, expr * bg) { smt::solver sctx(m, get_fparams()); if(bg) { sctx.assert_expr(bg); } sctx.assert_expr(lhs); expr_ref neg_rhs(m.mk_not(rhs),m); sctx.assert_expr(neg_rhs); lbool smt_res = sctx.check(); return smt_res==l_false; } };