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.statistics.distribution;
018
019/**
020 * This class implements the <a href="http://en.wikipedia.org/wiki/Gumbel_distribution">Gumbel distribution</a>.
021 */
022public class GumbelDistribution extends AbstractContinuousDistribution {
023    /** Support lower bound. */
024    private static final double SUPPORT_LO = Double.NEGATIVE_INFINITY;
025    /** Support upper bound. */
026    private static final double SUPPORT_HI = Double.POSITIVE_INFINITY;
027    /** &pi;<sup>2</sup>/6. */
028    private static final double PI_SQUARED_OVER_SIX = Math.PI * Math.PI / 6;
029    /**
030     * <a href="http://mathworld.wolfram.com/Euler-MascheroniConstantApproximations.html">
031     * Approximation of Euler's constant</a>.
032     */
033    private static final double EULER = Math.PI / (2 * Math.E);
034    /** Location parameter. */
035    private final double mu;
036    /** Scale parameter. */
037    private final double beta;
038
039    /**
040     * Creates a distribution.
041     *
042     * @param mu location parameter
043     * @param beta scale parameter (must be positive)
044     * @throws IllegalArgumentException if {@code beta <= 0}
045     */
046    public GumbelDistribution(double mu,
047                              double beta) {
048        if (beta <= 0) {
049            throw new DistributionException(DistributionException.NEGATIVE, beta);
050        }
051
052        this.beta = beta;
053        this.mu = mu;
054    }
055
056    /**
057     * Gets the location parameter.
058     *
059     * @return the location parameter.
060     */
061    public double getLocation() {
062        return mu;
063    }
064
065    /**
066     * Gets the scale parameter.
067     *
068     * @return the scale parameter.
069     */
070    public double getScale() {
071        return beta;
072    }
073
074    /** {@inheritDoc} */
075    @Override
076    public double density(double x) {
077        if (x <= SUPPORT_LO) {
078            return 0;
079        }
080
081        final double z = (x - mu) / beta;
082        final double t = Math.exp(-z);
083        return Math.exp(-z - t) / beta;
084    }
085
086    /** {@inheritDoc} */
087    @Override
088    public double cumulativeProbability(double x) {
089        final double z = (x - mu) / beta;
090        return Math.exp(-Math.exp(-z));
091    }
092
093    /** {@inheritDoc} */
094    @Override
095    public double inverseCumulativeProbability(double p) {
096        if (p < 0 || p > 1) {
097            throw new DistributionException(DistributionException.INVALID_PROBABILITY, p);
098        } else if (p == 0) {
099            return Double.NEGATIVE_INFINITY;
100        } else if (p == 1) {
101            return Double.POSITIVE_INFINITY;
102        }
103        return mu - Math.log(-Math.log(p)) * beta;
104    }
105
106    /** {@inheritDoc} */
107    @Override
108    public double getMean() {
109        return mu + EULER * beta;
110    }
111
112    /** {@inheritDoc} */
113    @Override
114    public double getVariance() {
115        return PI_SQUARED_OVER_SIX * beta * beta;
116    }
117
118    /** {@inheritDoc} */
119    @Override
120    public double getSupportLowerBound() {
121        return SUPPORT_LO;
122    }
123
124    /** {@inheritDoc} */
125    @Override
126    public double getSupportUpperBound() {
127        return SUPPORT_HI;
128    }
129
130    /** {@inheritDoc} */
131    @Override
132    public boolean isSupportConnected() {
133        return true;
134    }
135
136}