Repository: commons-rng
Updated Branches:
  refs/heads/multimodule 7e12202ac -> 79fcc8c29


RNG-24: Bridge to "java.util.Random".


Project: http://git-wip-us.apache.org/repos/asf/commons-rng/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-rng/commit/79fcc8c2
Tree: http://git-wip-us.apache.org/repos/asf/commons-rng/tree/79fcc8c2
Diff: http://git-wip-us.apache.org/repos/asf/commons-rng/diff/79fcc8c2

Branch: refs/heads/multimodule
Commit: 79fcc8c29017bbeaaf88dc228c32f446efd845c5
Parents: 7e12202
Author: Gilles <er...@apache.org>
Authored: Wed Nov 9 13:41:51 2016 +0100
Committer: Gilles <er...@apache.org>
Committed: Wed Nov 9 13:41:51 2016 +0100

----------------------------------------------------------------------
 .../commons/rng/simple/JDKRandomBridge.java     | 125 +++++++++++++++++++
 .../commons/rng/simple/JDKRandomBridgeTest.java | 121 ++++++++++++++++++
 2 files changed, 246 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-rng/blob/79fcc8c2/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomBridge.java
----------------------------------------------------------------------
diff --git 
a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomBridge.java
 
b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomBridge.java
new file mode 100644
index 0000000..b2831db
--- /dev/null
+++ 
b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomBridge.java
@@ -0,0 +1,125 @@
+/*
+ * 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.io.Serializable;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.util.Random;
+import org.apache.commons.rng.RestorableUniformRandomProvider;
+import org.apache.commons.rng.core.RandomProviderDefaultState;
+
+/**
+ * Subclass of {@link Random} that {@link #next(int) delegates} to a
+ * {@link RestorableUniformRandomProvider} instance but will otherwise
+ * rely on the base class for generating all the random types.
+ * </p>
+ *
+ * <p>
+ * Legacy applications coded against the JDK's API could use this subclass
+ * of {@link Random} in order to replace its linear congruential generator
+ * by any {@link RandomSource}.
+ * Use of this class is however <em>not</em> recommended for new applications.
+ * </p>
+ *
+ * @since 1.0
+ */
+public final class JDKRandomBridge extends Random {
+    /** Serializable version identifier. */
+    private static final long serialVersionUID = 20161107L;
+    /** Source. */
+    private final RandomSource source;
+    /** Delegate. */
+    private transient RestorableUniformRandomProvider delegate;
+    /** Workaround JDK's "Random" bug: 
https://bugs.openjdk.java.net/browse/JDK-8154225 */
+    private final boolean isInitialized;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param source Source of randomness.
+     * @param seed Seed.  Can be {@code null}.
+     */
+    public JDKRandomBridge(RandomSource source,
+                           Object seed) {
+        this.source = source;
+        delegate = RandomSource.create(source, seed);
+        isInitialized = true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public synchronized void setSeed(long seed) {
+        if (isInitialized) {
+            delegate = RandomSource.create(source, seed);
+
+            // Force the clearing of the "haveNextNextGaussian" flag
+            // (cf. Javadoc of the base class); the value passed here
+            // is irrelevant (since it will not be used).
+            super.setSeed(0L);
+        }
+    }
+
+    /**
+     * Delegates the generation of 32 random bits to the
+     * {@code RandomSource} argument provided at
+     * {@link #JDKRandomBridge(RandomSource,Object) construction}.
+     * The returned value is such that if the source of randomness is
+     * {@link RandomSource#JDK}, all the generated values will be identical
+     * to those produced by the same sequence of calls on a {@link Random}
+     * instance initialized with the same seed.
+     *
+     * @param n Number of random bits which the requested value must contain.
+     * @return the value represented by the {@code n} high-order bits of a
+     * pseudo-random 32-bits integer.
+     */
+    @Override
+    protected synchronized int next(int n) {
+        return delegate.nextInt() >>> (32 - n);
+    }
+
+    /**
+     * @param out Output stream.
+     * @throws IOException if an error occurs.
+     */
+    private synchronized void writeObject(ObjectOutputStream out)
+        throws IOException {
+        // Write non-transient fields.
+        out.defaultWriteObject();
+
+        // Save current state.
+        out.writeObject(((RandomProviderDefaultState) 
delegate.saveState()).getState());
+   }
+
+    /**
+     * @param in Input stream.
+     * @throws IOException if an error occurs.
+     * @throws ClassNotFoundException if an error occurs.
+     */
+    private synchronized void readObject(ObjectInputStream in)
+        throws IOException,
+               ClassNotFoundException {
+        // Read non-transient fields.
+        in.defaultReadObject();
+
+        // Recreate the "delegate" from serialized info.
+        delegate = RandomSource.create(source);
+        // And restore its state.
+        delegate.restoreState(new RandomProviderDefaultState((byte[]) 
in.readObject()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-rng/blob/79fcc8c2/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomBridgeTest.java
----------------------------------------------------------------------
diff --git 
a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomBridgeTest.java
 
b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomBridgeTest.java
new file mode 100644
index 0000000..70fa450
--- /dev/null
+++ 
b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomBridgeTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.util.Random;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests for the {@link JDKRandomBridge} adaptor class.
+ */
+public class JDKRandomBridgeTest {
+    @Test
+    public void testJDKRandomEquivalence() {
+        // Initialize.
+        final long seed = RandomSource.createLong();
+        final Random rng1 = new Random(seed);
+        final Random rng2 = new JDKRandomBridge(RandomSource.JDK, seed);
+        checkSameSequence(rng1, rng2);
+
+        // Reseed.
+        final long newSeed = RandomSource.createLong();
+        Assert.assertNotEquals(seed, newSeed);
+        rng1.setSeed(newSeed);
+        rng2.setSeed(newSeed);
+        checkSameSequence(rng1, rng2);
+    }
+
+    @Test
+    public void testSerialization()
+        throws IOException,
+               ClassNotFoundException {
+        // Initialize.
+        final long seed = RandomSource.createLong();
+        final Random rng = new JDKRandomBridge(RandomSource.SPLIT_MIX_64, 
seed);
+
+        // Serialize.
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(rng);
+
+        // Retrieve from serialized stream.
+        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+        ObjectInputStream ois = new ObjectInputStream(bis);
+        final Random serialRng = (Random) (ois.readObject());
+
+        // Check that the serialized data recreated the orginal state.
+        checkSameSequence(rng, serialRng);
+    }
+
+    /**
+     * Ensure that both generators produce the same sequences.
+     *
+     * @param rng1 RNG.
+     * @param rng2 RNG.
+     */
+    private void checkSameSequence(Random rng1,
+                                   Random 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 < 17; i++) {
+            Assert.assertEquals(rng1.nextGaussian(),
+                                rng2.nextGaussian(),
+                                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]);
+        }
+    }
+}

Reply via email to