【问题标题】:How to split set of vertices with Boost Graph?如何使用 Boost Graph 分割顶点集?
【发布时间】:2021-12-28 09:03:22
【问题描述】:

我正在用 C++ 编写一些算法,用于使用 Boost Graphadjacency_list 进行并行图形着色。 我正在处理非常大的图(最小的有 32K 个顶点)。

我正在尝试做的是获取整个顶点集,将它们分成几部分并将每个部分分配给不同的线程并并行工作,但我在一些段落中遇到了困难。

基本思路是什么:

int step = g.m_vertices.size()/4;
int min = 0;

for(int i = 0; i < 4; i++){
    // call the function
}

而我在里面调用的函数就是这样的

for (vp = vertices(g); vp.first != vp.second; ++vp.first) {
    cout << *vp.first << endl;
}

所以我有两个问题:

  1. g.m_vertices.size()/4; 是正确的解决方案吗?如果最初我有 10 个顶点,那么我删除了中间的一些顶点(例如 4 个),只剩下 6 个顶点(所以这是新大小)但是顶点的索引从 0 到 5还是从 0 到 9

  2. 如何只将顶点子集传递给 vp 而不是传递vertices(g)

【问题讨论】:

  • 这是并行for_each算法的普遍问题吗?如果是,您是否考虑过使用std::for_eachstd::execution::par 执行策略?
  • @smitsyn 是的,我做到了。我正在寻找一些更有效的解决方案(如果实施起来不太难)

标签: c++ graph boost parallel-processing


【解决方案1】:

g.m_vertices.size()/4;是正确的解决方案吗?

这仅取决于您的要求。

如果最初我有 10 个顶点,那么我删除中间的一些顶点(例如 4 个),只剩下 6 个顶点(所以这是新大小),但顶点的索引从 0 到 5 或从 0 到9?

这取决于您的图形模型。您没有指定图表的类型(我知道,您确实说的是哪个模板,而不是模板参数)。假设顶点容器选择器为 vecS,那么是的,在 4 次删除后,顶点描述符(和索引)将为 [0,6)。

如何只将顶点的子集传递给vp而不是传递顶点(g)

很多方法。

  1. 您可以std::for_each 使用并行执行策略
  2. 您可以使用 openmp 从普通循环创建并行部分
  3. 您可以使用filtered_graph 适配器创建底层图形的 4 个“视图”并对其进行操作
  4. 您可以使用PBGL,它实际上是为处理大图而创建的。这具有额外的好处,它可以与线程/进程间/主机间通信一起使用,可以跨段协调算法等。
  5. 您可以使用sub_graphs;如果您的图表构建方式具有自然分割,这主要(仅)有趣

没有一个解决方案是微不足道的。但是,这里是使用filtered_graph 的简单演示:

Live On Compiler Explorer

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/random.hpp>
#include <iostream>
#include <random>

using G = boost::adjacency_list<>;
using V = G::vertex_descriptor;

G make_graph() {
    G g;
    std::mt19937 prng(std::random_device{}());
    generate_random_graph(g, 32 * 1024 - (prng() % 37), 64 * 1024, prng);
    return g;
}

template <int NSegments, int Segment> struct SegmentVertices {
    std::hash<V> _h;
    bool operator()(V vd) const { return (_h(vd) % NSegments) == Segment; }
};

template <int N>
using Quart = boost::filtered_graph<G, boost::keep_all, SegmentVertices<4, N>>;

template <typename Graph>
void the_function(Graph const& g, std::string_view name)
{
    std::cout << name << " " << size(boost::make_iterator_range(vertices(g)))
            << " vertices\n";
}

int main()
{
    G g = make_graph();
    the_function(g, "full graph");

    Quart<0> f0(g, {}, {});
    Quart<1> f1(g, {}, {});
    Quart<2> f2(g, {}, {});
    Quart<3> f3(g, {}, {});

    the_function(f0, "f0");
    the_function(f1, "f1");
    the_function(f2, "f2");
    the_function(f3, "f3");
}

打印例如

full graph 32766 vertices
f0 8192 vertices
f1 8192 vertices
f2 8191 vertices
f3 8191 vertices

【讨论】:

  • 谢谢。我正在使用 vecS,但我并不完全了解它是如何工作的,我必须更好地研究它。对于第二个答案,我想我正在尝试使用 filters_graph 适配器,看看它是否在我的项目中正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-07
  • 1970-01-01
  • 2017-06-10
  • 2010-10-14
相关资源
最近更新 更多