ossrv_pub/boost_apis/boost/graph/dominator_tree.hpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     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