This is an automated email from the ASF dual-hosted git repository.

erans pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-math.git


The following commit(s) were added to refs/heads/master by this push:
     new 0df313b  MATH-1401: Cover all possible inputs.
0df313b is described below

commit 0df313bef62d5fedc18286b80fc93248b5f180fd
Author: Gilles Sadowski <[email protected]>
AuthorDate: Thu Apr 18 14:43:27 2019 +0200

    MATH-1401: Cover all possible inputs.
    
    Thanks to Michele De Stefano.
---
 src/changes/changes.xml                            |  4 +-
 .../stat/interval/ClopperPearsonInterval.java      | 22 ++++----
 .../stat/interval/ClopperPearsonIntervalTest.java  | 64 ++++++++++++++++++++++
 3 files changed, 76 insertions(+), 14 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 8b5f8e5..090969c 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -54,8 +54,8 @@ If the output is not quite correct, check for invisible 
trailing spaces!
     </release>
 
     <release version="4.0" date="XXXX-XX-XX" description="">
-      <action dev="erans" type="fix" issue="MATH-1401">
-        "ClopperPearsonInterval": Fixed case where number of trials equals 
number of successes.
+      <action dev="erans" type="fix" issue="MATH-1401" due-to="Michele De 
Stefano">
+        "ClopperPearsonInterval": Missing cases.
       </action>
       <action dev="erans" type="add" issue="MATH-1477" due-to="Chee Sing Lee">
         "MillerUpdatingRegression": Fixed "ArrayIndexOutOfBounds" exception.
diff --git 
a/src/main/java/org/apache/commons/math4/stat/interval/ClopperPearsonInterval.java
 
