예제 #1
0
        /*public static IEnumerable<IMutableVertexAndEdgeListGraph<TVertex, TEdge>> StronglyConnectedComponents<TVertex, TEdge>(this IVertexListGraph<TVertex, TEdge> g, Func<IMutableVertexAndEdgeListGraph<TVertex, TEdge>> componentMaker)
         *  where TEdge : QuickGraph.IEdge<TVertex>
         * {
         *  g.StronglyConnectedComponents(out var scc);
         *
         *  return scc.GroupBy(kv => kv.Value).Select(group =>
         *  {
         *      var c = componentMaker();
         *
         *      group.ForEach(kv => c.AddVertex(kv.Key));
         *
         *      foreach (var v1 in c.Vertices)
         *          foreach (var v2 in c.Vertices)
         *          {
         *              if (g.TryGetEdges(v1, v2, out var edges))
         *                  edges.ForEach(e => c.AddEdge(e));
         *          }
         *  });
         * }*/



        /// <summary>
        /// Returns the list of weakly connected components in a graph. A weakly connected component is one in which
        /// <list type="number">
        ///     <item>for every pair of vertices V,W, W is reachable from V, ignoring edge-direction, and </item>
        ///     <item>one cannot add another node U such that the first property still holds.</item>
        /// </list>
        /// </summary>
        /// <typeparam name="TGraph">The type of the produced components.</typeparam>
        /// <typeparam name="TVertex">The type of the vertices.</typeparam>
        /// <typeparam name="TEdge">The type of the edges.</typeparam>
        /// <param name="g">The graph.</param>
        /// <param name="componentMaker">A producer-function for empty empty components.</param>
        public static IList <TGraph> WeaklyConnectedComponents <TGraph, TVertex, TEdge>(this GraphBase <TVertex, TEdge> g, Func <TGraph> componentMaker)
            where TEdge : class, IEdge <TVertex>
            where TGraph : GraphBase <TVertex, TEdge>
        {
            var undirected = new NonDirectedGraph <TVertex, NonDirectedEdge <TVertex> >();

            g.Vertices.ForEach(undirected.Add);
            g.Edges.ForEach(e => undirected.Add(new NonDirectedEdge <TVertex>(e.StartVertex, e.EndVertex)));

            var subgraphs = new List <TGraph>();

            //Find the subgraphs (connected components that are candidates for being turned into trees).
            var dcGraphFinder = new DisconnectedGraphsFinder <TVertex, NonDirectedEdge <TVertex> >(
                () => new SubGraphView <TVertex, NonDirectedEdge <TVertex> >(undirected), undirected);

            dcGraphFinder.FindDisconnectedGraphs();

            foreach (var component in dcGraphFinder.FoundDisconnectedGraphs)
            {
                var subG = componentMaker();
                component.Vertices.ForEach(subG.Add);

                foreach (var v1 in component.Vertices)
                {
                    foreach (var v2 in component.Vertices)
                    {
                        g.GetEdges(v1, v2).ForEach(subG.Add);
                    }
                }

                subgraphs.Add(subG);
            }

            return(subgraphs);
        }
