new graph implementation for incremental graph extension
This commit is contained in:
parent
50c4ae2faa
commit
3e55f0b370
|
@ -0,0 +1,82 @@
|
|||
package com.ibm.wala.core.tests.basic;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.ibm.wala.util.collections.IteratorUtil;
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
import com.ibm.wala.util.graph.impl.ExtensionGraph;
|
||||
import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph;
|
||||
import com.ibm.wala.util.graph.traverse.SCCIterator;
|
||||
|
||||
public class ExtensionGraphTest {
|
||||
|
||||
private static NumberedGraph<String> makeBaseGraph() {
|
||||
NumberedGraph<String> base = SlowSparseNumberedGraph.make();
|
||||
|
||||
base.addNode("A");
|
||||
base.addNode("B");
|
||||
base.addNode("C");
|
||||
base.addNode("D");
|
||||
base.addNode("E");
|
||||
base.addNode("F");
|
||||
base.addNode("G");
|
||||
base.addNode("H");
|
||||
|
||||
base.addEdge("A", "B");
|
||||
base.addEdge("B", "C");
|
||||
base.addEdge("A", "D");
|
||||
base.addEdge("D", "E");
|
||||
base.addEdge("A", "F");
|
||||
base.addEdge("F", "G");
|
||||
base.addEdge("C", "H");
|
||||
base.addEdge("E", "H");
|
||||
base.addEdge("G", "H");
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
private static void augmentA(NumberedGraph<String> base) {
|
||||
base.addEdge("C", "B");
|
||||
base.addEdge("E", "D");
|
||||
base.addEdge("G", "F");
|
||||
}
|
||||
|
||||
private static void augmentB(NumberedGraph<String> base) {
|
||||
base.addNode("I");
|
||||
base.addNode("J");
|
||||
|
||||
base.addEdge("I", "J");
|
||||
base.addEdge("A", "I");
|
||||
base.addEdge("H", "J");
|
||||
}
|
||||
|
||||
private static void augmentC(NumberedGraph<String> base) {
|
||||
base.addEdge("H", "A");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAugment() {
|
||||
NumberedGraph<String> base = makeBaseGraph();
|
||||
Assert.assertEquals("base has 8 SCCs", 8, IteratorUtil.count(new SCCIterator<String>(base)));
|
||||
|
||||
NumberedGraph<String> x = new ExtensionGraph<String>(base);
|
||||
augmentA(x);
|
||||
Assert.assertEquals("base+A has 5 SCCs", 5, IteratorUtil.count(new SCCIterator<String>(x)));
|
||||
Assert.assertEquals("base has 8 SCCs", 8, IteratorUtil.count(new SCCIterator<String>(base)));
|
||||
|
||||
NumberedGraph<String> y = new ExtensionGraph<String>(x);
|
||||
augmentB(y);
|
||||
Assert.assertEquals("base+A+B has 7 SCCs", 7, IteratorUtil.count(new SCCIterator<String>(y)));
|
||||
Assert.assertEquals("base+A has 5 SCCs", 5, IteratorUtil.count(new SCCIterator<String>(x)));
|
||||
Assert.assertEquals("base has 8 SCCs", 8, IteratorUtil.count(new SCCIterator<String>(base)));
|
||||
|
||||
NumberedGraph<String> z = new ExtensionGraph<String>(y);
|
||||
augmentC(z);
|
||||
Assert.assertEquals("base+A+B+C has 3 SCCs", 3, IteratorUtil.count(new SCCIterator<String>(z)));
|
||||
Assert.assertEquals("base+A+B has 7 SCCs", 7, IteratorUtil.count(new SCCIterator<String>(y)));
|
||||
Assert.assertEquals("base+A has 5 SCCs", 5, IteratorUtil.count(new SCCIterator<String>(x)));
|
||||
Assert.assertEquals("base has 8 SCCs", 8, IteratorUtil.count(new SCCIterator<String>(base)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,305 @@
|
|||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.util.collections.CompoundIterator;
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.graph.NumberedEdgeManager;
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
import com.ibm.wala.util.graph.NumberedNodeManager;
|
||||
import com.ibm.wala.util.intset.EmptyIntSet;
|
||||
import com.ibm.wala.util.intset.IntIterator;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.IntSetAction;
|
||||
import com.ibm.wala.util.intset.IntSetUtil;
|
||||
import com.ibm.wala.util.intset.MutableIntSet;
|
||||
|
||||
public class ExtensionGraph<T> implements NumberedGraph<T> {
|
||||
private final NumberedGraph<T> original;
|
||||
private final NumberedNodeManager<T> additionalNodes = new SlowNumberedNodeManager<T>();
|
||||
private final NumberedEdgeManager<T> edgeManager = new NumberedEdgeManager<T>() {
|
||||
private final Map<T, MutableIntSet> inEdges = HashMapFactory.make();
|
||||
private final Map<T, MutableIntSet> outEdges = HashMapFactory.make();
|
||||
|
||||
private Iterator<T> nodes(final T node, final Map<T,? extends IntSet> extra) {
|
||||
if (extra.containsKey(node)) {
|
||||
return new Iterator<T>() {
|
||||
private final IntIterator i = extra.get(node).intIterator();
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return ExtensionGraph.this.getNode(i.next());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return EmptyIterator.instance();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> getPredNodes(T n) {
|
||||
Iterator<T> orig = (original.containsNode(n)? original.getPredNodes(n): EmptyIterator.<T>instance());
|
||||
return new CompoundIterator<T>(orig, nodes(n, inEdges));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPredNodeCount(T n) {
|
||||
return
|
||||
(original.containsNode(n)? original.getPredNodeCount(n): 0) +
|
||||
(inEdges.containsKey(n)? inEdges.get(n).size(): 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> getSuccNodes(T n) {
|
||||
Iterator<T> orig = (original.containsNode(n)? original.getSuccNodes(n): EmptyIterator.<T>instance());
|
||||
return new CompoundIterator<T>(orig, nodes(n, outEdges));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSuccNodeCount(T n) {
|
||||
return
|
||||
(original.containsNode(n)? original.getSuccNodeCount(n): 0) +
|
||||
(outEdges.containsKey(n)? outEdges.get(n).size(): 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEdge(T src, T dst) {
|
||||
assert !original.hasEdge(src, dst);
|
||||
assert containsNode(src) && containsNode(dst);
|
||||
if (! inEdges.containsKey(dst)) { inEdges.put(dst, IntSetUtil.make()); }
|
||||
inEdges.get(dst).add(getNumber(src));
|
||||
if (! outEdges.containsKey(src)) { outEdges.put(src, IntSetUtil.make()); }
|
||||
outEdges.get(src).add(getNumber(dst));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEdge(T src, T dst) throws UnsupportedOperationException {
|
||||
assert hasEdge(src, dst);
|
||||
assert !original.hasEdge(src, dst);
|
||||
assert containsNode(src) && containsNode(dst);
|
||||
inEdges.get(dst).remove(getNumber(src));
|
||||
outEdges.get(src).remove(getNumber(dst));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllIncidentEdges(T node) throws UnsupportedOperationException {
|
||||
removeIncomingEdges(node);
|
||||
removeOutgoingEdges(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeIncomingEdges(T node) throws UnsupportedOperationException {
|
||||
assert !original.containsNode(node) || original.getPredNodeCount(node) == 0;
|
||||
inEdges.remove(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOutgoingEdges(T node) throws UnsupportedOperationException {
|
||||
assert !original.containsNode(node) || original.getSuccNodeCount(node) == 0;
|
||||
outEdges.remove(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
return original.hasEdge(src, dst) || outEdges.get(src).contains(getNumber(dst));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSet getSuccNodeNumbers(T node) {
|
||||
if (original.containsNode(node)) {
|
||||
if (outEdges.containsKey(node)) {
|
||||
MutableIntSet x = IntSetUtil.makeMutableCopy(original.getSuccNodeNumbers(node));
|
||||
x.addAll(outEdges.get(node));
|
||||
return x;
|
||||
} else {
|
||||
return original.getSuccNodeNumbers(node);
|
||||
}
|
||||
} else {
|
||||
if (outEdges.containsKey(node)) {
|
||||
return outEdges.get(node);
|
||||
} else {
|
||||
return EmptyIntSet.instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSet getPredNodeNumbers(T node) {
|
||||
if (original.containsNode(node)) {
|
||||
if (inEdges.containsKey(node)) {
|
||||
MutableIntSet x = IntSetUtil.makeMutableCopy(original.getPredNodeNumbers(node));
|
||||
x.addAll(inEdges.get(node));
|
||||
return x;
|
||||
} else {
|
||||
return original.getPredNodeNumbers(node);
|
||||
}
|
||||
} else {
|
||||
if (inEdges.containsKey(node)) {
|
||||
return inEdges.get(node);
|
||||
} else {
|
||||
return EmptyIntSet.instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public ExtensionGraph(NumberedGraph<T> original) {
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new CompoundIterator<T>(original.iterator(), additionalNodes.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfNodes() {
|
||||
return original.getNumberOfNodes() + additionalNodes.getNumberOfNodes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(T n) {
|
||||
assert !original.containsNode(n);
|
||||
additionalNodes.addNode(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(T n) throws UnsupportedOperationException {
|
||||
assert !original.containsNode(n);
|
||||
additionalNodes.removeNode(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsNode(T n) {
|
||||
return original.containsNode(n) || additionalNodes.containsNode(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumber(T N) {
|
||||
if (original.containsNode(N)) {
|
||||
return original.getNumber(N);
|
||||
} else {
|
||||
return additionalNodes.getNumber(N) + original.getMaxNumber() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getNode(int number) {
|
||||
if (number <= original.getMaxNumber()) {
|
||||
return original.getNode(number);
|
||||
} else {
|
||||
return additionalNodes.getNode(number - original.getMaxNumber() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxNumber() {
|
||||
if (additionalNodes.iterator().hasNext()) {
|
||||
return original.getMaxNumber() + 1 + additionalNodes.getMaxNumber();
|
||||
} else {
|
||||
return original.getMaxNumber();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterateNodes(IntSet s) {
|
||||
final MutableIntSet os = IntSetUtil.make();
|
||||
final MutableIntSet es = IntSetUtil.make();
|
||||
s.foreach(new IntSetAction() {
|
||||
@Override
|
||||
public void act(int x) {
|
||||
if (x <= original.getMaxNumber()) {
|
||||
os.add(x);
|
||||
} else {
|
||||
es.add(x - original.getMaxNumber() - 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
return new CompoundIterator<T>(original.iterateNodes(os), additionalNodes.iterateNodes(es));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> getPredNodes(T n) {
|
||||
return edgeManager.getPredNodes(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPredNodeCount(T n) {
|
||||
return edgeManager.getPredNodeCount(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSet getPredNodeNumbers(T node) {
|
||||
return edgeManager.getPredNodeNumbers(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> getSuccNodes(T n) {
|
||||
return edgeManager.getSuccNodes(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSuccNodeCount(T N) {
|
||||
return edgeManager.getSuccNodeCount(N);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSet getSuccNodeNumbers(T node) {
|
||||
return edgeManager.getSuccNodeNumbers(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEdge(T src, T dst) {
|
||||
assert !original.hasEdge(src, dst);
|
||||
edgeManager.addEdge(src, dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEdge(T src, T dst) throws UnsupportedOperationException {
|
||||
assert !original.hasEdge(src, dst);
|
||||
edgeManager.removeEdge(src, dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllIncidentEdges(T node) throws UnsupportedOperationException {
|
||||
assert !original.containsNode(node);
|
||||
edgeManager.removeAllIncidentEdges(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeIncomingEdges(T node) throws UnsupportedOperationException {
|
||||
assert !original.containsNode(node);
|
||||
edgeManager.removeIncomingEdges(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOutgoingEdges(T node) throws UnsupportedOperationException {
|
||||
assert !original.containsNode(node);
|
||||
edgeManager.removeOutgoingEdges(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
return edgeManager.hasEdge(src, dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNodeAndEdges(T n) throws UnsupportedOperationException {
|
||||
assert !original.containsNode(n);
|
||||
edgeManager.removeAllIncidentEdges(n);
|
||||
additionalNodes.removeNode(n);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue