3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-10-25 08:54:35 +00:00

add option to validate result of PDR. Add PDR tactic. Add fixedpoint parsing

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2012-11-17 20:47:49 +01:00
parent 68ae5d434c
commit 50385e7e29
32 changed files with 836 additions and 393 deletions

View file

@ -1096,6 +1096,10 @@ namespace datalog {
m_solver.collect_statistics(st);
}
void bmc::reset_statistics() {
m_solver.reset_statistics();
}
void bmc::collect_params(param_descrs& p) {
}

View file

@ -127,6 +127,8 @@ namespace datalog {
void collect_statistics(statistics& st) const;
void reset_statistics();
expr_ref get_answer();
static void collect_params(param_descrs& p);

View file

@ -28,20 +28,25 @@ Notes:
#include"cancel_eh.h"
#include"scoped_ctrl_c.h"
#include"scoped_timer.h"
#include"trail.h"
#include<iomanip>
class dl_context {
cmd_context & m_cmd;
dl_collected_cmds* m_collected_cmds;
unsigned m_ref_count;
datalog::dl_decl_plugin* m_decl_plugin;
scoped_ptr<datalog::context> m_context;
scoped_ptr<datalog::context> m_context;
trail_stack<dl_context> m_trail;
public:
dl_context(cmd_context & ctx):
dl_context(cmd_context & ctx, dl_collected_cmds* collected_cmds):
m_cmd(ctx),
m_collected_cmds(collected_cmds),
m_ref_count(0),
m_decl_plugin(0) {}
m_decl_plugin(0),
m_trail(*this) {}
void inc_ref() {
++m_ref_count;
@ -74,14 +79,53 @@ public:
void reset() {
m_context = 0;
}
void register_predicate(func_decl* pred, unsigned num_kinds, symbol const* kinds) {
if (m_collected_cmds) {
m_collected_cmds->m_rels.push_back(pred);
m_trail.push(push_back_vector<dl_context, func_decl_ref_vector>(m_collected_cmds->m_rels));
}
dlctx().register_predicate(pred, false);
dlctx().set_predicate_representation(pred, num_kinds, kinds);
}
void add_rule(expr * rule, symbol const& name) {
init();
std::string error_msg;
m_context->add_rule(rule, name);
if (m_collected_cmds) {
expr_ref rl = m_context->bind_variables(rule, true);
m_collected_cmds->m_rules.push_back(rl);
m_collected_cmds->m_names.push_back(name);
m_trail.push(push_back_vector<dl_context, expr_ref_vector>(m_collected_cmds->m_rules));
m_trail.push(push_back_vector<dl_context, svector<symbol> >(m_collected_cmds->m_names));
}
else {
m_context->add_rule(rule, name);
}
}
bool collect_query(expr* q) {
if (m_collected_cmds) {
expr_ref qr = m_context->bind_variables(q, false);
m_collected_cmds->m_queries.push_back(qr);
m_trail.push(push_back_vector<dl_context, expr_ref_vector>(m_collected_cmds->m_queries));
return true;
}
else {
return false;
}
}
void push() {
m_trail.push_scope();
dlctx().push();
}
void pop() {
m_trail.pop_scope(1);
dlctx().pop();
}
datalog::context & get_dl_context() {
datalog::context & dlctx() {
init();
return *m_context;
}
@ -160,7 +204,10 @@ public:
if (m_target == 0) {
throw cmd_exception("invalid query command, argument expected");
}
datalog::context& dlctx = m_dl_ctx->get_dl_context();
if (m_dl_ctx->collect_query(m_target)) {
return;
}
datalog::context& dlctx = m_dl_ctx->dlctx();
set_background(ctx);
dlctx.updt_params(m_params);
unsigned timeout = m_params.get_uint(":timeout", UINT_MAX);
@ -217,7 +264,7 @@ public:
}
virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) {
m_dl_ctx->get_dl_context().collect_params(p);
m_dl_ctx->dlctx().collect_params(p);
insert_timeout(p);
p.insert(":print-answer", CPK_BOOL, "(default: false) print answer instance(s) to query.");
p.insert(":print-certificate", CPK_BOOL, "(default: false) print certificate for reachability or non-reachability.");
@ -227,7 +274,7 @@ public:
private:
void set_background(cmd_context& ctx) {
datalog::context& dlctx = m_dl_ctx->get_dl_context();
datalog::context& dlctx = m_dl_ctx->dlctx();
ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
ptr_vector<expr>::const_iterator end = ctx.end_assertions();
for (; it != end; ++it) {
@ -237,7 +284,7 @@ private:
void print_answer(cmd_context& ctx) {
if (m_params.get_bool(":print-answer", false)) {
datalog::context& dlctx = m_dl_ctx->get_dl_context();
datalog::context& dlctx = m_dl_ctx->dlctx();
ast_manager& m = ctx.m();
expr_ref query_result(dlctx.get_answer_as_formula(), m);
sbuffer<symbol> var_names;
@ -253,7 +300,7 @@ private:
void print_statistics(cmd_context& ctx) {
if (m_params.get_bool(":print-statistics", false)) {
statistics st;
datalog::context& dlctx = m_dl_ctx->get_dl_context();
datalog::context& dlctx = m_dl_ctx->dlctx();
unsigned long long max_mem = memory::get_max_used_memory();
unsigned long long mem = memory::get_allocation_size();
dlctx.collect_statistics(st);
@ -266,7 +313,7 @@ private:
void print_certificate(cmd_context& ctx) {
if (m_params.get_bool(":print-certificate", false)) {
datalog::context& dlctx = m_dl_ctx->get_dl_context();
datalog::context& dlctx = m_dl_ctx->dlctx();
if (!dlctx.display_certificate(ctx.regular_stream())) {
throw cmd_exception("certificates are not supported for selected DL_ENGINE");
}
@ -286,6 +333,7 @@ class dl_declare_rel_cmd : public cmd {
void ensure_domain(cmd_context& ctx) {
if (!m_domain) m_domain = alloc(sort_ref_vector, ctx.m());
}
public:
dl_declare_rel_cmd(dl_context * dl_ctx):
cmd("declare-rel"),
@ -334,11 +382,7 @@ public:
func_decl_ref pred(
m.mk_func_decl(m_rel_name, m_domain->size(), m_domain->c_ptr(), m.mk_bool_sort()), m);
ctx.insert(pred);
datalog::context& dctx = m_dl_ctx->get_dl_context();
dctx.register_predicate(pred, false);
if(!m_kinds.empty()) {
dctx.set_predicate_representation(pred, m_kinds.size(), m_kinds.c_ptr());
}
m_dl_ctx->register_predicate(pred, m_kinds.size(), m_kinds.c_ptr());
m_domain = 0;
}
@ -385,7 +429,7 @@ public:
ast_manager& m = ctx.m();
func_decl_ref var(m.mk_func_decl(m_var_name, 0, static_cast<sort*const*>(0), m_var_sort), m);
ctx.insert(var);
m_dl_ctx->get_dl_context().register_variable(var);
m_dl_ctx->dlctx().register_variable(var);
}
};
@ -402,7 +446,7 @@ public:
virtual char const * get_descr(cmd_context & ctx) const { return "push context on the fixedpoint engine"; }
virtual void execute(cmd_context& ctx) {
m_ctx->get_dl_context().push();
m_ctx->push();
}
};
@ -418,19 +462,24 @@ public:
virtual char const * get_descr(cmd_context & ctx) const { return "pop context on the fixedpoint engine"; }
virtual void execute(cmd_context& ctx) {
m_ctx->get_dl_context().pop();
m_ctx->pop();
}
};
void install_dl_cmds(cmd_context & ctx) {
dl_context * dl_ctx = alloc(dl_context, ctx);
static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_cmds) {
dl_context * dl_ctx = alloc(dl_context, ctx, collected_cmds);
ctx.insert(alloc(dl_rule_cmd, dl_ctx));
ctx.insert(alloc(dl_query_cmd, dl_ctx));
ctx.insert(alloc(dl_declare_rel_cmd, dl_ctx));
ctx.insert(alloc(dl_declare_var_cmd, dl_ctx));
PRIVATE_PARAMS(ctx.insert(alloc(dl_push_cmd, dl_ctx));); // not exposed to keep command-extensions simple.
PRIVATE_PARAMS(ctx.insert(alloc(dl_pop_cmd, dl_ctx)););
PRIVATE_PARAMS(ctx.insert(alloc(dl_pop_cmd, dl_ctx)););
}
void install_dl_cmds(cmd_context & ctx) {
install_dl_cmds_aux(ctx, 0);
}
void install_dl_collect_cmds(dl_collected_cmds& collected_cmds, cmd_context & ctx) {
install_dl_cmds_aux(ctx, &collected_cmds);
}

View file

@ -10,7 +10,7 @@ Abstract:
Author:
Leonardo (leonardo) 2011-03-28
Nikolaj Bjorner (nbjorner) 2012-11-17
Notes:
@ -18,30 +18,20 @@ Notes:
#ifndef _DL_CMDS_H_
#define _DL_CMDS_H_
class cmd;
#include "ast.h"
class cmd_context;
struct dl_collected_cmds {
expr_ref_vector m_rules;
svector<symbol> m_names;
expr_ref_vector m_queries;
func_decl_ref_vector m_rels;
dl_collected_cmds(ast_manager& m) : m_rules(m), m_queries(m), m_rels(m) {}
};
void install_dl_cmds(cmd_context & ctx);
void install_dl_collect_cmds(dl_collected_cmds& collected_cmds, cmd_context& ctx);
namespace datalog {
class context;
/**
Create a command for declaring relations which is connected to
a particular datalog context.
Caller must ensure the returned object is deallocated (e.g. by passing it to a cmd_context).
*/
cmd * mk_declare_rel_cmd(context& dctx);
/**
Declare a constant as a universal/existential variable.
It is implicitly existentially or universally quantified
by the rules.
*/
cmd * mk_declare_var_cmd(context& dctx);
}
#endif

View file

@ -49,11 +49,14 @@ Revision History:
#include"dl_skip_table.h"
#endif
#include"for_each_expr.h"
#include"ast_smt_pp.h"
#include"ast_smt2_pp.h"
#include"expr_functors.h"
#include"dl_mk_partial_equiv.h"
#include"dl_mk_bit_blast.h"
#include"datatype_decl_plugin.h"
#include"expr_abstract.h"
namespace datalog {
@ -331,8 +334,39 @@ namespace datalog {
m_vars.push_back(m.mk_const(var));
}
expr_ref context::bind_variables(expr* fml, bool is_forall) {
expr_ref result(m);
app_ref_vector const& vars = m_vars;
if (vars.empty()) {
result = fml;
}
else {
ptr_vector<sort> sorts;
expr_abstract(m, 0, vars.size(), reinterpret_cast<expr*const*>(vars.c_ptr()), fml, result);
get_free_vars(result, sorts);
if (sorts.empty()) {
result = fml;
}
else {
svector<symbol> names;
for (unsigned i = 0; i < sorts.size(); ++i) {
if (!sorts[i]) {
sorts[i] = m.mk_bool_sort();
}
names.push_back(symbol(i));
}
quantifier_ref q(m);
q = m.mk_quantifier(is_forall, sorts.size(), sorts.c_ptr(), names.c_ptr(), result);
elim_unused_vars(m, q, result);
}
}
return result;
}
void context::register_predicate(func_decl * decl, bool named) {
SASSERT(!m_preds.contains(decl));
if (m_preds.contains(decl)) {
return;
}
m_pinned.push_back(decl);
m_preds.insert(decl);
if (named) {
@ -429,57 +463,35 @@ namespace datalog {
}
void context::set_predicate_representation(func_decl * pred, unsigned relation_name_cnt,
symbol * const relation_names) {
symbol const * relation_names) {
relation_manager & rmgr = get_rmanager();
family_id target_kind = null_family_id;
if (relation_name_cnt==1) {
switch (relation_name_cnt) {
case 0:
return;
case 1:
target_kind = get_ordinary_relation_plugin(relation_names[0]).get_kind();
} else {
relation_plugin * tr_plugin = 0; //table plugin, if there is such
ptr_vector<relation_plugin> rel_plugins; //plugins that are not table plugins
svector<family_id> rel_kinds; //kinds of plugins that are not table plugins
for (unsigned i=0; i<relation_name_cnt; i++) {
break;
default: {
svector<family_id> rel_kinds; // kinds of plugins that are not table plugins
family_id rel_kind; // the aggregate kind of non-table plugins
for (unsigned i = 0; i < relation_name_cnt; i++) {
relation_plugin & p = get_ordinary_relation_plugin(relation_names[i]);
//commented out, because support combining relations with tables using fpr is not yet implemented
/*if (p.from_table()) {
if (tr_plugin) {
//it does not give any extra benefit to have an intersection of two tables.
//Maybe when we can specify which columns belong to which plugin,
//it might be of use.
throw default_exception("two table plugins cannot be specified as relation type");
}
tr_plugin = &p;
}
else {*/
rel_plugins.push_back(&p);
rel_kinds.push_back(p.get_kind());
/*}*/
rel_kinds.push_back(p.get_kind());
}
SASSERT(!rel_kinds.empty());
// relation_plugin * rel_plugin; //the aggregate kind of non-table plugins
family_id rel_kind; //the aggregate kind of non-table plugins
if (rel_kinds.size()==1) {
if (rel_kinds.size() == 1) {
rel_kind = rel_kinds[0];
// rel_plugin = rel_plugins[0];
}
else {
relation_signature rel_sig;
//rmgr.from_predicate(pred, rel_sig);
product_relation_plugin & prod_plugin = product_relation_plugin::get_plugin(rmgr);
rel_kind = prod_plugin.get_relation_kind(rel_sig, rel_kinds);
// rel_plugin = &prod_plugin;
}
if (tr_plugin==0) {
target_kind = rel_kind;
}
else {
NOT_IMPLEMENTED_YET();
#if 0
finite_product_relation_plugin & fprp = finite_product_relation_plugin::get_plugin(rmgr, *rel_plugin);
finite_product_relation_plugin::rel_spec spec;
#endif
}
target_kind = rel_kind;
break;
}
}
SASSERT(target_kind != null_family_id);
@ -958,7 +970,8 @@ namespace datalog {
p.insert(":output-profile", CPK_BOOL, "determines whether profile informations should be output when outputting Datalog rules or instructions");
p.insert(":output-tuples", CPK_BOOL, "determines whether tuples for output predicates should be output");
p.insert(":profile-timeout-milliseconds", CPK_UINT, "instructions and rules that took less than the threshold will not be printed when printed the instruction/rule list");
p.insert(":print-with-fixedpoint-extensions", CPK_BOOL, "(default true) use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, when printing rules");
PRIVATE_PARAMS(
p.insert(":dbg-fpr-nonempty-relation-signature", CPK_BOOL,
"if true, finite_product_relation will attempt to avoid creating inner relation with empty signature "
@ -1198,7 +1211,6 @@ namespace datalog {
case DATALOG_ENGINE:
return dl_query(query);
case PDR_ENGINE:
return pdr_query(query);
case QPDR_ENGINE:
return pdr_query(query);
case BMC_ENGINE:
@ -1219,6 +1231,28 @@ namespace datalog {
m_last_answer = get_manager().mk_true();
}
model_ref context::get_model() {
switch(get_engine()) {
case PDR_ENGINE:
case QPDR_ENGINE:
ensure_pdr();
return m_pdr->get_model();
default:
return model_ref(alloc(model, m));
}
}
proof_ref context::get_proof() {
switch(get_engine()) {
case PDR_ENGINE:
case QPDR_ENGINE:
ensure_pdr();
return m_pdr->get_proof();
default:
return proof_ref(m.mk_asserted(m.mk_true()), m);
}
}
void context::ensure_pdr() {
if (!m_pdr.get()) {
m_pdr = alloc(pdr::dl_interface, *this);
@ -1479,13 +1513,12 @@ namespace datalog {
case DATALOG_ENGINE:
return false;
case PDR_ENGINE:
m_pdr->display_certificate(out);
return true;
case QPDR_ENGINE:
ensure_pdr();
m_pdr->display_certificate(out);
return true;
case BMC_ENGINE:
case QBMC_ENGINE:
ensure_bmc();
m_bmc->display_certificate(out);
return true;
default:
@ -1493,20 +1526,31 @@ namespace datalog {
}
}
void context::reset_statistics() {
if (m_pdr) {
m_pdr->reset_statistics();
}
if (m_bmc) {
m_bmc->reset_statistics();
}
}
void context::collect_statistics(statistics& st) {
switch(get_engine()) {
void context::collect_statistics(statistics& st) const {
switch(m_engine) {
case DATALOG_ENGINE:
break;
case PDR_ENGINE:
m_pdr->collect_statistics(st);
break;
case QPDR_ENGINE:
m_pdr->collect_statistics(st);
if (m_pdr) {
m_pdr->collect_statistics(st);
}
break;
case BMC_ENGINE:
case QBMC_ENGINE:
m_bmc->collect_statistics(st);
if (m_bmc) {
m_bmc->collect_statistics(st);
}
break;
default:
break;
@ -1564,6 +1608,7 @@ namespace datalog {
expr* const* axioms = m_background.c_ptr();
expr_ref fml(m);
expr_ref_vector rules(m);
bool use_fixedpoint_extensions = m_params.get_bool(":print-with-fixedpoint-extensions", true);
{
rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end();
for (; it != end; ++it) {
@ -1586,13 +1631,17 @@ namespace datalog {
if (f->get_family_id() != null_family_id) {
//
}
else if (is_predicate(f)) {
else if (is_predicate(f) && use_fixedpoint_extensions) {
rels.insert(f);
}
else {
funcs.insert(f);
}
}
if (!use_fixedpoint_extensions) {
out << "(set-logic HORN)\n";
}
it = funcs.begin(), end = funcs.end();
@ -1619,23 +1668,44 @@ namespace datalog {
out << "))\n";
}
declare_vars(rules, fresh_names, out);
if (use_fixedpoint_extensions) {
declare_vars(rules, fresh_names, out);
}
for (unsigned i = 0; i < num_axioms; ++i) {
SASSERT(use_fixedpoint_extensions);
out << "(assert ";
ast_smt2_pp(out, axioms[i], env, params);
out << ")\n";
}
for (unsigned i = 0; i < rules.size(); ++i) {
out << "(rule ";
ast_smt2_pp(out, rules[i].get(), env, params);
for (unsigned i = 0; i < rules.size(); ++i) {
out << (use_fixedpoint_extensions?"(rule ":"(assert ");
if (use_fixedpoint_extensions) {
ast_smt2_pp(out, rules[i].get(), env, params);
}
else {
out << mk_smt_pp(rules[i].get(), m);
}
out << ")\n";
}
for (unsigned i = 0; i < num_queries; ++i) {
out << "(query ";
ast_smt2_pp(out, queries[i], env, params);
out << ")\n";
if (use_fixedpoint_extensions) {
for (unsigned i = 0; i < num_queries; ++i) {
out << "(query ";
ast_smt2_pp(out, queries[i], env, params);
out << ")\n";
}
}
else {
for (unsigned i = 0; i < num_queries; ++i) {
if (num_queries > 1) out << "(push)\n";
out << "(assert ";
expr_ref q(m);
q = m.mk_not(queries[i]);
ast_smt2_pp(out, q, env, params);
out << ")\n";
out << "(check-sat)\n";
if (num_queries > 1) out << "(pop)\n";
}
}
}

View file

@ -184,7 +184,7 @@ namespace datalog {
void register_variable(func_decl* var);
app_ref_vector const& get_variables() const { return m_vars; }
expr_ref bind_variables(expr* fml, bool is_forall);
/**
Register datalog relation.
@ -242,7 +242,7 @@ namespace datalog {
symbol get_argument_name(const func_decl * pred, unsigned arg_index);
void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt,
symbol * const relation_names);
symbol const * relation_names);
void set_output_predicate(func_decl * pred);
bool is_output_predicate(func_decl * pred) { return m_output_preds.contains(pred); }
@ -383,6 +383,21 @@ namespace datalog {
lbool query(expr* q);
/**
\brief retrieve model from inductive invariant that shows query is unsat.
\pre engine == 'pdr' - this option is only supported for PDR mode.
*/
model_ref get_model();
/**
\brief retrieve proof from derivation of the query.
\pre engine == 'pdr' - this option is only supported for PDR mode.
*/
proof_ref get_proof();
/**
Query multiple output relations.
*/
@ -411,7 +426,9 @@ namespace datalog {
expr* get_answer_as_formula();
void collect_statistics(statistics& st);
void collect_statistics(statistics& st) const;
void reset_statistics();
/**
\brief Display a certificate for reachability and/or unreachability.

View file

@ -116,16 +116,20 @@ namespace datalog {
apply(src, false, UINT_MAX, tail, tail_neg);
mk_rule_inliner::remove_duplicate_tails(tail, tail_neg);
SASSERT(tail.size()==tail_neg.size());
res = m_rm.mk(new_head, tail.size(), tail.c_ptr(), tail_neg.c_ptr());
res = m_rm.mk(new_head, tail.size(), tail.c_ptr(), tail_neg.c_ptr(), tgt.name(), m_normalize);
res->set_accounting_parent_object(m_context, const_cast<rule*>(&tgt));
res->norm_vars(m_rm);
m_rm.fix_unbound_vars(res, true);
if (m_interp_simplifier.transform_rule(res.get(), simpl_rule)) {
res = simpl_rule;
return true;
if (m_normalize) {
m_rm.fix_unbound_vars(res, true);
if (m_interp_simplifier.transform_rule(res.get(), simpl_rule)) {
res = simpl_rule;
return true;
}
else {
return false;
}
}
else {
return false;
return true;
}
}

View file

@ -38,11 +38,12 @@ namespace datalog {
substitution m_subst;
unifier m_unif;
bool m_ready;
bool m_normalize;
unsigned m_deltas[2];
public:
rule_unifier(context& ctx)
: m(ctx.get_manager()), m_rm(ctx.get_rule_manager()), m_context(ctx),
m_interp_simplifier(ctx), m_subst(m), m_unif(m), m_ready(false) {}
m_interp_simplifier(ctx), m_subst(m), m_unif(m), m_ready(false), m_normalize(true) {}
/** Reset subtitution and unify tail tgt_idx of the target rule and the head of the src rule */
bool unify_rules(rule const& tgt, unsigned tgt_idx, rule const& src);
@ -60,6 +61,13 @@ namespace datalog {
*/
expr_ref_vector get_rule_subst(rule const& r, bool is_tgt);
/**
Control if bound variables are normalized after unification.
The default is 'true': bound variables are re-mapped to an
initial segment of de-Bruijn indices.
*/
void set_normalize(bool n) { m_normalize = n; }
private:
void apply(app * a, bool is_tgt, app_ref& res);

View file

@ -33,7 +33,6 @@ Revision History:
#include"for_each_expr.h"
#include"used_vars.h"
#include"var_subst.h"
#include"expr_abstract.h"
#include"rewriter_def.h"
#include"th_rewriter.h"
#include"ast_smt2_pp.h"
@ -291,30 +290,7 @@ namespace datalog {
}
void rule_manager::bind_variables(expr* fml, bool is_forall, expr_ref& result) {
app_ref_vector const& vars = m_ctx.get_variables();
if (vars.empty()) {
result = fml;
}
else {
ptr_vector<sort> sorts;
expr_abstract(m, 0, vars.size(), reinterpret_cast<expr*const*>(vars.c_ptr()), fml, result);
get_free_vars(result, sorts);
if (sorts.empty()) {
result = fml;
}
else {
svector<symbol> names;
for (unsigned i = 0; i < sorts.size(); ++i) {
if (!sorts[i]) {
sorts[i] = m.mk_bool_sort();
}
names.push_back(symbol(i));
}
quantifier_ref q(m);
q = m.mk_quantifier(is_forall, sorts.size(), sorts.c_ptr(), names.c_ptr(), result);
elim_unused_vars(m, q, result);
}
}
result = m_ctx.bind_variables(fml, is_forall);
}
void rule_manager::flatten_body(app_ref_vector& body) {
@ -526,7 +502,7 @@ namespace datalog {
}
}
rule * rule_manager::mk(app * head, unsigned n, app * const * tail, bool const * is_negated, symbol const& name) {
rule * rule_manager::mk(app * head, unsigned n, app * const * tail, bool const * is_negated, symbol const& name, bool normalize) {
DEBUG_CODE(check_valid_rule(head, n, tail););
unsigned sz = rule::get_obj_size(n);
void * mem = m.get_allocator().allocate(sz);
@ -588,7 +564,9 @@ namespace datalog {
r->m_positive_cnt = r->m_uninterp_cnt;
}
r->norm_vars(*this);
if (normalize) {
r->norm_vars(*this);
}
return r;
}
@ -823,7 +801,7 @@ namespace datalog {
new_tail.push_back(to_app(tmp));
tail_neg.push_back(r->is_neg_tail(i));
}
r = mk(new_head.get(), new_tail.size(), new_tail.c_ptr(), tail_neg.c_ptr(), r->name());
r = mk(new_head.get(), new_tail.size(), new_tail.c_ptr(), tail_neg.c_ptr(), r->name(), false);
// keep old variable indices around so we can compose with substitutions.
// r->norm_vars(*this);
@ -1068,24 +1046,25 @@ namespace datalog {
us(fml);
sorts.reverse();
for (unsigned i = 0; i < sorts.size(); ) {
for (unsigned i = 0; i < sorts.size(); ++i) {
if (!sorts[i]) {
sorts[i] = m.mk_bool_sort();
}
for (unsigned j = 0; i < sorts.size(); ++j) {
for (char c = 'A'; i < sorts.size() && c <= 'Z'; ++c) {
func_decl_ref f(m);
std::stringstream _name;
_name << c;
if (j > 0) _name << j;
symbol name(_name.str().c_str());
if (!us.contains(name)) {
names.push_back(name);
++i;
}
}
for (unsigned j = 0, i = 0; i < sorts.size(); ++j) {
for (char c = 'A'; i < sorts.size() && c <= 'Z'; ++c) {
func_decl_ref f(m);
std::stringstream _name;
_name << c;
if (j > 0) _name << j;
symbol name(_name.str().c_str());
if (!us.contains(name)) {
names.push_back(name);
++i;
}
}
}
}
fml = m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), fml);
}

View file

@ -116,7 +116,7 @@ namespace datalog {
\remark A tail may contain negation. tail[i] is assumed to be negated if is_neg != 0 && is_neg[i] == true
*/
rule * mk(app * head, unsigned n, app * const * tail, bool const * is_neg = 0,
symbol const& name = symbol::null);
symbol const& name = symbol::null, bool normalize = true);
/**
\brief Create a rule with the same tail as \c source and with a specified head.
@ -252,7 +252,7 @@ namespace datalog {
std::ostream& display_smt2(ast_manager& m, std::ostream & out) const;
symbol const& name() { return m_name; }
symbol const& name() const { return m_name; }
unsigned hash() const;

View file

@ -20,9 +20,6 @@ Revision History:
Notes:
TODO:
- fix the slicing with covers.
-
--*/
@ -100,6 +97,13 @@ namespace pdr {
np += m_levels[i].size();
}
st.update("PDR num properties", np);
std::cout << m_stats.m_num_propagations << " " << np << "\n";
}
void pred_transformer::reset_statistics() {
m_solver.reset_statistics();
m_reachable.reset_statistics();
m_stats.reset();
}
void pred_transformer::init_sig() {
@ -971,6 +975,7 @@ namespace pdr {
proof_ref_vector trail(m);
datalog::rule_ref_vector rules_trail(rm);
proof* pr = 0;
unifier.set_normalize(false);
todo.push_back(m_root);
while (!todo.empty()) {
model_node* n = todo.back();
@ -1022,6 +1027,7 @@ namespace pdr {
binding_is_id = is_var(v) && to_var(v)->get_idx() == i;
}
if (rls.size() > 1 || !binding_is_id) {
expr_ref tmp(m);
vector<expr_ref_vector> substs;
svector<std::pair<unsigned,unsigned> > positions;
substs.push_back(binding); // TODO base substitution.
@ -1029,9 +1035,10 @@ namespace pdr {
datalog::rule& src = *rls[i];
bool unified = unifier.unify_rules(*reduced_rule, 0, src);
if (!unified) {
std::cout << "Could not unify rules: ";
reduced_rule->display(dctx, std::cout);
src.display(dctx, std::cout);
IF_VERBOSE(0,
verbose_stream() << "Could not unify rules: ";
reduced_rule->display(dctx, verbose_stream());
src.display(dctx, verbose_stream()););
}
expr_ref_vector sub1 = unifier.get_rule_subst(*reduced_rule, true);
TRACE("pdr",
@ -1040,8 +1047,15 @@ namespace pdr {
}
tout << "\n";
);
for (unsigned j = 0; j < substs.size(); ++j) {
// TODO. apply sub1 to subst.
for (unsigned k = 0; k < substs[j].size(); ++k) {
var_subst(m, false)(substs[j][k].get(), sub1.size(), sub1.c_ptr(), tmp);
substs[j][k] = tmp;
}
while (substs[j].size() < sub1.size()) {
substs[j].push_back(sub1[substs[j].size()].get());
}
}
positions.push_back(std::make_pair(i,0));
@ -1049,9 +1063,11 @@ namespace pdr {
VERIFY(unifier.apply(*reduced_rule.get(), 0, src, r3));
reduced_rule = r3;
}
expr_ref fml_concl(m);
reduced_rule->to_formula(fml_concl);
p1 = m.mk_hyper_resolve(pfs.size(), pfs.c_ptr(), fml_concl, positions, substs);
}
cache.insert(n->state(), p1);
rules.insert(n->state(), reduced_rule);
@ -1334,24 +1350,68 @@ namespace pdr {
if (!ok) {
IF_VERBOSE(0, verbose_stream() << "proof validation failed\n";);
}
for (unsigned i = 0; i < side_conditions.size(); ++i) {
expr* cond = side_conditions[i].get();
expr_ref tmp(m);
tmp = m.mk_not(cond);
IF_VERBOSE(2, verbose_stream() << "checking side-condition:\n" << mk_pp(cond, m) << "\n";);
smt::kernel solver(m, get_fparams());
solver.assert_expr(tmp);
lbool res = solver.check();
if (res != l_false) {
IF_VERBOSE(0, verbose_stream() << "rule validation failed\n";
verbose_stream() << mk_pp(cond, m) << "\n";
);
}
}
break;
}
case l_false: {
expr_ref_vector refs(m);
expr_ref_vector refs(m), fmls(m);
expr_ref tmp(m);
model_ref model;
vector<relation_info> rs;
model_converter_ref mc;
get_level_property(m_inductive_lvl, refs, rs);
inductive_property ex(m, const_cast<model_converter_ref&>(m_mc), rs);
inductive_property ex(m, mc, rs);
ex.to_model(model);
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
var_subst vs(m, false);
var_subst vs(m, false);
for (; it != end; ++it) {
ptr_vector<datalog::rule> const& rules = it->m_value->rules();
for (unsigned i = 0; i < rules.size(); ++i) {
// datalog::rule* rule = rules[i];
// vs(rule->get_head(),
// apply interpretation of predicates to rule.
// create formula and check for unsat.
datalog::rule& r = *rules[i];
model->eval(r.get_head(), tmp);
fmls.push_back(m.mk_not(tmp));
unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size();
for (unsigned j = 0; j < utsz; ++j) {
model->eval(r.get_tail(j), tmp);
fmls.push_back(tmp);
}
for (unsigned j = utsz; j < tsz; ++j) {
fmls.push_back(r.get_tail(j));
}
tmp = m.mk_and(fmls.size(), fmls.c_ptr());
ptr_vector<sort> sorts;
svector<symbol> names;
get_free_vars(tmp, sorts);
for (unsigned i = 0; i < sorts.size(); ++i) {
if (!sorts[i]) {
sorts[i] = m.mk_bool_sort();
}
names.push_back(symbol(i));
}
sorts.reverse();
tmp = m.mk_exists(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp);
smt::kernel solver(m, get_fparams());
solver.assert_expr(tmp);
lbool res = solver.check();
if (res != l_false) {
IF_VERBOSE(0, verbose_stream() << "rule validation failed\n";
verbose_stream() << mk_pp(tmp, m) << "\n";
);
}
}
}
break;
@ -1476,13 +1536,15 @@ namespace pdr {
}
}
void context::get_model(model_ref& md) {
model_ref context::get_model() {
SASSERT(m_last_result == l_false);
expr_ref_vector refs(m);
vector<relation_info> rs;
model_ref md;
get_level_property(m_inductive_lvl, refs, rs);
inductive_property ex(m, m_mc, rs);
ex.to_model(md);
return md;
}
proof_ref context::get_proof() const {
@ -1870,6 +1932,20 @@ namespace pdr {
}
}
void context::reset_statistics() {
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
for (it = m_rels.begin(); it != end; ++it) {
it->m_value->reset_statistics();
}
m_stats.reset();
m_pm.reset_statistics();
for (unsigned i = 0; i < m_core_generalizers.size(); ++i) {
m_core_generalizers[i]->reset_statistics();
}
}
std::ostream& context::display(std::ostream& out) const {
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();

View file

@ -132,6 +132,7 @@ namespace pdr {
std::ostream& display(std::ostream& strm) const;
void collect_statistics(statistics& st) const;
void reset_statistics();
bool is_reachable(expr* state);
void remove_predecessors(expr_ref_vector& literals);
@ -275,6 +276,7 @@ namespace pdr {
}
}
virtual void collect_statistics(statistics& st) const {}
virtual void reset_statistics() {}
};
class context {
@ -366,6 +368,7 @@ namespace pdr {
void collect_statistics(statistics& st) const;
void reset_statistics();
std::ostream& display(std::ostream& strm) const;
@ -401,7 +404,7 @@ namespace pdr {
void add_cover(int level, func_decl* pred, expr* property);
void get_model(model_ref& md);
model_ref get_model();
proof_ref get_proof() const;

View file

@ -197,6 +197,10 @@ void dl_interface::collect_statistics(statistics& st) const {
m_context->collect_statistics(st);
}
void dl_interface::reset_statistics() {
m_context->reset_statistics();
}
void dl_interface::display_certificate(std::ostream& out) const {
m_context->display_certificate(out);
}
@ -218,6 +222,14 @@ void dl_interface::updt_params() {
m_context = alloc(pdr::context, m_ctx.get_fparams(), m_ctx.get_params(), m_ctx.get_manager());
}
model_ref dl_interface::get_model() {
return m_context->get_model();
}
proof_ref dl_interface::get_proof() {
return m_context->get_proof();
}
void dl_interface::collect_params(param_descrs& p) {
p.insert(":bfs-model-search", CPK_BOOL, "PDR: (default true) use BFS strategy for expanding model search");
p.insert(":use-farkas", CPK_BOOL, "PDR: (default true) use lemma generator based on Farkas (for linear real arithmetic)");

View file

@ -57,6 +57,8 @@ namespace pdr {
void collect_statistics(statistics& st) const;
void reset_statistics();
expr_ref get_answer();
unsigned get_num_levels(func_decl* pred);
@ -66,8 +68,12 @@ namespace pdr {
void add_cover(int level, func_decl* pred, expr* property);
static void collect_params(param_descrs& p);
void updt_params();
model_ref get_model();
proof_ref get_proof();
};
}

View file

@ -313,6 +313,8 @@ namespace pdr {
pdr::smt_context* mk_fresh() { return m_contexts.mk_fresh(); }
void collect_statistics(statistics& st) const { m_contexts.collect_statistics(st); }
void reset_statistics() { m_contexts.reset_statistics(); }
};
}

View file

@ -364,8 +364,7 @@ namespace pdr {
m_core->append(lemmas);
}
lbool prop_solver::check_assumptions(const expr_ref_vector & atoms)
{
lbool prop_solver::check_assumptions(const expr_ref_vector & atoms) {
return check_assumptions_and_formula(atoms, m.mk_true());
}
@ -393,5 +392,10 @@ namespace pdr {
void prop_solver::collect_statistics(statistics& st) const {
}
void prop_solver::reset_statistics() {
}
}

View file

@ -122,6 +122,8 @@ namespace pdr {
expr * form);
void collect_statistics(statistics& st) const;
void reset_statistics();
};
}

View file

@ -27,9 +27,6 @@ namespace pdr {
m_ctx(0),
m_ref_holder(m),
m_disj_connector(m),
m_cache_hits(0),
m_cache_miss(0),
m_cache_inserts(0),
m_cache_mode((datalog::PDR_CACHE_MODE)params.get_uint(":cache-mode",0)) {
if (m_cache_mode == datalog::CONSTRAINT_CACHE) {
m_ctx = pm.mk_fresh();
@ -63,13 +60,13 @@ namespace pdr {
break;
case datalog::HASH_CACHE:
m_cache_inserts++;
m_stats.m_inserts++;
m_cache.insert(cube);
m_ref_holder.push_back(cube);
break;
case datalog::CONSTRAINT_CACHE:
m_cache_inserts++;
m_stats.m_inserts++;
TRACE("pdr", tout << mk_pp(cube, m) << "\n";);
add_disjuncted_formula(cube);
break;
@ -112,14 +109,18 @@ namespace pdr {
UNREACHABLE();
break;
}
if (found) m_cache_hits++; m_cache_miss++;
if (found) m_stats.m_hits++; m_stats.m_miss++;
return found;
}
void reachable_cache::collect_statistics(statistics& st) const {
st.update("cache inserts", m_cache_inserts);
st.update("cache miss", m_cache_miss);
st.update("cache hits", m_cache_hits);
st.update("cache inserts", m_stats.m_inserts);
st.update("cache miss", m_stats.m_miss);
st.update("cache hits", m_stats.m_hits);
}
void reachable_cache::reset_statistics() {
m_stats.reset();
}

View file

@ -28,15 +28,21 @@ Revision History:
namespace pdr {
class reachable_cache {
struct stats {
unsigned m_hits;
unsigned m_miss;
unsigned m_inserts;
stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
};
ast_manager & m;
manager & m_pm;
scoped_ptr<smt_context> m_ctx;
ast_ref_vector m_ref_holder;
app_ref m_disj_connector;
obj_hashtable<expr> m_cache;
unsigned m_cache_hits;
unsigned m_cache_miss;
unsigned m_cache_inserts;
stats m_stats;
datalog::PDR_CACHE_MODE m_cache_mode;
void add_disjuncted_formula(expr * f);
@ -53,6 +59,8 @@ namespace pdr {
bool is_reachable(expr * cube);
void collect_statistics(statistics& st) const;
void reset_statistics();
};
}

View file

@ -136,6 +136,12 @@ namespace pdr {
}
}
void smt_context_manager::reset_statistics() {
for (unsigned i = 0; i < m_contexts.size(); ++i) {
m_contexts[i]->reset_statistics();
}
}
};

View file

@ -100,6 +100,7 @@ namespace pdr {
~smt_context_manager();
smt_context* mk_fresh();
void collect_statistics(statistics& st) const;
void reset_statistics();
bool is_aux_predicate(func_decl* p) const { return m_predicate_set.contains(p); }
};