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 */
017package org.apache.commons.statistics.distribution;
018
019import java.util.stream.DoubleStream;
020import org.apache.commons.rng.UniformRandomProvider;
021
022/**
023 * Interface for distributions on the reals.
024 */
025public interface ContinuousDistribution {
026    /**
027     * Returns the probability density function (PDF) of this distribution
028     * evaluated at the specified point {@code x}.
029     * In general, the PDF is the derivative of the {@link #cumulativeProbability(double) CDF}.
030     * If the derivative does not exist at {@code x}, then an appropriate
031     * replacement should be returned, e.g. {@link Double#POSITIVE_INFINITY},
032     * {@link Double#NaN}, or the limit inferior or limit superior of the
033     * difference quotient.
034     *
035     * @param x Point at which the PDF is evaluated.
036     * @return the value of the probability density function at {@code x}.
037     */
038    double density(double x);
039
040    /**
041     * For a random variable {@code X} whose values are distributed according
042     * to this distribution, this method returns {@code P(x0 < X <= x1)}.
043     * The default implementation uses the identity
044     * {@code P(x0 < X <= x1) = P(X <= x1) - P(X <= x0)}
045     *
046     * @param x0 Lower bound (exclusive).
047     * @param x1 Upper bound (inclusive).
048     * @return the probability that a random variable with this distribution
049     * takes a value between {@code x0} and {@code x1},  excluding the lower
050     * and including the upper endpoint.
051     * @throws IllegalArgumentException if {@code x0 > x1}.
052     */
053    default double probability(double x0,
054                               double x1) {
055        if (x0 > x1) {
056            throw new DistributionException(DistributionException.INVALID_RANGE_LOW_GT_HIGH, x0, x1);
057        }
058        return cumulativeProbability(x1) - cumulativeProbability(x0);
059    }
060
061    /**
062     * Returns the natural logarithm of the probability density function
063     * (PDF) of this distribution evaluated at the specified point {@code x}.
064     *
065     * @param x Point at which the PDF is evaluated.
066     * @return the logarithm of the value of the probability density function
067     * at {@code x}.
068     */
069    default double logDensity(double x) {
070        return Math.log(density(x));
071    }
072
073    /**
074     * For a random variable {@code X} whose values are distributed according
075     * to this distribution, this method returns {@code P(X <= x)}.
076     * In other words, this method represents the (cumulative) distribution
077     * function (CDF) for this distribution.
078     *
079     * @param x Point at which the CDF is evaluated.
080     * @return the probability that a random variable with this
081     * distribution takes a value less than or equal to {@code x}.
082     */
083    double cumulativeProbability(double x);
084
085    /**
086     * For a random variable {@code X} whose values are distributed according
087     * to this distribution, this method returns {@code P(X > x)}.
088     * In other words, this method represents the complementary cumulative
089     * distribution function.
090     *
091     * <p>By default, this is defined as {@code 1 - cumulativeProbability(x)}, but
092     * the specific implementation may be more accurate.
093     *
094     * @param x Point at which the survival function is evaluated.
095     * @return the probability that a random variable with this
096     * distribution takes a value greater than {@code x}.
097     */
098    default double survivalProbability(double x) {
099        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 \ge x) \le p\}   &amp; \text{for } 0 \le p \lt 1 \\
126     *       \inf \{ x \in \mathbb R : P(X \ge 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}