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/12/16 12:17:48 UTC
[commons-statistics] 02/05: PMD fix: Refactor adjustment of infinite bounds to methods
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 e17a87ac678b796aa720fa6882986a5f4b540556
Author: aherbert <ah...@apache.org>
AuthorDate: Thu Dec 16 12:12:54 2021 +0000
PMD fix: Refactor adjustment of infinite bounds to methods
This reduces complexity in the inverseProbability method
---
.../AbstractContinuousDistribution.java | 121 ++++++++++++++-------
.../AbstractContinuousDistributionTest.java | 54 +++++++--
2 files changed, 128 insertions(+), 47 deletions(-)
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/AbstractContinuousDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/AbstractContinuousDistribution.java
index 5e26812..1a95654 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/AbstractContinuousDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/AbstractContinuousDistribution.java
@@ -228,45 +228,11 @@ abstract class AbstractContinuousDistribution
ArgumentUtils.isFiniteStrictlyPositive(sig);
if (lowerBound == Double.NEGATIVE_INFINITY) {
- if (chebyshevApplies) {
- lowerBound = mu - sig * Math.sqrt(q / p);
- }
- // Bound may have been set as infinite
- if (lowerBound == Double.NEGATIVE_INFINITY) {
- lowerBound = Math.min(-1, upperBound);
- if (complement) {
- while (survivalProbability(lowerBound) < q) {
- lowerBound *= 2;
- }
- } else {
- while (cumulativeProbability(lowerBound) >= p) {
- lowerBound *= 2;
- }
- }
- // Ensure finite
- lowerBound = Math.max(lowerBound, -Double.MAX_VALUE);
- }
+ lowerBound = createFiniteLowerBound(p, q, complement, upperBound, mu, sig, chebyshevApplies);
}
if (upperBound == Double.POSITIVE_INFINITY) {
- if (chebyshevApplies) {
- upperBound = mu + sig * Math.sqrt(p / q);
- }
- // Bound may have been set as infinite
- if (upperBound == Double.POSITIVE_INFINITY) {
- upperBound = Math.max(1, lowerBound);
- if (complement) {
- while (survivalProbability(upperBound) >= q) {
- upperBound *= 2;
- }
- } else {
- while (cumulativeProbability(upperBound) < p) {
- upperBound *= 2;
- }
- }
- // Ensure finite
- upperBound = Math.min(upperBound, Double.MAX_VALUE);
- }
+ upperBound = createFiniteUpperBound(p, q, complement, lowerBound, mu, sig, chebyshevApplies);
}
// Here the bracket [lower, upper] uses finite values. If the support
@@ -275,19 +241,19 @@ abstract class AbstractContinuousDistribution
if (upperBound == Double.MAX_VALUE) {
if (complement) {
if (survivalProbability(upperBound) > q) {
- return Double.POSITIVE_INFINITY;
+ return getSupportUpperBound();
}
} else if (cumulativeProbability(upperBound) < p) {
- return Double.POSITIVE_INFINITY;
+ return getSupportUpperBound();
}
}
if (lowerBound == -Double.MAX_VALUE) {
if (complement) {
if (survivalProbability(lowerBound) < q) {
- return Double.NEGATIVE_INFINITY;
+ return getSupportLowerBound();
}
} else if (cumulativeProbability(lowerBound) > p) {
- return Double.NEGATIVE_INFINITY;
+ return getSupportLowerBound();
}
}
@@ -310,6 +276,81 @@ abstract class AbstractContinuousDistribution
return x;
}
+ /**
+ * Create a finite lower bound. Assumes the current lower bound is negative infinity.
+ *
+ * @param p Cumulative probability.
+ * @param q Survival probability.
+ * @param complement Set to true to compute the inverse survival probability
+ * @param upperBound Current upper bound
+ * @param mu Mean
+ * @param sig Standard deviation
+ * @param chebyshevApplies True if the Chebyshev inequality applies (mean is finite and {@code sig > 0}}
+ * @return the finite lower bound
+ */
+ private double createFiniteLowerBound(final double p, final double q, boolean complement,
+ double upperBound, final double mu, final double sig, final boolean chebyshevApplies) {
+ double lowerBound;
+ if (chebyshevApplies) {
+ lowerBound = mu - sig * Math.sqrt(q / p);
+ } else {
+ lowerBound = Double.NEGATIVE_INFINITY;
+ }
+ // Bound may have been set as infinite
+ if (lowerBound == Double.NEGATIVE_INFINITY) {
+ lowerBound = Math.min(-1, upperBound);
+ if (complement) {
+ while (survivalProbability(lowerBound) < q) {
+ lowerBound *= 2;
+ }
+ } else {
+ while (cumulativeProbability(lowerBound) >= p) {
+ lowerBound *= 2;
+ }
+ }
+ // Ensure finite
+ lowerBound = Math.max(lowerBound, -Double.MAX_VALUE);
+ }
+ return lowerBound;
+ }
+
+ /**
+ * Create a finite upper bound. Assumes the current upper bound is positive infinity.
+ *
+ * @param p Cumulative probability.
+ * @param q Survival probability.
+ * @param complement Set to true to compute the inverse survival probability
+ * @param lowerBound Current lower bound
+ * @param mu Mean
+ * @param sig Standard deviation
+ * @param chebyshevApplies True if the Chebyshev inequality applies (mean is finite and {@code sig > 0}}
+ * @return the finite lower bound
+ */
+ private double createFiniteUpperBound(final double p, final double q, boolean complement,
+ double lowerBound, final double mu, final double sig, final boolean chebyshevApplies) {
+ double upperBound;
+ if (chebyshevApplies) {
+ upperBound = mu + sig * Math.sqrt(p / q);
+ } else {
+ upperBound = Double.POSITIVE_INFINITY;
+ }
+ // Bound may have been set as infinite
+ if (upperBound == Double.POSITIVE_INFINITY) {
+ upperBound = Math.max(1, lowerBound);
+ if (complement) {
+ while (survivalProbability(upperBound) >= q) {
+ upperBound *= 2;
+ }
+ } else {
+ while (cumulativeProbability(upperBound) < p) {
+ upperBound *= 2;
+ }
+ }
+ // Ensure finite
+ upperBound = Math.min(upperBound, Double.MAX_VALUE);
+ }
+ return upperBound;
+ }
/**
* Indicates whether the support is connected, i.e. whether all values between the
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/AbstractContinuousDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/AbstractContinuousDistributionTest.java
index e72698a..3cce2e0 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/AbstractContinuousDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/AbstractContinuousDistributionTest.java
@@ -374,12 +374,32 @@ class AbstractContinuousDistributionTest {
/**
* Create a distribution near positive infinity so that it is truncated by MAX_VALUE.
+ * This distribution reports the upper bound as infinite.
*/
@Test
void testTruncatedDistributionAtPositiveInfinity() {
+ assertTruncatedDistributionAtPositiveInfinity(false);
+ }
+
+ /**
+ * Create a distribution near positive infinity so that it is truncated by MAX_VALUE.
+ * This distribution reports the upper bound as finite.
+ */
+ @Test
+ void testTruncatedDistributionAtPositiveInfinity2() {
+ assertTruncatedDistributionAtPositiveInfinity(true);
+ }
+
+ private static void assertTruncatedDistributionAtPositiveInfinity(boolean finiteBound) {
final double mean = Double.MAX_VALUE;
final double width = Double.MAX_VALUE / 2;
- final CentredUniformDistribution dist = new CentredUniformDistribution(mean, width);
+ final double bound = finiteBound ? Double.MAX_VALUE : Double.POSITIVE_INFINITY;
+ final CentredUniformDistribution dist = new CentredUniformDistribution(mean, width) {
+ @Override
+ public double getSupportUpperBound() {
+ return bound;
+ }
+ };
final double x = mean - width / 2;
Assertions.assertEquals(0, dist.cumulativeProbability(x));
Assertions.assertTrue(dist.cumulativeProbability(Math.nextUp(x)) > 0);
@@ -392,18 +412,38 @@ class AbstractContinuousDistributionTest {
// Inversion should be robust to return the upper infinite bound
Assertions.assertEquals(mean, dist.inverseCumulativeProbability(0.5));
Assertions.assertEquals(mean, dist.inverseSurvivalProbability(0.5));
- Assertions.assertEquals(Double.POSITIVE_INFINITY, dist.inverseCumulativeProbability(0.75));
- Assertions.assertEquals(Double.POSITIVE_INFINITY, dist.inverseSurvivalProbability(0.25));
+ Assertions.assertEquals(bound, dist.inverseCumulativeProbability(0.75));
+ Assertions.assertEquals(bound, dist.inverseSurvivalProbability(0.25));
}
/**
* Create a distribution near negative infinity so that it is truncated by -MAX_VALUE.
+ * This distribution reports the lower bound as infinite.
*/
@Test
void testTruncatedDistributionAtNegativeInfinity() {
+ assertTruncatedDistributionAtNegativeInfinity(false);
+ }
+
+ /**
+ * Create a distribution near negative infinity so that it is truncated by -MAX_VALUE.
+ * This distribution reports the lower bound as finite.
+ */
+ @Test
+ void testTruncatedDistributionAtNegativeInfinity2() {
+ assertTruncatedDistributionAtNegativeInfinity(true);
+ }
+
+ private static void assertTruncatedDistributionAtNegativeInfinity(boolean finiteBound) {
final double mean = -Double.MAX_VALUE;
final double width = Double.MAX_VALUE / 2;
- final CentredUniformDistribution dist = new CentredUniformDistribution(mean, width);
+ final double bound = finiteBound ? -Double.MAX_VALUE : Double.NEGATIVE_INFINITY;
+ final CentredUniformDistribution dist = new CentredUniformDistribution(mean, width) {
+ @Override
+ public double getSupportLowerBound() {
+ return bound;
+ }
+ };
final double x = mean + width / 2;
Assertions.assertEquals(1, dist.cumulativeProbability(x));
Assertions.assertTrue(dist.cumulativeProbability(Math.nextDown(x)) < 1);
@@ -416,8 +456,8 @@ class AbstractContinuousDistributionTest {
// Inversion should be robust to return the lower infinite bound
Assertions.assertEquals(mean, dist.inverseCumulativeProbability(0.5));
Assertions.assertEquals(mean, dist.inverseSurvivalProbability(0.5));
- Assertions.assertEquals(Double.NEGATIVE_INFINITY, dist.inverseCumulativeProbability(0.25));
- Assertions.assertEquals(Double.NEGATIVE_INFINITY, dist.inverseSurvivalProbability(0.75));
+ Assertions.assertEquals(bound, dist.inverseCumulativeProbability(0.25));
+ Assertions.assertEquals(bound, dist.inverseSurvivalProbability(0.75));
}
/**
@@ -425,7 +465,7 @@ class AbstractContinuousDistributionTest {
* This can be use to place the centre of the distribution at the limit of a finite double
* value so that the distribution is truncated.
*/
- static final class CentredUniformDistribution extends AbstractContinuousDistribution {
+ static class CentredUniformDistribution extends AbstractContinuousDistribution {
private final double mean;
private final double width;
private final double density;