public void SingleNode() { var graph = TestGraphs.CreateSingularGraph(); var startNode = graph.GetNodeById(1); // Record a depth first traversal. var traversal = new DepthFirstTraversal(); var recorder = new TraversalOrderRecorder(traversal); traversal.Run(startNode); Assert.Single(recorder.GetTraversal()); Assert.Equal(0, recorder.GetIndex(startNode)); }
public void PathReversed() { // Artificially construct a path of four nodes in sequential order. var graph = TestGraphs.CreatePath(); // Record a depth first traversal. var traversal = new DepthFirstTraversal(true); var recorder = new TraversalOrderRecorder(traversal); traversal.Run(graph.GetNodeById(4)); // Traversal should exactly be the path. Assert.Equal(new INode[] { graph.GetNodeById(4), graph.GetNodeById(3), graph.GetNodeById(2), graph.GetNodeById(1), }, recorder.GetTraversal()); }
/// <summary> /// Computes the dominator tree of a control flow graph, defined by its entrypoint. /// </summary> /// <param name="entrypoint">The entrypoint of the control flow graph.</param> /// <returns>A dictionary mapping all the nodes to their immediate dominator.</returns> /// <remarks> /// The algorithm used is based on the one engineered by Lengauer and Tarjan. /// https://www.cs.princeton.edu/courses/archive/fall03/cs528/handouts/a%20fast%20algorithm%20for%20finding.pdf /// https://www.cl.cam.ac.uk/~mr10/lengtarj.pdf /// </remarks> private static IDictionary <IIdentifiedNode, IIdentifiedNode> GetImmediateDominators(IIdentifiedNode entrypoint) { var idom = new Dictionary <IIdentifiedNode, IIdentifiedNode>(); var semi = new Dictionary <IIdentifiedNode, IIdentifiedNode>(); var ancestor = new Dictionary <IIdentifiedNode, IIdentifiedNode>(); var bucket = new Dictionary <IIdentifiedNode, ISet <IIdentifiedNode> >(); var traversal = new DepthFirstTraversal(); var order = new TraversalOrderRecorder(traversal); var parents = new ParentRecorder(traversal); traversal.Run(entrypoint); var orderedNodes = order.GetTraversal(); foreach (var node in orderedNodes.Cast <IIdentifiedNode>()) { idom[node] = null; semi[node] = node; ancestor[node] = null; bucket[node] = new HashSet <IIdentifiedNode>(); } for (int i = orderedNodes.Count - 1; i >= 1; i--) { var current = (IIdentifiedNode)orderedNodes[i]; var parent = (IIdentifiedNode)parents.GetParent(current); // step 2 foreach (var predecessor in current.GetPredecessors().Cast <IIdentifiedNode>()) { var u = Eval(predecessor, ancestor, semi, order); if (order.GetIndex(semi[current]) > order.GetIndex(semi[u])) { semi[current] = semi[u]; } } bucket[semi[current]].Add(current); Link(parent, current, ancestor); // step 3 foreach (var bucketNode in bucket[parent]) { var u = Eval(bucketNode, ancestor, semi, order); if (order.GetIndex(semi[u]) < order.GetIndex(semi[bucketNode])) { idom[bucketNode] = u; } else { idom[bucketNode] = parent; } } bucket[parent].Clear(); } // step 4 for (int i = 1; i < orderedNodes.Count; i++) { var w = (IIdentifiedNode)orderedNodes[i]; if (idom[w] != semi[w]) { idom[w] = idom[idom[w]]; } } idom[entrypoint] = entrypoint; return(idom); }