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 < 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 < 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 < <i>lower bound</i>) < <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 < <i>upper bound</i>) > <code>p</code> 119 */ 120 protected double getDomainUpperBound(double p) { 121 // NOTE: chi squared is skewed to the left 122 // NOTE: therefore, P(X < μ) > .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 < μ) > .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 }