N Boost interval_set 的组合
Posted
技术标签:
【中文标题】N Boost interval_set 的组合【英文标题】:Combinations of N Boost interval_set 【发布时间】:2015-04-03 21:13:17 【问题描述】:我有一项服务在 4 个不同的位置中断。我将每个位置中断建模为 Boost ICL interval_set。我想知道至少有 N 个位置何时发生活动中断。
因此,在this answer之后,我实现了一个组合算法,因此我可以通过interval_set交集在元素之间创建组合。
当这个过程结束时,我应该有一定数量的 interval_set,它们中的每一个同时定义 N 个位置的中断,最后一步将加入它们以获得所需的全貌。
问题是我目前正在调试代码,当打印每个交叉点的时间到了,输出的文字就变得疯狂了(即使我是用gdb一步步调试的时候),我不能看到它们,导致大量 CPU 使用。
我猜我以某种方式发送以输出比我应该的更大部分的内存,但我看不出问题出在哪里。
这是一个 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;
有什么帮助吗?
【问题讨论】:
【参考方案1】:作为I surmised,这里有一个“高级”方法。
Boost ICL 容器不仅仅是“美化的间隔起点/终点对”的容器。它们旨在以一般优化的方式实现只是组合、搜索的业务。
所以你不必这样做。
如果你让图书馆做它应该做的事情:
using TimePoint = unsigned;
using DownTimes = boost::icl::interval_set<TimePoint>;
using Interval = DownTimes::interval_type;
using Records = std::vector<DownTimes>;
使用功能域 typedef 会带来更高级别的方法。现在,让我们提出假设的“业务问题”:
我们实际上想对每个位置的停机时间记录做什么?
好吧,我们本质上想要
-
为所有可识别的时间段统计它们并
过滤计数至少为 2 的那些
最后,我们想显示剩余的“合并”时隙。
好的,工程师:实现它!
嗯。统计。它能有多难?
❕ 优雅解决方案的关键是选择正确的数据结构
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 的谓词,对吧
// define threshold where at least 2 locations have an outage
auto exceeds_threshold = [](DownMap::value_type const& slot)
return slot.second >= 2;
;
合并时间段!
其实。我们只是创建另一个 DownTimes 集,对。只是,这次不是每个位置。
数据结构的选择再次获胜:
// 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!] 集合元素的暴力排列。
我们只是陈述了我们的目标,让图书馆来做这项工作。
完整演示
Live On 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]
【讨论】:
【参考方案2】:在置换循环的最后,你写:
numCombinations++;
std::cout << "[-INTERSEC-] " << combinations[numCombinations] << std::endl; // The problem appears here
我的调试器告诉我,在第一次迭代中numCombinations
在增量之前是 0。但是增加它会使它超出combinations
容器的范围(因为它只是一个元素,所以索引为 0)。
您的意思是在使用后增加它吗?有什么特别的理由不使用
std::cout << "[-INTERSEC-] " << combinations.back() << "\n";
或者,对于 c++03
std::cout << "[-INTERSEC-] " << combinations[combinations.size()-1] << "\n";
甚至只是:
std::cout << "[-INTERSEC-] " << combinations.at(numCombinations) << "\n";
哪个会抛出std::out_of_range
?
另一方面,我认为 Boost ICL 有大量更有效的方法来获得您所追求的答案。让我考虑一下。如果我看到它会发布另一个答案。
更新:发布了 other answer 展示了使用 Boost ICL 进行外壳高级编码
【讨论】:
以上是关于N Boost interval_set 的组合的主要内容,如果未能解决你的问题,请参考以下文章
在 boost.python 中;如何公开包含在另一个类中的类(通过组合)?
在 boost.python 中;如何公开包含在另一个类中的类(通过组合)?