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 018 package org.apache.commons.math.distribution; 019 020 import java.io.Serializable; 021 022 import org.apache.commons.math.MathRuntimeException; 023 024 /** 025 * Default implementation of 026 * {@link org.apache.commons.math.distribution.CauchyDistribution}. 027 * 028 * @since 1.1 029 * @version $Revision: 925900 $ $Date: 2010-03-21 17:10:07 -0400 (Sun, 21 Mar 2010) $ 030 */ 031 public class CauchyDistributionImpl extends AbstractContinuousDistribution 032 implements CauchyDistribution, Serializable { 033 034 /** 035 * Default inverse cumulative probability accuracy 036 * @since 2.1 037 */ 038 public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9; 039 040 /** Serializable version identifier */ 041 private static final long serialVersionUID = 8589540077390120676L; 042 043 /** The median of this distribution. */ 044 private double median = 0; 045 046 /** The scale of this distribution. */ 047 private double scale = 1; 048 049 /** Inverse cumulative probability accuracy */ 050 private final double solverAbsoluteAccuracy; 051 052 /** 053 * Creates cauchy distribution with the medain equal to zero and scale 054 * equal to one. 055 */ 056 public CauchyDistributionImpl(){ 057 this(0.0, 1.0); 058 } 059 060 /** 061 * Create a cauchy distribution using the given median and scale. 062 * @param median median for this distribution 063 * @param s scale parameter for this distribution 064 */ 065 public CauchyDistributionImpl(double median, double s){ 066 this(median, s, DEFAULT_INVERSE_ABSOLUTE_ACCURACY); 067 } 068 069 /** 070 * Create a cauchy distribution using the given median and scale. 071 * @param median median for this distribution 072 * @param s scale parameter for this distribution 073 * @param inverseCumAccuracy the maximum absolute error in inverse cumulative probability estimates 074 * (defaults to {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}) 075 * @since 2.1 076 */ 077 public CauchyDistributionImpl(double median, double s, double inverseCumAccuracy) { 078 super(); 079 setMedianInternal(median); 080 setScaleInternal(s); 081 solverAbsoluteAccuracy = inverseCumAccuracy; 082 } 083 084 /** 085 * For this distribution, X, this method returns P(X < <code>x</code>). 086 * @param x the value at which the CDF is evaluated. 087 * @return CDF evaluted at <code>x</code>. 088 */ 089 public double cumulativeProbability(double x) { 090 return 0.5 + (Math.atan((x - median) / scale) / Math.PI); 091 } 092 093 /** 094 * Access the median. 095 * @return median for this distribution 096 */ 097 public double getMedian() { 098 return median; 099 } 100 101 /** 102 * Access the scale parameter. 103 * @return scale parameter for this distribution 104 */ 105 public double getScale() { 106 return scale; 107 } 108 109 /** 110 * Returns the probability density for a particular point. 111 * 112 * @param x The point at which the density should be computed. 113 * @return The pdf at point x. 114 * @since 2.1 115 */ 116 @Override 117 public double density(double x) { 118 final double dev = x - median; 119 return (1 / Math.PI) * (scale / (dev * dev + scale * scale)); 120 } 121 122 /** 123 * For this distribution, X, this method returns the critical point x, such 124 * that P(X < x) = <code>p</code>. 125 * <p> 126 * Returns <code>Double.NEGATIVE_INFINITY</code> for p=0 and 127 * <code>Double.POSITIVE_INFINITY</code> for p=1.</p> 128 * 129 * @param p the desired probability 130 * @return x, such that P(X < x) = <code>p</code> 131 * @throws IllegalArgumentException if <code>p</code> is not a valid 132 * probability. 133 */ 134 @Override 135 public double inverseCumulativeProbability(double p) { 136 double ret; 137 if (p < 0.0 || p > 1.0) { 138 throw MathRuntimeException.createIllegalArgumentException( 139 "{0} out of [{1}, {2}] range", p, 0.0, 1.0); 140 } else if (p == 0) { 141 ret = Double.NEGATIVE_INFINITY; 142 } else if (p == 1) { 143 ret = Double.POSITIVE_INFINITY; 144 } else { 145 ret = median + scale * Math.tan(Math.PI * (p - .5)); 146 } 147 return ret; 148 } 149 150 /** 151 * Modify the median. 152 * @param median for this distribution 153 * @deprecated as of 2.1 (class will become immutable in 3.0) 154 */ 155 @Deprecated 156 public void setMedian(double median) { 157 setMedianInternal(median); 158 } 159 /** 160 * Modify the median. 161 * @param newMedian for this distribution 162 */ 163 private void setMedianInternal(double newMedian) { 164 this.median = newMedian; 165 } 166 167 /** 168 * Modify the scale parameter. 169 * @param s scale parameter for this distribution 170 * @throws IllegalArgumentException if <code>sd</code> is not positive. 171 * @deprecated as of 2.1 (class will become immutable in 3.0) 172 */ 173 @Deprecated 174 public void setScale(double s) { 175 setScaleInternal(s); 176 } 177 /** 178 * Modify the scale parameter. 179 * @param s scale parameter for this distribution 180 * @throws IllegalArgumentException if <code>sd</code> is not positive. 181 */ 182 private void setScaleInternal(double s) { 183 if (s <= 0.0) { 184 throw MathRuntimeException.createIllegalArgumentException( 185 "scale must be positive ({0})", s); 186 } 187 scale = s; 188 } 189 190 /** 191 * Access the domain value lower bound, based on <code>p</code>, used to 192 * bracket a CDF root. This method is used by 193 * {@link #inverseCumulativeProbability(double)} to find critical values. 194 * 195 * @param p the desired probability for the critical value 196 * @return domain value lower bound, i.e. 197 * P(X < <i>lower bound</i>) < <code>p</code> 198 */ 199 @Override 200 protected double getDomainLowerBound(double p) { 201 double ret; 202 203 if (p < .5) { 204 ret = -Double.MAX_VALUE; 205 } else { 206 ret = median; 207 } 208 209 return ret; 210 } 211 212 /** 213 * Access the domain value upper bound, based on <code>p</code>, used to 214 * bracket a CDF root. This method is used by 215 * {@link #inverseCumulativeProbability(double)} to find critical values. 216 * 217 * @param p the desired probability for the critical value 218 * @return domain value upper bound, i.e. 219 * P(X < <i>upper bound</i>) > <code>p</code> 220 */ 221 @Override 222 protected double getDomainUpperBound(double p) { 223 double ret; 224 225 if (p < .5) { 226 ret = median; 227 } else { 228 ret = Double.MAX_VALUE; 229 } 230 231 return ret; 232 } 233 234 /** 235 * Access the initial domain value, based on <code>p</code>, used to 236 * bracket a CDF root. This method is used by 237 * {@link #inverseCumulativeProbability(double)} to find critical values. 238 * 239 * @param p the desired probability for the critical value 240 * @return initial domain value 241 */ 242 @Override 243 protected double getInitialDomain(double p) { 244 double ret; 245 246 if (p < .5) { 247 ret = median - scale; 248 } else if (p > .5) { 249 ret = median + scale; 250 } else { 251 ret = median; 252 } 253 254 return ret; 255 } 256 257 /** 258 * Return the absolute accuracy setting of the solver used to estimate 259 * inverse cumulative probabilities. 260 * 261 * @return the solver absolute accuracy 262 * @since 2.1 263 */ 264 @Override 265 protected double getSolverAbsoluteAccuracy() { 266 return solverAbsoluteAccuracy; 267 } 268 }