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.exception.NumberIsTooLargeException;
022    import org.apache.commons.math.exception.util.LocalizedFormats;
023    
024    /**
025     * Base class for probability distributions.
026     *
027     * @version $Id: AbstractDistribution.java 1178295 2011-10-03 04:36:27Z psteitz $
028     */
029    public abstract class AbstractDistribution
030        implements Distribution, Serializable {
031    
032        /** Serializable version identifier */
033        private static final long serialVersionUID = -38038050983108802L;
034    
035        /** Cached numerical mean */
036        private double numericalMean = Double.NaN;
037    
038        /** Whether or not the numerical mean has been calculated */
039        private boolean numericalMeanIsCalculated = false;
040    
041        /** Cached numerical variance */
042        private double numericalVariance = Double.NaN;
043    
044        /** Whether or not the numerical variance has been calculated */
045        private boolean numericalVarianceIsCalculated = false;
046    
047        /**
048         * Default constructor.
049         */
050        protected AbstractDistribution() {
051            super();
052        }
053    
054        /**
055         * For a random variable X whose values are distributed according
056         * to this distribution, this method returns P(x0 ≤ X ≤ x1).
057         * <p>
058         * The default implementation uses the identity</p>
059         * <p>
060         * P(x0 &le; X &le; x1) = P(X &le; x1) - P(X &le; x0) </p>
061         *
062         * @param x0 the (inclusive) lower bound
063         * @param x1 the (inclusive) upper bound
064         * @return the probability that a random variable with this distribution
065         * will take a value between {@code x0} and {@code x1},
066         * including the endpoints.
067         * @throws NumberIsTooLargeException if {@code x0 > x1}
068         */
069        public double cumulativeProbability(double x0, double x1) {
070            if (x0 > x1) {
071                throw new NumberIsTooLargeException(LocalizedFormats.LOWER_ENDPOINT_ABOVE_UPPER_ENDPOINT,
072                                                    x0, x1, true);
073            }
074            return cumulativeProbability(x1) - cumulativeProbability(x0);
075        }
076    
077        /**
078         * Use this method to actually calculate the mean for the
079         * specific distribution. Use {@link #getNumericalMean()}
080         * (which implements caching) to actually get the mean.
081         *
082         * @return the mean or Double.NaN if it's not defined
083         */
084        protected abstract double calculateNumericalMean();
085    
086        /**
087         * Use this method to get the numerical value of the mean of this
088         * distribution.
089         *
090         * @return the mean or Double.NaN if it's not defined
091         */
092        public double getNumericalMean() {
093            if (!numericalMeanIsCalculated) {
094                numericalMean = calculateNumericalMean();
095                numericalMeanIsCalculated = true;
096            }
097    
098            return numericalMean;
099        }
100    
101        /**
102         * Use this method to actually calculate the variance for the
103         * specific distribution.  Use {@link #getNumericalVariance()}
104         * (which implements caching) to actually get the variance.
105         *
106         * @return the variance or Double.NaN if it's not defined
107         */
108        protected abstract double calculateNumericalVariance();
109    
110        /**
111         * Use this method to get the numerical value of the variance of this
112         * distribution.
113         *
114         * @return the variance (possibly Double.POSITIVE_INFINITY as
115         * for certain cases in {@link TDistributionImpl}) or
116         * Double.NaN if it's not defined
117         */
118        public double getNumericalVariance() {
119            if (!numericalVarianceIsCalculated) {
120                numericalVariance = calculateNumericalVariance();
121                numericalVarianceIsCalculated = true;
122            }
123    
124            return numericalVariance;
125        }
126    
127        /**
128         * Use this method to get information about whether the lower bound
129         * of the support is inclusive or not.
130         *
131         * @return whether the lower bound of the support is inclusive or not
132         */
133        public abstract boolean isSupportLowerBoundInclusive();
134    
135        /**
136         * Use this method to get information about whether the upper bound
137         * of the support is inclusive or not.
138         *
139         * @return whether the upper bound of the support is inclusive or not
140         */
141        public abstract boolean isSupportUpperBoundInclusive();
142    
143        /**
144         * Use this method to get information about whether the support is connected,
145         * i.e. whether all values between the lower and upper bound of the support
146         * is included in the support.
147         *
148         * For {@link AbstractIntegerDistribution} the support is discrete, so
149         * if this is true, then the support is
150         * {lower bound, lower bound + 1, ..., upper bound}.
151         *
152         * For {@link AbstractContinuousDistribution} the support is continuous, so
153         * if this is true, then the support is the interval
154         * [lower bound, upper bound]
155         * where the limits are inclusive or not according to
156         * {@link #isSupportLowerBoundInclusive()} and {@link #isSupportUpperBoundInclusive()}
157         * (in the example both are true). If both are false, then the support is the interval
158         * (lower bound, upper bound)
159         *
160         * @return whether the support limits given by subclassed methods are connected or not
161         */
162        public boolean isSupportConnected() {
163            return true;
164        }
165    }