namespace WhiteRabbit { using System; using System.Collections.Generic; using System.Linq; internal static class PrecomputedPermutationsGenerator { static PrecomputedPermutationsGenerator() { Permutations = new ulong[Constants.MaxNumberOfWords + 1][][]; PermutationsNumbers = new long[Constants.MaxNumberOfWords + 1][]; for (var i = 0; i <= Constants.MaxNumberOfWords; i++) { var permutationsInfo = GeneratePermutations(i); Permutations[i] = permutationsInfo.Item1; PermutationsNumbers[i] = permutationsInfo.Item2; } } private static ulong[][][] Permutations { get; } private static long[][] PermutationsNumbers { get; } public static ulong[] HamiltonianPermutations(int n, uint filter) => Permutations[n][filter]; public static long GetPermutationsNumber(int n, uint filter) => PermutationsNumbers[n][filter]; private static Tuple GeneratePermutations(int n) { if (n == 0) { return Tuple.Create(new ulong[0][], new long[0]); } var allPermutations = PermutationsGenerator.HamiltonianPermutations(n) .Select(FormatPermutation) .ToArray(); var statesCount = (uint)1 << (n - 1); var resultUnpadded = new PermutationInfo[statesCount][]; resultUnpadded[0] = allPermutations; for (uint i = 1; i < statesCount; i++) { var mask = i; mask |= mask >> 1; mask |= mask >> 2; mask |= mask >> 4; mask |= mask >> 8; mask |= mask >> 16; mask = mask >> 1; var existing = i & mask; var seniorBit = i ^ existing; var position = 0; while (seniorBit != 0) { seniorBit = seniorBit >> 1; position++; } resultUnpadded[i] = resultUnpadded[existing] .Where(info => ((info.PermutationInverse >> (4 * (position - 1))) % 16 < (info.PermutationInverse >> (4 * position)) % 16)) .ToArray(); } var result = new ulong[statesCount][]; var numbers = new long[statesCount]; for (uint i = 0; i < statesCount; i++) { result[i] = PadToWholeChunks(resultUnpadded[i], Constants.PhrasesPerSet); numbers[i] = resultUnpadded[i].LongLength; } return Tuple.Create(result, numbers); } public static bool IsOrderPreserved(ulong permutation, uint position) { var currentPermutation = permutation; while (currentPermutation != 0) { if ((currentPermutation & 15) == position) { return true; } if ((currentPermutation & 15) == (position + 1)) { return false; } currentPermutation = currentPermutation >> 4; } throw new ApplicationException("Malformed permutation " + permutation + " for position " + position); } private static ulong[] PadToWholeChunks(PermutationInfo[] original, int chunkSize) { ulong[] result; if (original.Length % chunkSize == 0) { result = new ulong[original.Length]; } else { result = new ulong[original.Length + chunkSize - (original.Length % chunkSize)]; } for (var i = 0; i < original.Length; i++) { result[i] = original[i].Permutation; } return result; } private static PermutationInfo FormatPermutation(PermutationsGenerator.Permutation permutation) { System.Diagnostics.Debug.Assert(permutation.PermutationData.Length <= 16); ulong result = 0; ulong resultInverse = 0; for (var i = 0; i < permutation.PermutationData.Length; i++) { var source = i; var target = permutation.PermutationData[i]; result |= (ulong)(target) << (4 * source); resultInverse |= (ulong)(source) << (4 * target); } return new PermutationInfo { Permutation = result, PermutationInverse = resultInverse }; } private static IEnumerable GeneratePermutationsNumbers() { long result = 1; yield return result; var i = 1; while (true) { result *= i; yield return result; i++; } } private struct PermutationInfo { public ulong Permutation; public ulong PermutationInverse; } } }