001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.math3.random;
019
020import java.io.Serializable;
021import java.security.MessageDigest;
022import java.security.NoSuchAlgorithmException;
023import java.security.NoSuchProviderException;
024import java.security.SecureRandom;
025import java.util.Collection;
026
027import org.apache.commons.math3.distribution.BetaDistribution;
028import org.apache.commons.math3.distribution.BinomialDistribution;
029import org.apache.commons.math3.distribution.CauchyDistribution;
030import org.apache.commons.math3.distribution.ChiSquaredDistribution;
031import org.apache.commons.math3.distribution.ExponentialDistribution;
032import org.apache.commons.math3.distribution.FDistribution;
033import org.apache.commons.math3.distribution.GammaDistribution;
034import org.apache.commons.math3.distribution.HypergeometricDistribution;
035import org.apache.commons.math3.distribution.PascalDistribution;
036import org.apache.commons.math3.distribution.PoissonDistribution;
037import org.apache.commons.math3.distribution.TDistribution;
038import org.apache.commons.math3.distribution.WeibullDistribution;
039import org.apache.commons.math3.distribution.ZipfDistribution;
040import org.apache.commons.math3.distribution.UniformIntegerDistribution;
041import org.apache.commons.math3.exception.MathInternalError;
042import org.apache.commons.math3.exception.NotANumberException;
043import org.apache.commons.math3.exception.NotFiniteNumberException;
044import org.apache.commons.math3.exception.NotPositiveException;
045import org.apache.commons.math3.exception.NotStrictlyPositiveException;
046import org.apache.commons.math3.exception.NumberIsTooLargeException;
047import org.apache.commons.math3.exception.OutOfRangeException;
048import org.apache.commons.math3.exception.util.LocalizedFormats;
049import org.apache.commons.math3.util.MathArrays;
050
051/**
052 * Implements the {@link RandomData} interface using a {@link RandomGenerator}
053 * instance to generate non-secure data and a {@link java.security.SecureRandom}
054 * instance to provide data for the <code>nextSecureXxx</code> methods. If no
055 * <code>RandomGenerator</code> is provided in the constructor, the default is
056 * to use a {@link Well19937c} generator. To plug in a different
057 * implementation, either implement <code>RandomGenerator</code> directly or
058 * extend {@link AbstractRandomGenerator}.
059 * <p>
060 * Supports reseeding the underlying pseudo-random number generator (PRNG). The
061 * <code>SecurityProvider</code> and <code>Algorithm</code> used by the
062 * <code>SecureRandom</code> instance can also be reset.
063 * </p>
064 * <p>
065 * For details on the default PRNGs, see {@link java.util.Random} and
066 * {@link java.security.SecureRandom}.
067 * </p>
068 * <p>
069 * <strong>Usage Notes</strong>:
070 * <ul>
071 * <li>
072 * Instance variables are used to maintain <code>RandomGenerator</code> and
073 * <code>SecureRandom</code> instances used in data generation. Therefore, to
074 * generate a random sequence of values or strings, you should use just
075 * <strong>one</strong> <code>RandomDataImpl</code> instance repeatedly.</li>
076 * <li>
077 * The "secure" methods are *much* slower. These should be used only when a
078 * cryptographically secure random sequence is required. A secure random
079 * sequence is a sequence of pseudo-random values which, in addition to being
080 * well-dispersed (so no subsequence of values is an any more likely than other
081 * subsequence of the the same length), also has the additional property that
082 * knowledge of values generated up to any point in the sequence does not make
083 * it any easier to predict subsequent values.</li>
084 * <li>
085 * When a new <code>RandomDataImpl</code> is created, the underlying random
086 * number generators are <strong>not</strong> initialized. If you do not
087 * explicitly seed the default non-secure generator, it is seeded with the
088 * current time in milliseconds plus the system identity hash code on first use.
089 * The same holds for the secure generator. If you provide a <code>RandomGenerator</code>
090 * to the constructor, however, this generator is not reseeded by the constructor
091 * nor is it reseeded on first use.</li>
092 * <li>
093 * The <code>reSeed</code> and <code>reSeedSecure</code> methods delegate to the
094 * corresponding methods on the underlying <code>RandomGenerator</code> and
095 * <code>SecureRandom</code> instances. Therefore, <code>reSeed(long)</code>
096 * fully resets the initial state of the non-secure random number generator (so
097 * that reseeding with a specific value always results in the same subsequent
098 * random sequence); whereas reSeedSecure(long) does <strong>not</strong>
099 * 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 */
113public 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}