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
commit d441d958581c09cef31d6a46d6b70faf1d029598 Author: aherbert <[email protected]> AuthorDate: Tue May 10 16:42:30 2022 +0100 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. --- .../jmh/simple/ThreadLocalPerformance.java | 23 +- .../DiscreteProbabilityCollectionSamplerTest.java | 23 +- .../distribution/SmallMeanPoissonSamplerTest.java | 32 +-- .../ZigguratNormalizedGaussianSamplerTest.java | 15 +- .../apache/commons/rng/simple/RandomSource.java | 125 ++++++++++- .../apache/commons/rng/simple/RandomAssert.java | 30 ++- .../commons/rng/simple/RandomSourceTest.java | 244 +++++++++++++++++++++ src/main/resources/pmd/pmd-ruleset.xml | 8 +- 8 files changed, 414 insertions(+), 86 deletions(-) diff --git a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/simple/ThreadLocalPerformance.java b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/simple/ThreadLocalPerformance.java index 8b62fe0d..c2f6ccaf 100644 --- a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/simple/ThreadLocalPerformance.java +++ b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/simple/ThreadLocalPerformance.java @@ -133,28 +133,7 @@ public class ThreadLocalPerformance { @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(); diff --git a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/DiscreteProbabilityCollectionSamplerTest.java b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/DiscreteProbabilityCollectionSamplerTest.java index d6424d95..f41d7b32 100644 --- a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/DiscreteProbabilityCollectionSamplerTest.java +++ b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/DiscreteProbabilityCollectionSamplerTest.java @@ -168,18 +168,17 @@ class DiscreteProbabilityCollectionSamplerTest { // 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); diff --git a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSamplerTest.java b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSamplerTest.java index 06670474..6a55e69e 100644 --- a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSamplerTest.java +++ b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSamplerTest.java @@ -21,6 +21,8 @@ import org.apache.commons.rng.sampling.RandomAssert; 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 @@ class SmallMeanPoissonSamplerTest { /** * 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()); } /** diff --git a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ZigguratNormalizedGaussianSamplerTest.java b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ZigguratNormalizedGaussianSamplerTest.java index 8f8667f4..430681cf 100644 --- a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ZigguratNormalizedGaussianSamplerTest.java +++ b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ZigguratNormalizedGaussianSamplerTest.java @@ -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); diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/RandomSource.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/RandomSource.java index 28b49755..2432631f 100644 --- a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/RandomSource.java +++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/RandomSource.java @@ -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,20 +1018,36 @@ public enum RandomSource { /** * 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, @@ -1036,49 +1055,131 @@ public enum RandomSource { 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(); diff --git a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomAssert.java b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomAssert.java index d2955282..6b44dac8 100644 --- a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomAssert.java +++ b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomAssert.java @@ -46,25 +46,33 @@ public final class RandomAssert { 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 final class RandomAssert { 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()); } } diff --git a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java index 5bb0c8ef..49bd9635 100644 --- a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java +++ b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java @@ -16,7 +16,16 @@ */ package org.apache.commons.rng.simple; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.time.Duration; +import java.util.SplittableRandom; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import org.apache.commons.rng.RandomProviderState; +import org.apache.commons.rng.RestorableUniformRandomProvider; +import org.apache.commons.rng.UniformRandomProvider; import org.apache.commons.rng.core.source64.LongProvider; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -99,4 +108,239 @@ class RandomSourceTest { RandomSource.MSWS.createSeed(broken); }); } + + /** + * Test the unrestorable method correctly delegates all methods. + * This includes the methods with default implementations in UniformRandomProvider, i.e. + * the default methods should not be used. + */ + @Test + void testUnrestorable() { + // The test class should override all default methods + assertNoDefaultMethods(RestorableRNG.class); + + final UniformRandomProvider rng1 = new RestorableRNG(); + final RestorableRNG r = new RestorableRNG(); + final UniformRandomProvider rng2 = RandomSource.unrestorable(r); + Assertions.assertNotSame(rng2, r); + + // The unrestorable instance should override all default methods + assertNoDefaultMethods(rng2.getClass()); + + // Despite the newly created RNG not being a RestorableUniformRandomProvider, + // the method still wraps it in a new object. This is the behaviour since version 1.0. + // It allows the method to wrap objects that implement UniformRandomProvider (such + // as sub-interfaces or concrete classes) to prevent access to any additional methods. + Assertions.assertNotSame(rng2, RandomSource.unrestorable(rng2)); + + // Ensure that they generate the same values. + RandomAssert.assertProduceSameSequence(rng1, rng2); + + // Cast must work. + @SuppressWarnings("unused") + final RestorableUniformRandomProvider restorable = (RestorableUniformRandomProvider) rng1; + // Cast must fail. + Assertions.assertThrows(ClassCastException.class, () -> { + @SuppressWarnings("unused") + RestorableUniformRandomProvider dummy = (RestorableUniformRandomProvider) rng2; + }); + } + + /** + * Assert the class has overridden all default public interface methods. + * + * @param cls the class + */ + private static void assertNoDefaultMethods(Class<?> cls) { + for (final Method method : cls.getMethods()) { + if ((method.getModifiers() & Modifier.PUBLIC) != 0) { + Assertions.assertTrue(!method.isDefault(), + () -> cls.getName() + " should override method: " + method.toGenericString()); + } + } + } + + /** + * Class to provide a complete implementation of the {@link UniformRandomProvider} interface. + * This must return a different result than the default implementations in the interface. + */ + private static class RestorableRNG implements RestorableUniformRandomProvider { + /** The source of randomness. */ + private final SplittableRandom rng = new SplittableRandom(123); + + @Override + public void nextBytes(byte[] bytes) { + nextBytes(bytes, 0, bytes.length); + } + + @Override + public void nextBytes(byte[] bytes, int start, int len) { + RestorableUniformRandomProvider.super.nextBytes(bytes, start, len); + // Rotate + for (int i = start + len; i-- > start;) { + bytes[i] += 1; + } + } + + @Override + public int nextInt() { + return RestorableUniformRandomProvider.super.nextInt() + 1; + } + + @Override + public int nextInt(int n) { + final int v = RestorableUniformRandomProvider.super.nextInt(n) + 1; + return v == n ? 0 : v; + } + + @Override + public int nextInt(int origin, int bound) { + final int v = RestorableUniformRandomProvider.super.nextInt(origin, bound) + 1; + return v == bound ? origin : v; + } + + @Override + public long nextLong() { + // Source of randomness for all derived methods + return rng.nextLong(); + } + + @Override + public long nextLong(long n) { + final long v = RestorableUniformRandomProvider.super.nextLong(n) + 1; + return v == n ? 0 : v; + } + + @Override + public long nextLong(long origin, long bound) { + final long v = RestorableUniformRandomProvider.super.nextLong(origin, bound) + 1; + return v == bound ? origin : v; + } + + @Override + public boolean nextBoolean() { + return !RestorableUniformRandomProvider.super.nextBoolean(); + } + + @Override + public float nextFloat() { + final float v = 1 - RestorableUniformRandomProvider.super.nextFloat(); + return v == 1 ? 0 : v; + } + + @Override + public float nextFloat(float bound) { + final float v = Math.nextUp(RestorableUniformRandomProvider.super.nextFloat(bound)); + return v == bound ? 0 : v; + } + + @Override + public float nextFloat(float origin, float bound) { + final float v = Math.nextUp(RestorableUniformRandomProvider.super.nextFloat(origin, bound)); + return v == bound ? 0 : v; + } + + @Override + public double nextDouble() { + final double v = 1 - RestorableUniformRandomProvider.super.nextDouble(); + return v == 1 ? 0 : v; + } + + @Override + public double nextDouble(double bound) { + final double v = Math.nextUp(RestorableUniformRandomProvider.super.nextDouble(bound)); + return v == bound ? 0 : v; + } + + @Override + public double nextDouble(double origin, double bound) { + final double v = Math.nextUp(RestorableUniformRandomProvider.super.nextDouble(origin, bound)); + return v == bound ? 0 : v; + } + + // Stream methods must return different values than the default so we reimplement them + + @Override + public IntStream ints() { + return IntStream.generate(() -> nextInt() + 1).sequential(); + } + + @Override + public IntStream ints(int origin, int bound) { + return IntStream.generate(() -> { + final int v = nextInt(origin, bound) + 1; + return v == bound ? origin : v; + }).sequential(); + } + + @Override + public IntStream ints(long streamSize) { + return ints().limit(streamSize); + } + + @Override + public IntStream ints(long streamSize, int origin, int bound) { + return ints(origin, bound).limit(streamSize); + } + + @Override + public LongStream longs() { + return LongStream.generate(() -> nextLong() + 1).sequential(); + } + + @Override + public LongStream longs(long origin, long bound) { + return LongStream.generate(() -> { + final long v = nextLong(origin, bound) + 1; + return v == bound ? origin : v; + }).sequential(); + } + + @Override + public LongStream longs(long streamSize) { + return longs().limit(streamSize); + } + + @Override + public LongStream longs(long streamSize, long origin, long bound) { + return longs(origin, bound).limit(streamSize); + } + + @Override + public DoubleStream doubles() { + return DoubleStream.generate(() -> { + final double v = Math.nextUp(nextDouble()); + return v == 1 ? 0 : v; + }).sequential(); + } + + @Override + public DoubleStream doubles(double origin, double bound) { + return DoubleStream.generate(() -> { + final double v = Math.nextUp(nextDouble(origin, bound)); + return v == bound ? origin : v; + }).sequential(); + } + + @Override + public DoubleStream doubles(long streamSize) { + return doubles().limit(streamSize); + } + + @Override + public DoubleStream doubles(long streamSize, double origin, double bound) { + return doubles(origin, bound).limit(streamSize); + } + + @Override + public RandomProviderState saveState() { + // Do nothing + return null; + } + + @Override + public void restoreState(RandomProviderState state) { + // Do nothing + } + } } diff --git a/src/main/resources/pmd/pmd-ruleset.xml b/src/main/resources/pmd/pmd-ruleset.xml index ae95f65f..288690f7 100644 --- a/src/main/resources/pmd/pmd-ruleset.xml +++ b/src/main/resources/pmd/pmd-ruleset.xml @@ -171,16 +171,18 @@ </rule> <rule ref="category/java/design.xml/ExcessiveMethodLength"> <properties> - <!-- The length is due to comments --> + <!-- The length is due to comments, or for RandomSource the wrapping of a delegate UniformRandomProvider --> <property name="violationSuppressXPath" value="//ClassOrInterfaceDeclaration[@SimpleName='AliasMethodDiscreteSampler' - or @SimpleName='ProbabilityDensityApproximationCommand']"/> + or @SimpleName='ProbabilityDensityApproximationCommand'] + or ./ancestor::EnumDeclaration[@SimpleName='RandomSource']"/> </properties> </rule> <rule ref="category/java/design.xml/ExcessiveClassLength"> <properties> <!-- The length is due to multiple implementations as inner classes --> <property name="violationSuppressXPath" value="//ClassOrInterfaceDeclaration[@SimpleName='MarsagliaTsangWangDiscreteSampler' - or @SimpleName='CompositeSamplers' or @SimpleName='StableSampler' or @SimpleName='ZigguratSampler']"/> + or @SimpleName='CompositeSamplers' or @SimpleName='StableSampler' or @SimpleName='ZigguratSampler'] + or ./ancestor::EnumDeclaration[@SimpleName='RandomSource']"/> </properties> </rule> <rule ref="category/java/design.xml/ExcessiveParameterList">
