コード例 #1
0
        /// <summary>
        ///     Computes the minimum spanning tree for the connected component containing a specified vertex.
        /// </summary>
        /// <param name="startVertex">The vertex where the algorithm should start.</param>
        /// <returns>The set of edges that define the minimum spanning tree.</returns>
        public ReadOnlySpan <TEdgeId> ComputeMinimumSpanningTree(TVertexId startVertex)
        {
            var heapNodes = new Dictionary <TVertexId, PairingHeap <VertexWithDistanceAndEdge> .ElementPointer>(this._graph.Comparer)
            {
                { startVertex, PairingHeap <VertexWithDistanceAndEdge> .ElementPointer.Undefined }
            };
            var todo   = new PairingHeap <VertexWithDistanceAndEdge>(new DistanceComparer(this._comparer));
            var result = new DynamicArray <TEdgeId>(true);

            ProcessEdges(startVertex);
            while (todo.TryExtractMinimum(out var next))
            {
                heapNodes[next.Vertex] = PairingHeap <VertexWithDistanceAndEdge> .ElementPointer.Undefined;
                result.AddLast(next.Edge);
                ProcessEdges(next.Vertex);
            }

            return(result.AsSpan());

            void ProcessEdges(TVertexId vertex)
            {
                foreach (var outEdgeIdx in this._graph.GetOutEdges(vertex))
                {
                    var target = this._graph.GetTarget(outEdgeIdx);
                    if (heapNodes.TryGetValue(target, out var vertexState))
                    {
                        if (vertexState.IsUndefined)
                        {
                            continue;
                        }

                        var currentBestDistanceToTarget = todo[vertexState].Distance;
                        var distance = this._graph.GetEdgeTag(outEdgeIdx);
                        if (this._comparer.Compare(distance, currentBestDistanceToTarget) >= 0)
                        {
                            continue;
                        }

                        todo.Decrease(vertexState, new(target, distance, outEdgeIdx));
                    }
                    else
                    {
                        var distance = this._graph.GetEdgeTag(outEdgeIdx);
                        var node     = todo.Insert(new(target, distance, outEdgeIdx));
                        heapNodes.Add(target, node);
                    }
                }
            }
        }
コード例 #2
0
        private ReadOnlySpan <TEdgeId> ResolveShortestPath(TVertexId startVertex, TVertexId targetVertex, Dictionary <TVertexId, VertexInfo> sources)
        {
            var result = new DynamicArray <TEdgeId>(true);
            var vertex = targetVertex;

            while (!this._graph.Equals(vertex, startVertex))
            {
                var info = sources[vertex];
                result.AddLast(info.ShortestPathEdge);
                vertex = info.ShortestPathSource;
            }

            var span = result.AsSpan();

            span.Reverse();
            return(span);
        }
コード例 #3
0
        private ReadOnlySpan <TEdgeId> ResolveShortestPath(TVertexId startVertex, TVertexId targetVertex, Dictionary <TVertexId, KeyValuePair <TVertexId, TEdgeId> > sources)
        {
            var result = new DynamicArray <TEdgeId>(true);
            var vertex = targetVertex;

            while (!this._graph.Equals(vertex, startVertex))
            {
                var pair = sources[vertex];
                result.AddLast(pair.Value);
                vertex = pair.Key;
            }

            var span = result.AsSpan();

            span.Reverse();
            return(span);
        }
