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.math.distribution;
018    
019    import java.io.Serializable;
020    
021    import org.apache.commons.math.MathException;
022    import org.apache.commons.math.MathRuntimeException;
023    import org.apache.commons.math.special.Beta;
024    
025    /**
026     * Default implementation of
027     * {@link org.apache.commons.math.distribution.TDistribution}.
028     *
029     * @version $Revision: 772119 $ $Date: 2009-05-06 05:43:28 -0400 (Wed, 06 May 2009) $
030     */
031    public class TDistributionImpl
032        extends AbstractContinuousDistribution
033        implements TDistribution, Serializable  {
034    
035        /** Serializable version identifier */
036        private static final long serialVersionUID = -5852615386664158222L;
037        
038        /** The degrees of freedom*/
039        private double degreesOfFreedom;
040    
041        /**
042         * Create a t distribution using the given degrees of freedom.
043         * @param degreesOfFreedom the degrees of freedom.
044         */
045        public TDistributionImpl(double degreesOfFreedom) {
046            super();
047            setDegreesOfFreedom(degreesOfFreedom);
048        }
049    
050        /**
051         * Modify the degrees of freedom.
052         * @param degreesOfFreedom the new degrees of freedom.
053         */
054        public void setDegreesOfFreedom(double degreesOfFreedom) {
055            if (degreesOfFreedom <= 0.0) {
056                throw MathRuntimeException.createIllegalArgumentException(
057                      "degrees of freedom must be positive ({0})",
058                      degreesOfFreedom);
059            }
060            this.degreesOfFreedom = degreesOfFreedom;
061        }
062    
063        /**
064         * Access the degrees of freedom.
065         * @return the degrees of freedom.
066         */
067        public double getDegreesOfFreedom() {
068            return degreesOfFreedom;
069        }
070    
071        /**
072         * For this distribution, X, this method returns P(X &lt; <code>x</code>).
073         * @param x the value at which the CDF is evaluated.
074         * @return CDF evaluted at <code>x</code>. 
075         * @throws MathException if the cumulative probability can not be
076         *            computed due to convergence or other numerical errors.
077         */
078        public double cumulativeProbability(double x) throws MathException{
079            double ret;
080            if (x == 0.0) {
081                ret = 0.5;
082            } else {
083                double t =
084                    Beta.regularizedBeta(
085                        getDegreesOfFreedom() / (getDegreesOfFreedom() + (x * x)),
086                        0.5 * getDegreesOfFreedom(),
087                        0.5);
088                if (x < 0.0) {
089                    ret = 0.5 * t;
090                } else {
091                    ret = 1.0 - 0.5 * t;
092                }
093            }
094    
095            return ret;
096        }
097        
098        /**
099         * For this distribution, X, this method returns the critical point x, such
100         * that P(X &lt; x) = <code>p</code>.
101         * <p>
102         * Returns <code>Double.NEGATIVE_INFINITY</code> for p=0 and 
103         * <code>Double.POSITIVE_INFINITY</code> for p=1.</p>
104         *
105         * @param p the desired probability
106         * @return x, such that P(X &lt; x) = <code>p</code>
107         * @throws MathException if the inverse cumulative probability can not be
108         *         computed due to convergence or other numerical errors.
109         * @throws IllegalArgumentException if <code>p</code> is not a valid
110         *         probability.
111         */
112        @Override
113        public double inverseCumulativeProbability(final double p) 
114        throws MathException {
115            if (p == 0) {
116                return Double.NEGATIVE_INFINITY;
117            }
118            if (p == 1) {
119                return Double.POSITIVE_INFINITY;
120            }
121            return super.inverseCumulativeProbability(p);
122        }
123    
124        /**
125         * Access the domain value lower bound, based on <code>p</code>, used to
126         * bracket a CDF root.  This method is used by
127         * {@link #inverseCumulativeProbability(double)} to find critical values.
128         * 
129         * @param p the desired probability for the critical value
130         * @return domain value lower bound, i.e.
131         *         P(X &lt; <i>lower bound</i>) &lt; <code>p</code> 
132         */
133        @Override
134        protected double getDomainLowerBound(double p) {
135            return -Double.MAX_VALUE;
136        }
137    
138        /**
139         * Access the domain value upper bound, based on <code>p</code>, used to
140         * bracket a CDF root.  This method is used by
141         * {@link #inverseCumulativeProbability(double)} to find critical values.
142         * 
143         * @param p the desired probability for the critical value
144         * @return domain value upper bound, i.e.
145         *         P(X &lt; <i>upper bound</i>) &gt; <code>p</code> 
146         */
147        @Override
148        protected double getDomainUpperBound(double p) {
149            return Double.MAX_VALUE;
150        }
151    
152        /**
153         * Access the initial domain value, based on <code>p</code>, used to
154         * bracket a CDF root.  This method is used by
155         * {@link #inverseCumulativeProbability(double)} to find critical values.
156         * 
157         * @param p the desired probability for the critical value
158         * @return initial domain value
159         */
160        @Override
161        protected double getInitialDomain(double p) {
162            return 0.0;
163        }
164    }