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 }