You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2019/06/06 08:00:14 UTC

[commons-rng] 01/11: RNG-75: Update ProviderBuilder factory methods.

This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-rng.git

commit 827bc9f1e36a8d06b0face13c9ef16f3db50567d
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Wed May 22 20:31:05 2019 +0100

    RNG-75: Update ProviderBuilder factory methods.
    
    Allow the RandomSourceInternal to create the seed. This can control the
    size of array seeds and provisions for future changes where the seed has
    requirements other than just random bits.
---
 .../commons/rng/simple/internal/Long2IntArray.java |  37 +-
 .../rng/simple/internal/Long2LongArray.java        |  20 +-
 .../rng/simple/internal/ProviderBuilder.java       | 651 +++++++++++++++------
 ...Long2IntArray.java => Seed2ArrayConverter.java} |  32 +-
 4 files changed, 544 insertions(+), 196 deletions(-)

diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2IntArray.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2IntArray.java
index b1b66f2..d98a77c 100644
--- a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2IntArray.java
+++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2IntArray.java
@@ -17,6 +17,7 @@
 package org.apache.commons.rng.simple.internal;
 
 import org.apache.commons.rng.core.source64.SplitMix64;
+import org.apache.commons.rng.core.util.NumberFactory;
 
 /**
  * Uses a {@code long} value to seed a {@link SplitMix64} RNG and
@@ -25,7 +26,7 @@ import org.apache.commons.rng.core.source64.SplitMix64;
  *
  * @since 1.0
  */
