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 {@linkplain #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\} & \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}