Copy from grid_graph to adjacency_list with boost :: copy_graph

I am using the boost graph library and trying to initialize a MutableGraph to get started as a grid. Edges will be added and removed later in life, so I think adjacency_list<vecS,listS,undirectedS> is the right choice.

My reading of BGL showed that a reasonable way to initialize it with these edges is to use boost::grid_graph , using boost::copy_graph to copy from boost::grid_graph , which can do all the initial edges for me for free. I thought it made sense to copy_graph copy from the VertexListGraph model to the MutableGraph model, which is what I have.

At first I tried to use the copy_graph argument copy_graph with 2 arguments, with the vague hope that something reasonable would happen to the default values ​​for the rest. This turned out to be wrong, grid_graph (for reasons that I could not understand) seems to be unable to use PropertyMap with edges or vertices, so by default vertex_copy and edge_copy could not (with a compiler error) copy the properties.

Since the version with two arguments didn’t seem appropriate, I go over to it and try to implement my own binary operator for copying vertices and edges. Even with a "no-op" copy, this does not work as I hope (i.e. it does not compile).

I put together a minimal working example that illustrates the problem:

 #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)); } 

This example does not compile:

 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> >&) 

My analysis of this error is that it seems to be trying to create a default construct from the internal elements of grid_graph , which cannot be built by default, for some reason this is not very clear to me. (clang doesn't really tell me anything that I can't see from g ++ here).

Questions:

  • Is it right to do this to initialize a mutable graph to start as a regular grid? At first I thought it was a lot easier than writing a function to do it myself, but now I'm not sure!
  • Why is the default value of orig_to_copy and / or vertex_index not suitable here? I assume that these two are the cause of the error. (Which, if any, actually causes the problem? I cannot decipher what is the main cause of the current error).
  • What is the β€œright” way to fix this?
+7
source share
1 answer

You're on the right track, but there are two things that need to be changed in the code. First, there is a special method for defining custom vertex properties. Secondly, there is another syntax (more preferable and probably the only one that is correct) for the named BGL parameters.

In the first element, refer to the documentation section entitled Custom Custom Vertex Properties . Essentially, to define your own vertex property, you first need to define a "tag type" (a struct with a name ending in _t ):

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

Then you specify the tag type somewhere in the boost::property template, which defines the internal stored properties of the vertices:

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

The above typedef defines two internal stored properties: an index and a custom "position".

In the second element, the preferred way to use named parameters is with the chaining method syntax. For example, if a function accepts two named parameters, named_param1 and named_param2 , there are two functions in the boost namespace named named_param1 and named_param2 , with respect. The boost::named_param1 takes a value for the named_param1 parameter and returns an object having the named_param2 method (similarly, the boost::named_param2 takes a value for the named_param2 parameter and returns an object with the named_param1 method). You call a method to set a value for this named parameter (which, in turn, returns another object that has methods for other supported named parameters).

To pass the values val1 and val2 for the named parameters named_param1 and named_param2 , you can use:

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

or

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

For reference, here is a complete program that copies a grid into an object of type 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; } 

When I ran this, I got the following output:

  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

 graph G {
 0;
 one;
 2;
 3;
 4;
 5;
 6;
 7;
 8;
 nine;
 10;
 eleven;
 12;
 thirteen;
 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;
 }
+10
source

All Articles