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  package org.apache.commons.statistics.distribution;
18  
19  import org.apache.commons.rng.UniformRandomProvider;
20  import org.apache.commons.rng.simple.RandomSource;
21  import org.junit.jupiter.api.Assertions;
22  import org.junit.jupiter.api.Test;
23  import org.junit.jupiter.params.ParameterizedTest;
24  import org.junit.jupiter.params.provider.CsvSource;
25  
26  /**
27   * Test cases for {@link PoissonDistribution}.
28   * Extends {@link BaseDiscreteDistributionTest}. See javadoc of that class for details.
29   */
30  class PoissonDistributionTest extends BaseDiscreteDistributionTest {
31      @Override
32      DiscreteDistribution makeDistribution(Object... parameters) {
33          final double mean = (Double) parameters[0];
34          return PoissonDistribution.of(mean);
35      }
36  
37  
38      @Override
39      Object[][] makeInvalidParameters() {
40          return new Object[][] {
41              {0.0},
42              {-0.1},
43          };
44      }
45  
46      @Override
47      String[] getParameterNames() {
48          return new String[] {"Mean"};
49      }
50  
51      @Override
52      protected double getRelativeTolerance() {
53          return 1e-14;
54      }
55  
56      //-------------------- Additional test cases -------------------------------
57  
58      @Test
59      void testLargeMeanCumulativeProbability() {
60          double mean = 1.0;
61          while (mean <= 10000000.0) {
62              final PoissonDistribution dist = PoissonDistribution.of(mean);
63  
64              double x = mean * 2.0;
65              final double dx = x / 10.0;
66              final double sigma = Math.sqrt(mean);
67              while (x >= 0) {
68                  try {
69                      final double p = dist.cumulativeProbability((int) x);
70                      Assertions.assertFalse(Double.isNaN(p), "NaN cumulative probability");
71                      if (x > mean - 2 * sigma) {
72                          Assertions.assertTrue(p > 0, "Zero cumulative probaility");
73                      }
74                  } catch (final AssertionError ex) {
75                      Assertions.fail("mean of " + mean + " and x of " + x + " caused " + ex.getMessage());
76                  }
77                  x -= dx;
78              }
79  
80              mean *= 10.0;
81          }
82      }
83  
84      /**
85       * JIRA: MATH-282
86       */
87      @ParameterizedTest
88      @CsvSource({
89          "9120, 9075",
90          "9120, 9102",
91          "5058, 5044",
92          "6986, 6950",
93      })
94      void testCumulativeProbabilitySpecial(double mean, int x) {
95          final PoissonDistribution dist = PoissonDistribution.of(mean);
96          final double p = dist.cumulativeProbability(x);
97          Assertions.assertFalse(Double.isNaN(p), () -> "NaN cumulative probability returned for mean = " +
98                  dist.getMean() + " x = " + x);
99          Assertions.assertTrue(p > 0, () -> "Zero cum probability returned for mean = " +
100                 dist.getMean() + " x = " + x);
101     }
102 
103     @Test
104     void testLargeMeanInverseCumulativeProbability() {
105         double mean = 1.0;
106         while (mean <= 100000.0) { // Extended test value: 1E7.  Reduced to limit run time.
107             final PoissonDistribution dist = PoissonDistribution.of(mean);
108             double p = 0.1;
109             final double dp = p;
110             while (p < .99) {
111                 try {
112                     final int ret = dist.inverseCumulativeProbability(p);
113                     // Verify that returned value satisfies definition
114                     Assertions.assertTrue(p <= dist.cumulativeProbability(ret));
115                     Assertions.assertTrue(p > dist.cumulativeProbability(ret - 1));
116                 } catch (final AssertionError ex) {
117                     Assertions.fail("mean of " + mean + " and p of " + p + " caused " + ex.getMessage());
118                 }
119                 p += dp;
120             }
121             mean *= 10.0;
122         }
123     }
124 
125     @Test
126     void testAdditionalCumulativeProbabilityHighPrecision() {
127         // computed using R version 3.4.4
128         testCumulativeProbabilityHighPrecision(
129                 PoissonDistribution.of(100),
130                 new int[] {28, 25},
131                 new double[] {1.6858675763053070496e-17, 3.184075559619425735e-19},
132                 DoubleTolerances.relative(5e-14));
133     }
134 
135     /**
136      * Test creation of a sampler with a large mean that computes valid probabilities.
137      */
138     @Test
139     void testCreateSamplerWithLargeMean() {
140         final int mean = Integer.MAX_VALUE;
141         final PoissonDistribution dist = PoissonDistribution.of(mean);
142         // The mean is roughly the median for large mean
143         Assertions.assertEquals(0.5, dist.cumulativeProbability(mean), 0.05);
144         final UniformRandomProvider rng = RandomSource.SPLIT_MIX_64.create();
145         dist.createSampler(rng)
146             .samples(50)
147             .forEach(i -> Assertions.assertTrue(i >= 0, () -> "Bad sample: " + i));
148     }
149 }