public void When_UserTriesToAddLastItemAndCountEqualsCapacityArray_Must_Resize(int capacity, int newCapacity) { DynamicArray <int> array = null; $"Given there is an array model with '{capacity}' capacity and '{capacity}' items" .x(() => { array = new DynamicArray <int>(); array.SetCapacity(capacity); // generate for (int index = 1; index < capacity + 1; index++) { array.AddLast(index); } }); $"When tries to adds '{capacity + 1}' item in array's tail" .x(() => { array.AddLast(1000); }); $"Then array's capacity should resize from '{capacity}' to '{newCapacity}'" .x(() => { var cap = array.GetCapacity(); var resizeStatus = array.ResizeStatus(); cap.Should().Be(newCapacity); resizeStatus.Should().Be(ResizeStatus.Increase); }); }
public void User_CanAddItemInArrayWhenCountEqualsCapacity() { DynamicArray <int> array = null; $"Given there is an array model with '16' capacity and '16' items" .x(() => { array = new DynamicArray <int>(); array.SetCapacity(16); // generate for (int index = 1; index < 17; index++) { array.AddLast(index); } }); $"When tries to adds '17' item in array's tail" .x(() => { array.AddLast(1000); // set cursor array.SetCursor(16); }); $"Then item should be added to 17's position" .x(() => { var item = array.GetItem(); var count = array.GetItemsCount(); item.Should().Be(1000); count.Should().Be(17); }); }
public void ArrayDoNotResizeIfNewCountEqualsCapacity() { DynamicArray <int> array = null; "Given there is an array model with 16 capacity and 15 items" .x(() => { array = new DynamicArray <int>(); array.SetCapacity(16); // generate for (int index = 0; index < 15; index++) { array.AddLast(index); } }); "When user adds 16's item in array's tail" .x(() => { array.AddLast(1000); }); "Then array's count should be equal to array's capacity and no resize happens" .x(() => { var count = array.GetItemsCount(); var capacity = array.GetCapacity(); var resizeStatus = array.ResizeStatus(); count.Should().Be(capacity); resizeStatus.Should().Be(ResizeStatus.NoChanges); }); }
/// <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 strongly connected components in the graph that are reachable from a specified vertex. /// </summary> /// <param name="startVertex">The vertex where the algorithm should start.</param> /// <returns>Strongly connected components of the graph, that are reachable from <paramref name="startVertex"/> and weren't reported by previous calls to this method.</returns> public SplitArray <TVertexId> ComputeStronglyConnectedComponents(TVertexId startVertex) { var result = new SplitArrayBuilder <TVertexId>(0, 0); if (this._data.ContainsKey(startVertex)) { return(result.Build()); } var s = new DynamicArray <TVertexId>(true); var index = 0; var stack = new DynamicArray <VertexEdgeIterator>(true); stack.AddLast(new(startVertex, -1)); while (stack.TryRemoveLast(out var next)) { startOfLoop: var v = next.Vertex; var edges = this._graph.GetOutEdges(v); if (next.LastEdge < 0) { this._data[v] = new DataPerVertex(index); index++; s.AddLast(v); } else { var w = this._graph.GetTarget(edges[next.LastEdge]); var vData = this._data[v]; vData.LowLink = Math.Min(vData.LowLink, this._data[w].LowLink); this._data[v] = vData; } for (var i = next.LastEdge + 1; i < edges.Length; i++) { var w = this._graph.GetTarget(edges[i]); if (!this._data.TryGetValue(w, out var wData)) { stack.AddLast(new(v, i)); next = new(w, -1); goto startOfLoop; } else if (wData.IsOnStack) { var vData = this._data[v]; vData.LowLink = Math.Min(vData.LowLink, wData.Index); this._data[v] = vData; } } var finalData = this._data[v]; if (finalData.LowLink == finalData.Index) { TVertexId w; do { w = s.RemoveLast(); var dw = this._data[w]; dw.IsOnStack = false; this._data[w] = dw; result.AddValue(w); } while (!this._graph.Equals(w, v)); result.EndPart(); } } return(result.Build()); }
/// <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); } } }