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 }