123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- //=======================================================================
- // Copyright (C) 2005-2009 Jongsoo Park <jongsoo.park -at- gmail.com>
- //
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //=======================================================================
- #ifndef BOOST_GRAPH_DOMINATOR_HPP
- #define BOOST_GRAPH_DOMINATOR_HPP
- #include <boost/config.hpp>
- #include <deque>
- #include <set>
- #include <boost/graph/depth_first_search.hpp>
- #include <boost/concept/assert.hpp>
- // Dominator tree computation
- namespace boost
- {
- namespace detail
- {
- /**
- * An extended time_stamper which also records vertices for each dfs number
- */
- template < class TimeMap, class VertexVector, class TimeT, class Tag >
- class time_stamper_with_vertex_vector
- : public base_visitor<
- time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT, Tag > >
- {
- public:
- typedef Tag event_filter;
- time_stamper_with_vertex_vector(
- TimeMap timeMap, VertexVector& v, TimeT& t)
- : timeStamper_(timeMap, t), v_(v)
- {
- }
- template < class Graph >
- void operator()(const typename property_traits< TimeMap >::key_type& v,
- const Graph& g)
- {
- timeStamper_(v, g);
- v_[timeStamper_.m_time] = v;
- }
- private:
- time_stamper< TimeMap, TimeT, Tag > timeStamper_;
- VertexVector& v_;
- };
- /**
- * A convenient way to create a time_stamper_with_vertex_vector
- */
- template < class TimeMap, class VertexVector, class TimeT, class Tag >
- time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT, Tag >
- stamp_times_with_vertex_vector(
- TimeMap timeMap, VertexVector& v, TimeT& t, Tag)
- {
- return time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT,
- Tag >(timeMap, v, t);
- }
- template < class Graph, class IndexMap, class TimeMap, class PredMap,
- class DomTreePredMap >
- class dominator_visitor
- {
- typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
- typedef
- typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
- public:
- /**
- * @param g [in] the target graph of the dominator tree
- * @param entry [in] the entry node of g
- * @param indexMap [in] the vertex index map for g
- * @param domTreePredMap [out] the immediate dominator map
- * (parent map in dominator tree)
- */
- dominator_visitor(const Graph& g, const Vertex& entry,
- const IndexMap& indexMap, DomTreePredMap domTreePredMap)
- : semi_(num_vertices(g))
- , ancestor_(num_vertices(g), graph_traits< Graph >::null_vertex())
- , samedom_(ancestor_)
- , best_(semi_)
- , semiMap_(make_iterator_property_map(semi_.begin(), indexMap))
- , ancestorMap_(make_iterator_property_map(ancestor_.begin(), indexMap))
- , bestMap_(make_iterator_property_map(best_.begin(), indexMap))
- , buckets_(num_vertices(g))
- , bucketMap_(make_iterator_property_map(buckets_.begin(), indexMap))
- , entry_(entry)
- , domTreePredMap_(domTreePredMap)
- , numOfVertices_(num_vertices(g))
- , samedomMap(make_iterator_property_map(samedom_.begin(), indexMap))
- {
- }
- void operator()(const Vertex& n, const TimeMap& dfnumMap,
- const PredMap& parentMap, const Graph& g)
- {
- if (n == entry_)
- return;
- const Vertex p(get(parentMap, n));
- Vertex s(p);
- // 1. Calculate the semidominator of n,
- // based on the semidominator thm.
- // * Semidominator thm. : To find the semidominator of a node n,
- // consider all predecessors v of n in the CFG (Control Flow
- // Graph).
- // - If v is a proper ancestor of n in the spanning tree
- // (so dfnum(v) < dfnum(n)), then v is a candidate for semi(n)
- // - If v is a non-ancestor of n (so dfnum(v) > dfnum(n))
- // then for each u that is an ancestor of v (or u = v),
- // Let semi(u) be a candidate for semi(n)
- // of all these candidates, the one with lowest dfnum is
- // the semidominator of n.
- // For each predecessor of n
- typename graph_traits< Graph >::in_edge_iterator inItr, inEnd;
- for (boost::tie(inItr, inEnd) = in_edges(n, g); inItr != inEnd;
- ++inItr)
- {
- const Vertex v = source(*inItr, g);
- // To deal with unreachable nodes
- if (get(dfnumMap, v) < 0 || get(dfnumMap, v) >= numOfVertices_)
- continue;
- Vertex s2;
- if (get(dfnumMap, v) <= get(dfnumMap, n))
- s2 = v;
- else
- s2 = get(semiMap_, ancestor_with_lowest_semi_(v, dfnumMap));
- if (get(dfnumMap, s2) < get(dfnumMap, s))
- s = s2;
- }
- put(semiMap_, n, s);
- // 2. Calculation of n's dominator is deferred until
- // the path from s to n has been linked into the forest
- get(bucketMap_, s).push_back(n);
- get(ancestorMap_, n) = p;
- get(bestMap_, n) = n;
- // 3. Now that the path from p to v has been linked into
- // the spanning forest, these lines calculate the dominator of v,
- // based on the dominator thm., or else defer the calculation
- // until y's dominator is known
- // * Dominator thm. : On the spanning-tree path below semi(n) and
- // above or including n, let y be the node
- // with the smallest-numbered semidominator. Then,
- //
- // idom(n) = semi(n) if semi(y)=semi(n) or
- // idom(y) if semi(y) != semi(n)
- typename std::deque< Vertex >::iterator buckItr;
- for (buckItr = get(bucketMap_, p).begin();
- buckItr != get(bucketMap_, p).end(); ++buckItr)
- {
- const Vertex v(*buckItr);
- const Vertex y(ancestor_with_lowest_semi_(v, dfnumMap));
- if (get(semiMap_, y) == get(semiMap_, v))
- put(domTreePredMap_, v, p);
- else
- put(samedomMap, v, y);
- }
- get(bucketMap_, p).clear();
- }
- protected:
- /**
- * Evaluate function in Tarjan's path compression
- */
- const Vertex ancestor_with_lowest_semi_(
- const Vertex& v, const TimeMap& dfnumMap)
- {
- const Vertex a(get(ancestorMap_, v));
- if (get(ancestorMap_, a) != graph_traits< Graph >::null_vertex())
- {
- const Vertex b(ancestor_with_lowest_semi_(a, dfnumMap));
- put(ancestorMap_, v, get(ancestorMap_, a));
- if (get(dfnumMap, get(semiMap_, b))
- < get(dfnumMap, get(semiMap_, get(bestMap_, v))))
- put(bestMap_, v, b);
- }
- return get(bestMap_, v);
- }
- std::vector< Vertex > semi_, ancestor_, samedom_, best_;
- PredMap semiMap_, ancestorMap_, bestMap_;
- std::vector< std::deque< Vertex > > buckets_;
- iterator_property_map<
- typename std::vector< std::deque< Vertex > >::iterator, IndexMap >
- bucketMap_;
- const Vertex& entry_;
- DomTreePredMap domTreePredMap_;
- const VerticesSizeType numOfVertices_;
- public:
- PredMap samedomMap;
- };
- } // namespace detail
- /**
- * @brief Build dominator tree using Lengauer-Tarjan algorithm.
- * It takes O((V+E)log(V+E)) time.
- *
- * @pre dfnumMap, parentMap and verticesByDFNum have dfs results corresponding
- * indexMap.
- * If dfs has already run before,
- * this function would be good for saving computations.
- * @pre Unreachable nodes must be masked as
- * graph_traits<Graph>::null_vertex in parentMap.
- * @pre Unreachable nodes must be masked as
- * (std::numeric_limits<VerticesSizeType>::max)() in dfnumMap.
- *
- * @param domTreePredMap [out] : immediate dominator map (parent map
- * in dom. tree)
- *
- * @note reference Appel. p. 452~453. algorithm 19.9, 19.10.
- *
- * @todo : Optimization in Finding Dominators in Practice, Loukas Georgiadis
- */
- template < class Graph, class IndexMap, class TimeMap, class PredMap,
- class VertexVector, class DomTreePredMap >
- void 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)
- {
- // Typedefs and concept check
- typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
- typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
- BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >));
- const VerticesSizeType numOfVertices = num_vertices(g);
- if (numOfVertices == 0)
- return;
- // 1. Visit each vertex in reverse post order and calculate sdom.
- detail::dominator_visitor< Graph, IndexMap, TimeMap, PredMap,
- DomTreePredMap >
- visitor(g, entry, indexMap, domTreePredMap);
- VerticesSizeType i;
- for (i = 0; i < numOfVertices; ++i)
- {
- const Vertex u(verticesByDFNum[numOfVertices - 1 - i]);
- if (u != graph_traits< Graph >::null_vertex())
- visitor(u, dfnumMap, parentMap, g);
- }
- // 2. Now all the deferred dominator calculations,
- // based on the second clause of the dominator thm., are performed
- for (i = 0; i < numOfVertices; ++i)
- {
- const Vertex n(verticesByDFNum[i]);
- if (n == entry || n == graph_traits< Graph >::null_vertex())
- continue;
- Vertex u = get(visitor.samedomMap, n);
- if (u != graph_traits< Graph >::null_vertex())
- {
- put(domTreePredMap, n, get(domTreePredMap, u));
- }
- }
- }
- /**
- * Unlike lengauer_tarjan_dominator_tree_without_dfs,
- * dfs is run in this function and
- * the result is written to dfnumMap, parentMap, vertices.
- *
- * If the result of dfs required after this algorithm,
- * this function can eliminate the need of rerunning dfs.
- */
- template < class Graph, class IndexMap, class TimeMap, class PredMap,
- class VertexVector, class DomTreePredMap >
- void 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)
- {
- // Typedefs and concept check
- typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
- BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >));
- // 1. Depth first visit
- const VerticesSizeType numOfVertices = num_vertices(g);
- if (numOfVertices == 0)
- return;
- VerticesSizeType time = (std::numeric_limits< VerticesSizeType >::max)();
- std::vector< default_color_type > colors(
- numOfVertices, color_traits< default_color_type >::white());
- depth_first_visit(g, entry,
- make_dfs_visitor(
- make_pair(record_predecessors(parentMap, on_tree_edge()),
- detail::stamp_times_with_vertex_vector(
- dfnumMap, verticesByDFNum, time, on_discover_vertex()))),
- make_iterator_property_map(colors.begin(), indexMap));
- // 2. Run main algorithm.
- lengauer_tarjan_dominator_tree_without_dfs(g, entry, indexMap, dfnumMap,
- parentMap, verticesByDFNum, domTreePredMap);
- }
- /**
- * Use vertex_index as IndexMap and make dfnumMap, parentMap, verticesByDFNum
- * internally.
- * If we don't need the result of dfs (dfnumMap, parentMap, verticesByDFNum),
- * this function would be more convenient one.
- */
- template < class Graph, class DomTreePredMap >
- void lengauer_tarjan_dominator_tree(const Graph& g,
- const typename graph_traits< Graph >::vertex_descriptor& entry,
- DomTreePredMap domTreePredMap)
- {
- // typedefs
- typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
- typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
- typedef typename property_map< Graph, vertex_index_t >::const_type IndexMap;
- typedef iterator_property_map<
- typename std::vector< VerticesSizeType >::iterator, IndexMap >
- TimeMap;
- typedef iterator_property_map< typename std::vector< Vertex >::iterator,
- IndexMap >
- PredMap;
- // Make property maps
- const VerticesSizeType numOfVertices = num_vertices(g);
- if (numOfVertices == 0)
- return;
- const IndexMap indexMap = get(vertex_index, g);
- std::vector< VerticesSizeType > dfnum(numOfVertices, 0);
- TimeMap dfnumMap(make_iterator_property_map(dfnum.begin(), indexMap));
- std::vector< Vertex > parent(
- numOfVertices, graph_traits< Graph >::null_vertex());
- PredMap parentMap(make_iterator_property_map(parent.begin(), indexMap));
- std::vector< Vertex > verticesByDFNum(parent);
- // Run main algorithm
- lengauer_tarjan_dominator_tree(g, entry, indexMap, dfnumMap, parentMap,
- verticesByDFNum, domTreePredMap);
- }
- /**
- * Muchnick. p. 182, 184
- *
- * using iterative bit vector analysis
- */
- template < class Graph, class IndexMap, class DomTreePredMap >
- void iterative_bit_vector_dominator_tree(const Graph& g,
- const typename graph_traits< Graph >::vertex_descriptor& entry,
- const IndexMap& indexMap, DomTreePredMap domTreePredMap)
- {
- typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
- typedef typename graph_traits< Graph >::vertex_iterator vertexItr;
- typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
- typedef iterator_property_map<
- typename std::vector< std::set< Vertex > >::iterator, IndexMap >
- vertexSetMap;
- BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >));
- // 1. Finding dominator
- // 1.1. Initialize
- const VerticesSizeType numOfVertices = num_vertices(g);
- if (numOfVertices == 0)
- return;
- vertexItr vi, viend;
- boost::tie(vi, viend) = vertices(g);
- const std::set< Vertex > N(vi, viend);
- bool change = true;
- std::vector< std::set< Vertex > > dom(numOfVertices, N);
- vertexSetMap domMap(make_iterator_property_map(dom.begin(), indexMap));
- get(domMap, entry).clear();
- get(domMap, entry).insert(entry);
- while (change)
- {
- change = false;
- for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
- {
- if (*vi == entry)
- continue;
- std::set< Vertex > T(N);
- typename graph_traits< Graph >::in_edge_iterator inItr, inEnd;
- for (boost::tie(inItr, inEnd) = in_edges(*vi, g); inItr != inEnd;
- ++inItr)
- {
- const Vertex p = source(*inItr, g);
- std::set< Vertex > tempSet;
- std::set_intersection(T.begin(), T.end(),
- get(domMap, p).begin(), get(domMap, p).end(),
- std::inserter(tempSet, tempSet.begin()));
- T.swap(tempSet);
- }
- T.insert(*vi);
- if (T != get(domMap, *vi))
- {
- change = true;
- get(domMap, *vi).swap(T);
- }
- } // end of for (boost::tie(vi, viend) = vertices(g)
- } // end of while(change)
- // 2. Build dominator tree
- for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
- get(domMap, *vi).erase(*vi);
- Graph domTree(numOfVertices);
- for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
- {
- if (*vi == entry)
- continue;
- // We have to iterate through copied dominator set
- const std::set< Vertex > tempSet(get(domMap, *vi));
- typename std::set< Vertex >::const_iterator s;
- for (s = tempSet.begin(); s != tempSet.end(); ++s)
- {
- typename std::set< Vertex >::iterator t;
- for (t = get(domMap, *vi).begin(); t != get(domMap, *vi).end();)
- {
- typename std::set< Vertex >::iterator old_t = t;
- ++t; // Done early because t may become invalid
- if (*old_t == *s)
- continue;
- if (get(domMap, *s).find(*old_t) != get(domMap, *s).end())
- get(domMap, *vi).erase(old_t);
- }
- }
- }
- for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
- {
- if (*vi != entry && get(domMap, *vi).size() == 1)
- {
- Vertex temp = *get(domMap, *vi).begin();
- put(domTreePredMap, *vi, temp);
- }
- }
- }
- template < class Graph, class DomTreePredMap >
- void iterative_bit_vector_dominator_tree(const Graph& g,
- const typename graph_traits< Graph >::vertex_descriptor& entry,
- DomTreePredMap domTreePredMap)
- {
- typename property_map< Graph, vertex_index_t >::const_type indexMap
- = get(vertex_index, g);
- iterative_bit_vector_dominator_tree(g, entry, indexMap, domTreePredMap);
- }
- } // namespace boost
- #endif // BOOST_GRAPH_DOMINATOR_HPP
|