in commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/CompositeSamplers.java [445:488]
private DiscreteSampler createDiscreteSampler(UniformRandomProvider rng,
double[] weights) {
// Edge case. Detect uniform weights.
final int n = weights.length;
if (uniform(weights)) {
// Uniformly sample from the size.
// Note: Upper bound is inclusive.
return DiscreteUniformSampler.of(rng, 0, n - 1);
}
// If possible normalise with a simple sum.
final double sum = sum(weights);
if (sum < Double.POSITIVE_INFINITY) {
// Do not use f = 1.0 / sum and multiplication by f.
// Use of divide handles a sub-normal sum.
for (int i = 0; i < n; i++) {
weights[i] /= sum;
}
} else {
// The sum is not finite. We know the weights are all positive finite.
// Compute the mean without overflow and divide by the mean and number of items.
final double mean = mean(weights);
for (int i = 0; i < n; i++) {
// Two step division avoids using the denominator (mean * n)
weights[i] = weights[i] / mean / n;
}
}
// Create the sampler from the factory.
// Check if a SharedStateSampler is required.
// If a default factory then the result is a SharedStateDiscreteSampler,
// otherwise the sampler must be checked.
if (specialisation == Specialisation.SHARED_STATE_SAMPLER &&
!(factory instanceof DiscreteProbabilitySampler)) {
// If the factory was user-defined then clone the weights as they may be required
// to create a SharedStateDiscreteProbabilitySampler.
final DiscreteSampler sampler = factory.create(rng, weights.clone());
return sampler instanceof SharedStateDiscreteSampler ?
sampler :
new SharedStateDiscreteProbabilitySampler(sampler, factory, weights);
}
return factory.create(rng, weights);
}