/// <summary>
/// Sample from the provided discrete probability distribution.
/// </summary>
/// <param name="dist">The discrete distribution to sample from.</param>
/// <param name="rng">Random number generator.</param>
public static int Sample(DiscreteDistribution dist, XorShiftRandom rng)
{
// Throw the ball and return an integer indicating the outcome.
double sample = rng.NextDouble();
double acc = 0.0;
for(int i=0; i<dist.Probabilities.Length; i++)
{
acc += dist.Probabilities[i];
if(sample < acc) {
return dist.Labels[i];
}
}
// We might get here through floating point arithmetic rounding issues.
// e.g. accumulator == throwValue.
// Find a nearby non-zero probability to select.
// Wrap around to start of array.
for(int i=0; i<dist.Probabilities.Length; i++)
{
if(0.0 != dist.Probabilities[i]) {
return dist.Labels[i];
}
}
// If we get here then we have an array of zero probabilities.
throw new InvalidOperationException("Invalid operation. No non-zero probabilities to select.");
}