PageRenderTime 61ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

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