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