dominator_tree.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. //=======================================================================
  2. // Copyright (C) 2005-2009 Jongsoo 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. #ifndef BOOST_GRAPH_DOMINATOR_HPP
  9. #define BOOST_GRAPH_DOMINATOR_HPP
  10. #include <boost/config.hpp>
  11. #include <deque>
  12. #include <set>
  13. #include <boost/graph/depth_first_search.hpp>
  14. #include <boost/concept/assert.hpp>
  15. // Dominator tree computation
  16. namespace boost
  17. {
  18. namespace detail
  19. {
  20. /**
  21. * An extended time_stamper which also records vertices for each dfs number
  22. */
  23. template < class TimeMap, class VertexVector, class TimeT, class Tag >
  24. class time_stamper_with_vertex_vector
  25. : public base_visitor<
  26. time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT, Tag > >
  27. {
  28. public:
  29. typedef Tag event_filter;
  30. time_stamper_with_vertex_vector(
  31. TimeMap timeMap, VertexVector& v, TimeT& t)
  32. : timeStamper_(timeMap, t), v_(v)
  33. {
  34. }
  35. template < class Graph >
  36. void operator()(const typename property_traits< TimeMap >::key_type& v,
  37. const Graph& g)
  38. {
  39. timeStamper_(v, g);
  40. v_[timeStamper_.m_time] = v;
  41. }
  42. private:
  43. time_stamper< TimeMap, TimeT, Tag > timeStamper_;
  44. VertexVector& v_;
  45. };
  46. /**
  47. * A convenient way to create a time_stamper_with_vertex_vector
  48. */
  49. template < class TimeMap, class VertexVector, class TimeT, class Tag >
  50. time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT, Tag >
  51. stamp_times_with_vertex_vector(
  52. TimeMap timeMap, VertexVector& v, TimeT& t, Tag)
  53. {
  54. return time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT,
  55. Tag >(timeMap, v, t);
  56. }
  57. template < class Graph, class IndexMap, class TimeMap, class PredMap,
  58. class DomTreePredMap >
  59. class dominator_visitor
  60. {
  61. typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
  62. typedef
  63. typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
  64. public:
  65. /**
  66. * @param g [in] the target graph of the dominator tree
  67. * @param entry [in] the entry node of g
  68. * @param indexMap [in] the vertex index map for g
  69. * @param domTreePredMap [out] the immediate dominator map
  70. * (parent map in dominator tree)
  71. */
  72. dominator_visitor(const Graph& g, const Vertex& entry,
  73. const IndexMap& indexMap, DomTreePredMap domTreePredMap)
  74. : semi_(num_vertices(g))
  75. , ancestor_(num_vertices(g), graph_traits< Graph >::null_vertex())
  76. , samedom_(ancestor_)
  77. , best_(semi_)
  78. , semiMap_(make_iterator_property_map(semi_.begin(), indexMap))
  79. , ancestorMap_(make_iterator_property_map(ancestor_.begin(), indexMap))
  80. , bestMap_(make_iterator_property_map(best_.begin(), indexMap))
  81. , buckets_(num_vertices(g))
  82. , bucketMap_(make_iterator_property_map(buckets_.begin(), indexMap))
  83. , entry_(entry)
  84. , domTreePredMap_(domTreePredMap)
  85. , numOfVertices_(num_vertices(g))
  86. , samedomMap(make_iterator_property_map(samedom_.begin(), indexMap))
  87. {
  88. }
  89. void operator()(const Vertex& n, const TimeMap& dfnumMap,
  90. const PredMap& parentMap, const Graph& g)
  91. {
  92. if (n == entry_)
  93. return;
  94. const Vertex p(get(parentMap, n));
  95. Vertex s(p);
  96. // 1. Calculate the semidominator of n,
  97. // based on the semidominator thm.
  98. // * Semidominator thm. : To find the semidominator of a node n,
  99. // consider all predecessors v of n in the CFG (Control Flow
  100. // Graph).
  101. // - If v is a proper ancestor of n in the spanning tree
  102. // (so dfnum(v) < dfnum(n)), then v is a candidate for semi(n)
  103. // - If v is a non-ancestor of n (so dfnum(v) > dfnum(n))
  104. // then for each u that is an ancestor of v (or u = v),
  105. // Let semi(u) be a candidate for semi(n)
  106. // of all these candidates, the one with lowest dfnum is
  107. // the semidominator of n.
  108. // For each predecessor of n
  109. typename graph_traits< Graph >::in_edge_iterator inItr, inEnd;
  110. for (boost::tie(inItr, inEnd) = in_edges(n, g); inItr != inEnd;
  111. ++inItr)
  112. {
  113. const Vertex v = source(*inItr, g);
  114. // To deal with unreachable nodes
  115. if (get(dfnumMap, v) < 0 || get(dfnumMap, v) >= numOfVertices_)
  116. continue;
  117. Vertex s2;
  118. if (get(dfnumMap, v) <= get(dfnumMap, n))
  119. s2 = v;
  120. else
  121. s2 = get(semiMap_, ancestor_with_lowest_semi_(v, dfnumMap));
  122. if (get(dfnumMap, s2) < get(dfnumMap, s))
  123. s = s2;
  124. }
  125. put(semiMap_, n, s);
  126. // 2. Calculation of n's dominator is deferred until
  127. // the path from s to n has been linked into the forest
  128. get(bucketMap_, s).push_back(n);
  129. get(ancestorMap_, n) = p;
  130. get(bestMap_, n) = n;
  131. // 3. Now that the path from p to v has been linked into
  132. // the spanning forest, these lines calculate the dominator of v,
  133. // based on the dominator thm., or else defer the calculation
  134. // until y's dominator is known
  135. // * Dominator thm. : On the spanning-tree path below semi(n) and
  136. // above or including n, let y be the node
  137. // with the smallest-numbered semidominator. Then,
  138. //
  139. // idom(n) = semi(n) if semi(y)=semi(n) or
  140. // idom(y) if semi(y) != semi(n)
  141. typename std::deque< Vertex >::iterator buckItr;
  142. for (buckItr = get(bucketMap_, p).begin();
  143. buckItr != get(bucketMap_, p).end(); ++buckItr)
  144. {
  145. const Vertex v(*buckItr);
  146. const Vertex y(ancestor_with_lowest_semi_(v, dfnumMap));
  147. if (get(semiMap_, y) == get(semiMap_, v))
  148. put(domTreePredMap_, v, p);
  149. else
  150. put(samedomMap, v, y);
  151. }
  152. get(bucketMap_, p).clear();
  153. }
  154. protected:
  155. /**
  156. * Evaluate function in Tarjan's path compression
  157. */
  158. const Vertex ancestor_with_lowest_semi_(
  159. const Vertex& v, const TimeMap& dfnumMap)
  160. {
  161. const Vertex a(get(ancestorMap_, v));
  162. if (get(ancestorMap_, a) != graph_traits< Graph >::null_vertex())
  163. {
  164. const Vertex b(ancestor_with_lowest_semi_(a, dfnumMap));
  165. put(ancestorMap_, v, get(ancestorMap_, a));
  166. if (get(dfnumMap, get(semiMap_, b))
  167. < get(dfnumMap, get(semiMap_, get(bestMap_, v))))
  168. put(bestMap_, v, b);
  169. }
  170. return get(bestMap_, v);
  171. }
  172. std::vector< Vertex > semi_, ancestor_, samedom_, best_;
  173. PredMap semiMap_, ancestorMap_, bestMap_;
  174. std::vector< std::deque< Vertex > > buckets_;
  175. iterator_property_map<
  176. typename std::vector< std::deque< Vertex > >::iterator, IndexMap >
  177. bucketMap_;
  178. const Vertex& entry_;
  179. DomTreePredMap domTreePredMap_;
  180. const VerticesSizeType numOfVertices_;
  181. public:
  182. PredMap samedomMap;
  183. };
  184. } // namespace detail
  185. /**
  186. * @brief Build dominator tree using Lengauer-Tarjan algorithm.
  187. * It takes O((V+E)log(V+E)) time.
  188. *
  189. * @pre dfnumMap, parentMap and verticesByDFNum have dfs results corresponding
  190. * indexMap.
  191. * If dfs has already run before,
  192. * this function would be good for saving computations.
  193. * @pre Unreachable nodes must be masked as
  194. * graph_traits<Graph>::null_vertex in parentMap.
  195. * @pre Unreachable nodes must be masked as
  196. * (std::numeric_limits<VerticesSizeType>::max)() in dfnumMap.
  197. *
  198. * @param domTreePredMap [out] : immediate dominator map (parent map
  199. * in dom. tree)
  200. *
  201. * @note reference Appel. p. 452~453. algorithm 19.9, 19.10.
  202. *
  203. * @todo : Optimization in Finding Dominators in Practice, Loukas Georgiadis
  204. */
  205. template < class Graph, class IndexMap, class TimeMap, class PredMap,
  206. class VertexVector, class DomTreePredMap >
  207. void lengauer_tarjan_dominator_tree_without_dfs(const Graph& g,
  208. const typename graph_traits< Graph >::vertex_descriptor& entry,
  209. const IndexMap& indexMap, TimeMap dfnumMap, PredMap parentMap,
  210. VertexVector& verticesByDFNum, DomTreePredMap domTreePredMap)
  211. {
  212. // Typedefs and concept check
  213. typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
  214. typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
  215. BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >));
  216. const VerticesSizeType numOfVertices = num_vertices(g);
  217. if (numOfVertices == 0)
  218. return;
  219. // 1. Visit each vertex in reverse post order and calculate sdom.
  220. detail::dominator_visitor< Graph, IndexMap, TimeMap, PredMap,
  221. DomTreePredMap >
  222. visitor(g, entry, indexMap, domTreePredMap);
  223. VerticesSizeType i;
  224. for (i = 0; i < numOfVertices; ++i)
  225. {
  226. const Vertex u(verticesByDFNum[numOfVertices - 1 - i]);
  227. if (u != graph_traits< Graph >::null_vertex())
  228. visitor(u, dfnumMap, parentMap, g);
  229. }
  230. // 2. Now all the deferred dominator calculations,
  231. // based on the second clause of the dominator thm., are performed
  232. for (i = 0; i < numOfVertices; ++i)
  233. {
  234. const Vertex n(verticesByDFNum[i]);
  235. if (n == entry || n == graph_traits< Graph >::null_vertex())
  236. continue;
  237. Vertex u = get(visitor.samedomMap, n);
  238. if (u != graph_traits< Graph >::null_vertex())
  239. {
  240. put(domTreePredMap, n, get(domTreePredMap, u));
  241. }
  242. }
  243. }
  244. /**
  245. * Unlike lengauer_tarjan_dominator_tree_without_dfs,
  246. * dfs is run in this function and
  247. * the result is written to dfnumMap, parentMap, vertices.
  248. *
  249. * If the result of dfs required after this algorithm,
  250. * this function can eliminate the need of rerunning dfs.
  251. */
  252. template < class Graph, class IndexMap, class TimeMap, class PredMap,
  253. class VertexVector, class DomTreePredMap >
  254. void lengauer_tarjan_dominator_tree(const Graph& g,
  255. const typename graph_traits< Graph >::vertex_descriptor& entry,
  256. const IndexMap& indexMap, TimeMap dfnumMap, PredMap parentMap,
  257. VertexVector& verticesByDFNum, DomTreePredMap domTreePredMap)
  258. {
  259. // Typedefs and concept check
  260. typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
  261. BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >));
  262. // 1. Depth first visit
  263. const VerticesSizeType numOfVertices = num_vertices(g);
  264. if (numOfVertices == 0)
  265. return;
  266. VerticesSizeType time = (std::numeric_limits< VerticesSizeType >::max)();
  267. std::vector< default_color_type > colors(
  268. numOfVertices, color_traits< default_color_type >::white());
  269. depth_first_visit(g, entry,
  270. make_dfs_visitor(
  271. make_pair(record_predecessors(parentMap, on_tree_edge()),
  272. detail::stamp_times_with_vertex_vector(
  273. dfnumMap, verticesByDFNum, time, on_discover_vertex()))),
  274. make_iterator_property_map(colors.begin(), indexMap));
  275. // 2. Run main algorithm.
  276. lengauer_tarjan_dominator_tree_without_dfs(g, entry, indexMap, dfnumMap,
  277. parentMap, verticesByDFNum, domTreePredMap);
  278. }
  279. /**
  280. * Use vertex_index as IndexMap and make dfnumMap, parentMap, verticesByDFNum
  281. * internally.
  282. * If we don't need the result of dfs (dfnumMap, parentMap, verticesByDFNum),
  283. * this function would be more convenient one.
  284. */
  285. template < class Graph, class DomTreePredMap >
  286. void lengauer_tarjan_dominator_tree(const Graph& g,
  287. const typename graph_traits< Graph >::vertex_descriptor& entry,
  288. DomTreePredMap domTreePredMap)
  289. {
  290. // typedefs
  291. typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
  292. typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
  293. typedef typename property_map< Graph, vertex_index_t >::const_type IndexMap;
  294. typedef iterator_property_map<
  295. typename std::vector< VerticesSizeType >::iterator, IndexMap >
  296. TimeMap;
  297. typedef iterator_property_map< typename std::vector< Vertex >::iterator,
  298. IndexMap >
  299. PredMap;
  300. // Make property maps
  301. const VerticesSizeType numOfVertices = num_vertices(g);
  302. if (numOfVertices == 0)
  303. return;
  304. const IndexMap indexMap = get(vertex_index, g);
  305. std::vector< VerticesSizeType > dfnum(numOfVertices, 0);
  306. TimeMap dfnumMap(make_iterator_property_map(dfnum.begin(), indexMap));
  307. std::vector< Vertex > parent(
  308. numOfVertices, graph_traits< Graph >::null_vertex());
  309. PredMap parentMap(make_iterator_property_map(parent.begin(), indexMap));
  310. std::vector< Vertex > verticesByDFNum(parent);
  311. // Run main algorithm
  312. lengauer_tarjan_dominator_tree(g, entry, indexMap, dfnumMap, parentMap,
  313. verticesByDFNum, domTreePredMap);
  314. }
  315. /**
  316. * Muchnick. p. 182, 184
  317. *
  318. * using iterative bit vector analysis
  319. */
  320. template < class Graph, class IndexMap, class DomTreePredMap >
  321. void iterative_bit_vector_dominator_tree(const Graph& g,
  322. const typename graph_traits< Graph >::vertex_descriptor& entry,
  323. const IndexMap& indexMap, DomTreePredMap domTreePredMap)
  324. {
  325. typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
  326. typedef typename graph_traits< Graph >::vertex_iterator vertexItr;
  327. typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType;
  328. typedef iterator_property_map<
  329. typename std::vector< std::set< Vertex > >::iterator, IndexMap >
  330. vertexSetMap;
  331. BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >));
  332. // 1. Finding dominator
  333. // 1.1. Initialize
  334. const VerticesSizeType numOfVertices = num_vertices(g);
  335. if (numOfVertices == 0)
  336. return;
  337. vertexItr vi, viend;
  338. boost::tie(vi, viend) = vertices(g);
  339. const std::set< Vertex > N(vi, viend);
  340. bool change = true;
  341. std::vector< std::set< Vertex > > dom(numOfVertices, N);
  342. vertexSetMap domMap(make_iterator_property_map(dom.begin(), indexMap));
  343. get(domMap, entry).clear();
  344. get(domMap, entry).insert(entry);
  345. while (change)
  346. {
  347. change = false;
  348. for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
  349. {
  350. if (*vi == entry)
  351. continue;
  352. std::set< Vertex > T(N);
  353. typename graph_traits< Graph >::in_edge_iterator inItr, inEnd;
  354. for (boost::tie(inItr, inEnd) = in_edges(*vi, g); inItr != inEnd;
  355. ++inItr)
  356. {
  357. const Vertex p = source(*inItr, g);
  358. std::set< Vertex > tempSet;
  359. std::set_intersection(T.begin(), T.end(),
  360. get(domMap, p).begin(), get(domMap, p).end(),
  361. std::inserter(tempSet, tempSet.begin()));
  362. T.swap(tempSet);
  363. }
  364. T.insert(*vi);
  365. if (T != get(domMap, *vi))
  366. {
  367. change = true;
  368. get(domMap, *vi).swap(T);
  369. }
  370. } // end of for (boost::tie(vi, viend) = vertices(g)
  371. } // end of while(change)
  372. // 2. Build dominator tree
  373. for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
  374. get(domMap, *vi).erase(*vi);
  375. Graph domTree(numOfVertices);
  376. for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
  377. {
  378. if (*vi == entry)
  379. continue;
  380. // We have to iterate through copied dominator set
  381. const std::set< Vertex > tempSet(get(domMap, *vi));
  382. typename std::set< Vertex >::const_iterator s;
  383. for (s = tempSet.begin(); s != tempSet.end(); ++s)
  384. {
  385. typename std::set< Vertex >::iterator t;
  386. for (t = get(domMap, *vi).begin(); t != get(domMap, *vi).end();)
  387. {
  388. typename std::set< Vertex >::iterator old_t = t;
  389. ++t; // Done early because t may become invalid
  390. if (*old_t == *s)
  391. continue;
  392. if (get(domMap, *s).find(*old_t) != get(domMap, *s).end())
  393. get(domMap, *vi).erase(old_t);
  394. }
  395. }
  396. }
  397. for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
  398. {
  399. if (*vi != entry && get(domMap, *vi).size() == 1)
  400. {
  401. Vertex temp = *get(domMap, *vi).begin();
  402. put(domTreePredMap, *vi, temp);
  403. }
  404. }
  405. }
  406. template < class Graph, class DomTreePredMap >
  407. void iterative_bit_vector_dominator_tree(const Graph& g,
  408. const typename graph_traits< Graph >::vertex_descriptor& entry,
  409. DomTreePredMap domTreePredMap)
  410. {
  411. typename property_map< Graph, vertex_index_t >::const_type indexMap
  412. = get(vertex_index, g);
  413. iterative_bit_vector_dominator_tree(g, entry, indexMap, domTreePredMap);
  414. }
  415. } // namespace boost
  416. #endif // BOOST_GRAPH_DOMINATOR_HPP