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    *      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 java.io.Serializable;
20  
21  import org.apache.commons.math.MathException;
22  import org.apache.commons.math.special.Gamma;
23  import org.apache.commons.math.util.MathUtils;
24  
25  /**
26   * Implementation for the {@link PoissonDistribution}.
27   * 
28   * @version $Revision: 617953 $ $Date: 2008-02-02 22:54:00 -0700 (Sat, 02 Feb 2008) $
29   */
30  public class PoissonDistributionImpl extends AbstractIntegerDistribution
31          implements PoissonDistribution, Serializable {
32  
33      /** Serializable version identifier */
34      private static final long serialVersionUID = -3349935121172596109L;
35  
36      /** Distribution used to compute normal approximation. */
37      private NormalDistribution normal;
38      
39      /**
40       * Holds the Poisson mean for the distribution.
41       */
42      private double mean;
43  
44      /**
45       * Create a new Poisson distribution with the given the mean.
46       * The mean value must be positive; otherwise an 
47       * <code>IllegalArgument</code> is thrown.
48       * 
49       * @param p the Poisson mean
50       * @throws IllegalArgumentException if p &le; 0
51       */
52      public PoissonDistributionImpl(double p) {
53          this(p, new NormalDistributionImpl());
54      }
55  
56      /**
57       * Create a new Poisson distribution with the given the mean.
58       * The mean value must be positive; otherwise an 
59       * <code>IllegalArgument</code> is thrown.
60       * 
61       * @param p the Poisson mean
62       * @param z a normal distribution used to compute normal approximations.
63       * @throws IllegalArgumentException if p &le; 0
64       * @since 1.2
65       */
66      public PoissonDistributionImpl(double p, NormalDistribution z) {
67          super();
68          setNormal(z);
69          setMean(p);
70      }
71  
72      /**
73       * Get the Poisson mean for the distribution.
74       * 
75       * @return the Poisson mean for the distribution.
76       */
77      public double getMean() {
78          return this.mean;
79      }
80  
81      /**
82       * Set the Poisson mean for the distribution.
83       * The mean value must be positive; otherwise an 
84       * <code>IllegalArgument</code> is thrown.
85       * 
86       * @param p the Poisson mean value
87       * @throws IllegalArgumentException if p &le; 0
88       */
89      public void setMean(double p) {
90          if (p <= 0) {
91              throw new IllegalArgumentException(
92                      "The Poisson mean must be positive");
93          }
94          this.mean = p;
95          normal.setMean(p);
96          normal.setStandardDeviation(Math.sqrt(p));
97      }
98  
99      /**
100      * The probability mass function P(X = x) for a Poisson distribution.
101      * 
102      * @param x the value at which the probability density function is evaluated.
103      * @return the value of the probability mass function at x
104      */
105     public double probability(int x) {
106         if (x < 0 || x == Integer.MAX_VALUE) {
107             return 0;
108         }
109         return Math.pow(getMean(), x) / 
110             MathUtils.factorialDouble(x) * Math.exp(-mean);
111     }
112     
113     /**
114      * The probability distribution function P(X <= x) for a Poisson distribution.
115      * 
116      * @param x the value at which the PDF is evaluated.
117      * @return Poisson distribution function evaluated at x
118      * @throws MathException if the cumulative probability can not be
119      *            computed due to convergence or other numerical errors.
120      */
121     public double cumulativeProbability(int x) throws MathException {
122         if (x < 0) {
123             return 0;
124         }
125         if (x == Integer.MAX_VALUE) {
126             return 1;
127         }
128         return Gamma.regularizedGammaQ((double)x + 1, mean, 
129                 1E-12, Integer.MAX_VALUE);
130     }
131 
132     /**
133      * Calculates the Poisson distribution function using a normal
134      * approximation.  The <code>N(mean, sqrt(mean))</code>
135      * distribution is used to approximate the Poisson distribution.
136      * <p>
137      * The computation uses "half-correction" -- evaluating the normal
138      * distribution function at <code>x + 0.5</code></p>
139      * 
140      * @param x the upper bound, inclusive
141      * @return the distribution function value calculated using a normal approximation
142      * @throws MathException if an error occurs computing the normal approximation
143      */
144     public double normalApproximateProbability(int x) throws MathException {
145         // calculate the probability using half-correction
146         return normal.cumulativeProbability(x + 0.5);
147     }
148 
149     /**
150      * Access the domain value lower bound, based on <code>p</code>, used to
151      * bracket a CDF root.  This method is used by
152      * {@link #inverseCumulativeProbability(double)} to find critical values.
153      * 
154      * @param p the desired probability for the critical value
155      * @return domain lower bound
156      */
157     protected int getDomainLowerBound(double p) {
158         return 0;
159     }
160 
161     /**
162      * Access the domain value upper bound, based on <code>p</code>, used to
163      * bracket a CDF root.  This method is used by
164      * {@link #inverseCumulativeProbability(double)} to find critical values.
165      * 
166      * @param p the desired probability for the critical value
167      * @return domain upper bound
168      */
169     protected int getDomainUpperBound(double p) {
170         return Integer.MAX_VALUE;
171     }
172     
173     /**
174      * Modify the normal distribution used to compute normal approximations.
175      * The caller is responsible for insuring the normal distribution has the
176      * proper parameter settings.
177      * @param value the new distribution
178      * @since 1.2
179      */
180     public void setNormal(NormalDistribution value) {
181         normal = value;
182     }
183     
184 }