using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Amphora.RandomComparisons
{
///
/// How much work each check does, so a quick run and a full one differ only in size.
///
public sealed class Scale
{
public readonly int Divisor;
public Scale(int divisor)
{
Divisor = divisor;
}
public long Count(long full, long minimum)
{
return Math.Max(minimum, full / Divisor);
}
public int Count(int full, int minimum)
{
return Math.Max(minimum, full / Divisor);
}
}
///
/// Runs every check on a subject.
///
public static class Battery
{
public const int BlockLength = 2000;
public static List Run(Subject subject, Scale scale, ulong seed)
{
var returnMe = new List();
Func fresh = () => new WordStream(subject.Make(seed));
returnMe.Add(new NamedOutcome("bit balance",
BitBalance.Run(fresh(), scale.Count(1L << 22, minimum: 1L << 18))));
var windows = new List { Window.High };
if (subject.HasLowWindow)
{
windows.Add(Window.Low);
}
foreach (Window window in windows)
{
string where = window == Window.High ? "high bits" : "low bits";
returnMe.Add(new NamedOutcome("serial, " + where,
SerialTest.Series(fresh(), window, scale.Count(1L << 23, minimum: 1L << 19))));
returnMe.Add(new NamedOutcome("birthday spacings 2^28, " + where, BirthdaySpacings.Run(fresh(), window,
dayBits: 28, birthdays: 2048, samples: scale.Count(1 << 13, minimum: 1 << 10))));
returnMe.Add(new NamedOutcome("birthday spacings 2^32, " + where, BirthdaySpacings.Run(fresh(), window,
dayBits: 32, birthdays: 4096, samples: scale.Count(1 << 12, minimum: 1 << 9))));
returnMe.Add(new NamedOutcome("binary rank 32x32, " + where,
BinaryRank.Run(fresh(), window, size: 32, matrices: scale.Count(1L << 17, minimum: 1L << 14))));
returnMe.Add(new NamedOutcome("linear complexity, " + where, LinearComplexity.Run(fresh(), window,
BlockLength, blocks: scale.Count(1000, minimum: 125))));
}
if (subject.HasLowWindow)
{
returnMe.Add(new NamedOutcome("binary rank 64x64", BinaryRank.Run(fresh(), Window.High, size: 64,
matrices: scale.Count(1L << 16, minimum: 1L << 13))));
}
if (subject.IsSingleStream)
{
foreach (Window window in windows)
{
returnMe.AddRange(AdjacentSeeds.Run(subject, window, firstSeed: 1,
seeds: scale.Count(1L << 21, minimum: 1L << 17)));
}
if (subject.StateBits > 0)
{
returnMe.Add(new NamedOutcome("recovery from single-bit states", SparseStateRecovery.Run(subject)));
}
}
if (subject.BoundedChecks != null)
{
returnMe.AddRange(subject.BoundedChecks(seed, scale));
}
return returnMe;
}
///
/// Runs every subject on its own thread, and returns the outcomes in the subjects' order.
///
public static List[] RunAll(IReadOnlyList subjects, Scale scale, ulong seed,
Action onFinished)
{
var returnMe = new List[subjects.Count];
var options = new ParallelOptions { MaxDegreeOfParallelism = Math.Max(1, Environment.ProcessorCount - 1) };
Parallel.For(0, subjects.Count, options, index =>
{
returnMe[index] = Run(subjects[index], scale, seed);
onFinished(subjects[index]);
});
return returnMe;
}
}
}