/// <summary> /// Scans the specified graph, using recursion, and produces SCC results. /// </summary> /// <param name="graph">The graph to search.</param> /// <param name="vertex">The current vertex to scan and connect.</param> /// <param name="weigher">The optional weigher to use.</param> /// <param name="result">The graph search result.</param> /// <returns>Augmentation vertex data for the current vertex.</returns> private VertexData Connect(IGraph <V, E> graph, V vertex, IEdgeWeigher <V, E> weigher, SccResult result) { VertexData data = result.AddData(vertex); // Scan through all egress edges of the current vertex. foreach (E edge in graph.GetEdgesFrom(vertex)) { V nextVertex = edge.Dst; // If edge is not viable, skip it. if (weigher != null && !weigher.GetWeight(edge).IsViable) { continue; } // Attempt to get the augmentation vertex data for the next vertex. VertexData nextData = result.GetData(nextVertex); if (nextData is null) { // Next vertex has not been visited yet, so do this now. nextData = Connect(graph, nextVertex, weigher, result); data.LowLink = Math.Min(data.LowLink, nextData.LowLink); } else if (result.Visited(nextData)) { // Next vertex has been visited, which means // it is in the same cluster as the current vertex. data.LowLink = Math.Min(data.LowLink, nextData.Index); } } if (data.LowLink == data.Index) { result.AddCluster(data); } return(data); }
/// <summary> /// Determines whether the given vertex has been visited. /// </summary> /// <param name="data">The vertex to check.</param> /// <returns>True if the vertex has been visited, otherwise false.</returns> internal bool Visited(VertexData data) => visited.Contains(data);