001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.statistics.distribution; 018 019import org.apache.commons.rng.UniformRandomProvider; 020 021/** 022 * Implementation of the chi-squared distribution. 023 * 024 * <p>The probability density function of \( X \) is: 025 * 026 * <p>\[ f(x; k) = \frac{1}{2^{k/2} \Gamma(k/2)} x^{k/2 -1} e^{-x/2} \] 027 * 028 * <p>for \( k > 0 \) the degrees of freedom, 029 * \( \Gamma(k/2) \) is the gamma function, and 030 * \( x \in [0, \infty) \). 031 * 032 * @see <a href="https://en.wikipedia.org/wiki/Chi-squared_distribution">Chi-squared distribution (Wikipedia)</a> 033 * @see <a href="https://mathworld.wolfram.com/Chi-SquaredDistribution.html">Chi-squared distribution (MathWorld)</a> 034 */ 035public final class ChiSquaredDistribution extends AbstractContinuousDistribution { 036 /** Internal Gamma distribution. */ 037 private final GammaDistribution gamma; 038 039 /** 040 * @param degreesOfFreedom Degrees of freedom. 041 */ 042 private ChiSquaredDistribution(double degreesOfFreedom) { 043 gamma = GammaDistribution.of(degreesOfFreedom / 2, 2); 044 } 045 046 /** 047 * Creates a chi-squared distribution. 048 * 049 * @param degreesOfFreedom Degrees of freedom. 050 * @return the distribution 051 * @throws IllegalArgumentException if {@code degreesOfFreedom <= 0}. 052 */ 053 public static ChiSquaredDistribution of(double degreesOfFreedom) { 054 return new ChiSquaredDistribution(degreesOfFreedom); 055 } 056 057 /** 058 * Gets the degrees of freedom parameter of this distribution. 059 * 060 * @return the degrees of freedom. 061 */ 062 public double getDegreesOfFreedom() { 063 return gamma.getShape() * 2; 064 } 065 066 /** {@inheritDoc} 067 * 068 * <p>Returns the limit when {@code x = 0}: 069 * <ul> 070 * <li>{@code df < 2}: Infinity 071 * <li>{@code df == 2}: 1 / 2 072 * <li>{@code df > 2}: 0 073 * </ul> 074 */ 075 @Override 076 public double density(double x) { 077 return gamma.density(x); 078 } 079 080 /** {@inheritDoc} 081 * 082 * <p>Returns the limit when {@code x = 0}: 083 * <ul> 084 * <li>{@code df < 2}: Infinity 085 * <li>{@code df == 2}: log(1 / 2) 086 * <li>{@code df > 2}: -Infinity 087 * </ul> 088 */ 089 @Override 090 public double logDensity(double x) { 091 return gamma.logDensity(x); 092 } 093 094 /** {@inheritDoc} */ 095 @Override 096 public double cumulativeProbability(double x) { 097 return gamma.cumulativeProbability(x); 098 } 099 100 /** {@inheritDoc} */ 101 @Override 102 public double survivalProbability(double x) { 103 return gamma.survivalProbability(x); 104 } 105 106 /** {@inheritDoc} */ 107 @Override 108 public double inverseCumulativeProbability(double p) { 109 return gamma.inverseCumulativeProbability(p); 110 } 111 112 /** {@inheritDoc} */ 113 @Override 114 public double inverseSurvivalProbability(double p) { 115 return gamma.inverseSurvivalProbability(p); 116 } 117 118 /** 119 * {@inheritDoc} 120 * 121 * <p>For \( k \) degrees of freedom, the mean is \( k \). 122 */ 123 @Override 124 public double getMean() { 125 return getDegreesOfFreedom(); 126 } 127 128 /** 129 * {@inheritDoc} 130 * 131 * <p>For \( k \) degrees of freedom, the variance is \( 2k \). 132 */ 133 @Override 134 public double getVariance() { 135 return 2 * getDegreesOfFreedom(); 136 } 137 138 /** 139 * {@inheritDoc} 140 * 141 * <p>The lower bound of the support is always 0. 142 * 143 * @return 0. 144 */ 145 @Override 146 public double getSupportLowerBound() { 147 return 0; 148 } 149 150 /** 151 * {@inheritDoc} 152 * 153 * <p>The upper bound of the support is always positive infinity. 154 * 155 * @return {@linkplain Double#POSITIVE_INFINITY positive infinity}. 156 */ 157 @Override 158 public double getSupportUpperBound() { 159 return Double.POSITIVE_INFINITY; 160 } 161 162 /** {@inheritDoc} */ 163 @Override 164 public ContinuousDistribution.Sampler createSampler(final UniformRandomProvider rng) { 165 return gamma.createSampler(rng); 166 } 167}