예제 #2
0
        public void BasicDepthFirstSearchCrawlerTest()
        {
            // create example graph, non-directed.
            NonDirectedGraph <string, NonDirectedEdge <string> > graph = new NonDirectedGraph <string, NonDirectedEdge <string> >();

            // create edges. simply use string literals, which will point to the same vertices anyway.
            graph.Add(new NonDirectedEdge <string>("A", "B"));
            graph.Add(new NonDirectedEdge <string>("A", "C"));
            graph.Add(new NonDirectedEdge <string>("A", "G"));
            graph.Add(new NonDirectedEdge <string>("A", "F"));
            graph.Add(new NonDirectedEdge <string>("F", "D"));
            graph.Add(new NonDirectedEdge <string>("F", "E"));
            graph.Add(new NonDirectedEdge <string>("D", "E"));
            graph.Add(new NonDirectedEdge <string>("E", "G"));
            graph.Add(new NonDirectedEdge <string>("H", "I"));
            graph.Add(new NonDirectedEdge <string>("J", "K"));
            graph.Add(new NonDirectedEdge <string>("J", "L"));
            graph.Add(new NonDirectedEdge <string>("J", "M"));
            graph.Add(new NonDirectedEdge <string>("L", "M"));

            DepthFirstSearchTester <string, NonDirectedEdge <string> > dfs = new DepthFirstSearchTester <string, NonDirectedEdge <string> >(graph);

            dfs.Start();
            Assert.AreEqual(13, dfs.VerticesLoggedInOnVisiting.Count);
            Assert.AreEqual(13, dfs.VerticesLoggedInOnVisited.Count);

            // visual confirmation logging code
            Console.Write("Vertices logged in order by OnVisiting:\n\t");
            foreach (string v in dfs.VerticesLoggedInOnVisiting)
            {
                Console.Write(v + " ");
            }
            Console.Write("\n\nVertices logged in order by OnVisited:\n\t");
            foreach (string v in dfs.VerticesLoggedInOnVisited)
            {
                Console.Write(v + " ");
            }

            // start in another tree in the graph
            dfs.VerticesLoggedInOnVisited.Clear();
            dfs.VerticesLoggedInOnVisiting.Clear();
            dfs.Start("L");
            Assert.AreEqual(13, dfs.VerticesLoggedInOnVisiting.Count);
            Assert.AreEqual(13, dfs.VerticesLoggedInOnVisited.Count);

            Console.Write("\n\nVertices logged in order by OnVisiting:\n\t");
            foreach (string v in dfs.VerticesLoggedInOnVisiting)
            {
                Console.Write(v + " ");
            }
            Console.Write("\n\nVertices logged in order by OnVisited:\n\t");
            foreach (string v in dfs.VerticesLoggedInOnVisited)
            {
                Console.Write(v + " ");
            }
        }
예제 #3
0
        public void AsNonDirectedGraphTest()
        {
            DirectedGraph <string, DirectedEdge <string> > graph = new DirectedGraph <string, DirectedEdge <string> >();

            graph.Add(new DirectedEdge <string>("A", "B"));             // A->B
            graph.Add(new DirectedEdge <string>("A", "C"));             // A->C
            graph.Add(new DirectedEdge <string>("B", "D"));             // B->D
            graph.Add(new DirectedEdge <string>("C", "D"));             // C->D
            graph.Add(new DirectedEdge <string>("D", "E"));             // D->E

            Assert.IsTrue(graph.IsDirected);
            Assert.IsTrue(graph.EdgeCount == 5);

            NonDirectedGraph <string, NonDirectedEdge <string> > nonDirectedGraph = (NonDirectedGraph <string, NonDirectedEdge <string> >)graph.GetAsNonDirectedCopy();

            Assert.IsFalse(nonDirectedGraph.IsDirected);

            Assert.IsTrue(nonDirectedGraph.ContainsEdge("A", "B"));
            Assert.IsTrue(nonDirectedGraph.ContainsEdge("B", "A"));

            Assert.IsTrue(nonDirectedGraph.ContainsEdge("A", "C"));
            Assert.IsTrue(nonDirectedGraph.ContainsEdge("C", "A"));

            Assert.IsTrue(nonDirectedGraph.ContainsEdge("B", "D"));
            Assert.IsTrue(nonDirectedGraph.ContainsEdge("D", "B"));

            Assert.IsTrue(nonDirectedGraph.ContainsEdge("C", "D"));
            Assert.IsTrue(nonDirectedGraph.ContainsEdge("D", "C"));

            Assert.IsTrue(nonDirectedGraph.ContainsEdge("D", "E"));
            Assert.IsTrue(nonDirectedGraph.ContainsEdge("E", "D"));

            foreach (Edge <string> edge in nonDirectedGraph.Edges)
            {
                Console.Write("\n\nEdge Start index: " + edge.StartVertex + "\tEdge End index:" + edge.EndVertex + "\n\t");

                Assert.IsFalse(edge.IsDirected);
            }

            //Assert.IsTrue(nonDirectedGraph.EdgeCount == 10);
        }
