public void Binomial(float p) { var weightSum = 0f; var itemWeights = new float[10]; var n = itemWeights.Length - 1; for (var i = 0; i < itemWeights.Length; i++) { itemWeights[i] = (float)Stat.BinomialDistributionMass(i, n, p); weightSum += itemWeights[i]; } var seed = (uint)Environment.TickCount; var random = new SimpleRandom { Seed = seed }; var selectedCounts = new int[itemWeights.Length]; var selectionCount = 500000; for (var i = 0; i < selectionCount; i++) { var selectedIndex = random.NextBinomial(p, n); selectedCounts[selectedIndex]++; } AssertDistribution(itemWeights, weightSum, selectedCounts, selectionCount, seed); }
public void NoStreakBool(int p) { var itemWeights = new[] { p, 100f - p }; var maxPositiveStreak = 2; var maxNegativeStreak = 2; if (p == 0) { maxPositiveStreak = 0; maxNegativeStreak = int.MaxValue; } else if (p == 100) { maxPositiveStreak = int.MaxValue; maxNegativeStreak = 0; } else if (p > 50) { maxPositiveStreak = (int)Math.Ceiling((100f / (100 - p)) - 1) * 2; } else { maxNegativeStreak = (int)Math.Ceiling((100f / p) - 1) * 2; } var seed = (uint)Environment.TickCount; var random = new SimpleRandom { Seed = seed }; var selectedCounts = new int[itemWeights.Length]; var selectionCount = 500000; var entropy = 0; var positiveStreak = 0; var negativeStreak = 0; for (var i = 0; i < selectionCount; i++) { var result = random.NextBool(p, ref entropy); if (result) { selectedCounts[0]++; positiveStreak++; Assert.True(negativeStreak <= maxNegativeStreak, $"Found negative streak of length {negativeStreak} at {i} for seed {seed}. Max streak expected {maxNegativeStreak}."); negativeStreak = 0; } else { selectedCounts[1]++; negativeStreak++; Assert.True(positiveStreak <= maxPositiveStreak, $"Found positive streak of length {positiveStreak} at {i} for seed {seed}. Max streak expected {maxPositiveStreak}."); positiveStreak = 0; } } AssertDistribution(itemWeights, 100f, selectedCounts, selectionCount, seed); }
public void Pick_predicate() { var weightSum = 0f; var items = new float[10]; for (var i = 0; i < items.Length; i++) { items[i] = 1; weightSum += items[i]; } var seed = (uint)Environment.TickCount; var random = new SimpleRandom { Seed = seed }; var selectedCounts = new int[items.Length]; var selectionCount = 10000; for (var i = 0; i < selectionCount; i++) { var orderedItems = random.WeightedOrder(items, f => f, (f, index) => (f, index)); var selectedIndex = orderedItems.First(tuple => tuple.index % 2 == 0).index; selectedCounts[selectedIndex]++; } var tolerance = 1.5 * items.Length / Math.Sqrt(selectionCount); for (var i = 0; i < items.Length; i++) { var expected = i % 2 == 0 ? 2.0 * items[i] / weightSum : 0; var actual = (double)selectedCounts[i] / selectionCount; if (!(Math.Abs(expected - actual) <= tolerance * expected)) { var builder = new StringBuilder(); builder.Append( $"Expected {expected}, actual {actual}, tolerance {tolerance * expected} at index {i}, seed {seed}"); builder.AppendLine("\tIndex:\tfrequency,\tweight:"); for (var j = 0; j < items.Length; j++) { builder.AppendLine($"\t{j}:\t{selectedCounts[j]},\t{items[j]}"); } Assert.False(true, builder.ToString()); } } }
private void TestPick(float[] itemWeights, float weightSum) { var seed = (uint)Environment.TickCount; var random = new SimpleRandom { Seed = seed }; var selectedCounts = new int[itemWeights.Length]; var selectionCount = 100000; for (var i = 0; i < selectionCount; i++) { var selectedIndex = random.Pick(itemWeights, f => f, (_, index) => index); selectedCounts[selectedIndex]++; } AssertDistribution(itemWeights, weightSum, selectedCounts, selectionCount, seed); }