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/11/22 13:11:13 UTC
[commons-statistics] 02/03: Add probability range implementation for continuous uniform 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 07a9de308dca81a210d35052c4f91fa6d28bb5c1
Author: aherbert <ah...@apache.org>
AuthorDate: Mon Nov 22 12:30:38 2021 +0000
Add probability range implementation for continuous uniform distribution
---
.../UniformContinuousDistribution.java | 30 +++++++---
.../UniformContinuousDistributionTest.java | 67 ++++++++++++++++++++++
.../test.uniformcontinuous.1.properties | 5 ++
3 files changed, 94 insertions(+), 8 deletions(-)
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java
index 48145de..ce1c67a 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java
@@ -77,6 +77,28 @@ public final class UniformContinuousDistribution extends AbstractContinuousDistr
/** {@inheritDoc} */
@Override
+ public double probability(double x0,
+ double x1) {
+ if (x0 > x1) {
+ throw new DistributionException(DistributionException.INVALID_RANGE_LOW_GT_HIGH, x0, x1);
+ }
+ if (x0 >= upper || x1 <= lower) {
+ // (x0, x1] does not overlap [lower, upper]
+ return 0;
+ }
+
+ // x0 < upper
+ // x1 >= lower
+
+ // Find the range between x0 and x1 that is within [lower, upper].
+ final double l = Math.max(lower, x0);
+ final double u = Math.min(upper, x1);
+
+ return (u - l) / upperMinusLower;
+ }
+
+ /** {@inheritDoc} */
+ @Override
public double logDensity(double x) {
if (x < lower ||
x > upper) {
@@ -187,14 +209,6 @@ public final class UniformContinuousDistribution extends AbstractContinuousDistr
/** {@inheritDoc} */
@Override
- protected double getMedian() {
- // Overridden for the probability(double, double) method.
- // This is intentionally not a public method.
- return getMean();
- }
-
- /** {@inheritDoc} */
- @Override
public ContinuousDistribution.Sampler createSampler(final UniformRandomProvider rng) {
// Uniform distribution sampler.
return ContinuousUniformSampler.of(rng, lower, upper)::sample;
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java
index 862d17e..28b384a 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java
@@ -17,8 +17,14 @@
package org.apache.commons.statistics.distribution;
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.sampling.distribution.ContinuousSampler;
+import org.apache.commons.rng.sampling.distribution.ContinuousUniformSampler;
+import org.apache.commons.rng.simple.RandomSource;
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;
/**
* Test cases for {@link UniformContinuousDistribution}.
@@ -83,4 +89,65 @@ class UniformContinuousDistributionTest extends BaseContinuousDistributionTest {
Assertions.assertEquals(-7.5e-10, dist2.inverseCumulativeProbability(0.25), Math.ulp(-7.5e-10));
Assertions.assertEquals(-upper + tiny * upper, dist2.inverseCumulativeProbability(tiny));
}
+
+ /**
+ * Test the probability in a range uses the exact computation of
+ * {@code (x1 - x0) / (upper - lower)} assuming x0 and x1 are within [lower, upper].
+ * This test will fail if the distribution uses the default implementation in
+ * {@link AbstractContinuousDistribution}.
+ */
+ @ParameterizedTest
+ @CsvSource(value = {
+ "-1.6358421681, -0.566237287234",
+ "-10.23678, 234.234",
+ "234.2342, 54322342.13",
+ })
+ void testProbabilityRange(double lower, double upper) {
+ final UniformContinuousDistribution dist = UniformContinuousDistribution.of(lower, upper);
+ final double r = upper - lower;
+ final UniformRandomProvider rng = RandomSource.XO_RO_SHI_RO_128_PP.create();
+ final ContinuousSampler sampler = ContinuousUniformSampler.of(rng, lower, upper);
+ for (int i = 0; i < 100; i++) {
+ double x0 = sampler.sample();
+ double x1 = sampler.sample();
+ if (x1 < x0) {
+ final double tmp = x0;
+ x1 = x0;
+ x0 = tmp;
+ }
+ Assertions.assertEquals((x1 - x0) / r, dist.probability(x0, x1));
+ }
+ }
+
+ @Test
+ void testProbabilityRangeEdgeCases() {
+ final UniformContinuousDistribution dist = UniformContinuousDistribution.of(0, 11);
+
+ Assertions.assertThrows(DistributionException.class, () -> dist.probability(4, 3));
+
+ // x0 >= upper
+ Assertions.assertEquals(0, dist.probability(11, 16));
+ Assertions.assertEquals(0, dist.probability(15, 16));
+ // x1 < lower
+ Assertions.assertEquals(0, dist.probability(-3, -1));
+
+ // x0 == x1
+ Assertions.assertEquals(0, dist.probability(4.12, 4.12));
+ Assertions.assertEquals(0, dist.probability(5.68, 5.68));
+
+ // x1 > upper
+ Assertions.assertEquals(1, dist.probability(0, 16));
+ Assertions.assertEquals((11 - 3.45) / 11, dist.probability(3.45, 16));
+ Assertions.assertEquals((11 - 4.89) / 11, dist.probability(4.89, 16));
+ Assertions.assertEquals(0, dist.probability(11, 16));
+
+ // x0 < lower
+ Assertions.assertEquals(2.0 / 11, dist.probability(-2, 2));
+ Assertions.assertEquals(3.0 / 11, dist.probability(-2, 3));
+ Assertions.assertEquals(4.0 / 11, dist.probability(-2, 4));
+ Assertions.assertEquals(1.0, dist.probability(-2, 11));
+
+ // x1 > upper && x0 < lower
+ Assertions.assertEquals(1, dist.probability(-2, 16));
+ }
}
diff --git a/commons-statistics-distribution/src/test/resources/org/apache/commons/statistics/distribution/test.uniformcontinuous.1.properties b/commons-statistics-distribution/src/test/resources/org/apache/commons/statistics/distribution/test.uniformcontinuous.1.properties
index 922fae4..aee6b1e 100644
--- a/commons-statistics-distribution/src/test/resources/org/apache/commons/statistics/distribution/test.uniformcontinuous.1.properties
+++ b/commons-statistics-distribution/src/test/resources/org/apache/commons/statistics/distribution/test.uniformcontinuous.1.properties
@@ -17,6 +17,11 @@ parameters = -0.5 1.25
# Lower tolerance to pass survival function test.
# scipy uniform does not appear to compute sf to high precision.
tolerance.relative = 1e-14
+# probability(x0, x1) test expects this to be cdf(x1) - cdf(x0).
+# The computation is 0.5 ulp exact using (x1 - x0) / (upper - lower).
+# Configure the absolute error to allow this.
+tolerance.absolute = 5e-17
+
# Computed using scipy.stats uniform(-0.5, 1.75)
mean = 0.375
variance = 0.2552083333333333