|
1 //======================================================================= |
|
2 // Copyright (C) 2005 Jong Soo Park <jongsoo.park -at- gmail.com> |
|
3 // |
|
4 // Distributed under the Boost Software License, Version 1.0. |
|
5 // (See accompanying file LICENSE_1_0.txt or copy at |
|
6 // http://www.boost.org/LICENSE_1_0.txt) |
|
7 //======================================================================= |
|
8 // Dominator tree computation |
|
9 #ifndef BOOST_GRAPH_DOMINATOR_HPP |
|
10 #define BOOST_GRAPH_DOMINATOR_HPP |
|
11 |
|
12 #include <boost/config.hpp> |
|
13 #include <deque> |
|
14 #include <set> |
|
15 #include <boost/graph/depth_first_search.hpp> |
|
16 |
|
17 namespace boost { |
|
18 namespace detail { |
|
19 /** |
|
20 * An extended time_stamper which also records vertices for each dfs number |
|
21 */ |
|
22 template<class TimeMap, class VertexVector, class TimeT, class Tag> |
|
23 class time_stamper_with_vertex_vector |
|
24 : public base_visitor< |
|
25 time_stamper_with_vertex_vector<TimeMap, VertexVector, TimeT, Tag> > |
|
26 { |
|
27 public : |
|
28 typedef Tag event_filter; |
|
29 time_stamper_with_vertex_vector(TimeMap timeMap, VertexVector& v, |
|
30 TimeT& t) |
|
31 : timeStamper_(timeMap, t), v_(v) { } |
|
32 |
|
33 template<class Graph> |
|
34 void |
|
35 operator()(const typename property_traits<TimeMap>::key_type& v, |
|
36 const Graph& g) |
|
37 { |
|
38 timeStamper_(v, g); |
|
39 v_[timeStamper_.m_time] = v; |
|
40 } |
|
41 |
|
42 private : |
|
43 time_stamper<TimeMap, TimeT, Tag> timeStamper_; |
|
44 VertexVector& v_; |
|
45 }; |
|
46 |
|
47 /** |
|
48 * A convenient way to create a time_stamper_with_vertex_vector |
|
49 */ |
|
50 template<class TimeMap, class VertexVector, class TimeT, class Tag> |
|
51 time_stamper_with_vertex_vector<TimeMap, VertexVector, TimeT, Tag> |
|
52 stamp_times_with_vertex_vector(TimeMap timeMap, VertexVector& v, TimeT& t, |
|
53 Tag) |
|
54 { |
|
55 return time_stamper_with_vertex_vector<TimeMap, VertexVector, TimeT, |
|
56 Tag>(timeMap, v, t); |
|
57 } |
|
58 |
|
59 template<class Graph, class IndexMap, class TimeMap, class PredMap, |
|
60 class DomTreePredMap> |
|
61 class dominator_visitor |
|
62 { |
|
63 typedef typename graph_traits<Graph>::vertex_descriptor Vertex; |
|
64 typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType; |
|
65 |
|
66 public : |
|
67 /** |
|
68 * @param g [in] the target graph of the dominator tree |
|
69 * @param entry [in] the entry node of g |
|
70 * @param domTreePredMap [out] the immediate dominator map |
|
71 * (parent map in dominator tree) |
|
72 */ |
|
73 dominator_visitor(const Graph& g, const Vertex& entry, |
|
74 DomTreePredMap domTreePredMap) |
|
75 : semi_(num_vertices(g)), |
|
76 ancestor_(num_vertices(g), graph_traits<Graph>::null_vertex()), |
|
77 samedom_(ancestor_), |
|
78 best_(semi_), |
|
79 semiMap_(make_iterator_property_map(semi_.begin(), |
|
80 get(vertex_index, g))), |
|
81 ancestorMap_(make_iterator_property_map(ancestor_.begin(), |
|
82 get(vertex_index, g))), |
|
83 bestMap_(make_iterator_property_map(best_.begin(), |
|
84 get(vertex_index, g))), |
|
85 buckets_(num_vertices(g)), |
|
86 bucketMap_(make_iterator_property_map(buckets_.begin(), |
|
87 get(vertex_index, g))), |
|
88 entry_(entry), |
|
89 domTreePredMap_(domTreePredMap), |
|
90 samedomMap(make_iterator_property_map(samedom_.begin(), |
|
91 get(vertex_index, g))) |
|
92 { |
|
93 } |
|
94 |
|
95 void |
|
96 operator()(const Vertex& n, const TimeMap& dfnumMap, |
|
97 const PredMap& parentMap, const Graph& g) |
|
98 { |
|
99 if (n == entry_) return; |
|
100 |
|
101 const VerticesSizeType numOfVertices = num_vertices(g); |
|
102 const Vertex p(get(parentMap, n)); |
|
103 Vertex s(p); |
|
104 |
|
105 // 1. Calculate the semidominator of n, |
|
106 // based on the semidominator thm. |
|
107 // * Semidominator thm. : To find the semidominator of a node n, |
|
108 // consider all predecessors v of n in the CFG (Control Flow Graph). |
|
109 // - If v is a proper ancestor of n in the spanning tree |
|
110 // (so dfnum(v) < dfnum(n)), then v is a candidate for semi(n) |
|
111 // - If v is a non-ancestor of n (so dfnum(v) > dfnum(n)) |
|
112 // then for each u that is an ancestor of v (or u = v), |
|
113 // Let semi(u) be a candidate for semi(n) |
|
114 // of all these candidates, the one with lowest dfnum is |
|
115 // the semidominator of n. |
|
116 |
|
117 // For each predecessor of n |
|
118 typename graph_traits<Graph>::in_edge_iterator inItr, inEnd; |
|
119 for (tie(inItr, inEnd) = in_edges(n, g); inItr != inEnd; ++inItr) |
|
120 { |
|
121 const Vertex v = source(*inItr, g); |
|
122 // To deal with unreachable nodes |
|
123 if (get(dfnumMap, v) < 0 || get(dfnumMap, v) >= numOfVertices) |
|
124 continue; |
|
125 |
|
126 Vertex s2; |
|
127 if (get(dfnumMap, v) <= get(dfnumMap, n)) |
|
128 s2 = v; |
|
129 else |
|
130 s2 = get(semiMap_, ancestor_with_lowest_semi_(v, dfnumMap)); |
|
131 |
|
132 if (get(dfnumMap, s2) < get(dfnumMap, s)) |
|
133 s = s2; |
|
134 } |
|
135 put(semiMap_, n, s); |
|
136 |
|
137 // 2. Calculation of n's dominator is deferred until |
|
138 // the path from s to n has been linked into the forest |
|
139 get(bucketMap_, s).push_back(n); |
|
140 get(ancestorMap_, n) = p; |
|
141 get(bestMap_, n) = n; |
|
142 |
|
143 // 3. Now that the path from p to v has been linked into |
|
144 // the spanning forest, these lines calculate the dominator of v, |
|
145 // based on the dominator thm., or else defer the calculation |
|
146 // until y's dominator is known |
|
147 // * Dominator thm. : On the spanning-tree path below semi(n) and |
|
148 // above or including n, let y be the node |
|
149 // with the smallest-numbered semidominator. Then, |
|
150 // |
|
151 // idom(n) = semi(n) if semi(y)=semi(n) or |
|
152 // idom(y) if semi(y) != semi(n) |
|
153 typename std::deque<Vertex>::iterator buckItr; |
|
154 for (buckItr = get(bucketMap_, p).begin(); |
|
155 buckItr != get(bucketMap_, p).end(); |
|
156 ++buckItr) |
|
157 { |
|
158 const Vertex v(*buckItr); |
|
159 const Vertex y(ancestor_with_lowest_semi_(v, dfnumMap)); |
|
160 if (get(semiMap_, y) == get(semiMap_, v)) |
|
161 put(domTreePredMap_, v, p); |
|
162 else |
|
163 put(samedomMap, v, y); |
|
164 } |
|
165 |
|
166 get(bucketMap_, p).clear(); |
|
167 } |
|
168 |
|
169 protected : |
|
170 |
|
171 /** |
|
172 * Evaluate function in Tarjan's path compression |
|
173 */ |
|
174 const Vertex |
|
175 ancestor_with_lowest_semi_(const Vertex& v, const TimeMap& dfnumMap) |
|
176 { |
|
177 const Vertex a(get(ancestorMap_, v)); |
|
178 |
|
179 if (get(ancestorMap_, a) != graph_traits<Graph>::null_vertex()) |
|
180 { |
|
181 const Vertex b(ancestor_with_lowest_semi_(a, dfnumMap)); |
|
182 |
|
183 put(ancestorMap_, v, get(ancestorMap_, a)); |
|
184 |
|
185 if (get(dfnumMap, get(semiMap_, b)) < |
|
186 get(dfnumMap, get(semiMap_, get(bestMap_, v)))) |
|
187 put(bestMap_, v, b); |
|
188 } |
|
189 |
|
190 return get(bestMap_, v); |
|
191 } |
|
192 |
|
193 std::vector<Vertex> semi_, ancestor_, samedom_, best_; |
|
194 PredMap semiMap_, ancestorMap_, bestMap_; |
|
195 std::vector< std::deque<Vertex> > buckets_; |
|
196 |
|
197 iterator_property_map<typename std::vector<std::deque<Vertex> >::iterator, |
|
198 IndexMap> bucketMap_; |
|
199 |
|
200 const Vertex& entry_; |
|
201 DomTreePredMap domTreePredMap_; |
|
202 |
|
203 public : |
|
204 |
|
205 PredMap samedomMap; |
|
206 }; |
|
207 |
|
208 } // namespace detail |
|
209 |
|
210 /** |
|
211 * @brief Build dominator tree using Lengauer-Tarjan algorithm. |
|
212 * It takes O((V+E)log(V+E)) time. |
|
213 * |
|
214 * @pre dfnumMap, parentMap and verticesByDFNum have dfs results corresponding |
|
215 * indexMap. |
|
216 * If dfs has already run before, |
|
217 * this function would be good for saving computations. |
|
218 * @pre Unreachable nodes must be masked as |
|
219 * graph_traits<Graph>::null_vertex in parentMap. |
|
220 * @pre Unreachable nodes must be masked as |
|
221 * (std::numeric_limits<VerticesSizeType>::max)() in dfnumMap. |
|
222 * |
|
223 * @param domTreePredMap [out] : immediate dominator map (parent map |
|
224 * in dom. tree) |
|
225 * |
|
226 * @note reference Appel. p. 452~453. algorithm 19.9, 19.10. |
|
227 * |
|
228 * @todo : Optimization in Finding Dominators in Practice, Loukas Georgiadis |
|
229 */ |
|
230 template<class Graph, class IndexMap, class TimeMap, class PredMap, |
|
231 class VertexVector, class DomTreePredMap> |
|
232 void |
|
233 lengauer_tarjan_dominator_tree_without_dfs |
|
234 (const Graph& g, |
|
235 const typename graph_traits<Graph>::vertex_descriptor& entry, |
|
236 const IndexMap& indexMap, |
|
237 TimeMap dfnumMap, PredMap parentMap, VertexVector& verticesByDFNum, |
|
238 DomTreePredMap domTreePredMap) |
|
239 { |
|
240 // Typedefs and concept check |
|
241 typedef typename graph_traits<Graph>::vertex_descriptor Vertex; |
|
242 typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType; |
|
243 |
|
244 function_requires< BidirectionalGraphConcept<Graph> >(); |
|
245 |
|
246 const VerticesSizeType numOfVertices = num_vertices(g); |
|
247 if (numOfVertices == 0) return; |
|
248 |
|
249 // 1. Visit each vertex in reverse post order and calculate sdom. |
|
250 detail::dominator_visitor<Graph, IndexMap, TimeMap, PredMap, DomTreePredMap> |
|
251 visitor(g, entry, domTreePredMap); |
|
252 |
|
253 VerticesSizeType i; |
|
254 for (i = 0; i < numOfVertices; ++i) |
|
255 { |
|
256 const Vertex u(verticesByDFNum[numOfVertices - 1 - i]); |
|
257 if (u != graph_traits<Graph>::null_vertex()) |
|
258 visitor(u, dfnumMap, parentMap, g); |
|
259 } |
|
260 |
|
261 // 2. Now all the deferred dominator calculations, |
|
262 // based on the second clause of the dominator thm., are performed |
|
263 for (i = 0; i < numOfVertices; ++i) |
|
264 { |
|
265 const Vertex n(verticesByDFNum[i]); |
|
266 |
|
267 if (n == entry || n == graph_traits<Graph>::null_vertex()) |
|
268 continue; |
|
269 |
|
270 Vertex u = get(visitor.samedomMap, n); |
|
271 if (u != graph_traits<Graph>::null_vertex()) |
|
272 { |
|
273 put(domTreePredMap, n, get(domTreePredMap, u)); |
|
274 } |
|
275 } |
|
276 } |
|
277 |
|
278 /** |
|
279 * Unlike lengauer_tarjan_dominator_tree_without_dfs, |
|
280 * dfs is run in this function and |
|
281 * the result is written to dfnumMap, parentMap, vertices. |
|
282 * |
|
283 * If the result of dfs required after this algorithm, |
|
284 * this function can eliminate the need of rerunning dfs. |
|
285 */ |
|
286 template<class Graph, class IndexMap, class TimeMap, class PredMap, |
|
287 class VertexVector, class DomTreePredMap> |
|
288 void |
|
289 lengauer_tarjan_dominator_tree |
|
290 (const Graph& g, |
|
291 const typename graph_traits<Graph>::vertex_descriptor& entry, |
|
292 const IndexMap& indexMap, |
|
293 TimeMap dfnumMap, PredMap parentMap, VertexVector& verticesByDFNum, |
|
294 DomTreePredMap domTreePredMap) |
|
295 { |
|
296 // Typedefs and concept check |
|
297 typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType; |
|
298 |
|
299 function_requires< BidirectionalGraphConcept<Graph> >(); |
|
300 |
|
301 // 1. Depth first visit |
|
302 const VerticesSizeType numOfVertices = num_vertices(g); |
|
303 if (numOfVertices == 0) return; |
|
304 |
|
305 VerticesSizeType time = |
|
306 (std::numeric_limits<VerticesSizeType>::max)(); |
|
307 std::vector<default_color_type> |
|
308 colors(numOfVertices, color_traits<default_color_type>::white()); |
|
309 depth_first_visit |
|
310 (g, entry, |
|
311 make_dfs_visitor |
|
312 (make_pair(record_predecessors(parentMap, on_tree_edge()), |
|
313 detail::stamp_times_with_vertex_vector |
|
314 (dfnumMap, verticesByDFNum, time, on_discover_vertex()))), |
|
315 make_iterator_property_map(colors.begin(), indexMap)); |
|
316 |
|
317 // 2. Run main algorithm. |
|
318 lengauer_tarjan_dominator_tree_without_dfs(g, entry, indexMap, dfnumMap, |
|
319 parentMap, verticesByDFNum, |
|
320 domTreePredMap); |
|
321 } |
|
322 |
|
323 /** |
|
324 * Use vertex_index as IndexMap and make dfnumMap, parentMap, verticesByDFNum |
|
325 * internally. |
|
326 * If we don't need the result of dfs (dfnumMap, parentMap, verticesByDFNum), |
|
327 * this function would be more convenient one. |
|
328 */ |
|
329 template<class Graph, class DomTreePredMap> |
|
330 void |
|
331 lengauer_tarjan_dominator_tree |
|
332 (const Graph& g, |
|
333 const typename graph_traits<Graph>::vertex_descriptor& entry, |
|
334 DomTreePredMap domTreePredMap) |
|
335 { |
|
336 // typedefs |
|
337 typedef typename graph_traits<Graph>::vertex_descriptor Vertex; |
|
338 typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType; |
|
339 typedef typename property_map<Graph, vertex_index_t>::const_type IndexMap; |
|
340 typedef |
|
341 iterator_property_map<typename std::vector<VerticesSizeType>::iterator, |
|
342 IndexMap> TimeMap; |
|
343 typedef |
|
344 iterator_property_map<typename std::vector<Vertex>::iterator, IndexMap> |
|
345 PredMap; |
|
346 |
|
347 // Make property maps |
|
348 const VerticesSizeType numOfVertices = num_vertices(g); |
|
349 if (numOfVertices == 0) return; |
|
350 |
|
351 const IndexMap indexMap = get(vertex_index, g); |
|
352 |
|
353 std::vector<VerticesSizeType> dfnum(numOfVertices, 0); |
|
354 TimeMap dfnumMap(make_iterator_property_map(dfnum.begin(), indexMap)); |
|
355 |
|
356 std::vector<Vertex> parent(numOfVertices, |
|
357 graph_traits<Graph>::null_vertex()); |
|
358 PredMap parentMap(make_iterator_property_map(parent.begin(), indexMap)); |
|
359 |
|
360 std::vector<Vertex> verticesByDFNum(parent); |
|
361 |
|
362 // Run main algorithm |
|
363 lengauer_tarjan_dominator_tree(g, entry, |
|
364 indexMap, dfnumMap, parentMap, |
|
365 verticesByDFNum, domTreePredMap); |
|
366 } |
|
367 |
|
368 /** |
|
369 * Muchnick. p. 182, 184 |
|
370 * |
|
371 * using iterative bit vector analysis |
|
372 */ |
|
373 template<class Graph, class IndexMap, class DomTreePredMap> |
|
374 void |
|
375 iterative_bit_vector_dominator_tree |
|
376 (const Graph& g, |
|
377 const typename graph_traits<Graph>::vertex_descriptor& entry, |
|
378 const IndexMap& indexMap, |
|
379 DomTreePredMap domTreePredMap) |
|
380 { |
|
381 typedef typename graph_traits<Graph>::vertex_descriptor Vertex; |
|
382 typedef typename graph_traits<Graph>::vertex_iterator vertexItr; |
|
383 typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType; |
|
384 typedef |
|
385 iterator_property_map<typename std::vector< std::set<Vertex> >::iterator, |
|
386 IndexMap> vertexSetMap; |
|
387 |
|
388 function_requires<BidirectionalGraphConcept<Graph> >(); |
|
389 |
|
390 // 1. Finding dominator |
|
391 // 1.1. Initialize |
|
392 const VerticesSizeType numOfVertices = num_vertices(g); |
|
393 if (numOfVertices == 0) return; |
|
394 |
|
395 vertexItr vi, viend; |
|
396 tie(vi, viend) = vertices(g); |
|
397 const std::set<Vertex> N(vi, viend); |
|
398 |
|
399 bool change = true; |
|
400 |
|
401 std::vector< std::set<Vertex> > dom(numOfVertices, N); |
|
402 vertexSetMap domMap(make_iterator_property_map(dom.begin(), indexMap)); |
|
403 get(domMap, entry).clear(); |
|
404 get(domMap, entry).insert(entry); |
|
405 |
|
406 while (change) |
|
407 { |
|
408 change = false; |
|
409 for (tie(vi, viend) = vertices(g); vi != viend; ++vi) |
|
410 { |
|
411 if (*vi == entry) continue; |
|
412 |
|
413 std::set<Vertex> T(N); |
|
414 |
|
415 typename graph_traits<Graph>::in_edge_iterator inItr, inEnd; |
|
416 for (tie(inItr, inEnd) = in_edges(*vi, g); inItr != inEnd; ++inItr) |
|
417 { |
|
418 const Vertex p = source(*inItr, g); |
|
419 |
|
420 std::set<Vertex> tempSet; |
|
421 std::set_intersection(T.begin(), T.end(), |
|
422 get(domMap, p).begin(), |
|
423 get(domMap, p).end(), |
|
424 std::inserter(tempSet, tempSet.begin())); |
|
425 T.swap(tempSet); |
|
426 } |
|
427 |
|
428 T.insert(*vi); |
|
429 if (T != get(domMap, *vi)) |
|
430 { |
|
431 change = true; |
|
432 get(domMap, *vi).swap(T); |
|
433 } |
|
434 } // end of for (tie(vi, viend) = vertices(g) |
|
435 } // end of while(change) |
|
436 |
|
437 // 2. Build dominator tree |
|
438 for (tie(vi, viend) = vertices(g); vi != viend; ++vi) |
|
439 get(domMap, *vi).erase(*vi); |
|
440 |
|
441 Graph domTree(numOfVertices); |
|
442 |
|
443 for (tie(vi, viend) = vertices(g); vi != viend; ++vi) |
|
444 { |
|
445 if (*vi == entry) continue; |
|
446 |
|
447 // We have to iterate through copied dominator set |
|
448 const std::set<Vertex> tempSet(get(domMap, *vi)); |
|
449 typename std::set<Vertex>::const_iterator s; |
|
450 for (s = tempSet.begin(); s != tempSet.end(); ++s) |
|
451 { |
|
452 typename std::set<Vertex>::iterator t; |
|
453 for (t = get(domMap, *vi).begin(); t != get(domMap, *vi).end(); ) |
|
454 { |
|
455 typename std::set<Vertex>::iterator old_t = t; |
|
456 ++t; // Done early because t may become invalid |
|
457 if (*old_t == *s) continue; |
|
458 if (get(domMap, *s).find(*old_t) != get(domMap, *s).end()) |
|
459 get(domMap, *vi).erase(old_t); |
|
460 } |
|
461 } |
|
462 } |
|
463 |
|
464 for (tie(vi, viend) = vertices(g); vi != viend; ++vi) |
|
465 { |
|
466 if (*vi != entry && get(domMap, *vi).size() == 1) |
|
467 { |
|
468 Vertex temp = *get(domMap, *vi).begin(); |
|
469 put(domTreePredMap, *vi, temp); |
|
470 } |
|
471 } |
|
472 } |
|
473 |
|
474 template<class Graph, class DomTreePredMap> |
|
475 void |
|
476 iterative_bit_vector_dominator_tree |
|
477 (const Graph& g, |
|
478 const typename graph_traits<Graph>::vertex_descriptor& entry, |
|
479 DomTreePredMap domTreePredMap) |
|
480 { |
|
481 typename property_map<Graph, vertex_index_t>::const_type |
|
482 indexMap = get(vertex_index, g); |
|
483 |
|
484 iterative_bit_vector_dominator_tree(g, entry, indexMap, domTreePredMap); |
|
485 } |
|
486 } // namespace boost |
|
487 |
|
488 #endif // BOOST_GRAPH_DOMINATOR_HPP |