Refactored to use RX

rx
Inga 🏳‍🌈 7 years ago
parent e153e20cc6
commit 5fb43799af
  1. 10
      WhiteRabbit/App.config
  2. 31
      WhiteRabbit/Program.cs
  3. 13
      WhiteRabbit/StringsProcessor.cs
  4. 16
      WhiteRabbit/VectorsProcessor.cs
  5. 22
      WhiteRabbit/WhiteRabbit.csproj
  6. 6
      WhiteRabbit/packages.config

@ -1,6 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" /> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup> </startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> </configuration>

@ -5,6 +5,8 @@
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
@ -31,11 +33,18 @@
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(ReadInput()))) var phrases = processor.GeneratePhrases(ReadInput());
using (var hasher = MD5.Create())
{ {
if (expectedHashesAsVectors.Contains(result.Item2)) var phrasesWithHashes = phrases
.Select(phrase => new { phrase, hash = ComputeHash(hasher, phrase) })
.SubscribeOn(NewThreadScheduler.Default);
var filteredPhrases = phrasesWithHashes.Where(tuple => expectedHashesAsVectors.Contains(tuple.hash));
foreach (var result in filteredPhrases.ToEnumerable())
{ {
Console.WriteLine($"Found phrase: {result.Item1} (spent {stopwatch.Elapsed})"); Console.WriteLine($"Found phrase with hash {HashToString(result.hash)}: {result.phrase} (spent {stopwatch.Elapsed})");
} }
} }
@ -52,16 +61,14 @@
.ToArray(); .ToArray();
} }
private static IEnumerable<Tuple<string, Vector<byte>>> AddHashes(IEnumerable<string> input) private static Vector<byte> ComputeHash(HashAlgorithm hasher, string phrase)
{ {
using (MD5 hasher = MD5.Create()) return new Vector<byte>(hasher.ComputeHash(Encoding.ASCII.GetBytes(phrase)));
{ }
foreach (var line in input)
{ private static string HashToString(Vector<byte> hash)
var data = hasher.ComputeHash(Encoding.ASCII.GetBytes(line)); {
yield return Tuple.Create(line, new Vector<byte>(data)); return string.Concat(Enumerable.Range(0, 16).Select(i => hash[i].ToString("x2")));
}
}
} }
private static IEnumerable<string> ReadInput() private static IEnumerable<string> ReadInput()

@ -1,8 +1,11 @@
namespace WhiteRabbit namespace WhiteRabbit
{ {
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
internal class StringsProcessor internal class StringsProcessor
{ {
@ -20,7 +23,7 @@
private VectorsProcessor VectorsProcessor { get; } private VectorsProcessor VectorsProcessor { get; }
public IEnumerable<string> GeneratePhrases(IEnumerable<string> words) public IObservable<string> GeneratePhrases(IEnumerable<string> words)
{ {
// Dictionary of vectors to array of words represented by this vector // Dictionary of vectors to array of words represented by this vector
var formattedWords = words var formattedWords = words
@ -32,15 +35,17 @@
.ToDictionary(group => group.Key, group => group.Select(tuple => tuple.word).ToArray()); .ToDictionary(group => group.Key, group => group.Select(tuple => tuple.word).ToArray());
// task of finding anagrams could be reduced to the task of finding sequences of dictionary vectors with the target sum // 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(formattedWords.Keys); var sums = this.VectorsProcessor.GenerateSequences(formattedWords.Keys).ObserveOn(Scheduler.Default);
// converting sequences of vectors to the sequences of words... // converting sequences of vectors to the sequences of words...
var anagramsWords = sums var anagramsWords = sums
.Select(sum => ImmutableStack.Create(sum.Select(vector => formattedWords[vector]).ToArray())) .Select(sum => ImmutableStack.Create(sum.Select(vector => formattedWords[vector]).ToArray()))
.SelectMany(this.Flatten) .SelectMany(this.Flatten)
.Select(stack => stack.ToArray()); .Select(stack => stack.ToArray())
.SubscribeOn(NewThreadScheduler.Default);
return anagramsWords.Select(list => string.Join(" ", list)); return anagramsWords.Select(list => string.Join(" ", list))
.SubscribeOn(NewThreadScheduler.Default);
} }
// 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]]

@ -6,6 +6,8 @@
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
internal class VectorsProcessor internal class VectorsProcessor
{ {
@ -33,12 +35,18 @@
private long Iterations { get; set; } = 0; private long Iterations { get; set; } = 0;
// Produces all sequences of vectors with the target sum // Produces all sequences of vectors with the target sum
public IEnumerable<Vector<byte>[]> GenerateSequences(IEnumerable<Vector<byte>> vectors) public IObservable<Vector<byte>[]> GenerateSequences(IReadOnlyCollection<Vector<byte>> vectors)
{ {
var filteredVectors = this.FilterVectors(vectors); var filteredVectors = this.FilterVectors(vectors);
var dictionary = ImmutableStack.Create(filteredVectors.ToArray()); var dictionary = ImmutableStack.Create(filteredVectors.ToArray());
var unorderedSequences = this.GenerateUnorderedSequences(this.Target, ImmutableStack.Create<Vector<byte>>(), dictionary);
var allSequences = unorderedSequences.SelectMany(this.GeneratePermutations); var unorderedSequences = this.GenerateUnorderedSequences(this.Target, ImmutableStack.Create<Vector<byte>>(), dictionary)
.ToObservable()
.SubscribeOn(NewThreadScheduler.Default);
var allSequences = unorderedSequences
.SelectMany(this.GeneratePermutations)
.SubscribeOn(NewThreadScheduler.Default);
return allSequences; return allSequences;
} }
@ -59,7 +67,7 @@
return weight; return weight;
} }
private IEnumerable<Vector<byte>> FilterVectors(IEnumerable<Vector<byte>> vectors) private IEnumerable<Vector<byte>> FilterVectors(IReadOnlyCollection<Vector<byte>> vectors)
{ {
return vectors return vectors
.Where(vector => ((this.Target - vector) & Negative) == Vector<byte>.Zero) .Where(vector => ((this.Target - vector) & Negative) == Vector<byte>.Zero)

@ -45,12 +45,34 @@
<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.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reactive.Core.3.1.1\lib\net46\System.Reactive.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Interfaces, Version=3.0.1000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reactive.Interfaces.3.1.1\lib\net45\System.Reactive.Interfaces.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Linq, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reactive.Linq.3.1.1\lib\net46\System.Reactive.Linq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.PlatformServices, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reactive.PlatformServices.3.1.1\lib\net46\System.Reactive.PlatformServices.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Windows.Threading, Version=3.0.1000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reactive.Windows.Threading.3.1.1\lib\net45\System.Reactive.Windows.Threading.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Windows" />
<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" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="PrecomputedPermutationsGenerator.cs" /> <Compile Include="PrecomputedPermutationsGenerator.cs" />

@ -2,4 +2,10 @@
<packages> <packages>
<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" />
<package id="System.Reactive" version="3.1.1" targetFramework="net46" />
<package id="System.Reactive.Core" version="3.1.1" targetFramework="net46" />
<package id="System.Reactive.Interfaces" version="3.1.1" targetFramework="net46" />
<package id="System.Reactive.Linq" version="3.1.1" targetFramework="net46" />
<package id="System.Reactive.PlatformServices" version="3.1.1" targetFramework="net46" />
<package id="System.Reactive.Windows.Threading" version="3.1.1" targetFramework="net46" />
</packages> </packages>
Loading…
Cancel
Save