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

z3-z3-4.13.0.src.muz.rel.dl_product_relation.cpp Maven / Gradle / Ivy

The newest version!
/*++
Copyright (c) 2010 Microsoft Corporation

Module Name:

    dl_product_relation.cpp

Abstract:

    A Relation combinator.

Author:

    Nikolaj Bjorner (nbjorner) 2010-4-11

Revision History:

Notes:

     join  = 
           more refined version lets augment the product 
           relation as a consequence of join.
            join Q =
              join  = 
             

     u  =  
            more refined version:
                    < (R u R') n (R u S') n (R' u S), (S u S') n (S u R') n (S' u R)>
            

    proj     = < proj R, proj S>

     & phi   = 
                    attach S to [R & phi] whenever R & phi can propagate to S
                    

    [rename] = 



--*/


#include "muz/rel/dl_sieve_relation.h"
#include "muz/rel/dl_table_relation.h"
#include "muz/rel/dl_product_relation.h"
#include "ast/rewriter/bool_rewriter.h"
#include "ast/ast_pp.h"

namespace datalog {

    // -----------------------------------
    //
    // product_relation_plugin
    //
    // -----------------------------------

    product_relation_plugin & product_relation_plugin::get_plugin(relation_manager & rmgr) {
        product_relation_plugin * res = 
            static_cast(rmgr.get_relation_plugin(get_name()));
        if(!res) {
            res = alloc(product_relation_plugin, rmgr);
            rmgr.register_plugin(res);
        }
        return *res;
    }

    product_relation_plugin::product_relation_plugin(relation_manager& m):
        relation_plugin(product_relation_plugin::get_name(), m, ST_PRODUCT_RELATION), 
        m_spec_store(*this) {
    }

    void product_relation_plugin::initialize(family_id fid) { 
        relation_plugin::initialize(fid);
        m_spec_store.add_available_kind(get_kind());
    }

    family_id product_relation_plugin::get_relation_kind(const relation_signature & sig, const rel_spec & spec) {
        SASSERT(spec.well_formed());
        return m_spec_store.get_relation_kind(sig, spec);
    }

    family_id product_relation_plugin::get_relation_kind(const product_relation & r) {
        return get_relation_kind(r.get_signature(), r.m_spec);
    }

    bool product_relation_plugin::can_handle_signature(const relation_signature & s) {
        return m_spec_store.contains_signature(s);
    }

    bool product_relation_plugin::can_handle_signature(const relation_signature & s, family_id k) {
        return true;
    }

    product_relation& product_relation_plugin::get(relation_base& r) {
        return dynamic_cast(r);
    }

    product_relation const & product_relation_plugin::get(relation_base const& r) {
        return dynamic_cast(r);
    }

    product_relation* product_relation_plugin::get(relation_base* r) {
        return dynamic_cast(r);
    }

    product_relation const* product_relation_plugin::get(relation_base const* r) {
        return dynamic_cast(r);
    }

    bool product_relation_plugin::is_product_relation(relation_base const& r) {
        return r.get_plugin().get_name() == product_relation_plugin::get_name();
    }

