View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.distribution.discrete;
23  
24  import org.hipparchus.distribution.IntegerDistribution;
25  import org.hipparchus.exception.MathIllegalArgumentException;
26  import org.hipparchus.util.FastMath;
27  import org.junit.jupiter.api.Test;
28  
29  import static org.junit.jupiter.api.Assertions.assertEquals;
30  import static org.junit.jupiter.api.Assertions.assertFalse;
31  import static org.junit.jupiter.api.Assertions.assertThrows;
32  import static org.junit.jupiter.api.Assertions.assertTrue;
33  import static org.junit.jupiter.api.Assertions.fail;
34  
35  /**
36   * <code>PoissonDistributionTest</code>
37   */
38  public class PoissonDistributionTest extends IntegerDistributionAbstractTest {
39  
40      /**
41       * Poisson parameter value for the test distribution.
42       */
43      private static final double DEFAULT_TEST_POISSON_PARAMETER = 4.0;
44  
45      /**
46       * Constructor.
47       */
48      public PoissonDistributionTest() {
49          setTolerance(1e-12);
50      }
51  
52      /**
53       * Creates the default discrete distribution instance to use in tests.
54       */
55      @Override
56      public IntegerDistribution makeDistribution() {
57          return new PoissonDistribution(DEFAULT_TEST_POISSON_PARAMETER);
58      }
59  
60      /**
61       * Creates the default probability density test input values.
62       */
63      @Override
64      public int[] makeDensityTestPoints() {
65          return new int[] { -1, 0, 1, 2, 3, 4, 5, 10, 20};
66      }
67  
68      /**
69       * Creates the default probability density test expected values.
70       * These and all other test values are generated by R, version 1.8.1
71       */
72      @Override
73      public double[] makeDensityTestValues() {
74          return new double[] { 0d, 0.0183156388887d,  0.073262555555d,
75                  0.14652511111d, 0.195366814813d, 0.195366814813,
76                  0.156293451851d, 0.00529247667642d, 8.27746364655e-09};
77      }
78  
79      /**
80       * Creates the default logarithmic probability density test expected values.
81       * Reference values are from R, version 2.14.1.
82       */
83      @Override
84      public double[] makeLogDensityTestValues() {
85          return new double[] { Double.NEGATIVE_INFINITY, -4.000000000000d,
86                  -2.613705638880d, -1.920558458320d, -1.632876385868d,
87                  -1.632876385868d, -1.856019937183d, -5.241468961877d,
88                  -18.609729238356d};
89      }
90  
91      /**
92       * Creates the default cumulative probability density test input values.
93       */
94      @Override
95      public int[] makeCumulativeTestPoints() {
96          return new int[] { -1, 0, 1, 2, 3, 4, 5, 10, 20 };
97      }
98  
99      /**
100      * Creates the default cumulative probability density test expected values.
101      */
102     @Override
103     public double[] makeCumulativeTestValues() {
104         return new double[] { 0d,  0.0183156388887d, 0.0915781944437d,
105                 0.238103305554d, 0.433470120367d, 0.62883693518,
106                 0.78513038703d,  0.99716023388d, 0.999999998077 };
107     }
108 
109     /**
110      * Creates the default inverse cumulative probability test input values.
111      */
112     @Override
113     public double[] makeInverseCumulativeTestPoints() {
114         IntegerDistribution dist = getDistribution();
115         return new double[] { 0d, 0.018315638886d, 0.018315638890d,
116                 0.091578194441d, 0.091578194445d, 0.238103305552d,
117                 0.238103305556d, dist.cumulativeProbability(3),
118                 dist.cumulativeProbability(4), dist.cumulativeProbability(5),
119                 dist.cumulativeProbability(10), dist.cumulativeProbability(20)};
120     }
121 
122     /**
123      * Creates the default inverse cumulative probability density test expected values.
124      */
125     @Override
126     public int[] makeInverseCumulativeTestValues() {
127         return new int[] { 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 10, 20};
128     }
129 
130     /**
131      * Test the normal approximation of the Poisson distribution by
132      * calculating P(90 &le; X &le; 110) for X = Po(100) and
133      * P(9900 &le; X &le; 10200) for X  = Po(10000)
134      */
135     @Test
136     void testNormalApproximateProbability() {
137         PoissonDistribution dist = new PoissonDistribution(100);
138         double result = dist.normalApproximateProbability(110)
139                 - dist.normalApproximateProbability(89);
140         assertEquals(0.706281887248, result, 1E-10);
141 
142         dist = new PoissonDistribution(10000);
143         result = dist.normalApproximateProbability(10200)
144         - dist.normalApproximateProbability(9899);
145         assertEquals(0.820070051552, result, 1E-10);
146     }
147 
148     /**
149      * Test the degenerate cases of a 0.0 and 1.0 inverse cumulative probability.
150      */
151     @Test
152     void testDegenerateInverseCumulativeProbability() {
153         PoissonDistribution dist = new PoissonDistribution(DEFAULT_TEST_POISSON_PARAMETER);
154         assertEquals(Integer.MAX_VALUE, dist.inverseCumulativeProbability(1.0d));
155         assertEquals(0, dist.inverseCumulativeProbability(0d));
156     }
157 
158     @Test
159     void testNegativeMean() {
160         assertThrows(MathIllegalArgumentException.class, () -> {
161             new PoissonDistribution(-1);
162         });
163     }
164 
165     @Test
166     void testMean() {
167         PoissonDistribution dist = new PoissonDistribution(10.0);
168         assertEquals(10.0, dist.getMean(), 0.0);
169     }
170 
171     @Test
172     void testLargeMeanCumulativeProbability() {
173         double mean = 1.0;
174         while (mean <= 10000000.0) {
175             PoissonDistribution dist = new PoissonDistribution(mean);
176 
177             double x = mean * 2.0;
178             double dx = x / 10.0;
179             double p = Double.NaN;
180             double sigma = FastMath.sqrt(mean);
181             while (x >= 0) {
182                 try {
183                     p = dist.cumulativeProbability((int) x);
184                     assertFalse(Double.isNaN(p),"NaN cumulative probability returned for mean = " +
185                             mean + " x = " + x);
186                     if (x > mean - 2 * sigma) {
187                         assertTrue(p > 0, "Zero cum probaility returned for mean = " +
188                                 mean + " x = " + x);
189                     }
190                 } catch (Exception ex) {
191                     fail("mean of " + mean + " and x of " + x + " caused " + ex.getMessage());
192                 }
193                 x -= dx;
194             }
195 
196             mean *= 10.0;
197         }
198     }
199 
200     /**
201      * JIRA: MATH-282
202      */
203     @Test
204     void testCumulativeProbabilitySpecial() {
205         PoissonDistribution dist;
206         dist = new PoissonDistribution(9120);
207         checkProbability(dist, 9075);
208         checkProbability(dist, 9102);
209         dist = new PoissonDistribution(5058);
210         checkProbability(dist, 5044);
211         dist = new PoissonDistribution(6986);
212         checkProbability(dist, 6950);
213     }
214 
215     private void checkProbability(PoissonDistribution dist, int x) {
216         double p = dist.cumulativeProbability(x);
217         assertFalse(Double.isNaN(p), "NaN cumulative probability returned for mean = " +
218                 dist.getMean() + " x = " + x);
219         assertTrue(p > 0, "Zero cum probability returned for mean = " +
220                 dist.getMean() + " x = " + x);
221     }
222 
223     @Test
224     void testLargeMeanInverseCumulativeProbability() {
225         double mean = 1.0;
226         while (mean <= 100000.0) { // Extended test value: 1E7.  Reduced to limit run time.
227             PoissonDistribution dist = new PoissonDistribution(mean);
228             double p = 0.1;
229             double dp = p;
230             while (p < .99) {
231                 try {
232                     int ret = dist.inverseCumulativeProbability(p);
233                     // Verify that returned value satisties definition
234                     assertTrue(p <= dist.cumulativeProbability(ret));
235                     assertTrue(p > dist.cumulativeProbability(ret - 1));
236                 } catch (Exception ex) {
237                     fail("mean of " + mean + " and p of " + p + " caused " + ex.getMessage());
238                 }
239                 p += dp;
240             }
241             mean *= 10.0;
242         }
243     }
244 
245     @Test
246     void testMoments() {
247         final double tol = 1e-9;
248         PoissonDistribution dist;
249 
250         dist = new PoissonDistribution(1);
251         assertEquals(1, dist.getNumericalMean(), tol);
252         assertEquals(1, dist.getNumericalVariance(), tol);
253 
254         dist = new PoissonDistribution(11.23);
255         assertEquals(11.23, dist.getNumericalMean(), tol);
256         assertEquals(11.23, dist.getNumericalVariance(), tol);
257     }
258 }