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