This is an automated email from the ASF dual-hosted git repository. aherbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-statistics.git
commit 912bcf7a19566b711e3c6807255fc2b5ac8587a6 Author: Benjamin Trent <4357155+benwtr...@users.noreply.github.com> AuthorDate: Wed Jul 14 11:54:24 2021 -0400 STATISTICS-31: New "survivalProbability" function for all continuous distributions. This commit adds a new function for all continuous distributions `survivalProbability`. While a naive implementation would simply be `1-cumulativeProbability`, that would result in loss of precision. For many of the current cont. dist. a higher precision survival probability is calculated For others, it is simply `1-cumulativeProbability` Many tests were added to verify the following: - the precision of cumulativeProbability - the precision of survivalProbability - That survivalProbabiliy is near 1-cumulative - That survival and cumulative probabilities are complementary Through this development, certain distributions were found lacking precision for their cumulativeProbabilities and were improved. Those were: - CauchyDistribution - ExponentialDistribution - LogNormalDistribution - PretoDistribution - WeibullDistribution Addresses Jira: STATISTICS-31 --- .../statistics/distribution/BetaDistribution.java | 12 ++ .../distribution/CauchyDistribution.java | 17 ++- .../distribution/ChiSquaredDistribution.java | 6 + .../distribution/ContinuousDistribution.java | 17 +++ .../distribution/ExponentialDistribution.java | 12 +- .../statistics/distribution/FDistribution.java | 17 +++ .../statistics/distribution/GammaDistribution.java | 11 ++ .../distribution/GumbelDistribution.java | 7 ++ .../distribution/LaplaceDistribution.java | 10 ++ .../statistics/distribution/LevyDistribution.java | 10 ++ .../distribution/LogNormalDistribution.java | 17 ++- .../distribution/LogisticDistribution.java | 7 ++ .../distribution/NakagamiDistribution.java | 12 ++ .../distribution/NormalDistribution.java | 10 ++ .../distribution/ParetoDistribution.java | 12 +- .../statistics/distribution/TDistribution.java | 6 + .../distribution/WeibullDistribution.java | 12 +- .../distribution/BetaDistributionTest.java | 106 +++++++++++++++- .../distribution/CauchyDistributionTest.java | 24 +++- .../distribution/ChiSquaredDistributionTest.java | 22 ++++ .../ContinuousDistributionAbstractTest.java | 138 +++++++++++++++++++++ .../distribution/ExponentialDistributionTest.java | 23 ++++ .../statistics/distribution/FDistributionTest.java | 22 ++++ .../distribution/GammaDistributionTest.java | 22 ++++ .../distribution/GumbelDistributionTest.java | 22 ++++ .../distribution/LaplaceDistributionTest.java | 24 ++++ .../distribution/LevyDistributionTest.java | 22 ++++ .../distribution/LogNormalDistributionTest.java | 33 ++++- .../distribution/LogisticsDistributionTest.java | 22 ++++ .../distribution/NakagamiDistributionTest.java | 22 ++++ .../distribution/NormalDistributionTest.java | 24 +++- .../distribution/ParetoDistributionTest.java | 24 +++- .../statistics/distribution/TDistributionTest.java | 22 ++++ .../distribution/WeibullDistributionTest.java | 28 +++++ 34 files changed, 784 insertions(+), 11 deletions(-) diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BetaDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BetaDistribution.java index 54e9cf3..0d7653f 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BetaDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BetaDistribution.java @@ -107,6 +107,18 @@ public class BetaDistribution extends AbstractContinuousDistribution { } } + /** {@inheritDoc} */ + @Override + public double survivalProbability(double x) { + if (x <= 0) { + return 1; + } else if (x >= 1) { + return 0; + } else { + return RegularizedBeta.value(1 - x, beta, alpha); + } + } + /** * {@inheritDoc} * diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/CauchyDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/CauchyDistribution.java index 1ef4ae1..771ea90 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/CauchyDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/CauchyDistribution.java @@ -44,7 +44,22 @@ public class CauchyDistribution extends AbstractContinuousDistribution { /** {@inheritDoc} */ @Override public double cumulativeProbability(double x) { - return 0.5 + (Math.atan((x - median) / scale) / Math.PI); + return cdf((x - median) / scale); + } + + /** {@inheritDoc} */ + @Override + public double survivalProbability(double x) { + return cdf(-(x - median) / scale); + } + + /** + * Compute the CDF of the Cauchy distribution with location 0 and scale 1. + * @param x Point at which the CDF is evaluated + * @return CDF(x) + */ + private static double cdf(double x) { + return 0.5 + (Math.atan(x) / Math.PI); } /** diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ChiSquaredDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ChiSquaredDistribution.java index e012281..c10adf5 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ChiSquaredDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ChiSquaredDistribution.java @@ -61,6 +61,12 @@ public class ChiSquaredDistribution extends AbstractContinuousDistribution { return gamma.cumulativeProbability(x); } + /** {@inheritDoc} */ + @Override + public double survivalProbability(double x) { + return gamma.survivalProbability(x); + } + /** * {@inheritDoc} * diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ContinuousDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ContinuousDistribution.java index 19f7584..129dd14 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ContinuousDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ContinuousDistribution.java @@ -95,6 +95,23 @@ public interface ContinuousDistribution { double cumulativeProbability(double x); /** + * For a random variable {@code X} whose values are distributed according + * to this distribution, this method returns {@code P(X > x)}. + * In other words, this method represents the complementary cumulative + * distribution function. + * <p> + * By default, this is defined as {@code 1 - cumulativeProbability(x)}, but + * the specific implementation may be more accurate. + * + * @param x Point at which the survival function is evaluated. + * @return the probability that a random variable with this + * distribution takes a value greater than {@code x}. + */ + default double survivalProbability(double x) { + return 1.0 - cumulativeProbability(x); + } + + /** * Computes the quantile function of this distribution. For a random * variable {@code X} distributed according to this distribution, the * returned value is diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ExponentialDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ExponentialDistribution.java index 20e0d88..e076197 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ExponentialDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ExponentialDistribution.java @@ -80,7 +80,17 @@ public class ExponentialDistribution extends AbstractContinuousDistribution { return 0; } - return 1 - Math.exp(-x / mean); + return -Math.expm1(-x / mean); + } + + /** {@inheritDoc} */ + @Override + public double survivalProbability(double x) { + if (x <= SUPPORT_LO) { + return 1; + } + + return Math.exp(-x / mean); } /** diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/FDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/FDistribution.java index b96511f..0acccbb 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/FDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/FDistribution.java @@ -118,6 +118,23 @@ public class FDistribution extends AbstractContinuousDistribution { 0.5 * m); } + /** {@inheritDoc} */ + @Override + public double survivalProbability(double x) { + if (x <= SUPPORT_LO) { + return 1; + } else if (x >= SUPPORT_HI) { + return 0; + } + + final double n = numeratorDegreesOfFreedom; + final double m = denominatorDegreesOfFreedom; + + return RegularizedBeta.value(m / (m + n * x), + 0.5 * m, + 0.5 * n); + } + /** * Access the numerator degrees of freedom. * diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GammaDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GammaDistribution.java index 5053955..eb6761c 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GammaDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GammaDistribution.java @@ -255,6 +255,17 @@ public class GammaDistribution extends AbstractContinuousDistribution { return RegularizedGamma.P.value(shape, x / scale); } + /** {@inheritDoc} */ + @Override + public double survivalProbability(double x) { + if (x <= SUPPORT_LO) { + return 1; + } else if (x >= SUPPORT_HI) { + return 0; + } + return RegularizedGamma.Q.value(shape, x / scale); + } + /** * {@inheritDoc} * diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GumbelDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GumbelDistribution.java index 6b28c06..812ad8e 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GumbelDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GumbelDistribution.java @@ -92,6 +92,13 @@ public class GumbelDistribution extends AbstractContinuousDistribution { /** {@inheritDoc} */ @Override + public double survivalProbability(double x) { + final double z = (x - mu) / beta; + return -Math.expm1(-Math.exp(-z)); + } + + /** {@inheritDoc} */ + @Override public double inverseCumulativeProbability(double p) { if (p < 0 || p > 1) { throw new DistributionException(DistributionException.INVALID_PROBABILITY, p); diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LaplaceDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LaplaceDistribution.java index a4fab52..ef3c76c 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LaplaceDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LaplaceDistribution.java @@ -80,6 +80,16 @@ public class LaplaceDistribution extends AbstractContinuousDistribution { /** {@inheritDoc} */ @Override + public double survivalProbability(double x) { + if (x <= mu) { + return 1.0 - Math.exp((x - mu) / beta) / 2.0; + } else { + return Math.exp((mu - x) / beta) / 2.0; + } + } + + /** {@inheritDoc} */ + @Override public double inverseCumulativeProbability(double p) { if (p < 0 || p > 1) { diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LevyDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LevyDistribution.java index 4f59f28..e38d01a 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LevyDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LevyDistribution.java @@ -16,6 +16,7 @@ */ package org.apache.commons.statistics.distribution; +import org.apache.commons.numbers.gamma.Erf; import org.apache.commons.numbers.gamma.Erfc; import org.apache.commons.numbers.gamma.InverseErfc; @@ -102,6 +103,15 @@ public class LevyDistribution extends AbstractContinuousDistribution { /** {@inheritDoc} */ @Override + public double survivalProbability(final double x) { + if (x < mu) { + return 1; + } + return Erf.value(Math.sqrt(halfC / (x - mu))); + } + + /** {@inheritDoc} */ + @Override public double inverseCumulativeProbability(final double p) { if (p < 0 || p > 1) { diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogNormalDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogNormalDistribution.java index 584bdd5..211170b 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogNormalDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogNormalDistribution.java @@ -17,8 +17,8 @@ package org.apache.commons.statistics.distribution; -import org.apache.commons.numbers.gamma.Erf; import org.apache.commons.numbers.gamma.ErfDifference; +import org.apache.commons.numbers.gamma.Erfc; import org.apache.commons.rng.UniformRandomProvider; import org.apache.commons.rng.sampling.distribution.LogNormalSampler; import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler; @@ -151,7 +151,20 @@ public class LogNormalDistribution extends AbstractContinuousDistribution { if (Math.abs(dev) > 40 * shape) { return dev < 0 ? 0.0d : 1.0d; } - return 0.5 + 0.5 * Erf.value(dev / (shape * SQRT2)); + return 0.5 * Erfc.value(-dev / (shape * SQRT2)); + } + + /** {@inheritDoc} */ + @Override + public double survivalProbability(double x) { + if (x <= 0) { + return 1; + } + final double dev = Math.log(x) - scale; + if (Math.abs(dev) > 40 * shape) { + return dev > 0 ? 0.0d : 1.0d; + } + return 0.5 * Erfc.value(dev / (shape * SQRT2)); } /** {@inheritDoc} */ diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogisticDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogisticDistribution.java index 0480206..522ccda 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogisticDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogisticDistribution.java @@ -92,6 +92,13 @@ public class LogisticDistribution extends AbstractContinuousDistribution { /** {@inheritDoc} */ @Override + public double survivalProbability(double x) { + final double z = oneOverScale * (x - mu); + return 1 / (1 + Math.exp(z)); + } + + /** {@inheritDoc} */ + @Override public double inverseCumulativeProbability(double p) { if (p < 0 || p > 1) { diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NakagamiDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NakagamiDistribution.java index da925fb..05429d4 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NakagamiDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NakagamiDistribution.java @@ -100,6 +100,18 @@ public class NakagamiDistribution extends AbstractContinuousDistribution { /** {@inheritDoc} */ @Override + public double survivalProbability(double x) { + if (x <= SUPPORT_LO) { + return 1; + } else if (x >= SUPPORT_HI) { + return 0; + } + + return RegularizedGamma.Q.value(mu, mu * x * x / omega); + } + + /** {@inheritDoc} */ + @Override public double getMean() { return Gamma.value(mu + 0.5) / Gamma.value(mu) * Math.sqrt(omega / mu); } diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NormalDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NormalDistribution.java index 6817a6f..37213ec 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NormalDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NormalDistribution.java @@ -96,6 +96,16 @@ public class NormalDistribution extends AbstractContinuousDistribution { /** {@inheritDoc} */ @Override + public double survivalProbability(double x) { + final double dev = x - mean; + if (Math.abs(dev) > 40 * standardDeviation) { + return dev > 0 ? 0.0d : 1.0d; + } + return 0.5 * Erfc.value(dev / (standardDeviation * SQRT2)); + } + + /** {@inheritDoc} */ + @Override public double inverseCumulativeProbability(final double p) { if (p < 0 || p > 1) { diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ParetoDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ParetoDistribution.java index eb45bd5..51bff39 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ParetoDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ParetoDistribution.java @@ -126,7 +126,17 @@ public class ParetoDistribution extends AbstractContinuousDistribution { if (x <= scale) { return 0; } - return 1 - Math.pow(scale / x, shape); + // Can be improved by improving log calculation + return -Math.expm1(shape * Math.log(scale / x)); + } + + /** {@inheritDoc} */ + @Override + public double survivalProbability(double x) { + if (x <= scale) { + return 1; + } + return Math.pow(scale / x, shape); } /** diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java index 612a89c..f1f90a8 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java @@ -112,6 +112,12 @@ public class TDistribution extends AbstractContinuousDistribution { } } + /** {@inheritDoc} */ + @Override + public double survivalProbability(double x) { + return cumulativeProbability(-x); + } + /** * {@inheritDoc} * diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/WeibullDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/WeibullDistribution.java index d79c001..60505d9 100644 --- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/WeibullDistribution.java +++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/WeibullDistribution.java @@ -126,7 +126,17 @@ public class WeibullDistribution extends AbstractContinuousDistribution { return 0; } - return 1 - Math.exp(-Math.pow(x / scale, shape)); + return -Math.expm1(-Math.pow(x / scale, shape)); + } + + /** {@inheritDoc} */ + @Override + public double survivalProbability(double x) { + if (x <= SUPPORT_LO) { + return 1; + } + + return Math.exp(-Math.pow(x / scale, shape)); } /** diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java index 8e2ce43..ee0aec1 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java @@ -29,10 +29,13 @@ class BetaDistributionTest { static final double[] ALPHA_BETAS = {0.1, 1, 10, 100, 1000}; static final double EPSILON = StatUtils.min(ALPHA_BETAS); + static final double[] CUMULATIVE_TEST_POINTS = new double[]{ + -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1 + }; @Test void testCumulative() { - final double[] x = new double[]{-0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1}; + final double[] x = CUMULATIVE_TEST_POINTS; // all test data computed using R 2.5 checkCumulative(0.1, 0.1, x, new double[]{ @@ -149,6 +152,72 @@ class BetaDistributionTest { 0.710208, 0.873964, 0.966656, 0.997272, 1.000000, 1.000000}); } + @Test + void testSurvival() { + checkSurvival(1, 1, new double[]{ + 0.0, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.0}); + checkSurvival(4, 1, new double[]{ + 0.0000, 0.0000, 0.0001, 0.0016, 0.0081, 0.0256, 0.0625, 0.1296, 0.2401, + 0.4096, 0.6561, 1.0000, 1.0000}); + checkSurvival(2, 4, new double[]{ + 0.00000, 0.00000, 0.08146, 0.26272, 0.47178, 0.66304, 0.81250, 0.91296, + 0.96922, 0.99328, 0.99954, 1.00000, 1.00000}); + } + + @Test + void testCumulativeAndSurvivalComplement() { + checkCumulativeSurvivalComplement(0.1, 0.1); + checkCumulativeSurvivalComplement(0.1, 0.5); + checkCumulativeSurvivalComplement(0.1, 1.0); + checkCumulativeSurvivalComplement(0.1, 2.0); + checkCumulativeSurvivalComplement(0.1, 4.0); + checkCumulativeSurvivalComplement(0.5, 0.1); + checkCumulativeSurvivalComplement(0.5, 0.5); + checkCumulativeSurvivalComplement(0.5, 1.0); + checkCumulativeSurvivalComplement(0.5, 2.0); + checkCumulativeSurvivalComplement(0.5, 4.0); + checkCumulativeSurvivalComplement(1.0, 0.1); + checkCumulativeSurvivalComplement(1.0, 0.5); + checkCumulativeSurvivalComplement(1, 1); + checkCumulativeSurvivalComplement(1, 2); + checkCumulativeSurvivalComplement(1, 4); + checkCumulativeSurvivalComplement(2.0, 0.1); + checkCumulativeSurvivalComplement(2, 1); + checkCumulativeSurvivalComplement(2.0, 0.5); + checkCumulativeSurvivalComplement(2, 2); + checkCumulativeSurvivalComplement(2, 4); + checkCumulativeSurvivalComplement(4.0, 0.1); + checkCumulativeSurvivalComplement(4.0, 0.5); + checkCumulativeSurvivalComplement(4, 1); + checkCumulativeSurvivalComplement(4, 2); + checkCumulativeSurvivalComplement(4, 4); + } + + /** Precision tests for verifying that CDF calculates accurately in cases where 1-cdf(x) is inaccurately 1. */ + @Test + void testCumulativePrecision() { + // Calculated using WolframAlpha + checkCumulativePrecision(5.0, 5.0, 0.0001, 1.2595800539968654e-18); + checkCumulativePrecision(4.0, 5.0, 0.00001, 6.999776002800025e-19); + checkCumulativePrecision(5.0, 4.0, 0.0001, 5.598600119996539e-19); + checkCumulativePrecision(6.0, 2.0, 0.001, 6.994000000000028e-18); + checkCumulativePrecision(2.0, 6.0, 1e-9, 2.0999999930000014e-17); + } + + /** + * Precision tests for verifying that survivalFunction calculates accurately in cases + * where 1-sf(x) is inaccurately 1. + */ + @Test + void testSurvivalPrecision() { + // Calculated using WolframAlpha + checkSurvivalPrecision(5.0, 5.0, 0.9999, 1.2595800539961496e-18); + checkSurvivalPrecision(4.0, 5.0, 0.9999, 5.598600119993397e-19); + checkSurvivalPrecision(5.0, 4.0, 0.99998, 1.1199283217964632e-17); + checkSurvivalPrecision(6.0, 2.0, 0.999999999, 2.0999998742158932e-17); + checkSurvivalPrecision(2.0, 6.0, 0.999, 6.994000000000077e-18); + } + private void checkCumulative(double alpha, double beta, double[] x, double[] cumes) { final BetaDistribution d = new BetaDistribution(alpha, beta); for (int i = 0; i < x.length; i++) { @@ -160,6 +229,41 @@ class BetaDistributionTest { } } + private void checkSurvival(double alpha, double beta, double[] cumes) { + final BetaDistribution d = new BetaDistribution(alpha, beta); + for (int i = 0; i < CUMULATIVE_TEST_POINTS.length; i++) { + Assertions.assertEquals(1 - cumes[i], d.survivalProbability(CUMULATIVE_TEST_POINTS[i]), 1e-8); + } + } + + private void checkCumulativeSurvivalComplement(double alpha, double beta) { + final BetaDistribution d = new BetaDistribution(alpha, beta); + for (int i = 0; i < CUMULATIVE_TEST_POINTS.length; i++) { + double x = CUMULATIVE_TEST_POINTS[i]; + Assertions.assertEquals(1, d.cumulativeProbability(x) + d.survivalProbability(x), 1e-8); + } + } + + private void checkCumulativePrecision(double alpha, double beta, double value, double expected) { + final double tolerance = 1e-22; + BetaDistribution d = new BetaDistribution(alpha, beta); + TestUtils.assertEquals( + "cumulative probability not precise at " + value + " for a=" + alpha + " & b=" + beta, + d.cumulativeProbability(value), + expected, + tolerance); + } + + private void checkSurvivalPrecision(double alpha, double beta, double value, double expected) { + final double tolerance = 1e-22; + BetaDistribution d = new BetaDistribution(alpha, beta); + TestUtils.assertEquals( + "survival function not precise at " + value + " for a=" + alpha + " & b=" + beta, + d.survivalProbability(value), + expected, + tolerance); + } + @Test void testDensity() { final double[] x = new double[]{1e-6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9}; diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java index 4d07667..61a283e 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java @@ -28,7 +28,7 @@ import org.junit.jupiter.api.Test; */ class CauchyDistributionTest extends ContinuousDistributionAbstractTest { - private static final double DEFAULT_TOLERANCE = 1e-7; + private static final double DEFAULT_TOLERANCE = 1e-8; //---------------------- Override tolerance -------------------------------- @@ -67,6 +67,28 @@ class CauchyDistributionTest extends ContinuousDistributionAbstractTest { 1.49599158008e-06, 0.000149550440335, 0.000933076881878, 0.00370933207799, 0.0144742330437}; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {-1e16}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {5.551115123125783e-17}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {1e16}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return makeCumulativePrecisionTestValues(); + } + //-------------------- Additional test cases ------------------------------- @Test diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java index 921129b..e8030a3 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java @@ -79,6 +79,28 @@ class ChiSquaredDistributionTest extends ContinuousDistributionAbstractTest { 0.000433630076361, 0.00412780610309, 0.00999340341045, 0.0193246438937, 0.0368460089216}; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {1e-7, 4e-7, 9e-8}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {1.6820882879388572e-19, 5.382681944688393e-18, 1.292572946953654e-19}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {93, 97.3}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {1.5731947657596637e-18, 1.9583114656146269e-19}; + } + //-------------------- Additional test cases ------------------------------- @Test diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ContinuousDistributionAbstractTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ContinuousDistributionAbstractTest.java index b7044f8..260d7c7 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ContinuousDistributionAbstractTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ContinuousDistributionAbstractTest.java @@ -46,6 +46,20 @@ import org.junit.jupiter.api.BeforeEach; * makeInverseCumulativeTestPoints() -- arguments used to test inverse cdf * makeInverseCumulativeTestValues() -- expected inverse cdf values * <p> + * If the continuous distribution provides higher precision implementations of cumulativeProbability + * and/or survivalProbability, the following methods should be implemented to provide testing. + * To use these tests, calculate the cumulativeProbability and survivalProbability such that their naive + * complement is exceptionally close to `1` and consequently could lose precision due to floating point + * arithmetic. + * + * NOTE: The default high-precision threshold is 1e-22. + * <pre> + * makeCumulativePrecisionTestPoints() -- high precision test inputs + * makeCumulativePrecisionTestValues() -- high precision expected results + * makeSurvivalPrecisionTestPoints() -- high precision test inputs + * makeSurvivalPrecisionTestValues() -- high precision expected results + * </pre> + * <p> * To implement additional test cases with different distribution instances and * test data, use the setXxx methods for the instance data in test cases and * call the verifyXxx methods to verify results. @@ -69,12 +83,27 @@ abstract class ContinuousDistributionAbstractTest { /** Tolerance used in comparing expected and returned values */ private double tolerance = 1e-4; + /** Tolerance used in high precision tests */ + private final double highPrecisionTolerance = 1e-22; + /** Arguments used to test cumulative probability density calculations */ private double[] cumulativeTestPoints; /** Values used to test cumulative probability density calculations */ private double[] cumulativeTestValues; + /** Arguments used to test cumulative probability precision, effectively any x where 1-cdf(x) would result in 1 */ + private double[] cumulativePrecisionTestPoints; + + /** Values used to test cumulative probability precision, usually exceptionally tiny values */ + private double[] cumulativePrecisionTestValues; + + /** Arguments used to test survival probability precision, effectively any x where 1-sf(x) would result in 1 */ + private double[] survivalPrecisionTestPoints; + + /** Values used to test survival probability precision, usually exceptionally tiny values */ + private double[] survivalPrecisionTestValues; + /** Arguments used to test inverse cumulative probability density calculations */ private double[] inverseCumulativeTestPoints; @@ -98,6 +127,34 @@ abstract class ContinuousDistributionAbstractTest { /** Creates the default cumulative probability test expected values */ public abstract double[] makeCumulativeTestValues(); + /** Creates the default cumulative probability precision test input values */ + public double[] makeCumulativePrecisionTestPoints() { + return new double[0]; + } + + /** + * Creates the default cumulative probability precision test expected values. + * Note: The default threshold is 1e-22, any expected values with much higher precision may + * not test the desired results without increasing precision threshold. + */ + public double[] makeCumulativePrecisionTestValues() { + return new double[0]; + } + + /** Creates the default survival probability precision test input values */ + public double[] makeSurvivalPrecisionTestPoints() { + return new double[0]; + } + + /** + * Creates the default survival probability precision test expected values. + * Note: The default threshold is 1e-22, any expected values with much higher precision may + * not test the desired results without increasing precision threshold. + */ + public double[] makeSurvivalPrecisionTestValues() { + return new double[0]; + } + /** Creates the default density test expected values */ public abstract double[] makeDensityTestValues(); @@ -138,6 +195,10 @@ abstract class ContinuousDistributionAbstractTest { distribution = makeDistribution(); cumulativeTestPoints = makeCumulativeTestPoints(); cumulativeTestValues = makeCumulativeTestValues(); + cumulativePrecisionTestPoints = makeCumulativePrecisionTestPoints(); + cumulativePrecisionTestValues = makeCumulativePrecisionTestValues(); + survivalPrecisionTestPoints = makeSurvivalPrecisionTestPoints(); + survivalPrecisionTestValues = makeSurvivalPrecisionTestValues(); inverseCumulativeTestPoints = makeInverseCumulativeTestPoints(); inverseCumulativeTestValues = makeInverseCumulativeTestValues(); densityTestValues = makeDensityTestValues(); @@ -191,6 +252,54 @@ abstract class ContinuousDistributionAbstractTest { } } + protected void verifySurvivalProbability() { + for (int i = 0; i < cumulativeTestPoints.length; i++) { + TestUtils.assertEquals("Incorrect survival probability value returned for " + + cumulativeTestPoints[i], 1 - cumulativeTestValues[i], + distribution.survivalProbability(cumulativeTestPoints[i]), + getTolerance()); + } + } + + protected void verifySurvivalAndCumulativeProbabilityComplement() { + for (final double x : cumulativeTestPoints) { + TestUtils.assertEquals("survival + cumulative probability were not close to 1.0" + + x, 1.0, + distribution.survivalProbability(x) + distribution.cumulativeProbability(x), + getTolerance()); + } + } + + /** + * Verifies that survival is simply not 1-cdf by testing calculations that would underflow that calculation and + * result in an inaccurate answer. + */ + protected void verifySurvivalProbabilityPrecision() { + for (int i = 0; i < survivalPrecisionTestPoints.length; i++) { + final double x = survivalPrecisionTestPoints[i]; + TestUtils.assertEquals( + "survival probability is not precise for value " + x, + survivalPrecisionTestValues[i], + distribution.survivalProbability(x), + getHighPrecisionTolerance()); + } + } + + /** + * Verifies that CDF is simply not 1-survival function by testing values that would result with inaccurate results + * if simply calculating 1-survival function. + */ + protected void verifyCumulativeProbabilityPrecision() { + for (int i = 0; i < cumulativePrecisionTestPoints.length; i++) { + final double x = cumulativePrecisionTestPoints[i]; + TestUtils.assertEquals( + "cumulative probability is not precise for value " + x, + cumulativePrecisionTestValues[i], + distribution.cumulativeProbability(x), + getHighPrecisionTolerance()); + } + } + /** * Verifies that inverse cumulative probability density calculations match expected values * using current test instance data @@ -239,6 +348,26 @@ abstract class ContinuousDistributionAbstractTest { verifyCumulativeProbabilities(); } + @Test + void testSurvivalProbability() { + verifySurvivalProbability(); + } + + @Test + void testSurvivalAndCumulativeProbabilitiesAreComplementary() { + verifySurvivalAndCumulativeProbabilityComplement(); + } + + @Test + void testCumulativeProbabilityPrecision() { + verifyCumulativeProbabilityPrecision(); + } + + @Test + void testSurvivalProbabilityPrecision() { + verifySurvivalProbabilityPrecision(); + } + /** * Verifies that inverse cumulative probability density calculations match expected values * using default test instance data @@ -319,6 +448,8 @@ abstract class ContinuousDistributionAbstractTest { Assertions.assertEquals(Double.NEGATIVE_INFINITY, distribution.logDensity(above)); Assertions.assertEquals(0d, distribution.cumulativeProbability(below)); Assertions.assertEquals(1d, distribution.cumulativeProbability(above)); + Assertions.assertEquals(1d, distribution.survivalProbability(below)); + Assertions.assertEquals(0d, distribution.survivalProbability(above)); } /** @@ -497,6 +628,13 @@ abstract class ContinuousDistributionAbstractTest { } /** + * @return Returns the high precision tolerance + */ + protected double getHighPrecisionTolerance() { + return highPrecisionTolerance; + } + + /** * @param tolerance The tolerance to set. */ protected void setTolerance(double tolerance) { diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ExponentialDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ExponentialDistributionTest.java index c62f638..2be38be 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ExponentialDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ExponentialDistributionTest.java @@ -65,6 +65,29 @@ class ExponentialDistributionTest extends ContinuousDistributionAbstractTest { 0.00200000000002, 0.00499999999997, 0.00999999999994, 0.0199999999999}; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {1e-15, 4e-16, 9e-16}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // calculated via scipy, specifically expon.cdf(x/5). + // WolframAlpha provided either too accurate or inaccurate values + return new double[] {2.0000000000000002e-16, 7.999999999999999e-17, 1.8000000000000002e-16}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {183, 197}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha. NOTE lambda parameter is 1/mean + return new double[] {1.2729811194234181e-16, 7.741006159285781e-18}; + } + //------------ Additional tests ------------------------------------------- @Test diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/FDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/FDistributionTest.java index ae87559..8f692b2 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/FDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/FDistributionTest.java @@ -63,6 +63,28 @@ class FDistributionTest extends ContinuousDistributionAbstractTest { 0.000133443915657, 0.00286681303403, 0.00969192007502, 0.0242883861471, 0.0605491314658}; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {1e-7, 4e-8, 9e-8}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {1.578691625481747e-17, 1.597523916857153e-18, 1.2131195257872846e-17}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {1e6, 42e5, 63e5}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {1.1339943867175144e-17, 1.5306104409634358e-19, 4.535143828961954e-20}; + } + //-------------------- Additional test cases ------------------------------- @Test diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GammaDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GammaDistributionTest.java index 11e3b93..72abf34 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GammaDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GammaDistributionTest.java @@ -73,6 +73,28 @@ class GammaDistributionTest extends ContinuousDistributionAbstractTest { 0.000394468852816, 0.00366559696761, 0.00874649473311, 0.0166712508128, 0.0311798227954}; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {1e-4, 9e-5}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {2.6040625021701086e-19, 1.7085322417782863e-19}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {99, 103}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {6.833817088979342e-18, 1.0390567840208212e-18}; + } + //-------------------- Additional test cases ------------------------------- @Test diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GumbelDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GumbelDistributionTest.java index e90fde0..ea90adf 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GumbelDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GumbelDistributionTest.java @@ -54,6 +54,28 @@ class GumbelDistributionTest extends ContinuousDistributionAbstractTest { }; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {-7.0, -7.1}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha, specifically =CDF[ExtremeValueDistribution[0.5, 2], x] + return new double[] {3.414512624812977e-19, 3.859421750095851e-20}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {75}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // Not calculated via WolframAlpha, instead utilizing scipy gumbel_r, Wolframalpha could not get precise enough + return new double[] {6.64554417291507e-17}; + } + //-------------------- Additional test cases ------------------------------- @Test diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LaplaceDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LaplaceDistributionTest.java index ce066b5..117f4a1 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LaplaceDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LaplaceDistributionTest.java @@ -54,6 +54,30 @@ class LaplaceDistributionTest extends ContinuousDistributionAbstractTest { }; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + // Negative values only as anything > 0 falls into an imprecise calculation by being subtracted from 1 + return new double[] {-42, -43}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {2.87476113214678e-19, 1.0575655187955402e-19}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + // Positive values only as anything < 0 falls into an imprecise calculation by being subtracted from 1 + return new double[] {42, 43}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {2.87476113214678e-19, 1.0575655187955402e-19}; + } + //-------------------- Additional test cases ------------------------------- @Test diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LevyDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LevyDistributionTest.java index 977b4dd..558a3d7 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LevyDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LevyDistributionTest.java @@ -65,6 +65,28 @@ class LevyDistributionTest extends ContinuousDistributionAbstractTest { -2.650679030597d, -3.644945255983d}; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {1.205, 1.2049}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {3.7440973842063723e-19, 1.6388396909072308e-19}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {1e39, 42e37}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {1.5957691216057308e-20, 2.4623252122982907e-20}; + } + //-------------------- Additional test cases ------------------------------- @Test diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogNormalDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogNormalDistributionTest.java index f5c5cb6..711602a 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogNormalDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogNormalDistributionTest.java @@ -32,7 +32,7 @@ class LogNormalDistributionTest extends ContinuousDistributionAbstractTest { @BeforeEach void customSetUp() { - setTolerance(1e-7); + setTolerance(1e-10); } //-------------- Implementations for abstract methods ---------------------- @@ -102,6 +102,28 @@ class LogNormalDistributionTest extends ContinuousDistributionAbstractTest { //return Arrays.copyOfRange(points, 1, points.length - 4); } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {4e-5, 7e-5}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {1.2366527173500762e-18, 3.9216120913158885e-17}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {999999, 2e6}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {2.924727705260493e-17, 3.8830698713006447e-19}; + } + //-------------------- Additional test cases ------------------------------- private void verifyQuantiles() { @@ -169,6 +191,15 @@ class LogNormalDistributionTest extends ContinuousDistributionAbstractTest { } @Test + void testSurvivalProbabilityExtremes() { + // Use a small shape parameter so that we can exceed 40 * shape + setDistribution(new LogNormalDistribution(1, 0.0001)); + setCumulativeTestPoints(new double[] {0.5, 10}); + setCumulativeTestValues(new double[] {0, 1.0}); + verifySurvivalProbability(); + } + + @Test void testParameterAccessors() { final LogNormalDistribution distribution = (LogNormalDistribution)getDistribution(); Assertions.assertEquals(2.1, distribution.getScale()); diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticsDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticsDistributionTest.java index e334b48..e0d9ef0 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticsDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticsDistributionTest.java @@ -54,6 +54,28 @@ class LogisticsDistributionTest extends ContinuousDistributionAbstractTest { }; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {-197, -203}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {5.188951605054656e-18, 1.5628821893349888e-18}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {197, 203}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {1.1548224173015786e-17, 3.478258278776922e-18}; + } + //-------------------- Additional test cases ------------------------------- @Test diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NakagamiDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NakagamiDistributionTest.java index d9d5934..a158c80 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NakagamiDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NakagamiDistributionTest.java @@ -54,6 +54,28 @@ class NakagamiDistributionTest extends ContinuousDistributionAbstractTest { }; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {1e-16, 4e-17}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {7.978845608028653e-17, 3.1915382432114614e-17}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {9, 8.7}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {2.2571768119076845e-19, 3.318841739929575e-18}; + } + //-------------------- Additional test cases ------------------------------- @Test diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java index 87fd6a9..940d162 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java @@ -28,7 +28,7 @@ import org.junit.jupiter.api.Test; */ class NormalDistributionTest extends ContinuousDistributionAbstractTest { - private static final double DEFAULT_TOLERANCE = 1e-7; + private static final double DEFAULT_TOLERANCE = 1e-10; //---------------------- Override tolerance -------------------------------- @@ -67,6 +67,28 @@ class NormalDistributionTest extends ContinuousDistributionAbstractTest { 0.00240506434076, 0.0190372444310, 0.0417464784322, 0.0736683145538, 0.125355951380}; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {-10, -10.3}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {2.741222634611109e-18, 4.1045652533919113e-19}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {14.5, 13.9}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {4.1045652533919576e-19, 1.749552800697539e-17}; + } + //-------------------- Additional test cases ------------------------------- private void verifyQuantiles() { diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java index 73b13d3..9d962df 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java @@ -31,7 +31,7 @@ class ParetoDistributionTest extends ContinuousDistributionAbstractTest { @BeforeEach void customSetUp() { - setTolerance(1e-7); + setTolerance(1e-9); } //-------------- Implementations for abstract methods ---------------------- @@ -90,6 +90,28 @@ class ParetoDistributionTest extends ContinuousDistributionAbstractTest { return points2; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {2.100000000000001, 2.100000000000005}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were not created using WolframAlpha, the calculation for Math.log underflows in java + return new double[] {6.217248937900875e-16, 3.2640556923979585e-15}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {42e11, 64e11}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {6.005622169907148e-18, 3.330082930386111e-18}; + } + //-------------------- Additional test cases ------------------------------- private void verifyQuantiles() { diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java index 0ef996a..bcab69f 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java @@ -63,6 +63,28 @@ class TDistributionTest extends ContinuousDistributionAbstractTest { 0.000756494565517, 0.0109109752919, 0.0303377878006, 0.0637967988952, 0.128289492005}; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {-4200, -6400}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {7.261513520181652e-18, 8.838404680725267e-19}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {4200, 6400}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {7.261513520181652e-18, 8.838404680725267e-19}; + } + //-------------------- Additional test cases ------------------------------- /** diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java index 02df59a..c35056f 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java @@ -19,6 +19,7 @@ package org.apache.commons.statistics.distribution; import org.apache.commons.numbers.gamma.LogGamma; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** @@ -28,6 +29,11 @@ import org.junit.jupiter.api.Test; */ class WeibullDistributionTest extends ContinuousDistributionAbstractTest { + @BeforeEach + void customSetUp() { + setTolerance(1e-10); + } + //-------------- Implementations for abstract methods ---------------------- /** Creates the default continuous distribution instance to use in tests. */ @@ -57,6 +63,28 @@ class WeibullDistributionTest extends ContinuousDistributionAbstractTest { 0.353441418887, 0.000788590320203, 0.00737060094841, 0.0177576041516, 0.0343043442574, 0.065664589369}; } + @Override + public double[] makeCumulativePrecisionTestPoints() { + return new double[] {1e-14, 1e-15}; + } + + @Override + public double[] makeCumulativePrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {6.506341377907031e-18, 4.1052238780858223e-19}; + } + + @Override + public double[] makeSurvivalPrecisionTestPoints() { + return new double[] {45, 47.2}; + } + + @Override + public double[] makeSurvivalPrecisionTestValues() { + // These were created using WolframAlpha + return new double[] {6.6352694710268576e-18, 6.444810903667567e-19}; + } + //-------------------- Additional test cases ------------------------------- @Test