You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2016/04/22 01:15:22 UTC

[36/53] [abbrv] [math] MATH-1335.

MATH-1335.

New package "o.a.c.m.rng" contains RNG core functionality (uniform distribution).

Utilities to interface with stress test suites.
Userguide: benchmarks and stress test suites reports (MATH-1327).


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

Branch: refs/heads/develop
Commit: 6ddf4769919bb32cc43c5bf43e2f4e7526d3cda0
Parents: 7a8dc00
Author: Gilles <er...@apache.org>
Authored: Fri Mar 11 01:51:58 2016 +0100
Committer: Gilles <er...@apache.org>
Committed: Sun Mar 20 23:29:55 2016 +0100

----------------------------------------------------------------------
 .../apache/commons/math4/rng/RandomSource.java  |  417 ++
 .../math4/rng/UniformRandomProvider.java        |  118 +
 .../math4/rng/internal/BaseProvider.java        |  141 +
 .../math4/rng/internal/ProviderBuilder.java     |  346 ++
 .../math4/rng/internal/StateSettable.java       |   49 +
 .../math4/rng/internal/package-info.java        |   51 +
 .../rng/internal/source32/AbstractWell.java     |  208 +
 .../rng/internal/source32/ISAACRandom.java      |  270 ++
 .../rng/internal/source32/IntProvider.java      |  137 +
 .../math4/rng/internal/source32/JDKRandom.java  |   95 +
 .../rng/internal/source32/MersenneTwister.java  |  230 ++
 .../rng/internal/source32/RandomIntSource.java  |   30 +
 .../math4/rng/internal/source32/Well1024a.java  |   78 +
 .../math4/rng/internal/source32/Well19937a.java |   80 +
 .../math4/rng/internal/source32/Well19937c.java |   85 +
 .../math4/rng/internal/source32/Well44497a.java |   83 +
 .../math4/rng/internal/source32/Well44497b.java |   90 +
 .../math4/rng/internal/source32/Well512a.java   |   78 +
 .../rng/internal/source32/package-info.java     |   52 +
 .../rng/internal/source64/LongProvider.java     |  141 +
 .../internal/source64/MersenneTwister64.java    |  201 +
 .../rng/internal/source64/RandomLongSource.java |   30 +
 .../math4/rng/internal/source64/SplitMix64.java |   78 +
 .../math4/rng/internal/source64/TwoCmres.java   |  310 ++
 .../rng/internal/source64/XorShift1024Star.java |  108 +
 .../rng/internal/source64/package-info.java     |   52 +
 .../math4/rng/internal/util/Int2Long.java       |   37 +
 .../math4/rng/internal/util/IntArray2Int.java   |   41 +
 .../rng/internal/util/IntArray2LongArray.java   |   44 +
 .../math4/rng/internal/util/Long2Int.java       |   36 +
 .../math4/rng/internal/util/Long2IntArray.java  |   50 +
 .../math4/rng/internal/util/Long2LongArray.java |   56 +
 .../rng/internal/util/LongArray2IntArray.java   |   43 +
 .../math4/rng/internal/util/LongArray2Long.java |   41 +
 .../math4/rng/internal/util/LongMixInt.java     |   50 +
 .../math4/rng/internal/util/LongMixLong.java    |   56 +
 .../math4/rng/internal/util/NoOpConverter.java  |   40 +
 .../math4/rng/internal/util/NumberFactory.java  |  327 ++
 .../math4/rng/internal/util/SeedConverter.java  |   35 +
 .../internal/util/SeedConverterComposer.java    |   56 +
 .../math4/rng/internal/util/SeedFactory.java    |  262 ++
 .../math4/rng/internal/util/package-info.java   |   22 +
 .../apache/commons/math4/rng/package-info.java  |   95 +
 src/site/apt/userguide/rng.apt                  |  228 +
 .../txt/userguide/rng/stress/dh/run_1/dh_1      |  146 +
 .../txt/userguide/rng/stress/dh/run_1/dh_10     |  139 +
 .../txt/userguide/rng/stress/dh/run_1/dh_11     |  148 +
 .../txt/userguide/rng/stress/dh/run_1/dh_12     |  172 +
 .../txt/userguide/rng/stress/dh/run_1/dh_13     |  168 +
 .../txt/userguide/rng/stress/dh/run_1/dh_2      |  139 +
 .../txt/userguide/rng/stress/dh/run_1/dh_3      |  173 +
 .../txt/userguide/rng/stress/dh/run_1/dh_4      |  140 +
 .../txt/userguide/rng/stress/dh/run_1/dh_5      |  140 +
 .../txt/userguide/rng/stress/dh/run_1/dh_6      |  146 +
 .../txt/userguide/rng/stress/dh/run_1/dh_7      |  204 +
 .../txt/userguide/rng/stress/dh/run_1/dh_8      |  201 +
 .../txt/userguide/rng/stress/dh/run_1/dh_9      |  143 +
 .../txt/userguide/rng/stress/dh/run_2/dh_1      |  146 +
 .../txt/userguide/rng/stress/dh/run_2/dh_10     |  172 +
 .../txt/userguide/rng/stress/dh/run_2/dh_11     |  259 ++
 .../txt/userguide/rng/stress/dh/run_2/dh_12     |  168 +
 .../txt/userguide/rng/stress/dh/run_2/dh_13     |  261 ++
 .../txt/userguide/rng/stress/dh/run_2/dh_2      |  140 +
 .../txt/userguide/rng/stress/dh/run_2/dh_3      |  139 +
 .../txt/userguide/rng/stress/dh/run_2/dh_4      |  171 +
 .../txt/userguide/rng/stress/dh/run_2/dh_5      |  143 +
 .../txt/userguide/rng/stress/dh/run_2/dh_6      |  260 ++
 .../txt/userguide/rng/stress/dh/run_2/dh_7      |  143 +
 .../txt/userguide/rng/stress/dh/run_2/dh_8      |  800 ++++
 .../txt/userguide/rng/stress/dh/run_2/dh_9      |  175 +
 .../txt/userguide/rng/stress/tu/run_1/tu_1      | 3882 ++++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_10     | 3803 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_11     | 3795 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_12     | 3803 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_13     | 3802 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_2      | 3803 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_3      | 3807 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_4      | 3806 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_5      | 3804 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_6      | 3804 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_7      | 3803 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_8      | 3804 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_1/tu_9      | 3802 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_1      | 3879 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_10     | 3803 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_11     | 3795 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_12     | 3795 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_13     | 3795 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_2      | 3803 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_3      | 3808 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_4      | 3805 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_5      | 3804 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_6      | 3803 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_7      | 3803 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_8      | 3803 +++++++++++++++++
 .../txt/userguide/rng/stress/tu/run_2/tu_9      | 3795 +++++++++++++++++
 src/site/site.xml                               |    1 +
 src/site/xdoc/userguide/index.xml               |    7 +
 .../math4/rng/Providers32ParametricTest.java    |   64 +
 .../math4/rng/Providers64ParametricTest.java    |   64 +
 .../rng/ProvidersCommonParametricTest.java      |  667 +++
 .../apache/commons/math4/rng/ProvidersList.java |  157 +
 .../rng/internal/source32/ISAACRandomTest.java  |  389 ++
 .../rng/internal/source32/JDKRandomTest.java    |   38 +
 .../internal/source32/MersenneTwisterTest.java  |  240 ++
 .../rng/internal/source32/Well1024aTest.java    |   71 +
 .../rng/internal/source32/Well19937aTest.java   |  109 +
 .../rng/internal/source32/Well19937cTest.java   |  109 +
 .../rng/internal/source32/Well44497aTest.java   |  109 +
 .../rng/internal/source32/Well44497bTest.java   |  109 +
 .../rng/internal/source32/Well512aTest.java     |   69 +
 .../source64/MersenneTwister64Test.java         |  239 ++
 .../rng/internal/source64/SplitMix64Test.java   |   45 +
 .../rng/internal/source64/TwoCmresTest.java     |   55 +
 .../internal/source64/XorShift1024StarTest.java |   55 +
 .../rng/internal/util/NumberFactoryTest.java    |  164 +
 .../rng/internal/util/SeedFactoryTest.java      |  111 +
 src/userguide/README                            |   15 +-
 src/userguide/c/rng/stdin2testu01.c             |  127 +
 .../math4/userguide/rng/GeneratorsList.java     |   57 +
 .../math4/userguide/rng/RandomStressTester.java |  280 ++
 src/userguide/pom.xml                           |   30 +
 122 files changed, 112502 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-math/blob/6ddf4769/src/main/java/org/apache/commons/math4/rng/RandomSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/rng/RandomSource.java b/src/main/java/org/apache/commons/math4/rng/RandomSource.java
