blob: 85623d45cce3c29206c757d2665ff3943c68fb52 [file] [log] [blame]
Raymonddee08492015-04-02 10:43:13 -07001/*
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 */
17package org.apache.commons.math.distribution;
18
19import java.io.Serializable;
20
21import org.apache.commons.math.MathException;
22import org.apache.commons.math.MathRuntimeException;
23import org.apache.commons.math.exception.util.LocalizedFormats;
24import org.apache.commons.math.special.Gamma;
25import org.apache.commons.math.util.MathUtils;
26import org.apache.commons.math.util.FastMath;
27
28/**
29 * Implementation for the {@link PoissonDistribution}.
30 *
31 * @version $Revision: 1054524 $ $Date: 2011-01-03 05:59:18 +0100 (lun. 03 janv. 2011) $
32 */
33public class PoissonDistributionImpl extends AbstractIntegerDistribution
34 implements PoissonDistribution, Serializable {
35
36 /**
37 * Default maximum number of iterations for cumulative probability calculations.
38 * @since 2.1
39 */
40 public static final int DEFAULT_MAX_ITERATIONS = 10000000;
41
42 /**
43 * Default convergence criterion.
44 * @since 2.1
45 */
46 public static final double DEFAULT_EPSILON = 1E-12;
47
48 /** Serializable version identifier */
49 private static final long serialVersionUID = -3349935121172596109L;
50
51 /** Distribution used to compute normal approximation. */
52 private NormalDistribution normal;
53
54 /**
55 * Holds the Poisson mean for the distribution.
56 */
57 private double mean;
58
59 /**
60 * Maximum number of iterations for cumulative probability.
61 *
62 * Cumulative probabilities are estimated using either Lanczos series approximation of
63 * Gamma#regularizedGammaP or continued fraction approximation of Gamma#regularizedGammaQ.
64 */
65 private int maxIterations = DEFAULT_MAX_ITERATIONS;
66
67 /**
68 * Convergence criterion for cumulative probability.
69 */
70 private double epsilon = DEFAULT_EPSILON;
71
72 /**
73 * Create a new Poisson distribution with the given the mean. The mean value
74 * must be positive; otherwise an <code>IllegalArgument</code> is thrown.
75 *
76 * @param p the Poisson mean
77 * @throws IllegalArgumentException if p &le; 0
78 */
79 public PoissonDistributionImpl(double p) {
80 this(p, new NormalDistributionImpl());
81 }
82
83 /**
84 * Create a new Poisson distribution with the given mean, convergence criterion
85 * and maximum number of iterations.
86 *
87 * @param p the Poisson mean
88 * @param epsilon the convergence criteria for cumulative probabilites
89 * @param maxIterations the maximum number of iterations for cumulative probabilites
90 * @since 2.1
91 */
92 public PoissonDistributionImpl(double p, double epsilon, int maxIterations) {
93 setMean(p);
94 this.epsilon = epsilon;
95 this.maxIterations = maxIterations;
96 }
97
98 /**
99 * Create a new Poisson distribution with the given mean and convergence criterion.
100 *
101 * @param p the Poisson mean
102 * @param epsilon the convergence criteria for cumulative probabilites
103 * @since 2.1
104 */
105 public PoissonDistributionImpl(double p, double epsilon) {
106 setMean(p);
107 this.epsilon = epsilon;
108 }
109
110 /**
111 * Create a new Poisson distribution with the given mean and maximum number of iterations.
112 *
113 * @param p the Poisson mean
114 * @param maxIterations the maximum number of iterations for cumulative probabilites
115 * @since 2.1
116 */
117 public PoissonDistributionImpl(double p, int maxIterations) {
118 setMean(p);
119 this.maxIterations = maxIterations;
120 }
121
122
123 /**
124 * Create a new Poisson distribution with the given the mean. The mean value
125 * must be positive; otherwise an <code>IllegalArgument</code> is thrown.
126 *
127 * @param p the Poisson mean
128 * @param z a normal distribution used to compute normal approximations.
129 * @throws IllegalArgumentException if p &le; 0
130 * @since 1.2
131 * @deprecated as of 2.1 (to avoid possibly inconsistent state, the
132 * "NormalDistribution" will be instantiated internally)
133 */
134 @Deprecated
135 public PoissonDistributionImpl(double p, NormalDistribution z) {
136 super();
137 setNormalAndMeanInternal(z, p);
138 }
139
140 /**
141 * Get the Poisson mean for the distribution.
142 *
143 * @return the Poisson mean for the distribution.
144 */
145 public double getMean() {
146 return mean;
147 }
148
149 /**
150 * Set the Poisson mean for the distribution. The mean value must be
151 * positive; otherwise an <code>IllegalArgument</code> is thrown.
152 *
153 * @param p the Poisson mean value
154 * @throws IllegalArgumentException if p &le; 0
155 * @deprecated as of 2.1 (class will become immutable in 3.0)
156 */
157 @Deprecated
158 public void setMean(double p) {
159 setNormalAndMeanInternal(normal, p);
160 }
161 /**
162 * Set the Poisson mean for the distribution. The mean value must be
163 * positive; otherwise an <code>IllegalArgument</code> is thrown.
164 *
165 * @param z the new distribution
166 * @param p the Poisson mean value
167 * @throws IllegalArgumentException if p &le; 0
168 */
169 private void setNormalAndMeanInternal(NormalDistribution z,
170 double p) {
171 if (p <= 0) {
172 throw MathRuntimeException.createIllegalArgumentException(
173 LocalizedFormats.NOT_POSITIVE_POISSON_MEAN, p);
174 }
175 mean = p;
176 normal = z;
177 normal.setMean(p);
178 normal.setStandardDeviation(FastMath.sqrt(p));
179 }
180
181 /**
182 * The probability mass function P(X = x) for a Poisson distribution.
183 *
184 * @param x the value at which the probability density function is
185 * evaluated.
186 * @return the value of the probability mass function at x
187 */
188 public double probability(int x) {
189 double ret;
190 if (x < 0 || x == Integer.MAX_VALUE) {
191 ret = 0.0;
192 } else if (x == 0) {
193 ret = FastMath.exp(-mean);
194 } else {
195 ret = FastMath.exp(-SaddlePointExpansion.getStirlingError(x) -
196 SaddlePointExpansion.getDeviancePart(x, mean)) /
197 FastMath.sqrt(MathUtils.TWO_PI * x);
198 }
199 return ret;
200 }
201
202 /**
203 * The probability distribution function P(X <= x) for a Poisson
204 * distribution.
205 *
206 * @param x the value at which the PDF is evaluated.
207 * @return Poisson distribution function evaluated at x
208 * @throws MathException if the cumulative probability can not be computed
209 * due to convergence or other numerical errors.
210 */
211 @Override
212 public double cumulativeProbability(int x) throws MathException {
213 if (x < 0) {
214 return 0;
215 }
216 if (x == Integer.MAX_VALUE) {
217 return 1;
218 }
219 return Gamma.regularizedGammaQ((double) x + 1, mean, epsilon, maxIterations);
220 }
221
222 /**
223 * Calculates the Poisson distribution function using a normal
224 * approximation. The <code>N(mean, sqrt(mean))</code> distribution is used
225 * to approximate the Poisson distribution.
226 * <p>
227 * The computation uses "half-correction" -- evaluating the normal
228 * distribution function at <code>x + 0.5</code>
229 * </p>
230 *
231 * @param x the upper bound, inclusive
232 * @return the distribution function value calculated using a normal
233 * approximation
234 * @throws MathException if an error occurs computing the normal
235 * approximation
236 */
237 public double normalApproximateProbability(int x) throws MathException {
238 // calculate the probability using half-correction
239 return normal.cumulativeProbability(x + 0.5);
240 }
241
242 /**
243 * Generates a random value sampled from this distribution.
244 *
245 * <p><strong>Algorithm Description</strong>:
246 * <ul><li> For small means, uses simulation of a Poisson process
247 * using Uniform deviates, as described
248 * <a href="http://irmi.epfl.ch/cmos/Pmmi/interactive/rng7.htm"> here.</a>
249 * The Poisson process (and hence value returned) is bounded by 1000 * mean.</li><
250 *
251 * <li> For large means, uses the rejection algorithm described in <br/>
252 * Devroye, Luc. (1981).<i>The Computer Generation of Poisson Random Variables</i>
253 * <strong>Computing</strong> vol. 26 pp. 197-207.</li></ul></p>
254 *
255 * @return random value
256 * @since 2.2
257 * @throws MathException if an error occurs generating the random value
258 */
259 @Override
260 public int sample() throws MathException {
261 return (int) FastMath.min(randomData.nextPoisson(mean), Integer.MAX_VALUE);
262 }
263
264 /**
265 * Access the domain value lower bound, based on <code>p</code>, used to
266 * bracket a CDF root. This method is used by
267 * {@link #inverseCumulativeProbability(double)} to find critical values.
268 *
269 * @param p the desired probability for the critical value
270 * @return domain lower bound
271 */
272 @Override
273 protected int getDomainLowerBound(double p) {
274 return 0;
275 }
276
277 /**
278 * Access the domain value upper bound, based on <code>p</code>, used to
279 * bracket a CDF root. This method is used by
280 * {@link #inverseCumulativeProbability(double)} to find critical values.
281 *
282 * @param p the desired probability for the critical value
283 * @return domain upper bound
284 */
285 @Override
286 protected int getDomainUpperBound(double p) {
287 return Integer.MAX_VALUE;
288 }
289
290 /**
291 * Modify the normal distribution used to compute normal approximations. The
292 * caller is responsible for insuring the normal distribution has the proper
293 * parameter settings.
294 *
295 * @param value the new distribution
296 * @since 1.2
297 * @deprecated as of 2.1 (class will become immutable in 3.0)
298 */
299 @Deprecated
300 public void setNormal(NormalDistribution value) {
301 setNormalAndMeanInternal(value, mean);
302 }
303
304 /**
305 * Returns the lower bound of the support for the distribution.
306 *
307 * The lower bound of the support is always 0 no matter the mean parameter.
308 *
309 * @return lower bound of the support (always 0)
310 * @since 2.2
311 */
312 public int getSupportLowerBound() {
313 return 0;
314 }
315
316 /**
317 * Returns the upper bound of the support for the distribution.
318 *
319 * The upper bound of the support is positive infinity,
320 * regardless of the parameter values. There is no integer infinity,
321 * so this method returns <code>Integer.MAX_VALUE</code> and
322 * {@link #isSupportUpperBoundInclusive()} returns <code>true</code>.
323 *
324 * @return upper bound of the support (always <code>Integer.MAX_VALUE</code> for positive infinity)
325 * @since 2.2
326 */
327 public int getSupportUpperBound() {
328 return Integer.MAX_VALUE;
329 }
330
331 /**
332 * Returns the variance of the distribution.
333 *
334 * For mean parameter <code>p</code>, the variance is <code>p</code>
335 *
336 * @return the variance
337 * @since 2.2
338 */
339 public double getNumericalVariance() {
340 return getMean();
341 }
342
343}