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 }