Example #1
0
        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);
            });
        }
Example #2
0
        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);
            });
        }
Example #3
0
        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);
                    }
                }
            }
        }
Example #5
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);
        }
Example #6
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);
        }
        /// <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);
                }
            }
        }