mirror of
https://github.com/Z3Prover/z3
synced 2025-04-08 18:31:49 +00:00
preparing handling of arrays/quantifiers, fix cover-related bugs reported by Arie
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
6834abd781
commit
93ad91d2f9
|
@ -144,7 +144,21 @@ public:
|
|||
bool is_map(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAP); }
|
||||
bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); }
|
||||
bool is_as_array_tree(expr * n);
|
||||
bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); }
|
||||
bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); }
|
||||
bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); }
|
||||
bool is_map(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_MAP); }
|
||||
bool is_as_array(func_decl* f) const { return is_decl_of(f, m_fid, OP_AS_ARRAY); }
|
||||
func_decl * get_as_array_func_decl(app * n) const { SASSERT(is_as_array(n)); return to_func_decl(n->get_decl()->get_parameter(0).get_ast()); }
|
||||
|
||||
app * mk_store(unsigned num_args, expr * const * args) {
|
||||
return m_manager.mk_app(m_fid, OP_STORE, 0, 0, num_args, args);
|
||||
}
|
||||
|
||||
app * mk_select(unsigned num_args, expr * const * args) {
|
||||
return m_manager.mk_app(m_fid, OP_SELECT, 0, 0, num_args, args);
|
||||
}
|
||||
|
||||
app * mk_map(func_decl * f, unsigned num_args, expr * const * args) {
|
||||
parameter p(f);
|
||||
return m_manager.mk_app(m_fid, OP_ARRAY_MAP, 1, &p, num_args, args);
|
||||
|
|
|
@ -44,8 +44,7 @@ namespace datalog {
|
|||
m_num_sym("N"),
|
||||
m_lt_sym("<"),
|
||||
m_le_sym("<="),
|
||||
m_rule_sym("R"),
|
||||
m_hyper_resolve_sym("hyper-res")
|
||||
m_rule_sym("R")
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,6 @@ namespace datalog {
|
|||
symbol m_lt_sym;
|
||||
symbol m_le_sym;
|
||||
symbol m_rule_sym;
|
||||
symbol m_hyper_resolve_sym;
|
||||
|
||||
bool check_bounds(char const* msg, unsigned low, unsigned up, unsigned val) const;
|
||||
bool check_domain(unsigned low, unsigned up, unsigned val) const;
|
||||
|
@ -93,7 +92,6 @@ namespace datalog {
|
|||
func_decl * mk_compare(decl_kind k, symbol const& sym, sort*const* domain);
|
||||
func_decl * mk_clone(sort* r);
|
||||
func_decl * mk_rule(unsigned arity);
|
||||
func_decl * mk_hyper_res(unsigned num_params, parameter const* params, unsigned arity, sort *const* domain);
|
||||
|
||||
sort * mk_finite_sort(unsigned num_params, parameter const* params);
|
||||
sort * mk_relation_sort(unsigned num_params, parameter const* params);
|
||||
|
|
|
@ -147,7 +147,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
|
|||
return m_a_rw.mk_app_core(f, num, args, result);
|
||||
if (fid == m_bv_rw.get_fid())
|
||||
return m_bv_rw.mk_app_core(f, num, args, result);
|
||||
if (fid == m_ar_rw.get_fid())
|
||||
if (fid == m_ar_rw.get_fid())
|
||||
return m_ar_rw.mk_app_core(f, num, args, result);
|
||||
if (fid == m_dt_rw.get_fid())
|
||||
return m_dt_rw.mk_app_core(f, num, args, result);
|
||||
|
|
|
@ -54,6 +54,7 @@ Revision History:
|
|||
#include"expr_functors.h"
|
||||
#include"dl_mk_partial_equiv.h"
|
||||
#include"dl_mk_bit_blast.h"
|
||||
#include"dl_mk_array_blast.h"
|
||||
#include"datatype_decl_plugin.h"
|
||||
#include"expr_abstract.h"
|
||||
|
||||
|
@ -944,6 +945,7 @@ namespace datalog {
|
|||
transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880));
|
||||
|
||||
transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000));
|
||||
transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000));
|
||||
transform_rules(transf, mc, pc);
|
||||
}
|
||||
|
||||
|
|
139
src/muz_qe/dl_mk_array_blast.cpp
Normal file
139
src/muz_qe/dl_mk_array_blast.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_mk_array_blast.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Remove array variables from rules.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-11-23
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "dl_mk_array_blast.h"
|
||||
#include "expr_replacer.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
|
||||
mk_array_blast::mk_array_blast(context & ctx, unsigned priority) :
|
||||
rule_transformer::plugin(priority, false),
|
||||
m_ctx(ctx),
|
||||
m(ctx.get_manager()),
|
||||
a(m),
|
||||
rm(ctx.get_rule_manager()),
|
||||
m_rewriter(m, m_params){
|
||||
m_params.set_bool(":expand-select-store",true);
|
||||
m_rewriter.updt_params(m_params);
|
||||
}
|
||||
|
||||
mk_array_blast::~mk_array_blast() {
|
||||
}
|
||||
|
||||
bool mk_array_blast::is_store_def(expr* e, expr*& x, expr*& y) {
|
||||
if (m.is_iff(e, x, y) || m.is_eq(e, x, y)) {
|
||||
if (!a.is_store(y)) {
|
||||
std::swap(x,y);
|
||||
}
|
||||
if (is_var(x) && a.is_store(y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mk_array_blast::blast(rule& r, rule_set& rules) {
|
||||
unsigned utsz = r.get_uninterpreted_tail_size();
|
||||
unsigned tsz = r.get_tail_size();
|
||||
expr_ref_vector conjs(m), new_conjs(m);
|
||||
for (unsigned i = 0; i < utsz; ++i) {
|
||||
new_conjs.push_back(r.get_tail(i));
|
||||
}
|
||||
for (unsigned i = utsz; i < tsz; ++i) {
|
||||
conjs.push_back(r.get_tail(i));
|
||||
}
|
||||
flatten_and(conjs);
|
||||
expr_substitution sub(m);
|
||||
uint_set lhs_vars, rhs_vars;
|
||||
for (unsigned i = 0; i < conjs.size(); ++i) {
|
||||
expr* x, *y;
|
||||
if (is_store_def(conjs[i].get(), x, y)) {
|
||||
// enforce topological order consistency:
|
||||
uint_set lhs;
|
||||
collect_vars(m, x, lhs_vars);
|
||||
collect_vars(m, y, rhs_vars);
|
||||
lhs = lhs_vars;
|
||||
lhs &= rhs_vars;
|
||||
if (!lhs.empty()) {
|
||||
new_conjs.push_back(conjs[i].get());
|
||||
}
|
||||
else {
|
||||
sub.insert(x, y);
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_conjs.push_back(conjs[i].get());
|
||||
}
|
||||
}
|
||||
if (sub.empty()) {
|
||||
rules.add_rule(&r);
|
||||
return false;
|
||||
}
|
||||
|
||||
rule_ref_vector new_rules(rm);
|
||||
expr_ref fml1(m), fml2(m), body(m), head(m);
|
||||
r.to_formula(fml1);
|
||||
body = m.mk_and(new_conjs.size(), new_conjs.c_ptr());
|
||||
head = r.get_head();
|
||||
scoped_ptr<expr_replacer> replace = mk_default_expr_replacer(m);
|
||||
replace->set_substitution(&sub);
|
||||
(*replace)(body);
|
||||
m_rewriter(body);
|
||||
(*replace)(head);
|
||||
m_rewriter(head);
|
||||
fml2 = m.mk_implies(body, head);
|
||||
rm.mk_rule(fml2, new_rules, r.name());
|
||||
SASSERT(new_rules.size() == 1);
|
||||
|
||||
rules.add_rule(new_rules[0].get());
|
||||
if (m_pc) {
|
||||
new_rules[0]->to_formula(fml2);
|
||||
m_pc->insert(fml1, fml2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
rule_set * mk_array_blast::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
|
||||
ref<equiv_proof_converter> epc;
|
||||
if (pc) {
|
||||
epc = alloc(equiv_proof_converter, m);
|
||||
}
|
||||
m_pc = epc.get();
|
||||
|
||||
rule_set* rules = alloc(rule_set, m_ctx);
|
||||
rule_set::iterator it = source.begin(), end = source.end();
|
||||
bool change = false;
|
||||
for (; it != end; ++it) {
|
||||
change = blast(**it, *rules) || change;
|
||||
}
|
||||
if (!change) {
|
||||
dealloc(rules);
|
||||
rules = 0;
|
||||
}
|
||||
if (pc) {
|
||||
pc = concat(pc.get(), epc.get());
|
||||
}
|
||||
return rules;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
61
src/muz_qe/dl_mk_array_blast.h
Normal file
61
src/muz_qe/dl_mk_array_blast.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_mk_array_blast.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Remove array variables from rules.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-11-23
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _DL_MK_ARRAY_BLAST_H_
|
||||
#define _DL_MK_ARRAY_BLAST_H_
|
||||
|
||||
#include"dl_context.h"
|
||||
#include"dl_rule_set.h"
|
||||
#include"dl_rule_transformer.h"
|
||||
#include "equiv_proof_converter.h"
|
||||
#include "array_decl_plugin.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
/**
|
||||
\brief Blast occurrences of arrays in rules
|
||||
*/
|
||||
class mk_array_blast : public rule_transformer::plugin {
|
||||
context& m_ctx;
|
||||
ast_manager& m;
|
||||
array_util a;
|
||||
rule_manager& rm;
|
||||
params_ref m_params;
|
||||
th_rewriter m_rewriter;
|
||||
equiv_proof_converter* m_pc;
|
||||
|
||||
bool blast(rule& r, rule_set& new_rules);
|
||||
|
||||
bool is_store_def(expr* e, expr*& x, expr*& y);
|
||||
|
||||
public:
|
||||
/**
|
||||
\brief Create rule transformer that extracts universal quantifiers (over recursive predicates).
|
||||
*/
|
||||
mk_array_blast(context & ctx, unsigned priority);
|
||||
|
||||
virtual ~mk_array_blast();
|
||||
|
||||
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* _DL_MK_ARRAY_BLAST_H_ */
|
||||
|
|
@ -40,29 +40,32 @@ namespace datalog {
|
|||
|
||||
|
||||
void mk_extract_quantifiers::extract(rule& r, rule_set& new_rules) {
|
||||
app_ref_vector tail(m);
|
||||
svector<bool> neg_tail;
|
||||
expr_ref_vector tail(m);
|
||||
quantifier_ref_vector quantifiers(m);
|
||||
unsigned utsz = r.get_uninterpreted_tail_size();
|
||||
unsigned tsz = r.get_tail_size();
|
||||
for (unsigned i = 0; i < utsz; ++i) {
|
||||
tail.push_back(r.get_tail(i));
|
||||
neg_tail.push_back(r.is_neg_tail(i));
|
||||
if (r.is_neg_tail(i)) {
|
||||
new_rules.add_rule(&r);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (unsigned i = utsz; i < tsz; ++i) {
|
||||
SASSERT(!r.is_neg_tail(i));
|
||||
app* t = r.get_tail(i);
|
||||
expr_ref_vector conjs(m);
|
||||
datalog::flatten_and(t, conjs);
|
||||
quantifier_ref qe(m);
|
||||
quantifier* q = 0;
|
||||
for (unsigned j = 0; j < conjs.size(); ++j) {
|
||||
expr* e = conjs[j].get();
|
||||
quantifier* q = 0;
|
||||
if (rule_manager::is_forall(m, e, q)) {
|
||||
quantifiers.push_back(q);
|
||||
qe = m.mk_exists(q->get_num_decls(), q->get_decl_sorts(), q->get_decl_names(), q->get_expr());
|
||||
tail.push_back(qe);
|
||||
}
|
||||
else {
|
||||
tail.push_back(is_app(e)?to_app(e):m.mk_eq(e, m.mk_true()));
|
||||
neg_tail.push_back(false);
|
||||
tail.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,11 +73,16 @@ namespace datalog {
|
|||
new_rules.add_rule(&r);
|
||||
}
|
||||
else {
|
||||
rule* new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), neg_tail.c_ptr(), r.name(), false);
|
||||
new_rules.add_rule(new_rule);
|
||||
expr_ref fml(m);
|
||||
rule_ref_vector rules(rm);
|
||||
fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), r.get_head());
|
||||
rm.mk_rule(fml, rules, r.name());
|
||||
quantifier_ref_vector* qs = alloc(quantifier_ref_vector, quantifiers);
|
||||
m_quantifiers.insert(new_rule, qs);
|
||||
m_refs.push_back(qs);
|
||||
for (unsigned i = 0; i < rules.size(); ++i) {
|
||||
m_quantifiers.insert(rules[i].get(), qs);
|
||||
new_rules.add_rule(rules[i].get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -196,6 +196,12 @@ namespace datalog {
|
|||
scoped_no_proof(ast_manager& m): scoped_proof_mode(m, PGM_DISABLED) {}
|
||||
};
|
||||
|
||||
class scoped_restore_proof : public scoped_proof_mode {
|
||||
public:
|
||||
scoped_restore_proof(ast_manager& m): scoped_proof_mode(m, m.proof_mode()) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class variable_intersection
|
||||
|
|
58
src/muz_qe/equiv_proof_converter.h
Normal file
58
src/muz_qe/equiv_proof_converter.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
equiv_proof_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Proof converter that applies equivalence rule to leaves.
|
||||
|
||||
Given a proof P with occurrences of [asserted fml]
|
||||
replace [asserted fml] by a proof of the form
|
||||
[mp [asserted fml'] [~ fml fml']]
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-11-23
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _EQUIV_PROOF_CONVERTER_H_
|
||||
#define _EQUIV_PROOF_CONVERTER_H_
|
||||
|
||||
#include "replace_proof_converter.h"
|
||||
|
||||
class equiv_proof_converter : public proof_converter {
|
||||
ast_manager& m;
|
||||
replace_proof_converter m_replace;
|
||||
public:
|
||||
|
||||
equiv_proof_converter(ast_manager& m): m(m), m_replace(m) {}
|
||||
|
||||
virtual ~equiv_proof_converter() {}
|
||||
|
||||
virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) {
|
||||
m_replace(m, num_source, source, result);
|
||||
}
|
||||
|
||||
virtual proof_converter * translate(ast_translation & translator) {
|
||||
return m_replace.translate(translator);
|
||||
}
|
||||
|
||||
void insert(expr* fml1, expr* fml2) {
|
||||
proof_ref p1(m), p2(m), p3(m);
|
||||
p1 = m.mk_asserted(fml1);
|
||||
p2 = m.mk_rewrite(fml1, fml2);
|
||||
p3 = m.mk_modus_ponens(p1, p2);
|
||||
m_replace.insert(p3);
|
||||
}
|
||||
|
||||
ast_manager& get_manager() { return m; }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -35,7 +35,6 @@ Notes:
|
|||
#include "pdr_generalizers.h"
|
||||
#include "datatype_decl_plugin.h"
|
||||
#include "for_each_expr.h"
|
||||
#include "model_v2_pp.h"
|
||||
#include "dl_rule_set.h"
|
||||
#include "unit_subsumption_tactic.h"
|
||||
#include "model_smt2_pp.h"
|
||||
|
@ -146,7 +145,6 @@ namespace pdr {
|
|||
expr_ref vl(m);
|
||||
for (; it != end; ++it) {
|
||||
expr* pred = it->m_key;
|
||||
TRACE("pdr", tout << mk_pp(pred, m) << "\n";);
|
||||
if (model.eval(to_app(pred)->get_decl(), vl) && m.is_true(vl)) {
|
||||
return *it->m_value;
|
||||
}
|
||||
|
@ -362,7 +360,7 @@ namespace pdr {
|
|||
}
|
||||
// replace local constants by bound variables.
|
||||
expr_substitution sub(m);
|
||||
for (unsigned i = 0; i < m_sig.size(); ++i) {
|
||||
for (unsigned i = 0; i < sig_size(); ++i) {
|
||||
c = m.mk_const(pm.o2n(sig(i), 0));
|
||||
v = m.mk_var(i, sig(i)->get_range());
|
||||
sub.insert(c, v);
|
||||
|
@ -397,7 +395,7 @@ namespace pdr {
|
|||
// replace bound variables by local constants.
|
||||
expr_ref result(property, m), v(m), c(m);
|
||||
expr_substitution sub(m);
|
||||
for (unsigned i = 0; i < m_sig.size(); ++i) {
|
||||
for (unsigned i = 0; i < sig_size(); ++i) {
|
||||
c = m.mk_const(pm.o2n(sig(i), 0));
|
||||
v = m.mk_var(i, sig(i)->get_range());
|
||||
sub.insert(v, c);
|
||||
|
@ -602,6 +600,12 @@ namespace pdr {
|
|||
}
|
||||
m_rule2inst.insert(&rule,&var_reprs);
|
||||
m_rule2vars.insert(&rule, aux_vars);
|
||||
TRACE("pdr",
|
||||
tout << rule.get_decl()->get_name() << "\n";
|
||||
for (unsigned i = 0; i < var_reprs.size(); ++i) {
|
||||
tout << mk_pp(var_reprs[i].get(), m) << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
}
|
||||
|
||||
bool pred_transformer::check_filled(app_ref_vector const& v) const {
|
||||
|
@ -723,7 +727,7 @@ namespace pdr {
|
|||
pred_transformer& p = pt();
|
||||
ast_manager& m = p.get_manager();
|
||||
manager& pm = p.get_pdr_manager();
|
||||
TRACE("pdr", model_v2_pp(tout, get_model()););
|
||||
TRACE("pdr", model_smt2_pp(tout, m, get_model(), 0););
|
||||
func_decl* f = p.head();
|
||||
unsigned arity = f->get_arity();
|
||||
expr_ref_vector args(m);
|
||||
|
|
|
@ -116,6 +116,7 @@ namespace pdr {
|
|||
ptr_vector<datalog::rule> const& rules() const { return m_rules; }
|
||||
func_decl* sig(unsigned i) { init_sig(); return m_sig[i].get(); } // signature
|
||||
func_decl* const* sig() { init_sig(); return m_sig.c_ptr(); }
|
||||
unsigned sig_size() { init_sig(); return m_sig.size(); }
|
||||
expr* transition() const { return m_transition; }
|
||||
expr* initial_state() const { return m_initial_state; }
|
||||
expr* rule2tag(datalog::rule const* r) { return m_rule2tag.find(r); }
|
||||
|
|
|
@ -58,18 +58,18 @@ dl_interface::~dl_interface() {
|
|||
//
|
||||
void dl_interface::check_reset() {
|
||||
datalog::rule_ref_vector const& new_rules = m_ctx.get_rules().get_rules();
|
||||
datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules();
|
||||
for (unsigned i = 0; i < new_rules.size(); ++i) {
|
||||
bool found = false;
|
||||
for (unsigned j = 0; !found && j < old_rules.size(); ++j) {
|
||||
datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules();
|
||||
bool is_subsumed = !old_rules.empty();
|
||||
for (unsigned i = 0; is_subsumed && i < new_rules.size(); ++i) {
|
||||
is_subsumed = false;
|
||||
for (unsigned j = 0; !is_subsumed && j < old_rules.size(); ++j) {
|
||||
if (m_ctx.check_subsumes(*old_rules[j], *new_rules[i])) {
|
||||
found = true;
|
||||
is_subsumed = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
CTRACE("pdr", (old_rules.size() > 0), new_rules[i]->display(m_ctx, tout << "Fresh rule "););
|
||||
if (!is_subsumed) {
|
||||
TRACE("pdr", new_rules[i]->display(m_ctx, tout << "Fresh rule "););
|
||||
m_context->reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_old_rules.reset();
|
||||
|
@ -160,6 +160,8 @@ lbool dl_interface::query(expr * query) {
|
|||
m_ctx.replace_rules(old_rules);
|
||||
|
||||
quantifier_model_checker quantifier_mc(*m_context, m, extract_quantifiers->quantifiers(), m_pdr_rules);
|
||||
|
||||
datalog::scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode.
|
||||
|
||||
m_context->set_proof_converter(pc);
|
||||
m_context->set_model_converter(mc);
|
||||
|
|
|
@ -24,6 +24,7 @@ Revision History:
|
|||
#include "qe.h"
|
||||
#include "var_subst.h"
|
||||
#include "dl_rule_set.h"
|
||||
#include "model_smt2_pp.h"
|
||||
|
||||
|
||||
namespace pdr {
|
||||
|
@ -181,25 +182,21 @@ namespace pdr {
|
|||
bool found_instance = false;
|
||||
TRACE("pdr", tout << mk_pp(m_A,m) << "\n";);
|
||||
|
||||
ast_manager mp(PGM_COARSE);
|
||||
ast_translation tr(m, mp);
|
||||
ast_translation rev_tr(mp, m);
|
||||
expr_ref_vector fmls(mp);
|
||||
datalog::scoped_coarse_proof _scp(m);
|
||||
|
||||
expr_ref_vector fmls(m);
|
||||
front_end_params fparams;
|
||||
fparams.m_proof_mode = PGM_COARSE;
|
||||
// TBD: does not work on integers: fparams.m_mbqi = true;
|
||||
expr_ref C(m);
|
||||
fmls.push_back(tr(m_A.get()));
|
||||
for (unsigned i = 0; i < m_Bs.size(); ++i) {
|
||||
C = m.update_quantifier(qs[i], m_Bs[i].get());
|
||||
fmls.push_back(tr(C.get()));
|
||||
}
|
||||
|
||||
fmls.push_back(m_A.get());
|
||||
fmls.append(m_Bs);
|
||||
TRACE("pdr",
|
||||
tout << "assert\n";
|
||||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
tout << mk_pp(fmls[i].get(), mp) << "\n";
|
||||
tout << mk_pp(fmls[i].get(), m) << "\n";
|
||||
});
|
||||
smt::kernel solver(mp, fparams);
|
||||
smt::kernel solver(m, fparams);
|
||||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
solver.assert_expr(fmls[i].get());
|
||||
}
|
||||
|
@ -216,8 +213,8 @@ namespace pdr {
|
|||
}
|
||||
|
||||
proof* p = solver.get_proof();
|
||||
TRACE("pdr", tout << mk_ismt2_pp(p, mp) << "\n";);
|
||||
collect_insts collector(mp);
|
||||
TRACE("pdr", tout << mk_ismt2_pp(p, m) << "\n";);
|
||||
collect_insts collector(m);
|
||||
for_each_expr(collector, p);
|
||||
ptr_vector<quantifier> const& quants = collector.quantifiers();
|
||||
|
||||
|
@ -225,20 +222,20 @@ namespace pdr {
|
|||
symbol qid = quants[i]->get_qid();
|
||||
if (!qid_map.find(qid, q)) {
|
||||
TRACE("pdr", tout << "Could not find quantifier "
|
||||
<< mk_pp(quants[i], mp) << "\n";);
|
||||
<< mk_pp(quants[i], m) << "\n";);
|
||||
continue;
|
||||
}
|
||||
expr_ref_vector const& binding = collector.bindings()[i];
|
||||
|
||||
TRACE("pdr", tout << "Instantiating:\n" << mk_pp(quants[i], mp) << "\n";
|
||||
TRACE("pdr", tout << "Instantiating:\n" << mk_pp(quants[i], m) << "\n";
|
||||
for (unsigned j = 0; j < binding.size(); ++j) {
|
||||
tout << mk_pp(binding[j], mp) << " ";
|
||||
tout << mk_pp(binding[j], m) << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
|
||||
expr_ref_vector new_binding(m);
|
||||
for (unsigned j = 0; j < binding.size(); ++j) {
|
||||
new_binding.push_back(rev_tr(binding[j]));
|
||||
new_binding.push_back(binding[j]);
|
||||
}
|
||||
add_binding(q, new_binding);
|
||||
found_instance = true;
|
||||
|
@ -258,11 +255,32 @@ namespace pdr {
|
|||
return found_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
Given node:
|
||||
|
||||
- pt - predicate transformer for rule:
|
||||
P(x) :- Body1(x,y) || Body2(x,z) & (Fa u . Q(u,x,z)).
|
||||
- rule - P(x) :- Body2(x,z)
|
||||
|
||||
- qis - Fa u . Q(u,x,z)
|
||||
|
||||
- A := node.state(x) && Body2(x,y)
|
||||
|
||||
- Bs := array of Bs of the form:
|
||||
. Fa u . Q(u, P_x, P_y) - instantiate quantifier to P variables.
|
||||
. B := inv(Q_0,Q_1,Q_2)
|
||||
. B := inv(u, P_x, P_y) := B[u/Q_0, P_x/Q_1, P_y/Q_2]
|
||||
. B := Fa u . inv(u, P_x, P_y)
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
void quantifier_model_checker::model_check_node(model_node& node) {
|
||||
TRACE("pdr", node.display(tout, 0););
|
||||
pred_transformer& pt = node.pt();
|
||||
manager& pm = pt.get_pdr_manager();
|
||||
expr_ref A(m), B(m), C(m);
|
||||
expr_ref A(m), B(m), C(m), v(m);
|
||||
expr_ref_vector As(m);
|
||||
m_Bs.reset();
|
||||
//
|
||||
|
@ -285,8 +303,12 @@ namespace pdr {
|
|||
return;
|
||||
}
|
||||
unsigned level = node.level();
|
||||
unsigned previous_level = (level == 0)?0:(level-1);
|
||||
if (level == 0) {
|
||||
return;
|
||||
}
|
||||
unsigned previous_level = level - 1;
|
||||
|
||||
|
||||
As.push_back(pt.get_propagation_formula(m_ctx.get_pred_transformers(), level));
|
||||
As.push_back(node.state());
|
||||
As.push_back(pt.rule2tag(m_current_rule));
|
||||
|
@ -296,28 +318,42 @@ namespace pdr {
|
|||
|
||||
{
|
||||
datalog::scoped_no_proof _no_proof(m);
|
||||
quantifier_ref q(m);
|
||||
scoped_ptr<expr_replacer> rep = mk_default_expr_replacer(m);
|
||||
for (unsigned j = 0; j < qis->size(); ++j) {
|
||||
quantifier* q = (*qis)[j].get();
|
||||
q = (*qis)[j].get();
|
||||
app_ref_vector& inst = pt.get_inst(m_current_rule);
|
||||
ptr_vector<app>& aux_vars = pt.get_aux_vars(*m_current_rule);
|
||||
TRACE("pdr",
|
||||
tout << "q:\n" << mk_pp(q, m) << "\n";
|
||||
tout << "level: " << level << "\n";
|
||||
model_smt2_pp(tout, m, node.get_model(), 0);
|
||||
m_current_rule->display(m_ctx.get_context(), tout << "rule:\n");
|
||||
|
||||
);
|
||||
|
||||
var_subst vs(m, false);
|
||||
vs(q, inst.size(), (expr*const*)inst.c_ptr(), B);
|
||||
q = to_quantifier(B);
|
||||
TRACE("pdr", tout << "q instantiated:\n" << mk_pp(q, m) << "\n";);
|
||||
|
||||
app* a = to_app(q->get_expr());
|
||||
func_decl* f = a->get_decl();
|
||||
pred_transformer& pt2 = m_ctx.get_pred_transformer(f);
|
||||
B = pt2.get_formulas(previous_level, true);
|
||||
TRACE("pdr", tout << "B:\n" << mk_pp(B, m) << "\n";);
|
||||
|
||||
|
||||
expr_substitution sub(m);
|
||||
expr_ref_vector refs(m);
|
||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||
expr* v = m.mk_const(pm.o2n(pt2.sig(i),0));
|
||||
v = m.mk_const(pm.o2n(pt2.sig(i),0));
|
||||
sub.insert(v, a->get_arg(i));
|
||||
refs.push_back(v);
|
||||
}
|
||||
rep->set_substitution(&sub);
|
||||
(*rep)(B);
|
||||
app_ref_vector& inst = pt.get_inst(m_current_rule);
|
||||
ptr_vector<app>& aux_vars = pt.get_aux_vars(*m_current_rule);
|
||||
pt.ground_free_vars(B, inst, aux_vars);
|
||||
var_subst vs(m, false);
|
||||
vs(B, inst.size(), (expr*const*)inst.c_ptr(), B);
|
||||
TRACE("pdr", tout << "B substituted:\n" << mk_pp(B, m) << "\n";);
|
||||
|
||||
B = m.update_quantifier(q, B);
|
||||
m_Bs.push_back(B);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -28,6 +28,7 @@ Revision History:
|
|||
#include "trace.h"
|
||||
#include "vector.h"
|
||||
#include "arith_decl_plugin.h"
|
||||
#include "array_decl_plugin.h"
|
||||
#include "bv_decl_plugin.h"
|
||||
|
||||
|
||||
|
@ -56,6 +57,7 @@ namespace pdr {
|
|||
class model_evaluator {
|
||||
ast_manager& m;
|
||||
arith_util m_arith;
|
||||
array_util m_array;
|
||||
obj_map<expr,rational> m_numbers;
|
||||
expr_ref_vector m_refs;
|
||||
obj_map<expr, expr*> m_values;
|
||||
|
@ -78,7 +80,8 @@ namespace pdr {
|
|||
expr_ref_vector prune_by_cone_of_influence(ptr_vector<expr> const & formulas);
|
||||
void eval_arith(app* e);
|
||||
void eval_basic(app* e);
|
||||
void eval_iff(app* e, expr* arg1, expr* arg2);
|
||||
void eval_eq(app* e, expr* arg1, expr* arg2);
|
||||
void eval_array_eq(app* e, expr* arg1, expr* arg2);
|
||||
void inherit_value(expr* e, expr* v);
|
||||
|
||||
inline bool is_unknown(expr* x) { return !m1.is_marked(x) && !m2.is_marked(x); }
|
||||
|
@ -99,9 +102,11 @@ namespace pdr {
|
|||
inline void set_value(expr* x, expr* v) { set_v(x); m_refs.push_back(v); m_values.insert(x, v); }
|
||||
|
||||
bool check_model(ptr_vector<expr> const & formulas);
|
||||
|
||||
bool extract_array_func_interp(expr* a, vector<expr_ref_vector>& stores, expr_ref else_case);
|
||||
|
||||
public:
|
||||
model_evaluator(ast_manager& m) : m(m), m_arith(m), m_refs(m) {}
|
||||
model_evaluator(ast_manager& m) : m(m), m_arith(m), m_array(m), m_refs(m) {}
|
||||
|
||||
/**
|
||||
\brief extract equalities from model that suffice to satisfy formula.
|
||||
|
@ -118,13 +123,12 @@ namespace pdr {
|
|||
*/
|
||||
expr_ref_vector minimize_literals(ptr_vector<expr> const & formulas, model_ref& mdl);
|
||||
|
||||
|
||||
// for_each_expr visitor.
|
||||
/**
|
||||
for_each_expr visitor.
|
||||
*/
|
||||
void operator()(expr* e) {}
|
||||
};
|
||||
|
||||
void get_value_from_model(const model_core & mdl, func_decl * f, expr_ref& res);
|
||||
|
||||
/**
|
||||
\brief replace variables that are used in many disequalities by
|
||||
an equality using the model.
|
||||
|
|
Loading…
Reference in a new issue