org.jgrapht.alg.TransitiveClosure Maven / Gradle / Ivy
/* ==========================================
* JGraphT : a free Java graph-theory library
* ==========================================
*
* Project Info: http://jgrapht.sourceforge.net/
* Project Creator: Barak Naveh (http://sourceforge.net/users/barak_naveh)
*
* (C) Copyright 2003-2008, by Barak Naveh and Contributors.
*
* This program and the accompanying materials are dual-licensed under
* either
*
* (a) the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation, or (at your option) any
* later version.
*
* or (per the licensee's choosing)
*
* (b) the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation.
*/
/* ----------------------
* TransitiveClosure.java
* ----------------------
* (C) Copyright 2007, by Vinayak R. Borkar.
*
* Original Author: Vinayak R. Borkar
* Contributor(s):
*
* Changes
* -------
* 5-May-2007: Initial revision (VRB);
*
*/
package org.jgrapht.alg;
import java.util.*;
import org.jgrapht.graph.*;
/**
* Constructs the transitive closure of the input graph.
*
* @author Vinayak R. Borkar
* @since May 5, 2007
*/
public class TransitiveClosure
{
/**
* Singleton instance.
*/
public static final TransitiveClosure INSTANCE = new TransitiveClosure();
/**
* Private Constructor.
*/
private TransitiveClosure()
{
}
/**
* Computes the transitive closure of the given graph.
*
* @param graph - Graph to compute transitive closure for.
*/
public void closeSimpleDirectedGraph(SimpleDirectedGraph graph)
{
Set vertexSet = graph.vertexSet();
Set newEdgeTargets = new HashSet();
// At every iteration of the outer loop, we add a path of length 1
// between nodes that originally had a path of length 2. In the worst
// case, we need to make floor(log |V|) + 1 iterations. We stop earlier
// if there is no change to the output graph.
int bound = computeBinaryLog(vertexSet.size());
boolean done = false;
for (int i = 0; !done && (i < bound); ++i) {
done = true;
for (V v1 : vertexSet) {
newEdgeTargets.clear();
for (E v1OutEdge : graph.outgoingEdgesOf(v1)) {
V v2 = graph.getEdgeTarget(v1OutEdge);
for (E v2OutEdge : graph.outgoingEdgesOf(v2)) {
V v3 = graph.getEdgeTarget(v2OutEdge);
if (v1.equals(v3)) {
// Its a simple graph, so no self loops.
continue;
}
if (graph.getEdge(v1, v3) != null) {
// There is already an edge from v1 ---> v3, skip;
continue;
}
newEdgeTargets.add(v3);
done = false;
}
}
for (V v3 : newEdgeTargets) {
graph.addEdge(v1, v3);
}
}
}
}
/**
* Computes floor(log_2(n)) + 1
*/
private int computeBinaryLog(int n)
{
assert n >= 0;
int result = 0;
while (n > 0) {
n >>= 1;
++result;
}
return result;
}
}
// End TransitiveClosure.java