General continuous distribution.

The general continuous distribution provides the automatic calculation for a variety of distribution functions and measures given only definitions for the Probability Density Function (PDF) or the Cumulative Distribution Function (CDF). Values such as the Expected value, Variance, Entropy and others are computed through numeric integration.

Inheritance: UnivariateContinuousDistribution
        private static void testNormal(GeneralContinuousDistribution normal)
        {
            double mean = normal.Mean;     // 4.0
            double median = normal.Median; // 4.0
            double var = normal.Variance;  // 17.64

            double cdf = normal.DistributionFunction(x: 1.4); // 0.26794249453351904
            double pdf = normal.ProbabilityDensityFunction(x: 1.4); // 0.078423391448155175
            double lpdf = normal.LogProbabilityDensityFunction(x: 1.4); // -2.5456330358182586

            double ccdf = normal.ComplementaryDistributionFunction(x: 1.4); // 0.732057505466481
            double icdf = normal.InverseDistributionFunction(p: cdf); // 1.4

            double hf = normal.HazardFunction(x: 1.4); // 0.10712736480747137
            double chf = normal.CumulativeHazardFunction(x: 1.4); // 0.31189620872601354

            Assert.AreEqual(4.0, mean);
            Assert.AreEqual(4.0, median);
            Assert.AreEqual(17.64, var);
            Assert.AreEqual(0.31189620872601354, chf);
            Assert.AreEqual(0.26794249453351904, cdf);
            Assert.AreEqual(0.078423391448155175, pdf);
            Assert.AreEqual(-2.5456330358182586, lpdf);
            Assert.AreEqual(0.10712736480747137, hf);
            Assert.AreEqual(0.732057505466481, ccdf);
            Assert.AreEqual(1.4, icdf);
        }
        /// <summary>
        ///   Creates a new object that is a copy of the current instance.
        /// </summary>
        /// 
        /// <returns>
        ///   A new object that is a copy of this instance.
        /// </returns>
        /// 
        public override object Clone()
        {
            GeneralContinuousDistribution c = new GeneralContinuousDistribution();

            c.pdf = pdf;
            c.cdf = cdf;
            c.method = (IUnivariateIntegration)method.Clone();

            return c;
        }
 /// <summary>
 ///   Creates a new <see cref="GeneralContinuousDistribution"/> 
 ///   using only a cumulative distribution function definition.
 /// </summary>
 /// 
 /// <param name="support">The distribution's support over the real line.</param>
 /// <param name="cdf">A cumulative distribution function.</param>
 /// <param name="method">The integration method to use for numerical computations.</param>
 /// 
 /// <returns>A <see cref="GeneralContinuousDistribution"/> created from the 
 /// <paramref name="cdf"/> whose measures and functions are computed using 
 /// numerical integration and differentiation.</returns>
 /// 
 public static GeneralContinuousDistribution FromDistributionFunction(
     DoubleRange support, Func<double, double> cdf, IUnivariateIntegration method)
 {
     GeneralContinuousDistribution dist = new GeneralContinuousDistribution();
     dist.support = support;
     dist.cdf = cdf;
     dist.method = method;
     return dist;
 }
 /// <summary>
 ///   Creates a new <see cref="GeneralContinuousDistribution"/> 
 ///   from an existing <see cref="UnivariateContinuousDistribution">
 ///   continuous distribution</see>.
 /// </summary>
 /// 
 /// <param name="distribution">The distribution.</param>
 /// 
 /// <returns>A <see cref="GeneralContinuousDistribution"/> representing the same
 /// <paramref name="distribution"/> but whose measures and functions are computed
 /// using numerical integration and differentiation.</returns>
 /// 
 public static GeneralContinuousDistribution FromDistribution(UnivariateContinuousDistribution distribution)
 {
     GeneralContinuousDistribution dist = new GeneralContinuousDistribution();
     dist.support = distribution.Support;
     dist.pdf = distribution.ProbabilityDensityFunction;
     dist.cdf = distribution.DistributionFunction;
     return dist;
 }
        public void ConstructorTest0()
        {
            var original = new NormalDistribution(mean: 4, stdDev: 4.2);

            var normal = new GeneralContinuousDistribution(
                original.Support,
                original.ProbabilityDensityFunction,
                original.DistributionFunction);

            testNormal(normal, 1);
        }
        private static void testVonMises(GeneralContinuousDistribution vonMises, double prec)
        {
            double mean = vonMises.Mean;     // 0.42
            double median = vonMises.Median; // 0.42
            double var = vonMises.Variance;  // 0.48721760532782921

            double cdf = vonMises.DistributionFunction(x: 1.4); // 0.81326928491589345
            double pdf = vonMises.ProbabilityDensityFunction(x: 1.4); // 0.2228112141141676
            double lpdf = vonMises.LogProbabilityDensityFunction(x: 1.4); // -1.5014304395467863

            double ccdf = vonMises.ComplementaryDistributionFunction(x: 1.4); // 0.18673071508410655
            double icdf = vonMises.InverseDistributionFunction(p: cdf); // 1.3999999637927665

            double hf = vonMises.HazardFunction(x: 1.4); // 1.1932220899695576
            double chf = vonMises.CumulativeHazardFunction(x: 1.4); // 1.6780877262500649

            double imedian = vonMises.InverseDistributionFunction(p: 0.5);

            Assert.AreEqual(0.42, mean, 1e-8 * prec);
            Assert.AreEqual(0.42, median, 1e-8 * prec);
            Assert.AreEqual(0.42000000260613551, imedian, 1e-8 * prec);
            // TODO: Von Mises variance doesn't match.
            // Assert.AreEqual(0.48721760532782921, var);
            Assert.AreEqual(1.6780877262500649, chf, 1e-7 * prec);
            Assert.AreEqual(0.81326928491589345, cdf, 1e-7 * prec);
            Assert.AreEqual(0.2228112141141676, pdf, 1e-8 * prec);
            Assert.AreEqual(-1.5014304395467863, lpdf, 1e-6 * prec);
            Assert.AreEqual(1.1932220899695576, hf, 1e-6 * prec);
            Assert.AreEqual(0.18673071508410655, ccdf, 1e-8 * prec);
            Assert.AreEqual(1.39999999999, icdf, 1e-8 * prec);
        }
        private static void testNakagami(GeneralContinuousDistribution nakagami)
        {
            double mean = nakagami.Mean;     // 1.946082119049118
            double median = nakagami.Median; // 1.9061151110206338
            double var = nakagami.Variance;  // 0.41276438591729486

            double cdf = nakagami.DistributionFunction(x: 1.4); // 0.20603416752368109
            double pdf = nakagami.ProbabilityDensityFunction(x: 1.4); // 0.49253215371343023
            double lpdf = nakagami.LogProbabilityDensityFunction(x: 1.4); // -0.708195533773302

            double ccdf = nakagami.ComplementaryDistributionFunction(x: 1.4); // 0.79396583247631891
            double icdf = nakagami.InverseDistributionFunction(p: cdf); // 1.400000000131993

            double hf = nakagami.HazardFunction(x: 1.4); // 0.62034426869133652
            double chf = nakagami.CumulativeHazardFunction(x: 1.4); // 0.23071485080660473

            Assert.AreEqual(1.946082119049118, mean, 1e-6);
            Assert.AreEqual(1.9061151110206338, median, 1e-6);
            Assert.AreEqual(0.41276438591729486, var, 1e-6);
            Assert.AreEqual(0.23071485080660473, chf, 1e-7);
            Assert.AreEqual(0.20603416752368109, cdf, 1e-7);
            Assert.AreEqual(0.49253215371343023, pdf, 1e-6);
            Assert.AreEqual(-0.708195533773302, lpdf, 1e-6);
            Assert.AreEqual(0.62034426869133652, hf, 1e-6);
            Assert.AreEqual(0.79396583247631891, ccdf, 1e-7);
            Assert.AreEqual(1.40, icdf, 1e-7);
        }
        private static void testGompertz(GeneralContinuousDistribution gompertz)
        {
            double median = gompertz.Median; // 0.13886469671401389

            double cdf = gompertz.DistributionFunction(x: 0.27); // 0.76599768199799145
            double pdf = gompertz.ProbabilityDensityFunction(x: 0.27); // 1.4549484164912097
            double lpdf = gompertz.LogProbabilityDensityFunction(x: 0.27); // 0.37497044741163688

            double ccdf = gompertz.ComplementaryDistributionFunction(x: 0.27); // 0.23400231800200855
            double icdf = gompertz.InverseDistributionFunction(p: cdf); // 0.26999999999766749

            double hf = gompertz.HazardFunction(x: 0.27); // 6.2176666834502088
            double chf = gompertz.CumulativeHazardFunction(x: 0.27); // 1.4524242576820101

            Assert.AreEqual(0.13886469671401389, median, 1e-6);
            Assert.AreEqual(1.4524242576820101, chf, 1e-5);
            Assert.AreEqual(0.76599768199799145, cdf, 1e-5);
            Assert.AreEqual(1.4549484164912097, pdf, 1e-6);
            Assert.AreEqual(0.37497044741163688, lpdf, 1e-6);
            Assert.AreEqual(6.2176666834502088, hf, 1e-4);
            Assert.AreEqual(0.23400231800200855, ccdf, 1e-5);
            Assert.AreEqual(0.26999999999766749, icdf, 1e-5);
        }
        private static void testChiSquare(GeneralContinuousDistribution chisq)
        {
            double mean = chisq.Mean;     // 7
            double median = chisq.Median; // 6.345811195595612
            double var = chisq.Variance;  // 14

            double cdf = chisq.DistributionFunction(x: 6.27); // 0.49139966433823956
            double pdf = chisq.ProbabilityDensityFunction(x: 6.27); // 0.11388708001184455
            double lpdf = chisq.LogProbabilityDensityFunction(x: 6.27); // -2.1725478476948092

            double ccdf = chisq.ComplementaryDistributionFunction(x: 6.27); // 0.50860033566176044
            double icdf = chisq.InverseDistributionFunction(p: cdf); // 6.2700000000852318

            double hf = chisq.HazardFunction(x: 6.27); // 0.22392254197721179
            double chf = chisq.CumulativeHazardFunction(x: 6.27); // 0.67609276602233315

            Assert.AreEqual(7, mean, 1e-8);
            Assert.AreEqual(6.345811195595612, median, 1e-6);
            Assert.AreEqual(14, var, 1e-6);
            Assert.AreEqual(0.67609276602233315, chf, 1e-8);
            Assert.AreEqual(0.49139966433823956, cdf, 1e-8);
            Assert.AreEqual(0.11388708001184455, pdf, 1e-8);
            Assert.AreEqual(-2.1725478476948092, lpdf, 1e-8);
            Assert.AreEqual(0.22392254197721179, hf, 1e-8);
            Assert.AreEqual(0.50860033566176044, ccdf, 1e-8);
            Assert.AreEqual(6.2700000000852318, icdf, 1e-6);
        }
        private static void testLognormal(GeneralContinuousDistribution log)
        {
            double mean = log.Mean;     // 2.7870954605658511
            double median = log.Median; // 1.5219615583481305
            double var = log.Variance;  // 18.28163603621158

            double cdf = log.DistributionFunction(x: 0.27); // 0.057961222885664958
            double pdf = log.ProbabilityDensityFunction(x: 0.27); // 0.39035530085982068
            double lpdf = log.LogProbabilityDensityFunction(x: 0.27); // -0.94069792674674835

            double ccdf = log.ComplementaryDistributionFunction(x: 0.27); // 0.942038777114335
            double icdf = log.InverseDistributionFunction(p: cdf); // 0.26999997937815973

            double hf = log.HazardFunction(x: 0.27); // 0.41437285846720867
            double chf = log.CumulativeHazardFunction(x: 0.27); // 0.059708840588116374


            Assert.AreEqual(2.7870954605658511, mean, 1e-6);
            Assert.AreEqual(1.5219615583481305, median, 1e-7);
            Assert.AreEqual(18.28163603621158, var, 1e-4);
            Assert.AreEqual(0.059708840588116374, chf);
            Assert.AreEqual(0.057961222885664958, cdf, 1e-7);
            Assert.AreEqual(0.39035530085982068, pdf, 1e-6);
            Assert.AreEqual(-0.94069792674674835, lpdf, 1e-6);
            Assert.AreEqual(0.41437285846720867, hf, 1e-6);
            Assert.AreEqual(0.942038777114335, ccdf, 1e-6);
            Assert.AreEqual(0.26999997937815973, icdf, 1e-5);
        }
        private static void testLaplace(GeneralContinuousDistribution laplace)
        {
            double mean = laplace.Mean;     // 4.0
            double median = laplace.Median; // 4.0
            double var = laplace.Variance;  // 8.0

            double cdf = laplace.DistributionFunction(x: 0.27); // 0.077448104942453522
            double pdf = laplace.ProbabilityDensityFunction(x: 0.27); // 0.038724052471226761
            double lpdf = laplace.LogProbabilityDensityFunction(x: 0.27); // -3.2512943611198906

            double ccdf = laplace.ComplementaryDistributionFunction(x: 0.27); // 0.92255189505754642
            double icdf = laplace.InverseDistributionFunction(p: cdf); // 0.27

            double hf = laplace.HazardFunction(x: 0.27); // 0.041974931360160776
            double chf = laplace.CumulativeHazardFunction(x: 0.27); // 0.080611649844768624

            Assert.AreEqual(4.0, mean, 1e-5);
            Assert.AreEqual(4.0, median, 1e-6);
            Assert.AreEqual(8.0, var, 1e-5);
            Assert.AreEqual(0.080611649844768624, chf, 1e-6);
            Assert.AreEqual(0.077448104942453522, cdf, 1e-6);
            Assert.AreEqual(0.038724052471226761, pdf, 1e-6);
            Assert.AreEqual(-3.2512943611198906, lpdf, 1e-6);
            Assert.AreEqual(0.041974931360160776, hf, 1e-6);
            Assert.AreEqual(0.92255189505754642, ccdf, 1e-6);
            Assert.AreEqual(0.26999999840794775, icdf, 1e-6);
        }
        private static void testInvGaussian(GeneralContinuousDistribution invGaussian)
        {
            double mean = invGaussian.Mean;     // 0.42
            double median = invGaussian.Median;   // 0.35856861093990083
            double var = invGaussian.Variance; // 0.061739999999999989

            double cdf = invGaussian.DistributionFunction(x: 0.27); // 0.30658791274125458
            double pdf = invGaussian.ProbabilityDensityFunction(x: 0.27); // 2.3461495925760354
            double lpdf = invGaussian.LogProbabilityDensityFunction(x: 0.27); // 0.85277551314980737

            double ccdf = invGaussian.ComplementaryDistributionFunction(x: 0.27); // 0.69341208725874548
            double icdf = invGaussian.InverseDistributionFunction(p: cdf); // 0.26999999957543408

            double hf = invGaussian.HazardFunction(x: 0.27); // 3.383485283406336
            double chf = invGaussian.CumulativeHazardFunction(x: 0.27); // 0.36613081401302111


            Assert.AreEqual(0.42, mean, 1e-10);
            Assert.AreEqual(0.35856861093990083, median, 1e-7);
            Assert.AreEqual(0.061739999999999989, var, 1e-7);
            Assert.AreEqual(0.36613081401302111, chf, 1e-7);
            Assert.AreEqual(0.30658791274125458, cdf, 1e-7);
            Assert.AreEqual(2.3461495925760354, pdf, 1e-7);
            Assert.AreEqual(0.85277551314980737, lpdf, 1e-7);
            Assert.AreEqual(3.383485283406336, hf, 1e-7);
            Assert.AreEqual(0.69341208725874548, ccdf, 1e-7);
            Assert.AreEqual(0.26999999957543408, icdf, 1e-6);
        }
        public void MeasuresTest_KaplanMeier()
        {
            double[] values = 
            {
               0.0000000000000000, 0.0351683340828711, 0.0267358118285064,
               0.0000000000000000, 0.0103643094219679, 0.9000000000000000,
               0.0000000000000000, 0.0000000000000000, 0.0000000000000000,
               0.000762266794052363, 0.000000000000000
            };

            double[] times =
            {
                11, 1, 9, 8, 7, 3, 6, 5, 4, 2, 10
            };

            var target = new EmpiricalHazardDistribution(times, values, SurvivalEstimator.KaplanMeier);
            var general = new GeneralContinuousDistribution(target);

            //Assert.AreEqual(general.Mean, target.Mean);
            //Assert.AreEqual(general.Variance, target.Variance);
            Assert.AreEqual(general.Median, target.Median);

            for (int i = -10; i < 10; i++)
            {
                double x = i;
                double expected = general.CumulativeHazardFunction(x);
                double actual = target.CumulativeHazardFunction(x);
                Assert.AreEqual(expected, actual, 1e-4);
            }

            for (int i = -10; i < 10; i++)
            {
                double x = i;
                double expected = general.HazardFunction(x);
                double actual = target.HazardFunction(x);
                Assert.AreEqual(expected, actual, 1e-5);
            }
        }