View Javadoc

    1   /*
    2    * Copyright 2003-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
    17  package org.apache.commons.math.distribution;
    18
    19  import java.io.Serializable;
    20
    21  import org.apache.commons.math.MathException;
    22  import org.apache.commons.math.util.MathUtils;
    23
    24  /***
    25   * The default implementation of {@link HypergeometricDistribution}.
    26   *
    27   * @version $Revision: 1.16 $ $Date: 2004/11/07 03:32:48 $
    28   */
    29  public class HypergeometricDistributionImpl extends AbstractIntegerDistribution
    30      implements HypergeometricDistribution, Serializable
    31  {
    32
    33      /*** Serializable version identifier */
    34      static final long serialVersionUID = -436928820673516179L;
    35
    36      /*** The number of successes in the population. */
    37      private int numberOfSuccesses;
    38
    39      /*** The population size. */
    40      private int populationSize;
    41
    42      /*** The sample size. */
    43      private int sampleSize;
    44
    45      /***
    46       * Construct a new hypergeometric distribution with the given the population
    47       * size, the number of successes in the population, and the sample size.
    48       * @param populationSize the population size.
    49       * @param numberOfSuccesses number of successes in the population.
    50       * @param sampleSize the sample size.
    51       */
    52      public HypergeometricDistributionImpl(int populationSize,
    53          int numberOfSuccesses, int sampleSize) {
    54          super();
    55          if (numberOfSuccesses > populationSize) {
    56              throw new IllegalArgumentException(
    57              "number of successes must be less than or equal to population size");
    58          }
    59          if (sampleSize > populationSize) {
    60              throw new IllegalArgumentException(
    61              "sample size must be less than or equal to population size");
    62          }
    63          setPopulationSize(populationSize);
    64          setSampleSize(sampleSize);
    65          setNumberOfSuccesses(numberOfSuccesses);
    66      }
    67
    68      /***
    69       * For this disbution, X, this method returns P(X &le; x).
    70       * @param x the value at which the PDF is evaluated.
    71       * @return PDF for this distribution.
    72       * @throws MathException if the cumulative probability can not be
    73       *            computed due to convergence or other numerical errors.
    74       */
    75      public double cumulativeProbability(int x) throws MathException{
    76          double ret;
    77
    78          int n = getPopulationSize();
    79          int m = getNumberOfSuccesses();
    80          int k = getSampleSize();
    81
    82          int[] domain = getDomain(n, m, k);
    83          if (x < domain[0]) {
    84              ret = 0.0;
    85          } else if(x >= domain[1]) {
    86              ret = 1.0;
    87          } else {
    88              ret = 0.0;
    89              for (int i = domain[0]; i <= x; ++i){
    90                  ret += probability(n, m, k, i);
    91              }
    92          }
    93
    94          return ret;
    95      }
    96
    97      /***
    98       * Return the domain for the given hypergeometric distribution parameters.
    99       * @param n the population size.
    100      * @param m number of successes in the population.
    101      * @param k the sample size.
    102      * @return a two element array containing the lower and upper bounds of the
    103      *         hypergeometric distribution.
    104      */
    105     private int[] getDomain(int n, int m, int k){
    106         return new int[]{
    107             getLowerDomain(n, m, k),
    108             getUpperDomain(m, k)
    109         };
    110     }
    111
    112     /***
    113      * Access the domain value lower bound, based on <code>p</code>, used to
    114      * bracket a PDF root.
    115      *
    116      * @param p the desired probability for the critical value
    117      * @return domain value lower bound, i.e.
    118      *         P(X &lt; <i>lower bound</i>) &lt; <code>p</code>
    119      */
    120     protected int getDomainLowerBound(double p) {
    121         return getLowerDomain(getPopulationSize(), getNumberOfSuccesses(),
    122             getSampleSize());
    123     }
    124
    125     /***
    126      * Access the domain value upper bound, based on <code>p</code>, used to
    127      * bracket a PDF root.
    128      *
    129      * @param p the desired probability for the critical value
    130      * @return domain value upper bound, i.e.
    131      *         P(X &lt; <i>upper bound</i>) &gt; <code>p</code>
    132      */
    133     protected int getDomainUpperBound(double p) {
    134         return getUpperDomain(getSampleSize(), getNumberOfSuccesses());
    135     }
    136
    137     /***
    138      * Return the lowest domain value for the given hypergeometric distribution
    139      * parameters.
    140      * @param n the population size.
    141      * @param m number of successes in the population.
    142      * @param k the sample size.
    143      * @return the lowest domain value of the hypergeometric distribution.
    144      */
    145     private int getLowerDomain(int n, int m, int k) {
    146         return Math.max(0, m - (n - k));
    147     }
    148
    149     /***
    150      * Access the number of successes.
    151      * @return the number of successes.
    152      */
    153     public int getNumberOfSuccesses() {
    154         return numberOfSuccesses;
    155     }
    156
    157     /***
    158      * Access the population size.
    159      * @return the population size.
    160      */
    161     public int getPopulationSize() {
    162         return populationSize;
    163     }
    164
    165     /***
    166      * Access the sample size.
    167      * @return the sample size.
    168      */
    169     public int getSampleSize() {
    170         return sampleSize;
    171     }
    172
    173     /***
    174      * Return the highest domain value for the given hypergeometric distribution
    175      * parameters.
    176      * @param m number of successes in the population.
    177      * @param k the sample size.
    178      * @return the highest domain value of the hypergeometric distribution.
    179      */
    180     private int getUpperDomain(int m, int k){
    181         return Math.min(k, m);
    182     }
    183
    184     /***
    185      * For this disbution, X, this method returns P(X = x).
    186      *
    187      * @param x the value at which the PMF is evaluated.
    188      * @return PMF for this distribution.
    189      */
    190     public double probability(int x) {
    191         double ret;
    192
    193         int n = getPopulationSize();
    194         int m = getNumberOfSuccesses();
    195         int k = getSampleSize();
    196
    197         int[] domain = getDomain(n, m, k);
    198         if(x < domain[0] || x > domain[1]){
    199             ret = 0.0;
    200         } else {
    201             ret = probability(n, m, k, x);
    202         }
    203
    204         return ret;
    205     }
    206
    207     /***
    208      * For the disbution, X, defined by the given hypergeometric distribution
    209      * parameters, this method returns P(X = x).
    210      *
    211      * @param n the population size.
    212      * @param m number of successes in the population.
    213      * @param k the sample size.
    214      * @param x the value at which the PMF is evaluated.
    215      * @return PMF for the distribution.
    216      */
    217     private double probability(int n, int m, int k, int x) {
    218         return Math.exp(MathUtils.binomialCoefficientLog(m, x) +
    219             MathUtils.binomialCoefficientLog(n - m, k - x) -
    220             MathUtils.binomialCoefficientLog(n, k));
    221     }
    222
    223     /***
    224      * Modify the number of successes.
    225      * @param num the new number of successes.
    226      * @throws IllegalArgumentException if <code>num</code> is negative.
    227      */
    228     public void setNumberOfSuccesses(int num) {
    229         if(num < 0){
    230             throw new IllegalArgumentException(
    231                 "number of successes must be non-negative.");
    232         }
    233         numberOfSuccesses = num;
    234     }
    235
    236     /***
    237      * Modify the population size.
    238      * @param size the new population size.
    239      * @throws IllegalArgumentException if <code>size</code> is not positive.
    240      */
    241     public void setPopulationSize(int size) {
    242         if(size <= 0){
    243             throw new IllegalArgumentException(
    244                 "population size must be positive.");
    245         }
    246         populationSize = size;
    247     }
    248
    249     /***
    250      * Modify the sample size.
    251      * @param size the new sample size.
    252      * @throws IllegalArgumentException if <code>size</code> is negative.
    253      */
    254     public void setSampleSize(int size) {
    255         if (size < 0) {
    256             throw new IllegalArgumentException(
    257                 "sample size must be non-negative.");
    258         }
    259         sampleSize = size;
    260     }
    261 }