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 Laplace distribution.
021 *
022 * @see <a href="http://en.wikipedia.org/wiki/Laplace_distribution">Laplace distribution (Wikipedia)</a>
023 */
024public class LaplaceDistribution extends AbstractContinuousDistribution {
025    /** The location parameter. */
026    private final double mu;
027    /** The scale parameter. */
028    private final double beta;
029
030    /**
031     * Creates a distribution.
032     *
033     * @param mu location parameter
034     * @param beta scale parameter (must be positive)
035     * @throws IllegalArgumentException if {@code beta <= 0}
036     */
037    public LaplaceDistribution(double mu,
038                               double beta) {
039        if (beta <= 0) {
040            throw new DistributionException(DistributionException.NEGATIVE, beta);
041        }
042
043        this.mu = mu;
044        this.beta = beta;
045    }
046
047    /**
048     * Access the location parameter, {@code mu}.
049     *
050     * @return the location parameter.
051     */
052    public double getLocation() {
053        return mu;
054    }
055
056    /**
057     * Access the scale parameter, {@code beta}.
058     *
059     * @return the scale parameter.
060     */
061    public double getScale() {
062        return beta;
063    }
064
065    /** {@inheritDoc} */
066    @Override
067    public double density(double x) {
068        return Math.exp(-Math.abs(x - mu) / beta) / (2.0 * beta);
069    }
070
071    /** {@inheritDoc} */
072    @Override
073    public double cumulativeProbability(double x) {
074        if (x <= mu) {
075            return Math.exp((x - mu) / beta) / 2.0;
076        } else {
077            return 1.0 - Math.exp((mu - x) / beta) / 2.0;
078        }
079    }
080
081    /** {@inheritDoc} */
082    @Override
083    public double inverseCumulativeProbability(double p) {
084        if (p < 0 ||
085            p > 1) {
086            throw new DistributionException(DistributionException.INVALID_PROBABILITY, p);
087        } else if (p == 0) {
088            return Double.NEGATIVE_INFINITY;
089        } else if (p == 1) {
090            return Double.POSITIVE_INFINITY;
091        }
092        final double x = (p > 0.5) ? -Math.log(2.0 - 2.0 * p) : Math.log(2.0 * p);
093        return mu + beta * x;
094    }
095
096    /** {@inheritDoc} */
097    @Override
098    public double getMean() {
099        return getLocation();
100    }
101
102    /** {@inheritDoc} */
103    @Override
104    public double getVariance() {
105        return 2.0 * beta * beta;
106    }
107
108    /** {@inheritDoc} */
109    @Override
110    public double getSupportLowerBound() {
111        return Double.NEGATIVE_INFINITY;
112    }
113
114    /** {@inheritDoc} */
115    @Override
116    public double getSupportUpperBound() {
117        return Double.POSITIVE_INFINITY;
118    }
119
120    /** {@inheritDoc} */
121    @Override
122    public boolean isSupportConnected() {
123        return true;
124    }
125}