N个Boost interval_set的组合 [英] Combinations of N Boost interval_set

查看:81
本文介绍了N个Boost interval_set的组合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一项服务,该服务在4个不同的位置都发生了故障.我正在将每个位置中断建模为Boost ICL interval_set.我想知道至少N个位置何时发生活动中断.

I have a service which has outages in 4 different locations. I am modeling each location outages into a Boost ICL interval_set. I want to know when at least N locations have an active outage.

因此,按照这个答案,我实现了一种组合算法,因此我可以通过interval_set相交来创建元素之间的组合

Therefore, following this answer, I have implemented a combination algorithm, so I can create combinations between elemenets via interval_set intersections.

此过程结束后,我应该有一定数量的interval_set,其中每个都同时定义N个位置的中断,最后一步是将它们合并以获得所需的全貌.

Whehn this process is over, I should have a certain number of interval_set, each one of them defining the outages for N locations simultaneusly, and the final step will be joining them to get the desired full picture.

问题是我当前正在调试代码,并且当打印每个相交的时间到来时,输出文本变得疯狂(即使当我使用gdb逐步调试时),我也无法看到它们,导致大量的CPU使用率.

The problem is that I'm currently debugging the code, and when the time of printing each intersection arrives, the output text gets crazy (even when I'm using gdb to debug step by step), and I can't see them, resulting in a lot of CPU usage.

我想我会以某种方式发送输出比我应有的更大的内存,但是我看不出问题出在哪里.

I guess that somehow I'm sending to output a larger portion of memory than I should, but I can't see where the problem is.

这是一个SSCCE:

#include <boost/icl/interval_set.hpp>
#include <algorithm>
#include <iostream>
#include <vector>


int main() {
    // Initializing data for test
    std::vector<boost::icl::interval_set<unsigned int> > outagesPerLocation;
    for(unsigned int j=0; j<4; j++){
        boost::icl::interval_set<unsigned int> outages;
        for(unsigned int i=0; i<5; i++){
            outages += boost::icl::discrete_interval<unsigned int>::closed(
                (i*10), ((i*10) + 5 - j));
        }
        std::cout << "[Location " << (j+1) << "] " << outages << std::endl;
        outagesPerLocation.push_back(outages);
    }

    // So now we have a vector of interval_sets, one per location. We will combine
    // them so we get an interval_set defined for those periods where at least
    // 2 locations have an outage (N)
    unsigned int simultaneusOutagesRequired = 2;  // (N)

    // Create a bool vector in order to filter permutations, and only get
    // the sorted permutations (which equals the combinations)
    std::vector<bool> auxVector(outagesPerLocation.size());
    std::fill(auxVector.begin() + simultaneusOutagesRequired, auxVector.end(), true);

    // Create a vector where combinations will be stored
    std::vector<boost::icl::interval_set<unsigned int> > combinations;

    // Get all the combinations of N elements
    unsigned int numCombinations = 0;
    do{
        bool firstElementSet = false;
        for(unsigned int i=0; i<auxVector.size(); i++){
            if(!auxVector[i]){
                if(!firstElementSet){
                    // First location, insert to combinations vector
                    combinations.push_back(outagesPerLocation[i]);
                    firstElementSet = true;
                }
                else{
                    // Intersect with the other locations
                    combinations[numCombinations] -= outagesPerLocation[i];
                }
            }
        }
        numCombinations++;
        std::cout << "[-INTERSEC-] " << combinations[numCombinations] << std::endl;  // The problem appears here
    }
    while(std::next_permutation(auxVector.begin(), auxVector.end()));

    // Get the union of the intersections and see the results
    boost::icl::interval_set<unsigned int> finalOutages;
    for(std::vector<boost::icl::interval_set<unsigned int> >::iterator
        it = combinations.begin(); it != combinations.end(); it++){
        finalOutages += *it;
    }

    std::cout << finalOutages << std::endl;
    return 0;
}

有帮助吗?

推荐答案

正如我推测,这是高级"靠近这里.

As I surmised, there's a "highlevel" approach here.

增强的ICL容器不仅仅是间隔化的起点/终点对"的容器.它们旨在以通用优化的方式实现恰好的合并,搜索业务.

Boost ICL containers are more than just containers of "glorified pairs of interval starting/end points". They are designed to implement just that business of combining, searching, in a generically optimized fashion.

如果您让图书馆去做应该做的事情:

If you let the library do what it's supposed to do:

using TimePoint = unsigned;
using DownTimes = boost::icl::interval_set<TimePoint>;
using Interval  = DownTimes::interval_type;
using Records   = std::vector<DownTimes>;

使用功能域typedefs会提出更高层次的方法.现在,让我们问一个假想的业务问题":

Using functional domain typedefs invites a higher level approach. Now, let's ask the hypothetical "business question":

