Compare commits

...

2 Commits

  1. 1
      WhiteRabbit/App.config
  2. 11
      WhiteRabbit/Program.cs
  3. 3
      WhiteRabbit/StringsProcessor.cs
  4. 38
      WhiteRabbit/VectorsProcessor.cs

@ -6,6 +6,7 @@
<appSettings> <appSettings>
<add key="SourcePhrase" value="poultry outwits ants" /> <add key="SourcePhrase" value="poultry outwits ants" />
<add key="MaxWordsInPhrase" value="5" /> <add key="MaxWordsInPhrase" value="5" />
<add key="AllowWordsReuse" value="false" />
<add key="ExpectedHashes" value="e4820b45d2277f3844eac66c903e84be,23170acc097c24edb98fc5488ab033fe,665e5bcb0c20062fe8abaaf4628bb154"/> <add key="ExpectedHashes" value="e4820b45d2277f3844eac66c903e84be,23170acc097c24edb98fc5488ab033fe,665e5bcb0c20062fe8abaaf4628bb154"/>
</appSettings> </appSettings>
</configuration> </configuration>

@ -27,6 +27,7 @@
var sourceChars = ToOrderedChars(sourcePhrase); var sourceChars = ToOrderedChars(sourcePhrase);
var maxWordsInPhrase = int.Parse(ConfigurationManager.AppSettings["MaxWordsInPhrase"]); var maxWordsInPhrase = int.Parse(ConfigurationManager.AppSettings["MaxWordsInPhrase"]);
var allowWordsReuse = bool.Parse(ConfigurationManager.AppSettings["AllowWordsReuse"]);
var expectedHashesAsVectors = ConfigurationManager.AppSettings["ExpectedHashes"] var expectedHashesAsVectors = ConfigurationManager.AppSettings["ExpectedHashes"]
.Split(',') .Split(',')
@ -40,6 +41,7 @@
var processor = new StringsProcessor( var processor = new StringsProcessor(
Encoding.ASCII.GetBytes(sourcePhrase), Encoding.ASCII.GetBytes(sourcePhrase),
maxWordsInPhrase, maxWordsInPhrase,
allowWordsReuse,
ReadInput()); ReadInput());
Console.WriteLine($"Initialization complete; time from start: {stopwatch.Elapsed}"); Console.WriteLine($"Initialization complete; time from start: {stopwatch.Elapsed}");
@ -51,13 +53,14 @@
sourceChars == ToOrderedChars(Encoding.ASCII.GetString(phraseBytes)), sourceChars == ToOrderedChars(Encoding.ASCII.GetString(phraseBytes)),
$"StringsProcessor produced incorrect anagram: {Encoding.ASCII.GetString(phraseBytes)}"); $"StringsProcessor produced incorrect anagram: {Encoding.ASCII.GetString(phraseBytes)}");
var hashVector = ComputeHashVector(phraseBytes); Console.WriteLine(Encoding.ASCII.GetString(phraseBytes));
/*var hashVector = ComputeHashVector(phraseBytes);
if (Array.IndexOf(expectedHashesAsVectors, hashVector) >= 0) if (Array.IndexOf(expectedHashesAsVectors, hashVector) >= 0)
{ {
var phrase = Encoding.ASCII.GetString(phraseBytes); var phrase = Encoding.ASCII.GetString(phraseBytes);
var hash = VectorToHexadecimalString(hashVector); var hash = VectorToHexadecimalString(hashVector);
Console.WriteLine($"Found phrase for {hash}: {phrase}; time from start is {stopwatch.Elapsed}"); Console.WriteLine($"Found phrase for {hash}: {phrase}; time from start is {stopwatch.Elapsed}");
} }*/
#if DEBUG #if DEBUG
anagramsBag.Add(Encoding.ASCII.GetString(phraseBytes)); anagramsBag.Add(Encoding.ASCII.GetString(phraseBytes));
@ -113,6 +116,10 @@
string line; string line;
while ((line = Console.ReadLine()) != null) while ((line = Console.ReadLine()) != null)
{ {
if (line.Length == 1 && line != "a" && line != "i")
{
continue;
}
yield return Encoding.ASCII.GetBytes(line); yield return Encoding.ASCII.GetBytes(line);
} }
} }

