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
018 package org.apache.commons.math.distribution;
019
020 import java.io.Serializable;
021
022 import org.apache.commons.math.MathRuntimeException;
023
024 /**
025 * Default implementation of
026 * {@link org.apache.commons.math.distribution.WeibullDistribution}.
027 *
028 * @since 1.1
029 * @version $Revision: 925812 $ $Date: 2010-03-21 11:49:31 -0400 (Sun, 21 Mar 2010) $
030 */
031 public class WeibullDistributionImpl extends AbstractContinuousDistribution
032 implements WeibullDistribution, Serializable {
033
034 /**
035 * Default inverse cumulative probability accuracy
036 * @since 2.1
037 */
038 public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
039
040 /** Serializable version identifier */
041 private static final long serialVersionUID = 8589540077390120676L;
042
043 /** The shape parameter. */
044 private double shape;
045
046 /** The scale parameter. */
047 private double scale;
048
049 /** Inverse cumulative probability accuracy */
050 private final double solverAbsoluteAccuracy;
051
052 /**
053 * Creates weibull distribution with the given shape and scale and a
054 * location equal to zero.
055 * @param alpha the shape parameter.
056 * @param beta the scale parameter.
057 */
058 public WeibullDistributionImpl(double alpha, double beta){
059 this(alpha, beta, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
060 }
061
062 /**
063 * Creates weibull distribution with the given shape, scale and inverse
064 * cumulative probability accuracy and a location equal to zero.
065 * @param alpha the shape parameter.
066 * @param beta the scale parameter.
067 * @param inverseCumAccuracy the maximum absolute error in inverse cumulative probability estimates
068 * (defaults to {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY})
069 * @since 2.1
070 */
071 public WeibullDistributionImpl(double alpha, double beta, double inverseCumAccuracy){
072 super();
073 setShapeInternal(alpha);
074 setScaleInternal(beta);
075 solverAbsoluteAccuracy = inverseCumAccuracy;
076 }
077
078 /**
079 * For this distribution, X, this method returns P(X < <code>x</code>).
080 * @param x the value at which the CDF is evaluated.
081 * @return CDF evaluted at <code>x</code>.
082 */
083 public double cumulativeProbability(double x) {
084 double ret;
085 if (x <= 0.0) {
086 ret = 0.0;
087 } else {
088 ret = 1.0 - Math.exp(-Math.pow(x / scale, shape));
089 }
090 return ret;
091 }
092
093 /**
094 * Access the shape parameter.
095 * @return the shape parameter.
096 */
097 public double getShape() {
098 return shape;
099 }
100
101 /**
102 * Access the scale parameter.
103 * @return the scale parameter.
104 */
105 public double getScale() {
106 return scale;
107 }
108
109 /**
110 * Returns the probability density for a particular point.
111 *
112 * @param x The point at which the density should be computed.
113 * @return The pdf at point x.
114 * @since 2.1
115 */
116 @Override
117 public double density(double x) {
118 if (x < 0) {
119 return 0;
120 }
121
122 final double xscale = x / scale;
123 final double xscalepow = Math.pow(xscale, shape - 1);
124
125 /*
126 * Math.pow(x / scale, shape) =
127 * Math.pow(xscale, shape) =
128 * Math.pow(xscale, shape - 1) * xscale
129 */
130 final double xscalepowshape = xscalepow * xscale;
131
132 return (shape / scale) * xscalepow * Math.exp(-xscalepowshape);
133 }
134
135 /**
136 * For this distribution, X, this method returns the critical point x, such
137 * that P(X < x) = <code>p</code>.
138 * <p>
139 * Returns <code>Double.NEGATIVE_INFINITY</code> for p=0 and
140 * <code>Double.POSITIVE_INFINITY</code> for p=1.</p>
141 *
142 * @param p the desired probability
143 * @return x, such that P(X < x) = <code>p</code>
144 * @throws IllegalArgumentException if <code>p</code> is not a valid
145 * probability.
146 */
147 @Override
148 public double inverseCumulativeProbability(double p) {
149 double ret;
150 if (p < 0.0 || p > 1.0) {
151 throw MathRuntimeException.createIllegalArgumentException(
152 "{0} out of [{1}, {2}] range", p, 0.0, 1.0);
153 } else if (p == 0) {
154 ret = 0.0;
155 } else if (p == 1) {
156 ret = Double.POSITIVE_INFINITY;
157 } else {
158 ret = scale * Math.pow(-Math.log(1.0 - p), 1.0 / shape);
159 }
160 return ret;
161 }
162
163 /**
164 * Modify the shape parameter.
165 * @param alpha the new shape parameter value.
166 * @deprecated as of 2.1 (class will become immutable in 3.0)
167 */
168 @Deprecated
169 public void setShape(double alpha) {
170 setShapeInternal(alpha);
171 }
172 /**
173 * Modify the shape parameter.
174 * @param alpha the new shape parameter value.
175 */
176 private void setShapeInternal(double alpha) {
177 if (alpha <= 0.0) {
178 throw MathRuntimeException.createIllegalArgumentException(
179 "shape must be positive ({0})",
180 alpha);
181 }
182 this.shape = alpha;
183 }
184
185 /**
186 * Modify the scale parameter.
187 * @param beta the new scale parameter value.
188 * @deprecated as of 2.1 (class will become immutable in 3.0)
189 */
190 @Deprecated
191 public void setScale(double beta) {
192 setScaleInternal(beta);
193 }
194 /**
195 * Modify the scale parameter.
196 * @param beta the new scale parameter value.
197 */
198 private void setScaleInternal(double beta) {
199 if (beta <= 0.0) {
200 throw MathRuntimeException.createIllegalArgumentException(
201 "scale must be positive ({0})",
202 beta);
203 }
204 this.scale = beta;
205 }
206
207 /**
208 * Access the domain value lower bound, based on <code>p</code>, used to
209 * bracket a CDF root. This method is used by
210 * {@link #inverseCumulativeProbability(double)} to find critical values.
211 *
212 * @param p the desired probability for the critical value
213 * @return domain value lower bound, i.e.
214 * P(X < <i>lower bound</i>) < <code>p</code>
215 */
216 @Override
217 protected double getDomainLowerBound(double p) {
218 return 0.0;
219 }
220
221 /**
222 * Access the domain value upper bound, based on <code>p</code>, used to
223 * bracket a CDF root. This method is used by
224 * {@link #inverseCumulativeProbability(double)} to find critical values.
225 *
226 * @param p the desired probability for the critical value
227 * @return domain value upper bound, i.e.
228 * P(X < <i>upper bound</i>) > <code>p</code>
229 */
230 @Override
231 protected double getDomainUpperBound(double p) {
232 return Double.MAX_VALUE;
233 }
234
235 /**
236 * Access the initial domain value, based on <code>p</code>, used to
237 * bracket a CDF root. This method is used by
238 * {@link #inverseCumulativeProbability(double)} to find critical values.
239 *
240 * @param p the desired probability for the critical value
241 * @return initial domain value
242 */
243 @Override
244 protected double getInitialDomain(double p) {
245 // use median
246 return Math.pow(scale * Math.log(2.0), 1.0 / shape);
247 }
248
249 /**
250 * Return the absolute accuracy setting of the solver used to estimate
251 * inverse cumulative probabilities.
252 *
253 * @return the solver absolute accuracy
254 * @since 2.1
255 */
256 @Override
257 protected double getSolverAbsoluteAccuracy() {
258 return solverAbsoluteAccuracy;
259 }
260 }