【问题标题】:Copying from grid_graph to adjacency_list with boost::copy_graph使用 boost::copy_graph 从 grid_graph 复制到 adjacency_list
【发布时间】:2011-11-23 20:44:10
【问题描述】:

我正在使用 boost 图形库并尝试初始化 MutableGraph 以开始作为网格的生活。 边缘会在以后添加和删除,所以我认为adjacency_list<vecS,listS,undirectedS> 是正确的选择。

我对 BGL 的阅读表明,用这些边缘初始化它的明智方法是利用 boost::grid_graph 通过使用 boost::copy_graphboost::grid_graph 复制,可以免费为我制作所有初始边缘。 我认为这是有道理的 - copy_graphVertexListGraph 的模型复制到 MutableGraph 的模型,这正是我所拥有的。

我最初尝试使用 copy_graph 的 2-argument 版本,模糊地希望其余的默认值会发生一些明智的事情。事实证明并非如此,grid_graph(由于我无法弄清楚的原因)似乎没有将PropertyMaps 与边或顶点一起使用的功能,因此默认的vertex_copyedge_copy 复制属性失败(出现编译器错误)。

由于 2-argument 版本显然看起来不合适,我继续前进并尝试实现我自己的二元运算符来复制顶点和边。即使使用“无操作”副本,它也不能像我希望的那样工作(即它无法编译)。

我整理了一个说明问题的最小工作示例:

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/grid_graph.hpp>
#include <boost/graph/copy.hpp>

struct Position {
  int x, y;
};

struct VertexProperties {
  Position pos;
};

typedef boost::adjacency_list<boost::vecS, boost::listS, boost::undirectedS, 
                      VertexProperties> Graph;

struct MyCopy {
  template <typename S, typename D>
  void operator()(const S& /*src*/, D& /*dest*/) {
    // Nothing for now, deduced types to try and just make it compile
    // TODO: set values for pos to reflect position on grid.
  }
};

int main() {
    boost::array<std::size_t, 2> lengths = { { 3, 3 } };
    boost::grid_graph<2> grid(lengths);

    Graph graph;
    MyCopy copier;
    // Using 3-Arg version of copy_graph so we can specify a custom way of copying to create the properties
    boost::copy_graph(grid,graph,boost::bgl_named_params<MyCopy,boost::vertex_copy_t,
                                 boost::bgl_named_params<MyCopy,boost::edge_copy_t> >(copier));
}

此示例无法编译:

g++ -Wextra -Wall -O2 -g -o copytest.o -c copytest.cc
In file included from /usr/include/boost/graph/grid_graph.hpp:24:0,
                 from copytest.cc:2:
/usr/include/boost/iterator/transform_iterator.hpp: In constructor ‘boost::transform_iterator<UnaryFunction, Iterator, Reference, Value>::transform_iterator() [with UnaryFunc = boost::detail::grid_graph_vertex_at<boost::grid_graph<2u> >, Iterator = boost::counting_iterator<unsigned int, boost::use_default, boost::use_default>, Reference = boost::use_default, Value = boost::use_default]’:
/usr/include/boost/graph/copy.hpp:115:55:   instantiated from ‘static void boost::detail::copy_graph_impl<0>::apply(const Graph&, MutableGraph&, CopyVertex, CopyEdge, Orig2CopyVertexIndexMap, IndexMap) [with Graph = boost::grid_graph<2u>, MutableGraph = boost::adjacency_list<boost::vecS, boost::listS, boost::undirectedS, VertexProperties>, CopyVertex = MyCopy, CopyEdge = MyCopy, IndexMap = boost::grid_graph_index_map<boost::grid_graph<2u>, boost::array<unsigned int, 2u>, unsigned int>, Orig2CopyVertexIndexMap = boost::iterator_property_map<__gnu_cxx::__normal_iterator<void**, std::vector<void*, std::allocator<void*> > >, boost::grid_graph_index_map<boost::grid_graph<2u>, boost::array<unsigned int, 2u>, unsigned int>, void*, void*&>]’
/usr/include/boost/graph/copy.hpp:327:5:   instantiated from ‘void boost::copy_graph(const VertexListGraph&, MutableGraph&, const boost::bgl_named_params<P, T, R>&) [with VertexListGraph = boost::grid_graph<2u>, MutableGraph = boost::adjacency_list<boost::vecS, boost::listS, boost::undirectedS, VertexProperties>, P = MyCopy, T = boost::vertex_copy_t, R = boost::bgl_named_params<MyCopy, boost::edge_copy_t>]’
/mnt/home/ajw/code/hpcwales/copytest.cc:31:66:   instantiated from here
/usr/include/boost/iterator/transform_iterator.hpp:100:26: error: no matching function for call to ‘boost::detail::grid_graph_vertex_at<boost::grid_graph<2u> >::grid_graph_vertex_at()’
/usr/include/boost/graph/grid_graph.hpp:104:7: note: candidates are: boost::detail::grid_graph_vertex_at<Graph>::grid_graph_vertex_at(const Graph*) [with Graph = boost::grid_graph<2u>]
/usr/include/boost/graph/grid_graph.hpp:100:33: note:                 boost::detail::grid_graph_vertex_at<boost::grid_graph<2u> >::grid_graph_vertex_at(const boost::detail::grid_graph_vertex_at<boost::grid_graph<2u> >&)

