The transitive closure for a digraph G is a digraph G’ with an edge (i, j) corresponding to each directed path from i to j in G. The resultant digraph G’ representation in the form of the adjacency matrix is called the connectivity matrix.

For example, consider the following directed graph:

Transitive Closure

Its connectivity matrix C is
 
1   0   1   0
1   1   1   0
0   0   1   0
1   1   1   1

The value of C[i][j] is 1 only if a directed path exists from vertex i to vertex j. Note that all diagonal elements in the connectivity matrix are 1 since a path exists from every vertex to itself.

Practice this problem

Method 1

As discussed in the previous post, we can use the Floyd–Warshall algorithm to find the transitive closure of a graph with V vertices in O(V3) time. The algorithm returns the shortest paths between each of the vertices in the graph. We can easily modify the algorithm to return 1/0 depending upon path exists between a pair of vertices or not. The implementation can be seen here.

Method 2: (Commonly used)

Warshall’s algorithm is commonly used to construct transitive closures. It is very identical to Floyd’s all-pairs shortest path algorithm. The core idea behind Warshall’s algorithm is that a path exists between two pairs of vertices i, j if and only if there is an edge from i to j, or any of the following conditions is true:

  • There is a path from i to j going through vertex 1.
  • There is a path from i to j going through vertex 1 and/or 2.
  • There is a path from i to j going through vertex 1, 2, and/or 3.
  • There is a path from i to j going through any other vertices.

The time complexity of this algorithm is the same as that of Floyd–Warshall algorithm, i.e., O(V3), but it reduces storage by retaining only one bit for each matrix element (e.g., we can use bool data type instead of int). The implementation can be seen here.

Method 3: (For dense graphs)

We know that all pairs of vertices are reachable from each other in each strongly connected component of a graph. We also know that the strongly connected components of the graph can be computed in linear time. The idea is to exploit this fact to compute the transitive closure of the graph. Further, if (x, y) is an edge between two vertices in different strongly connected components, every vertex in y's component is reachable from each vertex in x's component. Thus, the problem reduces finding the transitive closure on a graph of strongly connected components, which should have considerably fewer edges and vertices than the given graph.

Method 4: (For sparse graphs)

We know that we can find all vertices reachable from a vertex v by calling Depth–first search (DFS) on the vertex v. If we do the same for all vertices present in the graph and store the path information in a matrix, we will get transitive closure of the graph. The total time complexity will also reduce to O(V × (V + E)), where V and E are the total number of vertices and edges in the graph, respectively. This is equal to O(V3) only if the graph is dense (remember E = V2 for a dense graph). We can also use BFS instead of DFS.

The algorithm can be implemented as follows in C++, Java, and Python:

C++


Download  Run Code

Output:

1   0   1   0
1   1   1   0
0   0   1   0
1   1   1   1

Java


Download  Run Code

Output:

[1, 0, 1, 0]
[1, 1, 1, 0]
[0, 0, 1, 0]
[1, 1, 1, 1]

Python


Download  Run Code

Output:

[1, 0, 1, 0]
[1, 1, 1, 0]
[0, 0, 1, 0]
[1, 1, 1, 1]

Transitive closure is used to answer reachability queries (can we get to x from y?) efficiently in constant time after preprocessing of constructing the transitive closure.

Transitive Reduction

Transitive reduction (also known as minimum equivalent digraph) reduces the total number of edges while maintaining identical reachability properties, i.e., the transitive closure of G is similar to the transitive closure of the transitive reduction of G. The primary application of transitive reduction is space minimization by eliminating redundant edges from G that do not affect reachability.

 
References:

1. Transitive Closure and Reduction
2. CS 440 Theory of Algorithms – Dynamic Programming Part II