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());

Reply via email to