// Tarjan's strongly connected components algorithm. // https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm protected override IList <CircularDependency <T> > FindStronglyConnectedComponents() { int index = 0; var stack = new Stack <T>(); var indexLookup = new Dictionary <T, int>(); var lowLinkLookup = new Dictionary <T, int>(); var circularDependencies = new List <CircularDependency <T> >(); foreach (T id in EdgeIds) { indexLookup.Add(id, -1); lowLinkLookup.Add(id, -1); } void StrongConnect(T referenceId) { indexLookup[referenceId] = index; lowLinkLookup[referenceId] = index; index++; stack.Push(referenceId); Edge <T, TActivity> referenceEdge = EdgeLookup[referenceId]; Node <T, TEvent> tailNode = EdgeTailNodeLookup[referenceId]; if (tailNode.NodeType == NodeType.End || tailNode.NodeType == NodeType.Normal) { foreach (T incomingEdgeId in tailNode.IncomingEdges) { if (indexLookup[incomingEdgeId] < 0) { StrongConnect(incomingEdgeId); lowLinkLookup[referenceId] = Math.Min(lowLinkLookup[referenceId], lowLinkLookup[incomingEdgeId]); } else if (stack.Contains(incomingEdgeId)) { lowLinkLookup[referenceId] = Math.Min(lowLinkLookup[referenceId], indexLookup[incomingEdgeId]); } } } if (lowLinkLookup[referenceId] == indexLookup[referenceId]) { var circularDependency = new CircularDependency <T>(Enumerable.Empty <T>()); T currentId; do { currentId = stack.Pop(); Edge <T, TActivity> currentEdge = EdgeLookup[currentId]; if (!currentEdge.Content.CanBeRemoved) { circularDependency.Dependencies.Add(currentId); } } while (!referenceId.Equals(currentId)); circularDependencies.Add(circularDependency); } } foreach (T id in EdgeIds) { if (indexLookup[id] < 0) { StrongConnect(id); } } return(circularDependencies); }