You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2021/09/22 11:15:53 UTC

[commons-statistics] 03/03: Additional parameterisation tests for Nakagami distribution

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 d797bf2da350a8e111ecdad8f84b65627c2c6ae2
Author: aherbert <ah...@apache.org>
AuthorDate: Wed Sep 22 12:13:59 2021 +0100

    Additional parameterisation tests for Nakagami distribution
    
    Support any positive shape parameter. The limit of mu >= 0.5 on the
    wikipedia reference is incorrect.
---
 .../distribution/NakagamiDistribution.java         |  6 +-
 .../distribution/NakagamiDistributionTest.java     | 94 +++++++++++++++++++---
 2 files changed, 84 insertions(+), 16 deletions(-)

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 c17f034..de7a8a7 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
@@ -28,8 +28,6 @@ public class NakagamiDistribution extends AbstractContinuousDistribution {
     private static final double SUPPORT_LO = 0;
     /** Support upper bound. */
     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;
 
@@ -52,8 +50,8 @@ public class NakagamiDistribution extends AbstractContinuousDistribution {
      */
     public NakagamiDistribution(double mu,
                                 double omega) {
-        if (mu < MIN_SHAPE) {
-            throw new DistributionException(DistributionException.TOO_SMALL, mu, MIN_SHAPE);
+        if (mu <= 0) {
+            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, mu);
         }
         if (omega <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, omega);
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 3acd437..e27b4b9 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
@@ -28,6 +28,11 @@ class NakagamiDistributionTest extends ContinuousDistributionAbstractTest {
 
     //-------------- Implementations for abstract methods ----------------------
 
+    // Test values created using scipy.stats nakagami
+    // The distribution is not defined for x=0.
+    // Some implementations compute the formula and return the natural limit as x -> 0.
+    // This implementation returns zero for any x outside the domain.
+
     @Override
     public NakagamiDistribution makeDistribution() {
         return new NakagamiDistribution(0.5, 1);
@@ -36,23 +41,29 @@ class NakagamiDistributionTest extends ContinuousDistributionAbstractTest {
     @Override
     public double[] makeCumulativeTestPoints() {
         return new double[] {
-            0, 0.2, 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8, 2
+            0, 1e-3, 0.2, 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8, 2
         };
     }
 
     @Override
     public double[] makeDensityTestValues() {
         return new double[] {
-            0.0000000, 0.7820854, 0.7365403, 0.6664492, 0.5793831, 0.4839414,
-            0.3883721, 0.2994549, 0.2218417, 0.1579003, 0.1079819
+            0.0,                 0.79788416186068489, 0.78208538795091187,
+            0.73654028060664678, 0.66644920578359934, 0.57938310552296557,
+            0.48394144903828679, 0.38837210996642596, 0.29945493127148981,
+            0.22184166935891111, 0.15790031660178833, 0.10798193302637614,
         };
     }
 
     @Override
     public double[] makeCumulativeTestValues() {
         return new double[] {
-            0.0000000, 0.1585194, 0.3108435, 0.4514938, 0.5762892, 0.6826895,
-            0.7698607, 0.8384867, 0.8904014, 0.9281394, 0.9544997
+            0.0,                     7.97884427822125389e-04,
+            1.58519418878206031e-01, 3.10843483220648364e-01,
+            4.51493764499852956e-01, 5.76289202833206615e-01,
+            6.82689492137085852e-01, 7.69860659556583560e-01,
+            8.38486681532458089e-01, 8.90401416600884343e-01,
+            9.28139361774148575e-01, 9.54499736103641472e-01,
         };
     }
 
@@ -81,6 +92,66 @@ class NakagamiDistributionTest extends ContinuousDistributionAbstractTest {
     //-------------------- Additional test cases -------------------------------
 
     @Test
+    void testAdditionalDistribution1() {
+        final NakagamiDistribution dist = new NakagamiDistribution(1.0 / 3, 1);
+        setDistribution(dist);
+        setCumulativeTestPoints(makeCumulativeTestPoints());
+        // Computed using scipy.stats nakagami
+        setCumulativeTestValues(new double[] {
+            0.,                  0.00776458146673576, 0.26466318463713673,
+            0.41599060641445568, 0.53633771818837206, 0.63551561797542433,
+            0.71746556659624028, 0.7845448997061909,  0.83861986211366601,
+            0.88141004735798412, 0.91458032800205946, 0.93973541101651015
+        });
+        setDensityTestValues(new double[] {
+            0,                   5.17638635039373352, 0.8734262427029803,
+            0.66605658341650675, 0.54432849968092045, 0.45048535438453824,
+            0.3709044132031733,  0.30141976583757241, 0.24075672187548078,
+            0.18853365020699897, 0.14451001716499515, 0.10829893529327907
+        });
+        setInverseCumulativeTestPoints(getCumulativeTestValues());
+        setInverseCumulativeTestValues(getCumulativeTestPoints());
+        verifyDensities();
+        verifyLogDensities();
+        verifyCumulativeProbabilities();
+        verifySurvivalProbability();
+        verifySurvivalAndCumulativeProbabilityComplement();
+        verifyInverseCumulativeProbabilities();
+    }
+
+    @Test
+    void testAdditionalDistribution2() {
+        final NakagamiDistribution dist = new NakagamiDistribution(1.5, 2);
+        setDistribution(dist);
+        setCumulativeTestPoints(makeCumulativeTestPoints());
+        // Computed using matlab (scipy.stats does not support the omega parameter)
+        setCumulativeTestValues(new double[] {
+            0,                 0.000000000488602,
+            0.003839209349952, 0.029112642643164,
+            0.089980307387723, 0.189070530913232,
+            0.317729669663787, 0.460129965238200,
+            0.599031192110653, 0.720732382881390,
+            0.817659600745483, 0.888389774905287,
+        });
+        setDensityTestValues(new double[] {
+            0,                 0.000001465806436,
+            0.056899455042812, 0.208008745554258,
+            0.402828269545621, 0.580491109555755,
+            0.692398452624549, 0.716805620039994,
+            0.660571957322857, 0.550137830087772,
+            0.418105970486118, 0.291913039977849,
+        });
+        setInverseCumulativeTestPoints(getCumulativeTestValues());
+        setInverseCumulativeTestValues(getCumulativeTestPoints());
+        verifyDensities();
+        verifyLogDensities();
+        verifyCumulativeProbabilities();
+        verifySurvivalProbability();
+        verifySurvivalAndCumulativeProbabilityComplement();
+        verifyInverseCumulativeProbabilities();
+    }
+
+    @Test
     void testExtremeLogDensity() {
         // XXX: Verify with more test data from a reference distribution
         final NakagamiDistribution dist = new NakagamiDistribution(0.5, 1);
@@ -100,15 +171,10 @@ class NakagamiDistributionTest extends ContinuousDistributionAbstractTest {
         Assertions.assertEquals(scale, dist.getScale());
     }
 
-    @Test
-    void testParameterAccessors() {
-        final NakagamiDistribution dist = makeDistribution();
-        Assertions.assertEquals(1, dist.getScale());
-    }
-
     @ParameterizedTest
     @CsvSource({
-        "0.4999, 1.0",
+        "0.0, 1.0",
+        "-0.1, 1.0",
         "0.5, 0.0",
         "0.5, -0.1",
     })
@@ -132,6 +198,10 @@ class NakagamiDistributionTest extends ContinuousDistributionAbstractTest {
         dist = new NakagamiDistribution(1.23, 2.5);
         Assertions.assertEquals(1.431786259006201, dist.getMean(), eps);
         Assertions.assertEquals(0.449988108521028, dist.getVariance(), eps);
+
+        dist = new NakagamiDistribution(1.0 / 3, 2.0);
+        Assertions.assertEquals(1.032107387207478, dist.getMean(), eps);
+        Assertions.assertEquals(0.934754341271753, dist.getVariance(), eps);
     }
 
     @Test