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 */
017package org.apache.commons.math3.distribution;
018
019import org.apache.commons.math3.exception.NotStrictlyPositiveException;
020import org.apache.commons.math3.exception.util.LocalizedFormats;
021import org.apache.commons.math3.random.RandomGenerator;
022import org.apache.commons.math3.random.Well19937c;
023import org.apache.commons.math3.special.Gamma;
024import org.apache.commons.math3.util.FastMath;
025
026/**
027 * Implementation of the Gamma distribution.
028 *
029 * @see <a href="http://en.wikipedia.org/wiki/Gamma_distribution">Gamma distribution (Wikipedia)</a>
030 * @see <a href="http://mathworld.wolfram.com/GammaDistribution.html">Gamma distribution (MathWorld)</a>
031 */
032public class GammaDistribution extends AbstractRealDistribution {
033    /**
034     * Default inverse cumulative probability accuracy.
035     * @since 2.1
036     */
037    public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
038    /** Serializable version identifier. */
039    private static final long serialVersionUID = 20120524L;
040    /** The shape parameter. */
041    private final double shape;
042    /** The scale parameter. */
043    private final double scale;
044    /**
045     * The constant value of {@code shape + g + 0.5}, where {@code g} is the
046     * Lanczos constant {@link Gamma#LANCZOS_G}.
047     */
048    private final double shiftedShape;
049    /**
050     * The constant value of
051     * {@code shape / scale * sqrt(e / (2 * pi * (shape + g + 0.5))) / L(shape)},
052     * where {@code L(shape)} is the Lanczos approximation returned by
053     * {@link Gamma#lanczos(double)}. This prefactor is used in
054     * {@link #density(double)}, when no overflow occurs with the natural
055     * calculation.
056     */
057    private final double densityPrefactor1;
058    /**
059     * The constant value of
060     * {@code log(shape / scale * sqrt(e / (2 * pi * (shape + g + 0.5))) / L(shape))},
061     * where {@code L(shape)} is the Lanczos approximation returned by
062     * {@link Gamma#lanczos(double)}. This prefactor is used in
063     * {@link #logDensity(double)}, when no overflow occurs with the natural
064     * calculation.
065     */
066    private final double logDensityPrefactor1;
067    /**
068     * The constant value of
069     * {@code shape * sqrt(e / (2 * pi * (shape + g + 0.5))) / L(shape)},
070     * where {@code L(shape)} is the Lanczos approximation returned by
071     * {@link Gamma#lanczos(double)}. This prefactor is used in
072     * {@link #density(double)}, when overflow occurs with the natural
073     * calculation.
074     */
075    private final double densityPrefactor2;
076    /**
077     * The constant value of
078     * {@code log(shape * sqrt(e / (2 * pi * (shape + g + 0.5))) / L(shape))},
079     * where {@code L(shape)} is the Lanczos approximation returned by
080     * {@link Gamma#lanczos(double)}. This prefactor is used in
081     * {@link #logDensity(double)}, when overflow occurs with the natural
082     * calculation.
083     */
084    private final double logDensityPrefactor2;
085    /**
086     * Lower bound on {@code y = x / scale} for the selection of the computation
087     * method in {@link #density(double)}. For {@code y <= minY}, the natural
088     * calculation overflows.
089     */
090    private final double minY;
091    /**
092     * Upper bound on {@code log(y)} ({@code y = x / scale}) for the selection
093     * of the computation method in {@link #density(double)}. For
094     * {@code log(y) >= maxLogY}, the natural calculation overflows.
095     */
096    private final double maxLogY;
097    /** Inverse cumulative probability accuracy. */
098    private final double solverAbsoluteAccuracy;
099
100    /**
101     * Creates a new gamma distribution with specified values of the shape and
102     * scale parameters.
103     * <p>
104     * <b>Note:</b> this constructor will implicitly create an instance of
105     * {@link Well19937c} as random generator to be used for sampling only (see
106     * {@link #sample()} and {@link #sample(int)}). In case no sampling is
107     * needed for the created distribution, it is advised to pass {@code null}
108     * as random generator via the appropriate constructors to avoid the
109     * additional initialisation overhead.
110     *
111     * @param shape the shape parameter
112     * @param scale the scale parameter
113     * @throws NotStrictlyPositiveException if {@code shape <= 0} or
114     * {@code scale <= 0}.
115     */
116    public GammaDistribution(double shape, double scale) throws NotStrictlyPositiveException {
117        this(shape, scale, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
118    }
119
120    /**
121     * Creates a new gamma distribution with specified values of the shape and
122     * scale parameters.
123     * <p>
124     * <b>Note:</b> this constructor will implicitly create an instance of
125     * {@link Well19937c} as random generator to be used for sampling only (see
126     * {@link #sample()} and {@link #sample(int)}). In case no sampling is
127     * needed for the created distribution, it is advised to pass {@code null}
128     * as random generator via the appropriate constructors to avoid the
129     * additional initialisation overhead.
130     *
131     * @param shape the shape parameter
132     * @param scale the scale parameter
133     * @param inverseCumAccuracy the maximum absolute error in inverse
134     * cumulative probability estimates (defaults to
135     * {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}).
136     * @throws NotStrictlyPositiveException if {@code shape <= 0} or
137     * {@code scale <= 0}.
138     * @since 2.1
139     */
140    public GammaDistribution(double shape, double scale, double inverseCumAccuracy)
141        throws NotStrictlyPositiveException {
142        this(new Well19937c(), shape, scale, inverseCumAccuracy);
143    }
144
145    /**
146     * Creates a Gamma distribution.
147     *
148     * @param rng Random number generator.
149     * @param shape the shape parameter
150     * @param scale the scale parameter
151     * @throws NotStrictlyPositiveException if {@code shape <= 0} or
152     * {@code scale <= 0}.
153     * @since 3.3
154     */
155    public GammaDistribution(RandomGenerator rng, double shape, double scale)
156        throws NotStrictlyPositiveException {
157        this(rng, shape, scale, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
158    }
159
160    /**
161     * Creates a Gamma distribution.
162     *
163     * @param rng Random number generator.
164     * @param shape the shape parameter
165     * @param scale the scale parameter
166     * @param inverseCumAccuracy the maximum absolute error in inverse
167     * cumulative probability estimates (defaults to
168     * {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}).
169     * @throws NotStrictlyPositiveException if {@code shape <= 0} or
170     * {@code scale <= 0}.
171     * @since 3.1
172     */
173    public GammaDistribution(RandomGenerator rng,
174                             double shape,
175                             double scale,
176                             double inverseCumAccuracy)
177        throws NotStrictlyPositiveException {
178        super(rng);
179
180        if (shape <= 0) {
181            throw new NotStrictlyPositiveException(LocalizedFormats.SHAPE, shape);
182        }
183        if (scale <= 0) {
184            throw new NotStrictlyPositiveException(LocalizedFormats.SCALE, scale);
185        }
186
187        this.shape = shape;
188        this.scale = scale;
189        this.solverAbsoluteAccuracy = inverseCumAccuracy;
190        this.shiftedShape = shape + Gamma.LANCZOS_G + 0.5;
191        final double aux = FastMath.E / (2.0 * FastMath.PI * shiftedShape);
192        this.densityPrefactor2 = shape * FastMath.sqrt(aux) / Gamma.lanczos(shape);
193        this.logDensityPrefactor2 = FastMath.log(shape) + 0.5 * FastMath.log(aux) -
194                                    FastMath.log(Gamma.lanczos(shape));
195        this.densityPrefactor1 = this.densityPrefactor2 / scale *
196                FastMath.pow(shiftedShape, -shape) *
197                FastMath.exp(shape + Gamma.LANCZOS_G);
198        this.logDensityPrefactor1 = this.logDensityPrefactor2 - FastMath.log(scale) -
199                FastMath.log(shiftedShape) * shape +
200                shape + Gamma.LANCZOS_G;
201        this.minY = shape + Gamma.LANCZOS_G - FastMath.log(Double.MAX_VALUE);
202        this.maxLogY = FastMath.log(Double.MAX_VALUE) / (shape - 1.0);
203    }
204
205    /**
206     * Returns the shape parameter of {@code this} distribution.
207     *
208     * @return the shape parameter
209     * @deprecated as of version 3.1, {@link #getShape()} should be preferred.
210     * This method will be removed in version 4.0.
211     */
212    @Deprecated
213    public double getAlpha() {
214        return shape;
215    }
216
217    /**
218     * Returns the shape parameter of {@code this} distribution.
219     *
220     * @return the shape parameter
221     * @since 3.1
222     */
223    public double getShape() {
224        return shape;
225    }
226
227    /**
228     * Returns the scale parameter of {@code this} distribution.
229     *
230     * @return the scale parameter
231     * @deprecated as of version 3.1, {@link #getScale()} should be preferred.
232     * This method will be removed in version 4.0.
233     */
234    @Deprecated
235    public double getBeta() {
236        return scale;
237    }
238
239    /**
240     * Returns the scale parameter of {@code this} distribution.
241     *
242     * @return the scale parameter
243     * @since 3.1
244     */
245    public double getScale() {
246        return scale;
247    }
248
249    /** {@inheritDoc} */
250    public double density(double x) {
251       /* The present method must return the value of
252        *
253        *     1       x a     - x
254        * ---------- (-)  exp(---)
255        * x Gamma(a)  b        b
256        *
257        * where a is the shape parameter, and b the scale parameter.
258        * Substituting the Lanczos approximation of Gamma(a) leads to the
259        * following expression of the density
260        *
261        * a              e            1         y      a
262        * - sqrt(------------------) ---- (-----------)  exp(a - y + g),
263        * x      2 pi (a + g + 0.5)  L(a)  a + g + 0.5
264        *
265        * where y = x / b. The above formula is the "natural" computation, which
266        * is implemented when no overflow is likely to occur. If overflow occurs
267        * with the natural computation, the following identity is used. It is
268        * based on the BOOST library
269        * http://www.boost.org/doc/libs/1_35_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/sf_gamma/igamma.html
270        * Formula (15) needs adaptations, which are detailed below.
271        *
272        *       y      a
273        * (-----------)  exp(a - y + g)
274        *  a + g + 0.5
275        *                              y - a - g - 0.5    y (g + 0.5)
276        *               = exp(a log1pm(---------------) - ----------- + g),
277        *                                a + g + 0.5      a + g + 0.5
278        *
279        *  where log1pm(z) = log(1 + z) - z. Therefore, the value to be
280        *  returned is
281        *
282        * a              e            1
283        * - sqrt(------------------) ----
284        * x      2 pi (a + g + 0.5)  L(a)
285        *                              y - a - g - 0.5    y (g + 0.5)
286        *               * exp(a log1pm(---------------) - ----------- + g).
287        *                                a + g + 0.5      a + g + 0.5
288        */
289        if (x < 0) {
290            return 0;
291        }
292        final double y = x / scale;
293        if ((y <= minY) || (FastMath.log(y) >= maxLogY)) {
294            /*
295             * Overflow.
296             */
297            final double aux1 = (y - shiftedShape) / shiftedShape;
298            final double aux2 = shape * (FastMath.log1p(aux1) - aux1);
299            final double aux3 = -y * (Gamma.LANCZOS_G + 0.5) / shiftedShape +
300                    Gamma.LANCZOS_G + aux2;
301            return densityPrefactor2 / x * FastMath.exp(aux3);
302        }
303        /*
304         * Natural calculation.
305         */
306        return densityPrefactor1 * FastMath.exp(-y) * FastMath.pow(y, shape - 1);
307    }
308
309    /** {@inheritDoc} **/
310    @Override
311    public double logDensity(double x) {
312        /*
313         * see the comment in {@link #density(double)} for computation details
314         */
315        if (x < 0) {
316            return Double.NEGATIVE_INFINITY;
317        }
318        final double y = x / scale;
319        if ((y <= minY) || (FastMath.log(y) >= maxLogY)) {
320            /*
321             * Overflow.
322             */
323            final double aux1 = (y - shiftedShape) / shiftedShape;
324            final double aux2 = shape * (FastMath.log1p(aux1) - aux1);
325            final double aux3 = -y * (Gamma.LANCZOS_G + 0.5) / shiftedShape +
326                    Gamma.LANCZOS_G + aux2;
327            return logDensityPrefactor2 - FastMath.log(x) + aux3;
328        }
329        /*
330         * Natural calculation.
331         */
332        return logDensityPrefactor1 - y + FastMath.log(y) * (shape - 1);
333    }
334
335    /**
336     * {@inheritDoc}
337     *
338     * The implementation of this method is based on:
339     * <ul>
340     *  <li>
341     *   <a href="http://mathworld.wolfram.com/Chi-SquaredDistribution.html">
342     *    Chi-Squared Distribution</a>, equation (9).
343     *  </li>
344     *  <li>Casella, G., & Berger, R. (1990). <i>Statistical Inference</i>.
345     *    Belmont, CA: Duxbury Press.
346     *  </li>
347     * </ul>
348     */
349    public double cumulativeProbability(double x) {
350        double ret;
351
352        if (x <= 0) {
353            ret = 0;
354        } else {
355            ret = Gamma.regularizedGammaP(shape, x / scale);
356        }
357
358        return ret;
359    }
360
361    /** {@inheritDoc} */
362    @Override
363    protected double getSolverAbsoluteAccuracy() {
364        return solverAbsoluteAccuracy;
365    }
366
367    /**
368     * {@inheritDoc}
369     *
370     * For shape parameter {@code alpha} and scale parameter {@code beta}, the
371     * mean is {@code alpha * beta}.
372     */
373    public double getNumericalMean() {
374        return shape * scale;
375    }
376
377    /**
378     * {@inheritDoc}
379     *
380     * For shape parameter {@code alpha} and scale parameter {@code beta}, the
381     * variance is {@code alpha * beta^2}.
382     *
383     * @return {@inheritDoc}
384     */
385    public double getNumericalVariance() {
386        return shape * scale * scale;
387    }
388
389    /**
390     * {@inheritDoc}
391     *
392     * The lower bound of the support is always 0 no matter the parameters.
393     *
394     * @return lower bound of the support (always 0)
395     */
396    public double getSupportLowerBound() {
397        return 0;
398    }
399
400    /**
401     * {@inheritDoc}
402     *
403     * The upper bound of the support is always positive infinity
404     * no matter the parameters.
405     *
406     * @return upper bound of the support (always Double.POSITIVE_INFINITY)
407     */
408    public double getSupportUpperBound() {
409        return Double.POSITIVE_INFINITY;
410    }
411
412    /** {@inheritDoc} */
413    public boolean isSupportLowerBoundInclusive() {
414        return true;
415    }
416
417    /** {@inheritDoc} */
418    public boolean isSupportUpperBoundInclusive() {
419        return false;
420    }
421
422    /**
423     * {@inheritDoc}
424     *
425     * The support of this distribution is connected.
426     *
427     * @return {@code true}
428     */
429    public boolean isSupportConnected() {
430        return true;
431    }
432
433    /**
434     * <p>This implementation uses the following algorithms: </p>
435     *
436     * <p>For 0 < shape < 1: <br/>
437     * Ahrens, J. H. and Dieter, U., <i>Computer methods for
438     * sampling from gamma, beta, Poisson and binomial distributions.</i>
439     * Computing, 12, 223-246, 1974.</p>
440     *
441     * <p>For shape >= 1: <br/>
442     * Marsaglia and Tsang, <i>A Simple Method for Generating
443     * Gamma Variables.</i> ACM Transactions on Mathematical Software,
444     * Volume 26 Issue 3, September, 2000.</p>
445     *
446     * @return random value sampled from the Gamma(shape, scale) distribution
447     */
448    @Override
449    public double sample()  {
450        if (shape < 1) {
451            // [1]: p. 228, Algorithm GS
452
453            while (true) {
454                // Step 1:
455                final double u = random.nextDouble();
456                final double bGS = 1 + shape / FastMath.E;
457                final double p = bGS * u;
458
459                if (p <= 1) {
460                    // Step 2:
461
462                    final double x = FastMath.pow(p, 1 / shape);
463                    final double u2 = random.nextDouble();
464
465                    if (u2 > FastMath.exp(-x)) {
466                        // Reject
467                        continue;
468                    } else {
469                        return scale * x;
470                    }
471                } else {
472                    // Step 3:
473
474                    final double x = -1 * FastMath.log((bGS - p) / shape);
475                    final double u2 = random.nextDouble();
476
477                    if (u2 > FastMath.pow(x, shape - 1)) {
478                        // Reject
479                        continue;
480                    } else {
481                        return scale * x;
482                    }
483                }
484            }
485        }
486
487        // Now shape >= 1
488
489        final double d = shape - 0.333333333333333333;
490        final double c = 1 / (3 * FastMath.sqrt(d));
491
492        while (true) {
493            final double x = random.nextGaussian();
494            final double v = (1 + c * x) * (1 + c * x) * (1 + c * x);
495
496            if (v <= 0) {
497                continue;
498            }
499
500            final double x2 = x * x;
501            final double u = random.nextDouble();
502
503            // Squeeze
504            if (u < 1 - 0.0331 * x2 * x2) {
505                return scale * d * v;
506            }
507
508            if (FastMath.log(u) < 0.5 * x2 + d * (1 - v + FastMath.log(v))) {
509                return scale * d * v;
510            }
511        }
512    }
513}