Optimization; GeneratePermutations is called after flattening

performance-simd-rust
Inga 🏳‍🌈 7 years ago
parent 97d73e54af
commit 9a158edc8b
  1. 10
      README.md
  2. 2
      WhiteRabbit/Program.cs
  3. 22
      WhiteRabbit/StringsProcessor.cs
  4. 26
      WhiteRabbit/VectorsProcessor.cs

@ -41,15 +41,15 @@ That's why the given hashes are solved much sooner than it takes to check all an
Anagrams generation is not parallelized, as even single-threaded performance for 4-word anagrams is high enough; and 5-word (or larger) anagrams are frequent enough for most of the time being spent on computing hashes, with full CPU load.
Multi-threaded performance with RyuJIT (.NET 4.6, 64-bit system) on quad-core Sandy Bridge @2.8GHz is as follows:
Multi-threaded performance with RyuJIT (.NET 4.6, 64-bit system) on quad-core Sandy Bridge @2.8GHz is as follows (excluding initialization time of 0.2 seconds):
* If only phrases of at most 4 words are allowed, then it takes **less than 2 seconds** to find and check all 7433016 anagrams; all hashes are solved in first 0.3 seconds.
* If only phrases of at most 4 words are allowed, then it takes **1.5 seconds** to find and check all 7433016 anagrams; **all hashes are solved in first 0.2 seconds**.
* If phrases of 5 words are allowed as well, then it takes around 4 minutes to find and check all 1348876896 anagrams; all hashes are solved in first 6.5 seconds.
* If phrases of 5 words are allowed as well, then it takes 3.5 minutes to find and check all 1348876896 anagrams; all hashes are solved in first 5 seconds.
* If phrases of 6 words are allowed as well, then "more difficult" hash is solved in 6 seconds, "easiest" in 38 seconds, and "hard" in 1.5 minutes.
* If phrases of 6 words are allowed as well, then "more difficult" hash is solved in 5 seconds, "easiest" in 30 seconds, and "hard" in 75 seconds.
* If phrases of 7 words are allowed as well, then "more difficult" hash is solved in 39 seconds, "easiest" in less than 5 minutes, and "hard" in 13 minutes.
* If phrases of 7 words are allowed as well, then "more difficult" hash is solved in 29 seconds, "easiest" in 3.5 minutes, and "hard" in 9.5 minutes.
Note that all measurements were done on a Release build; Debug build is significantly slower.

@ -55,6 +55,8 @@
Console.WriteLine($"Initialization complete; time from start: {stopwatch.Elapsed}");
stopwatch.Restart();
processor.GeneratePhrases()
.ForAll(phraseBytes =>
{

@ -8,6 +8,12 @@
{
private const byte SPACE = 32;
// Ensure that permutations are precomputed prior to main run, so that processing times will be correct
static StringsProcessor()
{
PrecomputedPermutationsGenerator.HamiltonianPermutations(0);
}
public StringsProcessor(byte[] sourceString, int maxWordsCount, IEnumerable<byte[]> words)
{
var filteredSource = sourceString.Where(ch => ch != SPACE).ToArray();
@ -56,9 +62,25 @@
return sums
.Select(this.ConvertVectorsToWords)
.SelectMany(Flattener.Flatten)
.SelectMany(GeneratePermutations)
.Select(this.ConvertWordsToPhrase);
}
private static IEnumerable<T[]> GeneratePermutations<T>(T[] original)
{
var length = original.Length;
foreach (var permutation in PrecomputedPermutationsGenerator.HamiltonianPermutations(length))
{
var result = new T[length];
for (var i = 0; i < length; i++)
{
result[i] = original[permutation[i]];
}
yield return result;
}
}
private byte[][][] ConvertVectorsToWords(int[] vectors)
{
var length = vectors.Length;

@ -11,12 +11,6 @@
private const byte MaxComponentValue = 8;
private const int LeastCommonMultiple = 840;
// Ensure that permutations are precomputed prior to main run, so that processing times will be correct
static VectorsProcessor()
{
PrecomputedPermutationsGenerator.HamiltonianPermutations(0);
}
public VectorsProcessor(Vector<byte> target, int maxVectorsCount, Vector<byte>[] dictionary)
{
if (Enumerable.Range(0, Vector<byte>.Count).Any(i => target[i] > MaxComponentValue))
@ -36,7 +30,7 @@
private ImmutableArray<VectorInfo> Dictionary { get; }
// Produces all sequences of vectors with the target sum
// Produces all sets of vectors with the target sum
#if SINGLE_THREADED
public IEnumerable<int[]> GenerateSequences()
#else
@ -47,8 +41,7 @@
#if !SINGLE_THREADED
.AsParallel()
#endif
.Select(Enumerable.ToArray)
.SelectMany(GeneratePermutations);
.Select(Enumerable.ToArray);
}
// We want words with more letters (and among these, words with more "rare" letters) to appear first, to reduce the searching time somewhat.
@ -165,21 +158,6 @@
return start;
}
private static IEnumerable<T[]> GeneratePermutations<T>(T[] original)
{
var length = original.Length;
foreach (var permutation in PrecomputedPermutationsGenerator.HamiltonianPermutations(length))
{
var result = new T[length];
for (var i = 0; i < length; i++)
{
result[i] = original[permutation[i]];
}
yield return result;
}
}
private struct VectorInfo
{
public VectorInfo(Vector<byte> vector, int norm, int index)

Loading…
Cancel
Save