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 org.apache.commons.rng.core.util.NumberFactory;
020import org.apache.commons.rng.core.source32.RandomIntSource;
021import org.apache.commons.rng.core.source32.Well44497b;
022import org.apache.commons.rng.core.source64.RandomLongSource;
023import org.apache.commons.rng.core.source64.SplitMix64;
024
025/**
026 * Utilities related to seeding.
027 *
028 * <p>
029 * This class provides methods to generate random seeds (single values
030 * or arrays of values, of {@code int} or {@code long} types) that can
031 * be passed to the {@link org.apache.commons.rng.simple.RandomSource
032 * methods that create a generator instance}.
033 * <br>
034 * Although the seed-generating methods defined in this class will likely
035 * return different values for all calls, there is no guarantee that the
036 * produced seed will result always in a "good" sequence of numbers (even
037 * if the generator initialized with that seed is good).
038 * <br>
039 * There is <i>no guarantee</i> that sequences will not overlap.
040 * </p>
041 *
042 * @since 1.0
043 */
044public final class SeedFactory {
045    /** Generator with a long period. */
046    private static final RandomIntSource SEED_GENERATOR;
047
048    static {
049        // Another RNG for initializing the "SEED_GENERATOR".
050        final long t = System.currentTimeMillis();
051        final int h = System.identityHashCode(Runtime.getRuntime());
052        final SplitMix64 rng = new SplitMix64(t ^ NumberFactory.makeLong(h, ~h));
053
054        final int blockCount = 1391; // Size of the state array of "Well44497b".
055        SEED_GENERATOR = new Well44497b(createIntArray(blockCount, rng));
056    }
057
058    /**
059     * Class contains only static methods.
060     */
061    private SeedFactory() {}
062
063    /**
064     * Creates a number for use as a seed.
065     *
066     * @return a random number.
067     */
068    public static int createInt() {
069        return createInt(SEED_GENERATOR, System.identityHashCode(new Object()));
070    }
071
072    /**
073     * Creates a number for use as a seed.
074     *
075     * @return a random number.
076     */
077    public static long createLong() {
078        return createLong(SEED_GENERATOR, System.identityHashCode(new Object()));
079    }
080
081    /**
082     * Creates an array of numbers for use as a seed.
083     *
084     * @param n Size of the array to create.
085     * @return an array of {@code n} random numbers.
086     */
087    public static int[] createIntArray(int n) {
088        return createIntArray(n, SEED_GENERATOR, new Object());
089    }
090
091    /**
092     * Creates an array of numbers for use as a seed.
093     *
094     * @param n Size of the array to create.
095     * @return an array of {@code n} random numbers.
096     */
097    public static long[] createLongArray(int n) {
098        return createLongArray(n, SEED_GENERATOR, new Object());
099    }
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}