Skip to content

File support-meat.hpp

File List > barry > support-meat.hpp

Go to the documentation of this file

#ifndef BARRY_SUPPORT_MEAT
#define BARRY_SUPPORT_MEAT_HPP 1

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::init_support(
    std::vector< Array_Type > * array_bank,
    std::vector< double > * stats_bank
) {

    // Resetting the counter
    this->iter_counter = 0u;

    // Computing the locations
    coordinates_free.clear();
    coordinates_locked.clear();
    rules->get_seq(EmptyArray, &coordinates_free, &coordinates_locked);

    coordiantes_n_free   = coordinates_free.size() / 2u;
    coordiantes_n_locked = coordinates_locked.size() / 2u;
    n_counters           = counters->size();

    hashes.resize(coordiantes_n_free, 0u);
    hashes_initialized.resize(coordiantes_n_free, false);

    // Computing initial statistics
    if (EmptyArray.nnozero() > 0u)
    {

        for (size_t i = 0u; i < coordiantes_n_free; ++i)
            EmptyArray.rm_cell(
                coordinates_free[i * 2u],
                coordinates_free[i * 2u + 1u],
                false, true
                );

    }

    // Looked coordinates should still be removed if these are
    // equivalent to zero
    for (size_t i = 0u; i < coordiantes_n_locked; ++i)
    {

        if (static_cast<int>(EmptyArray(
            coordinates_locked[i * 2u], coordinates_locked[i * 2u + 1u]
            )) == 0)

            EmptyArray.rm_cell(
                coordinates_locked[i * 2u],
                coordinates_locked[i * 2u + 1u],
                false, true
                );

    }

    // Do we have any counter?
    if (n_counters == 0u)
        throw std::logic_error("No counters added: Cannot compute the support without knowning what to count!");

    // Initial count (including constrains)
    if (coordiantes_n_locked)
    {

        StatsCounter<Array_Type,Data_Counter_Type> tmpcount(&EmptyArray);
        tmpcount.set_counters(counters);
        current_stats = tmpcount.count_all();

    }
    else
    {

        current_stats.resize(n_counters, 0.0);

        // Initialize counters
        for (size_t n = 0u; n < n_counters; ++n)
        {

            current_stats[n] = counters->operator[](n).init(
                EmptyArray,
                coordinates_free[0u],
                coordinates_free[1u]
                );

        }

    }

    // Resizing support
    data.reserve(
        pow(2.0, static_cast<double>(coordiantes_n_free)),
        counters->size()
        ); 

    // Adding to the overall count
    bool include_it = rules_dyn->operator()(EmptyArray, 0u, 0u);
    if (include_it)
        data.add(current_stats, nullptr);

    change_stats.resize(coordiantes_n_free * n_counters, 0.0);

    if (include_it && (array_bank != nullptr)) 
        array_bank->push_back(EmptyArray);

    if (include_it && (stats_bank != nullptr))
        std::copy(current_stats.begin(), current_stats.end(), std::back_inserter(*stats_bank));

    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::reset_array() {

    data.clear();

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::reset_array(const Array_Type & Array_) {

    data.clear();
    EmptyArray = Array_;
    N = Array_.nrow();
    M = Array_.ncol();

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::calc_backend_sparse(
        size_t pos,
        std::vector< Array_Type > * array_bank,
        std::vector< double > * stats_bank
    ) {

    #ifdef BARRY_USER_INTERRUPT
    if (++iter_counter % 1000u == 0u)
    {
        BARRY_USER_INTERRUPT
    }
    #endif

    // Did we reached the end??
    if (pos >= coordiantes_n_free)
        return;

    // We will pass it to the next step, if the iteration makes sense.
    calc_backend_sparse(pos + 1u, array_bank, stats_bank);

    // Once we have returned, everything will be back as it used to be, so we
    // treat the data as if nothing has changed.
    const size_t & coord_i = coordinates_free[pos * 2u];
    const size_t & coord_j = coordinates_free[pos * 2u + 1u];

    // Toggle the cell (we will toggle it back after calling the counter)
    EmptyArray.insert_cell(
        coord_i,
        coord_j,
        EmptyArray.default_val().value,
        false, false
        );

    // Counting
    // std::vector< double > change_stats(counters.size());
    double tmp_chng;
    size_t change_stats_different = hashes_initialized[pos] ? 0u : 1u;
    for (size_t n = 0u; n < n_counters; ++n)
    {

        tmp_chng = counters->operator[](n).count(
            EmptyArray,
            coord_i,
            coord_j
            );

        if ((tmp_chng < DBL_MIN) & (tmp_chng > -DBL_MIN))
        {

            change_stats[pos * n_counters + n] = 0.0;

        }
        else
        {

            change_stats_different++;
            current_stats[n] += tmp_chng;
            change_stats[pos * n_counters + n] = tmp_chng;

        }

    }

    // Adding to the overall count
    BARRY_CHECK_SUPPORT(data, max_num_elements)
    if (rules_dyn->size() > 0u)
    {

        if (rules_dyn->operator()(
            EmptyArray,
            coord_i,
            coord_j
            ))
        {

            if (change_stats_different > 0u)
                hashes[pos] = data.add(current_stats, nullptr);
            else
                (void) data.add(current_stats, &hashes[pos]);

            // Need to save?
            if (array_bank != nullptr)
                array_bank->push_back(EmptyArray);

            if (stats_bank != nullptr)
                std::copy(current_stats.begin(), current_stats.end(), std::back_inserter(*stats_bank));

        }


    } else {

        if (change_stats_different > 0u)
            hashes[pos] = data.add(current_stats, nullptr);
        else
            (void) data.add(current_stats, &hashes[pos]);

        // Need to save?
        if (array_bank != nullptr)
            array_bank->push_back(EmptyArray);

        if (stats_bank != nullptr)
            std::copy(current_stats.begin(), current_stats.end(), std::back_inserter(*stats_bank));

    }

    // Again, we only pass it to the next level iff the next level is not
    // passed the last step.
    calc_backend_sparse(pos + 1u, array_bank, stats_bank);

    // We need to restore the state of the cell
    EmptyArray.rm_cell(
        coord_i,
        coord_j,
        false, false
        );

    if (change_stats_different > 0u)
    {
        #if defined(__OPENMP) || defined(_OPENMP)
        #pragma omp simd
        #endif
        for (size_t n = 0u; n < n_counters; ++n) 
            current_stats[n] -= change_stats[pos * n_counters + n];
    }


    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::calc_backend_dense(
        size_t pos,
        std::vector< Array_Type > * array_bank,
        std::vector< double > * stats_bank
    ) {

    #ifdef BARRY_USER_INTERRUPT
    if (++iter_counter % 1000u == 0u)
    {
        BARRY_USER_INTERRUPT
    }
    #endif

    // Did we reached the end??
    if (pos >= coordiantes_n_free)
        return;

    // We will pass it to the next step, if the iteration makes sense.
    calc_backend_dense(pos + 1u, array_bank, stats_bank);

    // Once we have returned, everything will be back as it used to be, so we
    // treat the data as if nothing has changed.
    const size_t & coord_i = coordinates_free[pos * 2u];
    const size_t & coord_j = coordinates_free[pos * 2u + 1u];

    // Toggle the cell (we will toggle it back after calling the counter)
    EmptyArray.insert_cell(coord_i, coord_j, 1, false, false);

    // Counting
    // std::vector< double > change_stats(counters.size());
    double tmp_chng;
    size_t change_stats_different = hashes_initialized[pos] ? 0u : 1u;
    for (size_t n = 0u; n < n_counters; ++n)
    {

        tmp_chng = counters->operator[](n).count(
            EmptyArray,
            coord_i,
            coord_j
            );

        if ((tmp_chng < DBL_MIN) & (tmp_chng > -DBL_MIN))
        {

            change_stats[pos * n_counters + n] = 0.0;

        }
        else
        {
            if (std::isnan(tmp_chng))
                throw std::domain_error("Undefined number.");

            change_stats_different++;
            current_stats[n] += tmp_chng;
            change_stats[pos * n_counters + n] = tmp_chng;

        }

    }

    // Adding to the overall count
    BARRY_CHECK_SUPPORT(data, max_num_elements)
    if (rules_dyn->size() > 0u)
    {

        if (rules_dyn->operator()(EmptyArray, coord_i, coord_j))
        {

            if (change_stats_different > 0u)
                hashes[pos] = data.add(current_stats, nullptr);
            else
                (void) data.add(current_stats, &hashes[pos]);

            // Need to save?
            if (array_bank != nullptr)
                array_bank->push_back(EmptyArray);

            if (stats_bank != nullptr)
                std::copy(current_stats.begin(), current_stats.end(), std::back_inserter(*stats_bank));

        }


    }
    else
    {

        if (change_stats_different > 0u)
            hashes[pos] = data.add(current_stats, nullptr);
        else
            (void) data.add(current_stats, &hashes[pos]);

        // Need to save?
        if (array_bank != nullptr)
            array_bank->push_back(EmptyArray);

        if (stats_bank != nullptr)
            std::copy(current_stats.begin(), current_stats.end(), std::back_inserter(*stats_bank));

    }

    // Again, we only pass it to the next level iff the next level is not
    // passed the last step.
    calc_backend_dense(pos + 1u, array_bank, stats_bank);

    // We need to restore the state of the cell
    EmptyArray.rm_cell(coord_i, coord_j, false, false);

    if (change_stats_different > 0u)
    {
        #if defined(__OPENMP) || defined(_OPENMP)
        #pragma omp simd
        #endif
        for (size_t n = 0u; n < n_counters; ++n) 
            current_stats[n] -= change_stats[pos * n_counters + n];
    }

    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void
Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::calc(
    std::vector< Array_Type > * array_bank,
    std::vector< double > * stats_bank,
    size_t max_num_elements_
) {

    if (max_num_elements_ != 0u)
        this->max_num_elements = max_num_elements_;

    // Generating sequence
    this->init_support(array_bank, stats_bank);

    // Recursive function to count
    if (EmptyArray.is_dense())
        calc_backend_dense(0u, array_bank, stats_bank);
    else
        calc_backend_sparse(0u, array_bank, stats_bank);

    change_stats.clear();

    if (max_num_elements_ != 0u)
        this->max_num_elements = BARRY_MAX_NUM_ELEMENTS;

    if (this->data.size() == 0u)
    {
        throw std::logic_error("The array has support of size 0 (i.e., empty support). This could be a problem in the rules (constraints).\n");
    }


    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::add_counter(
        Counter<Array_Type,Data_Counter_Type> f_
) {

    counters->add_counter(f_);
    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::set_counters(
        Counters<Array_Type,Data_Counter_Type> * counters_
) {

    // Cleaning up before replacing the memory
    if (delete_counters)
        delete counters;
    delete_counters = false;
    counters = counters_;

    return;

}


template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::add_rule(
        Rule<Array_Type, Data_Rule_Type> * f_
) {

    rules->add_rule(f_);
    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::add_rule(
        Rule<Array_Type,Data_Rule_Type> f_
) {

    rules->add_rule(f_);
    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::set_rules(
        Rules<Array_Type,Data_Rule_Type> * rules_
) {

    // Cleaning up before replacing the memory
    if (delete_rules)
        delete rules;
    delete_rules = false;
    rules = rules_;

    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::add_rule_dyn(
        Rule<Array_Type, Data_Rule_Dyn_Type> * f_
) {

    rules_dyn->add_rule(f_);
    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::add_rule_dyn(
        Rule<Array_Type,Data_Rule_Dyn_Type> f_
) {

    rules_dyn->add_rule(f_);
    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::set_rules_dyn(
        Rules<Array_Type,Data_Rule_Dyn_Type> * rules_
) {

    // Cleaning up before replacing the memory
    if (delete_rules_dyn)
        delete rules_dyn;
    delete_rules_dyn = false;
    rules_dyn = rules_;

    return;

}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline bool Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::eval_rules_dyn(
    const std::vector< double > & counts,
    const size_t & i,
    const size_t & j
) {

    if (rules_dyn->size() == 0u)
        return true;

    // Swapping pointers for a while
    std::vector< double > tmpstats = current_stats;
    current_stats = counts;

    bool rule_res = rules_dyn->operator()(EmptyArray, i, j);
    current_stats = tmpstats;

    return rule_res;

}

// template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
//inline bool Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::eval_rules_dyn(
//     const double * counts,
//     const size_t & i,
//     const size_t & j
// ) {

//     if (rules_dyn->size() == 0u)
//         return true;

//     // Swapping pointers for a while
//     std::vector< double > tmpstats = current_stats;
//     current_stats = counts;

//     bool rule_res = rules_dyn->operator()(EmptyArray, i, j);
//     current_stats = tmpstats;

//     return rule_res;

// }

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline const std::vector< double > & Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::get_counts() const {

    return data.get_data(); 

}

// template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
// inline const MapVec_type<> * Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::get_counts_ptr() const {

//     return data.get_data_ptr();

// }

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline std::vector< double > * Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::get_current_stats() {
    return &this->current_stats;
}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline void Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::print() const {

    // Starting from the name of the stats
    printf_barry("Position of variables:\n");
    for (size_t i = 0u; i < n_counters; ++i)
    {
        printf_barry(
            "[% 2i] %s\n",
            static_cast<int>(i),
            counters->operator[](i).name.c_str()
        );
    }

    data.print();
}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline const FreqTable<double> & Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::get_data() const {
    return this->data;
}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline Counters<Array_Type,Data_Counter_Type> * Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::get_counters() {
    return this->counters;
}   

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline Rules<Array_Type,Data_Rule_Type> * Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::get_rules() {
    return this->rules;
}

template <typename Array_Type, typename Data_Counter_Type, typename Data_Rule_Type, typename Data_Rule_Dyn_Type>
inline Rules<Array_Type,Data_Rule_Dyn_Type> * Support<Array_Type,Data_Counter_Type,Data_Rule_Type, Data_Rule_Dyn_Type>::get_rules_dyn() {
    return this->rules_dyn;
}


#endif