PageRenderTime 144ms CodeModel.GetById 34ms app.highlight 97ms RepoModel.GetById 2ms app.codeStats 0ms

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

http://hadesmem.googlecode.com/
C++ Header | 1725 lines | 1279 code | 277 blank | 169 comment | 134 complexity | 3c5cc5e53d9cdbd8c727a8a0edd8053e MD5 | raw file

Large files files are truncated, but you can click here to view the full 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_PARALLEL_BRANDES_BETWEENNESS_CENTRALITY_HPP
  10#define BOOST_GRAPH_PARALLEL_BRANDES_BETWEENNESS_CENTRALITY_HPP
  11
  12#ifndef BOOST_GRAPH_USE_MPI
  13#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
  14#endif
  15
  16// #define COMPUTE_PATH_COUNTS_INLINE
  17
  18#include <boost/graph/betweenness_centrality.hpp>
  19#include <boost/graph/overloading.hpp>
  20#include <boost/graph/distributed/concepts.hpp>
  21#include <boost/graph/graph_traits.hpp>
  22#include <boost/config.hpp>
  23#include <boost/assert.hpp>
  24
  25// For additive_reducer
  26#include <boost/graph/distributed/distributed_graph_utility.hpp>
  27#include <boost/type_traits/is_convertible.hpp>
  28#include <boost/type_traits/is_same.hpp>
  29#include <boost/property_map/property_map.hpp>
  30#include <boost/graph/named_function_params.hpp>
  31
  32#include <boost/property_map/parallel/distributed_property_map.hpp>
  33#include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp>
  34#include <boost/tuple/tuple.hpp>
  35
  36// NGE - Needed for minstd_rand at L807, should pass vertex list
  37//       or generator instead 
  38#include <boost/random/linear_congruential.hpp>
  39
  40#include <algorithm>
  41#include <stack>
  42#include <vector>
  43
  44// Appending reducer
  45template <typename T>
  46struct append_reducer {
  47  BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
  48      
  49  template<typename K>
  50  T operator()(const K&) const { return T(); }
  51      
  52  template<typename K>
  53  T operator()(const K&, const T& x, const T& y) const 
  54  { 
  55    T z(x.begin(), x.end());
  56    for (typename T::const_iterator iter = y.begin(); iter != y.end(); ++iter)
  57      if (std::find(z.begin(), z.end(), *iter) == z.end())
  58        z.push_back(*iter);
  59    
  60    return z;
  61  }
  62};
  63
  64namespace boost {
  65
  66  namespace serialization {
  67
  68    // TODO(nge): Write generalized serialization for tuples
  69    template<typename Archive, typename T1, typename T2, typename T3, 
  70             typename T4>
  71    void serialize(Archive & ar,
  72                   boost::tuple<T1,T2,T3, T4>& t,
  73                   const unsigned int)
  74    {
  75      ar & boost::tuples::get<0>(t);
  76      ar & boost::tuples::get<1>(t);
  77      ar & boost::tuples::get<2>(t);
  78      ar & boost::tuples::get<3>(t);
  79    }
  80
  81  } // serialization
  82
  83  template <typename OwnerMap, typename Tuple>
  84  class get_owner_of_first_tuple_element {
  85
  86  public:
  87    typedef typename property_traits<OwnerMap>::value_type owner_type;
  88    
  89    get_owner_of_first_tuple_element(OwnerMap owner) : owner(owner) { }
  90
  91    owner_type get_owner(Tuple t) { return get(owner, boost::tuples::get<0>(t)); }
  92
  93  private:
  94    OwnerMap owner;
  95  };
  96
  97  template <typename OwnerMap, typename Tuple>
  98  typename get_owner_of_first_tuple_element<OwnerMap, Tuple>::owner_type
  99  get(get_owner_of_first_tuple_element<OwnerMap, Tuple> o, Tuple t)
 100  { return o.get_owner(t); } 
 101
 102  template <typename OwnerMap>
 103  class get_owner_of_first_pair_element {
 104
 105  public:
 106    typedef typename property_traits<OwnerMap>::value_type owner_type;
 107    
 108    get_owner_of_first_pair_element(OwnerMap owner) : owner(owner) { }
 109
 110    template <typename Vertex, typename T>
 111    owner_type get_owner(std::pair<Vertex, T> p) { return get(owner, p.first); }
 112
 113  private:
 114    OwnerMap owner;
 115  };
 116
 117  template <typename OwnerMap, typename Vertex, typename T>
 118  typename get_owner_of_first_pair_element<OwnerMap>::owner_type
 119  get(get_owner_of_first_pair_element<OwnerMap> o, std::pair<Vertex, T> p)
 120  { return o.get_owner(p); } 
 121
 122  namespace graph { namespace parallel { namespace detail {
 123
 124  template<typename DistanceMap, typename IncomingMap>
 125  class betweenness_centrality_msg_value
 126  {
 127    typedef typename property_traits<DistanceMap>::value_type distance_type;
 128    typedef typename property_traits<IncomingMap>::value_type incoming_type;
 129    typedef typename incoming_type::value_type incoming_value_type;
 130
 131  public:
 132    typedef std::pair<distance_type, incoming_value_type> type;
 133    
 134    static type create(distance_type dist, incoming_value_type source)
 135    { return std::make_pair(dist, source); }
 136  };
 137
 138
 139  /************************************************************************/
 140  /* Delta-stepping Betweenness Centrality                                */
 141  /************************************************************************/
 142
 143  template<typename Graph, typename DistanceMap, typename IncomingMap, 
 144           typename EdgeWeightMap, typename PathCountMap
 145#ifdef COMPUTE_PATH_COUNTS_INLINE
 146           , typename IsSettledMap, typename VertexIndexMap
 147#endif
 148           >
 149  class betweenness_centrality_delta_stepping_impl { 
 150    // Could inherit from delta_stepping_impl to get run() method
 151    // but for the time being it's just reproduced here
 152
 153    typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
 154    typedef typename graph_traits<Graph>::degree_size_type Degree;
 155    typedef typename property_traits<EdgeWeightMap>::value_type Dist;
 156    typedef typename property_traits<IncomingMap>::value_type IncomingType;
 157    typedef typename boost::graph::parallel::process_group_type<Graph>::type 
 158      ProcessGroup;
 159    
 160    typedef std::list<Vertex> Bucket;
 161    typedef typename Bucket::iterator BucketIterator;
 162    typedef typename std::vector<Bucket*>::size_type BucketIndex;
 163
 164    typedef betweenness_centrality_msg_value<DistanceMap, IncomingMap> 
 165      MessageValue;
 166    
 167    enum { 
 168      // Relax a remote vertex. The message contains a pair<Vertex,
 169      // MessageValue>, the first part of which is the vertex whose
 170      // tentative distance is being relaxed and the second part
 171      // contains either the new distance (if there is no predecessor
 172      // map) or a pair with the distance and predecessor.
 173      msg_relax 
 174    };
 175
 176  public:
 177
 178    // Must supply delta, ctor that guesses delta removed 
 179    betweenness_centrality_delta_stepping_impl(const Graph& g,
 180                                               DistanceMap distance, 
 181                                               IncomingMap incoming,
 182                                               EdgeWeightMap weight,
 183                                               PathCountMap path_count,
 184#ifdef COMPUTE_PATH_COUNTS_INLINE
 185                                               IsSettledMap is_settled,
 186                                               VertexIndexMap vertex_index,
 187#endif
 188                                               Dist delta);
 189    
 190    void run(Vertex s);
 191
 192  private:
 193    // Relax the edge (u, v), creating a new best path of distance x.
 194    void relax(Vertex u, Vertex v, Dist x);
 195
 196    // Synchronize all of the processes, by receiving all messages that
 197    // have not yet been received.
 198    void synchronize()
 199    {
 200      using boost::graph::parallel::synchronize;
 201      synchronize(pg);
 202    }
 203    
 204    // Setup triggers for msg_relax messages
 205    void setup_triggers()
 206    {
 207      using boost::graph::parallel::simple_trigger;
 208      simple_trigger(pg, msg_relax, this, 
 209                     &betweenness_centrality_delta_stepping_impl::handle_msg_relax);
 210    }
 211
 212    void handle_msg_relax(int /*source*/, int /*tag*/,
 213                          const std::pair<Vertex, typename MessageValue::type>& data,
 214                          trigger_receive_context)
 215    { relax(data.second.second, data.first, data.second.first); }
 216
 217    const Graph& g;
 218    IncomingMap incoming;
 219    DistanceMap distance;
 220    EdgeWeightMap weight;
 221    PathCountMap path_count;
 222#ifdef COMPUTE_PATH_COUNTS_INLINE
 223    IsSettledMap is_settled;
 224    VertexIndexMap vertex_index;
 225#endif
 226    Dist delta;
 227    ProcessGroup pg;
 228    typename property_map<Graph, vertex_owner_t>::const_type owner;
 229    typename property_map<Graph, vertex_local_t>::const_type local;
 230    
 231    // A "property map" that contains the position of each vertex in
 232    // whatever bucket it resides in.
 233    std::vector<BucketIterator> position_in_bucket;
 234    
 235    // Bucket data structure. The ith bucket contains all local vertices
 236    // with (tentative) distance in the range [i*delta,
 237    // (i+1)*delta). 
 238    std::vector<Bucket*> buckets;
 239    
 240    // This "dummy" list is used only so that we can initialize the
 241    // position_in_bucket property map with non-singular iterators. This
 242    // won't matter for most implementations of the C++ Standard
 243    // Library, but it avoids undefined behavior and allows us to run
 244    // with library "debug modes".
 245    std::list<Vertex> dummy_list;
 246    
 247    // A "property map" that states which vertices have been deleted
 248    // from the bucket in this iteration.
 249    std::vector<bool> vertex_was_deleted;
 250  };
 251
 252  template<typename Graph, typename DistanceMap, typename IncomingMap, 
 253           typename EdgeWeightMap, typename PathCountMap
 254#ifdef COMPUTE_PATH_COUNTS_INLINE
 255           , typename IsSettledMap, typename VertexIndexMap
 256#endif
 257           >
 258  betweenness_centrality_delta_stepping_impl<
 259    Graph, DistanceMap, IncomingMap, EdgeWeightMap, PathCountMap
 260#ifdef COMPUTE_PATH_COUNTS_INLINE
 261           , IsSettledMap, VertexIndexMap
 262#endif
 263    >::
 264  betweenness_centrality_delta_stepping_impl(const Graph& g,
 265                                             DistanceMap distance,
 266                                             IncomingMap incoming,
 267                                             EdgeWeightMap weight,
 268                                             PathCountMap path_count,
 269#ifdef COMPUTE_PATH_COUNTS_INLINE
 270                                             IsSettledMap is_settled,
 271                                             VertexIndexMap vertex_index,
 272#endif
 273                                             Dist delta)
 274    : g(g),
 275      incoming(incoming),
 276      distance(distance),
 277      weight(weight),
 278      path_count(path_count),
 279#ifdef COMPUTE_PATH_COUNTS_INLINE
 280      is_settled(is_settled),
 281      vertex_index(vertex_index),
 282#endif
 283      delta(delta),
 284      pg(boost::graph::parallel::process_group_adl(g), attach_distributed_object()),
 285      owner(get(vertex_owner, g)),
 286      local(get(vertex_local, g))
 287
 288  { setup_triggers(); }
 289
 290  template<typename Graph, typename DistanceMap, typename IncomingMap, 
 291           typename EdgeWeightMap, typename PathCountMap
 292#ifdef COMPUTE_PATH_COUNTS_INLINE
 293           , typename IsSettledMap, typename VertexIndexMap
 294#endif
 295           >
 296  void
 297  betweenness_centrality_delta_stepping_impl<
 298    Graph, DistanceMap, IncomingMap, EdgeWeightMap, PathCountMap
 299#ifdef COMPUTE_PATH_COUNTS_INLINE
 300           , IsSettledMap, VertexIndexMap
 301#endif
 302    >::
 303  run(Vertex s)
 304  {
 305    typedef typename boost::graph::parallel::process_group_type<Graph>::type 
 306      process_group_type;
 307    typename process_group_type::process_id_type id = process_id(pg);
 308
 309    Dist inf = (std::numeric_limits<Dist>::max)();
 310    
 311    // None of the vertices are stored in the bucket.
 312    position_in_bucket.clear();
 313    position_in_bucket.resize(num_vertices(g), dummy_list.end());
 314    
 315    // None of the vertices have been deleted
 316    vertex_was_deleted.clear();
 317    vertex_was_deleted.resize(num_vertices(g), false);
 318    
 319    // No path from s to any other vertex, yet
 320    BGL_FORALL_VERTICES_T(v, g, Graph)
 321      put(distance, v, inf);
 322    
 323    // The distance to the starting node is zero
 324    if (get(owner, s) == id) 
 325      // Put "s" into its bucket (bucket 0)
 326      relax(s, s, 0);
 327    else
 328      // Note that we know the distance to s is zero
 329      cache(distance, s, 0);
 330    
 331#ifdef COMPUTE_PATH_COUNTS_INLINE
 332    // Synchronize here to deliver initial relaxation since we don't
 333    // synchronize at the beginning of the inner loop any more
 334    synchronize(); 
 335
 336    // Incoming edge count map is an implementation detail and should
 337    // be freed as soon as possible so build it here
 338    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
 339
 340    std::vector<edges_size_type> incoming_edge_countS(num_vertices(g));
 341    iterator_property_map<typename std::vector<edges_size_type>::iterator, VertexIndexMap> 
 342      incoming_edge_count(incoming_edge_countS.begin(), vertex_index);
 343#endif
 344
 345    BucketIndex max_bucket = (std::numeric_limits<BucketIndex>::max)();
 346    BucketIndex current_bucket = 0;
 347    do {
 348#ifdef COMPUTE_PATH_COUNTS_INLINE
 349      // We need to clear the outgoing map after every bucket so just build it here
 350      std::vector<IncomingType> outgoingS(num_vertices(g));
 351      IncomingMap outgoing(outgoingS.begin(), vertex_index);
 352      
 353      outgoing.set_reduce(append_reducer<IncomingType>());
 354#else
 355      // Synchronize with all of the other processes.
 356      synchronize();
 357#endif    
 358  
 359      // Find the next bucket that has something in it.
 360      while (current_bucket < buckets.size() 
 361             && (!buckets[current_bucket] || buckets[current_bucket]->empty()))
 362        ++current_bucket;
 363      if (current_bucket >= buckets.size())
 364        current_bucket = max_bucket;
 365      
 366      // Find the smallest bucket (over all processes) that has vertices
 367      // that need to be processed.
 368      using boost::parallel::all_reduce;
 369      using boost::parallel::minimum;
 370      current_bucket = all_reduce(pg, current_bucket, minimum<BucketIndex>());
 371      
 372      if (current_bucket == max_bucket)
 373        // There are no non-empty buckets in any process; exit. 
 374        break;
 375      
 376      // Contains the set of vertices that have been deleted in the
 377      // relaxation of "light" edges. Note that we keep track of which
 378      // vertices were deleted with the property map
 379      // "vertex_was_deleted".
 380      std::vector<Vertex> deleted_vertices;
 381      
 382      // Repeatedly relax light edges
 383      bool nonempty_bucket;
 384      do {
 385        // Someone has work to do in this bucket.
 386        
 387        if (current_bucket < buckets.size() && buckets[current_bucket]) {
 388          Bucket& bucket = *buckets[current_bucket];
 389          // For each element in the bucket
 390          while (!bucket.empty()) {
 391            Vertex u = bucket.front();
 392            
 393            // Remove u from the front of the bucket
 394            bucket.pop_front();
 395            
 396            // Insert u into the set of deleted vertices, if it hasn't
 397            // been done already.
 398            if (!vertex_was_deleted[get(local, u)]) {
 399              vertex_was_deleted[get(local, u)] = true;
 400              deleted_vertices.push_back(u);
 401            }
 402            
 403            // Relax each light edge. 
 404            Dist u_dist = get(distance, u);
 405            BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
 406              if (get(weight, e) <= delta) // light edge 
 407                relax(u, target(e, g), u_dist + get(weight, e));
 408          }
 409        }
 410
 411        // Synchronize with all of the other processes.
 412        synchronize();
 413        
 414        // Is the bucket empty now?
 415        nonempty_bucket = (current_bucket < buckets.size() 
 416                           && buckets[current_bucket]
 417                           && !buckets[current_bucket]->empty());
 418      } while (all_reduce(pg, nonempty_bucket, std::logical_or<bool>()));
 419      
 420      // Relax heavy edges for each of the vertices that we previously
 421      // deleted.
 422      for (typename std::vector<Vertex>::iterator iter = deleted_vertices.begin();
 423           iter != deleted_vertices.end(); ++iter) {
 424        // Relax each heavy edge. 
 425        Vertex u = *iter;
 426        Dist u_dist = get(distance, u);
 427        BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
 428          if (get(weight, e) > delta) // heavy edge
 429            relax(u, target(e, g), u_dist + get(weight, e)); 
 430
 431#ifdef COMPUTE_PATH_COUNTS_INLINE
 432        // Set outgoing paths
 433        IncomingType in = get(incoming, u);
 434        for (typename IncomingType::iterator pred = in.begin(); pred != in.end(); ++pred) 
 435          if (get(owner, *pred) == id) {
 436            IncomingType x = get(outgoing, *pred);
 437            if (std::find(x.begin(), x.end(), u) == x.end())
 438              x.push_back(u);
 439            put(outgoing, *pred, x);
 440          } else {
 441            IncomingType in;
 442            in.push_back(u);
 443            put(outgoing, *pred, in);
 444          }
 445
 446        // Set incoming edge counts
 447        put(incoming_edge_count, u, in.size());
 448#endif
 449      }
 450
 451#ifdef COMPUTE_PATH_COUNTS_INLINE
 452      synchronize();  // Deliver heavy edge relaxations and outgoing paths
 453
 454      // Build Queue
 455      typedef typename property_traits<PathCountMap>::value_type PathCountType;
 456      typedef std::pair<Vertex, PathCountType> queue_value_type;
 457      typedef typename property_map<Graph, vertex_owner_t>::const_type OwnerMap;
 458      typedef typename get_owner_of_first_pair_element<OwnerMap> IndirectOwnerMap;
 459
 460      typedef boost::queue<queue_value_type> local_queue_type;
 461      typedef boost::graph::distributed::distributed_queue<process_group_type,
 462                                                           IndirectOwnerMap,
 463                                                           local_queue_type> dist_queue_type;
 464
 465      IndirectOwnerMap indirect_owner(owner);
 466      dist_queue_type Q(pg, indirect_owner);
 467
 468      // Find sources to initialize queue
 469      BGL_FORALL_VERTICES_T(v, g, Graph) {
 470        if (get(is_settled, v) && !(get(outgoing, v).empty())) {
 471          put(incoming_edge_count, v, 1); 
 472          Q.push(std::make_pair(v, 0)); // Push this vertex with no additional path count
 473        }
 474      }
 475
 476      // Set path counts for vertices in this bucket
 477      while (!Q.empty()) {
 478        queue_value_type t = Q.top(); Q.pop();
 479        Vertex v = t.first;
 480        PathCountType p = t.second;
 481
 482        put(path_count, v, get(path_count, v) + p);
 483        put(incoming_edge_count, v, get(incoming_edge_count, v) - 1);
 484
 485        if (get(incoming_edge_count, v) == 0) {
 486          IncomingType out = get(outgoing, v);
 487          for (typename IncomingType::iterator iter = out.begin(); iter != out.end(); ++iter)
 488            Q.push(std::make_pair(*iter, get(path_count, v)));
 489        }
 490      }
 491
 492      // Mark the vertices in this bucket settled 
 493      for (typename std::vector<Vertex>::iterator iter = deleted_vertices.begin();
 494           iter != deleted_vertices.end(); ++iter) 
 495        put(is_settled, *iter, true);
 496
 497      // No need to clear path count map as it is never read/written remotely
 498      // No need to clear outgoing map as it is re-alloced every bucket 
 499#endif
 500      
 501      // Go to the next bucket: the current bucket must already be empty.
 502      ++current_bucket;
 503    } while (true);
 504    
 505    // Delete all of the buckets.
 506    for (typename std::vector<Bucket*>::iterator iter = buckets.begin();
 507         iter != buckets.end(); ++iter) {
 508      if (*iter) {
 509        delete *iter;
 510        *iter = 0;
 511      }
 512    }
 513  }
 514        
 515  template<typename Graph, typename DistanceMap, typename IncomingMap, 
 516           typename EdgeWeightMap, typename PathCountMap
 517#ifdef COMPUTE_PATH_COUNTS_INLINE
 518           , typename IsSettledMap, typename VertexIndexMap
 519#endif
 520           >
 521  void
 522  betweenness_centrality_delta_stepping_impl<
 523    Graph, DistanceMap, IncomingMap, EdgeWeightMap, PathCountMap
 524#ifdef COMPUTE_PATH_COUNTS_INLINE
 525           , IsSettledMap, VertexIndexMap
 526#endif
 527    >::
 528  relax(Vertex u, Vertex v, Dist x)
 529  {
 530
 531    if (x <= get(distance, v)) {
 532      
 533      // We're relaxing the edge to vertex v.
 534      if (get(owner, v) == process_id(pg)) {
 535        if (x < get(distance, v)) {
 536          // Compute the new bucket index for v
 537          BucketIndex new_index = static_cast<BucketIndex>(x / delta);
 538        
 539          // Make sure there is enough room in the buckets data structure.
 540          if (new_index >= buckets.size()) buckets.resize(new_index + 1, 0);
 541        
 542          // Make sure that we have allocated the bucket itself.
 543          if (!buckets[new_index]) buckets[new_index] = new Bucket;
 544          
 545          if (get(distance, v) != (std::numeric_limits<Dist>::max)()
 546              && !vertex_was_deleted[get(local, v)]) {
 547            // We're moving v from an old bucket into a new one. Compute
 548            // the old index, then splice it in.
 549            BucketIndex old_index 
 550              = static_cast<BucketIndex>(get(distance, v) / delta);
 551            buckets[new_index]->splice(buckets[new_index]->end(),
 552                                       *buckets[old_index],
 553                                       position_in_bucket[get(local, v)]);
 554          } else {
 555            // We're inserting v into a bucket for the first time. Put it
 556            // at the end.
 557            buckets[new_index]->push_back(v);
 558          }
 559          
 560          // v is now at the last position in the new bucket
 561          position_in_bucket[get(local, v)] = buckets[new_index]->end();
 562          --position_in_bucket[get(local, v)];
 563          
 564          // Update tentative distance information and incoming, path_count
 565          if (u != v) put(incoming, v, IncomingType(1, u));
 566          put(distance, v, x);
 567        }        // u != v covers initial source relaxation and self-loops
 568        else if (x == get(distance, v) && u != v) {
 569
 570          // Add incoming edge if it's not already in the list
 571          IncomingType in = get(incoming, v);
 572          if (std::find(in.begin(), in.end(), u) == in.end()) {
 573            in.push_back(u);
 574            put(incoming, v, in);
 575          }
 576        }
 577      } else {
 578        // The vertex is remote: send a request to the vertex's owner
 579        send(pg, get(owner, v), msg_relax, 
 580             std::make_pair(v, MessageValue::create(x, u)));
 581
 582        // Cache tentative distance information
 583        cache(distance, v, x);
 584      }
 585    }
 586  }
 587
 588  /************************************************************************/
 589  /* Shortest Paths function object for betweenness centrality            */
 590  /************************************************************************/
 591
 592  template<typename WeightMap>
 593  struct brandes_shortest_paths {
 594    typedef typename property_traits<WeightMap>::value_type weight_type;
 595
 596    brandes_shortest_paths() 
 597      : weight(1), delta(0)  { }
 598    brandes_shortest_paths(weight_type delta) 
 599      : weight(1), delta(delta)  { }
 600    brandes_shortest_paths(WeightMap w) 
 601      : weight(w), delta(0)  { }
 602    brandes_shortest_paths(WeightMap w, weight_type delta) 
 603      : weight(w), delta(delta)  { }
 604
 605    template<typename Graph, typename IncomingMap, typename DistanceMap,
 606             typename PathCountMap
 607#ifdef COMPUTE_PATH_COUNTS_INLINE
 608             , typename IsSettledMap, typename VertexIndexMap
 609#endif
 610
 611             > 
 612    void 
 613    operator()(Graph& g, 
 614               typename graph_traits<Graph>::vertex_descriptor s,
 615               IncomingMap incoming,
 616               DistanceMap distance,
 617               PathCountMap path_count
 618#ifdef COMPUTE_PATH_COUNTS_INLINE
 619               , IsSettledMap is_settled,
 620               VertexIndexMap vertex_index 
 621#endif
 622               )
 623    {  
 624      typedef typename property_traits<DistanceMap>::value_type 
 625        distance_type;
 626
 627      typedef std::plus<distance_type> Combine;
 628      typedef std::less<distance_type> Compare;
 629
 630      // The "distance" map needs to act like one, retrieving the default
 631      // value of infinity.
 632      set_property_map_role(vertex_distance, distance);
 633      
 634      // Only calculate delta the first time operator() is called
 635      // This presumes g is the same every time, but so does the fact
 636      // that we're reusing the weight map
 637      if (delta == 0)
 638        set_delta(g);
 639      
 640      // TODO (NGE): Restructure the code so we don't have to construct
 641      //             impl every time?
 642      betweenness_centrality_delta_stepping_impl<
 643          Graph, DistanceMap, IncomingMap, WeightMap, PathCountMap
 644#ifdef COMPUTE_PATH_COUNTS_INLINE
 645          , IsSettledMap, VertexIndexMap
 646#endif
 647            >
 648        impl(g, distance, incoming, weight, path_count, 
 649#ifdef COMPUTE_PATH_COUNTS_INLINE
 650             is_settled, vertex_index, 
 651#endif
 652             delta);
 653
 654      impl.run(s);
 655    }
 656
 657  private:
 658
 659    template <typename Graph>
 660    void
 661    set_delta(const Graph& g)
 662    {
 663      using boost::parallel::all_reduce;
 664      using boost::parallel::maximum;
 665      using std::max;
 666
 667      typedef typename graph_traits<Graph>::degree_size_type Degree;
 668      typedef weight_type Dist;
 669
 670      // Compute the maximum edge weight and degree
 671      Dist max_edge_weight = 0;
 672      Degree max_degree = 0;
 673      BGL_FORALL_VERTICES_T(u, g, Graph) {
 674        max_degree = max BOOST_PREVENT_MACRO_SUBSTITUTION (max_degree, out_degree(u, g));
 675        BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
 676          max_edge_weight = max BOOST_PREVENT_MACRO_SUBSTITUTION (max_edge_weight, get(weight, e));
 677      }
 678      
 679      max_edge_weight = all_reduce(process_group(g), max_edge_weight, maximum<Dist>());
 680      max_degree = all_reduce(process_group(g), max_degree, maximum<Degree>());
 681      
 682      // Take a guess at delta, based on what works well for random
 683      // graphs.
 684      delta = max_edge_weight / max_degree;
 685      if (delta == 0)
 686        delta = 1;
 687    }
 688
 689    WeightMap     weight;
 690    weight_type   delta;
 691  };
 692
 693  // Perform a single SSSP from the specified vertex and update the centrality map(s)
 694  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
 695           typename IncomingMap, typename DistanceMap, typename DependencyMap, 
 696           typename PathCountMap, 
 697#ifdef COMPUTE_PATH_COUNTS_INLINE
 698           typename IsSettledMap,
 699#endif 
 700           typename VertexIndexMap, typename ShortestPaths> 
 701  void
 702  do_brandes_sssp(const Graph& g, 
 703                  CentralityMap centrality,     
 704                  EdgeCentralityMap edge_centrality_map,
 705                  IncomingMap incoming,
 706                  DistanceMap distance,
 707                  DependencyMap dependency,
 708                  PathCountMap path_count, 
 709#ifdef COMPUTE_PATH_COUNTS_INLINE
 710                  IsSettledMap is_settled,
 711#endif 
 712                  VertexIndexMap vertex_index,
 713                  ShortestPaths shortest_paths,
 714                  typename graph_traits<Graph>::vertex_descriptor s)
 715  {
 716    using boost::detail::graph::update_centrality;      
 717    using boost::graph::parallel::process_group;
 718
 719    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
 720    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
 721    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
 722
 723    typedef typename property_traits<IncomingMap>::value_type incoming_type;
 724    typedef typename property_traits<DistanceMap>::value_type distance_type;
 725    typedef typename property_traits<DependencyMap>::value_type dependency_type;
 726    typedef typename property_traits<PathCountMap>::value_type path_count_type;
 727
 728    typedef typename incoming_type::iterator incoming_iterator;
 729
 730    typedef typename property_map<Graph, vertex_owner_t>::const_type OwnerMap;
 731    OwnerMap owner = get(vertex_owner, g);
 732
 733    typedef typename boost::graph::parallel::process_group_type<Graph>::type 
 734      process_group_type;
 735    process_group_type pg = process_group(g);
 736    typename process_group_type::process_id_type id = process_id(pg);
 737
 738    // TODO: Is it faster not to clear some of these maps?
 739    // Initialize for this iteration
 740    distance.clear();
 741    incoming.clear();
 742    path_count.clear();
 743    dependency.clear();
 744    BGL_FORALL_VERTICES_T(v, g, Graph) {
 745      put(path_count, v, 0);
 746      put(dependency, v, 0);
 747    }
 748
 749    if (get(owner, s) == id) {
 750      put(incoming, s, incoming_type());
 751#ifdef COMPUTE_PATH_COUNTS_INLINE
 752      put(path_count, s, 1);
 753      put(is_settled, s, true);
 754#endif
 755    }
 756
 757    // Execute the shortest paths algorithm. This will be either
 758    // a weighted or unweighted customized breadth-first search,
 759    shortest_paths(g, s, incoming, distance, path_count
 760#ifdef COMPUTE_PATH_COUNTS_INLINE
 761                   , is_settled, vertex_index
 762#endif 
 763                   );
 764
 765#ifndef COMPUTE_PATH_COUNTS_INLINE
 766
 767    //
 768    // TODO: Optimize case where source has no out-edges
 769    //
 770 
 771    // Count of incoming edges to tell when all incoming edges have been relaxed in 
 772    // the induced shortest paths DAG 
 773    std::vector<edges_size_type> incoming_edge_countS(num_vertices(g));
 774    iterator_property_map<typename std::vector<edges_size_type>::iterator, VertexIndexMap> 
 775      incoming_edge_count(incoming_edge_countS.begin(), vertex_index);
 776
 777    BGL_FORALL_VERTICES_T(v, g, Graph) {
 778      put(incoming_edge_count, v, get(incoming, v).size());
 779    }
 780
 781    if (get(owner, s) == id) {
 782      put(incoming_edge_count, s, 1);
 783      put(incoming, s, incoming_type());
 784    }
 785
 786    std::vector<incoming_type> outgoingS(num_vertices(g));
 787    iterator_property_map<typename std::vector<incoming_type>::iterator, VertexIndexMap> 
 788      outgoing(outgoingS.begin(), vertex_index);
 789
 790    outgoing.set_reduce(append_reducer<incoming_type>());
 791
 792    // Mark forward adjacencies in DAG of shortest paths
 793
 794    // TODO: It's possible to do this using edge flags but it's not currently done this way
 795    //       because during traversal of the DAG we would have to examine all out edges
 796    //       which would lead to more memory accesses and a larger cache footprint.
 797    //
 798    //       In the bidirectional graph case edge flags would be an excellent way of marking
 799    //       edges in the DAG of shortest paths  
 800    BGL_FORALL_VERTICES_T(v, g, Graph) {
 801      incoming_type i = get(incoming, v);
 802      for (typename incoming_type::iterator iter = i.begin(); iter != i.end(); ++iter) {
 803        if (get(owner, *iter) == id) {
 804          incoming_type x = get(outgoing, *iter);
 805          if (std::find(x.begin(), x.end(), v) == x.end())
 806            x.push_back(v);
 807          put(outgoing, *iter, x);
 808        } else {
 809          incoming_type in;
 810          in.push_back(v);
 811          put(outgoing, *iter, in);
 812        }
 813      }
 814    }
 815
 816    synchronize(pg);
 817
 818    // Traverse DAG induced by forward edges in dependency order and compute path counts
 819    {
 820      typedef std::pair<vertex_descriptor, path_count_type> queue_value_type;
 821      typedef get_owner_of_first_pair_element<OwnerMap> IndirectOwnerMap;
 822
 823      typedef boost::queue<queue_value_type> local_queue_type;
 824      typedef boost::graph::distributed::distributed_queue<process_group_type,
 825                                                           IndirectOwnerMap,
 826                                                           local_queue_type> dist_queue_type;
 827
 828      IndirectOwnerMap indirect_owner(owner);
 829      dist_queue_type Q(pg, indirect_owner);
 830
 831      if (get(owner, s) == id)
 832        Q.push(std::make_pair(s, 1));
 833
 834      while (!Q.empty()) {
 835        queue_value_type t = Q.top(); Q.pop();
 836        vertex_descriptor v = t.first;
 837        path_count_type p = t.second;
 838
 839        put(path_count, v, get(path_count, v) + p);
 840        put(incoming_edge_count, v, get(incoming_edge_count, v) - 1);
 841
 842        if (get(incoming_edge_count, v) == 0) {
 843          incoming_type out = get(outgoing, v);
 844          for (typename incoming_type::iterator iter = out.begin(); iter != out.end(); ++iter)
 845            Q.push(std::make_pair(*iter, get(path_count, v)));
 846        }
 847      }
 848    }
 849
 850#endif // COMPUTE_PATH_COUNTS_INLINE
 851
 852    //
 853    // Compute dependencies 
 854    //    
 855
 856
 857    // Build the distributed_queue
 858    // Value type consists of 1) target of update 2) source of update
 859    // 3) dependency of source 4) path count of source
 860    typedef boost::tuple<vertex_descriptor, vertex_descriptor, dependency_type, path_count_type>
 861      queue_value_type;
 862    typedef get_owner_of_first_tuple_element<OwnerMap, queue_value_type> IndirectOwnerMap;
 863
 864    typedef boost::queue<queue_value_type> local_queue_type;
 865    typedef boost::graph::distributed::distributed_queue<process_group_type,
 866                                                         IndirectOwnerMap,
 867                                                         local_queue_type> dist_queue_type;
 868
 869    IndirectOwnerMap indirect_owner(owner);
 870    dist_queue_type Q(pg, indirect_owner);
 871
 872    // Calculate number of vertices each vertex depends on, when a vertex has been pushed
 873    // that number of times then we will update it
 874    // AND Request path counts of sources of incoming edges
 875    std::vector<dependency_type> dependency_countS(num_vertices(g), 0);
 876    iterator_property_map<typename std::vector<dependency_type>::iterator, VertexIndexMap> 
 877      dependency_count(dependency_countS.begin(), vertex_index);
 878
 879    dependency_count.set_reduce(boost::graph::distributed::additive_reducer<dependency_type>());
 880
 881    path_count.set_max_ghost_cells(0);
 882
 883    BGL_FORALL_VERTICES_T(v, g, Graph) {
 884      if (get(distance, v) < (std::numeric_limits<distance_type>::max)()) {
 885        incoming_type el = get(incoming, v);
 886        for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw) {
 887          if (get(owner, *vw) == id)
 888            put(dependency_count, *vw, get(dependency_count, *vw) + 1);
 889          else {
 890            put(dependency_count, *vw, 1);
 891
 892            // Request path counts
 893            get(path_count, *vw); 
 894          }
 895
 896          // request() doesn't work here, perhaps because we don't have a copy of this 
 897          // ghost cell already?
 898        }
 899      }
 900    }
 901
 902    synchronize(pg);
 903
 904    // Push vertices with non-zero distance/path count and zero dependency count
 905    BGL_FORALL_VERTICES_T(v, g, Graph) {
 906      if (get(distance, v) < (std::numeric_limits<distance_type>::max)()
 907          && get(dependency_count, v) == 0) 
 908        Q.push(boost::make_tuple(v, v, get(dependency, v), get(path_count, v)));
 909    }
 910
 911    dependency.set_max_ghost_cells(0);
 912    while(!Q.empty()) {
 913
 914      queue_value_type x = Q.top(); Q.pop();
 915      vertex_descriptor w = boost::tuples::get<0>(x);
 916      vertex_descriptor source = boost::tuples::get<1>(x);
 917      dependency_type dep = boost::tuples::get<2>(x);
 918      path_count_type pc = boost::tuples::get<3>(x);
 919
 920      cache(dependency, source, dep);
 921      cache(path_count, source, pc);
 922
 923      if (get(dependency_count, w) != 0)
 924        put(dependency_count, w, get(dependency_count, w) - 1);
 925
 926      if (get(dependency_count, w) == 0) { 
 927
 928        // Update dependency and centrality of sources of incoming edges
 929        incoming_type el = get(incoming, w);
 930        for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw) {
 931          vertex_descriptor v = *vw;
 932
 933          BOOST_ASSERT(get(path_count, w) != 0);
 934
 935          dependency_type factor = dependency_type(get(path_count, v))
 936            / dependency_type(get(path_count, w));
 937          factor *= (dependency_type(1) + get(dependency, w));
 938          
 939          if (get(owner, v) == id)
 940            put(dependency, v, get(dependency, v) + factor);
 941          else
 942            put(dependency, v, factor);
 943          
 944          update_centrality(edge_centrality_map, v, factor);
 945        }
 946        
 947        if (w != s)
 948          update_centrality(centrality, w, get(dependency, w));
 949
 950        // Push sources of edges in incoming edge list
 951        for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw)
 952          Q.push(boost::make_tuple(*vw, w, get(dependency, w), get(path_count, w)));
 953      }
 954    }
 955  }
 956
 957  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
 958           typename IncomingMap, typename DistanceMap, typename DependencyMap, 
 959           typename PathCountMap, typename VertexIndexMap, typename ShortestPaths, 
 960           typename Buffer>
 961  void 
 962  brandes_betweenness_centrality_impl(const Graph& g, 
 963                                      CentralityMap centrality,     
 964                                      EdgeCentralityMap edge_centrality_map,
 965                                      IncomingMap incoming,
 966                                      DistanceMap distance,
 967                                      DependencyMap dependency,
 968                                      PathCountMap path_count, 
 969                                      VertexIndexMap vertex_index,
 970                                      ShortestPaths shortest_paths,
 971                                      Buffer sources)
 972  {
 973    using boost::detail::graph::init_centrality_map;
 974    using boost::detail::graph::divide_centrality_by_two;       
 975    using boost::graph::parallel::process_group;
 976    
 977    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
 978    typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
 979    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
 980    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
 981
 982    typedef typename property_traits<DistanceMap>::value_type distance_type;
 983    typedef typename property_traits<DependencyMap>::value_type dependency_type;
 984
 985    // Initialize centrality
 986    init_centrality_map(vertices(g), centrality);
 987    init_centrality_map(edges(g), edge_centrality_map);
 988
 989    // Set the reduction operation on the dependency map to be addition
 990    dependency.set_reduce(boost::graph::distributed::additive_reducer<dependency_type>()); 
 991    distance.set_reduce(boost::graph::distributed::choose_min_reducer<distance_type>());
 992
 993    // Don't allow remote procs to write incoming or path_count maps
 994    // updating them is handled inside the betweenness_centrality_queue
 995    incoming.set_consistency_model(0);
 996    path_count.set_consistency_model(0);
 997
 998    typedef typename boost::graph::parallel::process_group_type<Graph>::type 
 999      process_group_type;
1000    process_group_type pg = process_group(g);
1001
1002#ifdef COMPUTE_PATH_COUNTS_INLINE
1003    // Build is_settled maps
1004    std::vector<bool> is_settledS(num_vertices(g));
1005    typedef iterator_property_map<std::vector<bool>::iterator, VertexIndexMap> 
1006      IsSettledMap;
1007
1008    IsSettledMap is_settled(is_settledS.begin(), vertex_index);
1009#endif
1010
1011    if (!sources.empty()) {
1012      // DO SSSPs
1013      while (!sources.empty()) {
1014        do_brandes_sssp(g, centrality, edge_centrality_map, incoming, distance,
1015                        dependency, path_count, 
1016#ifdef COMPUTE_PATH_COUNTS_INLINE
1017                        is_settled,
1018#endif 
1019                        vertex_index, shortest_paths, sources.top());
1020        sources.pop();
1021      }
1022    } else { // Exact Betweenness Centrality
1023      typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
1024      vertices_size_type n = num_vertices(g);
1025      n = boost::parallel::all_reduce(pg, n, std::plus<vertices_size_type>());
1026      
1027      for (vertices_size_type i = 0; i < n; ++i) {
1028        vertex_descriptor v = vertex(i, g);
1029
1030        do_brandes_sssp(g, centrality, edge_centrality_map, incoming, distance,
1031                        dependency, path_count, 
1032#ifdef COMPUTE_PATH_COUNTS_INLINE
1033                        is_settled,
1034#endif 
1035                        vertex_index, shortest_paths, v);
1036      }
1037    }
1038
1039    typedef typename graph_traits<Graph>::directed_category directed_category;
1040    const bool is_undirected = 
1041      is_convertible<directed_category*, undirected_tag*>::value;
1042    if (is_undirected) {
1043      divide_centrality_by_two(vertices(g), centrality);
1044      divide_centrality_by_two(edges(g), edge_centrality_map);
1045    }
1046  }
1047
1048  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
1049           typename IncomingMap, typename DistanceMap, typename DependencyMap, 
1050           typename PathCountMap, typename VertexIndexMap, typename ShortestPaths,
1051           typename Stack>
1052  void
1053  do_sequential_brandes_sssp(const Graph& g, 
1054                             CentralityMap centrality,     
1055                             EdgeCentralityMap edge_centrality_map,
1056                             IncomingMap incoming,
1057                             DistanceMap distance,
1058                             DependencyMap dependency,
1059                             PathCountMap path_count, 
1060                             VertexIndexMap vertex_index,
1061                             ShortestPaths shortest_paths,
1062                             Stack& ordered_vertices,
1063                             typename graph_traits<Graph>::vertex_descriptor v)
1064  {
1065    using boost::detail::graph::update_centrality;
1066
1067    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
1068    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
1069
1070    typedef typename property_traits<IncomingMap>::value_type incoming_type;
1071
1072    // Initialize for this iteration
1073    BGL_FORALL_VERTICES_T(w, g, Graph) {
1074      // put(path_count, w, 0);
1075      incoming[w].clear();
1076      put(dependency, w, 0);
1077    }
1078
1079    put(path_count, v, 1);
1080    incoming[v].clear();
1081
1082    // Execute the shortest paths algorithm. This will be either
1083    // Dijkstra's algorithm or a customized breadth-first search,
1084    // depending on whether the graph is weighted or unweighted.
1085    shortest_paths(g, v, ordered_vertices, incoming, distance,
1086                   path_count, vertex_index);
1087    
1088    while (!ordered_vertices.empty()) {
1089      vertex_descriptor w = ordered_vertices.top();
1090      ordered_vertices.pop();
1091      
1092      typedef typename property_traits<IncomingMap>::value_type
1093            incoming_type;
1094      typedef typename incoming_type::iterator incoming_iterator;
1095      typedef typename property_traits<DependencyMap>::value_type 
1096        dependency_type;
1097      
1098      for (incoming_iterator vw = incoming[w].begin();
1099           vw != incoming[w].end(); ++vw) {
1100        vertex_descriptor v = source(*vw, g);
1101        dependency_type factor = dependency_type(get(path_count, v))
1102          / dependency_type(get(path_count, w));
1103        factor *= (dependency_type(1) + get(dependency, w));
1104        put(dependency, v, get(dependency, v) + factor);
1105        update_centrality(edge_centrality_map, *vw, factor);
1106      }
1107      
1108      if (w != v) {
1109        update_centrality(centrality, w, get(dependency, w));
1110      }
1111    }
1112  }
1113
1114  // Betweenness Centrality variant that duplicates graph across processors
1115  // and parallizes SSSPs
1116  // This function expects a non-distributed graph and property-maps
1117  template<typename ProcessGroup, typename Graph, 
1118           typename CentralityMap, typename EdgeCentralityMap,
1119           typename IncomingMap, typename DistanceMap, 
1120           typename DependencyMap, typename PathCountMap,
1121           typename VertexIndexMap, typename ShortestPaths,
1122           typename Buffer>
1123  void
1124  non_distributed_brandes_betweenness_centrality_impl(const ProcessGroup& pg,
1125                                                      const Graph& g,
1126                                                      CentralityMap centrality,
1127                                                      EdgeCentralityMap edge_centrality_map,
1128                                                      IncomingMap incoming, // P
1129                                                      DistanceMap distance,         // d
1130                                                      DependencyMap dependency,     // delta
1131                                                      PathCountMap path_count,      // sigma
1132                                                      VertexIndexMap vertex_index,
1133                                                      ShortestPaths shortest_paths,
1134                                                      Buffer sources)
1135  {
1136    using boost::detail::graph::init_centrality_map;
1137    using boost::detail::graph::divide_centrality_by_two;       
1138    using boost::graph::parallel::process_group;
1139
1140    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
1141    typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
1142    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
1143    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
1144
1145    typedef typename property_traits<DistanceMap>::value_type distance_type;
1146
1147    typedef ProcessGroup process_group_type;
1148
1149    typename process_group_type::process_id_type id = process_id(pg);
1150    typename process_group_type::process_size_type p = num_processes(pg);
1151
1152    // Initialize centrality
1153    init_centrality_map(vertices(g), centrality);
1154    init_centrality_map(edges(g), edge_centrality_map);
1155
1156    std::stack<vertex_descriptor> ordered_vertices;
1157
1158    if (!sources.empty()) {
1159      std::vector<vertex_descriptor> local_sources;
1160
1161      for (int i = 0; i < id; ++i) if (!sources.empty()) sources.pop();
1162      while (!sources.empty()) {
1163        local_sources.push_back(sources.top());
1164
1165        for (int i = 0; i < p; ++i) if (!sources.empty()) sources.pop();
1166      }
1167
1168      // DO SSSPs
1169      for(size_t i = 0; i < local_sources.size(); ++i)
1170        do_sequential_brandes_sssp(g, centrality, edge_centrality_map, incoming,
1171                                   distance, dependency, path_count, vertex_index,
1172                                   shortest_paths, ordered_vertices, local_sources[i]);
1173
1174    } else { // Exact Betweenness Centrality
1175      typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
1176      vertices_size_type n = num_vertices(g);
1177      
1178      for (vertices_size_type i = id; i < n; i += p) {
1179        vertex_descriptor v = vertex(i, g);
1180
1181        do_sequential_brandes_sssp(g, centrality, edge_centrality_map, incoming,
1182                                   distance, dependency, path_count, vertex_index,
1183                                   shortest_paths, ordered_vertices, v);
1184      }
1185    }
1186
1187    typedef typename graph_traits<Graph>::directed_category directed_category;
1188    const bool is_undirected = 
1189      is_convertible<directed_category*, undirected_tag*>::value;
1190    if (is_undirected) {
1191      divide_centrality_by_two(vertices(g), centrality);
1192      divide_centrality_by_two(edges(g), edge_centrality_map);
1193    }
1194
1195    // Merge the centrality maps by summing the values at each vertex)
1196    // TODO(nge): this copy-out, reduce, copy-in is lame
1197    typedef typename property_traits<CentralityMap>::value_type centrality_type;
1198    typedef typename property_traits<EdgeCentralityMap>::value_type edge_centrality_type;
1199
1200    std::vector<centrality_type> centrality_v(num_vertices(g));
1201    std::vector<edge_centrality_type> edge_centrality_v;
1202    edge_centrality_v.reserve(num_edges(g));
1203
1204    BGL_FORALL_VERTICES_T(v, g, Graph) {
1205      centrality_v[get(vertex_index, v)] = get(centrality, v);
1206    }
1207    
1208    // Skip when EdgeCentralityMap is a dummy_property_map
1209    if (!is_same<EdgeCentralityMap, dummy_property_map>::value) {
1210      BGL_FORALL_EDGES_T(e, g, Graph) {
1211        edge_centrality_v.push_back(get(edge_centrality_map, e));
1212      }
1213      // NGE: If we trust that the order of elements in the vector isn't changed in the
1214      //      all_reduce below then this method avoids the need for an edge index map
1215    }
1216
1217    using boost::parallel::all_reduce;
1218
1219    all_reduce(pg, &centrality_v[0], &centrality_v[centrality_v.size()],
1220               &centrality_v[0], std::plus<centrality_type>());
1221
1222    if (edge_centrality_v.size()) 
1223      all_reduce(pg, &edge_centrality_v[0], &edge_centrality_v[edge_centrality_v.size()],
1224                 &edge_centrality_v[0], std::plus<edge_centrality_type>());
1225
1226    BGL_FORALL_VERTICES_T(v, g, Graph) {
1227      put(centrality, v, centrality_v[get(vertex_index, v)]);
1228    }
1229
1230    // Skip when EdgeCentralityMap is a dummy_property_map
1231    if (!is_same<EdgeCentralityMap, dummy_property_map>::value) {
1232      int i = 0;
1233      BGL_FORALL_EDGES_T(e, g, Graph) {
1234        put(edge_centrality_map, e, edge_centrality_v[i]);
1235        ++i;
1236      }
1237    }
1238  }
1239
1240} } } // end namespace graph::parallel::detail
1241
1242template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
1243         typename IncomingMap, typename DistanceMap, typename DependencyMap, 
1244         typename PathCountMap, typename VertexIndexMap, typename Buffer>
1245void 
1246brandes_betweenness_centrality(const Graph& g, 
1247                               CentralityMap centrality,
1248                               EdgeCentralityMap edge_centrality_map,
1249                               IncomingMap incoming, 
1250                               DistanceMap distance, 
1251                               DependencyMap dependency,     
1252                               PathCountMap path_count,   
1253                               VertexIndexMap vertex_index,
1254                               Buffer sources,
1255                               typename property_traits<DistanceMap>::value_type delta
1256                               BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
1257{
1258  typedef typename property_traits<DistanceMap>::value_type distance_type;
1259  typedef static_property_map<distance_type> WeightMap;
1260
1261  graph::parallel::detail::brandes_shortest_paths<WeightMap> 
1262    shortest_paths(delta);
1263
1264  graph::parallel::detail::brandes_betweenness_centrality_impl(g, centrality, 
1265                                                               edge_centrality_map,
1266                                                               incoming, distance,
1267                                                               dependency, path_count,
1268                                                               vertex_index, 
1269                                                               shortest_paths,
1270                                                               sources);
1271}
1272
1273template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, 
1274         typename IncomingMap, typename DistanceMap, typename DependencyMap, 
1275         typename PathCountMap, typename VertexIndexMap, typename WeightMap, 
1276         typename Buffer>    
1277void 
1278brandes_betweenness_centrality(const Graph& g, 
1279                               CentralityMap centrality,
1280                               EdgeCentralityMap edge_centrality_map,
1281                               IncomingMap incoming, 
1282                               DistanceMap distance, 
1283                               DependencyMap dependency,
1284                               PathCountMap path_count, 
1285                               VertexIndexMap vertex_index,
1286                               Buffer sources,
1287                               typename p

Large files files are truncated, but you can click here to view the full file