001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.math.distribution;
018    
019    import junit.framework.TestCase;
020    
021    /**
022     * Abstract base class for {@link IntegerDistribution} tests.
023     * <p>
024     * To create a concrete test class for an integer distribution implementation,
025     *  implement makeDistribution() to return a distribution instance to use in 
026     *  tests and each of the test data generation methods below.  In each case, the
027     *  test points and test values arrays returned represent parallel arrays of 
028     *  inputs and expected values for the distribution returned by makeDistribution().
029     *  <p>
030     *  makeDensityTestPoints() -- arguments used to test probability density calculation
031     *  makeDensityTestValues() -- expected probability densities
032     *  makeCumulativeTestPoints() -- arguments used to test cumulative probabilities
033     *  makeCumulativeTestValues() -- expected cumulative probabilites
034     *  makeInverseCumulativeTestPoints() -- arguments used to test inverse cdf evaluation
035     *  makeInverseCumulativeTestValues() -- expected inverse cdf values
036     * <p>
037     *  To implement additional test cases with different distribution instances and test data,
038     *  use the setXxx methods for the instance data in test cases and call the verifyXxx methods
039     *  to verify results. 
040     * 
041     * @version $Revision: 762118 $ $Date: 2009-04-05 12:55:59 -0400 (Sun, 05 Apr 2009) $
042     */
043    public abstract class IntegerDistributionAbstractTest extends TestCase {
044        
045    //-------------------- Private test instance data -------------------------
046        /** Discrete distribution instance used to perform tests */
047        private IntegerDistribution distribution;
048        
049        /** Tolerance used in comparing expected and returned values */
050        private double tolerance = 1E-4;
051        
052        /** Arguments used to test probability density calculations */
053        private int[] densityTestPoints;
054        
055        /** Values used to test probability density calculations */
056        private double[] densityTestValues;
057        
058        /** Arguments used to test cumulative probability density calculations */
059        private int[] cumulativeTestPoints;
060        
061        /** Values used to test cumulative probability density calculations */
062        private double[] cumulativeTestValues;
063        
064        /** Arguments used to test inverse cumulative probability density calculations */
065        private double[] inverseCumulativeTestPoints;
066        
067        /** Values used to test inverse cumulative probability density calculations */
068        private int[] inverseCumulativeTestValues;
069        
070        //-------------------------------------------------------------------------
071        
072        /**
073         * Constructor for IntegerDistributionAbstractTest.
074         * @param name
075         */
076        public IntegerDistributionAbstractTest(String name) {
077            super(name);
078        }
079        
080        //-------------------- Abstract methods -----------------------------------
081        
082        /** Creates the default discrete distribution instance to use in tests. */
083        public abstract IntegerDistribution makeDistribution();
084        
085        /** Creates the default probability density test input values */
086        public abstract int[] makeDensityTestPoints();
087        
088        /** Creates the default probability density test expected values */
089        public abstract double[] makeDensityTestValues();
090        
091        /** Creates the default cumulative probability density test input values */
092        public abstract int[] makeCumulativeTestPoints();
093        
094        /** Creates the default cumulative probability density test expected values */
095        public abstract double[] makeCumulativeTestValues();
096        
097        /** Creates the default inverse cumulative probability test input values */
098        public abstract double[] makeInverseCumulativeTestPoints();
099        
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        @Override
109        protected void setUp() throws Exception {
110            super.setUp();
111            distribution = makeDistribution();
112            densityTestPoints = makeDensityTestPoints();
113            densityTestValues = makeDensityTestValues();
114            cumulativeTestPoints = makeCumulativeTestPoints();
115            cumulativeTestValues = makeCumulativeTestValues();
116            inverseCumulativeTestPoints = makeInverseCumulativeTestPoints();
117            inverseCumulativeTestValues = makeInverseCumulativeTestValues();   
118        }
119        
120        /**
121         * Cleans up test instance data
122         */
123        @Override
124        protected void tearDown() throws Exception {      
125            super.tearDown();
126            distribution = null;
127            densityTestPoints = null;
128            densityTestValues = null;
129            cumulativeTestPoints = null;
130            cumulativeTestValues = null;
131            inverseCumulativeTestPoints = null;
132            inverseCumulativeTestValues = null;   
133        }
134        
135        //-------------------- Verification methods -------------------------------
136        
137        /**
138         * Verifies that probability density calculations match expected values
139         * using current test instance data
140         */
141        protected void verifyDensities() throws Exception {
142            for (int i = 0; i < densityTestPoints.length; i++) {
143                assertEquals("Incorrect density value returned for " + densityTestPoints[i],
144                        densityTestValues[i], 
145                        distribution.probability(densityTestPoints[i]), tolerance);
146            }     
147        }
148        
149        /**
150         * Verifies that cumulative probability density calculations match expected values
151         * using current test instance data
152         */   
153        protected void verifyCumulativeProbabilities() throws Exception {
154            for (int i = 0; i < cumulativeTestPoints.length; i++) {
155                assertEquals("Incorrect cumulative probability value returned for " + cumulativeTestPoints[i],
156                        cumulativeTestValues[i], 
157                        distribution.cumulativeProbability(cumulativeTestPoints[i]), tolerance);
158            }           
159        }
160        
161        
162        /**
163         * Verifies that inverse cumulative probability density calculations match expected values
164         * using current test instance data
165         */
166        protected void verifyInverseCumulativeProbabilities() throws Exception {
167            for (int i = 0; i < inverseCumulativeTestPoints.length; i++) {
168                assertEquals("Incorrect inverse cumulative probability value returned for " 
169                        + inverseCumulativeTestPoints[i], inverseCumulativeTestValues[i], 
170                        distribution.inverseCumulativeProbability(inverseCumulativeTestPoints[i]));
171            }           
172        }
173        
174        //------------------------ Default test cases -----------------------------
175    
176        /**
177         * Verifies that probability density calculations match expected values
178         * using default test instance data
179         */
180        public void testDensities() throws Exception {
181            verifyDensities();     
182        }
183        
184        /**
185         * Verifies that cumulative probability density calculations match expected values
186         * using default test instance data
187         */
188        public void testCumulativeProbabilities() throws Exception {
189            verifyCumulativeProbabilities();      
190        }
191        
192        /**
193         * Verifies that floating point arguments are correctly handled by
194         * cumulativeProbablility(-,-)
195         * JIRA: MATH-184
196         */
197        public void testFloatingPointArguments() throws Exception {
198            for (int i = 0; i < cumulativeTestPoints.length; i++) {
199                double arg = cumulativeTestPoints[i];
200                assertEquals(
201                        "Incorrect cumulative probability value returned for " +
202                        cumulativeTestPoints[i],
203                        cumulativeTestValues[i], 
204                        distribution.cumulativeProbability(arg), tolerance);
205                if (i < cumulativeTestPoints.length - 1) {
206                    double arg2 = cumulativeTestPoints[i + 1];
207                    assertEquals("Inconsistent probability for discrete range " +
208                            "[ " + arg + "," + arg2 + " ]",
209                       distribution.cumulativeProbability(
210                               cumulativeTestPoints[i],
211                               cumulativeTestPoints[i + 1]),
212                       distribution.cumulativeProbability(arg, arg2), tolerance);
213                    arg = arg - Math.random();
214                    arg2 = arg2 + Math.random();
215                    assertEquals("Inconsistent probability for discrete range " +
216                            "[ " + arg + "," + arg2 + " ]",
217                       distribution.cumulativeProbability(
218                               cumulativeTestPoints[i],
219                               cumulativeTestPoints[i + 1]),
220                       distribution.cumulativeProbability(arg, arg2), tolerance);
221                }
222            } 
223            int one = 1;
224            int ten = 10;
225            int two = 2;
226            double oned = one;
227            double twod = two;
228            double tend = ten;
229            assertEquals(distribution.cumulativeProbability(one, two), 
230                    distribution.cumulativeProbability(oned, twod), tolerance);
231            assertEquals(distribution.cumulativeProbability(one, two), 
232                    distribution.cumulativeProbability(oned - tolerance,
233                            twod + 0.9), tolerance);
234            assertEquals(distribution.cumulativeProbability(two, ten), 
235                    distribution.cumulativeProbability(twod, tend), tolerance);
236            assertEquals(distribution.cumulativeProbability(two, ten), 
237                    distribution.cumulativeProbability(twod - tolerance,
238                            tend + 0.9), tolerance);
239        }
240        
241        /**
242         * Verifies that inverse cumulative probability density calculations match expected values
243         * using default test instance data
244         */
245        public void testInverseCumulativeProbabilities() throws Exception {
246            verifyInverseCumulativeProbabilities();       
247        }
248        
249        /**
250         * Verifies that illegal arguments are correctly handled
251         */
252        public void testIllegalArguments() throws Exception {
253            try {
254                distribution.cumulativeProbability(1, 0);
255                fail("Expecting IllegalArgumentException for bad cumulativeProbability interval");
256            } catch (IllegalArgumentException ex) {
257                // expected
258            }
259            try {
260                distribution.inverseCumulativeProbability(-1);
261                fail("Expecting IllegalArgumentException for p = -1");
262            } catch (IllegalArgumentException ex) {
263                // expected
264            }
265            try {
266                distribution.inverseCumulativeProbability(2);
267                fail("Expecting IllegalArgumentException for p = 2");
268            } catch (IllegalArgumentException ex) {
269                // expected
270            }       
271        }
272        
273        //------------------ Getters / Setters for test instance data -----------
274        /**
275         * @return Returns the cumulativeTestPoints.
276         */
277        protected int[] getCumulativeTestPoints() {
278            return cumulativeTestPoints;
279        }
280    
281        /**
282         * @param cumulativeTestPoints The cumulativeTestPoints to set.
283         */
284        protected void setCumulativeTestPoints(int[] cumulativeTestPoints) {
285            this.cumulativeTestPoints = cumulativeTestPoints;
286        }
287    
288        /**
289         * @return Returns the cumulativeTestValues.
290         */
291        protected double[] getCumulativeTestValues() {
292            return cumulativeTestValues;
293        }
294    
295        /**
296         * @param cumulativeTestValues The cumulativeTestValues to set.
297         */
298        protected void setCumulativeTestValues(double[] cumulativeTestValues) {
299            this.cumulativeTestValues = cumulativeTestValues;
300        }
301    
302        /**
303         * @return Returns the densityTestPoints.
304         */
305        protected int[] getDensityTestPoints() {
306            return densityTestPoints;
307        }
308    
309        /**
310         * @param densityTestPoints The densityTestPoints to set.
311         */
312        protected void setDensityTestPoints(int[] densityTestPoints) {
313            this.densityTestPoints = densityTestPoints;
314        }
315    
316        /**
317         * @return Returns the densityTestValues.
318         */
319        protected double[] getDensityTestValues() {
320            return densityTestValues;
321        }
322    
323        /**
324         * @param densityTestValues The densityTestValues to set.
325         */
326        protected void setDensityTestValues(double[] densityTestValues) {
327            this.densityTestValues = densityTestValues;
328        }
329    
330        /**
331         * @return Returns the distribution.
332         */
333        protected IntegerDistribution getDistribution() {
334            return distribution;
335        }
336    
337        /**
338         * @param distribution The distribution to set.
339         */
340        protected void setDistribution(IntegerDistribution distribution) {
341            this.distribution = distribution;
342        }
343    
344        /**
345         * @return Returns the inverseCumulativeTestPoints.
346         */
347        protected double[] getInverseCumulativeTestPoints() {
348            return inverseCumulativeTestPoints;
349        }
350    
351        /**
352         * @param inverseCumulativeTestPoints The inverseCumulativeTestPoints to set.
353         */
354        protected void setInverseCumulativeTestPoints(double[] inverseCumulativeTestPoints) {
355            this.inverseCumulativeTestPoints = inverseCumulativeTestPoints;
356        }
357    
358        /**
359         * @return Returns the inverseCumulativeTestValues.
360         */
361        protected int[] getInverseCumulativeTestValues() {
362            return inverseCumulativeTestValues;
363        }
364    
365        /**
366         * @param inverseCumulativeTestValues The inverseCumulativeTestValues to set.
367         */
368        protected void setInverseCumulativeTestValues(int[] inverseCumulativeTestValues) {
369            this.inverseCumulativeTestValues = inverseCumulativeTestValues;
370        }
371    
372        /**
373         * @return Returns the tolerance.
374         */
375        protected double getTolerance() {
376            return tolerance;
377        }
378    
379        /**
380         * @param tolerance The tolerance to set.
381         */
382        protected void setTolerance(double tolerance) {
383            this.tolerance = tolerance;
384        }
385    
386    }