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.After;
28  import org.junit.Assert;
29  import org.junit.Before;
30  import org.junit.Test;
31  
32  /**
33   * Abstract base class for {@link IntegerDistribution} tests.
34   * <p>
35   * To create a concrete test class for an integer distribution implementation,
36   * implement makeDistribution() to return a distribution instance to use in
37   * tests and each of the test data generation methods below.  In each case, the
38   * test points and test values arrays returned represent parallel arrays of
39   * inputs and expected values for the distribution returned by makeDistribution().
40   * <p>
41   * makeDensityTestPoints() -- arguments used to test probability density calculation
42   * makeDensityTestValues() -- expected probability densities
43   * makeCumulativeTestPoints() -- arguments used to test cumulative probabilities
44   * makeCumulativeTestValues() -- expected cumulative probabilities
45   * makeInverseCumulativeTestPoints() -- arguments used to test inverse cdf evaluation
46   * makeInverseCumulativeTestValues() -- expected inverse cdf values
47   * <p>
48   * To implement additional test cases with different distribution instances and test data,
49   * use the setXxx methods for the instance data in test cases and call the verifyXxx methods
50   * to verify results.
51   */
52  public abstract class IntegerDistributionAbstractTest {
53  
54  //-------------------- Private test instance data -------------------------
55      /** Discrete distribution instance used to perform tests */
56      private IntegerDistribution distribution;
57  
58      /** Tolerance used in comparing expected and returned values */
59      private double tolerance = 1E-12;
60  
61      /** Arguments used to test probability density calculations */
62      private int[] densityTestPoints;
63  
64      /** Values used to test probability density calculations */
65      private double[] densityTestValues;
66  
67      /** Values used to test logarithmic probability density calculations */
68      private double[] logDensityTestValues;
69  
70      /** Arguments used to test cumulative probability density calculations */
71      private int[] cumulativeTestPoints;
72  
73      /** Values used to test cumulative probability density calculations */
74      private double[] cumulativeTestValues;
75  
76      /** Arguments used to test inverse cumulative probability density calculations */
77      private double[] inverseCumulativeTestPoints;
78  
79      /** Values used to test inverse cumulative probability density calculations */
80      private int[] inverseCumulativeTestValues;
81  
82      //-------------------- Abstract methods -----------------------------------
83  
84      /** Creates the default discrete distribution instance to use in tests. */
85      public abstract IntegerDistribution makeDistribution();
86  
87      /** Creates the default probability density test input values */
88      public abstract int[] makeDensityTestPoints();
89  
90      /** Creates the default probability density test expected values */
91      public abstract double[] makeDensityTestValues();
92  
93      /** Creates the default logarithmic probability density test expected values.
94       *
95       * The default implementation simply computes the logarithm of all the values in
96       * {@link #makeDensityTestValues()}.
97       *
98       * @return double[] the default logarithmic probability density test expected values.
99       */
100     public double[] makeLogDensityTestValues() {
101         final double[] densityTestValues = makeDensityTestValues();
102         final double[] logDensityTestValues = new double[densityTestValues.length];
103         for (int i = 0; i < densityTestValues.length; i++) {
104             logDensityTestValues[i] = FastMath.log(densityTestValues[i]);
105         }
106         return logDensityTestValues;
107     }
108 
109     /** Creates the default cumulative probability density test input values */
110     public abstract int[] makeCumulativeTestPoints();
111 
112     /** Creates the default cumulative probability density test expected values */
113     public abstract double[] makeCumulativeTestValues();
114 
115     /** Creates the default inverse cumulative probability test input values */
116     public abstract double[] makeInverseCumulativeTestPoints();
117 
118     /** Creates the default inverse cumulative probability density test expected values */
119     public abstract int[] makeInverseCumulativeTestValues();
120 
121     //-------------------- Setup / tear down ----------------------------------
122 
123     /**
124      * Setup sets all test instance data to default values
125      */
126     @Before
127     public void setUp() {
128         distribution = makeDistribution();
129         densityTestPoints = makeDensityTestPoints();
130         densityTestValues = makeDensityTestValues();
131         logDensityTestValues = makeLogDensityTestValues();
132         cumulativeTestPoints = makeCumulativeTestPoints();
133         cumulativeTestValues = makeCumulativeTestValues();
134         inverseCumulativeTestPoints = makeInverseCumulativeTestPoints();
135         inverseCumulativeTestValues = makeInverseCumulativeTestValues();
136     }
137 
138     /**
139      * Cleans up test instance data
140      */
141     @After
142     public void tearDown() {
143         distribution = null;
144         densityTestPoints = null;
145         densityTestValues = null;
146         logDensityTestValues = null;
147         cumulativeTestPoints = null;
148         cumulativeTestValues = null;
149         inverseCumulativeTestPoints = null;
150         inverseCumulativeTestValues = null;
151     }
152 
153     //-------------------- Verification methods -------------------------------
154 
155     /**
156      * Verifies that probability density calculations match expected values
157      * using current test instance data
158      */
159     protected void verifyDensities() {
160         for (int i = 0; i < densityTestPoints.length; i++) {
161             Assert.assertEquals("Incorrect density value returned for " + densityTestPoints[i],
162                     densityTestValues[i],
163                     distribution.probability(densityTestPoints[i]), getTolerance());
164         }
165     }
166 
167     /**
168      * Verifies that logarithmic probability density calculations match expected values
169      * using current test instance data.
170      */
171     protected void verifyLogDensities() {
172         for (int i = 0; i < densityTestPoints.length; i++) {
173             // FIXME: when logProbability methods are added to IntegerDistribution in 4.0, remove cast below
174             Assert.assertEquals("Incorrect log density value returned for " + densityTestPoints[i],
175                     logDensityTestValues[i],
176                     ((AbstractIntegerDistribution) distribution).logProbability(densityTestPoints[i]), tolerance);
177         }
178     }
179 
180     /**
181      * Verifies that cumulative probability density calculations match expected values
182      * using current test instance data
183      */
184     protected void verifyCumulativeProbabilities() {
185         for (int i = 0; i < cumulativeTestPoints.length; i++) {
186             Assert.assertEquals("Incorrect cumulative probability value returned for " + cumulativeTestPoints[i],
187                     cumulativeTestValues[i],
188                     distribution.cumulativeProbability(cumulativeTestPoints[i]), getTolerance());
189         }
190     }
191 
192 
193     /**
194      * Verifies that inverse cumulative probability density calculations match expected values
195      * using current test instance data
196      */
197     protected void verifyInverseCumulativeProbabilities() {
198         for (int i = 0; i < inverseCumulativeTestPoints.length; i++) {
199             Assert.assertEquals("Incorrect inverse cumulative probability value returned for "
200                     + inverseCumulativeTestPoints[i], inverseCumulativeTestValues[i],
201                     distribution.inverseCumulativeProbability(inverseCumulativeTestPoints[i]));
202         }
203     }
204 
205     //------------------------ Default test cases -----------------------------
206 
207     /**
208      * Verifies that probability density calculations match expected values
209      * using default test instance data
210      */
211     @Test
212     public void testDensities() {
213         verifyDensities();
214     }
215 
216     /**
217      * Verifies that logarithmic probability density calculations match expected values
218      * using default test instance data
219      */
220     @Test
221     public void testLogDensities() {
222         verifyLogDensities();
223     }
224 
225     /**
226      * Verifies that cumulative probability density calculations match expected values
227      * using default test instance data
228      */
229     @Test
230     public void testCumulativeProbabilities() {
231         verifyCumulativeProbabilities();
232     }
233 
234     /**
235      * Verifies that inverse cumulative probability density calculations match expected values
236      * using default test instance data
237      */
238     @Test
239     public void testInverseCumulativeProbabilities() {
240         verifyInverseCumulativeProbabilities();
241     }
242 
243     @Test
244     public void testConsistencyAtSupportBounds() {
245         final int lower = distribution.getSupportLowerBound();
246         Assert.assertEquals("Cumulative probability mmust be 0 below support lower bound.",
247                 0.0, distribution.cumulativeProbability(lower - 1), 0.0);
248         Assert.assertEquals("Cumulative probability of support lower bound must be equal to probability mass at this point.",
249                 distribution.probability(lower), distribution.cumulativeProbability(lower), getTolerance());
250         Assert.assertEquals("Inverse cumulative probability of 0 must be equal to support lower bound.",
251                 lower, distribution.inverseCumulativeProbability(0.0));
252 
253         final int upper = distribution.getSupportUpperBound();
254         if (upper != Integer.MAX_VALUE)
255             Assert.assertEquals("Cumulative probability of support upper bound must be equal to 1.",
256                     1.0, distribution.cumulativeProbability(upper), 0.0);
257         Assert.assertEquals("Inverse cumulative probability of 1 must be equal to support upper bound.",
258                 upper, distribution.inverseCumulativeProbability(1.0));
259     }
260 
261     /**
262      * Verifies that illegal arguments are correctly handled
263      */
264     @Test
265     public void testIllegalArguments() {
266         try {
267             distribution.probability(1, 0);
268             Assert.fail("Expecting MathIllegalArgumentException for bad cumulativeProbability interval");
269         } catch (MathIllegalArgumentException ex) {
270             // expected
271         }
272         try {
273             distribution.inverseCumulativeProbability(-1);
274             Assert.fail("Expecting MathIllegalArgumentException for p = -1");
275         } catch (MathIllegalArgumentException ex) {
276             // expected
277         }
278         try {
279             distribution.inverseCumulativeProbability(2);
280             Assert.fail("Expecting MathIllegalArgumentException for p = 2");
281         } catch (MathIllegalArgumentException ex) {
282             // expected
283         }
284     }
285 
286     //------------------ Getters / Setters for test instance data -----------
287     /**
288      * @return Returns the cumulativeTestPoints.
289      */
290     protected int[] getCumulativeTestPoints() {
291         return cumulativeTestPoints;
292     }
293 
294     /**
295      * @param cumulativeTestPoints The cumulativeTestPoints to set.
296      */
297     protected void setCumulativeTestPoints(int[] cumulativeTestPoints) {
298         this.cumulativeTestPoints = cumulativeTestPoints;
299     }
300 
301     /**
302      * @return Returns the cumulativeTestValues.
303      */
304     protected double[] getCumulativeTestValues() {
305         return cumulativeTestValues;
306     }
307 
308     /**
309      * @param cumulativeTestValues The cumulativeTestValues to set.
310      */
311     protected void setCumulativeTestValues(double[] cumulativeTestValues) {
312         this.cumulativeTestValues = cumulativeTestValues;
313     }
314 
315     /**
316      * @return Returns the densityTestPoints.
317      */
318     protected int[] getDensityTestPoints() {
319         return densityTestPoints;
320     }
321 
322     /**
323      * @param densityTestPoints The densityTestPoints to set.
324      */
325     protected void setDensityTestPoints(int[] densityTestPoints) {
326         this.densityTestPoints = densityTestPoints;
327     }
328 
329     /**
330      * @return Returns the densityTestValues.
331      */
332     protected double[] getDensityTestValues() {
333         return densityTestValues;
334     }
335 
336     /**
337      * @param densityTestValues The densityTestValues to set.
338      */
339     protected void setDensityTestValues(double[] densityTestValues) {
340         this.densityTestValues = densityTestValues;
341     }
342 
343     /**
344      * @return Returns the distribution.
345      */
346     protected IntegerDistribution getDistribution() {
347         return distribution;
348     }
349 
350     /**
351      * @param distribution The distribution to set.
352      */
353     protected void setDistribution(IntegerDistribution distribution) {
354         this.distribution = distribution;
355     }
356 
357     /**
358      * @return Returns the inverseCumulativeTestPoints.
359      */
360     protected double[] getInverseCumulativeTestPoints() {
361         return inverseCumulativeTestPoints;
362     }
363 
364     /**
365      * @param inverseCumulativeTestPoints The inverseCumulativeTestPoints to set.
366      */
367     protected void setInverseCumulativeTestPoints(double[] inverseCumulativeTestPoints) {
368         this.inverseCumulativeTestPoints = inverseCumulativeTestPoints;
369     }
370 
371     /**
372      * @return Returns the inverseCumulativeTestValues.
373      */
374     protected int[] getInverseCumulativeTestValues() {
375         return inverseCumulativeTestValues;
376     }
377 
378     /**
379      * @param inverseCumulativeTestValues The inverseCumulativeTestValues to set.
380      */
381     protected void setInverseCumulativeTestValues(int[] inverseCumulativeTestValues) {
382         this.inverseCumulativeTestValues = inverseCumulativeTestValues;
383     }
384 
385     /**
386      * @return Returns the tolerance.
387      */
388     protected double getTolerance() {
389         return tolerance;
390     }
391 
392     /**
393      * @param tolerance The tolerance to set.
394      */
395     protected void setTolerance(double tolerance) {
396         this.tolerance = tolerance;
397     }
398 
399 }