001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.rng.simple.internal;
018
019import java.lang.reflect.Array;
020import java.lang.reflect.Constructor;
021import java.lang.reflect.InvocationTargetException;
022
023import org.apache.commons.rng.UniformRandomProvider;
024import org.apache.commons.rng.RestorableUniformRandomProvider;
025import org.apache.commons.rng.core.source32.JDKRandom;
026import org.apache.commons.rng.core.source32.Well512a;
027import org.apache.commons.rng.core.source32.Well1024a;
028import org.apache.commons.rng.core.source32.Well19937a;
029import org.apache.commons.rng.core.source32.Well19937c;
030import org.apache.commons.rng.core.source32.Well44497a;
031import org.apache.commons.rng.core.source32.Well44497b;
032import org.apache.commons.rng.core.source32.ISAACRandom;
033import org.apache.commons.rng.core.source32.IntProvider;
034import org.apache.commons.rng.core.source32.MersenneTwister;
035import org.apache.commons.rng.core.source32.MiddleSquareWeylSequence;
036import org.apache.commons.rng.core.source32.MultiplyWithCarry256;
037import org.apache.commons.rng.core.source32.KISSRandom;
038import org.apache.commons.rng.core.source32.XoRoShiRo64Star;
039import org.apache.commons.rng.core.source32.XoRoShiRo64StarStar;
040import org.apache.commons.rng.core.source32.XoShiRo128Plus;
041import org.apache.commons.rng.core.source32.XoShiRo128PlusPlus;
042import org.apache.commons.rng.core.source32.XoShiRo128StarStar;
043import org.apache.commons.rng.core.source32.PcgXshRr32;
044import org.apache.commons.rng.core.source32.PcgXshRs32;
045import org.apache.commons.rng.core.source32.PcgMcgXshRr32;
046import org.apache.commons.rng.core.source32.PcgMcgXshRs32;
047import org.apache.commons.rng.core.source32.DotyHumphreySmallFastCounting32;
048import org.apache.commons.rng.core.source32.JenkinsSmallFast32;
049import org.apache.commons.rng.core.source32.L32X64Mix;
050import org.apache.commons.rng.core.source64.SplitMix64;
051import org.apache.commons.rng.core.source64.XorShift1024Star;
052import org.apache.commons.rng.core.source64.XorShift1024StarPhi;
053import org.apache.commons.rng.core.source64.TwoCmres;
054import org.apache.commons.rng.core.source64.XoRoShiRo1024PlusPlus;
055import org.apache.commons.rng.core.source64.XoRoShiRo1024Star;
056import org.apache.commons.rng.core.source64.XoRoShiRo1024StarStar;
057import org.apache.commons.rng.core.source64.MersenneTwister64;
058import org.apache.commons.rng.core.source64.XoRoShiRo128Plus;
059import org.apache.commons.rng.core.source64.XoRoShiRo128PlusPlus;
060import org.apache.commons.rng.core.source64.XoRoShiRo128StarStar;
061import org.apache.commons.rng.core.source64.XoShiRo256Plus;
062import org.apache.commons.rng.core.source64.XoShiRo256PlusPlus;
063import org.apache.commons.rng.core.source64.XoShiRo256StarStar;
064import org.apache.commons.rng.core.source64.XoShiRo512Plus;
065import org.apache.commons.rng.core.source64.XoShiRo512PlusPlus;
066import org.apache.commons.rng.core.source64.XoShiRo512StarStar;
067import org.apache.commons.rng.core.source64.PcgRxsMXs64;
068import org.apache.commons.rng.core.source64.DotyHumphreySmallFastCounting64;
069import org.apache.commons.rng.core.source64.JenkinsSmallFast64;
070import org.apache.commons.rng.core.source64.L64X1024Mix;
071import org.apache.commons.rng.core.source64.L64X128Mix;
072import org.apache.commons.rng.core.source64.L64X128StarStar;
073import org.apache.commons.rng.core.source64.L64X256Mix;
074import org.apache.commons.rng.core.source64.L128X1024Mix;
075import org.apache.commons.rng.core.source64.L128X128Mix;
076import org.apache.commons.rng.core.source64.L128X256Mix;
077
078/**
079 * RNG builder.
080 * <p>
081 * It uses reflection to find the factory method of the RNG implementation,
082 * and performs seed type conversions.
083 * </p>
084 */
085public final class ProviderBuilder {
086    /** Error message. */
087    private static final String INTERNAL_ERROR_MSG = "Internal error: Please file a bug report";
088
089    /**
090     * Class only contains static method.
091     */
092    private ProviderBuilder() {}
093
094    /**
095     * Creates a RNG instance.
096     *
097     * @param source RNG specification.
098     * @return a new RNG instance.
099     * @throws IllegalArgumentException if argument data to initialize the
100     * generator implemented by the given {@code source} is missing.
101     * @since 1.3
102     */
103    public static RestorableUniformRandomProvider create(RandomSourceInternal source) {
104        // Delegate to the random source allowing generator specific implementations.
105        return source.create();
106    }
107
108    /**
109     * Creates a RNG instance.
110     *
111     * @param source RNG specification.
112     * @param seed Seed value.  It can be {@code null} (in which case a
113     * random value will be used).
114     * @param args Additional arguments to the implementation's constructor.
115     * @return a new RNG instance.
116     * @throws UnsupportedOperationException if the seed type is invalid.
117     * @throws IllegalArgumentException if argument data to initialize the
118     * generator implemented by the given {@code source} is invalid.
119     */
120    public static RestorableUniformRandomProvider create(RandomSourceInternal source,
121                                                         Object seed,
122                                                         Object[] args) {
123        // Delegate to the random source allowing generator specific implementations.
124        // This method checks arguments for null and calls the appropriate internal method.
125        if (args != null) {
126            return source.create(seed, args);
127        }
128        return seed == null ?
129                source.create() :
130                source.create(seed);
131    }
132
133    /**
134     * Identifiers of the generators.
135     */
136    public enum RandomSourceInternal {
137        /** Source of randomness is {@link JDKRandom}. */
138        JDK(JDKRandom.class,
139            1,
140            NativeSeedType.LONG),
141        /** Source of randomness is {@link Well512a}. */
142        WELL_512_A(Well512a.class,
143                   16, 0, 16,
144                   NativeSeedType.INT_ARRAY),
145        /** Source of randomness is {@link Well1024a}. */
146        WELL_1024_A(Well1024a.class,
147                    32, 0, 32,
148                    NativeSeedType.INT_ARRAY),
149        /** Source of randomness is {@link Well19937a}. */
150        WELL_19937_A(Well19937a.class,
151                     624, 0, 623,
152                     NativeSeedType.INT_ARRAY),
153        /** Source of randomness is {@link Well19937c}. */
154        WELL_19937_C(Well19937c.class,
155                     624, 0, 623,
156                     NativeSeedType.INT_ARRAY),
157        /** Source of randomness is {@link Well44497a}. */
158        WELL_44497_A(Well44497a.class,
159                     1391, 0, 1390,
160                     NativeSeedType.INT_ARRAY),
161        /** Source of randomness is {@link Well44497b}. */
162        WELL_44497_B(Well44497b.class,
163                     1391, 0, 1390,
164                     NativeSeedType.INT_ARRAY),
165        /** Source of randomness is {@link MersenneTwister}. */
166        MT(MersenneTwister.class,
167           624,
168           NativeSeedType.INT_ARRAY),
169        /** Source of randomness is {@link ISAACRandom}. */
170        ISAAC(ISAACRandom.class,
171              256,
172              NativeSeedType.INT_ARRAY),
173        /** Source of randomness is {@link SplitMix64}. */
174        SPLIT_MIX_64(SplitMix64.class,
175                     1,
176                     NativeSeedType.LONG),
177        /** Source of randomness is {@link XorShift1024Star}. */
178        XOR_SHIFT_1024_S(XorShift1024Star.class,
179                         16, 0, 16,
180                         NativeSeedType.LONG_ARRAY),
181        /** Source of randomness is {@link TwoCmres}. */
182        TWO_CMRES(TwoCmres.class,
183                  1,
184                  NativeSeedType.INT),
185        /**
186         * Source of randomness is {@link TwoCmres} with explicit selection
187         * of the two subcycle generators.
188         */
189        TWO_CMRES_SELECT(TwoCmres.class,
190                         1,
191                         NativeSeedType.INT,
192                         Integer.TYPE,
193                         Integer.TYPE),
194        /** Source of randomness is {@link MersenneTwister64}. */
195        MT_64(MersenneTwister64.class,
196              312,
197              NativeSeedType.LONG_ARRAY),
198        /** Source of randomness is {@link MultiplyWithCarry256}. */
199        MWC_256(MultiplyWithCarry256.class,
200                257, 0, 257,
201                NativeSeedType.INT_ARRAY),
202        /** Source of randomness is {@link KISSRandom}. */
203        KISS(KISSRandom.class,
204             // If zero in initial 3 positions the output is a simple LCG
205             4, 0, 3,
206             NativeSeedType.INT_ARRAY),
207        /** Source of randomness is {@link XorShift1024StarPhi}. */
208        XOR_SHIFT_1024_S_PHI(XorShift1024StarPhi.class,
209                             16, 0, 16,
210                             NativeSeedType.LONG_ARRAY),
211        /** Source of randomness is {@link XoRoShiRo64Star}. */
212        XO_RO_SHI_RO_64_S(XoRoShiRo64Star.class,
213                          2, 0, 2,
214                          NativeSeedType.INT_ARRAY),
215        /** Source of randomness is {@link XoRoShiRo64StarStar}. */
216        XO_RO_SHI_RO_64_SS(XoRoShiRo64StarStar.class,
217                           2, 0, 2,
218                           NativeSeedType.INT_ARRAY),
219        /** Source of randomness is {@link XoShiRo128Plus}. */
220        XO_SHI_RO_128_PLUS(XoShiRo128Plus.class,
221                           4, 0, 4,
222                           NativeSeedType.INT_ARRAY),
223        /** Source of randomness is {@link XoShiRo128StarStar}. */
224        XO_SHI_RO_128_SS(XoShiRo128StarStar.class,
225                         4, 0, 4,
226                         NativeSeedType.INT_ARRAY),
227        /** Source of randomness is {@link XoRoShiRo128Plus}. */
228        XO_RO_SHI_RO_128_PLUS(XoRoShiRo128Plus.class,
229                              2, 0, 2,
230                              NativeSeedType.LONG_ARRAY),
231        /** Source of randomness is {@link XoRoShiRo128StarStar}. */
232        XO_RO_SHI_RO_128_SS(XoRoShiRo128StarStar.class,
233                            2, 0, 2,
234                            NativeSeedType.LONG_ARRAY),
235        /** Source of randomness is {@link XoShiRo256Plus}. */
236        XO_SHI_RO_256_PLUS(XoShiRo256Plus.class,
237                           4, 0, 4,
238                           NativeSeedType.LONG_ARRAY),
239        /** Source of randomness is {@link XoShiRo256StarStar}. */
240        XO_SHI_RO_256_SS(XoShiRo256StarStar.class,
241                         4, 0, 4,
242                         NativeSeedType.LONG_ARRAY),
243        /** Source of randomness is {@link XoShiRo512Plus}. */
244        XO_SHI_RO_512_PLUS(XoShiRo512Plus.class,
245                           8, 0, 8,
246                           NativeSeedType.LONG_ARRAY),
247        /** Source of randomness is {@link XoShiRo512StarStar}. */
248        XO_SHI_RO_512_SS(XoShiRo512StarStar.class,
249                         8, 0, 8,
250                         NativeSeedType.LONG_ARRAY),
251        /** Source of randomness is {@link PcgXshRr32}. */
252        PCG_XSH_RR_32(PcgXshRr32.class,
253                2,
254                NativeSeedType.LONG_ARRAY),
255        /** Source of randomness is {@link PcgXshRs32}. */
256        PCG_XSH_RS_32(PcgXshRs32.class,
257                2,
258                NativeSeedType.LONG_ARRAY),
259        /** Source of randomness is {@link PcgRxsMXs64}. */
260        PCG_RXS_M_XS_64(PcgRxsMXs64.class,
261                2,
262                NativeSeedType.LONG_ARRAY),
263        /** Source of randomness is {@link PcgMcgXshRr32}. */
264        PCG_MCG_XSH_RR_32(PcgMcgXshRr32.class,
265                1,
266                NativeSeedType.LONG),
267        /** Source of randomness is {@link PcgMcgXshRs32}. */
268        PCG_MCG_XSH_RS_32(PcgMcgXshRs32.class,
269                1,
270                NativeSeedType.LONG),
271        /** Source of randomness is {@link MiddleSquareWeylSequence}. */
272        MSWS(MiddleSquareWeylSequence.class,
273             // Many partially zero seeds can create low quality initial output.
274             // The Weyl increment cascades bits into the random state so ideally it
275             // has a high number of bit transitions. Minimally ensure it is non-zero.
276             3, 2, 3,
277             NativeSeedType.LONG_ARRAY) {
278            @Override
279            protected Object createSeed() {
280                return createMswsSeed(SeedFactory.createLong());
281            }
282
283            @Override
284            protected Object convertSeed(Object seed) {
285                // Allow seeding with primitives to generate a good seed
286                if (seed instanceof Integer) {
287                    return createMswsSeed((Integer) seed);
288                } else if (seed instanceof Long) {
289                    return createMswsSeed((Long) seed);
290                }
291                // Other types (e.g. the native long[]) are handled by the default conversion
292                return super.convertSeed(seed);
293            }
294
295            @Override
296            protected byte[] createByteArraySeed(UniformRandomProvider source) {
297                // The seed requires approximately 4-6 calls to nextInt().
298                // Wrap the input and switch to a default if the input is faulty.
299                final UniformRandomProvider wrapped = new IntProvider() {
300                    /** The number of remaining calls to the source generator. */
301                    private int calls = 100;
302                    /** Default generator, initialised when required. */
303                    private UniformRandomProvider defaultGen;
304                    @Override
305                    public int next() {
306                        if (calls == 0) {
307                            // The input source is broken.
308                            // Seed a default
309                            if (defaultGen == null) {
310                                defaultGen = new SplitMix64(source.nextLong());
311                            }
312                            return defaultGen.nextInt();
313                        }
314                        calls--;
315                        return source.nextInt();
316                    }
317                    @Override
318                    public long nextLong() {
319                        // No specific requirements so always use the source
320                        return source.nextLong();
321                    }
322                };
323                return NativeSeedType.convertSeedToBytes(createMswsSeed(wrapped));
324            }
325
326            /**
327             * Creates the full length seed array from the input seed.
328             *
329             * @param seed the seed
330             * @return the seed array
331             */
332            private long[] createMswsSeed(long seed) {
333                return createMswsSeed(new SplitMix64(seed));
334            }
335
336            /**
337             * Creates the full length seed array from the input seed using the method
338             * recommended for the generator. This is a high quality Weyl increment composed
339             * of a hex character permutation.
340             *
341             * @param source Source of randomness.
342             * @return the seed array
343             */
344            private long[] createMswsSeed(UniformRandomProvider source) {
345                final long increment = SeedUtils.createLongHexPermutation(source);
346                // The initial state should not be low complexity but the Weyl
347                // state can be any number.
348                final long state = increment;
349                final long weylState = source.nextLong();
350                return new long[] {state, weylState, increment};
351            }
352        },
353        /** Source of randomness is {@link DotyHumphreySmallFastCounting32}. */
354        SFC_32(DotyHumphreySmallFastCounting32.class,
355               3,
356               NativeSeedType.INT_ARRAY),
357        /** Source of randomness is {@link DotyHumphreySmallFastCounting64}. */
358        SFC_64(DotyHumphreySmallFastCounting64.class,
359               3,
360               NativeSeedType.LONG_ARRAY),
361        /** Source of randomness is {@link JenkinsSmallFast32}. */
362        JSF_32(JenkinsSmallFast32.class,
363               1,
364               NativeSeedType.INT),
365        /** Source of randomness is {@link JenkinsSmallFast64}. */
366        JSF_64(JenkinsSmallFast64.class,
367               1,
368               NativeSeedType.LONG),
369        /** Source of randomness is {@link XoShiRo128PlusPlus}. */
370        XO_SHI_RO_128_PP(XoShiRo128PlusPlus.class,
371                         4, 0, 4,
372                         NativeSeedType.INT_ARRAY),
373        /** Source of randomness is {@link XoRoShiRo128PlusPlus}. */
374        XO_RO_SHI_RO_128_PP(XoRoShiRo128PlusPlus.class,
375                            2, 0, 2,
376                            NativeSeedType.LONG_ARRAY),
377        /** Source of randomness is {@link XoShiRo256PlusPlus}. */
378        XO_SHI_RO_256_PP(XoShiRo256PlusPlus.class,
379                         4, 0, 4,
380                         NativeSeedType.LONG_ARRAY),
381        /** Source of randomness is {@link XoShiRo512PlusPlus}. */
382        XO_SHI_RO_512_PP(XoShiRo512PlusPlus.class,
383                         8, 0, 8,
384                         NativeSeedType.LONG_ARRAY),
385        /** Source of randomness is {@link XoRoShiRo1024PlusPlus}. */
386        XO_RO_SHI_RO_1024_PP(XoRoShiRo1024PlusPlus.class,
387                             16, 0, 16,
388                             NativeSeedType.LONG_ARRAY),
389        /** Source of randomness is {@link XoRoShiRo1024Star}. */
390        XO_RO_SHI_RO_1024_S(XoRoShiRo1024Star.class,
391                            16, 0, 16,
392                            NativeSeedType.LONG_ARRAY),
393        /** Source of randomness is {@link XoRoShiRo1024StarStar}. */
394        XO_RO_SHI_RO_1024_SS(XoRoShiRo1024StarStar.class,
395                             16, 0, 16,
396                             NativeSeedType.LONG_ARRAY),
397        /** Source of randomness is {@link PcgXshRr32}. */
398        PCG_XSH_RR_32_OS(PcgXshRr32.class,
399                1,
400                NativeSeedType.LONG),
401        /** Source of randomness is {@link PcgXshRs32}. */
402        PCG_XSH_RS_32_OS(PcgXshRs32.class,
403                1,
404                NativeSeedType.LONG),
405        /** Source of randomness is {@link PcgRxsMXs64}. */
406        PCG_RXS_M_XS_64_OS(PcgRxsMXs64.class,
407                1,
408                NativeSeedType.LONG),
409        /** Source of randomness is {@link L64X128StarStar}. */
410        L64_X128_SS(L64X128StarStar.class,
411                4, 2, 4,
412                NativeSeedType.LONG_ARRAY),
413        /** Source of randomness is {@link L64X128Mix}. */
414        L64_X128_MIX(L64X128Mix.class,
415                4, 2, 4,
416                NativeSeedType.LONG_ARRAY),
417        /** Source of randomness is {@link L64X256Mix}. */
418        L64_X256_MIX(L64X256Mix.class,
419                6, 2, 6,
420                NativeSeedType.LONG_ARRAY),
421        /** Source of randomness is {@link L64X1024Mix}. */
422        L64_X1024_MIX(L64X1024Mix.class,
423                18, 2, 18,
424                NativeSeedType.LONG_ARRAY),
425        /** Source of randomness is {@link L128X128Mix}. */
426        L128_X128_MIX(L128X128Mix.class,
427                6, 4, 6,
428                NativeSeedType.LONG_ARRAY),
429        /** Source of randomness is {@link L128X256Mix}. */
430        L128_X256_MIX(L128X256Mix.class,
431                8, 4, 8,
432                NativeSeedType.LONG_ARRAY),
433        /** Source of randomness is {@link L128X1024Mix}. */
434        L128_X1024_MIX(L128X1024Mix.class,
435                20, 4, 20,
436                NativeSeedType.LONG_ARRAY),
437        /** Source of randomness is {@link L32X64Mix}. */
438        L32_X64_MIX(L32X64Mix.class,
439                4, 2, 4,
440                NativeSeedType.INT_ARRAY);
441
442        /** Source type. */
443        private final Class<? extends UniformRandomProvider> rng;
444        /** Native seed size. Used for array seeds. */
445        private final int nativeSeedSize;
446        /** Start of the not all-zero sub-range for array seeds (inclusive). */
447        private final int notAllZeroFrom;
448        /** End of the not all-zero sub-range for array seeds (exclusive). */
449        private final int notAllZeroTo;
450        /** Define the parameter types of the data needed to build the generator. */
451        private final Class<?>[] args;
452        /** Native seed type. Used to create a seed or convert input seeds. */
453        private final NativeSeedType nativeSeedType;
454        /**
455         * The constructor.
456         * This is discovered using the constructor parameter types and stored for re-use.
457         */
458        private Constructor<?> rngConstructor;
459
460        /**
461         * Create a new instance.
462         *
463         * <p>Used when the seed array has no requirement for a not all-zero sub-range.
464         *
465         * @param rng Source type.
466         * @param nativeSeedSize Native seed size (array types only).
467         * @param nativeSeedType Native seed type.
468         * @param args Additional data needed to create a generator instance.
469         */
470        RandomSourceInternal(Class<? extends UniformRandomProvider> rng,
471                             int nativeSeedSize,
472                             NativeSeedType nativeSeedType,
473                             Class<?>... args) {
474            this(rng, nativeSeedSize, 0, 0, nativeSeedType, args);
475        }
476
477        /**
478         * Create a new instance.
479         *
480         * <p>Note: The sub-range of an array seed that is not all-zero can be specified.
481         * If the native seed array is used to represent a number of bits
482         * that is not an exact multiple of the number of bytes in the seed, then a
483         * safe approach is to specify the sub-range using a smaller size than the
484         * full length seed. For example a {@link Well19937a} generator uses 19937
485         * bits and has a seed bit length of 19968. A safe range is [0, 19937 / 32).
486         *
487         * @param rng Source type.
488         * @param nativeSeedSize Native seed size (array types only).
489         * @param notAllZeroFrom The start of the not all-zero sub-range (inclusive).
490         * @param notAllZeroTo The end of the not all-zero sub-range (exclusive).
491         * @param nativeSeedType Native seed type.
492         * @param args Additional data needed to create a generator instance.
493         */
494        RandomSourceInternal(Class<? extends UniformRandomProvider> rng,
495                             int nativeSeedSize,
496                             int notAllZeroFrom,
497                             int notAllZeroTo,
498                             NativeSeedType nativeSeedType,
499                             Class<?>... args) {
500            this.rng = rng;
501            this.nativeSeedSize = nativeSeedSize;
502            this.notAllZeroFrom = notAllZeroFrom;
503            this.notAllZeroTo = notAllZeroTo;
504            this.nativeSeedType = nativeSeedType;
505            // Build the complete list of class types for the constructor
506            this.args = (Class<?>[]) Array.newInstance(args.getClass().getComponentType(), 1 + args.length);
507            this.args[0] = nativeSeedType.getType();
508            System.arraycopy(args, 0, this.args, 1, args.length);
509        }
510
511        /**
512         * Gets the implementing class of the random source.
513         *
514         * @return the random source class.
515         */
516        public Class<?> getRng() {
517            return rng;
518        }
519
520        /**
521         * Gets the class of the native seed.
522         *
523         * @return the seed class.
524         */
525        Class<?> getSeed() {
526            return args[0];
527        }
528
529        /**
530         * Gets the parameter types of the data needed to build the generator.
531         *
532         * @return the data needed to build the generator.
533         */
534        Class<?>[] getArgs() {
535            return args;
536        }
537
538        /**
539         * Checks whether the type of given {@code seed} is the native type
540         * of the implementation.
541         *
542         * @param <SEED> Seed type.
543         *
544         * @param seed Seed value.
545         * @return {@code true} if the seed can be passed to the builder
546         * for this RNG type.
547         */
548        public <SEED> boolean isNativeSeed(SEED seed) {
549            return seed != null && getSeed().equals(seed.getClass());
550        }
551
552        /**
553         * Creates a RNG instance.
554         *
555         * <p>This method can be over-ridden to allow fast construction of a generator
556         * with low seeding cost that has no additional constructor arguments.</p>
557         *
558         * @return a new RNG instance.
559         */
560        RestorableUniformRandomProvider create() {
561            // Create a seed.
562            final Object nativeSeed = createSeed();
563            // Instantiate.
564            return create(getConstructor(), new Object[] {nativeSeed});
565        }
566
567        /**
568         * Creates a RNG instance. It is assumed the seed is not {@code null}.
569         *
570         * <p>This method can be over-ridden to allow fast construction of a generator
571         * with low seed conversion cost that has no additional constructor arguments.</p>
572         *
573         * @param seed Seed value. It must not be {@code null}.
574         * @return a new RNG instance.
575         * @throws UnsupportedOperationException if the seed type is invalid.
576         */
577        RestorableUniformRandomProvider create(Object seed) {
578            // Convert seed to native type.
579            final Object nativeSeed = convertSeed(seed);
580            // Instantiate.
581            return create(getConstructor(), new Object[] {nativeSeed});
582        }
583
584        /**
585         * Creates a RNG instance. This constructs a RNG using reflection and will error
586         * if the constructor arguments do not match those required by the RNG's constructor.
587         *
588         * @param seed Seed value. It can be {@code null} (in which case a suitable
589         * seed will be generated).
590         * @param constructorArgs Additional arguments to the implementation's constructor.
591         * It must not be {@code null}.
592         * @return a new RNG instance.
593         * @throws UnsupportedOperationException if the seed type is invalid.
594         */
595        RestorableUniformRandomProvider create(Object seed,
596                                               Object[] constructorArgs) {
597            final Object nativeSeed = createNativeSeed(seed);
598
599            // Build a single array with all the arguments to be passed
600            // (in the right order) to the constructor.
601            Object[] all = new Object[constructorArgs.length + 1];
602            all[0] = nativeSeed;
603            System.arraycopy(constructorArgs, 0, all, 1, constructorArgs.length);
604
605            // Instantiate.
606            return create(getConstructor(), all);
607        }
608
609        /**
610         * Creates a native seed.
611         *
612         * <p>The default implementation creates a seed of the native type and, for array seeds,
613         * ensures not all bits are zero.</p>
614         *
615         * <p>This method should be over-ridden to satisfy seed requirements for the generator.</p>
616         *
617         * @return the native seed
618         * @since 1.3
619         */
620        protected Object createSeed() {
621            // Ensure the seed is not all-zero in the sub-range
622            return nativeSeedType.createSeed(nativeSeedSize, notAllZeroFrom, notAllZeroTo);
623        }
624
625        /**
626         * Creates a {@code byte[]} seed using the provided source of randomness.
627         *
628         * <p>The default implementation creates a full-length seed and ensures not all bits
629         * are zero.</p>
630         *
631         * <p>This method should be over-ridden to satisfy seed requirements for the generator.</p>
632         *
633         * @param source Source of randomness.
634         * @return the byte[] seed
635         * @since 1.3
636         */
637        protected byte[] createByteArraySeed(UniformRandomProvider source) {
638            // Ensure the seed is not all-zero in the sub-range.
639            // Note: Convert the native seed array size/positions to byte size/positions.
640            final int bytes = nativeSeedType.getBytes();
641            return SeedFactory.createByteArray(source,
642                bytes * nativeSeedSize,
643                bytes * notAllZeroFrom,
644                bytes * notAllZeroTo);
645        }
646
647        /**
648         * Converts a seed from any of the supported seed types to a native seed.
649         *
650         * <p>The default implementation delegates to the native seed type conversion.</p>
651         *
652         * <p>This method should be over-ridden to satisfy seed requirements for the generator.</p>
653         *
654         * @param seed Input seed (must not be null).
655         * @return the native seed
656         * @throws UnsupportedOperationException if the {@code seed} type is invalid.
657         * @since 1.3
658         */
659        protected Object convertSeed(Object seed) {
660            return nativeSeedType.convertSeed(seed, nativeSeedSize);
661        }
662
663        /**
664         * Creates a native seed from any of the supported seed types.
665         *
666         * @param seed Input seed (may be null).
667         * @return the native seed.
668         * @throws UnsupportedOperationException if the {@code seed} type cannot be converted.
669         */
670        private Object createNativeSeed(Object seed) {
671            return seed == null ?
672                createSeed() :
673                convertSeed(seed);
674        }
675
676        /**
677         * Creates a seed suitable for the implementing class represented by this random source.
678         *
679         * <p>It will satisfy the seed size and any other seed requirements for the
680         * implementing class. The seed is converted from the native type to bytes.</p>
681         *
682         * @return the seed bytes
683         * @since 1.3
684         */
685        public final byte[] createSeedBytes() {
686            // Custom implementations can override createSeed
687            final Object seed = createSeed();
688            return NativeSeedType.convertSeedToBytes(seed);
689        }
690
691        /**
692         * Creates a seed suitable for the implementing class represented by this random source
693         * using the supplied source of randomness.
694         *
695         * <p>It will satisfy the seed size and any other seed requirements for the
696         * implementing class. The seed is converted from the native type to bytes.</p>
697         *
698         * @param source Source of randomness.
699         * @return the seed bytes
700         * @since 1.3
701         */
702        public final byte[] createSeedBytes(UniformRandomProvider source) {
703            // Custom implementations can override createByteArraySeed
704            return createByteArraySeed(source);
705        }
706
707        /**
708         * Gets the constructor.
709         *
710         * @return the RNG constructor.
711         */
712        private Constructor<?> getConstructor() {
713            // The constructor never changes so it is stored for re-use.
714            Constructor<?> constructor = rngConstructor;
715            if (constructor == null) {
716                // If null this is either the first attempt to find it or
717                // look-up previously failed and this method will throw
718                // upon each invocation.
719                constructor = createConstructor();
720                rngConstructor = constructor;
721            }
722            return constructor;
723        }
724
725        /**
726         * Creates a constructor.
727         *
728         * @return a RNG constructor.
729         */
730        private Constructor<?> createConstructor() {
731            try {
732                return getRng().getConstructor(getArgs());
733            } catch (NoSuchMethodException e) {
734                // Info in "RandomSourceInternal" is inconsistent with the
735                // constructor of the implementation.
736                throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
737            }
738        }
739
740        /**
741         * Creates a RNG.
742         *
743         * @param rng RNG specification.
744         * @param args Arguments to the implementation's constructor.
745         * @return a new RNG instance.
746         */
747        private static RestorableUniformRandomProvider create(Constructor<?> rng,
748                                                              Object[] args) {
749            try {
750                return (RestorableUniformRandomProvider) rng.newInstance(args);
751            } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
752                throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
753            }
754        }
755    }
756}