Exemplo n.º 1
0
        // 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);
        }