336 lines
8.7 KiB
Java
336 lines
8.7 KiB
Java
/*******************************************************************************
|
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* Contributors:
|
|
* IBM Corporation - initial API and implementation
|
|
*******************************************************************************/
|
|
package com.ibm.wala.util.graph;
|
|
|
|
import java.util.Collection;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import com.ibm.wala.util.Predicate;
|
|
import com.ibm.wala.util.collections.FilterIterator;
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
|
import com.ibm.wala.util.collections.Iterator2Collection;
|
|
import com.ibm.wala.util.collections.IteratorUtil;
|
|
import com.ibm.wala.util.debug.Assertions;
|
|
import com.ibm.wala.util.functions.Function;
|
|
import com.ibm.wala.util.graph.impl.GraphInverter;
|
|
import com.ibm.wala.util.graph.traverse.DFS;
|
|
|
|
/**
|
|
* Utilities related to simple graph subset operations.
|
|
*/
|
|
public class GraphSlicer {
|
|
|
|
/**
|
|
* Performs a backward slice.
|
|
*
|
|
* @param <T> type for nodes
|
|
* @param g the graph to slice
|
|
* @param p identifies targets for the backward slice
|
|
* @return the set of nodes in g, from which any of the targets (nodes that f accepts) is reachable.
|
|
*/
|
|
public static <T> Set<T> slice(Graph<T> g, Predicate<T> p){
|
|
if (g == null) {
|
|
throw new IllegalArgumentException("g is null");
|
|
}
|
|
HashSet<T> roots = HashSetFactory.make();
|
|
for (Iterator<? extends T> it = g.iterator(); it.hasNext();) {
|
|
T o = it.next();
|
|
if (p.test(o)) {
|
|
roots.add(o);
|
|
}
|
|
}
|
|
|
|
Set<T> result = DFS.getReachableNodes(GraphInverter.invert(g), roots);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Prune a graph to only the nodes accepted by the {@link Predicate} p
|
|
*/
|
|
public static <T> Graph<T> prune(final Graph<T> g, final Predicate<T> p) {
|
|
if (g == null) {
|
|
throw new IllegalArgumentException("g is null");
|
|
}
|
|
final NodeManager<T> n = new NodeManager<T>() {
|
|
int nodeCount = -1;
|
|
|
|
@Override
|
|
public Iterator<T> iterator() {
|
|
return Predicate.filter(g.iterator(), p).iterator();
|
|
}
|
|
|
|
@Override
|
|
public int getNumberOfNodes() {
|
|
if (nodeCount == -1) {
|
|
nodeCount = IteratorUtil.count(iterator());
|
|
}
|
|
return nodeCount;
|
|
}
|
|
|
|
@Override
|
|
public void addNode(T n) {
|
|
Assertions.UNREACHABLE();
|
|
}
|
|
|
|
@Override
|
|
public void removeNode(T n) {
|
|
Assertions.UNREACHABLE();
|
|
}
|
|
|
|
@Override
|
|
public boolean containsNode(T n) {
|
|
return p.test(n) && g.containsNode(n);
|
|
}
|
|
|
|
};
|
|
final EdgeManager<T> e = new EdgeManager<T>() {
|
|
|
|
@Override
|
|
public Iterator<T> getPredNodes(T n) {
|
|
return Predicate.filter(g.getPredNodes(n), p).iterator();
|
|
}
|
|
|
|
@Override
|
|
public int getPredNodeCount(T n) {
|
|
return IteratorUtil.count(getPredNodes(n));
|
|
}
|
|
|
|
@Override
|
|
public Iterator<T> getSuccNodes(T n) {
|
|
return Predicate.filter(g.getSuccNodes(n), p).iterator();
|
|
}
|
|
|
|
@Override
|
|
public int getSuccNodeCount(T N) {
|
|
return IteratorUtil.count(getSuccNodes(N));
|
|
}
|
|
|
|
@Override
|
|
public void addEdge(T src, T dst) {
|
|
Assertions.UNREACHABLE();
|
|
}
|
|
|
|
@Override
|
|
public void removeEdge(T src, T dst) {
|
|
Assertions.UNREACHABLE();
|
|
}
|
|
|
|
@Override
|
|
public void removeAllIncidentEdges(T node) {
|
|
Assertions.UNREACHABLE();
|
|
}
|
|
|
|
@Override
|
|
public void removeIncomingEdges(T node) {
|
|
Assertions.UNREACHABLE();
|
|
}
|
|
|
|
@Override
|
|
public void removeOutgoingEdges(T node) {
|
|
Assertions.UNREACHABLE();
|
|
}
|
|
|
|
@Override
|
|
public boolean hasEdge(T src, T dst) {
|
|
return g.hasEdge(src, dst) && p.test(src) && p.test(dst);
|
|
}
|
|
|
|
};
|
|
AbstractGraph<T> output = new AbstractGraph<T>() {
|
|
|
|
@Override
|
|
protected NodeManager<T> getNodeManager() {
|
|
return n;
|
|
}
|
|
|
|
@Override
|
|
protected EdgeManager<T> getEdgeManager() {
|
|
return e;
|
|
}
|
|
|
|
};
|
|
|
|
return output;
|
|
}
|
|
|
|
public static <E> AbstractGraph<E> project(final Graph<E> G, final Predicate<E> fmember) {
|
|
final NodeManager<E> nodeManager = new NodeManager<E>() {
|
|
private int count = -1;
|
|
|
|
@Override
|
|
public void addNode(E n) {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
public boolean containsNode(E N) {
|
|
return G.containsNode(N) && fmember.test(N);
|
|
}
|
|
|
|
@Override
|
|
public int getNumberOfNodes() {
|
|
if (count == -1) {
|
|
count = IteratorUtil.count(iterator());
|
|
}
|
|
return count;
|
|
}
|
|
|
|
@Override
|
|
public Iterator<E> iterator() {
|
|
return new FilterIterator<E>(G.iterator(), fmember);
|
|
}
|
|
|
|
@Override
|
|
public void removeNode(E n) {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
};
|
|
|
|
final EdgeManager<E> edgeManager = new EdgeManager<E>() {
|
|
|
|
private Map<E, Collection<E>> succs = new HashMap<E, Collection<E>>();
|
|
|
|
private Map<E, Collection<E>> preds = new HashMap<E, Collection<E>>();
|
|
|
|
private Set<E> getConnected(E inst, Function<E, Iterator<? extends E>> fconnected) {
|
|
Set<E> result = new LinkedHashSet<E>();
|
|
Set<E> seenInsts = new HashSet<E>();
|
|
Set<E> newInsts = Iterator2Collection.toSet(fconnected.apply(inst));
|
|
while (!newInsts.isEmpty()) {
|
|
Set<E> nextInsts = new HashSet<E>();
|
|
for (E s : newInsts) {
|
|
if (!seenInsts.contains(s)) {
|
|
seenInsts.add(s);
|
|
if (nodeManager.containsNode(s)) {
|
|
result.add(s);
|
|
} else {
|
|
Iterator<? extends E> ss = fconnected.apply(s);
|
|
while (ss.hasNext()) {
|
|
E n = ss.next();
|
|
if (!seenInsts.contains(n)) {
|
|
nextInsts.add(n);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
newInsts = nextInsts;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private void setPredNodes(E N) {
|
|
preds.put(N, getConnected(N, new Function<E, Iterator<? extends E>>() {
|
|
@Override
|
|
public Iterator<? extends E> apply(E object) {
|
|
return G.getPredNodes(object);
|
|
}
|
|
}));
|
|
}
|
|
|
|
private void setSuccNodes(E N) {
|
|
succs.put(N, getConnected(N, new Function<E, Iterator<? extends E>>() {
|
|
@Override
|
|
public Iterator<? extends E> apply(E object) {
|
|
return G.getSuccNodes(object);
|
|
}
|
|
}));
|
|
}
|
|
|
|
@Override
|
|
public int getPredNodeCount(E N) {
|
|
if (!preds.containsKey(N)) {
|
|
setPredNodes(N);
|
|
}
|
|
return preds.get(N).size();
|
|
}
|
|
|
|
@Override
|
|
public Iterator<E> getPredNodes(E N) {
|
|
if (!preds.containsKey(N)) {
|
|
setPredNodes(N);
|
|
}
|
|
return preds.get(N).iterator();
|
|
}
|
|
|
|
@Override
|
|
public int getSuccNodeCount(E N) {
|
|
if (!succs.containsKey(N)) {
|
|
setSuccNodes(N);
|
|
}
|
|
return succs.get(N).size();
|
|
}
|
|
|
|
@Override
|
|
public Iterator<E> getSuccNodes(E N) {
|
|
if (!succs.containsKey(N)) {
|
|
setSuccNodes(N);
|
|
}
|
|
return succs.get(N).iterator();
|
|
}
|
|
|
|
@Override
|
|
public boolean hasEdge(E src, E dst) {
|
|
if (!preds.containsKey(dst)) {
|
|
setPredNodes(dst);
|
|
}
|
|
return preds.get(dst).contains(src);
|
|
}
|
|
|
|
@Override
|
|
public void addEdge(E src, E dst) {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
public void removeAllIncidentEdges(E node) throws UnsupportedOperationException {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
public void removeEdge(E src, E dst) throws UnsupportedOperationException {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
public void removeIncomingEdges(E node) throws UnsupportedOperationException {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
public void removeOutgoingEdges(E node) throws UnsupportedOperationException {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
};
|
|
|
|
return new AbstractGraph<E>() {
|
|
|
|
@Override
|
|
protected EdgeManager<E> getEdgeManager() {
|
|
return edgeManager;
|
|
}
|
|
|
|
@Override
|
|
protected NodeManager<E> getNodeManager() {
|
|
return nodeManager;
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
} |