【问题标题】:BGL - graph passed to visitor's functions forgetting vertex propertiesBGL - 传递给访问者函数的图忘记了顶点属性
【发布时间】:2015-10-17 17:42:40
【问题描述】:

我正在尝试通过编写自定义 DFS 访问者 (class TarjanVisitor : public default_dfs_visitor) 在 BGL 中实现桥接检测算法 (tarjan),并且我正在使用顶点属性 parent 来跟踪节点的来源到达。

但是,如果不求助于一些访问者全局参考,我似乎无法在遍历期间设置顶点的属性。

在我的特殊情况下,我的tree_edge 中有以下内容:

debug_print("setting " << g[trgt].id << "'s parent to " << g[curr].id)
g[trgt].parent = g[curr].id;
debug_print(g[trgt].id << "'s parent is now " << g[trgt].parent)

debug_print 只是一个打印,我可以通过取消定义宏来关闭它)

然后在discover_vertex,我有

debug_print(g[u].id << "'s parent is " << g[u].parent)
assert(g[u].parent >= 0);

我通过将 1 设置为 root 并将其 parent 设置为自身来启动 DFS 遍历。

TarjanVisitor vis = TarjanVisitor();
g[vertex(1,g)].parent = 1;
depth_first_search(g,visitor(vis)
    .root_vertex(vertex(1,g)) //note to self: DOT, not comma
);

这是我得到的(清理后的)调试输出:

