mirror of
https://github.com/Z3Prover/z3
synced 2025-05-02 13:27:01 +00:00
re-organize muz_qe into separate units
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
4597872be8
commit
0d56499e2d
131 changed files with 994 additions and 20069 deletions
469
src/muz/fp/dl_cmds.cpp
Normal file
469
src/muz/fp/dl_cmds.cpp
Normal file
|
@ -0,0 +1,469 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_cmds.cpp
|
||||
|
||||
Abstract:
|
||||
Datalog commands for SMT2 front-end.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-03-28
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"cmd_context.h"
|
||||
#include"dl_cmds.h"
|
||||
#include"dl_external_relation.h"
|
||||
#include"dl_context.h"
|
||||
#include"dl_register_engine.h"
|
||||
#include"dl_decl_plugin.h"
|
||||
#include"dl_instruction.h"
|
||||
#include"dl_compiler.h"
|
||||
#include"dl_rule.h"
|
||||
#include"ast_pp.h"
|
||||
#include"parametric_cmd.h"
|
||||
#include"cancel_eh.h"
|
||||
#include"scoped_ctrl_c.h"
|
||||
#include"scoped_timer.h"
|
||||
#include"trail.h"
|
||||
#include<iomanip>
|
||||
|
||||
|
||||
struct dl_context {
|
||||
smt_params m_fparams;
|
||||
params_ref m_params_ref;
|
||||
fixedpoint_params m_params;
|
||||
cmd_context & m_cmd;
|
||||
datalog::register_engine m_register_engine;
|
||||
dl_collected_cmds* m_collected_cmds;
|
||||
unsigned m_ref_count;
|
||||
datalog::dl_decl_plugin* m_decl_plugin;
|
||||
scoped_ptr<datalog::context> m_context;
|
||||
trail_stack<dl_context> m_trail;
|
||||
|
||||
fixedpoint_params const& get_params() {
|
||||
init();
|
||||
return m_context->get_params();
|
||||
}
|
||||
|
||||
dl_context(cmd_context & ctx, dl_collected_cmds* collected_cmds):
|
||||
m_params(m_params_ref),
|
||||
m_cmd(ctx),
|
||||
m_collected_cmds(collected_cmds),
|
||||
m_ref_count(0),
|
||||
m_decl_plugin(0),
|
||||
m_trail(*this) {}
|
||||
|
||||
void inc_ref() {
|
||||
++m_ref_count;
|
||||
}
|
||||
|
||||
void dec_ref() {
|
||||
--m_ref_count;
|
||||
if (0 == m_ref_count) {
|
||||
dealloc(this);
|
||||
}
|
||||
}
|
||||
|
||||
void init() {
|
||||
ast_manager& m = m_cmd.m();
|
||||
if (!m_context) {
|
||||
m_context = alloc(datalog::context, m, m_register_engine, m_fparams, m_params_ref);
|
||||
}
|
||||
if (!m_decl_plugin) {
|
||||
symbol name("datalog_relation");
|
||||
if (m.has_plugin(name)) {
|
||||
m_decl_plugin = static_cast<datalog::dl_decl_plugin*>(m_cmd.m().get_plugin(m.mk_family_id(name)));
|
||||
}
|
||||
else {
|
||||
m_decl_plugin = alloc(datalog::dl_decl_plugin);
|
||||
m.register_plugin(symbol("datalog_relation"), m_decl_plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
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 & dlctx() {
|
||||
init();
|
||||
return *m_context;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
\brief rule command. It is also the owner of dl_context object.
|
||||
*/
|
||||
class dl_rule_cmd : public cmd {
|
||||
ref<dl_context> m_dl_ctx;
|
||||
mutable unsigned m_arg_idx;
|
||||
expr* m_t;
|
||||
symbol m_name;
|
||||
public:
|
||||
dl_rule_cmd(dl_context * dl_ctx):
|
||||
cmd("rule"),
|
||||
m_dl_ctx(dl_ctx),
|
||||
m_arg_idx(0),
|
||||
m_t(0) {}
|
||||
virtual char const * get_usage() const { return "(forall (q) (=> (and body) head)) :optional-name"; }
|
||||
virtual char const * get_descr(cmd_context & ctx) const { return "add a Horn rule."; }
|
||||
virtual unsigned get_arity() const { return VAR_ARITY; }
|
||||
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const {
|
||||
switch(m_arg_idx) {
|
||||
case 0: return CPK_EXPR;
|
||||
case 1: return CPK_SYMBOL;
|
||||
default: return CPK_SYMBOL;
|
||||
}
|
||||
}
|
||||
virtual void set_next_arg(cmd_context & ctx, expr * t) {
|
||||
m_t = t;
|
||||
m_arg_idx++;
|
||||
}
|
||||
virtual void set_next_arg(cmd_context & ctx, symbol const & s) {
|
||||
m_name = s;
|
||||
}
|
||||
virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); }
|
||||
virtual void prepare(cmd_context& ctx) { m_arg_idx = 0; m_name = symbol::null; }
|
||||
virtual void finalize(cmd_context & ctx) {
|
||||
}
|
||||
virtual void execute(cmd_context & ctx) {
|
||||
m_dl_ctx->add_rule(m_t, m_name);
|
||||
}
|
||||
};
|
||||
|
||||
class dl_query_cmd : public parametric_cmd {
|
||||
ref<dl_context> m_dl_ctx;
|
||||
expr* m_target;
|
||||
public:
|
||||
dl_query_cmd(dl_context * dl_ctx):
|
||||
parametric_cmd("query"),
|
||||
m_dl_ctx(dl_ctx),
|
||||
m_target(0) {
|
||||
}
|
||||
virtual char const * get_usage() const { return "(exists (q) (and body))"; }
|
||||
virtual char const * get_main_descr() const {
|
||||
return "pose a query based on the Horn rules.";
|
||||
}
|
||||
|
||||
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const {
|
||||
if (m_target == 0) return CPK_EXPR;
|
||||
return parametric_cmd::next_arg_kind(ctx);
|
||||
}
|
||||
|
||||
virtual void set_next_arg(cmd_context & ctx, expr * t) {
|
||||
m_target = t;
|
||||
}
|
||||
|
||||
virtual void prepare(cmd_context & ctx) {
|
||||
parametric_cmd::prepare(ctx);
|
||||
m_target = 0;
|
||||
}
|
||||
|
||||
virtual void execute(cmd_context& ctx) {
|
||||
if (m_target == 0) {
|
||||
throw cmd_exception("invalid query command, argument expected");
|
||||
}
|
||||
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_dl_ctx->get_params().timeout();
|
||||
cancel_eh<datalog::context> eh(dlctx);
|
||||
lbool status = l_undef;
|
||||
{
|
||||
scoped_ctrl_c ctrlc(eh);
|
||||
scoped_timer timer(timeout, &eh);
|
||||
cmd_context::scoped_watch sw(ctx);
|
||||
try {
|
||||
status = dlctx.query(m_target);
|
||||
}
|
||||
catch (z3_error & ex) {
|
||||
ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl;
|
||||
throw ex;
|
||||
}
|
||||
catch (z3_exception& ex) {
|
||||
ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl;
|
||||
}
|
||||
}
|
||||
switch (status) {
|
||||
case l_false:
|
||||
ctx.regular_stream() << "unsat\n";
|
||||
print_certificate(ctx);
|
||||
break;
|
||||
case l_true:
|
||||
ctx.regular_stream() << "sat\n";
|
||||
print_answer(ctx);
|
||||
print_certificate(ctx);
|
||||
break;
|
||||
case l_undef:
|
||||
ctx.regular_stream() << "unknown\n";
|
||||
switch(dlctx.get_status()) {
|
||||
case datalog::INPUT_ERROR:
|
||||
ctx.regular_stream() << "input error\n";
|
||||
break;
|
||||
|
||||
case datalog::MEMOUT:
|
||||
ctx.regular_stream() << "memory bounds exceeded\n";
|
||||
break;
|
||||
|
||||
case datalog::TIMEOUT:
|
||||
ctx.regular_stream() << "timeout\n";
|
||||
break;
|
||||
|
||||
case datalog::APPROX:
|
||||
ctx.regular_stream() << "approximated relations\n";
|
||||
break;
|
||||
|
||||
case datalog::OK:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
|
||||
case datalog::CANCELED:
|
||||
ctx.regular_stream() << "canceled\n";
|
||||
dlctx.display_profile(ctx.regular_stream());
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
dlctx.cleanup();
|
||||
print_statistics(ctx);
|
||||
m_target = 0;
|
||||
}
|
||||
|
||||
virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) {
|
||||
m_dl_ctx->dlctx().collect_params(p);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void set_background(cmd_context& ctx) {
|
||||
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) {
|
||||
dlctx.assert_expr(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void print_answer(cmd_context& ctx) {
|
||||
if (m_dl_ctx->get_params().print_answer()) {
|
||||
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;
|
||||
unsigned num_decls = 0;
|
||||
if (is_quantifier(m_target)) {
|
||||
num_decls = to_quantifier(m_target)->get_num_decls();
|
||||
}
|
||||
ctx.display(ctx.regular_stream(), query_result, 0, num_decls, "X", var_names);
|
||||
ctx.regular_stream() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void print_statistics(cmd_context& ctx) {
|
||||
if (m_dl_ctx->get_params().print_statistics()) {
|
||||
statistics st;
|
||||
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);
|
||||
st.update("time", ctx.get_seconds());
|
||||
st.update("memory", static_cast<double>(mem)/static_cast<double>(1024*1024));
|
||||
st.update("max-memory", static_cast<double>(max_mem)/static_cast<double>(1024*1024));
|
||||
st.display_smt2(ctx.regular_stream());
|
||||
}
|
||||
}
|
||||
|
||||
void print_certificate(cmd_context& ctx) {
|
||||
if (m_dl_ctx->get_params().print_certificate()) {
|
||||
datalog::context& dlctx = m_dl_ctx->dlctx();
|
||||
dlctx.display_certificate(ctx.regular_stream());
|
||||
ctx.regular_stream() << "\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class dl_declare_rel_cmd : public cmd {
|
||||
ref<dl_context> m_dl_ctx;
|
||||
unsigned m_arg_idx;
|
||||
mutable unsigned m_query_arg_idx;
|
||||
symbol m_rel_name;
|
||||
scoped_ptr<sort_ref_vector> m_domain;
|
||||
svector<symbol> m_kinds;
|
||||
|
||||
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"),
|
||||
m_dl_ctx(dl_ctx),
|
||||
m_domain(0) {}
|
||||
|
||||
virtual char const * get_usage() const { return "<symbol> (<arg1 sort> ...) <representation>*"; }
|
||||
virtual char const * get_descr(cmd_context & ctx) const { return "declare new relation"; }
|
||||
virtual unsigned get_arity() const { return VAR_ARITY; }
|
||||
|
||||
virtual void prepare(cmd_context & ctx) {
|
||||
m_arg_idx = 0;
|
||||
m_query_arg_idx = 0;
|
||||
m_domain = 0;
|
||||
m_kinds.reset();
|
||||
}
|
||||
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const {
|
||||
switch(m_query_arg_idx++) {
|
||||
case 0: return CPK_SYMBOL; // relation name
|
||||
case 1: return CPK_SORT_LIST; // arguments
|
||||
default: return CPK_SYMBOL; // optional representation specification
|
||||
}
|
||||
}
|
||||
virtual void set_next_arg(cmd_context & ctx, unsigned num, sort * const * slist) {
|
||||
ensure_domain(ctx);
|
||||
m_domain->append(num, slist);
|
||||
m_arg_idx++;
|
||||
}
|
||||
virtual void set_next_arg(cmd_context & ctx, symbol const & s) {
|
||||
if(m_arg_idx==0) {
|
||||
m_rel_name = s;
|
||||
}
|
||||
else {
|
||||
SASSERT(m_arg_idx>1);
|
||||
m_kinds.push_back(s);
|
||||
}
|
||||
m_arg_idx++;
|
||||
}
|
||||
virtual void execute(cmd_context & ctx) {
|
||||
if(m_arg_idx<2) {
|
||||
throw cmd_exception("at least 2 arguments expected");
|
||||
}
|
||||
ensure_domain(ctx);
|
||||
ast_manager& m = ctx.m();
|
||||
|
||||
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);
|
||||
m_dl_ctx->register_predicate(pred, m_kinds.size(), m_kinds.c_ptr());
|
||||
m_domain = 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class dl_declare_var_cmd : public cmd {
|
||||
unsigned m_arg_idx;
|
||||
symbol m_var_name;
|
||||
sort* m_var_sort;
|
||||
ref<dl_context> m_dl_ctx;
|
||||
public:
|
||||
dl_declare_var_cmd(dl_context* dl_ctx):
|
||||
cmd("declare-var"),
|
||||
m_arg_idx(0),
|
||||
m_dl_ctx(dl_ctx)
|
||||
{}
|
||||
|
||||
virtual char const * get_usage() const { return "<symbol> <sort>"; }
|
||||
virtual char const * get_descr(cmd_context & ctx) const { return "declare constant as variable"; }
|
||||
virtual unsigned get_arity() const { return 2; }
|
||||
|
||||
virtual void prepare(cmd_context & ctx) {
|
||||
m_arg_idx = 0;
|
||||
}
|
||||
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const {
|
||||
SASSERT(m_arg_idx <= 1);
|
||||
if (m_arg_idx == 0) {
|
||||
return CPK_SYMBOL;
|
||||
}
|
||||
return CPK_SORT;
|
||||
}
|
||||
|
||||
virtual void set_next_arg(cmd_context & ctx, sort* s) {
|
||||
m_var_sort = s;
|
||||
++m_arg_idx;
|
||||
}
|
||||
|
||||
virtual void set_next_arg(cmd_context & ctx, symbol const & s) {
|
||||
m_var_name = s;
|
||||
++m_arg_idx;
|
||||
}
|
||||
|
||||
virtual void execute(cmd_context & ctx) {
|
||||
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->dlctx().register_variable(var);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
51
src/muz/fp/dl_register_engine.cpp
Normal file
51
src/muz/fp/dl_register_engine.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_register_engine.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Class for creating Datalog engines.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-08-28
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "dl_register_engine.h"
|
||||
#include "dl_bmc_engine.h"
|
||||
#include "clp_context.h"
|
||||
#include "tab_context.h"
|
||||
#include "rel_context.h"
|
||||
#include "pdr_dl_interface.h"
|
||||
|
||||
namespace datalog {
|
||||
register_engine::register_engine(): m_ctx(0) {}
|
||||
|
||||
engine_base* register_engine::mk_engine(DL_ENGINE engine_type) {
|
||||
switch(engine_type) {
|
||||
case PDR_ENGINE:
|
||||
case QPDR_ENGINE:
|
||||
return alloc(pdr::dl_interface, *m_ctx);
|
||||
case DATALOG_ENGINE:
|
||||
return alloc(rel_context, *m_ctx);
|
||||
case BMC_ENGINE:
|
||||
case QBMC_ENGINE:
|
||||
return alloc(bmc, *m_ctx);
|
||||
case TAB_ENGINE:
|
||||
return alloc(tab, *m_ctx);
|
||||
case CLP_ENGINE:
|
||||
return alloc(clp, *m_ctx);
|
||||
case LAST_ENGINE:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
36
src/muz/fp/dl_register_engine.h
Normal file
36
src/muz/fp/dl_register_engine.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_register_engine.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Class for creating Datalog engines.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-08-28
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _DL_REGISTER_ENGINE_H_
|
||||
#define _DL_REGISTER_ENGINE_H_
|
||||
|
||||
#include "dl_context.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
class register_engine : public register_engine_base {
|
||||
context* m_ctx;
|
||||
public:
|
||||
register_engine();
|
||||
engine_base* mk_engine(DL_ENGINE engine_type);
|
||||
void set_context(context* ctx) { m_ctx = ctx; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
421
src/muz/fp/horn_tactic.cpp
Normal file
421
src/muz/fp/horn_tactic.cpp
Normal file
|
@ -0,0 +1,421 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
horn_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
HORN as a tactic to solve Horn clauses.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-11-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"model_converter.h"
|
||||
#include"proof_converter.h"
|
||||
#include"horn_tactic.h"
|
||||
#include"dl_context.h"
|
||||
#include"dl_register_engine.h"
|
||||
#include"expr_replacer.h"
|
||||
#include"dl_rule_transformer.h"
|
||||
#include"dl_mk_slice.h"
|
||||
#include"filter_model_converter.h"
|
||||
#include"dl_transforms.h"
|
||||
|
||||
class horn_tactic : public tactic {
|
||||
struct imp {
|
||||
ast_manager& m;
|
||||
bool m_is_simplify;
|
||||
datalog::register_engine m_register_engine;
|
||||
datalog::context m_ctx;
|
||||
smt_params m_fparams;
|
||||
|
||||
imp(bool t, ast_manager & m, params_ref const & p):
|
||||
m(m),
|
||||
m_is_simplify(t),
|
||||
m_ctx(m, m_register_engine, m_fparams) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_ctx.updt_params(p);
|
||||
}
|
||||
|
||||
void collect_param_descrs(param_descrs & r) {
|
||||
m_ctx.collect_params(r);
|
||||
}
|
||||
|
||||
void reset_statistics() {
|
||||
m_ctx.reset_statistics();
|
||||
}
|
||||
|
||||
void collect_statistics(statistics & st) const {
|
||||
m_ctx.collect_statistics(st);
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
if (f) {
|
||||
m_ctx.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void normalize(expr_ref& f) {
|
||||
bool is_positive = true;
|
||||
expr* e = 0;
|
||||
while (true) {
|
||||
if (is_forall(f) && is_positive) {
|
||||
f = to_quantifier(f)->get_expr();
|
||||
}
|
||||
else if (is_exists(f) && !is_positive) {
|
||||
f = to_quantifier(f)->get_expr();
|
||||
}
|
||||
else if (m.is_not(f, e)) {
|
||||
is_positive = !is_positive;
|
||||
f = e;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_positive) {
|
||||
f = m.mk_not(f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool is_predicate(expr* a) {
|
||||
SASSERT(m.is_bool(a));
|
||||
return is_app(a) && to_app(a)->get_decl()->get_family_id() == null_family_id;
|
||||
}
|
||||
|
||||
void register_predicate(expr* a) {
|
||||
SASSERT(is_predicate(a));
|
||||
m_ctx.register_predicate(to_app(a)->get_decl(), false);
|
||||
}
|
||||
|
||||
void check_predicate(ast_mark& mark, expr* a) {
|
||||
ptr_vector<expr> todo;
|
||||
todo.push_back(a);
|
||||
while (!todo.empty()) {
|
||||
a = todo.back();
|
||||
todo.pop_back();
|
||||
if (mark.is_marked(a)) {
|
||||
continue;
|
||||
}
|
||||
mark.mark(a, true);
|
||||
if (is_quantifier(a)) {
|
||||
a = to_quantifier(a)->get_expr();
|
||||
todo.push_back(a);
|
||||
}
|
||||
else if (m.is_not(a) || m.is_and(a) || m.is_or(a) || m.is_implies(a)) {
|
||||
todo.append(to_app(a)->get_num_args(), to_app(a)->get_args());
|
||||
}
|
||||
else if (m.is_ite(a)) {
|
||||
todo.push_back(to_app(a)->get_arg(1));
|
||||
todo.push_back(to_app(a)->get_arg(2));
|
||||
}
|
||||
else if (is_predicate(a)) {
|
||||
register_predicate(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum formula_kind { IS_RULE, IS_QUERY, IS_NONE };
|
||||
|
||||
bool is_implication(expr* f) {
|
||||
expr* e1;
|
||||
while (is_forall(f)) {
|
||||
f = to_quantifier(f)->get_expr();
|
||||
}
|
||||
while (m.is_implies(f, e1, f)) ;
|
||||
return is_predicate(f);
|
||||
}
|
||||
|
||||
formula_kind get_formula_kind(expr_ref& f) {
|
||||
expr_ref tmp(f);
|
||||
normalize(tmp);
|
||||
ast_mark mark;
|
||||
expr_ref_vector args(m), body(m);
|
||||
expr_ref head(m);
|
||||
expr* a = 0, *a1 = 0;
|
||||
qe::flatten_or(tmp, args);
|
||||
for (unsigned i = 0; i < args.size(); ++i) {
|
||||
a = args[i].get();
|
||||
check_predicate(mark, a);
|
||||
if (m.is_not(a, a1)) {
|
||||
body.push_back(a1);
|
||||
}
|
||||
else if (is_predicate(a)) {
|
||||
if (head) {
|
||||
return IS_NONE;
|
||||
}
|
||||
head = a;
|
||||
}
|
||||
else {
|
||||
body.push_back(m.mk_not(a));
|
||||
}
|
||||
}
|
||||
if (head) {
|
||||
if (!is_implication(f)) {
|
||||
f = m.mk_and(body.size(), body.c_ptr());
|
||||
f = m.mk_implies(f, head);
|
||||
}
|
||||
return IS_RULE;
|
||||
}
|
||||
else {
|
||||
f = m.mk_and(body.size(), body.c_ptr());
|
||||
return IS_QUERY;
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref mk_rule(expr* body, expr* head) {
|
||||
return expr_ref(m.mk_implies(body, head), m);
|
||||
}
|
||||
|
||||
void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(g->is_well_sorted());
|
||||
mc = 0; pc = 0; core = 0;
|
||||
tactic_report report("horn", *g);
|
||||
bool produce_proofs = g->proofs_enabled();
|
||||
|
||||
if (produce_proofs) {
|
||||
if (!m_ctx.get_params().generate_proof_trace()) {
|
||||
params_ref params = m_ctx.get_params().p;
|
||||
params.set_bool("generate_proof_trace", true);
|
||||
updt_params(params);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned sz = g->size();
|
||||
expr_ref q(m), f(m);
|
||||
expr_ref_vector queries(m);
|
||||
std::stringstream msg;
|
||||
|
||||
m_ctx.reset();
|
||||
m_ctx.ensure_opened();
|
||||
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
f = g->form(i);
|
||||
formula_kind k = get_formula_kind(f);
|
||||
switch(k) {
|
||||
case IS_RULE:
|
||||
m_ctx.add_rule(f, symbol::null);
|
||||
break;
|
||||
case IS_QUERY:
|
||||
queries.push_back(f);
|
||||
break;
|
||||
default:
|
||||
msg << "formula is not in Horn fragment: " << mk_pp(g->form(i), m) << "\n";
|
||||
TRACE("horn", tout << msg.str(););
|
||||
throw tactic_exception(msg.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (queries.size() != 1 || m_is_simplify) {
|
||||
q = m.mk_fresh_const("query", m.mk_bool_sort());
|
||||
register_predicate(q);
|
||||
for (unsigned i = 0; i < queries.size(); ++i) {
|
||||
f = mk_rule(queries[i].get(), q);
|
||||
m_ctx.add_rule(f, symbol::null);
|
||||
}
|
||||
queries.reset();
|
||||
queries.push_back(q);
|
||||
filter_model_converter* mc1 = alloc(filter_model_converter, m);
|
||||
mc1->insert(to_app(q)->get_decl());
|
||||
mc = mc1;
|
||||
}
|
||||
SASSERT(queries.size() == 1);
|
||||
q = queries[0].get();
|
||||
if (m_is_simplify) {
|
||||
simplify(q, g, result, mc, pc);
|
||||
}
|
||||
else {
|
||||
verify(q, g, result, mc, pc);
|
||||
}
|
||||
}
|
||||
|
||||
void verify(expr* q,
|
||||
goal_ref const& g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc) {
|
||||
|
||||
lbool is_reachable = l_undef;
|
||||
|
||||
try {
|
||||
is_reachable = m_ctx.query(q);
|
||||
}
|
||||
catch (default_exception& ex) {
|
||||
IF_VERBOSE(1, verbose_stream() << ex.msg() << "\n";);
|
||||
throw ex;
|
||||
}
|
||||
g->inc_depth();
|
||||
|
||||
bool produce_models = g->models_enabled();
|
||||
bool produce_proofs = g->proofs_enabled();
|
||||
|
||||
result.push_back(g.get());
|
||||
switch (is_reachable) {
|
||||
case l_true: {
|
||||
// goal is unsat
|
||||
if (produce_proofs) {
|
||||
proof_ref proof = m_ctx.get_proof();
|
||||
pc = proof2proof_converter(m, proof);
|
||||
g->assert_expr(m.mk_false(), proof, 0);
|
||||
}
|
||||
else {
|
||||
g->assert_expr(m.mk_false());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case l_false: {
|
||||
// goal is sat
|
||||
g->reset();
|
||||
if (produce_models) {
|
||||
model_ref md = m_ctx.get_model();
|
||||
model_converter_ref mc2 = model2model_converter(&*md);
|
||||
if (mc) {
|
||||
mc = concat(mc.get(), mc2.get());
|
||||
}
|
||||
else {
|
||||
mc = mc2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case l_undef:
|
||||
// subgoal is unchanged.
|
||||
break;
|
||||
}
|
||||
TRACE("horn", g->display(tout););
|
||||
SASSERT(g->is_well_sorted());
|
||||
}
|
||||
|
||||
void simplify(expr* q,
|
||||
goal_ref const& g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc) {
|
||||
|
||||
expr_ref fml(m);
|
||||
|
||||
|
||||
func_decl* query_pred = to_app(q)->get_decl();
|
||||
m_ctx.set_output_predicate(query_pred);
|
||||
m_ctx.get_rules(); // flush adding rules.
|
||||
apply_default_transformation(m_ctx);
|
||||
|
||||
if (m_ctx.get_params().slice()) {
|
||||
datalog::rule_transformer transformer(m_ctx);
|
||||
datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx);
|
||||
transformer.register_plugin(slice);
|
||||
m_ctx.transform_rules(transformer);
|
||||
}
|
||||
|
||||
expr_substitution sub(m);
|
||||
sub.insert(q, m.mk_false());
|
||||
scoped_ptr<expr_replacer> rep = mk_default_expr_replacer(m);
|
||||
rep->set_substitution(&sub);
|
||||
g->inc_depth();
|
||||
g->reset();
|
||||
result.push_back(g.get());
|
||||
datalog::rule_set const& rules = m_ctx.get_rules();
|
||||
datalog::rule_set::iterator it = rules.begin(), end = rules.end();
|
||||
for (; it != end; ++it) {
|
||||
datalog::rule* r = *it;
|
||||
r->to_formula(fml);
|
||||
(*rep)(fml);
|
||||
g->assert_expr(fml);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
bool m_is_simplify;
|
||||
params_ref m_params;
|
||||
statistics m_stats;
|
||||
imp * m_imp;
|
||||
public:
|
||||
horn_tactic(bool t, ast_manager & m, params_ref const & p):
|
||||
m_is_simplify(t),
|
||||
m_params(p) {
|
||||
m_imp = alloc(imp, t, m, p);
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(horn_tactic, m_is_simplify, m, m_params);
|
||||
}
|
||||
|
||||
virtual ~horn_tactic() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_imp->updt_params(p);
|
||||
}
|
||||
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
m_imp->collect_param_descrs(r);
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
(*m_imp)(in, result, mc, pc, core);
|
||||
}
|
||||
|
||||
virtual void collect_statistics(statistics & st) const {
|
||||
m_imp->collect_statistics(st);
|
||||
st.copy(m_stats);
|
||||
}
|
||||
|
||||
virtual void reset_statistics() {
|
||||
m_stats.reset();
|
||||
m_imp->reset_statistics();
|
||||
}
|
||||
|
||||
virtual void cleanup() {
|
||||
ast_manager & m = m_imp->m;
|
||||
imp * d = m_imp;
|
||||
d->collect_statistics(m_stats);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = 0;
|
||||
}
|
||||
dealloc(d);
|
||||
d = alloc(imp, m_is_simplify, m, m_params);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = d;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
};
|
||||
|
||||
tactic * mk_horn_tactic(ast_manager & m, params_ref const & p) {
|
||||
return clean(alloc(horn_tactic, false, m, p));
|
||||
}
|
||||
|
||||
tactic * mk_horn_simplify_tactic(ast_manager & m, params_ref const & p) {
|
||||
return clean(alloc(horn_tactic, true, m, p));
|
||||
}
|
||||
|
35
src/muz/fp/horn_tactic.h
Normal file
35
src/muz/fp/horn_tactic.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
horn_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
PDR as a tactic to solve Horn clauses.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-11-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _HORN_TACTIC_H_
|
||||
#define _HORN_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_horn_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
/*
|
||||
ADD_TACTIC("horn", "apply tactic for horn clauses.", "mk_horn_tactic(m, p)")
|
||||
*/
|
||||
|
||||
tactic * mk_horn_simplify_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
/*
|
||||
ADD_TACTIC("horn-simplify", "simplify horn clauses.", "mk_horn_simplify_tactic(m, p)")
|
||||
*/
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue