Skip to content
Permalink
Browse files
RNG-176: Update anonymous implementations of UniformRandomProvider
Only one method is required to implement the interface. This simplifies
creation of implementations for testing edge cases.

For a delegate implementation then additional methods must be added.
This applies to RandomSource.unrestorable.
  • Loading branch information
aherbert committed May 13, 2022
1 parent 04c1c97 commit d441d958581c09cef31d6a46d6b70faf1d029598
Showing 8 changed files with 414 additions and 86 deletions.
@@ -133,28 +133,7 @@ public long threadLocalRandom() {
@Threads(4)
public long threadLocalRandomWrapped() {
final ThreadLocalRandom rand = ThreadLocalRandom.current();
final UniformRandomProvider rng = new UniformRandomProvider() {
// CHECKSTYLE: stop all
@Override
public void nextBytes(byte[] bytes) { /* Ignore this. */ }
@Override
public void nextBytes(byte[] bytes, int start, int len) { /* Ignore this. */ }
@Override
public int nextInt() { return rand.nextInt(); }
@Override
public int nextInt(int n) { return rand.nextInt(n); }
@Override
public long nextLong() { return rand.nextLong(); }
@Override
public long nextLong(long n) { return rand.nextLong(n); }
@Override
public boolean nextBoolean() { return rand.nextBoolean(); }
@Override
public float nextFloat() { return rand.nextFloat(); }
@Override
public double nextDouble() { return rand.nextDouble(); }
// CHECKSTYLE: resume all
};
final UniformRandomProvider rng = rand::nextLong;
long result = 0;
for (int i = 0; i < numValues; i++) {
result = result ^ rng.nextLong();
@@ -168,18 +168,17 @@ void testSampleWithProbabilityAtLastItem() {
// a probability (for the second item) that hits an edge case.
final UniformRandomProvider dummyRng = new UniformRandomProvider() {
private int count;
// CHECKSTYLE: stop all
public long nextLong(long n) { return 0; }
public long nextLong() { return 0; }
public int nextInt(int n) { return 0; }
public int nextInt() { return 0; }
public float nextFloat() { return 0; }
// Return 0 then the given probability
public double nextDouble() { return (count++ == 0) ? 0 : 1.0; }
public void nextBytes(byte[] bytes, int start, int len) {}
public void nextBytes(byte[] bytes) {}
public boolean nextBoolean() { return false; }
// CHECKSTYLE: resume all

@Override
public long nextLong() {
return 0;
}

@Override
public double nextDouble() {
// Return 0 then the 1.0 for the probability
return (count++ == 0) ? 0 : 1.0;
}
};

final List<Double> items = Arrays.asList(1d, 2d);
@@ -21,6 +21,8 @@
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.ValueSource;

/**
* Test for the {@link SmallMeanPoissonSampler}. The tests hit edge cases for the sampler.
@@ -56,27 +58,15 @@ void testConstructorThrowsWithZeroMean() {
/**
* Test the sample is bounded to 1000 * mean.
*/
@Test
void testSampleUpperBounds() {
// If the nextDouble() is always 1 then the sample will hit the upper bounds
final UniformRandomProvider rng = new UniformRandomProvider() {
// CHECKSTYLE: stop all
public long nextLong(long n) { return 0; }
public long nextLong() { return 0; }
public int nextInt(int n) { return 0; }
public int nextInt() { return 0; }
public float nextFloat() { return 0; }
public double nextDouble() { return 1;}
public void nextBytes(byte[] bytes, int start, int len) {}
public void nextBytes(byte[] bytes) {}
public boolean nextBoolean() { return false; }
// CHECKSTYLE: resume all
};
for (double mean : new double[] {0.5, 1, 1.5, 2.2}) {
final SharedStateDiscreteSampler sampler = SmallMeanPoissonSampler.of(rng, mean);
final int expected = (int) Math.ceil(1000 * mean);
Assertions.assertEquals(expected, sampler.sample());
}
@ParameterizedTest
@ValueSource(doubles = {0.5, 1, 1.5, 2.2})
void testSampleUpperBounds(double mean) {
// If the nextDouble() is always ~1 then the sample will hit the upper bounds.
// nextLong() returns -1; nextDouble returns Math.nextDown(1.0).
final UniformRandomProvider rng = () -> -1;
final SharedStateDiscreteSampler sampler = SmallMeanPoissonSampler.of(rng, mean);
final int expected = (int) Math.ceil(1000 * mean);
Assertions.assertEquals(expected, sampler.sample());
}

/**
@@ -31,19 +31,8 @@ class ZigguratNormalizedGaussianSamplerTest {
void testInfiniteLoop() {
// A bad implementation whose only purpose is to force access
// to the rarest branch.
final UniformRandomProvider bad = new UniformRandomProvider() {
// CHECKSTYLE: stop all
public long nextLong(long n) { return 0; }
public long nextLong() { return Long.MAX_VALUE; }
public int nextInt(int n) { return 0; }
public int nextInt() { return Integer.MAX_VALUE; }
public float nextFloat() { return 1; }
public double nextDouble() { return 1;}
public void nextBytes(byte[] bytes, int start, int len) {}
public void nextBytes(byte[] bytes) {}
public boolean nextBoolean() { return false; }
// CHECKSTYLE: resume all
};
// nextLong() returns Long.MAX_VALUE
final UniformRandomProvider bad = () -> Long.MAX_VALUE;

// Infinite loop (in v1.1).
final ZigguratNormalizedGaussianSampler sampler = new ZigguratNormalizedGaussianSampler(bad);
@@ -16,6 +16,9 @@
*/
package org.apache.commons.rng.simple;

import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.RestorableUniformRandomProvider;
import org.apache.commons.rng.simple.internal.ProviderBuilder;
@@ -1015,70 +1018,168 @@ public static long[] createLongArray(int n) {

/**
* Wraps the given {@code delegate} generator in a new instance that
* does not allow access to the "save/restore" functionality.
* only provides access to the {@link UniformRandomProvider} methods.
*
* <p>This method can be used to prevent access to any methods of the {@code delegate}
* that are not defined in the {@link UniformRandomProvider} interface.
* For example this will prevent access to the "save/restore" functionality of
* any {@link RestorableUniformRandomProvider} {@link #create() created}
* by the {@link RandomSource} factory methods, or will prevent access to the jump
* functionality of generators.
*
* <p>Since the method applies to more than the {@link RestorableUniformRandomProvider}
* interface it is left to the caller to determine if any methods require hiding,
* for example:
*
* <pre><code>
* UniformRandomProvider rng = ...;
* if (rng instanceof JumpableUniformRandomProvider) {
* rng = RandomSource.unrestorable(rng);
* }
* </code></pre>
*
* @param delegate Generator to which calls will be delegated.
* @return a new instance whose state cannot be saved or restored.
* @return a new instance
*/
public static UniformRandomProvider unrestorable(final UniformRandomProvider delegate) {
return new UniformRandomProvider() {
/** {@inheritDoc} */
@Override
public void nextBytes(byte[] bytes) {
delegate.nextBytes(bytes);
}

/** {@inheritDoc} */
@Override
public void nextBytes(byte[] bytes,
int start,
int len) {
delegate.nextBytes(bytes, start, len);
}

/** {@inheritDoc} */
@Override
public int nextInt() {
return delegate.nextInt();
}

/** {@inheritDoc} */
@Override
public int nextInt(int n) {
return delegate.nextInt(n);
}

/** {@inheritDoc} */
@Override
public int nextInt(int origin, int bound) {
return delegate.nextInt(origin, bound);
}

@Override
public long nextLong() {
return delegate.nextLong();
}

/** {@inheritDoc} */
@Override
public long nextLong(long n) {
return delegate.nextLong(n);
}

/** {@inheritDoc} */
@Override
public long nextLong(long origin, long bound) {
return delegate.nextLong(origin, bound);
}

@Override
public boolean nextBoolean() {
return delegate.nextBoolean();
}

/** {@inheritDoc} */
@Override
public float nextFloat() {
return delegate.nextFloat();
}

/** {@inheritDoc} */
@Override
public float nextFloat(float bound) {
return delegate.nextFloat(bound);
}

@Override
public float nextFloat(float origin, float bound) {
return delegate.nextFloat(origin, bound);
}

@Override
public double nextDouble() {
return delegate.nextDouble();
}

/** {@inheritDoc} */
@Override
public double nextDouble(double bound) {
return delegate.nextDouble(bound);
}

@Override
public double nextDouble(double origin, double bound) {
return delegate.nextDouble(origin, bound);
}

@Override
public IntStream ints() {
return delegate.ints();
}

@Override
public IntStream ints(int origin, int bound) {
return delegate.ints(origin, bound);
}

@Override
public IntStream ints(long streamSize) {
return delegate.ints(streamSize);
}

@Override
public IntStream ints(long streamSize, int origin, int bound) {
return delegate.ints(streamSize, origin, bound);
}

@Override
public LongStream longs() {
return delegate.longs();
}

@Override
public LongStream longs(long origin, long bound) {
return delegate.longs(origin, bound);
}

@Override
public LongStream longs(long streamSize) {
return delegate.longs(streamSize);
}

@Override
public LongStream longs(long streamSize, long origin, long bound) {
return delegate.longs(streamSize, origin, bound);
}

@Override
public DoubleStream doubles() {
return delegate.doubles();
}

@Override
public DoubleStream doubles(double origin, double bound) {
return delegate.doubles(origin, bound);
}

@Override
public DoubleStream doubles(long streamSize) {
return delegate.doubles(streamSize);
}

@Override
public DoubleStream doubles(long streamSize, double origin, double bound) {
return delegate.doubles(streamSize, origin, bound);
}

@Override
public String toString() {
return delegate.toString();
@@ -46,25 +46,33 @@ public static void assertProduceSameSequence(UniformRandomProvider rng1,
Assertions.assertEquals(rng1.nextInt(), rng2.nextInt());
}
for (int i = 0; i < 4; i++) {
final int min = 31 * i + 3;
for (int j = 0; j < 5; j++) {
final int max = 107 * i + 374 * j + 11;
Assertions.assertEquals(rng1.nextInt(max), rng2.nextInt(max));
Assertions.assertEquals(rng1.nextInt(min, max), rng2.nextInt(min, max));
}
}
for (int i = 0; i < 23; i++) {
Assertions.assertEquals(rng1.nextLong(), rng2.nextLong());
}
for (int i = 0; i < 4; i++) {
final int min = 31 * i + 3;
for (int j = 0; j < 5; j++) {
final long max = (Long.MAX_VALUE << 2) + 107 * i + 374 * j + 11;
final long max = (Long.MAX_VALUE >> 2) + 107 * i + 374 * j + 11;
Assertions.assertEquals(rng1.nextLong(max), rng2.nextLong(max));
Assertions.assertEquals(rng1.nextLong(min, max), rng2.nextLong(min, max));
}
}
for (int i = 0; i < 103; i++) {
for (int i = 0; i < 35; i++) {
Assertions.assertEquals(rng1.nextFloat(), rng2.nextFloat());
Assertions.assertEquals(rng1.nextFloat(12.34f), rng2.nextFloat(12.34f));
Assertions.assertEquals(rng1.nextFloat(1.23f, 12.34f), rng2.nextFloat(1.23f, 12.34f));
}
for (int i = 0; i < 79; i++) {
for (int i = 0; i < 27; i++) {
Assertions.assertEquals(rng1.nextDouble(), rng2.nextDouble());
Assertions.assertEquals(rng1.nextDouble(12.34), rng2.nextDouble(12.34));
Assertions.assertEquals(rng1.nextDouble(1.23, 12.34), rng2.nextDouble(1.23, 12.34));
}

final int size = 345;
@@ -84,5 +92,21 @@ public static void assertProduceSameSequence(UniformRandomProvider rng1,
rng2.nextBytes(a2, offset, n);
Assertions.assertArrayEquals(a1, a2);
}

// Streams
Assertions.assertArrayEquals(rng1.ints().limit(4).toArray(), rng2.ints().limit(4).toArray());
Assertions.assertArrayEquals(rng1.ints(5).toArray(), rng2.ints(5).toArray());
Assertions.assertArrayEquals(rng1.ints(-3, 12).limit(4).toArray(), rng2.ints(-3, 12).limit(4).toArray());
Assertions.assertArrayEquals(rng1.ints(5, -13, 2).toArray(), rng2.ints(5, -13, 2).toArray());

Assertions.assertArrayEquals(rng1.longs().limit(4).toArray(), rng2.longs().limit(4).toArray());
Assertions.assertArrayEquals(rng1.longs(5).toArray(), rng2.longs(5).toArray());
Assertions.assertArrayEquals(rng1.longs(-3, 12).limit(4).toArray(), rng2.longs(-3, 12).limit(4).toArray());
Assertions.assertArrayEquals(rng1.longs(5, -13, 2).toArray(), rng2.longs(5, -13, 2).toArray());

Assertions.assertArrayEquals(rng1.doubles().limit(4).toArray(), rng2.doubles().limit(4).toArray());
Assertions.assertArrayEquals(rng1.doubles(5).toArray(), rng2.doubles(5).toArray());
Assertions.assertArrayEquals(rng1.doubles(-3, 12).limit(4).toArray(), rng2.doubles(-3, 12).limit(4).toArray());
Assertions.assertArrayEquals(rng1.doubles(5, -13, 2).toArray(), rng2.doubles(5, -13, 2).toArray());
}
}

0 comments on commit d441d95

Please sign in to comment.