View Javadoc

1   /*
2    * Copyright 2003-2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.math.distribution;
17  
18  import java.io.Serializable;
19  
20  import org.apache.commons.math.MathException;
21  
22  /**
23   * The default implementation of {@link ChiSquaredDistribution}
24   *
25   * @version $Revision: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
26   */
27  public class ChiSquaredDistributionImpl
28      extends AbstractContinuousDistribution
29      implements ChiSquaredDistribution, Serializable  {
30      
31      /** Serializable version identifier */
32      private static final long serialVersionUID = -8352658048349159782L;
33  
34      /** Internal Gamma distribution. */    
35      private GammaDistribution gamma;
36      
37      /**
38       * Create a Chi-Squared distribution with the given degrees of freedom.
39       * @param degreesOfFreedom degrees of freedom.
40       */
41      public ChiSquaredDistributionImpl(double degreesOfFreedom) {
42          super();
43          setGamma(DistributionFactory.newInstance().createGammaDistribution(
44              degreesOfFreedom / 2.0, 2.0));
45      }
46      
47      /**
48       * Modify the degrees of freedom.
49       * @param degreesOfFreedom the new degrees of freedom.
50       */
51      public void setDegreesOfFreedom(double degreesOfFreedom) {
52          getGamma().setAlpha(degreesOfFreedom / 2.0);
53      }
54          
55      /**
56       * Access the degrees of freedom.
57       * @return the degrees of freedom.
58       */
59      public double getDegreesOfFreedom() {
60          return getGamma().getAlpha() * 2.0;
61      }
62          
63      /**
64       * For this disbution, X, this method returns P(X < x).
65       * @param x the value at which the CDF is evaluated.
66       * @return CDF for this distribution. 
67       * @throws MathException if the cumulative probability can not be
68       *            computed due to convergence or other numerical errors.
69       */
70      public double cumulativeProbability(double x) throws MathException {
71          return getGamma().cumulativeProbability(x);
72      }
73      
74      /**
75       * For this distribution, X, this method returns the critical point x, such
76       * that P(X &lt; x) = <code>p</code>.
77       * <p>
78       * Returns 0 for p=0 and <code>Double.POSITIVE_INFINITY</code> for p=1.
79       *
80       * @param p the desired probability
81       * @return x, such that P(X &lt; x) = <code>p</code>
82       * @throws MathException if the inverse cumulative probability can not be
83       *         computed due to convergence or other numerical errors.
84       * @throws IllegalArgumentException if <code>p</code> is not a valid
85       *         probability.
86       */
87      public double inverseCumulativeProbability(final double p)
88          throws MathException {
89          if (p == 0) {
90              return 0d;
91          }
92          if (p == 1) {
93              return Double.POSITIVE_INFINITY;
94          }
95          return super.inverseCumulativeProbability(p);
96      }
97          
98      /**
99       * Access the domain value lower bound, based on <code>p</code>, used to
100      * bracket a CDF root.  This method is used by
101      * {@link #inverseCumulativeProbability(double)} to find critical values.
102      * 
103      * @param p the desired probability for the critical value
104      * @return domain value lower bound, i.e.
105      *         P(X &lt; <i>lower bound</i>) &lt; <code>p</code> 
106      */
107     protected double getDomainLowerBound(double p) {
108         return Double.MIN_VALUE * getGamma().getBeta();
109     }
110 
111     /**
112      * Access the domain value upper bound, based on <code>p</code>, used to
113      * bracket a CDF root.  This method is used by
114      * {@link #inverseCumulativeProbability(double)} to find critical values.
115      * 
116      * @param p the desired probability for the critical value
117      * @return domain value upper bound, i.e.
118      *         P(X &lt; <i>upper bound</i>) &gt; <code>p</code> 
119      */
120     protected double getDomainUpperBound(double p) {
121         // NOTE: chi squared is skewed to the left
122         // NOTE: therefore, P(X < &mu;) > .5
123 
124         double ret;
125 
126         if (p < .5) {
127             // use mean
128             ret = getDegreesOfFreedom();
129         } else {
130             // use max
131             ret = Double.MAX_VALUE;
132         }
133         
134         return ret;
135     }
136 
137     /**
138      * Access the initial domain value, based on <code>p</code>, used to
139      * bracket a CDF root.  This method is used by
140      * {@link #inverseCumulativeProbability(double)} to find critical values.
141      * 
142      * @param p the desired probability for the critical value
143      * @return initial domain value
144      */
145     protected double getInitialDomain(double p) {
146         // NOTE: chi squared is skewed to the left
147         // NOTE: therefore, P(X < &mu;) > .5
148         
149         double ret;
150 
151         if (p < .5) {
152             // use 1/2 mean
153             ret = getDegreesOfFreedom() * .5;
154         } else {
155             // use mean
156             ret = getDegreesOfFreedom();
157         }
158         
159         return ret;
160     }
161     
162     /**
163      * Modify the Gamma distribution.
164      * @param gamma the new distribution.
165      */
166     private void setGamma(GammaDistribution gamma) {
167         this.gamma = gamma;
168     }
169 
170     /**
171      * Access the Gamma distribution.
172      * @return the internal Gamma distribution.
173      */
174     private GammaDistribution getGamma() {
175         return gamma;
176     }
177 }