简体   繁体   English

N Boost interval_set的组合

[英]Combinations of N Boost interval_set

I have a service which has outages in 4 different locations. 我有一个服务,在4个不同的地方停运。 I am modeling each location outages into a Boost ICL interval_set. 我将每个位置中断建模为Boost ICL interval_set。 I want to know when at least N locations have an active outage. 我想知道什么时候至少有N个地点有活动中断。

Therefore, following this answer , I have implemented a combination algorithm, so I can create combinations between elemenets via interval_set intersections. 因此,在这个答案之后 ,我实现了一个组合算法,因此我可以通过interval_set交集创建elemenets之间的组合。

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. 当这个过程结束时,我应该有一定数量的interval_set,每个interval_set同时定义N个位置的中断,最后一步将加入它们以获得所需的全图。

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. 问题是我正在调试代码,当打印每个交集的时间到了,输出文本变得疯狂(即使我正在逐步使用gdb进行调试),我看不到它们,导致大量CPU使用。

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. 我想我不知何故发送输出的内存比我应该多,但我看不出问题出在哪里。

This is a SSCCE: 这是一个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;
}

Any help? 有帮助吗?

As I surmised , there's a "highlevel" approach here. 正如我猜测的那样 ,这里有一种“高级”方法。

Boost ICL containers are more than just containers of "glorified pairs of interval starting/end points". 提升ICL容器不仅仅是“美化的间隔起点/终点对”的容器。 They are designed to implement just that business of combining, searching, in a generically optimized fashion. 他们的目的是实现这一点相结合,搜索,在一般优化的方式经营。

So you don't have to. 所以不必。

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

Using functional domain typedefs invites a higher level approach. 使用功能域typedef会引发更高级别的方法。 Now, let's ask the hypothetical "business question": 现在,让我们问一下假设的“商业问题”:

What do we actually want to do with our records of per-location downtimes? 我们对每个位置停机记录实际上想做些什么?

Well, we essentially want to 好吧,我们基本上想要

  1. tally them for all discernable time slots and 为所有可辨别的时间段计算它们
  2. filter those where tallies are at least 2 过滤那些标签至少为2的那些
  3. finally, we'd like to show the "merged" time slots that remain. 最后,我们想展示剩下的“合并”时段。

Ok, engineer: implement it! 好的,工程师:实现它!


  1. Hmm. 嗯。 Tallying. 清点。 How hard could it be? 它能有多难?

    ❕ The key to elegant solutions is the choice of the right datastructure elegant优雅解决方案的关键是选择正确的数据结构

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

    Now it's just bulk insertion: 现在它只是批量插入:

     // 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}); 
  2. Ok, let's filter. 好的,让我们过滤一下。 We just need the predicate that works on our DownMap, right 我们只需要适用于我们的DownMap的谓词,对吧

     // define threshold where at least 2 locations have an outage auto exceeds_threshold = [](DownMap::value_type const& slot) { return slot.second >= 2; }; 
  3. Merge the time slots! 合并时间段!

    Actually. 其实。 We just create another DownTimes set, right. 我们只是创建另一个DownTimes集。 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); 

Report! 报告!

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

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. 或者,[eeeeek!]收集元素的强力排列。

We just stated our goals, and let the library do the work. 我们刚刚阐述了目标,让图书馆开展工作。

Full Demo 完整的演示

Live On Coliru 住在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";
}

Which prints 哪个打印

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

At the end of the permutation loop, you write: 在置换循环结束时,你写道:

numCombinations++;
std::cout << "[-INTERSEC-] " << combinations[numCombinations] << std::endl;  // The problem appears here

My debugger tells me that on the first iteration numCombinations was 0 before the increment. 我的调试器告诉我,在第一次迭代时, numCombinations在增量之前 0。 But incrementing it made it out of range for the combinations container (since that is only a single element, so having index 0). 但是增加它会使它超出combinations容器的范围(因为它只是一个元素,所以索引为0)。

Did you mean to increment it after the use? 你的意思是在使用后增加它吗? Was there any particular reason not to use 有没有特别的理由不使用

std::cout << "[-INTERSEC-] " << combinations.back() << "\n";

or, for c++03 或者,对于c ++ 03

std::cout << "[-INTERSEC-] " << combinations[combinations.size()-1] << "\n";

or even just: 甚至只是:

std::cout << "[-INTERSEC-] " << combinations.at(numCombinations) << "\n";

which would have thrown std::out_of_range ? 哪个会抛出std::out_of_range


On a side note, I think Boost ICL has vastly more efficient ways to get the answer you're after. 在一个侧面说明,我认为加速ICL已大大更有效的方式得到你想要的是答案。 Let me think about this for a moment. 让我考虑一下这一点。 Will post another answer if I see it. 如果我看到它会发布另一个答案。

UPDATE : Posted the other answer show casing highlevel coding with Boost ICL 更新 :发布其他答案展示使用Boost ICL进行高级编码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM