/** * */ package soottocfg.cfg.optimization; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Set; import org.jgrapht.DirectedGraph; import org.jgrapht.Graphs; import org.jgrapht.alg.DijkstraShortestPath; import org.jgrapht.alg.NaiveLcaFinder; import com.google.common.base.Preconditions; /** * @author schaef * */ public class UnreachableNodeRemover { /** * Removes all nodes and edges from the control-flow graph that are not * connected to the source. * @return true if vertices or edges have been removed. */ public static <A, B> boolean pruneUnreachableNodes(DirectedGraph<A, B> graph, A source) { Preconditions.checkArgument(graph.containsVertex(source), "Source not found in graph"); int vertCount = graph.vertexSet().size(); int edgeCount = graph.edgeSet().size(); // collect all unreachable nodes. Set<A> verticesToRemove = new HashSet<A>(graph.vertexSet()); verticesToRemove.removeAll(reachableFromSource(graph, source)); // collect all unreachable edges Set<B> egdesToRemove = new HashSet<B>(); for (A b : verticesToRemove) { for (B edge : graph.incomingEdgesOf(b)) { if (verticesToRemove.contains(graph.getEdgeSource(edge))) { egdesToRemove.add(edge); } } for (B edge : graph.outgoingEdgesOf(b)) { if (verticesToRemove.contains(graph.getEdgeTarget(edge))) { egdesToRemove.add(edge); } } } graph.removeAllVertices(verticesToRemove); graph.removeAllEdges(egdesToRemove); return !(vertCount == graph.vertexSet().size() && edgeCount == graph.edgeSet().size()); } private static <A, B> Set<A> reachableFromSource(DirectedGraph<A, B> graph, A source) { Set<A> res = new HashSet<A>(); Queue<A> todo = new LinkedList<A>(); todo.add(source); while (!todo.isEmpty()) { A current = todo.poll(); res.add(current); for (A succ : Graphs.successorListOf(graph, current)) { if (!todo.contains(succ) && !res.contains(succ)) { todo.add(succ); } } } return res; } /** * Removes all nodes and edges from which the sink of the method is not * reachable. Normally, all nodes and edges should be able to reach the * sink. However, is we remove edges (e.g., when eliminating loops), this * property might be violated and we have to re-establish it. */ public static <A, B> void removeDangelingPaths(DirectedGraph<A, B> graph, A source, A sink) { Preconditions.checkArgument(graph.containsVertex(source), "Source not found in graph"); Preconditions.checkArgument(graph.containsVertex(sink), "Sink not found in graph"); Set<B> edgesToRemove = new HashSet<B>(); for (A b : graph.vertexSet()) { if (b != sink && graph.outDegreeOf(b) == 0) { NaiveLcaFinder<A, B> lca = new NaiveLcaFinder<A, B>(graph); A ancestor = lca.findLca(b, sink); List<B> path = DijkstraShortestPath.findPathBetween(graph, ancestor, b); Preconditions.checkArgument(path!=null && !path.isEmpty()); edgesToRemove.add(path.get(0)); } } graph.removeAllEdges(edgesToRemove); pruneUnreachableNodes(graph, source); } }