diff --git a/src/Numerics/Distributions/Rayleigh.cs b/src/Numerics/Distributions/Rayleigh.cs index dd85730a..46ed2459 100644 --- a/src/Numerics/Distributions/Rayleigh.cs +++ b/src/Numerics/Distributions/Rayleigh.cs @@ -85,16 +85,6 @@ namespace MathNet.Numerics.Distributions return "Rayleigh(σ = " + _scale + ")"; } - /// - /// Checks whether the parameters of the distribution are valid. - /// - /// The scale (σ) of the distribution. Range: σ > 0. - /// true when the parameters are valid, false otherwise. - static bool IsValidParameterSet(double scale) - { - return scale > 0.0; - } - /// /// Sets the parameters of the distribution after checking their validity. /// @@ -102,7 +92,7 @@ namespace MathNet.Numerics.Distributions /// When the parameters are out of range. void SetParameters(double scale) { - if (Control.CheckDistributionParameters && !IsValidParameterSet(scale)) + if (scale <= 0.0 || Double.IsNaN(scale)) { throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters); } @@ -205,6 +195,7 @@ namespace MathNet.Numerics.Distributions /// /// The location at which to compute the density. /// the density at . + /// public double Density(double x) { return (x/(_scale*_scale))*Math.Exp(-x*x/(2.0*_scale*_scale)); @@ -215,6 +206,7 @@ namespace MathNet.Numerics.Distributions /// /// The location at which to compute the log density. /// the log density at . + /// public double DensityLn(double x) { return Math.Log(x/(_scale*_scale)) - (x*x/(2.0*_scale*_scale)); @@ -225,20 +217,22 @@ namespace MathNet.Numerics.Distributions /// /// The location at which to compute the cumulative distribution function. /// the cumulative distribution at location . + /// public double CumulativeDistribution(double x) { return 1.0 - Math.Exp(-x*x/(2.0*_scale*_scale)); } /// - /// Generates a sample from the Rayleigh distribution without doing parameter checking. + /// 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 random number generator to use. - /// The scale (σ) of the distribution. Range: σ > 0. - /// a random number from the Rayleigh distribution. - static double SampleUnchecked(System.Random rnd, double scale) + /// The location at which to compute the inverse cumulative density. + /// the inverse cumulative density at . + /// + public double InverseCumulativeDistribution(double p) { - return scale*Math.Sqrt(-2.0*Math.Log(rnd.NextDouble())); + return _scale*Math.Sqrt(-2*Math.Log(1 - p)); } /// @@ -247,7 +241,7 @@ namespace MathNet.Numerics.Distributions /// A random number from this distribution. public double Sample() { - return SampleUnchecked(_random, _scale); + return _scale*Math.Sqrt(-2.0*Math.Log(_random.NextDouble())); } /// @@ -258,10 +252,67 @@ namespace MathNet.Numerics.Distributions { while (true) { - yield return SampleUnchecked(_random, _scale); + yield return _scale*Math.Sqrt(-2.0*Math.Log(_random.NextDouble())); } } + /// + /// Computes the probability density of the distribution (PDF) at x, i.e. ∂P(X ≤ x)/∂x. + /// + /// The scale (σ) of the distribution. Range: σ > 0. + /// The location at which to compute the density. + /// the density at . + /// + public static double PDF(double scale, double x) + { + if (scale <= 0.0) throw new ArgumentOutOfRangeException("scale", Resources.InvalidDistributionParameters); + + return (x/(scale*scale))*Math.Exp(-x*x/(2.0*scale*scale)); + } + + /// + /// Computes the log probability density of the distribution (lnPDF) at x, i.e. ln(∂P(X ≤ x)/∂x). + /// + /// The scale (σ) of the distribution. Range: σ > 0. + /// The location at which to compute the density. + /// the log density at . + /// + public static double PDFLn(double scale, double x) + { + if (scale <= 0.0) throw new ArgumentOutOfRangeException("scale", Resources.InvalidDistributionParameters); + + return Math.Log(x/(scale*scale)) - (x*x/(2.0*scale*scale)); + } + + /// + /// Computes the cumulative distribution (CDF) of the distribution at x, i.e. P(X ≤ x). + /// + /// The location at which to compute the cumulative distribution function. + /// The scale (σ) of the distribution. Range: σ > 0. + /// the cumulative distribution at location . + /// + public static double CDF(double scale, double x) + { + if (scale <= 0.0) throw new ArgumentOutOfRangeException("scale", Resources.InvalidDistributionParameters); + + return 1.0 - Math.Exp(-x*x/(2.0*scale*scale)); + } + + /// + /// 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 scale (σ) of the distribution. Range: σ > 0. + /// the inverse cumulative density at . + /// + public static double InvCDF(double scale, double p) + { + if (scale <= 0.0) throw new ArgumentOutOfRangeException("scale", Resources.InvalidDistributionParameters); + + return scale*Math.Sqrt(-2*Math.Log(1 - p)); + } + /// /// Generates a sample from the distribution. /// @@ -270,12 +321,9 @@ namespace MathNet.Numerics.Distributions /// a sample from the distribution. public static double Sample(System.Random rnd, double scale) { - if (Control.CheckDistributionParameters && !IsValidParameterSet(scale)) - { - throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters); - } + if (scale <= 0.0) throw new ArgumentOutOfRangeException("scale", Resources.InvalidDistributionParameters); - return SampleUnchecked(rnd, scale); + return scale*Math.Sqrt(-2.0*Math.Log(rnd.NextDouble())); } /// @@ -286,14 +334,11 @@ namespace MathNet.Numerics.Distributions /// a sequence of samples from the distribution. public static IEnumerable Samples(System.Random rnd, double scale) { - if (Control.CheckDistributionParameters && !IsValidParameterSet(scale)) - { - throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters); - } + if (scale <= 0.0) throw new ArgumentOutOfRangeException("scale", Resources.InvalidDistributionParameters); while (true) { - yield return SampleUnchecked(rnd, scale); + yield return scale*Math.Sqrt(-2.0*Math.Log(rnd.NextDouble())); } } } diff --git a/src/UnitTests/DistributionTests/Continuous/RayleighTests.cs b/src/UnitTests/DistributionTests/Continuous/RayleighTests.cs index f37d01d5..6a87b93c 100644 --- a/src/UnitTests/DistributionTests/Continuous/RayleighTests.cs +++ b/src/UnitTests/DistributionTests/Continuous/RayleighTests.cs @@ -241,11 +241,6 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous Assert.AreEqual(Double.PositiveInfinity, n.Maximum); } - /// - /// Validate density. - /// - /// Scale value. - /// Input X value. [TestCase(0.1, 0.1)] [TestCase(1.0, 1.0)] [TestCase(10.0, 10.0)] @@ -253,14 +248,11 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous public void ValidateDensity(double scale, double x) { var n = new Rayleigh(scale); - Assert.AreEqual((x / (scale * scale)) * Math.Exp(-x * x / (2.0 * scale * scale)), n.Density(x)); + double expected = (x/(scale*scale))*Math.Exp(-x*x/(2.0*scale*scale)); + Assert.AreEqual(expected, n.Density(x)); + Assert.AreEqual(expected, Rayleigh.PDF(scale, x)); } - /// - /// Validate density log. - /// - /// Scale value. - /// Input X value. [TestCase(0.1, 0.1)] [TestCase(1.0, 1.0)] [TestCase(10.0, 10.0)] @@ -268,7 +260,20 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous public void ValidateDensityLn(double scale, double x) { var n = new Rayleigh(scale); - Assert.AreEqual(Math.Log(x / (scale * scale)) - (x * (x / (2.0 * (scale * scale)))), n.DensityLn(x)); + double expected = Math.Log(x/(scale*scale)) - (x*(x/(2.0*(scale*scale)))); + Assert.AreEqual(expected, n.DensityLn(x)); + Assert.AreEqual(expected, Rayleigh.PDFLn(scale, x)); + } + + [TestCase(0.1, 0.1)] + [TestCase(1.0, 1.0)] + [TestCase(10.0, 10.0)] + public void ValidateInverseCumulativeDistribution(double scale, double x) + { + var n = new Rayleigh(scale); + double cdf = 1.0 - Math.Exp(-x*x/(2.0*scale*scale)); + Assert.AreEqual(x, n.InverseCumulativeDistribution(cdf)); + Assert.AreEqual(x, Rayleigh.InvCDF(scale, cdf)); } /// @@ -291,20 +296,5 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous var ied = n.Samples(); ied.Take(5).ToArray(); } - - /// - /// Validate cumulative distribution. - /// - /// Scale value. - /// Input X value. - [TestCase(0.1, 0.1)] - [TestCase(1.0, 1.0)] - [TestCase(10.0, 10.0)] - [TestCase(Double.PositiveInfinity, Double.PositiveInfinity)] - public void ValidateCumulativeDistribution(double scale, double x) - { - var n = new Rayleigh(scale); - Assert.AreEqual(1.0 - Math.Exp(-x * x / (2.0 * scale * scale)), n.CumulativeDistribution(x)); - } } }