View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.math.distribution;
19  
20  import java.io.Serializable;
21  
22  import org.apache.commons.math.MathRuntimeException;
23  
24  /**
25   * Default implementation of
26   * {@link org.apache.commons.math.distribution.CauchyDistribution}.
27   *
28   * @since 1.1
29   * @version $Revision: 772119 $ $Date: 2009-05-06 05:43:28 -0400 (Wed, 06 May 2009) $
30   */
31  public class CauchyDistributionImpl extends AbstractContinuousDistribution 
32          implements CauchyDistribution, Serializable {
33      
34      /** Serializable version identifier */
35      private static final long serialVersionUID = 8589540077390120676L;
36  
37      /** The median of this distribution. */
38      private double median = 0;
39      
40      /** The scale of this distribution. */
41      private double scale = 1;
42      
43      /**
44       * Creates cauchy distribution with the medain equal to zero and scale
45       * equal to one. 
46       */
47      public CauchyDistributionImpl(){
48          this(0.0, 1.0);
49      }
50      
51      /**
52       * Create a cauchy distribution using the given median and scale.
53       * @param median median for this distribution
54       * @param s scale parameter for this distribution
55       */
56      public CauchyDistributionImpl(double median, double s){
57          super();
58          setMedian(median);
59          setScale(s);
60      }
61  
62      /**
63       * For this distribution, X, this method returns P(X &lt; <code>x</code>).
64       * @param x the value at which the CDF is evaluated.
65       * @return CDF evaluted at <code>x</code>. 
66       */
67      public double cumulativeProbability(double x) {
68          return 0.5 + (Math.atan((x - median) / scale) / Math.PI);
69      }
70      
71      /**
72       * Access the median.
73       * @return median for this distribution
74       */ 
75      public double getMedian() {
76          return median;
77      }
78  
79      /**
80       * Access the scale parameter.
81       * @return scale parameter for this distribution
82       */
83      public double getScale() {
84          return scale;
85      }
86      
87      /**
88       * For this distribution, X, this method returns the critical point x, such
89       * that P(X &lt; x) = <code>p</code>.
90       * <p>
91       * Returns <code>Double.NEGATIVE_INFINITY</code> for p=0 and 
92       * <code>Double.POSITIVE_INFINITY</code> for p=1.</p>
93       *
94       * @param p the desired probability
95       * @return x, such that P(X &lt; x) = <code>p</code>
96       * @throws IllegalArgumentException if <code>p</code> is not a valid
97       *         probability.
98       */
99      @Override
100     public double inverseCumulativeProbability(double p) {
101         double ret;
102         if (p < 0.0 || p > 1.0) {
103             throw MathRuntimeException.createIllegalArgumentException(
104                   "{0} out of [{1}, {2}] range", p, 0.0, 1.0);
105         } else if (p == 0) {
106             ret = Double.NEGATIVE_INFINITY;
107         } else  if (p == 1) {
108             ret = Double.POSITIVE_INFINITY;
109         } else {
110             ret = median + scale * Math.tan(Math.PI * (p - .5));
111         }
112         return ret;
113     }
114     
115     /**
116      * Modify the median.
117      * @param median for this distribution
118      */
119     public void setMedian(double median) {
120         this.median = median;
121     }
122 
123     /**
124      * Modify the scale parameter.
125      * @param s scale parameter for this distribution
126      * @throws IllegalArgumentException if <code>sd</code> is not positive.
127      */
128     public void setScale(double s) {
129         if (s <= 0.0) {
130             throw MathRuntimeException.createIllegalArgumentException(
131                   "scale must be positive ({0})", s);
132         }       
133         scale = s;
134     }
135     
136     /**
137      * Access the domain value lower bound, based on <code>p</code>, used to
138      * bracket a CDF root.  This method is used by
139      * {@link #inverseCumulativeProbability(double)} to find critical values.
140      * 
141      * @param p the desired probability for the critical value
142      * @return domain value lower bound, i.e.
143      *         P(X &lt; <i>lower bound</i>) &lt; <code>p</code> 
144      */
145     @Override
146     protected double getDomainLowerBound(double p) {
147         double ret;
148 
149         if (p < .5) {
150             ret = -Double.MAX_VALUE;
151         } else {
152             ret = getMedian();
153         }
154         
155         return ret;
156     }
157 
158     /**
159      * Access the domain value upper bound, based on <code>p</code>, used to
160      * bracket a CDF root.  This method is used by
161      * {@link #inverseCumulativeProbability(double)} to find critical values.
162      * 
163      * @param p the desired probability for the critical value
164      * @return domain value upper bound, i.e.
165      *         P(X &lt; <i>upper bound</i>) &gt; <code>p</code> 
166      */
167     @Override
168     protected double getDomainUpperBound(double p) {
169         double ret;
170 
171         if (p < .5) {
172             ret = getMedian();
173         } else {
174             ret = Double.MAX_VALUE;
175         }
176         
177         return ret;
178     }
179 
180     /**
181      * Access the initial domain value, based on <code>p</code>, used to
182      * bracket a CDF root.  This method is used by
183      * {@link #inverseCumulativeProbability(double)} to find critical values.
184      * 
185      * @param p the desired probability for the critical value
186      * @return initial domain value
187      */
188     @Override
189     protected double getInitialDomain(double p) {
190         double ret;
191 
192         if (p < .5) {
193             ret = getMedian() - getScale();
194         } else if (p > .5) {
195             ret = getMedian() + getScale();
196         } else {
197             ret = getMedian();
198         }
199         
200         return ret;
201     }
202 }