MATH-1348

Subclass of "java.util.Random".


Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/3411f29e
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/3411f29e
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/3411f29e

Branch: refs/heads/develop
Commit: 3411f29e2377788cdaa5a4eeaddc53355f085a78
Parents: e366894
Author: Gilles <er...@apache.org>
Authored: Mon Mar 28 03:25:05 2016 +0200
Committer: Gilles <er...@apache.org>
Committed: Mon Mar 28 03:25:05 2016 +0200

----------------------------------------------------------------------
 .../commons/math4/random/JDKRandomAdaptor.java  | 148 +++++++++++++++++++
 .../math4/random/JDKRandomAdaptorTest.java      | 113 ++++++++++++++
 2 files changed, 261 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-math/blob/3411f29e/src/main/java/org/apache/commons/math4/random/JDKRandomAdaptor.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/math4/random/JDKRandomAdaptor.java 
b/src/main/java/org/apache/commons/math4/random/JDKRandomAdaptor.java
new file mode 100644
index 0000000..f3ab22e
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/random/JDKRandomAdaptor.java
@@ -0,0 +1,148 @@
+/*
+ * 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.math4.random;
+
+import java.util.Random;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import org.apache.commons.math4.exception.MathInternalError;
+import org.apache.commons.math4.exception.MathUnsupportedOperationException;
+import org.apache.commons.math4.rng.UniformRandomProvider;
+import org.apache.commons.math4.distribution.RealDistribution;
+import org.apache.commons.math4.distribution.NormalDistribution;
+
+/**
+ * Extension of {@link java.util.Random} that delegates the number
+ * generation to a {@link UniformRandomProvider}.
+ *
+ * <p>
+ * This class allows usage of JDK utilities that take an instance
+ * of type {@code Random} as argument.
+ * <br>
+ * Other than for this specific purpose, usage of this class
+ * is best avoided; indeed, because of the following limitations:
+ * <ul>
+ *  <li>
+ *   {@code MathUnsupportedOperationException} will be raised if
+ *   serialization is attempted.
+ *  </li>
+ *  <li>
+ *   Reseeding is not supported.
+ *  </li>
+ * </ul>
+ * an instance of this class cannot be a substitute for an instance
+ * of the parent class if those functionalities are required.
+ * </p>
+ *
+ * @since 4.0
+ */
+public final class JDKRandomAdaptor extends Random {
+    /** Serial version identifier. */
+    private static final long serialVersionUID = 666L;
+    /** Delegate. */
+    private final transient UniformRandomProvider rng;
+    /** Cf. "nextGaussian()" method. */
+    private final transient RealDistribution.Sampler gauss;
+
+    /**
+     * Creates an adaptor.
+     *
+     * @param rng Generator.
+     */
+    public JDKRandomAdaptor(UniformRandomProvider rng) {
+        super(0L);
+
+        this.rng = rng;
+        gauss = new NormalDistribution().createSampler(rng);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean nextBoolean() {
+        return rng.nextBoolean();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void nextBytes(byte[] bytes) {
+        rng.nextBytes(bytes);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public double nextDouble() {
+        return rng.nextDouble();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public float nextFloat() {
+        return rng.nextFloat();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public double nextGaussian() {
+        return gauss.sample();
+    }
+
+    /** {@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
+    protected int next(int bits) {
+        // Should never happen: it means that some methods were not overridden.
+        throw new MathInternalError();
+    }
+
+    /**
+     * Seeding is not supported.
+     *
+     * @param seed Ignored.
+     */
+    @Override
+    public void setSeed(long seed) {
+        // Cannot throw because the constructor of "Random" calls it.
+        // throw new MathUnsupportedOperationException();
+    }
+
+    /**
+     * @param out Ignored.
+     * @throws IOException Ignored.
+     * @throws MathUnsupportedOperationException if called.
+     */
+    private void writeObject(ObjectOutputStream out)
+        throws IOException {
+        throw new MathUnsupportedOperationException();
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/3411f29e/src/test/java/org/apache/commons/math4/random/JDKRandomAdaptorTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/commons/math4/random/JDKRandomAdaptorTest.java 
b/src/test/java/org/apache/commons/math4/random/JDKRandomAdaptorTest.java
new file mode 100644
index 0000000..5ba68c7
--- /dev/null
+++ b/src/test/java/org/apache/commons/math4/random/JDKRandomAdaptorTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.math4.random;
+
+import java.util.Random;
+import org.apache.commons.math4.exception.MathUnsupportedOperationException;
+import org.apache.commons.math4.rng.UniformRandomProvider;
+import org.apache.commons.math4.rng.RandomSource;
+import org.apache.commons.math4.distribution.RealDistribution;
+import org.apache.commons.math4.distribution.NormalDistribution;
+import org.apache.commons.math4.TestUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test cases for {@link JDKRandomAdaptor}.
+ */
+public class JDKRandomAdaptorTest {
+
+    @Test
+    public void testUniform() {
+        final RandomSource source = RandomSource.WELL_19937_C;
+        final long seed = RandomSource.createLong(); // Random seed.
+
+        final UniformRandomProvider reference = RandomSource.create(source, 
seed);
+        final Random random = new JDKRandomAdaptor(RandomSource.create(source, 
seed));
+
+        final int n = 3; // Check several times, reusing the same RNG.
+        for (int i = 0; i < n; i++) {
+            checkUniform(reference, random);
+        }
+    }
+
+    @Test
+    public void testGaussian() {
+        final RandomSource source = RandomSource.WELL_19937_C;
+        final long seed = RandomSource.createLong(); // Random seed.
+
+        final UniformRandomProvider reference = RandomSource.create(source, 
seed);
+        final RealDistribution.Sampler s = new NormalDistribution(0, 
1).createSampler(reference);
+
+        final Random random = new JDKRandomAdaptor(RandomSource.create(source, 
seed));
+
+        final int n = 11; // Check several times, reusing the same RNG.
+        for (int i = 0; i < n; i++) {
+            Assert.assertEquals(s.sample(), random.nextGaussian(), 0);
+        }
+    }
+
+    @Test
+    public void testSeedIsIgnored() {
+        final RandomSource source = RandomSource.WELL_19937_C;
+        final long seed = RandomSource.createLong(); // Random seed.
+
+        Random random;
+
+        random = new JDKRandomAdaptor(RandomSource.create(source, seed));
+        final double withoutReseed = random.nextDouble();
+
+        // Same RNG.
+        random = new JDKRandomAdaptor(RandomSource.create(source, seed));
+        final long differentSeed = seed + 1;
+        random.setSeed(differentSeed); // Is seeding ignored?
+        final double withReseed = random.nextDouble();
+
+        Assert.assertEquals(withoutReseed, withReseed, 0);
+    }
+
+    @Test(expected=MathUnsupportedOperationException.class)
+    public void testSerializeIsNotSupported() {
+        TestUtils.serializeAndRecover(new 
JDKRandomAdaptor(RandomSource.create(RandomSource.WELL_512_A)));
+    }
+
+    /**
+     * Check uniform random generator.
+     *
+     * @param rand1 Reference generator.
+     * @param rand2 Generator under test.
+     */
+    private void checkUniform(UniformRandomProvider rand1,
+                              Random rand2) {
+        final int len = 11;
+        final byte[] bytes1 = new byte[len];
+        final byte[] bytes2 = new byte[len];
+        rand1.nextBytes(bytes1);
+        rand2.nextBytes(bytes2);
+        Assert.assertArrayEquals(bytes1, bytes2);
+
+        Assert.assertEquals(rand1.nextBoolean(), rand2.nextBoolean());
+
+        Assert.assertEquals(rand1.nextInt(), rand2.nextInt());
+        Assert.assertEquals(rand1.nextInt(len), rand2.nextInt(len));
+
+        Assert.assertEquals(rand1.nextLong(), rand2.nextLong());
+
+        Assert.assertEquals(rand1.nextDouble(), rand2.nextDouble(), 0);
+        Assert.assertEquals(rand1.nextFloat(), rand2.nextFloat(), 0);
+    }
+}

Reply via email to