public void ConstructorTest1()
        {

            NormalDistribution normal = new NormalDistribution(4.2, 1.2);
            MultivariateNormalDistribution target = new MultivariateNormalDistribution(new[] { 4.2 }, new[,] { { 1.2 * 1.2 } });

            double[] mean = target.Mean;
            double[] median = target.Median;
            double[] var = target.Variance;
            double[,] cov = target.Covariance;

            double apdf1 = target.ProbabilityDensityFunction(new double[] { 2 });
            double apdf2 = target.ProbabilityDensityFunction(new double[] { 4 });
            double apdf3 = target.ProbabilityDensityFunction(new double[] { 3 });
            double alpdf = target.LogProbabilityDensityFunction(new double[] { 3 });
            double acdf = target.DistributionFunction(new double[] { 3 });
            double accdf = target.ComplementaryDistributionFunction(new double[] { 3 });

            double epdf1 = target.ProbabilityDensityFunction(new double[] { 2 });
            double epdf2 = target.ProbabilityDensityFunction(new double[] { 4 });
            double epdf3 = target.ProbabilityDensityFunction(new double[] { 3 });
            double elpdf = target.LogProbabilityDensityFunction(new double[] { 3 });
            double ecdf = target.DistributionFunction(new double[] { 3 });
            double eccdf = target.ComplementaryDistributionFunction(new double[] { 3 });


            Assert.AreEqual(normal.Mean, target.Mean[0]);
            Assert.AreEqual(normal.Median, target.Median[0]);
            Assert.AreEqual(normal.Variance, target.Variance[0]);
            Assert.AreEqual(normal.Variance, target.Covariance[0, 0]);

            Assert.AreEqual(epdf1, apdf1);
            Assert.AreEqual(epdf2, apdf2);
            Assert.AreEqual(epdf3, apdf3);
            Assert.AreEqual(elpdf, alpdf);
            Assert.AreEqual(ecdf, acdf);
            Assert.AreEqual(eccdf, accdf);
            Assert.AreEqual(1.0 - ecdf, eccdf);
        }
        public void ConstructorTest4()
        {
            // Create a multivariate Gaussian distribution 
            var dist = new MultivariateNormalDistribution
            (
                // mean vector mu
                mean: new double[] { 4, 2 },

                // covariance matrix sigma
                covariance: new double[,] 
                {
                    { 0.3, 0.1 },
                    { 0.1, 0.7 }
                }
            );

            // Common measures
            double[] mean = dist.Mean;       // { 4, 2 }
            double[] median = dist.Median;   // { 4, 2 }
            double[] mode = dist.Mode;       // { 4, 2 }
            double[,] cov = dist.Covariance; // { { 0.3, 0.1 }, { 0.1, 0.7 } }
            double[] var = dist.Variance;    // { 0.3, 0.7 } (diagonal from cov)
            int dimensions = dist.Dimension; // 2

            // Probability density functions
            double pdf1 = dist.ProbabilityDensityFunction(2, 5);    // 0.000000018917884164743237
            double pdf2 = dist.ProbabilityDensityFunction(4, 2);    // 0.35588127170858852
            double pdf3 = dist.ProbabilityDensityFunction(3, 7);    // 0.000000000036520107734505265
            double lpdf = dist.LogProbabilityDensityFunction(3, 7); // -24.033158110192296

            // Cumulative distribution function (for up to two dimensions)
            double cdf = dist.DistributionFunction(3, 5); // 0.033944035782101534
            double ccdf = dist.ComplementaryDistributionFunction(3, 5); // 0.00016755510356109232


            // compared against R package mnormt: install.packages("mnormt")
            // pmnorm(c(3,5), mean=c(4,2), varcov=matrix(c(0.3,0.1,0.1,0.7), 2,2))


            Assert.AreEqual(4, mean[0]);
            Assert.AreEqual(2, mean[1]);
            Assert.AreEqual(4, mode[0]);
            Assert.AreEqual(2, mode[1]);
            Assert.AreEqual(4, median[0]);
            Assert.AreEqual(2, median[1]);
            Assert.AreEqual(0.3, var[0]);
            Assert.AreEqual(0.7, var[1]);
            Assert.AreEqual(0.3, cov[0, 0]);
            Assert.AreEqual(0.1, cov[0, 1]);
            Assert.AreEqual(0.1, cov[1, 0]);
            Assert.AreEqual(0.7, cov[1, 1]);
            Assert.AreEqual(0.000000018917884164743237, pdf1);
            Assert.AreEqual(0.35588127170858852, pdf2);
            Assert.AreEqual(0.000000000036520107734505265, pdf3);
            Assert.AreEqual(-24.033158110192296, lpdf);
            Assert.AreEqual(0.033944035782101534, cdf);
        }
        private static void checkDegenerate(MultivariateNormalDistribution target)
        {
            Assert.AreEqual(1, target.Mean[0]);
            Assert.AreEqual(2, target.Mean[1]);
            Assert.AreEqual(0, target.Covariance[0, 0]);
            Assert.AreEqual(0, target.Covariance[0, 1]);
            Assert.AreEqual(0, target.Covariance[1, 0]);
            Assert.AreEqual(0, target.Covariance[1, 1]);


            // Common measures
            double[] mean = target.Mean; // { 1, 2 }
            double[] median = target.Median; // { 4, 2 }
            double[] var = target.Variance; // { 0.0, 0.0 } (diagonal from cov)
            double[,] cov = target.Covariance; // { { 0.0, 0.0 }, { 0.0, 0.0 } }

            // Probability mass functions
            double pdf1 = target.ProbabilityDensityFunction(new double[] { 1, 2 });
            double pdf2 = target.ProbabilityDensityFunction(new double[] { 4, 2 });
            double pdf3 = target.ProbabilityDensityFunction(new double[] { 3, 7 });
            double lpdf = target.LogProbabilityDensityFunction(new double[] { 3, 7 });

            // Cumulative distribution function (for up to two dimensions)
            double cdf1 = target.DistributionFunction(new double[] { 1, 2 });
            double cdf2 = target.DistributionFunction(new double[] { 3, 5 });

            double ccdf1 = target.ComplementaryDistributionFunction(new double[] { 1, 2 });
            double ccdf2 = target.ComplementaryDistributionFunction(new double[] { 3, 5 });


            Assert.AreEqual(1, mean[0]);
            Assert.AreEqual(2, mean[1]);
            Assert.AreEqual(1, median[0]);
            Assert.AreEqual(2, median[1]);
            Assert.AreEqual(0.0, var[0]);
            Assert.AreEqual(0.0, var[1]);
            Assert.AreEqual(0.0, cov[0, 0]);
            Assert.AreEqual(0.0, cov[0, 1]);
            Assert.AreEqual(0.0, cov[1, 0]);
            Assert.AreEqual(0.0, cov[1, 1]);
            Assert.AreEqual(0.15915494309189532, pdf1);
            Assert.AreEqual(0.15915494309189532, pdf2);
            Assert.AreEqual(0.15915494309189532, pdf3);
            Assert.AreEqual(-1.8378770664093456, lpdf);
            Assert.AreEqual(1.0, cdf1);
            Assert.AreEqual(0.0, cdf2);
            Assert.AreEqual(0.0, ccdf1);
            Assert.AreEqual(1.0, ccdf2);
        }
        public void CumulativeFunctionTest2()
        {
            double[] mean = { 4.2 };

            double[,] covariance = { { 1.4 } };

            var baseline = new NormalDistribution(4.2, System.Math.Sqrt(covariance[0, 0]));
            var target = new MultivariateNormalDistribution(mean, covariance);

            for (int i = 0; i < 10; i++)
            {
                double x = (i - 2) / 10.0;

                {
                    double actual = target.ProbabilityDensityFunction(x);
                    double expected = baseline.ProbabilityDensityFunction(x);
                    Assert.AreEqual(expected, actual, 1e-10);
                }

                {
                    double actual = target.DistributionFunction(x);
                    double expected = baseline.DistributionFunction(x);
                    Assert.AreEqual(expected, actual);
                }

                {
                    double actual = target.ComplementaryDistributionFunction(x);
                    double expected = baseline.ComplementaryDistributionFunction(x);
                    Assert.AreEqual(expected, actual);
                }
            }
        }
        public void CumulativeFunctionTest1()
        {
            // Comparison against dmvnorm from the mvtnorm R package

            double[] mean = { 1, -1 };

            double[,] covariance = 
            {
                { 0.9, 0.4 },
                { 0.4, 0.3 },
            };

            var target = new MultivariateNormalDistribution(mean, covariance);

            double[] x = { 1.2, -0.8 };

            // dmvnorm(x=c(1.2, -0.8), mean=c(1, -1), sigma=matrix(c(0.9, 0.4, 0.4, 0.3), 2, 2))
            double pdf = target.ProbabilityDensityFunction(x);

            // pmvnorm(upper=c(1.2, -0.8), mean=c(1, -1), sigma=matrix(c(0.9, 0.4, 0.4, 0.3), 2, 2))
            double cdf = target.DistributionFunction(x);

            // pmvnorm(lower=c(1.2, -0.8), mean=c(1, -1), sigma=matrix(c(0.9, 0.4, 0.4, 0.3), 2, 2))
            double ccdf = target.ComplementaryDistributionFunction(x);

            Assert.AreEqual(0.44620942136345987, pdf);
            Assert.AreEqual(0.5049523013014460826, cdf, 1e-10);
            Assert.AreEqual(0.27896707550525140507, ccdf, 1e-10);
        }