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  package org.apache.commons.math.distribution;
18  
19  import java.io.Serializable;
20  
21  import org.apache.commons.math.MathException;
22  
23  /**
24   * The default implementation of {@link ChiSquaredDistribution}
25   *
26   * @version $Revision: 617953 $ $Date: 2008-02-02 22:54:00 -0700 (Sat, 02 Feb 2008) $
27   */
28  public class ChiSquaredDistributionImpl
29      extends AbstractContinuousDistribution
30      implements ChiSquaredDistribution, Serializable  {
31      
32      /** Serializable version identifier */
33      private static final long serialVersionUID = -8352658048349159782L;
34  
35      /** Internal Gamma distribution. */    
36      private GammaDistribution gamma;
37      
38      /**
39       * Create a Chi-Squared distribution with the given degrees of freedom.
40       * @param df degrees of freedom.
41       */
42      public ChiSquaredDistributionImpl(double df) {
43          this(df, new GammaDistributionImpl(df / 2.0, 2.0));
44      }
45      
46      /**
47       * Create a Chi-Squared distribution with the given degrees of freedom.
48       * @param df degrees of freedom.
49       * @param g the underlying gamma distribution used to compute probabilities.
50       * @since 1.2
51       */
52      public ChiSquaredDistributionImpl(double df, GammaDistribution g) {
53          super();
54          setGamma(g);
55          setDegreesOfFreedom(df);
56      }
57      
58      /**
59       * Modify the degrees of freedom.
60       * @param degreesOfFreedom the new degrees of freedom.
61       */
62      public void setDegreesOfFreedom(double degreesOfFreedom) {
63          getGamma().setAlpha(degreesOfFreedom / 2.0);
64      }
65          
66      /**
67       * Access the degrees of freedom.
68       * @return the degrees of freedom.
69       */
70      public double getDegreesOfFreedom() {
71          return getGamma().getAlpha() * 2.0;
72      }
73          
74      /**
75       * For this disbution, X, this method returns P(X < x).
76       * @param x the value at which the CDF is evaluated.
77       * @return CDF for this distribution. 
78       * @throws MathException if the cumulative probability can not be
79       *            computed due to convergence or other numerical errors.
80       */
81      public double cumulativeProbability(double x) throws MathException {
82          return getGamma().cumulativeProbability(x);
83      }
84      
85      /**
86       * For this distribution, X, this method returns the critical point x, such
87       * that P(X &lt; x) = <code>p</code>.
88       * <p>
89       * Returns 0 for p=0 and <code>Double.POSITIVE_INFINITY</code> for p=1.</p>
90       *
91       * @param p the desired probability
92       * @return x, such that P(X &lt; x) = <code>p</code>
93       * @throws MathException if the inverse cumulative probability can not be
94       *         computed due to convergence or other numerical errors.
95       * @throws IllegalArgumentException if <code>p</code> is not a valid
96       *         probability.
97       */
98      public double inverseCumulativeProbability(final double p)
99          throws MathException {
100         if (p == 0) {
101             return 0d;
102         }
103         if (p == 1) {
104             return Double.POSITIVE_INFINITY;
105         }
106         return super.inverseCumulativeProbability(p);
107     }
108         
109     /**
110      * Access the domain value lower bound, based on <code>p</code>, used to
111      * bracket a CDF root.  This method is used by
112      * {@link #inverseCumulativeProbability(double)} to find critical values.
113      * 
114      * @param p the desired probability for the critical value
115      * @return domain value lower bound, i.e.
116      *         P(X &lt; <i>lower bound</i>) &lt; <code>p</code> 
117      */
118     protected double getDomainLowerBound(double p) {
119         return Double.MIN_VALUE * getGamma().getBeta();
120     }
121 
122     /**
123      * Access the domain value upper bound, based on <code>p</code>, used to
124      * bracket a CDF root.  This method is used by
125      * {@link #inverseCumulativeProbability(double)} to find critical values.
126      * 
127      * @param p the desired probability for the critical value
128      * @return domain value upper bound, i.e.
129      *         P(X &lt; <i>upper bound</i>) &gt; <code>p</code> 
130      */
131     protected double getDomainUpperBound(double p) {
132         // NOTE: chi squared is skewed to the left
133         // NOTE: therefore, P(X < &mu;) > .5
134 
135         double ret;
136 
137         if (p < .5) {
138             // use mean
139             ret = getDegreesOfFreedom();
140         } else {
141             // use max
142             ret = Double.MAX_VALUE;
143         }
144         
145         return ret;
146     }
147 
148     /**
149      * Access the initial domain value, based on <code>p</code>, used to
150      * bracket a CDF root.  This method is used by
151      * {@link #inverseCumulativeProbability(double)} to find critical values.
152      * 
153      * @param p the desired probability for the critical value
154      * @return initial domain value
155      */
156     protected double getInitialDomain(double p) {
157         // NOTE: chi squared is skewed to the left
158         // NOTE: therefore, P(X < &mu;) > .5
159         
160         double ret;
161 
162         if (p < .5) {
163             // use 1/2 mean
164             ret = getDegreesOfFreedom() * .5;
165         } else {
166             // use mean
167             ret = getDegreesOfFreedom();
168         }
169         
170         return ret;
171     }
172     
173     /**
174      * Modify the underlying gamma distribution.  The caller is responsible for
175      * insuring the gamma distribution has the proper parameter settings.
176      * @param g the new distribution.
177      * @since 1.2 made public
178      */
179     public void setGamma(GammaDistribution g) {
180         this.gamma = g;
181         
182     }
183 
184     /**
185      * Access the Gamma distribution.
186      * @return the internal Gamma distribution.
187      */
188     private GammaDistribution getGamma() {
189         return gamma;
190     }
191 }