1

I'm learning to use Boost Graph Library. I have defined a custom struct for storing information about vertex as is instructed here: Modifying vertex properties in a Boost::Graph.

struct VertexProperties {
    int attribute1; 
    string attribute2;
    }; 
typedef adjacency_list<vecS, vecS, directedS, VertexProperties, no_property> Graph; 

I can iterate graph vertices and modifying their properties simply like this:

for (int i = 0; i < num_vertices(g); i++)
{
    g[i].attribute1 = 123; 
    g[i].attribute2 = "123";
} 

But how do I actually get to these properties (i.e. the corresponding instance of VertexProperties), when all I have is a vertex iterator?

GraphTraits::vertex_iterator vert_i, vert_end;
for (tie(vert_i, vert_end) = vertices(g); vert_i != vert_end; ++vert_i){
    //how do i get to "vert_i.attribute1" ?
}

The same question goes for edges and edge iterators. It should be very easy, but I can't seem to find it in the BGL documentation or anywhere else for that matter.

Thanks for your help.

Community
  • 1
  • 1
Coloss
  • 45
  • 6

1 Answers1

6

Using g[*vert_i].attribute1 should work. This is the way that it is specified, and it does work. If you look at the doc page on bundled properties, it says:

To access a bundled property for a particular edge or vertex, subscript your graph with the descriptor of the edge or vertex whose bundled property you wish to access.

And they give the example:

Graph g;
Graph::vertex_descriptor v = *vertices(g).first;
g[v].name = "Troy";

The vertex_iterator types are supposed to de-reference into a vertex_descriptor which you are supposed to use to subscript into the graph (g[v]). Therefore, using g[*vert_i].attribute1 should definitely work. If not, it's a bug that you need to file on the tracker.

So, this also means that your original code, with g[i].attribute1, is not correct, because there is no guarantee that integer indices are necessarily the same as the vertex_descriptor type for that graph (it just happens to work because you used vecS as VertexList argument, which makes the vertex_descriptor an integer, but it doesn't have to be, even with vecS). You should only use vertex_descriptor objects to index into the graph. And furthermore, if your g[i] code worked, then g[*vert_i] should work as well, there is simply no way that one could work and not the other, unless there is a serious bug.

Note, however, that I know that bundled properties are disabled under certain conditions. In particular, it uses some techniques that some compilers might not support, which means that older or exotic compilers might not be able to make this work. This is a flaw that I hope to be able to remove in the future with an alternative implementation that completely overhauls the current adjacency_list class template, but such a drastic re-design is unlikely to make it into BGL until some time.

An alternative way to access the bundled properties is to use its property-map, which has some nasty syntax, but might have a greater chance of working. For your example, it would be something like this:

boost::property_map<Graph, int VertexProperties::*>::type attr1 = 
  get(&VertexProperties::attribute1, g);

GraphTraits::vertex_iterator vert_i, vert_end;
for (tie(vert_i, vert_end) = vertices(g); vert_i != vert_end; ++vert_i){
  put(attr1, *vert_i, 123);
}

There is also an unsupported feature (under-the-hood) for obtaining a property-map for the whole bundle, but you cannot use it, because it's not part of the supported interface.

Mikael Persson
  • 18,174
  • 6
  • 36
  • 52
  • OK. It works now, I must have done something wrong when I was trying it for the first time. Thanks :-) – Coloss Oct 21 '14 at 22:15