我对该错误的分析是,它似乎试图默认构造 grid_graph 的内部结构的一部分,由于某种原因,这对我来说并不是很清楚。 (clang 并没有真正告诉我任何我从 g++ 看不到的东西)。

问题:

  1. 这是将可变图形初始化为常规网格的正确方法吗?我最初认为这比自己编写函数要容易得多,但现在我不太确定了!
  2. 为什么orig_to_copy 和/或vertex_index 的默认值在这里不合适?我假设这两个是错误的原因。 (如果有的话,实际上是哪一个导致了问题?我无法解读当前错误的根本原因是什么)。
  3. 解决此问题的“正确”方法是什么?

【问题讨论】:

    标签: c++ boost boost-graph


    【解决方案1】:

    您在正确的轨道上,但有两件事需要在您的代码中进行更改。首先是定义自定义顶点属性的特殊方法。第二个是 BGL 命名参数有不同的语法(更可取,并且可能是唯一正确的)。

    关于第一项,请参考the section of the documentation titled Custom Vertex Properties。本质上,为了定义一个自定义顶点属性,你需要首先定义一个“标签类型”(一个名称以_t结尾的struct):

    struct vertex_position_t {
        typedef boost::vertex_property_tag kind;
    };
    

    然后在定义内部存储的顶点属性的boost::property 模板中的某处包含标记类型:

    typedef boost::property<boost::vertex_index_t, std::size_t,
            boost::property<vertex_position_t, Position> > VertexProperties;
    

    上面的typedef 定义了两个内部存储的属性:索引和自定义的“位置”。

    关于第二项,the preferred way 使用命名参数是一种“类方法链接”语法。例如,如果一个函数接受两个命名参数named_param1named_param2,则boost 命名空间中有两个函数分别命名为named_param1named_param2boost::named_param1 函数接受 named_param1 参数的值并返回具有 named_param2 方法 的对象(类似地,boost::named_param2 函数接受 named_param2 参数的值并返回具有named_param1 方法的对象)。您调用该方法来设置该命名参数的值(这反过来又返回另一个对象,该对象具有其他支持的命名参数的方法)。

    要为命名参数named_param1named_param2 传递值val1val2,您可以使用:

    boost::named_parameter1(val1).named_param2(val2)
    

    或:

    boost::named_parameter2(val2).named_param1(val1)
    

     

    作为参考,这里有一个完整的程序,它将网格复制到Graph 类型的对象:

    #include <cassert>
    #include <cstddef>
    #include <cstdlib>
    #include <iostream>
    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/copy.hpp>
    #include <boost/graph/graphviz.hpp>
    #include <boost/graph/grid_graph.hpp>
    #include <boost/property_map/property_map.hpp>
    
    struct vertex_position_t {
        typedef boost::vertex_property_tag kind;
    };
    
    struct Position {
        std::size_t x, y;
    
        Position()
            : x(0), y(0)
        {
        }
    };
    
    typedef boost::property<boost::vertex_index_t, std::size_t, boost::property<vertex_position_t, Position> > VertexProperties;
    typedef boost::adjacency_list<boost::vecS, boost::listS, boost::undirectedS, VertexProperties> Graph;
    typedef boost::graph_traits<Graph> GraphTraits;
    
    namespace detail {
    typedef boost::grid_graph<2> Grid;
    typedef boost::graph_traits<Grid> GridTraits;
    
    struct grid_to_graph_vertex_copier {
        typedef boost::property_map< Grid, boost::vertex_index_t>::type grid_vertex_index_map;
        typedef boost::property_map< ::Graph, boost::vertex_index_t>::type graph_vertex_index_map;
        typedef boost::property_map< ::Graph, ::vertex_position_t>::type graph_vertex_position_map;
    
        const Grid& grid;
        grid_vertex_index_map grid_vertex_index;
        graph_vertex_index_map graph_vertex_index;
        graph_vertex_position_map graph_vertex_position;
    
        grid_to_graph_vertex_copier(const Grid& grid_, Graph& graph)
            : grid(grid_), grid_vertex_index(get(boost::vertex_index_t(), grid_)),
            graph_vertex_index(get(boost::vertex_index_t(), graph)),
            graph_vertex_position(get(::vertex_position_t(), graph))
        {
        }
    
    private:
        Position grid_vertex_index_to_position(std::size_t idx) const {
            unsigned num_dims = grid.dimensions();
            assert(grid.dimensions() == 2);
    
            idx %= grid.length(0) * grid.length(1);
    
            Position ret;
            ret.x = idx % grid.length(0);
            ret.y = idx / grid.length(0);
    
            return ret;
        }
    
    public:
        void operator()(GridTraits::vertex_descriptor grid_vertex, ::GraphTraits::vertex_descriptor graph_vertex) const {
            std::size_t idx = get(grid_vertex_index, grid_vertex);
            put(graph_vertex_index, graph_vertex, idx);
            Position pos = grid_vertex_index_to_position(idx);
            std::cout << "grid_vertex = " << idx << ", pos.x = " << pos.x << ", pos.y = " << pos.y << std::endl;
            put(graph_vertex_position, graph_vertex, pos);
        }
    };
    
    struct grid_to_graph_edge_copier {
        void operator()(GridTraits::edge_descriptor grid_edge, ::GraphTraits::edge_descriptor graph_edge) const {
        }
    };
    }
    
    int main()
    {
        boost::array<std::size_t, 2> lengths = { { 3, 5 } };
        detail::Grid grid(lengths);
    
        Graph graph;
    
        boost::copy_graph(grid, graph, boost::vertex_copy(detail::grid_to_graph_vertex_copier(grid, graph))
                .edge_copy(detail::grid_to_graph_edge_copier()));
    
        std::cout << std::endl;
        boost::write_graphviz(std::cout, graph);
    
        return EXIT_SUCCESS;
    }
    

    当我运行它时,我收到了以下输出:

    grid_vertex = 0,pos.x = 0,pos.y = 0 grid_vertex = 1,pos.x = 1,pos.y = 0 grid_vertex = 2,pos.x = 2,pos.y = 0 grid_vertex = 3,pos.x = 0,pos.y = 1 grid_vertex = 4,pos.x = 1,pos.y = 1 grid_vertex = 5,pos.x = 2,pos.y = 1 grid_vertex = 6,pos.x = 0,pos.y = 2 grid_vertex = 7,pos.x = 1,pos.y = 2 grid_vertex = 8,pos.x = 2,pos.y = 2 grid_vertex = 9,pos.x = 0,pos.y = 3 grid_vertex = 10,pos.x = 1,pos.y = 3 grid_vertex = 11,pos.x = 2,pos.y = 3 grid_vertex = 12,pos.x = 0,pos.y = 4 grid_vertex = 13,pos.x = 1,pos.y = 4 grid_vertex = 14,pos.x = 2,pos.y = 4 图 G { 0; 1个; 2; 3; 4; 5个; 6; 7; 8个; 9; 10个; 11; 12; 13; 14; 0--1 ; 1--2; 3--4; 4--5; 6--7; 7--8; 9--10; 10--11; 12--13; 13--14; 1--0 ; 2--1; 4--3; 5--4; 7--6; 8--7; 10--9; 11--10; 13--12; 14--13; 0--3 ; 1--4; 2--5; 3--6; 4--7; 5--8; 6--9; 7--10; 8--11; 9--12; 10--13; 11--14; 3--0 ; 4--1; 5--2; 6--3; 7--4; 8--5; 9--6; 10--7; 11--8; 12--9; 13--10; 14--11; }

    【讨论】:

    • 快速检查:在谈论命名参数时,您一直将其称为named_param1named_param2,直到示例中突然变成boost::named_parameter1boost::named_parameter2链条的第一部分 - 这是一个错字吗?
    • @awoodland:不是错字,因为第一个是boost 命名空间中的函数,它返回一个具有methods 的对象其他命名参数。 boost::named_parameter1(val1).named_param2(val2)首先通过调用boost::named_parameter1函数来配置named_parameter1参数。然后,它通过在boost::named_parameter1() 返回的对象上调用named_parameter2 方法 来配置named_parameter2 参数。
    • 原来我尝试这个答案的机器最初运行的是 1.46。在 1.42 的机器上,它无法编译出与我看到的完全相同的错误。我猜这是1.42中的一个错误?这个答案仍然解决了我在尝试中遇到的所有其他问题,对此我非常感激。
    • @awoodland:这很有趣。您在使用 Boost v1.42 的机器上看到的编译错误是什么?另外,两台机器是否运行相同的编译器版本?它可能是旧编译器中的错误(例如替换失败/SFINAE 问题)。
    • 与我粘贴的问题相同的失败 - /usr/include/boost/iterator/transform_iterator.hpp:100: error: no matching function for call to âboost::detail::grid_graph_vertex_at&lt;boost::grid_graph&lt;2u, unsigned int, unsigned int&gt; &gt;::grid_graph_vertex_at()â。它使用 gcc 4.5 和 boost 1.42 失败,但使用相同版本的 gcc 和 boost 1.46 成功。新版本的 boost 可能会解决 SFINAE 失败错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    • 2019-09-11
    相关资源
    最近更新 更多