001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.math.distribution;
018
019 import java.io.Serializable;
020
021 import org.apache.commons.math.MathException;
022 import org.apache.commons.math.MathRuntimeException;
023 import org.apache.commons.math.special.Beta;
024 import org.apache.commons.math.util.MathUtils;
025
026 /**
027 * The default implementation of {@link PascalDistribution}.
028 * @version $Revision: 920852 $ $Date: 2010-03-09 07:53:44 -0500 (Tue, 09 Mar 2010) $
029 * @since 1.2
030 */
031 public class PascalDistributionImpl extends AbstractIntegerDistribution
032 implements PascalDistribution, Serializable {
033
034 /** Serializable version identifier */
035 private static final long serialVersionUID = 6751309484392813623L;
036
037 /** The number of successes */
038 private int numberOfSuccesses;
039
040 /** The probability of success */
041 private double probabilityOfSuccess;
042
043 /**
044 * Create a binomial distribution with the given number of trials and
045 * probability of success.
046 * @param r the number of successes
047 * @param p the probability of success
048 */
049 public PascalDistributionImpl(int r, double p) {
050 super();
051 setNumberOfSuccessesInternal(r);
052 setProbabilityOfSuccessInternal(p);
053 }
054
055 /**
056 * Access the number of successes for this distribution.
057 * @return the number of successes
058 */
059 public int getNumberOfSuccesses() {
060 return numberOfSuccesses;
061 }
062
063 /**
064 * Access the probability of success for this distribution.
065 * @return the probability of success
066 */
067 public double getProbabilityOfSuccess() {
068 return probabilityOfSuccess;
069 }
070
071 /**
072 * Change the number of successes for this distribution.
073 * @param successes the new number of successes
074 * @throws IllegalArgumentException if <code>successes</code> is not
075 * positive.
076 * @deprecated as of 2.1 (class will become immutable in 3.0)
077 */
078 @Deprecated
079 public void setNumberOfSuccesses(int successes) {
080 setNumberOfSuccessesInternal(successes);
081 }
082 /**
083 * Change the number of successes for this distribution.
084 * @param successes the new number of successes
085 * @throws IllegalArgumentException if <code>successes</code> is not
086 * positive.
087 */
088 private void setNumberOfSuccessesInternal(int successes) {
089 if (successes < 0) {
090 throw MathRuntimeException.createIllegalArgumentException(
091 "number of successes must be non-negative ({0})",
092 successes);
093 }
094 numberOfSuccesses = successes;
095 }
096
097 /**
098 * Change the probability of success for this distribution.
099 * @param p the new probability of success
100 * @throws IllegalArgumentException if <code>p</code> is not a valid
101 * probability.
102 * @deprecated as of 2.1 (class will become immutable in 3.0)
103 */
104 @Deprecated
105 public void setProbabilityOfSuccess(double p) {
106 setProbabilityOfSuccessInternal(p);
107 }
108 /**
109 * Change the probability of success for this distribution.
110 * @param p the new probability of success
111 * @throws IllegalArgumentException if <code>p</code> is not a valid
112 * probability.
113 */
114 private void setProbabilityOfSuccessInternal(double p) {
115 if (p < 0.0 || p > 1.0) {
116 throw MathRuntimeException.createIllegalArgumentException(
117 "{0} out of [{1}, {2}] range", p, 0.0, 1.0);
118 }
119 probabilityOfSuccess = p;
120 }
121
122 /**
123 * Access the domain value lower bound, based on <code>p</code>, used to
124 * bracket a PDF root.
125 * @param p the desired probability for the critical value
126 * @return domain value lower bound, i.e. P(X < <i>lower bound</i>) <
127 * <code>p</code>
128 */
129 @Override
130 protected int getDomainLowerBound(double p) {
131 return -1;
132 }
133
134 /**
135 * Access the domain value upper bound, based on <code>p</code>, used to
136 * bracket a PDF root.
137 * @param p the desired probability for the critical value
138 * @return domain value upper bound, i.e. P(X < <i>upper bound</i>) >
139 * <code>p</code>
140 */
141 @Override
142 protected int getDomainUpperBound(double p) {
143 // use MAX - 1 because MAX causes loop
144 return Integer.MAX_VALUE - 1;
145 }
146
147 /**
148 * For this distribution, X, this method returns P(X ≤ x).
149 * @param x the value at which the PDF is evaluated
150 * @return PDF for this distribution
151 * @throws MathException if the cumulative probability can not be computed
152 * due to convergence or other numerical errors
153 */
154 @Override
155 public double cumulativeProbability(int x) throws MathException {
156 double ret;
157 if (x < 0) {
158 ret = 0.0;
159 } else {
160 ret = Beta.regularizedBeta(probabilityOfSuccess,
161 numberOfSuccesses, x + 1);
162 }
163 return ret;
164 }
165
166 /**
167 * For this distribution, X, this method returns P(X = x).
168 * @param x the value at which the PMF is evaluated
169 * @return PMF for this distribution
170 */
171 public double probability(int x) {
172 double ret;
173 if (x < 0) {
174 ret = 0.0;
175 } else {
176 ret = MathUtils.binomialCoefficientDouble(x +
177 numberOfSuccesses - 1, numberOfSuccesses - 1) *
178 Math.pow(probabilityOfSuccess, numberOfSuccesses) *
179 Math.pow(1.0 - probabilityOfSuccess, x);
180 }
181 return ret;
182 }
183
184 /**
185 * For this distribution, X, this method returns the largest x, such that
186 * P(X ≤ x) ≤ <code>p</code>.
187 * <p>
188 * Returns <code>-1</code> for p=0 and <code>Integer.MAX_VALUE</code>
189 * for p=1.</p>
190 * @param p the desired probability
191 * @return the largest x such that P(X ≤ x) <= p
192 * @throws MathException if the inverse cumulative probability can not be
193 * computed due to convergence or other numerical errors.
194 * @throws IllegalArgumentException if p < 0 or p > 1
195 */
196 @Override
197 public int inverseCumulativeProbability(final double p)
198 throws MathException {
199 int ret;
200
201 // handle extreme values explicitly
202 if (p == 0) {
203 ret = -1;
204 } else if (p == 1) {
205 ret = Integer.MAX_VALUE;
206 } else {
207 ret = super.inverseCumulativeProbability(p);
208 }
209
210 return ret;
211 }
212 }