示例#1
0
            public ImmutableList <ImmutableHashSet <T> > Solve <T>(IDirectedAcyclicGraph <T> graph)
                where T : IEquatable <T>
            {
                var reducedGraph = DirectedAcyclicGraphTransitiveReducer <T> .ReduceGraph(graph);

                return(internalSolver.Solve(reducedGraph));
            }
示例#2
0
            public ImmutableList <ImmutableHashSet <T> > Solve <T>(IDirectedAcyclicGraph <T> graph)
                where T : IEquatable <T>
            {
                if (graph.Count == 0)
                {
                    return(ImmutableList <ImmutableHashSet <T> > .Empty);
                }

                var ordering = createTopologicalOrdering(graph);

                return(createLayers(graph, ordering, maxLayerSize));
            }
        // ReSharper disable once SuggestBaseTypeForParameter
        private static IEnumerable <T> getAllSuccessorsRecursively(IDirectedAcyclicGraph <T> graph, T start)
        {
            yield return(start);

            foreach (var child in graph.GetDirectSuccessorsOf(start))
            {
                foreach (var descendant in getAllSuccessorsRecursively(graph, child))
                {
                    yield return(descendant);
                }
            }
        }
示例#4
0
            // ReSharper disable once SuggestBaseTypeForParameter
            private static IList <T> createTopologicalOrdering <T>(IDirectedAcyclicGraph <T> graph)
                where T : IEquatable <T>
            {
                // The topological ordering from low to high.
                var ordering = new List <T>(graph.Count);

                var elements = new HashSet <T>(graph.Elements);
                var orderedElementIndices = new Dictionary <T, int>();

                while (ordering.Count < graph.Count)
                {
                    // All the remaining elements which have all their predecessors added to the topological ordering
                    // already. This includes elements which have no predecessors at all. This is equivalent to the set
                    // of sources in a directed acyclic graph where all already elements and adjacent arrows have been
                    // removed.
                    var sources = elements.Where(allPredecessorsHaveBeenOrdered);

                    // For each considered element, we look at the place of all their predecessors in the partial
                    // topological ordering we have constructed so far.
                    // * We first consider the most recently added predecessor of each element. That is, the predecessor
                    //   of said element that is the highest in the current partial topological ordering.
                    // * Of all these predecessors, we pick the predecessor that is lowest in the ordering. If
                    //   there is only one element with said predecessor, that element is added to the ordering next.
                    // * Ties are broken by looking at the next highest ordered predecessor of all tied elements.
                    // * If all predecessors of 2 or more elements are the same, we pick the element with the least
                    //   predecessors.
                    // This selection process is implemented by representing the predecessors of an element as a
                    // decreasing number sequence of the predecessors' indices, and selecting the lowest of those in a
                    // reflected lexicographic ordering.
                    var next = sources.MinBy(createDecreasingNumberSequenceOfPredecessorIndices);

                    orderedElementIndices.Add(next, ordering.Count);
                    ordering.Add(next);
                    elements.Remove(next);
                }

                return(ordering);

                bool allPredecessorsHaveBeenOrdered(T e) => graph.GetDirectPredecessorsOf(e)
                .All(n => orderedElementIndices.ContainsKey(n));

                DecreasingNumberSequence createDecreasingNumberSequenceOfPredecessorIndices(T e)
                {
                    var predecessorIndices = graph.GetDirectPredecessorsOf(e).Select(n => orderedElementIndices[n]);

                    return(DecreasingNumberSequence.FromUnsortedNumbers(predecessorIndices));
                }
            }
示例#5
0
            private static ImmutableList <ImmutableHashSet <T> > createLayers <T>(
                // ReSharper disable once SuggestBaseTypeForParameter
                IDirectedAcyclicGraph <T> graph, IList <T> ordering, int maxLayerSize)
                where T : IEquatable <T>
            {
                var layersReversed = new List <ImmutableHashSet <T> .Builder>();
                var elementToLayer = new Dictionary <T, int>();

                for (var i = ordering.Count - 1; i >= 0; i--)
                {
                    // We fill in the layers from the last to the first (or bottom to top, if using the traditional
                    // representation where parents go above their children). For each element, we always choose the
                    // layer closest to the last (or lowest), such that all its successors are in a later (or lower)
                    // layer, and the layer has less than W elements.
                    // The list represents the layers in reverse order, meaning that the last layer of our result is the
                    // first element in the list. This allows us to use the automatic growing property of the list.
                    // Combining these two things, the following looks for the lowest integer k such that (1) each
                    // successor is in a set with an index lower lower than k, and (2) the set at index k has less than
                    // W elements.

                    // Requirement (1)
                    var highestSuccessorLevel = graph.GetDirectSuccessorsOf(ordering[i])
                                                .Select(elmt => elementToLayer[elmt] + 1)
                                                .Aggregate(0, Math.Max);

                    // Requirement (2)
                    var candidateLayer = highestSuccessorLevel;
                    while (
                        candidateLayer < layersReversed.Count && layersReversed[candidateLayer].Count == maxLayerSize)
                    {
                        candidateLayer++;
                    }

                    // Expand the list as needed
                    while (candidateLayer >= layersReversed.Count)
                    {
                        layersReversed.Add(ImmutableHashSet.CreateBuilder <T>());
                    }

                    // Add the element to the layer
                    layersReversed[candidateLayer].Add(ordering[i]);
                    elementToLayer.Add(ordering[i], candidateLayer);
                }

                return(ImmutableList.CreateRange(layersReversed.Select(b => b.ToImmutable()).Reverse()));
            }
        public static IDirectedAcyclicGraph <T> ReduceGraph(IDirectedAcyclicGraph <T> graph)
        {
            var elementsEnumerable = graph.Elements;
            var elements           = elementsEnumerable as IList <T> ?? elementsEnumerable.ToList();
            var graphBuilder       = DirectedGraphBuilder <T> .NewBuilder();

            foreach (var element in elements)
            {
                graphBuilder.AddElement(element);
            }

            foreach (var element in elements)
            {
                foreach (var child in getOnlyChildrenWithoutIndirectPath(graph, element))
                {
                    graphBuilder.AddArrow(element, child);
                }
            }

            return(graphBuilder.CreateAcyclicGraphUnsafe());
        }
        private static IEnumerable <T> getOnlyChildrenWithoutIndirectPath(IDirectedAcyclicGraph <T> graph, T element)
        {
            var childrenEnumerable = graph.GetDirectSuccessorsOf(element);
            var children           = childrenEnumerable as IList <T>
                                     ?? childrenEnumerable.ToList();
            var reducedEdges = new HashSet <T>(children);

            foreach (var child in children)
            {
                foreach (var descendant in getAllSuccessorsRecursively(graph, child))
                {
                    if (descendant.Equals(child))
                    {
                        continue;
                    }

                    // Every arrow to a successor of our direct child is already reachable.
                    reducedEdges.Remove(descendant);
                }
            }

            return(reducedEdges);
        }