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