Merged ChiSquaredDistribution and ChiSquaredDistributionImpl (MATH-711).

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1206060 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Sebastien Brisard 2011-11-25 05:16:56 +00:00
parent 20d9eb1a5d
commit 776514240d
6 changed files with 204 additions and 278 deletions

View File

@ -16,24 +16,199 @@
*/
package org.apache.commons.math.distribution;
import java.io.Serializable;
/**
* The Chi-Squared Distribution.
*
* <p>
* References:
* <ul>
* <li><a href="http://mathworld.wolfram.com/Chi-SquaredDistribution.html">
* Chi-Squared Distribution</a></li>
* </ul>
* </p>
* Implementation of the chi-squared distribution.
*
* @see <a href="http://en.wikipedia.org/wiki/Chi-squared_distribution">Chi-squared distribution (Wikipedia)</a>
* @see <a href="http://mathworld.wolfram.com/Chi-SquaredDistribution.html">Chi-squared Distribution (MathWorld)</a>
* @version $Id$
*/
public interface ChiSquaredDistribution extends ContinuousDistribution {
public class ChiSquaredDistribution
extends AbstractContinuousDistribution
implements Serializable {
/**
* Default inverse cumulative probability accuracy
* @since 2.1
*/
public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
/** Serializable version identifier */
private static final long serialVersionUID = -8352658048349159782L;
/** Internal Gamma distribution. */
private final GammaDistribution gamma;
/** Inverse cumulative probability accuracy */
private final double solverAbsoluteAccuracy;
/**
* Create a Chi-Squared distribution with the given degrees of freedom.
*
* @param degreesOfFreedom Degrees of freedom.
*/
public ChiSquaredDistribution(double degreesOfFreedom) {
this(degreesOfFreedom, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
}
/**
* Create a Chi-Squared distribution with the given degrees of freedom and
* inverse cumulative probability accuracy.
*
* @param degreesOfFreedom Degrees of freedom.
* @param inverseCumAccuracy the maximum absolute error in inverse
* cumulative probability estimates (defaults to
* {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}).
* @since 2.1
*/
public ChiSquaredDistribution(double degreesOfFreedom,
double inverseCumAccuracy) {
gamma = new GammaDistributionImpl(degreesOfFreedom / 2, 2);
solverAbsoluteAccuracy = inverseCumAccuracy;
}
/**
* Access the number of degrees of freedom.
*
* @return the degrees of freedom.
*/
double getDegreesOfFreedom();
public double getDegreesOfFreedom() {
return gamma.getAlpha() * 2.0;
}
/** {@inheritDoc} */
public double density(double x) {
return gamma.density(x);
}
/** {@inheritDoc} */
public double cumulativeProbability(double x) {
return gamma.cumulativeProbability(x);
}
/**
* {@inheritDoc}
*
* Returns {@code 0} when {@code p == 0} and
* {@code Double.POSITIVE_INFINITY} when {@code p == 1}.
*/
@Override
public double inverseCumulativeProbability(final double p) {
if (p == 0) {
return 0d;
}
if (p == 1) {
return Double.POSITIVE_INFINITY;
}
return super.inverseCumulativeProbability(p);
}
/** {@inheritDoc} */
@Override
protected double getDomainLowerBound(double p) {
return Double.MIN_VALUE * gamma.getBeta();
}
/** {@inheritDoc} */
@Override
protected double getDomainUpperBound(double p) {
// NOTE: chi squared is skewed to the left
// NOTE: therefore, P(X < &mu;) > .5
double ret;
if (p < .5) {
// use mean
ret = getDegreesOfFreedom();
} else {
// use max
ret = Double.MAX_VALUE;
}
return ret;
}
/** {@inheritDoc} */
@Override
protected double getInitialDomain(double p) {
// NOTE: chi squared is skewed to the left
// NOTE: therefore, P(X < &mu;) > 0.5
double ret;
if (p < 0.5) {
// use 1/2 mean
ret = getDegreesOfFreedom() * 0.5;
} else {
// use mean
ret = getDegreesOfFreedom();
}
return ret;
}
/** {@inheritDoc} */
@Override
protected double getSolverAbsoluteAccuracy() {
return solverAbsoluteAccuracy;
}
/**
* {@inheritDoc}
*
* The lower bound of the support is always 0 no matter the
* degrees of freedom.
*
* @return lower bound of the support (always 0)
*/
@Override
public double getSupportLowerBound() {
return 0;
}
/**
* {@inheritDoc}
*
* The upper bound of the support is always positive infinity no matter the
* degrees of freedom.
*
* @return upper bound of the support (always Double.POSITIVE_INFINITY)
*/
@Override
public double getSupportUpperBound() {
return Double.POSITIVE_INFINITY;
}
/**
* {@inheritDoc}
*
* For {@code k} degrees of freedom, the mean is {@code k}.
*/
@Override
protected double calculateNumericalMean() {
return getDegreesOfFreedom();
}
/**
* {@inheritDoc}
*
* For {@code k} degrees of freedom, the variance is {@code 2 * k}.
*
* @return {@inheritDoc}
*/
@Override
protected double calculateNumericalVariance() {
return 2*getDegreesOfFreedom();
}
/** {@inheritDoc} */
@Override
public boolean isSupportLowerBoundInclusive() {
return true;
}
/** {@inheritDoc} */
@Override
public boolean isSupportUpperBoundInclusive() {
return false;
}
}

View File

@ -1,249 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.math.distribution;
import java.io.Serializable;
/**
* The default implementation of {@link ChiSquaredDistribution}
*
* @version $Id$
*/
public class ChiSquaredDistributionImpl
extends AbstractContinuousDistribution
implements ChiSquaredDistribution, Serializable {
/**
* Default inverse cumulative probability accuracy
* @since 2.1
*/
public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
/** Serializable version identifier */
private static final long serialVersionUID = -8352658048349159782L;
/** Internal Gamma distribution. */
private final GammaDistribution gamma;
/** Inverse cumulative probability accuracy */
private final double solverAbsoluteAccuracy;
/**
* Create a Chi-Squared distribution with the given degrees of freedom.
*
* @param degreesOfFreedom Degrees of freedom.
*/
public ChiSquaredDistributionImpl(double degreesOfFreedom) {
this(degreesOfFreedom, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
}
/**
* Create a Chi-Squared distribution with the given degrees of freedom and
* inverse cumulative probability accuracy.
*
* @param degreesOfFreedom Degrees of freedom.
* @param inverseCumAccuracy the maximum absolute error in inverse
* cumulative probability estimates (defaults to
* {@link #DEFAULT_INVERSE_ABSOLUTE_ACCURACY}).
* @since 2.1
*/
public ChiSquaredDistributionImpl(double degreesOfFreedom,
double inverseCumAccuracy) {
gamma = new GammaDistributionImpl(degreesOfFreedom / 2, 2);
solverAbsoluteAccuracy = inverseCumAccuracy;
}
/**
* {@inheritDoc}
*/
public double getDegreesOfFreedom() {
return gamma.getAlpha() * 2.0;
}
/**
* {@inheritDoc}
*/
public double density(double x) {
return gamma.density(x);
}
/**
* {@inheritDoc}
*/
public double cumulativeProbability(double x) {
return gamma.cumulativeProbability(x);
}
/**
* {@inheritDoc}
*
* It will return {@code 0} when {@code p = 0} and
* {@code Double.POSITIVE_INFINITY} when {@code p = 1}.
*/
@Override
public double inverseCumulativeProbability(final double p) {
if (p == 0) {
return 0d;
}
if (p == 1) {
return Double.POSITIVE_INFINITY;
}
return super.inverseCumulativeProbability(p);
}
/**
* Access the domain value lower bound, based on {@code p}, used to
* bracket a CDF root. This method is used by
* {@link #inverseCumulativeProbability(double)} to find critical values.
*
* @param p the desired probability for the critical value
* @return domain value lower bound, i.e. {@code P(X < 'lower bound') < p}.
*/
@Override
protected double getDomainLowerBound(double p) {
return Double.MIN_VALUE * gamma.getBeta();
}
/**
* Access the domain value upper bound, based on {@code p}, used to
* bracket a CDF root. This method is used by
* {@link #inverseCumulativeProbability(double)} to find critical values.
*
* @param p Desired probability for the critical value.
* @return domain value upper bound, i.e. {@code P(X < 'upper bound') > p}.
*/
@Override
protected double getDomainUpperBound(double p) {
// NOTE: chi squared is skewed to the left
// NOTE: therefore, P(X < &mu;) > .5
double ret;
if (p < .5) {
// use mean
ret = getDegreesOfFreedom();
} else {
// use max
ret = Double.MAX_VALUE;
}
return ret;
}
/**
* Access the initial domain value, based on {@code p}, used to
* bracket a CDF root. This method is used by
* {@link #inverseCumulativeProbability(double)} to find critical values.
*
* @param p Desired probability for the critical value.
* @return the initial domain value.
*/
@Override
protected double getInitialDomain(double p) {
// NOTE: chi squared is skewed to the left
// NOTE: therefore, P(X < &mu;) > 0.5
double ret;
if (p < 0.5) {
// use 1/2 mean
ret = getDegreesOfFreedom() * 0.5;
} else {
// use mean
ret = getDegreesOfFreedom();
}
return ret;
}
/**
* Return the absolute accuracy setting of the solver used to estimate
* inverse cumulative probabilities.
*
* @return the solver absolute accuracy.
* @since 2.1
*/
@Override
protected double getSolverAbsoluteAccuracy() {
return solverAbsoluteAccuracy;
}
/**
* {@inheritDoc}
*
* The lower bound of the support is always 0 no matter the
* degrees of freedom.
*
* @return lower bound of the support (always 0)
*/
@Override
public double getSupportLowerBound() {
return 0;
}
/**
* {@inheritDoc}
*
* The upper bound of the support is always positive infinity no matter the
* degrees of freedom.
*
* @return upper bound of the support (always Double.POSITIVE_INFINITY)
*/
@Override
public double getSupportUpperBound() {
return Double.POSITIVE_INFINITY;
}
/**
* {@inheritDoc}
*
* For <code>k</code> degrees of freedom, the mean is
* <code>k</code>
*
* @return {@inheritDoc}
*/
@Override
protected double calculateNumericalMean() {
return getDegreesOfFreedom();
}
/**
* {@inheritDoc}
*
* For <code>k</code> degrees of freedom, the variance is
* <code>2 * k</code>
*
* @return {@inheritDoc}
*/
@Override
protected double calculateNumericalVariance() {
return 2*getDegreesOfFreedom();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSupportLowerBoundInclusive() {
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSupportUpperBoundInclusive() {
return false;
}
}

View File

@ -27,7 +27,7 @@ import java.util.Collection;
import org.apache.commons.math.distribution.BetaDistribution;
import org.apache.commons.math.distribution.BinomialDistribution;
import org.apache.commons.math.distribution.CauchyDistribution;
import org.apache.commons.math.distribution.ChiSquaredDistributionImpl;
import org.apache.commons.math.distribution.ChiSquaredDistribution;
import org.apache.commons.math.distribution.ContinuousDistribution;
import org.apache.commons.math.distribution.FDistributionImpl;
import org.apache.commons.math.distribution.HypergeometricDistributionImpl;
@ -641,7 +641,7 @@ public class RandomDataImpl implements RandomData, Serializable {
}
/**
* Generates a random value from the {@link ChiSquaredDistributionImpl ChiSquare Distribution}.
* Generates a random value from the {@link ChiSquaredDistribution ChiSquare Distribution}.
* This implementation uses {@link #nextInversionDeviate(ContinuousDistribution) inversion}
* to generate random values.
*
@ -650,7 +650,7 @@ public class RandomDataImpl implements RandomData, Serializable {
* @since 2.2
*/
public double nextChiSquare(double df) {
return nextInversionDeviate(new ChiSquaredDistributionImpl(df));
return nextInversionDeviate(new ChiSquaredDistribution(df));
}
/**

View File

@ -22,7 +22,6 @@ import org.apache.commons.math.exception.OutOfRangeException;
import org.apache.commons.math.exception.DimensionMismatchException;
import org.apache.commons.math.exception.MathIllegalArgumentException;
import org.apache.commons.math.distribution.ChiSquaredDistribution;
import org.apache.commons.math.distribution.ChiSquaredDistributionImpl;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.util.MathUtils;
@ -102,7 +101,7 @@ public class ChiSquareTestImpl implements UnknownDistributionChiSquareTest {
public double chiSquareTest(double[] expected, long[] observed)
throws MathException {
ChiSquaredDistribution distribution =
new ChiSquaredDistributionImpl(expected.length - 1.0);
new ChiSquaredDistribution(expected.length - 1.0);
return 1.0 - distribution.cumulativeProbability(
chiSquare(expected, observed));
}
@ -176,7 +175,8 @@ public class ChiSquareTestImpl implements UnknownDistributionChiSquareTest {
throws MathException {
checkArray(counts);
double df = ((double) counts.length -1) * ((double) counts[0].length - 1);
ChiSquaredDistribution distribution = new ChiSquaredDistributionImpl(df);
ChiSquaredDistribution distribution;
distribution = new ChiSquaredDistribution(df);
return 1 - distribution.cumulativeProbability(chiSquare(counts));
}
@ -270,8 +270,8 @@ public class ChiSquareTestImpl implements UnknownDistributionChiSquareTest {
*/
public double chiSquareTestDataSetsComparison(long[] observed1, long[] observed2)
throws MathException {
ChiSquaredDistribution distribution =
new ChiSquaredDistributionImpl((double) observed1.length - 1);
ChiSquaredDistribution distribution;
distribution = new ChiSquaredDistribution((double) observed1.length - 1);
return 1 - distribution.cumulativeProbability(
chiSquareDataSetsComparison(observed1, observed2));
}

View File

@ -34,7 +34,7 @@ public class ChiSquareDistributionTest extends ContinuousDistributionAbstractTes
/** Creates the default continuous distribution instance to use in tests. */
@Override
public ChiSquaredDistribution makeDistribution() {
return new ChiSquaredDistributionImpl(5.0);
return new ChiSquaredDistribution(5.0);
}
/** Creates the default cumulative probability distribution test input values */
@ -84,7 +84,7 @@ public class ChiSquareDistributionTest extends ContinuousDistributionAbstractTes
@Test
public void testSmallDf() throws Exception {
setDistribution(new ChiSquaredDistributionImpl(0.1d));
setDistribution(new ChiSquaredDistribution(0.1d));
setTolerance(1E-4);
// quantiles computed using R version 1.8.1 (linux version)
setCumulativeTestPoints(new double[] {1.168926E-60, 1.168926E-40, 1.063132E-32,
@ -116,7 +116,7 @@ public class ChiSquareDistributionTest extends ContinuousDistributionAbstractTes
}
private void checkDensity(double df, double[] x, double[] expected) {
ChiSquaredDistribution d = new ChiSquaredDistributionImpl(df);
ChiSquaredDistribution d = new ChiSquaredDistribution(df);
for (int i = 0; i < x.length; i++) {
Assert.assertEquals(expected[i], d.density(x[i]), 1e-5);
}
@ -126,12 +126,12 @@ public class ChiSquareDistributionTest extends ContinuousDistributionAbstractTes
public void testMoments() {
final double tol = 1e-9;
ChiSquaredDistribution dist;
dist = new ChiSquaredDistributionImpl(1500);
dist = new ChiSquaredDistribution(1500);
Assert.assertEquals(dist.getNumericalMean(), 1500, tol);
Assert.assertEquals(dist.getNumericalVariance(), 3000, tol);
dist = new ChiSquaredDistributionImpl(1.12);
Assert.assertEquals(dist.getNumericalVariance(), 3000, tol);
dist = new ChiSquaredDistribution(1.12);
Assert.assertEquals(dist.getNumericalMean(), 1.12, tol);
Assert.assertEquals(dist.getNumericalVariance(), 2.24, tol);
}

View File

@ -29,7 +29,7 @@ import org.apache.commons.math.distribution.BetaDistribution;
import org.apache.commons.math.distribution.BinomialDistribution;
import org.apache.commons.math.distribution.BinomialDistributionTest;
import org.apache.commons.math.distribution.CauchyDistribution;
import org.apache.commons.math.distribution.ChiSquaredDistributionImpl;
import org.apache.commons.math.distribution.ChiSquaredDistribution;
import org.apache.commons.math.distribution.ExponentialDistributionImpl;
import org.apache.commons.math.distribution.FDistributionImpl;
import org.apache.commons.math.distribution.GammaDistributionImpl;
@ -884,7 +884,7 @@ public class RandomDataTest {
@Test
public void testNextChiSquare() throws Exception {
double[] quartiles = TestUtils.getDistributionQuartiles(new ChiSquaredDistributionImpl(12));
double[] quartiles = TestUtils.getDistributionQuartiles(new ChiSquaredDistribution(12));
long[] counts = new long[4];
randomData.reSeed(1000);
for (int i = 0; i < 1000; i++) {