Further optimization

feature-optimized-md5
Inga 🏳‍🌈 7 years ago
parent 7296d71187
commit c94b6b3eaa
  1. 76
      WhiteRabbit/VectorsProcessor.cs

@ -38,7 +38,7 @@
this.TargetNorm = Vector.Dot(target, Vector<byte>.One); this.TargetNorm = Vector.Dot(target, Vector<byte>.One);
this.MaxVectorsCount = maxVectorsCount; this.MaxVectorsCount = maxVectorsCount;
this.VectorToString = vectorToString; this.VectorToString = vectorToString;
this.Dictionary = ImmutableStack.Create(FilterVectors(dictionary, target, this.TargetComplement).ToArray()); this.Dictionary = ImmutableArray.Create(FilterVectors(dictionary, target, this.TargetComplement).ToArray());
} }
private Vector<byte> Target { get; } private Vector<byte> Target { get; }
@ -49,7 +49,7 @@
private int MaxVectorsCount { get; } private int MaxVectorsCount { get; }
private ImmutableStack<Vector<byte>> Dictionary { get; } private ImmutableArray<VectorInfo> Dictionary { get; }
private Func<Vector<byte>, string> VectorToString { get; } private Func<Vector<byte>, string> VectorToString { get; }
@ -58,7 +58,7 @@
// Produces all sequences of vectors with the target sum // Produces all sequences of vectors with the target sum
public ParallelQuery<Vector<byte>[]> GenerateSequences() public ParallelQuery<Vector<byte>[]> GenerateSequences()
{ {
return this.GenerateUnorderedSequences(this.Target, this.MaxVectorsCount, this.Dictionary) return this.GenerateUnorderedSequences(this.Target, this.MaxVectorsCount, 0)
.AsParallel() .AsParallel()
.Select(Enumerable.ToArray) .Select(Enumerable.ToArray)
.SelectMany(this.GeneratePermutations); .SelectMany(this.GeneratePermutations);
@ -70,9 +70,9 @@
// And total number of quintuplets becomes reasonable 1412M. // And total number of quintuplets becomes reasonable 1412M.
// Also, it produces the intended results faster (as these are more likely to contain longer words - e.g. "poultry outwits ants" is more likely than "p o u l t r y o u t w i t s a n t s"). // Also, it produces the intended results faster (as these are more likely to contain longer words - e.g. "poultry outwits ants" is more likely than "p o u l t r y o u t w i t s a n t s").
// This method basically gives us the 1-norm of the vector in the space rescaled so that the target is [1, 1, ..., 1]. // This method basically gives us the 1-norm of the vector in the space rescaled so that the target is [1, 1, ..., 1].
private static int GetVectorWeight(Vector<byte> vector, Vector<byte> target, Vector<byte> targetComplement)
{
#if SUPPORT_LARGE_STRINGS #if SUPPORT_LARGE_STRINGS
private static int GetVectorWeight(Vector<byte> vector, Vector<byte> target)
{
var weight = 0; var weight = 0;
for (var i = 0; target[i] != 0; i++) for (var i = 0; target[i] != 0; i++)
{ {
@ -80,16 +80,30 @@
} }
return weight; return weight;
}
#else #else
private static byte GetVectorWeight(Vector<byte> vector, Vector<byte> targetComplement)
{
return Vector.Dot(vector, targetComplement); return Vector.Dot(vector, targetComplement);
#endif
} }
#endif
private static IEnumerable<Vector<byte>> FilterVectors(IEnumerable<Vector<byte>> vectors, Vector<byte> target, Vector<byte> targetComplement) private static VectorInfo[] FilterVectors(IEnumerable<Vector<byte>> vectors, Vector<byte> target, Vector<byte> targetComplement)
{ {
return vectors return vectors
.Where(vector => Vector.GreaterThanOrEqualAll(target, vector)) .Where(vector => Vector.GreaterThanOrEqualAll(target, vector))
.OrderBy(vector => GetVectorWeight(vector, target, targetComplement)); #if SUPPORT_LARGE_STRINGS
.Select(vector => new { vector = vector, weight = GetVectorWeight(vector, target) })
#else
.Select(vector => new { vector = vector, weight = GetVectorWeight(vector, targetComplement) })
#endif
.OrderByDescending(tuple => tuple.weight)
#if SUPPORT_LARGE_STRINGS
.Select(tuple => new VectorInfo(tuple.vector, 0)))
#else
.Select(tuple => new VectorInfo(tuple.vector, tuple.weight))
#endif
.ToArray();
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
@ -106,23 +120,23 @@
// 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 IEnumerable<ImmutableStack<Vector<byte>>> GenerateUnorderedSequences(Vector<byte> remainder, int allowedRemainingWords, ImmutableStack<Vector<byte>> dictionaryStack) private IEnumerable<ImmutableStack<Vector<byte>>> GenerateUnorderedSequences(Vector<byte> remainder, int allowedRemainingWords, int currentDictionaryPosition)
{ {
#if !SUPPORT_LARGE_STRINGS
var remainderNorm = Vector.Dot(remainder, this.TargetComplement);
#endif
if (allowedRemainingWords > 1) if (allowedRemainingWords > 1)
{ {
var newAllowedRemainingWords = allowedRemainingWords - 1; var newAllowedRemainingWords = allowedRemainingWords - 1;
#if !SUPPORT_LARGE_STRINGS #if !SUPPORT_LARGE_STRINGS
// e.g. if remainder norm is 7, 8 or 9, and allowedRemainingWords is 3, // e.g. if remainder norm is 7, 8 or 9, and allowedRemainingWords is 3,
// we need the largest remaining word to have a norm of at least 3 // we need the largest remaining word to have a norm of at least 3
var remainderNorm = Vector.Dot(remainder, this.TargetComplement);
var requiredRemainder = (remainderNorm + allowedRemainingWords - 1) / allowedRemainingWords; var requiredRemainder = (remainderNorm + allowedRemainingWords - 1) / allowedRemainingWords;
#endif #endif
var dictionaryTail = dictionaryStack; for (var i = currentDictionaryPosition; i < this.Dictionary.Length; i++)
while (!dictionaryTail.IsEmpty)
{ {
Vector<byte> currentVector; Vector<byte> currentVector = this.Dictionary[i].Vector;
var nextDictionaryTail = dictionaryTail.Pop(out currentVector);
this.DebugState(allowedRemainingWords, currentVector); this.DebugState(allowedRemainingWords, currentVector);
@ -131,7 +145,7 @@
yield return ImmutableStack.Create(currentVector); yield return ImmutableStack.Create(currentVector);
} }
#if !SUPPORT_LARGE_STRINGS #if !SUPPORT_LARGE_STRINGS
else if (Vector.Dot(currentVector, this.TargetComplement) < requiredRemainder) else if (this.Dictionary[i].Norm < requiredRemainder)
{ {
break; break;
} }
@ -139,30 +153,31 @@
else if (Vector.LessThanOrEqualAll(currentVector, remainder)) else if (Vector.LessThanOrEqualAll(currentVector, remainder))
{ {
var newRemainder = remainder - currentVector; var newRemainder = remainder - currentVector;
foreach (var result in this.GenerateUnorderedSequences(newRemainder, newAllowedRemainingWords, dictionaryTail)) foreach (var result in this.GenerateUnorderedSequences(newRemainder, newAllowedRemainingWords, i))
{ {
yield return result.Push(currentVector); yield return result.Push(currentVector);
} }
} }
dictionaryTail = nextDictionaryTail;
} }
} }
else else
{ {
var dictionaryTail = dictionaryStack; for (var i = currentDictionaryPosition; i < this.Dictionary.Length; i++)
while (!dictionaryTail.IsEmpty)
{ {
Vector<byte> currentVector; Vector<byte> currentVector = this.Dictionary[i].Vector;
dictionaryTail = dictionaryTail.Pop(out currentVector);
this.DebugState(allowedRemainingWords, currentVector); this.DebugState(allowedRemainingWords, currentVector);
var newRemainder = remainder - currentVector; if (currentVector == remainder)
if (newRemainder == Vector<byte>.Zero)
{ {
yield return ImmutableStack.Create(currentVector); yield return ImmutableStack.Create(currentVector);
} }
#if !SUPPORT_LARGE_STRINGS
else if (this.Dictionary[i].Norm < remainderNorm)
{
break;
}
#endif
} }
} }
} }
@ -174,5 +189,18 @@
yield return permutation.Select(i => original[i]).ToArray(); yield return permutation.Select(i => original[i]).ToArray();
} }
} }
private struct VectorInfo
{
public VectorInfo(Vector<byte> vector, byte norm)
{
this.Vector = vector;
this.Norm = norm;
}
public Vector<byte> Vector { get; }
public byte Norm { get; }
}
} }
} }

Loading…
Cancel
Save