z3-z3-4.13.0.src.muz.rel.dl_mk_similarity_compressor.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
dl_mk_similarity_compressor.cpp
Abstract:
Author:
Krystof Hoder (t-khoder) 2010-10-22.
Revision History:
--*/
#include
#include
#include "muz/rel/dl_mk_similarity_compressor.h"
#include "muz/rel/dl_relation_manager.h"
namespace datalog {
mk_similarity_compressor::mk_similarity_compressor(context & ctx) :
plugin(5000),
m_context(ctx),
m_manager(ctx.get_manager()),
m_threshold_count(ctx.similarity_compressor_threshold()),
m_result_rules(ctx.get_rule_manager()),
m_modified(false),
m_pinned(m_manager) {
SASSERT(m_threshold_count>1);
}
void mk_similarity_compressor::reset() {
m_rules.reset();
m_result_rules.reset();
m_pinned.reset();
}
/**
Allows to traverse head and positive tails in a single for loop starting from -1
*/
static app * get_by_tail_index(rule * r, int idx) {
if (idx < 0) {
return r->get_head();
}
SASSERT(idx < static_cast(r->get_positive_tail_size()));
return r->get_tail(idx);
}
template
static int aux_compare(T a, T b) {
return (a>b) ? 1 : ( (a==b) ? 0 : -1);
}
template
static int aux_compare(T* a, T* b);
static int compare_var_args(app* t1, app* t2) {
SASSERT(t1->get_num_args()==t2->get_num_args());
int res;
unsigned n = t1->get_num_args();
for (unsigned i = 0; i < n; i++) {
expr * a1 = t1->get_arg(i);
expr * a2 = t2->get_arg(i);
res = aux_compare(is_var(a1), is_var(a2));
if (res != 0) {
return res;
}
if (is_var(a1)) {
res = aux_compare(to_var(a1)->get_idx(), to_var(a2)->get_idx());
if (res != 0) {
return res;
}
}
}
return 0;
}
static int compare_args(app* t1, app* t2, int & skip_countdown) {
SASSERT(t1->get_num_args()==t2->get_num_args());
int res;
unsigned n = t1->get_num_args();
for (unsigned i=0; iget_arg(i))) {
SASSERT(t1->get_arg(i) == t2->get_arg(i));
continue;
}
if ((skip_countdown--) == 0) {
continue;
}
res = aux_compare(t1->get_arg(i)->get_id(), t2->get_arg(i)->get_id());
if (res!=0) { return res; }
}
return 0;
}
/**
\brief Return 0 if r1 and r2 could be similar. If the rough similarity
equivalence class of r1 is greater than the one of r2, return 1; otherwise return -1.
Two rules are in the same rough similarity class if they differ only in constant arguments
of positive uninterpreted predicates.
*/
static int rough_compare(rule * r1, rule * r2) {
int res = aux_compare(r1->get_tail_size(), r2->get_tail_size());
if (res!=0) { return res; }
res = aux_compare(r1->get_uninterpreted_tail_size(), r2->get_uninterpreted_tail_size());
if (res!=0) { return res; }
res = aux_compare(r1->get_positive_tail_size(), r2->get_positive_tail_size());
if (res!=0) { return res; }
int pos_tail_sz = r1->get_positive_tail_size();
for (int i=-1; iget_decl()->get_id(), t2->get_decl()->get_id());
if (res!=0) { return res; }
res = compare_var_args(t1, t2);
if (res!=0) { return res; }
}
unsigned tail_sz = r1->get_tail_size();
for (unsigned i=pos_tail_sz; iget_tail(i)->get_id(), r2->get_tail(i)->get_id());
if (res!=0) { return res; }
}
return 0;
}
/**
\c r1 and \c r2 must be equal according to the \c rough_compare function for this function
to be called.
*/
static int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) {
SASSERT(rough_compare(r1, r2)==0);
int pos_tail_sz = r1->get_positive_tail_size();
for (int i=-1; i info_vector;
static void collect_const_indexes(app * t, int tail_index, info_vector & res) {
unsigned n = t->get_num_args();
for (unsigned i=0; iget_arg(i))) {
continue;
}
res.push_back(const_info(tail_index, i));
}
}
static void collect_const_indexes(rule * r, info_vector & res) {
collect_const_indexes(r->get_head(), -1, res);
unsigned pos_tail_sz = r->get_positive_tail_size();
for (unsigned i=0; iget_tail(i), i, res);
}
}
template
static void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) {
unsigned const_cnt = const_infos.size();
tgt.reset();
for (unsigned i=0; iget_arg(inf.arg_index())));
SASSERT(tgt.back()->get_num_args()==0);
}
}
template
static void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) {
unsigned const_cnt = const_infos.size();
tgt.reset();
for (unsigned i=0; iget_decl()->get_domain(inf.arg_index()));
}
}
/**
\brief From the \c tail_indexes and \c arg_indexes remove elements corresponding to constants
that are the same in rules \c *first ... \c *(after_last-1).
*/
static void remove_stable_constants(rule_vector::iterator first, rule_vector::iterator after_last,
info_vector & const_infos) {
SASSERT(after_last-first>1);
unsigned const_cnt = const_infos.size();
ptr_vector vals;
rule * r = *(first++);
collect_orphan_consts(r, const_infos, vals);
SASSERT(vals.size()==const_cnt);
rule_vector::iterator it = first;
for (; it!=after_last; ++it) {
for (unsigned i=0; iget_arg(const_infos[i].arg_index()));
if (vals[i]!=val) {
vals[i] = 0;
}
}
}
unsigned removed_cnt = 0;
for (unsigned i=0; i vals;
ptr_vector sorts;
rule * r = *(first++);
collect_orphan_consts(r, const_infos, vals);
collect_orphan_sorts(r, const_infos, sorts);
SASSERT(vals.size()==const_cnt);
vector possible_parents(const_cnt);
for (unsigned i=1; iget_head()->get_num_args() - count_variable_arguments(r->get_head());
unsigned pos_tail_sz = r->get_positive_tail_size();
for (unsigned i=0; iget_tail(i)->get_num_args() - count_variable_arguments(r->get_tail(i));
}
return res;
}
static bool initial_comparator(rule * r1, rule * r2) {
int res = rough_compare(r1, r2);
if (res!=0) { return res>0; }
return total_compare(r1, r2)>0;
}
class arg_ignoring_comparator {
unsigned m_ignored_index;
public:
arg_ignoring_comparator(unsigned ignored_index) : m_ignored_index(ignored_index) {}
bool operator()(rule * r1, rule * r2) const {
return total_compare(r1, r2, m_ignored_index)>0;
}
bool eq(rule * r1, rule * r2) const {
return total_compare(r1, r2, m_ignored_index)==0;
}
};
void mk_similarity_compressor::merge_class(rule_vector::iterator first,
rule_vector::iterator after_last) {
SASSERT(after_last-first>1);
info_vector const_infos;
rule * r = *first; //an arbitrary representative of the class
collect_const_indexes(r, const_infos);
remove_stable_constants(first, after_last, const_infos);
unsigned const_cnt = const_infos.size();
SASSERT(const_cnt>0);
detect_equal_constants(first, after_last, const_infos);
//The aux relation contains column for each constant which does not have an earlier constant
//that it is equal to (i.e. only has no parent)
ptr_vector aux_domain;
collect_orphan_sorts(r, const_infos, aux_domain);
func_decl* head_pred = r->get_decl();
symbol const& name_prefix = head_pred->get_name();
std::string name_suffix = "sc_" + to_string(const_cnt);
func_decl * aux_pred = m_context.mk_fresh_head_predicate(name_prefix, symbol(name_suffix.c_str()),
aux_domain.size(), aux_domain.data(), head_pred);
m_pinned.push_back(aux_pred);
relation_fact val_fact(m_manager, const_cnt);
rule_vector::iterator it = first;
for (; it!=after_last; ++it) {
collect_orphan_consts(*it, const_infos, val_fact);
m_context.add_fact(aux_pred, val_fact);
}
m_context.get_rel_context()->get_rmanager().mark_saturated(aux_pred);
app * new_head = r->get_head();
ptr_vector new_tail;
bool_vector new_negs;
unsigned tail_sz = r->get_tail_size();
for (unsigned i=0; iget_tail(i));
new_negs.push_back(r->is_neg_tail(i));
}
rule_counter ctr;
ctr.count_rule_vars(r);
unsigned max_var_idx, new_var_idx_base;
if (ctr.get_max_positive(max_var_idx)) {
new_var_idx_base = max_var_idx+1;
}
else {
new_var_idx_base = 0;
}
ptr_vector const_vars; //variables at indexes of their corresponding constants
expr_ref_vector aux_vars(m_manager); //variables as arguments for the auxiliary predicate
unsigned aux_column_index = 0;
for (unsigned i=0; i mod_args(mod_tail->get_num_args(), mod_tail->get_args());
for (; iget_decl(), mod_args.data());
m_pinned.push_back(upd_tail);
mod_tail = upd_tail;
}
app_ref aux_tail(m_manager.mk_app(aux_pred, aux_vars.data()), m_manager);
new_tail.push_back(aux_tail);
new_negs.push_back(false);
rule * new_rule = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.data(),
new_negs.data(), r->name());
m_result_rules.push_back(new_rule);
//TODO: allow for a rule to have multiple parent objects
new_rule->set_accounting_parent_object(m_context, r);
m_modified = true;
}
void mk_similarity_compressor::process_class(rule_set const& source, rule_vector::iterator first,
rule_vector::iterator after_last) {
SASSERT(first!=after_last);
//remove duplicates
{
rule_vector::iterator it = first;
rule_vector::iterator prev = it;
++it;
while(it!=after_last) {
if (it!=after_last && total_compare(*prev, *it)==0) {
--after_last;
std::swap(*it, *after_last);
m_modified = true;
}
else {
prev = it;
++it;
}
}
}
SASSERT(first!=after_last);
unsigned const_cnt = get_constant_count(*first);
#if 0
for (unsigned ignored_index=0; ignored_indexm_threshold_count) {
merge_class(grp_begin, it);
//group was processed, so we remove it from the class
if (it==after_last) {
after_last=grp_begin;
it=after_last;
}
else {
while(it!=grp_begin) {
std::swap(*--it, *--after_last);
}
}
}
grp_begin = it;
grp_size = 0;
}
}
}
#endif
//TODO: compress also rules with pairs (or tuples) of equal constants
#if 1
if (const_cnt>0 && !source.is_output_predicate((*first)->get_decl())) {
unsigned rule_cnt = static_cast(after_last-first);
if (rule_cnt>m_threshold_count) {
merge_class(first, after_last);
return;
}
}
#endif
//put rules which weren't merged into result
rule_vector::iterator it = first;
for (; it!=after_last; ++it) {
m_result_rules.push_back(*it);
}
}
rule_set * mk_similarity_compressor::operator()(rule_set const & source) {
// TODO mc
m_modified = false;
unsigned init_rule_cnt = source.get_num_rules();
SASSERT(m_rules.empty());
for (unsigned i=0; i(nullptr);
if (m_modified) {
result = alloc(rule_set, m_context);
unsigned fin_rule_cnt = m_result_rules.size();
for (unsigned i=0; iadd_rule(m_result_rules.get(i));
}
result->inherit_predicates(source);
}
reset();
return result;
}
};