/* Soot - a J*va Optimization Framework * Copyright (C) 1999 Patrick Lam, Raja Vallee-Rai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * Modified by the Sable Research Group and others 1997-1999. * See the 'credits' file distributed with Soot for the complete list of * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot) */ package soot.toolkits.graph; import soot.options.*; import soot.*; import soot.util.*; import java.util.*; /** * Identifies and provides an interface to query the strongly-connected * components of DirectedGraph instances. * @see DirectedGraph * @deprecated implementation is inefficient; use {@link StronglyConnectedComponentsFast} instead */ @Deprecated public class StronglyConnectedComponents { private HashMap<Object, Object> nodeToColor; private static final Object Visited=new Object(); private static final Object Black=new Object(); private final LinkedList<Object> finishingOrder; private List<List> componentList = new ArrayList<List>(); private final HashMap<Object, List<Object>> nodeToComponent = new HashMap<Object, List<Object>>(); MutableDirectedGraph sccGraph = new HashMutableDirectedGraph(); private final int[] indexStack; private final Object[] nodeStack; private int last; /** * @param g a graph for which we want to compute the strongly * connected components. * @see DirectedGraph */ public StronglyConnectedComponents(DirectedGraph g) { nodeToColor = new HashMap<Object, Object>((3*g.size())/2,0.7f); indexStack = new int[g.size()]; nodeStack = new Object[g.size()]; finishingOrder = new LinkedList<Object>(); // Visit each node { Iterator nodeIt = g.iterator(); while(nodeIt.hasNext()) { Object s = nodeIt.next(); if(nodeToColor.get(s) == null) visitNode(g, s); } } // Re-color all nodes white nodeToColor = new HashMap<Object, Object>((3*g.size()),0.7f); // Visit each node via transpose edges { Iterator<Object> revNodeIt = finishingOrder.iterator(); while (revNodeIt.hasNext()) { Object s = revNodeIt.next(); if(nodeToColor.get(s) == null) { List<Object> currentComponent = null; currentComponent = new StationaryArrayList(); nodeToComponent.put(s, currentComponent); sccGraph.addNode(currentComponent); componentList.add(currentComponent); visitRevNode(g, s, currentComponent); } } } componentList = Collections.unmodifiableList(componentList); if (Options.v().verbose()) { G.v().out.println("Done computing scc components"); G.v().out.println("number of nodes in underlying graph: "+g.size()); G.v().out.println("number of components: "+sccGraph.size()); } } private void visitNode(DirectedGraph graph, Object startNode) { last=0; nodeToColor.put(startNode, Visited); nodeStack[last]=startNode; indexStack[last++]= -1; while(last>0) { int toVisitIndex = ++indexStack[last-1]; Object toVisitNode = nodeStack[last-1]; if(toVisitIndex >= graph.getSuccsOf(toVisitNode).size()) { // Visit this node now that we ran out of children finishingOrder.addFirst(toVisitNode); // Pop this node off last--; } else { Object childNode = graph.getSuccsOf(toVisitNode).get(toVisitIndex); // Visit this child next if not already visited (or on stack) if(nodeToColor.get(childNode) == null) { nodeToColor.put(childNode, Visited); nodeStack[last]=childNode; indexStack[last++]=-1; } } } } private void visitRevNode(DirectedGraph graph, Object startNode, List<Object> currentComponent) { last=0; nodeToColor.put(startNode, Visited); nodeStack[last]=startNode; indexStack[last++]= -1; while(last>0) { int toVisitIndex = ++indexStack[last-1]; Object toVisitNode = nodeStack[last-1]; if(toVisitIndex >= graph.getPredsOf(toVisitNode).size()) { // No more nodes. Add toVisitNode to current component. currentComponent.add(toVisitNode); nodeToComponent.put(toVisitNode, currentComponent); nodeToColor.put(toVisitNode, Black); // Pop this node off last--; } else { Object childNode = graph.getPredsOf(toVisitNode).get(toVisitIndex); // Visit this child next if not already visited (or on stack) if(nodeToColor.get(childNode) == null) { nodeToColor.put(childNode, Visited); nodeStack[last]=childNode; indexStack[last++]=-1; } else if (nodeToColor.get(childNode) == Black) { /* we may be visiting a node in another component. if so, add edge to sccGraph. */ if (nodeToComponent.get(childNode) != currentComponent) sccGraph.addEdge(nodeToComponent.get(childNode), currentComponent); } } } } /** * Checks if 2 nodes are in the same strongly-connnected component. * @param a some graph node. * @param b some graph node * @return true if both nodes are in the same strongly-connnected component. * false otherwise. */ public boolean equivalent(Object a, Object b) { return nodeToComponent.get(a) == nodeToComponent.get(b); } /** * @return a list of the strongly-connnected components that make * up the computed strongly-connnect component graph. */ public List<List> getComponents() { return componentList; } /** * @param a a node of the original graph. * @return the strongly-connnected component node * to which the parameter node belongs. */ public List getComponentOf(Object a) { return nodeToComponent.get(a); } /** * @return the computed strongly-connnected component graph. * @see DirectedGraph */ public DirectedGraph getSuperGraph() { /* we should make this unmodifiable at some point. */ return sccGraph; } }