how to access BGL's vertex_descriptor as an int - c++

I have an adjacency list defined as shown below. At this point I need to access vertex_descriptor as an int type. How can I do that tvertex source = ...; int source_as_int = ???source??? I remember bumping into this same question before and solved it but don't remember how and the BGL documentation is useless using it as reference, they should try to take a look at and learn from Javadocs.
Another possibility is to use a possible member function of the vertex_descriptor type or otherwise some of the global BGL functions for this purpose ... one never knows where to look for this and they seem to randomly choose between making global functions or member functions, a total fail of an intuitive design if you ask me.
typedef adjacency_list_traits<setS, setS, bidirectionalS> ttraits;
typedef adjacency_list<setS, setS, bidirectionalS,
// vertex properties
property<vertex_color_t, default_color_type>,
// edge properties
property<edge_capacity_t, int,
property<edge_residual_capacity_t, int,
property<edge_reverse_t, ttraits::edge_descriptor> > >, no_property, vecS> tbgl_adjlist_bidir;
typedef graph_traits<tbgl_adjlist_bidir>::vertex_descriptor tvertex;
typedef graph_traits<tbgl_adjlist_bidir>::edge_descriptor tedge;
typedef property_map<tbgl_adjlist_bidir, edge_capacity_t>::type tedge_capacity_map;
typedef property_map<tbgl_adjlist_bidir, edge_reverse_t>::type treverse_edge_map;
typedef property_map<tbgl_adjlist_bidir, vertex_color_t>::type tvertex_color_map;
typedef graph_traits<tbgl_adjlist_bidir>::out_edge_iterator tout_edge_iterator;
typedef graph_traits<tbgl_adjlist_bidir>::in_edge_iterator tin_edge_iterator;

OK I figured it out. Adding the vertex property vertex_index_t solves the problem. I can then access the int index of the vertex like this:
typedef adjacency_list_traits<setS, vecS, bidirectionalS> ttraits;
typedef adjacency_list<setS, vecS, bidirectionalS,
// vertex properties
property<vertex_index_t, int,
property<vertex_color_t, default_color_type> >,
// edge properties
property<edge_capacity_t, int,
property<edge_residual_capacity_t, int,
property<edge_reverse_t, ttraits::edge_descriptor> > >, no_property, vecS> tbgl_adjlist_bidir;
typedef graph_traits<tbgl_adjlist_bidir>::vertex_descriptor tvertex;
typedef graph_traits<tbgl_adjlist_bidir>::edge_descriptor tedge;
typedef property_map<tbgl_adjlist_bidir, edge_capacity_t>::type tedge_capacity_map;
typedef property_map<tbgl_adjlist_bidir, edge_reverse_t>::type treverse_edge_map;
typedef property_map<tbgl_adjlist_bidir, vertex_color_t>::type tvertex_color_map;
typedef property_map<tbgl_adjlist_bidir, vertex_index_t>::type tvertex_index_map;
typedef graph_traits<tbgl_adjlist_bidir>::vertex_iterator tvertex_iterator;
typedef graph_traits<tbgl_adjlist_bidir>::edge_iterator tedge_iterator;
typedef graph_traits<tbgl_adjlist_bidir>::out_edge_iterator tout_edge_iterator;
typedef graph_traits<tbgl_adjlist_bidir>::in_edge_iterator tin_edge_iterator;
then I use it like this:
tbgl_adjlist_bidir bgl_adjlist_bidir;
// ...
tvertex_index_map indices = get(vertex_index, bgl_adjlist_bidir);
// ...
tvertex source;
// ...
int source_as_int = indices[source];

The type of a vertex_descriptor depends on the underlying structure of the VertexListS-template parameter of adjacency_list. The only case i know of, where the descriptor is an int is, when the VertexList-Type is vecS. But keep in mind: If you choose vecS as your VertexList-Type all (stored) descriptors can become invalid, when you change the structure of your graph(as described in Iterator and Descriptor Stability/Invalidation).

Could I interest you in using custom vertex and edge types instead? They're much, much easier to work with in your own code. And as for calling on BGL algorithms, you can use Bundled Properties.

Related

Boost graph: speeding up add_edge

