mirror of
https://github.com/Z3Prover/z3
synced 2025-08-21 02:30:23 +00:00
158 lines
5.6 KiB
C++
158 lines
5.6 KiB
C++
/*++
|
|
Copyright (c) 2013 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dl_mk_loop_counter.cpp
|
|
|
|
Abstract:
|
|
|
|
Add loop counter argument to relations.
|
|
|
|
Author:
|
|
|
|
Nikolaj Bjorner (nbjorner) 2013-03-31
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "muz/transforms/dl_mk_loop_counter.h"
|
|
#include "muz/base/dl_context.h"
|
|
|
|
namespace datalog {
|
|
|
|
mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority):
|
|
plugin(priority),
|
|
m(ctx.get_manager()),
|
|
m_ctx(ctx),
|
|
a(m),
|
|
m_refs(m) {
|
|
}
|
|
|
|
mk_loop_counter::~mk_loop_counter() { }
|
|
|
|
app_ref mk_loop_counter::add_arg(rule_set const& src, rule_set& dst, app* fn, unsigned idx) {
|
|
expr_ref_vector args(m);
|
|
func_decl* new_fn, *old_fn = fn->get_decl();
|
|
args.append(fn->get_num_args(), fn->get_args());
|
|
args.push_back(m.mk_var(idx, a.mk_int()));
|
|
|
|
if (!m_old2new.find(old_fn, new_fn)) {
|
|
ptr_vector<sort> domain;
|
|
domain.append(fn->get_num_args(), old_fn->get_domain());
|
|
domain.push_back(a.mk_int());
|
|
new_fn = m.mk_func_decl(old_fn->get_name(), domain.size(), domain.data(), old_fn->get_range());
|
|
m_old2new.insert(old_fn, new_fn);
|
|
m_new2old.insert(new_fn, old_fn);
|
|
m_refs.push_back(new_fn);
|
|
m_ctx.register_predicate(new_fn, false);
|
|
if (src.is_output_predicate(old_fn)) {
|
|
dst.set_output_predicate(new_fn);
|
|
}
|
|
}
|
|
return app_ref(m.mk_app(new_fn, args.size(), args.data()), m);
|
|
}
|
|
|
|
app_ref mk_loop_counter::del_arg(app* fn) {
|
|
expr_ref_vector args(m);
|
|
func_decl* old_fn = nullptr, *new_fn = fn->get_decl();
|
|
SASSERT(fn->get_num_args() > 0);
|
|
args.append(fn->get_num_args()-1, fn->get_args());
|
|
VERIFY (m_new2old.find(new_fn, old_fn));
|
|
return app_ref(m.mk_app(old_fn, args.size(), args.data()), m);
|
|
}
|
|
|
|
rule_set * mk_loop_counter::operator()(rule_set const & source) {
|
|
m_refs.reset();
|
|
m_old2new.reset();
|
|
m_new2old.reset();
|
|
rule_manager& rm = source.get_rule_manager();
|
|
scoped_ptr<rule_set> result = alloc(rule_set, m_ctx);
|
|
unsigned sz = source.get_num_rules();
|
|
rule_ref new_rule(rm);
|
|
app_ref_vector tail(m);
|
|
app_ref head(m);
|
|
bool_vector neg;
|
|
rule_counter& vc = rm.get_counter();
|
|
for (unsigned i = 0; i < sz; ++i) {
|
|
tail.reset();
|
|
neg.reset();
|
|
rule & r = *source.get_rule(i);
|
|
unsigned cnt = vc.get_max_rule_var(r)+1;
|
|
unsigned utsz = r.get_uninterpreted_tail_size();
|
|
unsigned tsz = r.get_tail_size();
|
|
for (unsigned j = 0; j < utsz; ++j, ++cnt) {
|
|
tail.push_back(add_arg(source, *result, r.get_tail(j), cnt));
|
|
neg.push_back(r.is_neg_tail(j));
|
|
}
|
|
for (unsigned j = utsz; j < tsz; ++j) {
|
|
tail.push_back(r.get_tail(j));
|
|
neg.push_back(false);
|
|
}
|
|
head = add_arg(source, *result, r.get_head(), cnt);
|
|
// set the loop counter to be an increment of the previous
|
|
bool found = false;
|
|
unsigned last = head->get_num_args()-1;
|
|
for (unsigned j = 0; !found && j < utsz; ++j) {
|
|
if (head->get_decl() == tail[j]->get_decl()) {
|
|
tail.push_back(m.mk_eq(head->get_arg(last),
|
|
a.mk_add(tail[j]->get_arg(last),
|
|
a.mk_numeral(rational(1), true))));
|
|
neg.push_back(false);
|
|
found = true;
|
|
}
|
|
}
|
|
// initialize loop counter to 0 if none was found.
|
|
if (!found) {
|
|
expr_ref_vector args(m);
|
|
args.append(head->get_num_args(), head->get_args());
|
|
args[last] = a.mk_numeral(rational(0), true);
|
|
head = m.mk_app(head->get_decl(), args.size(), args.data());
|
|
}
|
|
|
|
new_rule = rm.mk(head, tail.size(), tail.data(), neg.data(), r.name(), true);
|
|
result->add_rule(new_rule);
|
|
}
|
|
|
|
// model converter: remove references to extra argument.
|
|
// proof converter: remove references to extra argument as well.
|
|
|
|
return result.detach();
|
|
}
|
|
|
|
rule_set * mk_loop_counter::revert(rule_set const & source) {
|
|
context& ctx = source.get_context();
|
|
rule_manager& rm = source.get_rule_manager();
|
|
rule_set * result = alloc(rule_set, ctx);
|
|
unsigned sz = source.get_num_rules();
|
|
rule_ref new_rule(rm);
|
|
app_ref_vector tail(m);
|
|
app_ref head(m);
|
|
bool_vector neg;
|
|
for (unsigned i = 0; i < sz; ++i) {
|
|
tail.reset();
|
|
neg.reset();
|
|
rule & r = *source.get_rule(i);
|
|
unsigned utsz = r.get_uninterpreted_tail_size();
|
|
unsigned tsz = r.get_tail_size();
|
|
for (unsigned j = 0; j < utsz; ++j) {
|
|
tail.push_back(del_arg(r.get_tail(j)));
|
|
neg.push_back(r.is_neg_tail(j));
|
|
}
|
|
for (unsigned j = utsz; j < tsz; ++j) {
|
|
tail.push_back(r.get_tail(j));
|
|
neg.push_back(false);
|
|
}
|
|
head = del_arg(r.get_head());
|
|
new_rule = rm.mk(head, tail.size(), tail.data(), neg.data(), r.name(), true);
|
|
result->add_rule(new_rule);
|
|
}
|
|
|
|
// model converter: ...
|
|
// proof converter: ...
|
|
|
|
return result;
|
|
|
|
}
|
|
};
|