dominator_tree.hpp 18 KB

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