From 5c06f21b2919bb90aad3faac8149ee6379838e31 Mon Sep 17 00:00:00 2001 From: inga-lovinde <52715130+inga-lovinde@users.noreply.github.com> Date: Sun, 2 Apr 2017 15:48:28 +0300 Subject: [PATCH] norms index optimization (which does not really help) --- dotnet/WhiteRabbit/VectorsProcessor.cs | 63 ++++++++++---------------- 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/dotnet/WhiteRabbit/VectorsProcessor.cs b/dotnet/WhiteRabbit/VectorsProcessor.cs index 369f0ce..1c57014 100644 --- a/dotnet/WhiteRabbit/VectorsProcessor.cs +++ b/dotnet/WhiteRabbit/VectorsProcessor.cs @@ -22,14 +22,32 @@ this.MaxVectorsCount = maxVectorsCount; this.Dictionary = ImmutableArray.Create(FilterVectors(dictionary, target).ToArray()); + + var normsIndex = new int[GetVectorNorm(target, target) + 1]; + var wordOffset = 0; + for (var norm = normsIndex.Length - 1; norm >= 0; norm--) + { + while (wordOffset < this.Dictionary.Length && this.Dictionary[wordOffset].Norm > norm) + { + wordOffset++; + } + + normsIndex[norm] = wordOffset; + } + + this.NormsIndex = ImmutableArray.Create(normsIndex); } private Vector Target { get; } private int MaxVectorsCount { get; } + // Ordered by norm, descending private ImmutableArray Dictionary { get; } + // Contains index of first vector in Dictionary with norm less than or equal to key + private ImmutableArray NormsIndex { get; } + // Produces all sets of vectors with the target sum #if SINGLE_THREADED public IEnumerable GenerateSequences() @@ -37,7 +55,7 @@ public ParallelQuery GenerateSequences() #endif { - return GenerateUnorderedSequences(this.Target, GetVectorNorm(this.Target, this.Target), this.MaxVectorsCount, this.Dictionary, 0) + return GenerateUnorderedSequences(this.Target, GetVectorNorm(this.Target, this.Target), this.MaxVectorsCount, this.Dictionary, 0, this.NormsIndex) #if !SINGLE_THREADED .AsParallel() #endif @@ -74,7 +92,7 @@ // In every sequence, next vector always goes after the previous one from dictionary. // E.g. if dictionary is [x, y, z], then only [x, y] sequence could be generated, and [y, x] will never be generated. // That way, the complexity of search goes down by a factor of MaxVectorsCount! (as if [x, y] does not add up to a required target, there is no point in checking [y, x]) - private static IEnumerable> GenerateUnorderedSequences(Vector remainder, int remainderNorm, int allowedRemainingWords, ImmutableArray dictionary, int currentDictionaryPosition) + private static IEnumerable> GenerateUnorderedSequences(Vector remainder, int remainderNorm, int allowedRemainingWords, ImmutableArray dictionary, int currentDictionaryPosition, ImmutableArray normsIndex) { if (allowedRemainingWords > 1) { @@ -84,7 +102,7 @@ // we need the largest remaining word to have a norm of at least 3 var requiredRemainderPerWord = (remainderNorm + allowedRemainingWords - 1) / allowedRemainingWords; - for (var i = FindFirstWithNormLessOrEqual(remainderNorm, dictionary, currentDictionaryPosition); i < dictionary.Length; i++) + for (var i = Math.Max(normsIndex[remainderNorm], currentDictionaryPosition); i < dictionary.Length; i++) { var currentVectorInfo = dictionary[i]; if (currentVectorInfo.Vector == remainder) @@ -99,7 +117,7 @@ { var newRemainder = remainder - currentVectorInfo.Vector; var newRemainderNorm = remainderNorm - currentVectorInfo.Norm; - foreach (var result in GenerateUnorderedSequences(newRemainder, newRemainderNorm, newAllowedRemainingWords, dictionary, i)) + foreach (var result in GenerateUnorderedSequences(newRemainder, newRemainderNorm, newAllowedRemainingWords, dictionary, i, normsIndex)) { yield return result.Push(currentVectorInfo.Index); } @@ -108,7 +126,7 @@ } else { - for (var i = FindFirstWithNormLessOrEqual(remainderNorm, dictionary, currentDictionaryPosition); i < dictionary.Length; i++) + for (var i = Math.Max(normsIndex[remainderNorm], currentDictionaryPosition); i < dictionary.Length; i++) { var currentVectorInfo = dictionary[i]; if (currentVectorInfo.Vector == remainder) @@ -123,41 +141,6 @@ } } - // BCL BinarySearch would find any vector with required norm, not the first one; or would find nothing if there is no such vector - private static int FindFirstWithNormLessOrEqual(int expectedNorm, ImmutableArray dictionary, int offset) - { - var start = offset; - var end = dictionary.Length - 1; - - if (dictionary[start].Norm <= expectedNorm) - { - return start; - } - - if (dictionary[end].Norm > expectedNorm) - { - return dictionary.Length; - } - - // Norm for start is always greater than expected norm, or start is the required position; norm for end is always less than or equal to expected norm - // The loop always ends, because the difference always decreases; if start + 1 = end, then middle will be equal to start, and either end := middle = start or start := middle + 1 = end. - while (start < end) - { - var middle = (start + end) / 2; - var newNorm = dictionary[middle].Norm; - if (dictionary[middle].Norm <= expectedNorm) - { - end = middle; - } - else - { - start = middle + 1; - } - } - - return start; - } - private struct VectorInfo { public VectorInfo(Vector vector, int norm, int index)