Refactored to DataBlocks

dataflow
Inga 🏳‍🌈 8 years ago
parent e4a1cc0d23
commit 08ef75d4cf
  1. 23
      WhiteRabbit/Extensions.cs
  2. 62
      WhiteRabbit/Program.cs
  3. 50
      WhiteRabbit/StringsProcessor.cs
  4. 22
      WhiteRabbit/VectorsProcessor.cs
  5. 5
      WhiteRabbit/WhiteRabbit.csproj
  6. 1
      WhiteRabbit/packages.config

@ -0,0 +1,23 @@
namespace WhiteRabbit
{
using System.Threading.Tasks.Dataflow;
internal static class Extensions
{
public static void LinkForever<TOutput>(this ISourceBlock<TOutput> source, ITargetBlock<TOutput> target)
{
source.LinkTo(target);
source.Completion.ContinueWith(t =>
{
if (t.IsFaulted)
{
target.Fault(t.Exception);
}
else
{
target.Complete();
}
});
}
}
}

@ -7,7 +7,7 @@
using System.Numerics; using System.Numerics;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Threading.Tasks.Dataflow;
/// <summary> /// <summary>
/// Main class /// Main class
/// </summary> /// </summary>
@ -18,10 +18,6 @@
/// </summary> /// </summary>
public static void Main() public static void Main()
{ {
var stopwatch = new Stopwatch();
stopwatch.Start();
var processor = new StringsProcessor("poultry outwits ants", 4, ReadInput());
var expectedHashes = new[] var expectedHashes = new[]
{ {
"e4820b45d2277f3844eac66c903e84be", "e4820b45d2277f3844eac66c903e84be",
@ -31,17 +27,50 @@
var expectedHashesAsVectors = new HashSet<Vector<byte>>(expectedHashes.Select(hash => new Vector<byte>(StringToByteArray(hash)))); var expectedHashesAsVectors = new HashSet<Vector<byte>>(expectedHashes.Select(hash => new Vector<byte>(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<string, PhraseWithHash>(phrase =>
{ {
Console.WriteLine($"Found phrase: {result.Item1} (spent {stopwatch.Elapsed})"); var hash = new Vector<byte>(hasher.ComputeHash(Encoding.ASCII.GetBytes(phrase)));
} return new PhraseWithHash(phrase, hash);
});
var phrasesWithHashFilter = new TransformManyBlock<PhraseWithHash, PhraseWithHash>(phraseWithHash =>
{
if (!expectedHashesAsVectors.Contains(phraseWithHash.Hash))
{
return Enumerable.Empty<PhraseWithHash>();
} }
stopwatch.Stop(); return new PhraseWithHash[]
{
phraseWithHash,
};
});
var printPhrases = new ActionBlock<PhraseWithHash>(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}"); Console.WriteLine($"Total time spent: {stopwatch.Elapsed}");
} }
}
// Code taken from http://stackoverflow.com/a/321404/831314 // Code taken from http://stackoverflow.com/a/321404/831314
private static byte[] StringToByteArray(string hex) private static byte[] StringToByteArray(string hex)
@ -72,5 +101,18 @@
yield return line; yield return line;
} }
} }
private class PhraseWithHash
{
public PhraseWithHash(string phrase, Vector<byte> hash)
{
this.Phrase = phrase;
this.Hash = hash;
}
public string Phrase { get; }
public Vector<byte> Hash { get; }
}
} }
} }

