PageRenderTime 83ms CodeModel.GetById 38ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/graph/betweenness_centrality.hpp

http://hadesmem.googlecode.com/
C++ Header | 619 lines | 472 code | 73 blank | 74 comment | 24 complexity | 319e8cf81fe93da13e019633f5892385 MD5 | raw file
  1// Copyright 2004 The Trustees of Indiana University.
  2
  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)
  6
  7//  Authors: Douglas Gregor
  8//           Andrew Lumsdaine
  9#ifndef BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP
 10#define BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP
 11
 12#include <stack>
 13#include <vector>
 14#include <boost/graph/overloading.hpp>
 15#include <boost/graph/dijkstra_shortest_paths.hpp>
 16#include <boost/graph/breadth_first_search.hpp>
 17#include <boost/graph/relax.hpp>
 18#include <boost/graph/graph_traits.hpp>
 19#include <boost/tuple/tuple.hpp>
 20#include <boost/type_traits/is_convertible.hpp>
 21#include <boost/type_traits/is_same.hpp>
 22#include <boost/mpl/if.hpp>
 23#include <boost/property_map/property_map.hpp>
 24#include <boost/graph/named_function_params.hpp>
 25#include <algorithm>
 26
 27namespace boost {
 28
 29namespace detail { namespace graph {
 30
 31  /**
 32   * Customized visitor passed to Dijkstra's algorithm by Brandes'
 33   * betweenness centrality algorithm. This visitor is responsible for
 34   * keeping track of the order in which vertices are discovered, the
 35   * predecessors on the shortest path(s) to a vertex, and the number
 36   * of shortest paths.
 37   */
 38  template<typename Graph, typename WeightMap, typename IncomingMap,
 39           typename DistanceMap, typename PathCountMap>
 40  struct brandes_dijkstra_visitor : public bfs_visitor<>
 41  {
 42    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
 43    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
 44
 45    brandes_dijkstra_visitor(std::stack<vertex_descriptor>& ordered_vertices,
 46                             WeightMap weight,
 47                             IncomingMap incoming,
 48                             DistanceMap distance,
 49                             PathCountMap path_count)
 50      : ordered_vertices(ordered_vertices), weight(weight), 
 51        incoming(incoming), distance(distance),
 52        path_count(path_count)
 53    { }
 54
 55    /**
 56     * Whenever an edge e = (v, w) is relaxed, the incoming edge list
 57     * for w is set to {(v, w)} and the shortest path count of w is set to
 58     * the number of paths that reach {v}.
 59     */
 60    void edge_relaxed(edge_descriptor e, const Graph& g) 
 61    { 
 62      vertex_descriptor v = source(e, g), w = target(e, g);
 63      incoming[w].clear();
 64      incoming[w].push_back(e);
 65      put(path_count, w, get(path_count, v));
 66    }
 67
 68    /**
 69     * If an edge e = (v, w) was not relaxed, it may still be the case
 70     * that we've found more equally-short paths, so include {(v, w)} in the
 71     * incoming edges of w and add all of the shortest paths to v to the
 72     * shortest path count of w.
 73     */
 74    void edge_not_relaxed(edge_descriptor e, const Graph& g) 
 75    {
 76      typedef typename property_traits<WeightMap>::value_type weight_type;
 77      typedef typename property_traits<DistanceMap>::value_type distance_type;
 78      vertex_descriptor v = source(e, g), w = target(e, g);
 79      distance_type d_v = get(distance, v), d_w = get(distance, w);
 80      weight_type w_e = get(weight, e);
 81
 82      closed_plus<distance_type> combine;
 83      if (d_w == combine(d_v, w_e)) {
 84        put(path_count, w, get(path_count, w) + get(path_count, v));
 85        incoming[w].push_back(e);
 86      }
 87    }
 88
 89    /// Keep track of vertices as they are reached
 90    void examine_vertex(vertex_descriptor w, const Graph&) 
 91    { 
 92      ordered_vertices.push(w);
 93    }
 94
 95  private:
 96    std::stack<vertex_descriptor>& ordered_vertices;
 97    WeightMap weight;
 98    IncomingMap incoming;
 99    DistanceMap distance;
100    PathCountMap path_count;
101  };
102
103  /**
104   * Function object that calls Dijkstra's shortest paths algorithm
105   * using the Dijkstra visitor for the Brandes betweenness centrality
106   * algorithm.
107   */
108  template<typename WeightMap>
109  struct brandes_dijkstra_shortest_paths
110  {
111    brandes_dijkstra_shortest_paths(WeightMap weight_map) 
112      : weight_map(weight_map) { }
113
114    template<typename Graph, typename IncomingMap, typename DistanceMap, 
115             typename PathCountMap, typename VertexIndexMap>
116    void 
117    operator()(Graph& g, 
118               typename graph_traits<Graph>::vertex_descriptor s,
119               std::stack<typename graph_traits<Graph>::vertex_descriptor>& ov,
120               IncomingMap incoming,
121               DistanceMap distance,
122               PathCountMap path_count,
123               VertexIndexMap vertex_index)
124    {
125      typedef brandes_dijkstra_visitor<Graph, WeightMap, IncomingMap, 
126                                       DistanceMap, PathCountMap> visitor_type;
127      visitor_type visitor(ov, weight_map, incoming, distance, path_count);
128
129      dijkstra_shortest_paths(g, s, 
130                              boost::weight_map(weight_map)
131                              .vertex_index_map(vertex_index)
132                              .distance_map(distance)
133                              .visitor(visitor));
134    }
135
136  private:
137    WeightMap weight_map;
138  };
139
140  /**
141   * Function object that invokes breadth-first search for the
142   * unweighted form of the Brandes betweenness centrality algorithm.
143   */
144  struct brandes_unweighted_shortest_paths
145  {
146    /**
147     * Customized visitor passed to breadth-first search, which
148     * records predecessor and the number of shortest paths to each
149     * vertex.
150     */
151    template<typename Graph, typename IncomingMap, typename DistanceMap, 
152             typename PathCountMap>
153    struct visitor_type : public bfs_visitor<>
154    {
155      typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
156      typedef typename graph_traits<Graph>::vertex_descriptor 
157        vertex_descriptor;
158      
159      visitor_type(IncomingMap incoming, DistanceMap distance, 
160                   PathCountMap path_count, 
161                   std::stack<vertex_descriptor>& ordered_vertices)
162        : incoming(incoming), distance(distance), 
163          path_count(path_count), ordered_vertices(ordered_vertices) { }
164
165      /// Keep track of vertices as they are reached
166      void examine_vertex(vertex_descriptor v, Graph&)
167      {
168        ordered_vertices.push(v);
169      }
170
171      /**
172       * Whenever an edge e = (v, w) is labelled a tree edge, the
173       * incoming edge list for w is set to {(v, w)} and the shortest
174       * path count of w is set to the number of paths that reach {v}.
175       */
176      void tree_edge(edge_descriptor e, Graph& g)
177      {
178        vertex_descriptor v = source(e, g);
179        vertex_descriptor w = target(e, g);
180        put(distance, w, get(distance, v) + 1);
181        
182        put(path_count, w, get(path_count, v));
183        incoming[w].push_back(e);
184      }
185
186      /**
187       * If an edge e = (v, w) is not a tree edge, it may still be the
188       * case that we've found more equally-short paths, so include (v, w)
189       * in the incoming edge list of w and add all of the shortest
190       * paths to v to the shortest path count of w.
191       */
192      void non_tree_edge(edge_descriptor e, Graph& g)
193      {
194        vertex_descriptor v = source(e, g);
195        vertex_descriptor w = target(e, g);
196        if (get(distance, w) == get(distance, v) + 1) {
197          put(path_count, w, get(path_count, w) + get(path_count, v));
198          incoming[w].push_back(e);
199        }
200      }
201
202    private:
203      IncomingMap incoming;
204      DistanceMap distance;
205      PathCountMap path_count;
206      std::stack<vertex_descriptor>& ordered_vertices;
207    };
208
209    template<typename Graph, typename IncomingMap, typename DistanceMap, 
210             typename PathCountMap, typename VertexIndexMap>
211    void 
212    operator()(Graph& g, 
213               typename graph_traits<Graph>::vertex_descriptor s,
214               std::stack<typename graph_traits<Graph>::vertex_descriptor>& ov,
215               IncomingMap incoming,
216               DistanceMap distance,
217               PathCountMap path_count,
218               VertexIndexMap vertex_index)
219    {
220      typedef typename graph_traits<Graph>::vertex_descriptor
221        vertex_descriptor;
222
223      visitor_type<Graph, IncomingMap, DistanceMap, PathCountMap>
224        visitor(incoming, distance, path_count, ov);
225      
226      std::vector<default_color_type> 
227        colors(num_vertices(g), color_traits<default_color_type>::white());
228      boost::queue<vertex_descriptor> Q;
229      breadth_first_visit(g, s, Q, visitor, 
230                          make_iterator_property_map(colors.begin(), 
231                                                     vertex_index));
232    }
233  };
234
235  // When the edge centrality map is a dummy property map, no
236  // initialization is needed.
237  template<typename Iter>
238  inline void 
239  init_centrality_map(std::pair<Iter, Iter>, dummy_property_map) { }
240
241  // When we have a real edge centrality map, initialize all of the
242  // centralities to zero.
243  template<typename Iter, typename Centrality>
244  void 
245  init_centrality_map(std::pair<Iter, Iter> keys, Centrality centrality_map)
246  {
247    typedef typename property_traits<Centrality>::value_type 
248      centrality_type;
249    while (keys.first != keys.second) {
250      put(centrality_map, *keys.first, centrality_type(0));
251      ++keys.first;
252    }
253  }
254
255  // When the edge centrality map is a dummy property map, no update
256  // is performed.
257  template<typename Key, typename T>
258  inline void 
259  update_centrality(dummy_property_map, const Key&, const T&) { }
260
261  // When we have a real edge centrality map, add the value to the map
262  template<typename CentralityMap, typename Key, typename T>
263  inline void 
264  update_centrality(CentralityMap centrality_map, Key k, const T& x)
265  { put(centrality_map, k, get(centrality_map, k) + x); }
266
267  template<typename Iter>
268  inline void 
269  divide_centrality_by_two(std::pair<Iter, Iter>, dummy_property_map) {}
270
271  template<typename Iter, typename CentralityMap>
272  inline void
273  divide_centrality_by_two(std::pair<Iter, Iter> keys, 
274                           CentralityMap centrality_map)
275  {
276    typename property_traits<CentralityMap>::value_type two(2);
277    while (keys.first != keys.second) {
278      put(centrality_map, *keys.first, get(centrality_map, *keys.first) / two);
279      ++keys.first;
280    }
281  }
282
283  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
284           typename IncomingMap, typename DistanceMap, 
285           typename DependencyMap, typename PathCountMap,
286           typename VertexIndexMap, typename ShortestPaths>
287  void 
288  brandes_betweenness_centrality_impl(const Graph& g, 
289                                      CentralityMap centrality,     // C_B
290                                      EdgeCentralityMap edge_centrality_map,
291                                      IncomingMap incoming, // P
292                                      DistanceMap distance,         // d
293                                      DependencyMap dependency,     // delta
294                                      PathCountMap path_count,      // sigma
295                                      VertexIndexMap vertex_index,
296                                      ShortestPaths shortest_paths)
297  {
298    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
299    typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
300    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
301
302    // Initialize centrality
303    init_centrality_map(vertices(g), centrality);
304    init_centrality_map(edges(g), edge_centrality_map);
305
306    std::stack<vertex_descriptor> ordered_vertices;
307    vertex_iterator s, s_end;
308    for (boost::tie(s, s_end) = vertices(g); s != s_end; ++s) {
309      // Initialize for this iteration
310      vertex_iterator w, w_end;
311      for (boost::tie(w, w_end) = vertices(g); w != w_end; ++w) {
312        incoming[*w].clear();
313        put(path_count, *w, 0);
314        put(dependency, *w, 0);
315      }
316      put(path_count, *s, 1);
317      
318      // Execute the shortest paths algorithm. This will be either
319      // Dijkstra's algorithm or a customized breadth-first search,
320      // depending on whether the graph is weighted or unweighted.
321      shortest_paths(g, *s, ordered_vertices, incoming, distance,
322                     path_count, vertex_index);
323      
324      while (!ordered_vertices.empty()) {
325        vertex_descriptor w = ordered_vertices.top();
326        ordered_vertices.pop();
327        
328        typedef typename property_traits<IncomingMap>::value_type
329          incoming_type;
330        typedef typename incoming_type::iterator incoming_iterator;
331        typedef typename property_traits<DependencyMap>::value_type 
332          dependency_type;
333        
334        for (incoming_iterator vw = incoming[w].begin();
335             vw != incoming[w].end(); ++vw) {
336          vertex_descriptor v = source(*vw, g);
337          dependency_type factor = dependency_type(get(path_count, v))
338            / dependency_type(get(path_count, w));
339          factor *= (dependency_type(1) + get(dependency, w));
340          put(dependency, v, get(dependency, v) + factor);
341          update_centrality(edge_centrality_map, *vw, factor);
342        }
343        
344        if (w != *s) {
345          update_centrality(centrality, w, get(dependency, w));
346        }
347      }
348    }
349
350    typedef typename graph_traits<Graph>::directed_category directed_category;
351    const bool is_undirected = 
352      is_convertible<directed_category*, undirected_tag*>::value;
353    if (is_undirected) {
354      divide_centrality_by_two(vertices(g), centrality);
355      divide_centrality_by_two(edges(g), edge_centrality_map);
356    }
357  }
358
359} } // end namespace detail::graph
360
361template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
362         typename IncomingMap, typename DistanceMap, 
363         typename DependencyMap, typename PathCountMap, 
364         typename VertexIndexMap>
365void 
366brandes_betweenness_centrality(const Graph& g, 
367                               CentralityMap centrality,     // C_B
368                               EdgeCentralityMap edge_centrality_map,
369                               IncomingMap incoming, // P
370                               DistanceMap distance,         // d
371                               DependencyMap dependency,     // delta
372                               PathCountMap path_count,      // sigma
373                               VertexIndexMap vertex_index
374                               BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
375{
376  detail::graph::brandes_unweighted_shortest_paths shortest_paths;
377
378  detail::graph::brandes_betweenness_centrality_impl(g, centrality, 
379                                                     edge_centrality_map,
380                                                     incoming, distance,
381                                                     dependency, path_count,
382                                                     vertex_index, 
383                                                     shortest_paths);
384}
385
386template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, 
387         typename IncomingMap, typename DistanceMap, 
388         typename DependencyMap, typename PathCountMap, 
389         typename VertexIndexMap, typename WeightMap>    
390void 
391brandes_betweenness_centrality(const Graph& g, 
392                               CentralityMap centrality,     // C_B
393                               EdgeCentralityMap edge_centrality_map,
394                               IncomingMap incoming, // P
395                               DistanceMap distance,         // d
396                               DependencyMap dependency,     // delta
397                               PathCountMap path_count,      // sigma
398                               VertexIndexMap vertex_index,
399                               WeightMap weight_map
400                               BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
401{
402  detail::graph::brandes_dijkstra_shortest_paths<WeightMap>
403    shortest_paths(weight_map);
404
405  detail::graph::brandes_betweenness_centrality_impl(g, centrality, 
406                                                     edge_centrality_map,
407                                                     incoming, distance,
408                                                     dependency, path_count,
409                                                     vertex_index, 
410                                                     shortest_paths);
411}
412
413namespace detail { namespace graph {
414  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
415           typename WeightMap, typename VertexIndexMap>
416  void 
417  brandes_betweenness_centrality_dispatch2(const Graph& g,
418                                           CentralityMap centrality,
419                                           EdgeCentralityMap edge_centrality_map,
420                                           WeightMap weight_map,
421                                           VertexIndexMap vertex_index)
422  {
423    typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
424    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
425    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
426    typedef typename mpl::if_c<(is_same<CentralityMap, 
427                                        dummy_property_map>::value),
428                                         EdgeCentralityMap, 
429                               CentralityMap>::type a_centrality_map;
430    typedef typename property_traits<a_centrality_map>::value_type 
431      centrality_type;
432
433    typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
434    
435    std::vector<std::vector<edge_descriptor> > incoming(V);
436    std::vector<centrality_type> distance(V);
437    std::vector<centrality_type> dependency(V);
438    std::vector<degree_size_type> path_count(V);
439
440    brandes_betweenness_centrality(
441      g, centrality, edge_centrality_map,
442      make_iterator_property_map(incoming.begin(), vertex_index),
443      make_iterator_property_map(distance.begin(), vertex_index),
444      make_iterator_property_map(dependency.begin(), vertex_index),
445      make_iterator_property_map(path_count.begin(), vertex_index),
446      vertex_index,
447      weight_map);
448  }
449  
450
451  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
452           typename VertexIndexMap>
453  void 
454  brandes_betweenness_centrality_dispatch2(const Graph& g,
455                                           CentralityMap centrality,
456                                           EdgeCentralityMap edge_centrality_map,
457                                           VertexIndexMap vertex_index)
458  {
459    typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
460    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
461    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
462    typedef typename mpl::if_c<(is_same<CentralityMap, 
463                                        dummy_property_map>::value),
464                                         EdgeCentralityMap, 
465                               CentralityMap>::type a_centrality_map;
466    typedef typename property_traits<a_centrality_map>::value_type 
467      centrality_type;
468
469    typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
470    
471    std::vector<std::vector<edge_descriptor> > incoming(V);
472    std::vector<centrality_type> distance(V);
473    std::vector<centrality_type> dependency(V);
474    std::vector<degree_size_type> path_count(V);
475
476    brandes_betweenness_centrality(
477      g, centrality, edge_centrality_map,
478      make_iterator_property_map(incoming.begin(), vertex_index),
479      make_iterator_property_map(distance.begin(), vertex_index),
480      make_iterator_property_map(dependency.begin(), vertex_index),
481      make_iterator_property_map(path_count.begin(), vertex_index),
482      vertex_index);
483  }
484
485  template<typename WeightMap>
486  struct brandes_betweenness_centrality_dispatch1
487  {
488    template<typename Graph, typename CentralityMap, 
489             typename EdgeCentralityMap, typename VertexIndexMap>
490    static void 
491    run(const Graph& g, CentralityMap centrality, 
492        EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
493        WeightMap weight_map)
494    {
495      brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map,
496                                               weight_map, vertex_index);
497    }
498  };
499
500  template<>
501  struct brandes_betweenness_centrality_dispatch1<error_property_not_found>
502  {
503    template<typename Graph, typename CentralityMap, 
504             typename EdgeCentralityMap, typename VertexIndexMap>
505    static void 
506    run(const Graph& g, CentralityMap centrality, 
507        EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
508        error_property_not_found)
509    {
510      brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map,
511                                               vertex_index);
512    }
513  };
514
515  template <typename T>
516  struct is_bgl_named_params {
517    BOOST_STATIC_CONSTANT(bool, value = false);
518  };
519
520  template <typename Param, typename Tag, typename Rest>
521  struct is_bgl_named_params<bgl_named_params<Param, Tag, Rest> > {
522    BOOST_STATIC_CONSTANT(bool, value = true);
523  };
524
525} } // end namespace detail::graph
526
527template<typename Graph, typename Param, typename Tag, typename Rest>
528void 
529brandes_betweenness_centrality(const Graph& g, 
530                               const bgl_named_params<Param,Tag,Rest>& params
531                               BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
532{
533  typedef bgl_named_params<Param,Tag,Rest> named_params;
534
535  typedef typename property_value<named_params, edge_weight_t>::type ew;
536  detail::graph::brandes_betweenness_centrality_dispatch1<ew>::run(
537    g, 
538    choose_param(get_param(params, vertex_centrality), 
539                 dummy_property_map()),
540    choose_param(get_param(params, edge_centrality), 
541                 dummy_property_map()),
542    choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
543    get_param(params, edge_weight));
544}
545
546// disable_if is required to work around problem with MSVC 7.1 (it seems to not
547// get partial ordering getween this overload and the previous one correct)
548template<typename Graph, typename CentralityMap>
549typename disable_if<detail::graph::is_bgl_named_params<CentralityMap>,
550                    void>::type
551brandes_betweenness_centrality(const Graph& g, CentralityMap centrality
552                               BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
553{
554  detail::graph::brandes_betweenness_centrality_dispatch2(
555    g, centrality, dummy_property_map(), get(vertex_index, g));
556}
557
558template<typename Graph, typename CentralityMap, typename EdgeCentralityMap>
559void 
560brandes_betweenness_centrality(const Graph& g, CentralityMap centrality,
561                               EdgeCentralityMap edge_centrality_map
562                               BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
563{
564  detail::graph::brandes_betweenness_centrality_dispatch2(
565    g, centrality, edge_centrality_map, get(vertex_index, g));
566}
567
568/**
569 * Converts "absolute" betweenness centrality (as computed by the
570 * brandes_betweenness_centrality algorithm) in the centrality map
571 * into "relative" centrality. The result is placed back into the
572 * given centrality map.
573 */
574template<typename Graph, typename CentralityMap>
575void 
576relative_betweenness_centrality(const Graph& g, CentralityMap centrality)
577{
578  typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
579  typedef typename property_traits<CentralityMap>::value_type centrality_type;
580
581  typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
582  centrality_type factor = centrality_type(2)/centrality_type(n*n - 3*n + 2);
583  vertex_iterator v, v_end;
584  for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
585    put(centrality, *v, factor * get(centrality, *v));
586  }
587}
588
589// Compute the central point dominance of a graph.
590template<typename Graph, typename CentralityMap>
591typename property_traits<CentralityMap>::value_type
592central_point_dominance(const Graph& g, CentralityMap centrality
593                        BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
594{
595  using std::max;
596
597  typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
598  typedef typename property_traits<CentralityMap>::value_type centrality_type;
599
600  typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
601
602  // Find max centrality
603  centrality_type max_centrality(0);
604  vertex_iterator v, v_end;
605  for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
606    max_centrality = (max)(max_centrality, get(centrality, *v));
607  }
608
609  // Compute central point dominance
610  centrality_type sum(0);
611  for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
612    sum += (max_centrality - get(centrality, *v));
613  }
614  return sum/(n-1);
615}
616
617} // end namespace boost
618
619#endif // BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP