001: /*
002: * Copyright 2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.math.distribution;
017:
018: import java.io.Serializable;
019:
020: import org.apache.commons.math.MathException;
021: import org.apache.commons.math.special.Gamma;
022: import org.apache.commons.math.util.MathUtils;
023:
024: /**
025: * Implementation for the {@link PoissonDistribution}.
026: *
027: * @version $Revision: 355770 $ $Date: 2005-12-10 12:48:57 -0700 (Sat, 10 Dec 2005) $
028: */
029: public class PoissonDistributionImpl extends
030: AbstractIntegerDistribution implements PoissonDistribution,
031: Serializable {
032:
033: /** Serializable version identifier */
034: private static final long serialVersionUID = -3349935121172596109L;
035:
036: /**
037: * Holds the Poisson mean for the distribution.
038: */
039: private double mean;
040:
041: /**
042: * Create a new Poisson distribution with the given the mean.
043: * The mean value must be positive; otherwise an
044: * <code>IllegalArgument</code> is thrown.
045: *
046: * @param p the Poisson mean
047: * @throws IllegalArgumentException if p ≤ 0
048: */
049: public PoissonDistributionImpl(double p) {
050: super ();
051: setMean(p);
052: }
053:
054: /**
055: * Get the Poisson mean for the distribution.
056: *
057: * @return the Poisson mean for the distribution.
058: */
059: public double getMean() {
060: return this .mean;
061: }
062:
063: /**
064: * Set the Poisson mean for the distribution.
065: * The mean value must be positive; otherwise an
066: * <code>IllegalArgument</code> is thrown.
067: *
068: * @param p the Poisson mean value
069: * @throws IllegalArgumentException if p ≤ 0
070: */
071: public void setMean(double p) {
072: if (p <= 0) {
073: throw new IllegalArgumentException(
074: "The Poisson mean must be positive");
075: }
076: this .mean = p;
077: }
078:
079: /**
080: * The probability mass function P(X = x) for a Poisson distribution.
081: *
082: * @param x the value at which the probability density function is evaluated.
083: * @return the value of the probability mass function at x
084: */
085: public double probability(int x) {
086: if (x < 0 || x == Integer.MAX_VALUE) {
087: return 0;
088: }
089: return Math.pow(getMean(), x) / MathUtils.factorialDouble(x)
090: * Math.exp(-mean);
091: }
092:
093: /**
094: * The probability distribution function P(X <= x) for a Poisson distribution.
095: *
096: * @param x the value at which the PDF is evaluated.
097: * @return Poisson distribution function evaluated at x
098: * @throws MathException if the cumulative probability can not be
099: * computed due to convergence or other numerical errors.
100: */
101: public double cumulativeProbability(int x) throws MathException {
102: if (x < 0) {
103: return 0;
104: }
105: if (x == Integer.MAX_VALUE) {
106: return 1;
107: }
108: return Gamma.regularizedGammaQ((double) x + 1, mean, 1E-12,
109: Integer.MAX_VALUE);
110: }
111:
112: /**
113: * Calculates the Poisson distribution function using a normal
114: * approximation. The <code>N(mean, sqrt(mean))</code>
115: * distribution is used to approximate the Poisson distribution.
116: * <p>
117: * The computation uses "half-correction" -- evaluating the normal
118: * distribution function at <code>x + 0.5</code>
119: *
120: * @param x the upper bound, inclusive
121: * @return the distribution function value calculated using a normal approximation
122: * @throws MathException if an error occurs computing the normal approximation
123: */
124: public double normalApproximateProbability(int x)
125: throws MathException {
126: NormalDistribution normal = DistributionFactory.newInstance()
127: .createNormalDistribution(getMean(),
128: Math.sqrt(getMean()));
129:
130: // calculate the probability using half-correction
131: return normal.cumulativeProbability(x + 0.5);
132: }
133:
134: /**
135: * Access the domain value lower bound, based on <code>p</code>, used to
136: * bracket a CDF root. This method is used by
137: * {@link #inverseCumulativeProbability(double)} to find critical values.
138: *
139: * @param p the desired probability for the critical value
140: * @return domain lower bound
141: */
142: protected int getDomainLowerBound(double p) {
143: return 0;
144: }
145:
146: /**
147: * Access the domain value upper bound, based on <code>p</code>, used to
148: * bracket a CDF root. This method is used by
149: * {@link #inverseCumulativeProbability(double)} to find critical values.
150: *
151: * @param p the desired probability for the critical value
152: * @return domain upper bound
153: */
154: protected int getDomainUpperBound(double p) {
155: return Integer.MAX_VALUE;
156: }
157:
158: }
|