    bool product_relation_plugin::are_aligned(const product_relation& r1, const product_relation& r2) {
        unsigned sz = r1.size();
        if(sz!=r2.size()) {
            return false;
        }
        for(unsigned i=0; i & rels, 
            rel_spec & res) {
        vector specs;
        ptr_vector::const_iterator rit = rels.begin();
        ptr_vector::const_iterator rend = rels.end();
        for(; rit!=rend; ++rit) {
            specs.push_back((*rit)->m_spec);
            SASSERT(specs.back().well_formed());
            std::sort(specs.back().begin(), specs.back().end());
        }

        vector::iterator sit = specs.begin(), send = specs.end();

        res.reset();
        for(;;) {
            family_id next = -1;

            sit = specs.begin();
            for(; sit!=send; ++sit) {
                rel_spec & s = *sit;
                if(!s.empty() && s.back()>next) {
                    next = s.back();
                }
            }
            if(next==-1) {
                //we're done
                break;
            }
            res.push_back(next);
            sit = specs.begin();
            for(; sit!=send; ++sit) {
                rel_spec & s = *sit;
                while (!s.empty() && s.back()==next) {
                    s.pop_back();
                }
            }
        }
    }


    relation_base * product_relation_plugin::mk_empty(const relation_signature & s) {
        return alloc(product_relation,*this, s);
    }

    relation_base * product_relation_plugin::mk_empty(const relation_signature & s, family_id kind) {
        rel_spec spec;
        m_spec_store.get_relation_spec(s, kind, spec);
        relation_vector inner_rels;
        unsigned rel_cnt = spec.size();
        for(unsigned i=0; im_default_empty = false;
            return result;
        }
        rel_spec spec;
        m_spec_store.get_relation_spec(s, kind, spec);
        SASSERT(spec.well_formed());
        relation_vector inner_rels;
        unsigned rel_cnt = spec.size();
        for(unsigned i=0; i m_joins;
        ptr_vector m_full;
        unsigned_vector           m_offset1;
        svector           m_kind1;
        unsigned_vector           m_offset2;
        svector           m_kind2;

        const relation_base & get_nonsieve_relation(const relation_base & r) {
            relation_plugin & rp = r.get_plugin();
            if(rp.is_sieve_relation()) {
                return static_cast(r).get_inner();
            }
            else {
                return r;
            }
        }

        relation_plugin & get_nonsieve_plugin(const relation_base & r) {
            return get_nonsieve_relation(r).get_plugin();
        }

        family_id get_nonsieve_kind(const relation_base & r) {
            return get_nonsieve_relation(r).get_kind();
        }

        /**
           A tableish relatio is either a table_relation or a sieve_relation with a table_relation inside.
        */
        bool is_tableish_relation(const relation_base & r) {
            return get_nonsieve_plugin(r).from_table();
        }

        relation_base * get_full_tableish_relation(const relation_signature & sig, func_decl* p, family_id kind) {
            relation_manager& rmgr = m_plugin.get_manager();
            table_signature tsig;
            if(rmgr.relation_signature_to_table(sig, tsig)) {
                return rmgr.mk_table_relation(sig, rmgr.get_appropriate_plugin(tsig).mk_full(p, tsig, kind));
            }
            unsigned sz = sig.size();
            tsig.reset();
            for(unsigned i=0; i relations;
            unsigned sz = m_joins.size();
            relation_base* result = nullptr;
            for (unsigned i = 0; i < sz; ++i) {
                relation_base const& r1 = (m_kind1[i] == T_FULL)?(*m_full[m_offset1[i]]):access(m_offset1[i], _r1);
                relation_base const& r2 = (m_kind2[i] == T_FULL)?(*m_full[m_offset2[i]]):access(m_offset2[i], _r2);
                relations.push_back((*m_joins[i])(r1, r2));
            }
            result = alloc(product_relation, m_plugin, get_result_signature(), sz, relations.data());
            TRACE("dl",result->display(tout););
            return result;
        }
    };

    relation_join_fn * product_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2,
            unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) {
        if (is_product_relation(r1) && is_product_relation(r2)) {
            return alloc(join_fn, *this, get(r1), get(r2), col_cnt, cols1, cols2);
        }
        if (is_product_relation(r1)) {
            return alloc(join_fn, *this, get(r1), r2, col_cnt, cols1, cols2);
        }
        if (is_product_relation(r2)) {
            return alloc(join_fn, *this, r1, get(r2), col_cnt, cols1, cols2);
        }
        if (r1.get_kind() != r2.get_kind()) {
            return alloc(join_fn, *this, r1, r2, col_cnt, cols1, cols2);
        }
        return nullptr;
    }


    class product_relation_plugin::transform_fn : public relation_transformer_fn {
        relation_signature                  m_sig;
        ptr_vector m_transforms;
    public:
        transform_fn(relation_signature s, unsigned num_trans, relation_transformer_fn** trans):
          m_sig(std::move(s)),
          m_transforms(num_trans, trans) {}

          ~transform_fn() override { dealloc_ptr_vector_content(m_transforms); }

        relation_base * operator()(const relation_base & _r) override {
            product_relation const& r = get(_r);
            product_relation_plugin& p = r.get_plugin();
            SASSERT(m_transforms.size() == r.size());
            ptr_vector relations;
            for (unsigned i = 0; i < r.size(); ++i) {
                relations.push_back((*m_transforms[i])(r[i]));
            }
            relation_base* result = alloc(product_relation, p, m_sig, relations.size(), relations.data());
            TRACE("dl", _r.display(tout); result->display(tout););
            return result;
        }
    };

    relation_transformer_fn * product_relation_plugin::mk_project_fn(const relation_base & _r, 
            unsigned col_cnt, const unsigned * removed_cols) {
        if (is_product_relation(_r)) {
            product_relation const& r = get(_r);
            ptr_vector projs;
            for (unsigned i = 0; i < r.size(); ++i) {
                projs.push_back(get_manager().mk_project_fn(r[i], col_cnt, removed_cols));
            }
            relation_signature s;
            relation_signature::from_project(r.get_signature(), col_cnt, removed_cols, s);
            return alloc(transform_fn, s, projs.size(), projs.data());
        }
        return nullptr;
    }
   
    relation_transformer_fn * product_relation_plugin::mk_rename_fn(const relation_base & _r, 
            unsigned cycle_len, const unsigned * permutation_cycle) {
        if(is_product_relation(_r)) {
            ptr_vector trans;
            product_relation const& r = get(_r);
            for (unsigned i = 0; i < r.size(); ++i) {                
                trans.push_back(get_manager().mk_rename_fn(r[i], cycle_len, permutation_cycle));
            }
            relation_signature s;
            relation_signature::from_rename(r.get_signature(), cycle_len, permutation_cycle, s);
            return alloc(transform_fn, s, trans.size(), trans.data());
        }
        return nullptr;
    }
     
    class product_relation_plugin::aligned_union_fn : public relation_union_fn {
        relation_manager & m_rmgr;
        product_relation_plugin& m_plugin;
        bool m_is_widen;

        //m_union[i][j] is union between i-th and j-th relation.
        //It can be zero which means that particular union should be skipped.
        vector > m_unions;

        void mk_union_fn(unsigned i, unsigned j, relation_base const& r1, relation_base const& r2,
                const relation_base* delta) {
            relation_manager& rmgr = r1.get_manager();
            relation_union_fn* u = nullptr;
            if (m_is_widen) {
                u = rmgr.mk_widen_fn(r1, r2, delta);
            }
            else {
                u = rmgr.mk_union_fn(r1, r2, delta);
            }
            TRACE("dl_verbose", tout << r1.get_plugin().get_name() << " " << r2.get_plugin().get_name() << " " << (u?"found":"not found") << "\n";); 
            m_unions.back().push_back(u);
        }

        void init(const relation_vector & tgts, const relation_vector & srcs, const relation_vector * deltas) {
            SASSERT(tgts.size()==srcs.size());
            unsigned num = tgts.size();
            for (unsigned i = 0; i < num; ++i) {
                relation_base& r1 = *tgts[i];
                relation_base* delta = deltas ? (*deltas)[i] : 0;
                m_unions.push_back(ptr_vector());  
                for (unsigned j = 0; j < num; ++j) {
                    relation_base& r2 = *srcs[j];
                    mk_union_fn(i, j, r1, r2, delta);
                }
            }
        }

        bool can_do_inner_union(unsigned tgt_idx, unsigned src_idx) {
            return m_unions[tgt_idx][src_idx] != 0;
        }

        void do_inner_union(unsigned tgt_idx, unsigned src_idx, relation_base& tgt, 
                            relation_base& src, relation_base * delta) {
            SASSERT(m_unions[tgt_idx][src_idx]);
            (*m_unions[tgt_idx][src_idx])(tgt, src, delta);
        }
        
        /**
           If tgt is zero, it is assumed to be a full relation.
        */
        void do_destructive_intersection(scoped_rel& tgt, scoped_rel& src) {
            if(!src) {
                return;
            }
            if(!tgt) {
                tgt=src.release();
                return;
            }
            do_intersection(*tgt, *src);
            src = nullptr;
        }

        void do_intersection(relation_base& tgt, relation_base& src) {
            scoped_ptr intersect_fun = 
                m_rmgr.mk_filter_by_intersection_fn(tgt, src);
            if (!intersect_fun) {
                TRACE("dl", tgt.display(tout << "tgt\n"); src.display(tout << "src\n");); 
                warning_msg("intersection does not exist");
                return;
            }
            (*intersect_fun)(tgt, src);
        }
        void do_delta_union(unsigned rel_idx, relation_base& tgt, relation_base& src) {
            scoped_ptr union_fun = m_rmgr.mk_union_fn(tgt, src);
            SASSERT(union_fun);
            (*union_fun)(tgt, src);
        }
    public:
        aligned_union_fn(
            product_relation const& tgt, 
            product_relation const& src, 
            product_relation const* delta, 
            bool is_widen) :
                m_rmgr(tgt.get_manager()),
                m_plugin(tgt.get_plugin()),
                m_is_widen(is_widen) {
            SASSERT(vectors_equal(tgt.m_spec, src.m_spec));
            SASSERT(!delta || vectors_equal(tgt.m_spec, delta->m_spec));
            init(tgt.m_relations, src.m_relations, delta ? &delta->m_relations : nullptr);
        }

        ~aligned_union_fn() override {
            unsigned sz = m_unions.size();
            for(unsigned i=0; i side_results;
            ptr_vector side_deltas;

            for (unsigned i = 0; i < num; ++i) {
                relation_base& itgt = tgt[i];
                relation_base* idelta = delta ? &(*delta)[i] : nullptr;

                scoped_rel fresh_delta = idelta ? idelta->get_plugin().mk_empty(*idelta) : nullptr;
                scoped_rel side_result;
                scoped_rel side_delta;

                //compute the side unions with which we will intersect the result of the basic one
                for (unsigned j = 0; j < num; ++j) {
                    if (i == j) {
                        continue; //this is the basic union which we will perform later
                    }
                    if (can_do_inner_union(i, j) && can_do_inner_union(j, i)) {
                        TRACE("dl", itgt.display(tout << "tgt:\n"); src[j].display(tout << "src:\n"););
                        // union[i][j]
                        scoped_rel one_side_union = itgt.clone();
                        scoped_rel one_side_delta = fresh_delta ? fresh_delta->clone() : nullptr;
                        TRACE("dl", one_side_union->display(tout << "union 1:\n"); src[j].display(tout););
                        do_inner_union(i, j, *one_side_union, src[j], one_side_delta.get());
                        TRACE("dl", one_side_union->display(tout << "union:\n"););
                        do_destructive_intersection(side_result, one_side_union);                        
                        TRACE("dl", 
                              side_result->display(tout << "inner-union: " << i << " " << j << "\n");
                              itgt.display(tout << "tgt:\n"););
                        if (one_side_delta) {
                            do_destructive_intersection(side_delta, one_side_delta);
                        }

                        // union[j][i]
                        one_side_union = src[i].clone();
                        one_side_delta = fresh_delta ? fresh_delta->clone() : nullptr;
                        TRACE("dl", one_side_union->display(tout << "union 2:\n"); tgt[j].display(tout););
                        do_inner_union(i, j, *one_side_union, tgt[j], one_side_delta.get());
                        TRACE("dl", one_side_union->display(tout << "union:\n"););
                        do_destructive_intersection(side_result, one_side_union);
                        TRACE("dl", 
                              side_result->display(tout << "inner-union: " << i << " " << j << "\n");
                              itgt.display(tout << "tgt:\n"););
                        if (one_side_delta) {
                            do_destructive_intersection(side_delta, one_side_delta);
                        }
                    }
                }
                side_results.push_back(side_result.release());
                side_deltas.push_back(side_delta.release());
            }
            for (unsigned i = 0; i < num; ++i) {
                relation_base& itgt = tgt[i];
                relation_base* idelta = delta ? &(*delta)[i] : nullptr;
                scoped_rel fresh_delta = idelta ? idelta->get_plugin().mk_empty(*idelta) : nullptr;
                scoped_rel side_result(side_results[i]);
                scoped_rel side_delta(side_deltas[i]);

                // perform the basic union                
                // assume a relation can always perform union with the relation of the same type
                VERIFY(can_do_inner_union(i,i));
                do_inner_union(i, i, itgt, src[i], fresh_delta.get());
                
                if (side_result) {
                    do_intersection(itgt, *side_result);
                    TRACE("dl", side_result->display(tout << "inner-union-end: " << i << "\n"););
                }
                if (fresh_delta) {
                    do_destructive_intersection(fresh_delta,side_delta);
                    SASSERT(idelta);
                    do_delta_union(i, *idelta, *fresh_delta);
                }
            }
            if (num == 0) {
                //we need to handle product relation of no relations separately
                if (!src.m_default_empty && tgt.m_default_empty) {
                    tgt.m_default_empty = false;
                    if (delta) {
                        delta->m_default_empty = false;
                    }
                }
            }
            TRACE("dl", _tgt.display(tout << "dst':\n"); 
                  if (_delta)  _delta->display(tout  << "delta:\n"); ;);
        }
    };

    class product_relation_plugin::unaligned_union_fn : public relation_union_fn {
        bool m_is_widen;
        rel_spec m_common_spec;
        scoped_ptr m_aligned_union_fun;
    public:
        unaligned_union_fn(product_relation const& tgt, product_relation const& src, 
                product_relation const* delta, bool is_widen) : m_is_widen(is_widen) {
            ptr_vector rels;
            rels.push_back(&tgt);
            rels.push_back(&src);
            if(delta) {
                rels.push_back(delta);
            }
            get_common_spec(rels, m_common_spec);
        }


        void operator()(relation_base& _tgt, const relation_base& _src, relation_base* _delta) override {
            TRACE("dl_verbose", _tgt.display(tout << "dst:\n"); _src.display(tout  << "src:\n"););
            product_relation& tgt = get(_tgt);
            product_relation const& src0 = get(_src);
            product_relation* delta = _delta ? get(_delta) : nullptr;

            tgt.convert_spec(m_common_spec);
            if(delta) {
                delta->convert_spec(m_common_spec);
            }
            scoped_rel src_scoped;
            if(src0.get_kind()!=tgt.get_kind()) {
                src_scoped = src0.clone();
                src_scoped->convert_spec(m_common_spec);
            }
            product_relation const& src = src_scoped ? *src_scoped : src0;

            if(!m_aligned_union_fun) {
                m_aligned_union_fun = alloc(aligned_union_fn, tgt, src, delta, m_is_widen);
                SASSERT(m_aligned_union_fun);
            }
            (*m_aligned_union_fun)(tgt, src, delta);
            TRACE("dl", _tgt.display(tout << "dst':\n"); 
                        if (_delta) _delta->display(tout  << "delta:\n"););
        }
    };

    class product_relation_plugin::single_non_transparent_src_union_fn : public relation_union_fn {
        unsigned m_single_rel_idx;
        scoped_ptr m_inner_union_fun;
    public:
        single_non_transparent_src_union_fn(unsigned single_rel_idx, relation_union_fn* inner_union_fun) 
                : m_single_rel_idx(single_rel_idx),
                m_inner_union_fun(inner_union_fun) {}

        void operator()(relation_base& tgt, const relation_base& _src, relation_base* delta) override {
            TRACE("dl", tgt.display(tout); _src.display(tout); );
            product_relation const& src = get(_src);
            (*m_inner_union_fun)(tgt, src[m_single_rel_idx], delta);
        }
    };

    relation_union_fn * product_relation_plugin::mk_union_w_fn(const relation_base & tgt, const relation_base & src,
        const relation_base * delta, bool is_widen) {
        if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) {
            if(are_aligned(get(tgt), get(src)) && (!delta || are_aligned(get(tgt), *get(delta)))) {
                return alloc(aligned_union_fn, get(tgt), get(src), get(delta), is_widen);
            }
            return alloc(unaligned_union_fn, get(tgt), get(src), get(delta), is_widen);
        }
        if (check_kind(src)) {
            TRACE("dl", tgt.display(tout << "different kinds"); src.display(tout););
            const product_relation & p_src = get(src);
            unsigned single_idx;
            if(p_src.try_get_single_non_transparent(single_idx)) {
                relation_union_fn * inner;
                if(is_widen) {
                    inner = get_manager().mk_widen_fn(tgt, p_src[single_idx], delta);
                }
                else {
                    inner = get_manager().mk_union_fn(tgt, p_src[single_idx], delta);
                }
                if (inner) {
                    return alloc(single_non_transparent_src_union_fn, single_idx, inner);
                }
            }
        }
        return nullptr;
    }

    relation_union_fn * product_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src,
        const relation_base * delta) {
        return mk_union_w_fn(tgt, src, delta, false);
    }

    relation_union_fn * product_relation_plugin::mk_widen_fn(
        const relation_base & tgt, const relation_base & src, const relation_base * delta) {
        return mk_union_w_fn(tgt, src, delta, true);
    }

    class product_relation_plugin::mutator_fn : public relation_mutator_fn {
        ptr_vector m_mutators;
    public:
        mutator_fn(unsigned sz, relation_mutator_fn** muts):
          m_mutators(sz, muts) {}

       ~mutator_fn() override { dealloc_ptr_vector_content(m_mutators); }

        void operator()(relation_base & _r) override {
            TRACE("dl", _r.display(tout););
            product_relation& r = get(_r);
            SASSERT(m_mutators.size() == r.size());
            for (unsigned i = 0; i < r.size(); ++i) {
                relation_mutator_fn* m = m_mutators[i];
                if (m) {
                    (*m)(r[i]);
                }
            }
            TRACE("dl", _r.display(tout););
        }
    };


    relation_mutator_fn * product_relation_plugin::mk_filter_identical_fn(
        const relation_base & _t, unsigned col_cnt, const unsigned * identical_cols) {
        
        if(is_product_relation(_t)) {
            bool found = false;
            product_relation const& r = get(_t);
            ptr_vector mutators;
            for (unsigned i = 0; i < r.size(); ++i) {
                relation_mutator_fn* m = get_manager().mk_filter_identical_fn(r[i], col_cnt, identical_cols);
                mutators.push_back(m);
                if (m) found = true;
            }
            if (found) {
                return alloc(mutator_fn, mutators.size(), mutators.data());
            }
        }
        return nullptr;
    }

    relation_mutator_fn * product_relation_plugin::mk_filter_equal_fn(const relation_base & _t, 
        const relation_element & value, unsigned col) {
        if(is_product_relation(_t)) {
            product_relation const& r = get(_t);
            ptr_vector mutators;
            bool found = false;
            for (unsigned i = 0; i < r.size(); ++i) {
                relation_mutator_fn* m = get_manager().mk_filter_equal_fn(r[i], value, col);
                mutators.push_back(m);  
                if (m) found = true;
            }
            if (found) {
                return alloc(mutator_fn, mutators.size(), mutators.data());
            }
        }
        return nullptr;
    }

    class product_relation_plugin::filter_interpreted_fn : public relation_mutator_fn {
        ptr_vector m_mutators;
        svector > m_attach;
    public:

        filter_interpreted_fn(product_relation const& r, app* cond) {            
            for (unsigned i = 0; i < r.size(); ++i) {
                m_mutators.push_back(r.get_manager().mk_filter_interpreted_fn(r[i], cond));
            }
            for (unsigned i = 0; i < r.size(); ++i) {
                relation_mutator_fn& m1 = *(m_mutators[i]);
                for (unsigned j = i + 1; j < r.size(); ++j) {
                    relation_mutator_fn& m2 = *(m_mutators[j]);  
                    if (m1.supports_attachment(r[j])) {
                        m_attach.push_back(std::make_pair(i,j));
                    }
                    if (m2.supports_attachment(r[i])) {
                        m_attach.push_back(std::make_pair(j,i));
                    }
                }
            }
        }

        ~filter_interpreted_fn() override { dealloc_ptr_vector_content(m_mutators); }

        void operator()(relation_base& _r) override {
            TRACE("dl", _r.display(tout););
            product_relation const& r = get(_r);
            for (unsigned i = 0; i < m_attach.size(); ++i) {
                m_mutators[m_attach[i].first]->attach(r[m_attach[i].second]);
            }
            for (unsigned i = 0; i < m_mutators.size(); ++i) {
                (*m_mutators[i])(r[i]);
            }
            TRACE("dl", _r.display(tout););
        }      
    };

    relation_mutator_fn * product_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) {
        return alloc(filter_interpreted_fn, get(t), condition);
    }      


