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 * Implementation of the <a href="http://en.wikipedia.org/wiki/Logistic_distribution">Logistic distribution</a>.
021 */
022public class LogisticDistribution 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>/3. */
028    private static final double PI_SQUARED_OVER_THREE = Math.PI * Math.PI / 3;
029    /** Location parameter. */
030    private final double mu;
031    /** Scale parameter. */
032    private final double scale;
033    /** Inverse of "scale". */
034    private final double oneOverScale;
035
036    /**
037     * Creates a distribution.
038     *
039     * @param mu Location parameter.
040     * @param scale Scale parameter (must be positive).
041     * @throws IllegalArgumentException if {@code scale <= 0}.
042     */
043    public LogisticDistribution(double mu,
044                                double scale) {
045        if (scale <= 0) {
046            throw new DistributionException(DistributionException.NEGATIVE,
047                                            scale);
048        }
049
050        this.mu = mu;
051        this.scale = scale;
052        this.oneOverScale = 1 / scale;
053    }
054
055    /**
056     * Gets the location parameter.
057     *
058     * @return the location parameter.
059     */
060    public double getLocation() {
061        return mu;
062    }
063
064    /**
065     * Gets the scale parameter.
066     *
067     * @return the scale parameter.
068     */
069    public double getScale() {
070        return scale;
071    }
072
073    /** {@inheritDoc} */
074    @Override
075    public double density(double x) {
076        if (x <= SUPPORT_LO ||
077            x >= SUPPORT_HI) {
078            return 0;
079        }
080
081        final double z = oneOverScale * (x - mu);
082        final double v = Math.exp(-z);
083        return oneOverScale * v / ((1 + v) * (1 + v));
084    }
085
086    /** {@inheritDoc} */
087    @Override
088    public double cumulativeProbability(double x) {
089        final double z = oneOverScale * (x - mu);
090        return 1 / (1 + Math.exp(-z));
091    }
092
093    /** {@inheritDoc} */
094    @Override
095    public double inverseCumulativeProbability(double p) {
096        if (p < 0 ||
097            p > 1) {
098            throw new DistributionException(DistributionException.INVALID_PROBABILITY, p);
099        } else if (p == 0) {
100            return 0;
101        } else if (p == 1) {
102            return Double.POSITIVE_INFINITY;
103        } else {
104            return scale * Math.log(p / (1 - p)) + mu;
105        }
106    }
107
108    /** {@inheritDoc} */
109    @Override
110    public double getMean() {
111        return getLocation();
112    }
113
114    /** {@inheritDoc} */
115    @Override
116    public double getVariance() {
117        return scale * scale * PI_SQUARED_OVER_THREE;
118    }
119
120    /** {@inheritDoc} */
121    @Override
122    public double getSupportLowerBound() {
123        return SUPPORT_LO;
124    }
125
126    /** {@inheritDoc} */
127    @Override
128    public double getSupportUpperBound() {
129        return SUPPORT_HI;
130    }
131
132    /** {@inheritDoc} */
133    @Override
134    public boolean isSupportConnected() {
135        return true;
136    }
137}