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-rng.git
The following commit(s) were added to refs/heads/master by this push:
new a2e5e79 RNG-148: Revert detection of infinite length vectors
a2e5e79 is described below
commit a2e5e7937a1ea62f38efa8f270aac378b8286ccf
Author: aherbert <[email protected]>
AuthorDate: Fri Jul 9 11:08:12 2021 +0100
RNG-148: Revert detection of infinite length vectors
Due to the change in RNG-154 the underlying Gaussian cannot have
infinite tails.
---
.../commons/rng/sampling/UnitSphereSampler.java | 33 ++-------
.../rng/sampling/UnitSphereSamplerTest.java | 78 ++++++++--------------
src/changes/changes.xml | 3 -
3 files changed, 32 insertions(+), 82 deletions(-)
diff --git
a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/UnitSphereSampler.java
b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/UnitSphereSampler.java
index e9b2a2a..76db7b0 100644
---
a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/UnitSphereSampler.java
+++
b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/UnitSphereSampler.java
@@ -104,8 +104,8 @@ public class UnitSphereSampler implements
SharedStateObjectSampler<double[]> {
final double y = sampler.sample();
final double sum = x * x + y * y;
- if (isInvalidSumForNormalization(sum)) {
- // Invalid vector is discarded.
+ if (sum == 0) {
+ // Zero-norm vector is discarded.
return sample();
}
@@ -141,8 +141,8 @@ public class UnitSphereSampler implements
SharedStateObjectSampler<double[]> {
final double z = sampler.sample();
final double sum = x * x + y * y + z * z;
- if (isInvalidSumForNormalization(sum)) {
- // Invalid vector is discarded.
+ if (sum == 0) {
+ // Zero-norm vector is discarded.
return sample();
}
@@ -187,8 +187,8 @@ public class UnitSphereSampler implements
SharedStateObjectSampler<double[]> {
sum += x * x;
}
- if (isInvalidSumForNormalization(sum)) {
- // Invalid vector is discarded.
+ if (sum == 0) {
+ // Zero-norm vector is discarded.
// Using recursion as it is highly unlikely to generate more
// than a few such vectors. It also protects against infinite
// loop (in case a buggy generator is used), by eventually
@@ -284,25 +284,4 @@ public class UnitSphereSampler implements
SharedStateObjectSampler<double[]> {
}
return new UnitSphereSamplerND(dimension, rng);
}
-
- /**
- * Returns true if the sum of squared components of a vector is invalid for
- * normalization.
- *
- * <p>This is true for any sum where the factor {@code f = 1.0 / sqrt(sum)}
- * cannot be used to create a unit length vector by multiplication. The sum
- * is invalid if:
- *
- * <ul>
- * <li>{@code sum = 0} then {@code f = infinity}
- * <li>{@code sum = infinity} then {@code f = 0}
- * </ul>
- *
- * @param sum Sum of squared components of a vector
- * @return true if invalid for normalisation
- */
- private static boolean isInvalidSumForNormalization(double sum) {
- // Note: Deliberate floating-point comparison with zero
- return sum == 0 || sum == Double.POSITIVE_INFINITY;
- }
}
diff --git
a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/UnitSphereSamplerTest.java
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/UnitSphereSamplerTest.java
index 9733858..005d548 100644
---
a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/UnitSphereSamplerTest.java
+++
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/UnitSphereSamplerTest.java
@@ -388,72 +388,46 @@ public class UnitSphereSamplerTest {
}
/**
- * Test the edge case where the normalisation sum to divide by is zero.
+ * Test the edge case where the normalisation sum to divide by is zero for
2D.
*/
@Test
- public void testInvalidInverseNormalisationWithZeroLength() {
- for (int dim = 2; dim <= 4; dim++) {
- testInvalidInverseNormalisationND(dim, true);
- }
+ public void testInvalidInverseNormalisation2D() {
+ testInvalidInverseNormalisationND(2);
}
/**
- * Test the edge case where the normalisation sum to divide by is infinite.
+ * Test the edge case where the normalisation sum to divide by is zero for
3D.
*/
@Test
- public void testInvalidInverseNormalisationWithInfiniteLength() {
- for (int dim = 2; dim <= 4; dim++) {
- testInvalidInverseNormalisationND(dim, false);
- }
+ public void testInvalidInverseNormalisation3D() {
+ testInvalidInverseNormalisationND(3);
}
/**
- * Test the edge case where the normalisation sum to divide by is zero or
infinite. This
- * test requires generation of Gaussian samples with the value 0 or
infinity. See RNG-55.
- *
- * @param dimension the dimension
- * @param zeroSum true if the sum for the first vector should be zero
+ * Test the edge case where the normalisation sum to divide by is zero for
4D.
+ */
+ @Test
+ public void testInvalidInverseNormalisation4D() {
+ testInvalidInverseNormalisationND(4);
+ }
+
+ /**
+ * Test the edge case where the normalisation sum to divide by is zero.
+ * This test requires generation of Gaussian samples with the value 0.
+ * See RNG-55.
*/
- private static void testInvalidInverseNormalisationND(final int dimension,
boolean zeroSum) {
+ private static void testInvalidInverseNormalisationND(final int dimension)
{
// Create a provider that will create a bad first sample but then
recover.
// This checks recursion will return a good value.
+ final UniformRandomProvider bad = new SplitMix64(0x1a2b3cL) {
+ private int count = -2 * dimension;
- // This sampler will createbvalues that manipulate the underlying
Gaussian sampler.
- UniformRandomProvider bad;
- if (zeroSum) {
- // Create Gaussian samples of zero
- bad = new SplitMix64(0x1a2b3cL) {
- private int count = -2 * dimension;
-
- @Override
- public long nextLong() {
- // Return enough zeros to create Gaussian samples of zero
for all coordinates.
- return count++ < 0 ? 0 : super.nextLong();
- }
- };
- } else {
- // Create a Gaussian sample of infinity.
- // This only requires 1 infinite value to create an infinite
length vector.
- // Assumes the ZigguratNormalizedGaussianSampler.
- // To create infinity requires a very large long value with the
lowest 7 bits as 0,
- // then two doubles of zero.
- bad = new SplitMix64(0x1a2b3cL) {
- private int lcount = -1;
- private int dcount = -2;
-
- @Override
- public long nextLong() {
- return lcount++ < 0 ?
- (-1L << 7) & Long.MAX_VALUE :
- super.nextLong();
- }
-
- @Override
- public double nextDouble() {
- return dcount++ < 0 ? 0 : super.nextDouble();
- }
- };
- }
+ @Override
+ public long nextLong() {
+ // Return enough zeros to create Gaussian samples of zero for
all coordinates.
+ return count++ < 0 ? 0 : super.nextLong();
+ }
+ };
final double[] vector = UnitSphereSampler.of(dimension, bad).sample();
Assert.assertEquals(dimension, vector.length);
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 77c87dd..e211d01 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -94,9 +94,6 @@ as 'flaky' in the report).
New "ZigguratSampler" implementation of the modified "Ziggurat"
algorithm for
Gaussian and exponential sampling.
</action>
- <action dev="aherbert" type="fix" issue="148">
- "UnitSphereSampler": Detect and discard infinite length vectors.
- </action>
<action dev="aherbert" type="add" issue="147">
New "LevySampler" to sample from a Levy distribution.
</action>