我们实际上希望对每个位置的停机时间进行记录吗?

好吧,我们本质上想

  1. 统计所有可识别的时间段和
  2. 过滤那些计数至少为2的那些
  3. 最后,我们想显示剩余的合并"时隙.

好的,工程师:实施它!

Ok, engineer: implement it!

  1. 嗯.理货.它能有多难?

  1. Hmm. Tallying. How hard could it be?

❕优雅解决方案的关键是选择正确的数据结构

❕ The key to elegant solutions is the choice of the right datastructure

using Tally     = unsigned; // or: bit mask representing affected locations?
using DownMap   = boost::icl::interval_map<TimePoint, Tally>;

现在只是批量插入:

// We will do a tally of affected locations per time slot
DownMap tallied;
for (auto& location : records)
    for (auto& incident : location)
        tallied.add({incident, 1u});

  • 好,让我们过滤一下.我们只需要适用于DownMap的谓词,

  • Ok, let's filter. We just need the predicate that works on our DownMap, right

    // define threshold where at least 2 locations have an outage
    auto exceeds_threshold = [](DownMap::value_type const& slot) {
        return slot.second >= 2;
    };
    

  • 合并时隙!

  • Merge the time slots!

    实际上.我们只是创建另一个DownTimes集.只是,这次不是按位置.

    Actually. We just create another DownTimes set, right. Just, not per location this time.

    数据结构的选择再次赢得了胜利:

    The choice of data structure wins the day again:

    // just printing the union of any criticals:
    DownTimes merged;
    for (auto&& slot : tallied | filtered(exceeds_threshold) | map_keys)
        merged.insert(slot);
    

  • 报告!

    std::cout << "Criticals: " << merged << "\n";
    

    请注意,我们没有哪个地方可以操纵数组索引,重叠或不重叠的间隔,封闭或开放的边界.或者,[eeeeek!]收集元素的暴力置换.

    Note that nowhere did we come close to manipulating array indices, overlapping or non-overlapping intervals, closed or open boundaries. Or, [eeeeek!] brute force permutations of collection elements.

    我们只是陈述了我们的目标,然后让图书馆来完成工作.

    We just stated our goals, and let the library do the work.

    在Coliru上直播

    #include <boost/icl/interval_set.hpp>
    #include <boost/icl/interval_map.hpp>
    #include <boost/range.hpp>
    #include <boost/range/algorithm.hpp>
    #include <boost/range/adaptors.hpp>
    #include <boost/range/numeric.hpp>
    #include <boost/range/irange.hpp>
    #include <algorithm>
    #include <iostream>
    #include <vector>
    
    using TimePoint = unsigned;
    using DownTimes = boost::icl::interval_set<TimePoint>;
    using Interval  = DownTimes::interval_type;
    using Records   = std::vector<DownTimes>;
    
    using Tally     = unsigned; // or: bit mask representing affected locations?
    using DownMap   = boost::icl::interval_map<TimePoint, Tally>;
    
    // Just for fun, removed the explicit loops from the generation too. Obviously,
    // this is bit gratuitous :)
    static DownTimes generate_downtime(int j) {
        return boost::accumulate(
                boost::irange(0, 5),
                DownTimes{},
                [j](DownTimes accum, int i) { return accum + Interval::closed((i*10), ((i*10) + 5 - j)); }
            );
    }
    
    int main() {
        // Initializing data for test
        using namespace boost::adaptors;
        auto const records = boost::copy_range<Records>(boost::irange(0,4) | transformed(generate_downtime));
    
        for (auto location : records | indexed()) {
            std::cout << "Location " << (location.index()+1) << " " << location.value() << std::endl;
        }
    
        // We will do a tally of affected locations per time slot
        DownMap tallied;
        for (auto& location : records)
            for (auto& incident : location)
                tallied.add({incident, 1u});
    
        // We will combine them so we get an interval_set defined for those periods
        // where at least 2 locations have an outage
        auto exceeds_threshold = [](DownMap::value_type const& slot) {
            return slot.second >= 2;
        };
    
        // just printing the union of any criticals:
        DownTimes merged;
        for (auto&& slot : tallied | filtered(exceeds_threshold) | map_keys)
            merged.insert(slot);
    
        std::cout << "Criticals: " << merged << "\n";
    }
    

    哪些印刷品

    Location 1 {[0,5][10,15][20,25][30,35][40,45]}
    Location 2 {[0,4][10,14][20,24][30,34][40,44]}
    Location 3 {[0,3][10,13][20,23][30,33][40,43]}
    Location 4 {[0,2][10,12][20,22][30,32][40,42]}
    Criticals: {[0,4][10,14][20,24][30,34][40,44]}
    

    这篇关于N个Boost interval_set的组合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