【问题标题】:Return a list of connected component subgraphs in Boost Graph返回 Boost Graph 中的连通分量子图列表
【发布时间】:2015-01-01 23:58:12
【问题描述】:

我在过滤原始图中具有相同组件的子图时遇到问题。我想将它们输出到子图向量中。按照 `connected_components 中的示例,我尝试使其适应我的需求:

// Create a typedef for the Graph type
typedef adjacency_list<
vecS,
vecS,
undirectedS,
property<vertex_index_t,int >,
property<edge_index_t,int> > Graph;

//typedef subgraph < Graph > SubGraph;
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::edge_descriptor Edge;
typedef graph_traits<Graph> GraphTraits;

// Iterators
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
typedef graph_traits<Graph>::edge_iterator edge_iter;
typedef property_map<Graph, vertex_index_t>::type VertexIndexMap;
typedef property_map<Graph, edge_index_t>::type EdgeIndexMap;

std::vector<Graph> connected_components_subgraphs(const Graph &g)
{
    std::vector<int> component(num_vertices(g));
    int num = boost::connected_components(g, &component[0]);
    for (int i=0; i<component.size(); i++)
        cout << component[i] << endl;
    cout << "NUM=" << num << endl;

    // Something to output the induced subgraphs where every subgraph is in the same component
}

我完全陷入了图形的过滤,因为我不明白如何利用为向量组件中的顶点存储的外部属性或将其传递给过滤图形所需的某个函子.

特别是,这个问题似乎和我的需求很相似,但是没有一段代码我觉得很难弄清楚问题。

splitting a boost graph into connected components

如何从同一个连通分量中的节点输出诱导子图?

【问题讨论】:

    标签: c++ templates boost graph boost-graph


    【解决方案1】:

    您可以使用主图的filtered_graph 视图:

    typedef filtered_graph<Graph, EdgeInComponent, VertexInComponent> ComponentGraph;
    
    std::vector<ComponentGraph> connected_components_subgraphs(Graph const&g)
    {
        vertex_component_map mapping = boost::make_shared<std::vector<unsigned long>>(num_vertices(g));
        size_t num = boost::connected_components(g, mapping->data());
    
        std::vector<ComponentGraph> component_graphs;
    
        for (size_t i = 0; i < num; i++)
            component_graphs.push_back(ComponentGraph(g, EdgeInComponent(mapping, i, g), VertexInComponent(mapping, i)));
    
        return component_graphs;
    }
    

    当然,这只是引出了如何实现过滤谓词的问题。我选择分享mapping 向量:

    typedef boost::shared_ptr<std::vector<unsigned long>> vertex_component_map;
    

    我不想假设您可以共享全局或只是复制它。例如,VertexInComponent 谓词如下所示:

    struct VertexInComponent
    { 
        vertex_component_map mapping_;
        unsigned long which_;
    
        VertexInComponent(vertex_component_map m, unsigned long which)
            : mapping_(m), which_(which) {}
    
        template <typename Vertex> bool operator()(Vertex const&v) const {
            return mapping_->at(v)==which_;
        } 
    };
    

    同样可以实现EdgeInComponent。实际上,您可以将其简化并使用类似的东西

    struct AnyElement { 
        template <typename EdgeOrVertex> bool operator()(EdgeOrVertex const&) const { return true; }
    };
    

    两者之一。这是一个示例 main:

    Graph g;
    
    add_edge(0, 1, g);
    add_edge(1, 4, g);
    add_edge(4, 0, g);
    add_edge(2, 5, g);
    
    for (auto const& component : connected_components_subgraphs(g))
    {
        std::cout << "component [ ";
        for (auto e :  make_iterator_range(edges(component)))
            std::cout << source(e, component) << " -> " << target(e, component) << "; ";
        std::cout << "]\n";
    }
    

    然后打印出来:

    component [ 0 -> 1; 1 -> 4; 4 -> 0; ]
    component [ 2 -> 5; ]
    component [ ]
    

    完整代码

    Live On Coliru

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/connected_components.hpp>
    #include <boost/graph/filtered_graph.hpp>
    #include <boost/make_shared.hpp>
    #include <boost/range/iterator_range.hpp>
    #include <iostream>
    
    using namespace boost;
    
    // Create a typedef for the Graph type
    typedef adjacency_list<vecS, vecS, undirectedS, property<vertex_index_t, int>, property<edge_index_t, int>> Graph;
    
    // typedef subgraph < Graph > SubGraph;
    typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
    typedef typename graph_traits<Graph>::edge_descriptor Edge;
    typedef graph_traits<Graph> GraphTraits;
    
    // Iterators
    typedef graph_traits<Graph>::vertex_iterator vertex_iter;
    typedef graph_traits<Graph>::edge_iterator edge_iter;
    typedef property_map<Graph, vertex_index_t>::type VertexIndexMap;
    typedef property_map<Graph, edge_index_t>::type EdgeIndexMap;
    
    typedef boost::shared_ptr<std::vector<unsigned long>> vertex_component_map;
    
    struct EdgeInComponent
    { 
        vertex_component_map mapping_;
        unsigned long which_;
        Graph const& master_;
    
        EdgeInComponent(vertex_component_map m, unsigned long which, Graph const& master) 
            : mapping_(m), which_(which), master_(master) {}
    
        template <typename Edge> bool operator()(Edge const&e) const {
            return mapping_->at(source(e,master_))==which_
                || mapping_->at(target(e,master_))==which_;
        } 
    };
    
    struct VertexInComponent
    { 
        vertex_component_map mapping_;
        unsigned long which_;
    
        VertexInComponent(vertex_component_map m, unsigned long which)
            : mapping_(m), which_(which) {}
    
        template <typename Vertex> bool operator()(Vertex const&v) const {
            return mapping_->at(v)==which_;
        } 
    };
    
    struct AnyVertex { 
        template <typename Vertex> bool operator()(Vertex const&) const { return true; }
    };
    
    typedef filtered_graph<Graph, EdgeInComponent, VertexInComponent> ComponentGraph;
    
    std::vector<ComponentGraph> connected_components_subgraphs(Graph const&g)
    {
        vertex_component_map mapping = boost::make_shared<std::vector<unsigned long>>(num_vertices(g));
        size_t num = boost::connected_components(g, mapping->data());
    
        std::vector<ComponentGraph> component_graphs;
    
        for (size_t i = 0; i < num; i++)
            component_graphs.push_back(ComponentGraph(g, EdgeInComponent(mapping, i, g), VertexInComponent(mapping, i)));
    
        return component_graphs;
    }
    
    int main()
    {
        Graph g;
    
        add_edge(0, 1, g);
        add_edge(1, 4, g);
        add_edge(4, 0, g);
        add_edge(2, 5, g);
    
        for (auto const& component : connected_components_subgraphs(g))
        {
            std::cout << "component [ ";
            for (auto e :  make_iterator_range(edges(component)))
                std::cout << source(e, component) << " -> " << target(e, component) << "; ";
            std::cout << "]\n";
        }
    }
    

    奖励:c++11

    如果您可以使用 C++11,则 lambda 可以大大缩短代码,因为您可以就地定义过滤谓词:

    Live On Coliru

    typedef filtered_graph<Graph, function<bool(Graph::edge_descriptor)>, function<bool(Graph::vertex_descriptor)> > ComponentGraph;
    
    std::vector<ComponentGraph> connected_components_subgraphs(Graph const&g)
    {
        vertex_component_map mapping = boost::make_shared<std::vector<unsigned long>>(num_vertices(g));
        size_t num = boost::connected_components(g, mapping->data());
    
        std::vector<ComponentGraph> component_graphs;
    
        for (size_t i = 0; i < num; i++)
            component_graphs.emplace_back(g,
                [mapping,i,&g](Graph::edge_descriptor e) {
                    return mapping->at(source(e,g))==i
                        || mapping->at(target(e,g))==i;
                }, 
                [mapping,i](Graph::vertex_descriptor v) {
                    return mapping->at(v)==i;
                });
    
        return component_graphs;
    }
    

    【讨论】:

    • 太棒了!特别是我在理解如何将分量向量传递给过滤器方面遇到了问题。这样你就很清楚地向我解释了这个概念。我也是 Boost Graph 的新手,完全掌握它非常困难。谢谢!
    • 我有另一条评论,是否可以计算输出中每个filtered_graph 中的顶点数?因为num_vertices返回的是原始未过滤图的顶点数。我应该在每个过滤子图的节点上使用 boost::subgraph 吗?
    • @linello 如果您将vecSadjacency_list 一起使用,那么根据定义,所有索引都“实际上”存在。您可能应该为 VertexList 模板参数选择不同的容器策略。
    • 作为奖励,我在示例代码中添加了c++11 version
    • @linello 虽然这应该是一个单独的问题,但这里有一个使用setS 作为VertexList 的演示,并展示了distance(vertices(component)) 如何返回您想要的顶点数: Live On Coliru
    【解决方案2】:

    您可以使用subgraph 代替filtered_graph,如下所示:

    vector<int> comp(num_vertices(g));
    size_t num = boost::connected_components(g, comp.data());
    
    vector<Graph*> comps(num);
    for(size_t i=0;i<num;++i) {
        comps[i] = & g.create_subgraph();
    }
    
    for(size_t i=0;i<num_vertices(g);++i) {
        add_vertex(i, *comps[comp[i]]);
    }
    

    其中Graph 定义为:

    using Graph = subgraph< adjacency_list<vecS, vecS, undirectedS, property<vertex_index_t, int>, property<edge_index_t, int>> >;
    

    请注意,您需要使用local_to_global 将顶点描述符从子图映射到根图。

    运行示例:http://coliru.stacked-crooked.com/a/cebece41c0daed87

    在这种情况下了解filtered_graphsubgraph 的优点会很有趣。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-30
      • 1970-01-01
      • 1970-01-01
      • 2012-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多