betweenness_centrality.hpp 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700
  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