View Javadoc
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  
18  package org.apache.commons.math3.random;
19  
20  import java.io.Serializable;
21  import java.security.MessageDigest;
22  import java.security.NoSuchAlgorithmException;
23  import java.security.NoSuchProviderException;
24  import java.security.SecureRandom;
25  import java.util.Collection;
26  
27  import org.apache.commons.math3.distribution.BetaDistribution;
28  import org.apache.commons.math3.distribution.BinomialDistribution;
29  import org.apache.commons.math3.distribution.CauchyDistribution;
30  import org.apache.commons.math3.distribution.ChiSquaredDistribution;
31  import org.apache.commons.math3.distribution.ExponentialDistribution;
32  import org.apache.commons.math3.distribution.FDistribution;
33  import org.apache.commons.math3.distribution.GammaDistribution;
34  import org.apache.commons.math3.distribution.HypergeometricDistribution;
35  import org.apache.commons.math3.distribution.PascalDistribution;
36  import org.apache.commons.math3.distribution.PoissonDistribution;
37  import org.apache.commons.math3.distribution.TDistribution;
38  import org.apache.commons.math3.distribution.WeibullDistribution;
39  import org.apache.commons.math3.distribution.ZipfDistribution;
40  import org.apache.commons.math3.distribution.UniformIntegerDistribution;
41  import org.apache.commons.math3.exception.MathInternalError;
42  import org.apache.commons.math3.exception.NotANumberException;
43  import org.apache.commons.math3.exception.NotFiniteNumberException;
44  import org.apache.commons.math3.exception.NotPositiveException;
45  import org.apache.commons.math3.exception.NotStrictlyPositiveException;
46  import org.apache.commons.math3.exception.NumberIsTooLargeException;
47  import org.apache.commons.math3.exception.OutOfRangeException;
48  import org.apache.commons.math3.exception.util.LocalizedFormats;
49  import org.apache.commons.math3.util.MathArrays;
50  
51  /**
52   * Implements the {@link RandomData} interface using a {@link RandomGenerator}
53   * instance to generate non-secure data and a {@link java.security.SecureRandom}
54   * instance to provide data for the <code>nextSecureXxx</code> methods. If no
55   * <code>RandomGenerator</code> is provided in the constructor, the default is
56   * to use a {@link Well19937c} generator. To plug in a different
57   * implementation, either implement <code>RandomGenerator</code> directly or
58   * extend {@link AbstractRandomGenerator}.
59   * <p>
60   * Supports reseeding the underlying pseudo-random number generator (PRNG). The
61   * <code>SecurityProvider</code> and <code>Algorithm</code> used by the
62   * <code>SecureRandom</code> instance can also be reset.
63   * </p>
64   * <p>
65   * For details on the default PRNGs, see {@link java.util.Random} and
66   * {@link java.security.SecureRandom}.
67   * </p>
68   * <p>
69   * <strong>Usage Notes</strong>:
70   * <ul>
71   * <li>
72   * Instance variables are used to maintain <code>RandomGenerator</code> and
73   * <code>SecureRandom</code> instances used in data generation. Therefore, to
74   * generate a random sequence of values or strings, you should use just
75   * <strong>one</strong> <code>RandomDataImpl</code> instance repeatedly.</li>
76   * <li>
77   * The "secure" methods are *much* slower. These should be used only when a
78   * cryptographically secure random sequence is required. A secure random
79   * sequence is a sequence of pseudo-random values which, in addition to being
80   * well-dispersed (so no subsequence of values is an any more likely than other
81   * subsequence of the the same length), also has the additional property that
82   * knowledge of values generated up to any point in the sequence does not make
83   * it any easier to predict subsequent values.</li>
84   * <li>
85   * When a new <code>RandomDataImpl</code> is created, the underlying random
86   * number generators are <strong>not</strong> initialized. If you do not
87   * explicitly seed the default non-secure generator, it is seeded with the
88   * current time in milliseconds plus the system identity hash code on first use.
89   * The same holds for the secure generator. If you provide a <code>RandomGenerator</code>
90   * to the constructor, however, this generator is not reseeded by the constructor
91   * nor is it reseeded on first use.</li>
92   * <li>
93   * The <code>reSeed</code> and <code>reSeedSecure</code> methods delegate to the
94   * corresponding methods on the underlying <code>RandomGenerator</code> and
95   * <code>SecureRandom</code> instances. Therefore, <code>reSeed(long)</code>
96   * fully resets the initial state of the non-secure random number generator (so
97   * that reseeding with a specific value always results in the same subsequent
98   * random sequence); whereas reSeedSecure(long) does <strong>not</strong>
99   * reinitialize the secure random number generator (so secure sequences started
100  * with calls to reseedSecure(long) won't be identical).</li>
101  * <li>
102  * This implementation is not synchronized. The underlying <code>RandomGenerator</code>
103  * or <code>SecureRandom</code> instances are not protected by synchronization and
104  * are not guaranteed to be thread-safe.  Therefore, if an instance of this class
105  * is concurrently utilized by multiple threads, it is the responsibility of
106  * client code to synchronize access to seeding and data generation methods.
107  * </li>
108  * </ul>
109  * </p>
110  * @since 3.1
111  * @version $Id: RandomDataGenerator.java 1538368 2013-11-03 13:57:37Z erans $
112  */
113 public class RandomDataGenerator implements RandomData, Serializable {
114 
115     /** Serializable version identifier */
116     private static final long serialVersionUID = -626730818244969716L;
117 
118     /** underlying random number generator */
119     private RandomGenerator rand = null;
120 
121     /** underlying secure random number generator */
122     private RandomGenerator secRand = null;
123 
124     /**
125      * Construct a RandomDataGenerator, using a default random generator as the source
126      * of randomness.
127      *
128      * <p>The default generator is a {@link Well19937c} seeded
129      * with {@code System.currentTimeMillis() + System.identityHashCode(this))}.
130      * The generator is initialized and seeded on first use.</p>
131      */
132     public RandomDataGenerator() {
133     }
134 
135     /**
136      * Construct a RandomDataGenerator using the supplied {@link RandomGenerator} as
137      * the source of (non-secure) random data.
138      *
139      * @param rand the source of (non-secure) random data
140      * (may be null, resulting in the default generator)
141      */
142     public RandomDataGenerator(RandomGenerator rand) {
143         this.rand = rand;
144     }
145 
146     /**
147      * {@inheritDoc}
148      * <p>
149      * <strong>Algorithm Description:</strong> hex strings are generated using a
150      * 2-step process.
151      * <ol>
152      * <li>{@code len / 2 + 1} binary bytes are generated using the underlying
153      * Random</li>
154      * <li>Each binary byte is translated into 2 hex digits</li>
155      * </ol>
156      * </p>
157      *
158      * @param len the desired string length.
159      * @return the random string.
160      * @throws NotStrictlyPositiveException if {@code len <= 0}.
161      */
162     public String nextHexString(int len) throws NotStrictlyPositiveException {
163         if (len <= 0) {
164             throw new NotStrictlyPositiveException(LocalizedFormats.LENGTH, len);
165         }
166 
167         // Get a random number generator
168         RandomGenerator ran = getRandomGenerator();
169 
170         // Initialize output buffer
171         StringBuilder outBuffer = new StringBuilder();
172 
173         // Get int(len/2)+1 random bytes
174         byte[] randomBytes = new byte[(len / 2) + 1];
175         ran.nextBytes(randomBytes);
176 
177         // Convert each byte to 2 hex digits
178         for (int i = 0; i < randomBytes.length; i++) {
179             Integer c = Integer.valueOf(randomBytes[i]);
180 
181             /*
182              * Add 128 to byte value to make interval 0-255 before doing hex
183              * conversion. This guarantees <= 2 hex digits from toHexString()
184              * toHexString would otherwise add 2^32 to negative arguments.
185              */
186             String hex = Integer.toHexString(c.intValue() + 128);
187 
188             // Make sure we add 2 hex digits for each byte
189             if (hex.length() == 1) {
190                 hex = "0" + hex;
191             }
192             outBuffer.append(hex);
193         }
194         return outBuffer.toString().substring(0, len);
195     }
196 
197     /** {@inheritDoc} */
198     public int nextInt(final int lower, final int upper) throws NumberIsTooLargeException {
199         return new UniformIntegerDistribution(getRandomGenerator(), lower, upper).sample();
200     }
201 
202     /** {@inheritDoc} */
203     public long nextLong(final long lower, final long upper) throws NumberIsTooLargeException {
204         if (lower >= upper) {
205             throw new NumberIsTooLargeException(LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
206                                                 lower, upper, false);
207         }
208         final long max = (upper - lower) + 1;
209         if (max <= 0) {
210             // the range is too wide to fit in a positive long (larger than 2^63); as it covers
211             // more than half the long range, we use directly a simple rejection method
212             final RandomGenerator rng = getRandomGenerator();
213             while (true) {
214                 final long r = rng.nextLong();
215                 if (r >= lower && r <= upper) {
216                     return r;
217                 }
218             }
219         } else if (max < Integer.MAX_VALUE){
220             // we can shift the range and generate directly a positive int
221             return lower + getRandomGenerator().nextInt((int) max);
222         } else {
223             // we can shift the range and generate directly a positive long
224             return lower + nextLong(getRandomGenerator(), max);
225         }
226     }
227 
228     /**
229      * Returns a pseudorandom, uniformly distributed <tt>long</tt> value
230      * between 0 (inclusive) and the specified value (exclusive), drawn from
231      * this random number generator's sequence.
232      *
233      * @param rng random generator to use
234      * @param n the bound on the random number to be returned.  Must be
235      * positive.
236      * @return  a pseudorandom, uniformly distributed <tt>long</tt>
237      * value between 0 (inclusive) and n (exclusive).
238      * @throws IllegalArgumentException  if n is not positive.
239      */
240     private static long nextLong(final RandomGenerator rng, final long n) throws IllegalArgumentException {
241         if (n > 0) {
242             final byte[] byteArray = new byte[8];
243             long bits;
244             long val;
245             do {
246                 rng.nextBytes(byteArray);
247                 bits = 0;
248                 for (final byte b : byteArray) {
249                     bits = (bits << 8) | (((long) b) & 0xffL);
250                 }
251                 bits &= 0x7fffffffffffffffL;
252                 val  = bits % n;
253             } while (bits - val + (n - 1) < 0);
254             return val;
255         }
256         throw new NotStrictlyPositiveException(n);
257     }
258 
259     /**
260      * {@inheritDoc}
261      * <p>
262      * <strong>Algorithm Description:</strong> hex strings are generated in
263      * 40-byte segments using a 3-step process.
264      * <ol>
265      * <li>
266      * 20 random bytes are generated using the underlying
267      * <code>SecureRandom</code>.</li>
268      * <li>
269      * SHA-1 hash is applied to yield a 20-byte binary digest.</li>
270      * <li>
271      * Each byte of the binary digest is converted to 2 hex digits.</li>
272      * </ol>
273      * </p>
274      * @throws NotStrictlyPositiveException if {@code len <= 0}
275      */
276     public String nextSecureHexString(int len) throws NotStrictlyPositiveException {
277         if (len <= 0) {
278             throw new NotStrictlyPositiveException(LocalizedFormats.LENGTH, len);
279         }
280 
281         // Get SecureRandom and setup Digest provider
282         final RandomGenerator secRan = getSecRan();
283         MessageDigest alg = null;
284         try {
285             alg = MessageDigest.getInstance("SHA-1");
286         } catch (NoSuchAlgorithmException ex) {
287             // this should never happen
288             throw new MathInternalError(ex);
289         }
290         alg.reset();
291 
292         // Compute number of iterations required (40 bytes each)
293         int numIter = (len / 40) + 1;
294 
295         StringBuilder outBuffer = new StringBuilder();
296         for (int iter = 1; iter < numIter + 1; iter++) {
297             byte[] randomBytes = new byte[40];
298             secRan.nextBytes(randomBytes);
299             alg.update(randomBytes);
300 
301             // Compute hash -- will create 20-byte binary hash
302             byte[] hash = alg.digest();
303 
304             // Loop over the hash, converting each byte to 2 hex digits
305             for (int i = 0; i < hash.length; i++) {
306                 Integer c = Integer.valueOf(hash[i]);
307 
308                 /*
309                  * Add 128 to byte value to make interval 0-255 This guarantees
310                  * <= 2 hex digits from toHexString() toHexString would
311                  * otherwise add 2^32 to negative arguments
312                  */
313                 String hex = Integer.toHexString(c.intValue() + 128);
314 
315                 // Keep strings uniform length -- guarantees 40 bytes
316                 if (hex.length() == 1) {
317                     hex = "0" + hex;
318                 }
319                 outBuffer.append(hex);
320             }
321         }
322         return outBuffer.toString().substring(0, len);
323     }
324 
325     /**  {@inheritDoc} */
326     public int nextSecureInt(final int lower, final int upper) throws NumberIsTooLargeException {
327         return new UniformIntegerDistribution(getSecRan(), lower, upper).sample();
328     }
329 
330     /** {@inheritDoc} */
331     public long nextSecureLong(final long lower, final long upper) throws NumberIsTooLargeException {
332         if (lower >= upper) {
333             throw new NumberIsTooLargeException(LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
334                                                 lower, upper, false);
335         }
336         final RandomGenerator rng = getSecRan();
337         final long max = (upper - lower) + 1;
338         if (max <= 0) {
339             // the range is too wide to fit in a positive long (larger than 2^63); as it covers
340             // more than half the long range, we use directly a simple rejection method
341             while (true) {
342                 final long r = rng.nextLong();
343                 if (r >= lower && r <= upper) {
344                     return r;
345                 }
346             }
347         } else if (max < Integer.MAX_VALUE){
348             // we can shift the range and generate directly a positive int
349             return lower + rng.nextInt((int) max);
350         } else {
351             // we can shift the range and generate directly a positive long
352             return lower + nextLong(rng, max);
353         }
354     }
355 
356     /**
357      * {@inheritDoc}
358      * <p>
359      * <strong>Algorithm Description</strong>:
360      * <ul><li> For small means, uses simulation of a Poisson process
361      * using Uniform deviates, as described
362      * <a href="http://irmi.epfl.ch/cmos/Pmmi/interactive/rng7.htm"> here.</a>
363      * The Poisson process (and hence value returned) is bounded by 1000 * mean.</li>
364      *
365      * <li> For large means, uses the rejection algorithm described in <br/>
366      * Devroye, Luc. (1981).<i>The Computer Generation of Poisson Random Variables</i>
367      * <strong>Computing</strong> vol. 26 pp. 197-207.</li></ul></p>
368      * @throws NotStrictlyPositiveException if {@code len <= 0}
369      */
370     public long nextPoisson(double mean) throws NotStrictlyPositiveException {
371         return new PoissonDistribution(getRandomGenerator(), mean,
372                 PoissonDistribution.DEFAULT_EPSILON,
373                 PoissonDistribution.DEFAULT_MAX_ITERATIONS).sample();
374     }
375 
376     /** {@inheritDoc} */
377     public double nextGaussian(double mu, double sigma) throws NotStrictlyPositiveException {
378         if (sigma <= 0) {
379             throw new NotStrictlyPositiveException(LocalizedFormats.STANDARD_DEVIATION, sigma);
380         }
381         return sigma * getRandomGenerator().nextGaussian() + mu;
382     }
383 
384     /**
385      * {@inheritDoc}
386      *
387      * <p>
388      * <strong>Algorithm Description</strong>: Uses the Algorithm SA (Ahrens)
389      * from p. 876 in:
390      * [1]: Ahrens, J. H. and Dieter, U. (1972). Computer methods for
391      * sampling from the exponential and normal distributions.
392      * Communications of the ACM, 15, 873-882.
393      * </p>
394      */
395     public double nextExponential(double mean) throws NotStrictlyPositiveException {
396         return new ExponentialDistribution(getRandomGenerator(), mean,
397                 ExponentialDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
398     }
399 
400     /**
401      * <p>Generates a random value from the
402      * {@link org.apache.commons.math3.distribution.GammaDistribution Gamma Distribution}.</p>
403      *
404      * <p>This implementation uses the following algorithms: </p>
405      *
406      * <p>For 0 < shape < 1: <br/>
407      * Ahrens, J. H. and Dieter, U., <i>Computer methods for
408      * sampling from gamma, beta, Poisson and binomial distributions.</i>
409      * Computing, 12, 223-246, 1974.</p>
410      *
411      * <p>For shape >= 1: <br/>
412      * Marsaglia and Tsang, <i>A Simple Method for Generating
413      * Gamma Variables.</i> ACM Transactions on Mathematical Software,
414      * Volume 26 Issue 3, September, 2000.</p>
415      *
416      * @param shape the median of the Gamma distribution
417      * @param scale the scale parameter of the Gamma distribution
418      * @return random value sampled from the Gamma(shape, scale) distribution
419      * @throws NotStrictlyPositiveException if {@code shape <= 0} or
420      * {@code scale <= 0}.
421      */
422     public double nextGamma(double shape, double scale) throws NotStrictlyPositiveException {
423         return new GammaDistribution(getRandomGenerator(),shape, scale,
424                 GammaDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
425     }
426 
427     /**
428      * Generates a random value from the {@link HypergeometricDistribution Hypergeometric Distribution}.
429      *
430      * @param populationSize the population size of the Hypergeometric distribution
431      * @param numberOfSuccesses number of successes in the population of the Hypergeometric distribution
432      * @param sampleSize the sample size of the Hypergeometric distribution
433      * @return random value sampled from the Hypergeometric(numberOfSuccesses, sampleSize) distribution
434      * @throws NumberIsTooLargeException  if {@code numberOfSuccesses > populationSize},
435      * or {@code sampleSize > populationSize}.
436      * @throws NotStrictlyPositiveException if {@code populationSize <= 0}.
437      * @throws NotPositiveException  if {@code numberOfSuccesses < 0}.
438      */
439     public int nextHypergeometric(int populationSize, int numberOfSuccesses, int sampleSize) throws NotPositiveException, NotStrictlyPositiveException, NumberIsTooLargeException {
440         return new HypergeometricDistribution(getRandomGenerator(),populationSize,
441                 numberOfSuccesses, sampleSize).sample();
442     }
443 
444     /**
445      * Generates a random value from the {@link PascalDistribution Pascal Distribution}.
446      *
447      * @param r the number of successes of the Pascal distribution
448      * @param p the probability of success of the Pascal distribution
449      * @return random value sampled from the Pascal(r, p) distribution
450      * @throws NotStrictlyPositiveException if the number of successes is not positive
451      * @throws OutOfRangeException if the probability of success is not in the
452      * range {@code [0, 1]}.
453      */
454     public int nextPascal(int r, double p) throws NotStrictlyPositiveException, OutOfRangeException {
455         return new PascalDistribution(getRandomGenerator(), r, p).sample();
456     }
457 
458     /**
459      * Generates a random value from the {@link TDistribution T Distribution}.
460      *
461      * @param df the degrees of freedom of the T distribution
462      * @return random value from the T(df) distribution
463      * @throws NotStrictlyPositiveException if {@code df <= 0}
464      */
465     public double nextT(double df) throws NotStrictlyPositiveException {
466         return new TDistribution(getRandomGenerator(), df,
467                 TDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
468     }
469 
470     /**
471      * Generates a random value from the {@link WeibullDistribution Weibull Distribution}.
472      *
473      * @param shape the shape parameter of the Weibull distribution
474      * @param scale the scale parameter of the Weibull distribution
475      * @return random value sampled from the Weibull(shape, size) distribution
476      * @throws NotStrictlyPositiveException if {@code shape <= 0} or
477      * {@code scale <= 0}.
478      */
479     public double nextWeibull(double shape, double scale) throws NotStrictlyPositiveException {
480         return new WeibullDistribution(getRandomGenerator(), shape, scale,
481                 WeibullDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
482     }
483 
484     /**
485      * Generates a random value from the {@link ZipfDistribution Zipf Distribution}.
486      *
487      * @param numberOfElements the number of elements of the ZipfDistribution
488      * @param exponent the exponent of the ZipfDistribution
489      * @return random value sampled from the Zipf(numberOfElements, exponent) distribution
490      * @exception NotStrictlyPositiveException if {@code numberOfElements <= 0}
491      * or {@code exponent <= 0}.
492      */
493     public int nextZipf(int numberOfElements, double exponent) throws NotStrictlyPositiveException {
494         return new ZipfDistribution(getRandomGenerator(), numberOfElements, exponent).sample();
495     }
496 
497     /**
498      * Generates a random value from the {@link BetaDistribution Beta Distribution}.
499      *
500      * @param alpha first distribution shape parameter
501      * @param beta second distribution shape parameter
502      * @return random value sampled from the beta(alpha, beta) distribution
503      */
504     public double nextBeta(double alpha, double beta) {
505         return new BetaDistribution(getRandomGenerator(), alpha, beta,
506                 BetaDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
507     }
508 
509     /**
510      * Generates a random value from the {@link BinomialDistribution Binomial Distribution}.
511      *
512      * @param numberOfTrials number of trials of the Binomial distribution
513      * @param probabilityOfSuccess probability of success of the Binomial distribution
514      * @return random value sampled from the Binomial(numberOfTrials, probabilityOfSuccess) distribution
515      */
516     public int nextBinomial(int numberOfTrials, double probabilityOfSuccess) {
517         return new BinomialDistribution(getRandomGenerator(), numberOfTrials, probabilityOfSuccess).sample();
518     }
519 
520     /**
521      * Generates a random value from the {@link CauchyDistribution Cauchy Distribution}.
522      *
523      * @param median the median of the Cauchy distribution
524      * @param scale the scale parameter of the Cauchy distribution
525      * @return random value sampled from the Cauchy(median, scale) distribution
526      */
527     public double nextCauchy(double median, double scale) {
528         return new CauchyDistribution(getRandomGenerator(), median, scale,
529                 CauchyDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
530     }
531 
532     /**
533      * Generates a random value from the {@link ChiSquaredDistribution ChiSquare Distribution}.
534      *
535      * @param df the degrees of freedom of the ChiSquare distribution
536      * @return random value sampled from the ChiSquare(df) distribution
537      */
538     public double nextChiSquare(double df) {
539         return new ChiSquaredDistribution(getRandomGenerator(), df,
540                 ChiSquaredDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
541     }
542 
543     /**
544      * Generates a random value from the {@link FDistribution F Distribution}.
545      *
546      * @param numeratorDf the numerator degrees of freedom of the F distribution
547      * @param denominatorDf the denominator degrees of freedom of the F distribution
548      * @return random value sampled from the F(numeratorDf, denominatorDf) distribution
549      * @throws NotStrictlyPositiveException if
550      * {@code numeratorDf <= 0} or {@code denominatorDf <= 0}.
551      */
552     public double nextF(double numeratorDf, double denominatorDf) throws NotStrictlyPositiveException {
553         return new FDistribution(getRandomGenerator(), numeratorDf, denominatorDf,
554                 FDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
555     }
556 
557     /**
558      * {@inheritDoc}
559      *
560      * <p>
561      * <strong>Algorithm Description</strong>: scales the output of
562      * Random.nextDouble(), but rejects 0 values (i.e., will generate another
563      * random double if Random.nextDouble() returns 0). This is necessary to
564      * provide a symmetric output interval (both endpoints excluded).
565      * </p>
566      * @throws NumberIsTooLargeException if {@code lower >= upper}
567      * @throws NotFiniteNumberException if one of the bounds is infinite
568      * @throws NotANumberException if one of the bounds is NaN
569      */
570     public double nextUniform(double lower, double upper)
571         throws NumberIsTooLargeException, NotFiniteNumberException, NotANumberException {
572         return nextUniform(lower, upper, false);
573     }
574 
575     /**
576      * {@inheritDoc}
577      *
578      * <p>
579      * <strong>Algorithm Description</strong>: if the lower bound is excluded,
580      * scales the output of Random.nextDouble(), but rejects 0 values (i.e.,
581      * will generate another random double if Random.nextDouble() returns 0).
582      * This is necessary to provide a symmetric output interval (both
583      * endpoints excluded).
584      * </p>
585      *
586      * @throws NumberIsTooLargeException if {@code lower >= upper}
587      * @throws NotFiniteNumberException if one of the bounds is infinite
588      * @throws NotANumberException if one of the bounds is NaN
589      */
590     public double nextUniform(double lower, double upper, boolean lowerInclusive)
591         throws NumberIsTooLargeException, NotFiniteNumberException, NotANumberException {
592 
593         if (lower >= upper) {
594             throw new NumberIsTooLargeException(LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
595                                                 lower, upper, false);
596         }
597 
598         if (Double.isInfinite(lower)) {
599             throw new NotFiniteNumberException(LocalizedFormats.INFINITE_BOUND, lower);
600         }
601         if (Double.isInfinite(upper)) {
602             throw new NotFiniteNumberException(LocalizedFormats.INFINITE_BOUND, upper);
603         }
604 
605         if (Double.isNaN(lower) || Double.isNaN(upper)) {
606             throw new NotANumberException();
607         }
608 
609         final RandomGenerator generator = getRandomGenerator();
610 
611         // ensure nextDouble() isn't 0.0
612         double u = generator.nextDouble();
613         while (!lowerInclusive && u <= 0.0) {
614             u = generator.nextDouble();
615         }
616 
617         return u * upper + (1.0 - u) * lower;
618     }
619 
620     /**
621      * {@inheritDoc}
622      *
623      * This method calls {@link MathArrays#shuffle(int[],RandomGenerator)
624      * MathArrays.shuffle} in order to create a random shuffle of the set
625      * of natural numbers {@code { 0, 1, ..., n - 1 }}.
626      *
627      * @throws NumberIsTooLargeException if {@code k > n}.
628      * @throws NotStrictlyPositiveException if {@code k <= 0}.
629      */
630     public int[] nextPermutation(int n, int k)
631         throws NumberIsTooLargeException, NotStrictlyPositiveException {
632         if (k > n) {
633             throw new NumberIsTooLargeException(LocalizedFormats.PERMUTATION_EXCEEDS_N,
634                                                 k, n, true);
635         }
636         if (k <= 0) {
637             throw new NotStrictlyPositiveException(LocalizedFormats.PERMUTATION_SIZE,
638                                                    k);
639         }
640 
641         int[] index = MathArrays.natural(n);
642         MathArrays.shuffle(index, getRandomGenerator());
643 
644         // Return a new array containing the first "k" entries of "index".
645         return MathArrays.copyOf(index, k);
646     }
647 
648     /**
649      * {@inheritDoc}
650      *
651      * This method calls {@link #nextPermutation(int,int) nextPermutation(c.size(), k)}
652      * in order to sample the collection.
653      */
654     public Object[] nextSample(Collection<?> c, int k) throws NumberIsTooLargeException, NotStrictlyPositiveException {
655 
656         int len = c.size();
657         if (k > len) {
658             throw new NumberIsTooLargeException(LocalizedFormats.SAMPLE_SIZE_EXCEEDS_COLLECTION_SIZE,
659                                                 k, len, true);
660         }
661         if (k <= 0) {
662             throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_SAMPLES, k);
663         }
664 
665         Object[] objects = c.toArray();
666         int[] index = nextPermutation(len, k);
667         Object[] result = new Object[k];
668         for (int i = 0; i < k; i++) {
669             result[i] = objects[index[i]];
670         }
671         return result;
672     }
673 
674 
675 
676     /**
677      * Reseeds the random number generator with the supplied seed.
678      * <p>
679      * Will create and initialize if null.
680      * </p>
681      *
682      * @param seed the seed value to use
683      */
684     public void reSeed(long seed) {
685        getRandomGenerator().setSeed(seed);
686     }
687 
688     /**
689      * Reseeds the secure random number generator with the current time in
690      * milliseconds.
691      * <p>
692      * Will create and initialize if null.
693      * </p>
694      */
695     public void reSeedSecure() {
696         getSecRan().setSeed(System.currentTimeMillis());
697     }
698 
699     /**
700      * Reseeds the secure random number generator with the supplied seed.
701      * <p>
702      * Will create and initialize if null.
703      * </p>
704      *
705      * @param seed the seed value to use
706      */
707     public void reSeedSecure(long seed) {
708         getSecRan().setSeed(seed);
709     }
710 
711     /**
712      * Reseeds the random number generator with
713      * {@code System.currentTimeMillis() + System.identityHashCode(this))}.
714      */
715     public void reSeed() {
716         getRandomGenerator().setSeed(System.currentTimeMillis() + System.identityHashCode(this));
717     }
718 
719     /**
720      * Sets the PRNG algorithm for the underlying SecureRandom instance using
721      * the Security Provider API. The Security Provider API is defined in <a
722      * href =
723      * "http://java.sun.com/j2se/1.3/docs/guide/security/CryptoSpec.html#AppA">
724      * Java Cryptography Architecture API Specification & Reference.</a>
725      * <p>
726      * <strong>USAGE NOTE:</strong> This method carries <i>significant</i>
727      * overhead and may take several seconds to execute.
728      * </p>
729      *
730      * @param algorithm the name of the PRNG algorithm
731      * @param provider the name of the provider
732      * @throws NoSuchAlgorithmException if the specified algorithm is not available
733      * @throws NoSuchProviderException if the specified provider is not installed
734      */
735     public void setSecureAlgorithm(String algorithm, String provider)
736             throws NoSuchAlgorithmException, NoSuchProviderException {
737         secRand = RandomGeneratorFactory.createRandomGenerator(SecureRandom.getInstance(algorithm, provider));
738     }
739 
740     /**
741      * Returns the RandomGenerator used to generate non-secure random data.
742      * <p>
743      * Creates and initializes a default generator if null. Uses a {@link Well19937c}
744      * generator with {@code System.currentTimeMillis() + System.identityHashCode(this))}
745      * as the default seed.
746      * </p>
747      *
748      * @return the Random used to generate random data
749      * @since 3.2
750      */
751     public RandomGenerator getRandomGenerator() {
752         if (rand == null) {
753             initRan();
754         }
755         return rand;
756     }
757 
758     /**
759      * Sets the default generator to a {@link Well19937c} generator seeded with
760      * {@code System.currentTimeMillis() + System.identityHashCode(this))}.
761      */
762     private void initRan() {
763         rand = new Well19937c(System.currentTimeMillis() + System.identityHashCode(this));
764     }
765 
766     /**
767      * Returns the SecureRandom used to generate secure random data.
768      * <p>
769      * Creates and initializes if null.  Uses
770      * {@code System.currentTimeMillis() + System.identityHashCode(this)} as the default seed.
771      * </p>
772      *
773      * @return the SecureRandom used to generate secure random data, wrapped in a
774      * {@link RandomGenerator}.
775      */
776     private RandomGenerator getSecRan() {
777         if (secRand == null) {
778             secRand = RandomGeneratorFactory.createRandomGenerator(new SecureRandom());
779             secRand.setSeed(System.currentTimeMillis() + System.identityHashCode(this));
780         }
781         return secRand;
782     }
783 }