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 024 /** 025 * The default implementation of {@link ExponentialDistribution}. 026 * 027 * @version $Revision: 925900 $ $Date: 2010-03-21 17:10:07 -0400 (Sun, 21 Mar 2010) $ 028 */ 029 public class ExponentialDistributionImpl extends AbstractContinuousDistribution 030 implements ExponentialDistribution, Serializable { 031 032 /** 033 * Default inverse cumulative probability accuracy 034 * @since 2.1 035 */ 036 public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9; 037 038 /** Serializable version identifier */ 039 private static final long serialVersionUID = 2401296428283614780L; 040 041 /** The mean of this distribution. */ 042 private double mean; 043 044 /** Inverse cumulative probability accuracy */ 045 private final double solverAbsoluteAccuracy; 046 047 /** 048 * Create a exponential distribution with the given mean. 049 * @param mean mean of this distribution. 050 */ 051 public ExponentialDistributionImpl(double mean) { 052 this(mean, DEFAULT_INVERSE_ABSOLUTE_ACCURACY); 053 } 054 055 /** 056 * Create a exponential distribution with the given mean. 057 * @param mean mean of this distribution. 058 * @param inverseCumAccuracy the maximum absolute error in inverse cumulative probability estimates 059 * (defaults to {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}) 060 * @since 2.1 061 */ 062 public ExponentialDistributionImpl(double mean, double inverseCumAccuracy) { 063 super(); 064 setMeanInternal(mean); 065 solverAbsoluteAccuracy = inverseCumAccuracy; 066 } 067 068 /** 069 * Modify the mean. 070 * @param mean the new mean. 071 * @throws IllegalArgumentException if <code>mean</code> is not positive. 072 * @deprecated as of 2.1 (class will become immutable in 3.0) 073 */ 074 @Deprecated 075 public void setMean(double mean) { 076 setMeanInternal(mean); 077 } 078 /** 079 * Modify the mean. 080 * @param newMean the new mean. 081 * @throws IllegalArgumentException if <code>newMean</code> is not positive. 082 */ 083 private void setMeanInternal(double newMean) { 084 if (newMean <= 0.0) { 085 throw MathRuntimeException.createIllegalArgumentException( 086 "mean must be positive ({0})", newMean); 087 } 088 this.mean = newMean; 089 } 090 091 /** 092 * Access the mean. 093 * @return the mean. 094 */ 095 public double getMean() { 096 return mean; 097 } 098 099 /** 100 * Return the probability density for a particular point. 101 * 102 * @param x The point at which the density should be computed. 103 * @return The pdf at point x. 104 * @deprecated - use density(double) 105 */ 106 public double density(Double x) { 107 return density(x.doubleValue()); 108 } 109 110 /** 111 * Return the probability density for a particular point. 112 * 113 * @param x The point at which the density should be computed. 114 * @return The pdf at point x. 115 * @since 2.1 116 */ 117 @Override 118 public double density(double x) { 119 if (x < 0) { 120 return 0; 121 } 122 return Math.exp(-x / mean) / mean; 123 } 124 125 /** 126 * For this distribution, X, this method returns P(X < x). 127 * 128 * The implementation of this method is based on: 129 * <ul> 130 * <li> 131 * <a href="http://mathworld.wolfram.com/ExponentialDistribution.html"> 132 * Exponential Distribution</a>, equation (1).</li> 133 * </ul> 134 * 135 * @param x the value at which the CDF is evaluated. 136 * @return CDF for this distribution. 137 * @throws MathException if the cumulative probability can not be 138 * computed due to convergence or other numerical errors. 139 */ 140 public double cumulativeProbability(double x) throws MathException{ 141 double ret; 142 if (x <= 0.0) { 143 ret = 0.0; 144 } else { 145 ret = 1.0 - Math.exp(-x / mean); 146 } 147 return ret; 148 } 149 150 /** 151 * For this distribution, X, this method returns the critical point x, such 152 * that P(X < x) = <code>p</code>. 153 * <p> 154 * Returns 0 for p=0 and <code>Double.POSITIVE_INFINITY</code> for p=1.</p> 155 * 156 * @param p the desired probability 157 * @return x, such that P(X < x) = <code>p</code> 158 * @throws MathException if the inverse cumulative probability can not be 159 * computed due to convergence or other numerical errors. 160 * @throws IllegalArgumentException if p < 0 or p > 1. 161 */ 162 @Override 163 public double inverseCumulativeProbability(double p) throws MathException { 164 double ret; 165 166 if (p < 0.0 || p > 1.0) { 167 throw MathRuntimeException.createIllegalArgumentException( 168 "{0} out of [{1}, {2}] range", p, 0.0, 1.0); 169 } else if (p == 1.0) { 170 ret = Double.POSITIVE_INFINITY; 171 } else { 172 ret = -mean * Math.log(1.0 - p); 173 } 174 175 return ret; 176 } 177 178 /** 179 * Access the domain value lower bound, based on <code>p</code>, used to 180 * bracket a CDF root. 181 * 182 * @param p the desired probability for the critical value 183 * @return domain value lower bound, i.e. 184 * P(X < <i>lower bound</i>) < <code>p</code> 185 */ 186 @Override 187 protected double getDomainLowerBound(double p) { 188 return 0; 189 } 190 191 /** 192 * Access the domain value upper bound, based on <code>p</code>, used to 193 * bracket a CDF root. 194 * 195 * @param p the desired probability for the critical value 196 * @return domain value upper bound, i.e. 197 * P(X < <i>upper bound</i>) > <code>p</code> 198 */ 199 @Override 200 protected double getDomainUpperBound(double p) { 201 // NOTE: exponential is skewed to the left 202 // NOTE: therefore, P(X < μ) > .5 203 204 if (p < .5) { 205 // use mean 206 return mean; 207 } else { 208 // use max 209 return Double.MAX_VALUE; 210 } 211 } 212 213 /** 214 * Access the initial domain value, based on <code>p</code>, used to 215 * bracket a CDF root. 216 * 217 * @param p the desired probability for the critical value 218 * @return initial domain value 219 */ 220 @Override 221 protected double getInitialDomain(double p) { 222 // TODO: try to improve on this estimate 223 // TODO: what should really happen here is not derive from AbstractContinuousDistribution 224 // TODO: because the inverse cumulative distribution is simple. 225 // Exponential is skewed to the left, therefore, P(X < μ) > .5 226 if (p < .5) { 227 // use 1/2 mean 228 return mean * .5; 229 } else { 230 // use mean 231 return mean; 232 } 233 } 234 235 /** 236 * Return the absolute accuracy setting of the solver used to estimate 237 * inverse cumulative probabilities. 238 * 239 * @return the solver absolute accuracy 240 * @since 2.1 241 */ 242 @Override 243 protected double getSolverAbsoluteAccuracy() { 244 return solverAbsoluteAccuracy; 245 } 246 }