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