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 import org.apache.commons.math.special.Beta;
24 import org.apache.commons.math.util.MathUtils;
25
26 /**
27 * The default implementation of {@link PascalDistribution}.
28 * @version $Revision: 772119 $ $Date: 2009-05-06 05:43:28 -0400 (Wed, 06 May 2009) $
29 * @since 1.2
30 */
31 public class PascalDistributionImpl extends AbstractIntegerDistribution
32 implements PascalDistribution, Serializable {
33
34 /** Serializable version identifier */
35 private static final long serialVersionUID = 6751309484392813623L;
36
37 /** The number of successes */
38 private int numberOfSuccesses;
39
40 /** The probability of success */
41 private double probabilityOfSuccess;
42
43 /**
44 * Create a binomial distribution with the given number of trials and
45 * probability of success.
46 * @param r the number of successes
47 * @param p the probability of success
48 */
49 public PascalDistributionImpl(int r, double p) {
50 super();
51 setNumberOfSuccesses(r);
52 setProbabilityOfSuccess(p);
53 }
54
55 /**
56 * Access the number of successes for this distribution.
57 * @return the number of successes
58 */
59 public int getNumberOfSuccesses() {
60 return numberOfSuccesses;
61 }
62
63 /**
64 * Access the probability of success for this distribution.
65 * @return the probability of success
66 */
67 public double getProbabilityOfSuccess() {
68 return probabilityOfSuccess;
69 }
70
71 /**
72 * Change the number of successes for this distribution.
73 * @param successes the new number of successes
74 * @throws IllegalArgumentException if <code>successes</code> is not
75 * positive.
76 */
77 public void setNumberOfSuccesses(int successes) {
78 if (successes < 0) {
79 throw MathRuntimeException.createIllegalArgumentException(
80 "number of successes must be non-negative ({0})",
81 successes);
82 }
83 numberOfSuccesses = successes;
84 }
85
86 /**
87 * Change the probability of success for this distribution.
88 * @param p the new probability of success
89 * @throws IllegalArgumentException if <code>p</code> is not a valid
90 * probability.
91 */
92 public void setProbabilityOfSuccess(double p) {
93 if (p < 0.0 || p > 1.0) {
94 throw MathRuntimeException.createIllegalArgumentException(
95 "{0} out of [{1}, {2}] range", p, 0.0, 1.0);
96 }
97 probabilityOfSuccess = p;
98 }
99
100 /**
101 * Access the domain value lower bound, based on <code>p</code>, used to
102 * bracket a PDF root.
103 * @param p the desired probability for the critical value
104 * @return domain value lower bound, i.e. P(X < <i>lower bound</i>) <
105 * <code>p</code>
106 */
107 @Override
108 protected int getDomainLowerBound(double p) {
109 return -1;
110 }
111
112 /**
113 * Access the domain value upper bound, based on <code>p</code>, used to
114 * bracket a PDF root.
115 * @param p the desired probability for the critical value
116 * @return domain value upper bound, i.e. P(X < <i>upper bound</i>) >
117 * <code>p</code>
118 */
119 @Override
120 protected int getDomainUpperBound(double p) {
121 // use MAX - 1 because MAX causes loop
122 return Integer.MAX_VALUE - 1;
123 }
124
125 /**
126 * For this distribution, X, this method returns P(X ≤ x).
127 * @param x the value at which the PDF is evaluated
128 * @return PDF for this distribution
129 * @throws MathException if the cumulative probability can not be computed
130 * due to convergence or other numerical errors
131 */
132 @Override
133 public double cumulativeProbability(int x) throws MathException {
134 double ret;
135 if (x < 0) {
136 ret = 0.0;
137 } else {
138 ret = Beta.regularizedBeta(getProbabilityOfSuccess(),
139 getNumberOfSuccesses(), x + 1);
140 }
141 return ret;
142 }
143
144 /**
145 * For this distribution, X, this method returns P(X = x).
146 * @param x the value at which the PMF is evaluated
147 * @return PMF for this distribution
148 */
149 public double probability(int x) {
150 double ret;
151 if (x < 0) {
152 ret = 0.0;
153 } else {
154 ret = MathUtils.binomialCoefficientDouble(x +
155 getNumberOfSuccesses() - 1, getNumberOfSuccesses() - 1) *
156 Math.pow(getProbabilityOfSuccess(), getNumberOfSuccesses()) *
157 Math.pow(1.0 - getProbabilityOfSuccess(), x);
158 }
159 return ret;
160 }
161
162 /**
163 * For this distribution, X, this method returns the largest x, such that
164 * P(X ≤ x) ≤ <code>p</code>.
165 * <p>
166 * Returns <code>-1</code> for p=0 and <code>Integer.MAX_VALUE</code>
167 * for p=1.</p>
168 * @param p the desired probability
169 * @return the largest x such that P(X ≤ x) <= p
170 * @throws MathException if the inverse cumulative probability can not be
171 * computed due to convergence or other numerical errors.
172 * @throws IllegalArgumentException if p < 0 or p > 1
173 */
174 @Override
175 public int inverseCumulativeProbability(final double p)
176 throws MathException {
177 int ret;
178
179 // handle extreme values explicitly
180 if (p == 0) {
181 ret = -1;
182 } else if (p == 1) {
183 ret = Integer.MAX_VALUE;
184 } else {
185 ret = super.inverseCumulativeProbability(p);
186 }
187
188 return ret;
189 }
190 }