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 de690c8cb54c9c67b548d6f2355b8ae7e33f2c40 Author: Alex Herbert <aherb...@apache.org> AuthorDate: Sat Jul 31 00:06:27 2021 +0100 Add explicit logDensity computation Expands the range where computation is possible to allow logDensity(x) when density(x) == 0 for: - Logistic - Nakagami Added tests to demonstrate this. --- .../statistics/distribution/LogisticDistribution.java | 13 +++++++++++++ .../statistics/distribution/NakagamiDistribution.java | 15 +++++++++++++++ .../statistics/distribution/LogisticDistributionTest.java | 10 ++++++++++ .../statistics/distribution/NakagamiDistributionTest.java | 9 +++++++++ 4 files changed, 47 insertions(+) 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 7bbdebd..f945274 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 @@ -85,6 +85,19 @@ public class LogisticDistribution extends AbstractContinuousDistribution { /** {@inheritDoc} */ @Override + public double logDensity(double x) { + if (x <= SUPPORT_LO || + x >= SUPPORT_HI) { + return Double.NEGATIVE_INFINITY; + } + + final double z = oneOverScale * (x - mu); + final double v = Math.exp(-z); + return -Math.log(scale) - z - 2 * Math.log(1 + v); + } + + /** {@inheritDoc} */ + @Override public double cumulativeProbability(double x) { final double z = oneOverScale * (x - mu); return 1 / (1 + Math.exp(-z)); 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 05429d4..db838b2 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 @@ -17,6 +17,7 @@ package org.apache.commons.statistics.distribution; import org.apache.commons.numbers.gamma.Gamma; +import org.apache.commons.numbers.gamma.LogGamma; import org.apache.commons.numbers.gamma.RegularizedGamma; /** @@ -29,6 +30,8 @@ public class NakagamiDistribution extends AbstractContinuousDistribution { private static final double SUPPORT_HI = Double.POSITIVE_INFINITY; /** The minimum allowed for the shape parameter. */ private static final double MIN_SHAPE = 0.5; + /** Natural logarithm of 2. */ + private static final double LN_2 = 0.6931471805599453094172321; /** The shape parameter. */ private final double mu; @@ -88,6 +91,18 @@ public class NakagamiDistribution extends AbstractContinuousDistribution { /** {@inheritDoc} */ @Override + public double logDensity(double x) { + if (x <= SUPPORT_LO || + x >= SUPPORT_HI) { + return Double.NEGATIVE_INFINITY; + } + + return LN_2 + Math.log(mu) * mu - LogGamma.value(mu) - Math.log(omega) * mu + + Math.log(x) * (2 * mu - 1) - (mu * x * x / omega); + } + + /** {@inheritDoc} */ + @Override public double cumulativeProbability(double x) { if (x <= SUPPORT_LO) { return 0; diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticDistributionTest.java index b367283..25b5c51 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticDistributionTest.java @@ -79,6 +79,16 @@ class LogisticDistributionTest extends ContinuousDistributionAbstractTest { //-------------------- Additional test cases ------------------------------- @Test + void testExtremeLogDensity() { + final double scale = 2.5; + final LogisticDistribution dist = new LogisticDistribution(0, scale); + final double x = 1e160; + Assertions.assertEquals(0.0, dist.density(x)); + final double expected = -Math.log(scale) - x / scale; + Assertions.assertEquals(expected, dist.logDensity(x), Math.abs(expected) * 1e-14); + } + + @Test void testInverseCumulativeProbabilityExtremes() { setInverseCumulativeTestPoints(new double[] {0, 1}); setInverseCumulativeTestValues(new double[] {Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}); 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 9382de0..4ff0bba 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 @@ -79,6 +79,15 @@ class NakagamiDistributionTest extends ContinuousDistributionAbstractTest { //-------------------- Additional test cases ------------------------------- @Test + void testExtremeLogDensity() { + // XXX: Verify with more test data from a reference distribution + final NakagamiDistribution dist = new NakagamiDistribution(0.5, 1); + final double x = 50; + Assertions.assertEquals(0.0, dist.density(x)); + Assertions.assertEquals(-1250.22579, dist.logDensity(x), 1e-4); + } + + @Test void testParameterAccessors() { final NakagamiDistribution dist = makeDistribution(); Assertions.assertEquals(0.5, dist.getShape());