View Javadoc
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