diff --git a/README.md b/README.md index 3db1ccb..78fe601 100644 --- a/README.md +++ b/README.md @@ -47,10 +47,10 @@ Number of words|Time to check all anagrams no longer than that|Time to solve "ea ---------------|----------------------------------------------|-------------------------|-----------------------------------|-------------------------|--------------------------------------------- 3|0.04s||||4560 4|0.45s|||0.08s|7,431,984 -5|12s|0.15s|0.06s|0.3s|1,347,437,484 -6|6.5 minutes|1.2s|0.2s|3s|58,405,904,844 -7|2 hours|7s|0.9s|19s|1,070,307,744,114 -8|21.5 hours|25s|2.6s|80s|10,893,594,396,594 +5|11.7s|0.15s|0.06s|0.3s|1,347,437,484 +6|6.5 minutes|1.2s|0.2s|2.9s|58,405,904,844 +7|2 hours|6.7s|0.9s|19s|1,070,307,744,114 +8|21.5 hours|25s|2.6s|79s|10,893,594,396,594 9||2.5 minutes|13s|9.5 minutes|70,596,864,409,954 10||5 minutes|21s|17.5 minutes|314,972,701,475,754 diff --git a/dotnet/WhiteRabbit.UnmanagedBridge/WhiteRabbit.UnmanagedBridge.cpp b/dotnet/WhiteRabbit.UnmanagedBridge/WhiteRabbit.UnmanagedBridge.cpp index 9e11414..93bb6f0 100644 --- a/dotnet/WhiteRabbit.UnmanagedBridge/WhiteRabbit.UnmanagedBridge.cpp +++ b/dotnet/WhiteRabbit.UnmanagedBridge/WhiteRabbit.UnmanagedBridge.cpp @@ -27,7 +27,7 @@ void WhiteRabbitUnmanagedBridge::MD5Unmanaged::ComputeMD5(unsigned __int32 * inp #endif } -void WhiteRabbitUnmanagedBridge::MD5Unmanaged::FillPhraseSet(__int64* bufferPointer, __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfCharacters, int numberOfWords) +void WhiteRabbitUnmanagedBridge::MD5Unmanaged::FillPhraseSet(unsigned __int64* initialBufferPointer, unsigned __int64* bufferPointer, unsigned __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfWords) { - fillPhraseSet(bufferPointer, (unsigned __int64*)allWordsPointer, wordIndexes, permutationsPointer, numberOfCharacters, numberOfWords); + fillPhraseSet(initialBufferPointer, bufferPointer, allWordsPointer, wordIndexes, permutationsPointer, numberOfWords); } diff --git a/dotnet/WhiteRabbit.UnmanagedBridge/WhiteRabbit.UnmanagedBridge.h b/dotnet/WhiteRabbit.UnmanagedBridge/WhiteRabbit.UnmanagedBridge.h index 41468b5..35ecab5 100644 --- a/dotnet/WhiteRabbit.UnmanagedBridge/WhiteRabbit.UnmanagedBridge.h +++ b/dotnet/WhiteRabbit.UnmanagedBridge/WhiteRabbit.UnmanagedBridge.h @@ -13,6 +13,6 @@ namespace WhiteRabbitUnmanagedBridge { public: literal int PhrasesPerSet = PHRASES_PER_SET; static void ComputeMD5(unsigned int* input); - static void FillPhraseSet(__int64* bufferPointer, __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfCharacters, int numberOfWords); + static void FillPhraseSet(unsigned __int64* initialBufferPointer, unsigned __int64* bufferPointer, unsigned __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfWords); }; } diff --git a/dotnet/WhiteRabbit.UnmanagedBridge/phraseset.cpp b/dotnet/WhiteRabbit.UnmanagedBridge/phraseset.cpp index 767d45a..6fdc18c 100644 --- a/dotnet/WhiteRabbit.UnmanagedBridge/phraseset.cpp +++ b/dotnet/WhiteRabbit.UnmanagedBridge/phraseset.cpp @@ -27,12 +27,12 @@ #define INIT_WORD(phraseNumber) \ auto permutation = permutationsPointer[phraseNumber]; \ unsigned __int64 cumulativeWordOffset = 0; \ - auto phrase = _mm256_set1_epi32(0); + auto phrase = avx2initialBuffer[phraseNumber]; #define PROCESS_WORD(phraseNumber, wordNumber) \ { \ auto currentWord = allWordsPointer + wordIndexes[permutation % 16] * 128; \ - phrase = _mm256_or_si256(phrase, *(__m256i*)(currentWord + cumulativeWordOffset)); \ + phrase = _mm256_xor_si256(phrase, *(__m256i*)(currentWord + cumulativeWordOffset)); \ permutation >>= 4; \ cumulativeWordOffset += currentWord[127]; \ } @@ -118,8 +118,9 @@ #define REPEAT_WORDS10(phraseNumber) REPEAT_WORDS(phraseNumber, REPEAT_WORDS_SIMPLE10) -void fillPhraseSet(__int64* bufferPointer, unsigned __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfCharacters, int numberOfWords) +void fillPhraseSet(unsigned __int64* initialBufferPointer, unsigned __int64* bufferPointer, unsigned __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfWords) { + auto avx2initialBuffer = (__m256i*)initialBufferPointer; auto avx2buffer = (__m256i*)bufferPointer; switch (numberOfWords) @@ -155,15 +156,6 @@ void fillPhraseSet(__int64* bufferPointer, unsigned __int64* allWordsPointer, __ REPEAT_PHRASES(REPEAT_WORDS10); break; } - - auto length = numberOfCharacters + numberOfWords - 1; - auto lengthInBits = (unsigned __int32)(length << 3); - -#define FILL_PHRASE_LAST_BYTE(phraseNumber) ((unsigned char*)bufferPointer)[length + phraseNumber * 32] = 128; -#define FILL_PHRASE_SET_LENGTH(phraseNumber) ((unsigned __int32*)bufferPointer)[7 + phraseNumber * 8] = lengthInBits; - - REPEAT_PHRASES(FILL_PHRASE_LAST_BYTE); - REPEAT_PHRASES(FILL_PHRASE_SET_LENGTH); } #pragma managed diff --git a/dotnet/WhiteRabbit.UnmanagedBridge/phraseset.h b/dotnet/WhiteRabbit.UnmanagedBridge/phraseset.h index d13d516..d32d6a7 100644 --- a/dotnet/WhiteRabbit.UnmanagedBridge/phraseset.h +++ b/dotnet/WhiteRabbit.UnmanagedBridge/phraseset.h @@ -1,3 +1,3 @@ #pragma once -void fillPhraseSet(__int64* bufferPointer, unsigned __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfCharacters, int numberOfWords); +void fillPhraseSet(unsigned __int64* initialBufferPointer, unsigned __int64* bufferPointer, unsigned __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfWords); diff --git a/dotnet/WhiteRabbit/PhraseSet.cs b/dotnet/WhiteRabbit/PhraseSet.cs index b3dc8e2..e0a47c5 100644 --- a/dotnet/WhiteRabbit/PhraseSet.cs +++ b/dotnet/WhiteRabbit/PhraseSet.cs @@ -1,6 +1,7 @@ namespace WhiteRabbit { using System.Diagnostics; + using System.Linq; using System.Runtime.CompilerServices; using WhiteRabbitUnmanagedBridge; @@ -17,11 +18,23 @@ this.Buffer = new uint[8 * length]; } - public unsafe void FillPhraseSet(Word[] allWords, int[] wordIndexes, ulong[] permutations, int permutationOffset, int numberOfCharacters) + public unsafe void InitPhraseSet(int numberOfCharacters, int numberOfWords) { - Debug.Assert(numberOfCharacters + wordIndexes.Length - 1 < 27); - fixed (uint* bufferPointer = this.Buffer) + { + var length = (uint)(numberOfCharacters + numberOfWords - 1); + var lengthInBits = (uint)(length << 3); + for (var i = 0; i < this.Length; i++) + { + bufferPointer[7 + i * 8] = lengthInBits; + ((byte*)bufferPointer)[length + i * 32] = 128 ^ ' '; + } + } + } + + public unsafe void FillPhraseSet(PhraseSet initial, Word[] allWords, int[] wordIndexes, ulong[] permutations, int permutationOffset) + { + fixed (uint* bufferPointer = this.Buffer, initialBufferPointer = initial.Buffer) { fixed (ulong* permutationsPointer = permutations) { @@ -30,11 +43,11 @@ fixed (Word* allWordsPointer = allWords) { MD5Unmanaged.FillPhraseSet( - (long*)bufferPointer, - (long*)allWordsPointer, + (ulong*)initialBufferPointer, + (ulong*)bufferPointer, + (ulong*)allWordsPointer, wordIndexesPointer, permutationsPointer + permutationOffset, - numberOfCharacters, wordIndexes.Length); } } @@ -58,9 +71,9 @@ public unsafe byte[] GetBytes(int number) { - Debug.Assert(number < Constants.PhrasesPerSet); + Debug.Assert(number < this.Length); - fixed(uint* bufferPointer = this.Buffer) + fixed (uint* bufferPointer = this.Buffer) { var phrasePointer = bufferPointer + 8 * number; var length = 0; @@ -82,5 +95,16 @@ return result; } } + + public unsafe string DebugBytes(int number) + { + Debug.Assert(number < this.Length); + + fixed (uint* bufferPointer = this.Buffer) + { + var bytes = (byte*)bufferPointer; + return string.Concat(Enumerable.Range(32 * number, 32).Select(i => bytes[i].ToString("X2"))); + } + } } } diff --git a/dotnet/WhiteRabbit/StringsProcessor.cs b/dotnet/WhiteRabbit/StringsProcessor.cs index 150b62a..45fa83c 100644 --- a/dotnet/WhiteRabbit/StringsProcessor.cs +++ b/dotnet/WhiteRabbit/StringsProcessor.cs @@ -120,6 +120,8 @@ private void ProcessSum(int[] sum, Action action) { + var initialPhraseSet = new PhraseSet(Constants.PhrasesPerSet); + initialPhraseSet.InitPhraseSet(this.NumberOfCharacters, sum.Length); var phraseSet = new PhraseSet(Constants.PhrasesPerSet); var filter = ComputeFilter(sum); var wordsVariants = this.ConvertVectorsToWordIndexes(sum); @@ -130,7 +132,7 @@ var permutations = PrecomputedPermutationsGenerator.HamiltonianPermutations(wordsArray.Length, filter); for (var i = 0; i < permutations.Length; i += Constants.PhrasesPerSet) { - phraseSet.FillPhraseSet(this.AllWords, wordsArray, permutations, i, this.NumberOfCharacters); + phraseSet.FillPhraseSet(initialPhraseSet, this.AllWords, wordsArray, permutations, i); action(phraseSet); } }