ChiSquaredDistribution.java

  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. import org.apache.commons.rng.UniformRandomProvider;

  19. /**
  20.  * Implementation of the chi-squared distribution.
  21.  *
  22.  * <p>The probability density function of \( X \) is:
  23.  *
  24.  * <p>\[ f(x; k) = \frac{1}{2^{k/2} \Gamma(k/2)} x^{k/2 -1} e^{-x/2} \]
  25.  *
  26.  * <p>for \( k &gt; 0 \) the degrees of freedom,
  27.  * \( \Gamma(k/2) \) is the gamma function, and
  28.  * \( x \in [0, \infty) \).
  29.  *
  30.  * @see <a href="https://en.wikipedia.org/wiki/Chi-squared_distribution">Chi-squared distribution (Wikipedia)</a>
  31.  * @see <a href="https://mathworld.wolfram.com/Chi-SquaredDistribution.html">Chi-squared distribution (MathWorld)</a>
  32.  */
  33. public final class ChiSquaredDistribution extends AbstractContinuousDistribution {
  34.     /** Internal Gamma distribution. */
  35.     private final GammaDistribution gamma;

  36.     /**
  37.      * @param degreesOfFreedom Degrees of freedom.
  38.      */
  39.     private ChiSquaredDistribution(double degreesOfFreedom) {
  40.         gamma = GammaDistribution.of(degreesOfFreedom / 2, 2);
  41.     }

  42.     /**
  43.      * Creates a chi-squared distribution.
  44.      *
  45.      * @param degreesOfFreedom Degrees of freedom.
  46.      * @return the distribution
  47.      * @throws IllegalArgumentException if {@code degreesOfFreedom <= 0}.
  48.      */
  49.     public static ChiSquaredDistribution of(double degreesOfFreedom) {
  50.         return new ChiSquaredDistribution(degreesOfFreedom);
  51.     }

  52.     /**
  53.      * Gets the degrees of freedom parameter of this distribution.
  54.      *
  55.      * @return the degrees of freedom.
  56.      */
  57.     public double getDegreesOfFreedom() {
  58.         return gamma.getShape() * 2;
  59.     }

  60.     /** {@inheritDoc}
  61.      *
  62.      * <p>Returns the limit when {@code x = 0}:
  63.      * <ul>
  64.      * <li>{@code df < 2}: Infinity
  65.      * <li>{@code df == 2}: 1 / 2
  66.      * <li>{@code df > 2}: 0
  67.      * </ul>
  68.      */
  69.     @Override
  70.     public double density(double x) {
  71.         return gamma.density(x);
  72.     }

  73.     /** {@inheritDoc}
  74.      *
  75.      * <p>Returns the limit when {@code x = 0}:
  76.      * <ul>
  77.      * <li>{@code df < 2}: Infinity
  78.      * <li>{@code df == 2}: log(1 / 2)
  79.      * <li>{@code df > 2}: -Infinity
  80.      * </ul>
  81.      */
  82.     @Override
  83.     public double logDensity(double x) {
  84.         return gamma.logDensity(x);
  85.     }

  86.     /** {@inheritDoc} */
  87.     @Override
  88.     public double cumulativeProbability(double x)  {
  89.         return gamma.cumulativeProbability(x);
  90.     }

  91.     /** {@inheritDoc} */
  92.     @Override
  93.     public double survivalProbability(double x) {
  94.         return gamma.survivalProbability(x);
  95.     }

  96.     /** {@inheritDoc} */
  97.     @Override
  98.     public double inverseCumulativeProbability(double p) {
  99.         return gamma.inverseCumulativeProbability(p);
  100.     }

  101.     /** {@inheritDoc} */
  102.     @Override
  103.     public double inverseSurvivalProbability(double p) {
  104.         return gamma.inverseSurvivalProbability(p);
  105.     }

  106.     /**
  107.      * {@inheritDoc}
  108.      *
  109.      * <p>For \( k \) degrees of freedom, the mean is \( k \).
  110.      */
  111.     @Override
  112.     public double getMean() {
  113.         return getDegreesOfFreedom();
  114.     }

  115.     /**
  116.      * {@inheritDoc}
  117.      *
  118.      * <p>For \( k \) degrees of freedom, the variance is \( 2k \).
  119.      */
  120.     @Override
  121.     public double getVariance() {
  122.         return 2 * getDegreesOfFreedom();
  123.     }

  124.     /**
  125.      * {@inheritDoc}
  126.      *
  127.      * <p>The lower bound of the support is always 0.
  128.      *
  129.      * @return 0.
  130.      */
  131.     @Override
  132.     public double getSupportLowerBound() {
  133.         return 0;
  134.     }

  135.     /**
  136.      * {@inheritDoc}
  137.      *
  138.      * <p>The upper bound of the support is always positive infinity.
  139.      *
  140.      * @return {@linkplain Double#POSITIVE_INFINITY positive infinity}.
  141.      */
  142.     @Override
  143.     public double getSupportUpperBound() {
  144.         return Double.POSITIVE_INFINITY;
  145.     }

  146.     /** {@inheritDoc} */
  147.     @Override
  148.     public ContinuousDistribution.Sampler createSampler(final UniformRandomProvider rng) {
  149.         return gamma.createSampler(rng);
  150.     }
  151. }