001: /*
002: * Copyright 2003-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:
022: /**
023: * Base class for integer-valued discrete distributions. Default
024: * implementations are provided for some of the methods that do not vary
025: * from distribution to distribution.
026: *
027: * @version $Revision: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
028: */
029: public abstract class AbstractIntegerDistribution extends
030: AbstractDistribution implements IntegerDistribution,
031: Serializable {
032:
033: /** Serializable version identifier */
034: private static final long serialVersionUID = -1146319659338487221L;
035:
036: /**
037: * Default constructor.
038: */
039: protected AbstractIntegerDistribution() {
040: super ();
041: }
042:
043: /**
044: * For a random variable X whose values are distributed according
045: * to this distribution, this method returns P(X ≤ x). In other words,
046: * this method represents the (cumulative) distribution function, or
047: * CDF, for this distribution.
048: * <p>
049: * If <code>x</code> does not represent an integer value, the CDF is
050: * evaluated at the greatest integer less than x.
051: *
052: * @param x the value at which the distribution function is evaluated.
053: * @return cumulative probability that a random variable with this
054: * distribution takes a value less than or equal to <code>x</code>
055: * @throws MathException if the cumulative probability can not be
056: * computed due to convergence or other numerical errors.
057: */
058: public double cumulativeProbability(double x) throws MathException {
059: return cumulativeProbability((int) Math.floor(x));
060: }
061:
062: /**
063: * For a random variable X whose values are distributed according
064: * to this distribution, this method returns P(X ≤ x). In other words,
065: * this method represents the probability distribution function, or PDF,
066: * for this distribution.
067: *
068: * @param x the value at which the PDF is evaluated.
069: * @return PDF for this distribution.
070: * @throws MathException if the cumulative probability can not be
071: * computed due to convergence or other numerical errors.
072: */
073: abstract public double cumulativeProbability(int x)
074: throws MathException;
075:
076: /**
077: * For a random variable X whose values are distributed according
078: * to this distribution, this method returns P(X = x). In other words, this
079: * method represents the probability mass function, or PMF, for the distribution.
080: * <p>
081: * If <code>x</code> does not represent an integer value, 0 is returned.
082: *
083: * @param x the value at which the probability density function is evaluated
084: * @return the value of the probability density function at x
085: */
086: public double probability(double x) {
087: double fl = Math.floor(x);
088: if (fl == x) {
089: return this .probability((int) x);
090: } else {
091: return 0;
092: }
093: }
094:
095: /**
096: * For a random variable X whose values are distributed according
097: * to this distribution, this method returns P(x0 ≤ X ≤ x1).
098: *
099: * @param x0 the inclusive, lower bound
100: * @param x1 the inclusive, upper bound
101: * @return the cumulative probability.
102: * @throws MathException if the cumulative probability can not be
103: * computed due to convergence or other numerical errors.
104: * @throws IllegalArgumentException if x0 > x1
105: */
106: public double cumulativeProbability(int x0, int x1)
107: throws MathException {
108: if (x0 > x1) {
109: throw new IllegalArgumentException(
110: "lower endpoint must be less than or equal to upper endpoint");
111: }
112: return cumulativeProbability(x1)
113: - cumulativeProbability(x0 - 1);
114: }
115:
116: /**
117: * For a random variable X whose values are distributed according
118: * to this distribution, this method returns the largest x, such
119: * that P(X ≤ x) ≤ <code>p</code>.
120: *
121: * @param p the desired probability
122: * @return the largest x such that P(X ≤ x) <= p
123: * @throws MathException if the inverse cumulative probability can not be
124: * computed due to convergence or other numerical errors.
125: * @throws IllegalArgumentException if p < 0 or p > 1
126: */
127: public int inverseCumulativeProbability(final double p)
128: throws MathException {
129: if (p < 0.0 || p > 1.0) {
130: throw new IllegalArgumentException(
131: "p must be between 0 and 1.0 (inclusive)");
132: }
133:
134: // by default, do simple bisection.
135: // subclasses can override if there is a better method.
136: int x0 = getDomainLowerBound(p);
137: int x1 = getDomainUpperBound(p);
138: double pm;
139: while (x0 < x1) {
140: int xm = x0 + (x1 - x0) / 2;
141: pm = cumulativeProbability(xm);
142: if (pm > p) {
143: // update x1
144: if (xm == x1) {
145: // this can happen with integer division
146: // simply decrement x1
147: --x1;
148: } else {
149: // update x1 normally
150: x1 = xm;
151: }
152: } else {
153: // update x0
154: if (xm == x0) {
155: // this can happen with integer division
156: // simply increment x0
157: ++x0;
158: } else {
159: // update x0 normally
160: x0 = xm;
161: }
162: }
163: }
164:
165: // insure x0 is the correct critical point
166: pm = cumulativeProbability(x0);
167: while (pm > p) {
168: --x0;
169: pm = cumulativeProbability(x0);
170: }
171:
172: return x0;
173: }
174:
175: /**
176: * Access the domain value lower bound, based on <code>p</code>, used to
177: * bracket a PDF root. This method is used by
178: * {@link #inverseCumulativeProbability(double)} to find critical values.
179: *
180: * @param p the desired probability for the critical value
181: * @return domain value lower bound, i.e.
182: * P(X < <i>lower bound</i>) < <code>p</code>
183: */
184: protected abstract int getDomainLowerBound(double p);
185:
186: /**
187: * Access the domain value upper bound, based on <code>p</code>, used to
188: * bracket a PDF root. This method is used by
189: * {@link #inverseCumulativeProbability(double)} to find critical values.
190: *
191: * @param p the desired probability for the critical value
192: * @return domain value upper bound, i.e.
193: * P(X < <i>upper bound</i>) > <code>p</code>
194: */
195: protected abstract int getDomainUpperBound(double p);
196: }
|