This documentation is being rewritten. If something looks off, please cross-check with the Boost 1.91.0 Boost.Graph docs and open an issue.

Lengauer-Tarjan Dominator Tree Algorithm

Builds the dominator tree for a directed graph using the Lengauer-Tarjan algorithm.

Complexity: OV+E)log(V+E
Defined in: <boost/graph/dominator_tree.hpp>

Example

#include <iostream>
#include <vector>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dominator_tree.hpp>

int main() {
    using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS>;
    using Vertex = boost::graph_traits<Graph>::vertex_descriptor;
    Graph g(6);
    // CFG-like: 0 is entry
    boost::add_edge(0, 1, g); boost::add_edge(0, 2, g);
    boost::add_edge(1, 3, g); boost::add_edge(2, 3, g);
    boost::add_edge(3, 4, g); boost::add_edge(4, 5, g);

    std::vector<Vertex> dom(num_vertices(g), boost::graph_traits<Graph>::null_vertex());
    auto dom_map = boost::make_iterator_property_map(dom.begin(), get(boost::vertex_index, g));
    boost::lengauer_tarjan_dominator_tree(g, Vertex{0}, dom_map);

    std::cout << "Immediate dominators (entry = 0):\n";
    for (std::size_t v = 0; v < num_vertices(g); ++v) {
        if (dom[v] != boost::graph_traits<Graph>::null_vertex())
            std::cout << "  idom(" << v << ") = " << dom[v] << "\n";
        else
            std::cout << "  idom(" << v << ") = none (entry)\n";
    }
}
Immediate dominators (entry = 0):
  idom(0) = none (entry)
  idom(1) = 0
  idom(2) = 0
  idom(3) = 0
  idom(4) = 3
  idom(5) = 4

(1) Simple version

The simplest version: data structures for depth first search are created internally, and depth first search runs internally.

template <class Graph, class DomTreePredMap>
void lengauer_tarjan_dominator_tree(
    const Graph& g,
    const typename graph_traits<Graph>::vertex_descriptor& entry,
    DomTreePredMap domTreePredMap);
Direction Parameter Description

IN

const Graph& g

The graph object on which the algorithm will be applied. The type Graph must be a model of Vertex List Graph and Bidirectional Graph.

IN

vertex_descriptor entry

The entry vertex. The dominator tree will be rooted at this vertex.

OUT

DomTreePredMap domTreePredMap

The dominator tree where parents are each children’s immediate dominator.


(2) Version providing DFS data structures

After calling this function, the user can reuse the depth first search related information filled in property maps.

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);
Direction Parameter Description

IN

const Graph& g

The graph object on which the algorithm will be applied. The type Graph must be a model of Vertex List Graph and Bidirectional Graph.

IN

vertex_descriptor entry

The entry vertex. The dominator tree will be rooted at this vertex.

IN

IndexMap indexMap

This maps each vertex to an integer in the range [0, num_vertices(g)). The type VertexIndexMap must be a model of Readable Property Map. The value type of the map must be an integer type. The vertex descriptor type of the graph needs to be usable as the key type of the map.

IN/OUT

TimeMap dfnumMap

The sequence number of depth first search. The type TimeMap must be a model of Read/Write Property Map. The vertex descriptor type of the graph needs to be usable as the key type of the TimeMap.

IN/OUT

PredMap parentMap

The predecessor map records the parent of the depth first search tree. The PredMap type must be a Read/Write Property Map whose key and value types are the same as the vertex descriptor type of the graph.

IN/OUT

VertexVector verticesByDFNum

The vector containing vertices in depth first search order. If we access this vector sequentially, it’s equivalent to access vertices by depth first search order.

OUT

DomTreePredMap domTreePredMap

The dominator tree where parents are each children’s immediate dominator.


The caller should provide depth first search related information evaluated before calling this function.

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);
Direction Parameter Description

IN

const Graph& g

The graph object on which the algorithm will be applied. The type Graph must be a model of Vertex List Graph and Bidirectional Graph.

IN

vertex_descriptor entry

The entry vertex. The dominator tree will be rooted at this vertex.

IN

IndexMap indexMap

This maps each vertex to an integer in the range [0, num_vertices(g)). The type VertexIndexMap must be a model of Readable Property Map. The value type of the map must be an integer type. The vertex descriptor type of the graph needs to be usable as the key type of the map.

IN/OUT

TimeMap dfnumMap

The sequence number of depth first search. The type TimeMap must be a model of Read/Write Property Map. The vertex descriptor type of the graph needs to be usable as the key type of the TimeMap.

IN/OUT

PredMap parentMap

The predecessor map records the parent of the depth first search tree. The PredMap type must be a Read/Write Property Map whose key and value types are the same as the vertex descriptor type of the graph.

IN/OUT

VertexVector verticesByDFNum

The vector containing vertices in depth first search order. If we access this vector sequentially, it’s equivalent to access vertices by depth first search order.

OUT

DomTreePredMap domTreePredMap

The dominator tree where parents are each children’s immediate dominator.

Description

This algorithm [59,60,61] builds the dominator tree for a directed graph. There are three options for dealing with the depth first search related values. The simplest version creates data structures and runs depth first search internally. However, chances are that a user wants to reuse the depth first search data, so we have two additional versions.

A vertex u dominates a vertex v, if every path of the directed graph from the entry to v must go through u. In the left graph of Figure 1, vertex 1 dominates vertex 2, 3, 4, 5, 6 and 7, because we have to pass vertex 1 to reach those vertices. Note that vertex 4 dominates vertex 6, even though vertex 4 is a successor of vertex 6. Dominator relationship is useful in many applications especially for compiler optimization. We can define the immediate dominator for each vertex such that idom(n) dominates n but does not dominate any other dominator of n. For example, vertex 1, 3 and 4 are dominators of vertex 6, but vertex 4 is the immediate dominator, because vertex 1 and 3 dominate vertex 4. If we make every idom of each vertex as its parent, we can build the dominator tree like the right part of Figure 1.

Figure 1: An example graph and its dominator tree.

figs/dominator-tree1

figs/dominator-tree2

An easy way to build a dominator tree is to use an iterative bit vector algorithm, but it may be slow in the worst case. We implemented the Lengauer-Tarjan algorithm whose time complexity is OV+E)log(V+E.

Lengauer-Tarjan algorithm utilizes two techniques. The first one is, as an intermediate step, finding the semidominator which is relatively easier to evaluate than the immediate dominator, and the second one is path compression. For the detail of the algorithm, see [59].

Notes

The original HTML documentation contained a double parenthesis typo in the lengauer_tarjan_dominator_tree_without_dfs signature. This has been corrected to match the actual header file declaration.