コード例 #4
0
        /// <summary>
        ///     Computes the maximum flow between two specified vertices.
        /// </summary>
        /// <param name="source">The vertex where the flow should start.</param>
        /// <param name="target">The vertex where the flow should end.</param>
        /// <param name="sourcePartition">The partition of the corresponding minimum cut, which contains <paramref name="source"/>.</param>
        /// <returns>The maximum flow from <paramref name="source"/> to <paramref name="target"/>.</returns>
        public TCapacity ComputeMaximumFlow(TVertexId source, TVertexId target, out TVertexId[] sourcePartition)
        {
            var result       = this._calculator.Zero;
            var flows        = new Dictionary <TEdgeId, TCapacity>(this._graph.GetComparer <TGraph, TEdgeId>());
            var predecessors = new Dictionary <TVertexId, DirectedEdge>(this._graph.GetComparer <TGraph, TVertexId>());
            var queue        = new Queue <TVertexId>();

            while (true)
            {
                queue.Enqueue(source);
                while (queue.Count > 0)
                {
                    var currentVertex = queue.Dequeue();
                    var outEdges      = this._graph.GetOutEdges(currentVertex);
                    foreach (var edgeIdx in outEdges)
                    {
                        var t = this._graph.GetTarget(edgeIdx);
                        if (!this._graph.Equals(t, source) && !predecessors.ContainsKey(t))
                        {
                            if (!flows.TryGetValue(edgeIdx, out var flow))
                            {
                                flow = this._calculator.Zero;
                            }

                            var capacity = this._graph.GetEdgeTag(edgeIdx);
                            if (this._calculator.Compare(capacity, flow) > 0)
                            {
                                predecessors[t] = new(edgeIdx, false);
                                queue.Enqueue(t);
                            }
                        }
                    }

                    var inEdges = this._graph.GetInEdges(currentVertex);
                    foreach (var edgeIdx in inEdges)
                    {
                        var s = this._graph.GetSource(edgeIdx);
                        if (!this._graph.Equals(s, source) && !predecessors.ContainsKey(s))
                        {
                            if (flows.TryGetValue(edgeIdx, out var flow))
                            {
                                if (this._calculator.Compare(flow, this._calculator.Zero) > 0)
                                {
                                    predecessors[s] = new(edgeIdx, true);
                                    queue.Enqueue(s);
                                }
                            }
                        }
                    }
                }

                var augmentingPath = GetAugmentingPath(target);
                if (augmentingPath.IsEmpty)
                {
                    predecessors[source] = default;
                    sourcePartition      = predecessors.Keys.ToArray();
                    return(result);
                }

                var deltaFlow = GetResidualCapacity(augmentingPath[0]);
                for (var i = 1; i < augmentingPath.Length; i++)
                {
                    var residualCapacity = GetResidualCapacity(augmentingPath[i]);
                    if (this._calculator.Compare(residualCapacity, deltaFlow) < 0)
                    {
                        deltaFlow = residualCapacity;
                    }
                }

                var negativeDeltaFlow = this._calculator.Negate(deltaFlow);
                foreach (var e in augmentingPath)
                {
                    if (!flows.TryGetValue(e.Edge, out var flow))
                    {
                        flow = this._calculator.Zero;
                    }

                    flow          = this._calculator.Add(flow, e.IsReverse ? negativeDeltaFlow : deltaFlow);
                    flows[e.Edge] = flow;
                }

                result = this._calculator.Add(result, deltaFlow);
                predecessors.Clear();
            }

            TCapacity GetResidualCapacity(DirectedEdge e)
            {
                if (flows.TryGetValue(e.Edge, out var f))
                {
                    if (e.IsReverse)
                    {
                        return(f);
                    }

                    var capacity = this._graph.GetEdgeTag(e.Edge);
                    return(this._calculator.Add(capacity, this._calculator.Negate(f)));
                }

                Debug.Assert(!e.IsReverse);
                return(this._graph.GetEdgeTag(e.Edge));
            }

            ReadOnlySpan <DirectedEdge> GetAugmentingPath(TVertexId t)
            {
                var path = new DynamicArray <DirectedEdge>(true);

                while (true)
                {
                    if (!predecessors.TryGetValue(t, out var e))
                    {
                        return(path.AsSpan());
                    }

                    path.AddLast(e);
                    t = e.IsReverse ? this._graph.GetTarget(e.Edge) : this._graph.GetSource(e.Edge);
                }
            }
        }