discover_vertex: 1
1's parent is 1
examine_edge: 1 <-> 2
tree_edge: 1 <-> 2
setting 2's parent to 1
2's parent is now 1
discover_vertex: 2
2's parent is -1
Assertion `g[u].parent >= 0' failed.
Aborted (core dumped)

现在,如果不是使用传递给各个函数的 Graph,而是将 Graph 的引用传递给访问者的构造函数并将该 Graph 用作g,属性会按预期更新,所以我可以只能猜测问题是g 在例如void tree_edge(Edge e, Graph g) 按值传递图表,对其所做的任何更改都将被忽略。

更改为例如void tree_edge(Edge e, Graph&amp; g) 会给我一个很好的长且绝对难以辨认的错误消息,关于在 boost::detail::depth_first_visit_impl 的实例化过程中需要的东西。

传递对访问者的引用真的是唯一的方法吗?因为我有点拒绝相信我需要将一个图表按值传递给所有函数,只是为了对它做任何事情。

【问题讨论】:

    标签: c++ boost graph


    【解决方案1】:

    我刚刚有了一个脑电波。你说你试过了

     void tree_edge(Edge e, Graph& g) { ...
    

    如果图形是 const,这当然不会起作用(就像在 BGL 中实现 dfs 的情况一样。

    使它成为常量引用!

    Live On Coliru

    #include <iostream>
    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/depth_first_search.hpp>
    
    using namespace boost;
    
    struct MyVertex {};
    struct MyEdge   {};
    
    using Graph = adjacency_list<vecS, vecS, directedS, MyVertex, MyEdge>;
    
    struct my_visitor : default_dfs_visitor {
        template <class Vertex, class Graph>
            void initialize_vertex(Vertex u, const Graph& g) { 
                std::cout << __FUNCTION__ << "(" << u << ", g)\n";
                (void) g;
            }
        template <class Vertex, class Graph>
            void start_vertex(Vertex u, const Graph& g) { 
                std::cout << __FUNCTION__  << "(" << u << ", g)\n";
                (void) g;
            }
        template <class Vertex, class Graph>
            void discover_vertex(Vertex u, const Graph& g) { 
                std::cout << __FUNCTION__  << "(" << u << ", g)\n";
                (void) g;
            }
        template <class Edge, class Graph>
            void examine_edge(Edge u, const Graph& g) { 
                std::cout << __FUNCTION__  << "(" << u << ", g)\n";
                (void) g;
            }
        template <class Edge, class Graph>
            void tree_edge(Edge u, const Graph& g) { 
                std::cout << __FUNCTION__  << "(" << u << ", g)\n";
                (void) g;
            }
        template <class Edge, class Graph>
            void back_edge(Edge u, const Graph& g) { 
                std::cout << __FUNCTION__  << "(" << u << ", g)\n";
                (void) g;
            }
        template <class Edge, class Graph>
            void forward_or_cross_edge(Edge u, const Graph& g) { 
                std::cout << __FUNCTION__  << "(" << u << ", g)\n";
                (void) g;
            }
        template <class Edge, class Graph>
            void finish_edge(Edge u, const Graph& g) { 
                std::cout << __FUNCTION__  << "(" << u << ", g)\n";
                (void) g;
            }
        template <class Vertex, class Graph>
            void finish_vertex(Vertex u, const Graph& g) { 
                std::cout << __FUNCTION__  << "(" << u << ", g)\n";
                (void) g;
            }
    };
    
    #include <random>
    #include <boost/graph/random.hpp>
    
    int main() {
        Graph g;
    
        std::mt19937 prng {42};
        generate_random_graph(g, 10, 20, prng);
    
        my_visitor vis;
        std::vector<default_color_type> colormap(num_vertices(g));
        depth_first_search(g, vis, make_iterator_property_map(colormap.begin(), get(vertex_index, g)));
    }
    

    打印

    initialize_vertex(0, g)
    initialize_vertex(1, g)
    initialize_vertex(2, g)
    initialize_vertex(3, g)
    initialize_vertex(4, g)
    initialize_vertex(5, g)
    initialize_vertex(6, g)
    initialize_vertex(7, g)
    initialize_vertex(8, g)
    initialize_vertex(9, g)
    start_vertex(0, g)
    discover_vertex(0, g)
    examine_edge((0,4), g)
    tree_edge((0,4), g)
    discover_vertex(4, g)
    examine_edge((4,1), g)
    tree_edge((4,1), g)
    discover_vertex(1, g)
    finish_vertex(1, g)
    finish_vertex(4, g)
    examine_edge((0,9), g)
    tree_edge((0,9), g)
    discover_vertex(9, g)
    examine_edge((9,1), g)
    forward_or_cross_edge((9,1), g)
    examine_edge((9,2), g)
    tree_edge((9,2), g)
    discover_vertex(2, g)
    finish_vertex(2, g)
    examine_edge((9,1), g)
    forward_or_cross_edge((9,1), g)
    finish_vertex(9, g)
    examine_edge((0,1), g)
    forward_or_cross_edge((0,1), g)
    examine_edge((0,4), g)
    forward_or_cross_edge((0,4), g)
    examine_edge((0,2), g)
    forward_or_cross_edge((0,2), g)
    finish_vertex(0, g)
    start_vertex(3, g)
    discover_vertex(3, g)
    examine_edge((3,7), g)
    tree_edge((3,7), g)
    discover_vertex(7, g)
    examine_edge((7,5), g)
    tree_edge((7,5), g)
    discover_vertex(5, g)
    examine_edge((5,1), g)
    forward_or_cross_edge((5,1), g)
    examine_edge((5,6), g)
    tree_edge((5,6), g)
    discover_vertex(6, g)
    examine_edge((6,1), g)
    forward_or_cross_edge((6,1), g)
    examine_edge((6,3), g)
    back_edge((6,3), g)
    examine_edge((6,5), g)
    back_edge((6,5), g)
    finish_vertex(6, g)
    finish_vertex(5, g)
    examine_edge((7,6), g)
    forward_or_cross_edge((7,6), g)
    examine_edge((7,8), g)
    tree_edge((7,8), g)
    discover_vertex(8, g)
    examine_edge((8,3), g)
    back_edge((8,3), g)
    finish_vertex(8, g)
    finish_vertex(7, g)
    examine_edge((3,1), g)
    forward_or_cross_edge((3,1), g)
    finish_vertex(3, g)
    

    【讨论】:

    • 恐怕这行不通。如果您添加 - 例如 - 一个 int i 到您的 MyVertex 并尝试从 DFS 访问者 (g[u].i = 0) 中更改它,您将获得一个 error: assignment of member ‘MyVertex::i’ in read-only object
    • 好吧,我正在回答这个问题(声称它是通过副本传递的,显然不是这样)。但是仔细看,你有一个 const 图(因为depth_first_search takes a const graph)。这很有意义,因为修改图表很危险并且您应该能够搜索 const 图表。现在,您可以使用“注入非常量引用”的方法,将字段设为 mutable 或将属性存储在图表之外。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    • 2023-03-24
    • 1970-01-01
    • 2015-02-24
    相关资源
    最近更新 更多