001: /*
002: * Copyright 2003-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.math.distribution;
017:
018: import java.io.Serializable;
019:
020: import org.apache.commons.math.MathException;
021:
022: /**
023: * The default implementation of {@link ChiSquaredDistribution}
024: *
025: * @version $Revision: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
026: */
027: public class ChiSquaredDistributionImpl extends
028: AbstractContinuousDistribution implements
029: ChiSquaredDistribution, Serializable {
030:
031: /** Serializable version identifier */
032: private static final long serialVersionUID = -8352658048349159782L;
033:
034: /** Internal Gamma distribution. */
035: private GammaDistribution gamma;
036:
037: /**
038: * Create a Chi-Squared distribution with the given degrees of freedom.
039: * @param degreesOfFreedom degrees of freedom.
040: */
041: public ChiSquaredDistributionImpl(double degreesOfFreedom) {
042: super ();
043: setGamma(DistributionFactory.newInstance()
044: .createGammaDistribution(degreesOfFreedom / 2.0, 2.0));
045: }
046:
047: /**
048: * Modify the degrees of freedom.
049: * @param degreesOfFreedom the new degrees of freedom.
050: */
051: public void setDegreesOfFreedom(double degreesOfFreedom) {
052: getGamma().setAlpha(degreesOfFreedom / 2.0);
053: }
054:
055: /**
056: * Access the degrees of freedom.
057: * @return the degrees of freedom.
058: */
059: public double getDegreesOfFreedom() {
060: return getGamma().getAlpha() * 2.0;
061: }
062:
063: /**
064: * For this disbution, X, this method returns P(X < x).
065: * @param x the value at which the CDF is evaluated.
066: * @return CDF for this distribution.
067: * @throws MathException if the cumulative probability can not be
068: * computed due to convergence or other numerical errors.
069: */
070: public double cumulativeProbability(double x) throws MathException {
071: return getGamma().cumulativeProbability(x);
072: }
073:
074: /**
075: * For this distribution, X, this method returns the critical point x, such
076: * that P(X < x) = <code>p</code>.
077: * <p>
078: * Returns 0 for p=0 and <code>Double.POSITIVE_INFINITY</code> for p=1.
079: *
080: * @param p the desired probability
081: * @return x, such that P(X < x) = <code>p</code>
082: * @throws MathException if the inverse cumulative probability can not be
083: * computed due to convergence or other numerical errors.
084: * @throws IllegalArgumentException if <code>p</code> is not a valid
085: * probability.
086: */
087: public double inverseCumulativeProbability(final double p)
088: throws MathException {
089: if (p == 0) {
090: return 0d;
091: }
092: if (p == 1) {
093: return Double.POSITIVE_INFINITY;
094: }
095: return super .inverseCumulativeProbability(p);
096: }
097:
098: /**
099: * Access the domain value lower bound, based on <code>p</code>, used to
100: * bracket a CDF root. This method is used by
101: * {@link #inverseCumulativeProbability(double)} to find critical values.
102: *
103: * @param p the desired probability for the critical value
104: * @return domain value lower bound, i.e.
105: * P(X < <i>lower bound</i>) < <code>p</code>
106: */
107: protected double getDomainLowerBound(double p) {
108: return Double.MIN_VALUE * getGamma().getBeta();
109: }
110:
111: /**
112: * Access the domain value upper bound, based on <code>p</code>, used to
113: * bracket a CDF root. This method is used by
114: * {@link #inverseCumulativeProbability(double)} to find critical values.
115: *
116: * @param p the desired probability for the critical value
117: * @return domain value upper bound, i.e.
118: * P(X < <i>upper bound</i>) > <code>p</code>
119: */
120: protected double getDomainUpperBound(double p) {
121: // NOTE: chi squared is skewed to the left
122: // NOTE: therefore, P(X < μ) > .5
123:
124: double ret;
125:
126: if (p < .5) {
127: // use mean
128: ret = getDegreesOfFreedom();
129: } else {
130: // use max
131: ret = Double.MAX_VALUE;
132: }
133:
134: return ret;
135: }
136:
137: /**
138: * Access the initial domain value, based on <code>p</code>, used to
139: * bracket a CDF root. This method is used by
140: * {@link #inverseCumulativeProbability(double)} to find critical values.
141: *
142: * @param p the desired probability for the critical value
143: * @return initial domain value
144: */
145: protected double getInitialDomain(double p) {
146: // NOTE: chi squared is skewed to the left
147: // NOTE: therefore, P(X < μ) > .5
148:
149: double ret;
150:
151: if (p < .5) {
152: // use 1/2 mean
153: ret = getDegreesOfFreedom() * .5;
154: } else {
155: // use mean
156: ret = getDegreesOfFreedom();
157: }
158:
159: return ret;
160: }
161:
162: /**
163: * Modify the Gamma distribution.
164: * @param gamma the new distribution.
165: */
166: private void setGamma(GammaDistribution gamma) {
167: this .gamma = gamma;
168: }
169:
170: /**
171: * Access the Gamma distribution.
172: * @return the internal Gamma distribution.
173: */
174: private GammaDistribution getGamma() {
175: return gamma;
176: }
177: }
|