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/Cauchy_distribution">Cauchy distribution</a>.
021 */
022public class CauchyDistribution extends AbstractContinuousDistribution {
023    /** The median of this distribution. */
024    private final double median;
025    /** The scale of this distribution. */
026    private final double scale;
027
028    /**
029     * Creates a distribution.
030     *
031     * @param median Median for this distribution.
032     * @param scale Scale parameter for this distribution.
033     * @throws IllegalArgumentException if {@code scale <= 0}.
034     */
035    public CauchyDistribution(double median,
036                              double scale) {
037        if (scale <= 0) {
038            throw new DistributionException(DistributionException.NEGATIVE, scale);
039        }
040        this.scale = scale;
041        this.median = median;
042    }
043
044    /** {@inheritDoc} */
045    @Override
046    public double cumulativeProbability(double x) {
047        return 0.5 + (Math.atan((x - median) / scale) / Math.PI);
048    }
049
050    /**
051     * Access the median.
052     *
053     * @return the median for this distribution.
054     */
055    public double getMedian() {
056        return median;
057    }
058
059    /**
060     * Access the scale parameter.
061     *
062     * @return the scale parameter for this distribution.
063     */
064    public double getScale() {
065        return scale;
066    }
067
068    /** {@inheritDoc} */
069    @Override
070    public double density(double x) {
071        final double dev = x - median;
072        return (1 / Math.PI) * (scale / (dev * dev + scale * scale));
073    }
074
075    /**
076     * {@inheritDoc}
077     *
078     * Returns {@code Double.NEGATIVE_INFINITY} when {@code p == 0}
079     * and {@code Double.POSITIVE_INFINITY} when {@code p == 1}.
080     */
081    @Override
082    public double inverseCumulativeProbability(double p) {
083        double ret;
084        if (p < 0 ||
085            p > 1) {
086            throw new DistributionException(DistributionException.INVALID_PROBABILITY, p);
087        } else if (p == 0) {
088            ret = Double.NEGATIVE_INFINITY;
089        } else  if (p == 1) {
090            ret = Double.POSITIVE_INFINITY;
091        } else {
092            ret = median + scale * Math.tan(Math.PI * (p - .5));
093        }
094        return ret;
095    }
096
097    /**
098     * {@inheritDoc}
099     *
100     * The mean is always undefined no matter the parameters.
101     *
102     * @return mean (always Double.NaN)
103     */
104    @Override
105    public double getMean() {
106        return Double.NaN;
107    }
108
109    /**
110     * {@inheritDoc}
111     *
112     * The variance is always undefined no matter the parameters.
113     *
114     * @return variance (always Double.NaN)
115     */
116    @Override
117    public double getVariance() {
118        return Double.NaN;
119    }
120
121    /**
122     * {@inheritDoc}
123     *
124     * The lower bound of the support is always negative infinity no matter
125     * the parameters.
126     *
127     * @return lower bound of the support (always Double.NEGATIVE_INFINITY)
128     */
129    @Override
130    public double getSupportLowerBound() {
131        return Double.NEGATIVE_INFINITY;
132    }
133
134    /**
135     * {@inheritDoc}
136     *
137     * The upper bound of the support is always positive infinity no matter
138     * the parameters.
139     *
140     * @return upper bound of the support (always Double.POSITIVE_INFINITY)
141     */
142    @Override
143    public double getSupportUpperBound() {
144        return Double.POSITIVE_INFINITY;
145    }
146
147    /**
148     * {@inheritDoc}
149     *
150     * The support of this distribution is connected.
151     *
152     * @return {@code true}
153     */
154    @Override
155    public boolean isSupportConnected() {
156        return true;
157    }
158}