Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/graph/dominator_tree.hpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 17.3 KB
Line 
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
17namespace 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
Note: See TracBrowser for help on using the repository browser.