@ -8,7 +8,7 @@
{ {
private const byte SPACE = 32; private const byte SPACE = 32;
public StringsProcessor(byte[] sourceString, int maxWordsCount, IEnumerable<byte[]> words) public StringsProcessor(byte[] sourceString, int maxWordsCount, bool allowWordsReuse, IEnumerable<byte[]> words)
{ {
var filteredSource = sourceString.Where(ch => ch != SPACE).ToArray(); var filteredSource = sourceString.Where(ch => ch != SPACE).ToArray();
this.NumberOfCharacters = filteredSource.Length; this.NumberOfCharacters = filteredSource.Length;
@ -29,6 +29,7 @@
this.VectorsProcessor = new VectorsProcessor( this.VectorsProcessor = new VectorsProcessor(
this.VectorsConverter.GetVector(filteredSource).Value, this.VectorsConverter.GetVector(filteredSource).Value,
maxWordsCount, maxWordsCount,
allowWordsReuse,
vectorsToWords.Select(tuple => tuple.vector).ToArray()); vectorsToWords.Select(tuple => tuple.vector).ToArray());
} }

@ -17,7 +17,7 @@
PrecomputedPermutationsGenerator.HamiltonianPermutations(0); PrecomputedPermutationsGenerator.HamiltonianPermutations(0);
} }
public VectorsProcessor(Vector<byte> target, int maxVectorsCount, Vector<byte>[] dictionary) public VectorsProcessor(Vector<byte> target, int maxVectorsCount, bool allowWordsReuse, Vector<byte>[] dictionary)
{ {
if (Enumerable.Range(0, Vector<byte>.Count).Any(i => target[i] > MaxComponentValue)) if (Enumerable.Range(0, Vector<byte>.Count).Any(i => target[i] > MaxComponentValue))
{ {
@ -27,6 +27,7 @@
this.Target = target; this.Target = target;
this.MaxVectorsCount = maxVectorsCount; this.MaxVectorsCount = maxVectorsCount;
this.AllowWordsReuseAddendum = allowWordsReuse ? 0 : 1;
this.Dictionary = ImmutableArray.Create(FilterVectors(dictionary, target).ToArray()); this.Dictionary = ImmutableArray.Create(FilterVectors(dictionary, target).ToArray());
} }
@ -34,6 +35,8 @@
private int MaxVectorsCount { get; } private int MaxVectorsCount { get; }
private int AllowWordsReuseAddendum { get; }
private ImmutableArray<VectorInfo> Dictionary { get; } private ImmutableArray<VectorInfo> Dictionary { get; }
// Produces all sequences of vectors with the target sum // Produces all sequences of vectors with the target sum
@ -43,7 +46,14 @@
public ParallelQuery<int[]> GenerateSequences() public ParallelQuery<int[]> GenerateSequences()
#endif #endif
{ {
return GenerateUnorderedSequences(this.Target, GetVectorNorm(this.Target, this.Target), this.MaxVectorsCount, this.Dictionary, 0) var unorderedSequences = GenerateUnorderedSequences(
this.Target,
GetVectorNorm(this.Target, this.Target),
this.MaxVectorsCount,
this.Dictionary,
0,
this.AllowWordsReuseAddendum);
return unorderedSequences
#if !SINGLE_THREADED #if !SINGLE_THREADED
.AsParallel() .AsParallel()
#endif #endif
@ -81,7 +91,7 @@
// In every sequence, next vector always goes after the previous one from dictionary. // In every sequence, next vector always goes after the previous one from dictionary.
// E.g. if dictionary is [x, y, z], then only [x, y] sequence could be generated, and [y, x] will never be generated. // E.g. if dictionary is [x, y, z], then only [x, y] sequence could be generated, and [y, x] will never be generated.
// That way, the complexity of search goes down by a factor of MaxVectorsCount! (as if [x, y] does not add up to a required target, there is no point in checking [y, x]) // That way, the complexity of search goes down by a factor of MaxVectorsCount! (as if [x, y] does not add up to a required target, there is no point in checking [y, x])
private static IEnumerable<ImmutableStack<int>> GenerateUnorderedSequences(Vector<byte> remainder, int remainderNorm, int allowedRemainingWords, ImmutableArray<VectorInfo> dictionary, int currentDictionaryPosition) private static IEnumerable<ImmutableStack<int>> GenerateUnorderedSequences(Vector<byte> remainder, int remainderNorm, int allowedRemainingWords, ImmutableArray<VectorInfo> dictionary, int currentDictionaryPosition, int dictionaryPositionAddendum)
{ {
if (allowedRemainingWords > 1) if (allowedRemainingWords > 1)
{ {
@ -96,7 +106,7 @@
var currentVectorInfo = dictionary[i]; var currentVectorInfo = dictionary[i];
if (currentVectorInfo.Vector == remainder) if (currentVectorInfo.Vector == remainder)
{ {
yield return ImmutableStack.Create(currentVectorInfo.Index); //yield return ImmutableStack.Create(currentVectorInfo.Index);
} }
else if (currentVectorInfo.Norm < requiredRemainderPerWord) else if (currentVectorInfo.Norm < requiredRemainderPerWord)
{ {
@ -106,7 +116,15 @@
{ {
var newRemainder = remainder - currentVectorInfo.Vector; var newRemainder = remainder - currentVectorInfo.Vector;
var newRemainderNorm = remainderNorm - currentVectorInfo.Norm; var newRemainderNorm = remainderNorm - currentVectorInfo.Norm;
foreach (var result in GenerateUnorderedSequences(newRemainder, newRemainderNorm, newAllowedRemainingWords, dictionary, i)) var newSequences = GenerateUnorderedSequences(
newRemainder,
newRemainderNorm,
newAllowedRemainingWords,
dictionary,
i + dictionaryPositionAddendum,
dictionaryPositionAddendum);
foreach (var result in newSequences)
{ {
yield return result.Push(currentVectorInfo.Index); yield return result.Push(currentVectorInfo.Index);
} }
@ -133,6 +151,11 @@
// BCL BinarySearch would find any vector with required norm, not the first one; or would find nothing if there is no such vector // BCL BinarySearch would find any vector with required norm, not the first one; or would find nothing if there is no such vector
private static int FindFirstWithNormLessOrEqual(int expectedNorm, ImmutableArray<VectorInfo> dictionary, int offset) private static int FindFirstWithNormLessOrEqual(int expectedNorm, ImmutableArray<VectorInfo> dictionary, int offset)
{ {
if (offset >= dictionary.Length)
{
return dictionary.Length;
}
var start = offset; var start = offset;
var end = dictionary.Length - 1; var end = dictionary.Length - 1;
@ -167,6 +190,9 @@
private static IEnumerable<T[]> GeneratePermutations<T>(T[] original) private static IEnumerable<T[]> GeneratePermutations<T>(T[] original)
{ {
yield return original;
yield break;
/*
var length = original.Length; var length = original.Length;
foreach (var permutation in PrecomputedPermutationsGenerator.HamiltonianPermutations(length)) foreach (var permutation in PrecomputedPermutationsGenerator.HamiltonianPermutations(length))
{ {
@ -177,7 +203,7 @@
} }
yield return result; yield return result;
} }*/
} }
private struct VectorInfo private struct VectorInfo

Loading…
Cancel
Save