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