View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.rng.simple.internal;
18  
19  import java.security.SecureRandom;
20  import org.apache.commons.rng.core.util.NumberFactory;
21  import org.apache.commons.rng.core.source32.RandomIntSource;
22  import org.apache.commons.rng.core.source32.Well44497b;
23  import org.apache.commons.rng.core.source64.RandomLongSource;
24  import org.apache.commons.rng.core.source64.SplitMix64;
25  
26  /**
27   * Utilities related to seeding.
28   *
29   * <p>
30   * This class provides methods to generate random seeds (single values
31   * or arrays of values, of {@code int} or {@code long} types) that can
32   * be passed to the {@link org.apache.commons.rng.simple.RandomSource
33   * methods that create a generator instance}.
34   * <br>
35   * Although the seed-generating methods defined in this class will likely
36   * return different values for all calls, there is no guarantee that the
37   * produced seed will result always in a "good" sequence of numbers (even
38   * if the generator initialized with that seed is good).
39   * <br>
40   * There is <i>no guarantee</i> that sequences will not overlap.
41   * </p>
42   *
43   * @since 1.0
44   */
45  public final class SeedFactory {
46      /** Generator with a long period. */
47      private static final RandomIntSource SEED_GENERATOR;
48  
49      static {
50          // Use a secure RNG so that different instances (e.g. in multiple JVM
51          // instances started in rapid succession) will have different seeds.
52          final SecureRandom seedGen = new SecureRandom();
53          final long initSeed = NumberFactory.makeLong(seedGen.generateSeed(8));
54          final SplitMix64 rng = new SplitMix64(initSeed);
55  
56          final int blockCount = 1391; // Size of the state array of "Well44497b".
57          SEED_GENERATOR = new Well44497b(createIntArray(blockCount, rng));
58      }
59  
60      /**
61       * Class contains only static methods.
62       */
63      private SeedFactory() {}
64  
65      /**
66       * Creates a number for use as a seed.
67       *
68       * @return a random number.
69       */
70      public static int createInt() {
71          return createInt(SEED_GENERATOR, System.identityHashCode(new Object()));
72      }
73  
74      /**
75       * Creates a number for use as a seed.
76       *
77       * @return a random number.
78       */
79      public static long createLong() {
80          return createLong(SEED_GENERATOR, System.identityHashCode(new Object()));
81      }
82  
83      /**
84       * Creates an array of numbers for use as a seed.
85       *
86       * @param n Size of the array to create.
87       * @return an array of {@code n} random numbers.
88       */
89      public static int[] createIntArray(int n) {
90          return createIntArray(n, SEED_GENERATOR, new Object());
91      }
92  
93      /**
94       * Creates an array of numbers for use as a seed.
95       *
96       * @param n Size of the array to create.
97       * @return an array of {@code n} random numbers.
98       */
99      public static long[] createLongArray(int n) {
100         return createLongArray(n, SEED_GENERATOR, new Object());
101     }
102 
103     /**
104      * Creates an array of numbers for use as a seed.
105      *
106      * @param n Size of the array to create.
107      * @param source Source of randomness.
108      * @return an array of {@code n} random numbers drawn from the
109      * {@code source}.
110      */
111     static long[] createLongArray(int n,
112                                   RandomIntSource source) {
113         return createLongArray(n, source, null);
114     }
115 
116     /**
117      * Creates an array of numbers for use as a seed.
118      *
119      * @param n Size of the array to create.
120      * @param source Source of randomness.
121      * @return an array of {@code n} random numbers drawn from the
122      * {@code source}.
123      */
124     static int[] createIntArray(int n,
125                                 RandomLongSource source) {
126         return createIntArray(n, source, null);
127     }
128 
129     /**
130      * Creates an array of numbers for use as a seed.
131      *
132      * @param n Size of the array to create.
133      * @param source Source of randomness.
134      * @return an array of {@code n} random numbers drawn from the
135      * {@code source}.
136      */
137     static int[] createIntArray(int n,
138                                 RandomIntSource source) {
139         return createIntArray(n, source, null);
140     }
141 
142     /**
143      * Creates an array of numbers for use as a seed.
144      *
145      * @param n Size of the array to create.
146      * @param source Source of randomness.
147      * @param h Arbitrary object whose {@link System#identityHashCode(Object)
148      * hash code} will be combined with the next number drawn from
149      * the {@code source}.
150      * @return an array of {@code n} random numbers.
151      */
152     private static long[] createLongArray(int n,
153                                           RandomIntSource source,
154                                           Object h) {
155         final long[] array = new long[n];
156 
157         final int hash = System.identityHashCode(h);
158         for (int i = 0; i < n; i++) {
159             array[i] = createLong(source, hash);
160         }
161 
162         return array;
163     }
164 
165     /**
166      * Creates an array of numbers for use as a seed.
167      *
168      * @param n Size of the array to create.
169      * @param source Source of randomness.
170      * @param h Arbitrary object whose {@link System#identityHashCode(Object)
171      * hash code} will be combined with the next number drawn from
172      * the {@code source}.
173      * @return an array of {@code n} random numbers.
174      */
175     private static int[] createIntArray(int n,
176                                         RandomLongSource source,
177                                         Object h) {
178         final int[] array = new int[n];
179 
180         final int hash = System.identityHashCode(h);
181         for (int i = 0; i < n; i += 2) {
182             final long v = createLong(source, hash);
183 
184             array[i] = NumberFactory.extractHi(v);
185 
186             if (i + 1 < n) {
187                 array[i + 1] = NumberFactory.extractLo(v);
188             }
189         }
190 
191         return array;
192     }
193 
194     /**
195      * Creates an array of numbers for use as a seed.
196      *
197      * @param n Size of the array to create.
198      * @param source Source of randomness.
199      * @param h Arbitrary object whose {@link System#identityHashCode(Object)
200      * hash code} will be combined with the next number drawn from
201      * the {@code source}.
202      * @return an array of {@code n} random numbers.
203      */
204     private static int[] createIntArray(int n,
205                                         RandomIntSource source,
206                                         Object h) {
207         final int[] array = new int[n];
208 
209         final int hash = System.identityHashCode(h);
210         for (int i = 0; i < n; i++) {
211             array[i] = createInt(source, hash);
212         }
213 
214         return array;
215     }
216 
217     /**
218      * Creates a random number by performing an "xor" between the
219      * next value in the sequence of the {@code source} and the
220      * given {@code number}.
221      *
222      * @param source Source of randomness.
223      * @param number Arbitrary number.
224      * @return a random number.
225      */
226     private static long createLong(RandomLongSource source,
227                                    int number) {
228         synchronized (source) {
229             return source.next() ^ NumberFactory.makeLong(number, number);
230         }
231     }
232 
233     /**
234      * Creates a random number by performing an "xor" between the
235      * the next value in the sequence of the {@code source} and the
236      * given {@code number}.
237      *
238      * @param source Source of randomness.
239      * @param number Arbitrary number.
240      * @return a random number.
241      */
242     private static long createLong(RandomIntSource source,
243                                    int number) {
244         synchronized (source) {
245             return NumberFactory.makeLong(source.next() ^ number,
246                                           source.next() ^ number);
247         }
248     }
249 
250     /**
251      * Creates a random number by performing an "xor" between the
252      * next value in the sequence of the {@code source} and the
253      * given {@code number}.
254      *
255      * @param source Source of randomness.
256      * @param number Arbitrary number.
257      * @return a random number.
258      */
259     private static int createInt(RandomIntSource source,
260                                  int number) {
261         synchronized (source) {
262             return source.next() ^ number;
263         }
264     }
265 }