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 * https://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
18 /*
19 * This is not the original file distributed by the Apache Software Foundation
20 * It has been modified by the Hipparchus project
21 */
22
23 package org.hipparchus.distribution.continuous;
24
25 import org.hipparchus.exception.LocalizedCoreFormats;
26 import org.hipparchus.exception.MathIllegalArgumentException;
27 import org.hipparchus.special.Gamma;
28 import org.hipparchus.util.FastMath;
29 import org.hipparchus.util.MathUtils;
30
31 /**
32 * Implementation of the Weibull distribution. This implementation uses the
33 * two parameter form of the distribution defined by
34 * <a href="http://mathworld.wolfram.com/WeibullDistribution.html">
35 * Weibull Distribution</a>, equations (1) and (2).
36 *
37 * @see <a href="http://en.wikipedia.org/wiki/Weibull_distribution">Weibull distribution (Wikipedia)</a>
38 * @see <a href="http://mathworld.wolfram.com/WeibullDistribution.html">Weibull distribution (MathWorld)</a>
39 */
40 public class WeibullDistribution extends AbstractRealDistribution {
41 /** Serializable version identifier. */
42 private static final long serialVersionUID = 20160320L;
43 /** The shape parameter. */
44 private final double shape;
45 /** The scale parameter. */
46 private final double scale;
47
48 /**
49 * Create a Weibull distribution with the given shape and scale.
50 *
51 * @param alpha Shape parameter.
52 * @param beta Scale parameter.
53 * @throws MathIllegalArgumentException if {@code alpha <= 0} or {@code beta <= 0}.
54 */
55 public WeibullDistribution(double alpha, double beta)
56 throws MathIllegalArgumentException {
57 if (alpha <= 0) {
58 throw new MathIllegalArgumentException(LocalizedCoreFormats.SHAPE,
59 alpha);
60 }
61 if (beta <= 0) {
62 throw new MathIllegalArgumentException(LocalizedCoreFormats.SCALE,
63 beta);
64 }
65 scale = beta;
66 shape = alpha;
67 }
68
69 /**
70 * Access the shape parameter, {@code alpha}.
71 *
72 * @return the shape parameter, {@code alpha}.
73 */
74 public double getShape() {
75 return shape;
76 }
77
78 /**
79 * Access the scale parameter, {@code beta}.
80 *
81 * @return the scale parameter, {@code beta}.
82 */
83 public double getScale() {
84 return scale;
85 }
86
87 /** {@inheritDoc} */
88 @Override
89 public double density(double x) {
90 if (x < 0) {
91 return 0;
92 }
93
94 final double xscale = x / scale;
95 final double xscalepow = FastMath.pow(xscale, shape - 1);
96
97 /*
98 * FastMath.pow(x / scale, shape) =
99 * FastMath.pow(xscale, shape) =
100 * FastMath.pow(xscale, shape - 1) * xscale
101 */
102 final double xscalepowshape = xscalepow * xscale;
103
104 return (shape / scale) * xscalepow * FastMath.exp(-xscalepowshape);
105 }
106
107 /** {@inheritDoc} */
108 @Override
109 public double logDensity(double x) {
110 if (x < 0) {
111 return Double.NEGATIVE_INFINITY;
112 }
113
114 final double xscale = x / scale;
115 final double logxscalepow = FastMath.log(xscale) * (shape - 1);
116
117 /*
118 * FastMath.pow(x / scale, shape) =
119 * FastMath.pow(xscale, shape) =
120 * FastMath.pow(xscale, shape - 1) * xscale
121 */
122 final double xscalepowshape = FastMath.exp(logxscalepow) * xscale;
123
124 return FastMath.log(shape / scale) + logxscalepow - xscalepowshape;
125 }
126
127 /** {@inheritDoc} */
128 @Override
129 public double cumulativeProbability(double x) {
130 double ret;
131 if (x <= 0.0) {
132 ret = 0.0;
133 } else {
134 ret = 1.0 - FastMath.exp(-FastMath.pow(x / scale, shape));
135 }
136 return ret;
137 }
138
139 /**
140 * {@inheritDoc}
141 *
142 * Returns {@code 0} when {@code p == 0} and
143 * {@code Double.POSITIVE_INFINITY} when {@code p == 1}.
144 */
145 @Override
146 public double inverseCumulativeProbability(double p) {
147 MathUtils.checkRangeInclusive(p, 0, 1);
148
149 double ret;
150 if (p == 0) {
151 ret = 0.0;
152 } else if (p == 1) {
153 ret = Double.POSITIVE_INFINITY;
154 } else {
155 ret = scale * FastMath.pow(-FastMath.log1p(-p), 1.0 / shape);
156 }
157 return ret;
158 }
159
160 /**
161 * {@inheritDoc}
162 *
163 * The mean is {@code scale * Gamma(1 + (1 / shape))}, where {@code Gamma()}
164 * is the Gamma-function.
165 */
166 @Override
167 public double getNumericalMean() {
168 final double sh = getShape();
169 final double sc = getScale();
170
171 return sc * FastMath.exp(Gamma.logGamma(1 + (1 / sh)));
172 }
173
174 /**
175 * {@inheritDoc}
176 *
177 * The variance is {@code scale^2 * Gamma(1 + (2 / shape)) - mean^2}
178 * where {@code Gamma()} is the Gamma-function.
179 */
180 @Override
181 public double getNumericalVariance() {
182 final double sh = getShape();
183 final double sc = getScale();
184 final double mn = getNumericalMean();
185
186 return (sc * sc) * FastMath.exp(Gamma.logGamma(1 + (2 / sh))) -
187 (mn * mn);
188 }
189
190 /**
191 * {@inheritDoc}
192 *
193 * The lower bound of the support is always 0 no matter the parameters.
194 *
195 * @return lower bound of the support (always 0)
196 */
197 @Override
198 public double getSupportLowerBound() {
199 return 0;
200 }
201
202 /**
203 * {@inheritDoc}
204 *
205 * The upper bound of the support is always positive infinity
206 * no matter the parameters.
207 *
208 * @return upper bound of the support (always
209 * {@code Double.POSITIVE_INFINITY})
210 */
211 @Override
212 public double getSupportUpperBound() {
213 return Double.POSITIVE_INFINITY;
214 }
215
216 /**
217 * {@inheritDoc}
218 *
219 * The support of this distribution is connected.
220 *
221 * @return {@code true}
222 */
223 @Override
224 public boolean isSupportConnected() {
225 return true;
226 }
227 }
228