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