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