From 01c9957ee3a0accca940831e67c466071b1f0874 Mon Sep 17 00:00:00 2001 From: Jack Dermody Date: Fri, 2 Aug 2024 07:47:08 +1000 Subject: [PATCH] added weighted graphs and HNSW implementation --- BrightData.UnitTests/FixedSizeArrayTests.cs | 13 + BrightData.UnitTests/MatrixTests.cs | 30 +- BrightData.UnitTests/TensorTests.cs | 12 +- BrightData.UnitTests/VectorTests.cs | 32 +- BrightData/BrightData.csproj | 17 +- BrightData/BrightData.xml | 454 ++++-- .../Distribution/ContinuousDistribution.cs | 16 +- .../Distribution/ExponentialDistribution.cs | 16 +- BrightData/Distribution/NormalDistribution.cs | 30 +- BrightData/ExtensionMethods.Distributions.cs | 9 +- BrightData/Interfaces.cs | 46 +- .../Helper/IndexedFixedSizeGraphNode.cs | 3 - ...ray.cs => FixedSizeSortedArrayTemplate.cs} | 1344 +++++++++++++---- ...ray.tt => FixedSizeSortedArrayTemplate.tt} | 40 +- .../Types/Graph/FixedSizeWeightedGraph.cs | 84 ++ .../Types/Graph/FixedSizeWeightedGraphNode.cs | 64 + BrightData/Types/Graph/GraphIndex.cs | 21 + .../HierarchicalNavigationSmallWorldGraph.cs | 104 ++ .../SortedArrayHelper.cs} | 89 +- BrightData/Types/SortedArray.cs | 48 + .../WeightInitialisation/Gaussian.cs | 4 +- .../WeightInitialisation/Xavier.cs | 4 +- 22 files changed, 1936 insertions(+), 544 deletions(-) rename BrightData/Types/FixedSizeSortedArray/{FixedSizeSortedArray.cs => FixedSizeSortedArrayTemplate.cs} (83%) rename BrightData/Types/FixedSizeSortedArray/{FixedSizeSortedArray.tt => FixedSizeSortedArrayTemplate.tt} (85%) create mode 100644 BrightData/Types/Graph/FixedSizeWeightedGraph.cs create mode 100644 BrightData/Types/Graph/FixedSizeWeightedGraphNode.cs create mode 100644 BrightData/Types/Graph/GraphIndex.cs create mode 100644 BrightData/Types/Graph/HierarchicalNavigationSmallWorldGraph.cs rename BrightData/Types/{FixedSizeSortedArray/FixedSizeSortedArrayHelper.cs => Helper/SortedArrayHelper.cs} (68%) create mode 100644 BrightData/Types/SortedArray.cs diff --git a/BrightData.UnitTests/FixedSizeArrayTests.cs b/BrightData.UnitTests/FixedSizeArrayTests.cs index 5417b825..7e0fec79 100644 --- a/BrightData.UnitTests/FixedSizeArrayTests.cs +++ b/BrightData.UnitTests/FixedSizeArrayTests.cs @@ -40,5 +40,18 @@ public void TestDescending() array.Size.Should().Be(1); array.MaxValue.Should().Be(1); } + + [Fact] + public void TestSingle() + { + var array = new FixedSizeSortedAscending1Array(); + array.TryAdd(1, 0.2f).Should().BeTrue(); + array.TryAdd(2, 0.3f).Should().BeFalse(); + array.TryAdd(3, 0.1f).Should().BeTrue(); + array.MaxValue.Should().Be(array.MinValue); + array.MaxWeight.Should().Be(array.MinWeight); + array.RemoveAt(0); + array.Size.Should().Be(0); + } } } diff --git a/BrightData.UnitTests/MatrixTests.cs b/BrightData.UnitTests/MatrixTests.cs index f721fcb2..ad4ecf80 100644 --- a/BrightData.UnitTests/MatrixTests.cs +++ b/BrightData.UnitTests/MatrixTests.cs @@ -539,7 +539,7 @@ public void MatrixMultiplyEachColumnWith() [Fact] public void MatrixSigmoidActivation() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); using var cpu = a.Sigmoid(); using var gpu = Apply(_cuda, a, (a) => a.Sigmoid()); @@ -550,7 +550,7 @@ public void MatrixSigmoidActivation() [Fact] public void MatrixSigmoidDerivative() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); using var cpu = a.SigmoidDerivative(); using var gpu = Apply(_cuda, a, (a) => a.SigmoidDerivative()); @@ -561,7 +561,7 @@ public void MatrixSigmoidDerivative() [Fact] public void MatrixTanhActivation() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); using var cpu = a.Tanh(); using var gpu = Apply(_cuda, a, a => a.Tanh()); @@ -572,7 +572,7 @@ public void MatrixTanhActivation() [Fact] public void MatrixTanhDerivative() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); using var cpu = a.TanhDerivative(); using var gpu = Apply(_cuda, a, a => a.TanhDerivative()); @@ -583,7 +583,7 @@ public void MatrixTanhDerivative() [Fact] public void MatrixReluActivation() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); using var cpu = a.Relu(); using var gpu = Apply(_cuda, a, a => a.Relu()); @@ -594,7 +594,7 @@ public void MatrixReluActivation() [Fact] public void MatrixReluDerivative() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); using var cpu = a.ReluDerivative(); using var gpu = Apply(_cuda, a, a => a.ReluDerivative()); @@ -605,7 +605,7 @@ public void MatrixReluDerivative() [Fact] public void MatrixLeakyReluActivation() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); using var cpu = a.LeakyRelu(); using var gpu = Apply(_cuda, a, a => a.LeakyRelu()); @@ -616,7 +616,7 @@ public void MatrixLeakyReluActivation() [Fact] public void MatrixLeakyReluDerivative() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); using var cpu = a.LeakyReluDerivative(); using var gpu = Apply(_cuda, a, a => a.LeakyReluDerivative()); @@ -627,7 +627,7 @@ public void MatrixLeakyReluDerivative() [Fact] public void MatrixSoftmaxActivation() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); using var cpu = a.Softmax(); using var gpu = Apply(_cuda, a, a => a.Softmax()); @@ -638,7 +638,7 @@ public void MatrixSoftmaxActivation() [Fact] public void MatrixSoftmaxPerRow() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); var cpu = a.SoftmaxPerRow().Select(x => _cpu.CreateVector(x)).ToArray(); var gpu = Apply(_cuda, a, a => a.SoftmaxPerRow().Select(x => _cuda.CreateVector(x)).ToArray()); @@ -649,7 +649,7 @@ public void MatrixSoftmaxPerRow() [Fact] public void MatrixRowVector2() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); var cpu = 3.AsRange().Select(a.GetRowVector).ToArray(); var gpu = Apply(_cuda, a, a => 3.AsRange().Select(a.GetRowVector).ToArray()); @@ -660,7 +660,7 @@ public void MatrixRowVector2() [Fact] public void MatrixRowVectorsTransposed() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); using var aT = a.Transpose(); var cpu = 3.AsRange().Select(aT.GetColumnVector).ToArray(); @@ -672,7 +672,7 @@ public void MatrixRowVectorsTransposed() [Fact] public void MatrixSoftmaxDerivative() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); var cpu = _cpu.SoftmaxDerivative(a.Segment); var gpu = Apply(_cuda, a, a => _cuda.SoftmaxDerivative(a.Segment)); @@ -683,7 +683,7 @@ public void MatrixSoftmaxDerivative() [Fact] public void MatrixSoftmaxPerRowDerivative() { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var a = _cpu.CreateMatrix(3, 7, (j, k) => Convert.ToSingle(normalDistribution.Sample())); var cpu = a.SoftmaxPerRow(); var gpu = Apply(_cuda, a, a => a.SoftmaxPerRow()); @@ -961,7 +961,7 @@ public void MatrixPow() [Fact] public void MatrixConstrain() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var cpu = _cpu.CreateMatrix(100, 100, (x, y) => Convert.ToSingle(distribution.Sample())); using var gpu = Apply(_cuda, cpu, a => a.ConstrainInPlace(-2f, 2f)); using var mkl = Apply(_mkl, cpu, a => a.ConstrainInPlace(-2f, 2f)); diff --git a/BrightData.UnitTests/TensorTests.cs b/BrightData.UnitTests/TensorTests.cs index c5d61b42..b688c04e 100644 --- a/BrightData.UnitTests/TensorTests.cs +++ b/BrightData.UnitTests/TensorTests.cs @@ -119,7 +119,7 @@ public void TensorAddPadding2() void CheckTensorIm2Col(uint rows, uint columns, uint depth, uint filterWidth, uint filterHeight, uint xStride, uint yStride, bool randomData) { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var cpuTensor = _cpu.CreateTensor3D(depth.AsRange().Select(i => _cpu.CreateMatrix(rows, columns, (j, k) => randomData ? Convert.ToSingle(normalDistribution.Sample()) : Convert.ToSingle((i + 1) * (j + 1) * (k + 1)) @@ -318,7 +318,7 @@ public void TensorMaxPoolBlankIrregular() void CheckTensorMaxPool(uint rows, uint columns, uint depth, uint filterWidth, uint filterHeight, uint xStride, uint yStride, bool randomInit, bool calculateIndices) { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var cpuTensor = _cpu.CreateTensor3D(depth.AsRange().Select(i => _cpu.CreateMatrix(rows, columns, (j, k) => randomInit ? Convert.ToSingle(normalDistribution.Sample()) : Convert.ToSingle((i + 1) * (j + 1) * (k + 1)) @@ -359,7 +359,7 @@ void CheckTensorMaxPool(uint rows, uint columns, uint depth, uint filterWidth, u void CheckTensorReverseIm2Col(uint filterWidth, uint filterHeight, uint xStride, uint yStride, uint depth, uint filterCount, uint inputWidth, uint inputHeight) { - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); using var cpuTensor = _cpu.CreateTensor3D(depth.AsRange().Select(_ => _cpu.CreateMatrix(inputHeight, inputWidth, (_, _) => Convert.ToSingle(normalDistribution.Sample()))).ToArray()); using var im2Col = cpuTensor.Im2Col(filterWidth, filterHeight, xStride, yStride); using var cpuFilter = _cpu.CreateMatrix(depth * filterWidth * filterHeight, filterCount, (_, _) => normalDistribution.Sample()); @@ -793,7 +793,7 @@ public void Tensor3DToFloatTensor() [Fact] public void Tensor3DTransposeThisAndMultiply() { - var normalDistribution = _context.CreateNormalDistribution(); + var normalDistribution = _context.CreateNormalDistribution(); var tensor1 = CheckCreateTensor(9, 3, 3, (_, _, _) => normalDistribution.Sample()); var data = 3.AsRange().Select(_ => CheckCreateTensor(3, 3, 3, (i, j, k) => (i + 1) * (j + 1) * (k + 1))).ToArray(); @@ -814,7 +814,7 @@ public void Tensor3DTransposeThisAndMultiply() [Fact] public void Tensor3DMultiply() { - var normalDistribution = _context.CreateNormalDistribution(); + var normalDistribution = _context.CreateNormalDistribution(); var tensor1 = CheckCreateTensor(3, 9, 3, (_, _, _) => normalDistribution.Sample()); var data = 3.AsRange().Select(_ => CheckCreateTensor(3, 3, 3, (i, j, k) => (i + 1) * (j + 1) * (k + 1))).ToArray(); @@ -900,7 +900,7 @@ public void Tensor4DReverseIm2Col() { const int rows = 4, columns = 4, depth = 1, count = 1, filterWidth = 2, filterHeight = 2, filterCount = 1, xStride = 2, yStride = 2; - var normalDistribution = _context.CreateNormalDistribution(0, 1); + var normalDistribution = _context.CreateNormalDistribution(0, 1); var data = Enumerable.Range(0, count) .Select(_ => CheckCreateTensor(rows, columns, depth, (_, _, _) => normalDistribution.Sample())).ToArray(); using var cpuTensor = _cpu.CreateTensor4D(data); diff --git a/BrightData.UnitTests/VectorTests.cs b/BrightData.UnitTests/VectorTests.cs index d7813939..8e333a94 100644 --- a/BrightData.UnitTests/VectorTests.cs +++ b/BrightData.UnitTests/VectorTests.cs @@ -76,7 +76,7 @@ public void TestVectorCreation() void TestDistances(DistanceMetric distanceMetric) { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); var vectors = Enumerable.Range(0, 10).Select(_ => (IReadOnlyNumericSegment)_cpu.CreateSegment(100, _ => distribution.Sample())).ToArray(); var compareTo = Enumerable.Range(0, 20).Select(_ => (IReadOnlyNumericSegment)_cpu.CreateSegment(100, _ => distribution.Sample())).ToArray(); @@ -313,7 +313,7 @@ public void VectorMultiply() [Fact] public void VectorEuclideanDistance() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(500, _ => distribution.Sample()); using var b = _cpu.CreateVector(500, _ => distribution.Sample()); @@ -340,7 +340,7 @@ public void VectorCosineDistance() [Fact] public void VectorManhattanDistance() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(5000, _ => distribution.Sample()); using var b = _cpu.CreateVector(5000, _ => distribution.Sample()); @@ -354,7 +354,7 @@ public void VectorManhattanDistance() [Fact] public void VectorMeanSquaredDistance() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(1000, _ => distribution.Sample()); using var b = _cpu.CreateVector(1000, _ => distribution.Sample()); @@ -367,7 +367,7 @@ public void VectorMeanSquaredDistance() [Fact] public void VectorSquaredEuclideanDistance() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(1000, _ => distribution.Sample()); using var b = _cpu.CreateVector(1000, _ => distribution.Sample()); @@ -381,7 +381,7 @@ public void VectorSquaredEuclideanDistance() [Fact] public void VectorAverage() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(5000, _ => distribution.Sample()); var cpu = a.Average(); @@ -393,7 +393,7 @@ public void VectorAverage() [Fact] public void VectorL1Norm() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(5000, _ => distribution.Sample()); var cpu = a.L1Norm(); @@ -405,7 +405,7 @@ public void VectorL1Norm() [Fact] public void VectorAbs() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(5000, _ => distribution.Sample()); var cpu = a.Abs(); @@ -417,7 +417,7 @@ public void VectorAbs() [Fact] public void VectorLog() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(5000, _ => distribution.Sample()); var cpu = a.Log(); @@ -430,7 +430,7 @@ public void VectorLog() [Fact] public void VectorStdDev() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(5000, _ => distribution.Sample()); var cpu = a.StdDev(null); @@ -493,7 +493,7 @@ static IVector TestMultiDistance(LinearAlgebraProvider lap, IVecto [Fact] public void MultiEuclideanDistance() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(5000, _ => distribution.Sample()); using var b = _cpu.CreateVector(5000, _ => distribution.Sample()); @@ -507,7 +507,7 @@ public void MultiEuclideanDistance() [Fact] public void MultiManhattanDistance() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(5000, _ => distribution.Sample()); using var b = _cpu.CreateVector(5000, _ => distribution.Sample()); @@ -520,7 +520,7 @@ public void MultiManhattanDistance() [Fact] public void MultiCosineDistance() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(5000, _ => distribution.Sample()); using var b = _cpu.CreateVector(5000, _ => distribution.Sample()); @@ -623,7 +623,7 @@ public void VectorSplit() [Fact] public void VectorSoftMax() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(128, _ => distribution.Sample()); using var cpu = a.Softmax(); @@ -635,7 +635,7 @@ public void VectorSoftMax() [Fact] public void VectorSoftMaxDerivative() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); using var a = _cpu.CreateVector(128, _ => distribution.Sample()); using var cpu = a.SoftmaxDerivative(); @@ -650,7 +650,7 @@ public void VectorSoftMaxDerivative() [Fact] public void VectorReverse() { - var distribution = _context.CreateNormalDistribution(0, 5); + var distribution = _context.CreateNormalDistribution(0, 5); var a = _cpu.CreateVector(128, _ => distribution.Sample()); var cpu = a.Reverse(); diff --git a/BrightData/BrightData.csproj b/BrightData/BrightData.csproj index 507b41de..ad81d5e3 100644 --- a/BrightData/BrightData.csproj +++ b/BrightData/BrightData.csproj @@ -63,11 +63,6 @@ True GenericTypeMapping.tt - - True - True - FixedSizeSortedArray.tt - @@ -87,6 +82,10 @@ True \ + + TextTemplatingFileGenerator + FixedSizeSortedArrayTemplate.cs + TextTemplatingFileGenerator FixedSizeSortedArray.cs @@ -113,10 +112,14 @@ True GenericTypeMapping.tt - + + True + True + + True True - FixedSizeSortedArray.tt + FixedSizeSortedArrayTemplate.tt diff --git a/BrightData/BrightData.xml b/BrightData/BrightData.xml index a977f713..18c57f58 100644 --- a/BrightData/BrightData.xml +++ b/BrightData/BrightData.xml @@ -4031,7 +4031,7 @@ - + Create a continuous distribution @@ -4049,7 +4049,7 @@ - + Create a normal distribution @@ -4058,7 +4058,7 @@ Standard deviation - + Create an exponential distribution @@ -5741,7 +5741,7 @@ Categorical distribution - https://en.wikipedia.org/wiki/Categorical_distribution - + Continuous distribution - https://en.wikipedia.org/wiki/Probability_distribution#Absolutely_continuous_probability_distribution @@ -5751,7 +5751,7 @@ Discrete uniform distribution - https://en.wikipedia.org/wiki/Discrete_uniform_distribution - + Normal distribution - https://en.wikipedia.org/wiki/Normal_distribution @@ -5759,7 +5759,7 @@ - + Normal distribution - https://en.wikipedia.org/wiki/Normal_distribution @@ -6570,7 +6570,7 @@ Positive discrete data distribution - + Continuous data distribution @@ -12447,6 +12447,172 @@ + + + Fixed size sorted array of values and weights (max 1 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 1 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if elements should be unique - will return false if the value and weight already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 1 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 1 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a higher weight + + Value to add + Weight to add + True if elements should be unique - will return false if the value and weight already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + Fixed size sorted array of values and weights (max 2 elements) @@ -12520,7 +12686,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -12599,11 +12765,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -12686,7 +12852,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -12765,11 +12931,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -12852,7 +13018,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -12931,11 +13097,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13018,7 +13184,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13097,11 +13263,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13184,7 +13350,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13263,11 +13429,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13350,7 +13516,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13429,11 +13595,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13516,7 +13682,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13595,11 +13761,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13682,7 +13848,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13761,11 +13927,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13848,7 +14014,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -13927,11 +14093,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14014,7 +14180,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14093,11 +14259,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14180,7 +14346,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14259,11 +14425,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14346,7 +14512,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14425,11 +14591,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14512,7 +14678,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14591,11 +14757,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14678,7 +14844,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14757,11 +14923,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14844,7 +15010,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -14923,11 +15089,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15010,7 +15176,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15089,11 +15255,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15176,7 +15342,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15255,11 +15421,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15342,7 +15508,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15421,11 +15587,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15508,7 +15674,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15587,11 +15753,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15674,7 +15840,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15753,11 +15919,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15840,7 +16006,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -15919,11 +16085,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16006,7 +16172,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16085,11 +16251,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16172,7 +16338,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16251,11 +16417,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16338,7 +16504,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16417,11 +16583,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16504,7 +16670,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16583,11 +16749,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16670,7 +16836,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16749,11 +16915,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16836,7 +17002,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -16915,11 +17081,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -17002,7 +17168,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -17081,11 +17247,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -17168,7 +17334,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -17247,11 +17413,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -17334,7 +17500,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -17413,11 +17579,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -17500,7 +17666,7 @@ Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -17579,11 +17745,11 @@ - Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + Tries to add a new element - will succeed if there aren't already max elements with a higher weight Value to add Weight to add - True if values should be unique - will return false if the value already exists + True if elements should be unique - will return false if the value and weight already exists True if the element was added @@ -17593,6 +17759,94 @@ Index of element to remove + + + A fixed size graph weighted graph + + + + + + + + + + + + + + + + + + + + + + + A graph node with a (fixed size) maximum number of neighbours + + + + + A graph node with a (fixed size) maximum number of neighbours + + + + + + + + Tries to add a new neighbour + + Index of neighbour + Neighbour weight + + + + + + + Ordered span of neighbours by weight + + + + + Enumerates the neighbours by weight + + + + + + + + + + + Index only graph node value + + + + + + Index only graph node value + + + + + + + + + + + + + + + Fixed size array helper methods + + Contains a list of indices diff --git a/BrightData/Distribution/ContinuousDistribution.cs b/BrightData/Distribution/ContinuousDistribution.cs index ea108f7a..9fb6f749 100644 --- a/BrightData/Distribution/ContinuousDistribution.cs +++ b/BrightData/Distribution/ContinuousDistribution.cs @@ -1,27 +1,29 @@ using System; +using System.Numerics; namespace BrightData.Distribution { /// /// Continuous distribution - https://en.wikipedia.org/wiki/Probability_distribution#Absolutely_continuous_probability_distribution /// - internal class ContinuousDistribution : IContinuousDistribution + internal class ContinuousDistribution : IContinuousDistribution + where T : unmanaged, INumber, IBinaryFloatingPointIeee754 { readonly BrightDataContext _context; - public ContinuousDistribution(BrightDataContext context, float inclusiveLowerBound = 0f, float exclusiveUpperBound = 1f) + public ContinuousDistribution(BrightDataContext context, T? inclusiveLowerBound = null, T? exclusiveUpperBound = null) { if (inclusiveLowerBound > exclusiveUpperBound) throw new ArgumentException("Lower bound was higher than upper bound"); _context = context; - From = inclusiveLowerBound; - Size = exclusiveUpperBound - inclusiveLowerBound; + From = inclusiveLowerBound ?? T.Zero; + Size = (exclusiveUpperBound ?? T.One) - From; } - public float From { get; } - public float Size { get; } + public T From { get; } + public T Size { get; } - public float Sample() => From + _context.NextRandomFloat() * Size; + public T Sample() => From + _context.NextRandom() * Size; } } diff --git a/BrightData/Distribution/ExponentialDistribution.cs b/BrightData/Distribution/ExponentialDistribution.cs index a6ee0b6f..e2a6ed31 100644 --- a/BrightData/Distribution/ExponentialDistribution.cs +++ b/BrightData/Distribution/ExponentialDistribution.cs @@ -1,20 +1,24 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Numerics; using System.Text; using System.Threading.Tasks; namespace BrightData.Distribution { - internal class ExponentialDistribution(BrightDataContext context, float lambda) : IContinuousDistribution + internal class ExponentialDistribution(BrightDataContext context, T? lambda) : IContinuousDistribution + where T : unmanaged, INumber, IBinaryFloatingPointIeee754 { - public float Sample() + public T Lambda { get; } = lambda ?? T.One; + + public T Sample() { - float r; + T r; do { - r = context.NextRandomFloat(); - } while (r == 0f); - return -MathF.Log(r) / lambda; + r = context.NextRandom(); + } while (r == T.Zero); + return -T.Log(r) * Lambda; } } } diff --git a/BrightData/Distribution/NormalDistribution.cs b/BrightData/Distribution/NormalDistribution.cs index fb4bcbcd..c658e773 100644 --- a/BrightData/Distribution/NormalDistribution.cs +++ b/BrightData/Distribution/NormalDistribution.cs @@ -1,4 +1,5 @@ using System; +using System.Numerics; using BrightData.Helper; namespace BrightData.Distribution @@ -9,34 +10,35 @@ namespace BrightData.Distribution /// /// /// - internal class NormalDistribution(BrightDataContext context, float mean = 0f, float stdDev = 1f) - : IContinuousDistribution + internal class NormalDistribution(BrightDataContext context, T? mean = null, T? stdDev = null) : IContinuousDistribution + where T: unmanaged, INumber, IBinaryFloatingPointIeee754 { - public float Mean { get; } = mean; - public float StdDev { get; } = stdDev; + public T Mean { get; } = mean ?? T.Zero; + public T StdDev { get; } = stdDev ?? T.One; - public float Sample() + public T Sample() { - float x; - while (!PolarTransform(context.NextRandomFloat(), context.NextRandomFloat(), out x, out _)) { + T x; + while (!PolarTransform(context.NextRandom(), context.NextRandom(), out x, out _)) { // nop } return Mean + StdDev * x; } - static bool PolarTransform(float a, float b, out float x, out float y) + static bool PolarTransform(T a, T b, out T x, out T y) { - var v1 = (2.0f * a) - 1.0f; - var v2 = (2.0f * b) - 1.0f; + var two = T.One + T.One; + var v1 = (two * a) - T.One; + var v2 = (two * b) - T.One; var r = (v1 * v1) + (v2 * v2); - if (r >= 1.0 || MathF.Abs(r) < Math.AlmostZero) { - x = 0; - y = 0; + if (r >= T.One || T.Abs(r) < Math.AlmostZero) { + x = T.Zero; + y = T.Zero; return false; } - var fac = MathF.Sqrt(-2.0f * MathF.Log(r) / r); + var fac = T.Sqrt(-two * T.Log(r) / r); x = v1 * fac; y = v2 * fac; return true; diff --git a/BrightData/ExtensionMethods.Distributions.cs b/BrightData/ExtensionMethods.Distributions.cs index 5fbbbb91..efb4f436 100644 --- a/BrightData/ExtensionMethods.Distributions.cs +++ b/BrightData/ExtensionMethods.Distributions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Numerics; using BrightData.Distribution; namespace BrightData @@ -12,6 +13,8 @@ public partial class ExtensionMethods /// public static float NextRandomFloat(this BrightDataContext context) => (float)context.Random.NextDouble(); + public static T NextRandom(this BrightDataContext context) where T: unmanaged, INumber => T.CreateSaturating(context.Random.NextDouble()); + /// /// Returns a randomly initialized positive number /// @@ -60,7 +63,7 @@ public partial class ExtensionMethods /// /// /// - public static IContinuousDistribution CreateContinuousDistribution(this BrightDataContext context, float inclusiveLowerBound = 0f, float exclusiveUpperBound = 1f) => new ContinuousDistribution(context, inclusiveLowerBound, exclusiveUpperBound); + public static IContinuousDistribution CreateContinuousDistribution(this BrightDataContext context, T? inclusiveLowerBound = null, T? exclusiveUpperBound = null) where T: unmanaged, INumber, IBinaryFloatingPointIeee754 => new ContinuousDistribution(context, inclusiveLowerBound, exclusiveUpperBound); /// /// Create a discrete uniform distribution @@ -78,7 +81,7 @@ public partial class ExtensionMethods /// /// Standard deviation /// - public static IContinuousDistribution CreateNormalDistribution(this BrightDataContext context, float mean = 0f, float stdDev = 1f) => new NormalDistribution(context, mean, stdDev); + public static IContinuousDistribution CreateNormalDistribution(this BrightDataContext context, T? mean = null, T? stdDev = null) where T: unmanaged, INumber, IBinaryFloatingPointIeee754 => new NormalDistribution(context, mean, stdDev); /// /// Create an exponential distribution @@ -86,6 +89,6 @@ public partial class ExtensionMethods /// /// /// - public static IContinuousDistribution CreateExponentialDistribution(this BrightDataContext context, float lambda = 1f) => new ExponentialDistribution(context, lambda); + public static IContinuousDistribution CreateExponentialDistribution(this BrightDataContext context, T? lambda = null) where T: unmanaged, INumber, IBinaryFloatingPointIeee754 => new ExponentialDistribution(context, lambda); } } diff --git a/BrightData/Interfaces.cs b/BrightData/Interfaces.cs index 8b9cde82..d42f627e 100644 --- a/BrightData/Interfaces.cs +++ b/BrightData/Interfaces.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Numerics; using System.Threading; using System.Threading.Tasks; using BrightData.Types; @@ -301,7 +302,7 @@ public enum AggregationType /// /// public interface IDistribution - where T : struct + where T : unmanaged, INumber { /// /// Samples a value from the distribution @@ -323,7 +324,7 @@ public interface INonNegativeDiscreteDistribution : IDistribution; /// /// Continuous data distribution /// - public interface IContinuousDistribution : IDistribution; + public interface IContinuousDistribution : IDistribution where T : unmanaged, INumber, IBinaryFloatingPointIeee754; /// /// Indicates that the type has a size @@ -636,6 +637,45 @@ public interface IFixedSizeSortedArray : IHaveSize /// /// Index of element to remove /// - void RemoveAt(byte index); + V RemoveAt(byte index); + } + + public interface IGraphNode : IHaveSingleIndex + { + ReadOnlySpan NeighbourSpan { get; } + IEnumerable Neighbours { get; } + } + + public interface IWeightedGraphNode : IGraphNode + where T: IHaveSingleIndex + where W : unmanaged, INumber, IMinMaxValue + { + public T Value { get; } + + bool AddNeighbour(uint index, W weight); + + IEnumerable<(uint Index, W Weight)> WeightedNeighbours { get; } + } + + public interface ICalculateNodeWeights + where W : unmanaged, INumber, IMinMaxValue + { + W GetWeight(uint fromIndex, uint toIndex); + } + + public interface IWeightedGraph : IHaveSize + where T: IHaveSingleIndex + where W : unmanaged, INumber, IMinMaxValue + { + IWeightedGraphNode Create(T value, bool addToGraph = true); + + void Add(IWeightedGraphNode node); + + IWeightedGraphNode Get(uint index); + + RAT Search(uint q, uint entryPoint, ICalculateNodeWeights distanceCalculator) + where RAT : struct, IFixedSizeSortedArray + where CAT : struct, IFixedSizeSortedArray + ; } } diff --git a/BrightData/LinearAlgebra/VectorIndexing/Helper/IndexedFixedSizeGraphNode.cs b/BrightData/LinearAlgebra/VectorIndexing/Helper/IndexedFixedSizeGraphNode.cs index a1e8075f..065a5a22 100644 --- a/BrightData/LinearAlgebra/VectorIndexing/Helper/IndexedFixedSizeGraphNode.cs +++ b/BrightData/LinearAlgebra/VectorIndexing/Helper/IndexedFixedSizeGraphNode.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using BrightData.Types; namespace BrightData.LinearAlgebra.VectorIndexing.Helper { diff --git a/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.cs b/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayTemplate.cs similarity index 83% rename from BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.cs rename to BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayTemplate.cs index 4fa415d1..0ec85f22 100644 --- a/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.cs +++ b/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayTemplate.cs @@ -3,10 +3,267 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Collections.Generic; -using BrightData.Types.FixedSizeSortedArray; +using BrightData.Types.Helper; +using System.Linq; namespace BrightData.Types { + /// + /// Fixed size sorted array of values and weights (max 1 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending1Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 1; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if elements should be unique - will return false if the value and weight already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public V RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); + --_size; + return ret; + } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); + } + + /// + /// Fixed size sorted array of values and weights (max 1 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending1Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 1; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight + /// + /// Value to add + /// Weight to add + /// True if elements should be unique - will return false if the value and weight already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public V RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); + --_size; + return ret; + } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); + } + /// /// Fixed size sorted array of values and weights (max 2 elements) /// that is sorted in ascending order based on each weight @@ -103,13 +360,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -117,15 +377,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -134,7 +398,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending2Array() + public record struct FixedSizeSortedDescending2Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -142,6 +406,7 @@ public record struct FixedSizeSortedDescending2Array() /// Max size of the array /// public const int MaxSize = 2; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -219,17 +484,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -237,15 +505,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -344,13 +616,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -358,15 +633,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -375,7 +654,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending3Array() + public record struct FixedSizeSortedDescending3Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -383,6 +662,7 @@ public record struct FixedSizeSortedDescending3Array() /// Max size of the array /// public const int MaxSize = 3; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -460,17 +740,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -478,15 +761,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -585,13 +872,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -599,15 +889,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -616,7 +910,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending4Array() + public record struct FixedSizeSortedDescending4Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -624,6 +918,7 @@ public record struct FixedSizeSortedDescending4Array() /// Max size of the array /// public const int MaxSize = 4; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -701,17 +996,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -719,15 +1017,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -826,13 +1128,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -840,15 +1145,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -857,7 +1166,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending5Array() + public record struct FixedSizeSortedDescending5Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -865,6 +1174,7 @@ public record struct FixedSizeSortedDescending5Array() /// Max size of the array /// public const int MaxSize = 5; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -942,17 +1252,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -960,15 +1273,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -1067,13 +1384,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -1081,15 +1401,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -1098,7 +1422,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending6Array() + public record struct FixedSizeSortedDescending6Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -1106,6 +1430,7 @@ public record struct FixedSizeSortedDescending6Array() /// Max size of the array /// public const int MaxSize = 6; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -1183,17 +1508,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -1201,15 +1529,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -1308,13 +1640,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -1322,15 +1657,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -1339,7 +1678,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending7Array() + public record struct FixedSizeSortedDescending7Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -1347,6 +1686,7 @@ public record struct FixedSizeSortedDescending7Array() /// Max size of the array /// public const int MaxSize = 7; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -1424,17 +1764,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -1442,15 +1785,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -1549,13 +1896,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -1563,15 +1913,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -1580,7 +1934,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending8Array() + public record struct FixedSizeSortedDescending8Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -1588,6 +1942,7 @@ public record struct FixedSizeSortedDescending8Array() /// Max size of the array /// public const int MaxSize = 8; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -1665,17 +2020,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -1683,15 +2041,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -1790,13 +2152,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -1804,15 +2169,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -1821,7 +2190,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending9Array() + public record struct FixedSizeSortedDescending9Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -1829,6 +2198,7 @@ public record struct FixedSizeSortedDescending9Array() /// Max size of the array /// public const int MaxSize = 9; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -1906,17 +2276,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -1924,15 +2297,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -2031,13 +2408,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -2045,15 +2425,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -2062,7 +2446,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending10Array() + public record struct FixedSizeSortedDescending10Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -2070,6 +2454,7 @@ public record struct FixedSizeSortedDescending10Array() /// Max size of the array /// public const int MaxSize = 10; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -2147,17 +2532,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -2165,15 +2553,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -2272,13 +2664,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -2286,15 +2681,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -2303,7 +2702,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending11Array() + public record struct FixedSizeSortedDescending11Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -2311,6 +2710,7 @@ public record struct FixedSizeSortedDescending11Array() /// Max size of the array /// public const int MaxSize = 11; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -2388,17 +2788,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -2406,15 +2809,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -2513,13 +2920,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -2527,15 +2937,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -2544,7 +2958,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending12Array() + public record struct FixedSizeSortedDescending12Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -2552,6 +2966,7 @@ public record struct FixedSizeSortedDescending12Array() /// Max size of the array /// public const int MaxSize = 12; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -2629,17 +3044,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -2647,15 +3065,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -2754,13 +3176,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -2768,15 +3193,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -2785,7 +3214,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending13Array() + public record struct FixedSizeSortedDescending13Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -2793,6 +3222,7 @@ public record struct FixedSizeSortedDescending13Array() /// Max size of the array /// public const int MaxSize = 13; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -2870,17 +3300,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -2888,15 +3321,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -2995,13 +3432,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -3009,15 +3449,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -3026,7 +3470,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending14Array() + public record struct FixedSizeSortedDescending14Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -3034,6 +3478,7 @@ public record struct FixedSizeSortedDescending14Array() /// Max size of the array /// public const int MaxSize = 14; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -3111,17 +3556,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -3129,15 +3577,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -3236,13 +3688,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -3250,15 +3705,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -3267,7 +3726,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending15Array() + public record struct FixedSizeSortedDescending15Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -3275,6 +3734,7 @@ public record struct FixedSizeSortedDescending15Array() /// Max size of the array /// public const int MaxSize = 15; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -3352,17 +3812,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -3370,15 +3833,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -3477,13 +3944,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -3491,15 +3961,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -3508,7 +3982,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending16Array() + public record struct FixedSizeSortedDescending16Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -3516,6 +3990,7 @@ public record struct FixedSizeSortedDescending16Array() /// Max size of the array /// public const int MaxSize = 16; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -3593,17 +4068,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -3611,15 +4089,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -3718,13 +4200,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -3732,15 +4217,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -3749,7 +4238,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending17Array() + public record struct FixedSizeSortedDescending17Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -3757,6 +4246,7 @@ public record struct FixedSizeSortedDescending17Array() /// Max size of the array /// public const int MaxSize = 17; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -3834,17 +4324,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -3852,15 +4345,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -3959,13 +4456,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -3973,15 +4473,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -3990,7 +4494,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending18Array() + public record struct FixedSizeSortedDescending18Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -3998,6 +4502,7 @@ public record struct FixedSizeSortedDescending18Array() /// Max size of the array /// public const int MaxSize = 18; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -4075,17 +4580,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -4093,15 +4601,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -4200,13 +4712,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -4214,15 +4729,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -4231,7 +4750,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending19Array() + public record struct FixedSizeSortedDescending19Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -4239,6 +4758,7 @@ public record struct FixedSizeSortedDescending19Array() /// Max size of the array /// public const int MaxSize = 19; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -4316,17 +4836,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -4334,15 +4857,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -4441,13 +4968,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -4455,15 +4985,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -4472,7 +5006,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending20Array() + public record struct FixedSizeSortedDescending20Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -4480,6 +5014,7 @@ public record struct FixedSizeSortedDescending20Array() /// Max size of the array /// public const int MaxSize = 20; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -4557,17 +5092,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -4575,15 +5113,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -4682,13 +5224,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -4696,15 +5241,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -4713,7 +5262,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending21Array() + public record struct FixedSizeSortedDescending21Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -4721,6 +5270,7 @@ public record struct FixedSizeSortedDescending21Array() /// Max size of the array /// public const int MaxSize = 21; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -4798,17 +5348,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -4816,15 +5369,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -4923,13 +5480,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -4937,15 +5497,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -4954,7 +5518,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending22Array() + public record struct FixedSizeSortedDescending22Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -4962,6 +5526,7 @@ public record struct FixedSizeSortedDescending22Array() /// Max size of the array /// public const int MaxSize = 22; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -5039,17 +5604,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -5057,15 +5625,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -5164,13 +5736,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -5178,15 +5753,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -5195,7 +5774,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending23Array() + public record struct FixedSizeSortedDescending23Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -5203,6 +5782,7 @@ public record struct FixedSizeSortedDescending23Array() /// Max size of the array /// public const int MaxSize = 23; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -5280,17 +5860,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -5298,15 +5881,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -5405,13 +5992,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -5419,15 +6009,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -5436,7 +6030,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending24Array() + public record struct FixedSizeSortedDescending24Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -5444,6 +6038,7 @@ public record struct FixedSizeSortedDescending24Array() /// Max size of the array /// public const int MaxSize = 24; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -5521,17 +6116,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -5539,15 +6137,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -5646,13 +6248,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -5660,15 +6265,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -5677,7 +6286,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending25Array() + public record struct FixedSizeSortedDescending25Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -5685,6 +6294,7 @@ public record struct FixedSizeSortedDescending25Array() /// Max size of the array /// public const int MaxSize = 25; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -5762,17 +6372,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -5780,15 +6393,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -5887,13 +6504,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -5901,15 +6521,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -5918,7 +6542,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending26Array() + public record struct FixedSizeSortedDescending26Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -5926,6 +6550,7 @@ public record struct FixedSizeSortedDescending26Array() /// Max size of the array /// public const int MaxSize = 26; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -6003,17 +6628,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -6021,15 +6649,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -6128,13 +6760,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -6142,15 +6777,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -6159,7 +6798,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending27Array() + public record struct FixedSizeSortedDescending27Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -6167,6 +6806,7 @@ public record struct FixedSizeSortedDescending27Array() /// Max size of the array /// public const int MaxSize = 27; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -6244,17 +6884,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -6262,15 +6905,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -6369,13 +7016,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -6383,15 +7033,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -6400,7 +7054,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending28Array() + public record struct FixedSizeSortedDescending28Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -6408,6 +7062,7 @@ public record struct FixedSizeSortedDescending28Array() /// Max size of the array /// public const int MaxSize = 28; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -6485,17 +7140,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -6503,15 +7161,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -6610,13 +7272,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -6624,15 +7289,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -6641,7 +7310,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending29Array() + public record struct FixedSizeSortedDescending29Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -6649,6 +7318,7 @@ public record struct FixedSizeSortedDescending29Array() /// Max size of the array /// public const int MaxSize = 29; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -6726,17 +7396,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -6744,15 +7417,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -6851,13 +7528,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -6865,15 +7545,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -6882,7 +7566,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending30Array() + public record struct FixedSizeSortedDescending30Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -6890,6 +7574,7 @@ public record struct FixedSizeSortedDescending30Array() /// Max size of the array /// public const int MaxSize = 30; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -6967,17 +7652,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -6985,15 +7673,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -7092,13 +7784,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -7106,15 +7801,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -7123,7 +7822,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending31Array() + public record struct FixedSizeSortedDescending31Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -7131,6 +7830,7 @@ public record struct FixedSizeSortedDescending31Array() /// Max size of the array /// public const int MaxSize = 31; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -7208,17 +7908,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -7226,15 +7929,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -7333,13 +8040,16 @@ public readonly (V Value, W Weight) this[byte index] /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -7347,15 +8057,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -7364,7 +8078,7 @@ public void RemoveAt(byte index) /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending32Array() + public record struct FixedSizeSortedDescending32Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -7372,6 +8086,7 @@ public record struct FixedSizeSortedDescending32Array() /// Max size of the array /// public const int MaxSize = 32; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -7449,17 +8164,20 @@ public readonly (V Value, W Weight) this[byte index] } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -7467,15 +8185,19 @@ public bool TryAdd(V value, W weight, bool enforceUnique = true) /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } } \ No newline at end of file diff --git a/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.tt b/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayTemplate.tt similarity index 85% rename from BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.tt rename to BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayTemplate.tt index 49e9c088..88d1deb8 100644 --- a/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.tt +++ b/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayTemplate.tt @@ -9,11 +9,12 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Collections.Generic; -using BrightData.Types.FixedSizeSortedArray; +using BrightData.Types.Helper; +using System.Linq; namespace BrightData.Types { -<# for(var i = 2; i <= 32; i++) { #> +<# for(var i = 1; i <= 32; i++) { #> /// /// Fixed size sorted array of values and weights (max <#= i #> elements) /// that is sorted in ascending order based on each weight @@ -110,13 +111,16 @@ namespace BrightData.Types /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoAscending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -124,15 +128,19 @@ namespace BrightData.Types /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } /// @@ -141,7 +149,7 @@ namespace BrightData.Types /// /// Type of value to store /// Type of weight that will be used to sort - public record struct FixedSizeSortedDescending<#= i #>Array() + public record struct FixedSizeSortedDescending<#= i #>Array() : IFixedSizeSortedArray where V : IComparable where W : unmanaged, INumber, IMinMaxValue { @@ -149,6 +157,7 @@ namespace BrightData.Types /// Max size of the array /// public const int MaxSize = <#= i #>; + byte IFixedSizeSortedArray.MaxSize => MaxSize; [InlineArray(MaxSize)] internal struct ValueArray @@ -226,17 +235,20 @@ namespace BrightData.Types } /// - /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// Tries to add a new element - will succeed if there aren't already max elements with a higher weight /// /// Value to add /// Weight to add - /// True if values should be unique - will return false if the value already exists + /// True if elements should be unique - will return false if the value and weight already exists /// True if the element was added public bool TryAdd(V value, W weight, bool enforceUnique = true) { var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); - return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + var ret = SortedArrayHelper.InsertIntoDescending(enforceUnique, MaxSize, value, weight, values, weights); + if(ret && _size < MaxSize) + ++_size; + return ret; } /// @@ -244,15 +256,19 @@ namespace BrightData.Types /// /// Index of element to remove /// - public void RemoveAt(byte index) + public V RemoveAt(byte index) { if(index >= _size) throw new ArgumentOutOfRangeException(); var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); - FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + var ret = values[index]; + SortedArrayHelper.RemoveAt(index, values, weights); --_size; + return ret; } + + public override string ToString() => string.Join(", ", Elements.Select(x => $"{x.Value}|{x.Weight}")); } <# } #> diff --git a/BrightData/Types/Graph/FixedSizeWeightedGraph.cs b/BrightData/Types/Graph/FixedSizeWeightedGraph.cs new file mode 100644 index 00000000..d7e4ebec --- /dev/null +++ b/BrightData/Types/Graph/FixedSizeWeightedGraph.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace BrightData.Types.Graph +{ + /// + /// A fixed size graph weighted graph + /// + /// + /// + /// + public class FixedSizeWeightedGraph : IWeightedGraph + where T : IHaveSingleIndex + where W : unmanaged, INumber, IMinMaxValue + where AT : struct, IFixedSizeSortedArray + + { + readonly Dictionary> _nodes = []; + + /// + public IWeightedGraphNode Create(T value, bool addToGraph = true) + { + var ret = new FixedSizeWeightedGraphNode(value); + if(addToGraph) + _nodes.Add(value.Index, ret); + return ret; + } + + /// + public void Add(IWeightedGraphNode node) + { + if(node is FixedSizeWeightedGraphNode same) + _nodes.Add(same.Index, same); + else { + var ret = new FixedSizeWeightedGraphNode(node.Value); + foreach (var (neighbour, weight) in node.WeightedNeighbours) + ret.AddNeighbour(neighbour, weight); + _nodes.Add(ret.Index, ret); + } + } + + /// + public uint Size => (uint)_nodes.Count; + + /// + public IWeightedGraphNode Get(uint index) => _nodes[index]; + + /// + public RAT Search(uint q, uint entryPoint, ICalculateNodeWeights distanceCalculator) + where RAT : struct, IFixedSizeSortedArray + where CAT : struct, IFixedSizeSortedArray + { + var visited = new HashSet { entryPoint }; + var candidates = new CAT(); + var distanceEQ = distanceCalculator.GetWeight(q, entryPoint); + candidates.TryAdd(entryPoint, distanceEQ); + var ret = new RAT(); + ret.TryAdd(entryPoint, distanceEQ); + + while (candidates.Size > 0) { + var c = candidates.RemoveAt(0); + var f = ret.MaxValue; + if (distanceCalculator.GetWeight(c, q) > distanceCalculator.GetWeight(f, q)) + break; + + foreach (var neighbour in _nodes[c].NeighbourSpan) { + if(!visited.Add(neighbour)) + continue; + + f = ret.MaxValue; + if ((distanceEQ = distanceCalculator.GetWeight(neighbour, q)) < distanceCalculator.GetWeight(f, q)) { + candidates.TryAdd(neighbour, distanceEQ); + ret.TryAdd(neighbour, distanceEQ); + } + } + } + return ret; + } + } +} diff --git a/BrightData/Types/Graph/FixedSizeWeightedGraphNode.cs b/BrightData/Types/Graph/FixedSizeWeightedGraphNode.cs new file mode 100644 index 00000000..85cbd546 --- /dev/null +++ b/BrightData/Types/Graph/FixedSizeWeightedGraphNode.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace BrightData.Types.Graph +{ + /// + /// A graph node with a (fixed size) maximum number of neighbours + /// + public record FixedSizeWeightedGraphNode(T Value) : IWeightedGraphNode, IComparable> + where T : IHaveSingleIndex + where W : unmanaged, INumber, IMinMaxValue + where AT : struct, IFixedSizeSortedArray + { + AT _neighbours = new(); + + /// + public uint Index => Value.Index; + + /// + /// Tries to add a new neighbour + /// + /// Index of neighbour + /// Neighbour weight + public bool AddNeighbour(uint index, W weight) + { + if(index != Value.Index) + return _neighbours.TryAdd(index, weight); + return false; + } + + /// + public IEnumerable<(uint Index, W Weight)> WeightedNeighbours => _neighbours.Elements; + + /// + /// Ordered span of neighbours by weight + /// + public ReadOnlySpan NeighbourSpan => _neighbours.Values; + + /// + /// Enumerates the neighbours by weight + /// + public IEnumerable Neighbours + { + get + { + for (byte i = 0, len = _neighbours.Size; i < len; i++) { + yield return _neighbours.Values[i]; + } + } + } + + /// + public int CompareTo(FixedSizeWeightedGraphNode? other) => Value.Index.CompareTo(other?.Value.Index); + + /// + public override string ToString() => $"{Value}: {_neighbours}"; + + + } +} diff --git a/BrightData/Types/Graph/GraphIndex.cs b/BrightData/Types/Graph/GraphIndex.cs new file mode 100644 index 00000000..ed45a32b --- /dev/null +++ b/BrightData/Types/Graph/GraphIndex.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BrightData.Types.Graph +{ + /// + /// Index only graph node value + /// + /// + public readonly record struct GraphNodeIndex(uint Index) : IHaveSingleIndex, IComparable + { + /// + public int CompareTo(GraphNodeIndex other) => Index.CompareTo(other.Index); + + /// + public override string ToString() => Index.ToString(); + } +} diff --git a/BrightData/Types/Graph/HierarchicalNavigationSmallWorldGraph.cs b/BrightData/Types/Graph/HierarchicalNavigationSmallWorldGraph.cs new file mode 100644 index 00000000..4882fb85 --- /dev/null +++ b/BrightData/Types/Graph/HierarchicalNavigationSmallWorldGraph.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using BrightData.Distribution; + +namespace BrightData.Types.Graph +{ + public class HierarchicalNavigationSmallWorldGraph(BrightDataContext context, int maxLayers) + where T : IHaveSingleIndex + where W : unmanaged, INumber, IMinMaxValue, IBinaryFloatingPointIeee754 + where AT : struct, IFixedSizeSortedArray + where BLAT : struct, IFixedSizeSortedArray + { + public record NodeIndex(T Value, uint LayerIndex) : IHaveSingleIndex + { + public uint Index => Value.Index; + } + readonly IContinuousDistribution _distribution = context.CreateExponentialDistribution(W.CreateSaturating(maxLayers)); + readonly IWeightedGraph[] _layers = Enumerable.Range(0, maxLayers) + .Select(i => (IWeightedGraph)(i == 0 ? new FixedSizeWeightedGraph() : new FixedSizeWeightedGraph())) + .ToArray() + ; + IWeightedGraphNode? _entryPoint = null; + + public void Add(IEnumerable values, ICalculateNodeWeights distanceCalculator) + { + foreach (var value in values) { + var entryPoint = _entryPoint; + var level = GetRandomLevel(); + + // zoom in + uint? entryPointLevel = null; + if (entryPoint is not null) { + entryPointLevel = entryPoint.Value.LayerIndex; + for (var i = entryPointLevel.Value; i > level; i--) { + var layer = _layers[i]; + var w = layer.Search, AT>(value.Index, entryPoint.Index, distanceCalculator); + entryPoint = layer.Get(w.MinValue); + } + } + + // add to levels + var from = Math.Min(level, entryPoint?.Value.LayerIndex ?? int.MaxValue); + for(var i = level; i > from; i--) + _layers[i].Create(new NodeIndex(value, (uint)i)); + for (var i = from; i >= 0; i--) { + var layer = _layers[i]; + var newNode = layer.Create(new NodeIndex(value, (uint)i), false); + if (entryPoint is not null) { + var w = layer.Search(value.Index, entryPoint.Index, distanceCalculator); + foreach (var (ni, nw) in w.Elements) { + layer.Get(ni).AddNeighbour(value.Index, nw); + newNode.AddNeighbour(ni, nw); + } + } + layer.Add(newNode); + } + + if(!entryPointLevel.HasValue || level > entryPointLevel.Value) + _entryPoint = _layers[level].Get(value.Index); + } + } + + public AT KnnSearch(uint q, ICalculateNodeWeights distanceCalculator) + { + var entryPoint = _entryPoint ?? throw new Exception("No nodes in graph"); + for (var i = (int)entryPoint.Value.LayerIndex; i > 0; i--) { + var layer = _layers[i]; + var w = layer.Search(q, entryPoint.Index, distanceCalculator); + entryPoint = layer.Get(w.MinValue); + } + return _layers[0].Search(q, entryPoint.Index, distanceCalculator); + } + + public IEnumerable BreadthFirstSearch(uint index) + { + var queue = new Queue(); + var visited = new HashSet { index}; + var layer = _layers[0]; + queue.Enqueue(index); + + while (queue.Count > 0) { + var node = layer.Get(queue.Dequeue()); + foreach (var neighbour in node.Neighbours) { + if(!visited.Add(neighbour)) + continue; + yield return neighbour; + } + } + } + + int GetRandomLevel() + { + int ret; + do { + ret = int.CreateTruncating(_distribution.Sample()); + } while (ret >= maxLayers); + return ret; + } + } +} diff --git a/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayHelper.cs b/BrightData/Types/Helper/SortedArrayHelper.cs similarity index 68% rename from BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayHelper.cs rename to BrightData/Types/Helper/SortedArrayHelper.cs index 6c621d83..c1a5f4cb 100644 --- a/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayHelper.cs +++ b/BrightData/Types/Helper/SortedArrayHelper.cs @@ -1,18 +1,18 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Numerics; -using System.Text; -using System.Threading.Tasks; -namespace BrightData.Types.FixedSizeSortedArray +namespace BrightData.Types.Helper { - internal class FixedSizeSortedArrayHelper + /// + /// Fixed size array helper methods + /// + public class SortedArrayHelper { - public static bool InsertIntoAscending(bool enforceUnique, ref byte size, byte maxSize, V value, W weight, Span values, Span weights) + internal static bool InsertIntoAscending(bool enforceUnique, uint maxSize, V value, W weight, Span values, Span weights) where V : IComparable where W : unmanaged, INumber, IMinMaxValue { + var size = values.Length; var isFull = size == maxSize; // check to see if it should be inserted @@ -20,17 +20,20 @@ public static bool InsertIntoAscending(bool enforceUnique, ref byte size, return false; // use binary search to find the insertion position - int left = 0, - right = size - 1, + int left = 0, + right = size - 1, insertPosition = size ; - while (left <= right) { + while (left <= right) + { var mid = left + (right - left) / 2; - if (weights[mid] > weight) { + if (weights[mid] > weight) + { insertPosition = mid; right = mid - 1; } - else { + else + { // check for an existing weight/value if (enforceUnique && weights[mid] == weight && values[mid].CompareTo(value) == 0) return false; @@ -38,9 +41,11 @@ public static bool InsertIntoAscending(bool enforceUnique, ref byte size, } } - if (enforceUnique) { + if (enforceUnique) + { // check if the same element already exists in the left partition - for (var i = insertPosition - 1; i >= 0; i--) { + for (var i = insertPosition - 1; i >= 0; i--) + { if (weights[i] < weight) break; if (values[i].CompareTo(value) == 0) @@ -48,7 +53,8 @@ public static bool InsertIntoAscending(bool enforceUnique, ref byte size, } // check if the same element already exists in the right partition - for (var i = insertPosition; i < size; i++) { + for (var i = insertPosition; i < size; i++) + { if (weights[i] > weight) break; if (values[i].CompareTo(value) == 0) @@ -56,14 +62,17 @@ public static bool InsertIntoAscending(bool enforceUnique, ref byte size, } } - if (insertPosition == size) { + if (insertPosition == size) + { // there is no room left if (isFull) return false; } - else { + else + { // shuffle to make room - for (var i = size - (isFull ? 2 : 1); i >= insertPosition; i--) { + for (var i = size - (isFull ? 2 : 1); i >= insertPosition; i--) + { values[i + 1] = values[i]; weights[i + 1] = weights[i]; } @@ -72,15 +81,14 @@ public static bool InsertIntoAscending(bool enforceUnique, ref byte size, // insert the item values[insertPosition] = value; weights[insertPosition] = weight; - if (!isFull) - ++size; return true; } - public static bool InsertIntoDescending(bool enforceUnique, ref byte size, byte maxSize, V value, W weight, Span values, Span weights) + internal static bool InsertIntoDescending(bool enforceUnique, uint maxSize, V value, W weight, Span values, Span weights) where V : IComparable where W : unmanaged, INumber, IMinMaxValue { + var size = values.Length; var isFull = size == maxSize; // check to see if it should be inserted @@ -88,17 +96,20 @@ public static bool InsertIntoDescending(bool enforceUnique, ref byte size, return false; // use binary search to find the insertion position - int left = 0, - right = size - 1, + int left = 0, + right = size - 1, insertPosition = size ; - while (left <= right) { + while (left <= right) + { var mid = left + (right - left) / 2; - if (weights[mid] < weight) { + if (weights[mid] < weight) + { insertPosition = mid; right = mid - 1; } - else { + else + { // check for an existing weight/value if (enforceUnique && weights[mid] == weight && values[mid].CompareTo(value) == 0) return false; @@ -106,9 +117,11 @@ public static bool InsertIntoDescending(bool enforceUnique, ref byte size, } } - if (enforceUnique) { + if (enforceUnique) + { // check if the same element already exists in the left partition - for (var i = insertPosition - 1; i >= 0; i--) { + for (var i = insertPosition - 1; i >= 0; i--) + { if (weights[i] > weight) break; if (values[i].CompareTo(value) == 0) @@ -116,7 +129,8 @@ public static bool InsertIntoDescending(bool enforceUnique, ref byte size, } // check if the same element already exists in the right partition - for (var i = insertPosition; i < size; i++) { + for (var i = insertPosition; i < size; i++) + { if (weights[i] < weight) break; if (values[i].CompareTo(value) == 0) @@ -124,14 +138,17 @@ public static bool InsertIntoDescending(bool enforceUnique, ref byte size, } } - if (insertPosition == size) { + if (insertPosition == size) + { // there is no room left if (isFull) return false; } - else { + else + { // shuffle to make room - for (var i = size - (isFull ? 2 : 1); i >= insertPosition; i--) { + for (var i = size - (isFull ? 2 : 1); i >= insertPosition; i--) + { values[i + 1] = values[i]; weights[i + 1] = weights[i]; } @@ -140,15 +157,13 @@ public static bool InsertIntoDescending(bool enforceUnique, ref byte size, // insert the item values[insertPosition] = value; weights[insertPosition] = weight; - if (!isFull) - ++size; return true; } - public static void RemoveAt(byte index, Span values, Span weights) + internal static void RemoveAt(int index, Span values, Span weights) { - values[(index+1)..].CopyTo(values[index..]); - weights[(index+1)..].CopyTo(weights[index..]); + values[(index + 1)..].CopyTo(values[index..]); + weights[(index + 1)..].CopyTo(weights[index..]); } } } diff --git a/BrightData/Types/SortedArray.cs b/BrightData/Types/SortedArray.cs new file mode 100644 index 00000000..6b402458 --- /dev/null +++ b/BrightData/Types/SortedArray.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Runtime.InteropServices; +using BrightData.Types.Helper; + +namespace BrightData.Types +{ + public class SortedArray(int? capacity = null, bool isAscending = true) : IHaveSize + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + readonly List _values = capacity.HasValue ? new(capacity.Value) : new(); + readonly List _weights = capacity.HasValue ? new(capacity.Value) : new(); + + public Span Values => CollectionsMarshal.AsSpan(_values); + public Span Weights => CollectionsMarshal.AsSpan(_weights); + public uint Size => (uint)Values.Length; + + public bool Add(in V item, W weight) + { + _values.Add(item); + _weights.Add(weight); + return isAscending + ? SortedArrayHelper.InsertIntoAscending(false, uint.MaxValue, item, weight, Values, Weights) + : SortedArrayHelper.InsertIntoDescending(false, uint.MaxValue, item, weight, Values, Weights) + ; + } + + public void RemoveAt(uint index) + { + _values.RemoveAt((int)index); + _weights.RemoveAt((int)index); + } + + public bool TryGet(W weight, [NotNullWhen(true)]out V? value) + { + var index = Weights.BinarySearch(weight); + if (index >= 0) { + value = _values[index]; + return true; + } + value = default; + return false; + } + } +} diff --git a/BrightWire/ExecutionGraph/WeightInitialisation/Gaussian.cs b/BrightWire/ExecutionGraph/WeightInitialisation/Gaussian.cs index f37311f6..ef5b8d1e 100644 --- a/BrightWire/ExecutionGraph/WeightInitialisation/Gaussian.cs +++ b/BrightWire/ExecutionGraph/WeightInitialisation/Gaussian.cs @@ -9,7 +9,7 @@ namespace BrightWire.ExecutionGraph.WeightInitialisation /// internal class Gaussian : IWeightInitialisation { - readonly IContinuousDistribution _distribution; + readonly IContinuousDistribution _distribution; readonly GaussianVarianceCalibration _varianceCalibration; readonly GaussianVarianceCount _varianceCount; readonly LinearAlgebraProvider _lap; @@ -26,7 +26,7 @@ public Gaussian( _zeroBias = zeroInitialBias; _varianceCalibration = varianceCalibration; _varianceCount = varianceCount; - _distribution = _lap.Context.CreateNormalDistribution(0, stdDev); + _distribution = _lap.Context.CreateNormalDistribution(0, stdDev); } float GetBias() diff --git a/BrightWire/ExecutionGraph/WeightInitialisation/Xavier.cs b/BrightWire/ExecutionGraph/WeightInitialisation/Xavier.cs index f00b5c27..349f5905 100644 --- a/BrightWire/ExecutionGraph/WeightInitialisation/Xavier.cs +++ b/BrightWire/ExecutionGraph/WeightInitialisation/Xavier.cs @@ -12,7 +12,7 @@ namespace BrightWire.ExecutionGraph.WeightInitialisation internal class Xavier(LinearAlgebraProvider lap, float parameter = 6) : IWeightInitialisation { readonly float _parameter = MathF.Sqrt(parameter); - readonly Dictionary<(uint, uint), IContinuousDistribution> _distributionTable = new(); + readonly Dictionary<(uint, uint), IContinuousDistribution> _distributionTable = []; public IVector CreateBias(uint size) { @@ -29,7 +29,7 @@ public float GetWeight(uint inputSize, uint outputSize) var key = (inputSize, outputSize); if (!_distributionTable.TryGetValue(key, out var distribution)) { var stdDev = _parameter / (inputSize + outputSize); - _distributionTable.Add(key, distribution = lap.Context.CreateContinuousDistribution(0, stdDev)); + _distributionTable.Add(key, distribution = lap.Context.CreateContinuousDistribution(0, stdDev)); } return distribution.Sample(); }