All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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;
    }
};




© 2015 - 2024 Weber Informatics LLC | Privacy Policy