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.MathRuntimeException;
23
24
25 /**
26 * Base class for integer-valued discrete distributions. Default
27 * implementations are provided for some of the methods that do not vary
28 * from distribution to distribution.
29 *
30 * @version $Revision: 772119 $ $Date: 2009-05-06 05:43:28 -0400 (Wed, 06 May 2009) $
31 */
32 public abstract class AbstractIntegerDistribution extends AbstractDistribution
33 implements IntegerDistribution, Serializable {
34
35 /** Serializable version identifier */
36 private static final long serialVersionUID = -1146319659338487221L;
37
38 /**
39 * Default constructor.
40 */
41 protected AbstractIntegerDistribution() {
42 super();
43 }
44
45 /**
46 * For a random variable X whose values are distributed according
47 * to this distribution, this method returns P(X ≤ x). In other words,
48 * this method represents the (cumulative) distribution function, or
49 * CDF, for this distribution.
50 * <p>
51 * If <code>x</code> does not represent an integer value, the CDF is
52 * evaluated at the greatest integer less than x.
53 *
54 * @param x the value at which the distribution function is evaluated.
55 * @return cumulative probability that a random variable with this
56 * distribution takes a value less than or equal to <code>x</code>
57 * @throws MathException if the cumulative probability can not be
58 * computed due to convergence or other numerical errors.
59 */
60 public double cumulativeProbability(double x) throws MathException {
61 return cumulativeProbability((int) Math.floor(x));
62 }
63
64 /**
65 * For a random variable X whose values are distributed according
66 * to this distribution, this method returns P(x0 ≤ X ≤ x1).
67 *
68 * @param x0 the (inclusive) lower bound
69 * @param x1 the (inclusive) upper bound
70 * @return the probability that a random variable with this distribution
71 * will take a value between <code>x0</code> and <code>x1</code>,
72 * including the endpoints.
73 * @throws MathException if the cumulative probability can not be
74 * computed due to convergence or other numerical errors.
75 * @throws IllegalArgumentException if <code>x0 > x1</code>
76 */
77 @Override
78 public double cumulativeProbability(double x0, double x1)
79 throws MathException {
80 if (x0 > x1) {
81 throw MathRuntimeException.createIllegalArgumentException(
82 "lower endpoint ({0}) must be less than or equal to upper endpoint ({1})",
83 x0, x1);
84 }
85 if (Math.floor(x0) < x0) {
86 return cumulativeProbability(((int) Math.floor(x0)) + 1,
87 (int) Math.floor(x1)); // don't want to count mass below x0
88 } else { // x0 is mathematical integer, so use as is
89 return cumulativeProbability((int) Math.floor(x0),
90 (int) Math.floor(x1));
91 }
92 }
93
94 /**
95 * For a random variable X whose values are distributed according
96 * to this distribution, this method returns P(X ≤ x). In other words,
97 * this method represents the probability distribution function, or PDF,
98 * for this distribution.
99 *
100 * @param x the value at which the PDF is evaluated.
101 * @return PDF for this distribution.
102 * @throws MathException if the cumulative probability can not be
103 * computed due to convergence or other numerical errors.
104 */
105 abstract public double cumulativeProbability(int x) throws MathException;
106
107 /**
108 * For a random variable X whose values are distributed according
109 * to this distribution, this method returns P(X = x). In other words, this
110 * method represents the probability mass function, or PMF, for the distribution.
111 * <p>
112 * If <code>x</code> does not represent an integer value, 0 is returned.
113 *
114 * @param x the value at which the probability density function is evaluated
115 * @return the value of the probability density function at x
116 */
117 public double probability(double x) {
118 double fl = Math.floor(x);
119 if (fl == x) {
120 return this.probability((int) x);
121 } else {
122 return 0;
123 }
124 }
125
126 /**
127 * For a random variable X whose values are distributed according
128 * to this distribution, this method returns P(x0 ≤ X ≤ x1).
129 *
130 * @param x0 the inclusive, lower bound
131 * @param x1 the inclusive, upper bound
132 * @return the cumulative probability.
133 * @throws MathException if the cumulative probability can not be
134 * computed due to convergence or other numerical errors.
135 * @throws IllegalArgumentException if x0 > x1
136 */
137 public double cumulativeProbability(int x0, int x1) throws MathException {
138 if (x0 > x1) {
139 throw MathRuntimeException.createIllegalArgumentException(
140 "lower endpoint ({0}) must be less than or equal to upper endpoint ({1})",
141 x0, x1);
142 }
143 return cumulativeProbability(x1) - cumulativeProbability(x0 - 1);
144 }
145
146 /**
147 * For a random variable X whose values are distributed according
148 * to this distribution, this method returns the largest x, such
149 * that P(X ≤ x) ≤ <code>p</code>.
150 *
151 * @param p the desired probability
152 * @return the largest x such that P(X ≤ x) <= p
153 * @throws MathException if the inverse cumulative probability can not be
154 * computed due to convergence or other numerical errors.
155 * @throws IllegalArgumentException if p < 0 or p > 1
156 */
157 public int inverseCumulativeProbability(final double p) throws MathException{
158 if (p < 0.0 || p > 1.0) {
159 throw MathRuntimeException.createIllegalArgumentException(
160 "{0} out of [{1}, {2}] range", p, 0.0, 1.0);
161 }
162
163 // by default, do simple bisection.
164 // subclasses can override if there is a better method.
165 int x0 = getDomainLowerBound(p);
166 int x1 = getDomainUpperBound(p);
167 double pm;
168 while (x0 < x1) {
169 int xm = x0 + (x1 - x0) / 2;
170 pm = cumulativeProbability(xm);
171 if (pm > p) {
172 // update x1
173 if (xm == x1) {
174 // this can happen with integer division
175 // simply decrement x1
176 --x1;
177 } else {
178 // update x1 normally
179 x1 = xm;
180 }
181 } else {
182 // update x0
183 if (xm == x0) {
184 // this can happen with integer division
185 // simply increment x0
186 ++x0;
187 } else {
188 // update x0 normally
189 x0 = xm;
190 }
191 }
192 }
193
194 // insure x0 is the correct critical point
195 pm = cumulativeProbability(x0);
196 while (pm > p) {
197 --x0;
198 pm = cumulativeProbability(x0);
199 }
200
201 return x0;
202 }
203
204 /**
205 * Access the domain value lower bound, based on <code>p</code>, used to
206 * bracket a PDF root. This method is used by
207 * {@link #inverseCumulativeProbability(double)} to find critical values.
208 *
209 * @param p the desired probability for the critical value
210 * @return domain value lower bound, i.e.
211 * P(X < <i>lower bound</i>) < <code>p</code>
212 */
213 protected abstract int getDomainLowerBound(double p);
214
215 /**
216 * Access the domain value upper bound, based on <code>p</code>, used to
217 * bracket a PDF root. This method is used by
218 * {@link #inverseCumulativeProbability(double)} to find critical values.
219 *
220 * @param p the desired probability for the critical value
221 * @return domain value upper bound, i.e.
222 * P(X < <i>upper bound</i>) > <code>p</code>
223 */
224 protected abstract int getDomainUpperBound(double p);
225 }