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