1 //=======================================================================
2 // Copyright (C) 2005 Jong Soo Park <jongsoo.park -at- gmail.com>
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
12 #include <boost/config.hpp>
15 #include <boost/graph/depth_first_search.hpp>
20 * An extended time_stamper which also records vertices for each dfs number
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> >
28 typedef Tag event_filter;
29 time_stamper_with_vertex_vector(TimeMap timeMap, VertexVector& v,
31 : timeStamper_(timeMap, t), v_(v) { }
35 operator()(const typename property_traits<TimeMap>::key_type& v,
39 v_[timeStamper_.m_time] = v;
43 time_stamper<TimeMap, TimeT, Tag> timeStamper_;
48 * A convenient way to create a time_stamper_with_vertex_vector
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,
55 return time_stamper_with_vertex_vector<TimeMap, VertexVector, TimeT,
59 template<class Graph, class IndexMap, class TimeMap, class PredMap,
61 class dominator_visitor
63 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
64 typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType;
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)
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()),
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))),
89 domTreePredMap_(domTreePredMap),
90 samedomMap(make_iterator_property_map(samedom_.begin(),
91 get(vertex_index, g)))
96 operator()(const Vertex& n, const TimeMap& dfnumMap,
97 const PredMap& parentMap, const Graph& g)
99 if (n == entry_) return;
101 const VerticesSizeType numOfVertices = num_vertices(g);
102 const Vertex p(get(parentMap, n));
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.
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)
121 const Vertex v = source(*inItr, g);
122 // To deal with unreachable nodes
123 if (get(dfnumMap, v) < 0 || get(dfnumMap, v) >= numOfVertices)
127 if (get(dfnumMap, v) <= get(dfnumMap, n))
130 s2 = get(semiMap_, ancestor_with_lowest_semi_(v, dfnumMap));
132 if (get(dfnumMap, s2) < get(dfnumMap, s))
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;
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,
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();
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);
163 put(samedomMap, v, y);
166 get(bucketMap_, p).clear();
172 * Evaluate function in Tarjan's path compression
175 ancestor_with_lowest_semi_(const Vertex& v, const TimeMap& dfnumMap)
177 const Vertex a(get(ancestorMap_, v));
179 if (get(ancestorMap_, a) != graph_traits<Graph>::null_vertex())
181 const Vertex b(ancestor_with_lowest_semi_(a, dfnumMap));
183 put(ancestorMap_, v, get(ancestorMap_, a));
185 if (get(dfnumMap, get(semiMap_, b)) <
186 get(dfnumMap, get(semiMap_, get(bestMap_, v))))
190 return get(bestMap_, v);
193 std::vector<Vertex> semi_, ancestor_, samedom_, best_;
194 PredMap semiMap_, ancestorMap_, bestMap_;
195 std::vector< std::deque<Vertex> > buckets_;
197 iterator_property_map<typename std::vector<std::deque<Vertex> >::iterator,
198 IndexMap> bucketMap_;
200 const Vertex& entry_;
201 DomTreePredMap domTreePredMap_;
208 } // namespace detail
211 * @brief Build dominator tree using Lengauer-Tarjan algorithm.
212 * It takes O((V+E)log(V+E)) time.
214 * @pre dfnumMap, parentMap and verticesByDFNum have dfs results corresponding
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.
223 * @param domTreePredMap [out] : immediate dominator map (parent map
226 * @note reference Appel. p. 452~453. algorithm 19.9, 19.10.
228 * @todo : Optimization in Finding Dominators in Practice, Loukas Georgiadis
230 template<class Graph, class IndexMap, class TimeMap, class PredMap,
231 class VertexVector, class DomTreePredMap>
233 lengauer_tarjan_dominator_tree_without_dfs
235 const typename graph_traits<Graph>::vertex_descriptor& entry,
236 const IndexMap& indexMap,
237 TimeMap dfnumMap, PredMap parentMap, VertexVector& verticesByDFNum,
238 DomTreePredMap domTreePredMap)
240 // Typedefs and concept check
241 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
242 typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType;
244 function_requires< BidirectionalGraphConcept<Graph> >();
246 const VerticesSizeType numOfVertices = num_vertices(g);
247 if (numOfVertices == 0) return;
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);
254 for (i = 0; i < numOfVertices; ++i)
256 const Vertex u(verticesByDFNum[numOfVertices - 1 - i]);
257 if (u != graph_traits<Graph>::null_vertex())
258 visitor(u, dfnumMap, parentMap, g);
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)
265 const Vertex n(verticesByDFNum[i]);
267 if (n == entry || n == graph_traits<Graph>::null_vertex())
270 Vertex u = get(visitor.samedomMap, n);
271 if (u != graph_traits<Graph>::null_vertex())
273 put(domTreePredMap, n, get(domTreePredMap, u));
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.
283 * If the result of dfs required after this algorithm,
284 * this function can eliminate the need of rerunning dfs.
286 template<class Graph, class IndexMap, class TimeMap, class PredMap,
287 class VertexVector, class DomTreePredMap>
289 lengauer_tarjan_dominator_tree
291 const typename graph_traits<Graph>::vertex_descriptor& entry,
292 const IndexMap& indexMap,
293 TimeMap dfnumMap, PredMap parentMap, VertexVector& verticesByDFNum,
294 DomTreePredMap domTreePredMap)
296 // Typedefs and concept check
297 typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType;
299 function_requires< BidirectionalGraphConcept<Graph> >();
301 // 1. Depth first visit
302 const VerticesSizeType numOfVertices = num_vertices(g);
303 if (numOfVertices == 0) return;
305 VerticesSizeType time =
306 (std::numeric_limits<VerticesSizeType>::max)();
307 std::vector<default_color_type>
308 colors(numOfVertices, color_traits<default_color_type>::white());
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));
317 // 2. Run main algorithm.
318 lengauer_tarjan_dominator_tree_without_dfs(g, entry, indexMap, dfnumMap,
319 parentMap, verticesByDFNum,
324 * Use vertex_index as IndexMap and make dfnumMap, parentMap, verticesByDFNum
326 * If we don't need the result of dfs (dfnumMap, parentMap, verticesByDFNum),
327 * this function would be more convenient one.
329 template<class Graph, class DomTreePredMap>
331 lengauer_tarjan_dominator_tree
333 const typename graph_traits<Graph>::vertex_descriptor& entry,
334 DomTreePredMap domTreePredMap)
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;
341 iterator_property_map<typename std::vector<VerticesSizeType>::iterator,
344 iterator_property_map<typename std::vector<Vertex>::iterator, IndexMap>
347 // Make property maps
348 const VerticesSizeType numOfVertices = num_vertices(g);
349 if (numOfVertices == 0) return;
351 const IndexMap indexMap = get(vertex_index, g);
353 std::vector<VerticesSizeType> dfnum(numOfVertices, 0);
354 TimeMap dfnumMap(make_iterator_property_map(dfnum.begin(), indexMap));
356 std::vector<Vertex> parent(numOfVertices,
357 graph_traits<Graph>::null_vertex());
358 PredMap parentMap(make_iterator_property_map(parent.begin(), indexMap));
360 std::vector<Vertex> verticesByDFNum(parent);
362 // Run main algorithm
363 lengauer_tarjan_dominator_tree(g, entry,
364 indexMap, dfnumMap, parentMap,
365 verticesByDFNum, domTreePredMap);
369 * Muchnick. p. 182, 184
371 * using iterative bit vector analysis
373 template<class Graph, class IndexMap, class DomTreePredMap>
375 iterative_bit_vector_dominator_tree
377 const typename graph_traits<Graph>::vertex_descriptor& entry,
378 const IndexMap& indexMap,
379 DomTreePredMap domTreePredMap)
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;
385 iterator_property_map<typename std::vector< std::set<Vertex> >::iterator,
386 IndexMap> vertexSetMap;
388 function_requires<BidirectionalGraphConcept<Graph> >();
390 // 1. Finding dominator
392 const VerticesSizeType numOfVertices = num_vertices(g);
393 if (numOfVertices == 0) return;
396 tie(vi, viend) = vertices(g);
397 const std::set<Vertex> N(vi, viend);
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);
409 for (tie(vi, viend) = vertices(g); vi != viend; ++vi)
411 if (*vi == entry) continue;
413 std::set<Vertex> T(N);
415 typename graph_traits<Graph>::in_edge_iterator inItr, inEnd;
416 for (tie(inItr, inEnd) = in_edges(*vi, g); inItr != inEnd; ++inItr)
418 const Vertex p = source(*inItr, g);
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()));
429 if (T != get(domMap, *vi))
432 get(domMap, *vi).swap(T);
434 } // end of for (tie(vi, viend) = vertices(g)
435 } // end of while(change)
437 // 2. Build dominator tree
438 for (tie(vi, viend) = vertices(g); vi != viend; ++vi)
439 get(domMap, *vi).erase(*vi);
441 Graph domTree(numOfVertices);
443 for (tie(vi, viend) = vertices(g); vi != viend; ++vi)
445 if (*vi == entry) continue;
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)
452 typename std::set<Vertex>::iterator t;
453 for (t = get(domMap, *vi).begin(); t != get(domMap, *vi).end(); )
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);
464 for (tie(vi, viend) = vertices(g); vi != viend; ++vi)
466 if (*vi != entry && get(domMap, *vi).size() == 1)
468 Vertex temp = *get(domMap, *vi).begin();
469 put(domTreePredMap, *vi, temp);
474 template<class Graph, class DomTreePredMap>
476 iterative_bit_vector_dominator_tree
478 const typename graph_traits<Graph>::vertex_descriptor& entry,
479 DomTreePredMap domTreePredMap)
481 typename property_map<Graph, vertex_index_t>::const_type
482 indexMap = get(vertex_index, g);
484 iterative_bit_vector_dominator_tree(g, entry, indexMap, domTreePredMap);
488 #endif // BOOST_GRAPH_DOMINATOR_HPP