    1   /*
    2    * Copyright 2004 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.math.distribution;
    17
    18  import junit.framework.TestCase;
    19  import org.apache.commons.math.TestUtils;
    20
    21  /***
    22   * Abstract base class for {@link ContinuousDistribution} tests.
    23   * <p>
    24   * To create a concrete test class for a continuous 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   * makeCumulativeTestPoints() -- arguments used to test cumulative probabilities
    31   * makeCumulativeTestValues() -- expected cumulative probabilites
    32   * makeInverseCumulativeTestPoints() -- arguments used to test inverse cdf evaluation
    33   * makeInverseCumulativeTestValues() -- expected inverse cdf values
    34   * <p>
    35   * To implement additional test cases with different distribution instances and test data,
    36   * use the setXxx methods for the instance data in test cases and call the verifyXxx methods
    37   * to verify results.
    38   * <p>
    39   * Error tolerance can be overriden by implementing getTolerance().
    40   *
    41   * @version $Revision: 1.2 $ $Date: 2004/05/30 03:08:00 $
    42   */
    43  public abstract class ContinuousDistributionAbstractTest extends TestCase {
    44
    45  //-------------------- Private test instance data -------------------------
    46      /***  Distribution instance used to perform tests */
    47      private ContinuousDistribution distribution;
    48
    49      /*** Tolerance used in comparing expected and returned values */
    50      private double tolerance = 1E-4;
    51
    52      /*** Arguments used to test cumulative probability density calculations */
    53      private double[] cumulativeTestPoints;
    54
    55      /*** Values used to test cumulative probability density calculations */
    56      private double[] cumulativeTestValues;
    57
    58      /*** Arguments used to test inverse cumulative probability density calculations */
    59      private double[] inverseCumulativeTestPoints;
    60
    61      /*** Values used to test inverse cumulative probability density calculations */
    62      private double[] inverseCumulativeTestValues;
    63
    64      //-------------------------------------------------------------------------
    65
    66      /***
    67       * Constructor for ContinuousDistributionAbstractTest.
    68       * @param name
    69       */
    70      public ContinuousDistributionAbstractTest(String name) {
    71          super(name);
    72      }
    73
    74      //-------------------- Abstract methods -----------------------------------
    75
    76      /*** Creates the default continuous distribution instance to use in tests. */
    77      public abstract ContinuousDistribution makeDistribution();
    78
    79      /*** Creates the default cumulative probability density test input values */
    80      public abstract double[] makeCumulativeTestPoints();
    81
    82      /*** Creates the default cumulative probability density test expected values */
    83      public abstract double[] makeCumulativeTestValues();
    84
    85      //---- Default implementations of inverse test data generation methods ----
    86
    87      /*** Creates the default inverse cumulative probability test input values */
    88      public double[] makeInverseCumulativeTestPoints() {
    89          return makeCumulativeTestValues();
    90      }
    91
    92      /*** Creates the default inverse cumulative probability density test expected values */
    93      public double[] makeInverseCumulativeTestValues() {
    94          return makeCumulativeTestPoints();
    95      }
    96
    97      //-------------------- Setup / tear down ----------------------------------
    98
    99      /***
    100      * Setup sets all test instance data to default values
    101      */
    102     protected void setUp() throws Exception {
    103         super.setUp();
    104         distribution = makeDistribution();
    105         cumulativeTestPoints = makeCumulativeTestPoints();
    106         cumulativeTestValues = makeCumulativeTestValues();
    107         inverseCumulativeTestPoints = makeInverseCumulativeTestPoints();
    108         inverseCumulativeTestValues = makeInverseCumulativeTestValues();
    109     }
    110
    111     /***
    112      * Cleans up test instance data
    113      */
    114     protected void tearDown() throws Exception {
    115         super.tearDown();
    116         distribution = null;
    117         cumulativeTestPoints = null;
    118         cumulativeTestValues = null;
    119         inverseCumulativeTestPoints = null;
    120         inverseCumulativeTestValues = null;
    121     }
    122
    123     //-------------------- Verification methods -------------------------------
    124
    125     /***
    126      * Verifies that cumulative probability density calculations match expected values
    127      * using current test instance data
    128      */
    129     protected void verifyCumulativeProbabilities() throws Exception {
    130         for (int i = 0; i < cumulativeTestPoints.length; i++) {
    131             TestUtils.assertEquals("Incorrect cumulative probability value returned for "
    132                 + cumulativeTestPoints[i], cumulativeTestValues[i],
    133                 distribution.cumulativeProbability(cumulativeTestPoints[i]),
    134                 getTolerance());
    135         }
    136     }
    137
    138     /***
    139      * Verifies that inverse cumulative probability density calculations match expected values
    140      * using current test instance data
    141      */
    142     protected void verifyInverseCumulativeProbabilities() throws Exception {
    143         for (int i = 0; i < inverseCumulativeTestPoints.length; i++) {
    144             TestUtils.assertEquals("Incorrect inverse cumulative probability value returned for "
    145                 + inverseCumulativeTestPoints[i], inverseCumulativeTestValues[i],
    146                  distribution.inverseCumulativeProbability(inverseCumulativeTestPoints[i]),
    147                  getTolerance());
    148         }
    149     }
    150
    151     //------------------------ Default test cases -----------------------------
    152
    153     /***
    154      * Verifies that cumulative probability density calculations match expected values
    155      * using default test instance data
    156      */
    157     public void testCumulativeProbabilities() throws Exception {
    158         verifyCumulativeProbabilities();
    159     }
    160
    161     /***
    162      * Verifies that inverse cumulative probability density calculations match expected values
    163      * using default test instance data
    164      */
    165     public void testInverseCumulativeProbabilities() throws Exception {
    166         verifyInverseCumulativeProbabilities();
    167     }
    168
    169     /***
    170      * Verifies that probability computations are consistent
    171      */
    172     public void testConsistency() throws Exception {
    173         for (int i=1; i < cumulativeTestPoints.length; i++) {
    174
    175             // check that cdf(x, x) = 0
    176             TestUtils.assertEquals(0d,
    177                distribution.cumulativeProbability
    178                  (cumulativeTestPoints[i], cumulativeTestPoints[i]), tolerance);
    179
    180             // check that P(a < X < b) = P(X < b) - P(X < a)
    181             double upper = Math.max(cumulativeTestPoints[i], cumulativeTestPoints[i -1]);
    182             double lower = Math.min(cumulativeTestPoints[i], cumulativeTestPoints[i -1]);
    183             double diff = distribution.cumulativeProbability(upper) -
    184             	distribution.cumulativeProbability(lower);
    185             double direct = distribution.cumulativeProbability(lower, upper);
    186             TestUtils.assertEquals("Inconsistent cumulative probabilities for ("
    187                     + lower + "," + upper + ")", diff, direct, tolerance);
    188         }
    189     }
    190
    191     /***
    192      * Verifies that illegal arguments are correctly handled
    193      */
    194     public void testIllegalArguments() throws Exception {
    195         try {
    196             distribution.cumulativeProbability(1, 0);
    197             fail("Expecting IllegalArgumentException for bad cumulativeProbability interval");
    198         } catch (IllegalArgumentException ex) {
    199             // expected
    200         }
    201         try {
    202             distribution.inverseCumulativeProbability(-1);
    203             fail("Expecting IllegalArgumentException for p = -1");
    204         } catch (IllegalArgumentException ex) {
    205             // expected
    206         }
    207         try {
    208             distribution.inverseCumulativeProbability(2);
    209             fail("Expecting IllegalArgumentException for p = 2");
    210         } catch (IllegalArgumentException ex) {
    211             // expected
    212         }
    213     }
    214
    215     //------------------ Getters / Setters for test instance data -----------
    216     /***
    217      * @return Returns the cumulativeTestPoints.
    218      */
    219     protected double[] getCumulativeTestPoints() {
    220         return cumulativeTestPoints;
    221     }
    222
    223     /***
    224      * @param cumulativeTestPoints The cumulativeTestPoints to set.
    225      */
    226     protected void setCumulativeTestPoints(double[] cumulativeTestPoints) {
    227         this.cumulativeTestPoints = cumulativeTestPoints;
    228     }
    229
    230     /***
    231      * @return Returns the cumulativeTestValues.
    232      */
    233     protected double[] getCumulativeTestValues() {
    234         return cumulativeTestValues;
    235     }
    236
    237     /***
    238      * @param cumulativeTestValues The cumulativeTestValues to set.
    239      */
    240     protected void setCumulativeTestValues(double[] cumulativeTestValues) {
    241         this.cumulativeTestValues = cumulativeTestValues;
    242     }
    243
    244     /***
    245      * @return Returns the distribution.
    246      */
    247     protected ContinuousDistribution getDistribution() {
    248         return distribution;
    249     }
    250
    251     /***
    252      * @param distribution The distribution to set.
    253      */
    254     protected void setDistribution(ContinuousDistribution distribution) {
    255         this.distribution = distribution;
    256     }
    257
    258     /***
    259      * @return Returns the inverseCumulativeTestPoints.
    260      */
    261     protected double[] getInverseCumulativeTestPoints() {
    262         return inverseCumulativeTestPoints;
    263     }
    264
    265     /***
    266      * @param inverseCumulativeTestPoints The inverseCumulativeTestPoints to set.
    267      */
    268     protected void setInverseCumulativeTestPoints(double[] inverseCumulativeTestPoints) {
    269         this.inverseCumulativeTestPoints = inverseCumulativeTestPoints;
    270     }
    271
    272     /***
    273      * @return Returns the inverseCumulativeTestValues.
    274      */
    275     protected double[] getInverseCumulativeTestValues() {
    276         return inverseCumulativeTestValues;
    277     }
    278
    279     /***
    280      * @param inverseCumulativeTestValues The inverseCumulativeTestValues to set.
    281      */
    282     protected void setInverseCumulativeTestValues(double[] inverseCumulativeTestValues) {
    283         this.inverseCumulativeTestValues = inverseCumulativeTestValues;
    284     }
    285
    286     /***
    287      * @return Returns the tolerance.
    288      */
    289     protected double getTolerance() {
    290         return tolerance;
    291     }
    292
    293     /***
    294      * @param tolerance The tolerance to set.
    295      */
    296     protected void setTolerance(double tolerance) {
    297         this.tolerance = tolerance;
    298     }
    299
    300 }