Chris@16
|
1 // Copyright (C) 2004-2008 The Trustees of Indiana University.
|
Chris@16
|
2
|
Chris@16
|
3 // Use, modification and distribution is subject to the Boost Software
|
Chris@16
|
4 // License, Version 1.0. (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: Nick Edmonds
|
Chris@16
|
8 // Douglas Gregor
|
Chris@16
|
9 // Andrew Lumsdaine
|
Chris@16
|
10 #ifndef BOOST_GRAPH_DISTRIBUTED_SCC_HPP
|
Chris@16
|
11 #define BOOST_GRAPH_DISTRIBUTED_SCC_HPP
|
Chris@16
|
12
|
Chris@16
|
13 #ifndef BOOST_GRAPH_USE_MPI
|
Chris@16
|
14 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
|
Chris@16
|
15 #endif
|
Chris@16
|
16
|
Chris@16
|
17 // #define PBGL_SCC_DEBUG
|
Chris@16
|
18
|
Chris@16
|
19 #include <boost/assert.hpp>
|
Chris@16
|
20 #include <boost/property_map/property_map.hpp>
|
Chris@16
|
21 #include <boost/property_map/parallel/distributed_property_map.hpp>
|
Chris@16
|
22 #include <boost/property_map/parallel/caching_property_map.hpp>
|
Chris@16
|
23 #include <boost/graph/parallel/algorithm.hpp>
|
Chris@16
|
24 #include <boost/graph/parallel/process_group.hpp>
|
Chris@16
|
25 #include <boost/graph/distributed/queue.hpp>
|
Chris@16
|
26 #include <boost/graph/distributed/filtered_graph.hpp>
|
Chris@16
|
27 #include <boost/pending/indirect_cmp.hpp>
|
Chris@16
|
28 #include <boost/graph/breadth_first_search.hpp>
|
Chris@16
|
29 #include <boost/graph/graph_traits.hpp>
|
Chris@16
|
30 #include <boost/graph/overloading.hpp>
|
Chris@16
|
31 #include <boost/graph/distributed/concepts.hpp>
|
Chris@16
|
32 #include <boost/graph/distributed/local_subgraph.hpp>
|
Chris@16
|
33 #include <boost/graph/parallel/properties.hpp>
|
Chris@16
|
34 #include <boost/graph/named_function_params.hpp>
|
Chris@16
|
35 #include <boost/graph/random.hpp>
|
Chris@16
|
36 #include <boost/graph/distributed/reverse_graph.hpp>
|
Chris@16
|
37 #include <boost/optional.hpp>
|
Chris@16
|
38 #include <boost/graph/distributed/detail/filtered_queue.hpp>
|
Chris@16
|
39 #include <boost/graph/distributed/adjacency_list.hpp>
|
Chris@16
|
40 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
41 #include <iostream>
|
Chris@16
|
42 #include <cstdlib>
|
Chris@16
|
43 #include <iomanip>
|
Chris@16
|
44 #include <sys/time.h>
|
Chris@16
|
45 #include <boost/graph/distributed/graphviz.hpp> // for ostringstream
|
Chris@16
|
46 #endif
|
Chris@16
|
47 #include <vector>
|
Chris@16
|
48 #include <map>
|
Chris@16
|
49 #include <boost/graph/parallel/container_traits.hpp>
|
Chris@16
|
50
|
Chris@16
|
51 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
52 # include <boost/graph/accounting.hpp>
|
Chris@16
|
53 #endif /* PBGL_SCC_DEBUG */
|
Chris@16
|
54
|
Chris@16
|
55 // If your graph is likely to have large numbers of small strongly connected
|
Chris@16
|
56 // components then running the sequential SCC algorithm on the local subgraph
|
Chris@16
|
57 // and filtering components with no remote edges may increase performance
|
Chris@16
|
58 // #define FILTER_LOCAL_COMPONENTS
|
Chris@16
|
59
|
Chris@16
|
60 namespace boost { namespace graph { namespace distributed { namespace detail {
|
Chris@16
|
61
|
Chris@16
|
62 template<typename vertex_descriptor>
|
Chris@16
|
63 struct v_sets{
|
Chris@16
|
64 std::vector<vertex_descriptor> pred, succ, intersect, ps_union;
|
Chris@16
|
65 };
|
Chris@16
|
66
|
Chris@16
|
67 /* Serialize vertex set */
|
Chris@16
|
68 template<typename Graph>
|
Chris@16
|
69 void
|
Chris@16
|
70 marshal_set( std::vector<std::vector<typename graph_traits<Graph>::vertex_descriptor> > in,
|
Chris@16
|
71 std::vector<typename graph_traits<Graph>::vertex_descriptor>& out )
|
Chris@16
|
72 {
|
Chris@16
|
73 for( std::size_t i = 0; i < in.size(); ++i ) {
|
Chris@16
|
74 out.insert( out.end(), graph_traits<Graph>::null_vertex() );
|
Chris@16
|
75 out.insert( out.end(), in[i].begin(), in[i].end() );
|
Chris@16
|
76 }
|
Chris@16
|
77 }
|
Chris@16
|
78
|
Chris@16
|
79 /* Un-serialize vertex set */
|
Chris@16
|
80 template<typename Graph>
|
Chris@16
|
81 void
|
Chris@16
|
82 unmarshal_set( std::vector<typename graph_traits<Graph>::vertex_descriptor> in,
|
Chris@16
|
83 std::vector<std::vector<typename graph_traits<Graph>::vertex_descriptor> >& out )
|
Chris@16
|
84 {
|
Chris@16
|
85 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
Chris@16
|
86
|
Chris@16
|
87 while( !in.empty() ) {
|
Chris@16
|
88 typename std::vector<vertex_descriptor>::iterator end
|
Chris@16
|
89 = std::find( in.begin(), in.end(), graph_traits<Graph>::null_vertex() );
|
Chris@16
|
90
|
Chris@16
|
91 if( end == in.begin() )
|
Chris@16
|
92 in.erase( in.begin() );
|
Chris@16
|
93 else {
|
Chris@16
|
94 out.push_back(std::vector<vertex_descriptor>());
|
Chris@16
|
95 out[out.size() - 1].insert( out[out.size() - 1].end(), in.begin(), end );
|
Chris@16
|
96 in.erase( in.begin(), end );
|
Chris@16
|
97 }
|
Chris@16
|
98 }
|
Chris@16
|
99 }
|
Chris@16
|
100
|
Chris@16
|
101 /* Determine if vertex is in subset */
|
Chris@16
|
102 template <typename Set>
|
Chris@16
|
103 struct in_subset {
|
Chris@16
|
104 in_subset() : m_s(0) { }
|
Chris@16
|
105 in_subset(const Set& s) : m_s(&s) { }
|
Chris@16
|
106
|
Chris@16
|
107 template <typename Elt>
|
Chris@16
|
108 bool operator()(const Elt& x) const {
|
Chris@16
|
109 return ((*m_s).find(x) != (*m_s).end());
|
Chris@16
|
110 }
|
Chris@16
|
111
|
Chris@16
|
112 private:
|
Chris@16
|
113 const Set* m_s;
|
Chris@16
|
114 };
|
Chris@16
|
115
|
Chris@16
|
116 template<typename T>
|
Chris@16
|
117 struct vertex_identity_property_map
|
Chris@16
|
118 : public boost::put_get_helper<T, vertex_identity_property_map<T> >
|
Chris@16
|
119 {
|
Chris@16
|
120 typedef T key_type;
|
Chris@16
|
121 typedef T value_type;
|
Chris@16
|
122 typedef T reference;
|
Chris@16
|
123 typedef boost::readable_property_map_tag category;
|
Chris@16
|
124
|
Chris@16
|
125 inline value_type operator[](const key_type& v) const { return v; }
|
Chris@16
|
126 inline void clear() { }
|
Chris@16
|
127 };
|
Chris@16
|
128
|
Chris@16
|
129 template <typename T>
|
Chris@16
|
130 inline void synchronize( vertex_identity_property_map<T> & ) { }
|
Chris@16
|
131
|
Chris@16
|
132 /* BFS visitor for SCC */
|
Chris@16
|
133 template<typename Graph, typename SourceMap>
|
Chris@16
|
134 struct scc_discovery_visitor : bfs_visitor<>
|
Chris@16
|
135 {
|
Chris@16
|
136 scc_discovery_visitor(SourceMap& sourceM)
|
Chris@16
|
137 : sourceM(sourceM) {}
|
Chris@16
|
138
|
Chris@16
|
139 template<typename Edge>
|
Chris@16
|
140 void tree_edge(Edge e, const Graph& g)
|
Chris@16
|
141 {
|
Chris@16
|
142 put(sourceM, target(e,g), get(sourceM, source(e,g)));
|
Chris@16
|
143 }
|
Chris@16
|
144
|
Chris@16
|
145 private:
|
Chris@16
|
146 SourceMap& sourceM;
|
Chris@16
|
147 };
|
Chris@16
|
148
|
Chris@16
|
149 } } } } /* End namespace boost::graph::distributed::detail */
|
Chris@16
|
150
|
Chris@16
|
151 namespace boost { namespace graph { namespace distributed {
|
Chris@16
|
152 enum fhp_message_tags { fhp_edges_size_msg, fhp_add_edges_msg, fhp_pred_size_msg,
|
Chris@16
|
153 fhp_pred_msg, fhp_succ_size_msg, fhp_succ_msg };
|
Chris@16
|
154
|
Chris@16
|
155 template<typename Graph, typename ReverseGraph,
|
Chris@16
|
156 typename VertexComponentMap, typename IsoMapFR, typename IsoMapRF,
|
Chris@16
|
157 typename VertexIndexMap>
|
Chris@16
|
158 void
|
Chris@16
|
159 fleischer_hendrickson_pinar_strong_components(const Graph& g,
|
Chris@16
|
160 VertexComponentMap c,
|
Chris@16
|
161 const ReverseGraph& gr,
|
Chris@16
|
162 IsoMapFR fr, IsoMapRF rf,
|
Chris@16
|
163 VertexIndexMap vertex_index_map)
|
Chris@16
|
164 {
|
Chris@16
|
165 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
Chris@16
|
166 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
Chris@16
|
167 typedef typename graph_traits<ReverseGraph>::vertex_iterator rev_vertex_iterator;
|
Chris@16
|
168 typedef typename graph_traits<ReverseGraph>::vertex_descriptor rev_vertex_descriptor;
|
Chris@16
|
169 typedef typename boost::graph::parallel::process_group_type<Graph>::type
|
Chris@16
|
170 process_group_type;
|
Chris@16
|
171 typedef typename process_group_type::process_id_type process_id_type;
|
Chris@16
|
172 typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
|
Chris@16
|
173 VertexIndexMap> ParentMap;
|
Chris@16
|
174 typedef iterator_property_map<typename std::vector<default_color_type>::iterator,
|
Chris@16
|
175 VertexIndexMap> ColorMap;
|
Chris@16
|
176 typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
|
Chris@16
|
177 VertexIndexMap> Rev_ParentMap;
|
Chris@16
|
178 typedef std::vector<std::pair<vertex_descriptor, vertex_descriptor> > VertexPairVec;
|
Chris@16
|
179
|
Chris@16
|
180 typedef typename property_map<Graph, vertex_owner_t>::const_type
|
Chris@16
|
181 OwnerMap;
|
Chris@16
|
182
|
Chris@16
|
183 OwnerMap owner = get(vertex_owner, g);
|
Chris@16
|
184
|
Chris@16
|
185 using boost::graph::parallel::process_group;
|
Chris@16
|
186 process_group_type pg = process_group(g);
|
Chris@16
|
187 process_id_type id = process_id(pg);
|
Chris@16
|
188 int num_procs = num_processes(pg);
|
Chris@16
|
189 int n = 0;
|
Chris@16
|
190
|
Chris@16
|
191 int my_n = num_vertices(g);
|
Chris@16
|
192 all_reduce(pg, &my_n, &my_n+1, &n, std::plus<int>());
|
Chris@16
|
193
|
Chris@16
|
194 //
|
Chris@16
|
195 // Initialization
|
Chris@16
|
196 //
|
Chris@16
|
197
|
Chris@16
|
198 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
199 accounting::time_type start = accounting::get_time();
|
Chris@16
|
200 #endif
|
Chris@16
|
201
|
Chris@16
|
202 vertex_iterator vstart, vend;
|
Chris@16
|
203 rev_vertex_iterator rev_vstart, rev_vend;
|
Chris@16
|
204 std::vector<std::vector<vertex_descriptor> > vertex_sets, new_vertex_sets;
|
Chris@16
|
205
|
Chris@16
|
206 vertex_sets.push_back(std::vector<vertex_descriptor>());
|
Chris@16
|
207
|
Chris@16
|
208 // Remove vertices that do not have at least one in edge and one out edge
|
Chris@16
|
209 new_vertex_sets.push_back(std::vector<vertex_descriptor>());
|
Chris@16
|
210 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
|
Chris@16
|
211 if( out_degree( get(fr, *vstart), gr) > 0 && out_degree(*vstart, g) > 0 )
|
Chris@16
|
212 new_vertex_sets[0].push_back( *vstart );
|
Chris@16
|
213
|
Chris@16
|
214 // Perform sequential SCC on local subgraph, filter all components with external
|
Chris@16
|
215 // edges, mark remaining components and remove them from vertex_sets
|
Chris@16
|
216 #ifdef FILTER_LOCAL_COMPONENTS
|
Chris@16
|
217 // This doesn't actually speed up SCC in connected graphs it seems, but it does work
|
Chris@16
|
218 // and may help in the case where there are lots of small strong components.
|
Chris@16
|
219 {
|
Chris@16
|
220 local_subgraph<const Graph> ls(g);
|
Chris@16
|
221 typedef typename property_map<local_subgraph<const Graph>, vertex_index_t>::type
|
Chris@16
|
222 local_index_map_type;
|
Chris@16
|
223 local_index_map_type local_index = get(vertex_index, ls);
|
Chris@16
|
224
|
Chris@16
|
225 std::vector<int> ls_components_vec(num_vertices(ls));
|
Chris@16
|
226 typedef iterator_property_map<std::vector<int>::iterator, local_index_map_type>
|
Chris@16
|
227 ls_components_map_type;
|
Chris@16
|
228 ls_components_map_type ls_component(ls_components_vec.begin(), local_index);
|
Chris@16
|
229 int num_comp = boost::strong_components(ls, ls_component);
|
Chris@16
|
230
|
Chris@16
|
231 // Create map of components
|
Chris@16
|
232 std::map<int, std::vector<vertex_descriptor> > local_comp_map;
|
Chris@16
|
233 typedef typename graph_traits<local_subgraph<const Graph> >::vertex_iterator ls_vertex_iterator;
|
Chris@16
|
234 ls_vertex_iterator vstart, vend;
|
Chris@16
|
235 for( boost::tie(vstart,vend) = vertices(ls); vstart != vend; vstart++ )
|
Chris@16
|
236 local_comp_map[get(ls_component, *vstart)].push_back( *vstart );
|
Chris@16
|
237
|
Chris@16
|
238 // Filter components that have no non-local edges
|
Chris@16
|
239 typedef typename graph_traits<Graph>::adjacency_iterator adjacency_iterator;
|
Chris@16
|
240 typedef typename graph_traits<ReverseGraph>::adjacency_iterator rev_adjacency_iterator;
|
Chris@16
|
241 adjacency_iterator abegin, aend;
|
Chris@16
|
242 rev_adjacency_iterator rev_abegin, rev_aend;
|
Chris@16
|
243 for( std::size_t i = 0; i < num_comp; ++i ) {
|
Chris@16
|
244 bool local = true;
|
Chris@16
|
245 for( std::size_t j = 0; j < local_comp_map[i].size(); j++ ) {
|
Chris@16
|
246 for( boost::tie(abegin,aend) = adjacent_vertices(local_comp_map[i][j], g);
|
Chris@16
|
247 abegin != aend; abegin++ )
|
Chris@16
|
248 if( get(owner, *abegin) != id ) {
|
Chris@16
|
249 local = false;
|
Chris@16
|
250 break;
|
Chris@16
|
251 }
|
Chris@16
|
252
|
Chris@16
|
253 if( local )
|
Chris@16
|
254 for( boost::tie(rev_abegin,rev_aend) = adjacent_vertices(get(fr, local_comp_map[i][j]), gr);
|
Chris@16
|
255 rev_abegin != rev_aend; rev_abegin++ )
|
Chris@16
|
256 if( get(owner, *rev_abegin) != id ) {
|
Chris@16
|
257 local = false;
|
Chris@16
|
258 break;
|
Chris@16
|
259 }
|
Chris@16
|
260
|
Chris@16
|
261 if( !local ) break;
|
Chris@16
|
262 }
|
Chris@16
|
263
|
Chris@16
|
264 if( local ) // Mark and remove from new_vertex_sets
|
Chris@16
|
265 for( std::size_t j = 0; j < local_comp_map[i].size(); j++ ) {
|
Chris@16
|
266 put( c, local_comp_map[i][j], local_comp_map[i][0] );
|
Chris@16
|
267 typename std::vector<vertex_descriptor>::iterator pos =
|
Chris@16
|
268 std::find(new_vertex_sets[0].begin(), new_vertex_sets[0].end(), local_comp_map[i][j]);
|
Chris@16
|
269 if( pos != new_vertex_sets[0].end() )
|
Chris@16
|
270 new_vertex_sets[0].erase(pos);
|
Chris@16
|
271 }
|
Chris@16
|
272 }
|
Chris@16
|
273 }
|
Chris@16
|
274 #endif // FILTER_LOCAL_COMPONENTS
|
Chris@16
|
275
|
Chris@16
|
276 all_gather( pg, new_vertex_sets[0].begin(), new_vertex_sets[0].end(), vertex_sets[0] );
|
Chris@16
|
277 new_vertex_sets.clear();
|
Chris@16
|
278
|
Chris@16
|
279 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
280 accounting::time_type end = accounting::get_time();
|
Chris@16
|
281 if(id == 0)
|
Chris@16
|
282 std::cerr << "Trim local SCCs time = " << accounting::print_time(end - start) << " seconds.\n";
|
Chris@16
|
283 #endif
|
Chris@16
|
284
|
Chris@16
|
285 if( vertex_sets[0].empty() ) return;
|
Chris@16
|
286
|
Chris@16
|
287 //
|
Chris@16
|
288 // Recursively determine SCCs
|
Chris@16
|
289 //
|
Chris@16
|
290
|
Chris@16
|
291 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
292 int iterations = 0;
|
Chris@16
|
293 #endif
|
Chris@16
|
294
|
Chris@16
|
295 // Only need to be able to map starting vertices for BFS from now on
|
Chris@16
|
296 fr.clear();
|
Chris@16
|
297
|
Chris@16
|
298 do {
|
Chris@16
|
299
|
Chris@16
|
300 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
301 if(id == 0) {
|
Chris@16
|
302 printf("\n\nIteration %d:\n\n", iterations++);
|
Chris@16
|
303
|
Chris@16
|
304 if( iterations > 1 ) {
|
Chris@16
|
305 end = accounting::get_time();
|
Chris@16
|
306 std::cerr << "Running main loop destructors time = " << accounting::print_time(end - start) << " seconds.\n";
|
Chris@16
|
307 }
|
Chris@16
|
308
|
Chris@16
|
309 start = accounting::get_time();
|
Chris@16
|
310 }
|
Chris@16
|
311 #endif
|
Chris@16
|
312
|
Chris@16
|
313 // Get forward->reverse mappings for BFS start vertices
|
Chris@16
|
314 for (std::size_t i = 0; i < vertex_sets.size(); ++i)
|
Chris@16
|
315 get(fr, vertex_sets[i][0]);
|
Chris@16
|
316 synchronize(fr);
|
Chris@16
|
317
|
Chris@16
|
318 // Determine local vertices to start BFS from
|
Chris@16
|
319 std::vector<vertex_descriptor> local_start;
|
Chris@16
|
320 for( std::size_t i = id; i < vertex_sets.size(); i += num_procs )
|
Chris@16
|
321 local_start.push_back(vertex_sets[i][0]);
|
Chris@16
|
322
|
Chris@16
|
323 if( local_start.empty() )
|
Chris@16
|
324 local_start.push_back(vertex_sets[0][0]);
|
Chris@16
|
325
|
Chris@16
|
326
|
Chris@16
|
327 // Make filtered graphs
|
Chris@16
|
328 typedef std::set<vertex_descriptor> VertexSet;
|
Chris@16
|
329 typedef std::set<rev_vertex_descriptor> Rev_VertexSet;
|
Chris@16
|
330
|
Chris@16
|
331 VertexSet filter_set_g;
|
Chris@16
|
332 Rev_VertexSet filter_set_gr;
|
Chris@16
|
333 typename VertexSet::iterator fs;
|
Chris@16
|
334
|
Chris@16
|
335 int active_vertices = 0;
|
Chris@16
|
336 for (std::size_t i = 0; i < vertex_sets.size(); i++)
|
Chris@16
|
337 active_vertices += vertex_sets[i].size();
|
Chris@16
|
338
|
Chris@16
|
339 // This is a completely random bound
|
Chris@16
|
340 if ( active_vertices < 0.05*n ) {
|
Chris@16
|
341 // TODO: This set insertion is ridiculously inefficient, make it an in-place-merge?
|
Chris@16
|
342 for (std::size_t i = 0; i < vertex_sets.size(); i++)
|
Chris@16
|
343 filter_set_g.insert(vertex_sets[i].begin(), vertex_sets[i].end());
|
Chris@16
|
344
|
Chris@16
|
345 for (fs = filter_set_g.begin(); fs != filter_set_g.end(); ++fs )
|
Chris@16
|
346 filter_set_gr.insert(get(fr, *fs));
|
Chris@16
|
347 }
|
Chris@16
|
348
|
Chris@16
|
349 filtered_graph<const Graph, keep_all, detail::in_subset<VertexSet> >
|
Chris@16
|
350 fg(g, keep_all(), detail::in_subset<VertexSet>(filter_set_g));
|
Chris@16
|
351
|
Chris@16
|
352 filtered_graph<const ReverseGraph, keep_all, detail::in_subset<VertexSet> >
|
Chris@16
|
353 fgr(gr, keep_all(), detail::in_subset<VertexSet>(filter_set_gr));
|
Chris@16
|
354
|
Chris@16
|
355 // Add additional starting vertices to BFS queue
|
Chris@16
|
356 typedef filtered_queue<queue<vertex_descriptor>, boost::detail::has_not_been_seen<VertexIndexMap> >
|
Chris@16
|
357 local_queue_type;
|
Chris@16
|
358 typedef boost::graph::distributed::distributed_queue<process_group_type, OwnerMap, local_queue_type>
|
Chris@16
|
359 queue_t;
|
Chris@16
|
360
|
Chris@16
|
361 typedef typename property_map<ReverseGraph, vertex_owner_t>::const_type
|
Chris@16
|
362 RevOwnerMap;
|
Chris@16
|
363
|
Chris@16
|
364 typedef filtered_queue<queue<rev_vertex_descriptor>, boost::detail::has_not_been_seen<VertexIndexMap> >
|
Chris@16
|
365 rev_local_queue_type;
|
Chris@16
|
366 typedef boost::graph::distributed::distributed_queue<process_group_type, RevOwnerMap, rev_local_queue_type>
|
Chris@16
|
367 rev_queue_t;
|
Chris@16
|
368
|
Chris@16
|
369 queue_t Q(process_group(g),
|
Chris@16
|
370 owner,
|
Chris@16
|
371 make_filtered_queue(queue<vertex_descriptor>(),
|
Chris@16
|
372 boost::detail::has_not_been_seen<VertexIndexMap>
|
Chris@16
|
373 (num_vertices(g), vertex_index_map)),
|
Chris@16
|
374 false);
|
Chris@16
|
375
|
Chris@16
|
376 rev_queue_t Qr(process_group(gr),
|
Chris@16
|
377 get(vertex_owner, gr),
|
Chris@16
|
378 make_filtered_queue(queue<rev_vertex_descriptor>(),
|
Chris@16
|
379 boost::detail::has_not_been_seen<VertexIndexMap>
|
Chris@16
|
380 (num_vertices(gr), vertex_index_map)),
|
Chris@16
|
381 false);
|
Chris@16
|
382
|
Chris@16
|
383 for( std::size_t i = 1; i < local_start.size(); ++i ) {
|
Chris@16
|
384 Q.push(local_start[i]);
|
Chris@16
|
385 Qr.push(get(fr, local_start[i]));
|
Chris@16
|
386 }
|
Chris@16
|
387
|
Chris@16
|
388 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
389 end = accounting::get_time();
|
Chris@16
|
390 if(id == 0)
|
Chris@16
|
391 std::cerr << " Initialize BFS time = " << accounting::print_time(end - start) << " seconds.\n";
|
Chris@16
|
392 start = accounting::get_time();
|
Chris@16
|
393 #endif
|
Chris@16
|
394
|
Chris@16
|
395 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
396 accounting::time_type start2 = accounting::get_time();
|
Chris@16
|
397 #endif
|
Chris@16
|
398
|
Chris@16
|
399 // Forward BFS
|
Chris@16
|
400 std::vector<default_color_type> color_map_s(num_vertices(g));
|
Chris@16
|
401 ColorMap color_map(color_map_s.begin(), vertex_index_map);
|
Chris@16
|
402 std::vector<vertex_descriptor> succ_map_s(num_vertices(g), graph_traits<Graph>::null_vertex());
|
Chris@16
|
403 ParentMap succ_map(succ_map_s.begin(), vertex_index_map);
|
Chris@16
|
404
|
Chris@16
|
405 for( std::size_t i = 0; i < vertex_sets.size(); ++i )
|
Chris@16
|
406 put(succ_map, vertex_sets[i][0], vertex_sets[i][0]);
|
Chris@16
|
407
|
Chris@16
|
408 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
409 accounting::time_type end2 = accounting::get_time();
|
Chris@16
|
410 if(id == 0)
|
Chris@16
|
411 std::cerr << " Initialize forward BFS time = " << accounting::print_time(end2 - start2) << " seconds.\n";
|
Chris@16
|
412 #endif
|
Chris@16
|
413
|
Chris@16
|
414 if (active_vertices < 0.05*n)
|
Chris@16
|
415 breadth_first_search(fg, local_start[0], Q,
|
Chris@16
|
416 detail::scc_discovery_visitor<filtered_graph<const Graph, keep_all,
|
Chris@16
|
417 detail::in_subset<VertexSet> >, ParentMap>
|
Chris@16
|
418 (succ_map),
|
Chris@16
|
419 color_map);
|
Chris@16
|
420 else
|
Chris@16
|
421 breadth_first_search(g, local_start[0], Q,
|
Chris@16
|
422 detail::scc_discovery_visitor<const Graph, ParentMap>(succ_map),
|
Chris@16
|
423 color_map);
|
Chris@16
|
424
|
Chris@16
|
425 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
426 start2 = accounting::get_time();
|
Chris@16
|
427 #endif
|
Chris@16
|
428
|
Chris@16
|
429 // Reverse BFS
|
Chris@16
|
430 color_map.clear(); // reuse color map since g and gr have same vertex index
|
Chris@16
|
431 std::vector<vertex_descriptor> pred_map_s(num_vertices(gr), graph_traits<Graph>::null_vertex());
|
Chris@16
|
432 Rev_ParentMap pred_map(pred_map_s.begin(), vertex_index_map);
|
Chris@16
|
433
|
Chris@16
|
434 for( std::size_t i = 0; i < vertex_sets.size(); ++i )
|
Chris@16
|
435 put(pred_map, get(fr, vertex_sets[i][0]), vertex_sets[i][0]);
|
Chris@16
|
436
|
Chris@16
|
437 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
438 end2 = accounting::get_time();
|
Chris@16
|
439 if(id == 0)
|
Chris@16
|
440 std::cerr << " Initialize reverse BFS time = " << accounting::print_time(end2 - start2) << " seconds.\n";
|
Chris@16
|
441 #endif
|
Chris@16
|
442
|
Chris@16
|
443 if (active_vertices < 0.05*n)
|
Chris@16
|
444 breadth_first_search(fgr, get(fr, local_start[0]),
|
Chris@16
|
445 Qr,
|
Chris@16
|
446 detail::scc_discovery_visitor<filtered_graph<const ReverseGraph, keep_all,
|
Chris@16
|
447 detail::in_subset<Rev_VertexSet> >, Rev_ParentMap>
|
Chris@16
|
448 (pred_map),
|
Chris@16
|
449 color_map);
|
Chris@16
|
450 else
|
Chris@16
|
451 breadth_first_search(gr, get(fr, local_start[0]),
|
Chris@16
|
452 Qr,
|
Chris@16
|
453 detail::scc_discovery_visitor<const ReverseGraph, Rev_ParentMap>(pred_map),
|
Chris@16
|
454 color_map);
|
Chris@16
|
455
|
Chris@16
|
456 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
457 end = accounting::get_time();
|
Chris@16
|
458 if(id == 0)
|
Chris@16
|
459 std::cerr << " Perform forward and reverse BFS time = " << accounting::print_time(end - start) << " seconds.\n";
|
Chris@16
|
460 start = accounting::get_time();
|
Chris@16
|
461 #endif
|
Chris@16
|
462
|
Chris@16
|
463 // Send predecessors and successors discovered by this proc to the proc responsible for
|
Chris@16
|
464 // this BFS tree
|
Chris@16
|
465 typedef struct detail::v_sets<vertex_descriptor> Vsets;
|
Chris@16
|
466 std::map<vertex_descriptor, Vsets> set_map;
|
Chris@16
|
467
|
Chris@16
|
468 std::map<vertex_descriptor, int> dest_map;
|
Chris@16
|
469
|
Chris@16
|
470 std::vector<VertexPairVec> successors(num_procs);
|
Chris@16
|
471 std::vector<VertexPairVec> predecessors(num_procs);
|
Chris@16
|
472
|
Chris@16
|
473 // Calculate destinations for messages
|
Chris@16
|
474 for (std::size_t i = 0; i < vertex_sets.size(); ++i)
|
Chris@16
|
475 dest_map[vertex_sets[i][0]] = i % num_procs;
|
Chris@16
|
476
|
Chris@16
|
477 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ ) {
|
Chris@16
|
478 vertex_descriptor v = get(succ_map, *vstart);
|
Chris@16
|
479 if( v != graph_traits<Graph>::null_vertex() ) {
|
Chris@16
|
480 if (dest_map[v] == id)
|
Chris@16
|
481 set_map[v].succ.push_back(*vstart);
|
Chris@16
|
482 else
|
Chris@16
|
483 successors[dest_map[v]].push_back( std::make_pair(v, *vstart) );
|
Chris@16
|
484 }
|
Chris@16
|
485 }
|
Chris@16
|
486
|
Chris@16
|
487 for( boost::tie(rev_vstart, rev_vend) = vertices(gr); rev_vstart != rev_vend; rev_vstart++ ) {
|
Chris@16
|
488 vertex_descriptor v = get(pred_map, *rev_vstart);
|
Chris@16
|
489 if( v != graph_traits<Graph>::null_vertex() ) {
|
Chris@16
|
490 if (dest_map[v] == id)
|
Chris@16
|
491 set_map[v].pred.push_back(get(rf, *rev_vstart));
|
Chris@16
|
492 else
|
Chris@16
|
493 predecessors[dest_map[v]].push_back( std::make_pair(v, get(rf, *rev_vstart)) );
|
Chris@16
|
494 }
|
Chris@16
|
495 }
|
Chris@16
|
496
|
Chris@16
|
497 // Send predecessor and successor messages
|
Chris@16
|
498 for (process_id_type i = 0; i < num_procs; ++i) {
|
Chris@16
|
499 if (!successors[i].empty()) {
|
Chris@16
|
500 send(pg, i, fhp_succ_size_msg, successors[i].size());
|
Chris@16
|
501 send(pg, i, fhp_succ_msg, &successors[i][0], successors[i].size());
|
Chris@16
|
502 }
|
Chris@16
|
503 if (!predecessors[i].empty()) {
|
Chris@16
|
504 send(pg, i, fhp_pred_size_msg, predecessors[i].size());
|
Chris@16
|
505 send(pg, i, fhp_pred_msg, &predecessors[i][0], predecessors[i].size());
|
Chris@16
|
506 }
|
Chris@16
|
507 }
|
Chris@16
|
508 synchronize(pg);
|
Chris@16
|
509
|
Chris@16
|
510 // Receive predecessor and successor messages and handle them
|
Chris@16
|
511 while (optional<std::pair<process_id_type, int> > m = probe(pg)) {
|
Chris@16
|
512 BOOST_ASSERT(m->second == fhp_succ_size_msg || m->second == fhp_pred_size_msg);
|
Chris@16
|
513 std::size_t num_requests;
|
Chris@16
|
514 receive(pg, m->first, m->second, num_requests);
|
Chris@16
|
515 VertexPairVec requests(num_requests);
|
Chris@16
|
516 if (m->second == fhp_succ_size_msg) {
|
Chris@16
|
517 receive(pg, m->first, fhp_succ_msg, &requests[0],
|
Chris@16
|
518 num_requests);
|
Chris@16
|
519
|
Chris@16
|
520 std::map<vertex_descriptor, int> added;
|
Chris@16
|
521 for (std::size_t i = 0; i < requests.size(); ++i) {
|
Chris@16
|
522 set_map[requests[i].first].succ.push_back(requests[i].second);
|
Chris@16
|
523 added[requests[i].first]++;
|
Chris@16
|
524 }
|
Chris@16
|
525
|
Chris@16
|
526 // If order of vertex traversal in vertices() is std::less<vertex_descriptor>,
|
Chris@16
|
527 // then the successor sets will be in order
|
Chris@16
|
528 for (std::size_t i = 0; i < local_start.size(); ++i)
|
Chris@16
|
529 if (added[local_start[i]] > 0)
|
Chris@16
|
530 std::inplace_merge(set_map[local_start[i]].succ.begin(),
|
Chris@16
|
531 set_map[local_start[i]].succ.end() - added[local_start[i]],
|
Chris@16
|
532 set_map[local_start[i]].succ.end(),
|
Chris@16
|
533 std::less<vertex_descriptor>());
|
Chris@16
|
534
|
Chris@16
|
535 } else {
|
Chris@16
|
536 receive(pg, m->first, fhp_pred_msg, &requests[0],
|
Chris@16
|
537 num_requests);
|
Chris@16
|
538
|
Chris@16
|
539 std::map<vertex_descriptor, int> added;
|
Chris@16
|
540 for (std::size_t i = 0; i < requests.size(); ++i) {
|
Chris@16
|
541 set_map[requests[i].first].pred.push_back(requests[i].second);
|
Chris@16
|
542 added[requests[i].first]++;
|
Chris@16
|
543 }
|
Chris@16
|
544
|
Chris@16
|
545 if (boost::is_same<detail::vertex_identity_property_map<vertex_descriptor>, IsoMapRF>::value)
|
Chris@16
|
546 for (std::size_t i = 0; i < local_start.size(); ++i)
|
Chris@16
|
547 if (added[local_start[i]] > 0)
|
Chris@16
|
548 std::inplace_merge(set_map[local_start[i]].pred.begin(),
|
Chris@16
|
549 set_map[local_start[i]].pred.end() - added[local_start[i]],
|
Chris@16
|
550 set_map[local_start[i]].pred.end(),
|
Chris@16
|
551 std::less<vertex_descriptor>());
|
Chris@16
|
552 }
|
Chris@16
|
553 }
|
Chris@16
|
554
|
Chris@16
|
555 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
556 end = accounting::get_time();
|
Chris@16
|
557 if(id == 0)
|
Chris@16
|
558 std::cerr << " All gather successors and predecessors time = " << accounting::print_time(end - start) << " seconds.\n";
|
Chris@16
|
559 start = accounting::get_time();
|
Chris@16
|
560 #endif
|
Chris@16
|
561
|
Chris@16
|
562 //
|
Chris@16
|
563 // Filter predecessor and successor sets and perform set arithmetic
|
Chris@16
|
564 //
|
Chris@16
|
565 new_vertex_sets.clear();
|
Chris@16
|
566
|
Chris@16
|
567 if( std::size_t(id) < vertex_sets.size() ) { //If this proc has one or more unique starting points
|
Chris@16
|
568
|
Chris@16
|
569 for( std::size_t i = 0; i < local_start.size(); ++i ) {
|
Chris@16
|
570
|
Chris@16
|
571 vertex_descriptor v = local_start[i];
|
Chris@16
|
572
|
Chris@16
|
573 // Replace this sort with an in-place merges during receive step if possible
|
Chris@16
|
574 if (!boost::is_same<detail::vertex_identity_property_map<vertex_descriptor>, IsoMapRF>::value)
|
Chris@16
|
575 std::sort(set_map[v].pred.begin(), set_map[v].pred.end(), std::less<vertex_descriptor>());
|
Chris@16
|
576
|
Chris@16
|
577 // Limit predecessor and successor sets to members of the original set
|
Chris@16
|
578 std::vector<vertex_descriptor> temp;
|
Chris@16
|
579
|
Chris@16
|
580 std::set_intersection( vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(),
|
Chris@16
|
581 set_map[v].pred.begin(), set_map[v].pred.end(),
|
Chris@16
|
582 back_inserter(temp),
|
Chris@16
|
583 std::less<vertex_descriptor>());
|
Chris@16
|
584 set_map[v].pred.clear();
|
Chris@16
|
585 std::swap(set_map[v].pred, temp);
|
Chris@16
|
586
|
Chris@16
|
587 std::set_intersection( vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(),
|
Chris@16
|
588 set_map[v].succ.begin(), set_map[v].succ.end(),
|
Chris@16
|
589 back_inserter(temp),
|
Chris@16
|
590 std::less<vertex_descriptor>());
|
Chris@16
|
591 set_map[v].succ.clear();
|
Chris@16
|
592 std::swap(set_map[v].succ, temp);
|
Chris@16
|
593
|
Chris@16
|
594 // Intersection(pred, succ)
|
Chris@16
|
595 std::set_intersection(set_map[v].pred.begin(), set_map[v].pred.end(),
|
Chris@16
|
596 set_map[v].succ.begin(), set_map[v].succ.end(),
|
Chris@16
|
597 back_inserter(set_map[v].intersect),
|
Chris@16
|
598 std::less<vertex_descriptor>());
|
Chris@16
|
599
|
Chris@16
|
600 // Union(pred, succ)
|
Chris@16
|
601 std::set_union(set_map[v].pred.begin(), set_map[v].pred.end(),
|
Chris@16
|
602 set_map[v].succ.begin(), set_map[v].succ.end(),
|
Chris@16
|
603 back_inserter(set_map[v].ps_union),
|
Chris@16
|
604 std::less<vertex_descriptor>());
|
Chris@16
|
605
|
Chris@16
|
606 new_vertex_sets.push_back(std::vector<vertex_descriptor>());
|
Chris@16
|
607 // Original set - Union(pred, succ)
|
Chris@16
|
608 std::set_difference(vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(),
|
Chris@16
|
609 set_map[v].ps_union.begin(), set_map[v].ps_union.end(),
|
Chris@16
|
610 back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]),
|
Chris@16
|
611 std::less<vertex_descriptor>());
|
Chris@16
|
612
|
Chris@16
|
613 set_map[v].ps_union.clear();
|
Chris@16
|
614
|
Chris@16
|
615 new_vertex_sets.push_back(std::vector<vertex_descriptor>());
|
Chris@16
|
616 // Pred - Intersect(pred, succ)
|
Chris@16
|
617 std::set_difference(set_map[v].pred.begin(), set_map[v].pred.end(),
|
Chris@16
|
618 set_map[v].intersect.begin(), set_map[v].intersect.end(),
|
Chris@16
|
619 back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]),
|
Chris@16
|
620 std::less<vertex_descriptor>());
|
Chris@16
|
621
|
Chris@16
|
622 set_map[v].pred.clear();
|
Chris@16
|
623
|
Chris@16
|
624 new_vertex_sets.push_back(std::vector<vertex_descriptor>());
|
Chris@16
|
625 // Succ - Intersect(pred, succ)
|
Chris@16
|
626 std::set_difference(set_map[v].succ.begin(), set_map[v].succ.end(),
|
Chris@16
|
627 set_map[v].intersect.begin(), set_map[v].intersect.end(),
|
Chris@16
|
628 back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]),
|
Chris@16
|
629 std::less<vertex_descriptor>());
|
Chris@16
|
630
|
Chris@16
|
631 set_map[v].succ.clear();
|
Chris@16
|
632
|
Chris@16
|
633 // Label SCC just identified with the 'first' vertex in that SCC
|
Chris@16
|
634 for( std::size_t j = 0; j < set_map[v].intersect.size(); j++ )
|
Chris@16
|
635 put(c, set_map[v].intersect[j], set_map[v].intersect[0]);
|
Chris@16
|
636
|
Chris@16
|
637 set_map[v].intersect.clear();
|
Chris@16
|
638 }
|
Chris@16
|
639 }
|
Chris@16
|
640
|
Chris@16
|
641 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
642 end = accounting::get_time();
|
Chris@16
|
643 if(id == 0)
|
Chris@16
|
644 std::cerr << " Perform set arithemetic time = " << accounting::print_time(end - start) << " seconds.\n";
|
Chris@16
|
645 start = accounting::get_time();
|
Chris@16
|
646 #endif
|
Chris@16
|
647
|
Chris@16
|
648 // Remove sets of size 1 from new_vertex_sets
|
Chris@16
|
649 typename std::vector<std::vector<vertex_descriptor> >::iterator vviter;
|
Chris@16
|
650 for( vviter = new_vertex_sets.begin(); vviter != new_vertex_sets.end(); /*in loop*/ )
|
Chris@16
|
651 if( (*vviter).size() < 2 )
|
Chris@16
|
652 vviter = new_vertex_sets.erase( vviter );
|
Chris@16
|
653 else
|
Chris@16
|
654 vviter++;
|
Chris@16
|
655
|
Chris@16
|
656 // All gather new sets and recur (gotta marshal and unmarshal sets first)
|
Chris@16
|
657 vertex_sets.clear();
|
Chris@16
|
658 std::vector<vertex_descriptor> serial_sets, all_serial_sets;
|
Chris@16
|
659 detail::marshal_set<Graph>( new_vertex_sets, serial_sets );
|
Chris@16
|
660 all_gather( pg, serial_sets.begin(), serial_sets.end(), all_serial_sets );
|
Chris@16
|
661 detail::unmarshal_set<Graph>( all_serial_sets, vertex_sets );
|
Chris@16
|
662
|
Chris@16
|
663 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
664 end = accounting::get_time();
|
Chris@16
|
665 if(id == 0) {
|
Chris@16
|
666 std::cerr << " Serialize and gather new vertex sets time = " << accounting::print_time(end - start) << " seconds.\n\n\n";
|
Chris@16
|
667
|
Chris@16
|
668 printf("Vertex sets: %d\n", (int)vertex_sets.size() );
|
Chris@16
|
669 for( std::size_t i = 0; i < vertex_sets.size(); ++i )
|
Chris@16
|
670 printf(" %d: %d\n", i, (int)vertex_sets[i].size() );
|
Chris@16
|
671 }
|
Chris@16
|
672 start = accounting::get_time();
|
Chris@16
|
673 #endif
|
Chris@16
|
674
|
Chris@16
|
675 // HACK!?! -- This would be more properly implemented as a topological sort
|
Chris@16
|
676 // Remove vertices without an edge to another vertex in the set and an edge from another
|
Chris@16
|
677 // vertex in the set
|
Chris@16
|
678 typedef typename graph_traits<Graph>::out_edge_iterator out_edge_iterator;
|
Chris@16
|
679 out_edge_iterator estart, eend;
|
Chris@16
|
680 typedef typename graph_traits<ReverseGraph>::out_edge_iterator r_out_edge_iterator;
|
Chris@16
|
681 r_out_edge_iterator restart, reend;
|
Chris@16
|
682 for (std::size_t i = 0; i < vertex_sets.size(); ++i) {
|
Chris@16
|
683 std::vector<vertex_descriptor> new_set;
|
Chris@16
|
684 for (std::size_t j = 0; j < vertex_sets[i].size(); ++j) {
|
Chris@16
|
685 vertex_descriptor v = vertex_sets[i][j];
|
Chris@16
|
686 if (get(owner, v) == id) {
|
Chris@16
|
687 boost::tie(estart, eend) = out_edges(v, g);
|
Chris@16
|
688 while (estart != eend && find(vertex_sets[i].begin(), vertex_sets[i].end(),
|
Chris@16
|
689 target(*estart,g)) == vertex_sets[i].end()) estart++;
|
Chris@16
|
690 if (estart != eend) {
|
Chris@16
|
691 boost::tie(restart, reend) = out_edges(get(fr, v), gr);
|
Chris@16
|
692 while (restart != reend && find(vertex_sets[i].begin(), vertex_sets[i].end(),
|
Chris@16
|
693 get(rf, target(*restart,gr))) == vertex_sets[i].end()) restart++;
|
Chris@16
|
694 if (restart != reend)
|
Chris@16
|
695 new_set.push_back(v);
|
Chris@16
|
696 }
|
Chris@16
|
697 }
|
Chris@16
|
698 }
|
Chris@16
|
699 vertex_sets[i].clear();
|
Chris@16
|
700 all_gather(pg, new_set.begin(), new_set.end(), vertex_sets[i]);
|
Chris@16
|
701 std::sort(vertex_sets[i].begin(), vertex_sets[i].end(), std::less<vertex_descriptor>());
|
Chris@16
|
702 }
|
Chris@16
|
703 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
704 end = accounting::get_time();
|
Chris@16
|
705 if(id == 0)
|
Chris@16
|
706 std::cerr << " Trim vertex sets time = " << accounting::print_time(end - start) << " seconds.\n\n\n";
|
Chris@16
|
707 start = accounting::get_time();
|
Chris@16
|
708 #endif
|
Chris@16
|
709
|
Chris@16
|
710 } while ( !vertex_sets.empty() );
|
Chris@16
|
711
|
Chris@16
|
712
|
Chris@16
|
713 // Label vertices not in a SCC as their own SCC
|
Chris@16
|
714 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
|
Chris@16
|
715 if( get(c, *vstart) == graph_traits<Graph>::null_vertex() )
|
Chris@16
|
716 put(c, *vstart, *vstart);
|
Chris@16
|
717
|
Chris@16
|
718 synchronize(c);
|
Chris@16
|
719 }
|
Chris@16
|
720
|
Chris@16
|
721 template<typename Graph, typename ReverseGraph, typename IsoMap>
|
Chris@16
|
722 void
|
Chris@16
|
723 build_reverse_graph( const Graph& g, ReverseGraph& gr, IsoMap& fr, IsoMap& rf )
|
Chris@16
|
724 {
|
Chris@16
|
725 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
Chris@16
|
726 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
Chris@16
|
727 typedef typename graph_traits<Graph>::out_edge_iterator out_edge_iterator;
|
Chris@16
|
728 typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type;
|
Chris@16
|
729 typedef typename process_group_type::process_id_type process_id_type;
|
Chris@16
|
730 typedef std::vector<std::pair<vertex_descriptor, vertex_descriptor> > VertexPairVec;
|
Chris@16
|
731
|
Chris@16
|
732 typename property_map<Graph, vertex_owner_t>::const_type
|
Chris@16
|
733 owner = get(vertex_owner, g);
|
Chris@16
|
734
|
Chris@16
|
735 process_group_type pg = process_group(g);
|
Chris@16
|
736 process_id_type id = process_id(pg);
|
Chris@16
|
737
|
Chris@16
|
738 int n;
|
Chris@16
|
739 vertex_iterator vstart, vend;
|
Chris@16
|
740 int num_procs = num_processes(pg);
|
Chris@16
|
741
|
Chris@16
|
742 vertex_descriptor v;
|
Chris@16
|
743 out_edge_iterator oestart, oeend;
|
Chris@16
|
744 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
|
Chris@16
|
745 {
|
Chris@16
|
746 v = add_vertex(gr);
|
Chris@16
|
747 put(fr, *vstart, v);
|
Chris@16
|
748 put(rf, v, *vstart);
|
Chris@16
|
749 }
|
Chris@16
|
750
|
Chris@16
|
751 gr.distribution() = g.distribution();
|
Chris@16
|
752
|
Chris@16
|
753 int my_n = num_vertices(g);
|
Chris@16
|
754 all_reduce(pg, &my_n, &my_n+1, &n, std::plus<int>());
|
Chris@16
|
755
|
Chris@16
|
756 for (int i = 0; i < n; ++i)
|
Chris@16
|
757 get(fr, vertex(i,g));
|
Chris@16
|
758 synchronize(fr);
|
Chris@16
|
759
|
Chris@16
|
760 // Add edges to gr
|
Chris@16
|
761 std::vector<std::pair<vertex_descriptor, vertex_descriptor> > new_edges;
|
Chris@16
|
762 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
|
Chris@16
|
763 for( boost::tie(oestart, oeend) = out_edges(*vstart, g); oestart != oeend; oestart++ )
|
Chris@16
|
764 new_edges.push_back( std::make_pair(get(fr, target(*oestart,g)), get(fr, source(*oestart, g))) );
|
Chris@16
|
765
|
Chris@16
|
766 std::vector<VertexPairVec> edge_requests(num_procs);
|
Chris@16
|
767
|
Chris@16
|
768 typename std::vector<std::pair<vertex_descriptor, vertex_descriptor> >::iterator iter;
|
Chris@16
|
769 for( iter = new_edges.begin(); iter != new_edges.end(); iter++ ) {
|
Chris@16
|
770 std::pair<vertex_descriptor, vertex_descriptor> p1 = *iter;
|
Chris@16
|
771 if( get(owner, p1.first ) == id )
|
Chris@16
|
772 add_edge( p1.first, p1.second, gr );
|
Chris@16
|
773 else
|
Chris@16
|
774 edge_requests[get(owner, p1.first)].push_back(p1);
|
Chris@16
|
775 }
|
Chris@16
|
776 new_edges.clear();
|
Chris@16
|
777
|
Chris@16
|
778 // Send edge addition requests
|
Chris@16
|
779 for (process_id_type p = 0; p < num_procs; ++p) {
|
Chris@16
|
780 if (!edge_requests[p].empty()) {
|
Chris@16
|
781 VertexPairVec reqs(edge_requests[p].begin(), edge_requests[p].end());
|
Chris@16
|
782 send(pg, p, fhp_edges_size_msg, reqs.size());
|
Chris@16
|
783 send(pg, p, fhp_add_edges_msg, &reqs[0], reqs.size());
|
Chris@16
|
784 }
|
Chris@16
|
785 }
|
Chris@16
|
786 synchronize(pg);
|
Chris@16
|
787
|
Chris@16
|
788 // Receive edge addition requests and handle them
|
Chris@16
|
789 while (optional<std::pair<process_id_type, int> > m = probe(pg)) {
|
Chris@16
|
790 BOOST_ASSERT(m->second == fhp_edges_size_msg);
|
Chris@16
|
791 std::size_t num_requests;
|
Chris@16
|
792 receive(pg, m->first, m->second, num_requests);
|
Chris@16
|
793 VertexPairVec requests(num_requests);
|
Chris@16
|
794 receive(pg, m->first, fhp_add_edges_msg, &requests[0],
|
Chris@16
|
795 num_requests);
|
Chris@16
|
796 for( std::size_t i = 0; i < requests.size(); ++i )
|
Chris@16
|
797 add_edge( requests[i].first, requests[i].second, gr );
|
Chris@16
|
798 }
|
Chris@16
|
799 synchronize(gr);
|
Chris@16
|
800 }
|
Chris@16
|
801
|
Chris@16
|
802 template<typename Graph, typename VertexComponentMap, typename ComponentMap>
|
Chris@16
|
803 typename property_traits<ComponentMap>::value_type
|
Chris@16
|
804 number_components(const Graph& g, VertexComponentMap r, ComponentMap c)
|
Chris@16
|
805 {
|
Chris@16
|
806 typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type;
|
Chris@16
|
807 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
Chris@16
|
808 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
Chris@16
|
809 typedef typename property_traits<ComponentMap>::value_type ComponentMapType;
|
Chris@16
|
810 std::vector<vertex_descriptor> my_roots, all_roots;
|
Chris@16
|
811 vertex_iterator vstart, vend;
|
Chris@16
|
812
|
Chris@16
|
813 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
|
Chris@16
|
814 if( find( my_roots.begin(), my_roots.end(), get(r, *vstart) ) == my_roots.end() )
|
Chris@16
|
815 my_roots.push_back( get(r, *vstart) );
|
Chris@16
|
816
|
Chris@16
|
817 all_gather( process_group(g), my_roots.begin(), my_roots.end(), all_roots );
|
Chris@16
|
818
|
Chris@16
|
819 /* Number components */
|
Chris@16
|
820 std::map<vertex_descriptor, ComponentMapType> comp_numbers;
|
Chris@16
|
821 ComponentMapType c_num = 0;
|
Chris@16
|
822
|
Chris@16
|
823 // Compute component numbers
|
Chris@16
|
824 for (std::size_t i = 0; i < all_roots.size(); ++i )
|
Chris@16
|
825 if ( comp_numbers.count(all_roots[i]) == 0 )
|
Chris@16
|
826 comp_numbers[all_roots[i]] = c_num++;
|
Chris@16
|
827
|
Chris@16
|
828 // Broadcast component numbers
|
Chris@16
|
829 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
|
Chris@16
|
830 put( c, *vstart, comp_numbers[get(r,*vstart)] );
|
Chris@16
|
831
|
Chris@16
|
832 // Broadcast number of components
|
Chris@16
|
833 if (process_id(process_group(g)) == 0) {
|
Chris@16
|
834 typedef typename process_group_type::process_size_type
|
Chris@16
|
835 process_size_type;
|
Chris@16
|
836 for (process_size_type dest = 1, n = num_processes(process_group(g));
|
Chris@16
|
837 dest != n; ++dest)
|
Chris@16
|
838 send(process_group(g), dest, 0, c_num);
|
Chris@16
|
839 }
|
Chris@16
|
840
|
Chris@16
|
841 synchronize(process_group(g));
|
Chris@16
|
842
|
Chris@16
|
843 if (process_id(process_group(g)) != 0) receive(process_group(g), 0, 0, c_num);
|
Chris@16
|
844
|
Chris@16
|
845 synchronize(c);
|
Chris@16
|
846 return c_num;
|
Chris@16
|
847 }
|
Chris@16
|
848
|
Chris@16
|
849
|
Chris@16
|
850 template<typename Graph, typename ComponentMap, typename VertexComponentMap,
|
Chris@16
|
851 typename VertexIndexMap>
|
Chris@16
|
852 typename property_traits<ComponentMap>::value_type
|
Chris@16
|
853 fleischer_hendrickson_pinar_strong_components_impl
|
Chris@16
|
854 (const Graph& g,
|
Chris@16
|
855 ComponentMap c,
|
Chris@16
|
856 VertexComponentMap r,
|
Chris@16
|
857 VertexIndexMap vertex_index_map,
|
Chris@16
|
858 incidence_graph_tag)
|
Chris@16
|
859 {
|
Chris@16
|
860 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
Chris@16
|
861 typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
|
Chris@16
|
862 VertexIndexMap> IsoMap;
|
Chris@16
|
863 typename boost::graph::parallel::process_group_type<Graph>::type pg = process_group(g);
|
Chris@16
|
864
|
Chris@16
|
865 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
866 accounting::time_type start = accounting::get_time();
|
Chris@16
|
867 #endif
|
Chris@16
|
868
|
Chris@16
|
869 typedef adjacency_list<listS,
|
Chris@16
|
870 distributedS<typename boost::graph::parallel::process_group_type<Graph>::type, vecS>,
|
Chris@16
|
871 directedS > ReverseGraph;
|
Chris@16
|
872
|
Chris@16
|
873 ReverseGraph gr(0, pg);
|
Chris@16
|
874 std::vector<vertex_descriptor> fr_s(num_vertices(g));
|
Chris@16
|
875 std::vector<vertex_descriptor> rf_s(num_vertices(g));
|
Chris@16
|
876 IsoMap fr(fr_s.begin(), vertex_index_map); // fr = forward->reverse
|
Chris@16
|
877 IsoMap rf(rf_s.begin(), vertex_index_map); // rf = reverse->forward
|
Chris@16
|
878
|
Chris@16
|
879 build_reverse_graph(g, gr, fr, rf);
|
Chris@16
|
880
|
Chris@16
|
881 #ifdef PBGL_SCC_DEBUG
|
Chris@16
|
882 accounting::time_type end = accounting::get_time();
|
Chris@16
|
883 if(process_id(process_group(g)) == 0)
|
Chris@16
|
884 std::cerr << "Reverse graph initialization time = " << accounting::print_time(end - start) << " seconds.\n";
|
Chris@16
|
885 #endif
|
Chris@16
|
886
|
Chris@16
|
887 fleischer_hendrickson_pinar_strong_components(g, r, gr, fr, rf,
|
Chris@16
|
888 vertex_index_map);
|
Chris@16
|
889
|
Chris@16
|
890 typename property_traits<ComponentMap>::value_type c_num = number_components(g, r, c);
|
Chris@16
|
891
|
Chris@16
|
892 return c_num;
|
Chris@16
|
893 }
|
Chris@16
|
894
|
Chris@16
|
895 template<typename Graph, typename ComponentMap, typename VertexComponentMap,
|
Chris@16
|
896 typename VertexIndexMap>
|
Chris@16
|
897 typename property_traits<ComponentMap>::value_type
|
Chris@16
|
898 fleischer_hendrickson_pinar_strong_components_impl
|
Chris@16
|
899 (const Graph& g,
|
Chris@16
|
900 ComponentMap c,
|
Chris@16
|
901 VertexComponentMap r,
|
Chris@16
|
902 VertexIndexMap vertex_index_map,
|
Chris@16
|
903 bidirectional_graph_tag)
|
Chris@16
|
904 {
|
Chris@16
|
905 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
Chris@16
|
906
|
Chris@16
|
907 reverse_graph<Graph> gr(g);
|
Chris@16
|
908 detail::vertex_identity_property_map<vertex_descriptor> fr, rf;
|
Chris@16
|
909
|
Chris@16
|
910 fleischer_hendrickson_pinar_strong_components(g, r, gr, fr, rf,
|
Chris@16
|
911 vertex_index_map);
|
Chris@16
|
912
|
Chris@16
|
913 typename property_traits<ComponentMap>::value_type c_num
|
Chris@16
|
914 = number_components(g, r, c);
|
Chris@16
|
915
|
Chris@16
|
916 return c_num;
|
Chris@16
|
917 }
|
Chris@16
|
918
|
Chris@16
|
919 template<typename Graph, typename ComponentMap, typename VertexIndexMap>
|
Chris@16
|
920 inline typename property_traits<ComponentMap>::value_type
|
Chris@16
|
921 fleischer_hendrickson_pinar_strong_components
|
Chris@16
|
922 (const Graph& g,
|
Chris@16
|
923 ComponentMap c,
|
Chris@16
|
924 VertexIndexMap vertex_index_map)
|
Chris@16
|
925 {
|
Chris@16
|
926 typedef typename graph_traits<Graph>::vertex_descriptor
|
Chris@16
|
927 vertex_descriptor;
|
Chris@16
|
928 typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
|
Chris@16
|
929 VertexIndexMap> VertexComponentMap;
|
Chris@16
|
930 typename boost::graph::parallel::process_group_type<Graph>::type pg
|
Chris@16
|
931 = process_group(g);
|
Chris@16
|
932
|
Chris@16
|
933 if (num_processes(pg) == 1) {
|
Chris@16
|
934 local_subgraph<const Graph> ls(g);
|
Chris@16
|
935 return boost::strong_components(ls, c);
|
Chris@16
|
936 }
|
Chris@16
|
937
|
Chris@16
|
938 // Create a VertexComponentMap for intermediate labeling of SCCs
|
Chris@16
|
939 std::vector<vertex_descriptor> r_s(num_vertices(g), graph_traits<Graph>::null_vertex());
|
Chris@16
|
940 VertexComponentMap r(r_s.begin(), vertex_index_map);
|
Chris@16
|
941
|
Chris@16
|
942 return fleischer_hendrickson_pinar_strong_components_impl
|
Chris@16
|
943 (g, c, r, vertex_index_map,
|
Chris@16
|
944 typename graph_traits<Graph>::traversal_category());
|
Chris@16
|
945 }
|
Chris@16
|
946
|
Chris@16
|
947 template<typename Graph, typename ComponentMap>
|
Chris@16
|
948 inline typename property_traits<ComponentMap>::value_type
|
Chris@16
|
949 fleischer_hendrickson_pinar_strong_components(const Graph& g,
|
Chris@16
|
950 ComponentMap c)
|
Chris@16
|
951 {
|
Chris@16
|
952 return fleischer_hendrickson_pinar_strong_components(g, c, get(vertex_index, g));
|
Chris@16
|
953 }
|
Chris@16
|
954
|
Chris@16
|
955 } // end namespace distributed
|
Chris@16
|
956
|
Chris@16
|
957 using distributed::fleischer_hendrickson_pinar_strong_components;
|
Chris@16
|
958
|
Chris@16
|
959 } // end namespace graph
|
Chris@16
|
960
|
Chris@16
|
961 template<class Graph, class ComponentMap, class P, class T, class R>
|
Chris@16
|
962 inline typename property_traits<ComponentMap>::value_type
|
Chris@16
|
963 strong_components
|
Chris@16
|
964 (const Graph& g, ComponentMap comp,
|
Chris@16
|
965 const bgl_named_params<P, T, R>&
|
Chris@16
|
966 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag))
|
Chris@16
|
967 {
|
Chris@16
|
968 return graph::fleischer_hendrickson_pinar_strong_components(g, comp);
|
Chris@16
|
969 }
|
Chris@16
|
970
|
Chris@16
|
971 template<class Graph, class ComponentMap>
|
Chris@16
|
972 inline typename property_traits<ComponentMap>::value_type
|
Chris@16
|
973 strong_components
|
Chris@16
|
974 (const Graph& g, ComponentMap comp
|
Chris@16
|
975 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag))
|
Chris@16
|
976 {
|
Chris@16
|
977 return graph::fleischer_hendrickson_pinar_strong_components(g, comp);
|
Chris@16
|
978 }
|
Chris@16
|
979
|
Chris@16
|
980 } /* end namespace boost */
|
Chris@16
|
981
|
Chris@16
|
982 #endif // BOOST_GRAPH_DISTRIBUTED_SCC_HPP
|