/// <summary>
        /// Measures the predictablity of hashes generated using a given algorithm and reference data.
        /// </summary>
        /// <returns>The distance the observed entropy is from perfect. Lower is better.</returns>
        public double Predictability()
        {
            int total = 0;

            for (int i = 0; i < this.toggleBits; i++)
            {
                this.Toggle(i);
                int delta = this.hash.GetHashCode(this.target);
                int diff  = Avalanche.HammingDistance(this.reference, delta);
                total += diff;
            }

            this.grandTotal += total;
            return(Avalanche.Predictability(total, this.limit));
        }
        public void AffineHash_Hash_Measure_Avalanche()
        {
            Random random = new Random();
            var    cases  = new[]
            {
                new { name = "zeroes", source = Enumerable.Repeat((byte)0x00, 100).ToArray() },
                new { name = "ones", source = Enumerable.Repeat((byte)0xFF, 100).ToArray() },
                new { name = "alternating-right", source = Enumerable.Repeat((byte)0x55, 100).ToArray() },
                new { name = "alternating-left", source = Enumerable.Repeat((byte)0xAA, 100).ToArray() },
                new { name = "random", source = Enumerable.Repeat(default(byte), 100).Select(b => (byte)random.Next()).ToArray() },
            };
            Avalanche avalanche = new Avalanche();

            this.TestContext.WriteLine("power,predictability,scale,shift");
            for (int trial = 0; trial < 10000; trial++)
            {
                AffineHash target = new AffineHash(random);
                avalanche.Reset(target);
                bool strong = true;
                bool weak   = false;
                foreach (var c in cases)
                {
                    avalanche.Next(c.source);
                    double predictability = avalanche.Predictability();
                    if (predictability > 0.1)
                    {
                        strong = false;
                    }

                    if (predictability > 0.2)
                    {
                        weak = true;
                    }
                }

                if (strong)
                {
                    double predictability = avalanche.Finish();
                    this.TestContext.WriteLine("strong,{0},{1},{2}", predictability, target.Scale, target.Shift);
                }

                if (weak)
                {
                    double predictability = avalanche.Finish();
                    this.TestContext.WriteLine("weak,{0},{1},{2}", predictability, target.Scale, target.Shift);
                }
            }
        }
 /// <summary>
 /// Finishes the avalanche series for a given algorithm.
 /// </summary>
 /// <returns>The distance the observed entropy is from perfect. Lower is better.</returns>
 public double Finish()
 {
     return(Avalanche.Predictability(this.grandTotal, this.grandLimit));
 }