// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // // Copyright (c) 2009-2016 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 // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // 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 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Linq; using MathNet.Numerics.Distributions; using NUnit.Framework; namespace MathNet.Numerics.UnitTests.DistributionTests.Multivariate { using Random = System.Random; /// /// Dirichlet distribution tests /// [TestFixture, Category("Distributions")] public class DirichletTests { /// /// Set-up test parameters. /// [SetUp] public void SetUp() { Control.CheckDistributionParameters = true; } /// /// Can create symmetric Dirichlet. /// [Test] public void CanCreateSymmetricDirichlet() { var d = new Dirichlet(0.3, 5); for (var i = 0; i < 5; i++) { Assert.AreEqual(0.3, d.Alpha[i]); } } /// /// Can create dirichlet. /// [Test] public void CanCreateDirichlet() { var alpha = new double[10]; for (var i = 0; i < 10; i++) { alpha[i] = i; } var d = new Dirichlet(alpha); for (var i = 0; i < 5; i++) { Assert.AreEqual(i, d.Alpha[i]); } } /// /// Fail create dirichlet with bad parameters. /// [Test] public void FailCreateDirichlet() { Assert.That(() => new Dirichlet(0.0, 5), Throws.ArgumentException); Assert.That(() => new Dirichlet(-0.1, 5), Throws.ArgumentException); } /// /// Has random source. /// [Test] public void HasRandomSource() { var d = new Dirichlet(0.3, 5); Assert.IsNotNull(d.RandomSource); } /// /// Can set random source. /// [Test] public void CanSetRandomSource() { GC.KeepAlive(new Dirichlet(0.3, 5) { RandomSource = new Random(0) }); } [Test] public void HasRandomSourceEvenAfterSetToNull() { var d = new Dirichlet(0.3, 5); Assert.DoesNotThrow(() => d.RandomSource = null); Assert.IsNotNull(d.RandomSource); } /// /// Can get dimension. /// [Test] public void CanGetDimension() { var d = new Dirichlet(0.3, 10); Assert.AreEqual(10, d.Dimension); } /// /// Can get alpha. /// [Test] public void CanGetAlpha() { var d = new Dirichlet(0.3, 10); for (var i = 0; i < 10; i++) { Assert.AreEqual(0.3, d.Alpha[i]); } } /// /// Validate mean. /// [Test] public void ValidateMean() { var d = new Dirichlet(0.3, 5); for (var i = 0; i < 5; i++) { AssertHelpers.AlmostEqualRelative(0.3 / 1.5, d.Mean[i], 15); } } /// /// Validate variance. /// [Test] public void ValidateVariance() { var alpha = new double[10]; var sum = 0.0; for (var i = 0; i < 10; i++) { alpha[i] = i; sum += i; } var d = new Dirichlet(alpha); for (var i = 0; i < 10; i++) { AssertHelpers.AlmostEqualRelative(i * (sum - i) / (sum * sum * (sum + 1.0)), d.Variance[i], 15); } } /// /// Validate density. /// /// Alphas array. /// Expected value. /// /// Mathematica: InputForm[PDF[DirichletDistribution[{0.1, 0.3, 0.5, 0.8}], {0.01, 0.03, 0.5}]] /// [TestCase(new[] { 0.01, 0.03, 0.5 }, 18.77225681167061)] [TestCase(new[] { 0.1, 0.2, 0.3, 0.4 }, 0.8314656481199253)] public void ValidateDensity(double[] x, double res) { var d = new Dirichlet(new[] { 0.1, 0.3, 0.5, 0.8 }); AssertHelpers.AlmostEqualRelative(res, d.Density(x), 12); } /// /// Validate density log. /// /// Alpha array. [TestCase(new[] { 0.01, 0.03, 0.5, 0.5 })] [TestCase(new[] { 0.1, 0.2, 0.3, 0.4 })] public void ValidateDensityLn(double[] x) { var d = new Dirichlet(new[] { 0.1, 0.3, 0.5, 0.8 }); AssertHelpers.AlmostEqualRelative(d.DensityLn(x), Math.Log(d.Density(x)), 12); } /// /// Validate density log matches Beta for 2-dimension cases /// /// Alpha array. [TestCase(0.01)] [TestCase(0.1)] [TestCase(0.4)] [TestCase(0.71)] public void ValidateBetaSpecialCaseDensityLn(double x) { var d = new Dirichlet(new[] { 0.1, 0.3 }); var beta = new Beta(0.1, 0.3); AssertHelpers.AlmostEqualRelative(d.DensityLn(new[] { x }), beta.DensityLn(x), 10); } /// /// Validate entropy. /// /// Alpha array. [TestCase(new[] { 0.1, 0.3, 0.5, 0.8 })] [TestCase(new[] { 0.1, 0.2, 0.3, 0.4 })] public void ValidateEntropy(double[] x) { var d = new Dirichlet(x); var sum = x.Sum(t => (t - 1) * SpecialFunctions.DiGamma(t)); var res = SpecialFunctions.GammaLn(x.Sum()) + ((x.Sum() - x.Length) * SpecialFunctions.DiGamma(x.Sum())) - sum; AssertHelpers.AlmostEqualRelative(res, d.Entropy, 12); } /// /// Can sample symmetric dirichlet. /// [Test] public void CanSampleSymmetricDirichlet() { var d = new Dirichlet(1.0, 5); d.Sample(); } /// /// Can sample singular dirichlet. /// [Test] public void CanSampleSingularDirichlet() { var d = new Dirichlet(new[] { 2.0, 1.0, 0.0, 3.0 }); d.Sample(); } } }