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.statistics.distribution;
18  
19  import org.apache.commons.rng.UniformRandomProvider;
20  
21  /**
22   * Implementation of the chi-squared distribution.
23   *
24   * <p>The probability density function of \( X \) is:
25   *
26   * <p>\[ f(x; k) = \frac{1}{2^{k/2} \Gamma(k/2)} x^{k/2 -1} e^{-x/2} \]
27   *
28   * <p>for \( k &gt; 0 \) the degrees of freedom,
29   * \( \Gamma(k/2) \) is the gamma function, and
30   * \( x \in [0, \infty) \).
31   *
32   * @see <a href="https://en.wikipedia.org/wiki/Chi-squared_distribution">Chi-squared distribution (Wikipedia)</a>
33   * @see <a href="https://mathworld.wolfram.com/Chi-SquaredDistribution.html">Chi-squared distribution (MathWorld)</a>
34   */
35  public final class ChiSquaredDistribution extends AbstractContinuousDistribution {
36      /** Internal Gamma distribution. */
37      private final GammaDistribution gamma;
38  
39      /**
40       * @param degreesOfFreedom Degrees of freedom.
41       */
42      private ChiSquaredDistribution(double degreesOfFreedom) {
43          gamma = GammaDistribution.of(degreesOfFreedom / 2, 2);
44      }
45  
46      /**
47       * Creates a chi-squared distribution.
48       *
49       * @param degreesOfFreedom Degrees of freedom.
50       * @return the distribution
51       * @throws IllegalArgumentException if {@code degreesOfFreedom <= 0}.
52       */
53      public static ChiSquaredDistribution of(double degreesOfFreedom) {
54          return new ChiSquaredDistribution(degreesOfFreedom);
55      }
56  
57      /**
58       * Gets the degrees of freedom parameter of this distribution.
59       *
60       * @return the degrees of freedom.
61       */
62      public double getDegreesOfFreedom() {
63          return gamma.getShape() * 2;
64      }
65  
66      /** {@inheritDoc}
67       *
68       * <p>Returns the limit when {@code x = 0}:
69       * <ul>
70       * <li>{@code df < 2}: Infinity
71       * <li>{@code df == 2}: 1 / 2
72       * <li>{@code df > 2}: 0
73       * </ul>
74       */
75      @Override
76      public double density(double x) {
77          return gamma.density(x);
78      }
79  
80      /** {@inheritDoc}
81       *
82       * <p>Returns the limit when {@code x = 0}:
83       * <ul>
84       * <li>{@code df < 2}: Infinity
85       * <li>{@code df == 2}: log(1 / 2)
86       * <li>{@code df > 2}: -Infinity
87       * </ul>
88       */
89      @Override
90      public double logDensity(double x) {
91          return gamma.logDensity(x);
92      }
93  
94      /** {@inheritDoc} */
95      @Override
96      public double cumulativeProbability(double x)  {
97          return gamma.cumulativeProbability(x);
98      }
99  
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 }