http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java new file mode 100644 index 0000000..3b2889e --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java @@ -0,0 +1,213 @@ +/* + * 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.statistics.distribution; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Test cases for {@link NormalDistribution}. Extends + * {@link ContinuousDistributionAbstractTest}. See class javadoc of that class + * for details. + * + */ +public class NormalDistributionTest extends ContinuousDistributionAbstractTest { + + //-------------- Implementations for abstract methods ----------------------- + + /** Creates the default real distribution instance to use in tests. */ + @Override + public NormalDistribution makeDistribution() { + return new NormalDistribution(2.1, 1.4); + } + + /** Creates the default cumulative probability distribution test input values */ + @Override + public double[] makeCumulativeTestPoints() { + // quantiles computed using R + return new double[] {-2.226325228634938d, -1.156887023657177d, -0.643949578356075d, -0.2027950777320613d, 0.305827808237559d, + 6.42632522863494d, 5.35688702365718d, 4.843949578356074d, 4.40279507773206d, 3.89417219176244d}; + } + + /** Creates the default cumulative probability density test expected values */ + @Override + public double[] makeCumulativeTestValues() { + return new double[] {0.001d, 0.01d, 0.025d, 0.05d, 0.1d, 0.999d, + 0.990d, 0.975d, 0.950d, 0.900d}; + } + + /** Creates the default probability density test expected values */ + @Override + public double[] makeDensityTestValues() { + return new double[] {0.00240506434076, 0.0190372444310, 0.0417464784322, 0.0736683145538, 0.125355951380, + 0.00240506434076, 0.0190372444310, 0.0417464784322, 0.0736683145538, 0.125355951380}; + } + + // --------------------- Override tolerance -------------- + private double defaultTolerance = 1e-7; + @Override + public void setUp() { + super.setUp(); + setTolerance(defaultTolerance); + } + + //---------------------------- Additional test cases ------------------------- + + private void verifyQuantiles() { + NormalDistribution distribution = (NormalDistribution) getDistribution(); + double mu = distribution.getMean(); + double sigma = distribution.getStandardDeviation(); + setCumulativeTestPoints( new double[] {mu - 2 *sigma, mu - sigma, + mu, mu + sigma, mu + 2 * sigma, mu + 3 * sigma, mu + 4 * sigma, + mu + 5 * sigma}); + // Quantiles computed using R (same as Mathematica) + setCumulativeTestValues(new double[] {0.02275013194817921, 0.158655253931457, 0.5, 0.841344746068543, + 0.977249868051821, 0.99865010196837, 0.999968328758167, 0.999999713348428}); + verifyCumulativeProbabilities(); + } + + @Test + public void testQuantiles() { + setDensityTestValues(new double[] {0.0385649760808, 0.172836231799, 0.284958771715, 0.172836231799, 0.0385649760808, + 0.00316560600853, 9.55930184035e-05, 1.06194251052e-06}); + verifyQuantiles(); + verifyDensities(); + + setDistribution(new NormalDistribution(0, 1)); + setDensityTestValues(new double[] {0.0539909665132, 0.241970724519, 0.398942280401, 0.241970724519, 0.0539909665132, + 0.00443184841194, 0.000133830225765, 1.48671951473e-06}); + verifyQuantiles(); + verifyDensities(); + + setDistribution(new NormalDistribution(0, 0.1)); + setDensityTestValues(new double[] {0.539909665132, 2.41970724519, 3.98942280401, 2.41970724519, + 0.539909665132, 0.0443184841194, 0.00133830225765, 1.48671951473e-05}); + verifyQuantiles(); + verifyDensities(); + } + + @Test + public void testInverseCumulativeProbabilityExtremes() { + setInverseCumulativeTestPoints(new double[] {0, 1}); + setInverseCumulativeTestValues(new double[] {Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}); + verifyInverseCumulativeProbabilities(); + } + + // MATH-1257 + @Test + public void testCumulativeProbability() { + final ContinuousDistribution dist = new NormalDistribution(0, 1); + double x = -10; + double expected = 7.61985e-24; + double v = dist.cumulativeProbability(x); + double tol = 1e-5; + Assert.assertEquals(1, v / expected, 1e-5); + } + + @Test + public void testGetMean() { + NormalDistribution distribution = (NormalDistribution) getDistribution(); + Assert.assertEquals(2.1, distribution.getMean(), 0); + } + + @Test + public void testGetStandardDeviation() { + NormalDistribution distribution = (NormalDistribution) getDistribution(); + Assert.assertEquals(1.4, distribution.getStandardDeviation(), 0); + } + + @Test(expected=IllegalArgumentException.class) + public void testPrecondition1() { + new NormalDistribution(1, 0); + } + + @Test + public void testDensity() { + double [] x = new double[]{-2, -1, 0, 1, 2}; + // R 2.5: print(dnorm(c(-2,-1,0,1,2)), digits=10) + checkDensity(0, 1, x, new double[]{0.05399096651, 0.24197072452, 0.39894228040, 0.24197072452, 0.05399096651}); + // R 2.5: print(dnorm(c(-2,-1,0,1,2), mean=1.1), digits=10) + checkDensity(1.1, 1, x, new double[]{0.003266819056,0.043983595980,0.217852177033,0.396952547477,0.266085249899}); + } + + private void checkDensity(double mean, double sd, double[] x, double[] expected) { + NormalDistribution d = new NormalDistribution(mean, sd); + for (int i = 0; i < x.length; i++) { + Assert.assertEquals(expected[i], d.density(x[i]), 1e-9); + } + } + + /** + * Check to make sure top-coding of extreme values works correctly. + * Verifies fixes for JIRA MATH-167, MATH-414 + */ + @Test + public void testExtremeValues() { + NormalDistribution distribution = new NormalDistribution(0, 1); + for (int i = 0; i < 100; i++) { // make sure no convergence exception + double lowerTail = distribution.cumulativeProbability(-i); + double upperTail = distribution.cumulativeProbability(i); + if (i < 9) { // make sure not top-coded + // For i = 10, due to bad tail precision in erf (MATH-364), 1 is returned + // TODO: once MATH-364 is resolved, replace 9 with 30 + Assert.assertTrue(lowerTail > 0.0d); + Assert.assertTrue(upperTail < 1.0d); + } + else { // make sure top coding not reversed + Assert.assertTrue(lowerTail < 0.00001); + Assert.assertTrue(upperTail > 0.99999); + } + } + + Assert.assertEquals(distribution.cumulativeProbability(Double.MAX_VALUE), 1, 0); + Assert.assertEquals(distribution.cumulativeProbability(-Double.MAX_VALUE), 0, 0); + Assert.assertEquals(distribution.cumulativeProbability(Double.POSITIVE_INFINITY), 1, 0); + Assert.assertEquals(distribution.cumulativeProbability(Double.NEGATIVE_INFINITY), 0, 0); + } + + @Test + public void testMath280() { + NormalDistribution normal = new NormalDistribution(0,1); + double result = normal.inverseCumulativeProbability(0.9986501019683698); + Assert.assertEquals(3.0, result, defaultTolerance); + result = normal.inverseCumulativeProbability(0.841344746068543); + Assert.assertEquals(1.0, result, defaultTolerance); + result = normal.inverseCumulativeProbability(0.9999683287581673); + Assert.assertEquals(4.0, result, defaultTolerance); + result = normal.inverseCumulativeProbability(0.9772498680518209); + Assert.assertEquals(2.0, result, defaultTolerance); + } + + @Test + public void testMoments() { + final double tol = 1e-9; + NormalDistribution dist; + + dist = new NormalDistribution(0, 1); + Assert.assertEquals(dist.getNumericalMean(), 0, tol); + Assert.assertEquals(dist.getNumericalVariance(), 1, tol); + + dist = new NormalDistribution(2.2, 1.4); + Assert.assertEquals(dist.getNumericalMean(), 2.2, tol); + Assert.assertEquals(dist.getNumericalVariance(), 1.4 * 1.4, tol); + + dist = new NormalDistribution(-2000.9, 10.4); + Assert.assertEquals(dist.getNumericalMean(), -2000.9, tol); + Assert.assertEquals(dist.getNumericalVariance(), 10.4 * 10.4, tol); + } +}
http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java new file mode 100644 index 0000000..6223dbc --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java @@ -0,0 +1,201 @@ +/* + * 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.statistics.distribution; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Test cases for {@link ParetoDistribution}. + * Extends {@link ContinuousDistributionAbstractTest}. See class javadoc of that class for details. + */ +public class ParetoDistributionTest extends ContinuousDistributionAbstractTest { + + //-------------- Implementations for abstract methods ----------------------- + + /** Creates the default real distribution instance to use in tests. */ + @Override + public ParetoDistribution makeDistribution() { + return new ParetoDistribution(2.1, 1.4); + } + + /** Creates the default cumulative probability distribution test input values */ + @Override + public double[] makeCumulativeTestPoints() { + // quantiles computed using R + return new double[] { -2.226325228634938, -1.156887023657177, -0.643949578356075, -0.2027950777320613, 0.305827808237559, + +6.42632522863494, 5.35688702365718, 4.843949578356074, 4.40279507773206, 3.89417219176244 }; + } + + /** Creates the default cumulative probability density test expected values */ + @Override + public double[] makeCumulativeTestValues() { + return new double[] { 0, 0, 0, 0, 0, 0.791089998892, 0.730456085931, 0.689667290488, 0.645278794701, 0.578763688757 }; + } + + /** Creates the default probability density test expected values */ + @Override + public double[] makeDensityTestValues() { + return new double[] { 0, 0, 0, 0, 0, 0.0455118580441, 0.070444173646, 0.0896924681582, 0.112794186114, 0.151439332084 }; + } + + /** + * Creates the default inverse cumulative probability distribution test input values. + */ + @Override + public double[] makeInverseCumulativeTestPoints() { + // Exclude the test points less than zero, as they have cumulative + // probability of zero, meaning the inverse returns zero, and not the + // points less than zero. + double[] points = makeCumulativeTestValues(); + double[] points2 = new double[points.length - 5]; + System.arraycopy(points, 5, points2, 0, points.length - 5); + return points2; + } + + /** + * Creates the default inverse cumulative probability test expected values. + */ + @Override + public double[] makeInverseCumulativeTestValues() { + // Exclude the test points less than zero, as they have cumulative + // probability of zero, meaning the inverse returns zero, and not the + // points less than zero. + double[] points = makeCumulativeTestPoints(); + double[] points2 = new double[points.length - 5]; + System.arraycopy(points, 5, points2, 0, points.length - 5); + return points2; + } + + // --------------------- Override tolerance -------------- + @Override + public void setUp() { + super.setUp(); + setTolerance(1e-7); + } + + //---------------------------- Additional test cases ------------------------- + + private void verifyQuantiles() { + ParetoDistribution distribution = (ParetoDistribution)getDistribution(); + double mu = distribution.getScale(); + double sigma = distribution.getShape(); + setCumulativeTestPoints( new double[] { mu - 2 *sigma, mu - sigma, + mu, mu + sigma, + mu + 2 * sigma, mu + 3 * sigma, + mu + 4 * sigma, mu + 5 * sigma }); + verifyCumulativeProbabilities(); + } + + @Test + public void testQuantiles() { + setCumulativeTestValues(new double[] {0, 0, 0, 0.510884134236, 0.694625688662, 0.785201995008, 0.837811522357, 0.871634279326}); + setDensityTestValues(new double[] {0, 0, 0.666666666, 0.195646346305, 0.0872498032394, 0.0477328899983, 0.0294888141169, 0.0197485724114}); + verifyQuantiles(); + verifyDensities(); + + setDistribution(new ParetoDistribution(1, 1)); + setCumulativeTestValues(new double[] {0, 0, 0, 0.5, 0.666666666667, 0.75, 0.8, 0.833333333333}); + setDensityTestValues(new double[] {0, 0, 1.0, 0.25, 0.111111111111, 0.0625, 0.04, 0.0277777777778}); + verifyQuantiles(); + verifyDensities(); + + setDistribution(new ParetoDistribution(0.1, 0.1)); + setCumulativeTestValues(new double[] {0, 0, 0, 0.0669670084632, 0.104041540159, 0.129449436704, 0.148660077479, 0.164041197922}); + setDensityTestValues(new double[] {0, 0, 1.0, 0.466516495768, 0.298652819947, 0.217637640824, 0.170267984504, 0.139326467013}); + verifyQuantiles(); + verifyDensities(); + } + + @Test + public void testInverseCumulativeProbabilityExtremes() { + setInverseCumulativeTestPoints(new double[] {0, 1}); + setInverseCumulativeTestValues(new double[] {2.1, Double.POSITIVE_INFINITY}); + verifyInverseCumulativeProbabilities(); + } + + @Test + public void testGetScale() { + ParetoDistribution distribution = (ParetoDistribution)getDistribution(); + Assert.assertEquals(2.1, distribution.getScale(), 0); + } + + @Test + public void testGetShape() { + ParetoDistribution distribution = (ParetoDistribution)getDistribution(); + Assert.assertEquals(1.4, distribution.getShape(), 0); + } + + @Test(expected=IllegalArgumentException.class) + public void testPrecondition1() { + new ParetoDistribution(1, 0); + } + + @Test + public void testDensity() { + double [] x = new double[]{-2, -1, 0, 1, 2}; + // R 2.14: print(dpareto(c(-2,-1,0,1,2), scale=1, shape=1), digits=10) + checkDensity(1, 1, x, new double[] { 0.00, 0.00, 0.00, 1.00, 0.25 }); + // R 2.14: print(dpareto(c(-2,-1,0,1,2), scale=1.1, shape=1), digits=10) + checkDensity(1.1, 1, x, new double[] { 0.000, 0.000, 0.000, 0.000, 0.275 }); + } + + private void checkDensity(double scale, double shape, double[] x, + double[] expected) { + ParetoDistribution d = new ParetoDistribution(scale, shape); + for (int i = 0; i < x.length; i++) { + Assert.assertEquals(expected[i], d.density(x[i]), 1e-9); + } + } + + /** + * Check to make sure top-coding of extreme values works correctly. + */ + @Test + public void testExtremeValues() { + ParetoDistribution d = new ParetoDistribution(1, 1); + for (int i = 0; i < 1e5; i++) { // make sure no convergence exception + double upperTail = d.cumulativeProbability(i); + if (i <= 1000) { // make sure not top-coded + Assert.assertTrue(upperTail < 1.0d); + } + else { // make sure top coding not reversed + Assert.assertTrue(upperTail > 0.999); + } + } + + Assert.assertEquals(d.cumulativeProbability(Double.MAX_VALUE), 1, 0); + Assert.assertEquals(d.cumulativeProbability(-Double.MAX_VALUE), 0, 0); + Assert.assertEquals(d.cumulativeProbability(Double.POSITIVE_INFINITY), 1, 0); + Assert.assertEquals(d.cumulativeProbability(Double.NEGATIVE_INFINITY), 0, 0); + } + + @Test + public void testMeanVariance() { + final double tol = 1e-9; + ParetoDistribution dist; + + dist = new ParetoDistribution(1, 1); + Assert.assertEquals(dist.getNumericalMean(), Double.POSITIVE_INFINITY, tol); + Assert.assertEquals(dist.getNumericalVariance(), Double.POSITIVE_INFINITY, tol); + + dist = new ParetoDistribution(2.2, 2.4); + Assert.assertEquals(dist.getNumericalMean(), 3.771428571428, tol); + Assert.assertEquals(dist.getNumericalVariance(), 14.816326530, tol); + } +} http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PascalDistributionTest.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PascalDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PascalDistributionTest.java new file mode 100644 index 0000000..b0d7ac1 --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PascalDistributionTest.java @@ -0,0 +1,132 @@ +/* + * 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.statistics.distribution; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Test cases for PascalDistribution. + * Extends DiscreteDistributionAbstractTest. See class javadoc for + * DiscreteDistributionAbstractTest for details. + * + */ +public class PascalDistributionTest extends DiscreteDistributionAbstractTest { + + // --------------------- Override tolerance -------------- + protected double defaultTolerance = 1e-7; + @Override + public void setUp() { + super.setUp(); + setTolerance(defaultTolerance); + } + + //-------------- Implementations for abstract methods ----------------------- + + /** Creates the default discrete distribution instance to use in tests. */ + @Override + public DiscreteDistribution makeDistribution() { + return new PascalDistribution(10,0.70); + } + + /** Creates the default probability density test input values */ + @Override + public int[] makeDensityTestPoints() { + return new int[] {-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + } + + /** Creates the default probability density test expected values */ + @Override + public double[] makeDensityTestValues() { + return new double[] {0, 0.0282475249, 0.0847425747, 0.139825248255, 0.167790297906, 0.163595540458, + 0.137420253985, 0.103065190489, 0.070673273478, 0.0450542118422, 0.0270325271053, + 0.0154085404500, 0.0084046584273}; + } + + /** Creates the default cumulative probability density test input values */ + @Override + public int[] makeCumulativeTestPoints() { + return makeDensityTestPoints(); + } + + /** Creates the default cumulative probability density test expected values */ + @Override + public double[] makeCumulativeTestValues() { + return new double[] {0, 0.0282475249, 0.1129900996, 0.252815347855, 0.420605645761, 0.584201186219, + 0.721621440204, 0.824686630693, 0.895359904171, 0.940414116013, 0.967446643119, + 0.982855183569, 0.991259841996}; + } + + /** Creates the default inverse cumulative probability test input values */ + @Override + public double[] makeInverseCumulativeTestPoints() { + return new double[] {0.0, 0.001, 0.010, 0.025, 0.050, 0.100, 0.999, + 0.990, 0.975, 0.950, 0.900, 1.0}; + } + + /** Creates the default inverse cumulative probability density test expected values */ + @Override + public int[] makeInverseCumulativeTestValues() { + return new int[] {0, 0, 0, 0, 1, 1, 14, 11, 10, 9, 8, Integer.MAX_VALUE}; + } + + //----------------- Additional test cases --------------------------------- + + /** Test degenerate case p = 0 */ + @Test + public void testDegenerate0() { + setDistribution(new PascalDistribution(5, 0.0d)); + setCumulativeTestPoints(new int[] {-1, 0, 1, 5, 10 }); + setCumulativeTestValues(new double[] {0d, 0d, 0d, 0d, 0d}); + setDensityTestPoints(new int[] {-1, 0, 1, 10, 11}); + setDensityTestValues(new double[] {0d, 0d, 0d, 0d, 0d}); + setInverseCumulativeTestPoints(new double[] {0.1d, 0.5d}); + setInverseCumulativeTestValues(new int[] {Integer.MAX_VALUE, Integer.MAX_VALUE}); + verifyDensities(); + verifyCumulativeProbabilities(); + verifyInverseCumulativeProbabilities(); + } + + /** Test degenerate case p = 1 */ + @Test + public void testDegenerate1() { + setDistribution(new PascalDistribution(5, 1.0d)); + setCumulativeTestPoints(new int[] {-1, 0, 1, 2, 5, 10 }); + setCumulativeTestValues(new double[] {0d, 1d, 1d, 1d, 1d, 1d}); + setDensityTestPoints(new int[] {-1, 0, 1, 2, 5, 10}); + setDensityTestValues(new double[] {0d, 1d, 0d, 0d, 0d, 0d}); + setInverseCumulativeTestPoints(new double[] {0.1d, 0.5d}); + setInverseCumulativeTestValues(new int[] {0, 0}); + verifyDensities(); + verifyCumulativeProbabilities(); + verifyInverseCumulativeProbabilities(); + } + + @Test + public void testMoments() { + final double tol = 1e-9; + PascalDistribution dist; + + dist = new PascalDistribution(10, 0.5); + Assert.assertEquals(dist.getNumericalMean(), ( 10d * 0.5d ) / 0.5d, tol); + Assert.assertEquals(dist.getNumericalVariance(), ( 10d * 0.5d ) / (0.5d * 0.5d), tol); + + dist = new PascalDistribution(25, 0.7); + Assert.assertEquals(dist.getNumericalMean(), ( 25d * 0.3d ) / 0.7d, tol); + Assert.assertEquals(dist.getNumericalVariance(), ( 25d * 0.3d ) / (0.7d * 0.7d), tol); + } +} http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PoissonDistributionTest.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PoissonDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PoissonDistributionTest.java new file mode 100644 index 0000000..150e120 --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PoissonDistributionTest.java @@ -0,0 +1,244 @@ +/* + * 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.statistics.distribution; + +import org.junit.Assert; +import org.junit.Test; + +/** + * <code>PoissonDistributionTest</code> + * + */ +public class PoissonDistributionTest extends DiscreteDistributionAbstractTest { + + /** + * Poisson parameter value for the test distribution. + */ + private static final double DEFAULT_TEST_POISSON_PARAMETER = 4.0; + + /** + * Constructor. + */ + public PoissonDistributionTest() { + setTolerance(1e-12); + } + + /** + * Creates the default discrete distribution instance to use in tests. + */ + @Override + public DiscreteDistribution makeDistribution() { + return new PoissonDistribution(DEFAULT_TEST_POISSON_PARAMETER); + } + + /** + * Creates the default probability density test input values. + */ + @Override + public int[] makeDensityTestPoints() { + return new int[] { -1, 0, 1, 2, 3, 4, 5, 10, 20}; + } + + /** + * Creates the default probability density test expected values. + * These and all other test values are generated by R, version 1.8.1 + */ + @Override + public double[] makeDensityTestValues() { + return new double[] { 0d, 0.0183156388887d, 0.073262555555d, + 0.14652511111d, 0.195366814813d, 0.195366814813, + 0.156293451851d, 0.00529247667642d, 8.27746364655e-09}; + } + + /** + * Creates the default logarithmic probability density test expected values. + * Reference values are from R, version 2.14.1. + */ + @Override + public double[] makeLogDensityTestValues() { + return new double[] { Double.NEGATIVE_INFINITY, -4.000000000000d, + -2.613705638880d, -1.920558458320d, -1.632876385868d, + -1.632876385868d, -1.856019937183d, -5.241468961877d, + -18.609729238356d}; + } + + /** + * Creates the default cumulative probability density test input values. + */ + @Override + public int[] makeCumulativeTestPoints() { + return new int[] { -1, 0, 1, 2, 3, 4, 5, 10, 20 }; + } + + /** + * Creates the default cumulative probability density test expected values. + */ + @Override + public double[] makeCumulativeTestValues() { + return new double[] { 0d, 0.0183156388887d, 0.0915781944437d, + 0.238103305554d, 0.433470120367d, 0.62883693518, + 0.78513038703d, 0.99716023388d, 0.999999998077 }; + } + + /** + * Creates the default inverse cumulative probability test input values. + */ + @Override + public double[] makeInverseCumulativeTestPoints() { + DiscreteDistribution dist = getDistribution(); + return new double[] { 0d, 0.018315638886d, 0.018315638890d, + 0.091578194441d, 0.091578194445d, 0.238103305552d, + 0.238103305556d, dist.cumulativeProbability(3), + dist.cumulativeProbability(4), dist.cumulativeProbability(5), + dist.cumulativeProbability(10), dist.cumulativeProbability(20)}; + } + + /** + * Creates the default inverse cumulative probability density test expected values. + */ + @Override + public int[] makeInverseCumulativeTestValues() { + return new int[] { 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 10, 20}; + } + + /** + * Test the normal approximation of the Poisson distribution by + * calculating P(90 ≤ X ≤ 110) for X = Po(100) and + * P(9900 ≤ X ≤ 10200) for X = Po(10000) + */ + @Test + public void testNormalApproximateProbability() { + PoissonDistribution dist = new PoissonDistribution(100); + double result = dist.normalApproximateProbability(110) + - dist.normalApproximateProbability(89); + Assert.assertEquals(0.706281887248, result, 1e-10); + + dist = new PoissonDistribution(10000); + result = dist.normalApproximateProbability(10200) + - dist.normalApproximateProbability(9899); + Assert.assertEquals(0.820070051552, result, 1E-10); + } + + /** + * Test the degenerate cases of a 0.0 and 1.0 inverse cumulative probability. + */ + @Test + public void testDegenerateInverseCumulativeProbability() { + PoissonDistribution dist = new PoissonDistribution(DEFAULT_TEST_POISSON_PARAMETER); + Assert.assertEquals(Integer.MAX_VALUE, dist.inverseCumulativeProbability(1.0d)); + Assert.assertEquals(0, dist.inverseCumulativeProbability(0d)); + } + + @Test(expected=IllegalArgumentException.class) + public void testNegativeMean() { + new PoissonDistribution(-1); + } + + @Test + public void testMean() { + PoissonDistribution dist = new PoissonDistribution(10.0); + Assert.assertEquals(10.0, dist.getMean(), 0.0); + } + + @Test + public void testLargeMeanCumulativeProbability() { + double mean = 1.0; + while (mean <= 10000000.0) { + PoissonDistribution dist = new PoissonDistribution(mean); + + double x = mean * 2.0; + double dx = x / 10.0; + double p = Double.NaN; + double sigma = Math.sqrt(mean); + while (x >= 0) { + try { + p = dist.cumulativeProbability((int) x); + Assert.assertFalse("NaN cumulative probability returned for mean = " + + mean + " x = " + x,Double.isNaN(p)); + if (x > mean - 2 * sigma) { + Assert.assertTrue("Zero cum probaility returned for mean = " + + mean + " x = " + x, p > 0); + } + } catch (Exception ex) { + Assert.fail("mean of " + mean + " and x of " + x + " caused " + ex.getMessage()); + } + x -= dx; + } + + mean *= 10.0; + } + } + + /** + * JIRA: MATH-282 + */ + @Test + public void testCumulativeProbabilitySpecial() { + PoissonDistribution dist; + dist = new PoissonDistribution(9120); + checkProbability(dist, 9075); + checkProbability(dist, 9102); + dist = new PoissonDistribution(5058); + checkProbability(dist, 5044); + dist = new PoissonDistribution(6986); + checkProbability(dist, 6950); + } + + private void checkProbability(PoissonDistribution dist, int x) { + double p = dist.cumulativeProbability(x); + Assert.assertFalse("NaN cumulative probability returned for mean = " + + dist.getMean() + " x = " + x, Double.isNaN(p)); + Assert.assertTrue("Zero cum probability returned for mean = " + + dist.getMean() + " x = " + x, p > 0); + } + + @Test + public void testLargeMeanInverseCumulativeProbability() { + double mean = 1.0; + while (mean <= 100000.0) { // Extended test value: 1E7. Reduced to limit run time. + PoissonDistribution dist = new PoissonDistribution(mean); + double p = 0.1; + double dp = p; + while (p < .99) { + try { + int ret = dist.inverseCumulativeProbability(p); + // Verify that returned value satisties definition + Assert.assertTrue(p <= dist.cumulativeProbability(ret)); + Assert.assertTrue(p > dist.cumulativeProbability(ret - 1)); + } catch (Exception ex) { + Assert.fail("mean of " + mean + " and p of " + p + " caused " + ex.getMessage()); + } + p += dp; + } + mean *= 10.0; + } + } + + @Test + public void testMoments() { + final double tol = 1e-9; + PoissonDistribution dist; + + dist = new PoissonDistribution(1); + Assert.assertEquals(dist.getNumericalMean(), 1, tol); + Assert.assertEquals(dist.getNumericalVariance(), 1, tol); + + dist = new PoissonDistribution(11.23); + Assert.assertEquals(dist.getNumericalMean(), 11.23, tol); + Assert.assertEquals(dist.getNumericalVariance(), 11.23, tol); + } +} http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java new file mode 100644 index 0000000..46e2a08 --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java @@ -0,0 +1,169 @@ +/* + * 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.statistics.distribution; + +import org.junit.Assert; +import org.junit.Test; +/** + * Test cases for TDistribution. + * Extends ContinuousDistributionAbstractTest. See class javadoc for + * ContinuousDistributionAbstractTest for details. + * + */ +public class TDistributionTest extends ContinuousDistributionAbstractTest { + + //-------------- Implementations for abstract methods ----------------------- + + /** Creates the default continuous distribution instance to use in tests. */ + @Override + public TDistribution makeDistribution() { + return new TDistribution(5.0); + } + + /** Creates the default cumulative probability distribution test input values */ + @Override + public double[] makeCumulativeTestPoints() { + // quantiles computed using R version 2.9.2 + return new double[] {-5.89342953136, -3.36492999891, -2.57058183564, -2.01504837333, -1.47588404882, + 5.89342953136, 3.36492999891, 2.57058183564, 2.01504837333, 1.47588404882}; + } + + /** Creates the default cumulative probability density test expected values */ + @Override + public double[] makeCumulativeTestValues() { + return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999, + 0.990, 0.975, 0.950, 0.900}; + } + + /** Creates the default probability density test expected values */ + @Override + public double[] makeDensityTestValues() { + return new double[] {0.000756494565517, 0.0109109752919, 0.0303377878006, 0.0637967988952, 0.128289492005, + 0.000756494565517, 0.0109109752919, 0.0303377878006, 0.0637967988952, 0.128289492005}; + } + + // --------------------- Override tolerance -------------- + @Override + public void setUp() { + super.setUp(); + setTolerance(1e-9); + } + + //---------------------------- Additional test cases ------------------------- + /** + * @see <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=27243"> + * Bug report that prompted this unit test.</a> + */ + @Test + public void testCumulativeProbabilityAgainstStackOverflow() { + TDistribution td = new TDistribution(5.); + td.cumulativeProbability(.1); + td.cumulativeProbability(.01); + } + + @Test + public void testSmallDf() { + setDistribution(new TDistribution(1d)); + // quantiles computed using R version 2.9.2 + setCumulativeTestPoints(new double[] {-318.308838986, -31.8205159538, -12.7062047362, + -6.31375151468, -3.07768353718, 318.308838986, 31.8205159538, 12.7062047362, + 6.31375151468, 3.07768353718}); + setDensityTestValues(new double[] {3.14158231817e-06, 0.000314055924703, 0.00195946145194, + 0.00778959736375, 0.0303958893917, 3.14158231817e-06, 0.000314055924703, + 0.00195946145194, 0.00778959736375, 0.0303958893917}); + setInverseCumulativeTestValues(getCumulativeTestPoints()); + verifyCumulativeProbabilities(); + verifyInverseCumulativeProbabilities(); + verifyDensities(); + } + + @Test + public void testInverseCumulativeProbabilityExtremes() { + setInverseCumulativeTestPoints(new double[] {0, 1}); + setInverseCumulativeTestValues(new double[] {Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}); + verifyInverseCumulativeProbabilities(); + } + + @Test + public void testCumulativeProbablilityExtremes() { + TDistribution dist; + for (int i = 1; i < 11; i++) { + dist = new TDistribution(i * 5); + Assert.assertEquals(1, + dist.cumulativeProbability(Double.POSITIVE_INFINITY), Double.MIN_VALUE); + Assert.assertEquals(0, + dist.cumulativeProbability(Double.NEGATIVE_INFINITY), Double.MIN_VALUE); + } + } + + @Test + public void testDfAccessors() { + TDistribution dist = (TDistribution) getDistribution(); + Assert.assertEquals(5d, dist.getDegreesOfFreedom(), Double.MIN_VALUE); + } + + @Test(expected=IllegalArgumentException.class) + public void testPreconditions() { + new TDistribution(0); + } + + @Test + public void testMoments() { + final double tol = 1e-9; + TDistribution dist; + + dist = new TDistribution(1); + Assert.assertTrue(Double.isNaN(dist.getNumericalMean())); + Assert.assertTrue(Double.isNaN(dist.getNumericalVariance())); + + dist = new TDistribution(1.5); + Assert.assertEquals(dist.getNumericalMean(), 0, tol); + Assert.assertTrue(Double.isInfinite(dist.getNumericalVariance())); + + dist = new TDistribution(5); + Assert.assertEquals(dist.getNumericalMean(), 0, tol); + Assert.assertEquals(dist.getNumericalVariance(), 5d / (5d - 2d), tol); + } + + /* + * Adding this test to benchmark against tables published by NIST + * http://itl.nist.gov/div898/handbook/eda/section3/eda3672.htm + * Have chosen tabulated results for degrees of freedom 2,10,30,100 + * Have chosen problevels from 0.10 to 0.001 + */ + @Test + public void nistData(){ + double[] prob = new double[]{ 0.10,0.05,0.025,0.01,0.005,0.001}; + double[] args2 = new double[]{1.886,2.920,4.303,6.965,9.925,22.327}; + double[] args10 = new double[]{1.372,1.812,2.228,2.764,3.169,4.143}; + double[] args30 = new double[]{1.310,1.697,2.042,2.457,2.750,3.385}; + double[] args100= new double[]{1.290,1.660,1.984,2.364,2.626,3.174}; + TestUtils.assertEquals(prob, makeNistResults(args2, 2), 1.0e-4); + TestUtils.assertEquals(prob, makeNistResults(args10, 10), 1.0e-4); + TestUtils.assertEquals(prob, makeNistResults(args30, 30), 1.0e-4); + TestUtils.assertEquals(prob, makeNistResults(args100, 100), 1.0e-4); + return; + } + private double[] makeNistResults(double[] args, int df){ + TDistribution td = new TDistribution(df); + double[] res = new double[ args.length ]; + for( int i = 0 ; i < res.length ; i++){ + res[i] = 1.0 - td.cumulativeProbability(args[i]); + } + return res; + } +} http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TestUtils.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TestUtils.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TestUtils.java new file mode 100644 index 0000000..8a074d0 --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TestUtils.java @@ -0,0 +1,281 @@ +/* + * 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.statistics.distribution; + +import java.text.DecimalFormat; +import org.apache.commons.math3.stat.inference.ChiSquareTest; +import org.apache.commons.numbers.core.Precision; +import org.junit.Assert; + +/** + * + */ +public class TestUtils { + /** + * Collection of static methods used in math unit tests. + */ + private TestUtils() {} + + /** + * Verifies that expected and actual are within delta, or are both NaN or + * infinities of the same sign. + */ + public static void assertEquals(double expected, + double actual, + double delta) { + Assert.assertEquals(null, expected, actual, delta); + } + + /** + * Verifies that expected and actual are within delta, or are both NaN or + * infinities of the same sign. + */ + public static void assertEquals(String msg, + double expected, + double actual, + double delta) { + // check for NaN + if(Double.isNaN(expected)){ + Assert.assertTrue("" + actual + " is not NaN.", + Double.isNaN(actual)); + } else { + Assert.assertEquals(msg, expected, actual, delta); + } + } + + /** + * Verifies that two double arrays have equal entries, up to tolerance + */ + public static void assertEquals(double expected[], + double observed[], + double tolerance) { + assertEquals("Array comparison failure", expected, observed, tolerance); + } + + /** + * Verifies that the relative error in actual vs. expected is less than or + * equal to relativeError. If expected is infinite or NaN, actual must be + * the same (NaN or infinity of the same sign). + * + * @param expected expected value + * @param actual observed value + * @param relativeError maximum allowable relative error + */ + public static void assertRelativelyEquals(double expected, + double actual, + double relativeError) { + assertRelativelyEquals(null, expected, actual, relativeError); + } + + /** + * Verifies that the relative error in actual vs. expected is less than or + * equal to relativeError. If expected is infinite or NaN, actual must be + * the same (NaN or infinity of the same sign). + * + * @param msg message to return with failure + * @param expected expected value + * @param actual observed value + * @param relativeError maximum allowable relative error + */ + public static void assertRelativelyEquals(String msg, + double expected, + double actual, + double relativeError) { + if (Double.isNaN(expected)) { + Assert.assertTrue(msg, Double.isNaN(actual)); + } else if (Double.isNaN(actual)) { + Assert.assertTrue(msg, Double.isNaN(expected)); + } else if (Double.isInfinite(actual) || Double.isInfinite(expected)) { + Assert.assertEquals(expected, actual, relativeError); + } else if (expected == 0.0) { + Assert.assertEquals(msg, actual, expected, relativeError); + } else { + double absError = Math.abs(expected) * relativeError; + Assert.assertEquals(msg, expected, actual, absError); + } + } + + /** verifies that two arrays are close (sup norm) */ + public static void assertEquals(String msg, + double[] expected, + double[] observed, + double tolerance) { + StringBuilder out = new StringBuilder(msg); + if (expected.length != observed.length) { + out.append("\n Arrays not same length. \n"); + out.append("expected has length "); + out.append(expected.length); + out.append(" observed length = "); + out.append(observed.length); + Assert.fail(out.toString()); + } + boolean failure = false; + for (int i=0; i < expected.length; i++) { + if (!Precision.equalsIncludingNaN(expected[i], observed[i], tolerance)) { + failure = true; + out.append("\n Elements at index "); + out.append(i); + out.append(" differ. "); + out.append(" expected = "); + out.append(expected[i]); + out.append(" observed = "); + out.append(observed[i]); + } + } + if (failure) { + Assert.fail(out.toString()); + } + } + + /** + * Asserts the null hypothesis for a ChiSquare test. Fails and dumps arguments and test + * statistics if the null hypothesis can be rejected with confidence 100 * (1 - alpha)% + * + * @param valueLabels labels for the values of the discrete distribution under test + * @param expected expected counts + * @param observed observed counts + * @param alpha significance level of the test + */ + public static void assertChiSquareAccept(String[] valueLabels, + double[] expected, + long[] observed, + double alpha) { + 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"); + 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("value\texpected\tobserved\n"); + for (int i = 0; i < expected.length; i++) { + msgBuffer.append(valueLabels[i]); + msgBuffer.append("\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()); + } + } + + /** + * Asserts the null hypothesis for a ChiSquare test. Fails and dumps arguments and test + * statistics if the null hypothesis can be rejected with confidence 100 * (1 - alpha)% + * + * @param values integer values whose observed and expected counts are being compared + * @param expected expected counts + * @param observed observed counts + * @param alpha significance level of the test + */ + public static void assertChiSquareAccept(int[] values, + double[] expected, + long[] observed, + double alpha) { + String[] labels = new String[values.length]; + for (int i = 0; i < values.length; i++) { + labels[i] = Integer.toString(values[i]); + } + assertChiSquareAccept(labels, expected, observed, alpha); + } + + /** + * Asserts the null hypothesis for a ChiSquare test. Fails and dumps arguments and test + * statistics if the null hypothesis can be rejected with confidence 100 * (1 - alpha)% + * + * @param expected expected counts + * @param observed observed counts + * @param alpha significance level of the test + */ + public static void assertChiSquareAccept(double[] expected, + long[] observed, + double alpha) { + String[] labels = new String[expected.length]; + for (int i = 0; i < labels.length; i++) { + labels[i] = Integer.toString(i + 1); + } + assertChiSquareAccept(labels, expected, observed, alpha); + } + + /** + * Computes the 25th, 50th and 75th percentiles of the given distribution and returns + * these values in an array. + */ + public static double[] getDistributionQuartiles(ContinuousDistribution distribution) { + 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 + */ + public static void updateCounts(double value, long[] counts, double[] quartiles) { + if (value < quartiles[0]) { + counts[0]++; + } else if (value > quartiles[2]) { + counts[3]++; + } else if (value > quartiles[1]) { + counts[2]++; + } else { + counts[1]++; + } + } + + /** + * 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. + */ + public static 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; + } +} http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TriangularDistributionTest.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TriangularDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TriangularDistributionTest.java new file mode 100644 index 0000000..cddb70d --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TriangularDistributionTest.java @@ -0,0 +1,192 @@ +/* + * 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.statistics.distribution; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Test cases for {@link TriangularDistribution}. See class javadoc for + * {@link ContinuousDistributionAbstractTest} for further details. + */ +public class TriangularDistributionTest extends ContinuousDistributionAbstractTest { + + // --- Override tolerance ------------------------------------------------- + + @Override + public void setUp() { + super.setUp(); + setTolerance(1e-4); + } + + //--- Implementations for abstract methods -------------------------------- + + /** + * Creates the default triangular distribution instance to use in tests. + */ + @Override + public TriangularDistribution makeDistribution() { + // Left side 5 wide, right side 10 wide. + return new TriangularDistribution(-3, 2, 12); + } + + /** + * Creates the default cumulative probability distribution test input + * values. + */ + @Override + public double[] makeCumulativeTestPoints() { + return new double[] { + -3.0001, // below lower limit + -3.0, // at lower limit + -2.0, -1.0, 0.0, 1.0, // on lower side + 2.0, // at mode + 3.0, 4.0, 10.0, 11.0, // on upper side + 12.0, // at upper limit + 12.0001 // above upper limit + }; + } + + /** + * Creates the default cumulative probability density test expected values. + */ + @Override + public double[] makeCumulativeTestValues() { + // Top at 2 / (b - a) = 2 / (12 - -3) = 2 / 15 = 7.5 + // Area left = 7.5 * 5 * 0.5 = 18.75 (1/3 of the total area) + // Area right = 7.5 * 10 * 0.5 = 37.5 (2/3 of the total area) + // Area total = 18.75 + 37.5 = 56.25 + // Derivative left side = 7.5 / 5 = 1.5 + // Derivative right side = -7.5 / 10 = -0.75 + double third = 1 / 3.0; + double left = 18.75; + double area = 56.25; + return new double[] { 0.0, + 0.0, + 0.75 / area, 3 / area, 6.75 / area, 12 / area, + third, + (left + 7.125) / area, (left + 13.5) / area, + (left + 36) / area, (left + 37.125) / area, + 1.0, + 1.0 + }; + } + + /** + * Creates the default inverse cumulative probability distribution test + * input values. + */ + @Override + public double[] makeInverseCumulativeTestPoints() { + // Exclude the points outside the limits, as they have cumulative + // probability of zero and one, meaning the inverse returns the + // limits and not the points outside the limits. + double[] points = makeCumulativeTestValues(); + double[] points2 = new double[points.length-2]; + System.arraycopy(points, 1, points2, 0, points2.length); + return points2; + //return Arrays.copyOfRange(points, 1, points.length - 1); + } + + /** + * Creates the default inverse cumulative probability density test expected + * values. + */ + @Override + public double[] makeInverseCumulativeTestValues() { + // Exclude the points outside the limits, as they have cumulative + // probability of zero and one, meaning the inverse returns the + // limits and not the points outside the limits. + double[] points = makeCumulativeTestPoints(); + double[] points2 = new double[points.length-2]; + System.arraycopy(points, 1, points2, 0, points2.length); + return points2; + //return Arrays.copyOfRange(points, 1, points.length - 1); + } + + /** Creates the default probability density test expected values. */ + @Override + public double[] makeDensityTestValues() { + return new double[] { 0, + 0, + 2 / 75.0, 4 / 75.0, 6 / 75.0, 8 / 75.0, + 10 / 75.0, + 9 / 75.0, 8 / 75.0, 2 / 75.0, 1 / 75.0, + 0, + 0 + }; + } + + //--- Additional test cases ----------------------------------------------- + + /** Test lower bound getter. */ + @Test + public void testGetLowerBound() { + TriangularDistribution distribution = makeDistribution(); + Assert.assertEquals(-3.0, distribution.getSupportLowerBound(), 0); + } + + /** Test upper bound getter. */ + @Test + public void testGetUpperBound() { + TriangularDistribution distribution = makeDistribution(); + Assert.assertEquals(12.0, distribution.getSupportUpperBound(), 0); + } + + /** Test pre-condition for equal lower/upper limit. */ + @Test(expected=IllegalArgumentException.class) + public void testPreconditions1() { + new TriangularDistribution(0, 0, 0); + } + + /** Test pre-condition for lower limit larger than upper limit. */ + @Test(expected=IllegalArgumentException.class) + public void testPreconditions2() { + new TriangularDistribution(1, 1, 0); + } + + /** Test pre-condition for mode larger than upper limit. */ + @Test(expected=IllegalArgumentException.class) + public void testPreconditions3() { + new TriangularDistribution(0, 2, 1); + } + + /** Test pre-condition for mode smaller than lower limit. */ + @Test(expected=IllegalArgumentException.class) + public void testPreconditions4() { + new TriangularDistribution(2, 1, 3); + } + + /** Test mean/variance. */ + @Test + public void testMeanVariance() { + TriangularDistribution dist; + + dist = new TriangularDistribution(0, 0.5, 1.0); + Assert.assertEquals(dist.getNumericalMean(), 0.5, 0); + Assert.assertEquals(dist.getNumericalVariance(), 1 / 24.0, 0); + + dist = new TriangularDistribution(0, 1, 1); + Assert.assertEquals(dist.getNumericalMean(), 2 / 3.0, 0); + Assert.assertEquals(dist.getNumericalVariance(), 1 / 18.0, 0); + + dist = new TriangularDistribution(-3, 2, 12); + Assert.assertEquals(dist.getNumericalMean(), 3 + (2 / 3.0), 0); + Assert.assertEquals(dist.getNumericalVariance(), 175 / 18.0, 0); + } +} http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java new file mode 100644 index 0000000..7f76f08 --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java @@ -0,0 +1,123 @@ +/* + * 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.statistics.distribution; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Test cases for UniformContinuousDistribution. See class javadoc for + * {@link ContinuousDistributionAbstractTest} for further details. + */ +public class UniformContinuousDistributionTest extends ContinuousDistributionAbstractTest { + + // --- Override tolerance ------------------------------------------------- + + @Override + public void setUp() { + super.setUp(); + setTolerance(1e-4); + } + + //--- Implementations for abstract methods -------------------------------- + + /** Creates the default uniform real distribution instance to use in tests. */ + @Override + public UniformContinuousDistribution makeDistribution() { + return new UniformContinuousDistribution(-0.5, 1.25); + } + + /** Creates the default cumulative probability distribution test input values */ + @Override + public double[] makeCumulativeTestPoints() { + return new double[] {-0.5001, -0.5, -0.4999, -0.25, -0.0001, 0.0, + 0.0001, 0.25, 1.0, 1.2499, 1.25, 1.2501}; + } + + /** Creates the default cumulative probability density test expected values */ + @Override + public double[] makeCumulativeTestValues() { + return new double[] {0.0, 0.0, 0.0001, 0.25/1.75, 0.4999/1.75, + 0.5/1.75, 0.5001/1.75, 0.75/1.75, 1.5/1.75, + 1.7499/1.75, 1.0, 1.0}; + } + + /** Creates the default probability density test expected values */ + @Override + public double[] makeDensityTestValues() { + double d = 1 / 1.75; + return new double[] {0, d, d, d, d, d, d, d, d, d, d, 0}; + } + + //--- Additional test cases ----------------------------------------------- + + /** Test lower bound getter. */ + @Test + public void testGetLowerBound() { + UniformContinuousDistribution distribution = makeDistribution(); + Assert.assertEquals(-0.5, distribution.getSupportLowerBound(), 0); + } + + /** Test upper bound getter. */ + @Test + public void testGetUpperBound() { + UniformContinuousDistribution distribution = makeDistribution(); + Assert.assertEquals(1.25, distribution.getSupportUpperBound(), 0); + } + + /** Test pre-condition for equal lower/upper bound. */ + @Test(expected=IllegalArgumentException.class) + public void testPreconditions1() { + new UniformContinuousDistribution(0, 0); + } + + /** Test pre-condition for lower bound larger than upper bound. */ + @Test(expected=IllegalArgumentException.class) + public void testPreconditions2() { + new UniformContinuousDistribution(1, 0); + } + + /** Test mean/variance. */ + @Test + public void testMeanVariance() { + UniformContinuousDistribution dist; + + dist = new UniformContinuousDistribution(0, 1); + Assert.assertEquals(dist.getNumericalMean(), 0.5, 0); + Assert.assertEquals(dist.getNumericalVariance(), 1/12.0, 0); + + dist = new UniformContinuousDistribution(-1.5, 0.6); + Assert.assertEquals(dist.getNumericalMean(), -0.45, 0); + Assert.assertEquals(dist.getNumericalVariance(), 0.3675, 0); + + dist = new UniformContinuousDistribution(-0.5, 1.25); + Assert.assertEquals(dist.getNumericalMean(), 0.375, 0); + Assert.assertEquals(dist.getNumericalVariance(), 0.2552083333333333, 0); + } + + /** + * Check accuracy of analytical inverse CDF. Fails if a solver is used + * with the default accuracy. + */ + @Test + public void testInverseCumulativeDistribution() { + UniformContinuousDistribution dist = new UniformContinuousDistribution(0, 1e-9); + + Assert.assertEquals(2.5e-10, dist.inverseCumulativeProbability(0.25), 0); + } +} http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformDiscreteDistributionTest.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformDiscreteDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformDiscreteDistributionTest.java new file mode 100644 index 0000000..98305db --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformDiscreteDistributionTest.java @@ -0,0 +1,139 @@ +/* + * 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.statistics.distribution; + +import org.junit.Assert; +import org.junit.Test; +import org.apache.commons.numbers.core.Precision; + +/** + * Test cases for UniformDiscreteDistribution. See class javadoc for + * {@link DiscreteDistributionAbstractTest} for further details. + */ +public class UniformDiscreteDistributionTest extends DiscreteDistributionAbstractTest { + + // --- Override tolerance ------------------------------------------------- + + @Override + public void setUp() { + super.setUp(); + setTolerance(1e-9); + } + + //--- Implementations for abstract methods -------------------------------- + + /** Creates the default discrete distribution instance to use in tests. */ + @Override + public DiscreteDistribution makeDistribution() { + return new UniformDiscreteDistribution(-3, 5); + } + + /** Creates the default probability density test input values. */ + @Override + public int[] makeDensityTestPoints() { + return new int[] {-4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6}; + } + + /** Creates the default probability density test expected values. */ + @Override + public double[] makeDensityTestValues() { + double d = 1.0 / (5 - -3 + 1); + return new double[] {0, d, d, d, d, d, d, d, d, d, 0}; + } + + /** Creates the default cumulative probability density test input values. */ + @Override + public int[] makeCumulativeTestPoints() { + return makeDensityTestPoints(); + } + + /** Creates the default cumulative probability density test expected values. */ + @Override + public double[] makeCumulativeTestValues() { + return new double[] {0, 1 / 9.0, 2 / 9.0, 3 / 9.0, 4 / 9.0, 5 / 9.0, + 6 / 9.0, 7 / 9.0, 8 / 9.0, 1, 1}; + } + + /** Creates the default inverse cumulative probability test input values */ + @Override + public double[] makeInverseCumulativeTestPoints() { + return new double[] {0, 0.001, 0.010, 0.025, 0.050, 0.100, 0.200, + 0.5, 0.999, 0.990, 0.975, 0.950, 0.900, 1}; + } + + /** Creates the default inverse cumulative probability density test expected values */ + @Override + public int[] makeInverseCumulativeTestValues() { + return new int[] {-3, -3, -3, -3, -3, -3, -2, 1, 5, 5, 5, 5, 5, 5}; + } + + //--- Additional test cases ----------------------------------------------- + + /** Test mean/variance. */ + @Test + public void testMoments() { + UniformDiscreteDistribution dist; + + dist = new UniformDiscreteDistribution(0, 5); + Assert.assertEquals(dist.getNumericalMean(), 2.5, 0); + Assert.assertEquals(dist.getNumericalVariance(), 35 / 12.0, 0); + + dist = new UniformDiscreteDistribution(0, 1); + Assert.assertEquals(dist.getNumericalMean(), 0.5, 0); + Assert.assertEquals(dist.getNumericalVariance(), 3 / 12.0, 0); + } + + // MATH-1141 + @Test(expected=IllegalArgumentException.class) + public void testPreconditionUpperBoundInclusive1() { + new UniformDiscreteDistribution(1, 0); + } + + // MATH-1141 + @Test + public void testPreconditionUpperBoundInclusive2() { + // Degenerate case is allowed. + new UniformDiscreteDistribution(0, 0); + } + + // MATH-1396 + @Test + public void testLargeRangeSubtractionOverflow() { + final int hi = Integer.MAX_VALUE / 2 + 10; + UniformDiscreteDistribution dist = new UniformDiscreteDistribution(-hi, hi - 1); + + final double tol = Math.ulp(1d); + Assert.assertEquals(0.5 / hi, dist.probability(123456), tol); + Assert.assertEquals(0.5, dist.cumulativeProbability(-1), tol); + + Assert.assertTrue(Precision.equals((Math.pow(2d * hi, 2) - 1) / 12, dist.getNumericalVariance(), 1)); + } + + // MATH-1396 + @Test + public void testLargeRangeAdditionOverflow() { + final int hi = Integer.MAX_VALUE / 2 + 10; + UniformDiscreteDistribution dist = new UniformDiscreteDistribution(hi - 1, hi + 1); + + final double tol = Math.ulp(1d); + Assert.assertEquals(1d / 3d, dist.probability(hi), tol); + Assert.assertEquals(2d / 3d, dist.cumulativeProbability(hi), tol); + + Assert.assertTrue(Precision.equals(hi, dist.getNumericalMean(), 1)); + } +} http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java new file mode 100644 index 0000000..c993fba --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java @@ -0,0 +1,118 @@ +/* + * 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.statistics.distribution; + +import org.apache.commons.numbers.gamma.LogGamma; +import org.junit.Assert; +import org.junit.Test; + +/** + * Test cases for WeibullDistribution. + * Extends ContinuousDistributionAbstractTest. See class javadoc for + * ContinuousDistributionAbstractTest for details. + * + */ +public class WeibullDistributionTest extends ContinuousDistributionAbstractTest { + + //-------------- Implementations for abstract methods ----------------------- + + /** Creates the default continuous distribution instance to use in tests. */ + @Override + public WeibullDistribution makeDistribution() { + return new WeibullDistribution(1.2, 2.1); + } + + /** Creates the default cumulative probability distribution test input values */ + @Override + public double[] makeCumulativeTestPoints() { + // quantiles computed using R version 2.9.2 + return new double[] {0.00664355180993, 0.0454328283309, 0.0981162737374, 0.176713524579, 0.321946865392, + 10.5115496887, 7.4976304671, 6.23205600701, 5.23968436955, 4.2079028257}; + } + + /** Creates the default cumulative probability density test expected values */ + @Override + public double[] makeCumulativeTestValues() { + return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999, 0.990, 0.975, 0.950, 0.900}; + } + + /** Creates the default probability density test expected values */ + @Override + public double[] makeDensityTestValues() { + return new double[] {0.180535929306, 0.262801138133, 0.301905425199, 0.330899152971, + 0.353441418887, 0.000788590320203, 0.00737060094841, 0.0177576041516, 0.0343043442574, 0.065664589369}; + } + + //---------------------------- Additional test cases ------------------------- + + @Test + public void testInverseCumulativeProbabilitySmallPAccuracy() { + WeibullDistribution dist = new WeibullDistribution(2, 3); + double t = dist.inverseCumulativeProbability(1e-17); + // Analytically, answer is solution to 1e-17 = 1-exp(-(x/3)^2) + // x = sqrt(-9*log(1-1e-17)) + // If we're not careful, answer will be 0. Answer below is computed with care in Octave: + Assert.assertEquals(9.48683298050514e-9, t, 1e-17); + } + + @Test + public void testInverseCumulativeProbabilityExtremes() { + setInverseCumulativeTestPoints(new double[] {0.0, 1.0}); + setInverseCumulativeTestValues(new double[] {0.0, Double.POSITIVE_INFINITY}); + verifyInverseCumulativeProbabilities(); + } + + @Test + public void testAlpha() { + WeibullDistribution dist = new WeibullDistribution(1, 2); + Assert.assertEquals(1, dist.getShape(), 0); + } + @Test(expected=IllegalArgumentException.class) + public void testPrecondition1() { + new WeibullDistribution(0, 2); + } + + @Test + public void testBeta() { + WeibullDistribution dist = new WeibullDistribution(1, 2); + Assert.assertEquals(2, dist.getScale(), 0); + } + @Test(expected=IllegalArgumentException.class) + public void testPrecondition2() { + new WeibullDistribution(1, 0); + } + + @Test + public void testMoments() { + final double tol = 1e-9; + WeibullDistribution dist; + + dist = new WeibullDistribution(2.5, 3.5); + // In R: 3.5*gamma(1+(1/2.5)) (or emperically: mean(rweibull(10000, 2.5, 3.5))) + Assert.assertEquals(dist.getNumericalMean(), 3.5 * Math.exp(LogGamma.value(1 + (1 / 2.5))), tol); + Assert.assertEquals(dist.getNumericalVariance(), (3.5 * 3.5) * + Math.exp(LogGamma.value(1 + (2 / 2.5))) - + (dist.getNumericalMean() * dist.getNumericalMean()), tol); + + dist = new WeibullDistribution(10.4, 2.222); + Assert.assertEquals(dist.getNumericalMean(), 2.222 * Math.exp(LogGamma.value(1 + (1 / 10.4))), tol); + Assert.assertEquals(dist.getNumericalVariance(), (2.222 * 2.222) * + Math.exp(LogGamma.value(1 + (2 / 10.4))) - + (dist.getNumericalMean() * dist.getNumericalMean()), tol); + } +} http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ZipfDistributionTest.java ---------------------------------------------------------------------- diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ZipfDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ZipfDistributionTest.java new file mode 100644 index 0000000..489a4bb --- /dev/null +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ZipfDistributionTest.java @@ -0,0 +1,166 @@ +/* + * 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.statistics.distribution; + +import org.apache.commons.rng.simple.RandomSource; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Test cases for {@link ZipfDistribution}. + * Extends DiscreteDistributionAbstractTest. + * See class javadoc for DiscreteDistributionAbstractTest for details. + */ +public class ZipfDistributionTest extends DiscreteDistributionAbstractTest { + + /** + * Constructor to override default tolerance. + */ + public ZipfDistributionTest() { + setTolerance(1e-12); + } + + @Test(expected=IllegalArgumentException.class) + public void testPreconditions1() { + new ZipfDistribution(0, 1); + } + + @Test(expected=IllegalArgumentException.class) + public void testPreconditions2() { + new ZipfDistribution(1, 0); + } + + //-------------- Implementations for abstract methods ----------------------- + + /** Creates the default discrete distribution instance to use in tests. */ + @Override + public DiscreteDistribution makeDistribution() { + return new ZipfDistribution(10, 1); + } + + /** Creates the default probability density test input values */ + @Override + public int[] makeDensityTestPoints() { + return new int[] {-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + } + + /** + * Creates the default probability density test expected values. + * Reference values are from R, version 2.15.3 (VGAM package 0.9-0). + */ + @Override + public double[] makeDensityTestValues() { + return new double[] {0d, 0d, 0.341417152147, 0.170708576074, 0.113805717382, 0.0853542880369, 0.0682834304295, + 0.0569028586912, 0.0487738788782, 0.0426771440184, 0.0379352391275, 0.0341417152147, 0}; + } + + /** + * Creates the default logarithmic probability density test expected values. + * Reference values are from R, version 2.14.1. + */ + @Override + public double[] makeLogDensityTestValues() { + return new double[] {Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, + -1.07465022926458, -1.76779740982453, -2.17326251793269, -2.46094459038447, + -2.68408814169868, -2.86640969849264, -3.0205603783199, -3.15409177094442, + -3.2718748066008, -3.37723532225863, Double.NEGATIVE_INFINITY}; + } + + /** Creates the default cumulative probability density test input values */ + @Override + public int[] makeCumulativeTestPoints() { + return makeDensityTestPoints(); + } + + /** Creates the default cumulative probability density test expected values */ + @Override + public double[] makeCumulativeTestValues() { + return new double[] {0, 0, 0.341417152147, 0.512125728221, 0.625931445604, 0.71128573364, + 0.77956916407, 0.836472022761, 0.885245901639, 0.927923045658, 0.965858284785, 1d, 1d}; + } + + /** Creates the default inverse cumulative probability test input values */ + @Override + public double[] makeInverseCumulativeTestPoints() { + return new double[] {0d, 0.001d, 0.010d, 0.025d, 0.050d, 0.3413d, 0.3415d, 0.999d, + 0.990d, 0.975d, 0.950d, 0.900d, 1d}; + } + + /** Creates the default inverse cumulative probability density test expected values */ + @Override + public int[] makeInverseCumulativeTestValues() { + return new int[] {1, 1, 1, 1, 1, 1, 2, 10, 10, 10, 9, 8, 10}; + } + + @Test + public void testMoments() { + final double tol = 1e-9; + ZipfDistribution dist; + + dist = new ZipfDistribution(2, 0.5); + Assert.assertEquals(dist.getNumericalMean(), Math.sqrt(2), tol); + Assert.assertEquals(dist.getNumericalVariance(), 0.24264068711928521, tol); + } + + + /** + * Test sampling for various number of points and exponents. + */ + @Test + public void testSamplingExtended() { + int sampleSize = 1000; + + int[] numPointsValues = { + 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100 + }; + double[] exponentValues = { + 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 2e-1, 5e-1, + 1. - 1e-9, 1.0, 1. + 1e-9, 1.1, 1.2, 1.3, 1.5, 1.6, 1.7, 1.8, 2.0, + 2.5, 3.0, 4., 5., 6., 7., 8., 9., 10., 20., 30., 100., 150. + }; + + for (int numPoints : numPointsValues) { + for (double exponent : exponentValues) { + double weightSum = 0.; + double[] weights = new double[numPoints]; + for (int i = numPoints; i>=1; i-=1) { + weights[i-1] = Math.pow(i, -exponent); + weightSum += weights[i-1]; + } + + // 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 + DiscreteDistribution.Sampler distribution = + new ZipfDistribution(numPoints, exponent).createSampler(RandomSource.create(RandomSource.WELL_19937_C, 6)); + + double[] expectedCounts = new double[numPoints]; + long[] observedCounts = new long[numPoints]; + for (int i = 0; i < numPoints; i++) { + expectedCounts[i] = sampleSize * (weights[i]/weightSum); + } + int[] sample = AbstractDiscreteDistribution.sample(sampleSize, distribution); + for (int s : sample) { + observedCounts[s-1]++; + } + TestUtils.assertChiSquareAccept(expectedCounts, observedCounts, 0.001); + } + } + } +}
