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:
Gilles 2016-03-19 23:47:21 +01:00
parent 77c24aa926
commit ae2c81ad18
25 changed files with 388 additions and 802 deletions

View File

@ -19,11 +19,10 @@ package org.apache.commons.math4.distribution;
import java.io.Serializable; import java.io.Serializable;
import org.apache.commons.math4.exception.MathInternalError; 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.NumberIsTooLargeException;
import org.apache.commons.math4.exception.OutOfRangeException; import org.apache.commons.math4.exception.OutOfRangeException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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; 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 { public abstract class AbstractIntegerDistribution implements IntegerDistribution, Serializable {
/** Serializable version identifier */ /** Serializable version identifier */
private static final long serialVersionUID = -1146319659338487221L; private static final long serialVersionUID = 20160318L;
/**
* 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;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
@ -159,43 +143,6 @@ public abstract class AbstractIntegerDistribution implements IntegerDistribution
return upper; 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} * Computes the cumulative probability function and checks for {@code NaN}
* values returned. Throws {@code MathInternalError} if the value is * values returned. Throws {@code MathInternalError} if the value is
@ -227,4 +174,33 @@ public abstract class AbstractIntegerDistribution implements IntegerDistribution
public double logProbability(int x) { public double logProbability(int x) {
return FastMath.log(probability(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());
}
};
}
} }

View File

@ -19,8 +19,6 @@ package org.apache.commons.math4.distribution;
import org.apache.commons.math4.exception.NotPositiveException; import org.apache.commons.math4.exception.NotPositiveException;
import org.apache.commons.math4.exception.OutOfRangeException; import org.apache.commons.math4.exception.OutOfRangeException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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.special.Beta;
import org.apache.commons.math4.util.FastMath; import org.apache.commons.math4.util.FastMath;
@ -38,41 +36,16 @@ public class BinomialDistribution extends AbstractIntegerDistribution {
/** The probability of success. */ /** The probability of success. */
private final double probabilityOfSuccess; 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. * Creates a binomial distribution.
* *
* @param rng Random number generator.
* @param trials Number of trials. * @param trials Number of trials.
* @param p Probability of success. * @param p Probability of success.
* @throws NotPositiveException if {@code trials < 0}. * @throws NotPositiveException if {@code trials < 0}.
* @throws OutOfRangeException if {@code p < 0} or {@code p > 1}. * @throws OutOfRangeException if {@code p < 0} or {@code p > 1}.
* @since 3.1
*/ */
public BinomialDistribution(RandomGenerator rng, public BinomialDistribution(int trials,
int trials,
double p) { double p) {
super(rng);
if (trials < 0) { if (trials < 0) {
throw new NotPositiveException(LocalizedFormats.NUMBER_OF_TRIALS, throw new NotPositiveException(LocalizedFormats.NUMBER_OF_TRIALS,
trials); trials);

View File

@ -29,7 +29,6 @@ import org.apache.commons.math4.exception.NotPositiveException;
import org.apache.commons.math4.exception.NotStrictlyPositiveException; import org.apache.commons.math4.exception.NotStrictlyPositiveException;
import org.apache.commons.math4.exception.NullArgumentException; import org.apache.commons.math4.exception.NullArgumentException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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.rng.UniformRandomProvider;
import org.apache.commons.math4.util.MathArrays; import org.apache.commons.math4.util.MathArrays;
import org.apache.commons.math4.util.Pair; import org.apache.commons.math4.util.Pair;
@ -52,69 +51,23 @@ import org.apache.commons.math4.util.Pair;
* @since 3.2 * @since 3.2
*/ */
public class EnumeratedDistribution<T> implements Serializable { public class EnumeratedDistribution<T> implements Serializable {
/** Serializable UID. */ /** Serializable UID. */
private static final long serialVersionUID = 20123308L; private static final long serialVersionUID = 20160319L;
/**
* RNG instance used to generate samples from the distribution.
*/
@Deprecated
protected RandomGenerator random = null;
/** /**
* List of random variable values. * List of random variable values.
*/ */
private final List<T> singletons; private final List<T> singletons;
/** /**
* Probabilities of respective random variable values. For i = 0, ..., singletons.size() - 1, * 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 * probability[i] is the probability that a random variable following this distribution takes
* the value singletons[i]. * the value singletons[i].
*/ */
private final double[] probabilities; private final double[] probabilities;
/** /**
* Cumulative probabilities, cached to speed up sampling. * Cumulative probabilities, cached to speed up sampling.
*/ */
private final double[] cumulativeProbabilities; 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 * Create an enumerated distribution using the given random number generator
* and probability mass function enumeration. * 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 * <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, * this distribution, this method returns {@code P(X = x)}. In other words,
@ -215,97 +158,6 @@ public class EnumeratedDistribution<T> implements Serializable {
return samples; 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}. * Creates a {@link Sampler}.
* *

View File

@ -27,8 +27,7 @@ import org.apache.commons.math4.exception.MathArithmeticException;
import org.apache.commons.math4.exception.NotANumberException; import org.apache.commons.math4.exception.NotANumberException;
import org.apache.commons.math4.exception.NotFiniteNumberException; import org.apache.commons.math4.exception.NotFiniteNumberException;
import org.apache.commons.math4.exception.NotPositiveException; import org.apache.commons.math4.exception.NotPositiveException;
import org.apache.commons.math4.random.RandomGenerator; import org.apache.commons.math4.rng.UniformRandomProvider;
import org.apache.commons.math4.random.Well19937c;
import org.apache.commons.math4.util.Pair; import org.apache.commons.math4.util.Pair;
/** /**
@ -42,10 +41,8 @@ import org.apache.commons.math4.util.Pair;
* @since 3.2 * @since 3.2
*/ */
public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution { public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
/** Serializable UID. */ /** Serializable UID. */
private static final long serialVersionUID = 20130308L; private static final long serialVersionUID = 20130308L;
/** /**
* {@link EnumeratedDistribution} instance (using the {@link Integer} wrapper) * {@link EnumeratedDistribution} instance (using the {@link Integer} wrapper)
* used to generate the pmf. * used to generate the pmf.
@ -53,15 +50,7 @@ public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
protected final EnumeratedDistribution<Integer> innerDistribution; protected final EnumeratedDistribution<Integer> innerDistribution;
/** /**
* Create a discrete distribution using the given probability mass function * Create a discrete distribution.
* 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.
* *
* @param singletons array of random variable values. * @param singletons array of random variable values.
* @param probabilities array of probabilities. * @param probabilities array of probabilities.
@ -72,45 +61,24 @@ public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
* @throws NotANumberException if any of the probabilities are NaN. * @throws NotANumberException if any of the probabilities are NaN.
* @throws MathArithmeticException all of the probabilities are 0. * @throws MathArithmeticException all of the probabilities are 0.
*/ */
public EnumeratedIntegerDistribution(final int[] singletons, final double[] probabilities) public EnumeratedIntegerDistribution(final int[] singletons,
throws DimensionMismatchException, NotPositiveException, MathArithmeticException, final double[] probabilities)
NotFiniteNumberException, NotANumberException{ throws DimensionMismatchException,
this(new Well19937c(), singletons, probabilities); NotPositiveException,
MathArithmeticException,
NotFiniteNumberException,
NotANumberException {
innerDistribution = new EnumeratedDistribution<Integer>(createDistribution(singletons,
probabilities));
} }
/** /**
* Create a discrete distribution using the given random number generator * Create a discrete integer-valued distribution from the input data.
* and probability mass function definition. * 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 * @param data input dataset
* #since 3.6
*/ */
public EnumeratedIntegerDistribution(final RandomGenerator rng, final int[] data) { public EnumeratedIntegerDistribution(final int[] data) {
super(rng);
final Map<Integer, Integer> dataMap = new HashMap<Integer, Integer>(); final Map<Integer, Integer> dataMap = new HashMap<Integer, Integer>();
for (int value : data) { for (int value : data) {
Integer count = dataMap.get(value); Integer count = dataMap.get(value);
@ -129,19 +97,7 @@ public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
probabilities[index] = entry.getValue().intValue() / denom; probabilities[index] = entry.getValue().intValue() / denom;
index++; index++;
} }
innerDistribution = new EnumeratedDistribution<Integer>(rng, createDistribution(values, probabilities)); innerDistribution = new EnumeratedDistribution<Integer>(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);
} }
/** /**
@ -162,7 +118,6 @@ public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
samples.add(new Pair<Integer, Double>(singletons[i], probabilities[i])); samples.add(new Pair<Integer, Double>(singletons[i], probabilities[i]));
} }
return samples; return samples;
} }
/** /**
@ -273,11 +228,19 @@ public class EnumeratedIntegerDistribution extends AbstractIntegerDistribution {
return true; return true;
} }
/** /** {@inheritDoc} */
* {@inheritDoc} @Override
*/ public IntegerDistribution.Sampler createSampler(final UniformRandomProvider rng) {
return new IntegerDistribution.Sampler() {
/** Delegate. */
private final EnumeratedDistribution<Integer>.Sampler inner =
innerDistribution.createSampler(rng);
/** {@inheritDoc} */
@Override @Override
public int sample() { public int sample() {
return innerDistribution.sample(); return inner.sample();
}
};
} }
} }

View File

@ -18,8 +18,6 @@ package org.apache.commons.math4.distribution;
import org.apache.commons.math4.exception.OutOfRangeException; import org.apache.commons.math4.exception.OutOfRangeException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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; import org.apache.commons.math4.util.FastMath;
/** /**
@ -32,7 +30,7 @@ import org.apache.commons.math4.util.FastMath;
public class GeometricDistribution extends AbstractIntegerDistribution { public class GeometricDistribution extends AbstractIntegerDistribution {
/** Serializable version identifier. */ /** Serializable version identifier. */
private static final long serialVersionUID = 20130507L; private static final long serialVersionUID = 20160318L;
/** The probability of success. */ /** The probability of success. */
private final double probabilityOfSuccess; private final double probabilityOfSuccess;
/** {@code log(p)} where p is the probability of success. */ /** {@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. */ /** {@code log(1 - p)} where p is the probability of success. */
private final double log1mProbabilityOfSuccess; 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. * Creates a geometric distribution.
* *
* @param rng Random number generator.
* @param p Probability of success. * @param p Probability of success.
* @throws OutOfRangeException if {@code p <= 0} or {@code p > 1}. * @throws OutOfRangeException if {@code p <= 0} or {@code p > 1}.
*/ */
public GeometricDistribution(RandomGenerator rng, double p) { public GeometricDistribution(double p) {
super(rng);
if (p <= 0 || p > 1) { if (p <= 0 || p > 1) {
throw new OutOfRangeException(LocalizedFormats.OUT_OF_RANGE_LEFT, p, 0, 1); throw new OutOfRangeException(LocalizedFormats.OUT_OF_RANGE_LEFT, p, 0, 1);
} }

View File

@ -21,8 +21,6 @@ import org.apache.commons.math4.exception.NotPositiveException;
import org.apache.commons.math4.exception.NotStrictlyPositiveException; import org.apache.commons.math4.exception.NotStrictlyPositiveException;
import org.apache.commons.math4.exception.NumberIsTooLargeException; import org.apache.commons.math4.exception.NumberIsTooLargeException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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; import org.apache.commons.math4.util.FastMath;
/** /**
@ -33,7 +31,7 @@ import org.apache.commons.math4.util.FastMath;
*/ */
public class HypergeometricDistribution extends AbstractIntegerDistribution { public class HypergeometricDistribution extends AbstractIntegerDistribution {
/** Serializable version identifier. */ /** Serializable version identifier. */
private static final long serialVersionUID = -436928820673516179L; private static final long serialVersionUID = 20160318L;
/** The number of successes in the population. */ /** The number of successes in the population. */
private final int numberOfSuccesses; private final int numberOfSuccesses;
/** The population size. */ /** The population size. */
@ -45,34 +43,9 @@ public class HypergeometricDistribution extends AbstractIntegerDistribution {
/** Whether or not the numerical variance has been calculated */ /** Whether or not the numerical variance has been calculated */
private boolean numericalVarianceIsCalculated = false; 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. * Creates a new hypergeometric distribution.
* *
* @param rng Random number generator.
* @param populationSize Population size. * @param populationSize Population size.
* @param numberOfSuccesses Number of successes in the population. * @param numberOfSuccesses Number of successes in the population.
* @param sampleSize Sample size. * @param sampleSize Sample size.
@ -80,15 +53,13 @@ public class HypergeometricDistribution extends AbstractIntegerDistribution {
* @throws NotStrictlyPositiveException if {@code populationSize <= 0}. * @throws NotStrictlyPositiveException if {@code populationSize <= 0}.
* @throws NumberIsTooLargeException if {@code numberOfSuccesses > populationSize}, * @throws NumberIsTooLargeException if {@code numberOfSuccesses > populationSize},
* or {@code sampleSize > populationSize}. * or {@code sampleSize > populationSize}.
* @since 3.1
*/ */
public HypergeometricDistribution(RandomGenerator rng, public HypergeometricDistribution(int populationSize,
int populationSize,
int numberOfSuccesses, int numberOfSuccesses,
int sampleSize) int sampleSize)
throws NotPositiveException, NotStrictlyPositiveException, NumberIsTooLargeException { throws NotPositiveException,
super(rng); NotStrictlyPositiveException,
NumberIsTooLargeException {
if (populationSize <= 0) { if (populationSize <= 0) {
throw new NotStrictlyPositiveException(LocalizedFormats.POPULATION_SIZE, throw new NotStrictlyPositiveException(LocalizedFormats.POPULATION_SIZE,
populationSize); populationSize);

View File

@ -18,6 +18,7 @@ package org.apache.commons.math4.distribution;
import org.apache.commons.math4.exception.NumberIsTooLargeException; import org.apache.commons.math4.exception.NumberIsTooLargeException;
import org.apache.commons.math4.exception.OutOfRangeException; import org.apache.commons.math4.exception.OutOfRangeException;
import org.apache.commons.math4.rng.UniformRandomProvider;
/** /**
* Interface for distributions on the integers. * Interface for distributions on the integers.
@ -145,29 +146,23 @@ public interface IntegerDistribution {
boolean isSupportConnected(); boolean isSupportConnected();
/** /**
* Reseed the random generator used to generate samples. * Creates a sampler.
* *
* @param seed the new seed * @param rng Generator of uniformly distributed numbers.
* @since 3.0 * @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. * Sampling functionality.
*/
interface Sampler {
/**
* Generates a random value sampled from this distribution.
* *
* @return a random value * @return a random value.
* @since 3.0
*/ */
int sample(); 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);
} }

View File

@ -19,8 +19,6 @@ package org.apache.commons.math4.distribution;
import org.apache.commons.math4.exception.NotStrictlyPositiveException; import org.apache.commons.math4.exception.NotStrictlyPositiveException;
import org.apache.commons.math4.exception.OutOfRangeException; import org.apache.commons.math4.exception.OutOfRangeException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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.special.Beta;
import org.apache.commons.math4.util.CombinatoricsUtils; import org.apache.commons.math4.util.CombinatoricsUtils;
import org.apache.commons.math4.util.FastMath; 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 * Create a Pascal distribution with the given number of successes and
* probability of success. * 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 r Number of successes.
* @param p Probability of success. * @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 * @throws OutOfRangeException if the probability of success is not in the
* range {@code [0, 1]}. * range {@code [0, 1]}.
*/ */
public PascalDistribution(int r, double p) public PascalDistribution(int r,
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,
double p) double p)
throws NotStrictlyPositiveException, OutOfRangeException { throws NotStrictlyPositiveException,
super(rng); OutOfRangeException {
if (r <= 0) { if (r <= 0) {
throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_SUCCESSES, throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_SUCCESSES,
r); r);

View File

@ -18,13 +18,11 @@ package org.apache.commons.math4.distribution;
import org.apache.commons.math4.exception.NotStrictlyPositiveException; import org.apache.commons.math4.exception.NotStrictlyPositiveException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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.special.Gamma;
import org.apache.commons.math4.util.CombinatoricsUtils; import org.apache.commons.math4.util.CombinatoricsUtils;
import org.apache.commons.math4.util.FastMath; import org.apache.commons.math4.util.FastMath;
import org.apache.commons.math4.util.MathUtils; 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. * Implementation of the Poisson distribution.
@ -47,8 +45,6 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
private static final long serialVersionUID = -3349935121172596109L; private static final long serialVersionUID = -3349935121172596109L;
/** Distribution used to compute normal approximation. */ /** Distribution used to compute normal approximation. */
private final NormalDistribution normal; private final NormalDistribution normal;
/** Distribution needed for the {@link #sample()} method. */
private final RealDistribution.Sampler exponentialSampler;
/** Mean of the distribution. */ /** Mean of the distribution. */
private final double mean; private final double mean;
@ -66,31 +62,18 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
/** /**
* Creates a new Poisson distribution with specified mean. * 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 * @param p the Poisson mean
* @throws NotStrictlyPositiveException if {@code p <= 0}. * @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); this(p, DEFAULT_EPSILON, DEFAULT_MAX_ITERATIONS);
} }
/** /**
* Creates a new Poisson distribution with specified mean, convergence * Creates a new Poisson distribution with specified mean, convergence
* criterion and maximum number of iterations. * 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 p Poisson mean.
* @param epsilon Convergence criterion for cumulative probabilities. * @param epsilon Convergence criterion for cumulative probabilities.
@ -99,30 +82,10 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
* @throws NotStrictlyPositiveException if {@code p <= 0}. * @throws NotStrictlyPositiveException if {@code p <= 0}.
* @since 2.1 * @since 2.1
*/ */
public PoissonDistribution(double p, double epsilon, int maxIterations) public PoissonDistribution(double p,
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,
double epsilon, double epsilon,
int maxIterations) int maxIterations)
throws NotStrictlyPositiveException { throws NotStrictlyPositiveException {
super(rng);
if (p <= 0) { if (p <= 0) {
throw new NotStrictlyPositiveException(LocalizedFormats.MEAN, p); throw new NotStrictlyPositiveException(LocalizedFormats.MEAN, p);
} }
@ -130,12 +93,8 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
this.epsilon = epsilon; this.epsilon = epsilon;
this.maxIterations = maxIterations; this.maxIterations = maxIterations;
// Use the same RNG instance as the parent class.
normal = new NormalDistribution(p, FastMath.sqrt(p), normal = new NormalDistribution(p, FastMath.sqrt(p),
NormalDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY); 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));
} }
/** /**
@ -285,31 +244,22 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
return true; return true;
} }
/** /**{@inheritDoc} */
* {@inheritDoc} @Override
* <p> public IntegerDistribution.Sampler createSampler(final UniformRandomProvider rng) {
* <strong>Algorithm Description</strong>: return new IntegerDistribution.Sampler() {
* <ul> /** Exponential distribution. */
* <li>For small means, uses simulation of a Poisson process private final RealDistribution.Sampler exponentialSampler
* using Uniform deviates, as described = new ExponentialDistribution(1).createSampler(rng);
* <a href="http://mathaa.epfl.ch/cours/PMMI2001/interactive/rng7.htm"> here</a>. /** Gaussian distribution. */
* The Poisson process (and hence value returned) is bounded by 1000 * mean. private final RealDistribution.Sampler gaussianSampler
* </li> = new NormalDistribution().createSampler(rng);
* <li>For large means, uses the rejection algorithm described in
* <blockquote> /** {@inheritDoc} */
* 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
*/
@Override @Override
public int sample() { public int sample() {
return (int) FastMath.min(nextPoisson(mean), Integer.MAX_VALUE); return (int) FastMath.min(nextPoisson(mean),
Integer.MAX_VALUE);
} }
/** /**
@ -325,7 +275,7 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
double rnd = 1.0d; double rnd = 1.0d;
while (n < 1000 * meanPoisson) { while (n < 1000 * meanPoisson) {
rnd = random.nextDouble(); rnd = rng.nextDouble();
r *= rnd; r *= rnd;
if (r >= p) { if (r >= p) {
n++; n++;
@ -357,10 +307,10 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
double t = 0; double t = 0;
double qr = 0; double qr = 0;
double qa = 0; double qa = 0;
for (;;) { while (true) {
final double u = random.nextDouble(); final double u = rng.nextDouble();
if (u <= p1) { if (u <= p1) {
final double n = random.nextGaussian(); final double n = gaussianSampler.sample();
x = n * FastMath.sqrt(lambda + halfDelta) - 0.5d; x = n * FastMath.sqrt(lambda + halfDelta) - 0.5d;
if (x > delta || x < -lambda) { if (x > delta || x < -lambda) {
continue; continue;
@ -401,4 +351,6 @@ public class PoissonDistribution extends AbstractIntegerDistribution {
return y2 + (long) y; return y2 + (long) y;
} }
} }
};
}
} }

View File

@ -19,8 +19,7 @@ package org.apache.commons.math4.distribution;
import org.apache.commons.math4.exception.NumberIsTooLargeException; import org.apache.commons.math4.exception.NumberIsTooLargeException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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.random.Well19937c;
/** /**
* Implementation of the uniform integer distribution. * Implementation of the uniform integer distribution.
@ -32,7 +31,7 @@ import org.apache.commons.math4.random.Well19937c;
*/ */
public class UniformIntegerDistribution extends AbstractIntegerDistribution { public class UniformIntegerDistribution extends AbstractIntegerDistribution {
/** Serializable version identifier. */ /** Serializable version identifier. */
private static final long serialVersionUID = 20120109L; private static final long serialVersionUID = 20160308L;
/** Lower bound (inclusive) of this distribution. */ /** Lower bound (inclusive) of this distribution. */
private final int lower; private final int lower;
/** Upper bound (inclusive) of this distribution. */ /** 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 * Creates a new uniform integer distribution using the given lower and
* upper bounds (both inclusive). * 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 lower Lower bound (inclusive) of this distribution.
* @param upper Upper 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}. * @throws NumberIsTooLargeException if {@code lower > upper}.
* @since 3.1
*/ */
public UniformIntegerDistribution(RandomGenerator rng, public UniformIntegerDistribution(int lower,
int lower,
int upper) int upper)
throws NumberIsTooLargeException { throws NumberIsTooLargeException {
super(rng);
if (lower > upper) { if (lower > upper) {
throw new NumberIsTooLargeException( throw new NumberIsTooLargeException(
LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND, LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
@ -165,6 +139,10 @@ public class UniformIntegerDistribution extends AbstractIntegerDistribution {
return true; return true;
} }
/**{@inheritDoc} */
@Override
public IntegerDistribution.Sampler createSampler(final UniformRandomProvider rng) {
return new IntegerDistribution.Sampler() {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public int sample() { public int sample() {
@ -174,7 +152,7 @@ public class UniformIntegerDistribution extends AbstractIntegerDistribution {
// than 2^31); as it covers more than half the integer range, // than 2^31); as it covers more than half the integer range,
// we use a simple rejection method. // we use a simple rejection method.
while (true) { while (true) {
final int r = random.nextInt(); final int r = rng.nextInt();
if (r >= lower && if (r >= lower &&
r <= upper) { r <= upper) {
return r; return r;
@ -182,7 +160,9 @@ public class UniformIntegerDistribution extends AbstractIntegerDistribution {
} }
} else { } else {
// We can shift the range and directly generate a positive int. // We can shift the range and directly generate a positive int.
return lower + random.nextInt(max); return lower + rng.nextInt(max);
} }
} }
};
}
} }

View File

@ -19,8 +19,7 @@ package org.apache.commons.math4.distribution;
import org.apache.commons.math4.exception.NotStrictlyPositiveException; import org.apache.commons.math4.exception.NotStrictlyPositiveException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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.random.Well19937c;
import org.apache.commons.math4.util.FastMath; import org.apache.commons.math4.util.FastMath;
/** /**
@ -59,45 +58,18 @@ public class ZipfDistribution extends AbstractIntegerDistribution {
private double numericalVariance = Double.NaN; private double numericalVariance = Double.NaN;
/** Whether or not the numerical variance has been calculated */ /** Whether or not the numerical variance has been calculated */
private boolean numericalVarianceIsCalculated = false; 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 * Creates a distribution.
* 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.
* *
* @param numberOfElements Number of elements. * @param numberOfElements Number of elements.
* @param exponent Exponent. * @param exponent Exponent.
* @exception NotStrictlyPositiveException if {@code numberOfElements <= 0} * @exception NotStrictlyPositiveException if {@code numberOfElements <= 0}
* or {@code exponent <= 0}. * or {@code exponent <= 0}.
*/ */
public ZipfDistribution(final int numberOfElements, final double exponent) { public ZipfDistribution(int numberOfElements,
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,
double exponent) double exponent)
throws NotStrictlyPositiveException { throws NotStrictlyPositiveException {
super(rng);
if (numberOfElements <= 0) { if (numberOfElements <= 0) {
throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION, throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION,
numberOfElements); numberOfElements);
@ -285,13 +257,20 @@ public class ZipfDistribution extends AbstractIntegerDistribution {
return true; return true;
} }
/**{@inheritDoc} */
@Override
public IntegerDistribution.Sampler createSampler(final UniformRandomProvider rng) {
return new IntegerDistribution.Sampler() {
/** Helper. */
private final ZipfRejectionInversionSampler sampler =
new ZipfRejectionInversionSampler(numberOfElements, exponent);
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public int sample() { public int sample() {
if (sampler == null) { return sampler.sample(rng);
sampler = new ZipfRejectionInversionSampler(numberOfElements, exponent);
} }
return sampler.sample(random); };
} }
/** /**
@ -318,8 +297,7 @@ public class ZipfDistribution extends AbstractIntegerDistribution {
* *
* @since 3.6 * @since 3.6
*/ */
static final class ZipfRejectionInversionSampler { static class ZipfRejectionInversionSampler {
/** Exponent parameter of the distribution. */ /** Exponent parameter of the distribution. */
private final double exponent; private final double exponent;
/** Number of elements. */ /** Number of elements. */
@ -331,7 +309,7 @@ public class ZipfDistribution extends AbstractIntegerDistribution {
/** Constant equal to {@code 2 - hIntegralInverse(hIntegral(2.5) - h(2)}. */ /** Constant equal to {@code 2 - hIntegralInverse(hIntegral(2.5) - h(2)}. */
private final double s; private final double s;
/** Simple constructor. /**
* @param numberOfElements number of elements * @param numberOfElements number of elements
* @param exponent exponent parameter of the distribution * @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)); 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 * @param random random generator to use
* @return generated integral number in the range [1, numberOfElements] * @return generated integral number in the range [1, numberOfElements]
*/ */
int sample(final RandomGenerator random) { int sample(final UniformRandomProvider random) {
while(true) { while(true) {
final double u = hIntegralNumberOfElements + random.nextDouble() * (hIntegralX1 - hIntegralNumberOfElements); final double u = hIntegralNumberOfElements + random.nextDouble() * (hIntegralX1 - hIntegralNumberOfElements);
// u is uniformly distributed in (hIntegralX1, hIntegralNumberOfElements] // u is uniformly distributed in (hIntegralX1, hIntegralNumberOfElements]
double x = hIntegralInverse(u); double x = hIntegralInverse(u);
int k = (int)(x + 0.5); int k = (int)(x + 0.5);
// Limit k to the range [1, numberOfElements] // Limit k to the range [1, numberOfElements]

View File

@ -18,9 +18,6 @@
package org.apache.commons.math4.random; package org.apache.commons.math4.random;
import java.io.Serializable; import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; 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.NumberIsTooLargeException;
import org.apache.commons.math4.exception.OutOfRangeException; import org.apache.commons.math4.exception.OutOfRangeException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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.rng.UniformRandomProvider;
import org.apache.commons.math4.util.MathArrays; import org.apache.commons.math4.util.MathArrays;
@ -120,13 +116,7 @@ public class RandomDataGenerator implements Serializable {
private static final long serialVersionUID = -626730818244969716L; private static final long serialVersionUID = -626730818244969716L;
/** underlying random number generator */ /** underlying random number generator */
@Deprecated private RandomGenerator rand;
private RandomGenerator rand = null;
/** Underlying random number generator. */
private transient UniformRandomProvider randomProvider = null;
/** Underlying source of randomness. */
private final RandomSource randomSource;
/** underlying secure random number generator */ /** underlying secure random number generator */
private RandomGenerator secRand = null; private RandomGenerator secRand = null;
@ -140,7 +130,7 @@ public class RandomDataGenerator implements Serializable {
* The generator is initialized and seeded on first use.</p> * The generator is initialized and seeded on first use.</p>
*/ */
public RandomDataGenerator() { 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 * @param rand the source of (non-secure) random data
* (may be null, resulting in the default generator) * (may be null, resulting in the default generator)
*/ */
@Deprecated
public RandomDataGenerator(RandomGenerator rand) { public RandomDataGenerator(RandomGenerator rand) {
this.rand = 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} * @throws NumberIsTooLargeException if {@code lower >= upper}
*/ */
public int nextInt(final int lower, final int upper) throws NumberIsTooLargeException { 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} /** 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}. * @throws NumberIsTooLargeException if {@code lower >= upper}.
*/ */
public int nextSecureInt(final int lower, final int upper) throws NumberIsTooLargeException { 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}. * @throws NotStrictlyPositiveException if {@code mean <= 0}.
*/ */
public long nextPoisson(double mean) throws NotStrictlyPositiveException { public long nextPoisson(double mean) throws NotStrictlyPositiveException {
return new PoissonDistribution(getRandomGenerator(), mean, return new PoissonDistribution(mean,
PoissonDistribution.DEFAULT_EPSILON, 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}. * @throws NotPositiveException if {@code numberOfSuccesses < 0}.
*/ */
public int nextHypergeometric(int populationSize, int numberOfSuccesses, int sampleSize) throws NotPositiveException, NotStrictlyPositiveException, NumberIsTooLargeException { 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]}. * range {@code [0, 1]}.
*/ */
public int nextPascal(int r, double p) throws NotStrictlyPositiveException, OutOfRangeException { 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}. * or {@code exponent <= 0}.
*/ */
public int nextZipf(int numberOfElements, double exponent) throws NotStrictlyPositiveException { 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 * @return random value sampled from the Binomial(numberOfTrials, probabilityOfSuccess) distribution
*/ */
public int nextBinomial(int numberOfTrials, double probabilityOfSuccess) { 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> * <p>
* Generated arrays represent permutations of {@code n} taken {@code k} at a * Generated arrays represent permutations of {@code n} taken {@code k} at a
* time.</p> * 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 * MathArrays.shuffle} in order to create a random shuffle of the set
* of natural numbers {@code { 0, 1, ..., n - 1 }}. * of natural numbers {@code { 0, 1, ..., n - 1 }}.
* *
@ -788,7 +766,7 @@ public class RandomDataGenerator implements Serializable {
} }
int[] index = MathArrays.natural(n); 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 a new array containing the first "k" entries of "index".
return MathArrays.copyOf(index, k); return MathArrays.copyOf(index, k);
@ -845,7 +823,6 @@ public class RandomDataGenerator implements Serializable {
* @param seed the seed value to use * @param seed the seed value to use
*/ */
public void reSeed(long seed) { public void reSeed(long seed) {
randomProvider = RandomSource.create(randomSource, seed);
getRandomGenerator().setSeed(seed); getRandomGenerator().setSeed(seed);
} }
@ -912,7 +889,6 @@ public class RandomDataGenerator implements Serializable {
* @return the Random used to generate random data * @return the Random used to generate random data
* @since 3.2 * @since 3.2
*/ */
@Deprecated
public RandomGenerator getRandomGenerator() { public RandomGenerator getRandomGenerator() {
if (rand == null) { if (rand == null) {
initRan(); initRan();
@ -920,6 +896,77 @@ public class RandomDataGenerator implements Serializable {
return rand; 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. * @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! * "ValueServer" should be fixed to not use the internals of another class!
*/ */
UniformRandomProvider getRandomProvider() { UniformRandomProvider getRandomProvider() {
if (randomProvider == null) { return wrapRandomGenerator(getRandomGenerator());
randomProvider = RandomSource.create(randomSource);
}
return randomProvider;
} }
/** /**
* Sets the default generator to a {@link Well19937c} generator seeded with * Sets the default generator to a {@link Well19937c} generator seeded with
* {@code System.currentTimeMillis() + System.identityHashCode(this))}. * {@code System.currentTimeMillis() + System.identityHashCode(this))}.
*/ */
@Deprecated
private void initRan() { private void initRan() {
rand = new Well19937c(System.currentTimeMillis() + System.identityHashCode(this)); rand = new Well19937c(System.currentTimeMillis() + System.identityHashCode(this));
} }
@ -959,42 +1002,4 @@ public class RandomDataGenerator implements Serializable {
} }
return secRand; 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);
}
}
} }

View File

@ -119,8 +119,7 @@ public class BinomialTest {
throw new NullArgumentException(); throw new NullArgumentException();
} }
// pass a null rng to avoid unneeded overhead as we will not sample from this distribution final BinomialDistribution distribution = new BinomialDistribution(numberOfTrials, probability);
final BinomialDistribution distribution = new BinomialDistribution(null, numberOfTrials, probability);
switch (alternativeHypothesis) { switch (alternativeHypothesis) {
case GREATER_THAN: case GREATER_THAN:
return 1 - distribution.cumulativeProbability(numberOfSuccesses - 1); return 1 - distribution.cumulativeProbability(numberOfSuccesses - 1);

View File

@ -40,8 +40,8 @@ import org.apache.commons.math4.exception.NotStrictlyPositiveException;
import org.apache.commons.math4.exception.NullArgumentException; import org.apache.commons.math4.exception.NullArgumentException;
import org.apache.commons.math4.exception.NumberIsTooLargeException; import org.apache.commons.math4.exception.NumberIsTooLargeException;
import org.apache.commons.math4.exception.util.LocalizedFormats; import org.apache.commons.math4.exception.util.LocalizedFormats;
import org.apache.commons.math4.random.RandomGenerator; import org.apache.commons.math4.rng.RandomSource;
import org.apache.commons.math4.random.Well19937c; import org.apache.commons.math4.rng.UniformRandomProvider;
/** /**
* Arrays utilities. * Arrays utilities.
@ -1578,7 +1578,7 @@ public class MathArrays {
* The {@code start} and {@code pos} parameters select which portion * The {@code start} and {@code pos} parameters select which portion
* of the array is randomized and which is left untouched. * 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 list Array whose entries will be shuffled (in-place).
* @param start Index at which shuffling begins. * @param start Index at which shuffling begins.
@ -1589,7 +1589,7 @@ public class MathArrays {
public static void shuffle(int[] list, public static void shuffle(int[] list,
int start, int start,
Position pos) { 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, public static void shuffle(int[] list,
int start, int start,
Position pos, Position pos,
RandomGenerator rng) { UniformRandomProvider rng) {
switch (pos) { switch (pos) {
case TAIL: { case TAIL: {
for (int i = list.length - 1; i >= start; i--) { for (int i = list.length - 1; i >= start; i--) {
@ -1618,7 +1618,7 @@ public class MathArrays {
target = start; target = start;
} else { } else {
// NumberIsTooLargeException cannot occur. // NumberIsTooLargeException cannot occur.
target = new UniformIntegerDistribution(rng, start, i).sample(); target = new UniformIntegerDistribution(start, i).createSampler(rng).sample();
} }
final int temp = list[target]; final int temp = list[target];
list[target] = list[i]; list[target] = list[i];
@ -1633,7 +1633,7 @@ public class MathArrays {
target = start; target = start;
} else { } else {
// NumberIsTooLargeException cannot occur. // NumberIsTooLargeException cannot occur.
target = new UniformIntegerDistribution(rng, i, start).sample(); target = new UniformIntegerDistribution(i, start).createSampler(rng).sample();
} }
final int temp = list[target]; final int temp = list[target];
list[target] = list[i]; list[target] = list[i];
@ -1649,25 +1649,25 @@ public class MathArrays {
/** /**
* Shuffle the entries of the given array. * 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 list Array whose entries will be shuffled (in-place).
* @param rng Random number generator. * @param rng Random number generator.
*/ */
public static void shuffle(int[] list, public static void shuffle(int[] list,
RandomGenerator rng) { UniformRandomProvider rng) {
shuffle(list, 0, Position.TAIL, rng); shuffle(list, 0, Position.TAIL, rng);
} }
/** /**
* Shuffle the entries of the given array. * 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 list Array whose entries will be shuffled (in-place).
*/ */
public static void shuffle(int[] list) { public static void shuffle(int[] list) {
shuffle(list, new Well19937c()); shuffle(list, RandomSource.create(RandomSource.WELL_19937_C));
} }
/** /**

View File

@ -22,8 +22,8 @@ import java.util.regex.MatchResult;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import org.apache.commons.math4.util.MathArrays; import org.apache.commons.math4.util.MathArrays;
import org.apache.commons.math4.random.RandomGenerator; import org.apache.commons.math4.rng.UniformRandomProvider;
import org.apache.commons.math4.random.Well19937c; import org.apache.commons.math4.rng.RandomSource;
import org.apache.commons.math4.exception.MathIllegalStateException; import org.apache.commons.math4.exception.MathIllegalStateException;
import org.apache.commons.math4.exception.NumberIsTooLargeException; import org.apache.commons.math4.exception.NumberIsTooLargeException;
import org.apache.commons.math4.exception.util.LocalizedFormats; 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. */ /** Default number of code repeats for computing the average run time. */
private static final int DEFAULT_REPEAT_STAT = 10000; private static final int DEFAULT_REPEAT_STAT = 10000;
/** RNG. */ /** RNG. */
private static RandomGenerator rng = new Well19937c(); private static UniformRandomProvider rng = RandomSource.create(RandomSource.WELL_19937_C);
/** /**
* Timing. * Timing.

View File

@ -83,10 +83,6 @@ public class AbstractIntegerDistributionTest {
private final double p = 1d/6d; private final double p = 1d/6d;
public DiceDistribution() {
super(null);
}
public double probability(int x) { public double probability(int x) {
if (x < 1 || x > 6) { if (x < 1 || x > 6) {
return 0; return 0;

View File

@ -25,6 +25,7 @@ import org.apache.commons.math4.exception.NotANumberException;
import org.apache.commons.math4.exception.NotFiniteNumberException; import org.apache.commons.math4.exception.NotFiniteNumberException;
import org.apache.commons.math4.exception.NotPositiveException; import org.apache.commons.math4.exception.NotPositiveException;
import org.apache.commons.math4.util.FastMath; import org.apache.commons.math4.util.FastMath;
import org.apache.commons.math4.rng.RandomSource;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -157,8 +158,10 @@ public class EnumeratedIntegerDistributionTest {
@Test @Test
public void testSample() { public void testSample() {
final int n = 1000000; final int n = 1000000;
testDistribution.reseedRandomGenerator(-334759360); // fixed seed final IntegerDistribution.Sampler sampler
final int[] samples = testDistribution.sample(n); = testDistribution.createSampler(RandomSource.create(RandomSource.WELL_19937_C,
-334759360)); // fixed seed
final int[] samples = AbstractIntegerDistribution.sample(n, sampler);
Assert.assertEquals(n, samples.length); Assert.assertEquals(n, samples.length);
double sum = 0; double sum = 0;
double sumOfSquares = 0; double sumOfSquares = 0;

View File

@ -24,6 +24,7 @@ import org.apache.commons.math4.exception.NotPositiveException;
import org.apache.commons.math4.exception.NotStrictlyPositiveException; import org.apache.commons.math4.exception.NotStrictlyPositiveException;
import org.apache.commons.math4.exception.NumberIsTooLargeException; import org.apache.commons.math4.exception.NumberIsTooLargeException;
import org.apache.commons.math4.util.Precision; import org.apache.commons.math4.util.Precision;
import org.apache.commons.math4.rng.RandomSource;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -315,7 +316,8 @@ public class HypergeometricDistributionTest extends IntegerDistributionAbstractT
final int N = 43130568; final int N = 43130568;
final int m = 42976365; final int m = 42976365;
final int n = 50; 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++) { for (int i = 0; i < 100; i++) {
final int sample = dist.sample(); final int sample = dist.sample();

View File

@ -20,6 +20,7 @@ import org.apache.commons.math4.TestUtils;
import org.apache.commons.math4.distribution.AbstractIntegerDistribution; import org.apache.commons.math4.distribution.AbstractIntegerDistribution;
import org.apache.commons.math4.distribution.IntegerDistribution; import org.apache.commons.math4.distribution.IntegerDistribution;
import org.apache.commons.math4.exception.MathIllegalArgumentException; import org.apache.commons.math4.exception.MathIllegalArgumentException;
import org.apache.commons.math4.rng.RandomSource;
import org.apache.commons.math4.util.FastMath; import org.apache.commons.math4.util.FastMath;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
@ -296,8 +297,11 @@ public abstract class IntegerDistributionAbstractTest {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
expectedCounts[i] = sampleSize * densityValues[i]; expectedCounts[i] = sampleSize * densityValues[i];
} }
distribution.reseedRandomGenerator(1000); // Use fixed seed // Use fixed seed.
int[] sample = distribution.sample(sampleSize); 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 i = 0; i < sampleSize; i++) {
for (int j = 0; j < length; j++) { for (int j = 0; j < length; j++) {
if (sample[i] == densityPoints[j]) { if (sample[i] == densityPoints[j]) {

View File

@ -20,9 +20,7 @@ package org.apache.commons.math4.distribution;
import org.apache.commons.math4.TestUtils; import org.apache.commons.math4.TestUtils;
import org.apache.commons.math4.distribution.ZipfDistribution.ZipfRejectionInversionSampler; import org.apache.commons.math4.distribution.ZipfDistribution.ZipfRejectionInversionSampler;
import org.apache.commons.math4.exception.NotStrictlyPositiveException; import org.apache.commons.math4.exception.NotStrictlyPositiveException;
import org.apache.commons.math4.random.AbstractRandomGenerator; import org.apache.commons.math4.rng.RandomSource;
import org.apache.commons.math4.random.RandomGenerator;
import org.apache.commons.math4.random.Well1024a;
import org.apache.commons.math4.util.FastMath; import org.apache.commons.math4.util.FastMath;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore; import org.junit.Ignore;
@ -150,15 +148,18 @@ public class ZipfDistributionTest extends IntegerDistributionAbstractTest {
weightSum += weights[i-1]; weightSum += weights[i-1];
} }
ZipfDistribution distribution = new ZipfDistribution(numPoints, exponent); // Use fixed seed, the test is expected to fail for more than 50% of all
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 // 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]; double[] expectedCounts = new double[numPoints];
long[] observedCounts = new long[numPoints]; long[] observedCounts = new long[numPoints];
for (int i = 0; i < numPoints; i++) { for (int i = 0; i < numPoints; i++) {
expectedCounts[i] = sampleSize * (weights[i]/weightSum); expectedCounts[i] = sampleSize * (weights[i]/weightSum);
} }
int[] sample = distribution.sample(sampleSize); int[] sample = AbstractIntegerDistribution.sample(sampleSize, distribution);
for (int s : sample) { for (int s : sample) {
observedCounts[s-1]++; observedCounts[s-1]++;
} }
@ -177,11 +178,11 @@ public class ZipfDistributionTest extends IntegerDistributionAbstractTest {
}; };
for (final double testValue : testValues) { for (final double testValue : testValues) {
final double expected = FastMath.log1p(testValue); 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 @Test
public void testSamplerHelper1Minus1() { public void testSamplerHelper1Minus1() {
Assert.assertEquals(Double.POSITIVE_INFINITY, ZipfRejectionInversionSampler.helper1(-1d), 0d); Assert.assertEquals(Double.POSITIVE_INFINITY, ZipfRejectionInversionSampler.helper1(-1d), 0d);
@ -197,7 +198,8 @@ public class ZipfDistributionTest extends IntegerDistributionAbstractTest {
}; };
for (double testValue : testValues) { for (double testValue : testValues) {
final double expected = FastMath.expm1(testValue); 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(); long start = System.currentTimeMillis();
final int[] randomNumberCounter = new int[1]; final int[] randomNumberCounter = new int[1];
RandomGenerator randomGenerator = new AbstractRandomGenerator() { final IntegerDistribution.Sampler distribution =
new ZipfDistribution(numPoints, exponent).createSampler(RandomSource.create(RandomSource.WELL_1024_A));
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);
for (int i = 0; i < numGeneratedSamples; ++i) { for (int i = 0; i < numGeneratedSamples; ++i) {
sum += distribution.sample(); sum += distribution.sample();
} }

View File

@ -1209,18 +1209,4 @@ public class RandomDataGeneratorTest {
} }
TestUtils.assertChiSquareAccept(densityPoints, expectedCounts, observedCounts, .001); 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);
}
} }

View File

@ -282,7 +282,9 @@ public class AggregateSummaryStatisticsTest {
* @return array of random double values * @return array of random double values
*/ */
private double[] generateSample() { 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 final RealDistribution.Sampler randomData
= new UniformRealDistribution(-100, 100).createSampler(RandomSource.create(RandomSource.WELL_512_A, = new UniformRealDistribution(-100, 100).createSampler(RandomSource.create(RandomSource.WELL_512_A,
64925784252L));; 64925784252L));;
@ -312,7 +314,9 @@ public class AggregateSummaryStatisticsTest {
if (i == 4 || cur == length - 1) { if (i == 4 || cur == length - 1) {
next = length - 1; next = length - 1;
} else { } 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; final int subLength = next - cur + 1;
out[i] = new double[subLength]; out[i] = new double[subLength];

View File

@ -179,7 +179,9 @@ public abstract class UnivariateStatisticAbstractTest {
// Fill weights array with random int values between 1 and 5 // Fill weights array with random int values between 1 and 5
int[] intWeights = new int[len]; 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++) { for (int i = 0; i < len; i++) {
intWeights[i] = weightDist.sample(); intWeights[i] = weightDist.sample();
weights[i] = intWeights[i]; weights[i] = intWeights[i];
@ -188,8 +190,8 @@ public abstract class UnivariateStatisticAbstractTest {
// Fill values array with random data from N(mu, sigma) // Fill values array with random data from N(mu, sigma)
// and fill valuesList with values from values array with // and fill valuesList with values from values array with
// values[i] repeated weights[i] times, each i // values[i] repeated weights[i] times, each i
final RealDistribution.Sampler valueDist final RealDistribution.Sampler valueDist =
= new NormalDistribution(mu, sigma).createSampler(RandomSource.create(RandomSource.WELL_512_A, new NormalDistribution(mu, sigma).createSampler(RandomSource.create(RandomSource.WELL_512_A,
64925784252L)); 64925784252L));
List<Double> valuesList = new ArrayList<Double>(); List<Double> valuesList = new ArrayList<Double>();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {

View File

@ -25,6 +25,7 @@ import org.apache.commons.math4.exception.NotANumberException;
import org.apache.commons.math4.exception.NotPositiveException; import org.apache.commons.math4.exception.NotPositiveException;
import org.apache.commons.math4.exception.NotStrictlyPositiveException; import org.apache.commons.math4.exception.NotStrictlyPositiveException;
import org.apache.commons.math4.exception.NullArgumentException; 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.random.Well1024a;
import org.apache.commons.math4.util.FastMath; import org.apache.commons.math4.util.FastMath;
import org.apache.commons.math4.util.MathArrays; 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[] orig = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
final int[] list = orig.clone(); final int[] list = orig.clone();
final int start = 4; 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. // Ensure that all entries below index "start" did not move.
for (int i = 0; i < start; i++) { 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[] orig = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
final int[] list = orig.clone(); final int[] list = orig.clone();
final int start = 4; 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. // Ensure that all entries above index "start" did not move.
for (int i = start + 1; i < orig.length; i++) { for (int i = start + 1; i < orig.length; i++) {

View File

@ -20,6 +20,7 @@ import org.apache.commons.math4.distribution.IntegerDistribution;
import org.apache.commons.math4.distribution.UniformIntegerDistribution; import org.apache.commons.math4.distribution.UniformIntegerDistribution;
import org.apache.commons.math4.exception.MathIllegalArgumentException; import org.apache.commons.math4.exception.MathIllegalArgumentException;
import org.apache.commons.math4.exception.NullArgumentException; import org.apache.commons.math4.exception.NullArgumentException;
import org.apache.commons.math4.rng.RandomSource;
import org.apache.commons.math4.util.ResizableDoubleArray.ExpansionMode; import org.apache.commons.math4.util.ResizableDoubleArray.ExpansionMode;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
@ -321,7 +322,8 @@ public class ResizableDoubleArrayTest extends DoubleArrayAbstractTest {
ResizableDoubleArray eDA2 = new ResizableDoubleArray(2); ResizableDoubleArray eDA2 = new ResizableDoubleArray(2);
Assert.assertEquals("Initial number of elements should be 0", 0, eDA2.getNumElements()); 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(); final int iterations = randomData.sample();
for( int i = 0; i < iterations; i++) { 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); ResizableDoubleArray eDA3 = new ResizableDoubleArray(3, 3.0, 3.5);
Assert.assertEquals("Initial number of elements should be 0", 0, eDA3.getNumElements() ); 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(); final int iterations = randomData.sample();
for( int i = 0; i < iterations; i++) { for( int i = 0; i < iterations; i++) {