ProviderBuilder.java

  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. import java.lang.reflect.Array;
  19. import java.lang.reflect.Constructor;
  20. import java.lang.reflect.InvocationTargetException;

  21. import org.apache.commons.rng.UniformRandomProvider;
  22. import org.apache.commons.rng.RestorableUniformRandomProvider;
  23. import org.apache.commons.rng.core.source32.JDKRandom;
  24. import org.apache.commons.rng.core.source32.Well512a;
  25. import org.apache.commons.rng.core.source32.Well1024a;
  26. import org.apache.commons.rng.core.source32.Well19937a;
  27. import org.apache.commons.rng.core.source32.Well19937c;
  28. import org.apache.commons.rng.core.source32.Well44497a;
  29. import org.apache.commons.rng.core.source32.Well44497b;
  30. import org.apache.commons.rng.core.source32.ISAACRandom;
  31. import org.apache.commons.rng.core.source32.IntProvider;
  32. import org.apache.commons.rng.core.source32.MersenneTwister;
  33. import org.apache.commons.rng.core.source32.MiddleSquareWeylSequence;
  34. import org.apache.commons.rng.core.source32.MultiplyWithCarry256;
  35. import org.apache.commons.rng.core.source32.KISSRandom;
  36. import org.apache.commons.rng.core.source32.XoRoShiRo64Star;
  37. import org.apache.commons.rng.core.source32.XoRoShiRo64StarStar;
  38. import org.apache.commons.rng.core.source32.XoShiRo128Plus;
  39. import org.apache.commons.rng.core.source32.XoShiRo128PlusPlus;
  40. import org.apache.commons.rng.core.source32.XoShiRo128StarStar;
  41. import org.apache.commons.rng.core.source32.PcgXshRr32;
  42. import org.apache.commons.rng.core.source32.PcgXshRs32;
  43. import org.apache.commons.rng.core.source32.PcgMcgXshRr32;
  44. import org.apache.commons.rng.core.source32.PcgMcgXshRs32;
  45. import org.apache.commons.rng.core.source32.DotyHumphreySmallFastCounting32;
  46. import org.apache.commons.rng.core.source32.JenkinsSmallFast32;
  47. import org.apache.commons.rng.core.source32.L32X64Mix;
  48. import org.apache.commons.rng.core.source64.SplitMix64;
  49. import org.apache.commons.rng.core.source64.XorShift1024Star;
  50. import org.apache.commons.rng.core.source64.XorShift1024StarPhi;
  51. import org.apache.commons.rng.core.source64.TwoCmres;
  52. import org.apache.commons.rng.core.source64.XoRoShiRo1024PlusPlus;
  53. import org.apache.commons.rng.core.source64.XoRoShiRo1024Star;
  54. import org.apache.commons.rng.core.source64.XoRoShiRo1024StarStar;
  55. import org.apache.commons.rng.core.source64.MersenneTwister64;
  56. import org.apache.commons.rng.core.source64.XoRoShiRo128Plus;
  57. import org.apache.commons.rng.core.source64.XoRoShiRo128PlusPlus;
  58. import org.apache.commons.rng.core.source64.XoRoShiRo128StarStar;
  59. import org.apache.commons.rng.core.source64.XoShiRo256Plus;
  60. import org.apache.commons.rng.core.source64.XoShiRo256PlusPlus;
  61. import org.apache.commons.rng.core.source64.XoShiRo256StarStar;
  62. import org.apache.commons.rng.core.source64.XoShiRo512Plus;
  63. import org.apache.commons.rng.core.source64.XoShiRo512PlusPlus;
  64. import org.apache.commons.rng.core.source64.XoShiRo512StarStar;
  65. import org.apache.commons.rng.core.source64.PcgRxsMXs64;
  66. import org.apache.commons.rng.core.source64.DotyHumphreySmallFastCounting64;
  67. import org.apache.commons.rng.core.source64.JenkinsSmallFast64;
  68. import org.apache.commons.rng.core.source64.L64X1024Mix;
  69. import org.apache.commons.rng.core.source64.L64X128Mix;
  70. import org.apache.commons.rng.core.source64.L64X128StarStar;
  71. import org.apache.commons.rng.core.source64.L64X256Mix;
  72. import org.apache.commons.rng.core.source64.L128X1024Mix;
  73. import org.apache.commons.rng.core.source64.L128X128Mix;
  74. import org.apache.commons.rng.core.source64.L128X256Mix;

  75. /**
  76.  * RNG builder.
  77.  * <p>
  78.  * It uses reflection to find the factory method of the RNG implementation,
  79.  * and performs seed type conversions.
  80.  * </p>
  81.  */
  82. public final class ProviderBuilder {
  83.     /** Error message. */
  84.     private static final String INTERNAL_ERROR_MSG = "Internal error: Please file a bug report";

  85.     /**
  86.      * Class only contains static method.
  87.      */
  88.     private ProviderBuilder() {}

  89.     /**
  90.      * Creates a RNG instance.
  91.      *
  92.      * @param source RNG specification.
  93.      * @return a new RNG instance.
  94.      * @throws IllegalArgumentException if argument data to initialize the
  95.      * generator implemented by the given {@code source} is missing.
  96.      * @since 1.3
  97.      */
  98.     public static RestorableUniformRandomProvider create(RandomSourceInternal source) {
  99.         // Delegate to the random source allowing generator specific implementations.
  100.         return source.create();
  101.     }

  102.     /**
  103.      * Creates a RNG instance.
  104.      *
  105.      * @param source RNG specification.
  106.      * @param seed Seed value.  It can be {@code null} (in which case a
  107.      * random value will be used).
  108.      * @param args Additional arguments to the implementation's constructor.
  109.      * @return a new RNG instance.
  110.      * @throws UnsupportedOperationException if the seed type is invalid.
  111.      * @throws IllegalArgumentException if argument data to initialize the
  112.      * generator implemented by the given {@code source} is invalid.
  113.      */
  114.     public static RestorableUniformRandomProvider create(RandomSourceInternal source,
  115.                                                          Object seed,
  116.                                                          Object[] args) {
  117.         // Delegate to the random source allowing generator specific implementations.
  118.         // This method checks arguments for null and calls the appropriate internal method.
  119.         if (args != null) {
  120.             return source.create(seed, args);
  121.         }
  122.         return seed == null ?
  123.                 source.create() :
  124.                 source.create(seed);
  125.     }

  126.     /**
  127.      * Identifiers of the generators.
  128.      */
  129.     public enum RandomSourceInternal {
  130.         /** Source of randomness is {@link JDKRandom}. */
  131.         JDK(JDKRandom.class,
  132.             1,
  133.             NativeSeedType.LONG),
  134.         /** Source of randomness is {@link Well512a}. */
  135.         WELL_512_A(Well512a.class,
  136.                    16, 0, 16,
  137.                    NativeSeedType.INT_ARRAY),
  138.         /** Source of randomness is {@link Well1024a}. */
  139.         WELL_1024_A(Well1024a.class,
  140.                     32, 0, 32,
  141.                     NativeSeedType.INT_ARRAY),
  142.         /** Source of randomness is {@link Well19937a}. */
  143.         WELL_19937_A(Well19937a.class,
  144.                      624, 0, 623,
  145.                      NativeSeedType.INT_ARRAY),
  146.         /** Source of randomness is {@link Well19937c}. */
  147.         WELL_19937_C(Well19937c.class,
  148.                      624, 0, 623,
  149.                      NativeSeedType.INT_ARRAY),
  150.         /** Source of randomness is {@link Well44497a}. */
  151.         WELL_44497_A(Well44497a.class,
  152.                      1391, 0, 1390,
  153.                      NativeSeedType.INT_ARRAY),
  154.         /** Source of randomness is {@link Well44497b}. */
  155.         WELL_44497_B(Well44497b.class,
  156.                      1391, 0, 1390,
  157.                      NativeSeedType.INT_ARRAY),
  158.         /** Source of randomness is {@link MersenneTwister}. */
  159.         MT(MersenneTwister.class,
  160.            624,
  161.            NativeSeedType.INT_ARRAY),
  162.         /** Source of randomness is {@link ISAACRandom}. */
  163.         ISAAC(ISAACRandom.class,
  164.               256,
  165.               NativeSeedType.INT_ARRAY),
  166.         /** Source of randomness is {@link SplitMix64}. */
  167.         SPLIT_MIX_64(SplitMix64.class,
  168.                      1,
  169.                      NativeSeedType.LONG),
  170.         /** Source of randomness is {@link XorShift1024Star}. */
  171.         XOR_SHIFT_1024_S(XorShift1024Star.class,
  172.                          16, 0, 16,
  173.                          NativeSeedType.LONG_ARRAY),
  174.         /** Source of randomness is {@link TwoCmres}. */
  175.         TWO_CMRES(TwoCmres.class,
  176.                   1,
  177.                   NativeSeedType.INT),
  178.         /**
  179.          * Source of randomness is {@link TwoCmres} with explicit selection
  180.          * of the two subcycle generators.
  181.          */
  182.         TWO_CMRES_SELECT(TwoCmres.class,
  183.                          1,
  184.                          NativeSeedType.INT,
  185.                          Integer.TYPE,
  186.                          Integer.TYPE),
  187.         /** Source of randomness is {@link MersenneTwister64}. */
  188.         MT_64(MersenneTwister64.class,
  189.               312,
  190.               NativeSeedType.LONG_ARRAY),
  191.         /** Source of randomness is {@link MultiplyWithCarry256}. */
  192.         MWC_256(MultiplyWithCarry256.class,
  193.                 257, 0, 257,
  194.                 NativeSeedType.INT_ARRAY),
  195.         /** Source of randomness is {@link KISSRandom}. */
  196.         KISS(KISSRandom.class,
  197.              // If zero in initial 3 positions the output is a simple LCG
  198.              4, 0, 3,
  199.              NativeSeedType.INT_ARRAY),
  200.         /** Source of randomness is {@link XorShift1024StarPhi}. */
  201.         XOR_SHIFT_1024_S_PHI(XorShift1024StarPhi.class,
  202.                              16, 0, 16,
  203.                              NativeSeedType.LONG_ARRAY),
  204.         /** Source of randomness is {@link XoRoShiRo64Star}. */
  205.         XO_RO_SHI_RO_64_S(XoRoShiRo64Star.class,
  206.                           2, 0, 2,
  207.                           NativeSeedType.INT_ARRAY),
  208.         /** Source of randomness is {@link XoRoShiRo64StarStar}. */
  209.         XO_RO_SHI_RO_64_SS(XoRoShiRo64StarStar.class,
  210.                            2, 0, 2,
  211.                            NativeSeedType.INT_ARRAY),
  212.         /** Source of randomness is {@link XoShiRo128Plus}. */
  213.         XO_SHI_RO_128_PLUS(XoShiRo128Plus.class,
  214.                            4, 0, 4,
  215.                            NativeSeedType.INT_ARRAY),
  216.         /** Source of randomness is {@link XoShiRo128StarStar}. */
  217.         XO_SHI_RO_128_SS(XoShiRo128StarStar.class,
  218.                          4, 0, 4,
  219.                          NativeSeedType.INT_ARRAY),
  220.         /** Source of randomness is {@link XoRoShiRo128Plus}. */
  221.         XO_RO_SHI_RO_128_PLUS(XoRoShiRo128Plus.class,
  222.                               2, 0, 2,
  223.                               NativeSeedType.LONG_ARRAY),
  224.         /** Source of randomness is {@link XoRoShiRo128StarStar}. */
  225.         XO_RO_SHI_RO_128_SS(XoRoShiRo128StarStar.class,
  226.                             2, 0, 2,
  227.                             NativeSeedType.LONG_ARRAY),
  228.         /** Source of randomness is {@link XoShiRo256Plus}. */
  229.         XO_SHI_RO_256_PLUS(XoShiRo256Plus.class,
  230.                            4, 0, 4,
  231.                            NativeSeedType.LONG_ARRAY),
  232.         /** Source of randomness is {@link XoShiRo256StarStar}. */
  233.         XO_SHI_RO_256_SS(XoShiRo256StarStar.class,
  234.                          4, 0, 4,
  235.                          NativeSeedType.LONG_ARRAY),
  236.         /** Source of randomness is {@link XoShiRo512Plus}. */
  237.         XO_SHI_RO_512_PLUS(XoShiRo512Plus.class,
  238.                            8, 0, 8,
  239.                            NativeSeedType.LONG_ARRAY),
  240.         /** Source of randomness is {@link XoShiRo512StarStar}. */
  241.         XO_SHI_RO_512_SS(XoShiRo512StarStar.class,
  242.                          8, 0, 8,
  243.                          NativeSeedType.LONG_ARRAY),
  244.         /** Source of randomness is {@link PcgXshRr32}. */
  245.         PCG_XSH_RR_32(PcgXshRr32.class,
  246.                 2,
  247.                 NativeSeedType.LONG_ARRAY),
  248.         /** Source of randomness is {@link PcgXshRs32}. */
  249.         PCG_XSH_RS_32(PcgXshRs32.class,
  250.                 2,
  251.                 NativeSeedType.LONG_ARRAY),
  252.         /** Source of randomness is {@link PcgRxsMXs64}. */
  253.         PCG_RXS_M_XS_64(PcgRxsMXs64.class,
  254.                 2,
  255.                 NativeSeedType.LONG_ARRAY),
  256.         /** Source of randomness is {@link PcgMcgXshRr32}. */
  257.         PCG_MCG_XSH_RR_32(PcgMcgXshRr32.class,
  258.                 1,
  259.                 NativeSeedType.LONG),
  260.         /** Source of randomness is {@link PcgMcgXshRs32}. */
  261.         PCG_MCG_XSH_RS_32(PcgMcgXshRs32.class,
  262.                 1,
  263.                 NativeSeedType.LONG),
  264.         /** Source of randomness is {@link MiddleSquareWeylSequence}. */
  265.         MSWS(MiddleSquareWeylSequence.class,
  266.              // Many partially zero seeds can create low quality initial output.
  267.              // The Weyl increment cascades bits into the random state so ideally it
  268.              // has a high number of bit transitions. Minimally ensure it is non-zero.
  269.              3, 2, 3,
  270.              NativeSeedType.LONG_ARRAY) {
  271.             @Override
  272.             protected Object createSeed() {
  273.                 return createMswsSeed(SeedFactory.createLong());
  274.             }

  275.             @Override
  276.             protected Object convertSeed(Object seed) {
  277.                 // Allow seeding with primitives to generate a good seed
  278.                 if (seed instanceof Integer) {
  279.                     return createMswsSeed((Integer) seed);
  280.                 } else if (seed instanceof Long) {
  281.                     return createMswsSeed((Long) seed);
  282.                 }
  283.                 // Other types (e.g. the native long[]) are handled by the default conversion
  284.                 return super.convertSeed(seed);
  285.             }

  286.             @Override
  287.             protected byte[] createByteArraySeed(UniformRandomProvider source) {
  288.                 // The seed requires approximately 4-6 calls to nextInt().
  289.                 // Wrap the input and switch to a default if the input is faulty.
  290.                 final UniformRandomProvider wrapped = new IntProvider() {
  291.                     /** The number of remaining calls to the source generator. */
  292.                     private int calls = 100;
  293.                     /** Default generator, initialised when required. */
  294.                     private UniformRandomProvider defaultGen;
  295.                     @Override
  296.                     public int next() {
  297.                         if (calls == 0) {
  298.                             // The input source is broken.
  299.                             // Seed a default
  300.                             if (defaultGen == null) {
  301.                                 defaultGen = new SplitMix64(source.nextLong());
  302.                             }
  303.                             return defaultGen.nextInt();
  304.                         }
  305.                         calls--;
  306.                         return source.nextInt();
  307.                     }
  308.                     @Override
  309.                     public long nextLong() {
  310.                         // No specific requirements so always use the source
  311.                         return source.nextLong();
  312.                     }
  313.                 };
  314.                 return NativeSeedType.convertSeedToBytes(createMswsSeed(wrapped));
  315.             }

  316.             /**
  317.              * Creates the full length seed array from the input seed.
  318.              *
  319.              * @param seed the seed
  320.              * @return the seed array
  321.              */
  322.             private long[] createMswsSeed(long seed) {
  323.                 return createMswsSeed(new SplitMix64(seed));
  324.             }

  325.             /**
  326.              * Creates the full length seed array from the input seed using the method
  327.              * recommended for the generator. This is a high quality Weyl increment composed
  328.              * of a hex character permutation.
  329.              *
  330.              * @param source Source of randomness.
  331.              * @return the seed array
  332.              */
  333.             private long[] createMswsSeed(UniformRandomProvider source) {
  334.                 final long increment = SeedUtils.createLongHexPermutation(source);
  335.                 // The initial state should not be low complexity but the Weyl
  336.                 // state can be any number.
  337.                 final long state = increment;
  338.                 final long weylState = source.nextLong();
  339.                 return new long[] {state, weylState, increment};
  340.             }
  341.         },
  342.         /** Source of randomness is {@link DotyHumphreySmallFastCounting32}. */
  343.         SFC_32(DotyHumphreySmallFastCounting32.class,
  344.                3,
  345.                NativeSeedType.INT_ARRAY),
  346.         /** Source of randomness is {@link DotyHumphreySmallFastCounting64}. */
  347.         SFC_64(DotyHumphreySmallFastCounting64.class,
  348.                3,
  349.                NativeSeedType.LONG_ARRAY),
  350.         /** Source of randomness is {@link JenkinsSmallFast32}. */
  351.         JSF_32(JenkinsSmallFast32.class,
  352.                1,
  353.                NativeSeedType.INT),
  354.         /** Source of randomness is {@link JenkinsSmallFast64}. */
  355.         JSF_64(JenkinsSmallFast64.class,
  356.                1,
  357.                NativeSeedType.LONG),
  358.         /** Source of randomness is {@link XoShiRo128PlusPlus}. */
  359.         XO_SHI_RO_128_PP(XoShiRo128PlusPlus.class,
  360.                          4, 0, 4,
  361.                          NativeSeedType.INT_ARRAY),
  362.         /** Source of randomness is {@link XoRoShiRo128PlusPlus}. */
  363.         XO_RO_SHI_RO_128_PP(XoRoShiRo128PlusPlus.class,
  364.                             2, 0, 2,
  365.                             NativeSeedType.LONG_ARRAY),
  366.         /** Source of randomness is {@link XoShiRo256PlusPlus}. */
  367.         XO_SHI_RO_256_PP(XoShiRo256PlusPlus.class,
  368.                          4, 0, 4,
  369.                          NativeSeedType.LONG_ARRAY),
  370.         /** Source of randomness is {@link XoShiRo512PlusPlus}. */
  371.         XO_SHI_RO_512_PP(XoShiRo512PlusPlus.class,
  372.                          8, 0, 8,
  373.                          NativeSeedType.LONG_ARRAY),
  374.         /** Source of randomness is {@link XoRoShiRo1024PlusPlus}. */
  375.         XO_RO_SHI_RO_1024_PP(XoRoShiRo1024PlusPlus.class,
  376.                              16, 0, 16,
  377.                              NativeSeedType.LONG_ARRAY),
  378.         /** Source of randomness is {@link XoRoShiRo1024Star}. */
  379.         XO_RO_SHI_RO_1024_S(XoRoShiRo1024Star.class,
  380.                             16, 0, 16,
  381.                             NativeSeedType.LONG_ARRAY),
  382.         /** Source of randomness is {@link XoRoShiRo1024StarStar}. */
  383.         XO_RO_SHI_RO_1024_SS(XoRoShiRo1024StarStar.class,
  384.                              16, 0, 16,
  385.                              NativeSeedType.LONG_ARRAY),
  386.         /** Source of randomness is {@link PcgXshRr32}. */
  387.         PCG_XSH_RR_32_OS(PcgXshRr32.class,
  388.                 1,
  389.                 NativeSeedType.LONG),
  390.         /** Source of randomness is {@link PcgXshRs32}. */
  391.         PCG_XSH_RS_32_OS(PcgXshRs32.class,
  392.                 1,
  393.                 NativeSeedType.LONG),
  394.         /** Source of randomness is {@link PcgRxsMXs64}. */
  395.         PCG_RXS_M_XS_64_OS(PcgRxsMXs64.class,
  396.                 1,
  397.                 NativeSeedType.LONG),
  398.         /** Source of randomness is {@link L64X128StarStar}. */
  399.         L64_X128_SS(L64X128StarStar.class,
  400.                 4, 2, 4,
  401.                 NativeSeedType.LONG_ARRAY),
  402.         /** Source of randomness is {@link L64X128Mix}. */
  403.         L64_X128_MIX(L64X128Mix.class,
  404.                 4, 2, 4,
  405.                 NativeSeedType.LONG_ARRAY),
  406.         /** Source of randomness is {@link L64X256Mix}. */
  407.         L64_X256_MIX(L64X256Mix.class,
  408.                 6, 2, 6,
  409.                 NativeSeedType.LONG_ARRAY),
  410.         /** Source of randomness is {@link L64X1024Mix}. */
  411.         L64_X1024_MIX(L64X1024Mix.class,
  412.                 18, 2, 18,
  413.                 NativeSeedType.LONG_ARRAY),
  414.         /** Source of randomness is {@link L128X128Mix}. */
  415.         L128_X128_MIX(L128X128Mix.class,
  416.                 6, 4, 6,
  417.                 NativeSeedType.LONG_ARRAY),
  418.         /** Source of randomness is {@link L128X256Mix}. */
  419.         L128_X256_MIX(L128X256Mix.class,
  420.                 8, 4, 8,
  421.                 NativeSeedType.LONG_ARRAY),
  422.         /** Source of randomness is {@link L128X1024Mix}. */
  423.         L128_X1024_MIX(L128X1024Mix.class,
  424.                 20, 4, 20,
  425.                 NativeSeedType.LONG_ARRAY),
  426.         /** Source of randomness is {@link L32X64Mix}. */
  427.         L32_X64_MIX(L32X64Mix.class,
  428.                 4, 2, 4,
  429.                 NativeSeedType.INT_ARRAY);

  430.         /** Source type. */
  431.         private final Class<? extends UniformRandomProvider> rng;
  432.         /** Native seed size. Used for array seeds. */
  433.         private final int nativeSeedSize;
  434.         /** Start of the not all-zero sub-range for array seeds (inclusive). */
  435.         private final int notAllZeroFrom;
  436.         /** End of the not all-zero sub-range for array seeds (exclusive). */
  437.         private final int notAllZeroTo;
  438.         /** Define the parameter types of the data needed to build the generator. */
  439.         private final Class<?>[] args;
  440.         /** Native seed type. Used to create a seed or convert input seeds. */
  441.         private final NativeSeedType nativeSeedType;
  442.         /**
  443.          * The constructor.
  444.          * This is discovered using the constructor parameter types and stored for re-use.
  445.          */
  446.         private transient Constructor<?> rngConstructor;

  447.         /**
  448.          * Create a new instance.
  449.          *
  450.          * <p>Used when the seed array has no requirement for a not all-zero sub-range.
  451.          *
  452.          * @param rng Source type.
  453.          * @param nativeSeedSize Native seed size (array types only).
  454.          * @param nativeSeedType Native seed type.
  455.          * @param args Additional data needed to create a generator instance.
  456.          */
  457.         RandomSourceInternal(Class<? extends UniformRandomProvider> rng,
  458.                              int nativeSeedSize,
  459.                              NativeSeedType nativeSeedType,
  460.                              Class<?>... args) {
  461.             this(rng, nativeSeedSize, 0, 0, nativeSeedType, args);
  462.         }

  463.         /**
  464.          * Create a new instance.
  465.          *
  466.          * <p>Note: The sub-range of an array seed that is not all-zero can be specified.
  467.          * If the native seed array is used to represent a number of bits
  468.          * that is not an exact multiple of the number of bytes in the seed, then a
  469.          * safe approach is to specify the sub-range using a smaller size than the
  470.          * full length seed. For example a {@link Well19937a} generator uses 19937
  471.          * bits and has a seed bit length of 19968. A safe range is [0, 19937 / 32).
  472.          *
  473.          * @param rng Source type.
  474.          * @param nativeSeedSize Native seed size (array types only).
  475.          * @param notAllZeroFrom The start of the not all-zero sub-range (inclusive).
  476.          * @param notAllZeroTo The end of the not all-zero sub-range (exclusive).
  477.          * @param nativeSeedType Native seed type.
  478.          * @param args Additional data needed to create a generator instance.
  479.          */
  480.         RandomSourceInternal(Class<? extends UniformRandomProvider> rng,
  481.                              int nativeSeedSize,
  482.                              int notAllZeroFrom,
  483.                              int notAllZeroTo,
  484.                              NativeSeedType nativeSeedType,
  485.                              Class<?>... args) {
  486.             this.rng = rng;
  487.             this.nativeSeedSize = nativeSeedSize;
  488.             this.notAllZeroFrom = notAllZeroFrom;
  489.             this.notAllZeroTo = notAllZeroTo;
  490.             this.nativeSeedType = nativeSeedType;
  491.             // Build the complete list of class types for the constructor
  492.             this.args = (Class<?>[]) Array.newInstance(args.getClass().getComponentType(), 1 + args.length);
  493.             this.args[0] = nativeSeedType.getType();
  494.             System.arraycopy(args, 0, this.args, 1, args.length);
  495.         }

  496.         /**
  497.          * Gets the implementing class of the random source.
  498.          *
  499.          * @return the random source class.
  500.          */
  501.         public Class<?> getRng() {
  502.             return rng;
  503.         }

  504.         /**
  505.          * Gets the class of the native seed.
  506.          *
  507.          * @return the seed class.
  508.          */
  509.         Class<?> getSeed() {
  510.             return args[0];
  511.         }

  512.         /**
  513.          * Gets the parameter types of the data needed to build the generator.
  514.          *
  515.          * @return the data needed to build the generator.
  516.          */
  517.         Class<?>[] getArgs() {
  518.             return args;
  519.         }

  520.         /**
  521.          * Checks whether the type of given {@code seed} is the native type
  522.          * of the implementation.
  523.          *
  524.          * @param <SEED> Seed type.
  525.          *
  526.          * @param seed Seed value.
  527.          * @return {@code true} if the seed can be passed to the builder
  528.          * for this RNG type.
  529.          */
  530.         public <SEED> boolean isNativeSeed(SEED seed) {
  531.             return seed != null && getSeed().equals(seed.getClass());
  532.         }

  533.         /**
  534.          * Creates a RNG instance.
  535.          *
  536.          * <p>This method can be over-ridden to allow fast construction of a generator
  537.          * with low seeding cost that has no additional constructor arguments.</p>
  538.          *
  539.          * @return a new RNG instance.
  540.          */
  541.         RestorableUniformRandomProvider create() {
  542.             // Create a seed.
  543.             final Object nativeSeed = createSeed();
  544.             // Instantiate.
  545.             return create(getConstructor(), new Object[] {nativeSeed});
  546.         }

  547.         /**
  548.          * Creates a RNG instance. It is assumed the seed is not {@code null}.
  549.          *
  550.          * <p>This method can be over-ridden to allow fast construction of a generator
  551.          * with low seed conversion cost that has no additional constructor arguments.</p>
  552.          *
  553.          * @param seed Seed value. It must not be {@code null}.
  554.          * @return a new RNG instance.
  555.          * @throws UnsupportedOperationException if the seed type is invalid.
  556.          */
  557.         RestorableUniformRandomProvider create(Object seed) {
  558.             // Convert seed to native type.
  559.             final Object nativeSeed = convertSeed(seed);
  560.             // Instantiate.
  561.             return create(getConstructor(), new Object[] {nativeSeed});
  562.         }

  563.         /**
  564.          * Creates a RNG instance. This constructs a RNG using reflection and will error
  565.          * if the constructor arguments do not match those required by the RNG's constructor.
  566.          *
  567.          * @param seed Seed value. It can be {@code null} (in which case a suitable
  568.          * seed will be generated).
  569.          * @param constructorArgs Additional arguments to the implementation's constructor.
  570.          * It must not be {@code null}.
  571.          * @return a new RNG instance.
  572.          * @throws UnsupportedOperationException if the seed type is invalid.
  573.          */
  574.         RestorableUniformRandomProvider create(Object seed,
  575.                                                Object[] constructorArgs) {
  576.             final Object nativeSeed = createNativeSeed(seed);

  577.             // Build a single array with all the arguments to be passed
  578.             // (in the right order) to the constructor.
  579.             final Object[] all = new Object[constructorArgs.length + 1];
  580.             all[0] = nativeSeed;
  581.             System.arraycopy(constructorArgs, 0, all, 1, constructorArgs.length);

  582.             // Instantiate.
  583.             return create(getConstructor(), all);
  584.         }

  585.         /**
  586.          * Creates a native seed.
  587.          *
  588.          * <p>The default implementation creates a seed of the native type and, for array seeds,
  589.          * ensures not all bits are zero.</p>
  590.          *
  591.          * <p>This method should be over-ridden to satisfy seed requirements for the generator.</p>
  592.          *
  593.          * @return the native seed
  594.          * @since 1.3
  595.          */
  596.         protected Object createSeed() {
  597.             // Ensure the seed is not all-zero in the sub-range
  598.             return nativeSeedType.createSeed(nativeSeedSize, notAllZeroFrom, notAllZeroTo);
  599.         }

  600.         /**
  601.          * Creates a {@code byte[]} seed using the provided source of randomness.
  602.          *
  603.          * <p>The default implementation creates a full-length seed and ensures not all bits
  604.          * are zero.</p>
  605.          *
  606.          * <p>This method should be over-ridden to satisfy seed requirements for the generator.</p>
  607.          *
  608.          * @param source Source of randomness.
  609.          * @return the byte[] seed
  610.          * @since 1.3
  611.          */
  612.         protected byte[] createByteArraySeed(UniformRandomProvider source) {
  613.             // Ensure the seed is not all-zero in the sub-range.
  614.             // Note: Convert the native seed array size/positions to byte size/positions.
  615.             final int bytes = nativeSeedType.getBytes();
  616.             return SeedFactory.createByteArray(source,
  617.                 bytes * nativeSeedSize,
  618.                 bytes * notAllZeroFrom,
  619.                 bytes * notAllZeroTo);
  620.         }

  621.         /**
  622.          * Converts a seed from any of the supported seed types to a native seed.
  623.          *
  624.          * <p>The default implementation delegates to the native seed type conversion.</p>
  625.          *
  626.          * <p>This method should be over-ridden to satisfy seed requirements for the generator.</p>
  627.          *
  628.          * @param seed Input seed (must not be null).
  629.          * @return the native seed
  630.          * @throws UnsupportedOperationException if the {@code seed} type is invalid.
  631.          * @since 1.3
  632.          */
  633.         protected Object convertSeed(Object seed) {
  634.             return nativeSeedType.convertSeed(seed, nativeSeedSize);
  635.         }

  636.         /**
  637.          * Creates a native seed from any of the supported seed types.
  638.          *
  639.          * @param seed Input seed (may be null).
  640.          * @return the native seed.
  641.          * @throws UnsupportedOperationException if the {@code seed} type cannot be converted.
  642.          */
  643.         private Object createNativeSeed(Object seed) {
  644.             return seed == null ?
  645.                 createSeed() :
  646.                 convertSeed(seed);
  647.         }

  648.         /**
  649.          * Creates a seed suitable for the implementing class represented by this random source.
  650.          *
  651.          * <p>It will satisfy the seed size and any other seed requirements for the
  652.          * implementing class. The seed is converted from the native type to bytes.</p>
  653.          *
  654.          * @return the seed bytes
  655.          * @since 1.3
  656.          */
  657.         public final byte[] createSeedBytes() {
  658.             // Custom implementations can override createSeed
  659.             final Object seed = createSeed();
  660.             return NativeSeedType.convertSeedToBytes(seed);
  661.         }

  662.         /**
  663.          * Creates a seed suitable for the implementing class represented by this random source
  664.          * using the supplied source of randomness.
  665.          *
  666.          * <p>It will satisfy the seed size and any other seed requirements for the
  667.          * implementing class. The seed is converted from the native type to bytes.</p>
  668.          *
  669.          * @param source Source of randomness.
  670.          * @return the seed bytes
  671.          * @since 1.3
  672.          */
  673.         public final byte[] createSeedBytes(UniformRandomProvider source) {
  674.             // Custom implementations can override createByteArraySeed
  675.             return createByteArraySeed(source);
  676.         }

  677.         /**
  678.          * Gets the constructor.
  679.          *
  680.          * @return the RNG constructor.
  681.          */
  682.         private Constructor<?> getConstructor() {
  683.             // The constructor never changes so it is stored for re-use.
  684.             Constructor<?> constructor = rngConstructor;
  685.             if (constructor == null) {
  686.                 // If null this is either the first attempt to find it or
  687.                 // look-up previously failed and this method will throw
  688.                 // upon each invocation.
  689.                 constructor = createConstructor();
  690.                 rngConstructor = constructor;
  691.             }
  692.             return constructor;
  693.         }

  694.         /**
  695.          * Creates a constructor.
  696.          *
  697.          * @return a RNG constructor.
  698.          */
  699.         private Constructor<?> createConstructor() {
  700.             try {
  701.                 return getRng().getConstructor(getArgs());
  702.             } catch (NoSuchMethodException e) {
  703.                 // Info in "RandomSourceInternal" is inconsistent with the
  704.                 // constructor of the implementation.
  705.                 throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
  706.             }
  707.         }

  708.         /**
  709.          * Creates a RNG.
  710.          *
  711.          * @param rng RNG specification.
  712.          * @param args Arguments to the implementation's constructor.
  713.          * @return a new RNG instance.
  714.          */
  715.         private static RestorableUniformRandomProvider create(Constructor<?> rng,
  716.                                                               Object[] args) {
  717.             try {
  718.                 return (RestorableUniformRandomProvider) rng.newInstance(args);
  719.             } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
  720.                 throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
  721.             }
  722.         }
  723.     }
  724. }