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
The following commit(s) were added to refs/heads/master by this push:
new 8f2ae1d Move check for 2x2 contingency table to the Arguments utility
class
8f2ae1d is described below
commit 8f2ae1d9a426325905e70c004ce8df17178744a3
Author: aherbert <[email protected]>
AuthorDate: Wed Feb 22 10:18:48 2023 +0000
Move check for 2x2 contingency table to the Arguments utility class
---
.../commons/statistics/inference/Arguments.java | 29 ++++++++++++++++++
.../statistics/inference/FisherExactTest.java | 32 ++------------------
.../statistics/inference/ArgumentsTest.java | 34 ++++++++++++++++++++++
3 files changed, 65 insertions(+), 30 deletions(-)
diff --git
a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/Arguments.java
b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/Arguments.java
index ee9e310..715e589 100644
---
a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/Arguments.java
+++
b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/Arguments.java
@@ -24,6 +24,9 @@ import java.util.EnumSet;
* @since 1.1
*/
final class Arguments {
+ /** Two. */
+ private static final int TWO = 2;
+
/** No instances. */
private Arguments() {}
@@ -225,4 +228,30 @@ final class Arguments {
}
return v;
}
+
+ /**
+ * Check the input is a 2-by-2 contingency table.
+ *
+ * @param table Table.
+ * @throws IllegalArgumentException if the {@code table} is not a 2-by-2
table; any
+ * table entry is negative; or the sum is zero or is not an integer
+ */
+ static void checkTable(int[][] table) {
+ if (table.length != TWO || table[0].length != TWO || table[1].length
!= TWO) {
+ throw new InferenceException("Require a 2-by-2 contingency table");
+ }
+ // Must all be positive
+ final int a = table[0][0];
+ final int b = table[0][1];
+ final int c = table[1][0];
+ final int d = table[1][1];
+ // Bitwise OR combines the sign bit from all values
+ Arguments.checkNonNegative(a | b | c | d);
+ // Sum must be an integer
+ final long sum = (long) a + b + c + d;
+ if (sum > Integer.MAX_VALUE) {
+ throw new InferenceException(InferenceException.X_GT_Y, sum,
Integer.MAX_VALUE);
+ }
+ Arguments.checkStrictlyPositive((int) sum);
+ }
}
diff --git
a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/FisherExactTest.java
b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/FisherExactTest.java
index 740ee2d..cef4abe 100644
---
a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/FisherExactTest.java
+++
b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/FisherExactTest.java
@@ -32,8 +32,6 @@ import
org.apache.commons.statistics.distribution.HypergeometricDistribution;
* @since 1.1
*/
public final class FisherExactTest {
- /** Two. */
- private static final int TWO = 2;
/** Default instance. */
private static final FisherExactTest DEFAULT = new
FisherExactTest(AlternativeHypothesis.TWO_SIDED);
@@ -101,7 +99,7 @@ public final class FisherExactTest {
* @see #test(int[][])
*/
public double statistic(int[][] table) {
- checkTable(table);
+ Arguments.checkTable(table);
final double a = table[0][0];
final double b = table[0][1];
final double c = table[1][0];
@@ -137,7 +135,7 @@ public final class FisherExactTest {
* @see #statistic(int[][])
*/
public SignificanceResult test(int[][] table) {
- checkTable(table);
+ Arguments.checkTable(table);
final int a = table[0][0];
final int b = table[0][1];
final int c = table[1][0];
@@ -214,30 +212,4 @@ public final class FisherExactTest {
final double pm = distribution.probability(k == m1 ? m2 : m1);
return pm > pk ? 1 - pm : 1;
}
-
- /**
- * Check the input is a 2-by-2 contingency table.
- *
- * @param table Table.
- * @throws IllegalArgumentException if the {@code table} is not a 2-by-2
table; any
- * table entry is negative; or the sum is zero or is not an integer
- */
- private static void checkTable(int[][] table) {
- if (table.length != TWO || table[0].length != TWO || table[1].length
!= TWO) {
- throw new InferenceException("Require a 2-by-2 contingency table");
- }
- // Must all be positive
- final int a = table[0][0];
- final int b = table[0][1];
- final int c = table[1][0];
- final int d = table[1][1];
- // Bitwise OR combines the sign bit from all values
- Arguments.checkNonNegative(a | b | c | d);
- // Sum must be an integer
- final long sum = (long) a + b + c + d;
- if (sum > Integer.MAX_VALUE) {
- throw new InferenceException(InferenceException.X_GT_Y, sum,
Integer.MAX_VALUE);
- }
- Arguments.checkStrictlyPositive((int) sum);
- }
}
diff --git
a/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/ArgumentsTest.java
b/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/ArgumentsTest.java
index c7b68cb..51bf8dd 100644
---
a/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/ArgumentsTest.java
+++
b/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/ArgumentsTest.java
@@ -20,6 +20,7 @@ import java.util.EnumSet;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
/**
@@ -170,4 +171,37 @@ class ArgumentsTest {
TestUtils.assertThrowsWithMessage(IllegalArgumentException.class,
() -> Arguments.checkOption(PValueMethod.ESTIMATE, allowed),
"invalid", "option", PValueMethod.ESTIMATE.toString());
}
+
+ @Test
+ void testCheckTableInvalid2x2Throws() {
+ Assertions.assertThrows(NullPointerException.class, () ->
Arguments.checkTable(null));
+ // Non 2-by-2 input
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
Arguments.checkTable(new int[3][3]));
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
Arguments.checkTable(new int[2][1]));
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
Arguments.checkTable(new int[1][2]));
+ // Non-square input
+ final int[][] x = {{1, 2}, {3}};
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
Arguments.checkTable(x));
+ final int[][] y = {{1}, {2, 3}};
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
Arguments.checkTable(y));
+ }
+
+ @ParameterizedTest
+ @CsvSource({
+ "0, 0, 0, 0",
+ // Overflow
+ "2147483647, 1, 0, 0",
+ "2147483647, 0, 1, 0",
+ "2147483647, 0, 0, 1",
+ "2147483647, 2147483647, 0, 0",
+ "2147483647, 0, 2147483647, 0",
+ "2147483647, 0, 0, 2147483647",
+ "2147483647, 0, 2147483647, 2147483647",
+ "2147483647, 2147483647, 0, 2147483647",
+ "2147483647, 2147483647, 2147483647, 2147483647",
+ })
+ void testCheckTableInvalidSumThrows(int a, int b, int c, int d) {
+ final int[][] table = {{a, b}, {c, d}};
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
Arguments.checkTable(table));
+ }
}