in commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/GuideTableDiscreteSampler.java [146:194]
public static SharedStateDiscreteSampler of(UniformRandomProvider rng,
double[] probabilities,
double alpha) {
validateParameters(probabilities, alpha);
final int size = probabilities.length;
final double[] cumulativeProbabilities = new double[size];
double sumProb = 0;
int count = 0;
for (final double prob : probabilities) {
// Compute and store cumulative probability.
sumProb += InternalUtils.requirePositiveFinite(prob, "probability");
cumulativeProbabilities[count++] = sumProb;
}
InternalUtils.requireStrictlyPositiveFinite(sumProb, "sum of probabilities");
// Note: The guide table is at least length 1. Compute the size avoiding overflow
// in case (alpha * size) is too large.
final int guideTableSize = (int) Math.ceil(alpha * size);
final int[] guideTable = new int[Math.max(guideTableSize, guideTableSize + 1)];
// Compute and store cumulative probability.
for (int x = 0; x < size; x++) {
final double norm = cumulativeProbabilities[x] / sumProb;
cumulativeProbabilities[x] = (norm < 1) ? norm : 1.0;
// Set the guide table value as an exclusive upper bound (x + 1)
final int index = getGuideTableIndex(cumulativeProbabilities[x], guideTable.length);
guideTable[index] = x + 1;
}
// Edge case for round-off
cumulativeProbabilities[size - 1] = 1.0;
// The final guide table entry is (maximum value of x + 1)
guideTable[guideTable.length - 1] = size;
// The first non-zero value in the guide table is from f(x=0).
// Any probabilities mapped below this must be sample x=0 so the
// table may initially be filled with zeros.
// Fill missing values in the guide table.
for (int i = 1; i < guideTable.length; i++) {
guideTable[i] = Math.max(guideTable[i - 1], guideTable[i]);
}
return new GuideTableDiscreteSampler(rng, cumulativeProbabilities, guideTable);
}