1 // Copyright 2004 The Trustees of Indiana University.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 // Authors: Douglas Gregor
9 #ifndef BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP
10 #define BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP
14 #include <boost/graph/dijkstra_shortest_paths.hpp>
15 #include <boost/graph/breadth_first_search.hpp>
16 #include <boost/graph/relax.hpp>
17 #include <boost/graph/graph_traits.hpp>
18 #include <boost/tuple/tuple.hpp>
19 #include <boost/type_traits/is_convertible.hpp>
20 #include <boost/type_traits/is_same.hpp>
21 #include <boost/mpl/if.hpp>
22 #include <boost/property_map.hpp>
23 #include <boost/graph/named_function_params.hpp>
28 namespace detail { namespace graph {
31 * Customized visitor passed to Dijkstra's algorithm by Brandes'
32 * betweenness centrality algorithm. This visitor is responsible for
33 * keeping track of the order in which vertices are discovered, the
34 * predecessors on the shortest path(s) to a vertex, and the number
37 template<typename Graph, typename WeightMap, typename IncomingMap,
38 typename DistanceMap, typename PathCountMap>
39 struct brandes_dijkstra_visitor : public bfs_visitor<>
41 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
42 typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
44 brandes_dijkstra_visitor(std::stack<vertex_descriptor>& ordered_vertices,
48 PathCountMap path_count)
49 : ordered_vertices(ordered_vertices), weight(weight),
50 incoming(incoming), distance(distance),
51 path_count(path_count)
55 * Whenever an edge e = (v, w) is relaxed, the incoming edge list
56 * for w is set to {(v, w)} and the shortest path count of w is set to
57 * the number of paths that reach {v}.
59 void edge_relaxed(edge_descriptor e, const Graph& g)
61 vertex_descriptor v = source(e, g), w = target(e, g);
63 incoming[w].push_back(e);
64 put(path_count, w, get(path_count, v));
68 * If an edge e = (v, w) was not relaxed, it may still be the case
69 * that we've found more equally-short paths, so include {(v, w)} in the
70 * incoming edges of w and add all of the shortest paths to v to the
71 * shortest path count of w.
73 void edge_not_relaxed(edge_descriptor e, const Graph& g)
75 typedef typename property_traits<WeightMap>::value_type weight_type;
76 typedef typename property_traits<DistanceMap>::value_type distance_type;
77 vertex_descriptor v = source(e, g), w = target(e, g);
78 distance_type d_v = get(distance, v), d_w = get(distance, w);
79 weight_type w_e = get(weight, e);
81 closed_plus<distance_type> combine;
82 if (d_w == combine(d_v, w_e)) {
83 put(path_count, w, get(path_count, w) + get(path_count, v));
84 incoming[w].push_back(e);
88 /// Keep track of vertices as they are reached
89 void examine_vertex(vertex_descriptor w, const Graph&)
91 ordered_vertices.push(w);
95 std::stack<vertex_descriptor>& ordered_vertices;
99 PathCountMap path_count;
103 * Function object that calls Dijkstra's shortest paths algorithm
104 * using the Dijkstra visitor for the Brandes betweenness centrality
107 template<typename WeightMap>
108 struct brandes_dijkstra_shortest_paths
110 brandes_dijkstra_shortest_paths(WeightMap weight_map)
111 : weight_map(weight_map) { }
113 template<typename Graph, typename IncomingMap, typename DistanceMap,
114 typename PathCountMap, typename VertexIndexMap>
117 typename graph_traits<Graph>::vertex_descriptor s,
118 std::stack<typename graph_traits<Graph>::vertex_descriptor>& ov,
119 IncomingMap incoming,
120 DistanceMap distance,
121 PathCountMap path_count,
122 VertexIndexMap vertex_index)
124 typedef brandes_dijkstra_visitor<Graph, WeightMap, IncomingMap,
125 DistanceMap, PathCountMap> visitor_type;
126 visitor_type visitor(ov, weight_map, incoming, distance, path_count);
128 dijkstra_shortest_paths(g, s,
129 boost::weight_map(weight_map)
130 .vertex_index_map(vertex_index)
131 .distance_map(distance)
136 WeightMap weight_map;
140 * Function object that invokes breadth-first search for the
141 * unweighted form of the Brandes betweenness centrality algorithm.
143 struct brandes_unweighted_shortest_paths
146 * Customized visitor passed to breadth-first search, which
147 * records predecessor and the number of shortest paths to each
150 template<typename Graph, typename IncomingMap, typename DistanceMap,
151 typename PathCountMap>
152 struct visitor_type : public bfs_visitor<>
154 typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
155 typedef typename graph_traits<Graph>::vertex_descriptor
158 visitor_type(IncomingMap incoming, DistanceMap distance,
159 PathCountMap path_count,
160 std::stack<vertex_descriptor>& ordered_vertices)
161 : incoming(incoming), distance(distance),
162 path_count(path_count), ordered_vertices(ordered_vertices) { }
164 /// Keep track of vertices as they are reached
165 void examine_vertex(vertex_descriptor v, Graph&)
167 ordered_vertices.push(v);
171 * Whenever an edge e = (v, w) is labelled a tree edge, the
172 * incoming edge list for w is set to {(v, w)} and the shortest
173 * path count of w is set to the number of paths that reach {v}.
175 void tree_edge(edge_descriptor e, Graph& g)
177 vertex_descriptor v = source(e, g);
178 vertex_descriptor w = target(e, g);
179 put(distance, w, get(distance, v) + 1);
181 put(path_count, w, get(path_count, v));
182 incoming[w].push_back(e);
186 * If an edge e = (v, w) is not a tree edge, it may still be the
187 * case that we've found more equally-short paths, so include (v, w)
188 * in the incoming edge list of w and add all of the shortest
189 * paths to v to the shortest path count of w.
191 void non_tree_edge(edge_descriptor e, Graph& g)
193 vertex_descriptor v = source(e, g);
194 vertex_descriptor w = target(e, g);
195 if (get(distance, w) == get(distance, v) + 1) {
196 put(path_count, w, get(path_count, w) + get(path_count, v));
197 incoming[w].push_back(e);
202 IncomingMap incoming;
203 DistanceMap distance;
204 PathCountMap path_count;
205 std::stack<vertex_descriptor>& ordered_vertices;
208 template<typename Graph, typename IncomingMap, typename DistanceMap,
209 typename PathCountMap, typename VertexIndexMap>
212 typename graph_traits<Graph>::vertex_descriptor s,
213 std::stack<typename graph_traits<Graph>::vertex_descriptor>& ov,
214 IncomingMap incoming,
215 DistanceMap distance,
216 PathCountMap path_count,
217 VertexIndexMap vertex_index)
219 typedef typename graph_traits<Graph>::vertex_descriptor
222 visitor_type<Graph, IncomingMap, DistanceMap, PathCountMap>
223 visitor(incoming, distance, path_count, ov);
225 std::vector<default_color_type>
226 colors(num_vertices(g), color_traits<default_color_type>::white());
227 boost::queue<vertex_descriptor> Q;
228 breadth_first_visit(g, s, Q, visitor,
229 make_iterator_property_map(colors.begin(),
234 // When the edge centrality map is a dummy property map, no
235 // initialization is needed.
236 template<typename Iter>
238 init_centrality_map(std::pair<Iter, Iter>, dummy_property_map) { }
240 // When we have a real edge centrality map, initialize all of the
241 // centralities to zero.
242 template<typename Iter, typename Centrality>
244 init_centrality_map(std::pair<Iter, Iter> keys, Centrality centrality_map)
246 typedef typename property_traits<Centrality>::value_type
248 while (keys.first != keys.second) {
249 put(centrality_map, *keys.first, centrality_type(0));
254 // When the edge centrality map is a dummy property map, no update
256 template<typename Key, typename T>
258 update_centrality(dummy_property_map, const Key&, const T&) { }
260 // When we have a real edge centrality map, add the value to the map
261 template<typename CentralityMap, typename Key, typename T>
263 update_centrality(CentralityMap centrality_map, Key k, const T& x)
264 { put(centrality_map, k, get(centrality_map, k) + x); }
266 template<typename Iter>
268 divide_centrality_by_two(std::pair<Iter, Iter>, dummy_property_map) {}
270 template<typename Iter, typename CentralityMap>
272 divide_centrality_by_two(std::pair<Iter, Iter> keys,
273 CentralityMap centrality_map)
275 typename property_traits<CentralityMap>::value_type two(2);
276 while (keys.first != keys.second) {
277 put(centrality_map, *keys.first, get(centrality_map, *keys.first) / two);
282 template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
283 typename IncomingMap, typename DistanceMap,
284 typename DependencyMap, typename PathCountMap,
285 typename VertexIndexMap, typename ShortestPaths>
287 brandes_betweenness_centrality_impl(const Graph& g,
288 CentralityMap centrality, // C_B
289 EdgeCentralityMap edge_centrality_map,
290 IncomingMap incoming, // P
291 DistanceMap distance, // d
292 DependencyMap dependency, // delta
293 PathCountMap path_count, // sigma
294 VertexIndexMap vertex_index,
295 ShortestPaths shortest_paths)
297 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
298 typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
299 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
301 // Initialize centrality
302 init_centrality_map(vertices(g), centrality);
303 init_centrality_map(edges(g), edge_centrality_map);
305 std::stack<vertex_descriptor> ordered_vertices;
306 vertex_iterator s, s_end;
307 for (tie(s, s_end) = vertices(g); s != s_end; ++s) {
308 // Initialize for this iteration
309 vertex_iterator w, w_end;
310 for (tie(w, w_end) = vertices(g); w != w_end; ++w) {
311 incoming[*w].clear();
312 put(path_count, *w, 0);
313 put(dependency, *w, 0);
315 put(path_count, *s, 1);
317 // Execute the shortest paths algorithm. This will be either
318 // Dijkstra's algorithm or a customized breadth-first search,
319 // depending on whether the graph is weighted or unweighted.
320 shortest_paths(g, *s, ordered_vertices, incoming, distance,
321 path_count, vertex_index);
323 while (!ordered_vertices.empty()) {
324 vertex_descriptor w = ordered_vertices.top();
325 ordered_vertices.pop();
327 typedef typename property_traits<IncomingMap>::value_type
329 typedef typename incoming_type::iterator incoming_iterator;
330 typedef typename property_traits<DependencyMap>::value_type
333 for (incoming_iterator vw = incoming[w].begin();
334 vw != incoming[w].end(); ++vw) {
335 vertex_descriptor v = source(*vw, g);
336 dependency_type factor = dependency_type(get(path_count, v))
337 / dependency_type(get(path_count, w));
338 factor *= (dependency_type(1) + get(dependency, w));
339 put(dependency, v, get(dependency, v) + factor);
340 update_centrality(edge_centrality_map, *vw, factor);
344 update_centrality(centrality, w, get(dependency, w));
349 typedef typename graph_traits<Graph>::directed_category directed_category;
350 const bool is_undirected =
351 is_convertible<directed_category*, undirected_tag*>::value;
353 divide_centrality_by_two(vertices(g), centrality);
354 divide_centrality_by_two(edges(g), edge_centrality_map);
358 } } // end namespace detail::graph
360 template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
361 typename IncomingMap, typename DistanceMap,
362 typename DependencyMap, typename PathCountMap,
363 typename VertexIndexMap>
365 brandes_betweenness_centrality(const Graph& g,
366 CentralityMap centrality, // C_B
367 EdgeCentralityMap edge_centrality_map,
368 IncomingMap incoming, // P
369 DistanceMap distance, // d
370 DependencyMap dependency, // delta
371 PathCountMap path_count, // sigma
372 VertexIndexMap vertex_index)
374 detail::graph::brandes_unweighted_shortest_paths shortest_paths;
376 detail::graph::brandes_betweenness_centrality_impl(g, centrality,
379 dependency, path_count,
384 template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
385 typename IncomingMap, typename DistanceMap,
386 typename DependencyMap, typename PathCountMap,
387 typename VertexIndexMap, typename WeightMap>
389 brandes_betweenness_centrality(const Graph& g,
390 CentralityMap centrality, // C_B
391 EdgeCentralityMap edge_centrality_map,
392 IncomingMap incoming, // P
393 DistanceMap distance, // d
394 DependencyMap dependency, // delta
395 PathCountMap path_count, // sigma
396 VertexIndexMap vertex_index,
397 WeightMap weight_map)
399 detail::graph::brandes_dijkstra_shortest_paths<WeightMap>
400 shortest_paths(weight_map);
402 detail::graph::brandes_betweenness_centrality_impl(g, centrality,
405 dependency, path_count,
410 namespace detail { namespace graph {
411 template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
412 typename WeightMap, typename VertexIndexMap>
414 brandes_betweenness_centrality_dispatch2(const Graph& g,
415 CentralityMap centrality,
416 EdgeCentralityMap edge_centrality_map,
417 WeightMap weight_map,
418 VertexIndexMap vertex_index)
420 typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
421 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
422 typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
423 typedef typename mpl::if_c<(is_same<CentralityMap,
424 dummy_property_map>::value),
426 CentralityMap>::type a_centrality_map;
427 typedef typename property_traits<a_centrality_map>::value_type
430 typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
432 std::vector<std::vector<edge_descriptor> > incoming(V);
433 std::vector<centrality_type> distance(V);
434 std::vector<centrality_type> dependency(V);
435 std::vector<degree_size_type> path_count(V);
437 brandes_betweenness_centrality(
438 g, centrality, edge_centrality_map,
439 make_iterator_property_map(incoming.begin(), vertex_index),
440 make_iterator_property_map(distance.begin(), vertex_index),
441 make_iterator_property_map(dependency.begin(), vertex_index),
442 make_iterator_property_map(path_count.begin(), vertex_index),
448 template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
449 typename VertexIndexMap>
451 brandes_betweenness_centrality_dispatch2(const Graph& g,
452 CentralityMap centrality,
453 EdgeCentralityMap edge_centrality_map,
454 VertexIndexMap vertex_index)
456 typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
457 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
458 typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
459 typedef typename mpl::if_c<(is_same<CentralityMap,
460 dummy_property_map>::value),
462 CentralityMap>::type a_centrality_map;
463 typedef typename property_traits<a_centrality_map>::value_type
466 typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
468 std::vector<std::vector<edge_descriptor> > incoming(V);
469 std::vector<centrality_type> distance(V);
470 std::vector<centrality_type> dependency(V);
471 std::vector<degree_size_type> path_count(V);
473 brandes_betweenness_centrality(
474 g, centrality, edge_centrality_map,
475 make_iterator_property_map(incoming.begin(), vertex_index),
476 make_iterator_property_map(distance.begin(), vertex_index),
477 make_iterator_property_map(dependency.begin(), vertex_index),
478 make_iterator_property_map(path_count.begin(), vertex_index),
482 template<typename WeightMap>
483 struct brandes_betweenness_centrality_dispatch1
485 template<typename Graph, typename CentralityMap,
486 typename EdgeCentralityMap, typename VertexIndexMap>
488 run(const Graph& g, CentralityMap centrality,
489 EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
490 WeightMap weight_map)
492 brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map,
493 weight_map, vertex_index);
498 struct brandes_betweenness_centrality_dispatch1<error_property_not_found>
500 template<typename Graph, typename CentralityMap,
501 typename EdgeCentralityMap, typename VertexIndexMap>
503 run(const Graph& g, CentralityMap centrality,
504 EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
505 error_property_not_found)
507 brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map,
512 } } // end namespace detail::graph
514 template<typename Graph, typename Param, typename Tag, typename Rest>
516 brandes_betweenness_centrality(const Graph& g,
517 const bgl_named_params<Param,Tag,Rest>& params)
519 typedef bgl_named_params<Param,Tag,Rest> named_params;
521 typedef typename property_value<named_params, edge_weight_t>::type ew;
522 detail::graph::brandes_betweenness_centrality_dispatch1<ew>::run(
524 choose_param(get_param(params, vertex_centrality),
525 dummy_property_map()),
526 choose_param(get_param(params, edge_centrality),
527 dummy_property_map()),
528 choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
529 get_param(params, edge_weight));
532 template<typename Graph, typename CentralityMap>
534 brandes_betweenness_centrality(const Graph& g, CentralityMap centrality)
536 detail::graph::brandes_betweenness_centrality_dispatch2(
537 g, centrality, dummy_property_map(), get(vertex_index, g));
540 template<typename Graph, typename CentralityMap, typename EdgeCentralityMap>
542 brandes_betweenness_centrality(const Graph& g, CentralityMap centrality,
543 EdgeCentralityMap edge_centrality_map)
545 detail::graph::brandes_betweenness_centrality_dispatch2(
546 g, centrality, edge_centrality_map, get(vertex_index, g));
550 * Converts "absolute" betweenness centrality (as computed by the
551 * brandes_betweenness_centrality algorithm) in the centrality map
552 * into "relative" centrality. The result is placed back into the
553 * given centrality map.
555 template<typename Graph, typename CentralityMap>
557 relative_betweenness_centrality(const Graph& g, CentralityMap centrality)
559 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
560 typedef typename property_traits<CentralityMap>::value_type centrality_type;
562 typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
563 centrality_type factor = centrality_type(2)/centrality_type(n*n - 3*n + 2);
564 vertex_iterator v, v_end;
565 for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
566 put(centrality, *v, factor * get(centrality, *v));
570 // Compute the central point dominance of a graph.
571 template<typename Graph, typename CentralityMap>
572 typename property_traits<CentralityMap>::value_type
573 central_point_dominance(const Graph& g, CentralityMap centrality)
577 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
578 typedef typename property_traits<CentralityMap>::value_type centrality_type;
580 typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
582 // Find max centrality
583 centrality_type max_centrality(0);
584 vertex_iterator v, v_end;
585 for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
586 max_centrality = (max)(max_centrality, get(centrality, *v));
589 // Compute central point dominance
590 centrality_type sum(0);
591 for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
592 sum += (max_centrality - get(centrality, *v));
597 } // end namespace boost
599 #endif // BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP