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: 762087 $ $Date: 2009-04-05 10:20:18 -0400 (Sun, 05 Apr 2009) $
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       * Return the probability density for a particular point.
76       *
77       * @param x The point at which the density should be computed.
78       * @return The pdf at point x.
79       */
80      public double density(Double x) {
81          return gamma.density(x);
82      }
83  
84      /**
85       * For this distribution, X, this method returns P(X < x).
86       * @param x the value at which the CDF is evaluated.
87       * @return CDF for this distribution. 
88       * @throws MathException if the cumulative probability can not be
89       *            computed due to convergence or other numerical errors.
90       */
91      public double cumulativeProbability(double x) throws MathException {
92          return getGamma().cumulativeProbability(x);
93      }
94      
95      /**
96       * For this distribution, X, this method returns the critical point x, such
97       * that P(X &lt; x) = <code>p</code>.
98       * <p>
99       * Returns 0 for p=0 and <code>Double.POSITIVE_INFINITY</code> for p=1.</p>
100      *
101      * @param p the desired probability
102      * @return x, such that P(X &lt; x) = <code>p</code>
103      * @throws MathException if the inverse cumulative probability can not be
104      *         computed due to convergence or other numerical errors.
105      * @throws IllegalArgumentException if <code>p</code> is not a valid
106      *         probability.
107      */
108     @Override
109     public double inverseCumulativeProbability(final double p)
110         throws MathException {
111         if (p == 0) {
112             return 0d;
113         }
114         if (p == 1) {
115             return Double.POSITIVE_INFINITY;
116         }
117         return super.inverseCumulativeProbability(p);
118     }
119         
120     /**
121      * Access the domain value lower bound, based on <code>p</code>, used to
122      * bracket a CDF root.  This method is used by
123      * {@link #inverseCumulativeProbability(double)} to find critical values.
124      * 
125      * @param p the desired probability for the critical value
126      * @return domain value lower bound, i.e.
127      *         P(X &lt; <i>lower bound</i>) &lt; <code>p</code> 
128      */
129     @Override
130     protected double getDomainLowerBound(double p) {
131         return Double.MIN_VALUE * getGamma().getBeta();
132     }
133 
134     /**
135      * Access the domain value upper bound, based on <code>p</code>, used to
136      * bracket a CDF root.  This method is used by
137      * {@link #inverseCumulativeProbability(double)} to find critical values.
138      * 
139      * @param p the desired probability for the critical value
140      * @return domain value upper bound, i.e.
141      *         P(X &lt; <i>upper bound</i>) &gt; <code>p</code> 
142      */
143     @Override
144     protected double getDomainUpperBound(double p) {
145         // NOTE: chi squared is skewed to the left
146         // NOTE: therefore, P(X < &mu;) > .5
147 
148         double ret;
149 
150         if (p < .5) {
151             // use mean
152             ret = getDegreesOfFreedom();
153         } else {
154             // use max
155             ret = Double.MAX_VALUE;
156         }
157         
158         return ret;
159     }
160 
161     /**
162      * Access the initial domain value, based on <code>p</code>, used to
163      * bracket a CDF root.  This method is used by
164      * {@link #inverseCumulativeProbability(double)} to find critical values.
165      * 
166      * @param p the desired probability for the critical value
167      * @return initial domain value
168      */
169     @Override
170     protected double getInitialDomain(double p) {
171         // NOTE: chi squared is skewed to the left
172         // NOTE: therefore, P(X < &mu;) > .5
173         
174         double ret;
175 
176         if (p < .5) {
177             // use 1/2 mean
178             ret = getDegreesOfFreedom() * .5;
179         } else {
180             // use mean
181             ret = getDegreesOfFreedom();
182         }
183         
184         return ret;
185     }
186     
187     /**
188      * Modify the underlying gamma distribution.  The caller is responsible for
189      * insuring the gamma distribution has the proper parameter settings.
190      * @param g the new distribution.
191      * @since 1.2 made public
192      */
193     public void setGamma(GammaDistribution g) {
194         this.gamma = g;
195         
196     }
197 
198     /**
199      * Access the Gamma distribution.
200      * @return the internal Gamma distribution.
201      */
202     private GammaDistribution getGamma() {
203         return gamma;
204     }
205 }