    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     */
    017    package org.apache.commons.math3.distribution;
    018
    019    import org.apache.commons.math3.random.RandomGenerator;
    020    import org.apache.commons.math3.random.Well19937c;
    021
    022    /**
    023     * Implementation of the chi-squared distribution.
    024     *
    025     * @see <a href="http://en.wikipedia.org/wiki/Chi-squared_distribution">Chi-squared distribution (Wikipedia)</a>
    026     * @see <a href="http://mathworld.wolfram.com/Chi-SquaredDistribution.html">Chi-squared Distribution (MathWorld)</a>
    027     * @version $Id: ChiSquaredDistribution.java 1416643 2012-12-03 19:37:14Z tn $
    028     */
    029    public class ChiSquaredDistribution extends AbstractRealDistribution {
    030        /**
    031         * Default inverse cumulative probability accuracy
    032         * @since 2.1
    033         */
    034        public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
    035        /** Serializable version identifier */
    036        private static final long serialVersionUID = -8352658048349159782L;
    037        /** Internal Gamma distribution. */
    038        private final GammaDistribution gamma;
    039        /** Inverse cumulative probability accuracy */
    040        private final double solverAbsoluteAccuracy;
    041
    042        /**
    043         * Create a Chi-Squared distribution with the given degrees of freedom.
    044         *
    045         * @param degreesOfFreedom Degrees of freedom.
    046         */
    047        public ChiSquaredDistribution(double degreesOfFreedom) {
    048            this(degreesOfFreedom, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
    049        }
    050
    051        /**
    052         * Create a Chi-Squared distribution with the given degrees of freedom and
    053         * inverse cumulative probability accuracy.
    054         *
    055         * @param degreesOfFreedom Degrees of freedom.
    056         * @param inverseCumAccuracy the maximum absolute error in inverse
    057         * cumulative probability estimates (defaults to
    058         * {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}).
    059         * @since 2.1
    060         */
    061        public ChiSquaredDistribution(double degreesOfFreedom,
    062                                      double inverseCumAccuracy) {
    063            this(new Well19937c(), degreesOfFreedom, inverseCumAccuracy);
    064        }
    065
    066        /**
    067         * Create a Chi-Squared distribution with the given degrees of freedom and
    068         * inverse cumulative probability accuracy.
    069         *
    070         * @param rng Random number generator.
    071         * @param degreesOfFreedom Degrees of freedom.
    072         * @param inverseCumAccuracy the maximum absolute error in inverse
    073         * cumulative probability estimates (defaults to
    074         * {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}).
    075         * @since 3.1
    076         */
    077        public ChiSquaredDistribution(RandomGenerator rng,
    078                                      double degreesOfFreedom,
    079                                      double inverseCumAccuracy) {
    080            super(rng);
    081
    082            gamma = new GammaDistribution(degreesOfFreedom / 2, 2);
    083            solverAbsoluteAccuracy = inverseCumAccuracy;
    084        }
    085
    086        /**
    087         * Access the number of degrees of freedom.
    088         *
    089         * @return the degrees of freedom.
    090         */
    091        public double getDegreesOfFreedom() {
    092            return gamma.getShape() * 2.0;
    093        }
    094
    095        /** {@inheritDoc} */
    096        public double density(double x) {
    097            return gamma.density(x);
    098        }
    099
    100        /** {@inheritDoc} */
    101        public double cumulativeProbability(double x)  {
    102            return gamma.cumulativeProbability(x);
    103        }
    104
    105        /** {@inheritDoc} */
    106        @Override
    107        protected double getSolverAbsoluteAccuracy() {
    108            return solverAbsoluteAccuracy;
    109        }
    110
    111        /**
    112         * {@inheritDoc}
    113         *
    114         * For {@code k} degrees of freedom, the mean is {@code k}.
    115         */
    116        public double getNumericalMean() {
    117            return getDegreesOfFreedom();
    118        }
    119
    120        /**
    121         * {@inheritDoc}
    122         *
    123         * @return {@code 2 * k}, where {@code k} is the number of degrees of freedom.
    124         */
    125        public double getNumericalVariance() {
    126            return 2 * getDegreesOfFreedom();
    127        }
    128
    129        /**
    130         * {@inheritDoc}
    131         *
    132         * The lower bound of the support is always 0 no matter the
    133         * degrees of freedom.
    134         *
    135         * @return zero.
    136         */
    137        public double getSupportLowerBound() {
    138            return 0;
    139        }
    140
    141        /**
    142         * {@inheritDoc}
    143         *
    144         * The upper bound of the support is always positive infinity no matter the
    145         * degrees of freedom.
    146         *
    147         * @return {@code Double.POSITIVE_INFINITY}.
    148         */
    149        public double getSupportUpperBound() {
    150            return Double.POSITIVE_INFINITY;
    151        }
    152
    153        /** {@inheritDoc} */
    154        public boolean isSupportLowerBoundInclusive() {
    155            return true;
    156        }
    157
    158        /** {@inheritDoc} */
    159        public boolean isSupportUpperBoundInclusive() {
    160            return false;
    161        }
    162
    163        /**
    164         * {@inheritDoc}
    165         *
    166         * The support of this distribution is connected.
    167         *
    168         * @return {@code true}
    169         */
    170        public boolean isSupportConnected() {
    171            return true;
    172        }
    173    }