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 }