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 ≤ 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 ≤ 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 ≤ 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 }