diff --git a/src/Numerics/Distributions/Chi.cs b/src/Numerics/Distributions/Chi.cs index d9e98f0d..14c4d586 100644 --- a/src/Numerics/Distributions/Chi.cs +++ b/src/Numerics/Distributions/Chi.cs @@ -82,16 +82,6 @@ namespace MathNet.Numerics.Distributions return "Chi(k = " + _freedom + ")"; } - /// - /// Checks whether the parameters of the distribution are valid. - /// - /// The degrees of freedom (k) of the distribution. Range: k > 0. - /// true when the parameters are valid, false otherwise. - static bool IsValidParameterSet(double freedom) - { - return freedom > 0.0; - } - /// /// Sets the parameters of the distribution after checking their validity. /// @@ -99,7 +89,7 @@ namespace MathNet.Numerics.Distributions /// When the parameters are out of range. void SetParameters(double freedom) { - if (Control.CheckDistributionParameters && !IsValidParameterSet(freedom)) + if (freedom <= 0.0 || Double.IsNaN(freedom)) { throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters); } @@ -214,6 +204,7 @@ namespace MathNet.Numerics.Distributions /// /// The location at which to compute the density. /// the density at . + /// public double Density(double x) { return (Math.Pow(2.0, 1.0 - (_freedom/2.0))*Math.Pow(x, _freedom - 1.0)*Math.Exp(-x*x/2.0))/SpecialFunctions.Gamma(_freedom/2.0); @@ -224,6 +215,7 @@ namespace MathNet.Numerics.Distributions /// /// The location at which to compute the log density. /// the log density at . + /// public double DensityLn(double x) { return ((1.0 - (_freedom/2.0))*Math.Log(2.0)) + ((_freedom - 1.0)*Math.Log(x)) - (x*x/2.0) - SpecialFunctions.GammaLn(_freedom/2.0); @@ -234,11 +226,34 @@ 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 SpecialFunctions.GammaLowerIncomplete(_freedom/2.0, x*x/2.0)/SpecialFunctions.Gamma(_freedom/2.0); } + /// + /// Generates a sample from the Chi distribution. + /// + /// a sample from the distribution. + public double Sample() + { + return SampleUnchecked(_random, (int) _freedom); + } + + /// + /// Generates a sequence of samples from the Chi distribution. + /// + /// a sequence of samples from the distribution. + public IEnumerable Samples() + { + var freedom = (int)_freedom; + while (true) + { + yield return SampleUnchecked(_random, freedom); + } + } + /// /// Samples the distribution. /// @@ -257,25 +272,45 @@ namespace MathNet.Numerics.Distributions } /// - /// Generates a sample from the Chi distribution. + /// Computes the probability density of the distribution (PDF) at x, i.e. ∂P(X ≤ x)/∂x. /// - /// a sample from the distribution. - public double Sample() + /// The degrees of freedom (k) of the distribution. Range: k > 0. + /// The location at which to compute the density. + /// the density at . + /// + public static double PDF(double freedom, double x) { - return SampleUnchecked(_random, (int) _freedom); + if (freedom <= 0.0) throw new ArgumentOutOfRangeException("freedom", Resources.InvalidDistributionParameters); + + return (Math.Pow(2.0, 1.0 - (freedom/2.0))*Math.Pow(x, freedom - 1.0)*Math.Exp(-x*x/2.0))/SpecialFunctions.Gamma(freedom/2.0); } /// - /// Generates a sequence of samples from the Chi distribution. + /// Computes the log probability density of the distribution (lnPDF) at x, i.e. ln(∂P(X ≤ x)/∂x). /// - /// a sequence of samples from the distribution. - public IEnumerable Samples() + /// The degrees of freedom (k) of the distribution. Range: k > 0. + /// The location at which to compute the density. + /// the log density at . + /// + public static double PDFLn(double freedom, double x) { - var freedom = (int)_freedom; - while (true) - { - yield return SampleUnchecked(_random, freedom); - } + if (freedom <= 0.0) throw new ArgumentOutOfRangeException("freedom", Resources.InvalidDistributionParameters); + + return ((1.0 - (freedom/2.0))*Math.Log(2.0)) + ((freedom - 1.0)*Math.Log(x)) - (x*x/2.0) - SpecialFunctions.GammaLn(freedom/2.0); + } + + /// + /// 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 degrees of freedom (k) of the distribution. Range: k > 0. + /// the cumulative distribution at location . + /// + public static double CDF(double freedom, double x) + { + if (freedom <= 0.0) throw new ArgumentOutOfRangeException("freedom", Resources.InvalidDistributionParameters); + + return SpecialFunctions.GammaLowerIncomplete(freedom/2.0, x*x/2.0)/SpecialFunctions.Gamma(freedom/2.0); } /// @@ -286,10 +321,7 @@ namespace MathNet.Numerics.Distributions /// a sample from the distribution. public static double Sample(System.Random rnd, int freedom) { - if (Control.CheckDistributionParameters && !IsValidParameterSet(freedom)) - { - throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters); - } + if (freedom <= 0) throw new ArgumentOutOfRangeException("freedom", Resources.InvalidDistributionParameters); return SampleUnchecked(rnd, freedom); } @@ -302,10 +334,7 @@ namespace MathNet.Numerics.Distributions /// a sequence of samples from the distribution. public static IEnumerable Samples(System.Random rnd, int freedom) { - if (Control.CheckDistributionParameters && !IsValidParameterSet(freedom)) - { - throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters); - } + if (freedom <= 0) throw new ArgumentOutOfRangeException("freedom", Resources.InvalidDistributionParameters); while (true) { diff --git a/src/Numerics/Distributions/ChiSquared.cs b/src/Numerics/Distributions/ChiSquared.cs index 718937a1..07e69eb0 100644 --- a/src/Numerics/Distributions/ChiSquared.cs +++ b/src/Numerics/Distributions/ChiSquared.cs @@ -80,16 +80,6 @@ namespace MathNet.Numerics.Distributions return "ChiSquared(k = " + _freedom + ")"; } - /// - /// Checks whether the parameters of the distribution are valid. - /// - /// The degrees of freedom (k) of the distribution. Range: k > 0. - /// true when the parameters are valid, false otherwise. - static bool IsValidParameterSet(double freedom) - { - return freedom > 0; - } - /// /// Sets the parameters of the distribution after checking their validity. /// @@ -97,7 +87,7 @@ namespace MathNet.Numerics.Distributions /// When the parameters are out of range. void SetParameters(double freedom) { - if (Control.CheckDistributionParameters && !IsValidParameterSet(freedom)) + if (freedom <= 0.0 || Double.IsNaN(freedom)) { throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters); } @@ -200,9 +190,10 @@ namespace MathNet.Numerics.Distributions /// /// The location at which to compute the density. /// the density at . + /// public double Density(double x) { - return (Math.Pow(x, (_freedom / 2.0) - 1.0) * Math.Exp(-x / 2.0)) / (Math.Pow(2.0, _freedom / 2.0) * SpecialFunctions.Gamma(_freedom / 2.0)); + return (Math.Pow(x, (_freedom/2.0) - 1.0)*Math.Exp(-x/2.0))/(Math.Pow(2.0, _freedom/2.0)*SpecialFunctions.Gamma(_freedom/2.0)); } /// @@ -210,9 +201,10 @@ namespace MathNet.Numerics.Distributions /// /// The location at which to compute the log density. /// the log density at . + /// public double DensityLn(double x) { - return (-x / 2.0) + (((_freedom / 2.0) - 1.0) * Math.Log(x)) - ((_freedom / 2.0) * Math.Log(2)) - SpecialFunctions.GammaLn(_freedom / 2.0); + return (-x/2.0) + (((_freedom/2.0) - 1.0)*Math.Log(x)) - ((_freedom/2.0)*Math.Log(2)) - SpecialFunctions.GammaLn(_freedom/2.0); } /// @@ -220,9 +212,31 @@ 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 SpecialFunctions.GammaLowerIncomplete(_freedom / 2.0, x / 2.0) / SpecialFunctions.Gamma(_freedom / 2.0); + return SpecialFunctions.GammaLowerIncomplete(_freedom/2.0, x/2.0)/SpecialFunctions.Gamma(_freedom/2.0); + } + + /// + /// Generates a sample from the ChiSquare distribution. + /// + /// a sample from the distribution. + public double Sample() + { + return SampleUnchecked(_random, _freedom); + } + + /// + /// Generates a sequence of samples from the ChiSquare distribution. + /// + /// a sequence of samples from the distribution. + public IEnumerable Samples() + { + while (true) + { + yield return SampleUnchecked(_random, _freedom); + } } /// @@ -237,7 +251,7 @@ namespace MathNet.Numerics.Distributions if (Math.Floor(freedom) == freedom && freedom < Int32.MaxValue) { double sum = 0; - var n = (int) freedom; + var n = (int)freedom; for (var i = 0; i < n; i++) { sum += Math.Pow(Normal.Sample(rnd, 0.0, 1.0), 2); @@ -247,28 +261,49 @@ namespace MathNet.Numerics.Distributions //Call the gamma function (see http://en.wikipedia.org/wiki/Gamma_distribution#Specializations //for a justification) - return Gamma.SampleUnchecked(rnd, freedom/2.0, .5); + return Gamma.SampleUnchecked(rnd, freedom / 2.0, .5); } /// - /// Generates a sample from the ChiSquare distribution. + /// Computes the probability density of the distribution (PDF) at x, i.e. ∂P(X ≤ x)/∂x. /// - /// a sample from the distribution. - public double Sample() + /// The degrees of freedom (k) of the distribution. Range: k > 0. + /// The location at which to compute the density. + /// the density at . + /// + public static double PDF(double freedom, double x) { - return SampleUnchecked(_random, _freedom); + if (freedom <= 0.0) throw new ArgumentOutOfRangeException("freedom", Resources.InvalidDistributionParameters); + + return (Math.Pow(x, (freedom/2.0) - 1.0)*Math.Exp(-x/2.0))/(Math.Pow(2.0, freedom/2.0)*SpecialFunctions.Gamma(freedom/2.0)); } /// - /// Generates a sequence of samples from the ChiSquare distribution. + /// Computes the log probability density of the distribution (lnPDF) at x, i.e. ln(∂P(X ≤ x)/∂x). /// - /// a sequence of samples from the distribution. - public IEnumerable Samples() + /// The degrees of freedom (k) of the distribution. Range: k > 0. + /// The location at which to compute the density. + /// the log density at . + /// + public static double PDFLn(double freedom, double x) { - while (true) - { - yield return SampleUnchecked(_random, _freedom); - } + if (freedom <= 0.0) throw new ArgumentOutOfRangeException("freedom", Resources.InvalidDistributionParameters); + + return (-x/2.0) + (((freedom/2.0) - 1.0)*Math.Log(x)) - ((freedom/2.0)*Math.Log(2)) - SpecialFunctions.GammaLn(freedom/2.0); + } + + /// + /// 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 degrees of freedom (k) of the distribution. Range: k > 0. + /// the cumulative distribution at location . + /// + public static double CDF(double freedom, double x) + { + if (freedom <= 0.0) throw new ArgumentOutOfRangeException("freedom", Resources.InvalidDistributionParameters); + + return SpecialFunctions.GammaLowerIncomplete(freedom/2.0, x/2.0)/SpecialFunctions.Gamma(freedom/2.0); } /// @@ -279,10 +314,7 @@ namespace MathNet.Numerics.Distributions /// a sample from the distribution. public static double Sample(System.Random rnd, double freedom) { - if (Control.CheckDistributionParameters && !IsValidParameterSet(freedom)) - { - throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters); - } + if (freedom <= 0.0) throw new ArgumentOutOfRangeException("freedom", Resources.InvalidDistributionParameters); return SampleUnchecked(rnd, freedom); } @@ -295,10 +327,7 @@ namespace MathNet.Numerics.Distributions /// a sample from the distribution. public static IEnumerable Samples(System.Random rnd, double freedom) { - if (Control.CheckDistributionParameters && !IsValidParameterSet(freedom)) - { - throw new ArgumentOutOfRangeException(Resources.InvalidDistributionParameters); - } + if (freedom <= 0.0) throw new ArgumentOutOfRangeException("freedom", Resources.InvalidDistributionParameters); while (true) { diff --git a/src/UnitTests/DistributionTests/Continuous/ChiSquareTests.cs b/src/UnitTests/DistributionTests/Continuous/ChiSquareTests.cs index 416530e8..a0d9c8de 100644 --- a/src/UnitTests/DistributionTests/Continuous/ChiSquareTests.cs +++ b/src/UnitTests/DistributionTests/Continuous/ChiSquareTests.cs @@ -241,7 +241,9 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous public void ValidateDensity(double dof, double x) { var n = new ChiSquared(dof); - Assert.AreEqual((Math.Pow(x, (dof / 2.0) - 1.0) * Math.Exp(-x / 2.0)) / (Math.Pow(2.0, dof / 2.0) * SpecialFunctions.Gamma(dof / 2.0)), n.Density(x)); + double expected = (Math.Pow(x, (dof / 2.0) - 1.0) * Math.Exp(-x / 2.0)) / (Math.Pow(2.0, dof / 2.0) * SpecialFunctions.Gamma(dof / 2.0)); + Assert.AreEqual(expected, n.Density(x)); + Assert.AreEqual(expected, ChiSquared.PDF(dof, x)); } /// @@ -276,7 +278,9 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous public void ValidateDensityLn(double dof, double x) { var n = new ChiSquared(dof); - Assert.AreEqual((-x / 2.0) + (((dof / 2.0) - 1.0) * Math.Log(x)) - ((dof / 2.0) * Math.Log(2)) - SpecialFunctions.GammaLn(dof / 2.0), n.DensityLn(x)); + double expected = (-x / 2.0) + (((dof / 2.0) - 1.0) * Math.Log(x)) - ((dof / 2.0) * Math.Log(2)) - SpecialFunctions.GammaLn(dof / 2.0); + Assert.AreEqual(expected, n.DensityLn(x)); + Assert.AreEqual(expected, ChiSquared.PDFLn(dof, x)); } /// @@ -350,7 +354,9 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous public void ValidateCumulativeDistribution(double dof, double x) { var n = new ChiSquared(dof); - Assert.AreEqual(SpecialFunctions.GammaLowerIncomplete(dof / 2.0, x / 2.0) / SpecialFunctions.Gamma(dof / 2.0), n.CumulativeDistribution(x)); + double expected = SpecialFunctions.GammaLowerIncomplete(dof / 2.0, x / 2.0) / SpecialFunctions.Gamma(dof / 2.0); + Assert.AreEqual(expected, n.CumulativeDistribution(x)); + Assert.AreEqual(expected, ChiSquared.CDF(dof, x)); } } } diff --git a/src/UnitTests/DistributionTests/Continuous/ChiTests.cs b/src/UnitTests/DistributionTests/Continuous/ChiTests.cs index 47b42ca9..7d916412 100644 --- a/src/UnitTests/DistributionTests/Continuous/ChiTests.cs +++ b/src/UnitTests/DistributionTests/Continuous/ChiTests.cs @@ -3,7 +3,9 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com -// Copyright (c) 2009-2010 Math.NET +// +// Copyright (c) 2009-2013 Math.NET +// // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -12,8 +14,10 @@ // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -237,7 +241,9 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous public void ValidateDensity(double dof, double x) { var n = new Chi(dof); - Assert.AreEqual((Math.Pow(2.0, 1.0 - (dof / 2.0)) * Math.Pow(x, dof - 1.0) * Math.Exp(-x * (x / 2.0))) / SpecialFunctions.Gamma(dof / 2.0), n.Density(x)); + double expected = (Math.Pow(2.0, 1.0 - (dof / 2.0)) * Math.Pow(x, dof - 1.0) * Math.Exp(-x * (x / 2.0))) / SpecialFunctions.Gamma(dof / 2.0); + Assert.AreEqual(expected, n.Density(x)); + Assert.AreEqual(expected, Chi.PDF(dof, x)); } /// @@ -272,7 +278,9 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous public void ValidateDensityLn(double dof, double x) { var n = new Chi(dof); - Assert.AreEqual(((1.0 - (dof / 2.0)) * Math.Log(2.0)) + ((dof - 1.0) * Math.Log(x)) - (x * (x / 2.0)) - SpecialFunctions.GammaLn(dof / 2.0), n.DensityLn(x)); + double expected = ((1.0 - (dof / 2.0)) * Math.Log(2.0)) + ((dof - 1.0) * Math.Log(x)) - (x * (x / 2.0)) - SpecialFunctions.GammaLn(dof / 2.0); + Assert.AreEqual(expected, n.DensityLn(x)); + Assert.AreEqual(expected, Chi.PDFLn(dof, x)); } /// @@ -328,7 +336,9 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Continuous public void ValidateCumulativeDistribution(double dof, double x) { var n = new Chi(dof); - Assert.AreEqual(SpecialFunctions.GammaLowerIncomplete(dof / 2.0, x * x / 2.0) / SpecialFunctions.Gamma(dof / 2.0), n.CumulativeDistribution(x)); + double expected = SpecialFunctions.GammaLowerIncomplete(dof / 2.0, x * x / 2.0) / SpecialFunctions.Gamma(dof / 2.0); + Assert.AreEqual(expected, n.CumulativeDistribution(x)); + Assert.AreEqual(expected, Chi.CDF(dof, x)); } } }