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 }