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