@ -4,7 +4,7 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks.Dataflow;
internal class StringsProcessor internal class StringsProcessor
{ {
public StringsProcessor(string sourceString, int maxWordsCount, IEnumerable<string> words) public StringsProcessor(string sourceString, int maxWordsCount, IEnumerable<string> words)
@ -28,24 +28,26 @@
this.VectorsConverter.GetString); this.VectorsConverter.GetString);
} }
private VectorsConverter VectorsConverter { get; }
private VectorsProcessor VectorsProcessor { get; } private VectorsProcessor VectorsProcessor { get; }
private VectorsConverter VectorsConverter { get; }
private Dictionary<Vector<byte>, string[]> VectorsToWords { get; } private Dictionary<Vector<byte>, string[]> VectorsToWords { get; }
public IEnumerable<string> GeneratePhrases() public void PostUnorderedSequences(ITargetBlock<Vector<byte>[]> target) => this.VectorsProcessor.PostUnorderedSequences(target);
public IPropagatorBlock<Vector<byte>[], string> CreateUnorderedSequencesToPhrasesTransform()
{ {
// task of finding anagrams could be reduced to the task of finding sequences of dictionary vectors with the target sum var unorderedSequencesToOrderedSequences = this.VectorsProcessor.CreateUnorderedSequencesToOrderedSequencesTransform();
var sums = this.VectorsProcessor.GenerateSequences(); var orderedSequencesToWordVariants = this.CreateOrderedSequencesToWordVariantsTransform();
var wordVariantsToFlatWords = this.CreateWordVariantsToFlatWordsTransform();
var flatWordsToPhrases = this.CreateFlatWordsToPhrasesTransform();
// converting sequences of vectors to the sequences of words... unorderedSequencesToOrderedSequences.LinkForever(orderedSequencesToWordVariants);
var anagramsWords = sums orderedSequencesToWordVariants.LinkForever(wordVariantsToFlatWords);
.Select(sum => ImmutableStack.Create(sum.Select(vector => this.VectorsToWords[vector]).ToArray())) wordVariantsToFlatWords.LinkForever(flatWordsToPhrases);
.SelectMany(this.Flatten)
.Select(stack => stack.ToArray());
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]] // 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); var newStack = phrase.Pop(out wordVariants);
return this.Flatten(newStack).SelectMany(remainder => wordVariants.Select(word => remainder.Push(word))); return this.Flatten(newStack).SelectMany(remainder => wordVariants.Select(word => remainder.Push(word)));
} }
private IPropagatorBlock<Vector<byte>[], ImmutableStack<string[]>> CreateOrderedSequencesToWordVariantsTransform()
{
return new TransformBlock<Vector<byte>[], ImmutableStack<string[]>>(sum =>
{
return ImmutableStack.CreateRange(sum.Select(vector => this.VectorsToWords[vector]));
});
}
private IPropagatorBlock<ImmutableStack<string[]>, ImmutableStack<string>> CreateWordVariantsToFlatWordsTransform()
{
return new TransformManyBlock<ImmutableStack<string[]>, ImmutableStack<string>>(wordVariants =>
{
return this.Flatten(wordVariants);
});
}
private IPropagatorBlock<ImmutableStack<string>, string> CreateFlatWordsToPhrasesTransform()
{
return new TransformBlock<ImmutableStack<string>, string>(words =>
{
return string.Join(" ", words);
});
}
} }
} }

@ -6,7 +6,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks.Dataflow;
internal class VectorsProcessor internal class VectorsProcessor
{ {
public VectorsProcessor(Vector<byte> target, int maxVectorsCount, IEnumerable<Vector<byte>> vectors, Func<Vector<byte>, string> vectorToString) public VectorsProcessor(Vector<byte> target, int maxVectorsCount, IEnumerable<Vector<byte>> vectors, Func<Vector<byte>, string> vectorToString)
@ -37,13 +37,23 @@
private long Iterations { get; set; } = 0; private long Iterations { get; set; } = 0;
// Produces all sequences of vectors with the target sum public IPropagatorBlock<Vector<byte>[], Vector<byte>[]> CreateUnorderedSequencesToOrderedSequencesTransform()
public IEnumerable<Vector<byte>[]> GenerateSequences() {
return new TransformManyBlock<Vector<byte>[], Vector<byte>[]>(sequence =>
{ {
var unorderedSequences = this.GenerateUnorderedSequences(this.Target, ImmutableStack.Create<Vector<byte>>(), this.Vectors); return this.GeneratePermutations(sequence);
var allSequences = unorderedSequences.SelectMany(this.GeneratePermutations); });
}
public void PostUnorderedSequences(ITargetBlock<Vector<byte>[]> target)
{
var sequences = this.GenerateUnorderedSequences(this.Target, ImmutableStack.Create<Vector<byte>>(), 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. // We want words with more letters (and among these, words with more "rare" letters) to appear first, to reduce the searching time somewhat.

@ -45,6 +45,10 @@
<HintPath>..\packages\System.Numerics.Vectors.4.3.0\lib\net46\System.Numerics.Vectors.dll</HintPath> <HintPath>..\packages\System.Numerics.Vectors.4.3.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System.Threading.Tasks.Dataflow, Version=4.5.24.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Tpl.Dataflow.4.5.24\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
@ -53,6 +57,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Extensions.cs" />
<Compile Include="PrecomputedPermutationsGenerator.cs" /> <Compile Include="PrecomputedPermutationsGenerator.cs" />
<Compile Include="PermutationsGenerator.cs" /> <Compile Include="PermutationsGenerator.cs" />
<Compile Include="StringsProcessor.cs" /> <Compile Include="StringsProcessor.cs" />

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Microsoft.Tpl.Dataflow" version="4.5.24" targetFramework="net46" />
<package id="System.Collections.Immutable" version="1.3.1" targetFramework="net46" /> <package id="System.Collections.Immutable" version="1.3.1" targetFramework="net46" />
<package id="System.Numerics.Vectors" version="4.3.0" targetFramework="net46" /> <package id="System.Numerics.Vectors" version="4.3.0" targetFramework="net46" />
</packages> </packages>
Loading…
Cancel
Save