///// <summary> ///// Computes distances between a selected set of nodes and all nodes. ///// Pivot nodes are selected with maxmin strategy (first at random, later ///// ones to maximize distances to all previously selected ones). ///// </summary> ///// <param name="graph">A graph.</param> ///// <param name="directed">Whether shortest paths are directed.</param> ///// <param name="numberOfPivots">Number of pivots.</param> ///// <returns>A square matrix with shortest path distances.</returns> //public static double[][] PivotUniformDistances(GeometryGraph graph, bool directed, int numberOfPivots) { // double[][] d = new double[numberOfPivots][]; // Node[] nodes = new Node[graph.Nodes.Count]; // graph.Nodes.CopyTo(nodes, 0); // double[] min = new double[graph.Nodes.Count]; // for (int i = 0; i < min.Length; i++) { // min[i] = Double.PositiveInfinity; // } // System.Console.Write("pivoting "); // Node pivot = nodes[0]; // for (int i = 0; i < numberOfPivots; i++) { // System.Console.Write("."); // d[i] = SingleSourceUniformDistances(graph, pivot, directed); // int argmax = 0; // for (int j = 0; j < d[i].Length; j++) { // min[j] = Math.Min(min[j], d[i][j]); // if (min[j] > min[argmax]) // argmax = j; // } // pivot = nodes[argmax]; // } // System.Console.WriteLine(); // return d; //} ///// <summary> ///// Determines whether the graph is (weakly) connected, that is, ///// if there is a path connecting every two nodes. ///// </summary> ///// <param name="graph">A graph.</param> ///// <returns>true iff the graph is connected.</returns> //public static bool IsConnected(GeometryGraph graph) { // IEnumerator<Node> enumerator = graph.Nodes.GetEnumerator(); // enumerator.MoveNext(); // Node node=enumerator.Current; // double[] distances=SingleSourceUniformDistances(graph, node, false); // for (int i = 0; i < distances.Length; i++) { // if (distances[i] == Double.PositiveInfinity) return false; // } // return true; //} /// <summary> /// Gives graphs representing the connected components of the graph /// </summary> /// <param name="graph">A graph.</param> /// <param name="nodeToNodeIndex">the dictionary: node -> node index in the NodeMap</param> /// <returns>An array of connected components.</returns> internal static GeometryGraph[] ComponentGraphs(GeometryGraph graph, Dictionary <Node, int> nodeToNodeIndex) { Node[] nodes = new Node[graph.Nodes.Count]; graph.Nodes.CopyTo(nodes, 0); BasicGraph <IntPair> basicGraph = new BasicGraph <IntPair>( from edge in graph.Edges where !(edge.Source is Cluster || edge.Target is Cluster) select new IntPair(nodeToNodeIndex[edge.Source], nodeToNodeIndex[edge.Target]), graph.Nodes.Count); List <IEnumerable <int> > comps = new List <IEnumerable <int> >(ConnectedComponentCalculator <IntPair> .GetComponents(basicGraph)); if (comps.Count == 1) { return new GeometryGraph[] { graph } } ; GeometryGraph[] ret = new GeometryGraph[comps.Count]; int i = 0; foreach (var comp in comps) { ret[i++] = GeomGraphFromBasicGraph(comp, nodes); } return(ret); }
SetUp() { m_oConnectedComponentCalculator = new ConnectedComponentCalculator(); m_oGraph = new Graph(); m_oVertices = m_oGraph.Vertices; m_oEdges = m_oGraph.Edges; }
/// <summary> /// These blocks are connected components in the vertical constraints. They don't necesserely span consequent layers. /// </summary> /// <returns></returns> Dictionary <int, int> CreateVerticalComponents() { var vertGraph = new BasicGraph <IntEdge>(from pair in horizontalConstraints.VerticalInts select new IntEdge(pair.Item1, pair.Item2)); var verticalComponents = ConnectedComponentCalculator <IntEdge> .GetComponents(vertGraph); var nodesToComponentRoots = new Dictionary <int, int>(); foreach (var component in verticalComponents) { var ca = component.ToArray(); if (ca.Length == 1) { continue; } int componentRoot = -1; foreach (var j in component) { if (componentRoot == -1) { componentRoot = j; } nodesToComponentRoots[j] = componentRoot; } } return(nodesToComponentRoots); }
void UniteConnectedPreGraphs(ref List <PreGraph> preGraphs) { BasicGraph <IntPair> intersectionGraph = GetIntersectionGraphOfPreGraphs(preGraphs); if (intersectionGraph == null) { return; } var connectedComponents = ConnectedComponentCalculator <IntPair> .GetComponents(intersectionGraph); var newPreGraphList = new List <PreGraph>(); foreach (var component in connectedComponents) { PreGraph preGraph = null; foreach (var i in component) { if (preGraph == null) { preGraph = preGraphs[i]; newPreGraphList.Add(preGraph); } else { preGraph.AddGraph(preGraphs[i]); } } } preGraphs = newPreGraphList; foreach (var pg in preGraphs) { AddIntersectingNodes(pg); } }
private bool CreateConvexHulls() { var found = false; var graph = new BasicGraph <IntPair>(this.overlapPairs); var connectedComponents = ConnectedComponentCalculator <IntPair> .GetComponents(graph); foreach (var component in connectedComponents) { // GetComponents returns at least one self-entry for each index - including the < FirstNonSentinelOrdinal ones. if (component.Count() == 1) { continue; } found = true; var obstacles = component.Select(this.OrdinalToObstacle); var points = obstacles.SelectMany(obs => obs.VisibilityPolyline); var och = new OverlapConvexHull(ConvexHull.CreateConvexHullAsClosedPolyline(points), obstacles); foreach (var obstacle in obstacles) { obstacle.SetConvexHull(och); } } return(found); }
TestGetStronglyConnectedComponents5() { // One component with N vertices. const Int32 Vertices = 100; Int32 [] aiVertexIDs = new Int32[Vertices]; IVertex oFirstVertex = null; for (Int32 i = 0; i < Vertices; i++) { IVertex oVertex = m_oVertices.Add(); aiVertexIDs[i] = oVertex.ID; if (i == 0) { oFirstVertex = oVertex; } else { m_oEdges.Add(oFirstVertex, oVertex); } } List <LinkedList <IVertex> > oStronglyConnectedComponents = ConnectedComponentCalculator.GetStronglyConnectedComponents( m_oGraph); Assert.AreEqual(1, oStronglyConnectedComponents.Count); CheckThatComponentConsistsOfVertices(oStronglyConnectedComponents[0], aiVertexIDs); }
internal static RectangleNode <Polyline> ReplaceTightObstaclesWithConvexHulls(Set <Polyline> tightObsts, IEnumerable <Tuple <Polyline, Polyline> > overlappingPairSet) { var overlapping = new Set <Polyline>(); foreach (var pair in overlappingPairSet) { overlapping.Insert(pair.Item1); overlapping.Insert(pair.Item2); } var intToPoly = overlapping.ToArray(); var polyToInt = MapToInt(intToPoly); var graph = new BasicGraph <IntPair>( overlappingPairSet. Select(pair => new IntPair(polyToInt[pair.Item1], polyToInt[pair.Item2]))); var connectedComponents = ConnectedComponentCalculator <IntPair> .GetComponents(graph); foreach (var component in connectedComponents) { var polys = component.Select(i => intToPoly[i]); var points = polys.SelectMany(p => p); var convexHull = ConvexHull.CreateConvexHullAsClosedPolyline(points); foreach (var poly in polys) { tightObsts.Remove(poly); } tightObsts.Insert(convexHull); } return(CalculateHierarchy(tightObsts)); }
private void CreateDictionaryOfSameLayerRepresentatives() { BasicGraph <IntPair> graphOfSameLayers = CreateGraphOfSameLayers(); foreach (var comp in ConnectedComponentCalculator <IntPair> .GetComponents(graphOfSameLayers)) { GlueSameLayerNodesOfALayer(comp); } }
TestGetStronglyConnectedComponents() { // Empty graph. List <LinkedList <IVertex> > oStronglyConnectedComponents = ConnectedComponentCalculator.GetStronglyConnectedComponents( m_oGraph); Assert.AreEqual(0, oStronglyConnectedComponents.Count); }
void CreateConnectedGraphs() { Dictionary <Node, int> nodeToIndex; var listOfNodes = CreateNodeListForBasicGraph(out nodeToIndex); var basicGraph = new BasicGraph <SimpleIntEdge>(GetSimpleIntEdges(nodeToIndex), listOfNodes.Count); var comps = ConnectedComponentCalculator <SimpleIntEdge> .GetComponents(basicGraph); foreach (var comp in comps) { lgData.AddConnectedGeomGraph(GetConnectedSubgraph(comp, listOfNodes)); } }
/// <summary> /// For a set of nodes and edges that have not already been added to a graph will return an enumerable of new /// graphs each of which contains a connected component. /// </summary> /// <remarks> /// Debug.Asserts that Parent of nodes and edges has not yet been assigned to ensure that this is not being /// applied to nodes and edges that have already been added to a graph. Applying this to such edges would /// result in the Node InEdges and OutEdges lists containing duplicates. /// </remarks> /// <returns></returns> public static IEnumerable <GeometryGraph> CreateComponents(IList <Node> nodes, IEnumerable <Edge> edges, double nodeSeparation) { ValidateArg.IsNotNull(nodes, "nodes"); ValidateArg.IsNotNull(edges, "edges"); var nodeIndex = new Dictionary <Node, int>(); int nodeCount = 0; foreach (var v in nodes) { // Debug.Assert(v.Parent == null, "Node is already in a graph"); nodeIndex[v] = nodeCount++; } var intEdges = new List <SimpleIntEdge>(); foreach (var e in edges) { // Debug.Assert(e.Parent == null, "Edge is already in a graph"); intEdges.Add(new SimpleIntEdge { Source = nodeIndex[e.Source], Target = nodeIndex[e.Target] }); } var components = ConnectedComponentCalculator <SimpleIntEdge> .GetComponents(new BasicGraphOnEdges <SimpleIntEdge>(intEdges, nodeCount)); var nodeToGraph = new Dictionary <Node, GeometryGraph>(); var graphs = new List <GeometryGraph>(); foreach (var c in components) { var g = new GeometryGraph() { Margins = nodeSeparation / 2 }; foreach (var i in c) { var v = nodes[i]; g.Nodes.Add(v); nodeToGraph[v] = g; } graphs.Add(g); } foreach (var e in edges) { var g = nodeToGraph[e.Source]; Debug.Assert(nodeToGraph[e.Target] == g, "source and target of edge are not in the same graph"); g.Edges.Add(e); } return(graphs); }
TestGetStronglyConnectedComponents6() { // N components with 1-N vertices each. const Int32 Components = 100; Int32 [][] aiiVertexIDs = new Int32[Components][]; // Add the components in decreasing order to test component sorting. for (Int32 iComponent = Components - 1; iComponent >= 0; iComponent--) { Int32 iVertices = iComponent + 1; Int32 [] aiVertexIDs = new Int32[iVertices]; aiiVertexIDs[iComponent] = aiVertexIDs; IVertex oFirstVertex = null; for (Int32 i = 0; i < iVertices; i++) { IVertex oVertex = m_oVertices.Add(); aiVertexIDs[i] = oVertex.ID; if (i == 0) { oFirstVertex = oVertex; } else { m_oEdges.Add(oFirstVertex, oVertex); } } } List <LinkedList <IVertex> > oStronglyConnectedComponents = ConnectedComponentCalculator.GetStronglyConnectedComponents( m_oGraph); Assert.AreEqual(Components, oStronglyConnectedComponents.Count); Int32 j = 0; foreach (LinkedList <IVertex> oStronglyConnectedComponent in oStronglyConnectedComponents) { CheckThatComponentConsistsOfVertices( oStronglyConnectedComponent, aiiVertexIDs[j]); j++; } }
private void CreateClumps() { var graph = new BasicGraphOnEdges <IntPair>(this.overlapPairs); var connectedComponents = ConnectedComponentCalculator <IntPair> .GetComponents(graph); foreach (var component in connectedComponents) { // GetComponents returns at least one self-entry for each index - including the < FirstNonSentinelOrdinal ones. if (component.Count() == 1) { continue; } createClump(component); } }
TestGetStronglyConnectedComponents2() { // One component with one vertex. IVertex oVertex = m_oVertices.Add(); List <LinkedList <IVertex> > oStronglyConnectedComponents = ConnectedComponentCalculator.GetStronglyConnectedComponents( m_oGraph); Assert.AreEqual(1, oStronglyConnectedComponents.Count); CheckThatComponentConsistsOfVertices(oStronglyConnectedComponents[0], oVertex.ID); }
TestGetStronglyConnectedComponents4() { // One component with two vertices. IVertex oVertex1 = m_oVertices.Add(); IVertex oVertex2 = m_oVertices.Add(); m_oEdges.Add(oVertex1, oVertex2); List <LinkedList <IVertex> > oStronglyConnectedComponents = ConnectedComponentCalculator.GetStronglyConnectedComponents( m_oGraph); Assert.AreEqual(1, oStronglyConnectedComponents.Count); CheckThatComponentConsistsOfVertices(oStronglyConnectedComponents[0], oVertex1.ID, oVertex2.ID); }
TestGetStronglyConnectedComponents3() { // N components with one vertex each. const Int32 Vertices = 100; Int32 [] aiVertexIDs = new Int32[Vertices]; for (Int32 i = 0; i < Vertices; i++) { aiVertexIDs[i] = m_oVertices.Add().ID; } List <LinkedList <IVertex> > oStronglyConnectedComponents = ConnectedComponentCalculator.GetStronglyConnectedComponents( m_oGraph); Assert.AreEqual(Vertices, oStronglyConnectedComponents.Count); HashSet <Int32> oFoundVertexIDs = new HashSet <Int32>(); foreach (LinkedList <IVertex> oStronglyConnectedComponent in oStronglyConnectedComponents) { Assert.AreEqual(1, oStronglyConnectedComponent.Count); Int32 iFoundVertexID = oStronglyConnectedComponent.First.Value.ID; if (oFoundVertexIDs.Contains(iFoundVertexID)) { Assert.Fail("Two components contain the same vertex."); } oFoundVertexIDs.Add(iFoundVertexID); } foreach (Int32 iVertexID in aiVertexIDs) { if (!oFoundVertexIDs.Contains(iVertexID)) { Assert.Fail("A vertex is not contained in a component."); } } }
private void CreateClumps() { var graph = new BasicGraph <IntPair>(this.overlapPairs); var connectedComponents = ConnectedComponentCalculator <IntPair> .GetComponents(graph); foreach (var component in connectedComponents) { // GetComponents returns at least one self-entry for each index - including the < FirstNonSentinelOrdinal ones. if (component.Count() == 1) { continue; } var clump = new Clump(component.Select(this.OrdinalToObstacle)); foreach (var obstacle in clump) { obstacle.Clump = clump; } } }
public void InitConnectedComponents(List <SymmetricSegment> edges) { var treeNodes = new TreeNode[pointToTreeNode.Count]; foreach (var node in pointToTreeNode.Values) { treeNodes[node.id] = node; } var intEdges = new List <SimpleIntEdge>(); foreach (var edge in edges) { int sourceId = pointToTreeNode[edge.A].id; int targetId = pointToTreeNode[edge.B].id; intEdges.Add(new SimpleIntEdge { Source = sourceId, Target = targetId }); } var components = ConnectedComponentCalculator <SimpleIntEdge> .GetComponents(new BasicGraph <SimpleIntEdge>(intEdges, pointToTreeNode.Count)); foreach (var component in components) { List <TreeNode> nodeList = new List <TreeNode>(); foreach (var nodeId in component) { nodeList.Add(treeNodes[nodeId]); } _subtrees.Add(nodeList); } //ChooseRoots(); ChooseRootsRandom(); BuildForestFromCdtEdges(edges); foreach (var root in _roots) { OrientTreeEdges(root); } }
public int[] GetLayers() { List <IEnumerable <int> > comps = new List <IEnumerable <int> >(ConnectedComponentCalculator <IntEdge> .GetComponents(graph)); if (comps.Count == 1) { NetworkSimplex ns = new NetworkSimplex(graph, this.Cancel); return(ns.GetLayers()); } List <Dictionary <int, int> > mapToComponenents = GetMapsToComponent(comps); int[][] layerings = new int[comps.Count][]; for (int i = 0; i < comps.Count; i++) { BasicGraph <Node, IntEdge> shrunkedComp = ShrunkComponent(mapToComponenents[i]); NetworkSimplex ns = new NetworkSimplex(shrunkedComp, Cancel); layerings[i] = ns.GetLayers(); } return(UniteLayerings(layerings, mapToComponenents)); }
/// <summary> /// Extension method to break a GeometryGraph into connected components taking into consideration clusters. /// Leaves the original graph intact, the resultant components contain copies of the original elements, with /// the original elements referenced in their UserData properties. /// </summary> /// <returns> /// the set of components, each as its own GeometryGraph. /// </returns> public static IEnumerable <GeometryGraph> GetClusteredConnectedComponents(this GeometryGraph graph) { var flatGraph = FlatGraph(graph); var basicFlatGraph = new BasicGraph <AlgorithmDataEdgeWrap>( from e in flatGraph.Edges select(AlgorithmDataEdgeWrap) e.AlgorithmData, flatGraph.Nodes.Count); var nodes = flatGraph.Nodes.ToList(); var graphComponents = new List <GeometryGraph>(); foreach ( var componentNodes in ConnectedComponentCalculator <AlgorithmDataEdgeWrap> .GetComponents(basicFlatGraph)) { var g = new GeometryGraph(); var topClusters = new List <Cluster>(); var topNodes = new List <Node>(); foreach (int i in componentNodes) { var v = nodes[i]; var original = (Node)v.UserData; bool topLevel = ((AlgorithmDataNodeWrap)original.AlgorithmData).TopLevel; if (v.UserData is Cluster) { if (topLevel) { topClusters.Add((Cluster)original); } } else { // clear edges, we fix them up below v.ClearEdges(); g.Nodes.Add(v); if (topLevel) { topNodes.Add(v); } } } // copy the cluster hierarchies from the original graph int index = g.Nodes.Count; if (topClusters.Count != 0) { var root = new Cluster(topNodes); foreach (var top in topClusters) { root.AddChild(CopyCluster(top, ref index)); } g.RootCluster = root; } // add the real edges from the original graph to the component graph foreach (var v in g.GetFlattenedNodesAndClusters()) { var original = v.UserData as Node; Debug.Assert(original != null); foreach (var e in original.InEdges) { var source = GetCopy(e.Source); var target = GetCopy(e.Target); var copy = new Edge(source, target) { Length = e.Length, UserData = e, EdgeGeometry = e.EdgeGeometry }; e.AlgorithmData = copy; g.Edges.Add(copy); } } graphComponents.Add(g); } return(graphComponents); }
LayOutSmallerComponentsInBins ( IGraph graph, ICollection <IVertex> verticesToLayOut, LayoutContext layoutContext, out ICollection <IVertex> remainingVertices, out Rectangle remainingRectangle ) { AssertValid(); remainingVertices = null; remainingRectangle = Rectangle.Empty; // This method modifies some of the graph's metadata. Save the // original metadata. Boolean bOriginalGraphHasBeenLaidOut = LayoutMetadataUtil.GraphHasBeenLaidOut(graph); ICollection <IVertex> oOriginalLayOutTheseVerticesOnly = (ICollection <IVertex>)graph.GetValue( ReservedMetadataKeys.LayOutTheseVerticesOnly, typeof(ICollection <IVertex>)); // Split the vertices into strongly connected components, sorted in // increasing order of vertex count. ConnectedComponentCalculator oConnectedComponentCalculator = new ConnectedComponentCalculator(); IList <LinkedList <IVertex> > oComponents = oConnectedComponentCalculator.CalculateStronglyConnectedComponents( verticesToLayOut, graph, true); Int32 iComponents = oComponents.Count; // This object will split the graph rectangle into bin rectangles. RectangleBinner oRectangleBinner = new RectangleBinner( layoutContext.GraphRectangle, m_iBinLength); Int32 iComponent = 0; for (iComponent = 0; iComponent < iComponents; iComponent++) { LinkedList <IVertex> oComponent = oComponents[iComponent]; Int32 iVerticesInComponent = oComponent.Count; if (iVerticesInComponent > m_iMaximumVerticesPerBin) { // The vertices in the remaining components should not be // binned. break; } Rectangle oBinRectangle; if (!oRectangleBinner.TryGetNextBin(out oBinRectangle)) { // There is no room for an additional bin rectangle. break; } // Lay out the component within the bin rectangle. LayOutComponentInBin(graph, oComponent, oBinRectangle); } // Restore the original metadata on the graph. if (bOriginalGraphHasBeenLaidOut) { LayoutMetadataUtil.MarkGraphAsLaidOut(graph); } else { LayoutMetadataUtil.MarkGraphAsNotLaidOut(graph); } if (oOriginalLayOutTheseVerticesOnly != null) { graph.SetValue(ReservedMetadataKeys.LayOutTheseVerticesOnly, oOriginalLayOutTheseVerticesOnly); } else { graph.RemoveKey(ReservedMetadataKeys.LayOutTheseVerticesOnly); } if (oRectangleBinner.TryGetRemainingRectangle( out remainingRectangle)) { remainingVertices = GetRemainingVertices(oComponents, iComponent); return(remainingVertices.Count > 0); } return(false); }
/// <summary> /// Create the graph data structures. /// </summary> /// <param name="geometryGraph"></param> /// <param name="settings">The settings for the algorithm.</param> /// <param name="initialConstraintLevel">initialize at this constraint level</param> /// <param name="clusterSettings">settings by cluster</param> internal FastIncrementalLayout(GeometryGraph geometryGraph, FastIncrementalLayoutSettings settings, int initialConstraintLevel, Func <Cluster, LayoutAlgorithmSettings> clusterSettings) { graph = geometryGraph; this.settings = settings; this.clusterSettings = clusterSettings; int i = 0; ICollection <Node> allNodes = graph.Nodes; nodes = new FiNode[allNodes.Count]; foreach (Node v in allNodes) { v.AlgorithmData = nodes[i] = new FiNode(i, v); i++; } clusterEdges.Clear(); edges.Clear(); foreach (Edge e in graph.Edges) { if (e.Source is Cluster || e.Target is Cluster) { clusterEdges.Add(e); } else { edges.Add(new FiEdge(e)); } foreach (var l in e.Labels) { l.InnerPoints = l.OuterPoints = null; } } SetLockNodeWeights(); components = new List <FiNode[]>(); if (!settings.InterComponentForces) { basicGraph = new BasicGraph <FiEdge>(edges, nodes.Length); foreach (var componentNodes in ConnectedComponentCalculator <FiEdge> .GetComponents(basicGraph)) { var vs = new FiNode[componentNodes.Count()]; int vi = 0; foreach (int v in componentNodes) { vs[vi++] = nodes[v]; } components.Add(vs); } } else // just one big component (regardless of actual edges) { components.Add(nodes); } horizontalSolver = new AxisSolver(true, nodes, new[] { geometryGraph.RootCluster }, settings.AvoidOverlaps, settings.MinConstraintLevel, clusterSettings) { OverlapRemovalParameters = new OverlapRemovalParameters { AllowDeferToVertical = true, // use "ProportionalOverlap" mode only when iterative apply forces layout is being used. // it is not necessary otherwise. ConsiderProportionalOverlap = settings.ApplyForces } }; verticalSolver = new AxisSolver(false, nodes, new[] { geometryGraph.RootCluster }, settings.AvoidOverlaps, settings.MinConstraintLevel, clusterSettings); SetupConstraints(); geometryGraph.RootCluster.ComputeWeight(); foreach ( Cluster c in geometryGraph.RootCluster.AllClustersDepthFirst().Where(c => c.RectangularBoundary == null) ) { c.RectangularBoundary = new RectangularClusterBoundary(); } CurrentConstraintLevel = initialConstraintLevel; }
TestGetStronglyConnectedComponents7() { // Test component sorting when layout sort order is specified. IVertex [] aoVertices = new IVertex[14]; for (Int32 i = 0; i < aoVertices.Length; i++) { IVertex oVertex = m_oVertices.Add(); // Make sure that sorting can handle a missing key. They key is // optional. if (i != 12) { oVertex.SetValue(ReservedMetadataKeys.SortableLayoutOrder, (Single)i); } aoVertices[i] = oVertex; } m_oGraph.SetValue(ReservedMetadataKeys.SortableLayoutOrderSet, null); // Each group of Add() calls here is a strongly connected component. m_oEdges.Add(aoVertices[6], aoVertices[7]); m_oEdges.Add(aoVertices[4], aoVertices[5]); m_oEdges.Add(aoVertices[2], aoVertices[3]); m_oEdges.Add(aoVertices[13], aoVertices[12]); m_oEdges.Add(aoVertices[13], aoVertices[11]); m_oEdges.Add(aoVertices[10], aoVertices[9]); m_oEdges.Add(aoVertices[10], aoVertices[8]); List <LinkedList <IVertex> > oStronglyConnectedComponents = ConnectedComponentCalculator.GetStronglyConnectedComponents( m_oGraph); Assert.AreEqual(7, oStronglyConnectedComponents.Count); CheckThatComponentConsistsOfVertices(oStronglyConnectedComponents[0], new Int32[] { aoVertices[0].ID }); CheckThatComponentConsistsOfVertices(oStronglyConnectedComponents[1], new Int32[] { aoVertices[1].ID }); CheckThatComponentConsistsOfVertices(oStronglyConnectedComponents[2], new Int32[] { aoVertices[2].ID, aoVertices[3].ID }); CheckThatComponentConsistsOfVertices(oStronglyConnectedComponents[3], new Int32[] { aoVertices[4].ID, aoVertices[5].ID }); CheckThatComponentConsistsOfVertices(oStronglyConnectedComponents[4], new Int32[] { aoVertices[6].ID, aoVertices[7].ID }); CheckThatComponentConsistsOfVertices(oStronglyConnectedComponents[5], new Int32[] { aoVertices[8].ID, aoVertices[9].ID, aoVertices[10].ID }); CheckThatComponentConsistsOfVertices(oStronglyConnectedComponents[6], new Int32[] { aoVertices[11].ID, aoVertices[12].ID, aoVertices[13].ID }); }