/// <summary> /// <para> /// This implementation produces results augmented with information on SCCs within the graph. /// </para> /// <para> /// To prevent traversal of an edge, the <see cref="IEdgeWeigher{V, E}"/> should /// return a negative value as an edge weigher. /// </para> /// </summary> /// <param name="graph">The graph to search.</param> /// <param name="weigher">The weigher to use.</param> /// <returns>The SCC search result.</returns> public IResultBase <V, E> Search(IGraph <V, E> graph, IEdgeWeigher <V, E> weigher) { SccResult result = new SccResult(graph); foreach (V vertex in graph.Vertices) { VertexData data = result.GetData(vertex); if (data is null) { Connect(graph, vertex, weigher, result); } } return(result.Build()); }
/// <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); }