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; } } }