I have a boost graph application where I need to call the function add_edge( ) [documentation available here].
Profiling this application with KCachegrind reveals the following breakup of time spent:
As can be seen, the add_edge function call takes up roughly 21% of the time of the parent caller. Out of this 21%, 14.49% is simply some std::vector's reallocation.
The suggested way to prevent such vector reallocations seems to be to upfront reserve some amount of space. See for e.g., thread: How to prevent memory reallocation using std::vector
What is the equivalent way to do this reservation of some sufficient amount of space in boost graph?
The underlying graph object over which this repeated calls to add_edge are made is thus:
typedef adjacency_list<
vecS, vecS, directedS,
property<
vertex_name_t, std::string,
property<vertex_index_t, int,
property<vertex_color_t, boost::default_color_type,
property<vertex_distance_t, double,
property<vertex_predecessor_t, Traits::edge_descriptor>
> > > >,
property<
edge_index_t, int,
property<edge_capacity_t, double,
property<edge_weight_t, double,
property<edge_residual_capacity_t, double,
property<edge_reverse_t, Traits::edge_descriptor>
> > > > >
Graph;
Edited to add: Similar questions here and here.
Unfortunately for me, g.m_edges does NOT have function reserve.
Edited to add link to a minimal example (that is difficult to get to work fully) but compiles fine except for an undefined external reference that is not the main issue.
Unfortunately for me, g.m_edges does NOT have function reserve
But m_vertices does.
#include <boost/graph/adjacency_list.hpp>
int main() {
boost::adjacency_list<> g;
g.m_vertices.reserve(1024);
}
Also, since you're using vecS you could almost equivalently just construct with a pre-allocated number of vertices:
boost::adjacency_list<> g(1024);
The difference is, of course, that this doesn't just reserve space for, but resizes the graph to contain 1024 vertices.

When analyzing boost::graph, does one operate on vertex and edge descriptor or their iterators?

