All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.toolkits.graph.StronglyConnectedComponents Maven / Gradle / Ivy

There is a newer version: 2.5.0-9
Show newest version
/* 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 nodeToColor;
    private static final Object Visited=new Object();
    private static final Object Black=new Object();
    private final LinkedList finishingOrder;
    private List componentList = new ArrayList();
    private final HashMap> nodeToComponent = new HashMap>();
    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((3*g.size())/2,0.7f);
	indexStack = new int[g.size()];
	nodeStack = new Object[g.size()];        
	finishingOrder = new LinkedList();
	
        // 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((3*g.size()),0.7f);

        // Visit each node via transpose edges
        {
            Iterator revNodeIt = finishingOrder.iterator();
            while (revNodeIt.hasNext())
            {
                Object s = revNodeIt.next();

                if(nodeToColor.get(s) == null)
                {
                    List 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 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 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;
    }
}