1 /* 2 * Copyright (C) 2012 Alberto Irurueta Carro (alberto@irurueta.com) 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.irurueta.statistics; 17 18 import java.security.SecureRandom; 19 import java.util.Random; 20 21 /** 22 * Parent class of all Randomizers. Specific subclasses exist for different 23 * distribution types (currently only uniform and gaussian distributions are 24 * implemented). 25 * This class provides static methods to ease the instantiation of a Randomizer. 26 * For instance, a UniformRandomizer can be created like this: 27 * <pre> 28 * {@code 29 * Randomizer.create(RandomizerType.UNIFORM_RANDOMIZER); 30 * } 31 * </pre> 32 * whereas a GaussianRandomizer can be created like this: 33 * <pre> 34 * {@code 35 * Randomizer.create(RandomizerType.GAUSSIAN_RANDOMIZER); 36 * } 37 * </pre> 38 */ 39 public abstract class Randomizer { 40 41 /** 42 * Indicates that by default non-secured random instance is used if none 43 * is provided. 44 */ 45 public static final boolean USE_SECURE_RANDOM_BY_DEFAULT = false; 46 47 /** 48 * Indicates default randomizer type if non is provided. By default, uniform 49 * randomizers are created. 50 */ 51 public static final RandomizerType DEFAULT_RANDOMIZER_TYPE = RandomizerType.UNIFORM_RANDOMIZER; 52 53 /** 54 * Instance in charge of generating pseudo-random values. Secure instances 55 * can be used if the generated values need to be ensured to be "more" 56 * random at the expense of higher computational cost. 57 */ 58 private Random internalRandom; 59 60 /** 61 * Constructor. 62 * Uses default {@link Random} implementation. 63 */ 64 protected Randomizer() { 65 this(new Random()); 66 } 67 68 /** 69 * Constructor. 70 * 71 * @param internalRandom Instance in charge of generating pseudo-random 72 * values. 73 * @throws NullPointerException if provided value is null. 74 */ 75 protected Randomizer(final Random internalRandom) { 76 77 if (internalRandom == null) { 78 throw new NullPointerException(); 79 } 80 this.internalRandom = internalRandom; 81 } 82 83 /** 84 * Returns internal instance in charge of generating pseudo-random values. 85 * 86 * @return instance in charge of generating pseudo-random values. 87 */ 88 public Random getInternalRandom() { 89 return internalRandom; 90 } 91 92 /** 93 * Sets internal instance in charge of generating pseudo-random values. 94 * 95 * @param internalRandom Instance in charge of generating pseudo-random 96 * values. 97 * @throws NullPointerException if provided value is null. 98 */ 99 public void setInternalRandom(final Random internalRandom) { 100 if (internalRandom == null) { 101 throw new NullPointerException(); 102 } 103 this.internalRandom = internalRandom; 104 } 105 106 /** 107 * Sets the seed for the internal randomizer. 108 * A seed determines the sequence of pseudo-random numbers to be generated. 109 * Whenever the same seed is used on different executions, the generated 110 * sequence will be the same. 111 * To alleviate this issue and allow the generation of "more" random values 112 * the system clock can be used as the seed. 113 * Example: 114 * <pre> 115 * {@code 116 * Randomizer randomizer = Randomizer.create(); 117 * randomizer.setSeed(System.currentTimeMillis()); 118 * } 119 * </pre> 120 * Notice that using the clock as seed is not a secure solution to generate 121 * random values. If a secure solution is required (i.e. for encryption 122 * purposes, then a SecureRandom instance must be provided as the internal 123 * random instance) 124 * 125 * @param seed Value to be used as seed 126 */ 127 public void setSeed(final long seed) { 128 internalRandom.setSeed(seed); 129 } 130 131 /** 132 * Returns next random boolean value following a given distribution 133 * depending on the randomizer type. 134 * 135 * @return Next random boolean value 136 */ 137 public abstract boolean nextBoolean(); 138 139 /** 140 * Fills provided array with random booleans. 141 * 142 * @param array Array to be filled. 143 */ 144 public void fill(final boolean[] array) { 145 for (int i = 0; i < array.length; i++) { 146 array[i] = nextBoolean(); 147 } 148 } 149 150 /** 151 * Returns array of booleans. 152 * 153 * @param length Length of array to be returned. 154 * @return Array of uniform booleans. 155 * @throws IllegalArgumentException if provided value is zero or negative. 156 */ 157 public boolean[] nextBooleans(final int length) { 158 if (length <= 0) { 159 throw new IllegalArgumentException(); 160 } 161 final boolean[] array = new boolean[length]; 162 fill(array); 163 return array; 164 } 165 166 /** 167 * Returns next random integer value following a given distribution 168 * depending on the randomizer type. 169 * 170 * @return Next random integer value. 171 */ 172 public abstract int nextInt(); 173 174 /** 175 * Fills provided array with random integer values. 176 * 177 * @param array Array to be filled. 178 */ 179 public void fill(final int[] array) { 180 for (int i = 0; i < array.length; i++) { 181 array[i] = nextInt(); 182 } 183 } 184 185 /** 186 * Returns array of random integers. 187 * 188 * @param length Length of array to be returned. 189 * @return Array of random integers. 190 * @throws IllegalArgumentException if provided value is zero or negative. 191 */ 192 public int[] nextInts(final int length) { 193 if (length <= 0) { 194 throw new IllegalArgumentException(); 195 } 196 final int[] array = new int[length]; 197 fill(array); 198 return array; 199 } 200 201 /** 202 * Returns next random long value following a given distribution depending 203 * on the randomizer type. 204 * 205 * @return Next random integer value. 206 */ 207 public abstract long nextLong(); 208 209 /** 210 * Fills provided array with random long values. 211 * 212 * @param array Array to be filled. 213 */ 214 public void fill(final long[] array) { 215 for (int i = 0; i < array.length; i++) { 216 array[i] = nextLong(); 217 } 218 } 219 220 /** 221 * Returns array of random long values. 222 * 223 * @param length Length of array to be returned. 224 * @return Array of random long values. 225 * @throws IllegalArgumentException if provided value is zero or negative. 226 */ 227 public long[] nextLongs(final int length) { 228 if (length <= 0) { 229 throw new IllegalArgumentException(); 230 } 231 final long[] array = new long[length]; 232 fill(array); 233 return array; 234 } 235 236 /** 237 * Returns next random floating-point value following a given distribution 238 * depending on the randomizer type. 239 * 240 * @return Next random integer value. 241 */ 242 public abstract float nextFloat(); 243 244 /** 245 * Fills provided array with random floating point values. 246 * 247 * @param array Array to be filled. 248 */ 249 public void fill(final float[] array) { 250 for (int i = 0; i < array.length; i++) { 251 array[i] = nextFloat(); 252 } 253 } 254 255 /** 256 * Returns array of floating point values. 257 * 258 * @param length Length of array to be returned. 259 * @return Array of random float values. 260 * @throws IllegalArgumentException if provided value is zero or negative. 261 */ 262 public float[] nextFloats(final int length) { 263 if (length <= 0) { 264 throw new IllegalArgumentException(); 265 } 266 final float[] array = new float[length]; 267 fill(array); 268 return array; 269 } 270 271 /** 272 * Returns next random double precision floating-point value following a 273 * given distribution depending on the randomizer type. 274 * 275 * @return Next random double precision floating-point value. 276 */ 277 public abstract double nextDouble(); 278 279 /** 280 * Fills provided array with random double precision floating point values. 281 * 282 * @param array Array to be filled. 283 */ 284 public void fill(final double[] array) { 285 for (int i = 0; i < array.length; i++) { 286 array[i] = nextDouble(); 287 } 288 } 289 290 /** 291 * Returns array of double precision floating point values. 292 * 293 * @param length Length of array to be returned. 294 * @return Array of random double values. 295 * @throws IllegalArgumentException if provided value is zero or negative. 296 */ 297 public double[] nextDoubles(final int length) { 298 if (length <= 0) { 299 throw new IllegalArgumentException(); 300 } 301 final double[] array = new double[length]; 302 fill(array); 303 return array; 304 } 305 306 /** 307 * Returns the randomizer type of this instance. 308 * 309 * @return Randomizer type. 310 */ 311 public abstract RandomizerType getType(); 312 313 /** 314 * Creates a new Randomizer instance using DEFAULT_RANDOMIZER_TYPE and 315 * USE_SECURE_RANDOM_By_DEFAULT to determine what type of random 316 * distribution is to be used and whether the random generator must be 317 * secure or not. 318 * 319 * @return A Randomizer instance using default randomizer type and secure 320 * mode. 321 */ 322 public static Randomizer create() { 323 return create(DEFAULT_RANDOMIZER_TYPE); 324 } 325 326 /** 327 * Creates a new Randomizer instance using DEFAULT_RANDOMIZER_TYPE. The 328 * instantiated Randomizer will generate secure values depending on provided 329 * parameter. When secure random generator is requested, generated values 330 * tend to be more "random" at the expense of larger computational cost. 331 * Secure mode should only be used on specific applications, such as 332 * cryptography, and hence the name of the parameter. 333 * 334 * @param useSecureRandom Parameter indicating whether generated values will 335 * be used for security purposes such as cryptography. 336 * @return A Randomizer instance using provided secure mode. 337 */ 338 public static Randomizer create(final boolean useSecureRandom) { 339 return create(DEFAULT_RANDOMIZER_TYPE, useSecureRandom); 340 } 341 342 /** 343 * Creates a new Randomizer instance using provided internal randomizer 344 * instance. 345 * 346 * @param internalRandomizer Internal instance to be used for generation of 347 * pseudo-random values. 348 * @return A Randomizer instance using provided internal randomizer. 349 * @throws NullPointerException Exception thrown if provided internal 350 * randomizer is null. 351 */ 352 public static Randomizer create(final Random internalRandomizer) { 353 return create(DEFAULT_RANDOMIZER_TYPE, internalRandomizer); 354 } 355 356 /** 357 * Creates a new Randomizer instance using provided randomizer type and 358 * the default secure mode specified by USE_SECURE_RANDOM_BY_DEFAULT. 359 * 360 * @param type Randomizer type to be used when creating an instance. 361 * @return A Randomizer instance using provided randomizer type. 362 */ 363 public static Randomizer create(final RandomizerType type) { 364 return create(type, USE_SECURE_RANDOM_BY_DEFAULT); 365 } 366 367 /** 368 * Creates a new Randomizer instance using provided randomizer type and 369 * provided secure mode. 370 * 371 * @param type Randomizer type to be used when creating an instance. 372 * @param useSecureRandom Boolean indicating whether generated values will 373 * be secure for specific purposes such as cryptography. Secure mode 374 * generates more "random" values at the expense of higher computational 375 * cost. 376 * @return A Randomizer instance using provided randomizer type and secure 377 * mode. 378 */ 379 public static Randomizer create(final RandomizerType type, final boolean useSecureRandom) { 380 if (useSecureRandom) { 381 return create(type, new SecureRandom()); 382 } else { 383 return create(type, new Random()); 384 } 385 } 386 387 /** 388 * Creates a new Randomizer instance using provided randomizer type and 389 * internal randomizer. 390 * 391 * @param type Randomizer type to be used when creating an instance. 392 * @param internalRandom Internal random instance to be used to generate 393 * pseudo-random values. 394 * @return A Randomizer instance using provided randomizer type and internal 395 * random instance. 396 * @throws NullPointerException Exception thrown if internal random is null. 397 */ 398 public static Randomizer create(final RandomizerType type, final Random internalRandom) { 399 400 if (internalRandom == null) { 401 throw new NullPointerException(); 402 } 403 404 if (type == RandomizerType.GAUSSIAN_RANDOMIZER) { 405 return new GaussianRandomizer(internalRandom); 406 } else { 407 return new UniformRandomizer(internalRandom); 408 } 409 } 410 }