View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.rng.simple.internal;
18  
19  import java.lang.reflect.Array;
20  import java.lang.reflect.Constructor;
21  import java.lang.reflect.InvocationTargetException;
22  
23  import org.apache.commons.rng.UniformRandomProvider;
24  import org.apache.commons.rng.RestorableUniformRandomProvider;
25  import org.apache.commons.rng.core.source32.JDKRandom;
26  import org.apache.commons.rng.core.source32.Well512a;
27  import org.apache.commons.rng.core.source32.Well1024a;
28  import org.apache.commons.rng.core.source32.Well19937a;
29  import org.apache.commons.rng.core.source32.Well19937c;
30  import org.apache.commons.rng.core.source32.Well44497a;
31  import org.apache.commons.rng.core.source32.Well44497b;
32  import org.apache.commons.rng.core.source32.ISAACRandom;
33  import org.apache.commons.rng.core.source32.IntProvider;
34  import org.apache.commons.rng.core.source32.MersenneTwister;
35  import org.apache.commons.rng.core.source32.MiddleSquareWeylSequence;
36  import org.apache.commons.rng.core.source32.MultiplyWithCarry256;
37  import org.apache.commons.rng.core.source32.KISSRandom;
38  import org.apache.commons.rng.core.source32.XoRoShiRo64Star;
39  import org.apache.commons.rng.core.source32.XoRoShiRo64StarStar;
40  import org.apache.commons.rng.core.source32.XoShiRo128Plus;
41  import org.apache.commons.rng.core.source32.XoShiRo128PlusPlus;
42  import org.apache.commons.rng.core.source32.XoShiRo128StarStar;
43  import org.apache.commons.rng.core.source32.PcgXshRr32;
44  import org.apache.commons.rng.core.source32.PcgXshRs32;
45  import org.apache.commons.rng.core.source32.PcgMcgXshRr32;
46  import org.apache.commons.rng.core.source32.PcgMcgXshRs32;
47  import org.apache.commons.rng.core.source32.DotyHumphreySmallFastCounting32;
48  import org.apache.commons.rng.core.source32.JenkinsSmallFast32;
49  import org.apache.commons.rng.core.source32.L32X64Mix;
50  import org.apache.commons.rng.core.source64.SplitMix64;
51  import org.apache.commons.rng.core.source64.XorShift1024Star;
52  import org.apache.commons.rng.core.source64.XorShift1024StarPhi;
53  import org.apache.commons.rng.core.source64.TwoCmres;
54  import org.apache.commons.rng.core.source64.XoRoShiRo1024PlusPlus;
55  import org.apache.commons.rng.core.source64.XoRoShiRo1024Star;
56  import org.apache.commons.rng.core.source64.XoRoShiRo1024StarStar;
57  import org.apache.commons.rng.core.source64.MersenneTwister64;
58  import org.apache.commons.rng.core.source64.XoRoShiRo128Plus;
59  import org.apache.commons.rng.core.source64.XoRoShiRo128PlusPlus;
60  import org.apache.commons.rng.core.source64.XoRoShiRo128StarStar;
61  import org.apache.commons.rng.core.source64.XoShiRo256Plus;
62  import org.apache.commons.rng.core.source64.XoShiRo256PlusPlus;
63  import org.apache.commons.rng.core.source64.XoShiRo256StarStar;
64  import org.apache.commons.rng.core.source64.XoShiRo512Plus;
65  import org.apache.commons.rng.core.source64.XoShiRo512PlusPlus;
66  import org.apache.commons.rng.core.source64.XoShiRo512StarStar;
67  import org.apache.commons.rng.core.source64.PcgRxsMXs64;
68  import org.apache.commons.rng.core.source64.DotyHumphreySmallFastCounting64;
69  import org.apache.commons.rng.core.source64.JenkinsSmallFast64;
70  import org.apache.commons.rng.core.source64.L64X1024Mix;
71  import org.apache.commons.rng.core.source64.L64X128Mix;
72  import org.apache.commons.rng.core.source64.L64X128StarStar;
73  import org.apache.commons.rng.core.source64.L64X256Mix;
74  import org.apache.commons.rng.core.source64.L128X1024Mix;
75  import org.apache.commons.rng.core.source64.L128X128Mix;
76  import org.apache.commons.rng.core.source64.L128X256Mix;
77  
78  /**
79   * RNG builder.
80   * <p>
81   * It uses reflection to find the factory method of the RNG implementation,
82   * and performs seed type conversions.
83   * </p>
84   */
85  public final class ProviderBuilder {
86      /** Error message. */
87      private static final String INTERNAL_ERROR_MSG = "Internal error: Please file a bug report";
88  
89      /**
90       * Class only contains static method.
91       */
92      private ProviderBuilder() {}
93  
94      /**
95       * Creates a RNG instance.
96       *
97       * @param source RNG specification.
98       * @return a new RNG instance.
99       * @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 }