diff --git a/WhiteRabbit/StringsProcessor.cs b/WhiteRabbit/StringsProcessor.cs index 884c8bf..76a26a4 100644 --- a/WhiteRabbit/StringsProcessor.cs +++ b/WhiteRabbit/StringsProcessor.cs @@ -11,6 +11,7 @@ public StringsProcessor(byte[] sourceString, int maxWordsCount, IEnumerable words) { var filteredSource = sourceString.Where(ch => ch != 32).ToArray(); + this.NumberOfCharacters = filteredSource.Length; this.VectorsConverter = new VectorsConverter(filteredSource); // Dictionary of vectors to array of words represented by this vector @@ -35,6 +36,8 @@ private VectorsProcessor VectorsProcessor { get; } + private int NumberOfCharacters { get; } + public ParallelQuery GeneratePhrases() { // task of finding anagrams could be reduced to the task of finding sequences of dictionary vectors with the target sum @@ -64,7 +67,7 @@ private byte[] WordsToPhrase(byte[][] words) { - var result = new byte[words.Length + words.Sum(word => word.Length) - 1]; + var result = new byte[this.NumberOfCharacters + words.Length - 1]; Buffer.BlockCopy(words[0], 0, result, 0, words[0].Length); var position = words[0].Length; diff --git a/WhiteRabbit/VectorsProcessor.cs b/WhiteRabbit/VectorsProcessor.cs index 1a47a9b..9178ff5 100644 --- a/WhiteRabbit/VectorsProcessor.cs +++ b/WhiteRabbit/VectorsProcessor.cs @@ -58,11 +58,10 @@ // Produces all sequences of vectors with the target sum public ParallelQuery[]> GenerateSequences() { - var unorderedSequences = this.GenerateUnorderedSequences(this.Target, ImmutableStack.Create>(), this.Dictionary) - .AsParallel(); - var allSequences = unorderedSequences.SelectMany(this.GeneratePermutations); - - return allSequences; + return this.GenerateUnorderedSequences(this.Target, this.MaxVectorsCount, this.Dictionary) + .AsParallel() + .Select(Enumerable.ToArray) + .SelectMany(this.GeneratePermutations); } // We want words with more letters (and among these, words with more "rare" letters) to appear first, to reduce the searching time somewhat. @@ -94,12 +93,12 @@ } [Conditional("DEBUG")] - private void DebugState(ImmutableStack> partialSumStack, Vector currentVector) + private void DebugState(int allowedRemainingWords, Vector currentVector) { this.Iterations++; if (this.Iterations % 1000000 == 0) { - Console.WriteLine($"Iteration #{this.Iterations}: {string.Join(" ", partialSumStack.Push(currentVector).Reverse().Select(vector => this.VectorToString(vector)))}"); + Console.WriteLine($"Iteration #{this.Iterations}: {allowedRemainingWords}, {this.VectorToString(currentVector)}"); } } @@ -107,12 +106,11 @@ // 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 IEnumerable[]> GenerateUnorderedSequences(Vector remainder, ImmutableStack> partialSumStack, ImmutableStack> dictionaryStack) + private IEnumerable>> GenerateUnorderedSequences(Vector remainder, int allowedRemainingWords, ImmutableStack> dictionaryStack) { - var allowedRemainingWords = this.MaxVectorsCount - partialSumStack.Count(); if (allowedRemainingWords > 1) { - + var newAllowedRemainingWords = allowedRemainingWords - 1; #if !SUPPORT_LARGE_STRINGS // e.g. if remainder norm is 7, 8 or 9, and allowedRemainingWords is 3, // we need the largest remaining word to have a norm of at least 3 @@ -126,11 +124,11 @@ Vector currentVector; var nextDictionaryTail = dictionaryTail.Pop(out currentVector); - this.DebugState(partialSumStack, currentVector); + this.DebugState(allowedRemainingWords, currentVector); if (currentVector == remainder) { - yield return partialSumStack.Push(currentVector).Reverse().ToArray(); + yield return ImmutableStack.Create(currentVector); } #if !SUPPORT_LARGE_STRINGS else if (Vector.Dot(currentVector, this.TargetComplement) < requiredRemainder) @@ -141,9 +139,9 @@ else if (Vector.LessThanOrEqualAll(currentVector, remainder)) { var newRemainder = remainder - currentVector; - foreach (var result in this.GenerateUnorderedSequences(newRemainder, partialSumStack.Push(currentVector), dictionaryTail)) + foreach (var result in this.GenerateUnorderedSequences(newRemainder, newAllowedRemainingWords, dictionaryTail)) { - yield return result; + yield return result.Push(currentVector); } } @@ -158,12 +156,12 @@ Vector currentVector; dictionaryTail = dictionaryTail.Pop(out currentVector); - this.DebugState(partialSumStack, currentVector); + this.DebugState(allowedRemainingWords, currentVector); var newRemainder = remainder - currentVector; if (newRemainder == Vector.Zero) { - yield return partialSumStack.Push(currentVector).Reverse().ToArray(); + yield return ImmutableStack.Create(currentVector); } } }