From 1d3aa6734d0dd6ffff00c72c6bf1983c343f8e1d Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Sat, 4 Jan 2014 21:28:04 +0100 Subject: [PATCH] Distributions: Beta.InvCDF --- src/Numerics/Distributions/Beta.cs | 33 ++++++++++++++++++- .../DistributionTests/Continuous/BetaTests.cs | 27 ++++++++------- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/Numerics/Distributions/Beta.cs b/src/Numerics/Distributions/Beta.cs index 38a4cd50..d7fa9013 100644 --- a/src/Numerics/Distributions/Beta.cs +++ b/src/Numerics/Distributions/Beta.cs @@ -32,6 +32,7 @@ using System; using System.Collections.Generic; using MathNet.Numerics.Properties; using MathNet.Numerics.Random; +using MathNet.Numerics.RootFinding; namespace MathNet.Numerics.Distributions { @@ -326,6 +327,19 @@ namespace MathNet.Numerics.Distributions return CDF(_shapeA, _shapeB, x); } + /// + /// Computes the inverse of the cumulative distribution function (InvCDF) for the distribution + /// at the given probability. This is also known as the quantile or percent point function. + /// + /// The location at which to compute the inverse cumulative density. + /// the inverse cumulative density at . + /// + /// WARNING: currently not an explicit implementation, hence slow and unreliable. + public double InverseCumulativeDistribution(double p) + { + return InvCDF(_shapeA, _shapeB, p); + } + /// /// Generates a sample from the Beta distribution. /// @@ -458,7 +472,7 @@ namespace MathNet.Numerics.Distributions /// /// The location at which to compute the cumulative distribution function. /// The α shape parameter of the Beta distribution. Range: α ≥ 0. - /// The β shape parameter of the Beta distribution. Range: β ≥ 0.> + /// The β shape parameter of the Beta distribution. Range: β ≥ 0. /// the cumulative distribution at location . /// public static double CDF(double a, double b, double x) @@ -500,6 +514,23 @@ namespace MathNet.Numerics.Distributions return SpecialFunctions.BetaRegularized(a, b, x); } + /// + /// Computes the inverse of the cumulative distribution function (InvCDF) for the distribution + /// at the given probability. This is also known as the quantile or percent point function. + /// + /// The location at which to compute the inverse cumulative density. + /// The α shape parameter of the Beta distribution. Range: α ≥ 0. + /// The β shape parameter of the Beta distribution. Range: β ≥ 0. + /// the inverse cumulative density at . + /// + /// WARNING: currently not an explicit implementation, hence slow and unreliable. + public static double InvCDF(double a, double b, double p) + { + if (a < 0.0 || b < 0.0 || p < 0.0 || p > 1.0) throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters); + + return Brent.FindRoot(x => SpecialFunctions.BetaRegularized(a, b, x) - p, 0.0, 1.0, accuracy: 1e-8); + } + /// /// Generates a sample from the distribution. /// diff --git a/src/UnitTests/DistributionTests/Continuous/BetaTests.cs b/src/UnitTests/DistributionTests/Continuous/BetaTests.cs index 3e129758..e914b7a8 100644 --- a/src/UnitTests/DistributionTests/Continuous/BetaTests.cs +++ b/src/UnitTests/DistributionTests/Continuous/BetaTests.cs @@ -418,13 +418,6 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous AssertHelpers.AlmostEqualRelative(pdfln, Beta.PDFLn(a, b, x), 13); } - /// - /// Validate cumulative distribution. - /// - /// Parameter A. - /// Parameter B. - /// Input value X. - /// Cumulative distribution value. [TestCase(0.0, 0.0, 0.0, 0.5)] [TestCase(0.0, 0.0, 0.5, 0.5)] [TestCase(0.0, 0.0, 1.0, 1.0)] @@ -455,11 +448,23 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous [TestCase(Double.PositiveInfinity, 0.0, 0.0, 0.0)] [TestCase(Double.PositiveInfinity, 0.0, 0.5, 0.0)] [TestCase(Double.PositiveInfinity, 0.0, 1.0, 1.0)] - public void ValidateCumulativeDistribution(double a, double b, double x, double cdf) + public void ValidateCumulativeDistribution(double a, double b, double x, double p) { - var n = new Beta(a, b); - AssertHelpers.AlmostEqualRelative(cdf, n.CumulativeDistribution(x), 13); - AssertHelpers.AlmostEqualRelative(cdf, Beta.CDF(a, b, x), 13); + var dist = new Beta(a, b); + Assert.That(dist.CumulativeDistribution(x), Is.EqualTo(p).Within(1e-13)); + Assert.That(Beta.CDF(a, b, x), Is.EqualTo(p).Within(1e-13)); + } + + [TestCase(1.0, 1.0, 1.0, 1.0)] + [TestCase(9.0, 1.0, 0.0, 0.0)] + [TestCase(9.0, 1.0, 0.5, 0.001953125)] + [TestCase(9.0, 1.0, 1.0, 1.0)] + [TestCase(5.0, 100, 0.0, 0.0)] + public void ValidateInverseCumulativeDistribution(double a, double b, double x, double p) + { + var dist = new Beta(a, b); + Assert.That(dist.InverseCumulativeDistribution(p), Is.EqualTo(x).Within(1e-6)); + Assert.That(Beta.InvCDF(a, b, p), Is.EqualTo(x).Within(1e-6)); } } }