View Javadoc
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 }