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 ≤ X ≤ x1) = P(X ≤ x1) - P(X ≤ 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 }