epoc32/include/stdapis/boost/graph/dominator_tree.hpp
author William Roberts <williamr@symbian.org>
Wed, 31 Mar 2010 12:33:34 +0100 (2010-03-31)
branchSymbian3
changeset 4 837f303aceeb
permissions -rw-r--r--
Current Symbian^3 public API header files (from PDK 3.0.h)
This is the epoc32/include tree with the "platform" subtrees removed, and
all but a selected few mbg and rsg files removed.
     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