mirror of
https://github.com/Z3Prover/z3
synced 2025-04-10 11:17:07 +00:00
343 lines
10 KiB
C++
343 lines
10 KiB
C++
/*++
|
|
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 <sstream>
|
|
#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, symbol_hash_proc, symbol_eq_proc> 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<relation_info> 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<model_converter_ref&>(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<datalog::rule> 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<std::string> manager::get_state_suffixes() {
|
|
vector<std::string> 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;
|
|
}
|
|
|
|
};
|