View Javadoc
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\}   &amp; \text{for } 0 \lt p \le 1 \\
109      *       \inf \{ x \in \mathbb R : P(X \le x) \gt 0 \}  &amp; \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\}   &amp; \text{for } 0 \le p \lt 1 \\
126      *       \inf \{ x \in \mathbb R : P(X \gt x) \lt 1 \}  &amp; \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 }