예제 #1
0
        public void If()
        {
            // Artificially construct an if construct.
            var graph = TestGraphs.CreateIfElse();

            var n1 = graph.GetNodeById(1);
            var n2 = graph.GetNodeById(2);
            var n3 = graph.GetNodeById(3);
            var n4 = graph.GetNodeById(4);

            // Record a depth first traversal.
            var traversal = new DepthFirstTraversal();
            var recorder  = new TraversalOrderRecorder(traversal);

            traversal.Run(n1);

            // Check if n1 is before any node in the traversal.
            Assert.All(graph.GetNodes(),
                       n => Assert.True(n1 == n || recorder.GetIndex(n1) < recorder.GetIndex(n)));

            // DFS should either pick n2 or n3. If n2, then n4 is before n3, otherwise before n2.
            if (recorder.GetIndex(n2) < recorder.GetIndex(n3))
            {
                Assert.True(recorder.GetIndex(n4) < recorder.GetIndex(n3));
            }
            else
            {
                Assert.True(recorder.GetIndex(n4) < recorder.GetIndex(n2));
            }
        }
예제 #2
0
        public void PostOrderTest()
        {
            var graph = new Graph();

            graph.Nodes.Add("0");
            graph.Nodes.Add("1");
            graph.Nodes.Add("2");
            graph.Nodes.Add("3");
            graph.Nodes.Add("4");

            graph.Edges.Add("0", "2");
            graph.Edges.Add("2", "1");
            graph.Edges.Add("1", "0");
            graph.Edges.Add("0", "3");
            graph.Edges.Add("3", "4");

            var traversal = new DepthFirstTraversal();
            var recorder  = new PostOrderRecorder(traversal);

            traversal.Run(graph.Nodes["0"]);

            var order = recorder.GetOrder();

            Assert.Equal(order.Count, graph.Nodes.Count);
            Assert.All(graph.Nodes, n => Assert.True(order.IndexOf(graph.Nodes["0"]) >= order.IndexOf(n)));
            Assert.True(order.IndexOf(graph.Nodes["1"]) < order.IndexOf(graph.Nodes["2"]));
            Assert.True(order.IndexOf(graph.Nodes["4"]) < order.IndexOf(graph.Nodes["3"]));
        }
예제 #3
0
        public void TestDFSUnDirectedGraph()
        {
            IGraph graph = new Graph();

            graph.AddNode(new Node("s"));
            graph.AddNode(new Node("a"));
            graph.AddNode(new Node("b"));
            graph.AddNode(new Node("c"));
            graph.AddNode(new Node("d"));
            graph.AddNode(new Node("e"));


            graph.BuildEdge("s", "a", 0);
            graph.BuildEdge("s", "b", 0);
            graph.BuildEdge("a", "c", 0);
            graph.BuildEdge("a", "b", 0);
            graph.BuildEdge("b", "d", 0);
            graph.BuildEdge("c", "e", 0);
            graph.BuildEdge("c", "d", 0);
            graph.BuildEdge("d", "e", 0);

            DepthFirstTraversal dfs = new DepthFirstTraversal(graph, graph.GetNodeByID("s"));
            TraversalResult     tr  = dfs.Run();

            Assert.Equal("s,a,c,e,d,b", string.Join(",", tr.Nodes.Select(node => node.ID)));
        }
예제 #4
0
        public void TestDFSDirectedGraph()
        {
            INode node1 = new Node("1");
            INode node2 = new Node("2");
            INode node3 = new Node("3");
            INode node4 = new Node("4");
            INode node5 = new Node("5");

            IGraph graph = new Graph(true);

            graph.AddNode(node1);
            graph.AddNode(node2);
            graph.AddNode(node3);
            graph.AddNode(node4);
            graph.AddNode(node5);

            graph.BuildEdge(node1, node2, 0);
            graph.BuildEdge(node1, node3, 0);
            graph.BuildEdge(node2, node4, 0);
            graph.BuildEdge(node2, node5, 0);

            DepthFirstTraversal dfs             = new DepthFirstTraversal(graph, node1);
            TraversalResult     traversalResult = dfs.Run();

            string result = string.Join(",", traversalResult.Nodes.Select(node => node.ID));

            Assert.Equal("1,2,4,5,3", result);
        }