When working with the BOOST graph library, I have a graph instance fully initialized -- the structure is now static. I need to do some processing based on the graph.
I'm not clear if I should be working with the iterator types for vertices and edges, or the vertex and edge types themselves?
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, VertexProperty, EdgeProperty > GraphType;
typedef typename boost::graph_traits< GraphType >::vertex_descriptor VertexType;
typedef typename boost::graph_traits<GraphType>::vertex_iterator VertexIterator;
typedef typename boost::graph_traits< GraphType >::edge_descriptor EdgeType;
typedef typename boost::graph_traits<GraphType>::out_edge_iterator EdgeIterator;
I have an algorithm where I need to check if two edges are "the same". (in the strongest sense. Suppose the graph has two parallel edges connecting E1(S1,T2) & E2(S1,T2). An edge can only be "the same" with at most one of them.
What's the difference between (edge_descriptor == edge_descriptor) and (edge_iterator == edge_iterator)? Same question for vertices.
Most of the graph functions return iterators rather than the edge/vertex types themselves.
I also have the need to store a set of edges. Not sure whether I should be storing EdgeType or EdgeIterator?
std::vector<EdgeType> processedEdges;
std::vector<EdgeIterator> processedEdges;
vit = std::find( processedEdges.begin(), processedEdges.end(), anotherEdgeRef )
if ( vit == processedEdges.end() )
doSomethingBasedOnEdgeProperty(*vit);
Reference:
http://www.boost.org/doc/libs/1_64_0/libs/graph/doc/adjacency_list.html
You should be storing descriptors, not iterators.
Iterators relate to a logical range, not the graph. Iterators may not be valid between different ranges of the same graph:
auto range1 = out_edges(vertex1, g);
auto range2 = out_edges(vertex2, g);
assert(range1.first != range2.first); // unspecified or undefined
Instead, descriptors are graph-wide. Depending on graph model, descriptors may be more stable: if an operation invalidates iterators, it doesn't necessarily invalidate the descriptors corresponding to the same graph elements.
In other words, this makes descriptors more usable as vertex or edge "ID" - or, as Boost Graph would call it, vertex_index or edge_index properties.
I think that is very close to your question.
One caveat: even so, descriptors may not always be stable!
E.g.:
adjacency_list<vecS, vecS, directedS>
leads to vertex descriptors that are stable on append, but not on
deletion.
adjacency_list<setS, listS, directedS>
on the other hand, leads to vertex descriptors that are stable on both
insertion and removal.
See documentation section "Iterator and Descriptor
Stability/Invalidation"
If you need a completely stable identity for your graph elements, you may need to add one as a (bundled) property.

Adding edges to a graph in Boost.Graph

I am trying to use the Boost.Graph Library to run Goldberg's Max-Flow Algorithm. Boost.Graph calls it push_relabel_max_flow.
However, I have a very hard time understanding the library and its type-system. The documentation, which I linked above, gives an example code. But in that example, the graph is read from a file. I want to generate the graph at runtime. This is the code I have so far (mostly copied from the example):
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> Traits;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
boost::property<boost::vertex_name_t, std::string>,
boost::property<boost::edge_capacity_t, long,
boost::property<boost::edge_residual_capacity_t, long,
boost::property<boost::edge_reverse_t, Traits::edge_descriptor>>>> DirectedGraph;
DirectedGraph g;
Traits::vertex_descriptor s, t;
s = boost::add_vertex(g);
t = boost::add_vertex(g);
boost::add_vertex(g);
boost::add_vertex(g);
After I added 4 vertices to the graph I should "connect" them, i.e., making edges with a capacity, residual capacity and the reverse value. The function for this task is boost::add_edge() but I have no clue how I can pass my arguments. The example code does not show it, because as I said, the data is read from a file and then directly parsed to a graph. Maybe someone with experience in the Boost.Graph library can show me how.
You can add an edge between vertices s and t like so:
boost::add_edge(s, t, {33, 44}, g);
Here setting edge_capacity to 33, and edge_residual_capacity to 44.
To actually access the edge properties, as far as I know you must do something like this:
std::cout << boost::get(boost::edge_capacity, g, boost::edge(s,t,g).first) << '\n';
which is annoying. It's easier if you use bundled properties instead, like so:
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> Traits;
struct VertexProps {
std::string name;
};
struct EdgeProps {
long capacity;
long residual_capacity;
Traits::edge_descriptor reverse;
};
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
VertexProps, EdgeProps > DirectedGraph;
Then you can add vertices and edges just the same way, but it's easier to access edge properties, e.g.
auto e = boost::edge(s,t,g).first; // get the edge descriptor for an edge from s to t, if any
std::cout << g[e].capacity << '\n';
To add an edge between the anonymous third and fourth vertices you added, you can get away with
boost::add_edge(2, 3, {17, 26}, g);
since the underlying storage is vector, and so vertex_descriptor is just the vector index (aka size_t, aka unsigned long around here). But to be more strictly correct you should do
boost:add_edge(boost::vertex(2, g), boost::vertex(3, g), {17, 26}, g);
in order to get the vertex_descriptor for the 3rd and 4th vertices.

BGL Adding an edge with multiple properties

I want to have all edges have to properties, weight and capacity. I found that BGL has these both already defined. So I define Edge and Vertex properties for the Graph
typedef property<vertex_name_t, string> VertexProperty;
typedef property<edge_weight_t, int, property<edge_capacity_t, int> > EdgeProperty;
typedef adjacency_list<listS,vecS, undirectedS, VertexProperty, EdgeProperty > Graph;
Here is where I am trying to add the edges to the graph:
172: EdgeProperty prop = (weight, capacity);
173: add_edge(vertex1,vertex2, prop, g);
If I had just 1 property I know it would be prop = 5; However, with two I am confused about the formatting.
Here is the error I am receiving:
graph.cc: In function ‘void con_graph()’:
graph.cc:172: warning: left-hand operand of comma has no effect
If you look at the implementation of boost::property you'll see that a property value cannot be initialized this way. And even then, the syntax you have (weight, capacity) is not valid anyways, so, if it was possible to initialize the property like that, it would be written EdgeProperty prop = EdgeProperty(weight, capacity); or just EdgeProperty prop(weight, capacity);. But, again, that won't work. Technically, this is the way you would need to initialize the property value:
EdgeProperty prop = EdgeProperty(weight, property<edge_capacity_t, int>(capacity));
But this is kind of ugly as the number of properties increase. So, it would be cleaner to default-construct the edge-property and then manually set each individual property:
EdgeProperty prop;
get_property_value(prop, edge_weight_t) = weight;
get_property_value(prop, edge_capacity_t) = capacity;
Of course, the better alternative is to use bundled properties instead of the older boost::property chains.
The correct form is:
EdgeProperty prop;
get_property_value(prop, edge_weight) = weight;
get_property_value(prop, edge_capacity) = capacity;

Boost graph libraries: setting edge weight values

I am investigating the use of the boost graph libraries in order to apply them to various network problems I have in mind.
In the examples I have been looking at the graph edge values ("weights") are always initialized as integers, such as in these Bellman-Ford and Kruskal algorithms eg:
int weights[] = { 1, 1, 2, 7, 3, 1, 1, 1 };
My problem is if I try and change the weights to double, I get a heap of warning messages about conversions etc, which so far I have not been able to figure out how to overcome.
Does anyone see a way around this?
It's caused by a mismatch between the weights[] array and the type used for edge weights by your boost graph/algorithm.
In the first linked sample, eg, you should also change
struct EdgeProperties {
int weight;
};
[...]
property_map<Graph, int EdgeProperties::*>::type
to
struct EdgeProperties {
double weight;
};
[...]
property_map<Graph, double EdgeProperties::*>::type
In the second
typedef adjacency_list < vecS, vecS, undirectedS,
no_property, property < edge_weight_t, int > > Graph;
to
typedef adjacency_list < vecS, vecS, undirectedS,
no_property, property < edge_weight_t, double > > Graph;