-public class Long2IntArray implements SeedConverter<Long, int[]> {
+public class Long2IntArray implements Seed2ArrayConverter<Long, int[]> {
     /** Size of the output array. */
     private final int size;
 
@@ -39,6 +40,38 @@ public class Long2IntArray implements SeedConverter<Long, int[]> {
     /** {@inheritDoc} */
     @Override
     public int[] convert(Long seed) {
-        return SeedFactory.createIntArray(size, new SplitMix64(seed));
+        return convertSeed(seed, size);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int[] convert(Long seed, int outputSize) {
+        return convertSeed(seed, outputSize);
+    }
+
+    /**
+     * Convert the seed.
+     *
+     * @param seed Input seed.
+     * @param size Output array size.
+     * @return the converted seed.
+     */
+    private static int[] convertSeed(Long seed, int size) {
+        final int[] out = new int[size];
+        final SplitMix64 rng = new SplitMix64(seed);
+        int i = 0;
+        // Handle an odd size
+        if ((size & 1) == 1) {
+            out[i++] = NumberFactory.extractHi(rng.nextLong());
+        }
+        // Fill the remaining pairs
+        while (i < size) {
+            final long v = rng.nextLong();
+            out[i] = NumberFactory.extractHi(v);
+            out[i + 1] = NumberFactory.extractLo(v);
+            i += 2;
+        }
+
+        return out;
     }
 }
diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2LongArray.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2LongArray.java
index 9d22383..199f8cd 100644
--- a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2LongArray.java
+++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2LongArray.java
@@ -25,7 +25,7 @@ import org.apache.commons.rng.core.source64.SplitMix64;
  *
  * @since 1.0
  */
-public class Long2LongArray implements SeedConverter<Long, long[]> {
+public class Long2LongArray implements Seed2ArrayConverter<Long, long[]> {
     /** Size of the output array. */
     private final int size;
 
@@ -36,9 +36,27 @@ public class Long2LongArray implements SeedConverter<Long, long[]> {
         this.size = size;
     }
 
+
     /** {@inheritDoc} */
     @Override
     public long[] convert(Long seed) {
+        return convertSeed(seed, size);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public long[] convert(Long seed, int outputSize) {
+        return convertSeed(seed, outputSize);
+    }
+
+    /**
+     * Convert the seed.
+     *
+     * @param seed Input seed.
+     * @param size Output array size.
+     * @return the converted seed.
+     */
+    private static long[] convertSeed(Long seed, int size) {
         final long[] out = new long[size];
         final SplitMix64 rng = new SplitMix64(seed);
         for (int i = 0; i < size; i++) {
diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java
index 87b7f27..98c1c85 100644
--- a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java
+++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java
@@ -17,10 +17,6 @@
 package org.apache.commons.rng.simple.internal;
 
 import java.util.Arrays;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 
@@ -63,86 +59,6 @@ import org.apache.commons.rng.core.source64.XoShiRo512StarStar;
 public final class ProviderBuilder {
     /** Error message. */
     private static final String INTERNAL_ERROR_MSG = "Internal error: Please file a bug report";
-    /** 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();
-    /** Seed converter. */
-    private static final ByteArray2IntArray BYTE_ARRAY_TO_INT_ARRAY = new ByteArray2IntArray();
-    /** Seed converter. */
-    private static final ByteArray2LongArray BYTE_ARRAY_TO_LONG_ARRAY = new ByteArray2LongArray();
-    /** Map to convert "Integer" seeds. */
-    private static final Map<Class<?>, SeedConverter<Integer, ?>> CONV_INT =
-        new ConcurrentHashMap<Class<?>, SeedConverter<Integer, ?>>();
-    /** Map to convert "int[]" seeds. */
-    private static final Map<Class<?>, SeedConverter<int[], ?>> CONV_INT_ARRAY =
-        new ConcurrentHashMap<Class<?>, SeedConverter<int[], ?>>();
-    /** Map to convert "Long" seeds. */
-    private static final Map<Class<?>, SeedConverter<Long, ?>> CONV_LONG =
-        new ConcurrentHashMap<Class<?>, SeedConverter<Long, ?>>();
-    /** Map to convert "long[]" seeds. */
-    private static final Map<Class<?>, SeedConverter<long[], ?>> CONV_LONG_ARRAY =
-        new ConcurrentHashMap<Class<?>, SeedConverter<long[], ?>>();
-    /** Map to convert "byte[]" seeds. */
-    private static final Map<Class<?>, SeedConverter<byte[], ?>> CONV_BYTE_ARRAY =
-        new ConcurrentHashMap<Class<?>, SeedConverter<byte[], ?>>();
-
-    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[]>());
-
-        // Input seed type is "byte[]".
-        // Key is the implementation's "native" seed type.
-        CONV_BYTE_ARRAY.put(Integer.class, new SeedConverterComposer<byte[], int[], Integer>(
-                                               BYTE_ARRAY_TO_INT_ARRAY, INT_ARRAY_TO_INT));
-        CONV_BYTE_ARRAY.put(Long.class, new SeedConverterComposer<byte[], long[], Long>(
-                                            BYTE_ARRAY_TO_LONG_ARRAY, LONG_ARRAY_TO_LONG));
-        CONV_BYTE_ARRAY.put(int[].class, BYTE_ARRAY_TO_INT_ARRAY);
-        CONV_BYTE_ARRAY.put(long[].class, BYTE_ARRAY_TO_LONG_ARRAY);
-    }
 
     /**
      * Class only contains static method.
@@ -153,120 +69,294 @@ public final class ProviderBuilder {
      * Creates a RNG instance.
      *
      * @param source RNG specification.
+     * @return a new RNG instance.
+     * @throws IllegalStateException if data is missing to initialize the
+     * generator implemented by the given {@code source}.
+     */
+    public static RestorableUniformRandomProvider create(RandomSourceInternal source) {
+        // Delegate to the random source allowing generator specific implementations.
+        return source.create();
+    }
+
+    /**
+     * 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 UnsupportedOperationException if the seed type is invalid.
+     * @throws IllegalStateException if data is missing to initialize the
+     * generator implemented by the given {@code source}.
      */
     public static RestorableUniformRandomProvider 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<Object>();
-        all.add(nativeSeed);
+        // Delegate to the random source allowing generator specific implementations.
+        // This method checks arguments for null and calls the appropriate internal method.
         if (args != null) {
-            all.addAll(Arrays.asList(args));
+            return source.create(seed, args);
         }
-
-        // Instantiate.
-        return create(createConstructor(source), all.toArray());
+        return seed == null ?
+                source.create() :
+                source.create(seed);
     }
 
     /**
-     * Creates a native seed from any of the supported seed types.
+     * The native seed type. Contains values for all native seed types and methods
+     * to convert supported seed types to the native seed type.
+     *
+     * <p>Valid native seed types are:</p>
+     * <ul>
+     *  <li>{@code Integer}</li>
+     *  <li>{@code Long}</li>
+     *  <li>{@code int[]}</li>
+     *  <li>{@code long[]}</li>
+     * </ul>
      *
-     * @param source Source.
-     * @param seed Input seed.
-     * @return the native seed.
-     * @throw UnsupportedOperationException if the {@code seed} type is invalid.
+     * <p>Valid types for seed conversion are:</p>
+     * <ul>
+     *  <li>{@code Integer} (or {@code int})</li>
+     *  <li>{@code Long} (or {@code long})</li>
+     *  <li>{@code int[]}</li>
+     *  <li>{@code long[]}</li>
+     *  <li>{@code byte[]}</li>
+     * </ul>
      */
-    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 {
-                // Source's native type is not handled.
-                throw new IllegalStateException(INTERNAL_ERROR_MSG);
+    private enum NativeSeedType {
+        /** The seed type is {@code Integer}. */
+        INT {
+            @Override
+            public Object createSeed(int size) {
+                return SeedFactory.createInt();
+            }
+            @Override
+            protected Integer convert(Integer seed, int size) {
+                return seed;
+            }
+            @Override
+            protected Integer convert(Long seed, int size) {
+                return LONG_TO_INT.convert(seed);
+            }
+            @Override
+            protected Integer convert(int[] seed, int size) {
+                return INT_ARRAY_TO_INT.convert(seed);
+            }
+            @Override
+            protected Integer convert(long[] seed, int size) {
+                return LONG_TO_INT.convert(LONG_ARRAY_TO_LONG.convert(seed));
+            }
+            @Override
+            protected Integer convert(byte[] seed, int size) {
+                return INT_ARRAY_TO_INT.convert(BYTE_ARRAY_TO_INT_ARRAY.convert(seed));
+            }
+        },
+        /** The seed type is {@code Long}. */
+        LONG {
+            @Override
+            public Object createSeed(int size) {
+                return SeedFactory.createLong();
             }
-        } else {
+            @Override
+            protected Long convert(Integer seed, int size) {
+                return INT_TO_LONG.convert(seed);
+            }
+            @Override
+            protected Long convert(Long seed, int size) {
+                return seed;
+            }
+            @Override
+            protected Long convert(int[] seed, int size) {
+                return INT_TO_LONG.convert(INT_ARRAY_TO_INT.convert(seed));
+            }
+            @Override
+            protected Long convert(long[] seed, int size) {
+                return LONG_ARRAY_TO_LONG.convert(seed);
+            }
+            @Override
+            protected Long convert(byte[] seed, int size) {
+                return LONG_ARRAY_TO_LONG.convert(BYTE_ARRAY_TO_LONG_ARRAY.convert(seed));
+            }
+        },
+        /** The seed type is {@code int[]}. */
+        INT_ARRAY {
+            @Override
+            public Object createSeed(int size) {
+                return SeedFactory.createIntArray(size);
+            }
+            @Override
+            protected int[] convert(Integer seed, int size) {
+                return LONG_TO_INT_ARRAY.convert(INT_TO_LONG.convert(seed), size);
+            }
+            @Override
+            protected int[] convert(Long seed, int size) {
+                return LONG_TO_INT_ARRAY.convert(seed, size);
+            }
+            @Override
+            protected int[] convert(int[] seed, int size) {
+                return seed;
+            }
+            @Override
+            protected int[] convert(long[] seed, int size) {
+                return LONG_ARRAY_TO_INT_ARRAY.convert(seed);
+            }
+            @Override
+            protected int[] convert(byte[] seed, int size) {
+                return BYTE_ARRAY_TO_INT_ARRAY.convert(seed);
+            }
+        },
+        /** The seed type is {@code long[]}. */
+        LONG_ARRAY {
+            @Override
+            public Object createSeed(int size) {
+                return SeedFactory.createLongArray(size);
+            }
+            @Override
+            protected long[] convert(Integer seed, int size) {
+                return LONG_TO_LONG_ARRAY.convert(INT_TO_LONG.convert(seed), size);
+            }
+            @Override
+            protected long[] convert(Long seed, int size) {
+                return LONG_TO_LONG_ARRAY.convert(seed, size);
+            }
+            @Override
+            protected long[] convert(int[] seed, int size) {
+                return INT_ARRAY_TO_LONG_ARRAY.convert(seed);
+            }
+            @Override
+            protected long[] convert(long[] seed, int size) {
+                return seed;
+            }
+            @Override
+            protected long[] convert(byte[] seed, int size) {
+                return BYTE_ARRAY_TO_LONG_ARRAY.convert(seed);
+            }
+        };
+
+        /** Convert {@code Long} to {@code Integer}. */
+        private static final Long2Int LONG_TO_INT = new Long2Int();
+        /** Convert {@code Integer} to {@code Long}. */
+        private static final Int2Long INT_TO_LONG = new Int2Long();
+        /** Convert {@code Long} to {@code int[]}. */
+        private static final Long2IntArray LONG_TO_INT_ARRAY = new Long2IntArray(0);
+        /** Convert {@code Long} to {@code long[]}. */
+        private static final Long2LongArray LONG_TO_LONG_ARRAY = new Long2LongArray(0);
+        /** Convert {@code long[]} to {@code Long}. */
+        private static final LongArray2Long LONG_ARRAY_TO_LONG = new LongArray2Long();
+        /** Convert {@code int[]} to {@code Integer}. */
+        private static final IntArray2Int INT_ARRAY_TO_INT = new IntArray2Int();
+        /** Convert {@code long[]} to {@code int[]}. */
+        private static final LongArray2IntArray LONG_ARRAY_TO_INT_ARRAY = new LongArray2IntArray();
+        /** Convert {@code Long} to {@code long[]}. */
+        private static final IntArray2LongArray INT_ARRAY_TO_LONG_ARRAY = new IntArray2LongArray();
+        /** Convert {@code byte[]} to {@code int[]}. */
+        private static final ByteArray2IntArray BYTE_ARRAY_TO_INT_ARRAY = new ByteArray2IntArray();
+        /** Convert {@code byte[]} to {@code long[]}. */
+        private static final ByteArray2LongArray BYTE_ARRAY_TO_LONG_ARRAY = new ByteArray2LongArray();
+
+        /**
+         * Creates the seed. The output seed type is determined by the native seed type. If the
+         * output is an array the required size of the array can be specified.
+         *
+         * @param size The size of the seed (array types only).
+         * @return the seed
+         */
+        public abstract Object createSeed(int size);
+
+        /**
+         * Converts the input seed from any of the supported seed types to the native seed type.
+         * If the output is an array the required size of the array can be specified.
+         *
+         * @param seed Input seed.
+         * @param size The size of the output seed (array types only).
+         * @return the native seed.
+         * @throw UnsupportedOperationException if the {@code seed} type is invalid.
+         */
+        public Object convertSeed(Object seed,
+                                  int size) {
             // Convert to native type.
+            // Each method must be overridden by specific implementations.
 
             if (seed instanceof Integer) {
-                nativeSeed = CONV_INT.get(source.getSeed()).convert((Integer) seed);
+                return convert((Integer) seed, size);
             } else if (seed instanceof Long) {
-                nativeSeed = CONV_LONG.get(source.getSeed()).convert((Long) seed);
+                return convert((Long) seed, size);
             } else if (seed instanceof int[]) {
-                nativeSeed = CONV_INT_ARRAY.get(source.getSeed()).convert((int[]) seed);
+                return convert((int[]) seed, size);
             } else if (seed instanceof long[]) {
-                nativeSeed = CONV_LONG_ARRAY.get(source.getSeed()).convert((long[]) seed);
+                return convert((long[]) seed, size);
             } else if (seed instanceof byte[]) {
-                nativeSeed = CONV_BYTE_ARRAY.get(source.getSeed()).convert((byte[]) 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 UnsupportedOperationException("Unrecognized seed type");
+                return convert((byte[]) seed, size);
             }
 
-            if (!source.isNativeSeed(nativeSeed)) {
-                // Conversion setup is wrong.
-                throw new IllegalStateException(INTERNAL_ERROR_MSG);
-            }
+            throw new UnsupportedOperationException("Unrecognized seed type");
         }
 
-        return nativeSeed;
-    }
+        /**
+         * Convert the input {@code Integer} seed to the native seed type.
+         *
+         * @param seed Input seed.
+         * @param size The size of the output seed (array types only).
+         * @return the native seed.
+         */
+        protected abstract Object convert(Integer seed, int size);
 
-    /**
-     * 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 IllegalStateException(INTERNAL_ERROR_MSG, e);
-        }
-    }
+        /**
+         * Convert the input {@code Long} seed to the native seed type.
+         *
+         * @param seed Input seed.
+         * @param size The size of the output seed (array types only).
+         * @return the native seed.
+         */
+        protected abstract Object convert(Long seed, int size);
 
-    /**
-     * Creates a RNG.
-     *
-     * @param rng RNG specification.
-     * @param args Arguments to the implementation's constructor.
-     * @return a new RNG instance.
-     */
-    private static RestorableUniformRandomProvider create(Constructor<?> rng,
-                                                          Object[] args) {
-        try {
-            return (RestorableUniformRandomProvider) rng.newInstance(args);
-        } catch (InvocationTargetException e) {
-            throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
-        } catch (InstantiationException e) {
-            throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
-        } catch (IllegalAccessException e) {
-            throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
+        /**
+         * Convert the input {@code int[]} seed to the native seed type.
+         *
+         * @param seed Input seed.
+         * @param size The size of the output seed (array types only).
+         * @return the native seed.
+         */
+        protected abstract Object convert(int[] seed, int size);
+
+        /**
+         * Convert the input {@code long[]} seed to the native seed type.
+         *
+         * @param seed Input seed.
+         * @param size The size of the output seed (array types only).
+         * @return the native seed.
+         */
+        protected abstract Object convert(long[] seed, int size);
+
+        /**
+         * Convert the input {@code byte[]} seed to the native seed type.
+         *
+         * @param seed Input seed.
+         * @param size The size of the output seed (array types only).
+         * @return the native seed.
+         */
+        protected abstract Object convert(byte[] seed, int size);
+
+        /**
+         * Creates the native seed type.
+         *
+         * @param type Class of the native seed.
+         * @return the native seed type
+         */
+        public static NativeSeedType createNativeSeedType(Class<?> type) {
+            if (type.equals(Integer.class)) {
+                return NativeSeedType.INT;
+            } else if (type.equals(Long.class)) {
+                return NativeSeedType.LONG;
+            } else if (type.equals(int[].class)) {
+                return NativeSeedType.INT_ARRAY;
+            } else if (type.equals(long[].class)) {
+                return NativeSeedType.LONG_ARRAY;
+            } else {
+                // Unsupported seed type
+                throw new IllegalStateException(INTERNAL_ERROR_MSG);
+            }
         }
     }
 
@@ -276,122 +366,171 @@ public final class ProviderBuilder {
     public enum RandomSourceInternal {
         /** Source of randomness is {@link JDKRandom}. */
         JDK(JDKRandom.class,
+            1,
             Long.class),
         /** Source of randomness is {@link Well512a}. */
         WELL_512_A(Well512a.class,
+                   16,
                    int[].class),
         /** Source of randomness is {@link Well1024a}. */
         WELL_1024_A(Well1024a.class,
+                    32,
                     int[].class),
         /** Source of randomness is {@link Well19937a}. */
         WELL_19937_A(Well19937a.class,
+                     624,
                      int[].class),
         /** Source of randomness is {@link Well19937c}. */
         WELL_19937_C(Well19937c.class,
+                     624,
                      int[].class),
         /** Source of randomness is {@link Well44497a}. */
         WELL_44497_A(Well44497a.class,
+                     1391,
                      int[].class),
         /** Source of randomness is {@link Well44497b}. */
         WELL_44497_B(Well44497b.class,
+                     1391,
                      int[].class),
         /** Source of randomness is {@link MersenneTwister}. */
         MT(MersenneTwister.class,
+           624,
            int[].class),
         /** Source of randomness is {@link ISAACRandom}. */
         ISAAC(ISAACRandom.class,
+              256,
               int[].class),
         /** Source of randomness is {@link SplitMix64}. */
         SPLIT_MIX_64(SplitMix64.class,
+                     1,
                      Long.class),
         /** Source of randomness is {@link XorShift1024Star}. */
         XOR_SHIFT_1024_S(XorShift1024Star.class,
+                         16,
                          long[].class),
         /** Source of randomness is {@link TwoCmres}. */
         TWO_CMRES(TwoCmres.class,
+                  1,
                   Integer.class),
         /**
          * Source of randomness is {@link TwoCmres} with explicit selection
          * of the two subcycle generators.
          */
         TWO_CMRES_SELECT(TwoCmres.class,
+                         1,
                          Integer.class,
                          Integer.TYPE,
                          Integer.TYPE),
         /** Source of randomness is {@link MersenneTwister64}. */
         MT_64(MersenneTwister64.class,
+              312,
               long[].class),
         /** Source of randomness is {@link MultiplyWithCarry256}. */
         MWC_256(MultiplyWithCarry256.class,
+                257,
                 int[].class),
         /** Source of randomness is {@link KISSRandom}. */
         KISS(KISSRandom.class,
+             4,
              int[].class),
         /** Source of randomness is {@link XorShift1024StarPhi}. */
         XOR_SHIFT_1024_S_PHI(XorShift1024StarPhi.class,
+                             16,
                              long[].class),
         /** Source of randomness is {@link XoRoShiRo64Star}. */
         XO_RO_SHI_RO_64_S(XoRoShiRo64Star.class,
+                          2,
                           int[].class),
         /** Source of randomness is {@link XoRoShiRo64StarStar}. */
         XO_RO_SHI_RO_64_SS(XoRoShiRo64StarStar.class,
+                           2,
                            int[].class),
         /** Source of randomness is {@link XoShiRo128Plus}. */
         XO_SHI_RO_128_PLUS(XoShiRo128Plus.class,
+                           4,
                            int[].class),
         /** Source of randomness is {@link XoShiRo128StarStar}. */
         XO_SHI_RO_128_SS(XoShiRo128StarStar.class,
+                         4,
                          int[].class),
         /** Source of randomness is {@link XoRoShiRo128Plus}. */
         XO_RO_SHI_RO_128_PLUS(XoRoShiRo128Plus.class,
+                              2,
                               long[].class),
         /** Source of randomness is {@link XoRoShiRo128StarStar}. */
         XO_RO_SHI_RO_128_SS(XoRoShiRo128StarStar.class,
+                            2,
                             long[].class),
         /** Source of randomness is {@link XoShiRo256Plus}. */
         XO_SHI_RO_256_PLUS(XoShiRo256Plus.class,
+                           4,
                            long[].class),
         /** Source of randomness is {@link XoShiRo256StarStar}. */
         XO_SHI_RO_256_SS(XoShiRo256StarStar.class,
+                         4,
                          long[].class),
         /** Source of randomness is {@link XoShiRo512Plus}. */
         XO_SHI_RO_512_PLUS(XoShiRo512Plus.class,
+                           8,
                            long[].class),
         /** Source of randomness is {@link XoShiRo512StarStar}. */
         XO_SHI_RO_512_SS(XoShiRo512StarStar.class,
+                         8,
                          long[].class);
 
         /** Source type. */
         private final Class<? extends UniformRandomProvider> rng;
-        /** Data needed to build the generator. */
+        /** Native seed size. Used for array seeds. */
+        private final int nativeSeedSize;
+        /** Define the parameter types of the data needed to build the generator. */
         private final Class<?>[] args;
+        /** Native seed type. Used to create a seed or convert input seeds. */
+        private final NativeSeedType nativeSeedType;
+        /**
+         * The constructor.
+         * This is discovered using the constructor parameter types and cached.
+         */
+        private Constructor<?> constructor;
 
         /**
+         * Create a new instance.
+         *
          * @param rng Source type.
-         * @param args Data needed to create a generator instance.
-         * The first element must be the native seed type.
+         * @param nativeSeedSize Native seed size (array types only).
+         * @param args Data needed to create a generator instance. The first element
+         * must be the native seed type.
          */
         RandomSourceInternal(Class<? extends UniformRandomProvider> rng,
+                             int nativeSeedSize,
                              Class<?>... args) {
             this.rng = rng;
+            this.nativeSeedSize = nativeSeedSize;
             this.args = Arrays.copyOf(args, args.length);
+            // Look-up the native seed type from the class of the seed
+            nativeSeedType = NativeSeedType.createNativeSeedType(args[0]);
         }
 
         /**
-         * @return the source type.
+         * Gets the implementing class of the random source.
+         *
+         * @return the random source class.
          */
         public Class<?> getRng() {
             return rng;
         }
 
         /**
-         * @return the seed type.
+         * Gets the class of the native seed.
+         *
+         * @return the seed class.
          */
         Class<?> getSeed() {
             return args[0];
         }
 
         /**
+         * Gets the parameter types of the data needed to build the generator.
+         *
          * @return the data needed to build the generator.
          */
         Class<?>[] getArgs() {
@@ -411,5 +550,171 @@ public final class ProviderBuilder {
         public <SEED> boolean isNativeSeed(SEED seed) {
             return seed != null && getSeed().equals(seed.getClass());
         }
+
+        /**
+         * Creates a RNG instance.
+         *
+         * <p>This method can be over-ridden to allow fast construction of a generator
+         * with low seeding cost that has no additional constructor arguments.</p>
+         *
+         * @return a new RNG instance.
+         */
+        RestorableUniformRandomProvider create() {
+            // Create a seed.
+            final Object nativeSeed = createSeed();
+            checkSeed(nativeSeed);
+            // Instantiate.
+            return create(getConstructor(), new Object[] {nativeSeed});
+        }
+
+        /**
+         * Creates a RNG instance. It is assumed the seed is not {@code null}.
+         *
+         * <p>This method can be over-ridden to allow fast construction of a generator
+         * with low seed conversion cost that has no additional constructor arguments.</p>
+         *
+         * @param seed Seed value. It must not be {@code null}.
+         * @return a new RNG instance.
+         * @throws UnsupportedOperationException if the seed type is invalid.
+         */
+        RestorableUniformRandomProvider create(Object seed) {
+            // Convert seed to native type.
+            final Object nativeSeed = convertSeed(seed);
+            checkSeed(nativeSeed);
+            // Instantiate.
+            return create(getConstructor(), new Object[] {nativeSeed});
+        }
+
+        /**
+         * Creates a RNG instance. This constructs a RNG using reflection and will error
+         * if the constructor arguments do not match those required by the RNG's constructor.
+         *
+         * @param seed Seed value. It can be {@code null} (in which case a suitable
+         * seed will be generated).
+         * @param constructorArgs Additional arguments to the implementation's constructor.
+         * It must not be {@code null}.
+         * @return a new RNG instance.
+         * @throws UnsupportedOperationException if the seed type is invalid.
+         */
+        RestorableUniformRandomProvider create(Object seed,
+                                               Object[] constructorArgs) {
+            final Object nativeSeed = createNativeSeed(seed);
+
+            // Build a single array with all the arguments to be passed
+            // (in the right order) to the constructor.
+            Object[] all = new Object[constructorArgs.length + 1];
+            all[0] = nativeSeed;
+            System.arraycopy(constructorArgs, 0, all, 1, constructorArgs.length);
+
+            // Instantiate.
+            return create(getConstructor(), all);
+        }
+
+        /**
+         * Creates a native seed.
+         *
+         * <p>This method should be over-ridden to satisfy seed requirements for the generator,
+         * for example if a seed must contain non-zero bits.</p>
+         *
+         * @return the native seed
+         */
+        Object createSeed() {
+            return nativeSeedType.createSeed(nativeSeedSize);
+        }
+
+
+        /**
+         * Converts a seed from any of the supported seed types to a native seed.
+         *
+         * @param seed Input seed (must not be null).
+         * @return the native seed
+         * @throw UnsupportedOperationException if the {@code seed} type is invalid.
+         */
+        Object convertSeed(Object seed) {
+            return nativeSeedType.convertSeed(seed, nativeSeedSize);
+        }
+
+        /**
+         * Creates a native seed from any of the supported seed types.
+         *
+         * @param seed Input seed (may be null).
+         * @return the native seed.
+         * @throw UnsupportedOperationException if the {@code seed} type cannot be converted.
+         */
+        private Object createNativeSeed(Object seed) {
+            // Convert to native type.
+            Object nativeSeed;
+
+            if (seed == null) {
+                nativeSeed = createSeed();
+            } else {
+                nativeSeed = convertSeed(seed);
+            }
+
+            checkSeed(nativeSeed);
+
+            return nativeSeed;
+        }
+
+        /**
+         * Check the seed is a native seed.
+         *
+         * @param seed the seed
+         * @throws IllegalStateException if not a native seed.
+         */
+        private void checkSeed(Object seed) {
+            if (!isNativeSeed(seed)) {
+                // Conversion setup is wrong.
+                throw new IllegalStateException(INTERNAL_ERROR_MSG);
+            }
+        }
+
+        /**
+         * Gets the constructor.
+         *
+         * @return the RNG constructor.
+         */
+        private Constructor<?> getConstructor() {
+            Constructor<?> con = constructor;
+            if (con == null) {
+                con = createConstructor();
+                constructor = con;
+            }
+            return con;
+        }
+        /**
+         * Creates a constructor.
+         *
+         * @return a RNG constructor.
+         */
+        private Constructor<?> createConstructor() {
+            try {
+                return getRng().getConstructor(getArgs());
+            } catch (NoSuchMethodException e) {
+                // Info in "RandomSourceInternal" is inconsistent with the
+                // constructor of the implementation.
+                throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
+            }
+        }
+
+        /**
+         * Creates a RNG.
+         *
+         * @param rng RNG specification.
+         * @param args Arguments to the implementation's constructor.
+         * @return a new RNG instance.
+         */
+        private static RestorableUniformRandomProvider create(Constructor<?> rng,
+                                                              Object[] args) {
+            try {
+                return (RestorableUniformRandomProvider) rng.newInstance(args);
+            } catch (InvocationTargetException e) {
+                throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
+            } catch (InstantiationException e) {
+                throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
+            } catch (IllegalAccessException e) {
+                throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
+            }
+        }
     }
 }
diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2IntArray.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Seed2ArrayConverter.java
similarity index 59%
copy from commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2IntArray.java
copy to commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Seed2ArrayConverter.java
index b1b66f2..2cf5abb 100644
--- a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Long2IntArray.java
+++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/Seed2ArrayConverter.java
@@ -16,29 +16,21 @@
  */
 package org.apache.commons.rng.simple.internal;
 
-import org.apache.commons.rng.core.source64.SplitMix64;
-
 /**
- * Uses a {@code long} value to seed a {@link SplitMix64} RNG and
- * create a {@code int[]} with the requested number of random
- * values.
+ * Seed converter to create an output array type.
+ *
+ * @param <IN> Input seed type.
+ * @param <OUT> Output seed type.
  *
- * @since 1.0
+ * @since 1.3
  */
-public class Long2IntArray implements SeedConverter<Long, int[]> {
-    /** Size of the output array. */
-    private final int size;
-
+public interface Seed2ArrayConverter<IN, OUT> extends SeedConverter<IN, OUT> {
     /**
-     * @param size Size of the output array.
+     * Converts seed from input type to output type. The output type is expected to be an array.
+     *
+     * @param seed Original seed value.
+     * @param outputSize Output size.
+     * @return the converted seed value.
      */
-    public Long2IntArray(int size) {
-        this.size = size;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int[] convert(Long seed) {
-        return SeedFactory.createIntArray(size, new SplitMix64(seed));
-    }
+    OUT convert(IN seed, int outputSize);
 }