Beispiel #1
0
        private static List <List <Node <TValue, TMetadata> > > FindCycles <TValue, TMetadata>(List <Node <TValue, TMetadata> > unsortedItems)
            where TValue : class
            where TMetadata : IOrderable
        {
            for (int i = 0; (i < unsortedItems.Count); ++i)
            {
                var n = unsortedItems[i];
                n.Index    = -1;
                n.LowIndex = -1;
                n.ContainedInKnownCycle = false;
            }

            List <List <Node <TValue, TMetadata> > > cycles = new List <List <Node <TValue, TMetadata> > >();

            Stack <Node <TValue, TMetadata> > stack = new Stack <Node <TValue, TMetadata> >(unsortedItems.Count);
            int index = 0;

            for (int i = 0; (i < unsortedItems.Count); ++i)
            {
                var node = unsortedItems[i];
                if (node.Index == -1)
                {
                    Orderer.FindCycles(node, stack, ref index, cycles);
                    Debug.Assert(stack.Count == 0);
                }
            }

            return(cycles);
        }
Beispiel #2
0
        public static IList <Lazy <TValue, TMetadata> > Order <TValue, TMetadata>(IEnumerable <Lazy <TValue, TMetadata> > itemsToOrder)
            where TValue : class
            where TMetadata : IOrderable
        {
            if (itemsToOrder == null)
            {
                throw new ArgumentNullException(nameof(itemsToOrder));
            }

#if false && DEBUG
            Debug.WriteLine("Before ordering");
            DumpGraph(itemsToOrder);
#endif

            var roots         = new Queue <Node <TValue, TMetadata> >();
            var unsortedItems = new List <Node <TValue, TMetadata> >();

            Orderer.PrepareGraph(itemsToOrder, roots, unsortedItems);
            IList <Lazy <TValue, TMetadata> > sortedItems = Orderer.TopologicalSort(roots, unsortedItems);

#if false && DEBUG
            Debug.WriteLine("After ordering");
            DumpGraph(sortedItems);
#endif

            return(sortedItems);
        }
Beispiel #3
0
            public void ClearBefore(Queue <Node <TValue, TMetadata> > roots)
            {
                List <Node <TValue, TMetadata> > newRoots = new List <Node <TValue, TMetadata> >();

                foreach (Node <TValue, TMetadata> child in this.Before)
                {
                    child.After.Remove(this);

                    if (child.After.Count == 0)
                    {
                        newRoots.Add(child);
                    }
                }
                this.Before.Clear();

                Orderer.AddToRoots(roots, newRoots);
            }
Beispiel #4
0
        private static void FindCycles <TValue, TMetadata>(Node <TValue, TMetadata> node, Stack <Node <TValue, TMetadata> > stack, ref int index, List <List <Node <TValue, TMetadata> > > cycles)
            where TValue : class
            where TMetadata : IOrderable
        {
            node.Index    = index;
            node.LowIndex = index;
            ++index;

            stack.Push(node);

            foreach (Node <TValue, TMetadata> child in node.Before)
            {
                if (child.Index == -1)
                {
                    Orderer.FindCycles(child, stack, ref index, cycles);
                    node.LowIndex = Math.Min(node.LowIndex, child.LowIndex);
                }
                else if (!child.ContainedInKnownCycle)
                {
                    node.LowIndex = Math.Min(node.LowIndex, child.Index);
                }
            }

            if (node.Index == node.LowIndex)
            {
                List <Node <TValue, TMetadata> > cycle = new List <Node <TValue, TMetadata> >();
                while (stack.Count > 0)
                {
                    Node <TValue, TMetadata> child = stack.Pop();
                    cycle.Add(child);
                    child.ContainedInKnownCycle = true;

                    if (child == node)
                    {
                        //Single unit cycles aren't interesting (since we are preventing node from linking to themselves in the Resolve code below).
                        if (cycle.Count > 1)
                        {
                            cycles.Add(cycle);
                        }
                        break;
                    }

                    Debug.Assert(stack.Count > 0);
                }
            }
        }
Beispiel #5
0
        private static IList <Lazy <TValue, TMetadata> > TopologicalSort <TValue, TMetadata>(Queue <Node <TValue, TMetadata> > roots, List <Node <TValue, TMetadata> > unsortedItems)
            where TValue : class
            where TMetadata : IOrderable
        {
            List <Lazy <TValue, TMetadata> > sortedItems = new List <Lazy <TValue, TMetadata> >();

            while (unsortedItems.Count > 0)
            {
                Node <TValue, TMetadata> node = (roots.Count == 0) ? Orderer.BreakCircularReference(unsortedItems) : roots.Dequeue();

                Debug.Assert(node.After.Count == 0);

                if (node.Item != null)
                {
                    sortedItems.Add(node.Item);
                }

                unsortedItems.Remove(node);
                node.ClearBefore(roots);
            }

            return(sortedItems);
        }
Beispiel #6
0
        private static Node <TValue, TMetadata> BreakCircularReference <TValue, TMetadata>(List <Node <TValue, TMetadata> > unsortedItems)
            where TValue : class
            where TMetadata : IOrderable
        {
            //We have a circular reference in the unsortedItems.
            //This is an error in the definition that we need to handle gracefully.

            //Find & report the cycle.
            List <List <Node <TValue, TMetadata> > > cycles = Orderer.FindCycles(unsortedItems);

            Debug.Assert(cycles.Count > 0);

#if DEBUG
            Debug.WriteLine("Orderer found cycles:");
            foreach (List <Node <TValue, TMetadata> > cycle in cycles)
            {
                foreach (Node <TValue, TMetadata> node in cycle)
                {
                    Debug.Write("\t" + node.Name);
                }
                Debug.WriteLine("");
            }
#endif

            //Find the cycle with the fewest inbound links from other cycles.
            int bestInwardLinkCount = int.MaxValue;
            List <Node <TValue, TMetadata> > bestCycle = null;
            for (int i = 0; (i < cycles.Count); ++i)
            {
                var cycle           = cycles[i];
                int inwardLinkCount = 0;
                for (int j = 0; (j < cycle.Count); ++j)
                {
                    var node = cycle[j];
                    foreach (Node <TValue, TMetadata> child in node.After)
                    {
                        if (child.LowIndex != node.LowIndex)
                        {
                            ++inwardLinkCount;
                            break;
                        }
                    }
                }

                if (inwardLinkCount < bestInwardLinkCount)
                {
                    bestCycle           = cycle;
                    bestInwardLinkCount = inwardLinkCount;
                }
            }

            //Given the best cycle we can find, pick the node that would break the smallest number of "after" constraints.
            Node <TValue, TMetadata> bestNode;
            if (bestCycle == null)
            {
                //Odd, no cycles were found so we need to guess at random.
                bestNode = unsortedItems[0];
                Debug.Fail("Orderer was unable to find a cycle to break");
            }
            else
            {
                bestNode = bestCycle[0];
                for (int i = 1; (i < bestCycle.Count); ++i)
                {
                    Node <TValue, TMetadata> node = bestCycle[i];

                    if (node.After.Count < bestNode.After.Count)
                    {
                        bestNode = node;
                    }
                }
            }

            foreach (Node <TValue, TMetadata> a in bestNode.After)
            {
                a.Before.Remove(bestNode);
            }
            bestNode.After.Clear();

            return(bestNode);
        }