/// <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); } } } }
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); }
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); }
/// <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); } } }