/*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); }
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 + " "); } }
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); }
/// <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; }