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     */
017    package org.apache.commons.math3.distribution;
018    
019    import org.apache.commons.math3.exception.NotStrictlyPositiveException;
020    import org.apache.commons.math3.exception.OutOfRangeException;
021    import org.apache.commons.math3.exception.util.LocalizedFormats;
022    import org.apache.commons.math3.util.FastMath;
023    import org.apache.commons.math3.random.RandomGenerator;
024    import org.apache.commons.math3.random.Well19937c;
025    
026    /**
027     * Implementation of the Cauchy distribution.
028     *
029     * @see <a href="http://en.wikipedia.org/wiki/Cauchy_distribution">Cauchy distribution (Wikipedia)</a>
030     * @see <a href="http://mathworld.wolfram.com/CauchyDistribution.html">Cauchy Distribution (MathWorld)</a>
031     * @since 1.1 (changed to concrete class in 3.0)
032     * @version $Id: CauchyDistribution.java 1416643 2012-12-03 19:37:14Z tn $
033     */
034    public class CauchyDistribution extends AbstractRealDistribution {
035        /**
036         * Default inverse cumulative probability accuracy.
037         * @since 2.1
038         */
039        public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
040        /** Serializable version identifier */
041        private static final long serialVersionUID = 8589540077390120676L;
042        /** The median of this distribution. */
043        private final double median;
044        /** The scale of this distribution. */
045        private final double scale;
046        /** Inverse cumulative probability accuracy */
047        private final double solverAbsoluteAccuracy;
048    
049        /**
050         * Creates a Cauchy distribution with the median equal to zero and scale
051         * equal to one.
052         */
053        public CauchyDistribution() {
054            this(0, 1);
055        }
056    
057        /**
058         * Creates a Cauchy distribution using the given median and scale.
059         *
060         * @param median Median for this distribution.
061         * @param scale Scale parameter for this distribution.
062         */
063        public CauchyDistribution(double median, double scale) {
064            this(median, scale, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
065        }
066    
067        /**
068         * Creates a Cauchy distribution using the given median and scale.
069         *
070         * @param median Median for this distribution.
071         * @param scale Scale parameter for this distribution.
072         * @param inverseCumAccuracy Maximum absolute error in inverse
073         * cumulative probability estimates
074         * (defaults to {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}).
075         * @throws NotStrictlyPositiveException if {@code scale <= 0}.
076         * @since 2.1
077         */
078        public CauchyDistribution(double median, double scale,
079                                  double inverseCumAccuracy) {
080            this(new Well19937c(), median, scale, inverseCumAccuracy);
081        }
082    
083        /**
084         * Creates a Cauchy distribution.
085         *
086         * @param rng Random number generator.
087         * @param median Median for this distribution.
088         * @param scale Scale parameter for this distribution.
089         * @param inverseCumAccuracy Maximum absolute error in inverse
090         * cumulative probability estimates
091         * (defaults to {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}).
092         * @throws NotStrictlyPositiveException if {@code scale <= 0}.
093         * @since 3.1
094         */
095        public CauchyDistribution(RandomGenerator rng,
096                                  double median,
097                                  double scale,
098                                  double inverseCumAccuracy) {
099            super(rng);
100            if (scale <= 0) {
101                throw new NotStrictlyPositiveException(LocalizedFormats.SCALE, scale);
102            }
103            this.scale = scale;
104            this.median = median;
105            solverAbsoluteAccuracy = inverseCumAccuracy;
106        }
107    
108        /** {@inheritDoc} */
109        public double cumulativeProbability(double x) {
110            return 0.5 + (FastMath.atan((x - median) / scale) / FastMath.PI);
111        }
112    
113        /**
114         * Access the median.
115         *
116         * @return the median for this distribution.
117         */
118        public double getMedian() {
119            return median;
120        }
121    
122        /**
123         * Access the scale parameter.
124         *
125         * @return the scale parameter for this distribution.
126         */
127        public double getScale() {
128            return scale;
129        }
130    
131        /** {@inheritDoc} */
132        public double density(double x) {
133            final double dev = x - median;
134            return (1 / FastMath.PI) * (scale / (dev * dev + scale * scale));
135        }
136    
137        /**
138         * {@inheritDoc}
139         *
140         * Returns {@code Double.NEGATIVE_INFINITY} when {@code p == 0}
141         * and {@code Double.POSITIVE_INFINITY} when {@code p == 1}.
142         */
143        @Override
144        public double inverseCumulativeProbability(double p) throws OutOfRangeException {
145            double ret;
146            if (p < 0 || p > 1) {
147                throw new OutOfRangeException(p, 0, 1);
148            } else if (p == 0) {
149                ret = Double.NEGATIVE_INFINITY;
150            } else  if (p == 1) {
151                ret = Double.POSITIVE_INFINITY;
152            } else {
153                ret = median + scale * FastMath.tan(FastMath.PI * (p - .5));
154            }
155            return ret;
156        }
157    
158        /** {@inheritDoc} */
159        @Override
160        protected double getSolverAbsoluteAccuracy() {
161            return solverAbsoluteAccuracy;
162        }
163    
164        /**
165         * {@inheritDoc}
166         *
167         * The mean is always undefined no matter the parameters.
168         *
169         * @return mean (always Double.NaN)
170         */
171        public double getNumericalMean() {
172            return Double.NaN;
173        }
174    
175        /**
176         * {@inheritDoc}
177         *
178         * The variance is always undefined no matter the parameters.
179         *
180         * @return variance (always Double.NaN)
181         */
182        public double getNumericalVariance() {
183            return Double.NaN;
184        }
185    
186        /**
187         * {@inheritDoc}
188         *
189         * The lower bound of the support is always negative infinity no matter
190         * the parameters.
191         *
192         * @return lower bound of the support (always Double.NEGATIVE_INFINITY)
193         */
194        public double getSupportLowerBound() {
195            return Double.NEGATIVE_INFINITY;
196        }
197    
198        /**
199         * {@inheritDoc}
200         *
201         * The upper bound of the support is always positive infinity no matter
202         * the parameters.
203         *
204         * @return upper bound of the support (always Double.POSITIVE_INFINITY)
205         */
206        public double getSupportUpperBound() {
207            return Double.POSITIVE_INFINITY;
208        }
209    
210        /** {@inheritDoc} */
211        public boolean isSupportLowerBoundInclusive() {
212            return false;
213        }
214    
215        /** {@inheritDoc} */
216        public boolean isSupportUpperBoundInclusive() {
217            return false;
218        }
219    
220        /**
221         * {@inheritDoc}
222         *
223         * The support of this distribution is connected.
224         *
225         * @return {@code true}
226         */
227        public boolean isSupportConnected() {
228            return true;
229        }
230    }