soot.toolkits.graph.StronglyConnectedComponentsFast Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of robovm-soot Show documentation
Show all versions of robovm-soot Show documentation
RoboVM fork of Soot - A Java optimization framework
/* 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;
}
}