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 }