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-math.git
The following commit(s) were added to refs/heads/master by this push:
new 9a808f5a7 MATH-1696: Order enumerated real masses when computing
quantiles (#353)
9a808f5a7 is described below
commit 9a808f5a76f2f3bfd5db877fa35bf3f9d27d8dfb
Author: Parijat Biswas <[email protected]>
AuthorDate: Thu Nov 12 02:45:50 2026 +0530
MATH-1696: Order enumerated real masses when computing quantiles (#353)
Sort enumerated real masses during construction
---
.../distribution/EnumeratedRealDistribution.java | 11 ++++--
.../EnumeratedRealDistributionTest.java | 46 ++++++++++++++++++++++
2 files changed, 53 insertions(+), 4 deletions(-)
diff --git
a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/distribution/EnumeratedRealDistribution.java
b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/distribution/EnumeratedRealDistribution.java
index 77385c8d4..efb68b342 100644
---
a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/distribution/EnumeratedRealDistribution.java
+++
b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/distribution/EnumeratedRealDistribution.java
@@ -17,7 +17,7 @@
package org.apache.commons.math4.legacy.distribution;
import java.util.ArrayList;
-import java.util.LinkedHashMap;
+import java.util.TreeMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -70,7 +70,9 @@ public class EnumeratedRealDistribution
MathArithmeticException,
NotFiniteNumberException,
NotANumberException {
- innerDistribution = new
EnumeratedDistribution<>(createDistribution(singletons, probabilities));
+ final List<Pair<Double, Double>> samples =
createDistribution(singletons, probabilities);
+ samples.sort((a, b) -> Double.compare(a.getKey(), b.getKey()));
+ innerDistribution = new EnumeratedDistribution<>(samples);
}
/**
@@ -80,7 +82,7 @@ public class EnumeratedRealDistribution
* @param data input dataset
*/
public EnumeratedRealDistribution(final double[] data) {
- final Map<Double, Integer> dataMap = new LinkedHashMap<>();
+ final Map<Double, Integer> dataMap = new TreeMap<>();
for (double value : data) {
dataMap.merge(value, 1, Integer::sum);
}
@@ -158,7 +160,8 @@ public class EnumeratedRealDistribution
double probability = 0;
double x = getSupportLowerBound();
- for (final Pair<Double, Double> sample : innerDistribution.getPmf()) {
+ final List<Pair<Double, Double>> samples = innerDistribution.getPmf();
+ for (final Pair<Double, Double> sample : samples) {
if (sample.getValue() == 0.0) {
continue;
}
diff --git
a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/EnumeratedRealDistributionTest.java
b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/EnumeratedRealDistributionTest.java
index 8a67bec58..cadf9aa5c 100644
---
a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/EnumeratedRealDistributionTest.java
+++
b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/EnumeratedRealDistributionTest.java
@@ -236,6 +236,44 @@ public class EnumeratedRealDistributionTest {
assertEquals(28.0, distribution.inverseCumulativeProbability(0.7500),
0.0);
}
+ @Test
+ public void testInverseCumulativeProbabilityUnsortedSingletons() {
+ EnumeratedRealDistribution distribution = new
EnumeratedRealDistribution(
+ new double[] {7, 3, -1, 3, -2, 8},
+ new double[] {0.25, 0.25, 0.25, 0.25, 0, 0});
+ assertEquals(-1, distribution.inverseCumulativeProbability(0), 0);
+ assertEquals(-1, distribution.inverseCumulativeProbability(0.25), 0);
+ assertEquals(3, distribution.inverseCumulativeProbability(0.5), 0);
+ assertEquals(3, distribution.inverseCumulativeProbability(0.75), 0);
+ assertEquals(7, distribution.inverseCumulativeProbability(1), 0);
+ }
+
+ @Test
+ public void testInverseCumulativeProbabilityUnsortedData() {
+ EnumeratedRealDistribution distribution = new
EnumeratedRealDistribution(
+ new double[] {7, 3, -1, 3});
+ assertEquals(-1, distribution.inverseCumulativeProbability(0), 0);
+ assertEquals(-1, distribution.inverseCumulativeProbability(0.25), 0);
+ assertEquals(3, distribution.inverseCumulativeProbability(0.5), 0);
+ assertEquals(3, distribution.inverseCumulativeProbability(0.75), 0);
+ assertEquals(7, distribution.inverseCumulativeProbability(1), 0);
+ }
+
+ @Test
+ public void testInverseCumulativeProbabilityDoesNotChangeSampling() {
+ final double[] values = {7, 3, -1, 3};
+ EnumeratedRealDistribution distribution = new
EnumeratedRealDistribution(values);
+ EnumeratedRealDistribution control = new
EnumeratedRealDistribution(values);
+ distribution.inverseCumulativeProbability(0.5);
+ final ContinuousDistribution.Sampler actual =
+
distribution.createSampler(RandomSource.WELL_512_A.create(12345L));
+ final ContinuousDistribution.Sampler expected =
+ control.createSampler(RandomSource.WELL_512_A.create(12345L));
+ for (int i = 0; i < 100; i++) {
+ assertEquals(expected.sample(), actual.sample(), 0);
+ }
+ }
+
@Test
public void testCreateFromDoubles() {
final double[] data = new double[] {0, 1, 1, 2, 2, 2};
@@ -243,4 +281,12 @@ public class EnumeratedRealDistributionTest {
assertEquals(0.5, distribution.density(2), 0);
assertEquals(0.5, distribution.cumulativeProbability(1), 0);
}
+
+ @Test
+ public void testQuantileUsesSameAccumulationOrderAsCdf() {
+ final EnumeratedRealDistribution distribution = new
EnumeratedRealDistribution(
+ new double[] {2, 0, 1, 3}, new double[] {1, 2, 3, 1});
+ Assert.assertEquals(2, distribution.inverseCumulativeProbability(
+ distribution.cumulativeProbability(2)), 0);
+ }
}