public void EmpiricalHazardConstructorTest3()
        {
            double[] times  = { 11, 10, 9, 8, 6, 5, 4, 2 };
            double[] values = { 0.22, 0.67, 1.00, 0.18, 1.00, 1.00, 1.00, 0.55 };


            EmpiricalHazardDistribution distribution = new EmpiricalHazardDistribution(times, values);


            double mean   = distribution.Mean;                                      // 0.93696461879063664
            double median = distribution.Median;                                    // 3.9999999151458066
            double var    = distribution.Variance;                                  // 2.0441627748096289
            double chf    = distribution.CumulativeHazardFunction(x: 4.2);          // 1.55
            double cdf    = distribution.DistributionFunction(x: 4.2);              // 0.7877520261732569
            double pdf    = distribution.ProbabilityDensityFunction(x: 4.2);        // 0.046694554241883471
            double lpdf   = distribution.LogProbabilityDensityFunction(x: 4.2);     // -3.0641277326297756
            double hf     = distribution.HazardFunction(x: 4.2);                    // 0.22
            double ccdf   = distribution.ComplementaryDistributionFunction(x: 4.2); // 0.21224797382674304
            double icdf   = distribution.InverseDistributionFunction(p: cdf);       // 4.3483975243778978

            string str = distribution.ToString();                                   // H(x; v, t)

            Assert.AreEqual(0.93696461879063664, mean);
            Assert.AreEqual(3.9999999151458066, median, 1e-6);
            Assert.AreEqual(2.0441627748096289, var);
            Assert.AreEqual(1.55, chf);
            Assert.AreEqual(0.7877520261732569, cdf);
            Assert.AreEqual(0.046694554241883471, pdf);
            Assert.AreEqual(-3.0641277326297756, lpdf);
            Assert.AreEqual(0.22, hf);
            Assert.AreEqual(0.21224797382674304, ccdf);
            Assert.AreEqual(4.3483975243778978, icdf, 1e-8);
            Assert.AreEqual("H(x; v, t)", str);
        }
        public void EmpiricalHazardConstructorTest3()
        {
            double[] times = { 11, 10, 9, 8, 6, 5, 4, 2 };
            double[] values = { 0.22, 0.67, 1.00, 0.18, 1.00, 1.00, 1.00, 0.55 };
            

            EmpiricalHazardDistribution distribution = new EmpiricalHazardDistribution(times, values);


            double mean = distribution.Mean; // 0.93696461879063664
            double median = distribution.Median; // 3.9999999151458066
            double var = distribution.Variance; // 2.0441627748096289
            double chf = distribution.CumulativeHazardFunction(x: 4.2); // 1.55
            double cdf = distribution.DistributionFunction(x: 4.2); // 0.7877520261732569
            double pdf = distribution.ProbabilityDensityFunction(x: 4.2); // 0.046694554241883471
            double lpdf = distribution.LogProbabilityDensityFunction(x: 4.2); // -3.0641277326297756
            double hf = distribution.HazardFunction(x: 4.2); // 0.22
            double ccdf = distribution.ComplementaryDistributionFunction(x: 4.2); // 0.21224797382674304
            double icdf = distribution.InverseDistributionFunction(p: cdf); // 4.3483975243778978

            string str = distribution.ToString(); // H(x; v, t)

            Assert.AreEqual(0.93696461879063664, mean);
            Assert.AreEqual(3.9999999151458066, median, 1e-6);
            Assert.AreEqual(2.0441627748096289, var);
            Assert.AreEqual(1.55, chf);
            Assert.AreEqual(0.7877520261732569, cdf);
            Assert.AreEqual(0.046694554241883471, pdf);
            Assert.AreEqual(-3.0641277326297756, lpdf);
            Assert.AreEqual(0.22, hf);
            Assert.AreEqual(0.21224797382674304, ccdf);
            Assert.AreEqual(4.3483975243778978, icdf, 1e-8);
            Assert.AreEqual("H(x; v, t)", str);
        }
        public void DistributionFunctionTest()
        {
            double[] values =
            {
                1.0000000000000000, 0.8724284533876597, 0.9698946958777951,
                1.0000000000000000, 0.9840887140861863, 1.0000000000000000,
                1.0000000000000000, 1.0000000000000000, 1.0000000000000000,
                0.9979137773216293, 1.0000000000000000
            };

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

            EmpiricalHazardDistribution target = EmpiricalHazardDistribution
                                                 .FromSurvivalValues(times, values);


            // Data from: http://www.sph.emory.edu/~cdckms/CoxPH/prophaz2.html
            double[] expectedBaselineSurvivalFunction =
            {
                1.0000, 0.9979, 0.9979, 0.9979,
                0.9979, 0.9979, 0.9820,
                0.9820, 0.9525, 0.8310, 0.8310,
            };


            double[] hazardFunction   = new double[expectedBaselineSurvivalFunction.Length];
            double[] survivalFunction = new double[expectedBaselineSurvivalFunction.Length];

            for (int i = 0; i < 11; i++)
            {
                hazardFunction[i] = target.CumulativeHazardFunction(i + 1);
            }

            for (int i = 0; i < 11; i++)
            {
                survivalFunction[i] = target.ComplementaryDistributionFunction(i + 1);
            }


            for (int i = 0; i < expectedBaselineSurvivalFunction.Length; i++)
            {
                Assert.AreEqual(expectedBaselineSurvivalFunction[i], survivalFunction[i], 0.01);

                // Ho = -log(So)
                Assert.AreEqual(hazardFunction[i], -Math.Log(survivalFunction[i]), 0.01);

                // So = exp(-Ho)
                Assert.AreEqual(survivalFunction[i], Math.Exp(-hazardFunction[i]), 0.01);
            }
        }
        public void ConstructorTest1()
        {
            double[]          times;
            SurvivalOutcome[] censor;
            CreateExample1(out times, out censor);

            var distribution = EmpiricalHazardDistribution.Estimate(times, censor,
                                                                    SurvivalEstimator.FlemingHarrington, HazardEstimator.BreslowNelsonAalen);

            double[] t = distribution.Times;
            double[] s = distribution.Survivals;
            double[] h = distribution.Hazards;

            double[] nt = distribution.Times.Distinct();
            double[] nh = nt.Apply(distribution.HazardFunction);

            var target = new EmpiricalHazardDistribution(nt, nh, SurvivalEstimator.FlemingHarrington);

            for (int i = 0; i < times.Length; i++)
            {
                double expected = distribution.HazardFunction(times[i]);
                double actual   = target.HazardFunction(times[i]);
                Assert.AreEqual(expected, actual);
            }

            for (int i = 0; i < times.Length; i++)
            {
                double expected = distribution.CumulativeHazardFunction(times[i]);
                double actual   = target.CumulativeHazardFunction(times[i]);
                Assert.AreEqual(expected, actual, 1e-5);
            }

            for (int i = 0; i < times.Length; i++)
            {
                double expected = distribution.ProbabilityDensityFunction(times[i]);
                double actual   = target.ProbabilityDensityFunction(times[i]);
                Assert.AreEqual(expected, actual, 1e-5);
            }
        }
        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);
            }
        }
        public void DistributionFunctionTest2_KaplanMeier()
        {
            double[] values =
            {
                0.0000000000000000,   0.0351683340828711, 0.0267358118285064,
                0.0000000000000000,   0.0103643094219679, 0.0000000000000000,
                0.0000000000000000,   0.0000000000000000, 0.0000000000000000,
                0.000762266794052363, 0.000000000000000
            };

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


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

            double[] expected =
            {
                1.000000000000000,
                0.999238023657475,
                0.999238023657475,
                0.999238023657475,
                0.999238023657475,
                0.999238023657475,
                0.98893509519066469,
                0.98893509519066469,
                0.96284543081744489,
                0.92957227114936058,
                0.92957227114936058,
            };


            double[] hazardFunction   = new double[expected.Length];
            double[] survivalFunction = new double[expected.Length];

            for (int i = 0; i < 11; i++)
            {
                hazardFunction[i] = target.CumulativeHazardFunction(i + 1);
            }

            for (int i = 0; i < 11; i++)
            {
                survivalFunction[i] = target.ComplementaryDistributionFunction(i + 1);
            }


            for (int i = 0; i < expected.Length; i++)
            {
                Assert.AreEqual(expected[i], survivalFunction[i], 1e-3);

                // Ho = -log(So)
                Assert.AreEqual(hazardFunction[i], -Math.Log(survivalFunction[i]), 1e-5);

                // So = exp(-Ho)
                Assert.AreEqual(survivalFunction[i], Math.Exp(-hazardFunction[i]), 1e-5);
            }


            Assert.AreEqual(1, target.ComplementaryDistributionFunction(0));
            Assert.AreEqual(0, target.ComplementaryDistributionFunction(Double.PositiveInfinity));
        }
        public void DocumentationExample_Aalen()
        {
            // Consider the following hazard rates, occurring at the given time steps
            double[] times = { 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 17, 20, 21 };

            double[] hazards =
            {
                0,                  0.111111111111111, 0.0625, 0.0714285714285714, 0.0769230769230769,
                0,                 0.0909090909090909,      0,  0.111111111111111,              0.125,0,
                0.166666666666667,                0.2,      0,                0.5, 0
            };

            // Create a new distribution given the observations and event times
            var distribution = new EmpiricalHazardDistribution(times, hazards);

            // Common measures
            double mean   = distribution.Mean;     // 6.1658527179584119
            double median = distribution.Median;   // 11.999999704601453
            double var    = distribution.Variance; // 44.101147497430993

            // Cumulative distribution functions
            double cdf  = distribution.DistributionFunction(x: 4);              //  0.275274821017619
            double ccdf = distribution.ComplementaryDistributionFunction(x: 4); //  0.724725178982381
            double icdf = distribution.InverseDistributionFunction(p: cdf);     //  4.4588994137113307

            // Probability density functions
            double pdf  = distribution.ProbabilityDensityFunction(x: 4);        //  0.055748090690952365
            double lpdf = distribution.LogProbabilityDensityFunction(x: 4);     // -2.8869121169242962

            // Hazard (failure rate) functions
            double hf  = distribution.HazardFunction(x: 4);           //  0.0769230769230769
            double chf = distribution.CumulativeHazardFunction(x: 4); //  0.32196275946275932

            string str = distribution.ToString();                     // H(x; v, t)

            try { double mode = distribution.Mode; Assert.Fail(); }
            catch { }

            Assert.AreEqual(SurvivalEstimator.FlemingHarrington, distribution.Estimator);
            Assert.AreEqual(1, distribution.ComplementaryDistributionFunction(0));
            Assert.AreEqual(0, distribution.ComplementaryDistributionFunction(Double.PositiveInfinity));

            Assert.AreEqual(6.1658527179584119, mean);
            Assert.AreEqual(11.999999704601453, median, 1e-6);
            Assert.AreEqual(44.101147497430993, var);
            Assert.AreEqual(0.32196275946275932, chf);
            Assert.AreEqual(0.275274821017619, cdf);
            Assert.AreEqual(0.055748090690952365, pdf);
            Assert.AreEqual(-2.8869121169242962, lpdf);
            Assert.AreEqual(0.0769230769230769, hf);
            Assert.AreEqual(0.724725178982381, ccdf);
            Assert.AreEqual(4.4588994137113307, icdf, 1e-8);
            Assert.AreEqual("H(x; v, t)", str);

            var range1 = distribution.GetRange(0.95);
            var range2 = distribution.GetRange(0.99);
            var range3 = distribution.GetRange(0.01);

            Assert.AreEqual(1, range1.Min, 1e-3);
            Assert.AreEqual(20.562, range1.Max, 1e-3);
            Assert.AreEqual(1, range2.Min, 1e-3);
            Assert.AreEqual(20.562, range2.Max, 1e-3);
            Assert.AreEqual(1, range3.Min, 1e-3);
            Assert.AreEqual(20.562, range3.Max, 1e-3);

            for (int i = 0; i < hazards.Length; i++)
            {
                Assert.AreEqual(hazards[i], distribution.HazardFunction(times[i]));
            }
        }
        public void DocumentationExample_KaplanMeier()
        {
            // Consider the following hazard rates, occurring at the given time steps
            double[] times = { 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 17, 20, 21 };

            double[] hazards =
            {
                0,                  0.111111111111111, 0.0625, 0.0714285714285714, 0.0769230769230769,
                0,                 0.0909090909090909,      0,  0.111111111111111,              0.125,0,
                0.166666666666667,                0.2,      0,                0.5, 0
            };


            // Create a new distribution given the observations and event times
            var distribution = new EmpiricalHazardDistribution(times, hazards, SurvivalEstimator.KaplanMeier);

            // Common measures
            double mean   = distribution.Mean;     // 5.49198237428757
            double median = distribution.Median;   // 11.999999704601453
            double var    = distribution.Variance; // 39.83481657555663

            // Cumulative distribution functions
            double cdf  = distribution.DistributionFunction(x: 4);              //  0.275274821017619
            double ccdf = distribution.ComplementaryDistributionFunction(x: 4); //  0.018754904264376961
            double icdf = distribution.InverseDistributionFunction(p: cdf);     //  4.4588994137113307

            // Probability density functions
            double pdf  = distribution.ProbabilityDensityFunction(x: 4);        //  0.055748090690952365
            double lpdf = distribution.LogProbabilityDensityFunction(x: 4);     // -2.8869121169242962

            // Hazard (failure rate) functions
            double hf  = distribution.HazardFunction(x: 4);           //  0.0769230769230769
            double chf = distribution.CumulativeHazardFunction(x: 4); //  0.32196275946275932

            string str = distribution.ToString();                     // H(x; v, t)

            try { double mode = distribution.Mode; Assert.Fail(); }
            catch { }

            Assert.AreEqual(SurvivalEstimator.KaplanMeier, distribution.Estimator);
            Assert.AreEqual(1, distribution.ComplementaryDistributionFunction(0));
            Assert.AreEqual(0, distribution.ComplementaryDistributionFunction(Double.PositiveInfinity));

            Assert.AreEqual(5.49198237428757, mean);
            Assert.AreEqual(11.999999704601453, median, 1e-6);
            Assert.AreEqual(39.83481657555663, var);
            Assert.AreEqual(0.33647223662121273, chf);
            Assert.AreEqual(0.28571428571428559, cdf);
            Assert.AreEqual(0.054945054945054937, pdf);
            Assert.AreEqual(-2.9014215940827497, lpdf);
            Assert.AreEqual(0.0769230769230769, hf);
            Assert.AreEqual(0.71428571428571441, ccdf);
            Assert.AreEqual(5.8785425101214548, icdf, 1e-8);
            Assert.AreEqual("H(x; v, t)", str);

            var range1 = distribution.GetRange(0.95);
            var range2 = distribution.GetRange(0.99);
            var range3 = distribution.GetRange(0.01);

            Assert.AreEqual(1, range1.Min, 1e-3);
            Assert.AreEqual(20.562, range1.Max, 1e-3);
            Assert.AreEqual(1, range2.Min, 1e-3);
            Assert.AreEqual(20.562, range2.Max, 1e-3);
            Assert.AreEqual(1, range3.Min, 1e-3);
            Assert.AreEqual(20.562, range3.Max, 1e-3);

            for (int i = 0; i < hazards.Length; i++)
            {
                Assert.AreEqual(hazards[i], distribution.HazardFunction(times[i]));
            }
        }
        public void BaselineHazardTest()
        {
            double[,] data =
            {
                // t   c  in
                {  8, 0, 13 },
                {  4, 1, 56 },
                { 12, 0, 25 },
                {  6, 0, 64 },
                { 10, 0, 38 },
                {  8, 1, 80 },
                {  5, 0,  0 },
                {  5, 0, 81 },
                {  3, 1, 81 },
                { 14, 1, 38 },
                {  8, 0, 23 },
                { 11, 0, 99 },
                {  7, 0, 12 },
                {  7, 1, 36 },
                { 12, 0, 63 },
                {  8, 0, 92 },
                {  7, 0, 38 },
            };

            double[]   time   = data.GetColumn(0);
            int[]      censor = data.GetColumn(1).ToInt32();
            double[][] inputs = data.GetColumn(2).ToArray();

            ProportionalHazards regression = new ProportionalHazards(1);

            ProportionalHazardsNewtonRaphson target = new ProportionalHazardsNewtonRaphson(regression);

            target.Normalize = false;

            double error = target.Run(inputs, time, censor);
            double log   = -2 * regression.GetPartialLogLikelihood(inputs, time, censor);

            EmpiricalHazardDistribution baseline = regression.BaselineHazard as EmpiricalHazardDistribution;

            double[] actual = new double[(int)baseline.Support.Max];
            for (int i = (int)baseline.Support.Min; i < baseline.Support.Max; i++)
            {
                actual[i] = baseline.CumulativeHazardFunction(i);
            }

            Assert.AreEqual(14, actual.Length);

            double[] expected =
            {
                0,                                       0,                    0,
                0.025000345517572315, 0.052363663484639708, 0.052363663484639708, 0.052363663484639708,
                0.16317880290786446,
                0.34217461190678861,   0.34217461190678861,  0.34217461190678861,
                0.34217461190678861,   0.34217461190678861, 0.34217461190678861
            };

            for (int i = 0; i < actual.Length; i++)
            {
                Assert.AreEqual(expected[i], actual[i], 0.025);
            }
        }
        public void DistributionFunctionTest2()
        {

            double[] values = 
            {
               0.0000000000000000, 0.0351683340828711, 0.0267358118285064,
               0.0000000000000000, 0.0103643094219679, 0.0000000000000000,
               0.0000000000000000, 0.0000000000000000, 0.0000000000000000,
               0.000762266794052363, 0.000000000000000
            };

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


            EmpiricalHazardDistribution target =
                new EmpiricalHazardDistribution(times, values);

            double[] expected = 
            {
			    1.000000000000000,	
			    0.999238023657475,	
			    0.999238023657475,	
			    0.999238023657475,	
			    0.999238023657475,	
			    0.999238023657475,	
			    0.98893509519066469,	
			    0.98893509519066469,
			    0.96284543081744489,
			    0.92957227114936058,	
			    0.92957227114936058,	
            };


            double[] hazardFunction = new double[expected.Length];
            double[] survivalFunction = new double[expected.Length];
            double[] complementaryDistribution = new double[expected.Length];

            for (int i = 0; i < 11; i++)
                hazardFunction[i] = target.CumulativeHazardFunction(i + 1);

            for (int i = 0; i < 11; i++)
                survivalFunction[i] = target.ComplementaryDistributionFunction(i + 1);


            for (int i = 0; i < expected.Length; i++)
            {
                Assert.AreEqual(expected[i], survivalFunction[i], 1e-5);

                // Ho = -log(So)
                Assert.AreEqual(hazardFunction[i], -Math.Log(survivalFunction[i]), 1e-5);

                // So = exp(-Ho)
                Assert.AreEqual(survivalFunction[i], Math.Exp(-hazardFunction[i]), 1e-5);
            }
        }
        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);
            }
        }
        public void ConstructorTest1()
        {
            double[] times;
            SurvivalOutcome[] censor;
            CreateExample1(out times, out censor);

            var distribution = EmpiricalHazardDistribution.Estimate(times, censor,
                SurvivalEstimator.FlemingHarrington, HazardEstimator.BreslowNelsonAalen);

            double[] t = distribution.Times;
            double[] s = distribution.Survivals;
            double[] h = distribution.Hazards;

            double[] nt = distribution.Times.Distinct();
            double[] nh = nt.Apply(distribution.HazardFunction);

            var target = new EmpiricalHazardDistribution(nt, nh, SurvivalEstimator.FlemingHarrington);

            for (int i = 0; i < times.Length; i++)
            {
                double expected = distribution.HazardFunction(times[i]);
                double actual = target.HazardFunction(times[i]);
                Assert.AreEqual(expected, actual);
            }

            for (int i = 0; i < times.Length; i++)
            {
                double expected = distribution.CumulativeHazardFunction(times[i]);
                double actual = target.CumulativeHazardFunction(times[i]);
                Assert.AreEqual(expected, actual, 1e-5);
            }

            for (int i = 0; i < times.Length; i++)
            {
                double expected = distribution.ProbabilityDensityFunction(times[i]);
                double actual = target.ProbabilityDensityFunction(times[i]);
                Assert.AreEqual(expected, actual, 1e-5);
            }
        }
        public void DocumentationExample_Aalen()
        {
            // Consider the following hazard rates, occurring at the given time steps
            double[] times = { 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 17, 20, 21 };

            double[] hazards = 
            { 
                0, 0.111111111111111, 0.0625, 0.0714285714285714, 0.0769230769230769,
                0, 0.0909090909090909, 0, 0.111111111111111, 0.125, 0, 
                0.166666666666667, 0.2, 0, 0.5, 0 
            };

            // Create a new distribution given the observations and event times
            var distribution = new EmpiricalHazardDistribution(times, hazards);

            // Common measures
            double mean = distribution.Mean;     // 6.1658527179584119
            double median = distribution.Median; // 11.999999704601453
            double var = distribution.Variance;  // 44.101147497430993

            // Cumulative distribution functions
            double cdf = distribution.DistributionFunction(x: 4);               //  0.275274821017619
            double ccdf = distribution.ComplementaryDistributionFunction(x: 4); //  0.724725178982381
            double icdf = distribution.InverseDistributionFunction(p: cdf);     //  4.4588994137113307

            // Probability density functions
            double pdf = distribution.ProbabilityDensityFunction(x: 4);         //  0.055748090690952365
            double lpdf = distribution.LogProbabilityDensityFunction(x: 4);     // -2.8869121169242962

            // Hazard (failure rate) functions
            double hf = distribution.HazardFunction(x: 4);                      //  0.0769230769230769
            double chf = distribution.CumulativeHazardFunction(x: 4);           //  0.32196275946275932

            string str = distribution.ToString(); // H(x; v, t)

            try { double mode = distribution.Mode; Assert.Fail(); }
            catch { }

            Assert.AreEqual(SurvivalEstimator.FlemingHarrington, distribution.Estimator);
            Assert.AreEqual(1, distribution.ComplementaryDistributionFunction(0));
            Assert.AreEqual(0, distribution.ComplementaryDistributionFunction(Double.PositiveInfinity));

            Assert.AreEqual(6.1658527179584119, mean);
            Assert.AreEqual(11.999999704601453, median, 1e-6);
            Assert.AreEqual(44.101147497430993, var);
            Assert.AreEqual(0.32196275946275932, chf);
            Assert.AreEqual(0.275274821017619, cdf);
            Assert.AreEqual(0.055748090690952365, pdf);
            Assert.AreEqual(-2.8869121169242962, lpdf);
            Assert.AreEqual(0.0769230769230769, hf);
            Assert.AreEqual(0.724725178982381, ccdf);
            Assert.AreEqual(4.4588994137113307, icdf, 1e-8);
            Assert.AreEqual("H(x; v, t)", str);

            var range1 = distribution.GetRange(0.95);
            var range2 = distribution.GetRange(0.99);
            var range3 = distribution.GetRange(0.01);

            Assert.AreEqual(1, range1.Min, 1e-3);
            Assert.AreEqual(20.562, range1.Max, 1e-3);
            Assert.AreEqual(1, range2.Min, 1e-3);
            Assert.AreEqual(20.562, range2.Max, 1e-3);
            Assert.AreEqual(1, range3.Min, 1e-3);
            Assert.AreEqual(20.562, range3.Max, 1e-3);

            for (int i = 0; i < hazards.Length; i++)
                Assert.AreEqual(hazards[i], distribution.HazardFunction(times[i]));
        }
        public void DocumentationExample_KaplanMeier()
        {
            // Consider the following hazard rates, occurring at the given time steps
            double[] times = { 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 17, 20, 21 };

            double[] hazards = 
            { 
                0, 0.111111111111111, 0.0625, 0.0714285714285714, 0.0769230769230769,
                0, 0.0909090909090909, 0, 0.111111111111111, 0.125, 0, 
                0.166666666666667, 0.2, 0, 0.5, 0 
            };


            // Create a new distribution given the observations and event times
            var distribution = new EmpiricalHazardDistribution(times, hazards, SurvivalEstimator.KaplanMeier);

            // Common measures
            double mean = distribution.Mean;     // 5.49198237428757
            double median = distribution.Median; // 11.999999704601453
            double var = distribution.Variance;  // 39.83481657555663

            // Cumulative distribution functions
            double cdf = distribution.DistributionFunction(x: 4);               //  0.275274821017619
            double ccdf = distribution.ComplementaryDistributionFunction(x: 4); //  0.018754904264376961
            double icdf = distribution.InverseDistributionFunction(p: cdf);     //  4.4588994137113307

            // Probability density functions
            double pdf = distribution.ProbabilityDensityFunction(x: 4);         //  0.055748090690952365
            double lpdf = distribution.LogProbabilityDensityFunction(x: 4);     // -2.8869121169242962

            // Hazard (failure rate) functions
            double hf = distribution.HazardFunction(x: 4);                      //  0.0769230769230769
            double chf = distribution.CumulativeHazardFunction(x: 4);           //  0.32196275946275932

            string str = distribution.ToString(); // H(x; v, t)

            try { double mode = distribution.Mode; Assert.Fail(); }
            catch { }

            Assert.AreEqual(SurvivalEstimator.KaplanMeier, distribution.Estimator);
            Assert.AreEqual(1, distribution.ComplementaryDistributionFunction(0));
            Assert.AreEqual(0, distribution.ComplementaryDistributionFunction(Double.PositiveInfinity));

            Assert.AreEqual(5.49198237428757, mean);
            Assert.AreEqual(11.999999704601453, median, 1e-6);
            Assert.AreEqual(39.83481657555663, var);
            Assert.AreEqual(0.33647223662121273, chf);
            Assert.AreEqual(0.28571428571428559, cdf);
            Assert.AreEqual(0.054945054945054937, pdf);
            Assert.AreEqual(-2.9014215940827497, lpdf);
            Assert.AreEqual(0.0769230769230769, hf);
            Assert.AreEqual(0.71428571428571441, ccdf);
            Assert.AreEqual(5.8785425101214548, icdf, 1e-8);
            Assert.AreEqual("H(x; v, t)", str);

            var range1 = distribution.GetRange(0.95);
            var range2 = distribution.GetRange(0.99);
            var range3 = distribution.GetRange(0.01);

            Assert.AreEqual(1, range1.Min, 1e-3);
            Assert.AreEqual(20.562, range1.Max, 1e-3);
            Assert.AreEqual(1, range2.Min, 1e-3);
            Assert.AreEqual(20.562, range2.Max, 1e-3);
            Assert.AreEqual(1, range3.Min, 1e-3);
            Assert.AreEqual(20.562, range3.Max, 1e-3);

            for (int i = 0; i < hazards.Length; i++)
                Assert.AreEqual(hazards[i], distribution.HazardFunction(times[i]));
        }