예제 #5
0
        public void DepthFirstDepthShouldBeTwoWhenEndNodeIsFoundTest()
        {
            // Arrange
            var start = Tree.Nodes["1"];
            var stop  = Tree.Nodes["5"];

            var  traversal = new DepthFirstTraversal();
            Node result    = null;
            int  depth     = 0;

            traversal.NodeDiscovered += (sender, args) =>
            {
                if (args.NewNode == stop)
                {
                    args.ContinueExploring = false;
                    args.Abort             = true;
                    result = args.NewNode;
                    depth  = args.Depth;
                }
            };

            // Act
            traversal.Run(start);

            // Assert
            Assert.Equal(stop, result);
            Assert.Equal(2, depth);
        }
예제 #6
0
        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));
        }
예제 #7
0
        public void DepthFirstOrderTest()
        {
            var traversal = new DepthFirstTraversal();
            var recorder  = new TraversalOrderRecorder(traversal);

            traversal.Run(Tree.Nodes["1"]);

            if (recorder.GetIndex(Tree.Nodes["2"]) < recorder.GetIndex(Tree.Nodes["3A"]))
            {
                Assert.True(recorder.GetIndex(Tree.Nodes["4A"]) < recorder.GetIndex(Tree.Nodes["3A"]));
            }
            else
            {
                Assert.True(recorder.GetIndex(Tree.Nodes["5"]) < recorder.GetIndex(Tree.Nodes["4A"]));
            }
        }
예제 #8
0
        public void DepthFirstDepthShouldBeZeroOnFirstNodeTest()
        {
            // Arrange
            var start = new Node("7");

            Tree.Nodes.Add(start);

            var traversal = new DepthFirstTraversal();

            traversal.NodeDiscovered += (sender, args) =>
            {
                Assert.Equal(0, args.Depth);
            };

            // Act
            traversal.Run(start);

            // Assert done in NodeDiscoverd event handler.
        }
예제 #9
0
        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());
        }
예제 #10
0
        public void LoopReversed()
        {
            // Artificially construct a looping construct.
            var graph = TestGraphs.CreateLoop();
            var n1    = graph.GetNodeById(1);
            var n2    = graph.GetNodeById(2);
            var n3    = graph.GetNodeById(3);
            var n4    = graph.GetNodeById(4);

            // Record a depth first traversal.
            var traversal = new DepthFirstTraversal(true);
            var recorder  = new TraversalOrderRecorder(traversal);

            traversal.Run(n4);

            // Check if n1 is before any node in the traversal.
            Assert.All(graph.GetNodes(),
                       n => Assert.True(n4 == n || recorder.GetIndex(n4) < recorder.GetIndex(n)));

            Assert.True(recorder.GetIndex(n1) > recorder.GetIndex(n3));
        }
예제 #11
0
        /// <summary>
        /// Determines whether a graph contains at least one cycle.
        /// </summary>
        /// <param name="graph">The graph to test.</param>
        /// <returns>True if the graph is cyclic, false otherwise.</returns>
        public static bool IsCyclic(this Graph graph)
        {
            var visited = new HashSet <Node>();

            foreach (var node in graph.Nodes)
            {
                if (!visited.Add(node))
                {
                    return(false);
                }

                bool cycleDetected = false;

                var reachableNodes = new HashSet <Node>();
                var visitedEdges   = new HashSet <Edge>();

                var traversal = new DepthFirstTraversal();
                traversal.NodeDiscovered += (sender, args) =>
                {
                    if (visitedEdges.Add(args.Origin) && !reachableNodes.Add(args.NewNode))
                    {
                        args.ContinueExploring = false;
                        cycleDetected          = true;
                    }
                };
                traversal.Run(node);

                if (cycleDetected)
                {
                    return(true);
                }

                visited.UnionWith(reachableNodes);
            }

            return(false);
        }
예제 #12
0
        public static ICollection <ISet <Node> > FindStronglyConnectedComponents(this Node entrypoint)
        {
            var graph = entrypoint.ParentGraph;

            var traversal = new DepthFirstTraversal();
            var recorder  = new PostOrderRecorder(traversal);

            traversal.Run(entrypoint);

            var transpose = graph.Transpose();

            var visited = new HashSet <Node>();
            var result  = new List <ISet <Node> >();

            foreach (var node in recorder.GetOrder().Reverse())
            {
                if (!visited.Contains(node))
                {
                    var subTraversal = new DepthFirstTraversal();
                    var component    = new HashSet <Node>();
                    subTraversal.NodeDiscovered += (sender, args) =>
                    {
                        if (visited.Add(graph.Nodes[args.NewNode.Name]))
                        {
                            args.ContinueExploring = true;
                            component.Add(graph.Nodes[args.NewNode.Name]);
                        }
                    };
                    subTraversal.Run(transpose.Nodes[node.Name]);

                    result.Add(component);
                }
            }

            return(result);
        }
예제 #13
0
        /// <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);
        }