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