You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
491 lines
17 KiB
491 lines
17 KiB
//======================================================================= |
|
// 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> |
|
|
|
// 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 domTreePredMap [out] the immediate dominator map |
|
* (parent map in dominator tree) |
|
*/ |
|
dominator_visitor(const Graph& g, const Vertex& entry, |
|
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(), |
|
get(vertex_index, g))), |
|
ancestorMap_(make_iterator_property_map(ancestor_.begin(), |
|
get(vertex_index, g))), |
|
bestMap_(make_iterator_property_map(best_.begin(), |
|
get(vertex_index, g))), |
|
buckets_(num_vertices(g)), |
|
bucketMap_(make_iterator_property_map(buckets_.begin(), |
|
get(vertex_index, g))), |
|
entry_(entry), |
|
domTreePredMap_(domTreePredMap), |
|
numOfVertices_(num_vertices(g)), |
|
samedomMap(make_iterator_property_map(samedom_.begin(), |
|
get(vertex_index, g))) |
|
{ |
|
} |
|
|
|
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; |
|
|
|
function_requires< 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, 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; |
|
|
|
function_requires< 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; |
|
|
|
function_requires<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
|
|
|