blob: 839b1e62dbe30c2794365ebd25cfe0072c546afc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.math3.random;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.apache.commons.math3.Retry;
import org.apache.commons.math3.RetryRunner;
import org.apache.commons.math3.TestUtils;
import org.apache.commons.math3.distribution.BetaDistribution;
import org.apache.commons.math3.distribution.BinomialDistribution;
import org.apache.commons.math3.distribution.BinomialDistributionTest;
import org.apache.commons.math3.distribution.CauchyDistribution;
import org.apache.commons.math3.distribution.ChiSquaredDistribution;
import org.apache.commons.math3.distribution.ExponentialDistribution;
import org.apache.commons.math3.distribution.FDistribution;
import org.apache.commons.math3.distribution.GammaDistribution;
import org.apache.commons.math3.distribution.HypergeometricDistribution;
import org.apache.commons.math3.distribution.HypergeometricDistributionTest;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.distribution.PascalDistribution;
import org.apache.commons.math3.distribution.PascalDistributionTest;
import org.apache.commons.math3.distribution.PoissonDistribution;
import org.apache.commons.math3.distribution.TDistribution;
import org.apache.commons.math3.distribution.WeibullDistribution;
import org.apache.commons.math3.distribution.ZipfDistribution;
import org.apache.commons.math3.distribution.ZipfDistributionTest;
import org.apache.commons.math3.stat.Frequency;
import org.apache.commons.math3.stat.inference.ChiSquareTest;
import org.apache.commons.math3.util.FastMath;
import org.apache.commons.math3.exception.MathIllegalArgumentException;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Test cases for the RandomDataGenerator class.
*
*/
@RunWith(RetryRunner.class)
public class RandomDataGeneratorTest {
public RandomDataGeneratorTest() {
randomData = new RandomDataGenerator();
randomData.reSeed(1000);
}
protected final long smallSampleSize = 1000;
protected final double[] expected = { 250, 250, 250, 250 };
protected final int largeSampleSize = 10000;
private final String[] hex = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"a", "b", "c", "d", "e", "f" };
protected RandomDataGenerator randomData = null;
protected final ChiSquareTest testStatistic = new ChiSquareTest();
@Test
public void testNextIntExtremeValues() {
int x = randomData.nextInt(Integer.MIN_VALUE, Integer.MAX_VALUE);
int y = randomData.nextInt(Integer.MIN_VALUE, Integer.MAX_VALUE);
Assert.assertFalse(x == y);
}
@Test
public void testNextLongExtremeValues() {
long x = randomData.nextLong(Long.MIN_VALUE, Long.MAX_VALUE);
long y = randomData.nextLong(Long.MIN_VALUE, Long.MAX_VALUE);
Assert.assertFalse(x == y);
}
@Test
public void testNextUniformExtremeValues() {
double x = randomData.nextUniform(-Double.MAX_VALUE, Double.MAX_VALUE);
double y = randomData.nextUniform(-Double.MAX_VALUE, Double.MAX_VALUE);
Assert.assertFalse(x == y);
Assert.assertFalse(Double.isNaN(x));
Assert.assertFalse(Double.isNaN(y));
Assert.assertFalse(Double.isInfinite(x));
Assert.assertFalse(Double.isInfinite(y));
}
@Test
public void testNextIntIAE() {
try {
randomData.nextInt(4, 3);
Assert.fail("MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
}
@Test
public void testNextIntNegativeToPositiveRange() {
for (int i = 0; i < 5; i++) {
checkNextIntUniform(-3, 5);
checkNextIntUniform(-3, 6);
}
}
@Test
public void testNextIntNegativeRange() {
for (int i = 0; i < 5; i++) {
checkNextIntUniform(-7, -4);
checkNextIntUniform(-15, -2);
checkNextIntUniform(Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 12);
}
}
@Test
public void testNextIntPositiveRange() {
for (int i = 0; i < 5; i++) {
checkNextIntUniform(0, 3);
checkNextIntUniform(2, 12);
checkNextIntUniform(1,2);
checkNextIntUniform(Integer.MAX_VALUE - 12, Integer.MAX_VALUE - 1);
}
}
private void checkNextIntUniform(int min, int max) {
final Frequency freq = new Frequency();
for (int i = 0; i < smallSampleSize; i++) {
final int value = randomData.nextInt(min, max);
Assert.assertTrue("nextInt range", (value >= min) && (value <= max));
freq.addValue(value);
}
final int len = max - min + 1;
final long[] observed = new long[len];
for (int i = 0; i < len; i++) {
observed[i] = freq.getCount(min + i);
}
final double[] expected = new double[len];
for (int i = 0; i < len; i++) {
expected[i] = 1d / len;
}
TestUtils.assertChiSquareAccept(expected, observed, 0.001);
}
@Test
public void testNextIntWideRange() {
int lower = -0x6543210F;
int upper = 0x456789AB;
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int i = 0; i < 1000000; ++i) {
int r = randomData.nextInt(lower, upper);
max = FastMath.max(max, r);
min = FastMath.min(min, r);
Assert.assertTrue(r >= lower);
Assert.assertTrue(r <= upper);
}
double ratio = (((double) max) - ((double) min)) /
(((double) upper) - ((double) lower));
Assert.assertTrue(ratio > 0.99999);
}
@Test
public void testNextLongIAE() {
try {
randomData.nextLong(4, 3);
Assert.fail("MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
}
@Test
public void testNextLongNegativeToPositiveRange() {
for (int i = 0; i < 5; i++) {
checkNextLongUniform(-3, 5);
checkNextLongUniform(-3, 6);
}
}
@Test
public void testNextLongNegativeRange() {
for (int i = 0; i < 5; i++) {
checkNextLongUniform(-7, -4);
checkNextLongUniform(-15, -2);
checkNextLongUniform(Long.MIN_VALUE + 1, Long.MIN_VALUE + 12);
}
}
@Test
public void testNextLongPositiveRange() {
for (int i = 0; i < 5; i++) {
checkNextLongUniform(0, 3);
checkNextLongUniform(2, 12);
checkNextLongUniform(Long.MAX_VALUE - 12, Long.MAX_VALUE - 1);
}
}
private void checkNextLongUniform(long min, long max) {
final Frequency freq = new Frequency();
for (int i = 0; i < smallSampleSize; i++) {
final long value = randomData.nextLong(min, max);
Assert.assertTrue("nextLong range: " + value + " " + min + " " + max,
(value >= min) && (value <= max));
freq.addValue(value);
}
final int len = ((int) (max - min)) + 1;
final long[] observed = new long[len];
for (int i = 0; i < len; i++) {
observed[i] = freq.getCount(min + i);
}
final double[] expected = new double[len];
for (int i = 0; i < len; i++) {
expected[i] = 1d / len;
}
TestUtils.assertChiSquareAccept(expected, observed, 0.01);
}
@Test
public void testNextLongWideRange() {
long lower = -0x6543210FEDCBA987L;
long upper = 0x456789ABCDEF0123L;
long max = Long.MIN_VALUE;
long min = Long.MAX_VALUE;
for (int i = 0; i < 10000000; ++i) {
long r = randomData.nextLong(lower, upper);
max = FastMath.max(max, r);
min = FastMath.min(min, r);
Assert.assertTrue(r >= lower);
Assert.assertTrue(r <= upper);
}
double ratio = (((double) max) - ((double) min)) /
(((double) upper) - ((double) lower));
Assert.assertTrue(ratio > 0.99999);
}
@Test
public void testNextSecureLongIAE() {
try {
randomData.nextSecureLong(4, 3);
Assert.fail("MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
}
@Test
@Retry(3)
public void testNextSecureLongNegativeToPositiveRange() {
for (int i = 0; i < 5; i++) {
checkNextSecureLongUniform(-3, 5);
checkNextSecureLongUniform(-3, 6);
}
}
@Test
@Retry(3)
public void testNextSecureLongNegativeRange() {
for (int i = 0; i < 5; i++) {
checkNextSecureLongUniform(-7, -4);
checkNextSecureLongUniform(-15, -2);
}
}
@Test
@Retry(3)
public void testNextSecureLongPositiveRange() {
for (int i = 0; i < 5; i++) {
checkNextSecureLongUniform(0, 3);
checkNextSecureLongUniform(2, 12);
}
}
private void checkNextSecureLongUniform(int min, int max) {
final Frequency freq = new Frequency();
for (int i = 0; i < smallSampleSize; i++) {
final long value = randomData.nextSecureLong(min, max);
Assert.assertTrue("nextLong range", (value >= min) && (value <= max));
freq.addValue(value);
}
final int len = max - min + 1;
final long[] observed = new long[len];
for (int i = 0; i < len; i++) {
observed[i] = freq.getCount(min + i);
}
final double[] expected = new double[len];
for (int i = 0; i < len; i++) {
expected[i] = 1d / len;
}
TestUtils.assertChiSquareAccept(expected, observed, 0.0001);
}
@Test
public void testNextSecureIntIAE() {
try {
randomData.nextSecureInt(4, 3);
Assert.fail("MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
}
@Test
@Retry(3)
public void testNextSecureIntNegativeToPositiveRange() {
for (int i = 0; i < 5; i++) {
checkNextSecureIntUniform(-3, 5);
checkNextSecureIntUniform(-3, 6);
}
}
@Test
@Retry(3)
public void testNextSecureIntNegativeRange() {
for (int i = 0; i < 5; i++) {
checkNextSecureIntUniform(-7, -4);
checkNextSecureIntUniform(-15, -2);
}
}
@Test
@Retry(3)
public void testNextSecureIntPositiveRange() {
for (int i = 0; i < 5; i++) {
checkNextSecureIntUniform(0, 3);
checkNextSecureIntUniform(2, 12);
}
}
private void checkNextSecureIntUniform(int min, int max) {
final Frequency freq = new Frequency();
for (int i = 0; i < smallSampleSize; i++) {
final int value = randomData.nextSecureInt(min, max);
Assert.assertTrue("nextInt range", (value >= min) && (value <= max));
freq.addValue(value);
}
final int len = max - min + 1;
final long[] observed = new long[len];
for (int i = 0; i < len; i++) {
observed[i] = freq.getCount(min + i);
}
final double[] expected = new double[len];
for (int i = 0; i < len; i++) {
expected[i] = 1d / len;
}
TestUtils.assertChiSquareAccept(expected, observed, 0.0001);
}
/**
* Make sure that empirical distribution of random Poisson(4)'s has P(X <=
* 5) close to actual cumulative Poisson probability and that nextPoisson
* fails when mean is non-positive.
*/
@Test
public void testNextPoisson() {
try {
randomData.nextPoisson(0);
Assert.fail("zero mean -- expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// ignored
}
try {
randomData.nextPoisson(-1);
Assert.fail("negative mean supplied -- MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
try {
randomData.nextPoisson(0);
Assert.fail("0 mean supplied -- MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
final double mean = 4.0d;
final int len = 5;
PoissonDistribution poissonDistribution = new PoissonDistribution(mean);
Frequency f = new Frequency();
randomData.reSeed(1000);
for (int i = 0; i < largeSampleSize; i++) {
f.addValue(randomData.nextPoisson(mean));
}
final long[] observed = new long[len];
for (int i = 0; i < len; i++) {
observed[i] = f.getCount(i + 1);
}
final double[] expected = new double[len];
for (int i = 0; i < len; i++) {
expected[i] = poissonDistribution.probability(i + 1) * largeSampleSize;
}
TestUtils.assertChiSquareAccept(expected, observed, 0.0001);
}
@Test
public void testNextPoissonConsistency() {
// Small integral means
for (int i = 1; i < 100; i++) {
checkNextPoissonConsistency(i);
}
// non-integer means
for (int i = 1; i < 10; i++) {
checkNextPoissonConsistency(randomData.nextUniform(1, 1000));
}
// large means
for (int i = 1; i < 10; i++) {
checkNextPoissonConsistency(randomData.nextUniform(1000, 10000));
}
}
/**
* Verifies that nextPoisson(mean) generates an empirical distribution of values
* consistent with PoissonDistributionImpl by generating 1000 values, computing a
* grouped frequency distribution of the observed values and comparing this distribution
* to the corresponding expected distribution computed using PoissonDistributionImpl.
* Uses ChiSquare test of goodness of fit to evaluate the null hypothesis that the
* distributions are the same. If the null hypothesis can be rejected with confidence
* 1 - alpha, the check fails.
*/
public void checkNextPoissonConsistency(double mean) {
// Generate sample values
final int sampleSize = 1000; // Number of deviates to generate
final int minExpectedCount = 7; // Minimum size of expected bin count
long maxObservedValue = 0;
final double alpha = 0.001; // Probability of false failure
Frequency frequency = new Frequency();
for (int i = 0; i < sampleSize; i++) {
long value = randomData.nextPoisson(mean);
if (value > maxObservedValue) {
maxObservedValue = value;
}
frequency.addValue(value);
}
/*
* Set up bins for chi-square test.
* Ensure expected counts are all at least minExpectedCount.
* Start with upper and lower tail bins.
* Lower bin = [0, lower); Upper bin = [upper, +inf).
*/
PoissonDistribution poissonDistribution = new PoissonDistribution(mean);
int lower = 1;
while (poissonDistribution.cumulativeProbability(lower - 1) * sampleSize < minExpectedCount) {
lower++;
}
int upper = (int) (5 * mean); // Even for mean = 1, not much mass beyond 5
while ((1 - poissonDistribution.cumulativeProbability(upper - 1)) * sampleSize < minExpectedCount) {
upper--;
}
// Set bin width for interior bins. For poisson, only need to look at end bins.
int binWidth = 0;
boolean widthSufficient = false;
double lowerBinMass = 0;
double upperBinMass = 0;
while (!widthSufficient) {
binWidth++;
lowerBinMass = poissonDistribution.cumulativeProbability(lower - 1, lower + binWidth - 1);
upperBinMass = poissonDistribution.cumulativeProbability(upper - binWidth - 1, upper - 1);
widthSufficient = FastMath.min(lowerBinMass, upperBinMass) * sampleSize >= minExpectedCount;
}
/*
* Determine interior bin bounds. Bins are
* [1, lower = binBounds[0]), [lower, binBounds[1]), [binBounds[1], binBounds[2]), ... ,
* [binBounds[binCount - 2], upper = binBounds[binCount - 1]), [upper, +inf)
*
*/
List<Integer> binBounds = new ArrayList<Integer>();
binBounds.add(lower);
int bound = lower + binWidth;
while (bound < upper - binWidth) {
binBounds.add(bound);
bound += binWidth;
}
binBounds.add(upper); // The size of bin [binBounds[binCount - 2], upper) satisfies binWidth <= size < 2*binWidth.
// Compute observed and expected bin counts
final int binCount = binBounds.size() + 1;
long[] observed = new long[binCount];
double[] expected = new double[binCount];
// Bottom bin
observed[0] = 0;
for (int i = 0; i < lower; i++) {
observed[0] += frequency.getCount(i);
}
expected[0] = poissonDistribution.cumulativeProbability(lower - 1) * sampleSize;
// Top bin
observed[binCount - 1] = 0;
for (int i = upper; i <= maxObservedValue; i++) {
observed[binCount - 1] += frequency.getCount(i);
}
expected[binCount - 1] = (1 - poissonDistribution.cumulativeProbability(upper - 1)) * sampleSize;
// Interior bins
for (int i = 1; i < binCount - 1; i++) {
observed[i] = 0;
for (int j = binBounds.get(i - 1); j < binBounds.get(i); j++) {
observed[i] += frequency.getCount(j);
} // Expected count is (mass in [binBounds[i-1], binBounds[i])) * sampleSize
expected[i] = (poissonDistribution.cumulativeProbability(binBounds.get(i) - 1) -
poissonDistribution.cumulativeProbability(binBounds.get(i - 1) -1)) * sampleSize;
}
// Use chisquare test to verify that generated values are poisson(mean)-distributed
ChiSquareTest chiSquareTest = new ChiSquareTest();
// Fail if we can reject null hypothesis that distributions are the same
if (chiSquareTest.chiSquareTest(expected, observed, alpha)) {
StringBuilder msgBuffer = new StringBuilder();
DecimalFormat df = new DecimalFormat("#.##");
msgBuffer.append("Chisquare test failed for mean = ");
msgBuffer.append(mean);
msgBuffer.append(" p-value = ");
msgBuffer.append(chiSquareTest.chiSquareTest(expected, observed));
msgBuffer.append(" chisquare statistic = ");
msgBuffer.append(chiSquareTest.chiSquare(expected, observed));
msgBuffer.append(". \n");
msgBuffer.append("bin\t\texpected\tobserved\n");
for (int i = 0; i < expected.length; i++) {
msgBuffer.append("[");
msgBuffer.append(i == 0 ? 1: binBounds.get(i - 1));
msgBuffer.append(",");
msgBuffer.append(i == binBounds.size() ? "inf": binBounds.get(i));
msgBuffer.append(")");
msgBuffer.append("\t\t");
msgBuffer.append(df.format(expected[i]));
msgBuffer.append("\t\t");
msgBuffer.append(observed[i]);
msgBuffer.append("\n");
}
msgBuffer.append("This test can fail randomly due to sampling error with probability ");
msgBuffer.append(alpha);
msgBuffer.append(".");
Assert.fail(msgBuffer.toString());
}
}
/** test dispersion and failure modes for nextHex() */
@Test
public void testNextHex() {
try {
randomData.nextHexString(-1);
Assert.fail("negative length supplied -- MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
try {
randomData.nextHexString(0);
Assert.fail("zero length supplied -- MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
String hexString = randomData.nextHexString(3);
if (hexString.length() != 3) {
Assert.fail("incorrect length for generated string");
}
hexString = randomData.nextHexString(1);
if (hexString.length() != 1) {
Assert.fail("incorrect length for generated string");
}
try {
hexString = randomData.nextHexString(0);
Assert.fail("zero length requested -- expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// ignored
}
Frequency f = new Frequency();
for (int i = 0; i < smallSampleSize; i++) {
hexString = randomData.nextHexString(100);
if (hexString.length() != 100) {
Assert.fail("incorrect length for generated string");
}
for (int j = 0; j < hexString.length(); j++) {
f.addValue(hexString.substring(j, j + 1));
}
}
double[] expected = new double[16];
long[] observed = new long[16];
for (int i = 0; i < 16; i++) {
expected[i] = (double) smallSampleSize * 100 / 16;
observed[i] = f.getCount(hex[i]);
}
TestUtils.assertChiSquareAccept(expected, observed, 0.001);
}
/** test dispersion and failure modes for nextHex() */
@Test
@Retry(3)
public void testNextSecureHex() {
try {
randomData.nextSecureHexString(-1);
Assert.fail("negative length -- MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
try {
randomData.nextSecureHexString(0);
Assert.fail("zero length -- MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
String hexString = randomData.nextSecureHexString(3);
if (hexString.length() != 3) {
Assert.fail("incorrect length for generated string");
}
hexString = randomData.nextSecureHexString(1);
if (hexString.length() != 1) {
Assert.fail("incorrect length for generated string");
}
try {
hexString = randomData.nextSecureHexString(0);
Assert.fail("zero length requested -- expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// ignored
}
Frequency f = new Frequency();
for (int i = 0; i < smallSampleSize; i++) {
hexString = randomData.nextSecureHexString(100);
if (hexString.length() != 100) {
Assert.fail("incorrect length for generated string");
}
for (int j = 0; j < hexString.length(); j++) {
f.addValue(hexString.substring(j, j + 1));
}
}
double[] expected = new double[16];
long[] observed = new long[16];
for (int i = 0; i < 16; i++) {
expected[i] = (double) smallSampleSize * 100 / 16;
observed[i] = f.getCount(hex[i]);
}
TestUtils.assertChiSquareAccept(expected, observed, 0.001);
}
@Test
public void testNextUniformIAE() {
try {
randomData.nextUniform(4, 3);
Assert.fail("MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
try {
randomData.nextUniform(0, Double.POSITIVE_INFINITY);
Assert.fail("MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
try {
randomData.nextUniform(Double.NEGATIVE_INFINITY, 0);
Assert.fail("MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
try {
randomData.nextUniform(0, Double.NaN);
Assert.fail("MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
try {
randomData.nextUniform(Double.NaN, 0);
Assert.fail("MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
}
@Test
public void testNextUniformUniformPositiveBounds() {
for (int i = 0; i < 5; i++) {
checkNextUniformUniform(0, 10);
}
}
@Test
public void testNextUniformUniformNegativeToPositiveBounds() {
for (int i = 0; i < 5; i++) {
checkNextUniformUniform(-3, 5);
}
}
@Test
public void testNextUniformUniformNegaiveBounds() {
for (int i = 0; i < 5; i++) {
checkNextUniformUniform(-7, -3);
}
}
@Test
public void testNextUniformUniformMaximalInterval() {
for (int i = 0; i < 5; i++) {
checkNextUniformUniform(-Double.MAX_VALUE, Double.MAX_VALUE);
}
}
private void checkNextUniformUniform(double min, double max) {
// Set up bin bounds - min, binBound[0], ..., binBound[binCount-2], max
final int binCount = 5;
final double binSize = max / binCount - min/binCount; // Prevent overflow in extreme value case
final double[] binBounds = new double[binCount - 1];
binBounds[0] = min + binSize;
for (int i = 1; i < binCount - 1; i++) {
binBounds[i] = binBounds[i - 1] + binSize; // + instead of * to avoid overflow in extreme case
}
final Frequency freq = new Frequency();
for (int i = 0; i < smallSampleSize; i++) {
final double value = randomData.nextUniform(min, max);
Assert.assertTrue("nextUniform range", (value > min) && (value < max));
// Find bin
int j = 0;
while (j < binCount - 1 && value > binBounds[j]) {
j++;
}
freq.addValue(j);
}
final long[] observed = new long[binCount];
for (int i = 0; i < binCount; i++) {
observed[i] = freq.getCount(i);
}
final double[] expected = new double[binCount];
for (int i = 0; i < binCount; i++) {
expected[i] = 1d / binCount;
}
TestUtils.assertChiSquareAccept(expected, observed, 0.01);
}
/** test exclusive endpoints of nextUniform **/
@Test
public void testNextUniformExclusiveEndpoints() {
for (int i = 0; i < 1000; i++) {
double u = randomData.nextUniform(0.99, 1);
Assert.assertTrue(u > 0.99 && u < 1);
}
}
/** test failure modes and distribution of nextGaussian() */
@Test
public void testNextGaussian() {
try {
randomData.nextGaussian(0, 0);
Assert.fail("zero sigma -- MathIllegalArgumentException expected");
} catch (MathIllegalArgumentException ex) {
// ignored
}
double[] quartiles = TestUtils.getDistributionQuartiles(new NormalDistribution(0,1));
long[] counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextGaussian(0, 1);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
}
/** test failure modes and distribution of nextExponential() */
@Test
public void testNextExponential() {
try {
randomData.nextExponential(-1);
Assert.fail("negative mean -- expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// ignored
}
try {
randomData.nextExponential(0);
Assert.fail("zero mean -- expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// ignored
}
double[] quartiles;
long[] counts;
// Mean 1
quartiles = TestUtils.getDistributionQuartiles(new ExponentialDistribution(1));
counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextExponential(1);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
// Mean 5
quartiles = TestUtils.getDistributionQuartiles(new ExponentialDistribution(5));
counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextExponential(5);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
}
/** test reseeding, algorithm/provider games */
@Test
public void testConfig() {
randomData.reSeed(1000);
double v = randomData.nextUniform(0, 1);
randomData.reSeed();
Assert.assertTrue("different seeds", FastMath.abs(v - randomData.nextUniform(0, 1)) > 10E-12);
randomData.reSeed(1000);
Assert.assertEquals("same seeds", v, randomData.nextUniform(0, 1), 10E-12);
randomData.reSeedSecure(1000);
String hex = randomData.nextSecureHexString(40);
randomData.reSeedSecure();
Assert.assertTrue("different seeds", !hex.equals(randomData
.nextSecureHexString(40)));
randomData.reSeedSecure(1000);
Assert.assertTrue("same seeds", !hex
.equals(randomData.nextSecureHexString(40)));
/*
* remove this test back soon, since it takes about 4 seconds
*
* try { randomData.setSecureAlgorithm("SHA1PRNG","SUN"); } catch
* (NoSuchProviderException ex) { ; } Assert.assertTrue("different seeds",
* !hex.equals(randomData.nextSecureHexString(40))); try {
* randomData.setSecureAlgorithm("NOSUCHTHING","SUN");
* Assert.fail("expecting NoSuchAlgorithmException"); } catch
* (NoSuchProviderException ex) { ; } catch (NoSuchAlgorithmException
* ex) { ; }
*
* try { randomData.setSecureAlgorithm("SHA1PRNG","NOSUCHPROVIDER");
* Assert.fail("expecting NoSuchProviderException"); } catch
* (NoSuchProviderException ex) { ; }
*/
// test reseeding without first using the generators
RandomDataGenerator rd = new RandomDataGenerator();
rd.reSeed(100);
rd.nextLong(1, 2);
RandomDataGenerator rd2 = new RandomDataGenerator();
rd2.reSeedSecure(2000);
rd2.nextSecureLong(1, 2);
rd = new RandomDataGenerator();
rd.reSeed();
rd.nextLong(1, 2);
rd2 = new RandomDataGenerator();
rd2.reSeedSecure();
rd2.nextSecureLong(1, 2);
}
/** tests for nextSample() sampling from Collection */
@Test
public void testNextSample() {
Object[][] c = { { "0", "1" }, { "0", "2" }, { "0", "3" },
{ "0", "4" }, { "1", "2" }, { "1", "3" }, { "1", "4" },
{ "2", "3" }, { "2", "4" }, { "3", "4" } };
long[] observed = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
double[] expected = { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 };
HashSet<Object> cPop = new HashSet<Object>(); // {0,1,2,3,4}
for (int i = 0; i < 5; i++) {
cPop.add(Integer.toString(i));
}
Object[] sets = new Object[10]; // 2-sets from 5
for (int i = 0; i < 10; i++) {
HashSet<Object> hs = new HashSet<Object>();
hs.add(c[i][0]);
hs.add(c[i][1]);
sets[i] = hs;
}
for (int i = 0; i < 1000; i++) {
Object[] cSamp = randomData.nextSample(cPop, 2);
observed[findSample(sets, cSamp)]++;
}
/*
* Use ChiSquare dist with df = 10-1 = 9, alpha = .001 Change to 21.67
* for alpha = .01
*/
Assert.assertTrue("chi-square test -- will fail about 1 in 1000 times",
testStatistic.chiSquare(expected, observed) < 27.88);
// Make sure sample of size = size of collection returns same collection
HashSet<Object> hs = new HashSet<Object>();
hs.add("one");
Object[] one = randomData.nextSample(hs, 1);
String oneString = (String) one[0];
if ((one.length != 1) || !oneString.equals("one")) {
Assert.fail("bad sample for set size = 1, sample size = 1");
}
// Make sure we fail for sample size > collection size
try {
one = randomData.nextSample(hs, 2);
Assert.fail("sample size > set size, expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// ignored
}
// Make sure we fail for empty collection
try {
hs = new HashSet<Object>();
one = randomData.nextSample(hs, 0);
Assert.fail("n = k = 0, expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// ignored
}
}
@SuppressWarnings("unchecked")
private int findSample(Object[] u, Object[] samp) {
for (int i = 0; i < u.length; i++) {
HashSet<Object> set = (HashSet<Object>) u[i];
HashSet<Object> sampSet = new HashSet<Object>();
for (int j = 0; j < samp.length; j++) {
sampSet.add(samp[j]);
}
if (set.equals(sampSet)) {
return i;
}
}
Assert.fail("sample not found:{" + samp[0] + "," + samp[1] + "}");
return -1;
}
/** tests for nextPermutation */
@Test
public void testNextPermutation() {
int[][] p = { { 0, 1, 2 }, { 0, 2, 1 }, { 1, 0, 2 }, { 1, 2, 0 },
{ 2, 0, 1 }, { 2, 1, 0 } };
long[] observed = { 0, 0, 0, 0, 0, 0 };
double[] expected = { 100, 100, 100, 100, 100, 100 };
for (int i = 0; i < 600; i++) {
int[] perm = randomData.nextPermutation(3, 3);
observed[findPerm(p, perm)]++;
}
String[] labels = {"{0, 1, 2}", "{ 0, 2, 1 }", "{ 1, 0, 2 }",
"{ 1, 2, 0 }", "{ 2, 0, 1 }", "{ 2, 1, 0 }"};
TestUtils.assertChiSquareAccept(labels, expected, observed, 0.001);
// Check size = 1 boundary case
int[] perm = randomData.nextPermutation(1, 1);
if ((perm.length != 1) || (perm[0] != 0)) {
Assert.fail("bad permutation for n = 1, sample k = 1");
// Make sure we fail for k size > n
try {
perm = randomData.nextPermutation(2, 3);
Assert.fail("permutation k > n, expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// ignored
}
// Make sure we fail for n = 0
try {
perm = randomData.nextPermutation(0, 0);
Assert.fail("permutation k = n = 0, expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// ignored
}
// Make sure we fail for k < n < 0
try {
perm = randomData.nextPermutation(-1, -3);
Assert.fail("permutation k < n < 0, expecting MathIllegalArgumentException");
} catch (MathIllegalArgumentException ex) {
// ignored
}
}
}
// Disable until we have equals
//public void testSerial() {
// Assert.assertEquals(randomData, TestUtils.serializeAndRecover(randomData));
//}
private int findPerm(int[][] p, int[] samp) {
for (int i = 0; i < p.length; i++) {
boolean good = true;
for (int j = 0; j < samp.length; j++) {
if (samp[j] != p[i][j]) {
good = false;
}
}
if (good) {
return i;
}
}
Assert.fail("permutation not found");
return -1;
}
@Test
public void testNextBeta() {
double[] quartiles = TestUtils.getDistributionQuartiles(new BetaDistribution(2,5));
long[] counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextBeta(2, 5);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
}
@Test
public void testNextCauchy() {
double[] quartiles = TestUtils.getDistributionQuartiles(new CauchyDistribution(1.2, 2.1));
long[] counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextCauchy(1.2, 2.1);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
}
@Test
public void testNextChiSquare() {
double[] quartiles = TestUtils.getDistributionQuartiles(new ChiSquaredDistribution(12));
long[] counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextChiSquare(12);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
}
@Test
public void testNextF() {
double[] quartiles = TestUtils.getDistributionQuartiles(new FDistribution(12, 5));
long[] counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextF(12, 5);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
}
@Test
public void testNextGamma() {
double[] quartiles;
long[] counts;
// Tests shape > 1, one case in the rejection sampling
quartiles = TestUtils.getDistributionQuartiles(new GammaDistribution(4, 2));
counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextGamma(4, 2);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
// Tests shape <= 1, another case in the rejection sampling
quartiles = TestUtils.getDistributionQuartiles(new GammaDistribution(0.3, 3));
counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextGamma(0.3, 3);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
}
@Test
public void testNextT() {
double[] quartiles = TestUtils.getDistributionQuartiles(new TDistribution(10));
long[] counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextT(10);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
}
@Test
public void testNextWeibull() {
double[] quartiles = TestUtils.getDistributionQuartiles(new WeibullDistribution(1.2, 2.1));
long[] counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {
double value = randomData.nextWeibull(1.2, 2.1);
TestUtils.updateCounts(value, counts, quartiles);
}
TestUtils.assertChiSquareAccept(expected, counts, 0.001);
}
@Test
public void testNextBinomial() {
BinomialDistributionTest testInstance = new BinomialDistributionTest();
int[] densityPoints = testInstance.makeDensityTestPoints();
double[] densityValues = testInstance.makeDensityTestValues();
int sampleSize = 1000;
int length = TestUtils.eliminateZeroMassPoints(densityPoints, densityValues);
BinomialDistribution distribution = (BinomialDistribution) testInstance.makeDistribution();
double[] expectedCounts = new double[length];
long[] observedCounts = new long[length];
for (int i = 0; i < length; i++) {
expectedCounts[i] = sampleSize * densityValues[i];
}
randomData.reSeed(1000);
for (int i = 0; i < sampleSize; i++) {
int value = randomData.nextBinomial(distribution.getNumberOfTrials(),
distribution.getProbabilityOfSuccess());
for (int j = 0; j < length; j++) {
if (value == densityPoints[j]) {
observedCounts[j]++;
}
}
}
TestUtils.assertChiSquareAccept(densityPoints, expectedCounts, observedCounts, .001);
}
@Test
public void testNextHypergeometric() {
HypergeometricDistributionTest testInstance = new HypergeometricDistributionTest();
int[] densityPoints = testInstance.makeDensityTestPoints();
double[] densityValues = testInstance.makeDensityTestValues();
int sampleSize = 1000;
int length = TestUtils.eliminateZeroMassPoints(densityPoints, densityValues);
HypergeometricDistribution distribution = (HypergeometricDistribution) testInstance.makeDistribution();
double[] expectedCounts = new double[length];
long[] observedCounts = new long[length];
for (int i = 0; i < length; i++) {
expectedCounts[i] = sampleSize * densityValues[i];
}
randomData.reSeed(1000);
for (int i = 0; i < sampleSize; i++) {
int value = randomData.nextHypergeometric(distribution.getPopulationSize(),
distribution.getNumberOfSuccesses(), distribution.getSampleSize());
for (int j = 0; j < length; j++) {
if (value == densityPoints[j]) {
observedCounts[j]++;
}
}
}
TestUtils.assertChiSquareAccept(densityPoints, expectedCounts, observedCounts, .001);
}
@Test
public void testNextPascal() {
PascalDistributionTest testInstance = new PascalDistributionTest();
int[] densityPoints = testInstance.makeDensityTestPoints();
double[] densityValues = testInstance.makeDensityTestValues();
int sampleSize = 1000;
int length = TestUtils.eliminateZeroMassPoints(densityPoints, densityValues);
PascalDistribution distribution = (PascalDistribution) testInstance.makeDistribution();
double[] expectedCounts = new double[length];
long[] observedCounts = new long[length];
for (int i = 0; i < length; i++) {
expectedCounts[i] = sampleSize * densityValues[i];
}
randomData.reSeed(1000);
for (int i = 0; i < sampleSize; i++) {
int value = randomData.nextPascal(distribution.getNumberOfSuccesses(), distribution.getProbabilityOfSuccess());
for (int j = 0; j < length; j++) {
if (value == densityPoints[j]) {
observedCounts[j]++;
}
}
}
TestUtils.assertChiSquareAccept(densityPoints, expectedCounts, observedCounts, .001);
}
@Test
public void testNextZipf() {
ZipfDistributionTest testInstance = new ZipfDistributionTest();
int[] densityPoints = testInstance.makeDensityTestPoints();
double[] densityValues = testInstance.makeDensityTestValues();
int sampleSize = 1000;
int length = TestUtils.eliminateZeroMassPoints(densityPoints, densityValues);
ZipfDistribution distribution = (ZipfDistribution) testInstance.makeDistribution();
double[] expectedCounts = new double[length];
long[] observedCounts = new long[length];
for (int i = 0; i < length; i++) {
expectedCounts[i] = sampleSize * densityValues[i];
}
randomData.reSeed(1000);
for (int i = 0; i < sampleSize; i++) {
int value = randomData.nextZipf(distribution.getNumberOfElements(), distribution.getExponent());
for (int j = 0; j < length; j++) {
if (value == densityPoints[j]) {
observedCounts[j]++;
}
}
}
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);
}
}