    // -----------------------------------
    //
    // product_relation
    //
    // -----------------------------------

    product_relation::product_relation(product_relation_plugin& p, relation_signature const& s):
        relation_base(p, s), 
        m_default_empty(true) {
        ensure_correct_kind();
    }

    product_relation::product_relation(product_relation_plugin& p, relation_signature const& s, unsigned num_relations, relation_base** relations) :
        relation_base(p, s),
        m_default_empty(true) {
        for (unsigned i = 0; i < num_relations; ++i) {
            SASSERT(relations[i]->get_signature()==s);
            m_relations.push_back(relations[i]);
        }
        ensure_correct_kind();
    }

    product_relation::~product_relation() {
        unsigned num_relations = m_relations.size();
        for (unsigned i = 0; i < num_relations; ++i) {
            m_relations[i]->deallocate();
        }
    }

    product_relation_plugin& product_relation::get_plugin() const {
        return dynamic_cast(relation_base::get_plugin());
    }        

    void product_relation::ensure_correct_kind() {
        unsigned rel_cnt = m_relations.size();
        //the rel_cnt==0 part makes us to update the kind also when the relation is newly created
        bool spec_changed = rel_cnt != m_spec.size() || rel_cnt==0;
        if (spec_changed) {
            m_spec.resize(rel_cnt);
        }
        for (unsigned i = 0; i < rel_cnt; i++) {
            family_id rkind = m_relations[i]->get_kind();
            spec_changed |= (m_spec[i] != rkind);
            m_spec[i] = rkind;
        }
        if (spec_changed) {
            set_kind(get_plugin().get_relation_kind(*this));
        }
    }

