MATH-1158
Removed deprecated sampling API (and constructors). In this pass, the integer distributions have been updated. Class "RandomDataGenerator" has been reverted to use the old RNG implementation (a wrapper is created whenever it must be passed to a distribution's "createSampler" method).
This commit is contained in:
parent
77c24aa926
commit
ae2c81ad18
|
@ -19,11 +19,10 @@ package org.apache.commons.math4.distribution;
|
|||
import java.io.Serializable;
|
||||
|
||||
import org.apache.commons.math4.exception.MathInternalError;
|
||||
import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
||||
import org.apache.commons.math4.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math4.exception.OutOfRangeException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.rng.UniformRandomProvider;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
|
||||
/**
|
||||
|
@ -33,23 +32,8 @@ import org.apache.commons.math4.util.FastMath;
|
|||
*
|
||||
*/
|
||||
public abstract class AbstractIntegerDistribution implements IntegerDistribution, Serializable {
|
||||
|
||||
/** Serializable version identifier */
|
||||
private static final long serialVersionUID = -1146319659338487221L;
|
||||
|
||||
/**
|
||||
* RNG instance used to generate samples from the distribution.
|
||||
* @since 3.1
|
||||
*/
|
||||
protected final RandomGenerator random;
|
||||
|
||||
/**
|
||||
* @param rng Random number generator.
|
||||
* @since 3.1
|
||||
*/
|
||||
protected AbstractIntegerDistribution(RandomGenerator rng) {
|
||||
random = rng;
|
||||
}
|
||||
private static final long serialVersionUID = 20160318L;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -159,43 +143,6 @@ public abstract class AbstractIntegerDistribution implements IntegerDistribution
|
|||
return upper;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void reseedRandomGenerator(long seed) {
|
||||
random.setSeed(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* The default implementation uses the
|
||||
* <a href="http://en.wikipedia.org/wiki/Inverse_transform_sampling">
|
||||
* inversion method</a>.
|
||||
*/
|
||||
@Override
|
||||
public int sample() {
|
||||
return inverseCumulativeProbability(random.nextDouble());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* The default implementation generates the sample by calling
|
||||
* {@link #sample()} in a loop.
|
||||
*/
|
||||
@Override
|
||||
public int[] sample(int sampleSize) {
|
||||
if (sampleSize <= 0) {
|
||||
throw new NotStrictlyPositiveException(
|
||||
LocalizedFormats.NUMBER_OF_SAMPLES, sampleSize);
|
||||
}
|
||||
int[] out = new int[sampleSize];
|
||||
for (int i = 0; i < sampleSize; i++) {
|
||||
out[i] = sample();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the cumulative probability function and checks for {@code NaN}
|
||||
* values returned. Throws {@code MathInternalError} if the value is
|
||||
|
@ -227,4 +174,33 @@ public abstract class AbstractIntegerDistribution implements IntegerDistribution
|
|||
public double logProbability(int x) {
|
||||
return FastMath.log(probability(x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for allocating an array and filling it with {@code n}
|
||||
* samples generated by the given {@code sampler}.
|
||||
*
|
||||
* @param n Number of samples.
|
||||
* @param sampler Sampler.
|
||||
* @return an array of size {@code n}.
|
||||
*/
|
||||
public static int[] sample(int n,
|
||||
IntegerDistribution.Sampler sampler) {
|
||||
final int[] samples = new int[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
samples[i] = sampler.sample();
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
/**{@inheritDoc} */
|
||||
@Override
|
||||
public IntegerDistribution.Sampler createSampler(final UniformRandomProvider rng) {
|
||||
return new IntegerDistribution.Sampler() {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int sample() {
|
||||
return inverseCumulativeProbability(rng.nextDouble());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ package org.apache.commons.math4.distribution;
|
|||
import org.apache.commons.math4.exception.NotPositiveException;
|
||||
import org.apache.commons.math4.exception.OutOfRangeException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well19937c;
|
||||
import org.apache.commons.math4.special.Beta;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
|
||||
|
@ -38,41 +36,16 @@ public class BinomialDistribution extends AbstractIntegerDistribution {
|
|||
/** The probability of success. */
|
||||
private final double probabilityOfSuccess;
|
||||
|
||||
/**
|
||||
* Create a binomial distribution with the given number of trials and
|
||||
* probability of success.
|
||||
* <p>
|
||||
* <b>Note:</b> this constructor will implicitly create an instance of
|
||||
* {@link Well19937c} as random generator to be used for sampling only (see
|
||||
* {@link #sample()} and {@link #sample(int)}). In case no sampling is
|
||||
* needed for the created distribution, it is advised to pass {@code null}
|
||||
* as random generator via the appropriate constructors to avoid the
|
||||
* additional initialisation overhead.
|
||||
*
|
||||
* @param trials Number of trials.
|
||||
* @param p Probability of success.
|
||||
* @throws NotPositiveException if {@code trials < 0}.
|
||||
* @throws OutOfRangeException if {@code p < 0} or {@code p > 1}.
|
||||
*/
|
||||
public BinomialDistribution(int trials, double p) {
|
||||
this(new Well19937c(), trials, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a binomial distribution.
|
||||
*
|
||||
* @param rng Random number generator.
|
||||
* @param trials Number of trials.
|
||||
* @param p Probability of success.
|
||||
* @throws NotPositiveException if {@code trials < 0}.
|
||||
* @throws OutOfRangeException if {@code p < 0} or {@code p > 1}.
|
||||
* @since 3.1
|
||||
*/
|
||||
public BinomialDistribution(RandomGenerator rng,
|
||||
int trials,
|
||||
public BinomialDistribution(int trials,
|
||||
double p) {
|
||||
super(rng);
|
||||
|
||||
if (trials < 0) {
|
||||
throw new NotPositiveException(LocalizedFormats.NUMBER_OF_TRIALS,
|
||||
trials);
|
||||
|
|
|
@ -29,7 +29,6 @@ import org.apache.commons.math4.exception.NotPositiveException;
|
|||
import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
||||
import org.apache.commons.math4.exception.NullArgumentException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.rng.UniformRandomProvider;
|
||||
import org.apache.commons.math4.util.MathArrays;
|
||||
import org.apache.commons.math4.util.Pair;
|
||||
|
@ -52,69 +51,23 @@ import org.apache.commons.math4.util.Pair;
|
|||
* @since 3.2
|
||||
*/
|
||||
public class EnumeratedDistribution<T> implements Serializable {
|
||||
|
||||
/** Serializable UID. */
|
||||
private static final long serialVersionUID = 20123308L;
|
||||
|
||||
/**
|
||||
* RNG instance used to generate samples from the distribution.
|
||||
*/
|
||||
@Deprecated
|
||||
protected RandomGenerator random = null;
|
||||
|
||||
private static final long serialVersionUID = 20160319L;
|
||||
/**
|
||||
* List of random variable values.
|
||||
*/
|
||||
private final List<T> singletons;
|
||||
|
||||
/**
|
||||
* Probabilities of respective random variable values. For i = 0, ..., singletons.size() - 1,
|
||||
* probability[i] is the probability that a random variable following this distribution takes
|
||||
* the value singletons[i].
|
||||
*/
|
||||
private final double[] probabilities;
|
||||
|
||||
/**
|
||||
* Cumulative probabilities, cached to speed up sampling.
|
||||
*/
|
||||
private final double[] cumulativeProbabilities;
|
||||
|
||||
/**
|
||||
* XXX TODO: remove once "EnumeratedIntegerDistribution" has been changed.
|
||||
*/
|
||||
@Deprecated
|
||||
public EnumeratedDistribution(final RandomGenerator rng, final List<Pair<T, Double>> pmf)
|
||||
throws NotPositiveException, MathArithmeticException, NotFiniteNumberException, NotANumberException {
|
||||
random = rng;
|
||||
singletons = new ArrayList<T>(pmf.size());
|
||||
final double[] probs = new double[pmf.size()];
|
||||
|
||||
for (int i = 0; i < pmf.size(); i++) {
|
||||
final Pair<T, Double> sample = pmf.get(i);
|
||||
singletons.add(sample.getKey());
|
||||
final double p = sample.getValue();
|
||||
if (p < 0) {
|
||||
throw new NotPositiveException(sample.getValue());
|
||||
}
|
||||
if (Double.isInfinite(p)) {
|
||||
throw new NotFiniteNumberException(p);
|
||||
}
|
||||
if (Double.isNaN(p)) {
|
||||
throw new NotANumberException();
|
||||
}
|
||||
probs[i] = p;
|
||||
}
|
||||
|
||||
probabilities = MathArrays.normalizeArray(probs, 1.0);
|
||||
|
||||
cumulativeProbabilities = new double[probabilities.length];
|
||||
double sum = 0;
|
||||
for (int i = 0; i < probabilities.length; i++) {
|
||||
sum += probabilities[i];
|
||||
cumulativeProbabilities[i] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an enumerated distribution using the given random number generator
|
||||
* and probability mass function enumeration.
|
||||
|
@ -160,16 +113,6 @@ public class EnumeratedDistribution<T> implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseed the random generator used to generate samples.
|
||||
*
|
||||
* @param seed the new seed
|
||||
*/
|
||||
@Deprecated
|
||||
public void reseedRandomGenerator(long seed) {
|
||||
random.setSeed(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>For a random variable {@code X} whose values are distributed according to
|
||||
* this distribution, this method returns {@code P(X = x)}. In other words,
|
||||
|
@ -215,97 +158,6 @@ public class EnumeratedDistribution<T> implements Serializable {
|
|||
return samples;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random value sampled from this distribution.
|
||||
*
|
||||
* @return a random value.
|
||||
*/
|
||||
@Deprecated
|
||||
public T sample() {
|
||||
final double randomValue = random.nextDouble();
|
||||
|
||||
int index = Arrays.binarySearch(cumulativeProbabilities, randomValue);
|
||||
if (index < 0) {
|
||||
index = -index-1;
|
||||
}
|
||||
|
||||
if (index >= 0 &&
|
||||
index < probabilities.length &&
|
||||
randomValue < cumulativeProbabilities[index]) {
|
||||
return singletons.get(index);
|
||||
}
|
||||
|
||||
/* This should never happen, but it ensures we will return a correct
|
||||
* object in case there is some floating point inequality problem
|
||||
* wrt the cumulative probabilities. */
|
||||
return singletons.get(singletons.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random sample from the distribution.
|
||||
*
|
||||
* @param sampleSize the number of random values to generate.
|
||||
* @return an array representing the random sample.
|
||||
* @throws NotStrictlyPositiveException if {@code sampleSize} is not
|
||||
* positive.
|
||||
*/
|
||||
@Deprecated
|
||||
public Object[] sample(int sampleSize) throws NotStrictlyPositiveException {
|
||||
if (sampleSize <= 0) {
|
||||
throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_SAMPLES,
|
||||
sampleSize);
|
||||
}
|
||||
|
||||
final Object[] out = new Object[sampleSize];
|
||||
|
||||
for (int i = 0; i < sampleSize; i++) {
|
||||
out[i] = sample();
|
||||
}
|
||||
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random sample from the distribution.
|
||||
* <p>
|
||||
* If the requested samples fit in the specified array, it is returned
|
||||
* therein. Otherwise, a new array is allocated with the runtime type of
|
||||
* the specified array and the size of this collection.
|
||||
*
|
||||
* @param sampleSize the number of random values to generate.
|
||||
* @param array the array to populate.
|
||||
* @return an array representing the random sample.
|
||||
* @throws NotStrictlyPositiveException if {@code sampleSize} is not positive.
|
||||
* @throws NullArgumentException if {@code array} is null
|
||||
*/
|
||||
@Deprecated
|
||||
public T[] sample(int sampleSize, final T[] array) throws NotStrictlyPositiveException {
|
||||
if (sampleSize <= 0) {
|
||||
throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_SAMPLES, sampleSize);
|
||||
}
|
||||
|
||||
if (array == null) {
|
||||
throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
|
||||
}
|
||||
|
||||
T[] out;
|
||||
if (array.length < sampleSize) {
|
||||
@SuppressWarnings("unchecked") // safe as both are of type T
|
||||
final T[] unchecked = (T[]) Array.newInstance(array.getClass().getComponentType(), sampleSize);
|
||||
out = unchecked;
|
||||
} else {
|
||||
out = array;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sampleSize; i++) {
|
||||
out[i] = sample();
|
||||
}
|
||||
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Sampler}.
|
||||
*
|
||||
|
|
|
@ -27,8 +27,7 @@ import org.apache.commons.math4.exception.MathArithmeticException;
|
|||
import org.apache.commons.math4.exception.NotANumberException;
|
||||
import org.apache.commons.math4.exception.NotFiniteNumberException;
|
||||
import org.apache.commons.math4.exception.NotPositiveException;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well19937c;
|
||||
import org.apache.commons.math4.rng.UniformRandomProvider;
|
||||
import org.apache.commons.math4.util.Pair;
|
||||
|
||||
/**
|
||||
|
@ -42,10 +41,8 @@ import org.apache.commons.math4.util.Pair;
|
|||
* @since 3.2
|
||||
*/
|
||||
public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
|
||||
|
||||
/** Serializable UID. */
|
||||
private static final long serialVersionUID = 20130308L;
|
||||
|
||||
/**
|
||||
* {@link EnumeratedDistribution} instance (using the {@link Integer} wrapper)
|
||||
* used to generate the pmf.
|
||||
|
@ -53,15 +50,7 @@ public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
|
|||
protected final EnumeratedDistribution<Integer> innerDistribution;
|
||||
|
||||
/**
|
||||
* Create a discrete distribution using the given probability mass function
|
||||
* definition.
|
||||
* <p>
|
||||
* <b>Note:</b> this constructor will implicitly create an instance of
|
||||
* {@link Well19937c} as random generator to be used for sampling only (see
|
||||
* {@link #sample()} and {@link #sample(int)}). In case no sampling is
|
||||
* needed for the created distribution, it is advised to pass {@code null}
|
||||
* as random generator via the appropriate constructors to avoid the
|
||||
* additional initialisation overhead.
|
||||
* Create a discrete distribution.
|
||||
*
|
||||
* @param singletons array of random variable values.
|
||||
* @param probabilities array of probabilities.
|
||||
|
@ -72,45 +61,24 @@ public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
|
|||
* @throws NotANumberException if any of the probabilities are NaN.
|
||||
* @throws MathArithmeticException all of the probabilities are 0.
|
||||
*/
|
||||
public EnumeratedIntegerDistribution(final int[] singletons, final double[] probabilities)
|
||||
throws DimensionMismatchException, NotPositiveException, MathArithmeticException,
|
||||
NotFiniteNumberException, NotANumberException{
|
||||
this(new Well19937c(), singletons, probabilities);
|
||||
public EnumeratedIntegerDistribution(final int[] singletons,
|
||||
final double[] probabilities)
|
||||
throws DimensionMismatchException,
|
||||
NotPositiveException,
|
||||
MathArithmeticException,
|
||||
NotFiniteNumberException,
|
||||
NotANumberException {
|
||||
innerDistribution = new EnumeratedDistribution<Integer>(createDistribution(singletons,
|
||||
probabilities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a discrete distribution using the given random number generator
|
||||
* and probability mass function definition.
|
||||
* Create a discrete integer-valued distribution from the input data.
|
||||
* Values are assigned mass based on their frequency.
|
||||
*
|
||||
* @param rng random number generator.
|
||||
* @param singletons array of random variable values.
|
||||
* @param probabilities array of probabilities.
|
||||
* @throws DimensionMismatchException if
|
||||
* {@code singletons.length != probabilities.length}
|
||||
* @throws NotPositiveException if any of the probabilities are negative.
|
||||
* @throws NotFiniteNumberException if any of the probabilities are infinite.
|
||||
* @throws NotANumberException if any of the probabilities are NaN.
|
||||
* @throws MathArithmeticException all of the probabilities are 0.
|
||||
*/
|
||||
public EnumeratedIntegerDistribution(final RandomGenerator rng,
|
||||
final int[] singletons, final double[] probabilities)
|
||||
throws DimensionMismatchException, NotPositiveException, MathArithmeticException,
|
||||
NotFiniteNumberException, NotANumberException {
|
||||
super(rng);
|
||||
innerDistribution = new EnumeratedDistribution<Integer>(
|
||||
rng, createDistribution(singletons, probabilities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a discrete integer-valued distribution from the input data. Values are assigned
|
||||
* mass based on their frequency.
|
||||
*
|
||||
* @param rng random number generator used for sampling
|
||||
* @param data input dataset
|
||||
* #since 3.6
|
||||
*/
|
||||
public EnumeratedIntegerDistribution(final RandomGenerator rng, final int[] data) {
|
||||
super(rng);
|
||||
public EnumeratedIntegerDistribution(final int[] data) {
|
||||
final Map<Integer, Integer> dataMap = new HashMap<Integer, Integer>();
|
||||
for (int value : data) {
|
||||
Integer count = dataMap.get(value);
|
||||
|
@ -129,19 +97,7 @@ public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
|
|||
probabilities[index] = entry.getValue().intValue() / denom;
|
||||
index++;
|
||||
}
|
||||
innerDistribution = new EnumeratedDistribution<Integer>(rng, createDistribution(values, probabilities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a discrete integer-valued distribution from the input data. Values are assigned
|
||||
* mass based on their frequency. For example, [0,1,1,2] as input creates a distribution
|
||||
* with values 0, 1 and 2 having probability masses 0.25, 0.5 and 0.25 respectively,
|
||||
*
|
||||
* @param data input dataset
|
||||
* @since 3.6
|
||||
*/
|
||||
public EnumeratedIntegerDistribution(final int[] data) {
|
||||
this(new Well19937c(), data);
|
||||
innerDistribution = new EnumeratedDistribution<Integer>(createDistribution(values, probabilities));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,7 +118,6 @@ public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
|
|||
samples.add(new Pair<Integer, Double>(singletons[i], probabilities[i]));
|
||||
}
|
||||
return samples;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -273,11 +228,19 @@ public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int sample() {
|
||||
return innerDistribution.sample();
|
||||
public IntegerDistribution.Sampler createSampler(final UniformRandomProvider rng) {
|
||||
return new IntegerDistribution.Sampler() {
|
||||
/** Delegate. */
|
||||
private final EnumeratedDistribution<Integer>.Sampler inner =
|
||||
innerDistribution.createSampler(rng);
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int sample() {
|
||||
return inner.sample();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@ package org.apache.commons.math4.distribution;
|
|||
|
||||
import org.apache.commons.math4.exception.OutOfRangeException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well19937c;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
|
||||
/**
|
||||
|
@ -32,7 +30,7 @@ import org.apache.commons.math4.util.FastMath;
|
|||
public class GeometricDistribution extends AbstractIntegerDistribution {
|
||||
|
||||
/** Serializable version identifier. */
|
||||
private static final long serialVersionUID = 20130507L;
|
||||
private static final long serialVersionUID = 20160318L;
|
||||
/** The probability of success. */
|
||||
private final double probabilityOfSuccess;
|
||||
/** {@code log(p)} where p is the probability of success. */
|
||||
|
@ -40,33 +38,13 @@ public class GeometricDistribution extends AbstractIntegerDistribution {
|
|||
/** {@code log(1 - p)} where p is the probability of success. */
|
||||
private final double log1mProbabilityOfSuccess;
|
||||
|
||||
/**
|
||||
* Create a geometric distribution with the given probability of success.
|
||||
* <p>
|
||||
* <b>Note:</b> this constructor will implicitly create an instance of
|
||||
* {@link Well19937c} as random generator to be used for sampling only (see
|
||||
* {@link #sample()} and {@link #sample(int)}). In case no sampling is
|
||||
* needed for the created distribution, it is advised to pass {@code null}
|
||||
* as random generator via the appropriate constructors to avoid the
|
||||
* additional initialisation overhead.
|
||||
*
|
||||
* @param p probability of success.
|
||||
* @throws OutOfRangeException if {@code p <= 0} or {@code p > 1}.
|
||||
*/
|
||||
public GeometricDistribution(double p) {
|
||||
this(new Well19937c(), p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a geometric distribution.
|
||||
*
|
||||
* @param rng Random number generator.
|
||||
* @param p Probability of success.
|
||||
* @throws OutOfRangeException if {@code p <= 0} or {@code p > 1}.
|
||||
*/
|
||||
public GeometricDistribution(RandomGenerator rng, double p) {
|
||||
super(rng);
|
||||
|
||||
public GeometricDistribution(double p) {
|
||||
if (p <= 0 || p > 1) {
|
||||
throw new OutOfRangeException(LocalizedFormats.OUT_OF_RANGE_LEFT, p, 0, 1);
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ import org.apache.commons.math4.exception.NotPositiveException;
|
|||
import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
||||
import org.apache.commons.math4.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well19937c;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
|
||||
/**
|
||||
|
@ -33,7 +31,7 @@ import org.apache.commons.math4.util.FastMath;
|
|||
*/
|
||||
public class HypergeometricDistribution extends AbstractIntegerDistribution {
|
||||
/** Serializable version identifier. */
|
||||
private static final long serialVersionUID = -436928820673516179L;
|
||||
private static final long serialVersionUID = 20160318L;
|
||||
/** The number of successes in the population. */
|
||||
private final int numberOfSuccesses;
|
||||
/** The population size. */
|
||||
|
@ -45,34 +43,9 @@ public class HypergeometricDistribution extends AbstractIntegerDistribution {
|
|||
/** Whether or not the numerical variance has been calculated */
|
||||
private boolean numericalVarianceIsCalculated = false;
|
||||
|
||||
/**
|
||||
* Construct a new hypergeometric distribution with the specified population
|
||||
* size, number of successes in the population, and sample size.
|
||||
* <p>
|
||||
* <b>Note:</b> this constructor will implicitly create an instance of
|
||||
* {@link Well19937c} as random generator to be used for sampling only (see
|
||||
* {@link #sample()} and {@link #sample(int)}). In case no sampling is
|
||||
* needed for the created distribution, it is advised to pass {@code null}
|
||||
* as random generator via the appropriate constructors to avoid the
|
||||
* additional initialisation overhead.
|
||||
*
|
||||
* @param populationSize Population size.
|
||||
* @param numberOfSuccesses Number of successes in the population.
|
||||
* @param sampleSize Sample size.
|
||||
* @throws NotPositiveException if {@code numberOfSuccesses < 0}.
|
||||
* @throws NotStrictlyPositiveException if {@code populationSize <= 0}.
|
||||
* @throws NumberIsTooLargeException if {@code numberOfSuccesses > populationSize},
|
||||
* or {@code sampleSize > populationSize}.
|
||||
*/
|
||||
public HypergeometricDistribution(int populationSize, int numberOfSuccesses, int sampleSize)
|
||||
throws NotPositiveException, NotStrictlyPositiveException, NumberIsTooLargeException {
|
||||
this(new Well19937c(), populationSize, numberOfSuccesses, sampleSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new hypergeometric distribution.
|
||||
*
|
||||
* @param rng Random number generator.
|
||||
* @param populationSize Population size.
|
||||
* @param numberOfSuccesses Number of successes in the population.
|
||||
* @param sampleSize Sample size.
|
||||
|
@ -80,15 +53,13 @@ public class HypergeometricDistribution extends AbstractIntegerDistribution {
|
|||
* @throws NotStrictlyPositiveException if {@code populationSize <= 0}.
|
||||
* @throws NumberIsTooLargeException if {@code numberOfSuccesses > populationSize},
|
||||
* or {@code sampleSize > populationSize}.
|
||||
* @since 3.1
|
||||
*/
|
||||
public HypergeometricDistribution(RandomGenerator rng,
|
||||
int populationSize,
|
||||
public HypergeometricDistribution(int populationSize,
|
||||
int numberOfSuccesses,
|
||||
int sampleSize)
|
||||
throws NotPositiveException, NotStrictlyPositiveException, NumberIsTooLargeException {
|
||||
super(rng);
|
||||
|
||||
throws NotPositiveException,
|
||||
NotStrictlyPositiveException,
|
||||
NumberIsTooLargeException {
|
||||
if (populationSize <= 0) {
|
||||
throw new NotStrictlyPositiveException(LocalizedFormats.POPULATION_SIZE,
|
||||
populationSize);
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.commons.math4.distribution;
|
|||
|
||||
import org.apache.commons.math4.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math4.exception.OutOfRangeException;
|
||||
import org.apache.commons.math4.rng.UniformRandomProvider;
|
||||
|
||||
/**
|
||||
* Interface for distributions on the integers.
|
||||
|
@ -145,29 +146,23 @@ public interface IntegerDistribution {
|
|||
boolean isSupportConnected();
|
||||
|
||||
/**
|
||||
* Reseed the random generator used to generate samples.
|
||||
* Creates a sampler.
|
||||
*
|
||||
* @param seed the new seed
|
||||
* @since 3.0
|
||||
* @param rng Generator of uniformly distributed numbers.
|
||||
* @return a sampler that produces random numbers according this
|
||||
* distribution.
|
||||
*/
|
||||
void reseedRandomGenerator(long seed);
|
||||
Sampler createSampler(UniformRandomProvider rng);
|
||||
|
||||
/**
|
||||
* Generate a random value sampled from this distribution.
|
||||
*
|
||||
* @return a random value
|
||||
* @since 3.0
|
||||
* Sampling functionality.
|
||||
*/
|
||||
int sample();
|
||||
|
||||
/**
|
||||
* Generate a random sample from the distribution.
|
||||
*
|
||||
* @param sampleSize the number of random values to generate
|
||||
* @return an array representing the random sample
|
||||
* @throws org.apache.commons.math4.exception.NotStrictlyPositiveException
|
||||
* if {@code sampleSize} is not positive
|
||||
* @since 3.0
|
||||
*/
|
||||
int[] sample(int sampleSize);
|
||||
interface Sampler {
|
||||
/**
|
||||
* Generates a random value sampled from this distribution.
|
||||
*
|
||||
* @return a random value.
|
||||
*/
|
||||
int sample();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ package org.apache.commons.math4.distribution;
|
|||
import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
||||
import org.apache.commons.math4.exception.OutOfRangeException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well19937c;
|
||||
import org.apache.commons.math4.special.Beta;
|
||||
import org.apache.commons.math4.util.CombinatoricsUtils;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
|
@ -77,13 +75,6 @@ public class PascalDistribution extends AbstractIntegerDistribution {
|
|||
/**
|
||||
* Create a Pascal distribution with the given number of successes and
|
||||
* probability of success.
|
||||
* <p>
|
||||
* <b>Note:</b> this constructor will implicitly create an instance of
|
||||
* {@link Well19937c} as random generator to be used for sampling only (see
|
||||
* {@link #sample()} and {@link #sample(int)}). In case no sampling is
|
||||
* needed for the created distribution, it is advised to pass {@code null}
|
||||
* as random generator via the appropriate constructors to avoid the
|
||||
* additional initialisation overhead.
|
||||
*
|
||||
* @param r Number of successes.
|
||||
* @param p Probability of success.
|
||||
|
@ -91,29 +82,10 @@ public class PascalDistribution extends AbstractIntegerDistribution {
|
|||
* @throws OutOfRangeException if the probability of success is not in the
|
||||
* range {@code [0, 1]}.
|
||||
*/
|
||||
public PascalDistribution(int r, double p)
|
||||
throws NotStrictlyPositiveException, OutOfRangeException {
|
||||
this(new Well19937c(), r, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Pascal distribution with the given number of successes and
|
||||
* probability of success.
|
||||
*
|
||||
* @param rng Random number generator.
|
||||
* @param r Number of successes.
|
||||
* @param p Probability of success.
|
||||
* @throws NotStrictlyPositiveException if the number of successes is not positive
|
||||
* @throws OutOfRangeException if the probability of success is not in the
|
||||
* range {@code [0, 1]}.
|
||||
* @since 3.1
|
||||
*/
|
||||
public PascalDistribution(RandomGenerator rng,
|
||||
int r,
|
||||
public PascalDistribution(int r,
|
||||
double p)
|
||||
throws NotStrictlyPositiveException, OutOfRangeException {
|
||||
super(rng);
|
||||
|
||||
throws NotStrictlyPositiveException,
|
||||
OutOfRangeException {
|
||||
if (r <= 0) {
|
||||
throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_SUCCESSES,
|
||||
r);
|
||||
|
|
|
@ -18,13 +18,11 @@ package org.apache.commons.math4.distribution;
|
|||
|
||||
import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well19937c;
|
||||
import org.apache.commons.math4.special.Gamma;
|
||||
import org.apache.commons.math4.util.CombinatoricsUtils;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.apache.commons.math4.util.MathUtils;
|
||||
import org.apache.commons.math4.rng.RandomSource;
|
||||
import org.apache.commons.math4.rng.UniformRandomProvider;
|
||||
|
||||
/**
|
||||
* Implementation of the Poisson distribution.
|
||||
|
@ -47,8 +45,6 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
|
|||
private static final long serialVersionUID = -3349935121172596109L;
|
||||
/** Distribution used to compute normal approximation. */
|
||||
private final NormalDistribution normal;
|
||||
/** Distribution needed for the {@link #sample()} method. */
|
||||
private final RealDistribution.Sampler exponentialSampler;
|
||||
/** Mean of the distribution. */
|
||||
private final double mean;
|
||||
|
||||
|
@ -66,31 +62,18 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
|
|||
|
||||
/**
|
||||
* Creates a new Poisson distribution with specified mean.
|
||||
* <p>
|
||||
* <b>Note:</b> this constructor will implicitly create an instance of
|
||||
* {@link Well19937c} as random generator to be used for sampling only (see
|
||||
* {@link #sample()} and {@link #sample(int)}). In case no sampling is
|
||||
* needed for the created distribution, it is advised to pass {@code null}
|
||||
* as random generator via the appropriate constructors to avoid the
|
||||
* additional initialisation overhead.
|
||||
*
|
||||
* @param p the Poisson mean
|
||||
* @throws NotStrictlyPositiveException if {@code p <= 0}.
|
||||
*/
|
||||
public PoissonDistribution(double p) throws NotStrictlyPositiveException {
|
||||
public PoissonDistribution(double p)
|
||||
throws NotStrictlyPositiveException {
|
||||
this(p, DEFAULT_EPSILON, DEFAULT_MAX_ITERATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Poisson distribution with specified mean, convergence
|
||||
* criterion and maximum number of iterations.
|
||||
* <p>
|
||||
* <b>Note:</b> this constructor will implicitly create an instance of
|
||||
* {@link Well19937c} as random generator to be used for sampling only (see
|
||||
* {@link #sample()} and {@link #sample(int)}). In case no sampling is
|
||||
* needed for the created distribution, it is advised to pass {@code null}
|
||||
* as random generator via the appropriate constructors to avoid the
|
||||
* additional initialisation overhead.
|
||||
*
|
||||
* @param p Poisson mean.
|
||||
* @param epsilon Convergence criterion for cumulative probabilities.
|
||||
|
@ -99,30 +82,10 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
|
|||
* @throws NotStrictlyPositiveException if {@code p <= 0}.
|
||||
* @since 2.1
|
||||
*/
|
||||
public PoissonDistribution(double p, double epsilon, int maxIterations)
|
||||
throws NotStrictlyPositiveException {
|
||||
this(new Well19937c(), p, epsilon, maxIterations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Poisson distribution with specified mean, convergence
|
||||
* criterion and maximum number of iterations.
|
||||
*
|
||||
* @param rng Random number generator.
|
||||
* @param p Poisson mean.
|
||||
* @param epsilon Convergence criterion for cumulative probabilities.
|
||||
* @param maxIterations the maximum number of iterations for cumulative
|
||||
* probabilities.
|
||||
* @throws NotStrictlyPositiveException if {@code p <= 0}.
|
||||
* @since 3.1
|
||||
*/
|
||||
public PoissonDistribution(RandomGenerator rng,
|
||||
double p,
|
||||
public PoissonDistribution(double p,
|
||||
double epsilon,
|
||||
int maxIterations)
|
||||
throws NotStrictlyPositiveException {
|
||||
super(rng);
|
||||
|
||||
throws NotStrictlyPositiveException {
|
||||
if (p <= 0) {
|
||||
throw new NotStrictlyPositiveException(LocalizedFormats.MEAN, p);
|
||||
}
|
||||
|
@ -130,12 +93,8 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
|
|||
this.epsilon = epsilon;
|
||||
this.maxIterations = maxIterations;
|
||||
|
||||
// Use the same RNG instance as the parent class.
|
||||
normal = new NormalDistribution(p, FastMath.sqrt(p),
|
||||
NormalDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
|
||||
|
||||
// XXX TODO: RNG source should not be hard-coded.
|
||||
exponentialSampler = new ExponentialDistribution(1).createSampler(RandomSource.create(RandomSource.WELL_19937_C));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,7 +107,7 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
|
|||
* @since 2.1
|
||||
*/
|
||||
public PoissonDistribution(double p, double epsilon)
|
||||
throws NotStrictlyPositiveException {
|
||||
throws NotStrictlyPositiveException {
|
||||
this(p, epsilon, DEFAULT_MAX_ITERATIONS);
|
||||
}
|
||||
|
||||
|
@ -285,120 +244,113 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* <strong>Algorithm Description</strong>:
|
||||
* <ul>
|
||||
* <li>For small means, uses simulation of a Poisson process
|
||||
* using Uniform deviates, as described
|
||||
* <a href="http://mathaa.epfl.ch/cours/PMMI2001/interactive/rng7.htm"> here</a>.
|
||||
* The Poisson process (and hence value returned) is bounded by 1000 * mean.
|
||||
* </li>
|
||||
* <li>For large means, uses the rejection algorithm described in
|
||||
* <blockquote>
|
||||
* Devroye, Luc. (1981).<i>The Computer Generation of Poisson Random Variables</i><br>
|
||||
* <strong>Computing</strong> vol. 26 pp. 197-207.<br>
|
||||
* </blockquote>
|
||||
* </li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @return a random value.
|
||||
* @since 2.2
|
||||
*/
|
||||
/**{@inheritDoc} */
|
||||
@Override
|
||||
public int sample() {
|
||||
return (int) FastMath.min(nextPoisson(mean), Integer.MAX_VALUE);
|
||||
}
|
||||
public IntegerDistribution.Sampler createSampler(final UniformRandomProvider rng) {
|
||||
return new IntegerDistribution.Sampler() {
|
||||
/** Exponential distribution. */
|
||||
private final RealDistribution.Sampler exponentialSampler
|
||||
= new ExponentialDistribution(1).createSampler(rng);
|
||||
/** Gaussian distribution. */
|
||||
private final RealDistribution.Sampler gaussianSampler
|
||||
= new NormalDistribution().createSampler(rng);
|
||||
|
||||
/**
|
||||
* @param meanPoisson Mean of the Poisson distribution.
|
||||
* @return the next sample.
|
||||
*/
|
||||
private long nextPoisson(double meanPoisson) {
|
||||
final double pivot = 40.0d;
|
||||
if (meanPoisson < pivot) {
|
||||
double p = FastMath.exp(-meanPoisson);
|
||||
long n = 0;
|
||||
double r = 1.0d;
|
||||
double rnd = 1.0d;
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int sample() {
|
||||
return (int) FastMath.min(nextPoisson(mean),
|
||||
Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
while (n < 1000 * meanPoisson) {
|
||||
rnd = random.nextDouble();
|
||||
r *= rnd;
|
||||
if (r >= p) {
|
||||
n++;
|
||||
} else {
|
||||
/**
|
||||
* @param meanPoisson Mean of the Poisson distribution.
|
||||
* @return the next sample.
|
||||
*/
|
||||
private long nextPoisson(double meanPoisson) {
|
||||
final double pivot = 40.0d;
|
||||
if (meanPoisson < pivot) {
|
||||
double p = FastMath.exp(-meanPoisson);
|
||||
long n = 0;
|
||||
double r = 1.0d;
|
||||
double rnd = 1.0d;
|
||||
|
||||
while (n < 1000 * meanPoisson) {
|
||||
rnd = rng.nextDouble();
|
||||
r *= rnd;
|
||||
if (r >= p) {
|
||||
n++;
|
||||
} else {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
} else {
|
||||
final double lambda = FastMath.floor(meanPoisson);
|
||||
final double lambdaFractional = meanPoisson - lambda;
|
||||
final double logLambda = FastMath.log(lambda);
|
||||
final double logLambdaFactorial = CombinatoricsUtils.factorialLog((int) lambda);
|
||||
final long y2 = lambdaFractional < Double.MIN_VALUE ? 0 : nextPoisson(lambdaFractional);
|
||||
final double delta = FastMath.sqrt(lambda * FastMath.log(32 * lambda / FastMath.PI + 1));
|
||||
final double halfDelta = delta / 2;
|
||||
final double twolpd = 2 * lambda + delta;
|
||||
final double a1 = FastMath.sqrt(FastMath.PI * twolpd) * FastMath.exp(1 / (8 * lambda));
|
||||
final double a2 = (twolpd / delta) * FastMath.exp(-delta * (1 + delta) / twolpd);
|
||||
final double aSum = a1 + a2 + 1;
|
||||
final double p1 = a1 / aSum;
|
||||
final double p2 = a2 / aSum;
|
||||
final double c1 = 1 / (8 * lambda);
|
||||
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
double v = 0;
|
||||
int a = 0;
|
||||
double t = 0;
|
||||
double qr = 0;
|
||||
double qa = 0;
|
||||
for (;;) {
|
||||
final double u = random.nextDouble();
|
||||
if (u <= p1) {
|
||||
final double n = random.nextGaussian();
|
||||
x = n * FastMath.sqrt(lambda + halfDelta) - 0.5d;
|
||||
if (x > delta || x < -lambda) {
|
||||
continue;
|
||||
}
|
||||
y = x < 0 ? FastMath.floor(x) : FastMath.ceil(x);
|
||||
final double e = exponentialSampler.sample();
|
||||
v = -e - (n * n / 2) + c1;
|
||||
} else {
|
||||
if (u > p1 + p2) {
|
||||
y = lambda;
|
||||
break;
|
||||
} else {
|
||||
x = delta + (twolpd / delta) * exponentialSampler.sample();
|
||||
y = FastMath.ceil(x);
|
||||
v = -exponentialSampler.sample() - delta * (x + 1) / twolpd;
|
||||
final double lambda = FastMath.floor(meanPoisson);
|
||||
final double lambdaFractional = meanPoisson - lambda;
|
||||
final double logLambda = FastMath.log(lambda);
|
||||
final double logLambdaFactorial = CombinatoricsUtils.factorialLog((int) lambda);
|
||||
final long y2 = lambdaFractional < Double.MIN_VALUE ? 0 : nextPoisson(lambdaFractional);
|
||||
final double delta = FastMath.sqrt(lambda * FastMath.log(32 * lambda / FastMath.PI + 1));
|
||||
final double halfDelta = delta / 2;
|
||||
final double twolpd = 2 * lambda + delta;
|
||||
final double a1 = FastMath.sqrt(FastMath.PI * twolpd) * FastMath.exp(1 / (8 * lambda));
|
||||
final double a2 = (twolpd / delta) * FastMath.exp(-delta * (1 + delta) / twolpd);
|
||||
final double aSum = a1 + a2 + 1;
|
||||
final double p1 = a1 / aSum;
|
||||
final double p2 = a2 / aSum;
|
||||
final double c1 = 1 / (8 * lambda);
|
||||
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
double v = 0;
|
||||
int a = 0;
|
||||
double t = 0;
|
||||
double qr = 0;
|
||||
double qa = 0;
|
||||
while (true) {
|
||||
final double u = rng.nextDouble();
|
||||
if (u <= p1) {
|
||||
final double n = gaussianSampler.sample();
|
||||
x = n * FastMath.sqrt(lambda + halfDelta) - 0.5d;
|
||||
if (x > delta || x < -lambda) {
|
||||
continue;
|
||||
}
|
||||
y = x < 0 ? FastMath.floor(x) : FastMath.ceil(x);
|
||||
final double e = exponentialSampler.sample();
|
||||
v = -e - (n * n / 2) + c1;
|
||||
} else {
|
||||
if (u > p1 + p2) {
|
||||
y = lambda;
|
||||
break;
|
||||
} else {
|
||||
x = delta + (twolpd / delta) * exponentialSampler.sample();
|
||||
y = FastMath.ceil(x);
|
||||
v = -exponentialSampler.sample() - delta * (x + 1) / twolpd;
|
||||
}
|
||||
}
|
||||
a = x < 0 ? 1 : 0;
|
||||
t = y * (y + 1) / (2 * lambda);
|
||||
if (v < -t && a == 0) {
|
||||
y = lambda + y;
|
||||
break;
|
||||
}
|
||||
qr = t * ((2 * y + 1) / (6 * lambda) - 1);
|
||||
qa = qr - (t * t) / (3 * (lambda + a * (y + 1)));
|
||||
if (v < qa) {
|
||||
y = lambda + y;
|
||||
break;
|
||||
}
|
||||
if (v > qr) {
|
||||
continue;
|
||||
}
|
||||
if (v < y * logLambda - CombinatoricsUtils.factorialLog((int) (y + lambda)) + logLambdaFactorial) {
|
||||
y = lambda + y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
a = x < 0 ? 1 : 0;
|
||||
t = y * (y + 1) / (2 * lambda);
|
||||
if (v < -t && a == 0) {
|
||||
y = lambda + y;
|
||||
break;
|
||||
}
|
||||
qr = t * ((2 * y + 1) / (6 * lambda) - 1);
|
||||
qa = qr - (t * t) / (3 * (lambda + a * (y + 1)));
|
||||
if (v < qa) {
|
||||
y = lambda + y;
|
||||
break;
|
||||
}
|
||||
if (v > qr) {
|
||||
continue;
|
||||
}
|
||||
if (v < y * logLambda - CombinatoricsUtils.factorialLog((int) (y + lambda)) + logLambdaFactorial) {
|
||||
y = lambda + y;
|
||||
break;
|
||||
return y2 + (long) y;
|
||||
}
|
||||
}
|
||||
return y2 + (long) y;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ package org.apache.commons.math4.distribution;
|
|||
|
||||
import org.apache.commons.math4.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well19937c;
|
||||
import org.apache.commons.math4.rng.UniformRandomProvider;
|
||||
|
||||
/**
|
||||
* Implementation of the uniform integer distribution.
|
||||
|
@ -32,7 +31,7 @@ import org.apache.commons.math4.random.Well19937c;
|
|||
*/
|
||||
public class UniformIntegerDistribution extends AbstractIntegerDistribution {
|
||||
/** Serializable version identifier. */
|
||||
private static final long serialVersionUID = 20120109L;
|
||||
private static final long serialVersionUID = 20160308L;
|
||||
/** Lower bound (inclusive) of this distribution. */
|
||||
private final int lower;
|
||||
/** Upper bound (inclusive) of this distribution. */
|
||||
|
@ -41,39 +40,14 @@ public class UniformIntegerDistribution extends AbstractIntegerDistribution {
|
|||
/**
|
||||
* Creates a new uniform integer distribution using the given lower and
|
||||
* upper bounds (both inclusive).
|
||||
* <p>
|
||||
* <b>Note:</b> this constructor will implicitly create an instance of
|
||||
* {@link Well19937c} as random generator to be used for sampling only (see
|
||||
* {@link #sample()} and {@link #sample(int)}). In case no sampling is
|
||||
* needed for the created distribution, it is advised to pass {@code null}
|
||||
* as random generator via the appropriate constructors to avoid the
|
||||
* additional initialisation overhead.
|
||||
*
|
||||
* @param lower Lower bound (inclusive) of this distribution.
|
||||
* @param upper Upper bound (inclusive) of this distribution.
|
||||
* @throws NumberIsTooLargeException if {@code lower >= upper}.
|
||||
*/
|
||||
public UniformIntegerDistribution(int lower, int upper)
|
||||
throws NumberIsTooLargeException {
|
||||
this(new Well19937c(), lower, upper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new uniform integer distribution using the given lower and
|
||||
* upper bounds (both inclusive).
|
||||
*
|
||||
* @param rng Random number generator.
|
||||
* @param lower Lower bound (inclusive) of this distribution.
|
||||
* @param upper Upper bound (inclusive) of this distribution.
|
||||
* @throws NumberIsTooLargeException if {@code lower > upper}.
|
||||
* @since 3.1
|
||||
*/
|
||||
public UniformIntegerDistribution(RandomGenerator rng,
|
||||
int lower,
|
||||
public UniformIntegerDistribution(int lower,
|
||||
int upper)
|
||||
throws NumberIsTooLargeException {
|
||||
super(rng);
|
||||
|
||||
if (lower > upper) {
|
||||
throw new NumberIsTooLargeException(
|
||||
LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
|
||||
|
@ -165,24 +139,30 @@ public class UniformIntegerDistribution extends AbstractIntegerDistribution {
|
|||
return true;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
/**{@inheritDoc} */
|
||||
@Override
|
||||
public int sample() {
|
||||
final int max = (upper - lower) + 1;
|
||||
if (max <= 0) {
|
||||
// The range is too wide to fit in a positive int (larger
|
||||
// than 2^31); as it covers more than half the integer range,
|
||||
// we use a simple rejection method.
|
||||
while (true) {
|
||||
final int r = random.nextInt();
|
||||
if (r >= lower &&
|
||||
r <= upper) {
|
||||
return r;
|
||||
public IntegerDistribution.Sampler createSampler(final UniformRandomProvider rng) {
|
||||
return new IntegerDistribution.Sampler() {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int sample() {
|
||||
final int max = (upper - lower) + 1;
|
||||
if (max <= 0) {
|
||||
// The range is too wide to fit in a positive int (larger
|
||||
// than 2^31); as it covers more than half the integer range,
|
||||
// we use a simple rejection method.
|
||||
while (true) {
|
||||
final int r = rng.nextInt();
|
||||
if (r >= lower &&
|
||||
r <= upper) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We can shift the range and directly generate a positive int.
|
||||
return lower + rng.nextInt(max);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We can shift the range and directly generate a positive int.
|
||||
return lower + random.nextInt(max);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ package org.apache.commons.math4.distribution;
|
|||
|
||||
import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well19937c;
|
||||
import org.apache.commons.math4.rng.UniformRandomProvider;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
|
||||
/**
|
||||
|
@ -59,45 +58,18 @@ public class ZipfDistribution extends AbstractIntegerDistribution {
|
|||
private double numericalVariance = Double.NaN;
|
||||
/** Whether or not the numerical variance has been calculated */
|
||||
private boolean numericalVarianceIsCalculated = false;
|
||||
/** The sampler to be used for the sample() method */
|
||||
private transient ZipfRejectionInversionSampler sampler;
|
||||
|
||||
/**
|
||||
* Create a new Zipf distribution with the given number of elements and
|
||||
* exponent.
|
||||
* <p>
|
||||
* <b>Note:</b> this constructor will implicitly create an instance of
|
||||
* {@link Well19937c} as random generator to be used for sampling only (see
|
||||
* {@link #sample()} and {@link #sample(int)}). In case no sampling is
|
||||
* needed for the created distribution, it is advised to pass {@code null}
|
||||
* as random generator via the appropriate constructors to avoid the
|
||||
* additional initialisation overhead.
|
||||
* Creates a distribution.
|
||||
*
|
||||
* @param numberOfElements Number of elements.
|
||||
* @param exponent Exponent.
|
||||
* @exception NotStrictlyPositiveException if {@code numberOfElements <= 0}
|
||||
* or {@code exponent <= 0}.
|
||||
*/
|
||||
public ZipfDistribution(final int numberOfElements, final double exponent) {
|
||||
this(new Well19937c(), numberOfElements, exponent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Zipf distribution.
|
||||
*
|
||||
* @param rng Random number generator.
|
||||
* @param numberOfElements Number of elements.
|
||||
* @param exponent Exponent.
|
||||
* @exception NotStrictlyPositiveException if {@code numberOfElements <= 0}
|
||||
* or {@code exponent <= 0}.
|
||||
* @since 3.1
|
||||
*/
|
||||
public ZipfDistribution(RandomGenerator rng,
|
||||
int numberOfElements,
|
||||
public ZipfDistribution(int numberOfElements,
|
||||
double exponent)
|
||||
throws NotStrictlyPositiveException {
|
||||
super(rng);
|
||||
|
||||
if (numberOfElements <= 0) {
|
||||
throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION,
|
||||
numberOfElements);
|
||||
|
@ -285,13 +257,20 @@ public class ZipfDistribution extends AbstractIntegerDistribution {
|
|||
return true;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
/**{@inheritDoc} */
|
||||
@Override
|
||||
public int sample() {
|
||||
if (sampler == null) {
|
||||
sampler = new ZipfRejectionInversionSampler(numberOfElements, exponent);
|
||||
}
|
||||
return sampler.sample(random);
|
||||
public IntegerDistribution.Sampler createSampler(final UniformRandomProvider rng) {
|
||||
return new IntegerDistribution.Sampler() {
|
||||
/** Helper. */
|
||||
private final ZipfRejectionInversionSampler sampler =
|
||||
new ZipfRejectionInversionSampler(numberOfElements, exponent);
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int sample() {
|
||||
return sampler.sample(rng);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -318,8 +297,7 @@ public class ZipfDistribution extends AbstractIntegerDistribution {
|
|||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
static final class ZipfRejectionInversionSampler {
|
||||
|
||||
static class ZipfRejectionInversionSampler {
|
||||
/** Exponent parameter of the distribution. */
|
||||
private final double exponent;
|
||||
/** Number of elements. */
|
||||
|
@ -331,7 +309,7 @@ public class ZipfDistribution extends AbstractIntegerDistribution {
|
|||
/** Constant equal to {@code 2 - hIntegralInverse(hIntegral(2.5) - h(2)}. */
|
||||
private final double s;
|
||||
|
||||
/** Simple constructor.
|
||||
/**
|
||||
* @param numberOfElements number of elements
|
||||
* @param exponent exponent parameter of the distribution
|
||||
*/
|
||||
|
@ -343,18 +321,18 @@ public class ZipfDistribution extends AbstractIntegerDistribution {
|
|||
this.s = 2d - hIntegralInverse(hIntegral(2.5) - h(2));
|
||||
}
|
||||
|
||||
/** Generate one integral number in the range [1, numberOfElements].
|
||||
/**
|
||||
* Generates one integer in the range [1, numberOfElements].
|
||||
*
|
||||
* @param random random generator to use
|
||||
* @return generated integral number in the range [1, numberOfElements]
|
||||
*/
|
||||
int sample(final RandomGenerator random) {
|
||||
int sample(final UniformRandomProvider random) {
|
||||
while(true) {
|
||||
|
||||
final double u = hIntegralNumberOfElements + random.nextDouble() * (hIntegralX1 - hIntegralNumberOfElements);
|
||||
// u is uniformly distributed in (hIntegralX1, hIntegralNumberOfElements]
|
||||
|
||||
double x = hIntegralInverse(u);
|
||||
|
||||
int k = (int)(x + 0.5);
|
||||
|
||||
// Limit k to the range [1, numberOfElements]
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
package org.apache.commons.math4.random;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
|
@ -49,7 +46,6 @@ import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
|||
import org.apache.commons.math4.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math4.exception.OutOfRangeException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.rng.RandomSource;
|
||||
import org.apache.commons.math4.rng.UniformRandomProvider;
|
||||
import org.apache.commons.math4.util.MathArrays;
|
||||
|
||||
|
@ -120,13 +116,7 @@ public class RandomDataGenerator implements Serializable {
|
|||
private static final long serialVersionUID = -626730818244969716L;
|
||||
|
||||
/** underlying random number generator */
|
||||
@Deprecated
|
||||
private RandomGenerator rand = null;
|
||||
|
||||
/** Underlying random number generator. */
|
||||
private transient UniformRandomProvider randomProvider = null;
|
||||
/** Underlying source of randomness. */
|
||||
private final RandomSource randomSource;
|
||||
private RandomGenerator rand;
|
||||
|
||||
/** underlying secure random number generator */
|
||||
private RandomGenerator secRand = null;
|
||||
|
@ -140,7 +130,7 @@ public class RandomDataGenerator implements Serializable {
|
|||
* The generator is initialized and seeded on first use.</p>
|
||||
*/
|
||||
public RandomDataGenerator() {
|
||||
randomSource = RandomSource.WELL_19937_C;
|
||||
rand = new Well19937c();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,20 +140,8 @@ public class RandomDataGenerator implements Serializable {
|
|||
* @param rand the source of (non-secure) random data
|
||||
* (may be null, resulting in the default generator)
|
||||
*/
|
||||
@Deprecated
|
||||
public RandomDataGenerator(RandomGenerator rand) {
|
||||
this.rand = rand;
|
||||
randomSource = RandomSource.WELL_19937_C;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param source Source of (non-secure) random data.
|
||||
* If {@code null}, {@link RandomSource#WELL_19937_C} will be used.
|
||||
*/
|
||||
public RandomDataGenerator(RandomSource source) {
|
||||
randomSource = source == null ? RandomSource.WELL_19937_C : source;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -235,7 +213,7 @@ public class RandomDataGenerator implements Serializable {
|
|||
* @throws NumberIsTooLargeException if {@code lower >= upper}
|
||||
*/
|
||||
public int nextInt(final int lower, final int upper) throws NumberIsTooLargeException {
|
||||
return new UniformIntegerDistribution(getRandomGenerator(), lower, upper).sample();
|
||||
return new UniformIntegerDistribution(lower, upper).createSampler(getRandomProvider()).sample();
|
||||
}
|
||||
|
||||
/** Generates a uniformly distributed random long integer between {@code lower}
|
||||
|
@ -400,7 +378,7 @@ public class RandomDataGenerator implements Serializable {
|
|||
* @throws NumberIsTooLargeException if {@code lower >= upper}.
|
||||
*/
|
||||
public int nextSecureInt(final int lower, final int upper) throws NumberIsTooLargeException {
|
||||
return new UniformIntegerDistribution(getSecRan(), lower, upper).sample();
|
||||
return new UniformIntegerDistribution(lower, upper).createSampler(getSecureRandomProvider()).sample();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -470,9 +448,9 @@ public class RandomDataGenerator implements Serializable {
|
|||
* @throws NotStrictlyPositiveException if {@code mean <= 0}.
|
||||
*/
|
||||
public long nextPoisson(double mean) throws NotStrictlyPositiveException {
|
||||
return new PoissonDistribution(getRandomGenerator(), mean,
|
||||
return new PoissonDistribution(mean,
|
||||
PoissonDistribution.DEFAULT_EPSILON,
|
||||
PoissonDistribution.DEFAULT_MAX_ITERATIONS).sample();
|
||||
PoissonDistribution.DEFAULT_MAX_ITERATIONS).createSampler(getRandomProvider()).sample();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -557,7 +535,7 @@ public class RandomDataGenerator implements Serializable {
|
|||
* @throws NotPositiveException if {@code numberOfSuccesses < 0}.
|
||||
*/
|
||||
public int nextHypergeometric(int populationSize, int numberOfSuccesses, int sampleSize) throws NotPositiveException, NotStrictlyPositiveException, NumberIsTooLargeException {
|
||||
return new HypergeometricDistribution(getRandomGenerator(), populationSize, numberOfSuccesses, sampleSize).sample();
|
||||
return new HypergeometricDistribution(populationSize, numberOfSuccesses, sampleSize).createSampler(getRandomProvider()).sample();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -571,7 +549,7 @@ public class RandomDataGenerator implements Serializable {
|
|||
* range {@code [0, 1]}.
|
||||
*/
|
||||
public int nextPascal(int r, double p) throws NotStrictlyPositiveException, OutOfRangeException {
|
||||
return new PascalDistribution(getRandomGenerator(), r, p).sample();
|
||||
return new PascalDistribution(r, p).createSampler(getRandomProvider()).sample();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -608,7 +586,7 @@ public class RandomDataGenerator implements Serializable {
|
|||
* or {@code exponent <= 0}.
|
||||
*/
|
||||
public int nextZipf(int numberOfElements, double exponent) throws NotStrictlyPositiveException {
|
||||
return new ZipfDistribution(getRandomGenerator(), numberOfElements, exponent).sample();
|
||||
return new ZipfDistribution(numberOfElements, exponent).createSampler(getRandomProvider()).sample();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -630,7 +608,7 @@ public class RandomDataGenerator implements Serializable {
|
|||
* @return random value sampled from the Binomial(numberOfTrials, probabilityOfSuccess) distribution
|
||||
*/
|
||||
public int nextBinomial(int numberOfTrials, double probabilityOfSuccess) {
|
||||
return new BinomialDistribution(getRandomGenerator(), numberOfTrials, probabilityOfSuccess).sample();
|
||||
return new BinomialDistribution(numberOfTrials, probabilityOfSuccess).createSampler(getRandomProvider()).sample();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -764,7 +742,7 @@ public class RandomDataGenerator implements Serializable {
|
|||
* <p>
|
||||
* Generated arrays represent permutations of {@code n} taken {@code k} at a
|
||||
* time.</p>
|
||||
* This method calls {@link MathArrays#shuffle(int[],RandomGenerator)
|
||||
* This method calls {@link MathArrays#shuffle(int[],UniformRandomProvider)
|
||||
* MathArrays.shuffle} in order to create a random shuffle of the set
|
||||
* of natural numbers {@code { 0, 1, ..., n - 1 }}.
|
||||
*
|
||||
|
@ -788,7 +766,7 @@ public class RandomDataGenerator implements Serializable {
|
|||
}
|
||||
|
||||
int[] index = MathArrays.natural(n);
|
||||
MathArrays.shuffle(index, getRandomGenerator());
|
||||
MathArrays.shuffle(index, getRandomProvider());
|
||||
|
||||
// Return a new array containing the first "k" entries of "index".
|
||||
return MathArrays.copyOf(index, k);
|
||||
|
@ -845,7 +823,6 @@ public class RandomDataGenerator implements Serializable {
|
|||
* @param seed the seed value to use
|
||||
*/
|
||||
public void reSeed(long seed) {
|
||||
randomProvider = RandomSource.create(randomSource, seed);
|
||||
getRandomGenerator().setSeed(seed);
|
||||
}
|
||||
|
||||
|
@ -912,7 +889,6 @@ public class RandomDataGenerator implements Serializable {
|
|||
* @return the Random used to generate random data
|
||||
* @since 3.2
|
||||
*/
|
||||
@Deprecated
|
||||
public RandomGenerator getRandomGenerator() {
|
||||
if (rand == null) {
|
||||
initRan();
|
||||
|
@ -920,6 +896,77 @@ public class RandomDataGenerator implements Serializable {
|
|||
return rand;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rng {@link RandomGenerator} instance.
|
||||
* @return a {@link UniformRandomProvider} instance.
|
||||
*/
|
||||
private UniformRandomProvider wrapRandomGenerator(final RandomGenerator rng) {
|
||||
return new UniformRandomProvider() {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void nextBytes(byte[] bytes) {
|
||||
rng.nextBytes(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void nextBytes(byte[] bytes,
|
||||
int start,
|
||||
int len) {
|
||||
throw new MathInternalError();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int nextInt() {
|
||||
return rng.nextInt();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int nextInt(int n) {
|
||||
return rng.nextInt(n);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public long nextLong() {
|
||||
return rng.nextLong();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public long nextLong(long n) {
|
||||
throw new MathInternalError();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public boolean nextBoolean() {
|
||||
return rng.nextBoolean();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public float nextFloat() {
|
||||
return rng.nextFloat();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public double nextDouble() {
|
||||
return rng.nextDouble();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the generator used to generate secure random data.
|
||||
*/
|
||||
private UniformRandomProvider getSecureRandomProvider() {
|
||||
return wrapRandomGenerator(getSecRan());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the generator used to generate non-secure random data.
|
||||
*
|
||||
|
@ -927,17 +974,13 @@ public class RandomDataGenerator implements Serializable {
|
|||
* "ValueServer" should be fixed to not use the internals of another class!
|
||||
*/
|
||||
UniformRandomProvider getRandomProvider() {
|
||||
if (randomProvider == null) {
|
||||
randomProvider = RandomSource.create(randomSource);
|
||||
}
|
||||
return randomProvider;
|
||||
return wrapRandomGenerator(getRandomGenerator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default generator to a {@link Well19937c} generator seeded with
|
||||
* {@code System.currentTimeMillis() + System.identityHashCode(this))}.
|
||||
*/
|
||||
@Deprecated
|
||||
private void initRan() {
|
||||
rand = new Well19937c(System.currentTimeMillis() + System.identityHashCode(this));
|
||||
}
|
||||
|
@ -959,42 +1002,4 @@ public class RandomDataGenerator implements Serializable {
|
|||
}
|
||||
return secRand;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param out Output stream.
|
||||
* @throws IOException if an error occurs.
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream out)
|
||||
throws IOException {
|
||||
// Write non-transient fields.
|
||||
out.defaultWriteObject();
|
||||
|
||||
if (randomProvider != null) {
|
||||
// Save state of "randomProvider".
|
||||
out.writeObject(RandomSource.saveState(randomProvider));
|
||||
} else {
|
||||
out.writeObject(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in Input stream.
|
||||
* @throws IOException if an error occurs.
|
||||
* @throws ClassNotFoundException if an error occurs.
|
||||
*/
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws IOException,
|
||||
ClassNotFoundException {
|
||||
// Read non-transient fields.
|
||||
in.defaultReadObject();
|
||||
|
||||
// Read "randomProvider" state (can be null).
|
||||
final Object state = in.readObject();
|
||||
if (state != null) {
|
||||
// Recreate "randomProvider" from serialized info.
|
||||
randomProvider = RandomSource.create(randomSource);
|
||||
// And restore its state.
|
||||
RandomSource.restoreState(randomProvider, (RandomSource.State) state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,8 +119,7 @@ public class BinomialTest {
|
|||
throw new NullArgumentException();
|
||||
}
|
||||
|
||||
// pass a null rng to avoid unneeded overhead as we will not sample from this distribution
|
||||
final BinomialDistribution distribution = new BinomialDistribution(null, numberOfTrials, probability);
|
||||
final BinomialDistribution distribution = new BinomialDistribution(numberOfTrials, probability);
|
||||
switch (alternativeHypothesis) {
|
||||
case GREATER_THAN:
|
||||
return 1 - distribution.cumulativeProbability(numberOfSuccesses - 1);
|
||||
|
|
|
@ -40,8 +40,8 @@ import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
|||
import org.apache.commons.math4.exception.NullArgumentException;
|
||||
import org.apache.commons.math4.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well19937c;
|
||||
import org.apache.commons.math4.rng.RandomSource;
|
||||
import org.apache.commons.math4.rng.UniformRandomProvider;
|
||||
|
||||
/**
|
||||
* Arrays utilities.
|
||||
|
@ -1578,7 +1578,7 @@ public class MathArrays {
|
|||
* The {@code start} and {@code pos} parameters select which portion
|
||||
* of the array is randomized and which is left untouched.
|
||||
*
|
||||
* @see #shuffle(int[],int,Position,RandomGenerator)
|
||||
* @see #shuffle(int[],int,Position,UniformRandomProvider)
|
||||
*
|
||||
* @param list Array whose entries will be shuffled (in-place).
|
||||
* @param start Index at which shuffling begins.
|
||||
|
@ -1589,7 +1589,7 @@ public class MathArrays {
|
|||
public static void shuffle(int[] list,
|
||||
int start,
|
||||
Position pos) {
|
||||
shuffle(list, start, pos, new Well19937c());
|
||||
shuffle(list, start, pos, RandomSource.create(RandomSource.WELL_19937_C));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1609,7 +1609,7 @@ public class MathArrays {
|
|||
public static void shuffle(int[] list,
|
||||
int start,
|
||||
Position pos,
|
||||
RandomGenerator rng) {
|
||||
UniformRandomProvider rng) {
|
||||
switch (pos) {
|
||||
case TAIL: {
|
||||
for (int i = list.length - 1; i >= start; i--) {
|
||||
|
@ -1618,7 +1618,7 @@ public class MathArrays {
|
|||
target = start;
|
||||
} else {
|
||||
// NumberIsTooLargeException cannot occur.
|
||||
target = new UniformIntegerDistribution(rng, start, i).sample();
|
||||
target = new UniformIntegerDistribution(start, i).createSampler(rng).sample();
|
||||
}
|
||||
final int temp = list[target];
|
||||
list[target] = list[i];
|
||||
|
@ -1633,7 +1633,7 @@ public class MathArrays {
|
|||
target = start;
|
||||
} else {
|
||||
// NumberIsTooLargeException cannot occur.
|
||||
target = new UniformIntegerDistribution(rng, i, start).sample();
|
||||
target = new UniformIntegerDistribution(i, start).createSampler(rng).sample();
|
||||
}
|
||||
final int temp = list[target];
|
||||
list[target] = list[i];
|
||||
|
@ -1649,25 +1649,25 @@ public class MathArrays {
|
|||
/**
|
||||
* Shuffle the entries of the given array.
|
||||
*
|
||||
* @see #shuffle(int[],int,Position,RandomGenerator)
|
||||
* @see #shuffle(int[],int,Position,UniformRandomProvider)
|
||||
*
|
||||
* @param list Array whose entries will be shuffled (in-place).
|
||||
* @param rng Random number generator.
|
||||
*/
|
||||
public static void shuffle(int[] list,
|
||||
RandomGenerator rng) {
|
||||
UniformRandomProvider rng) {
|
||||
shuffle(list, 0, Position.TAIL, rng);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffle the entries of the given array.
|
||||
*
|
||||
* @see #shuffle(int[],int,Position,RandomGenerator)
|
||||
* @see #shuffle(int[],int,Position,UniformRandomProvider)
|
||||
*
|
||||
* @param list Array whose entries will be shuffled (in-place).
|
||||
*/
|
||||
public static void shuffle(int[] list) {
|
||||
shuffle(list, new Well19937c());
|
||||
shuffle(list, RandomSource.create(RandomSource.WELL_19937_C));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,8 +22,8 @@ import java.util.regex.MatchResult;
|
|||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.apache.commons.math4.util.MathArrays;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well19937c;
|
||||
import org.apache.commons.math4.rng.UniformRandomProvider;
|
||||
import org.apache.commons.math4.rng.RandomSource;
|
||||
import org.apache.commons.math4.exception.MathIllegalStateException;
|
||||
import org.apache.commons.math4.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
|
@ -53,7 +53,7 @@ public class PerfTestUtils {
|
|||
/** Default number of code repeats for computing the average run time. */
|
||||
private static final int DEFAULT_REPEAT_STAT = 10000;
|
||||
/** RNG. */
|
||||
private static RandomGenerator rng = new Well19937c();
|
||||
private static UniformRandomProvider rng = RandomSource.create(RandomSource.WELL_19937_C);
|
||||
|
||||
/**
|
||||
* Timing.
|
||||
|
|
|
@ -83,10 +83,6 @@ public class AbstractIntegerDistributionTest {
|
|||
|
||||
private final double p = 1d/6d;
|
||||
|
||||
public DiceDistribution() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public double probability(int x) {
|
||||
if (x < 1 || x > 6) {
|
||||
return 0;
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.commons.math4.exception.NotANumberException;
|
|||
import org.apache.commons.math4.exception.NotFiniteNumberException;
|
||||
import org.apache.commons.math4.exception.NotPositiveException;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.apache.commons.math4.rng.RandomSource;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -157,8 +158,10 @@ public class EnumeratedIntegerDistributionTest {
|
|||
@Test
|
||||
public void testSample() {
|
||||
final int n = 1000000;
|
||||
testDistribution.reseedRandomGenerator(-334759360); // fixed seed
|
||||
final int[] samples = testDistribution.sample(n);
|
||||
final IntegerDistribution.Sampler sampler
|
||||
= testDistribution.createSampler(RandomSource.create(RandomSource.WELL_19937_C,
|
||||
-334759360)); // fixed seed
|
||||
final int[] samples = AbstractIntegerDistribution.sample(n, sampler);
|
||||
Assert.assertEquals(n, samples.length);
|
||||
double sum = 0;
|
||||
double sumOfSquares = 0;
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.apache.commons.math4.exception.NotPositiveException;
|
|||
import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
||||
import org.apache.commons.math4.exception.NumberIsTooLargeException;
|
||||
import org.apache.commons.math4.util.Precision;
|
||||
import org.apache.commons.math4.rng.RandomSource;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -315,7 +316,8 @@ public class HypergeometricDistributionTest extends IntegerDistributionAbstractT
|
|||
final int N = 43130568;
|
||||
final int m = 42976365;
|
||||
final int n = 50;
|
||||
final HypergeometricDistribution dist = new HypergeometricDistribution(N, m, n);
|
||||
final IntegerDistribution.Sampler dist =
|
||||
new HypergeometricDistribution(N, m, n).createSampler(RandomSource.create(RandomSource.WELL_512_A));
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
final int sample = dist.sample();
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.apache.commons.math4.TestUtils;
|
|||
import org.apache.commons.math4.distribution.AbstractIntegerDistribution;
|
||||
import org.apache.commons.math4.distribution.IntegerDistribution;
|
||||
import org.apache.commons.math4.exception.MathIllegalArgumentException;
|
||||
import org.apache.commons.math4.rng.RandomSource;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
|
@ -296,8 +297,11 @@ public abstract class IntegerDistributionAbstractTest {
|
|||
for (int i = 0; i < length; i++) {
|
||||
expectedCounts[i] = sampleSize * densityValues[i];
|
||||
}
|
||||
distribution.reseedRandomGenerator(1000); // Use fixed seed
|
||||
int[] sample = distribution.sample(sampleSize);
|
||||
// Use fixed seed.
|
||||
final IntegerDistribution.Sampler sampler =
|
||||
distribution.createSampler(RandomSource.create(RandomSource.WELL_512_A,
|
||||
1000));
|
||||
int[] sample = AbstractIntegerDistribution.sample(sampleSize, sampler);
|
||||
for (int i = 0; i < sampleSize; i++) {
|
||||
for (int j = 0; j < length; j++) {
|
||||
if (sample[i] == densityPoints[j]) {
|
||||
|
|
|
@ -20,9 +20,7 @@ package org.apache.commons.math4.distribution;
|
|||
import org.apache.commons.math4.TestUtils;
|
||||
import org.apache.commons.math4.distribution.ZipfDistribution.ZipfRejectionInversionSampler;
|
||||
import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
||||
import org.apache.commons.math4.random.AbstractRandomGenerator;
|
||||
import org.apache.commons.math4.random.RandomGenerator;
|
||||
import org.apache.commons.math4.random.Well1024a;
|
||||
import org.apache.commons.math4.rng.RandomSource;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
|
@ -150,15 +148,18 @@ public class ZipfDistributionTest extends IntegerDistributionAbstractTest {
|
|||
weightSum += weights[i-1];
|
||||
}
|
||||
|
||||
ZipfDistribution distribution = new ZipfDistribution(numPoints, exponent);
|
||||
distribution.reseedRandomGenerator(6); // use fixed seed, the test is expected to fail for more than 50% of all seeds because each test case can fail with probability 0.001, the chance that all test cases do not fail is 0.999^(32*22) = 0.49442874426
|
||||
// Use fixed seed, the test is expected to fail for more than 50% of all
|
||||
// seeds because each test case can fail with probability 0.001, the chance
|
||||
// that all test cases do not fail is 0.999^(32*22) = 0.49442874426
|
||||
IntegerDistribution.Sampler distribution =
|
||||
new ZipfDistribution(numPoints, exponent).createSampler(RandomSource.create(RandomSource.WELL_19937_C, 6));
|
||||
|
||||
double[] expectedCounts = new double[numPoints];
|
||||
long[] observedCounts = new long[numPoints];
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
expectedCounts[i] = sampleSize * (weights[i]/weightSum);
|
||||
}
|
||||
int[] sample = distribution.sample(sampleSize);
|
||||
int[] sample = AbstractIntegerDistribution.sample(sampleSize, distribution);
|
||||
for (int s : sample) {
|
||||
observedCounts[s-1]++;
|
||||
}
|
||||
|
@ -177,11 +178,11 @@ public class ZipfDistributionTest extends IntegerDistributionAbstractTest {
|
|||
};
|
||||
for (final double testValue : testValues) {
|
||||
final double expected = FastMath.log1p(testValue);
|
||||
TestUtils.assertRelativelyEquals(expected, ZipfRejectionInversionSampler.helper1(testValue)*testValue, tol);
|
||||
final double actual = ZipfRejectionInversionSampler.helper1(testValue) * testValue;
|
||||
TestUtils.assertRelativelyEquals(expected, actual, tol);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSamplerHelper1Minus1() {
|
||||
Assert.assertEquals(Double.POSITIVE_INFINITY, ZipfRejectionInversionSampler.helper1(-1d), 0d);
|
||||
|
@ -197,7 +198,8 @@ public class ZipfDistributionTest extends IntegerDistributionAbstractTest {
|
|||
};
|
||||
for (double testValue : testValues) {
|
||||
final double expected = FastMath.expm1(testValue);
|
||||
TestUtils.assertRelativelyEquals(expected, ZipfRejectionInversionSampler.helper2(testValue)*testValue, tol);
|
||||
final double actual = ZipfRejectionInversionSampler.helper2(testValue) * testValue;
|
||||
TestUtils.assertRelativelyEquals(expected, actual, tol);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,22 +217,8 @@ public class ZipfDistributionTest extends IntegerDistributionAbstractTest {
|
|||
long start = System.currentTimeMillis();
|
||||
final int[] randomNumberCounter = new int[1];
|
||||
|
||||
RandomGenerator randomGenerator = new AbstractRandomGenerator() {
|
||||
|
||||
private final RandomGenerator r = new Well1024a(0L);
|
||||
|
||||
@Override
|
||||
public void setSeed(long seed) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public double nextDouble() {
|
||||
randomNumberCounter[0]+=1;
|
||||
return r.nextDouble();
|
||||
}
|
||||
};
|
||||
|
||||
final ZipfDistribution distribution = new ZipfDistribution(randomGenerator, numPoints, exponent);
|
||||
final IntegerDistribution.Sampler distribution =
|
||||
new ZipfDistribution(numPoints, exponent).createSampler(RandomSource.create(RandomSource.WELL_1024_A));
|
||||
for (int i = 0; i < numGeneratedSamples; ++i) {
|
||||
sum += distribution.sample();
|
||||
}
|
||||
|
|
|
@ -1209,18 +1209,4 @@ public class RandomDataGeneratorTest {
|
|||
}
|
||||
TestUtils.assertChiSquareAccept(densityPoints, expectedCounts, observedCounts, .001);
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* MATH-720
|
||||
*/
|
||||
public void testReseed() {
|
||||
PoissonDistribution x = new PoissonDistribution(3.0);
|
||||
x.reseedRandomGenerator(0);
|
||||
final double u = x.sample();
|
||||
PoissonDistribution y = new PoissonDistribution(3.0);
|
||||
y.reseedRandomGenerator(0);
|
||||
Assert.assertEquals(u, y.sample(), 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -282,7 +282,9 @@ public class AggregateSummaryStatisticsTest {
|
|||
* @return array of random double values
|
||||
*/
|
||||
private double[] generateSample() {
|
||||
final IntegerDistribution size = new UniformIntegerDistribution(10, 100);
|
||||
final IntegerDistribution.Sampler size =
|
||||
new UniformIntegerDistribution(10, 100).createSampler(RandomSource.create(RandomSource.WELL_512_A,
|
||||
327652));
|
||||
final RealDistribution.Sampler randomData
|
||||
= new UniformRealDistribution(-100, 100).createSampler(RandomSource.create(RandomSource.WELL_512_A,
|
||||
64925784252L));;
|
||||
|
@ -312,7 +314,9 @@ public class AggregateSummaryStatisticsTest {
|
|||
if (i == 4 || cur == length - 1) {
|
||||
next = length - 1;
|
||||
} else {
|
||||
next = (new UniformIntegerDistribution(cur, length - 1)).sample();
|
||||
final IntegerDistribution.Sampler sampler =
|
||||
new UniformIntegerDistribution(cur, length - 1).createSampler(RandomSource.create(RandomSource.WELL_512_A));
|
||||
next = sampler.sample();
|
||||
}
|
||||
final int subLength = next - cur + 1;
|
||||
out[i] = new double[subLength];
|
||||
|
|
|
@ -179,7 +179,9 @@ public abstract class UnivariateStatisticAbstractTest {
|
|||
|
||||
// Fill weights array with random int values between 1 and 5
|
||||
int[] intWeights = new int[len];
|
||||
final IntegerDistribution weightDist = new UniformIntegerDistribution(1, 5);
|
||||
final IntegerDistribution.Sampler weightDist =
|
||||
new UniformIntegerDistribution(1, 5).createSampler(RandomSource.create(RandomSource.WELL_512_A,
|
||||
234878544L));
|
||||
for (int i = 0; i < len; i++) {
|
||||
intWeights[i] = weightDist.sample();
|
||||
weights[i] = intWeights[i];
|
||||
|
@ -188,9 +190,9 @@ public abstract class UnivariateStatisticAbstractTest {
|
|||
// Fill values array with random data from N(mu, sigma)
|
||||
// and fill valuesList with values from values array with
|
||||
// values[i] repeated weights[i] times, each i
|
||||
final RealDistribution.Sampler valueDist
|
||||
= new NormalDistribution(mu, sigma).createSampler(RandomSource.create(RandomSource.WELL_512_A,
|
||||
64925784252L));
|
||||
final RealDistribution.Sampler valueDist =
|
||||
new NormalDistribution(mu, sigma).createSampler(RandomSource.create(RandomSource.WELL_512_A,
|
||||
64925784252L));
|
||||
List<Double> valuesList = new ArrayList<Double>();
|
||||
for (int i = 0; i < len; i++) {
|
||||
double value = valueDist.sample();
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.commons.math4.exception.NotANumberException;
|
|||
import org.apache.commons.math4.exception.NotPositiveException;
|
||||
import org.apache.commons.math4.exception.NotStrictlyPositiveException;
|
||||
import org.apache.commons.math4.exception.NullArgumentException;
|
||||
import org.apache.commons.math4.rng.RandomSource;
|
||||
import org.apache.commons.math4.random.Well1024a;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.apache.commons.math4.util.MathArrays;
|
||||
|
@ -1111,7 +1112,8 @@ public class MathArraysTest {
|
|||
final int[] orig = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
final int[] list = orig.clone();
|
||||
final int start = 4;
|
||||
MathArrays.shuffle(list, start, MathArrays.Position.TAIL, new Well1024a(7654321L));
|
||||
MathArrays.shuffle(list, start, MathArrays.Position.TAIL,
|
||||
RandomSource.create(RandomSource.WELL_19937_C, 7654321L));
|
||||
|
||||
// Ensure that all entries below index "start" did not move.
|
||||
for (int i = 0; i < start; i++) {
|
||||
|
@ -1134,7 +1136,8 @@ public class MathArraysTest {
|
|||
final int[] orig = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
final int[] list = orig.clone();
|
||||
final int start = 4;
|
||||
MathArrays.shuffle(list, start, MathArrays.Position.HEAD, new Well1024a(1234567L));
|
||||
MathArrays.shuffle(list, start, MathArrays.Position.HEAD,
|
||||
RandomSource.create(RandomSource.WELL_19937_C, 1234567L));
|
||||
|
||||
// Ensure that all entries above index "start" did not move.
|
||||
for (int i = start + 1; i < orig.length; i++) {
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.apache.commons.math4.distribution.IntegerDistribution;
|
|||
import org.apache.commons.math4.distribution.UniformIntegerDistribution;
|
||||
import org.apache.commons.math4.exception.MathIllegalArgumentException;
|
||||
import org.apache.commons.math4.exception.NullArgumentException;
|
||||
import org.apache.commons.math4.rng.RandomSource;
|
||||
import org.apache.commons.math4.util.ResizableDoubleArray.ExpansionMode;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
|
@ -321,7 +322,8 @@ public class ResizableDoubleArrayTest extends DoubleArrayAbstractTest {
|
|||
ResizableDoubleArray eDA2 = new ResizableDoubleArray(2);
|
||||
Assert.assertEquals("Initial number of elements should be 0", 0, eDA2.getNumElements());
|
||||
|
||||
final IntegerDistribution randomData = new UniformIntegerDistribution(100, 1000);
|
||||
final IntegerDistribution.Sampler randomData =
|
||||
new UniformIntegerDistribution(100, 1000).createSampler(RandomSource.create(RandomSource.WELL_19937_C));
|
||||
final int iterations = randomData.sample();
|
||||
|
||||
for( int i = 0; i < iterations; i++) {
|
||||
|
@ -342,7 +344,9 @@ public class ResizableDoubleArrayTest extends DoubleArrayAbstractTest {
|
|||
ResizableDoubleArray eDA3 = new ResizableDoubleArray(3, 3.0, 3.5);
|
||||
Assert.assertEquals("Initial number of elements should be 0", 0, eDA3.getNumElements() );
|
||||
|
||||
final IntegerDistribution randomData = new UniformIntegerDistribution(100, 3000);
|
||||
final IntegerDistribution.Sampler randomData =
|
||||
new UniformIntegerDistribution(100, 3000).createSampler(RandomSource.create(RandomSource.WELL_19937_C));
|
||||
;
|
||||
final int iterations = randomData.sample();
|
||||
|
||||
for( int i = 0; i < iterations; i++) {
|
||||
|
|
Loading…
Reference in New Issue