1 /* 2 * Copyright (C) 2015 Alberto Irurueta Carro (alberto@irurueta.com) 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 com.irurueta.statistics; 17 18 /** 19 * Contains methods to work with Chi squared distributions. 20 * Methods of this class use methods of the Gamma class. 21 * This class is based in code of Numerical Recipes 3rd ed. section 6.14.8. 22 */ 23 public class ChiSqDist { 24 25 /** 26 * Nu parameter of chi square distribution. 27 * Typically, this parameter is provided as an integer value indicating the 28 * number of degrees of freedom. 29 */ 30 private double nu; 31 32 /** 33 * Constant factor to multiply p.d.f of chi squared by. This factor depends 34 * on nu parameter. 35 */ 36 private double fac; 37 38 /** 39 * A gamma function instance to be reused for memory efficiency. 40 */ 41 private final Gamma gamma; 42 43 /** 44 * Constructor. 45 * 46 * @param nu parameter of chi square distribution. 47 * @throws IllegalArgumentException if provided nu parameter is negative or 48 * zero. 49 */ 50 public ChiSqDist(final double nu) { 51 gamma = new Gamma(); 52 setNu(nu); 53 } 54 55 /** 56 * Returns nu parameter of chi square distribution. 57 * Typically, this parameter is an integer value indicating the number of 58 * degrees of freedom. 59 * 60 * @return nu parameter of chi square distribution. 61 */ 62 public double getNu() { 63 return nu; 64 } 65 66 /** 67 * Sets nu parameter of chi square distribution. 68 * Typically, this parameter is an integer value indicating the number of 69 * degrees of freedom. 70 * 71 * @param nu nu parameter of chi square distribution. 72 * @throws IllegalArgumentException if provided nu parameter is negative or 73 * zero. 74 */ 75 public final void setNu(final double nu) { 76 if (nu <= 0.0) { 77 throw new IllegalArgumentException(); 78 } 79 80 this.nu = nu; 81 fac = fac(nu); 82 } 83 84 /** 85 * Evaluates the probability density function (p.d.f.) of a Chi square 86 * distribution. 87 * 88 * @param x2 chi square value where p.d.f. is evaluated. Must be greater 89 * than 0.0. 90 * @param nu nu parameter of chi square distribution. Typically, this is an 91 * integer value indicating the number of degrees of freedom. Must be 92 * greater than 0.0. 93 * @return evaluation of p.d.f. 94 * @throws IllegalArgumentException if either x2 or nu are negative or zero. 95 */ 96 public static double p(final double x2, final double nu) { 97 if (nu <= 0.0) { 98 throw new IllegalArgumentException(); 99 } 100 101 return internalP(x2, nu, fac(nu)); 102 } 103 104 /** 105 * Evaluates the probability density function (p.d.f.) of this Chi square 106 * distribution. 107 * 108 * @param x2 chi square value where p.d.f. is evaluated. Must be greater 109 * than 0.0. 110 * @return evaluation of p.d.f. 111 * @throws IllegalArgumentException if x2 is negative or zero. 112 */ 113 public double p(final double x2) { 114 return internalP(x2, nu, fac); 115 } 116 117 /** 118 * Evaluates the cumulative distribution function (c.d.f.) of a Chi-squared 119 * distribution having parameter nu. 120 * 121 * @param x2 chi square value where c.d.f. is evaluated. Must be positive or 122 * zero. 123 * @param nu nu parameter of chi square distribution. Typically, this is an 124 * integer value indicating the number of degrees of freedom. Must be 125 * greater than 0.0. 126 * @return evaluation of c.d.f. 127 * @throws IllegalArgumentException if provided chi square value is negative 128 * or if provided nu parameter is negative or zero. 129 * @throws MaxIterationsExceededException if convergence of incomplete 130 * gamma function cannot be reached. This is rarely thrown and happens 131 * usually for numerically unstable input values. 132 */ 133 public static double cdf(final double x2, final double nu) 134 throws MaxIterationsExceededException { 135 if (nu <= 0.0) { 136 throw new IllegalArgumentException("nu must be greater than 0.0"); 137 } 138 139 return internalCdf(x2, nu, new Gamma()); 140 } 141 142 /** 143 * Evaluates the cumulative distribution function (c.d.f.) of this Chi-square 144 * distribution. 145 * 146 * @param x2 chi square value where c.d.f. is evaluated. Must be positive or 147 * zero. 148 * @return evaluation of c.d.f. 149 * @throws IllegalArgumentException if provided chi square value is 150 * negative. 151 * @throws MaxIterationsExceededException if convergence of incomplete gamma 152 * function cannot be reached. This is rarely thrown and happens usually for 153 * numerically unstable input values. 154 */ 155 public double cdf(final double x2) throws MaxIterationsExceededException { 156 return internalCdf(x2, nu, gamma); 157 } 158 159 /** 160 * Evaluates the inverse cumulative distribution function of a Chi squared 161 * distribution having parameter nu. 162 * Because the c.d.f is a monotonically increasing function with values 163 * between 0.0 and 1.0, its inverse is uniquely defined between such range 164 * of values. 165 * 166 * @param p value to evaluate the inverse c.d.f. at. This value is 167 * equivalent to a probability and must be between 0.0 and 1.0. 168 * @param nu nu parameter of chi square distribution. Typically, this is an 169 * integer value indicating the number of degrees of freedom. Must be 170 * greater than 0.0. 171 * @return the value x2 for which the c.d.f. has value p. 172 * @throws IllegalArgumentException if provided probability value is not 173 * between 0.0 and 1.0 of if provided nu parameter is negative or zero. 174 * @throws MaxIterationsExceededException if convergence of inverse 175 * incomplete gamma function cannot be reached. This is rarely thrown and 176 * happens usually for numerically unstable values. 177 */ 178 public static double invcdf(final double p, final double nu) throws MaxIterationsExceededException { 179 if (nu <= 0.0) { 180 throw new IllegalArgumentException("nu must be greater than 0.0"); 181 } 182 183 return internalInvcdf(p, nu, new Gamma()); 184 } 185 186 /** 187 * Evaluates the inverse cumulative distribution function of this Chi squared 188 * distribution. 189 * Because the c.d.f is a monotonically increasing function with values 190 * between 0.0 and 1.0, its inverse is uniquely defined between such range 191 * of values. 192 * 193 * @param p value to evaluate the inverse c.d.f. at. This value is 194 * equivalent to a probability and must be between 0.0 and 1.0. 195 * @return the value x2 for which the c.d.f. has value p. 196 * @throws IllegalArgumentException if provided probability value is not 197 * between 0.0 and 1.0. 198 * @throws MaxIterationsExceededException if convergence of inverse 199 * incomplete gamma function cannot be reached. This is rarely thrown and 200 * happens usually for numerically unstable values. 201 */ 202 public double invcdf(final double p) throws MaxIterationsExceededException { 203 return internalInvcdf(p, nu, gamma); 204 } 205 206 /** 207 * Evaluates the probability density function (p.d.f.) of a Chi square 208 * distribution. 209 * This method is used internally. 210 * 211 * @param x2 chi square value where p.d.f. is evaluated. Must be greater 212 * than 0.0. 213 * @param nu nu parameter of chi square distribution. Typically, this is an 214 * integer value indicating the number of degrees of freedom. Must be 215 * greater than 0.0. 216 * @param fac actor to multiply p.d.f of chi squared by. 217 * @return evaluation of p.d.f. 218 * @throws IllegalArgumentException if x2 is negative or zero. 219 */ 220 private static double internalP(final double x2, final double nu, final double fac) { 221 if (x2 <= 0.0) { 222 throw new IllegalArgumentException( 223 "chi square must be greater than zero"); 224 } 225 226 return Math.exp(-0.5 * (x2 - (nu - 2.0) * Math.log(x2)) - fac); 227 } 228 229 /** 230 * Evaluates the cumulative distribution function (c.d.f.) of a Chi-squared 231 * distribution having parameter nu. 232 * This method is used internally. 233 * 234 * @param x2 chi square value where c.d.f. is evaluated. Must be positive 235 * or zero. 236 * @param nu nu parameter of chi square distribution. Typically, this is an 237 * integer value indicating the number of degrees of freedom. Must be 238 * greater than 0.0. 239 * @param gamma a gamma instance to evaluate the incomplete gamma function. 240 * @return evaluation of c.d.f. 241 * @throws IllegalArgumentException if provided chi square value is 242 * negative. 243 * @throws MaxIterationsExceededException if convergence of incomplete gamma 244 * function cannot be reached. This is rarely thrown and happens usually for 245 * numerically unstable values. 246 */ 247 private static double internalCdf(final double x2, final double nu, final Gamma gamma) 248 throws MaxIterationsExceededException { 249 if (x2 < 0.0) { 250 throw new IllegalArgumentException("chi square must be positive or zero"); 251 } 252 253 return gamma.gammp(0.5 * nu, 0.5 * x2); 254 } 255 256 /** 257 * Evaluates the inverse cumulative distribution function of a Chi squared 258 * distribution having parameter nu. 259 * Because the c.d.f is a monotonically increasing function with values 260 * between 0.0 and 1.0, its inverse is uniquely defined between such range 261 * of values. 262 * This method is used internally. 263 * 264 * @param p value to evaluate the inverse c.d.f. at. This value is 265 * equivalent to a probability and must be between 0.0 and 1.0. 266 * @param nu nu parameter of chi square distribution. Typically, this is an 267 * integer value indicating the number of degrees of freedom. Must be 268 * greater than 0.0. 269 * @param gamma a gamma instance to evaluate the inverse incomplete gamma 270 * function. 271 * @return the value x2 for which the c.d.f. has value p. 272 * @throws IllegalArgumentException if provided probability value is not 273 * between 0.0 and 1.0. 274 * @throws MaxIterationsExceededException if convergence of inverse 275 * incomplete gamma function cannot be reached. This is rarely thrown and 276 * happens usually for numerically unstable values. 277 */ 278 private static double internalInvcdf(final double p, final double nu, final Gamma gamma) 279 throws MaxIterationsExceededException { 280 281 if (p < 0.0 || p >= 1.0) { 282 throw new IllegalArgumentException("probability value must be between 0.0 and 1.0"); 283 } 284 285 return 2.0 * gamma.invgammp(p, 0.5 * nu); 286 } 287 288 /** 289 * Computes constant factor to multiply p.d.f. of chi squared by. 290 * 291 * @param nu nu parameter of chi square distribution. Typically, this 292 * parameter is provided as an integer value indicating the number of 293 * degrees of freedom. 294 * @return constant factor to multiply p.d.f. of chi squared. 295 */ 296 private static double fac(final double nu) { 297 return 0.693147180559945309 * (0.5 * nu) + Gamma.gammln(0.5 * nu); 298 } 299 }