    void product_relation::convert_spec(const rel_spec & spec) {

        func_decl* p = nullptr;
        const relation_signature & sig = get_signature();
        family_id new_kind = get_plugin().get_relation_kind(sig, spec);
        if (new_kind == get_kind()) {
            return;
        }

        TRACE("dl", {
                ast_manager& m = get_ast_manager_from_rel_manager(get_manager());
                sig.output(m, tout); tout << "\n";
                for (unsigned i = 0; i < spec.size(); ++i) {
                    tout << spec[i] << " ";
                }
                tout << "\n";
            }
            );

        unsigned old_sz = size();
        unsigned new_sz = spec.size();
        unsigned old_remain = old_sz;
        relation_vector new_rels;

        //the loop is quadratic with the number of relations, maybe we want to fix it
        for(unsigned i=0; iget_kind()==ikind) {
                    irel = m_relations[j];
                    m_relations[j] = 0;
                    old_remain--;
                    break;
                }
            }
            if(!irel) {
                if(old_sz == 0 && m_default_empty) {
                    //The relation didn't contain any inner relations but it was empty,
                    //so we make the newly added relations empty as well.
                    irel = get_manager().mk_empty_relation(sig, ikind);
                }
                else {
                    irel = get_manager().mk_full_relation(sig, p, ikind);
                }
            }
            new_rels.push_back(irel);
        }
        SASSERT(old_remain==0); //the new specification must be a superset of the old one
        m_relations = new_rels;

        set_kind(new_kind);
        m_spec = spec;
        SASSERT(get_kind() == new_kind);        
    }

    bool product_relation::try_get_single_non_transparent(unsigned & idx) const {
        unsigned sz = size();
        bool found = false;
        unsigned candidate;
        for(unsigned i=0; i relations;
        for (unsigned i = 0; i < size(); ++i) {
            relations.push_back((*this)[i].clone());
        }
        product_relation_plugin& p = get_plugin();
        return alloc(product_relation, p, get_signature(), relations.size(), relations.data());
    }

    product_relation * product_relation::complement(func_decl*) const {
        if(m_relations.empty()) {
            product_relation * res = clone();
            res->m_default_empty = !m_default_empty;
            return res;
        }
        UNREACHABLE();
        return nullptr;
    }

    bool product_relation::empty() const {
        if(m_relations.empty()) {
            return m_default_empty;
        }
        for (unsigned i = 0; i < m_relations.size(); ++i) {
            if (m_relations[i]->empty()) {
                return true;
            }
        }
        return false;
    }

    void product_relation::to_formula(expr_ref& fml) const {
        ast_manager& m = fml.get_manager();
        expr_ref_vector conjs(m);
        expr_ref tmp(m);
        for (unsigned i = 0; i < m_relations.size(); ++i) {
            m_relations[i]->to_formula(tmp);
            conjs.push_back(tmp);
        }
        bool_rewriter(m).mk_and(conjs.size(), conjs.data(), fml);
    }

    void product_relation::display(std::ostream & out) const {
        if (m_relations.empty()) {
            out << "{}\n";
            return;
        }
        out << "Product of the following relations:\n";
        for (unsigned i = 0; i < m_relations.size(); ++i) {
            m_relations[i]->display(out);
        }
    }

};







© 2015 - 2024 Weber Informatics LLC | Privacy Policy