예제 #4
0
        /// <summary>
        /// Generate a maze
        /// </summary>
        /// <param name="lenght">lenght</param>
        /// <param name="heigh">heigh</param>
        /// <param name="loops">number of loops in the maze , by default == 0</param>
        /// <returns>a matrix representing the maze</returns>
        public GraphNode<MazeNode, int>[,] GetMaze(int lenght, int heigh, int loops = 0)
        {
            // generate result matrix
            GraphNode<MazeNode, int>[,] result =  new GraphNode<MazeNode, int>[heigh,lenght];

            for(int i = 0;  i < lenght; i++)
            {
                for(int j=0;j<heigh;j++)
                {
                    result[j,i] = new NonDirectedGraph<MazeNode,int>()
                    { Value = new MazeNode()
                    { X =i, Y = j, Type = CellType.empty}};
                }
            }

            // randomly connect it
            Random rnd = new Random();
            // connect lines
            for(int i=0; i<lenght -1 ;i++)
            {
                for(int j=0; j<heigh;j++)
                {
                    result[j,i].AddNeightbour(result[j,i+1],rnd.Next());
                }
            }
            // connect columns
            for(int i=0; i<lenght;i++)
            {
                for(int j=0; j<heigh -1;j++)
                {
                    result[j,i].AddNeightbour(result[j+1,i],rnd.Next(1,Int16.MaxValue));
                }
            }

            // Generate maze by selecting minimum arches
            HashSet<GraphNode<MazeNode,int>> visited = new HashSet<GraphNode<MazeNode,int>>();

            var arches = result.
                Cast<GraphNode<MazeNode, int>>().
                SelectMany(n=>n.Neighbours.Select(l=> new {Start =n, End =l.Key, Lenght = l.Value})).
                OrderByDescending(a=>a.Lenght).
                ToList();

            var first = arches.First();
            visited.Add(first.Start);
            visited.Add(first.End);
            first.Start.Neighbours[first.End] = 0; // connection marked for keeping
            first.End.Neighbours[first.Start] = 0; // connection marked for keeping

            while(visited.Count < lenght * heigh  && arches.Any())
            {
                foreach (var arch in arches)
                {
                    if ((!visited.Contains(arch.Start)) ^ (!visited.Contains(arch.End)))
                    {
                        visited.Add(arch.Start);
                        visited.Add(arch.End);
                        arch.Start.Neighbours[arch.End] = 0; // connection marked for keeping
                        arch.End.Neighbours[arch.Start] = 0; // connection marked for keeping
                        arches.Remove(arch);
                        break;
                    }
                }
            }

            // add loops
            while (loops > 0 && arches.Any())
            {
                var arch = arches.ElementAt(0);
                arches.RemoveAt(0);
                if (arch.Start.Neighbours[arch.End] != 0)
                {
                    // connection marked for keeping
                    arch.Start.Neighbours[arch.End] = 0;
                    arch.End.Neighbours[arch.Start] = 0;
                    loops--;
                }
            }

            foreach (var cell in result)
            {
                foreach (var kvp in cell.Neighbours.ToList())
                {
                    // removed neighbours with arches >0
                    if (kvp.Value > 0)
                    {
                        cell.RemoveNeightbour(kvp.Key);
                    }
                }
            }

            // add start,end

            var start = visited.ElementAt(rnd.Next(visited.Count));
            start.Value.Type = CellType.start;
            visited.Remove(start);

            var end = visited.ElementAt(rnd.Next(visited.Count));
            end.Value.Type = CellType.end;
            visited.Remove(end);

            return result;
        }