From 08ef75d4cf1183369235dbd55d95fc0732187242 Mon Sep 17 00:00:00 2001 From: inga-lovinde <52715130+inga-lovinde@users.noreply.github.com> Date: Thu, 9 Mar 2017 13:18:59 +0300 Subject: [PATCH] Refactored to DataBlocks --- WhiteRabbit/Extensions.cs | 23 ++++++++++++ WhiteRabbit/Program.cs | 66 +++++++++++++++++++++++++++------ WhiteRabbit/StringsProcessor.cs | 50 +++++++++++++++++++------ WhiteRabbit/VectorsProcessor.cs | 22 ++++++++--- WhiteRabbit/WhiteRabbit.csproj | 5 +++ WhiteRabbit/packages.config | 1 + 6 files changed, 137 insertions(+), 30 deletions(-) create mode 100644 WhiteRabbit/Extensions.cs diff --git a/WhiteRabbit/Extensions.cs b/WhiteRabbit/Extensions.cs new file mode 100644 index 0000000..84c5f6b --- /dev/null +++ b/WhiteRabbit/Extensions.cs @@ -0,0 +1,23 @@ +namespace WhiteRabbit +{ + using System.Threading.Tasks.Dataflow; + + internal static class Extensions + { + public static void LinkForever(this ISourceBlock source, ITargetBlock target) + { + source.LinkTo(target); + source.Completion.ContinueWith(t => + { + if (t.IsFaulted) + { + target.Fault(t.Exception); + } + else + { + target.Complete(); + } + }); + } + } +} diff --git a/WhiteRabbit/Program.cs b/WhiteRabbit/Program.cs index 9d9ae8d..a5d0a6d 100644 --- a/WhiteRabbit/Program.cs +++ b/WhiteRabbit/Program.cs @@ -7,7 +7,7 @@ using System.Numerics; using System.Security.Cryptography; using System.Text; - + using System.Threading.Tasks.Dataflow; /// /// Main class /// @@ -18,10 +18,6 @@ /// public static void Main() { - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - var processor = new StringsProcessor("poultry outwits ants", 4, ReadInput()); var expectedHashes = new[] { "e4820b45d2277f3844eac66c903e84be", @@ -31,16 +27,49 @@ var expectedHashesAsVectors = new HashSet>(expectedHashes.Select(hash => new Vector(StringToByteArray(hash)))); - foreach (var result in AddHashes(processor.GeneratePhrases())) + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + using (var hasher = MD5.Create()) { - if (expectedHashesAsVectors.Contains(result.Item2)) + + var processor = new StringsProcessor("poultry outwits ants", 4, ReadInput()); + + var unorderedSequencesToPhrases = processor.CreateUnorderedSequencesToPhrasesTransform(); + + var phrasesToPhrasesWithHash = new TransformBlock(phrase => { - Console.WriteLine($"Found phrase: {result.Item1} (spent {stopwatch.Elapsed})"); - } - } + var hash = new Vector(hasher.ComputeHash(Encoding.ASCII.GetBytes(phrase))); + return new PhraseWithHash(phrase, hash); + }); + + var phrasesWithHashFilter = new TransformManyBlock(phraseWithHash => + { + if (!expectedHashesAsVectors.Contains(phraseWithHash.Hash)) + { + return Enumerable.Empty(); + } - stopwatch.Stop(); - Console.WriteLine($"Total time spent: {stopwatch.Elapsed}"); + return new PhraseWithHash[] + { + phraseWithHash, + }; + }); + + var printPhrases = new ActionBlock(phraseWithHash => + { + Console.WriteLine($"Found phrase for hash {phraseWithHash.Hash}: {phraseWithHash.Phrase} (spent {stopwatch.Elapsed})"); + }); + + unorderedSequencesToPhrases.LinkForever(phrasesToPhrasesWithHash); + phrasesToPhrasesWithHash.LinkForever(phrasesWithHashFilter); + phrasesWithHashFilter.LinkForever(printPhrases); + + processor.PostUnorderedSequences(unorderedSequencesToPhrases); + + printPhrases.Completion.Wait(); + Console.WriteLine($"Total time spent: {stopwatch.Elapsed}"); + } } // Code taken from http://stackoverflow.com/a/321404/831314 @@ -72,5 +101,18 @@ yield return line; } } + + private class PhraseWithHash + { + public PhraseWithHash(string phrase, Vector hash) + { + this.Phrase = phrase; + this.Hash = hash; + } + + public string Phrase { get; } + + public Vector Hash { get; } + } } } diff --git a/WhiteRabbit/StringsProcessor.cs b/WhiteRabbit/StringsProcessor.cs index 81d7509..93638b5 100644 --- a/WhiteRabbit/StringsProcessor.cs +++ b/WhiteRabbit/StringsProcessor.cs @@ -4,7 +4,7 @@ using System.Collections.Immutable; using System.Linq; using System.Numerics; - + using System.Threading.Tasks.Dataflow; internal class StringsProcessor { public StringsProcessor(string sourceString, int maxWordsCount, IEnumerable words) @@ -28,24 +28,26 @@ this.VectorsConverter.GetString); } - private VectorsConverter VectorsConverter { get; } - private VectorsProcessor VectorsProcessor { get; } + private VectorsConverter VectorsConverter { get; } + private Dictionary, string[]> VectorsToWords { get; } - public IEnumerable GeneratePhrases() + public void PostUnorderedSequences(ITargetBlock[]> target) => this.VectorsProcessor.PostUnorderedSequences(target); + + public IPropagatorBlock[], string> CreateUnorderedSequencesToPhrasesTransform() { - // task of finding anagrams could be reduced to the task of finding sequences of dictionary vectors with the target sum - var sums = this.VectorsProcessor.GenerateSequences(); + var unorderedSequencesToOrderedSequences = this.VectorsProcessor.CreateUnorderedSequencesToOrderedSequencesTransform(); + var orderedSequencesToWordVariants = this.CreateOrderedSequencesToWordVariantsTransform(); + var wordVariantsToFlatWords = this.CreateWordVariantsToFlatWordsTransform(); + var flatWordsToPhrases = this.CreateFlatWordsToPhrasesTransform(); - // converting sequences of vectors to the sequences of words... - var anagramsWords = sums - .Select(sum => ImmutableStack.Create(sum.Select(vector => this.VectorsToWords[vector]).ToArray())) - .SelectMany(this.Flatten) - .Select(stack => stack.ToArray()); + unorderedSequencesToOrderedSequences.LinkForever(orderedSequencesToWordVariants); + orderedSequencesToWordVariants.LinkForever(wordVariantsToFlatWords); + wordVariantsToFlatWords.LinkForever(flatWordsToPhrases); - return anagramsWords.Select(list => string.Join(" ", list)); + return DataflowBlock.Encapsulate(unorderedSequencesToOrderedSequences, flatWordsToPhrases); } // Converts e.g. pair of variants [[a, b, c], [d, e]] into all possible pairs: [[a, d], [a, e], [b, d], [b, e], [c, d], [c, e]] @@ -60,5 +62,29 @@ var newStack = phrase.Pop(out wordVariants); return this.Flatten(newStack).SelectMany(remainder => wordVariants.Select(word => remainder.Push(word))); } + + private IPropagatorBlock[], ImmutableStack> CreateOrderedSequencesToWordVariantsTransform() + { + return new TransformBlock[], ImmutableStack>(sum => + { + return ImmutableStack.CreateRange(sum.Select(vector => this.VectorsToWords[vector])); + }); + } + + private IPropagatorBlock, ImmutableStack> CreateWordVariantsToFlatWordsTransform() + { + return new TransformManyBlock, ImmutableStack>(wordVariants => + { + return this.Flatten(wordVariants); + }); + } + + private IPropagatorBlock, string> CreateFlatWordsToPhrasesTransform() + { + return new TransformBlock, string>(words => + { + return string.Join(" ", words); + }); + } } } diff --git a/WhiteRabbit/VectorsProcessor.cs b/WhiteRabbit/VectorsProcessor.cs index 76da483..a33c16f 100644 --- a/WhiteRabbit/VectorsProcessor.cs +++ b/WhiteRabbit/VectorsProcessor.cs @@ -6,7 +6,7 @@ using System.Diagnostics; using System.Linq; using System.Numerics; - + using System.Threading.Tasks.Dataflow; internal class VectorsProcessor { public VectorsProcessor(Vector target, int maxVectorsCount, IEnumerable> vectors, Func, string> vectorToString) @@ -37,13 +37,23 @@ private long Iterations { get; set; } = 0; - // Produces all sequences of vectors with the target sum - public IEnumerable[]> GenerateSequences() + public IPropagatorBlock[], Vector[]> CreateUnorderedSequencesToOrderedSequencesTransform() { - var unorderedSequences = this.GenerateUnorderedSequences(this.Target, ImmutableStack.Create>(), this.Vectors); - var allSequences = unorderedSequences.SelectMany(this.GeneratePermutations); + return new TransformManyBlock[], Vector[]>(sequence => + { + return this.GeneratePermutations(sequence); + }); + } + + public void PostUnorderedSequences(ITargetBlock[]> target) + { + var sequences = this.GenerateUnorderedSequences(this.Target, ImmutableStack.Create>(), this.Vectors); + foreach (var sequence in sequences) + { + target.Post(sequence); + } - return allSequences; + target.Complete(); } // We want words with more letters (and among these, words with more "rare" letters) to appear first, to reduce the searching time somewhat. diff --git a/WhiteRabbit/WhiteRabbit.csproj b/WhiteRabbit/WhiteRabbit.csproj index 1af7ec9..a7fc331 100644 --- a/WhiteRabbit/WhiteRabbit.csproj +++ b/WhiteRabbit/WhiteRabbit.csproj @@ -45,6 +45,10 @@ ..\packages\System.Numerics.Vectors.4.3.0\lib\net46\System.Numerics.Vectors.dll True + + ..\packages\Microsoft.Tpl.Dataflow.4.5.24\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll + True + @@ -53,6 +57,7 @@ + diff --git a/WhiteRabbit/packages.config b/WhiteRabbit/packages.config index d38493d..379667e 100644 --- a/WhiteRabbit/packages.config +++ b/WhiteRabbit/packages.config @@ -1,5 +1,6 @@  + \ No newline at end of file