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