betweenness_centrality.hpp 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701
  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::parallel::synchronize;
  156. synchronize(pg);
  157. }
  158. // Setup triggers for msg_relax messages
  159. void setup_triggers()
  160. {
  161. using boost::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. boost::parallel::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), boost::parallel::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. // The "distance" map needs to act like one, retrieving the default
  519. // value of infinity.
  520. set_property_map_role(vertex_distance, distance);
  521. // Only calculate delta the first time operator() is called
  522. // This presumes g is the same every time, but so does the fact
  523. // that we're reusing the weight map
  524. if (delta == 0)
  525. set_delta(g);
  526. // TODO (NGE): Restructure the code so we don't have to construct
  527. // impl every time?
  528. betweenness_centrality_delta_stepping_impl<
  529. Graph, DistanceMap, IncomingMap, WeightMap, PathCountMap
  530. #ifdef COMPUTE_PATH_COUNTS_INLINE
  531. , IsSettledMap, VertexIndexMap
  532. #endif
  533. >
  534. impl(g, distance, incoming, weight, path_count,
  535. #ifdef COMPUTE_PATH_COUNTS_INLINE
  536. is_settled, vertex_index,
  537. #endif
  538. delta);
  539. impl.run(s);
  540. }
  541. private:
  542. template <typename Graph>
  543. void
  544. set_delta(const Graph& g)
  545. {
  546. using boost::parallel::all_reduce;
  547. using boost::parallel::maximum;
  548. using std::max;
  549. typedef typename graph_traits<Graph>::degree_size_type Degree;
  550. typedef weight_type Dist;
  551. // Compute the maximum edge weight and degree
  552. Dist max_edge_weight = 0;
  553. Degree max_degree = 0;
  554. BGL_FORALL_VERTICES_T(u, g, Graph) {
  555. max_degree = max BOOST_PREVENT_MACRO_SUBSTITUTION (max_degree, out_degree(u, g));
  556. BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
  557. max_edge_weight = max BOOST_PREVENT_MACRO_SUBSTITUTION (max_edge_weight, get(weight, e));
  558. }
  559. max_edge_weight = all_reduce(process_group(g), max_edge_weight, maximum<Dist>());
  560. max_degree = all_reduce(process_group(g), max_degree, maximum<Degree>());
  561. // Take a guess at delta, based on what works well for random
  562. // graphs.
  563. delta = max_edge_weight / max_degree;
  564. if (delta == 0)
  565. delta = 1;
  566. }
  567. WeightMap weight;
  568. weight_type delta;
  569. };
  570. // Perform a single SSSP from the specified vertex and update the centrality map(s)
  571. template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
  572. typename IncomingMap, typename DistanceMap, typename DependencyMap,
  573. typename PathCountMap,
  574. #ifdef COMPUTE_PATH_COUNTS_INLINE
  575. typename IsSettledMap,
  576. #endif
  577. typename VertexIndexMap, typename ShortestPaths>
  578. void
  579. do_brandes_sssp(const Graph& g,
  580. CentralityMap centrality,
  581. EdgeCentralityMap edge_centrality_map,
  582. IncomingMap incoming,
  583. DistanceMap distance,
  584. DependencyMap dependency,
  585. PathCountMap path_count,
  586. #ifdef COMPUTE_PATH_COUNTS_INLINE
  587. IsSettledMap is_settled,
  588. #endif
  589. VertexIndexMap vertex_index,
  590. ShortestPaths shortest_paths,
  591. typename graph_traits<Graph>::vertex_descriptor s)
  592. {
  593. using boost::detail::graph::update_centrality;
  594. using boost::graph::parallel::process_group;
  595. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  596. typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
  597. typedef typename property_traits<IncomingMap>::value_type incoming_type;
  598. typedef typename property_traits<DistanceMap>::value_type distance_type;
  599. typedef typename property_traits<DependencyMap>::value_type dependency_type;
  600. typedef typename property_traits<PathCountMap>::value_type path_count_type;
  601. typedef typename incoming_type::iterator incoming_iterator;
  602. typedef typename property_map<Graph, vertex_owner_t>::const_type OwnerMap;
  603. OwnerMap owner = get(vertex_owner, g);
  604. typedef typename boost::graph::parallel::process_group_type<Graph>::type
  605. process_group_type;
  606. process_group_type pg = process_group(g);
  607. typename process_group_type::process_id_type id = process_id(pg);
  608. // TODO: Is it faster not to clear some of these maps?
  609. // Initialize for this iteration
  610. distance.clear();
  611. incoming.clear();
  612. path_count.clear();
  613. dependency.clear();
  614. BGL_FORALL_VERTICES_T(v, g, Graph) {
  615. put(path_count, v, 0);
  616. put(dependency, v, 0);
  617. }
  618. if (get(owner, s) == id) {
  619. put(incoming, s, incoming_type());
  620. #ifdef COMPUTE_PATH_COUNTS_INLINE
  621. put(path_count, s, 1);
  622. put(is_settled, s, true);
  623. #endif
  624. }
  625. // Execute the shortest paths algorithm. This will be either
  626. // a weighted or unweighted customized breadth-first search,
  627. shortest_paths(g, s, incoming, distance, path_count
  628. #ifdef COMPUTE_PATH_COUNTS_INLINE
  629. , is_settled, vertex_index
  630. #endif
  631. );
  632. #ifndef COMPUTE_PATH_COUNTS_INLINE
  633. //
  634. // TODO: Optimize case where source has no out-edges
  635. //
  636. // Count of incoming edges to tell when all incoming edges have been relaxed in
  637. // the induced shortest paths DAG
  638. std::vector<edges_size_type> incoming_edge_countS(num_vertices(g));
  639. iterator_property_map<typename std::vector<edges_size_type>::iterator, VertexIndexMap>
  640. incoming_edge_count(incoming_edge_countS.begin(), vertex_index);
  641. BGL_FORALL_VERTICES_T(v, g, Graph) {
  642. put(incoming_edge_count, v, get(incoming, v).size());
  643. }
  644. if (get(owner, s) == id) {
  645. put(incoming_edge_count, s, 1);
  646. put(incoming, s, incoming_type());
  647. }
  648. std::vector<incoming_type> outgoingS(num_vertices(g));
  649. iterator_property_map<typename std::vector<incoming_type>::iterator, VertexIndexMap>
  650. outgoing(outgoingS.begin(), vertex_index);
  651. outgoing.set_reduce(append_reducer<incoming_type>());
  652. // Mark forward adjacencies in DAG of shortest paths
  653. // TODO: It's possible to do this using edge flags but it's not currently done this way
  654. // because during traversal of the DAG we would have to examine all out edges
  655. // which would lead to more memory accesses and a larger cache footprint.
  656. //
  657. // In the bidirectional graph case edge flags would be an excellent way of marking
  658. // edges in the DAG of shortest paths
  659. BGL_FORALL_VERTICES_T(v, g, Graph) {
  660. incoming_type i = get(incoming, v);
  661. for (typename incoming_type::iterator iter = i.begin(); iter != i.end(); ++iter) {
  662. if (get(owner, *iter) == id) {
  663. incoming_type x = get(outgoing, *iter);
  664. if (std::find(x.begin(), x.end(), v) == x.end())
  665. x.push_back(v);
  666. put(outgoing, *iter, x);
  667. } else {
  668. incoming_type in;
  669. in.push_back(v);
  670. put(outgoing, *iter, in);
  671. }
  672. }
  673. }
  674. synchronize(pg);
  675. // Traverse DAG induced by forward edges in dependency order and compute path counts
  676. {
  677. typedef std::pair<vertex_descriptor, path_count_type> queue_value_type;
  678. typedef get_owner_of_first_pair_element<OwnerMap> IndirectOwnerMap;
  679. typedef boost::queue<queue_value_type> local_queue_type;
  680. typedef boost::graph::distributed::distributed_queue<process_group_type,
  681. IndirectOwnerMap,
  682. local_queue_type> dist_queue_type;
  683. IndirectOwnerMap indirect_owner(owner);
  684. dist_queue_type Q(pg, indirect_owner);
  685. if (get(owner, s) == id)
  686. Q.push(std::make_pair(s, 1));
  687. while (!Q.empty()) {
  688. queue_value_type t = Q.top(); Q.pop();
  689. vertex_descriptor v = t.first;
  690. path_count_type p = t.second;
  691. put(path_count, v, get(path_count, v) + p);
  692. put(incoming_edge_count, v, get(incoming_edge_count, v) - 1);
  693. if (get(incoming_edge_count, v) == 0) {
  694. incoming_type out = get(outgoing, v);
  695. for (typename incoming_type::iterator iter = out.begin(); iter != out.end(); ++iter)
  696. Q.push(std::make_pair(*iter, get(path_count, v)));
  697. }
  698. }
  699. }
  700. #endif // COMPUTE_PATH_COUNTS_INLINE
  701. //
  702. // Compute dependencies
  703. //
  704. // Build the distributed_queue
  705. // Value type consists of 1) target of update 2) source of update
  706. // 3) dependency of source 4) path count of source
  707. typedef boost::tuple<vertex_descriptor, vertex_descriptor, dependency_type, path_count_type>
  708. queue_value_type;
  709. typedef get_owner_of_first_tuple_element<OwnerMap, queue_value_type> IndirectOwnerMap;
  710. typedef boost::queue<queue_value_type> local_queue_type;
  711. typedef boost::graph::distributed::distributed_queue<process_group_type,
  712. IndirectOwnerMap,
  713. local_queue_type> dist_queue_type;
  714. IndirectOwnerMap indirect_owner(owner);
  715. dist_queue_type Q(pg, indirect_owner);
  716. // Calculate number of vertices each vertex depends on, when a vertex has been pushed
  717. // that number of times then we will update it
  718. // AND Request path counts of sources of incoming edges
  719. std::vector<dependency_type> dependency_countS(num_vertices(g), 0);
  720. iterator_property_map<typename std::vector<dependency_type>::iterator, VertexIndexMap>
  721. dependency_count(dependency_countS.begin(), vertex_index);
  722. dependency_count.set_reduce(boost::graph::distributed::additive_reducer<dependency_type>());
  723. path_count.set_max_ghost_cells(0);
  724. BGL_FORALL_VERTICES_T(v, g, Graph) {
  725. if (get(distance, v) < (std::numeric_limits<distance_type>::max)()) {
  726. incoming_type el = get(incoming, v);
  727. for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw) {
  728. if (get(owner, *vw) == id)
  729. put(dependency_count, *vw, get(dependency_count, *vw) + 1);
  730. else {
  731. put(dependency_count, *vw, 1);
  732. // Request path counts
  733. get(path_count, *vw);
  734. }
  735. // request() doesn't work here, perhaps because we don't have a copy of this
  736. // ghost cell already?
  737. }
  738. }
  739. }
  740. synchronize(pg);
  741. // Push vertices with non-zero distance/path count and zero dependency count
  742. BGL_FORALL_VERTICES_T(v, g, Graph) {
  743. if (get(distance, v) < (std::numeric_limits<distance_type>::max)()
  744. && get(dependency_count, v) == 0)
  745. Q.push(boost::make_tuple(v, v, get(dependency, v), get(path_count, v)));
  746. }
  747. dependency.set_max_ghost_cells(0);
  748. while(!Q.empty()) {
  749. queue_value_type x = Q.top(); Q.pop();
  750. vertex_descriptor w = boost::tuples::get<0>(x);
  751. vertex_descriptor source = boost::tuples::get<1>(x);
  752. dependency_type dep = boost::tuples::get<2>(x);
  753. path_count_type pc = boost::tuples::get<3>(x);
  754. cache(dependency, source, dep);
  755. cache(path_count, source, pc);
  756. if (get(dependency_count, w) != 0)
  757. put(dependency_count, w, get(dependency_count, w) - 1);
  758. if (get(dependency_count, w) == 0) {
  759. // Update dependency and centrality of sources of incoming edges
  760. incoming_type el = get(incoming, w);
  761. for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw) {
  762. vertex_descriptor v = *vw;
  763. BOOST_ASSERT(get(path_count, w) != 0);
  764. dependency_type factor = dependency_type(get(path_count, v))
  765. / dependency_type(get(path_count, w));
  766. factor *= (dependency_type(1) + get(dependency, w));
  767. if (get(owner, v) == id)
  768. put(dependency, v, get(dependency, v) + factor);
  769. else
  770. put(dependency, v, factor);
  771. update_centrality(edge_centrality_map, v, factor);
  772. }
  773. if (w != s)
  774. update_centrality(centrality, w, get(dependency, w));
  775. // Push sources of edges in incoming edge list
  776. for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw)
  777. Q.push(boost::make_tuple(*vw, w, get(dependency, w), get(path_count, w)));
  778. }
  779. }
  780. }
  781. template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
  782. typename IncomingMap, typename DistanceMap, typename DependencyMap,
  783. typename PathCountMap, typename VertexIndexMap, typename ShortestPaths,
  784. typename Buffer>
  785. void
  786. brandes_betweenness_centrality_impl(const Graph& g,
  787. CentralityMap centrality,
  788. EdgeCentralityMap edge_centrality_map,
  789. IncomingMap incoming,
  790. DistanceMap distance,
  791. DependencyMap dependency,
  792. PathCountMap path_count,
  793. VertexIndexMap vertex_index,
  794. ShortestPaths shortest_paths,
  795. Buffer sources)
  796. {
  797. using boost::detail::graph::init_centrality_map;
  798. using boost::detail::graph::divide_centrality_by_two;
  799. using boost::graph::parallel::process_group;
  800. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  801. typedef typename property_traits<DistanceMap>::value_type distance_type;
  802. typedef typename property_traits<DependencyMap>::value_type dependency_type;
  803. // Initialize centrality
  804. init_centrality_map(vertices(g), centrality);
  805. init_centrality_map(edges(g), edge_centrality_map);
  806. // Set the reduction operation on the dependency map to be addition
  807. dependency.set_reduce(boost::graph::distributed::additive_reducer<dependency_type>());
  808. distance.set_reduce(boost::graph::distributed::choose_min_reducer<distance_type>());
  809. // Don't allow remote procs to write incoming or path_count maps
  810. // updating them is handled inside the betweenness_centrality_queue
  811. incoming.set_consistency_model(0);
  812. path_count.set_consistency_model(0);
  813. typedef typename boost::graph::parallel::process_group_type<Graph>::type
  814. process_group_type;
  815. process_group_type pg = process_group(g);
  816. #ifdef COMPUTE_PATH_COUNTS_INLINE
  817. // Build is_settled maps
  818. std::vector<bool> is_settledS(num_vertices(g));
  819. typedef iterator_property_map<std::vector<bool>::iterator, VertexIndexMap>
  820. IsSettledMap;
  821. IsSettledMap is_settled(is_settledS.begin(), vertex_index);
  822. #endif
  823. if (!sources.empty()) {
  824. // DO SSSPs
  825. while (!sources.empty()) {
  826. do_brandes_sssp(g, centrality, edge_centrality_map, incoming, distance,
  827. dependency, path_count,
  828. #ifdef COMPUTE_PATH_COUNTS_INLINE
  829. is_settled,
  830. #endif
  831. vertex_index, shortest_paths, sources.top());
  832. sources.pop();
  833. }
  834. } else { // Exact Betweenness Centrality
  835. typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
  836. vertices_size_type n = num_vertices(g);
  837. n = boost::parallel::all_reduce(pg, n, std::plus<vertices_size_type>());
  838. for (vertices_size_type i = 0; i < n; ++i) {
  839. vertex_descriptor v = vertex(i, g);
  840. do_brandes_sssp(g, centrality, edge_centrality_map, incoming, distance,
  841. dependency, path_count,
  842. #ifdef COMPUTE_PATH_COUNTS_INLINE
  843. is_settled,
  844. #endif
  845. vertex_index, shortest_paths, v);
  846. }
  847. }
  848. typedef typename graph_traits<Graph>::directed_category directed_category;
  849. const bool is_undirected =
  850. is_convertible<directed_category*, undirected_tag*>::value;
  851. if (is_undirected) {
  852. divide_centrality_by_two(vertices(g), centrality);
  853. divide_centrality_by_two(edges(g), edge_centrality_map);
  854. }
  855. }
  856. template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
  857. typename IncomingMap, typename DistanceMap, typename DependencyMap,
  858. typename PathCountMap, typename VertexIndexMap, typename ShortestPaths,
  859. typename Stack>
  860. void
  861. do_sequential_brandes_sssp(const Graph& g,
  862. CentralityMap centrality,
  863. EdgeCentralityMap edge_centrality_map,
  864. IncomingMap incoming,
  865. DistanceMap distance,
  866. DependencyMap dependency,
  867. PathCountMap path_count,
  868. VertexIndexMap vertex_index,
  869. ShortestPaths shortest_paths,
  870. Stack& ordered_vertices,
  871. typename graph_traits<Graph>::vertex_descriptor v)
  872. {
  873. using boost::detail::graph::update_centrality;
  874. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  875. // Initialize for this iteration
  876. BGL_FORALL_VERTICES_T(w, g, Graph) {
  877. // put(path_count, w, 0);
  878. incoming[w].clear();
  879. put(dependency, w, 0);
  880. }
  881. put(path_count, v, 1);
  882. incoming[v].clear();
  883. // Execute the shortest paths algorithm. This will be either
  884. // Dijkstra's algorithm or a customized breadth-first search,
  885. // depending on whether the graph is weighted or unweighted.
  886. shortest_paths(g, v, ordered_vertices, incoming, distance,
  887. path_count, vertex_index);
  888. while (!ordered_vertices.empty()) {
  889. vertex_descriptor w = ordered_vertices.top();
  890. ordered_vertices.pop();
  891. typedef typename property_traits<IncomingMap>::value_type
  892. incoming_type;
  893. typedef typename incoming_type::iterator incoming_iterator;
  894. typedef typename property_traits<DependencyMap>::value_type
  895. dependency_type;
  896. for (incoming_iterator vw = incoming[w].begin();
  897. vw != incoming[w].end(); ++vw) {
  898. vertex_descriptor v = source(*vw, g);
  899. dependency_type factor = dependency_type(get(path_count, v))
  900. / dependency_type(get(path_count, w));
  901. factor *= (dependency_type(1) + get(dependency, w));
  902. put(dependency, v, get(dependency, v) + factor);
  903. update_centrality(edge_centrality_map, *vw, factor);
  904. }
  905. if (w != v) {
  906. update_centrality(centrality, w, get(dependency, w));
  907. }
  908. }
  909. }
  910. // Betweenness Centrality variant that duplicates graph across processors
  911. // and parallizes SSSPs
  912. // This function expects a non-distributed graph and property-maps
  913. template<typename ProcessGroup, typename Graph,
  914. typename CentralityMap, typename EdgeCentralityMap,
  915. typename IncomingMap, typename DistanceMap,
  916. typename DependencyMap, typename PathCountMap,
  917. typename VertexIndexMap, typename ShortestPaths,
  918. typename Buffer>
  919. void
  920. non_distributed_brandes_betweenness_centrality_impl(const ProcessGroup& pg,
  921. const Graph& g,
  922. CentralityMap centrality,
  923. EdgeCentralityMap edge_centrality_map,
  924. IncomingMap incoming, // P
  925. DistanceMap distance, // d
  926. DependencyMap dependency, // delta
  927. PathCountMap path_count, // sigma
  928. VertexIndexMap vertex_index,
  929. ShortestPaths shortest_paths,
  930. Buffer sources)
  931. {
  932. using boost::detail::graph::init_centrality_map;
  933. using boost::detail::graph::divide_centrality_by_two;
  934. using boost::graph::parallel::process_group;
  935. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  936. typedef ProcessGroup process_group_type;
  937. typename process_group_type::process_id_type id = process_id(pg);
  938. typename process_group_type::process_size_type p = num_processes(pg);
  939. // Initialize centrality
  940. init_centrality_map(vertices(g), centrality);
  941. init_centrality_map(edges(g), edge_centrality_map);
  942. std::stack<vertex_descriptor> ordered_vertices;
  943. if (!sources.empty()) {
  944. std::vector<vertex_descriptor> local_sources;
  945. for (int i = 0; i < id; ++i) if (!sources.empty()) sources.pop();
  946. while (!sources.empty()) {
  947. local_sources.push_back(sources.top());
  948. for (int i = 0; i < p; ++i) if (!sources.empty()) sources.pop();
  949. }
  950. // DO SSSPs
  951. for(size_t i = 0; i < local_sources.size(); ++i)
  952. do_sequential_brandes_sssp(g, centrality, edge_centrality_map, incoming,
  953. distance, dependency, path_count, vertex_index,
  954. shortest_paths, ordered_vertices, local_sources[i]);
  955. } else { // Exact Betweenness Centrality
  956. typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
  957. vertices_size_type n = num_vertices(g);
  958. for (vertices_size_type i = id; i < n; i += p) {
  959. vertex_descriptor v = vertex(i, g);
  960. do_sequential_brandes_sssp(g, centrality, edge_centrality_map, incoming,
  961. distance, dependency, path_count, vertex_index,
  962. shortest_paths, ordered_vertices, v);
  963. }
  964. }
  965. typedef typename graph_traits<Graph>::directed_category directed_category;
  966. const bool is_undirected =
  967. is_convertible<directed_category*, undirected_tag*>::value;
  968. if (is_undirected) {
  969. divide_centrality_by_two(vertices(g), centrality);
  970. divide_centrality_by_two(edges(g), edge_centrality_map);
  971. }
  972. // Merge the centrality maps by summing the values at each vertex)
  973. // TODO(nge): this copy-out, reduce, copy-in is lame
  974. typedef typename property_traits<CentralityMap>::value_type centrality_type;
  975. typedef typename property_traits<EdgeCentralityMap>::value_type edge_centrality_type;
  976. std::vector<centrality_type> centrality_v(num_vertices(g));
  977. std::vector<edge_centrality_type> edge_centrality_v;
  978. edge_centrality_v.reserve(num_edges(g));
  979. BGL_FORALL_VERTICES_T(v, g, Graph) {
  980. centrality_v[get(vertex_index, v)] = get(centrality, v);
  981. }
  982. // Skip when EdgeCentralityMap is a dummy_property_map
  983. if (!is_same<EdgeCentralityMap, dummy_property_map>::value) {
  984. BGL_FORALL_EDGES_T(e, g, Graph) {
  985. edge_centrality_v.push_back(get(edge_centrality_map, e));
  986. }
  987. // NGE: If we trust that the order of elements in the vector isn't changed in the
  988. // all_reduce below then this method avoids the need for an edge index map
  989. }
  990. using boost::parallel::all_reduce;
  991. all_reduce(pg, &centrality_v[0], &centrality_v[centrality_v.size()],
  992. &centrality_v[0], std::plus<centrality_type>());
  993. if (edge_centrality_v.size())
  994. all_reduce(pg, &edge_centrality_v[0], &edge_centrality_v[edge_centrality_v.size()],
  995. &edge_centrality_v[0], std::plus<edge_centrality_type>());
  996. BGL_FORALL_VERTICES_T(v, g, Graph) {
  997. put(centrality, v, centrality_v[get(vertex_index, v)]);
  998. }
  999. // Skip when EdgeCentralityMap is a dummy_property_map
  1000. if (!is_same<EdgeCentralityMap, dummy_property_map>::value) {
  1001. int i = 0;
  1002. BGL_FORALL_EDGES_T(e, g, Graph) {
  1003. put(edge_centrality_map, e, edge_centrality_v[i]);
  1004. ++i;
  1005. }
  1006. }
  1007. }
  1008. } } } // end namespace graph::parallel::detail
  1009. template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
  1010. typename IncomingMap, typename DistanceMap, typename DependencyMap,
  1011. typename PathCountMap, typename VertexIndexMap, typename Buffer>
  1012. void
  1013. brandes_betweenness_centrality(const Graph& g,
  1014. CentralityMap centrality,
  1015. EdgeCentralityMap edge_centrality_map,
  1016. IncomingMap incoming,
  1017. DistanceMap distance,
  1018. DependencyMap dependency,
  1019. PathCountMap path_count,
  1020. VertexIndexMap vertex_index,
  1021. Buffer sources,
  1022. typename property_traits<DistanceMap>::value_type delta
  1023. BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
  1024. {
  1025. typedef typename property_traits<DistanceMap>::value_type distance_type;
  1026. typedef static_property_map<distance_type> WeightMap;
  1027. graph::parallel::detail::brandes_shortest_paths<WeightMap>
  1028. shortest_paths(delta);
  1029. graph::parallel::detail::brandes_betweenness_centrality_impl(g, centrality,
  1030. edge_centrality_map,
  1031. incoming, distance,
  1032. dependency, path_count,
  1033. vertex_index,
  1034. shortest_paths,
  1035. sources);
  1036. }
  1037. template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
  1038. typename IncomingMap, typename DistanceMap, typename DependencyMap,
  1039. typename PathCountMap, typename VertexIndexMap, typename WeightMap,
  1040. typename Buffer>
  1041. void
  1042. brandes_betweenness_centrality(const Graph& g,
  1043. CentralityMap centrality,
  1044. EdgeCentralityMap edge_centrality_map,
  1045. IncomingMap incoming,
  1046. DistanceMap distance,
  1047. DependencyMap dependency,
  1048. PathCountMap path_count,
  1049. VertexIndexMap vertex_index,
  1050. Buffer sources,
  1051. typename property_traits<WeightMap>::value_type delta,
  1052. WeightMap weight_map
  1053. BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
  1054. {
  1055. graph::parallel::detail::brandes_shortest_paths<WeightMap> shortest_paths(weight_map, delta);
  1056. graph::parallel::detail::brandes_betweenness_centrality_impl(g, centrality,
  1057. edge_centrality_map,
  1058. incoming, distance,
  1059. dependency, path_count,
  1060. vertex_index,
  1061. shortest_paths,
  1062. sources);
  1063. }
  1064. namespace graph { namespace parallel { namespace detail {
  1065. template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
  1066. typename WeightMap, typename VertexIndexMap, typename Buffer>
  1067. void
  1068. brandes_betweenness_centrality_dispatch2(const Graph& g,
  1069. CentralityMap centrality,
  1070. EdgeCentralityMap edge_centrality_map,
  1071. WeightMap weight_map,
  1072. VertexIndexMap vertex_index,
  1073. Buffer sources,
  1074. typename property_traits<WeightMap>::value_type delta)
  1075. {
  1076. typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
  1077. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  1078. typedef typename mpl::if_c<(is_same<CentralityMap,
  1079. dummy_property_map>::value),
  1080. EdgeCentralityMap,
  1081. CentralityMap>::type a_centrality_map;
  1082. typedef typename property_traits<a_centrality_map>::value_type
  1083. centrality_type;
  1084. typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
  1085. std::vector<std::vector<vertex_descriptor> > incoming(V);
  1086. std::vector<centrality_type> distance(V);
  1087. std::vector<centrality_type> dependency(V);
  1088. std::vector<degree_size_type> path_count(V);
  1089. brandes_betweenness_centrality(
  1090. g, centrality, edge_centrality_map,
  1091. make_iterator_property_map(incoming.begin(), vertex_index),
  1092. make_iterator_property_map(distance.begin(), vertex_index),
  1093. make_iterator_property_map(dependency.begin(), vertex_index),
  1094. make_iterator_property_map(path_count.begin(), vertex_index),
  1095. vertex_index, unwrap_ref(sources), delta,
  1096. weight_map);
  1097. }
  1098. // TODO: Should the type of the distance and dependency map depend on the
  1099. // value type of the centrality map?
  1100. template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
  1101. typename VertexIndexMap, typename Buffer>
  1102. void
  1103. brandes_betweenness_centrality_dispatch2(const Graph& g,
  1104. CentralityMap centrality,
  1105. EdgeCentralityMap edge_centrality_map,
  1106. VertexIndexMap vertex_index,
  1107. Buffer sources,
  1108. typename graph_traits<Graph>::edges_size_type delta)
  1109. {
  1110. typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
  1111. typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
  1112. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  1113. typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
  1114. std::vector<std::vector<vertex_descriptor> > incoming(V);
  1115. std::vector<edges_size_type> distance(V);
  1116. std::vector<edges_size_type> dependency(V);
  1117. std::vector<degree_size_type> path_count(V);
  1118. brandes_betweenness_centrality(
  1119. g, centrality, edge_centrality_map,
  1120. make_iterator_property_map(incoming.begin(), vertex_index),
  1121. make_iterator_property_map(distance.begin(), vertex_index),
  1122. make_iterator_property_map(dependency.begin(), vertex_index),
  1123. make_iterator_property_map(path_count.begin(), vertex_index),
  1124. vertex_index, unwrap_ref(sources), delta);
  1125. }
  1126. template<typename WeightMap>
  1127. struct brandes_betweenness_centrality_dispatch1
  1128. {
  1129. template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
  1130. typename VertexIndexMap, typename Buffer>
  1131. static void
  1132. run(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map,
  1133. VertexIndexMap vertex_index, Buffer sources,
  1134. typename property_traits<WeightMap>::value_type delta, WeightMap weight_map)
  1135. {
  1136. boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2(
  1137. g, centrality, edge_centrality_map, weight_map, vertex_index, sources, delta);
  1138. }
  1139. };
  1140. template<>
  1141. struct brandes_betweenness_centrality_dispatch1<boost::param_not_found>
  1142. {
  1143. template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
  1144. typename VertexIndexMap, typename Buffer>
  1145. static void
  1146. run(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map,
  1147. VertexIndexMap vertex_index, Buffer sources,
  1148. typename graph_traits<Graph>::edges_size_type delta,
  1149. boost::param_not_found)
  1150. {
  1151. boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2(
  1152. g, centrality, edge_centrality_map, vertex_index, sources, delta);
  1153. }
  1154. };
  1155. } } } // end namespace graph::parallel::detail
  1156. template<typename Graph, typename Param, typename Tag, typename Rest>
  1157. void
  1158. brandes_betweenness_centrality(const Graph& g,
  1159. const bgl_named_params<Param,Tag,Rest>& params
  1160. BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
  1161. {
  1162. typedef bgl_named_params<Param,Tag,Rest> named_params;
  1163. typedef queue<typename graph_traits<Graph>::vertex_descriptor> queue_t;
  1164. queue_t q;
  1165. typedef typename get_param_type<edge_weight_t, named_params>::type ew_param;
  1166. typedef typename detail::choose_impl_result<mpl::true_, Graph, ew_param, edge_weight_t>::type ew;
  1167. graph::parallel::detail::brandes_betweenness_centrality_dispatch1<ew>::run(
  1168. g,
  1169. choose_param(get_param(params, vertex_centrality),
  1170. dummy_property_map()),
  1171. choose_param(get_param(params, edge_centrality),
  1172. dummy_property_map()),
  1173. choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
  1174. choose_param(get_param(params, buffer_param_t()), boost::ref(q)),
  1175. choose_param(get_param(params, lookahead_t()), 0),
  1176. choose_const_pmap(get_param(params, edge_weight), g, edge_weight));
  1177. }
  1178. template<typename Graph, typename CentralityMap>
  1179. void
  1180. brandes_betweenness_centrality(const Graph& g, CentralityMap centrality
  1181. BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
  1182. {
  1183. typedef queue<typename graph_traits<Graph>::vertex_descriptor> queue_t;
  1184. queue_t q;
  1185. boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2(
  1186. g, centrality, dummy_property_map(), get(vertex_index, g), boost::ref(q), 0);
  1187. }
  1188. template<typename Graph, typename CentralityMap, typename EdgeCentralityMap>
  1189. void
  1190. brandes_betweenness_centrality(const Graph& g, CentralityMap centrality,
  1191. EdgeCentralityMap edge_centrality_map
  1192. BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
  1193. {
  1194. typedef queue<int> queue_t;
  1195. queue_t q;
  1196. boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2(
  1197. g, centrality, edge_centrality_map, get(vertex_index, g), boost::ref(q), 0);
  1198. }
  1199. template<typename ProcessGroup, typename Graph, typename CentralityMap,
  1200. typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap,
  1201. typename DependencyMap, typename PathCountMap, typename VertexIndexMap,
  1202. typename Buffer>
  1203. void
  1204. non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg,
  1205. const Graph& g,
  1206. CentralityMap centrality,
  1207. EdgeCentralityMap edge_centrality_map,
  1208. IncomingMap incoming,
  1209. DistanceMap distance,
  1210. DependencyMap dependency,
  1211. PathCountMap path_count,
  1212. VertexIndexMap vertex_index,
  1213. Buffer sources)
  1214. {
  1215. detail::graph::brandes_unweighted_shortest_paths shortest_paths;
  1216. graph::parallel::detail::non_distributed_brandes_betweenness_centrality_impl(pg, g, centrality,
  1217. edge_centrality_map,
  1218. incoming, distance,
  1219. dependency, path_count,
  1220. vertex_index,
  1221. shortest_paths,
  1222. sources);
  1223. }
  1224. template<typename ProcessGroup, typename Graph, typename CentralityMap,
  1225. typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap,
  1226. typename DependencyMap, typename PathCountMap, typename VertexIndexMap,
  1227. typename WeightMap, typename Buffer>
  1228. void
  1229. non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg,
  1230. const Graph& g,
  1231. CentralityMap centrality,
  1232. EdgeCentralityMap edge_centrality_map,
  1233. IncomingMap incoming,
  1234. DistanceMap distance,
  1235. DependencyMap dependency,
  1236. PathCountMap path_count,
  1237. VertexIndexMap vertex_index,
  1238. WeightMap weight_map,
  1239. Buffer sources)
  1240. {
  1241. detail::graph::brandes_dijkstra_shortest_paths<WeightMap> shortest_paths(weight_map);
  1242. graph::parallel::detail::non_distributed_brandes_betweenness_centrality_impl(pg, g, centrality,
  1243. edge_centrality_map,
  1244. incoming, distance,
  1245. dependency, path_count,
  1246. vertex_index,
  1247. shortest_paths,
  1248. sources);
  1249. }
  1250. namespace detail { namespace graph {
  1251. template<typename ProcessGroup, typename Graph, typename CentralityMap,
  1252. typename EdgeCentralityMap, typename WeightMap, typename VertexIndexMap,
  1253. typename Buffer>
  1254. void
  1255. non_distributed_brandes_betweenness_centrality_dispatch2(const ProcessGroup& pg,
  1256. const Graph& g,
  1257. CentralityMap centrality,
  1258. EdgeCentralityMap edge_centrality_map,
  1259. WeightMap weight_map,
  1260. VertexIndexMap vertex_index,
  1261. Buffer sources)
  1262. {
  1263. typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
  1264. typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
  1265. typedef typename mpl::if_c<(is_same<CentralityMap,
  1266. dummy_property_map>::value),
  1267. EdgeCentralityMap,
  1268. CentralityMap>::type a_centrality_map;
  1269. typedef typename property_traits<a_centrality_map>::value_type
  1270. centrality_type;
  1271. typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
  1272. std::vector<std::vector<edge_descriptor> > incoming(V);
  1273. std::vector<centrality_type> distance(V);
  1274. std::vector<centrality_type> dependency(V);
  1275. std::vector<degree_size_type> path_count(V);
  1276. non_distributed_brandes_betweenness_centrality(
  1277. pg, g, centrality, edge_centrality_map,
  1278. make_iterator_property_map(incoming.begin(), vertex_index),
  1279. make_iterator_property_map(distance.begin(), vertex_index),
  1280. make_iterator_property_map(dependency.begin(), vertex_index),
  1281. make_iterator_property_map(path_count.begin(), vertex_index),
  1282. vertex_index, weight_map, unwrap_ref(sources));
  1283. }
  1284. template<typename ProcessGroup, typename Graph, typename CentralityMap,
  1285. typename EdgeCentralityMap, typename VertexIndexMap, typename Buffer>
  1286. void
  1287. non_distributed_brandes_betweenness_centrality_dispatch2(const ProcessGroup& pg,
  1288. const Graph& g,
  1289. CentralityMap centrality,
  1290. EdgeCentralityMap edge_centrality_map,
  1291. VertexIndexMap vertex_index,
  1292. Buffer sources)
  1293. {
  1294. typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
  1295. typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
  1296. typedef typename mpl::if_c<(is_same<CentralityMap,
  1297. dummy_property_map>::value),
  1298. EdgeCentralityMap,
  1299. CentralityMap>::type a_centrality_map;
  1300. typedef typename property_traits<a_centrality_map>::value_type
  1301. centrality_type;
  1302. typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
  1303. std::vector<std::vector<edge_descriptor> > incoming(V);
  1304. std::vector<centrality_type> distance(V);
  1305. std::vector<centrality_type> dependency(V);
  1306. std::vector<degree_size_type> path_count(V);
  1307. non_distributed_brandes_betweenness_centrality(
  1308. pg, g, centrality, edge_centrality_map,
  1309. make_iterator_property_map(incoming.begin(), vertex_index),
  1310. make_iterator_property_map(distance.begin(), vertex_index),
  1311. make_iterator_property_map(dependency.begin(), vertex_index),
  1312. make_iterator_property_map(path_count.begin(), vertex_index),
  1313. vertex_index, unwrap_ref(sources));
  1314. }
  1315. template<typename WeightMap>
  1316. struct non_distributed_brandes_betweenness_centrality_dispatch1
  1317. {
  1318. template<typename ProcessGroup, typename Graph, typename CentralityMap,
  1319. typename EdgeCentralityMap, typename VertexIndexMap, typename Buffer>
  1320. static void
  1321. run(const ProcessGroup& pg, const Graph& g, CentralityMap centrality,
  1322. EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
  1323. Buffer sources, WeightMap weight_map)
  1324. {
  1325. non_distributed_brandes_betweenness_centrality_dispatch2(pg, g, centrality, edge_centrality_map,
  1326. weight_map, vertex_index, sources);
  1327. }
  1328. };
  1329. template<>
  1330. struct non_distributed_brandes_betweenness_centrality_dispatch1<param_not_found>
  1331. {
  1332. template<typename ProcessGroup, typename Graph, typename CentralityMap,
  1333. typename EdgeCentralityMap, typename VertexIndexMap, typename Buffer>
  1334. static void
  1335. run(const ProcessGroup& pg, const Graph& g, CentralityMap centrality,
  1336. EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
  1337. Buffer sources, param_not_found)
  1338. {
  1339. non_distributed_brandes_betweenness_centrality_dispatch2(pg, g, centrality, edge_centrality_map,
  1340. vertex_index, sources);
  1341. }
  1342. };
  1343. } } // end namespace detail::graph
  1344. template<typename ProcessGroup, typename Graph, typename Param, typename Tag, typename Rest>
  1345. void
  1346. non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g,
  1347. const bgl_named_params<Param,Tag,Rest>& params)
  1348. {
  1349. typedef bgl_named_params<Param,Tag,Rest> named_params;
  1350. typedef queue<int> queue_t;
  1351. queue_t q;
  1352. typedef typename get_param_type<edge_weight_t, named_params>::type ew_param;
  1353. typedef typename detail::choose_impl_result<mpl::true_, Graph, ew_param, edge_weight_t>::type ew;
  1354. detail::graph::non_distributed_brandes_betweenness_centrality_dispatch1<ew>::run(
  1355. pg, g,
  1356. choose_param(get_param(params, vertex_centrality),
  1357. dummy_property_map()),
  1358. choose_param(get_param(params, edge_centrality),
  1359. dummy_property_map()),
  1360. choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
  1361. choose_param(get_param(params, buffer_param_t()), boost::ref(q)),
  1362. choose_const_pmap(get_param(params, edge_weight), g, edge_weight));
  1363. }
  1364. template<typename ProcessGroup, typename Graph, typename CentralityMap>
  1365. void
  1366. non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g,
  1367. CentralityMap centrality)
  1368. {
  1369. typedef queue<int> queue_t;
  1370. queue_t q;
  1371. detail::graph::non_distributed_brandes_betweenness_centrality_dispatch2(
  1372. pg, g, centrality, dummy_property_map(), get(vertex_index, g), boost::ref(q));
  1373. }
  1374. template<typename ProcessGroup, typename Graph, typename CentralityMap,
  1375. typename Buffer>
  1376. void
  1377. non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g,
  1378. CentralityMap centrality, Buffer sources)
  1379. {
  1380. detail::graph::non_distributed_brandes_betweenness_centrality_dispatch2(
  1381. pg, g, centrality, dummy_property_map(), get(vertex_index, g), sources);
  1382. }
  1383. template<typename ProcessGroup, typename Graph, typename CentralityMap,
  1384. typename EdgeCentralityMap, typename Buffer>
  1385. void
  1386. non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g,
  1387. CentralityMap centrality,
  1388. EdgeCentralityMap edge_centrality_map,
  1389. Buffer sources)
  1390. {
  1391. detail::graph::non_distributed_brandes_betweenness_centrality_dispatch2(
  1392. pg, g, centrality, edge_centrality_map, get(vertex_index, g), sources);
  1393. }
  1394. // Compute the central point dominance of a graph.
  1395. // TODO: Make sure central point dominance works in parallel case
  1396. template<typename Graph, typename CentralityMap>
  1397. typename property_traits<CentralityMap>::value_type
  1398. central_point_dominance(const Graph& g, CentralityMap centrality
  1399. BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
  1400. {
  1401. using std::max;
  1402. typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
  1403. typedef typename property_traits<CentralityMap>::value_type centrality_type;
  1404. typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
  1405. typedef typename boost::graph::parallel::process_group_type<Graph>::type
  1406. process_group_type;
  1407. process_group_type pg = boost::graph::parallel::process_group(g);
  1408. vertices_size_type n = num_vertices(g);
  1409. using boost::parallel::all_reduce;
  1410. n = all_reduce(pg, n, std::plus<vertices_size_type>());
  1411. // Find max centrality
  1412. centrality_type max_centrality(0);
  1413. vertex_iterator v, v_end;
  1414. for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
  1415. max_centrality = (max)(max_centrality, get(centrality, *v));
  1416. }
  1417. // All reduce to get global max centrality
  1418. max_centrality = all_reduce(pg, max_centrality, boost::parallel::maximum<centrality_type>());
  1419. // Compute central point dominance
  1420. centrality_type sum(0);
  1421. for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
  1422. sum += (max_centrality - get(centrality, *v));
  1423. }
  1424. sum = all_reduce(pg, sum, std::plus<centrality_type>());
  1425. return sum/(n-1);
  1426. }
  1427. } // end namespace boost
  1428. #endif // BOOST_GRAPH_PARALLEL_BRANDES_BETWEENNESS_CENTRALITY_HPP