williamr@2
|
1 |
//
|
williamr@2
|
2 |
//=======================================================================
|
williamr@2
|
3 |
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
|
williamr@2
|
4 |
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
|
williamr@2
|
5 |
//
|
williamr@2
|
6 |
// Distributed under the Boost Software License, Version 1.0. (See
|
williamr@2
|
7 |
// accompanying file LICENSE_1_0.txt or copy at
|
williamr@2
|
8 |
// http://www.boost.org/LICENSE_1_0.txt)
|
williamr@2
|
9 |
//=======================================================================
|
williamr@2
|
10 |
//
|
williamr@2
|
11 |
|
williamr@2
|
12 |
#ifndef BOOST_GRAPH_STRONG_COMPONENTS_HPP
|
williamr@2
|
13 |
#define BOOST_GRAPH_STRONG_COMPONENTS_HPP
|
williamr@2
|
14 |
|
williamr@2
|
15 |
#include <stack>
|
williamr@2
|
16 |
#include <boost/config.hpp>
|
williamr@2
|
17 |
#include <boost/graph/depth_first_search.hpp>
|
williamr@2
|
18 |
#include <boost/type_traits/conversion_traits.hpp>
|
williamr@2
|
19 |
#include <boost/static_assert.hpp>
|
williamr@2
|
20 |
|
williamr@2
|
21 |
namespace boost {
|
williamr@2
|
22 |
|
williamr@2
|
23 |
//==========================================================================
|
williamr@2
|
24 |
// This is Tarjan's algorithm for strongly connected components
|
williamr@2
|
25 |
// from his paper "Depth first search and linear graph algorithms".
|
williamr@2
|
26 |
// It calculates the components in a single application of DFS.
|
williamr@2
|
27 |
// We implement the algorithm as a dfs-visitor.
|
williamr@2
|
28 |
|
williamr@2
|
29 |
namespace detail {
|
williamr@2
|
30 |
|
williamr@2
|
31 |
template <typename ComponentMap, typename RootMap, typename DiscoverTime,
|
williamr@2
|
32 |
typename Stack>
|
williamr@2
|
33 |
class tarjan_scc_visitor : public dfs_visitor<>
|
williamr@2
|
34 |
{
|
williamr@2
|
35 |
typedef typename property_traits<ComponentMap>::value_type comp_type;
|
williamr@2
|
36 |
typedef typename property_traits<DiscoverTime>::value_type time_type;
|
williamr@2
|
37 |
public:
|
williamr@2
|
38 |
tarjan_scc_visitor(ComponentMap comp_map, RootMap r, DiscoverTime d,
|
williamr@2
|
39 |
comp_type& c_, Stack& s_)
|
williamr@2
|
40 |
: c(c_), comp(comp_map), root(r), discover_time(d),
|
williamr@2
|
41 |
dfs_time(time_type()), s(s_) { }
|
williamr@2
|
42 |
|
williamr@2
|
43 |
template <typename Graph>
|
williamr@2
|
44 |
void discover_vertex(typename graph_traits<Graph>::vertex_descriptor v,
|
williamr@2
|
45 |
const Graph&) {
|
williamr@2
|
46 |
put(root, v, v);
|
williamr@2
|
47 |
put(comp, v, (std::numeric_limits<comp_type>::max)());
|
williamr@2
|
48 |
put(discover_time, v, dfs_time++);
|
williamr@2
|
49 |
s.push(v);
|
williamr@2
|
50 |
}
|
williamr@2
|
51 |
template <typename Graph>
|
williamr@2
|
52 |
void finish_vertex(typename graph_traits<Graph>::vertex_descriptor v,
|
williamr@2
|
53 |
const Graph& g) {
|
williamr@2
|
54 |
typename graph_traits<Graph>::vertex_descriptor w;
|
williamr@2
|
55 |
typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
|
williamr@2
|
56 |
for (tie(ei, ei_end) = out_edges(v, g); ei != ei_end; ++ei) {
|
williamr@2
|
57 |
w = target(*ei, g);
|
williamr@2
|
58 |
if (get(comp, w) == (std::numeric_limits<comp_type>::max)())
|
williamr@2
|
59 |
put(root, v, this->min_discover_time(get(root,v), get(root,w)));
|
williamr@2
|
60 |
}
|
williamr@2
|
61 |
if (get(root, v) == v) {
|
williamr@2
|
62 |
do {
|
williamr@2
|
63 |
w = s.top(); s.pop();
|
williamr@2
|
64 |
put(comp, w, c);
|
williamr@2
|
65 |
} while (w != v);
|
williamr@2
|
66 |
++c;
|
williamr@2
|
67 |
}
|
williamr@2
|
68 |
}
|
williamr@2
|
69 |
private:
|
williamr@2
|
70 |
template <typename Vertex>
|
williamr@2
|
71 |
Vertex min_discover_time(Vertex u, Vertex v) {
|
williamr@2
|
72 |
return get(discover_time, u) < get(discover_time,v) ? u : v;
|
williamr@2
|
73 |
}
|
williamr@2
|
74 |
|
williamr@2
|
75 |
comp_type& c;
|
williamr@2
|
76 |
ComponentMap comp;
|
williamr@2
|
77 |
RootMap root;
|
williamr@2
|
78 |
DiscoverTime discover_time;
|
williamr@2
|
79 |
time_type dfs_time;
|
williamr@2
|
80 |
Stack& s;
|
williamr@2
|
81 |
};
|
williamr@2
|
82 |
|
williamr@2
|
83 |
template <class Graph, class ComponentMap, class RootMap,
|
williamr@2
|
84 |
class DiscoverTime, class P, class T, class R>
|
williamr@2
|
85 |
typename property_traits<ComponentMap>::value_type
|
williamr@2
|
86 |
strong_components_impl
|
williamr@2
|
87 |
(const Graph& g, // Input
|
williamr@2
|
88 |
ComponentMap comp, // Output
|
williamr@2
|
89 |
// Internal record keeping
|
williamr@2
|
90 |
RootMap root,
|
williamr@2
|
91 |
DiscoverTime discover_time,
|
williamr@2
|
92 |
const bgl_named_params<P, T, R>& params)
|
williamr@2
|
93 |
{
|
williamr@2
|
94 |
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
|
williamr@2
|
95 |
function_requires< ReadWritePropertyMapConcept<ComponentMap, Vertex> >();
|
williamr@2
|
96 |
function_requires< ReadWritePropertyMapConcept<RootMap, Vertex> >();
|
williamr@2
|
97 |
typedef typename property_traits<RootMap>::value_type RootV;
|
williamr@2
|
98 |
function_requires< ConvertibleConcept<RootV, Vertex> >();
|
williamr@2
|
99 |
function_requires< ReadWritePropertyMapConcept<DiscoverTime, Vertex> >();
|
williamr@2
|
100 |
|
williamr@2
|
101 |
typename property_traits<ComponentMap>::value_type total = 0;
|
williamr@2
|
102 |
|
williamr@2
|
103 |
std::stack<Vertex> s;
|
williamr@2
|
104 |
detail::tarjan_scc_visitor<ComponentMap, RootMap, DiscoverTime,
|
williamr@2
|
105 |
std::stack<Vertex> >
|
williamr@2
|
106 |
vis(comp, root, discover_time, total, s);
|
williamr@2
|
107 |
depth_first_search(g, params.visitor(vis));
|
williamr@2
|
108 |
return total;
|
williamr@2
|
109 |
}
|
williamr@2
|
110 |
|
williamr@2
|
111 |
//-------------------------------------------------------------------------
|
williamr@2
|
112 |
// The dispatch functions handle the defaults for the rank and discover
|
williamr@2
|
113 |
// time property maps.
|
williamr@2
|
114 |
// dispatch with class specialization to avoid VC++ bug
|
williamr@2
|
115 |
|
williamr@2
|
116 |
template <class DiscoverTimeMap>
|
williamr@2
|
117 |
struct strong_comp_dispatch2 {
|
williamr@2
|
118 |
template <class Graph, class ComponentMap, class RootMap, class P, class T, class R>
|
williamr@2
|
119 |
inline static typename property_traits<ComponentMap>::value_type
|
williamr@2
|
120 |
apply(const Graph& g,
|
williamr@2
|
121 |
ComponentMap comp,
|
williamr@2
|
122 |
RootMap r_map,
|
williamr@2
|
123 |
const bgl_named_params<P, T, R>& params,
|
williamr@2
|
124 |
DiscoverTimeMap time_map)
|
williamr@2
|
125 |
{
|
williamr@2
|
126 |
return strong_components_impl(g, comp, r_map, time_map, params);
|
williamr@2
|
127 |
}
|
williamr@2
|
128 |
};
|
williamr@2
|
129 |
|
williamr@2
|
130 |
|
williamr@2
|
131 |
template <>
|
williamr@2
|
132 |
struct strong_comp_dispatch2<detail::error_property_not_found> {
|
williamr@2
|
133 |
template <class Graph, class ComponentMap, class RootMap,
|
williamr@2
|
134 |
class P, class T, class R>
|
williamr@2
|
135 |
inline static typename property_traits<ComponentMap>::value_type
|
williamr@2
|
136 |
apply(const Graph& g,
|
williamr@2
|
137 |
ComponentMap comp,
|
williamr@2
|
138 |
RootMap r_map,
|
williamr@2
|
139 |
const bgl_named_params<P, T, R>& params,
|
williamr@2
|
140 |
detail::error_property_not_found)
|
williamr@2
|
141 |
{
|
williamr@2
|
142 |
typedef typename graph_traits<Graph>::vertices_size_type size_type;
|
williamr@2
|
143 |
size_type n = num_vertices(g) > 0 ? num_vertices(g) : 1;
|
williamr@2
|
144 |
std::vector<size_type> time_vec(n);
|
williamr@2
|
145 |
return strong_components_impl
|
williamr@2
|
146 |
(g, comp, r_map,
|
williamr@2
|
147 |
make_iterator_property_map(time_vec.begin(), choose_const_pmap
|
williamr@2
|
148 |
(get_param(params, vertex_index),
|
williamr@2
|
149 |
g, vertex_index), time_vec[0]),
|
williamr@2
|
150 |
params);
|
williamr@2
|
151 |
}
|
williamr@2
|
152 |
};
|
williamr@2
|
153 |
|
williamr@2
|
154 |
template <class Graph, class ComponentMap, class RootMap,
|
williamr@2
|
155 |
class P, class T, class R, class DiscoverTimeMap>
|
williamr@2
|
156 |
inline typename property_traits<ComponentMap>::value_type
|
williamr@2
|
157 |
scc_helper2(const Graph& g,
|
williamr@2
|
158 |
ComponentMap comp,
|
williamr@2
|
159 |
RootMap r_map,
|
williamr@2
|
160 |
const bgl_named_params<P, T, R>& params,
|
williamr@2
|
161 |
DiscoverTimeMap time_map)
|
williamr@2
|
162 |
{
|
williamr@2
|
163 |
return strong_comp_dispatch2<DiscoverTimeMap>::apply(g, comp, r_map, params, time_map);
|
williamr@2
|
164 |
}
|
williamr@2
|
165 |
|
williamr@2
|
166 |
template <class RootMap>
|
williamr@2
|
167 |
struct strong_comp_dispatch1 {
|
williamr@2
|
168 |
|
williamr@2
|
169 |
template <class Graph, class ComponentMap, class P, class T, class R>
|
williamr@2
|
170 |
inline static typename property_traits<ComponentMap>::value_type
|
williamr@2
|
171 |
apply(const Graph& g,
|
williamr@2
|
172 |
ComponentMap comp,
|
williamr@2
|
173 |
const bgl_named_params<P, T, R>& params,
|
williamr@2
|
174 |
RootMap r_map)
|
williamr@2
|
175 |
{
|
williamr@2
|
176 |
return scc_helper2(g, comp, r_map, params, get_param(params, vertex_discover_time));
|
williamr@2
|
177 |
}
|
williamr@2
|
178 |
};
|
williamr@2
|
179 |
template <>
|
williamr@2
|
180 |
struct strong_comp_dispatch1<detail::error_property_not_found> {
|
williamr@2
|
181 |
|
williamr@2
|
182 |
template <class Graph, class ComponentMap,
|
williamr@2
|
183 |
class P, class T, class R>
|
williamr@2
|
184 |
inline static typename property_traits<ComponentMap>::value_type
|
williamr@2
|
185 |
apply(const Graph& g,
|
williamr@2
|
186 |
ComponentMap comp,
|
williamr@2
|
187 |
const bgl_named_params<P, T, R>& params,
|
williamr@2
|
188 |
detail::error_property_not_found)
|
williamr@2
|
189 |
{
|
williamr@2
|
190 |
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
|
williamr@2
|
191 |
typename std::vector<Vertex>::size_type
|
williamr@2
|
192 |
n = num_vertices(g) > 0 ? num_vertices(g) : 1;
|
williamr@2
|
193 |
std::vector<Vertex> root_vec(n);
|
williamr@2
|
194 |
return scc_helper2
|
williamr@2
|
195 |
(g, comp,
|
williamr@2
|
196 |
make_iterator_property_map(root_vec.begin(), choose_const_pmap
|
williamr@2
|
197 |
(get_param(params, vertex_index),
|
williamr@2
|
198 |
g, vertex_index), root_vec[0]),
|
williamr@2
|
199 |
params,
|
williamr@2
|
200 |
get_param(params, vertex_discover_time));
|
williamr@2
|
201 |
}
|
williamr@2
|
202 |
};
|
williamr@2
|
203 |
|
williamr@2
|
204 |
template <class Graph, class ComponentMap, class RootMap,
|
williamr@2
|
205 |
class P, class T, class R>
|
williamr@2
|
206 |
inline typename property_traits<ComponentMap>::value_type
|
williamr@2
|
207 |
scc_helper1(const Graph& g,
|
williamr@2
|
208 |
ComponentMap comp,
|
williamr@2
|
209 |
const bgl_named_params<P, T, R>& params,
|
williamr@2
|
210 |
RootMap r_map)
|
williamr@2
|
211 |
{
|
williamr@2
|
212 |
return detail::strong_comp_dispatch1<RootMap>::apply(g, comp, params,
|
williamr@2
|
213 |
r_map);
|
williamr@2
|
214 |
}
|
williamr@2
|
215 |
|
williamr@2
|
216 |
} // namespace detail
|
williamr@2
|
217 |
|
williamr@2
|
218 |
template <class Graph, class ComponentMap,
|
williamr@2
|
219 |
class P, class T, class R>
|
williamr@2
|
220 |
inline typename property_traits<ComponentMap>::value_type
|
williamr@2
|
221 |
strong_components(const Graph& g, ComponentMap comp,
|
williamr@2
|
222 |
const bgl_named_params<P, T, R>& params)
|
williamr@2
|
223 |
{
|
williamr@2
|
224 |
typedef typename graph_traits<Graph>::directed_category DirCat;
|
williamr@2
|
225 |
BOOST_STATIC_ASSERT((is_convertible<DirCat*, directed_tag*>::value == true));
|
williamr@2
|
226 |
return detail::scc_helper1(g, comp, params,
|
williamr@2
|
227 |
get_param(params, vertex_root_t()));
|
williamr@2
|
228 |
}
|
williamr@2
|
229 |
|
williamr@2
|
230 |
template <class Graph, class ComponentMap>
|
williamr@2
|
231 |
inline typename property_traits<ComponentMap>::value_type
|
williamr@2
|
232 |
strong_components(const Graph& g, ComponentMap comp)
|
williamr@2
|
233 |
{
|
williamr@2
|
234 |
typedef typename graph_traits<Graph>::directed_category DirCat;
|
williamr@2
|
235 |
BOOST_STATIC_ASSERT((is_convertible<DirCat*, directed_tag*>::value == true));
|
williamr@2
|
236 |
bgl_named_params<int, int> params(0);
|
williamr@2
|
237 |
return strong_components(g, comp, params);
|
williamr@2
|
238 |
}
|
williamr@2
|
239 |
|
williamr@2
|
240 |
template <typename Graph, typename ComponentMap, typename ComponentLists>
|
williamr@2
|
241 |
void build_component_lists
|
williamr@2
|
242 |
(const Graph& g,
|
williamr@2
|
243 |
typename graph_traits<Graph>::vertices_size_type num_scc,
|
williamr@2
|
244 |
ComponentMap component_number,
|
williamr@2
|
245 |
ComponentLists& components)
|
williamr@2
|
246 |
{
|
williamr@2
|
247 |
components.resize(num_scc);
|
williamr@2
|
248 |
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
|
williamr@2
|
249 |
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
|
williamr@2
|
250 |
components[component_number[*vi]].push_back(*vi);
|
williamr@2
|
251 |
}
|
williamr@2
|
252 |
|
williamr@2
|
253 |
|
williamr@2
|
254 |
} // namespace boost
|
williamr@2
|
255 |
|
williamr@2
|
256 |
#include <queue>
|
williamr@2
|
257 |
#include <vector>
|
williamr@2
|
258 |
#include <boost/graph/transpose_graph.hpp>
|
williamr@2
|
259 |
#include <boost/pending/indirect_cmp.hpp>
|
williamr@2
|
260 |
#include <boost/graph/connected_components.hpp> // for components_recorder
|
williamr@2
|
261 |
|
williamr@2
|
262 |
namespace boost {
|
williamr@2
|
263 |
|
williamr@2
|
264 |
//==========================================================================
|
williamr@2
|
265 |
// This is the version of strongly connected components from
|
williamr@2
|
266 |
// "Intro. to Algorithms" by Cormen, Leiserson, Rivest, which was
|
williamr@2
|
267 |
// adapted from "Data Structure and Algorithms" by Aho, Hopcroft,
|
williamr@2
|
268 |
// and Ullman, who credit the algorithm to S.R. Kosaraju and M. Sharir.
|
williamr@2
|
269 |
// The algorithm is based on computing DFS forests the graph
|
williamr@2
|
270 |
// and its transpose.
|
williamr@2
|
271 |
|
williamr@2
|
272 |
// This algorithm is slower than Tarjan's by a constant factor, uses
|
williamr@2
|
273 |
// more memory, and puts more requirements on the graph type.
|
williamr@2
|
274 |
|
williamr@2
|
275 |
template <class Graph, class DFSVisitor, class ComponentsMap,
|
williamr@2
|
276 |
class DiscoverTime, class FinishTime,
|
williamr@2
|
277 |
class ColorMap>
|
williamr@2
|
278 |
typename property_traits<ComponentsMap>::value_type
|
williamr@2
|
279 |
kosaraju_strong_components(Graph& G, ComponentsMap c,
|
williamr@2
|
280 |
FinishTime finish_time, ColorMap color)
|
williamr@2
|
281 |
{
|
williamr@2
|
282 |
function_requires< MutableGraphConcept<Graph> >();
|
williamr@2
|
283 |
// ...
|
williamr@2
|
284 |
|
williamr@2
|
285 |
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
|
williamr@2
|
286 |
typedef typename property_traits<ColorMap>::value_type ColorValue;
|
williamr@2
|
287 |
typedef color_traits<ColorValue> Color;
|
williamr@2
|
288 |
typename property_traits<FinishTime>::value_type time = 0;
|
williamr@2
|
289 |
depth_first_search
|
williamr@2
|
290 |
(G, make_dfs_visitor(stamp_times(finish_time, time, on_finish_vertex())),
|
williamr@2
|
291 |
color);
|
williamr@2
|
292 |
|
williamr@2
|
293 |
Graph G_T(num_vertices(G));
|
williamr@2
|
294 |
transpose_graph(G, G_T);
|
williamr@2
|
295 |
|
williamr@2
|
296 |
typedef typename property_traits<ComponentsMap>::value_type count_type;
|
williamr@2
|
297 |
|
williamr@2
|
298 |
count_type c_count(0);
|
williamr@2
|
299 |
detail::components_recorder<ComponentsMap>
|
williamr@2
|
300 |
vis(c, c_count);
|
williamr@2
|
301 |
|
williamr@2
|
302 |
// initialize G_T
|
williamr@2
|
303 |
typename graph_traits<Graph>::vertex_iterator ui, ui_end;
|
williamr@2
|
304 |
for (tie(ui, ui_end) = vertices(G_T); ui != ui_end; ++ui)
|
williamr@2
|
305 |
put(color, *ui, Color::white());
|
williamr@2
|
306 |
|
williamr@2
|
307 |
typedef typename property_traits<FinishTime>::value_type D;
|
williamr@2
|
308 |
typedef indirect_cmp< FinishTime, std::less<D> > Compare;
|
williamr@2
|
309 |
|
williamr@2
|
310 |
Compare fl(finish_time);
|
williamr@2
|
311 |
std::priority_queue<Vertex, std::vector<Vertex>, Compare > Q(fl);
|
williamr@2
|
312 |
|
williamr@2
|
313 |
typename graph_traits<Graph>::vertex_iterator i, j, iend, jend;
|
williamr@2
|
314 |
tie(i, iend) = vertices(G_T);
|
williamr@2
|
315 |
tie(j, jend) = vertices(G);
|
williamr@2
|
316 |
for ( ; i != iend; ++i, ++j) {
|
williamr@2
|
317 |
put(finish_time, *i, get(finish_time, *j));
|
williamr@2
|
318 |
Q.push(*i);
|
williamr@2
|
319 |
}
|
williamr@2
|
320 |
|
williamr@2
|
321 |
while ( !Q.empty() ) {
|
williamr@2
|
322 |
Vertex u = Q.top();
|
williamr@2
|
323 |
Q.pop();
|
williamr@2
|
324 |
if (get(color, u) == Color::white()) {
|
williamr@2
|
325 |
depth_first_visit(G_T, u, vis, color);
|
williamr@2
|
326 |
++c_count;
|
williamr@2
|
327 |
}
|
williamr@2
|
328 |
}
|
williamr@2
|
329 |
return c_count;
|
williamr@2
|
330 |
}
|
williamr@2
|
331 |
|
williamr@2
|
332 |
} // namespace boost
|
williamr@2
|
333 |
|
williamr@2
|
334 |
#endif // BOOST_GRAPH_STRONG_COMPONENTS_HPP
|