b/src/main/java/org/apache/commons/math4/stat/interval/ClopperPearsonInterval.java
index 5bf642c..27cdc84 100644
--- 
a/src/main/java/org/apache/commons/math4/stat/interval/ClopperPearsonInterval.java
+++ 
b/src/main/java/org/apache/commons/math4/stat/interval/ClopperPearsonInterval.java
@@ -35,26 +35,24 @@ public class ClopperPearsonInterval implements 
BinomialConfidenceInterval {
                                              double confidenceLevel) {
         IntervalUtils.checkParameters(numberOfTrials, numberOfSuccesses, 
confidenceLevel);
         double lowerBound = 0;
-        double upperBound = 0;
+        double upperBound = 1;
 
-        if (numberOfSuccesses > 0) {
-            final double alpha = 0.5 * (1 - confidenceLevel);
+        final double alpha = 0.5 * (1 - confidenceLevel);
 
+        if (numberOfSuccesses > 0) {
             final FDistribution distributionLowerBound = new FDistribution(2 * 
(numberOfTrials - numberOfSuccesses + 1),
                                                                            2 * 
numberOfSuccesses);
             final double fValueLowerBound = 
distributionLowerBound.inverseCumulativeProbability(1 - alpha);
             lowerBound = numberOfSuccesses /
                 (numberOfSuccesses + (numberOfTrials - numberOfSuccesses + 1) 
* fValueLowerBound);
+        }
 
-            if (numberOfSuccesses != numberOfTrials) {
-                final FDistribution distributionUpperBound = new 
FDistribution(2 * (numberOfSuccesses + 1),
-                                                                               
2 * (numberOfTrials - numberOfSuccesses));
-                final double fValueUpperBound = 
distributionUpperBound.inverseCumulativeProbability(1 - alpha);
-                upperBound = (numberOfSuccesses + 1) * fValueUpperBound /
-                    (numberOfTrials - numberOfSuccesses + (numberOfSuccesses + 
1) * fValueUpperBound);
-            } else {
-                upperBound = 1;
-            }
+        if (numberOfSuccesses < numberOfTrials) {
+            final FDistribution distributionUpperBound = new FDistribution(2 * 
(numberOfSuccesses + 1),
+                                                                           2 * 
(numberOfTrials - numberOfSuccesses));
+            final double fValueUpperBound = 
distributionUpperBound.inverseCumulativeProbability(1 - alpha);
+            upperBound = (numberOfSuccesses + 1) * fValueUpperBound /
+                (numberOfTrials - numberOfSuccesses + (numberOfSuccesses + 1) 
* fValueUpperBound);
         }
 
         return new ConfidenceInterval(lowerBound, upperBound, confidenceLevel);
diff --git 
a/src/test/java/org/apache/commons/math4/stat/interval/ClopperPearsonIntervalTest.java
 
b/src/test/java/org/apache/commons/math4/stat/interval/ClopperPearsonIntervalTest.java
index a8a1db1..6a06f97 100644
--- 
a/src/test/java/org/apache/commons/math4/stat/interval/ClopperPearsonIntervalTest.java
+++ 
b/src/test/java/org/apache/commons/math4/stat/interval/ClopperPearsonIntervalTest.java
@@ -46,4 +46,68 @@ public class ClopperPearsonIntervalTest extends 
BinomialConfidenceIntervalAbstra
         Assert.assertEquals(0.025, interval.getLowerBound(), 1e-16);
         Assert.assertEquals(1, interval.getUpperBound(), 0d);
     }
+
+    // number of successes = 0, number of trials = N
+    @Test
+    public void testCase1() {
+        // Check correctness against values obtained with the Python 
statsmodels.stats.proportion.proportion_confint
+        final int successes = 0;
+        final int trials = 10;
+        final double confidenceLevel = 0.95;
+
+        // proportion_confint(0,10,method='beta') = (0, 0.3084971078187608)
+        final ConfidenceInterval expected = new ConfidenceInterval(0,
+                                                                   
0.3084971078187608,
+                                                                   
confidenceLevel);
+
+        check(expected, 
createBinomialConfidenceInterval().createInterval(trials, successes, 
confidenceLevel));
+    }
+
+    // number of successes = number of trials = N
+    @Test
+    public void testCase2() {
+        // Check correctness against values obtained with the Python 
statsmodels.stats.proportion.proportion_confint
+        final int successes = 10;
+        final int trials = 10;
+        final double confidenceLevel = 0.95;
+
+        // prop.proportion_confint(10,10,method='beta') = (0.6915028921812392, 
1)
+        final ConfidenceInterval expected = new 
ConfidenceInterval(0.6915028921812392,
+                                                                   1,
+                                                                   
confidenceLevel);
+
+        check(expected, 
createBinomialConfidenceInterval().createInterval(trials, successes, 
confidenceLevel));
+    }
+
+    // number of successes = k, number of trials = N, 0 < k < N
+    @Test
+    public void testCase3() {
+        // Check correctness against values obtained with the Python 
statsmodels.stats.proportion.proportion_confint
+        final int successes = 3;
+        final int trials = 10;
+        final double confidenceLevel = 0.95;
+
+        // prop.proportion_confint(3,10,method='beta') = (0.06673951117773447, 
0.6524528500599972)
+        final ConfidenceInterval expected = new 
ConfidenceInterval(0.06673951117773447,
+                                                                   
0.6524528500599972,
+                                                                   
confidenceLevel);
+
+        check(expected, 
createBinomialConfidenceInterval().createInterval(trials, successes, 
confidenceLevel));
+    }
+
+    private void check(ConfidenceInterval expected,
+                       ConfidenceInterval actual) {
+        final double relTol = 1.0e-6; // Reasonable relative tolerance for 
floating point comparison
+        // Compare bounds using a relative tolerance
+        Assert.assertEquals(expected.getLowerBound(),
+                            actual.getLowerBound(),
+                            relTol * (1.0 + 
Math.abs(expected.getLowerBound())));
+        Assert.assertEquals(expected.getUpperBound(),
+                            actual.getUpperBound(),
+                            relTol * (1.0 + 
Math.abs(expected.getUpperBound())));
+        // The confidence level must be exact
+        Assert.assertEquals(expected.getConfidenceLevel(),
+                            actual.getConfidenceLevel(),
+                            0.0);
+    }
 }

Reply via email to