Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
z3-z3-4.12.6.src.muz.fp.horn_tactic.cpp Maven / Gradle / Ivy
/*++
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 "ast/ast_util.h"
#include "ast/rewriter/var_subst.h"
#include "ast/rewriter/expr_replacer.h"
#include "tactic/tactical.h"
#include "ast/converters/model_converter.h"
#include "ast/converters/proof_converter.h"
#include "ast/converters/generic_model_converter.h"
#include "muz/fp/horn_tactic.h"
#include "muz/base/dl_context.h"
#include "muz/fp/dl_register_engine.h"
#include "muz/base/dl_rule_transformer.h"
#include "muz/transforms/dl_mk_slice.h"
#include "muz/transforms/dl_transforms.h"
#include "muz/base/fp_params.hpp"
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;
expr_free_vars m_free_vars;
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 normalize(expr_ref& f) {
bool is_positive = true;
expr* e = nullptr;
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 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 = nullptr, *a1 = nullptr;
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.data());
f = m.mk_implies(f, head);
}
return IS_RULE;
}
else {
f = m.mk_and(body.size(), body.data());
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) {
tactic_report report("horn", *g);
bool produce_proofs = g->proofs_enabled();
if (produce_proofs) {
if (!m_ctx.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;
check_parameters();
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());
}
}
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);
bind_variables(f);
m_ctx.add_rule(f, symbol::null);
}
queries.reset();
queries.push_back(q);
generic_model_converter* mc1 = alloc(generic_model_converter, m, "horn");
mc1->hide(q);
g->add(mc1);
}
SASSERT(queries.size() == 1);
q = queries[0].get();
proof_converter_ref pc = g->pc();
model_converter_ref mc;
if (m_is_simplify) {
simplify(q, g, result, mc, pc);
}
else {
verify(q, g, result, mc, pc);
}
g->set(pc.get());
g->add(mc.get());
}
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 (!m_ctx.is_monotone()) {
is_reachable = l_undef;
}
else if (produce_proofs) {
proof_ref proof = m_ctx.get_proof();
pc = proof2proof_converter(m, proof);
g->assert_expr(m.get_fact(proof), proof, nullptr);
}
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.get());
mc = mc2.get();
TRACE("dl", mc->display(tout << *md << "\n"););
}
break;
}
case l_undef:
// subgoal is unchanged.
break;
}
}
void bind_variables(expr_ref& f) {
m_free_vars.reset();
m_free_vars(f);
m_free_vars.set_default_sort(m.mk_bool_sort());
if (!m_free_vars.empty()) {
m_free_vars.reverse();
svector names;
for (unsigned i = 0; i < m_free_vars.size(); ++i) {
names.push_back(symbol(m_free_vars.size() - i - 1));
}
f = m.mk_forall(m_free_vars.size(), m_free_vars.data(), names.data(), f);
}
}
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.xform_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 rep = mk_default_expr_replacer(m, false);
rep->set_substitution(&sub);
g->inc_depth();
g->reset();
result.push_back(g.get());
datalog::rule_set const& rules = m_ctx.get_rules();
for (datalog::rule* r : rules) {
m_ctx.get_rule_manager().to_formula(*r, fml);
(*rep)(fml);
g->assert_expr(fml);
}
g->set_prec(goal::UNDER_OVER);
mc = g->mc();
}
void check_parameters() {
fp_params const& p = m_ctx.get_params();
if (p.engine() == symbol("datalog"))
not_supported("engine=datalog");
if (p.datalog_generate_explanations())
not_supported("datalog.generate_explanations");
if (p.datalog_magic_sets_for_queries())
not_supported("datalog.magic_sets_for_queries");
if (p.xform_instantiate_arrays())
not_supported("xform.instantiate_arrays");
if (p.xform_magic())
not_supported("xform.magic");
if (p.xform_quantify_arrays())
not_supported("xform.quantify_arrays");
if (p.xform_scale())
not_supported("xform.scale");
}
void not_supported(char const* s) {
throw default_exception(std::string("unsupported parameter ") + s);
}
};
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);
}
tactic * translate(ast_manager & m) override {
return alloc(horn_tactic, m_is_simplify, m, m_params);
}
~horn_tactic() override {
dealloc(m_imp);
}
char const* name() const override { return "horn"; }
void updt_params(params_ref const & p) override {
m_params.append(p);
m_imp->updt_params(m_params);
}
void collect_param_descrs(param_descrs & r) override {
m_imp->collect_param_descrs(r);
}
void operator()(goal_ref const & in,
goal_ref_buffer & result) override {
(*m_imp)(in, result);
}
void collect_statistics(statistics & st) const override {
m_imp->collect_statistics(st);
st.copy(m_stats);
}
void reset_statistics() override {
m_stats.reset();
m_imp->reset_statistics();
}
void cleanup() override {
ast_manager & m = m_imp->m;
m_imp->collect_statistics(m_stats);
dealloc(m_imp);
m_imp = alloc(imp, m_is_simplify, m, m_params);
}
};
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));
}