1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.statistics.distribution;
18
19 import java.util.stream.DoubleStream;
20 import org.apache.commons.rng.UniformRandomProvider;
21
22 /**
23 * Interface for distributions on the reals.
24 */
25 public interface ContinuousDistribution {
26 /**
27 * Returns the probability density function (PDF) of this distribution
28 * evaluated at the specified point {@code x}.
29 * In general, the PDF is the derivative of the {@linkplain #cumulativeProbability(double) CDF}.
30 * If the derivative does not exist at {@code x}, then an appropriate
31 * replacement should be returned, e.g. {@link Double#POSITIVE_INFINITY},
32 * {@link Double#NaN}, or the limit inferior or limit superior of the
33 * difference quotient.
34 *
35 * @param x Point at which the PDF is evaluated.
36 * @return the value of the probability density function at {@code x}.
37 */
38 double density(double x);
39
40 /**
41 * For a random variable {@code X} whose values are distributed according
42 * to this distribution, this method returns {@code P(x0 < X <= x1)}.
43 * The default implementation uses the identity
44 * {@code P(x0 < X <= x1) = P(X <= x1) - P(X <= x0)}
45 *
46 * @param x0 Lower bound (exclusive).
47 * @param x1 Upper bound (inclusive).
48 * @return the probability that a random variable with this distribution
49 * takes a value between {@code x0} and {@code x1}, excluding the lower
50 * and including the upper endpoint.
51 * @throws IllegalArgumentException if {@code x0 > x1}.
52 */
53 default double probability(double x0,
54 double x1) {
55 if (x0 > x1) {
56 throw new DistributionException(DistributionException.INVALID_RANGE_LOW_GT_HIGH, x0, x1);
57 }
58 return cumulativeProbability(x1) - cumulativeProbability(x0);
59 }
60
61 /**
62 * Returns the natural logarithm of the probability density function
63 * (PDF) of this distribution evaluated at the specified point {@code x}.
64 *
65 * @param x Point at which the PDF is evaluated.
66 * @return the logarithm of the value of the probability density function
67 * at {@code x}.
68 */
69 default double logDensity(double x) {
70 return Math.log(density(x));
71 }
72
73 /**
74 * For a random variable {@code X} whose values are distributed according
75 * to this distribution, this method returns {@code P(X <= x)}.
76 * In other words, this method represents the (cumulative) distribution
77 * function (CDF) for this distribution.
78 *
79 * @param x Point at which the CDF is evaluated.
80 * @return the probability that a random variable with this
81 * distribution takes a value less than or equal to {@code x}.
82 */
83 double cumulativeProbability(double x);
84
85 /**
86 * For a random variable {@code X} whose values are distributed according
87 * to this distribution, this method returns {@code P(X > x)}.
88 * In other words, this method represents the complementary cumulative
89 * distribution function.
90 *
91 * <p>By default, this is defined as {@code 1 - cumulativeProbability(x)}, but
92 * the specific implementation may be more accurate.
93 *
94 * @param x Point at which the survival function is evaluated.
95 * @return the probability that a random variable with this
96 * distribution takes a value greater than {@code x}.
97 */
98 default double survivalProbability(double x) {
99 return 1.0 - cumulativeProbability(x);
100 }
101
102 /**
103 * Computes the quantile function of this distribution. For a random
104 * variable {@code X} distributed according to this distribution, the
105 * returned value is:
106 *
107 * <p>\[ x = \begin{cases}
108 * \inf \{ x \in \mathbb R : P(X \le x) \ge p\} & \text{for } 0 \lt p \le 1 \\
109 * \inf \{ x \in \mathbb R : P(X \le x) \gt 0 \} & \text{for } p = 0
110 * \end{cases} \]
111 *
112 * @param p Cumulative probability.
113 * @return the smallest {@code p}-quantile of this distribution
114 * (largest 0-quantile for {@code p = 0}).
115 * @throws IllegalArgumentException if {@code p < 0} or {@code p > 1}.
116 */
117 double inverseCumulativeProbability(double p);
118
119 /**
120 * Computes the inverse survival probability function of this distribution. For a random
121 * variable {@code X} distributed according to this distribution, the
122 * returned value is:
123 *
124 * <p>\[ x = \begin{cases}
125 * \inf \{ x \in \mathbb R : P(X \gt x) \le p\} & \text{for } 0 \le p \lt 1 \\
126 * \inf \{ x \in \mathbb R : P(X \gt x) \lt 1 \} & \text{for } p = 1
127 * \end{cases} \]
128 *
129 * <p>By default, this is defined as {@code inverseCumulativeProbability(1 - p)}, but
130 * the specific implementation may be more accurate.
131 *
132 * @param p Survival probability.
133 * @return the smallest {@code (1-p)}-quantile of this distribution
134 * (largest 0-quantile for {@code p = 1}).
135 * @throws IllegalArgumentException if {@code p < 0} or {@code p > 1}.
136 */
137 default double inverseSurvivalProbability(double p) {
138 return inverseCumulativeProbability(1 - p);
139 }
140
141 /**
142 * Gets the mean of this distribution.
143 *
144 * @return the mean.
145 */
146 double getMean();
147
148 /**
149 * Gets the variance of this distribution.
150 *
151 * @return the variance.
152 */
153 double getVariance();
154
155 /**
156 * Gets the lower bound of the support.
157 * It must return the same value as
158 * {@code inverseCumulativeProbability(0)}, i.e.
159 * \( \inf \{ x \in \mathbb R : P(X \le x) \gt 0 \} \).
160 *
161 * @return the lower bound of the support.
162 */
163 double getSupportLowerBound();
164
165 /**
166 * Gets the upper bound of the support.
167 * It must return the same
168 * value as {@code inverseCumulativeProbability(1)}, i.e.
169 * \( \inf \{ x \in \mathbb R : P(X \le x) = 1 \} \).
170 *
171 * @return the upper bound of the support.
172 */
173 double getSupportUpperBound();
174
175 /**
176 * Creates a sampler.
177 *
178 * @param rng Generator of uniformly distributed numbers.
179 * @return a sampler that produces random numbers according this
180 * distribution.
181 */
182 Sampler createSampler(UniformRandomProvider rng);
183
184 /**
185 * Distribution sampling functionality.
186 */
187 @FunctionalInterface
188 interface Sampler {
189 /**
190 * Generates a random value sampled from this distribution.
191 *
192 * @return a random value.
193 */
194 double sample();
195
196 /**
197 * Returns an effectively unlimited stream of {@code double} sample values.
198 *
199 * <p>The default implementation produces a sequential stream that repeatedly
200 * calls {@link #sample sample}().
201 *
202 * @return a stream of {@code double} values.
203 */
204 default DoubleStream samples() {
205 return DoubleStream.generate(this::sample).sequential();
206 }
207
208 /**
209 * Returns a stream producing the given {@code streamSize} number of {@code double}
210 * sample values.
211 *
212 * <p>The default implementation produces a sequential stream that repeatedly
213 * calls {@link #sample sample}(); the stream is limited to the given {@code streamSize}.
214 *
215 * @param streamSize Number of values to generate.
216 * @return a stream of {@code double} values.
217 */
218 default DoubleStream samples(long streamSize) {
219 return samples().limit(streamSize);
220 }
221 }
222 }