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    }