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 */
112public 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}