new file mode 100644
index 0000000..087960c
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/rng/RandomSource.java
@@ -0,0 +1,417 @@
+/*
+ * 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.rng;
+
+import org.apache.commons.math4.exception.MathUnsupportedOperationException;
+import org.apache.commons.math4.rng.internal.ProviderBuilder;
+import org.apache.commons.math4.rng.internal.BaseProvider;
+import org.apache.commons.math4.rng.internal.util.SeedFactory;
+import org.apache.commons.math4.rng.internal.source64.TwoCmres;
+
+/**
+ * This class provides the API for creating generators of random numbers.
+ * <p>
+ * Usage examples:
+ * <pre><code>
+ *  UniformRandomProvider rng = RandomSource.create(RandomSource.MT);
+ * </code></pre>
+ * or
+ * <pre><code>
+ *  final int[] seed = new int[] { 196, 9, 0, 226  };
+ *  UniformRandomProvider rng = RandomSource.create(RandomSource.MT, seed);
+ * </code></pre>
+ * or
+ * <pre><code>
+ *  final int[] seed = RandomSource.createIntArray(256);
+ *  UniformRandomProvider rng = RandomSource.create(RandomSource.MT, seed);
+ * </code></pre>
+ * where the first argument to method {@code create} is the identifier
+ * of the generator's concrete implementation, and the second the is the
+ * (optional) seed.
+ * <br>
+ * In the first form, a random seed will be {@link SeedFactory generated
+ * automatically}; the random seed generation step is explicit in the
+ * third form.
+ * </p>
+ *
+ * <p>
+ * Seeding is the procedure by which a value (or set of values) is
+ * used to <i>initialize</i> a generator instance.
+ * The requirement that a given seed will always result in the same
+ * internal state allows to create different instances of a generator
+ * that will produce the same sequence of pseudo-random numbers.
+ * </p>
+ *
+ * <p>
+ * The type of data used as a seed depends on the concrete implementation
+ * as some types may not provide enough information to fully initialize
+ * the generator's internal state.
+ * <br>
+ * The reference algorithm's seeding procedure (if provided) operates
+ * on a value of a (single) <i>native</i> type:
+ * Each concrete implementation's constructor creates an instance using
+ * the native type whose information contents is used to set the
+ * internal state.
+ * <br>
+ * When the seed value passed by the caller is of the native type, it is
+ * expected that the sequences produced will be the same as those
+ * produced by other implementations of the algorithm.
+ * <br>
+ * However, when the seed value passed by the caller is not of the native
+ * type, a transformation is performed by this library and the resulting
+ * native type value will <i>not</i> contain more information than the
+ * original seed value.
+ * If the algorithm's native type is "simpler" than the type passed by
+ * the caller, then some (unuse) information will even be lost.
+ * <br>
+ * The transformation from non-native to native seed type is arbitrary,
+ * as long as it does not reduce the amount of information required by
+ * the algorithm to initialize its state.
+ * The consequence of the transformation is that the sequences produced
+ * by this library may not be the same as the sequences produced by other
+ * implementations of the same algorithm!
+ * </p>
+ *
+ * <p>
+ * This class provides methods to generate random seeds (single values
+ * or arrays of values, of {@code int} or {@code long} types) that can
+ * be passed to the {@link RandomSource#create(RandomSource,Object,Object[])
+ * generators factory method}.
+ * <br>
+ * Although the seed-generating methods defined in this class will likely
+ * return different values for all calls, there is no guarantee that the
+ * produced seed will result always in a "good" sequence of numbers, even
+ * if the generator is good.
+ * The only way to ensure that the selected seed will make the generator
+ * produce a "good" sequence is to submit that sequence to a series of
+ * stringent tests, as provided by tools such as
+ * <a href="http://www.phy.duke.edu/~rgb/General/dieharder.php">dieharder</a>
+ * or <a href="http://simul.iro.umontreal.ca/testu01/tu01.html">TestU01</a>.
+ * </p>
+ *
+ * <p>
+ * The current implementations have no provision for producing non-overlapping
+ * sequences.
+ * For parallel applications, a possible workaround is that each thread uses
+ * a generator of a different type (see {@link #TWO_CMRES_SELECT}).
+ * </p>
+ *
+ * <p>
+ * <b>Note:</b>
+ * Seeding is not equivalent to restoring the internal state of an
+ * <i>already initialized</i> generator.
+ * Indeed, generators can have a state that is more complex than the
+ * seed, and seeding is thus a transformation (from seed to state).
+ * Implementations do not provide the inverse transformation (from
+ * state to seed), hence it is not generally possible to know the seed
+ * that would initialize a new generator instance to the current state
+ * of another instance.
+ * Reseeding is also inefficient if the purpose is to continue the
+ * same sequence where another instance left off, as it would require
+ * to "replay" all the calls performed by that other instance (and it
+ * would require to know the number of calls to the primary source of
+ * randomness, which is also not usually accessible).
+ * <br>
+ * This factory thus provides a method for
+ * {@link #saveState(UniformRandomProvider) saving} the internal
+ * state of a generator.
+ * The state is encapsulated in an {@link State "opaque object"} to be
+ * used for {@link #restoreState(UniformRandomProvider,State) restoring}
+ * a generator (of the same type) to an identical state (e.g. to allow
+ * persistent storage, or to continue a sequence from where the original
+ * instance left off.).
+ * </p>
+ *
+ * @since 4.0
+ */
+public enum RandomSource {
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source32.JDKRandom}.
+     * Native seed type: {@code Long}.
+     */
+    JDK(ProviderBuilder.RandomSourceInternal.JDK),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source32.Well512a}.
+     * Native seed type: {@code int[]}.
+     */
+    WELL_512_A(ProviderBuilder.RandomSourceInternal.WELL_512_A),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source32.Well1024a}.
+     * Native seed type: {@code int[]}.
+     */
+    WELL_1024_A(ProviderBuilder.RandomSourceInternal.WELL_1024_A),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source32.Well19937a}.
+     * Native seed type: {@code int[]}.
+     */
+    WELL_19937_A(ProviderBuilder.RandomSourceInternal.WELL_19937_A),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source32.Well19937c}.
+     * Native seed type: {@code int[]}.
+     */
+    WELL_19937_C(ProviderBuilder.RandomSourceInternal.WELL_19937_C),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source32.Well44497a}.
+     * Native seed type: {@code int[]}.
+     */
+    WELL_44497_A(ProviderBuilder.RandomSourceInternal.WELL_44497_A),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source32.Well44497b}.
+     * Native seed type: {@code int[]}.
+     */
+    WELL_44497_B(ProviderBuilder.RandomSourceInternal.WELL_44497_B),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source32.MersenneTwister}.
+     * Native seed type: {@code int[]}.
+     */
+    MT(ProviderBuilder.RandomSourceInternal.MT),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source32.ISAACRandom}.
+     * Native seed type: {@code int[]}.
+     */
+    ISAAC(ProviderBuilder.RandomSourceInternal.ISAAC),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source64.SplitMix64}.
+     * Native seed type: {@code Long}.
+     */
+    SPLIT_MIX_64(ProviderBuilder.RandomSourceInternal.SPLIT_MIX_64),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source64.XorShift1024Star}.
+     * Native seed type: {@code long[]}.
+     */
+    XOR_SHIFT_1024_S(ProviderBuilder.RandomSourceInternal.XOR_SHIFT_1024_S),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source64.TwoCmres}.
+     * Native seed type: {@code Integer}.
+     */
+    TWO_CMRES(ProviderBuilder.RandomSourceInternal.TWO_CMRES),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source64.TwoCmres},
+     * with explicit selection of the two subcycle generators.
+     * Native seed type: {@code Integer}.
+     */
+    TWO_CMRES_SELECT(ProviderBuilder.RandomSourceInternal.TWO_CMRES_SELECT),
+    /**
+     * Source of randomness is {@link org.apache.commons.math4.rng.internal.source64.MersenneTwister64}.
+     * Native seed type: {@code long[]}.
+     */
+    MT_64(ProviderBuilder.RandomSourceInternal.MT_64);
+
+    /** Internal identifier. */
+    private final ProviderBuilder.RandomSourceInternal internalIdentifier;
+
+    /**
+     * @param id Internal identifier.
+     */
+    RandomSource(ProviderBuilder.RandomSourceInternal id) {
+        internalIdentifier = id;
+    }
+
+    /**
+     * @return the internal identifier.
+     */
+    ProviderBuilder.RandomSourceInternal getInternalIdentifier() {
+        return internalIdentifier;
+    }
+
+    /**
+     * Checks whether the type of given {@code seed} is the native type
+     * of the implementation.
+     *
+     * @param seed Seed value.
+     * @return {@code true} if the seed can be passed to the builder
+     * for this RNG type.
+     */
+    public boolean isNativeSeed(Object seed) {
+        return internalIdentifier.isNativeSeed(seed);
+    }
+
+    /**
+     * Marker interface used to define the "save" and "restore"
+     * functionality of the generators.
+     */
+    public interface State {}
+
+    /**
+     * Creates a random number generator with a random seed.
+     *
+     * <p>
+     * Example of usage:
+     * <pre><code>
+     *  UniformRandomProvider rng = RandomSource.create(Source.MT);
+     * </code></pre>
+     * </p>
+     *
+     * @param source {@link RandomSource RNG type}.
+     * @return the RNG.
+     */
+    public static UniformRandomProvider create(RandomSource source) {
+        return create(source, null);
+    }
+
+    /**
+     * Creates a random number generator with the given {@code seed}.
+     *
+     * <p>
+     * Example of usage:
+     * <pre><code>
+     *  UniformRandomProvider rng = RandomSource.create(Source.TWO_CMRES_SELECT, 26219, 6, 9);
+     * </code></pre>
+     * </p>
+     *
+     * <p>
+     * Valid types for the {@code seed} are:
+     *  <ul>
+     *   <li>{@code Integer} (or {@code int})</li>
+     *   <li>{@code Long} (or {@code long})</li>
+     *   <li>{@code int[]}</li>
+     *   <li>{@code long[]}</li>
+     *  </ul>
+     * </p>
+     *
+     * <p>
+     * Notes:
+     * <ul>
+     *  <li>
+     *   When the seed type passed as argument is more complex (i.e. more
+     *   bits can be independently chosen) than the generator's
+     *   {@link #isNativeSeed(Object) native type}, the conversion of a
+     *   set of different seeds will necessarily result in the same value
+     *   of the native seed type.
+     *  </li>
+     *  <li>
+     *   When the native seed type is an array, the same remark applies
+     *   when the array contains more bits than the state of the generator.
+     *  </li>
+     *  <li>
+     *   When the native seed type is an array and the {@code seed} is
+     *   {@code null}, the size of the generated array will be 128.
+     *  </li>
+     * </p>
+     *
+     * @param source {@link RandomSource RNG type}.
+     * @param seed Seed value.  It can be {@code null} (in which case a
+     * random value will be used).
+     * @param data Additional arguments to the implementation's constructor.
+     * Please refer to the documentation of each specific implementation.
+     * @return the RNG.
+     * @throws MathUnsupportedOperationException if the type of the
+     * {@code seed} is invalid.
+     * @throws org.apache.commons.math4.exception.InsufficientDataException
+     * if data is missing to initialize the generator implemented by the
+     * given {@code source}.
+     */
+    public static UniformRandomProvider create(RandomSource source,
+                                               Object seed,
+                                               Object ... data) {
+        return ProviderBuilder.create(source.getInternalIdentifier(), seed, data);
+    }
+
+    /**
+     * Gets the number of elements of the set of "subcycle" generators from
+     * which two can be selected in order to create a {@link TwoCmres} RNG.
+     *
+     * @return the number of implemented subcycle generators.
+     */
+    public static int numberOfCmresGenerators() {
+        return TwoCmres.numberOfSubcycleGenerators();
+    }
+
+    /**
+     * Saves the state of a RNG.
+     *
+     * @param provider Provider.
+     * @return the current state of the given {@code provider}.
+     * @throws MathUnsupportedOperationException if the {@code provider} is
+     * not an object created by this factory or the underlying source of
+     * randomness does not support this functionality.
+     *
+     * @see #restoreState(UniformRandomProvider,RandomSource.State)
+     */
+    public static State saveState(UniformRandomProvider provider) {
+        if (!(provider instanceof BaseProvider)) {
+            throw new MathUnsupportedOperationException();
+        } else {
+            return ((BaseProvider) provider).getState();
+        }
+    }
+
+    /**
+     * Restores the state of a RNG.
+     *
+     * @param provider Provider.
+     * @param state State which the {@code provider} will be set to.
+     * This parameter must have been obtained by a call to
+     * {@link #saveState(UniformRandomProvider) saveState(rng)}
+     * where {@code rng} is either the same object as {@code provider},
+     * or an object of the same concrete type.
+     * @throws MathUnsupportedOperationException if the {@code provider} is
+     * not an object created by this factory or the underlying source of
+     * randomness does not support this functionality.
+     * @throws org.apache.commons.math4.exception.InsufficientDataException
+     * if it was detected that the {@code state} is incompatible with the
+     * given {@code provider}.
+     *
+     * @see #saveState(UniformRandomProvider)
+     */
+    public static void restoreState(UniformRandomProvider provider,
+                                    State state) {
+        if (!(provider instanceof BaseProvider)) {
+            throw new MathUnsupportedOperationException();
+        } else {
+            ((BaseProvider) provider).setState(state);
+        }
+    }
+
+    /**
+     * Creates a number for use as a seed.
+     *
+     * @return a random number.
+     */
+    public static int createInt() {
+        return SeedFactory.createInt();
+    }
+
+    /**
+     * Creates a number for use as a seed.
+     *
+     * @return a random number.
+     */
+    public static long createLong() {
+        return SeedFactory.createLong();
+    }
+
+    /**
+     * Creates an array of numbers for use as a seed.
+     *
+     * @param n Size of the array to create.
+     * @return an array of {@code n} random numbers.
+     */
+    public static int[] createIntArray(int n) {
+        return SeedFactory.createIntArray(n);
+    }
+
+    /**
+     * Creates an array of numbers for use as a seed.
+     *
+     * @param n Size of the array to create.
+     * @return an array of {@code n} random numbers.
+     */
+    public static long[] createLongArray(int n) {
+        return SeedFactory.createLongArray(n);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/6ddf4769/src/main/java/org/apache/commons/math4/rng/UniformRandomProvider.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/rng/UniformRandomProvider.java b/src/main/java/org/apache/commons/math4/rng/UniformRandomProvider.java
new file mode 100644
index 0000000..ef17f06
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/rng/UniformRandomProvider.java
@@ -0,0 +1,118 @@
+/*
+ * 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.rng;
+
+/**
+ * Applies to generators of random number sequences that follow a uniform
+ * distribution.
+ *
+ * @since 4.0
+ */
+public interface UniformRandomProvider {
+    /**
+     * Generates {@code byte} values and places them into a user-supplied array.
+     * <p>
+     * The number of random bytes produced is equal to the length of the
+     * the byte array.
+     * </p>
+     *
+     * @param bytes Byte array in which to put the random bytes.
+     * Cannot be {@code null}.
+     */
+    void nextBytes(byte[] bytes);
+
+    /**
+     * Generates {@code byte} values and places them into a user-supplied array.
+     *
+     * <p>
+     * The array is filled with bytes extracted from random integers.
+     * This implies that the number of random bytes generated may be larger than
+     * the length of the byte array.
+     * </p>
+     *
+     * @param bytes Array in which to put the generated bytes.
+     * Cannot be {@code null}.
+     * @param start Index at which to start inserting the generated bytes.
+     * @param len Number of bytes to insert.
+     * @throws org.apache.commons.math4.exception.OutOfRangeException
+     * if {@code start < 0} or {@code start >= bytes.length}.
+     * @throws org.apache.commons.math4.exception.OutOfRangeException
+     * if {@code len < 0} or {@code len > bytes.length - start}.
+     */
+    void nextBytes(byte[] bytes,
+                   int start,
+                   int len);
+
+    /**
+     * Generates an {@code int} value.
+     *
+     * @return the next random value.
+     */
+    int nextInt();
+
+    /**
+     * Generates an {@code int} value between 0 (inclusive) and the
+     * specified value (exclusive).
+     *
+     * @param n Bound on the random number to be returned.  Must be positive.
+     * @return a random {@code int} value between 0 (inclusive) and n
+     * (exclusive).
+     * @throws org.apache.commons.math4.exception.NotStrictlyPositiveException
+     * if {@code n} is not positive.
+     */
+    int nextInt(int n);
+
+    /**
+     * Generates a {@code long} value.
+     *
+     * @return the next random value.
+     */
+    long nextLong();
+
+    /**
+     * Generates a {@code long} value between 0 (inclusive) and the specified
+     * value (exclusive).
+     *
+     * @param n Bound on the random number to be returned.  Must be positive.
+     * @return a random {@code long} value between 0 (inclusive) and n
+     * (exclusive).
+     * @throws org.apache.commons.math4.exception.NotStrictlyPositiveException
+     * if {@code n} is not positive.
+     */
+    long nextLong(long n);
+
+    /**
+     * Generates a {@code boolean} value.
+     *
+     * @return the next random value.
+     */
+    boolean nextBoolean();
+
+    /**
+     * Generates a {@code float} value between 0 and 1.
+     *
+     * @return the next random value between 0 and 1.
+     */
+    float nextFloat();
+
+    /**
+     * Generates a {@code double} value between 0 and 1.
+     *
+     * @return the next random value between 0 and 1.
+     */
+    double nextDouble();
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/6ddf4769/src/main/java/org/apache/commons/math4/rng/internal/BaseProvider.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/rng/internal/BaseProvider.java b/src/main/java/org/apache/commons/math4/rng/internal/BaseProvider.java
new file mode 100644
index 0000000..e29d854
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/rng/internal/BaseProvider.java
@@ -0,0 +1,141 @@
+/*
+ * 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.rng.internal;
+
+import java.util.Arrays;
+import java.io.Serializable;
+import org.apache.commons.math4.exception.MathUnsupportedOperationException;
+import org.apache.commons.math4.exception.NotStrictlyPositiveException;
+import org.apache.commons.math4.rng.UniformRandomProvider;
+import org.apache.commons.math4.rng.RandomSource;
+
+/**
+ * Base class with default implementation for common methods.
+ */
+public abstract class BaseProvider
+    implements UniformRandomProvider,
+               StateSettable {
+    /** {@inheritDoc} */
+    @Override
+    public int nextInt(int n) throws IllegalArgumentException {
+        if (n > 0) {
+            if ((n & -n) == n) {
+                return (int) ((n * (long) (nextInt() >>> 1)) >> 31);
+            }
+            int bits;
+            int val;
+            do {
+                bits = nextInt() >>> 1;
+                val = bits % n;
+            } while (bits - val + (n - 1) < 0);
+            return val;
+        }
+
+        throw new NotStrictlyPositiveException(n);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public long nextLong(long n) {
+        if (n > 0) {
+            long bits;
+            long val;
+            do {
+                bits = nextLong() >>> 1;
+                val  = bits % n;
+            } while (bits - val + (n - 1) < 0);
+            return val;
+        }
+
+        throw new NotStrictlyPositiveException(n);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return getClass().getName();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public RandomSource.State getState() {
+        return new State(getStateInternal());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void setState(RandomSource.State state) {
+        // Cast will intentionally fail if the argument is not one we created.
+        final State s = (State) state;
+        setStateInternal(s.getState());
+    }
+
+    /**
+     * Creates a snapshot of the RNG state.
+     *
+     * @return the internal state.
+     * @throws MathUnsupportedOperationException if not implemented.
+     */
+    protected byte[] getStateInternal() {
+        throw new MathUnsupportedOperationException();
+    }
+
+    /**
+     * Resets the RNG to the given {@code state}.
+     *
+     * @param state State (previously obtained by a call to
+     * {@link #getStateInternal()}).
+     * @throws MathUnsupportedOperationException if not implemented.
+     */
+    protected void setStateInternal(byte[] state) {
+        throw new MathUnsupportedOperationException();
+    }
+
+    /**
+     * "Black-box" state.
+     * Its sole purpose is to store all the data needed to recover
+     * the same state in order to restart a sequence where it left
+     * off.
+     * External code should not to modify the data contained in
+     * instances of this class.
+     */
+    private static class State
+        implements RandomSource.State,
+                   Serializable {
+        /** Serializable version identifier. */
+        private static final long serialVersionUID = 4720160226L;
+        /** Internal state. */
+        private byte[] state;
+
+        /**
+         * @param state Mapping of all the data which a subclass of
+         * {@link BaseProvider} needs in order to reset its internal
+         * state.
+         */
+        State(byte[] state) {
+            this.state = Arrays.copyOf(state, state.length);
+        }
+
+        /**
+         * @return the internal state.
+         */
+        byte[] getState() {
+            return Arrays.copyOf(state, state.length);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/6ddf4769/src/main/java/org/apache/commons/math4/rng/internal/ProviderBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/rng/internal/ProviderBuilder.java b/src/main/java/org/apache/commons/math4/rng/internal/ProviderBuilder.java
new file mode 100644
index 0000000..f38b679
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/rng/internal/ProviderBuilder.java
@@ -0,0 +1,346 @@
+/*
+ * 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.rng.internal;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.commons.math4.exception.MathUnsupportedOperationException;
+import org.apache.commons.math4.exception.MathInternalError;
+import org.apache.commons.math4.rng.UniformRandomProvider;
+import org.apache.commons.math4.rng.internal.util.SeedFactory;
+import org.apache.commons.math4.rng.internal.util.NoOpConverter;
+import org.apache.commons.math4.rng.internal.util.Int2Long;
+import org.apache.commons.math4.rng.internal.util.Long2Int;
+import org.apache.commons.math4.rng.internal.util.Long2IntArray;
+import org.apache.commons.math4.rng.internal.util.Long2LongArray;
+import org.apache.commons.math4.rng.internal.util.IntArray2LongArray;
+import org.apache.commons.math4.rng.internal.util.LongArray2IntArray;
+import org.apache.commons.math4.rng.internal.util.LongArray2Long;
+import org.apache.commons.math4.rng.internal.util.IntArray2Int;
+import org.apache.commons.math4.rng.internal.util.SeedConverter;
+import org.apache.commons.math4.rng.internal.util.SeedConverterComposer;
+import org.apache.commons.math4.rng.internal.source32.JDKRandom;
+import org.apache.commons.math4.rng.internal.source32.Well512a;
+import org.apache.commons.math4.rng.internal.source32.Well1024a;
+import org.apache.commons.math4.rng.internal.source32.Well19937a;
+import org.apache.commons.math4.rng.internal.source32.Well19937c;
+import org.apache.commons.math4.rng.internal.source32.Well44497a;
+import org.apache.commons.math4.rng.internal.source32.Well44497b;
+import org.apache.commons.math4.rng.internal.source32.ISAACRandom;
+import org.apache.commons.math4.rng.internal.source32.MersenneTwister;
+import org.apache.commons.math4.rng.internal.source64.SplitMix64;
+import org.apache.commons.math4.rng.internal.source64.XorShift1024Star;
+import org.apache.commons.math4.rng.internal.source64.TwoCmres;
+import org.apache.commons.math4.rng.internal.source64.MersenneTwister64;
+
+/**
+ * RNG builder.
+ * <p>
+ * It uses reflection to find the factory method of the RNG implementation,
+ * and performs seed type conversions.
+ * </p>
+ */
+public class ProviderBuilder {
+    /** Length of the seed array (for random seed). */
+    private static final int RANDOM_SEED_ARRAY_SIZE = 128;
+    /** Seed converter. */
+    private static final Long2Int LONG_TO_INT = new Long2Int();
+    /** Seed converter. */
+    private static final Int2Long INT_TO_LONG = new Int2Long();
+    /** Seed converter. */
+    private static final Long2IntArray LONG_TO_INT_ARRAY = new Long2IntArray(RANDOM_SEED_ARRAY_SIZE);
+    /** Seed converter. */
+    private static final Long2LongArray LONG_TO_LONG_ARRAY = new Long2LongArray(RANDOM_SEED_ARRAY_SIZE);
+    /** Seed converter. */
+    private static final LongArray2Long LONG_ARRAY_TO_LONG = new LongArray2Long();
+    /** Seed converter. */
+    private static final IntArray2Int INT_ARRAY_TO_INT = new IntArray2Int();
+    /** Seed converter. */
+    private static final LongArray2IntArray LONG_ARRAY_TO_INT_ARRAY = new LongArray2IntArray();
+    /** Seed converter. */
+    private static final IntArray2LongArray INT_ARRAY_TO_LONG_ARRAY = new IntArray2LongArray();
+    /** Map to convert "Integer" seeds. */
+    private static final Map<Class<?>, SeedConverter<Integer,?>> CONV_INT = new HashMap<>();
+    /** Map to convert "int[]" seeds. */
+    private static final Map<Class<?>, SeedConverter<int[],?>> CONV_INT_ARRAY = new HashMap<>();
+    /** Map to convert "Long" seeds. */
+    private static final Map<Class<?>, SeedConverter<Long,?>> CONV_LONG = new HashMap<>();
+    /** Map to convert "long[]" seeds. */
+    private static final Map<Class<?>, SeedConverter<long[],?>> CONV_LONG_ARRAY = new HashMap<>();
+
+    static {
+        // Input seed type is "Long".
+        // Key is the implementation's "native" seed type.
+        CONV_LONG.put(Integer.class, LONG_TO_INT);
+        CONV_LONG.put(Long.class, new NoOpConverter<Long>());
+        CONV_LONG.put(int[].class, LONG_TO_INT_ARRAY);
+        CONV_LONG.put(long[].class, LONG_TO_LONG_ARRAY);
+
+        // Input seed type is "Integer".
+        // Key is the implementation's "native" seed type.
+        CONV_INT.put(Integer.class, new NoOpConverter<Integer>());
+        CONV_INT.put(Long.class, INT_TO_LONG);
+        CONV_INT.put(int[].class, new SeedConverterComposer<Integer,Long,int[]>(INT_TO_LONG, LONG_TO_INT_ARRAY));
+        CONV_INT.put(long[].class, new SeedConverterComposer<Integer,Long,long[]>(INT_TO_LONG, LONG_TO_LONG_ARRAY));
+
+        // Input seed type is "int[]".
+        // Key is the implementation's "native" seed type.
+        CONV_INT_ARRAY.put(Integer.class, INT_ARRAY_TO_INT);
+        CONV_INT_ARRAY.put(Long.class, new SeedConverterComposer<int[],Integer,Long>(INT_ARRAY_TO_INT, INT_TO_LONG));
+        CONV_INT_ARRAY.put(int[].class, new NoOpConverter<int[]>());
+        CONV_INT_ARRAY.put(long[].class, INT_ARRAY_TO_LONG_ARRAY);
+
+        // Input seed type is "long[]".
+        // Key is the implementation's "native" seed type.
+        CONV_LONG_ARRAY.put(Integer.class, new SeedConverterComposer<long[],Long,Integer>(LONG_ARRAY_TO_LONG, LONG_TO_INT));
+        CONV_LONG_ARRAY.put(Long.class, LONG_ARRAY_TO_LONG);
+        CONV_LONG_ARRAY.put(int[].class, LONG_ARRAY_TO_INT_ARRAY);
+        CONV_LONG_ARRAY.put(long[].class, new NoOpConverter<long[]>());
+    }
+
+    /**
+     * Class only contains static method.
+     */
+    private ProviderBuilder() {}
+
+    /**
+     * Creates a RNG instance.
+     *
+     * @param source RNG specification.
+     * @param seed Seed value.  It can be {@code null} (in which case a
+     * random value will be used).
+     * @param args Additional arguments to the implementation's constructor.
+     * @return a new RNG instance.
+     * @throws MathUnsupportedOperationException if the seed type is
+     * invalid.
+     */
+    public static UniformRandomProvider create(RandomSourceInternal source,
+                                               Object seed,
+                                               Object[] args) {
+        // Convert seed to native type.
+        final Object nativeSeed = createSeed(source, seed);
+
+        // Build a single array with all the arguments to be passed
+        // (in the right order) to the constructor.
+        final List<Object> all = new ArrayList<>();
+        all.add(nativeSeed);
+        if (args != null) {
+            all.addAll(Arrays.asList(args));
+        }
+
+        // Instantiate.
+        return create(createConstructor(source), all.toArray());
+    }
+
+    /**
+     * Creates a native seed from any of the supported seed types.
+     *
+     * @param source Source.
+     * @param seed Input seed.
+     * @return the native seed.
+     * @throw MathUnsupportedOperationException if the {@code seed} type
+     * is invalid.
+     */
+    private static Object createSeed(RandomSourceInternal source,
+                                     Object seed) {
+        Object nativeSeed = null;
+
+        if (seed == null) {
+            // Create a random seed of the appropriate native type.
+
+            if (source.getSeed().equals(Integer.class)) {
+                nativeSeed = SeedFactory.createInt();
+            } else if (source.getSeed().equals(Long.class)) {
+                nativeSeed = SeedFactory.createLong();
+            } else if (source.getSeed().equals(int[].class)) {
+                nativeSeed = SeedFactory.createIntArray(RANDOM_SEED_ARRAY_SIZE);
+            } else if (source.getSeed().equals(long[].class)) {
+                nativeSeed = SeedFactory.createLongArray(RANDOM_SEED_ARRAY_SIZE);
+            }
+        } else {
+            // Convert to native type.
+
+            if (seed instanceof Integer) {
+                nativeSeed = CONV_INT.get(source.getSeed()).convert((Integer) seed);
+            } else if (seed instanceof Long) {
+                nativeSeed = CONV_LONG.get(source.getSeed()).convert((Long) seed);
+            } else if (seed instanceof int[]) {
+                nativeSeed = CONV_INT_ARRAY.get(source.getSeed()).convert((int[]) seed);
+            } else if (seed instanceof long[]) {
+                nativeSeed = CONV_LONG_ARRAY.get(source.getSeed()).convert((long[]) seed);
+            }
+
+            if (nativeSeed == null) {
+                // Since the input seed was not null, getting here means that
+                // no suitable converter is present in the maps.
+                throw new MathUnsupportedOperationException();
+            }
+
+            if (!source.isNativeSeed(nativeSeed)) {
+                // Conversion setup is wrong.
+                throw new MathInternalError();
+            }
+        }
+
+        return nativeSeed;
+    }
+
+    /**
+     * Creates a constructor.
+     *
+     * @param source RNG specification.
+     * @return a RNG constructor.
+     */
+    private static Constructor<?> createConstructor(RandomSourceInternal source) {
+        try {
+            return source.getRng().getConstructor(source.getArgs());
+        } catch (NoSuchMethodException e) {
+            // Info in "RandomSourceInternal" is inconsistent with the
+            // constructor of the implementation.
+            throw new MathInternalError(e);
+        }
+    }
+
+    /**
+     * Creates a RNG.
+     *
+     * @param rng RNG specification.
+     * @param args Arguments to the implementation's constructor.
+     * @return a new RNG instance.
+     */
+    private static UniformRandomProvider create(Constructor<?> rng,
+                                                Object[] args) {
+        try {
+            return (UniformRandomProvider) rng.newInstance(args);
+        } catch (InvocationTargetException |
+                 InstantiationException |
+                 IllegalArgumentException |
+                 IllegalAccessException e) {
+            throw new MathInternalError(e);
+        }
+    }
+
+    /**
+     * Identifiers of the generators.
+     */
+    public enum RandomSourceInternal {
+        /** Source of randomness is {@link JDKRandom}. */
+        JDK(JDKRandom.class,
+            Long.class),
+        /** Source of randomness is {@link Well512a}. */
+        WELL_512_A(Well512a.class,
+                   int[].class),
+        /** Source of randomness is {@link Well1024a}. */
+        WELL_1024_A(Well1024a.class,
+                    int[].class),
+        /** Source of randomness is {@link Well19937a}. */
+        WELL_19937_A(Well19937a.class,
+                     int[].class),
+        /** Source of randomness is {@link Well19937c}. */
+        WELL_19937_C(Well19937c.class,
+                     int[].class),
+        /** Source of randomness is {@link Well44497a}. */
+        WELL_44497_A(Well44497a.class,
+                     int[].class),
+        /** Source of randomness is {@link Well44497b}. */
+        WELL_44497_B(Well44497b.class,
+                     int[].class),
+        /** Source of randomness is {@link MersenneTwister}. */
+        MT(MersenneTwister.class,
+           int[].class),
+        /** Source of randomness is {@link ISAACRandom}. */
+        ISAAC(ISAACRandom.class,
+              int[].class),
+        /** Source of randomness is {@link SplitMix64}. */
+        SPLIT_MIX_64(SplitMix64.class,
+                     Long.class),
+        /** Source of randomness is {@link XorShift1024Star}. */
+        XOR_SHIFT_1024_S(XorShift1024Star.class,
+                         long[].class),
+        /** Source of randomness is {@link TwoCmres}. */
+        TWO_CMRES(TwoCmres.class,
+                  Integer.class),
+        /**
+         * Source of randomness is {@link TwoCmres} with explicit selection
+         * of the two subcycle generators.
+         */
+        TWO_CMRES_SELECT(TwoCmres.class,
+                         Integer.class,
+                         Integer.TYPE,
+                         Integer.TYPE),
+        /** Source of randomness is {@link MersenneTwister64}. */
+        MT_64(MersenneTwister64.class,
+              long[].class);
+
+        /** Source type. */
+        private final Class<? extends UniformRandomProvider> rng;
+        /** Data needed to build the generator. */
+        private final Class<?>[] args;
+
+        /**
+         * @param rng Source type.
+         * @param args Data needed to create a generator instance.
+         * The first element must be the native seed type.
+         */
+        RandomSourceInternal(Class<? extends UniformRandomProvider> rng,
+                             Class<?> ... args) {
+            this.rng = rng;
+            this.args = Arrays.copyOf(args, args.length);
+        }
+
+        /**
+         * @return the source type.
+         */
+        public Class<?> getRng() {
+            return rng;
+        }
+
+        /**
+         * @return the seed type.
+         */
+        Class<?> getSeed() {
+            return args[0];
+        }
+
+        /**
+         * @return the data needed to build the generator.
+         */
+        Class<?>[] getArgs() {
+            return args;
+        }
+
+        /**
+         * Checks whether the type of given {@code seed} is the native type
+         * of the implementation.
+         *
+         * @param <SEED> Seed type.
+         *
+         * @param seed Seed value.
+         * @return {@code true} if the seed can be passed to the builder
+         * for this RNG type.
+         */
+        public <SEED> boolean isNativeSeed(SEED seed) {
+            return getSeed().equals(seed.getClass());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/6ddf4769/src/main/java/org/apache/commons/math4/rng/internal/StateSettable.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/rng/internal/StateSettable.java b/src/main/java/org/apache/commons/math4/rng/internal/StateSettable.java
new file mode 100644
index 0000000..6c7e7a5
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/rng/internal/StateSettable.java
@@ -0,0 +1,49 @@
+/*
+ * 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.rng.internal;
+
+import org.apache.commons.math4.rng.RandomSource;
+
+/**
+ * Indicates that the state of the instance can be saved and restored.
+ *
+ * @since 4.0
+ */
+public interface StateSettable {
+    /**
+     * Sets the instance's state.
+     *
+     * @param state State. The given argument must have been retrieved
+     * by a call to {@link #getState()}.
+     *
+     * @throws org.apache.commons.math4.exception.MathUnsupportedOperationException
+     * if not implemented.
+     */
+    void setState(RandomSource.State state);
+
+    /**
+     * Gets the instance's state.
+     *
+     * @return the current state. The given argument can then be passed
+     * to {@link #setState(RandomSource.State)} in order to recover the
+     * current state.
+     *
+     * @throws org.apache.commons.math4.exception.MathUnsupportedOperationException
+     * if not implemented.
+     */
+     RandomSource.State getState();
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/6ddf4769/src/main/java/org/apache/commons/math4/rng/internal/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/rng/internal/package-info.java b/src/main/java/org/apache/commons/math4/rng/internal/package-info.java
new file mode 100644
index 0000000..47ad828
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/rng/internal/package-info.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/**
+ * <h3>Base classes for the {@link org.apache.commons.math4.rng.UniformRandomProvider
+ * generation of uniformly distributed random numbers}.
+ * </h3>
+ *
+ * <p>
+ * <b>For internal use only:</b> Direct access to classes in this package
+ * and below, is discouraged, as they could be modified without notice.
+ * </p>
+ *
+ * <p><b>Notes for developers</b></p>
+ *
+ * <p>
+ * This package contains the common functionality.
+ * <br>
+ * Implementations that produce
+ * {@link org.apache.commons.math4.rng.internal.source32.RandomIntSource int}
+ * values are defined in the
+ * {@link org.apache.commons.math4.rng.internal.source32 source32} package.
+ * <br>
+ * Implementations that produce
+ * {@link org.apache.commons.math4.rng.internal.source64.RandomLongSource long}
+ * values are defined in the
+ * {@link org.apache.commons.math4.rng.internal.source64 source64} package.
+ * </p>
+ *
+ * <p>
+ * Each implementation must have an identifier in
+ * {@link org.apache.commons.math4.rng.internal.ProviderBuilder.RandomSourceInternal}
+ * which must be referred to from the {@link org.apache.commons.math4.rng.RandomSource public API}.
+ * </p>
+ */
+
+package org.apache.commons.math4.rng.internal;

http://git-wip-us.apache.org/repos/asf/commons-math/blob/6ddf4769/src/main/java/org/apache/commons/math4/rng/internal/source32/AbstractWell.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/rng/internal/source32/AbstractWell.java b/src/main/java/org/apache/commons/math4/rng/internal/source32/AbstractWell.java
new file mode 100644
index 0000000..c9737db
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/rng/internal/source32/AbstractWell.java
@@ -0,0 +1,208 @@
+/*
+ * 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.rng.internal.source32;
+
+import java.util.Arrays;
+import org.apache.commons.math4.exception.InsufficientDataException;
+import org.apache.commons.math4.rng.internal.util.NumberFactory;
+
+/**
+ * This abstract class implements the WELL class of pseudo-random number
+ * generator from Fran&ccedil;ois Panneton, Pierre L'Ecuyer and Makoto
+ * Matsumoto.
+ * <p>
+ * This generator is described in a paper by Fran&ccedil;ois Panneton,
+ * Pierre L'Ecuyer and Makoto Matsumoto
+ * <a href="http://www.iro.umontreal.ca/~lecuyer/myftp/papers/wellrng.pdf">
+ * Improved Long-Period Generators Based on Linear Recurrences Modulo 2</a>
+ * ACM Transactions on Mathematical Software, 32, 1 (2006).
+ * The errata for the paper are in
+ * <a href="http://www.iro.umontreal.ca/~lecuyer/myftp/papers/wellrng-errata.txt">wellrng-errata.txt</a>.
+ * </p>
+ *
+ * @see <a href="http://www.iro.umontreal.ca/~panneton/WELLRNG.html">WELL Random number generator</a>
+ *
+ * @since 4.0
+ */
+public abstract class AbstractWell extends IntProvider {
+    /** Current index in the bytes pool. */
+    protected int index;
+    /** Bytes pool. */
+    protected final int[] v;
+
+    /**
+     * Creates a new random number generator using an int array seed.
+     *
+     * @param k Number of bits in the pool (not necessarily a multiple of 32).
+     * @param seed Initial seed.
+     */
+    protected AbstractWell(final int k,
+                           final int[] seed) {
+        final int r = calculateBlockCount(k);
+        v = new int[r];
+        index = 0;
+
+        // Initialize the pool content.
+        setSeedInternal(seed);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected byte[] getStateInternal() {
+        final int[] s = Arrays.copyOf(v, v.length + 1);
+        s[v.length] = index;
+
+        return NumberFactory.makeByteArray(s);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void setStateInternal(byte[] s) {
+        if (s.length != (v.length + 1) * 4) {
+            throw new InsufficientDataException();
+        }
+
+        final int[] tmp = NumberFactory.makeIntArray(s);
+
+        System.arraycopy(tmp, 0, v, 0, v.length);
+        index = tmp[v.length];
+    }
+
+    /**
+     * Reinitialize the generator as if just built with the given int array seed.
+     *
+     * <p>The state of the generator is exactly the same as a new generator built
+     * with the same seed.</p>
+     *
+     * @param seed Seed. Cannot be null.
+     */
+    private void setSeedInternal(final int[] seed) {
+        System.arraycopy(seed, 0, v, 0, Math.min(seed.length, v.length));
+
+        if (seed.length < v.length) {
+            for (int i = seed.length; i < v.length; ++i) {
+                final long current = v[i - seed.length];
+                v[i] = (int) ((1812433253L * (current ^ (current >> 30)) + i) & 0xffffffffL);
+            }
+        }
+
+        index = 0;
+    }
+
+    /**
+     * Calculate the number of 32-bits blocks.
+     *
+     * @param k Number of bits in the pool (not necessarily a multiple of 32).
+     * @return the number of 32-bits blocks.
+     */
+    private static int calculateBlockCount(final int k) {
+        // the bits pool contains k bits, k = r w - p where r is the number
+        // of w bits blocks, w is the block size (always 32 in the original paper)
+        // and p is the number of unused bits in the last block
+        final int w = 32;
+        final int r = (k + w - 1) / w;
+        return r;
+    }
+
+    /**
+     * Inner class used to store the indirection index table which is fixed for a given
+     * type of WELL class of pseudo-random number generator.
+     */
+    protected static final class IndexTable {
+        /** Index indirection table giving for each index its predecessor taking table size into account. */
+        private final int[] iRm1;
+        /** Index indirection table giving for each index its second predecessor taking table size into account. */
+        private final int[] iRm2;
+        /** Index indirection table giving for each index the value index + m1 taking table size into account. */
+        private final int[] i1;
+        /** Index indirection table giving for each index the value index + m2 taking table size into account. */
+        private final int[] i2;
+        /** Index indirection table giving for each index the value index + m3 taking table size into account. */
+        private final int[] i3;
+
+        /** Creates a new pre-calculated indirection index table.
+         * @param k number of bits in the pool (not necessarily a multiple of 32)
+         * @param m1 first parameter of the algorithm
+         * @param m2 second parameter of the algorithm
+         * @param m3 third parameter of the algorithm
+         */
+        public IndexTable(final int k, final int m1, final int m2, final int m3) {
+
+            final int r = calculateBlockCount(k);
+
+            // precompute indirection index tables. These tables are used for optimizing access
+            // they allow saving computations like "(j + r - 2) % r" with costly modulo operations
+            iRm1 = new int[r];
+            iRm2 = new int[r];
+            i1 = new int[r];
+            i2 = new int[r];
+            i3 = new int[r];
+            for (int j = 0; j < r; ++j) {
+                iRm1[j] = (j + r - 1) % r;
+                iRm2[j] = (j + r - 2) % r;
+                i1[j] = (j + m1) % r;
+                i2[j] = (j + m2) % r;
+                i3[j] = (j + m3) % r;
+            }
+        }
+
+        /**
+         * Returns the predecessor of the given index modulo the table size.
+         * @param index the index to look at
+         * @return (index - 1) % table size
+         */
+        public int getIndexPred(final int index) {
+            return iRm1[index];
+        }
+
+        /**
+         * Returns the second predecessor of the given index modulo the table size.
+         * @param index the index to look at
+         * @return (index - 2) % table size
+         */
+        public int getIndexPred2(final int index) {
+            return iRm2[index];
+        }
+
+        /**
+         * Returns index + M1 modulo the table size.
+         * @param index the index to look at
+         * @return (index + M1) % table size
+         */
+        public int getIndexM1(final int index) {
+            return i1[index];
+        }
+
+        /**
+         * Returns index + M2 modulo the table size.
+         * @param index the index to look at
+         * @return (index + M2) % table size
+         */
+        public int getIndexM2(final int index) {
+            return i2[index];
+        }
+
+        /**
+         * Returns index + M3 modulo the table size.
+         * @param index the index to look at
+         * @return (index + M3) % table size
+         */
+        public int getIndexM3(final int index) {
+            return i3[index];
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/6ddf4769/src/main/java/org/apache/commons/math4/rng/internal/source32/ISAACRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/rng/internal/source32/ISAACRandom.java b/src/main/java/org/apache/commons/math4/rng/internal/source32/ISAACRandom.java
new file mode 100644
index 0000000..c7dd73a
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/rng/internal/source32/ISAACRandom.java
@@ -0,0 +1,270 @@
+/*
+ * 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.rng.internal.source32;
+
+import java.util.Arrays;
+import org.apache.commons.math4.exception.InsufficientDataException;
+import org.apache.commons.math4.rng.internal.util.NumberFactory;
+
+/**
+ * A fast cryptographic pseudo-random number generator.
+ * <p>
+ * ISAAC (Indirection, Shift, Accumulate, Add, and Count) generates 32-bit
+ * random numbers.
+ * ISAAC has been designed to be cryptographically secure and is inspired
+ * by RC4.
+ * Cycles are guaranteed to be at least 2<sup>40</sup> values long, and they
+ * are 2<sup>8295</sup> values long on average.
+ * The results are uniformly distributed, unbiased, and unpredictable unless
+ * you know the seed.
+ * <p>
+ * This code is based (with minor changes and improvements) on the original
+ * implementation of the algorithm by Bob Jenkins.
+ *
+ * @see <a href="http://burtleburtle.net/bob/rand/isaacafa.html">
+ * ISAAC: a fast cryptographic pseudo-random number generator</a>
+ *
+ * @since 4.0
+ */
+public class ISAACRandom extends IntProvider {
+    /** Log of size of rsl[] and mem[] */
+    private static final int SIZE_L = 8;
+    /** Size of rsl[] and mem[] */
+    private static final int SIZE = 1 << SIZE_L;
+    /** Half-size of rsl[] and mem[] */
+    private static final int H_SIZE = SIZE >> 1;
+    /** For pseudo-random lookup */
+    private static final int MASK = SIZE - 1 << 2;
+    /** The golden ratio */
+    private static final int GLD_RATIO = 0x9e3779b9;
+    /** The results given to the user */
+    private final int[] rsl = new int[SIZE];
+    /** The internal state */
+    private final int[] mem = new int[SIZE];
+    /** Count through the results in rsl[] */
+    private int count;
+    /** Accumulator */
+    private int isaacA;
+    /** The last result */
+    private int isaacB;
+    /** Counter, guarantees cycle is at least 2^40 */
+    private int isaacC;
+    /** Service variable. */
+    private final int[] arr = new int[8];
+    /** Service variable. */
+    private int isaacX;
+    /** Service variable. */
+    private int isaacI;
+    /** Service variable. */
+    private int isaacJ;
+
+    /**
+     * Creates a new ISAAC random number generator.
+     *
+     * @param seed Initial seed
+     */
+    public ISAACRandom(int[] seed) {
+        setSeedInternal(seed);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected byte[] getStateInternal() {
+        final int[] sRsl = Arrays.copyOf(rsl, SIZE);
+        final int[] sMem = Arrays.copyOf(mem, SIZE);
+        final int[] sRem = Arrays.copyOf(new int[] { count, isaacA, isaacB, isaacC }, 4);
+
+        final int[] s = new int[2 * SIZE + sRem.length];
+        System.arraycopy(sRsl, 0, s, 0, SIZE);
+        System.arraycopy(sMem, 0, s, SIZE, SIZE);
+        System.arraycopy(sRem, 0, s, 2 * SIZE, sRem.length);
+
+        return NumberFactory.makeByteArray(s);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void setStateInternal(byte[] s) {
+        if (s.length != (2 * SIZE + 4) * 4) {
+            throw new InsufficientDataException();
+        }
+
+        final int[] tmp = NumberFactory.makeIntArray(s);
+
+        System.arraycopy(tmp, 0, rsl, 0, SIZE);
+        System.arraycopy(tmp, SIZE, mem, 0, SIZE);
+        final int offset = 2 * SIZE;
+        count = tmp[offset];
+        isaacA = tmp[offset + 1];
+        isaacB = tmp[offset + 2];
+        isaacC = tmp[offset + 3];
+    }
+
+    /**
+     * Reseeds the RNG.
+     *
+     * @param seed Seed. Cannot be null.
+     */
+    private void setSeedInternal(int[] seed) {
+        final int seedLen = seed.length;
+        final int rslLen = rsl.length;
+        System.arraycopy(seed, 0, rsl, 0, Math.min(seedLen, rslLen));
+        if (seedLen < rslLen) {
+            for (int j = seedLen; j < rslLen; j++) {
+                long k = rsl[j - seedLen];
+                rsl[j] = (int) (0x6c078965L * (k ^ k >> 30) + j & 0xffffffffL);
+            }
+        }
+        initState();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int next() {
+        if (count < 0) {
+            isaac();
+            count = SIZE - 1;
+        }
+        return rsl[count--];
+    }
+
+    /** Generate 256 results */
+    private void isaac() {
+        isaacI = 0;
+        isaacJ = H_SIZE;
+        isaacB += ++isaacC;
+        while (isaacI < H_SIZE) {
+            isaac2();
+        }
+        isaacJ = 0;
+        while (isaacJ < H_SIZE) {
+            isaac2();
+        }
+    }
+
+    /** Intermediate internal loop. */
+    private void isaac2() {
+        isaacX = mem[isaacI];
+        isaacA ^= isaacA << 13;
+        isaacA += mem[isaacJ++];
+        isaac3();
+        isaacX = mem[isaacI];
+        isaacA ^= isaacA >>> 6;
+        isaacA += mem[isaacJ++];
+        isaac3();
+        isaacX = mem[isaacI];
+        isaacA ^= isaacA << 2;
+        isaacA += mem[isaacJ++];
+        isaac3();
+        isaacX = mem[isaacI];
+        isaacA ^= isaacA >>> 16;
+        isaacA += mem[isaacJ++];
+        isaac3();
+    }
+
+    /** Lowest level internal loop. */
+    private void isaac3() {
+        mem[isaacI] = mem[(isaacX & MASK) >> 2] + isaacA + isaacB;
+        isaacB = mem[(mem[isaacI] >> SIZE_L & MASK) >> 2] + isaacX;
+        rsl[isaacI++] = isaacB;
+    }
+
+    /** Initialize, or reinitialize, this instance of rand. */
+    private void initState() {
+        isaacA = 0;
+        isaacB = 0;
+        isaacC = 0;
+        for (int j = 0; j < arr.length; j++) {
+            arr[j] = GLD_RATIO;
+        }
+        for (int j = 0; j < 4; j++) {
+            shuffle();
+        }
+        // fill in mem[] with messy stuff
+        for (int j = 0; j < SIZE; j += 8) {
+            arr[0] += rsl[j];
+            arr[1] += rsl[j + 1];
+            arr[2] += rsl[j + 2];
+            arr[3] += rsl[j + 3];
+            arr[4] += rsl[j + 4];
+            arr[5] += rsl[j + 5];
+            arr[6] += rsl[j + 6];
+            arr[7] += rsl[j + 7];
+            shuffle();
+            setState(j);
+        }
+        // second pass makes all of seed affect all of mem
+        for (int j = 0; j < SIZE; j += 8) {
+            arr[0] += mem[j];
+            arr[1] += mem[j + 1];
+            arr[2] += mem[j + 2];
+            arr[3] += mem[j + 3];
+            arr[4] += mem[j + 4];
+            arr[5] += mem[j + 5];
+            arr[6] += mem[j + 6];
+            arr[7] += mem[j + 7];
+            shuffle();
+            setState(j);
+        }
+        isaac();
+        count = SIZE - 1;
+    }
+
+    /** Shuffle array. */
+    private void shuffle() {
+        arr[0] ^= arr[1] << 11;
+        arr[3] += arr[0];
+        arr[1] += arr[2];
+        arr[1] ^= arr[2] >>> 2;
+        arr[4] += arr[1];
+        arr[2] += arr[3];
+        arr[2] ^= arr[3] << 8;
+        arr[5] += arr[2];
+        arr[3] += arr[4];
+        arr[3] ^= arr[4] >>> 16;
+        arr[6] += arr[3];
+        arr[4] += arr[5];
+        arr[4] ^= arr[5] << 10;
+        arr[7] += arr[4];
+        arr[5] += arr[6];
+        arr[5] ^= arr[6] >>> 4;
+        arr[0] += arr[5];
+        arr[6] += arr[7];
+        arr[6] ^= arr[7] << 8;
+        arr[1] += arr[6];
+        arr[7] += arr[0];
+        arr[7] ^= arr[0] >>> 9;
+        arr[2] += arr[7];
+        arr[0] += arr[1];
+    }
+
+    /** Set the state by copying the internal arrays.
+     *
+     * @param start First index into {@link #mem} array.
+     */
+    private void setState(int start) {
+        mem[start] = arr[0];
+        mem[start + 1] = arr[1];
+        mem[start + 2] = arr[2];
+        mem[start + 3] = arr[3];
+        mem[start + 4] = arr[4];
+        mem[start + 5] = arr[5];
+        mem[start + 6] = arr[6];
+        mem[start + 7] = arr[7];
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/6ddf4769/src/main/java/org/apache/commons/math4/rng/internal/source32/IntProvider.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/rng/internal/source32/IntProvider.java b/src/main/java/org/apache/commons/math4/rng/internal/source32/IntProvider.java
new file mode 100644
index 0000000..bae33fc
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/rng/internal/source32/IntProvider.java
@@ -0,0 +1,137 @@
+/*
+ * 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.rng.internal.source32;
+
+import org.apache.commons.math4.exception.OutOfRangeException;
+import org.apache.commons.math4.rng.internal.util.NumberFactory;
+import org.apache.commons.math4.rng.internal.BaseProvider;
+
+/**
+ * Base class for all implementations that provide an {@code int}-based
+ * source randomness.
+ */
+public abstract class IntProvider
+    extends BaseProvider
+    implements RandomIntSource {
+
+    /** {@inheritDoc} */
+    @Override
+    public abstract int next();
+
+    /** {@inheritDoc} */
+    @Override
+    public int nextInt() {
+        return next();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean nextBoolean() {
+        return NumberFactory.makeBoolean(nextInt());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public double nextDouble() {
+        return NumberFactory.makeDouble(nextInt(), nextInt());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public float nextFloat() {
+        return NumberFactory.makeFloat(nextInt());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public long nextLong() {
+        return NumberFactory.makeLong(nextInt(), nextInt());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void nextBytes(byte[] bytes) {
+        nextBytesFill(this, bytes, 0, bytes.length);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void nextBytes(byte[] bytes,
+                          int start,
+                          int len) {
+        if (start < 0 ||
+            start >= bytes.length) {
+            throw new OutOfRangeException(start, 0, bytes.length);
+        }
+        if (len < 0 ||
+            len > bytes.length - start) {
+            throw new OutOfRangeException(len, 0, bytes.length - start);
+        }
+
+        nextBytesFill(this, bytes, start, len);
+    }
+
+    /**
+     * Generates random bytes and places them into a user-supplied array.
+     *
+     * <p>
+     * The array is filled with bytes extracted from random {@code int} values.
+     * This implies that the number of random bytes generated may be larger than
+     * the length of the byte array.
+     * </p>
+     *
+     * @param source Source of randomness.
+     * @param bytes Array in which to put the generated bytes. Cannot be null.
+     * @param start Index at which to start inserting the generated bytes.
+     * @param len Number of bytes to insert.
+     */
+    static void nextBytesFill(RandomIntSource source,
+                              byte[] bytes,
+                              int start,
+                              int len) {
+        int index = start; // Index of first insertion.
+
+        // Index of first insertion plus multiple of 4 part of length
+        // (i.e. length with 2 least significant bits unset).
+        final int indexLoopLimit = index + (len & 0x7ffffffc);
+
+        // Start filling in the byte array, 4 bytes at a time.
+        while (index < indexLoopLimit) {
+            final int random = source.next();
+            bytes[index++] = (byte) random;
+            bytes[index++] = (byte) (random >>> 8);
+            bytes[index++] = (byte) (random >>> 16);
+            bytes[index++] = (byte) (random >>> 24);
+        }
+
+        final int indexLimit = start + len; // Index of last insertion + 1.
+
+        // Fill in the remaining bytes.
+        if (index < indexLimit) {
+            int random = source.next();
+            while (true) {
+                bytes[index++] = (byte) random;
+                if (index < indexLimit) {
+                    random >>>= 8;
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/6ddf4769/src/main/java/org/apache/commons/math4/rng/internal/source32/JDKRandom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/rng/internal/source32/JDKRandom.java b/src/main/java/org/apache/commons/math4/rng/internal/source32/JDKRandom.java
new file mode 100644
index 0000000..e393c12
--- /dev/null
+++ b/src/main/java/org/apache/commons/math4/rng/internal/source32/JDKRandom.java
@@ -0,0 +1,95 @@
+/*
+ * 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.rng.internal.source32;
+
+import java.util.Random;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+
+/**
+ * A provider that uses the {@link Random#nextInt()} method of the JDK's
+ * {@code Random} class as the source of randomness.
+ *
+ * <p>
+ * <b>Caveat:</b> All the other calls will be redirected to the methods
+ * implemented within this library.
+ * </p>
+ *
+ * <p>
+ * The state of this source of randomness is saved and restored through
+ * the serialization of the {@link Random} instance.
+ * </p>
+ *
+ * @since 4.0
+ */
+public class JDKRandom extends IntProvider {
+    /** Delegate.  Cannot be "final" (to allow serialization). */
+    private Random delegate;
+
+    /**
+     * Creates an instance with the given seed.
+     *
+     * @param seed Initial seed.
+     */
+    public JDKRandom(Long seed) {
+        delegate = new Random(seed);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see Random#nextInt()
+     */
+    @Override
+    public int next() {
+        return delegate.nextInt();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected byte[] getStateInternal() {
+        try {
+            final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            final ObjectOutputStream oos = new ObjectOutputStream(bos);
+
+            // Serialize the "delegate".
+            oos.writeObject(delegate);
+
+            return bos.toByteArray();
+        } catch (IOException e) {
+            // Workaround checked exception.
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void setStateInternal(byte[] s) {
+        try {
+            final ByteArrayInputStream bis = new ByteArrayInputStream(s);
+            final ObjectInputStream ois = new ObjectInputStream(bis);
+
+            delegate = (Random) ois.readObject();
+        } catch (ClassNotFoundException|IOException e) {
+            // Workaround checked exception.
+            throw new RuntimeException(e);
+        }
+    }
+}