commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pste...@apache.org
Subject svn commit: r949553 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math/random/RandomDataImpl.java site/xdoc/changes.xml site/xdoc/userguide/random.xml test/java/org/apache/commons/math/random/RandomDataTest.java
Date Sun, 30 May 2010 18:30:50 GMT
Author: psteitz
Date: Sun May 30 18:30:50 2010
New Revision: 949553

URL: http://svn.apache.org/viewvc?rev=949553&view=rev
Log:
Added random data generation methods to RandomDataImpl for the remaining
distributions in the distributions package.  Added a generic nextInversionDeviate method that
takes a discrete or continuous distribution as argument and generates
a random deviate from the distribution.
JIRA: MATH-310

Modified:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/random/RandomDataImpl.java
    commons/proper/math/trunk/src/site/xdoc/changes.xml
    commons/proper/math/trunk/src/site/xdoc/userguide/random.xml
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/random/RandomDataTest.java

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/random/RandomDataImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/random/RandomDataImpl.java?rev=949553&r1=949552&r2=949553&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/random/RandomDataImpl.java
(original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/random/RandomDataImpl.java
Sun May 30 18:30:50 2010
@@ -24,7 +24,21 @@ import java.security.NoSuchAlgorithmExce
 import java.security.NoSuchProviderException;
 import java.util.Collection;
 
+import org.apache.commons.math.MathException;
 import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.distribution.BetaDistributionImpl;
+import org.apache.commons.math.distribution.BinomialDistributionImpl;
+import org.apache.commons.math.distribution.CauchyDistributionImpl;
+import org.apache.commons.math.distribution.ChiSquaredDistributionImpl;
+import org.apache.commons.math.distribution.ContinuousDistribution;
+import org.apache.commons.math.distribution.FDistributionImpl;
+import org.apache.commons.math.distribution.GammaDistributionImpl;
+import org.apache.commons.math.distribution.HypergeometricDistributionImpl;
+import org.apache.commons.math.distribution.IntegerDistribution;
+import org.apache.commons.math.distribution.PascalDistributionImpl;
+import org.apache.commons.math.distribution.TDistributionImpl;
+import org.apache.commons.math.distribution.WeibullDistributionImpl;
+import org.apache.commons.math.distribution.ZipfDistributionImpl;
 import org.apache.commons.math.util.MathUtils;
 
 /**
@@ -62,7 +76,7 @@ import org.apache.commons.math.util.Math
  * it any easier to predict subsequent values.</li>
  * <li>
  * When a new <code>RandomDataImpl</code> is created, the underlying random
- * number generators are <strong>not</strong> intialized. If you do not
+ * number generators are <strong>not</strong> initialized. If you do not
  * explicitly seed the default non-secure generator, it is seeded with the
  * current time in milliseconds on first use. The same holds for the secure
  * generator. If you provide a <code>RandomGenerator</code> to the constructor,
@@ -507,6 +521,159 @@ public class RandomDataImpl implements R
     }
 
     /**
+     * Generates a random value from the {@link BetaDistributionImpl Beta Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(ContinuousDistribution) inversion}
+     * to generate random values.
+     *
+     * @param alpha first distribution shape parameter
+     * @param beta second distribution shape parameter
+     * @return random value sampled from the beta(alpha, beta) distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public double nextBeta(double alpha, double beta) throws MathException {
+        return nextInversionDeviate(new BetaDistributionImpl(alpha, beta));
+    }
+
+    /**
+     * Generates a random value from the {@link BinomialDistributionImpl Binomial Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(ContinuousDistribution) inversion}
+     * to generate random values.
+     *
+     * @param numberOfTrials number of trials of the Binomial distribution
+     * @param probabilityOfSuccess probability of success of the Binomial distribution
+     * @return random value sampled from the Binomial(numberOfTrials, probabilityOfSuccess)
distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public int nextBinomial(int numberOfTrials, double probabilityOfSuccess) throws MathException
{
+        return nextInversionDeviate(new BinomialDistributionImpl(numberOfTrials, probabilityOfSuccess));
+    }
+
+    /**
+     * Generates a random value from the {@link CauchyDistributionImpl Cauchy Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(ContinuousDistribution) inversion}
+     * to generate random values.
+     *
+     * @param median the median of the Cauchy distribution
+     * @param scale the scale parameter of the Cauchy distribution
+     * @return random value sampled from the Cauchy(median, scale) distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public double nextCauchy(double median, double scale) throws MathException {
+        return nextInversionDeviate(new CauchyDistributionImpl(median, scale));
+    }
+
+    /**
+     * Generates a random value from the {@link ChiSquaredDistributionImpl ChiSquare Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(ContinuousDistribution) inversion}
+     * to generate random values.
+     *
+     * @param df the degrees of freedom of the ChiSquare distribution
+     * @return random value sampled from the ChiSquare(df) distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public double nextChiSquare(double df) throws MathException {
+        return nextInversionDeviate(new ChiSquaredDistributionImpl(df));
+    }
+
+    /**
+     * Generates a random value from the {@link FDistributionImpl F Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(ContinuousDistribution) inversion}
+     * to generate random values.
+     *
+     * @param numeratorDf the numerator degrees of freedom of the F distribution
+     * @param denominatorDf the denominator degrees of freedom of the F distribution
+     * @return random value sampled from the F(numeratorDf, denominatorDf) distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public double nextF(double numeratorDf, double denominatorDf) throws MathException {
+        return nextInversionDeviate(new FDistributionImpl(numeratorDf, denominatorDf));
+    }
+
+    /**
+     * Generates a random value from the {@link GammaDistributionImpl Gamma Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(ContinuousDistribution) inversion}
+     * to generate random values.
+     *
+     * @param shape the median of the Gamma distribution
+     * @param scale the scale parameter of the Gamma distribution
+     * @return random value sampled from the Gamma(shape, scale) distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public double nextGamma(double shape, double scale) throws MathException {
+        return nextInversionDeviate(new GammaDistributionImpl(shape, scale));
+    }
+
+    /**
+     * Generates a random value from the {@link HypergeometricDistributionImpl Hypergeometric
Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(IntegerDistribution) inversion}
+     * to generate random values.
+     *
+     * @param populationSize the population size of the Hypergeometric distribution
+     * @param numberOfSuccesses number of successes in the population of the Hypergeometric
distribution
+     * @param sampleSize the sample size of the Hypergeometric distribution
+     * @return random value sampled from the Hypergeometric(numberOfSuccesses, sampleSize)
distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public int nextHypergeometric(int populationSize, int numberOfSuccesses, int sampleSize)
throws MathException {
+        return nextInversionDeviate(new HypergeometricDistributionImpl(populationSize, numberOfSuccesses,
sampleSize));
+    }
+
+    /**
+     * Generates a random value from the {@link PascalDistributionImpl Pascal Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(IntegerDistribution) inversion}
+     * to generate random values.
+     *
+     * @param r the number of successes of the Pascal distribution
+     * @param p the probability of success of the Pascal distribution
+     * @return random value sampled from the Pascal(r, p) distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public int nextPascal(int r, double p) throws MathException {
+        return nextInversionDeviate(new PascalDistributionImpl(r, p));
+    }
+
+    /**
+     * Generates a random value from the {@link TDistributionImpl T Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(ContinuousDistribution) inversion}
+     * to generate random values.
+     *
+     * @param df the degrees of freedom of the T distribution
+     * @return random value from the T(df) distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public double nextT(double df) throws MathException {
+        return nextInversionDeviate(new TDistributionImpl(df));
+    }
+
+    /**
+     * Generates a random value from the {@link WeibullDistributionImpl Weibull Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(ContinuousDistribution) inversion}
+     * to generate random values.
+     *
+     * @param shape the shape parameter of the Weibull distribution
+     * @param scale the scale parameter of the Weibull distribution
+     * @return random value sampled from the Weibull(shape, size) distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public double nextWeibull(double shape, double scale) throws MathException {
+        return nextInversionDeviate(new WeibullDistributionImpl(shape, scale));
+    }
+
+    /**
+     * Generates a random value from the {@link ZipfDistributionImpl Zipf Distribution}.
+     * This implementation uses {@link #nextInversionDeviate(IntegerDistribution) inversion}
+     * to generate random values.
+     *
+     * @param numberOfElements the number of elements of the ZipfDistribution
+     * @param exponent the exponent of the ZipfDistribution
+     * @return random value sampled from the Zipf(numberOfElements, exponent) distribution
+     * @throws MathException if an error occurs generating the random value
+     */
+    public int nextZipf(int numberOfElements, double exponent) throws MathException {
+        return nextInversionDeviate(new ZipfDistributionImpl(numberOfElements, exponent));
+    }
+
+    /**
      * Returns the RandomGenerator used to generate non-secure random data.
      * <p>
      * Creates and initializes a default generator if null.
@@ -705,6 +872,37 @@ public class RandomDataImpl implements R
         return result;
     }
 
+    /**
+     * Generate a random deviate from the given distribution using the
+     * <a href="http://en.wikipedia.org/wiki/Inverse_transform_sampling"> inversion
method.</a>
+     *
+     * @param distribution Continuous distribution to generate a random value from
+     * @return a random value sampled from the given distribution
+     * @throws MathException if an error occurs computing the inverse cumulative distribution
function
+     */
+    public double nextInversionDeviate(ContinuousDistribution distribution) throws MathException
{
+        return distribution.inverseCumulativeProbability(nextUniform(0, 1));
+
+    }
+
+    /**
+     * Generate a random deviate from the given distribution using the
+     * <a href="http://en.wikipedia.org/wiki/Inverse_transform_sampling"> inversion
method.</a>
+     *
+     * @param distribution Integer distribution to generate a random value from
+     * @return a random value sampled from the given distribution
+     * @throws MathException if an error occurs computing the inverse cumulative distribution
function
+     */
+    public int nextInversionDeviate(IntegerDistribution distribution) throws MathException
{
+        final double target = nextUniform(0, 1);
+        final int glb = distribution.inverseCumulativeProbability(target);
+        if (distribution.cumulativeProbability(glb) == 1.0d) { // No mass above
+            return glb;
+        } else {
+            return glb + 1;
+        }
+    }
+
     // ------------------------Private methods----------------------------------
 
     /**

Modified: commons/proper/math/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/changes.xml?rev=949553&r1=949552&r2=949553&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Sun May 30 18:30:50 2010
@@ -52,6 +52,11 @@ The <action> type attribute can be add,u
     If the output is not quite correct, check for invisible trailing spaces!
      -->
     <release version="2.2" date="TBD" description="TBD">
+      <action dev="psteitz" type="update" issue="MATH-310">
+        Added random data generation methods to RandomDataImpl for the remaining distributions
in the
+        distributions package. Added a generic nextInversionDeviate method that takes a discrete
+        or continuous distribution as argument and generates a random deviate from the distribution.
+      </action>
       <action dev="luc" type="fix" issue="MATH-362" >
         Fixed Levenberg-Marquardt optimizer that did not use the vectorial convergence checker.
         Now this optimizer can use either the general vectorial convergence checker or its
own

Modified: commons/proper/math/trunk/src/site/xdoc/userguide/random.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/userguide/random.xml?rev=949553&r1=949552&r2=949553&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/userguide/random.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/userguide/random.xml Sun May 30 18:30:50 2010
@@ -83,20 +83,13 @@
     probability distribution</a> basically amounts to asserting that different
     ranges in the set  of possible values of a random variable have
     different probabilities of containing the value.  Commons Math supports
-    generating random sequences from the following probability distributions.
+    generating random sequences from each of the distributions in the
+    <a href="../apidocs/org/apache/commons/math/distribution/package-summary.html">
+    distributions</a> package.
     The javadoc for the <code>nextXxx</code> methods in 
-    <code>RandomDataImpl</code> describes the algorithms used to generate
-    random deviates from each of these distributions. 
-    <ul>
-    <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3662.htm">
-     uniform distribution</a></li>
-    <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3667.htm">
-     exponential distribution</a></li>
-    <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda366j.htm">
-    poisson distribution</a></li>
-    <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm">
-    Gaussian distribution</a></li>
-    </ul>        
+    <a href="../apidocs/org/apache/commons/math/random/RandomDataImpl.html">
+    RandomDataImpl</a> describes the algorithms used to generate
+    random deviates.   
     </dd>
     <dt>Cryptographically secure random sequences</dt>
     <dd>It is possible for a sequence of numbers to appear random, but

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/random/RandomDataTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/random/RandomDataTest.java?rev=949553&r1=949552&r2=949553&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/random/RandomDataTest.java
(original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/random/RandomDataTest.java
Sun May 30 18:30:50 2010
@@ -24,8 +24,25 @@ import java.util.List;
 import junit.framework.AssertionFailedError;
 
 import org.apache.commons.math.RetryTestCase;
+import org.apache.commons.math.TestUtils;
+import org.apache.commons.math.distribution.BetaDistributionImpl;
+import org.apache.commons.math.distribution.BinomialDistributionImpl;
+import org.apache.commons.math.distribution.BinomialDistributionTest;
+import org.apache.commons.math.distribution.CauchyDistributionImpl;
+import org.apache.commons.math.distribution.ChiSquaredDistributionImpl;
+import org.apache.commons.math.distribution.ContinuousDistribution;
+import org.apache.commons.math.distribution.FDistributionImpl;
+import org.apache.commons.math.distribution.GammaDistributionImpl;
+import org.apache.commons.math.distribution.HypergeometricDistributionImpl;
+import org.apache.commons.math.distribution.HypergeometricDistributionTest;
+import org.apache.commons.math.distribution.PascalDistributionImpl;
+import org.apache.commons.math.distribution.PascalDistributionTest;
 import org.apache.commons.math.distribution.PoissonDistribution;
 import org.apache.commons.math.distribution.PoissonDistributionImpl;
+import org.apache.commons.math.distribution.TDistributionImpl;
+import org.apache.commons.math.distribution.WeibullDistributionImpl;
+import org.apache.commons.math.distribution.ZipfDistributionImpl;
+import org.apache.commons.math.distribution.ZipfDistributionTest;
 import org.apache.commons.math.stat.Frequency;
 import org.apache.commons.math.stat.descriptive.SummaryStatistics;
 import org.apache.commons.math.stat.inference.ChiSquareTest;
@@ -45,13 +62,13 @@ public class RandomDataTest extends Retr
         randomData = new RandomDataImpl();
     }
 
-    protected long smallSampleSize = 1000;
-    protected double[] expected = { 250, 250, 250, 250 };
-    protected int largeSampleSize = 10000;
-    private String[] hex = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+    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 RandomDataImpl randomData = null;
-    protected ChiSquareTestImpl testStatistic = new ChiSquareTestImpl();
+    protected final ChiSquareTestImpl testStatistic = new ChiSquareTestImpl();
 
     public void testNextIntExtremeValues() {
         int x = randomData.nextInt(Integer.MIN_VALUE, Integer.MAX_VALUE);
@@ -774,4 +791,259 @@ public class RandomDataTest extends Retr
         fail("permutation not found");
         return -1;
     }
+    
+    public void testNextInversionDeviate() throws Exception {
+        // Set the seed for the default random generator
+        randomData.reSeed(100);
+        double[] quantiles = new double[10];
+        for (int i = 0; i < 10; i++) {
+            quantiles[i] = randomData.nextUniform(0, 1);
+        }
+        // Reseed again so the inversion generator gets the same sequence
+        randomData.reSeed(100);
+        BetaDistributionImpl betaDistribution = new BetaDistributionImpl(2, 4);
+        /*
+         *  Generate a sequence of deviates using inversion - the distribution function
+         *  evaluated at the random value from the distribution should match the uniform
+         *  random value used to generate it, which is stored in the quantiles[] array.
+         */
+        for (int i = 0; i < 10; i++) {
+            double value = randomData.nextInversionDeviate(betaDistribution);
+            assertEquals(betaDistribution.cumulativeProbability(value), quantiles[i], 10E-9);
+        } 
+    }
+    
+    public void testNextBeta() throws Exception {
+        double[] quartiles = getDistributionQuartiles(new BetaDistributionImpl(2,5));
+        long[] counts = new long[4];
+        randomData.reSeed(1000);
+        for (int i = 0; i < 1000; i++) {
+            double value = randomData.nextBeta(2, 5);
+            updateCounts(value, counts, quartiles);
+        }
+        TestUtils.assertChiSquareAccept(quartiles, expected, counts, 0.001);
+    }
+    
+    public void testNextCauchy() throws Exception {
+        double[] quartiles = getDistributionQuartiles(new CauchyDistributionImpl(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);
+            updateCounts(value, counts, quartiles);
+        }
+        TestUtils.assertChiSquareAccept(quartiles, expected, counts, 0.001);
+    }
+    
+    public void testNextChiSquare() throws Exception {
+        double[] quartiles = getDistributionQuartiles(new ChiSquaredDistributionImpl(12));
+        long[] counts = new long[4];
+        randomData.reSeed(1000);
+        for (int i = 0; i < 1000; i++) {
+            double value = randomData.nextChiSquare(12);
+            updateCounts(value, counts, quartiles);
+        }
+        TestUtils.assertChiSquareAccept(quartiles, expected, counts, 0.001);
+    }
+    
+    public void testNextF() throws Exception {
+        double[] quartiles = getDistributionQuartiles(new FDistributionImpl(12, 5));
+        long[] counts = new long[4];
+        randomData.reSeed(1000);
+        for (int i = 0; i < 1000; i++) {
+            double value = randomData.nextF(12, 5);
+            updateCounts(value, counts, quartiles);
+        }
+        TestUtils.assertChiSquareAccept(quartiles, expected, counts, 0.001);
+    }
+    
+    public void testNextGamma() throws Exception {
+        double[] quartiles = getDistributionQuartiles(new GammaDistributionImpl(4, 2));
+        long[] counts = new long[4];
+        randomData.reSeed(1000);
+        for (int i = 0; i < 1000; i++) {
+            double value = randomData.nextGamma(4, 2);
+            updateCounts(value, counts, quartiles);
+        }
+        TestUtils.assertChiSquareAccept(quartiles, expected, counts, 0.001);
+    }
+    
+    public void testNextT() throws Exception {
+        double[] quartiles = getDistributionQuartiles(new TDistributionImpl(10));
+        long[] counts = new long[4];
+        randomData.reSeed(1000);
+        for (int i = 0; i < 1000; i++) {
+            double value = randomData.nextT(10);
+            updateCounts(value, counts, quartiles);
+        }
+        TestUtils.assertChiSquareAccept(quartiles, expected, counts, 0.001);
+    }
+    
+    public void testNextWeibull() throws Exception {
+        double[] quartiles = getDistributionQuartiles(new WeibullDistributionImpl(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);
+            updateCounts(value, counts, quartiles);
+        }
+        TestUtils.assertChiSquareAccept(quartiles, expected, counts, 0.001);
+    }
+    
+    /**
+     * Computes the 25th, 50th and 75th percentiles of the given distribution and returns
+     * these values in an array.
+     */
+    private double[] getDistributionQuartiles(ContinuousDistribution distribution) throws
Exception {
+        double[] quantiles = new double[3];
+        quantiles[0] = distribution.inverseCumulativeProbability(0.25d);
+        quantiles[1] = distribution.inverseCumulativeProbability(0.5d);
+        quantiles[2] = distribution.inverseCumulativeProbability(0.75d);
+        return quantiles;
+    }
+    
+    /**
+     * Updates observed counts of values in quartiles.
+     * counts[0] <-> 1st quartile ... counts[3] <-> top quartile
+     */
+    private void updateCounts(double value, long[] counts, double[] quantiles) {
+        if (value < quantiles[0]) {
+            counts[0]++;
+        } else if (value > quantiles[2]) {
+            counts[3]++;
+        } else if (value > quantiles[1]) {
+            counts[2]++;
+        } else {
+            counts[1]++;
+        }  
+    }
+    
+    public void testNextBinomial() throws Exception {
+        BinomialDistributionTest testInstance = new BinomialDistributionTest("");
+        int[] densityPoints = testInstance.makeDensityTestPoints();
+        double[] densityValues = testInstance.makeDensityTestValues();
+        int sampleSize = 1000;
+        int length = eliminateZeroMassPoints(densityPoints, densityValues);
+        BinomialDistributionImpl distribution = (BinomialDistributionImpl) 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);
+    }
+    
+    public void testNextHypergeometric() throws Exception {
+        HypergeometricDistributionTest testInstance = new HypergeometricDistributionTest("");
+        int[] densityPoints = testInstance.makeDensityTestPoints();
+        double[] densityValues = testInstance.makeDensityTestValues();
+        int sampleSize = 1000;
+        int length = eliminateZeroMassPoints(densityPoints, densityValues);
+        HypergeometricDistributionImpl distribution = (HypergeometricDistributionImpl) 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);
+    }
+    
+    public void testNextPascal() throws Exception {
+        PascalDistributionTest testInstance = new PascalDistributionTest("");
+        int[] densityPoints = testInstance.makeDensityTestPoints();
+        double[] densityValues = testInstance.makeDensityTestValues();
+        int sampleSize = 1000;
+        int length = eliminateZeroMassPoints(densityPoints, densityValues);
+        PascalDistributionImpl distribution = (PascalDistributionImpl) 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);
+    }
+    
+    public void testNextZipf() throws Exception {
+        ZipfDistributionTest testInstance = new ZipfDistributionTest("");
+        int[] densityPoints = testInstance.makeDensityTestPoints();
+        double[] densityValues = testInstance.makeDensityTestValues();
+        int sampleSize = 1000;
+        int length = eliminateZeroMassPoints(densityPoints, densityValues);
+        ZipfDistributionImpl distribution = (ZipfDistributionImpl) 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);
+    }
+    
+    /**
+     * Eliminates points with zero mass from densityPoints and densityValues parallel
+     * arrays.  Returns the number of positive mass points and collapses the arrays so
+     * that the first <returned value> elements of the input arrays represent the positive
+     * mass points.
+     */
+    private int eliminateZeroMassPoints(int[] densityPoints, double[] densityValues) {
+        int positiveMassCount = 0;
+        for (int i = 0; i < densityValues.length; i++) {
+            if (densityValues[i] > 0) {
+                positiveMassCount++;
+            }
+        }
+        if (positiveMassCount < densityValues.length) {
+            int[] newPoints = new int[positiveMassCount];
+            double[] newValues = new double[positiveMassCount];
+            int j = 0;
+            for (int i = 0; i < densityValues.length; i++) {
+                if (densityValues[i] > 0) {
+                    newPoints[j] = densityPoints[i];
+                    newValues[j] = densityValues[i];
+                    j++;
+                }
+            }
+            System.arraycopy(newPoints,0,densityPoints,0,positiveMassCount);
+            System.arraycopy(newValues,0,densityValues,0,positiveMassCount);
+        }
+        return positiveMassCount;
+    } 
+    
 }



Mime
View raw message