package freeboogie.tc; import java.util.Map; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import freeboogie.util.Closure; import freeboogie.util.Pair; /** * Represents a graph of objects of type {@code N}. The implementation * uses adjacency lists and hash tables. * * @author rgrig * @author reviewed by TODO * @param <N> the type of the graph node */ public class SimpleGraph<N> { private HashMap<N,HashSet<N>> parents; private HashMap<N,HashSet<N>> children; /** Construct an empty graph. */ public SimpleGraph() { parents = new HashMap<N,HashSet<N>>(); children = new HashMap<N,HashSet<N>>(); } /** * Adds a node to the graph. Does nothing if the node is already * in the graph. * @param n the node to add to the graph */ public void node(N n) { assert parents.size() == children.size(); if (parents.containsKey(n)) return; parents.put(n, new HashSet<N>()); children.put(n, new HashSet<N>()); } /** * Adds an edge to the graph. * @param from the source * @param to the target */ public void edge(N from, N to) { node(from); node(to); parents.get(to).add(from); children.get(from).add(to); } /** * Where can you go from {@code from}? The user shall not modify the * return value. * @param from the source, must be in this graph * @return the tips of the out-edges */ public Set<N> to(N from) { return children.get(from); } /** * From where can you get to {@code to}? The user shall not modify the * return value. * @param to the target, must be in this graph * @return the sources of the in-edges */ public Set<N> from(N to) { return parents.get(to); } /** * Execute {@code f} on all nodes, in a random order. * @param f the function to execute on all nodes */ public void iterNode(Closure<N> f) { for (N n : parents.keySet()) f.go(n); } /** * Execute {@code f} on all edges, in a random order. * @param f the function to execute on all nodes */ public void iterEdge(Closure<Pair<N,N>> f) { for (Map.Entry<N, HashSet<N>> a : parents.entrySet()) for (N b : a.getValue()) f.go(new Pair<N,N>(b, a.getKey())); } }