Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:26

0001 //=======================================================================
0002 // Copyright (C) 2005-2009 Jongsoo Park <jongsoo.park -at- gmail.com>
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt)
0007 //=======================================================================
0008 
0009 #ifndef BOOST_GRAPH_DOMINATOR_HPP
0010 #define BOOST_GRAPH_DOMINATOR_HPP
0011 
0012 #include <boost/config.hpp>
0013 #include <deque>
0014 #include <set>
0015 #include <boost/graph/depth_first_search.hpp>
0016 #include <boost/concept/assert.hpp>
0017 
0018 // Dominator tree computation
0019 
0020 namespace boost
0021 {
0022 namespace detail
0023 {
0024     /**
0025      * An extended time_stamper which also records vertices for each dfs number
0026      */
0027     template < class TimeMap, class VertexVector, class TimeT, class Tag >
0028     class time_stamper_with_vertex_vector
0029     : public base_visitor<
0030           time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT, Tag > >
0031     {
0032     public:
0033         typedef Tag event_filter;
0034         time_stamper_with_vertex_vector(
0035             TimeMap timeMap, VertexVector& v, TimeT& t)
0036         : timeStamper_(timeMap, t), v_(v)
0037         {
0038         }
0039 
0040         template < class Graph >
0041         void operator()(const typename property_traits< TimeMap >::key_type& v,
0042             const Graph& g)
0043         {
0044             timeStamper_(v, g);
0045             v_[timeStamper_.m_time] = v;
0046         }
0047 
0048     private:
0049         time_stamper< TimeMap, TimeT, Tag > timeStamper_;
0050         VertexVector& v_;
0051     };
0052 
0053     /**
0054      * A convenient way to create a time_stamper_with_vertex_vector
0055      */
0056     template < class TimeMap, class VertexVector, class TimeT, class Tag >
0057     time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT, Tag >
0058     stamp_times_with_vertex_vector(
0059         TimeMap timeMap, VertexVector& v, TimeT& t, Tag)
0060     {
0061         return time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT,
0062             Tag >(timeMap, v, t);
0063     }
0064 
0065     template < class Graph, class IndexMap, class TimeMap, class PredMap,
0066         class DomTreePredMap >
0067     class dominator_visitor
0068     {
0069         typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
0070         typedef
0071             typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
0072 
0073     public:
0074         /**
0075          * @param g [in] the target graph of the dominator tree
0076          * @param entry [in] the entry node of g
0077          * @param indexMap [in] the vertex index map for g
0078          * @param domTreePredMap [out] the immediate dominator map
0079          *                             (parent map in dominator tree)
0080          */
0081         dominator_visitor(const Graph& g, const Vertex& entry,
0082             const IndexMap& indexMap, DomTreePredMap domTreePredMap)
0083         : semi_(num_vertices(g))
0084         , ancestor_(num_vertices(g), graph_traits< Graph >::null_vertex())
0085         , samedom_(ancestor_)
0086         , best_(semi_)
0087         , semiMap_(make_iterator_property_map(semi_.begin(), indexMap))
0088         , ancestorMap_(make_iterator_property_map(ancestor_.begin(), indexMap))
0089         , bestMap_(make_iterator_property_map(best_.begin(), indexMap))
0090         , buckets_(num_vertices(g))
0091         , bucketMap_(make_iterator_property_map(buckets_.begin(), indexMap))
0092         , entry_(entry)
0093         , domTreePredMap_(domTreePredMap)
0094         , numOfVertices_(num_vertices(g))
0095         , samedomMap(make_iterator_property_map(samedom_.begin(), indexMap))
0096         {
0097         }
0098 
0099         void operator()(const Vertex& n, const TimeMap& dfnumMap,
0100             const PredMap& parentMap, const Graph& g)
0101         {
0102             if (n == entry_)
0103                 return;
0104 
0105             const Vertex p(get(parentMap, n));
0106             Vertex s(p);
0107 
0108             // 1. Calculate the semidominator of n,
0109             // based on the semidominator thm.
0110             // * Semidominator thm. : To find the semidominator of a node n,
0111             //   consider all predecessors v of n in the CFG (Control Flow
0112             //   Graph).
0113             //  - If v is a proper ancestor of n in the spanning tree
0114             //    (so dfnum(v) < dfnum(n)), then v is a candidate for semi(n)
0115             //  - If v is a non-ancestor of n (so dfnum(v) > dfnum(n))
0116             //    then for each u that is an ancestor of v (or u = v),
0117             //    Let semi(u) be a candidate for semi(n)
0118             //   of all these candidates, the one with lowest dfnum is
0119             //   the semidominator of n.
0120 
0121             // For each predecessor of n
0122             typename graph_traits< Graph >::in_edge_iterator inItr, inEnd;
0123             for (boost::tie(inItr, inEnd) = in_edges(n, g); inItr != inEnd;
0124                  ++inItr)
0125             {
0126                 const Vertex v = source(*inItr, g);
0127                 // To deal with unreachable nodes
0128                 if (get(dfnumMap, v) < 0 || get(dfnumMap, v) >= numOfVertices_)
0129                     continue;
0130 
0131                 Vertex s2;
0132                 if (get(dfnumMap, v) <= get(dfnumMap, n))
0133                     s2 = v;
0134                 else
0135                     s2 = get(semiMap_, ancestor_with_lowest_semi_(v, dfnumMap));
0136 
0137                 if (get(dfnumMap, s2) < get(dfnumMap, s))
0138                     s = s2;
0139             }
0140             put(semiMap_, n, s);
0141 
0142             // 2. Calculation of n's dominator is deferred until
0143             // the path from s to n has been linked into the forest
0144             get(bucketMap_, s).push_back(n);
0145             get(ancestorMap_, n) = p;
0146             get(bestMap_, n) = n;
0147 
0148             // 3. Now that the path from p to v has been linked into
0149             // the spanning forest, these lines calculate the dominator of v,
0150             // based on the dominator thm., or else defer the calculation
0151             // until y's dominator is known
0152             // * Dominator thm. : On the spanning-tree path below semi(n) and
0153             //   above or including n, let y be the node
0154             //   with the smallest-numbered semidominator. Then,
0155             //
0156             //  idom(n) = semi(n) if semi(y)=semi(n) or
0157             //            idom(y) if semi(y) != semi(n)
0158             typename std::deque< Vertex >::iterator buckItr;
0159             for (buckItr = get(bucketMap_, p).begin();
0160                  buckItr != get(bucketMap_, p).end(); ++buckItr)
0161             {
0162                 const Vertex v(*buckItr);
0163                 const Vertex y(ancestor_with_lowest_semi_(v, dfnumMap));
0164                 if (get(semiMap_, y) == get(semiMap_, v))
0165                     put(domTreePredMap_, v, p);
0166                 else
0167                     put(samedomMap, v, y);
0168             }
0169 
0170             get(bucketMap_, p).clear();
0171         }
0172 
0173     protected:
0174         /**
0175          * Evaluate function in Tarjan's path compression
0176          */
0177         const Vertex ancestor_with_lowest_semi_(
0178             const Vertex& v, const TimeMap& dfnumMap)
0179         {
0180             const Vertex a(get(ancestorMap_, v));
0181 
0182             if (get(ancestorMap_, a) != graph_traits< Graph >::null_vertex())
0183             {
0184                 const Vertex b(ancestor_with_lowest_semi_(a, dfnumMap));
0185 
0186                 put(ancestorMap_, v, get(ancestorMap_, a));
0187 
0188                 if (get(dfnumMap, get(semiMap_, b))
0189                     < get(dfnumMap, get(semiMap_, get(bestMap_, v))))
0190                     put(bestMap_, v, b);
0191             }
0192 
0193             return get(bestMap_, v);
0194         }
0195 
0196         std::vector< Vertex > semi_, ancestor_, samedom_, best_;
0197         PredMap semiMap_, ancestorMap_, bestMap_;
0198         std::vector< std::deque< Vertex > > buckets_;
0199 
0200         iterator_property_map<
0201             typename std::vector< std::deque< Vertex > >::iterator, IndexMap >
0202             bucketMap_;
0203 
0204         const Vertex& entry_;
0205         DomTreePredMap domTreePredMap_;
0206         const VerticesSizeType numOfVertices_;
0207 
0208     public:
0209         PredMap samedomMap;
0210     };
0211 
0212 } // namespace detail
0213 
0214 /**
0215  * @brief Build dominator tree using Lengauer-Tarjan algorithm.
0216  *                It takes O((V+E)log(V+E)) time.
0217  *
0218  * @pre dfnumMap, parentMap and verticesByDFNum have dfs results corresponding
0219  *      indexMap.
0220  *      If dfs has already run before,
0221  *      this function would be good for saving computations.
0222  * @pre Unreachable nodes must be masked as
0223  *      graph_traits<Graph>::null_vertex in parentMap.
0224  * @pre Unreachable nodes must be masked as
0225  *      (std::numeric_limits<VerticesSizeType>::max)() in dfnumMap.
0226  *
0227  * @param domTreePredMap [out] : immediate dominator map (parent map
0228  * in dom. tree)
0229  *
0230  * @note reference Appel. p. 452~453. algorithm 19.9, 19.10.
0231  *
0232  * @todo : Optimization in Finding Dominators in Practice, Loukas Georgiadis
0233  */
0234 template < class Graph, class IndexMap, class TimeMap, class PredMap,
0235     class VertexVector, class DomTreePredMap >
0236 void lengauer_tarjan_dominator_tree_without_dfs(const Graph& g,
0237     const typename graph_traits< Graph >::vertex_descriptor& entry,
0238     const IndexMap& indexMap, TimeMap dfnumMap, PredMap parentMap,
0239     VertexVector& verticesByDFNum, DomTreePredMap domTreePredMap)
0240 {
0241     // Typedefs and concept check
0242     typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
0243     typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
0244 
0245     BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >));
0246 
0247     const VerticesSizeType numOfVertices = num_vertices(g);
0248     if (numOfVertices == 0)
0249         return;
0250 
0251     // 1. Visit each vertex in reverse post order and calculate sdom.
0252     detail::dominator_visitor< Graph, IndexMap, TimeMap, PredMap,
0253         DomTreePredMap >
0254         visitor(g, entry, indexMap, domTreePredMap);
0255 
0256     VerticesSizeType i;
0257     for (i = 0; i < numOfVertices; ++i)
0258     {
0259         const Vertex u(verticesByDFNum[numOfVertices - 1 - i]);
0260         if (u != graph_traits< Graph >::null_vertex())
0261             visitor(u, dfnumMap, parentMap, g);
0262     }
0263 
0264     // 2. Now all the deferred dominator calculations,
0265     // based on the second clause of the dominator thm., are performed
0266     for (i = 0; i < numOfVertices; ++i)
0267     {
0268         const Vertex n(verticesByDFNum[i]);
0269 
0270         if (n == entry || n == graph_traits< Graph >::null_vertex())
0271             continue;
0272 
0273         Vertex u = get(visitor.samedomMap, n);
0274         if (u != graph_traits< Graph >::null_vertex())
0275         {
0276             put(domTreePredMap, n, get(domTreePredMap, u));
0277         }
0278     }
0279 }
0280 
0281 /**
0282  * Unlike lengauer_tarjan_dominator_tree_without_dfs,
0283  * dfs is run in this function and
0284  * the result is written to dfnumMap, parentMap, vertices.
0285  *
0286  * If the result of dfs required after this algorithm,
0287  * this function can eliminate the need of rerunning dfs.
0288  */
0289 template < class Graph, class IndexMap, class TimeMap, class PredMap,
0290     class VertexVector, class DomTreePredMap >
0291 void lengauer_tarjan_dominator_tree(const Graph& g,
0292     const typename graph_traits< Graph >::vertex_descriptor& entry,
0293     const IndexMap& indexMap, TimeMap dfnumMap, PredMap parentMap,
0294     VertexVector& verticesByDFNum, DomTreePredMap domTreePredMap)
0295 {
0296     // Typedefs and concept check
0297     typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
0298 
0299     BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >));
0300 
0301     // 1. Depth first visit
0302     const VerticesSizeType numOfVertices = num_vertices(g);
0303     if (numOfVertices == 0)
0304         return;
0305 
0306     VerticesSizeType time = (std::numeric_limits< VerticesSizeType >::max)();
0307     std::vector< default_color_type > colors(
0308         numOfVertices, color_traits< default_color_type >::white());
0309     depth_first_visit(g, entry,
0310         make_dfs_visitor(
0311             make_pair(record_predecessors(parentMap, on_tree_edge()),
0312                 detail::stamp_times_with_vertex_vector(
0313                     dfnumMap, verticesByDFNum, time, on_discover_vertex()))),
0314         make_iterator_property_map(colors.begin(), indexMap));
0315 
0316     // 2. Run main algorithm.
0317     lengauer_tarjan_dominator_tree_without_dfs(g, entry, indexMap, dfnumMap,
0318         parentMap, verticesByDFNum, domTreePredMap);
0319 }
0320 
0321 /**
0322  * Use vertex_index as IndexMap and make dfnumMap, parentMap, verticesByDFNum
0323  * internally.
0324  * If we don't need the result of dfs (dfnumMap, parentMap, verticesByDFNum),
0325  * this function would be more convenient one.
0326  */
0327 template < class Graph, class DomTreePredMap >
0328 void lengauer_tarjan_dominator_tree(const Graph& g,
0329     const typename graph_traits< Graph >::vertex_descriptor& entry,
0330     DomTreePredMap domTreePredMap)
0331 {
0332     // typedefs
0333     typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
0334     typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
0335     typedef typename property_map< Graph, vertex_index_t >::const_type IndexMap;
0336     typedef iterator_property_map<
0337         typename std::vector< VerticesSizeType >::iterator, IndexMap >
0338         TimeMap;
0339     typedef iterator_property_map< typename std::vector< Vertex >::iterator,
0340         IndexMap >
0341         PredMap;
0342 
0343     // Make property maps
0344     const VerticesSizeType numOfVertices = num_vertices(g);
0345     if (numOfVertices == 0)
0346         return;
0347 
0348     const IndexMap indexMap = get(vertex_index, g);
0349 
0350     std::vector< VerticesSizeType > dfnum(numOfVertices, 0);
0351     TimeMap dfnumMap(make_iterator_property_map(dfnum.begin(), indexMap));
0352 
0353     std::vector< Vertex > parent(
0354         numOfVertices, graph_traits< Graph >::null_vertex());
0355     PredMap parentMap(make_iterator_property_map(parent.begin(), indexMap));
0356 
0357     std::vector< Vertex > verticesByDFNum(parent);
0358 
0359     // Run main algorithm
0360     lengauer_tarjan_dominator_tree(g, entry, indexMap, dfnumMap, parentMap,
0361         verticesByDFNum, domTreePredMap);
0362 }
0363 
0364 /**
0365  * Muchnick. p. 182, 184
0366  *
0367  * using iterative bit vector analysis
0368  */
0369 template < class Graph, class IndexMap, class DomTreePredMap >
0370 void iterative_bit_vector_dominator_tree(const Graph& g,
0371     const typename graph_traits< Graph >::vertex_descriptor& entry,
0372     const IndexMap& indexMap, DomTreePredMap domTreePredMap)
0373 {
0374     typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
0375     typedef typename graph_traits< Graph >::vertex_iterator vertexItr;
0376     typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
0377     typedef iterator_property_map<
0378         typename std::vector< std::set< Vertex > >::iterator, IndexMap >
0379         vertexSetMap;
0380 
0381     BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >));
0382 
0383     // 1. Finding dominator
0384     // 1.1. Initialize
0385     const VerticesSizeType numOfVertices = num_vertices(g);
0386     if (numOfVertices == 0)
0387         return;
0388 
0389     vertexItr vi, viend;
0390     boost::tie(vi, viend) = vertices(g);
0391     const std::set< Vertex > N(vi, viend);
0392 
0393     bool change = true;
0394 
0395     std::vector< std::set< Vertex > > dom(numOfVertices, N);
0396     vertexSetMap domMap(make_iterator_property_map(dom.begin(), indexMap));
0397     get(domMap, entry).clear();
0398     get(domMap, entry).insert(entry);
0399 
0400     while (change)
0401     {
0402         change = false;
0403         for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
0404         {
0405             if (*vi == entry)
0406                 continue;
0407 
0408             std::set< Vertex > T(N);
0409 
0410             typename graph_traits< Graph >::in_edge_iterator inItr, inEnd;
0411             for (boost::tie(inItr, inEnd) = in_edges(*vi, g); inItr != inEnd;
0412                  ++inItr)
0413             {
0414                 const Vertex p = source(*inItr, g);
0415 
0416                 std::set< Vertex > tempSet;
0417                 std::set_intersection(T.begin(), T.end(),
0418                     get(domMap, p).begin(), get(domMap, p).end(),
0419                     std::inserter(tempSet, tempSet.begin()));
0420                 T.swap(tempSet);
0421             }
0422 
0423             T.insert(*vi);
0424             if (T != get(domMap, *vi))
0425             {
0426                 change = true;
0427                 get(domMap, *vi).swap(T);
0428             }
0429         } // end of for (boost::tie(vi, viend) = vertices(g)
0430     } // end of while(change)
0431 
0432     // 2. Build dominator tree
0433     for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
0434         get(domMap, *vi).erase(*vi);
0435 
0436     Graph domTree(numOfVertices);
0437 
0438     for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
0439     {
0440         if (*vi == entry)
0441             continue;
0442 
0443         // We have to iterate through copied dominator set
0444         const std::set< Vertex > tempSet(get(domMap, *vi));
0445         typename std::set< Vertex >::const_iterator s;
0446         for (s = tempSet.begin(); s != tempSet.end(); ++s)
0447         {
0448             typename std::set< Vertex >::iterator t;
0449             for (t = get(domMap, *vi).begin(); t != get(domMap, *vi).end();)
0450             {
0451                 typename std::set< Vertex >::iterator old_t = t;
0452                 ++t; // Done early because t may become invalid
0453                 if (*old_t == *s)
0454                     continue;
0455                 if (get(domMap, *s).find(*old_t) != get(domMap, *s).end())
0456                     get(domMap, *vi).erase(old_t);
0457             }
0458         }
0459     }
0460 
0461     for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
0462     {
0463         if (*vi != entry && get(domMap, *vi).size() == 1)
0464         {
0465             Vertex temp = *get(domMap, *vi).begin();
0466             put(domTreePredMap, *vi, temp);
0467         }
0468     }
0469 }
0470 
0471 template < class Graph, class DomTreePredMap >
0472 void iterative_bit_vector_dominator_tree(const Graph& g,
0473     const typename graph_traits< Graph >::vertex_descriptor& entry,
0474     DomTreePredMap domTreePredMap)
0475 {
0476     typename property_map< Graph, vertex_index_t >::const_type indexMap
0477         = get(vertex_index, g);
0478 
0479     iterative_bit_vector_dominator_tree(g, entry, indexMap, domTreePredMap);
0480 }
0481 } // namespace boost
0482 
0483 #endif // BOOST_GRAPH_DOMINATOR_HPP