package plume; import java.util.*; import java.io.*; /** * Graph utility methods. This class does not model a graph: all methods * are static. */ public class GraphMDE { // Algorithms for computing dominators: // // Wikipedia: // // dominator of the start node is the start itself // Dom(n_0) = {n_0} // // for all other nodes, set all nodes as the dominators // for each n in N - {n_0} // Dom(n) = N; // // iteratively eliminate nodes that are not dominators // while changes in any Dom(n) // for each n in N - {n_0}: // Dom(n) = {n} union with intersection over all p in pred(n) of Dom(p) // // Cooper/Harvey/Kennedy: // for all nodes, n // DOM[n] := {1 . . .N} // Changed := true // while (Changed) // Changed := false // for all nodes, n, in reverse postorder // new_set := (Intersect_{p:=preds(n)} DOM[p]) union {n} // if (new_set != DOM[n]) // DOM[n] := new_set // Changed := true // The two algorithms are essentially the same; this implementation // follows the Wikipedia one. /** * Computes, for each node in the graph, its set of (pre-)dominators. * Supply a successor graph if you want post-dominators. **/ public static <T> Map<T,List<T>> dominators(Map<T,List<T>> preds) { List<T> nodes = new ArrayList<T>(preds.keySet()); // Compute roots & non-roots, for convenience List<T> roots = new ArrayList<T>(); List<T> non_roots = new ArrayList<T>(); Map<T,List<T>> dom = new HashMap<T,List<T>>(); // Initialize result: for roots just the root, otherwise everything for (T node : preds.keySet()) { if (preds.get(node).isEmpty()) { // This is a root roots.add(node); // Its only dominator is itself. dom.put(node, new ArrayList<T>(Collections.singleton(node))); } else { non_roots.add(node); dom.put(node, new ArrayList<T>(nodes)); } } assert roots.size() + non_roots.size() == nodes.size(); boolean changed = true; while (changed) { changed = false; for (T node : non_roots) { List<T> new_doms = null; assert preds.containsKey(node); for (T pred : preds.get(node)) { assert dom.containsKey(pred); /*@NonNull*/ List<T> dom_of_pred = dom.get(pred); if (new_doms == null) { // make copy because we may side-effect new_doms new_doms = new ArrayList<T>(dom_of_pred); } else { new_doms.retainAll(dom_of_pred); } } new_doms.add(node); assert dom.containsKey(node); if (! dom.get(node).equals(new_doms)) { dom.put(node, new_doms); changed = true; } } } for (T node : preds.keySet()) { assert dom.containsKey(node); assert dom.get(node).contains(node); } return dom; } public static <T> void print(Map<T,List<T>> graph, PrintStream ps, int indent) { String indentString = ""; for (int i=0; i<indent; i++) { indentString += " "; } for (T node : graph.keySet()) { ps.printf("%s%s%n", indentString, node); for (T child : graph.get(node)) { ps.printf(" %s%s%n", indentString, child); } } } }