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 }