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