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

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

There is a newer version: 1.12.0
Show newest version
/* Soot - a J*va Optimization Framework
 * Copyright (C) 2008 Eric Bodden
 *
 * 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.
 */

package soot.toolkits.graph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

/**
 *  Identifies and provides an interface to query the strongly-connected
 *  components of DirectedGraph instances.
 *  
 *  Uses Tarjan's algorithm.
 *  
 *  @see DirectedGraph
 *  @author Eric Bodden
 */

public class StronglyConnectedComponentsFast
{
    protected final List> componentList = new ArrayList>();
    protected final List> trueComponentList = new ArrayList>();
    
    protected int index = 0;
    
    protected Map indexForNode, lowlinkForNode;
    
    protected Stack s;

	protected DirectedGraph g;
    
    /**
     *  @param g a graph for which we want to compute the strongly
     *           connected components. 
     *  @see DirectedGraph
     */
    public StronglyConnectedComponentsFast(DirectedGraph g)
    {
    	this.g = g;
		s = new Stack();
    	List heads = g.getHeads();
    	
    	if(heads.size()>1)
    		throw new RuntimeException("Cannot compute SCCs for graph with number of heads = "+heads.size());
    	
    	indexForNode = new HashMap();
    	lowlinkForNode = new HashMap();

    	recurse(heads.get(0));
    	
    	//free memory
    	indexForNode = null;
    	lowlinkForNode = null;
    	s = null;
    	g = null;
    }

	protected void recurse(N v) {
		indexForNode.put(v, index);
		lowlinkForNode.put(v, index);
		index++;
		s.push(v);
		for(N succ: g.getSuccsOf(v)) {
			if(!indexForNode.containsKey(succ)) {
				recurse(succ);
				lowlinkForNode.put(v, Math.min(lowlinkForNode.get(v), lowlinkForNode.get(succ)));
			} else if(s.contains(succ)) {
				lowlinkForNode.put(v, Math.min(lowlinkForNode.get(v), indexForNode.get(succ)));
			}			
		}
		if(lowlinkForNode.get(v).intValue() == indexForNode.get(v).intValue()) {
			List scc = new ArrayList();
			N v2;
			do {
				v2 = s.pop();
				scc.add(v2);
			}while(v!=v2);			
			componentList.add(scc);
			if(scc.size()>1) {
				trueComponentList.add(scc);
			} else {
				N n = scc.get(0);
				if(g.getSuccsOf(n).contains(n))
					trueComponentList.add(scc);
			}
		}
	}
	
    /**
     *   @return the list of the strongly-connected components
     */
    public List> getComponents()
    {
        return componentList;
    }
    
    /**
     *   @return the list of the strongly-connected components, but only those
     *   that are true components, i.e. components which have more than one element
     *   or consists of one node that has itself as a successor 
     */
    public List> getTrueComponents()
    {
        return trueComponentList;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy