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

com.ibm.wala.util.graph.GraphSlicer Maven / Gradle / Ivy

The newest version!
/*
 * 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 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.graph.impl.GraphInverter;
import com.ibm.wala.util.graph.traverse.DFS;
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 java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;

/** Utilities related to simple graph subset operations. */
public class GraphSlicer {

  /**
   * Performs a backward slice.
   *
   * @param  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  Set slice(Graph g, Predicate p) {
    if (g == null) {
      throw new IllegalArgumentException("g is null");
    }
    HashSet roots = HashSetFactory.make();
    for (T o : g) {
      if (p.test(o)) {
        roots.add(o);
      }
    }

    Set result = DFS.getReachableNodes(GraphInverter.invert(g), roots);

    return result;
  }

  /** Prune a graph to only the nodes accepted by the {@link Predicate} p */
  public static  Graph prune(final Graph g, final Predicate p) {
    if (g == null) {
      throw new IllegalArgumentException("g is null");
    }
    final NodeManager n =
        new NodeManager<>() {
          int nodeCount = -1;

          @Override
          public Iterator iterator() {
            return new FilterIterator<>(g.iterator(), p);
          }

          @Override
          public Stream stream() {
            return g.stream().filter(p);
          }

          @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(@Nullable T n) {
            return p.test(n) && g.containsNode(n);
          }
        };
    final EdgeManager e =
        new EdgeManager<>() {

          @Override
          public Iterator getPredNodes(@Nullable T n) {
            return new FilterIterator<>(g.getPredNodes(n), p);
          }

          @Override
          public int getPredNodeCount(T n) {
            return IteratorUtil.count(getPredNodes(n));
          }

          @Override
          public Iterator getSuccNodes(@Nullable T n) {
            return new FilterIterator<>(g.getSuccNodes(n), p);
          }

          @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(@Nullable T src, @Nullable T dst) {
            return g.hasEdge(src, dst) && p.test(src) && p.test(dst);
          }
        };
    AbstractGraph output =
        new AbstractGraph<>() {

          @SuppressWarnings({"unchecked", "rawtypes"})
          @Override
          protected String nodeString(T n, boolean forEdge) {
            if (g instanceof AbstractGraph) {
              return ((AbstractGraph) g).nodeString(n, forEdge);
            } else {
              return super.nodeString(n, forEdge);
            }
          }

          @Override
          protected NodeManager getNodeManager() {
            return n;
          }

          @Override
          protected EdgeManager getEdgeManager() {
            return e;
          }
        };

    return output;
  }

  public static  AbstractGraph project(final Graph G, final Predicate fmember) {
    final NodeManager nodeManager =
        new NodeManager<>() {
          private int count = -1;

          @Override
          public void addNode(E n) {
            throw new UnsupportedOperationException();
          }

          @Override
          public boolean containsNode(@Nullable 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 iterator() {
            return new FilterIterator<>(G.iterator(), fmember);
          }

          @Override
          public Stream stream() {
            return G.stream().filter(fmember);
          }

          @Override
          public void removeNode(E n) {
            throw new UnsupportedOperationException();
          }
        };

    final EdgeManager edgeManager =
        new EdgeManager<>() {

          private final Map> succs = new HashMap<>();

          private final Map> preds = new HashMap<>();

          private Set getConnected(E inst, Function> fconnected) {
            Set result = new LinkedHashSet<>();
            Set seenInsts = new HashSet<>();
            Set newInsts = Iterator2Collection.toSet(fconnected.apply(inst));
            while (!newInsts.isEmpty()) {
              Set nextInsts = new HashSet<>();
              for (E s : newInsts) {
                if (seenInsts.add(s)) {
                  if (nodeManager.containsNode(s)) {
                    result.add(s);
                  } else {
                    Iterator 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, G::getPredNodes));
          }

          private void setSuccNodes(E N) {
            succs.put(N, getConnected(N, G::getSuccNodes));
          }

          @NullUnmarked
          @Override
          public int getPredNodeCount(E N) {
            if (!preds.containsKey(N)) {
              setPredNodes(N);
            }
            return preds.get(N).size();
          }

          @NullUnmarked
          @Override
          public Iterator getPredNodes(@Nullable E N) {
            if (!preds.containsKey(N)) {
              setPredNodes(N);
            }
            return preds.get(N).iterator();
          }

          @NullUnmarked
          @Override
          public int getSuccNodeCount(E N) {
            if (!succs.containsKey(N)) {
              setSuccNodes(N);
            }
            return succs.get(N).size();
          }

          @NullUnmarked
          @Override
          public Iterator getSuccNodes(@Nullable E N) {
            if (!succs.containsKey(N)) {
              setSuccNodes(N);
            }
            return succs.get(N).iterator();
          }

          @NullUnmarked
          @Override
          public boolean hasEdge(@Nullable E src, @Nullable 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<>() {

      @SuppressWarnings({"unchecked", "rawtypes"})
      @Override
      protected String nodeString(E n, boolean forEdge) {
        if (G instanceof AbstractGraph) {
          return ((AbstractGraph) G).nodeString(n, forEdge);
        } else {
          return super.nodeString(n, forEdge);
        }
      }

      @Override
      protected EdgeManager getEdgeManager() {
        return edgeManager;
      }

      @Override
      protected NodeManager getNodeManager() {
        return nodeManager;
      }
    };
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy