ContinuousDistribution.java

  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. import java.util.stream.DoubleStream;
  19. import org.apache.commons.rng.UniformRandomProvider;

  20. /**
  21.  * Interface for distributions on the reals.
  22.  */
  23. public interface ContinuousDistribution {
  24.     /**
  25.      * Returns the probability density function (PDF) of this distribution
  26.      * evaluated at the specified point {@code x}.
  27.      * In general, the PDF is the derivative of the {@linkplain #cumulativeProbability(double) CDF}.
  28.      * If the derivative does not exist at {@code x}, then an appropriate
  29.      * replacement should be returned, e.g. {@link Double#POSITIVE_INFINITY},
  30.      * {@link Double#NaN}, or the limit inferior or limit superior of the
  31.      * difference quotient.
  32.      *
  33.      * @param x Point at which the PDF is evaluated.
  34.      * @return the value of the probability density function at {@code x}.
  35.      */
  36.     double density(double x);

  37.     /**
  38.      * For a random variable {@code X} whose values are distributed according
  39.      * to this distribution, this method returns {@code P(x0 < X <= x1)}.
  40.      * The default implementation uses the identity
  41.      * {@code P(x0 < X <= x1) = P(X <= x1) - P(X <= x0)}
  42.      *
  43.      * @param x0 Lower bound (exclusive).
  44.      * @param x1 Upper bound (inclusive).
  45.      * @return the probability that a random variable with this distribution
  46.      * takes a value between {@code x0} and {@code x1},  excluding the lower
  47.      * and including the upper endpoint.
  48.      * @throws IllegalArgumentException if {@code x0 > x1}.
  49.      */
  50.     default double probability(double x0,
  51.                                double x1) {
  52.         if (x0 > x1) {
  53.             throw new DistributionException(DistributionException.INVALID_RANGE_LOW_GT_HIGH, x0, x1);
  54.         }
  55.         return cumulativeProbability(x1) - cumulativeProbability(x0);
  56.     }

  57.     /**
  58.      * Returns the natural logarithm of the probability density function
  59.      * (PDF) of this distribution evaluated at the specified point {@code x}.
  60.      *
  61.      * @param x Point at which the PDF is evaluated.
  62.      * @return the logarithm of the value of the probability density function
  63.      * at {@code x}.
  64.      */
  65.     default double logDensity(double x) {
  66.         return Math.log(density(x));
  67.     }

  68.     /**
  69.      * For a random variable {@code X} whose values are distributed according
  70.      * to this distribution, this method returns {@code P(X <= x)}.
  71.      * In other words, this method represents the (cumulative) distribution
  72.      * function (CDF) for this distribution.
  73.      *
  74.      * @param x Point at which the CDF is evaluated.
  75.      * @return the probability that a random variable with this
  76.      * distribution takes a value less than or equal to {@code x}.
  77.      */
  78.     double cumulativeProbability(double x);

  79.     /**
  80.      * For a random variable {@code X} whose values are distributed according
  81.      * to this distribution, this method returns {@code P(X > x)}.
  82.      * In other words, this method represents the complementary cumulative
  83.      * distribution function.
  84.      *
  85.      * <p>By default, this is defined as {@code 1 - cumulativeProbability(x)}, but
  86.      * the specific implementation may be more accurate.
  87.      *
  88.      * @param x Point at which the survival function is evaluated.
  89.      * @return the probability that a random variable with this
  90.      * distribution takes a value greater than {@code x}.
  91.      */
  92.     default double survivalProbability(double x) {
  93.         return 1.0 - cumulativeProbability(x);
  94.     }

  95.     /**
  96.      * Computes the quantile function of this distribution. For a random
  97.      * variable {@code X} distributed according to this distribution, the
  98.      * returned value is:
  99.      *
  100.      * <p>\[ x = \begin{cases}
  101.      *       \inf \{ x \in \mathbb R : P(X \le x) \ge p\}   &amp; \text{for } 0 \lt p \le 1 \\
  102.      *       \inf \{ x \in \mathbb R : P(X \le x) \gt 0 \}  &amp; \text{for } p = 0
  103.      *       \end{cases} \]
  104.      *
  105.      * @param p Cumulative probability.
  106.      * @return the smallest {@code p}-quantile of this distribution
  107.      * (largest 0-quantile for {@code p = 0}).
  108.      * @throws IllegalArgumentException if {@code p < 0} or {@code p > 1}.
  109.      */
  110.     double inverseCumulativeProbability(double p);

  111.     /**
  112.      * Computes the inverse survival probability function of this distribution. For a random
  113.      * variable {@code X} distributed according to this distribution, the
  114.      * returned value is:
  115.      *
  116.      * <p>\[ x = \begin{cases}
  117.      *       \inf \{ x \in \mathbb R : P(X \gt x) \le p\}   &amp; \text{for } 0 \le p \lt 1 \\
  118.      *       \inf \{ x \in \mathbb R : P(X \gt x) \lt 1 \}  &amp; \text{for } p = 1
  119.      *       \end{cases} \]
  120.      *
  121.      * <p>By default, this is defined as {@code inverseCumulativeProbability(1 - p)}, but
  122.      * the specific implementation may be more accurate.
  123.      *
  124.      * @param p Survival probability.
  125.      * @return the smallest {@code (1-p)}-quantile of this distribution
  126.      * (largest 0-quantile for {@code p = 1}).
  127.      * @throws IllegalArgumentException if {@code p < 0} or {@code p > 1}.
  128.      */
  129.     default double inverseSurvivalProbability(double p) {
  130.         return inverseCumulativeProbability(1 - p);
  131.     }

  132.     /**
  133.      * Gets the mean of this distribution.
  134.      *
  135.      * @return the mean.
  136.      */
  137.     double getMean();

  138.     /**
  139.      * Gets the variance of this distribution.
  140.      *
  141.      * @return the variance.
  142.      */
  143.     double getVariance();

  144.     /**
  145.      * Gets the lower bound of the support.
  146.      * It must return the same value as
  147.      * {@code inverseCumulativeProbability(0)}, i.e.
  148.      * \( \inf \{ x \in \mathbb R : P(X \le x) \gt 0 \} \).
  149.      *
  150.      * @return the lower bound of the support.
  151.      */
  152.     double getSupportLowerBound();

  153.     /**
  154.      * Gets the upper bound of the support.
  155.      * It must return the same
  156.      * value as {@code inverseCumulativeProbability(1)}, i.e.
  157.      * \( \inf \{ x \in \mathbb R : P(X \le x) = 1 \} \).
  158.      *
  159.      * @return the upper bound of the support.
  160.      */
  161.     double getSupportUpperBound();

  162.     /**
  163.      * Creates a sampler.
  164.      *
  165.      * @param rng Generator of uniformly distributed numbers.
  166.      * @return a sampler that produces random numbers according this
  167.      * distribution.
  168.      */
  169.     Sampler createSampler(UniformRandomProvider rng);

  170.     /**
  171.      * Distribution sampling functionality.
  172.      */
  173.     @FunctionalInterface
  174.     interface Sampler {
  175.         /**
  176.          * Generates a random value sampled from this distribution.
  177.          *
  178.          * @return a random value.
  179.          */
  180.         double sample();

  181.         /**
  182.          * Returns an effectively unlimited stream of {@code double} sample values.
  183.          *
  184.          * <p>The default implementation produces a sequential stream that repeatedly
  185.          * calls {@link #sample sample}().
  186.          *
  187.          * @return a stream of {@code double} values.
  188.          */
  189.         default DoubleStream samples() {
  190.             return DoubleStream.generate(this::sample).sequential();
  191.         }

  192.         /**
  193.          * Returns a stream producing the given {@code streamSize} number of {@code double}
  194.          * sample values.
  195.          *
  196.          * <p>The default implementation produces a sequential stream that repeatedly
  197.          * calls {@link #sample sample}(); the stream is limited to the given {@code streamSize}.
  198.          *
  199.          * @param streamSize Number of values to generate.
  200.          * @return a stream of {@code double} values.
  201.          */
  202.         default DoubleStream samples(long streamSize) {
  203.             return samples().limit(streamSize);
  204.         }
  205.     }
  206. }