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 org.apache.commons.rng.core.util.NumberFactory;
20  import org.apache.commons.rng.core.source32.RandomIntSource;
21  import org.apache.commons.rng.core.source32.Well44497b;
22  import org.apache.commons.rng.core.source64.RandomLongSource;
23  import org.apache.commons.rng.core.source64.SplitMix64;
24  
25  /**
26   * Utilities related to seeding.
27   *
28   * <p>
29   * This class provides methods to generate random seeds (single values
30   * or arrays of values, of {@code int} or {@code long} types) that can
31   * be passed to the {@link org.apache.commons.rng.simple.RandomSource
32   * methods that create a generator instance}.
33   * <br>
34   * Although the seed-generating methods defined in this class will likely
35   * return different values for all calls, there is no guarantee that the
36   * produced seed will result always in a "good" sequence of numbers (even
37   * if the generator initialized with that seed is good).
38   * <br>
39   * There is <i>no guarantee</i> that sequences will not overlap.
40   * </p>
41   *
42   * @since 1.0
43   */
44  public final class SeedFactory {
45      /** Generator with a long period. */
46      private static final RandomIntSource SEED_GENERATOR;
47  
48      static {
49          // Another RNG for initializing the "SEED_GENERATOR".
50          final long t = System.currentTimeMillis();
51          final int h = System.identityHashCode(Runtime.getRuntime());
52          final SplitMix64 rng = new SplitMix64(t ^ NumberFactory.makeLong(h, ~h));
53  
54          final int blockCount = 1391; // Size of the state array of "Well44497b".
55          SEED_GENERATOR = new Well44497b(createIntArray(blockCount, rng));
56      }
57  
58      /**
59       * Class contains only static methods.
60       */
61      private SeedFactory() {}
62  
63      /**
64       * Creates a number for use as a seed.
65       *
66       * @return a random number.
67       */
68      public static int createInt() {
69          return createInt(SEED_GENERATOR, System.identityHashCode(new Object()));
70      }
71  
72      /**
73       * Creates a number for use as a seed.
74       *
75       * @return a random number.
76       */
77      public static long createLong() {
78          return createLong(SEED_GENERATOR, System.identityHashCode(new Object()));
79      }
80  
81      /**
82       * Creates an array of numbers for use as a seed.
83       *
84       * @param n Size of the array to create.
85       * @return an array of {@code n} random numbers.
86       */
87      public static int[] createIntArray(int n) {
88          return createIntArray(n, SEED_GENERATOR, new Object());
89      }
90  
91      /**
92       * Creates an array of numbers for use as a seed.
93       *
94       * @param n Size of the array to create.
95       * @return an array of {@code n} random numbers.
96       */
97      public static long[] createLongArray(int n) {
98          return createLongArray(n, SEED_GENERATOR, new Object());
99      }
100 
101     /**
102      * Creates an array of numbers for use as a seed.
103      *
104      * @param n Size of the array to create.
105      * @param source Source of randomness.
106      * @return an array of {@code n} random numbers drawn from the
107      * {@code source}.
108      */
109     static long[] createLongArray(int n,
110                                   RandomIntSource source) {
111         return createLongArray(n, source, null);
112     }
113 
114     /**
115      * Creates an array of numbers for use as a seed.
116      *
117      * @param n Size of the array to create.
118      * @param source Source of randomness.
119      * @return an array of {@code n} random numbers drawn from the
120      * {@code source}.
121      */
122     static int[] createIntArray(int n,
123                                 RandomLongSource source) {
124         return createIntArray(n, source, null);
125     }
126 
127     /**
128      * Creates an array of numbers for use as a seed.
129      *
130      * @param n Size of the array to create.
131      * @param source Source of randomness.
132      * @return an array of {@code n} random numbers drawn from the
133      * {@code source}.
134      */
135     static int[] createIntArray(int n,
136                                 RandomIntSource source) {
137         return createIntArray(n, source, null);
138     }
139 
140     /**
141      * Creates an array of numbers for use as a seed.
142      *
143      * @param n Size of the array to create.
144      * @param source Source of randomness.
145      * @param h Arbitrary object whose {@link System#identityHashCode(Object)
146      * hash code} will be combined with the next number drawn from
147      * the {@code source}.
148      * @return an array of {@code n} random numbers.
149      */
150     private static long[] createLongArray(int n,
151                                           RandomIntSource source,
152                                           Object h) {
153         final long[] array = new long[n];
154 
155         final int hash = System.identityHashCode(h);
156         for (int i = 0; i < n; i++) {
157             array[i] = createLong(source, hash);
158         }
159 
160         return array;
161     }
162 
163     /**
164      * Creates an array of numbers for use as a seed.
165      *
166      * @param n Size of the array to create.
167      * @param source Source of randomness.
168      * @param h Arbitrary object whose {@link System#identityHashCode(Object)
169      * hash code} will be combined with the next number drawn from
170      * the {@code source}.
171      * @return an array of {@code n} random numbers.
172      */
173     private static int[] createIntArray(int n,
174                                         RandomLongSource source,
175                                         Object h) {
176         final int[] array = new int[n];
177 
178         final int hash = System.identityHashCode(h);
179         for (int i = 0; i < n; i += 2) {
180             final long v = createLong(source, hash);
181 
182             array[i] = NumberFactory.extractHi(v);
183 
184             if (i + 1 < n) {
185                 array[i + 1] = NumberFactory.extractLo(v);
186             }
187         }
188 
189         return array;
190     }
191 
192     /**
193      * Creates an array of numbers for use as a seed.
194      *
195      * @param n Size of the array to create.
196      * @param source Source of randomness.
197      * @param h Arbitrary object whose {@link System#identityHashCode(Object)
198      * hash code} will be combined with the next number drawn from
199      * the {@code source}.
200      * @return an array of {@code n} random numbers.
201      */
202     private static int[] createIntArray(int n,
203                                         RandomIntSource source,
204                                         Object h) {
205         final int[] array = new int[n];
206 
207         final int hash = System.identityHashCode(h);
208         for (int i = 0; i < n; i++) {
209             array[i] = createInt(source, hash);
210         }
211 
212         return array;
213     }
214 
215     /**
216      * Creates a random number by performing an "xor" between the
217      * next value in the sequence of the {@code source} and the
218      * given {@code number}.
219      *
220      * @param source Source of randomness.
221      * @param number Arbitrary number.
222      * @return a random number.
223      */
224     private static long createLong(RandomLongSource source,
225                                    int number) {
226         synchronized (source) {
227             return source.next() ^ NumberFactory.makeLong(number, number);
228         }
229     }
230 
231     /**
232      * Creates a random number by performing an "xor" between the
233      * the next value in the sequence of the {@code source} and the
234      * given {@code number}.
235      *
236      * @param source Source of randomness.
237      * @param number Arbitrary number.
238      * @return a random number.
239      */
240     private static long createLong(RandomIntSource source,
241                                    int number) {
242         synchronized (source) {
243             return NumberFactory.makeLong(source.next() ^ number,
244                                           source.next() ^ number);
245         }
246     }
247 
248     /**
249      * Creates a random number by performing an "xor" between the
250      * next value in the sequence of the {@code source} and the
251      * given {@code number}.
252      *
253      * @param source Source of randomness.
254      * @param number Arbitrary number.
255      * @return a random number.
256      */
257     private static int createInt(RandomIntSource source,
258                                  int number) {
259         synchronized (source) {
260             return source.next() ^ number;
261         }
262     }
263 }