【问题标题】:Boost Graph Library: edge insertion slow for large graphBoost Graph Library:大图的边插入速度慢
【发布时间】:2011-12-15 00:09:39
【问题描述】:

我正在尝试使用“智能剪刀”来实现交互式图像分割。因此,我必须从每个顶点代表一个像素的图像创建一个有向图。然后每个顶点通过两条边连接到它的每个邻居:一条出边和一条入边。这是因为边缘 (a,b) 的成本可能与 (b,a) 的成本不同。我正在使用大小为 512*512 像素的图像,因此我需要创建一个具有 262144 个顶点和 2091012 个边的图形。目前,我正在使用以下图表:

typedef property<vertex_index_t, int,
        property<vertex_distance_t, double,
        property<x_t, int, 
        property<y_t, int
        >>>> VertexProperty;

typedef property<edge_weight_t, double> EdgeProperty;

// define MyGraph
typedef adjacency_list<     
    vecS,           // container used for the out-edges (list)
    vecS,           // container used for the vertices (vector)
    directedS,      // directed edges (not sure if this is the right choice for incidenceGraph)
    VertexProperty,
    EdgeProperty
    > MyGraph;

我正在使用一个额外的类 Graph(抱歉命名没有灵感):

class Graph
{
private:
    MyGraph *graph;
    property_map<MyGraph, vertex_index_t>::type indexmap;
    property_map<MyGraph, vertex_distance_t>::type distancemap;
    property_map<MyGraph, edge_weight_t>::type weightmap;
    property_map<MyGraph, x_t>::type xmap;
    property_map<MyGraph, y_t>::type ymap;
    std::vector<MyGraph::vertex_descriptor> predecessors;
public:
    Graph();
    ~Graph();

};

创建具有 262144 个顶点的新图非常快,但插入边需要 10 秒,这对于所需的应用程序来说太慢了。现在,我通过以下方式插入边缘:

tie(vertexIt, vertexEnd) = vertices(*graph);
for(; vertexIt != vertexEnd; vertexIt++){
    vertexID = *vertexIt;
    x = vertexID % 512;
    y = (vertexID - x) / 512;
    xmap[vertexID] = x;
    ymap[vertexID] = y;
    if(y > 0){
        if(x > 0){
            tie(edgeID, ok) = add_edge(vertexID, indexmap[IRES2D*(y-1)+(x-1)], *graph);    // upper left neighbour
        }
        tie(edgeID, ok) = add_edge(vertexID, indexmap[IRES2D*(y-1)+(x)], *graph);    // upper
        if(x < 511){
            tie(edgeID, ok) = add_edge(vertexID, indexmap[IRES2D*(y-1)+(x+1)], *graph);    // upper right
        }
    }
    if(x < 511){    
        tie(edgeID, ok) = add_edge(vertexID, indexmap[IRES2D*(y)+(x+1)], *graph);    // right
    }
    if(y < 511){
        if(x > 0){
            tie(edgeID, ok) = add_edge(vertexID, indexmap[IRES2D*(y+1)+(x-1)], *graph);    // lower left
        }
        tie(edgeID, ok) = add_edge(vertexID, indexmap[IRES2D*(y+1)+(x)], *graph);    // lower
        if(x < 511){
            tie(edgeID, ok) = add_edge(vertexID, indexmap[IRES2D*(y+1)+(x+1)], *graph);    // lower right
        }
    }
    if(x > 0){
        tie(edgeID, ok) = add_edge(vertexID, indexmap[IRES2D*(y)+(x-1)], *graph);    // left
    }
}

我能做些什么来提高程序的速度吗?我在发布模式下使用 Microsoft Visual C++ 2010 Express 并进行了优化(由 Boost 推荐)。我以为我可以为顶点或边使用 listS 容器,但顶点没有问题,如果我将 listS 用于边,它会变得更慢。

【问题讨论】:

    标签: performance boost graph boost-graph edges


    【解决方案1】:

    adjacency_list 非常通用;不幸的是,它永远不会像利用特定用例的规律性的解决方案那样有效。 BGL 不是魔法。

    您最好的选择可能是想出在没有 BGL 的情况下使用的有效图形表示(提示:对于图像的相邻像素的图形,这要明确分配所有这些节点和边缘对象),然后将 BGL 拟合到它(example),或者等效地直接实现现有adjacency_list / adjacency_matrix 模板(concept guidelines)的对应物,以适应系统的规律性.

    通过优化表示,我当然是指您实际上并没有显式存储所有节点和边缘,而是通过某种方式迭代隐式节点和边缘的枚举,这是由于图像是一个特定的大小。您真正需要存储的唯一内容是边缘权重数组。

    【讨论】:

    • 非常感谢。我想,我会按照你的第二个建议中提到的那样实现我自己的图形表示。我从一个很小的图像开始,并分配了每个节点和边缘,以便更好地了解问题。我希望,我可以通过使用 BGL 来保存此图表以节省一些时间,但实际上我花了将近 3 天的时间将所有内容都安装到 BGL...再次感谢。
    • 拥有一个有效的基于 adjacency_list 的实现至少意味着您拥有一个可以轻松测试您实现的任何替代 BGL 兼容替代图表示的系统。
    • 您可能还想查看 BGL 的 grid_graph,这是 @timday 所指的优化表示。
    • @Jeremiah:实际上我直到现在才知道 grid_graph!很明显,BGL 就是为此而生的。 (谢谢;我看到它是在 1.41 中引入的,这使它成为我书中最近添加的内容)。
    • @timday 啊。我在我的函数中调用 num_edges ,它添加了一条边及其反向边。我删除了那个调用并手动跟踪了边缘的数量,并获得了 300 倍的加速!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-13
    • 2011-12-08
    • 2017-06-03
    相关资源
    最近更新 更多