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 }