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 2019/09/03 08:43:35 UTC
[commons-rng] branch master updated (9f30ec9 -> b4e5338)
This is an automated email from the ASF dual-hosted git repository.
aherbert pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-rng.git.
from 9f30ec9 Add SFC32 and SFC64 stress test results.
new 592ad0b RNG-115: Fix JDKRandom to restore state to a new instance.
new 503b23d RNG-115: Track changes.
new 801d7ac RNG-19: Create a wrapper for JDK Random.
new b4e5338 RNG-19: Track changes.
The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../commons/rng/core/source32/JDKRandom.java | 19 ++-
.../commons/rng/core/source32/JDKRandomTest.java | 29 ++++
.../commons/rng/simple/JDKRandomWrapper.java | 123 +++++++++++++++
.../commons/rng/simple/JDKRandomWrapperTest.java | 170 +++++++++++++++++++++
src/changes/changes.xml | 10 ++
5 files changed, 346 insertions(+), 5 deletions(-)
create mode 100644 commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomWrapper.java
create mode 100644 commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomWrapperTest.java
[commons-rng] 04/04: RNG-19: Track changes.
Posted by ah...@apache.org.
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 b4e5338c309189d7c2b279c1ec874bd8eba35622
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Tue Sep 3 09:43:31 2019 +0100
RNG-19: Track changes.
---
src/changes/changes.xml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index cd604b4..771b4d6 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -75,6 +75,12 @@ re-run tests that fail, and pass the build if they succeed
within the allotted number of reruns (the test will be marked
as 'flaky' in the report).
">
+ <action dev="aherbert" type="add" issue="RNG-19">
+ "JDKRandomWrapper": Wraps an instance of java.util.Random for use as a
+ UniformRandomProvider. Can wrap a SecureRandom to use functionality
+ provided by the JDK for cryptographic random numbers and platform dependent
+ features such as reading /dev/urandom on Linux.
+ </action>
<action dev="aherbert" type="fix" issue="RNG-115">
"JDKRandom": Fixed the restore state method to function when the instance has not
previously been used to save state.
[commons-rng] 02/04: RNG-115: Track changes.
Posted by ah...@apache.org.
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 503b23d17a1742d24007758244b27274739f2d77
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Tue Sep 3 09:25:27 2019 +0100
RNG-115: Track changes.
---
src/changes/changes.xml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 020642b..cd604b4 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -75,6 +75,10 @@ re-run tests that fail, and pass the build if they succeed
within the allotted number of reruns (the test will be marked
as 'flaky' in the report).
">
+ <action dev="aherbert" type="fix" issue="RNG-115">
+ "JDKRandom": Fixed the restore state method to function when the instance has not
+ previously been used to save state.
+ </action>
<action dev="aherbert" type="add" issue="RNG-112">
New "SFC32" and "SFC64" (Small, Fast, Chaotic) generators.
</action>
[commons-rng] 03/04: RNG-19: Create a wrapper for JDK Random.
Posted by ah...@apache.org.
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 801d7acca82d0ca760de05eadf3a323c04da954d
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Sun Sep 1 15:34:23 2019 +0100
RNG-19: Create a wrapper for JDK Random.
This can wrap a SecureRandom instance to provide access to the
underlying OS source of randomness when on a supported platform.
---
.../commons/rng/simple/JDKRandomWrapper.java | 123 +++++++++++++++
.../commons/rng/simple/JDKRandomWrapperTest.java | 170 +++++++++++++++++++++
2 files changed, 293 insertions(+)
diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomWrapper.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomWrapper.java
new file mode 100644
index 0000000..998e4ec
--- /dev/null
+++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomWrapper.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rng.simple;
+
+import org.apache.commons.rng.UniformRandomProvider;
+
+import java.util.Random;
+
+/**
+ * Wraps a {@link Random} instance to implement {@link UniformRandomProvider}. All methods from
+ * the {@code Random} that match those in {@code UniformRandomProvider} are used directly.
+ *
+ * <p>This class can be used to wrap an instance of
+ * {@link java.security.SecureRandom SecureRandom}. The {@code SecureRandom} class provides
+ * cryptographic random number generation. The features available depend on the Java version
+ * and platform. Consult the Java documentation for more details.</p>
+ *
+ * <p>Note: Use of {@code java.util.Random} is <em>not</em> recommended for applications.
+ * There are many other pseudo-random number generators that are statistically superior and often
+ * faster (see {@link RandomSource}).</p>
+ *
+ * @since 1.3
+ * @see java.security.SecureRandom
+ * @see RandomSource
+ */
+public final class JDKRandomWrapper implements UniformRandomProvider {
+ /** The JDK Random instance. */
+ private final Random rng;
+
+ /**
+ * Create a wrapper around a Random instance.
+ *
+ * @param rng JDK {@link Random} instance to which the random number
+ * generation is delegated.
+ */
+ public JDKRandomWrapper(Random rng) {
+ this.rng = rng;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void nextBytes(byte[] bytes) {
+ rng.nextBytes(bytes);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void nextBytes(byte[] bytes,
+ int start,
+ int len) {
+ final byte[] reduced = new byte[len];
+ rng.nextBytes(reduced);
+ System.arraycopy(reduced, 0, bytes, start, len);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int nextInt() {
+ return rng.nextInt();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int nextInt(int n) {
+ return rng.nextInt(n);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public long nextLong() {
+ return rng.nextLong();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public long nextLong(long n) {
+ // Code copied from "o.a.c.rng.core.BaseProvider".
+ if (n <= 0) {
+ throw new IllegalArgumentException("Must be strictly positive: " + n);
+ }
+
+ long bits;
+ long val;
+ do {
+ bits = nextLong() >>> 1;
+ val = bits % n;
+ } while (bits - val + (n - 1) < 0);
+
+ return val;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean nextBoolean() {
+ return rng.nextBoolean();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public float nextFloat() {
+ return rng.nextFloat();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double nextDouble() {
+ return rng.nextDouble();
+ }
+}
diff --git a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomWrapperTest.java b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomWrapperTest.java
new file mode 100644
index 0000000..e4e9895
--- /dev/null
+++ b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomWrapperTest.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rng.simple;
+
+import java.util.Random;
+
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.core.source64.LongProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests for the {@link JDKRandomWrapper} class.
+ */
+public class JDKRandomWrapperTest {
+ /**
+ * Test all the methods shared by Random and UniformRandomProvider are equivalent.
+ */
+ @Test
+ public void testJDKRandomEquivalence() {
+ // Initialize.
+ final long seed = RandomSource.createLong();
+ final Random rng1 = new Random(seed);
+ final UniformRandomProvider rng2 = new JDKRandomWrapper(new Random(seed));
+ checkSameSequence(rng1, rng2);
+ }
+
+ /**
+ * Ensure that both generators produce the same sequences.
+ *
+ * @param rng1 RNG.
+ * @param rng2 RNG.
+ */
+ private static void checkSameSequence(Random rng1,
+ UniformRandomProvider rng2) {
+ for (int i = 0; i < 4; i++) {
+ Assert.assertEquals(rng1.nextInt(),
+ rng2.nextInt());
+ }
+ for (int i = 0; i < 7; i++) {
+ Assert.assertEquals(rng1.nextLong(),
+ rng2.nextLong());
+ }
+ for (int i = 0; i < 9; i++) {
+ Assert.assertEquals(rng1.nextFloat(),
+ rng2.nextFloat(),
+ 0f);
+ }
+ for (int i = 0; i < 12; i++) {
+ Assert.assertEquals(rng1.nextDouble(),
+ rng2.nextDouble(),
+ 0d);
+ }
+ for (int i = 0; i < 18; i++) {
+ Assert.assertEquals(rng1.nextBoolean(),
+ rng2.nextBoolean());
+ }
+ for (int i = 0; i < 19; i++) {
+ final int max = i + 123456;
+ Assert.assertEquals(rng1.nextInt(max),
+ rng2.nextInt(max));
+ }
+
+ final int len = 233;
+ final byte[] store1 = new byte[len];
+ final byte[] store2 = new byte[len];
+ rng1.nextBytes(store1);
+ rng2.nextBytes(store2);
+ for (int i = 0; i < len; i++) {
+ Assert.assertEquals(store1[i],
+ store2[i]);
+ }
+ }
+
+ /**
+ * Test {@link UniformRandomProvider#nextLong(long)} matches that from the core
+ * BaseProvider implementation.
+ */
+ @Test
+ public void testNextLongInRange() {
+ final long seed = RandomSource.createLong();
+ // This will use the RNG core BaseProvider implementation.
+ // Use a LongProvider to directly use the Random::nextLong method
+ // which is different from IntProvider::nextLong.
+ final UniformRandomProvider rng1 = new LongProvider() {
+ private final Random random = new Random(seed);
+
+ @Override
+ public long next() {
+ return random.nextLong();
+ }
+ };
+ final UniformRandomProvider rng2 = new JDKRandomWrapper(new Random(seed));
+
+ // Test cases
+ // 1 : Smallest range
+ // 256 : Integer power of 2
+ // 56757 : Integer range
+ // 1L << 32 : Non-integer power of 2
+ // (1L << 62) + 1 : Worst case for rejection rate for the algorithm.
+ // Reject probability is approximately 0.5 thus the test hits
+ // all code paths.
+ for (final long max : new long[] {1, 256, 56757, 1L << 32, (1L << 62) + 1}) {
+ for (int i = 0; i < 10; i++) {
+ Assert.assertEquals(rng1.nextLong(max),
+ rng2.nextLong(max));
+ }
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNextLongInRangeThrows() {
+ final UniformRandomProvider rng1 = new JDKRandomWrapper(new Random(5675767L));
+ rng1.nextLong(0);
+ }
+
+ /**
+ * Test the bytes created by {@link UniformRandomProvider#nextBytes(byte[], int, int)} matches
+ * {@link Random#nextBytes(byte[])}.
+ */
+ @Test
+ public void testNextByteInRange() {
+ final long seed = RandomSource.createLong();
+ final Random rng1 = new Random(seed);
+ final UniformRandomProvider rng2 = new JDKRandomWrapper(new Random(seed));
+
+ checkSameBytes(rng1, rng2, 1, 0, 1);
+ checkSameBytes(rng1, rng2, 100, 0, 100);
+ checkSameBytes(rng1, rng2, 100, 10, 90);
+ checkSameBytes(rng1, rng2, 245, 67, 34);
+ }
+
+ /**
+ * Ensure that the bytes produced in a sub-range of a byte array by
+ * {@link UniformRandomProvider#nextBytes(byte[], int, int)} match the bytes created
+ * by the JDK {@link Random#nextBytes(byte[])}.
+ *
+ * @param rng1 JDK Random.
+ * @param rng2 RNG.
+ * @param size Size of byte array.
+ * @param start Index at which to start inserting the generated bytes.
+ * @param len Number of bytes to insert.
+ */
+ private static void checkSameBytes(Random rng1,
+ UniformRandomProvider rng2,
+ int size, int start, int length) {
+ final byte[] store1 = new byte[length];
+ final byte[] store2 = new byte[size];
+ rng1.nextBytes(store1);
+ rng2.nextBytes(store2, start, length);
+ for (int i = 0; i < length; i++) {
+ Assert.assertEquals(store1[i],
+ store2[i + start]);
+ }
+ }
+}
[commons-rng] 01/04: RNG-115: Fix JDKRandom to restore state to a
new instance.
Posted by ah...@apache.org.
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 592ad0be4fe4fa912b5cdaf5f83b006eb8a02f77
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Mon Sep 2 21:42:12 2019 +0100
RNG-115: Fix JDKRandom to restore state to a new instance.
Save the state size to the byte array representation. This can be read
by any instance when restoring.
---
.../commons/rng/core/source32/JDKRandom.java | 19 ++++++++++----
.../commons/rng/core/source32/JDKRandomTest.java | 29 ++++++++++++++++++++++
2 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/JDKRandom.java b/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/JDKRandom.java
index 94ba0b4..e9245b1 100644
--- a/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/JDKRandom.java
+++ b/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/JDKRandom.java
@@ -21,6 +21,9 @@ import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.ByteArrayOutputStream;
+
+import org.apache.commons.rng.core.util.NumberFactory;
+
import java.io.ByteArrayInputStream;
/**
@@ -42,8 +45,6 @@ import java.io.ByteArrayInputStream;
public class JDKRandom extends IntProvider {
/** Delegate. Cannot be "final" (to allow serialization). */
private Random delegate;
- /** Size of the byte representation of the state (of the delegate). */
- private int stateSize;
/**
* Creates an instance with the given seed.
@@ -75,8 +76,11 @@ public class JDKRandom extends IntProvider {
oos.writeObject(delegate);
final byte[] state = bos.toByteArray();
- stateSize = state.length; // To allow state recovery.
- return composeStateInternal(state,
+ final int stateSize = state.length; // To allow state recovery.
+ // Compose the size with the state
+ final byte[] sizeAndState = composeStateInternal(NumberFactory.makeByteArray(stateSize),
+ state);
+ return composeStateInternal(sizeAndState,
super.getStateInternal());
} catch (IOException e) {
// Workaround checked exception.
@@ -87,7 +91,12 @@ public class JDKRandom extends IntProvider {
/** {@inheritDoc} */
@Override
protected void setStateInternal(byte[] s) {
- final byte[][] c = splitStateInternal(s, stateSize);
+ // First obtain the state size
+ final byte[][] s2 = splitStateInternal(s, 4);
+ final int stateSize = NumberFactory.makeInt(s2[0]);
+
+ // Second obtain the state
+ final byte[][] c = splitStateInternal(s2[1], stateSize);
try {
final ByteArrayInputStream bis = new ByteArrayInputStream(c[0]);
diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/JDKRandomTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/JDKRandomTest.java
index 73be52e..0e86baf 100644
--- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/JDKRandomTest.java
+++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/JDKRandomTest.java
@@ -18,6 +18,7 @@ package org.apache.commons.rng.core.source32;
import java.util.Random;
+import org.apache.commons.rng.RandomProviderState;
import org.junit.Assert;
import org.junit.Test;
@@ -35,4 +36,32 @@ public class JDKRandomTest {
Assert.assertEquals(r + " nextInt", jdk.nextInt(), rng.nextInt());
}
}
+
+ /**
+ * Test the state can be used to restore a new instance that has not previously had a call
+ * to save the state.
+ */
+ @Test
+ public void testRestoreToNewInstance() {
+ final long seed = 8796746234L;
+ final JDKRandom rng1 = new JDKRandom(seed);
+ final JDKRandom rng2 = new JDKRandom(seed + 1);
+
+ // Ensure different
+ final int numRepeats = 10;
+ for (int r = 0; r < numRepeats; r++) {
+ Assert.assertNotEquals(r + " nextInt", rng1.nextInt(), rng2.nextInt());
+ }
+
+ final RandomProviderState state = rng1.saveState();
+ // This second instance will not know the state size required to write
+ // java.util.Random to serialized form. This is only known when the saveState
+ // method is called.
+ rng2.restoreState(state);
+
+ // Ensure the same
+ for (int r = 0; r < numRepeats; r++) {
+ Assert.assertEquals(r + " nextInt", rng1.nextInt(), rng2.nextInt());
+ }
+ }
}