    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
    018    package org.apache.commons.math3.random;
    019
    020    import java.io.Serializable;
    021    import java.security.MessageDigest;
    022    import java.security.NoSuchAlgorithmException;
    023    import java.security.NoSuchProviderException;
    024    import java.security.SecureRandom;
    025    import java.util.Collection;
    026
    027    import org.apache.commons.math3.distribution.BetaDistribution;
    028    import org.apache.commons.math3.distribution.BinomialDistribution;
    029    import org.apache.commons.math3.distribution.CauchyDistribution;
    030    import org.apache.commons.math3.distribution.ChiSquaredDistribution;
    031    import org.apache.commons.math3.distribution.ExponentialDistribution;
    032    import org.apache.commons.math3.distribution.FDistribution;
    033    import org.apache.commons.math3.distribution.GammaDistribution;
    034    import org.apache.commons.math3.distribution.HypergeometricDistribution;
    035    import org.apache.commons.math3.distribution.PascalDistribution;
    036    import org.apache.commons.math3.distribution.PoissonDistribution;
    037    import org.apache.commons.math3.distribution.TDistribution;
    038    import org.apache.commons.math3.distribution.WeibullDistribution;
    039    import org.apache.commons.math3.distribution.ZipfDistribution;
    040    import org.apache.commons.math3.exception.MathInternalError;
    041    import org.apache.commons.math3.exception.NotANumberException;
    042    import org.apache.commons.math3.exception.NotFiniteNumberException;
    043    import org.apache.commons.math3.exception.NotPositiveException;
    044    import org.apache.commons.math3.exception.NotStrictlyPositiveException;
    045    import org.apache.commons.math3.exception.NumberIsTooLargeException;
    046    import org.apache.commons.math3.exception.OutOfRangeException;
    047    import org.apache.commons.math3.exception.util.LocalizedFormats;
    048    import org.apache.commons.math3.util.FastMath;
    049
    050    /**
    051     * Implements the {@link RandomData} interface using a {@link RandomGenerator}
    052     * instance to generate non-secure data and a {@link java.security.SecureRandom}
    053     * instance to provide data for the <code>nextSecureXxx</code> methods. If no
    054     * <code>RandomGenerator</code> is provided in the constructor, the default is
    055     * to use a {@link Well19937c} generator. To plug in a different
    056     * implementation, either implement <code>RandomGenerator</code> directly or
    057     * extend {@link AbstractRandomGenerator}.
    058     * <p>
    059     * Supports reseeding the underlying pseudo-random number generator (PRNG). The
    060     * <code>SecurityProvider</code> and <code>Algorithm</code> used by the
    061     * <code>SecureRandom</code> instance can also be reset.
    062     * </p>
    063     * <p>
    064     * For details on the default PRNGs, see {@link java.util.Random} and
    065     * {@link java.security.SecureRandom}.
    066     * </p>
    067     * <p>
    068     * <strong>Usage Notes</strong>:
    069     * <ul>
    070     * <li>
    071     * Instance variables are used to maintain <code>RandomGenerator</code> and
    072     * <code>SecureRandom</code> instances used in data generation. Therefore, to
    073     * generate a random sequence of values or strings, you should use just
    074     * <strong>one</strong> <code>RandomDataImpl</code> instance repeatedly.</li>
    075     * <li>
    076     * The "secure" methods are *much* slower. These should be used only when a
    077     * cryptographically secure random sequence is required. A secure random
    078     * sequence is a sequence of pseudo-random values which, in addition to being
    079     * well-dispersed (so no subsequence of values is an any more likely than other
    080     * subsequence of the the same length), also has the additional property that
    081     * knowledge of values generated up to any point in the sequence does not make
    082     * it any easier to predict subsequent values.</li>
    083     * <li>
    084     * When a new <code>RandomDataImpl</code> is created, the underlying random
    085     * number generators are <strong>not</strong> initialized. If you do not
    086     * explicitly seed the default non-secure generator, it is seeded with the
    087     * current time in milliseconds plus the system identity hash code on first use.
    088     * The same holds for the secure generator. If you provide a <code>RandomGenerator</code>
    089     * to the constructor, however, this generator is not reseeded by the constructor
    090     * nor is it reseeded on first use.</li>
    091     * <li>
    092     * The <code>reSeed</code> and <code>reSeedSecure</code> methods delegate to the
    093     * corresponding methods on the underlying <code>RandomGenerator</code> and
    094     * <code>SecureRandom</code> instances. Therefore, <code>reSeed(long)</code>
    095     * fully resets the initial state of the non-secure random number generator (so
    096     * that reseeding with a specific value always results in the same subsequent
    097     * random sequence); whereas reSeedSecure(long) does <strong>not</strong>
    098     * reinitialize the secure random number generator (so secure sequences started
    099     * with calls to reseedSecure(long) won't be identical).</li>
    100     * <li>
    101     * This implementation is not synchronized. The underlying <code>RandomGenerator</code>
    102     * or <code>SecureRandom</code> instances are not protected by synchronization and
    103     * are not guaranteed to be thread-safe.  Therefore, if an instance of this class
    104     * is concurrently utilized by multiple threads, it is the responsibility of
    105     * client code to synchronize access to seeding and data generation methods.
    106     * </li>
    107     * </ul>
    108     * </p>
    109     * @since 3.1
    110     * @version $Id: RandomDataGenerator.java 1422313 2012-12-15 18:53:41Z psteitz $
    111     */
    112    public class RandomDataGenerator implements RandomData, Serializable {
    113
    114        /** Serializable version identifier */
    115        private static final long serialVersionUID = -626730818244969716L;
    116
    117        /** underlying random number generator */
    118        private RandomGenerator rand = null;
    119
    120        /** underlying secure random number generator */
    121        private SecureRandom 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 = getRan();
    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(int lower, int upper) throws NumberIsTooLargeException {
    198            if (lower >= upper) {
    199                throw new NumberIsTooLargeException(LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
    200                                                    lower, upper, false);
    201            }
    202            double r = getRan().nextDouble();
    203            double scaled = r * upper + (1.0 - r) * lower + r;
    204            return (int) FastMath.floor(scaled);
    205        }
    206
    207        /** {@inheritDoc} */
    208        public long nextLong(long lower, long upper) throws NumberIsTooLargeException {
    209            if (lower >= upper) {
    210                throw new NumberIsTooLargeException(LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
    211                                                    lower, upper, false);
    212            }
    213            double r = getRan().nextDouble();
    214            double scaled = r * upper + (1.0 - r) * lower + r;
    215            return (long)FastMath.floor(scaled);
    216        }
    217
    218        /**
    219         * {@inheritDoc}
    220         * <p>
    221         * <strong>Algorithm Description:</strong> hex strings are generated in
    222         * 40-byte segments using a 3-step process.
    223         * <ol>
    224         * <li>
    225         * 20 random bytes are generated using the underlying
    226         * <code>SecureRandom</code>.</li>
    227         * <li>
    228         * SHA-1 hash is applied to yield a 20-byte binary digest.</li>
    229         * <li>
    230         * Each byte of the binary digest is converted to 2 hex digits.</li>
    231         * </ol>
    232         * </p>
    233         * @throws NotStrictlyPositiveException if {@code len <= 0}
    234         */
    235        public String nextSecureHexString(int len) throws NotStrictlyPositiveException {
    236            if (len <= 0) {
    237                throw new NotStrictlyPositiveException(LocalizedFormats.LENGTH, len);
    238            }
    239
    240            // Get SecureRandom and setup Digest provider
    241            SecureRandom secRan = getSecRan();
    242            MessageDigest alg = null;
    243            try {
    244                alg = MessageDigest.getInstance("SHA-1");
    245            } catch (NoSuchAlgorithmException ex) {
    246                // this should never happen
    247                throw new MathInternalError(ex);
    248            }
    249            alg.reset();
    250
    251            // Compute number of iterations required (40 bytes each)
    252            int numIter = (len / 40) + 1;
    253
    254            StringBuilder outBuffer = new StringBuilder();
    255            for (int iter = 1; iter < numIter + 1; iter++) {
    256                byte[] randomBytes = new byte[40];
    257                secRan.nextBytes(randomBytes);
    258                alg.update(randomBytes);
    259
    260                // Compute hash -- will create 20-byte binary hash
    261                byte[] hash = alg.digest();
    262
    263                // Loop over the hash, converting each byte to 2 hex digits
    264                for (int i = 0; i < hash.length; i++) {
    265                    Integer c = Integer.valueOf(hash[i]);
    266
    267                    /*
    268                     * Add 128 to byte value to make interval 0-255 This guarantees
    269                     * <= 2 hex digits from toHexString() toHexString would
    270                     * otherwise add 2^32 to negative arguments
    271                     */
    272                    String hex = Integer.toHexString(c.intValue() + 128);
    273
    274                    // Keep strings uniform length -- guarantees 40 bytes
    275                    if (hex.length() == 1) {
    276                        hex = "0" + hex;
    277                    }
    278                    outBuffer.append(hex);
    279                }
    280            }
    281            return outBuffer.toString().substring(0, len);
    282        }
    283
    284        /**  {@inheritDoc} */
    285        public int nextSecureInt(int lower, int upper) throws NumberIsTooLargeException {
    286            if (lower >= upper) {
    287                throw new NumberIsTooLargeException(LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
    288                                                    lower, upper, false);
    289            }
    290            SecureRandom sec = getSecRan();
    291            final double r = sec.nextDouble();
    292            final double scaled = r * upper + (1.0 - r) * lower + r;
    293            return (int)FastMath.floor(scaled);
    294        }
    295
    296        /** {@inheritDoc} */
    297        public long nextSecureLong(long lower, long upper) throws NumberIsTooLargeException {
    298            if (lower >= upper) {
    299                throw new NumberIsTooLargeException(LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
    300                                                    lower, upper, false);
    301            }
    302            SecureRandom sec = getSecRan();
    303            final double r = sec.nextDouble();
    304            final double scaled = r * upper + (1.0 - r) * lower + r;
    305            return (long)FastMath.floor(scaled);
    306        }
    307
    308        /**
    309         * {@inheritDoc}
    310         * <p>
    311         * <strong>Algorithm Description</strong>:
    312         * <ul><li> For small means, uses simulation of a Poisson process
    313         * using Uniform deviates, as described
    314         * <a href="http://irmi.epfl.ch/cmos/Pmmi/interactive/rng7.htm"> here.</a>
    315         * The Poisson process (and hence value returned) is bounded by 1000 * mean.</li>
    316         *
    317         * <li> For large means, uses the rejection algorithm described in <br/>
    318         * Devroye, Luc. (1981).<i>The Computer Generation of Poisson Random Variables</i>
    319         * <strong>Computing</strong> vol. 26 pp. 197-207.</li></ul></p>
    320         * @throws NotStrictlyPositiveException if {@code len <= 0}
    321         */
    322        public long nextPoisson(double mean) throws NotStrictlyPositiveException {
    323            return new PoissonDistribution(getRan(), mean,
    324                    PoissonDistribution.DEFAULT_EPSILON,
    325                    PoissonDistribution.DEFAULT_MAX_ITERATIONS).sample();
    326        }
    327
    328        /** {@inheritDoc} */
    329        public double nextGaussian(double mu, double sigma) throws NotStrictlyPositiveException {
    330            if (sigma <= 0) {
    331                throw new NotStrictlyPositiveException(LocalizedFormats.STANDARD_DEVIATION, sigma);
    332            }
    333            return sigma * getRan().nextGaussian() + mu;
    334        }
    335
    336        /**
    337         * {@inheritDoc}
    338         *
    339         * <p>
    340         * <strong>Algorithm Description</strong>: Uses the Algorithm SA (Ahrens)
    341         * from p. 876 in:
    342         * [1]: Ahrens, J. H. and Dieter, U. (1972). Computer methods for
    343         * sampling from the exponential and normal distributions.
    344         * Communications of the ACM, 15, 873-882.
    345         * </p>
    346         */
    347        public double nextExponential(double mean) throws NotStrictlyPositiveException {
    348            return new ExponentialDistribution(getRan(), mean,
    349                    ExponentialDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
    350        }
    351
    352        /**
    353         * <p>Generates a random value from the
    354         * {@link org.apache.commons.math3.distribution.GammaDistribution Gamma Distribution}.</p>
    355         *
    356         * <p>This implementation uses the following algorithms: </p>
    357         *
    358         * <p>For 0 < shape < 1: <br/>
    359         * Ahrens, J. H. and Dieter, U., <i>Computer methods for
    360         * sampling from gamma, beta, Poisson and binomial distributions.</i>
    361         * Computing, 12, 223-246, 1974.</p>
    362         *
    363         * <p>For shape >= 1: <br/>
    364         * Marsaglia and Tsang, <i>A Simple Method for Generating
    365         * Gamma Variables.</i> ACM Transactions on Mathematical Software,
    366         * Volume 26 Issue 3, September, 2000.</p>
    367         *
    368         * @param shape the median of the Gamma distribution
    369         * @param scale the scale parameter of the Gamma distribution
    370         * @return random value sampled from the Gamma(shape, scale) distribution
    371         * @throws NotStrictlyPositiveException if {@code shape <= 0} or
    372         * {@code scale <= 0}.
    373         */
    374        public double nextGamma(double shape, double scale) throws NotStrictlyPositiveException {
    375            return new GammaDistribution(getRan(),shape, scale,
    376                    GammaDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
    377        }
    378
    379        /**
    380         * Generates a random value from the {@link HypergeometricDistribution Hypergeometric Distribution}.
    381         *
    382         * @param populationSize the population size of the Hypergeometric distribution
    383         * @param numberOfSuccesses number of successes in the population of the Hypergeometric distribution
    384         * @param sampleSize the sample size of the Hypergeometric distribution
    385         * @return random value sampled from the Hypergeometric(numberOfSuccesses, sampleSize) distribution
    386         * @throws NumberIsTooLargeException  if {@code numberOfSuccesses > populationSize},
    387         * or {@code sampleSize > populationSize}.
    388         * @throws NotStrictlyPositiveException if {@code populationSize <= 0}.
    389         * @throws NotPositiveException  if {@code numberOfSuccesses < 0}.
    390         */
    391        public int nextHypergeometric(int populationSize, int numberOfSuccesses, int sampleSize) throws NotPositiveException, NotStrictlyPositiveException, NumberIsTooLargeException {
    392            return new HypergeometricDistribution(getRan(),populationSize,
    393                    numberOfSuccesses, sampleSize).sample();
    394        }
    395
    396        /**
    397         * Generates a random value from the {@link PascalDistribution Pascal Distribution}.
    398         *
    399         * @param r the number of successes of the Pascal distribution
    400         * @param p the probability of success of the Pascal distribution
    401         * @return random value sampled from the Pascal(r, p) distribution
    402         * @throws NotStrictlyPositiveException if the number of successes is not positive
    403         * @throws OutOfRangeException if the probability of success is not in the
    404         * range {@code [0, 1]}.
    405         */
    406        public int nextPascal(int r, double p) throws NotStrictlyPositiveException, OutOfRangeException {
    407            return new PascalDistribution(getRan(), r, p).sample();
    408        }
    409
    410        /**
    411         * Generates a random value from the {@link TDistribution T Distribution}.
    412         *
    413         * @param df the degrees of freedom of the T distribution
    414         * @return random value from the T(df) distribution
    415         * @throws NotStrictlyPositiveException if {@code df <= 0}
    416         */
    417        public double nextT(double df) throws NotStrictlyPositiveException {
    418            return new TDistribution(getRan(), df,
    419                    TDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
    420        }
    421
    422        /**
    423         * Generates a random value from the {@link WeibullDistribution Weibull Distribution}.
    424         *
    425         * @param shape the shape parameter of the Weibull distribution
    426         * @param scale the scale parameter of the Weibull distribution
    427         * @return random value sampled from the Weibull(shape, size) distribution
    428         * @throws NotStrictlyPositiveException if {@code shape <= 0} or
    429         * {@code scale <= 0}.
    430         */
    431        public double nextWeibull(double shape, double scale) throws NotStrictlyPositiveException {
    432            return new WeibullDistribution(getRan(), shape, scale,
    433                    WeibullDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
    434        }
    435
    436        /**
    437         * Generates a random value from the {@link ZipfDistribution Zipf Distribution}.
    438         *
    439         * @param numberOfElements the number of elements of the ZipfDistribution
    440         * @param exponent the exponent of the ZipfDistribution
    441         * @return random value sampled from the Zipf(numberOfElements, exponent) distribution
    442         * @exception NotStrictlyPositiveException if {@code numberOfElements <= 0}
    443         * or {@code exponent <= 0}.
    444         */
    445        public int nextZipf(int numberOfElements, double exponent) throws NotStrictlyPositiveException {
    446            return new ZipfDistribution(getRan(), numberOfElements, exponent).sample();
    447        }
    448
    449        /**
    450         * Generates a random value from the {@link BetaDistribution Beta Distribution}.
    451         *
    452         * @param alpha first distribution shape parameter
    453         * @param beta second distribution shape parameter
    454         * @return random value sampled from the beta(alpha, beta) distribution
    455         */
    456        public double nextBeta(double alpha, double beta) {
    457            return new BetaDistribution(getRan(), alpha, beta,
    458                    BetaDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
    459        }
    460
    461        /**
    462         * Generates a random value from the {@link BinomialDistribution Binomial Distribution}.
    463         *
    464         * @param numberOfTrials number of trials of the Binomial distribution
    465         * @param probabilityOfSuccess probability of success of the Binomial distribution
    466         * @return random value sampled from the Binomial(numberOfTrials, probabilityOfSuccess) distribution
    467         */
    468        public int nextBinomial(int numberOfTrials, double probabilityOfSuccess) {
    469            return new BinomialDistribution(getRan(), numberOfTrials, probabilityOfSuccess).sample();
    470        }
    471
    472        /**
    473         * Generates a random value from the {@link CauchyDistribution Cauchy Distribution}.
    474         *
    475         * @param median the median of the Cauchy distribution
    476         * @param scale the scale parameter of the Cauchy distribution
    477         * @return random value sampled from the Cauchy(median, scale) distribution
    478         */
    479        public double nextCauchy(double median, double scale) {
    480            return new CauchyDistribution(getRan(), median, scale,
    481                    CauchyDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
    482        }
    483
    484        /**
    485         * Generates a random value from the {@link ChiSquaredDistribution ChiSquare Distribution}.
    486         *
    487         * @param df the degrees of freedom of the ChiSquare distribution
    488         * @return random value sampled from the ChiSquare(df) distribution
    489         */
    490        public double nextChiSquare(double df) {
    491            return new ChiSquaredDistribution(getRan(), df,
    492                    ChiSquaredDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
    493        }
    494
    495        /**
    496         * Generates a random value from the {@link FDistribution F Distribution}.
    497         *
    498         * @param numeratorDf the numerator degrees of freedom of the F distribution
    499         * @param denominatorDf the denominator degrees of freedom of the F distribution
    500         * @return random value sampled from the F(numeratorDf, denominatorDf) distribution
    501         * @throws NotStrictlyPositiveException if
    502         * {@code numeratorDf <= 0} or {@code denominatorDf <= 0}.
    503         */
    504        public double nextF(double numeratorDf, double denominatorDf) throws NotStrictlyPositiveException {
    505            return new FDistribution(getRan(), numeratorDf, denominatorDf,
    506                    FDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY).sample();
    507        }
    508
    509        /**
    510         * {@inheritDoc}
    511         *
    512         * <p>
    513         * <strong>Algorithm Description</strong>: scales the output of
    514         * Random.nextDouble(), but rejects 0 values (i.e., will generate another
    515         * random double if Random.nextDouble() returns 0). This is necessary to
    516         * provide a symmetric output interval (both endpoints excluded).
    517         * </p>
    518         * @throws NumberIsTooLargeException if {@code lower >= upper}
    519         * @throws NotFiniteNumberException if one of the bounds is infinite
    520         * @throws NotANumberException if one of the bounds is NaN
    521         */
    522        public double nextUniform(double lower, double upper)
    523            throws NumberIsTooLargeException, NotFiniteNumberException, NotANumberException {
    524            return nextUniform(lower, upper, false);
    525        }
    526
    527        /**
    528         * {@inheritDoc}
    529         *
    530         * <p>
    531         * <strong>Algorithm Description</strong>: if the lower bound is excluded,
    532         * scales the output of Random.nextDouble(), but rejects 0 values (i.e.,
    533         * will generate another random double if Random.nextDouble() returns 0).
    534         * This is necessary to provide a symmetric output interval (both
    535         * endpoints excluded).
    536         * </p>
    537         *
    538         * @throws NumberIsTooLargeException if {@code lower >= upper}
    539         * @throws NotFiniteNumberException if one of the bounds is infinite
    540         * @throws NotANumberException if one of the bounds is NaN
    541         */
    542        public double nextUniform(double lower, double upper, boolean lowerInclusive)
    543            throws NumberIsTooLargeException, NotFiniteNumberException, NotANumberException {
    544
    545            if (lower >= upper) {
    546                throw new NumberIsTooLargeException(LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
    547                                                    lower, upper, false);
    548            }
    549
    550            if (Double.isInfinite(lower)) {
    551                throw new NotFiniteNumberException(LocalizedFormats.INFINITE_BOUND, lower);
    552            }
    553            if (Double.isInfinite(upper)) {
    554                throw new NotFiniteNumberException(LocalizedFormats.INFINITE_BOUND, upper);
    555            }
    556
    557            if (Double.isNaN(lower) || Double.isNaN(upper)) {
    558                throw new NotANumberException();
    559            }
    560
    561            final RandomGenerator generator = getRan();
    562
    563            // ensure nextDouble() isn't 0.0
    564            double u = generator.nextDouble();
    565            while (!lowerInclusive && u <= 0.0) {
    566                u = generator.nextDouble();
    567            }
    568
    569            return u * upper + (1.0 - u) * lower;
    570        }
    571
    572        /**
    573         * {@inheritDoc}
    574         *
    575         * <p>
    576         * Uses a 2-cycle permutation shuffle. The shuffling process is described <a
    577         * href="http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node83.html">
    578         * here</a>.
    579         * </p>
    580         * @throws NumberIsTooLargeException if {@code k > n}.
    581         * @throws NotStrictlyPositiveException if {@code k <= 0}.
    582         */
    583        public int[] nextPermutation(int n, int k)
    584            throws NumberIsTooLargeException, NotStrictlyPositiveException {
    585            if (k > n) {
    586                throw new NumberIsTooLargeException(LocalizedFormats.PERMUTATION_EXCEEDS_N,
    587                                                    k, n, true);
    588            }
    589            if (k <= 0) {
    590                throw new NotStrictlyPositiveException(LocalizedFormats.PERMUTATION_SIZE,
    591                                                       k);
    592            }
    593
    594            int[] index = getNatural(n);
    595            shuffle(index, n - k);
    596            int[] result = new int[k];
    597            for (int i = 0; i < k; i++) {
    598                result[i] = index[n - i - 1];
    599            }
    600
    601            return result;
    602        }
    603
    604        /**
    605         * {@inheritDoc}
    606         *
    607         * <p>
    608         * <strong>Algorithm Description</strong>: Uses a 2-cycle permutation
    609         * shuffle to generate a random permutation of <code>c.size()</code> and
    610         * then returns the elements whose indexes correspond to the elements of the
    611         * generated permutation. This technique is described, and proven to
    612         * generate random samples <a
    613         * href="http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node83.html">
    614         * here</a>
    615         * </p>
    616         */
    617        public Object[] nextSample(Collection<?> c, int k) throws NumberIsTooLargeException, NotStrictlyPositiveException {
    618
    619            int len = c.size();
    620            if (k > len) {
    621                throw new NumberIsTooLargeException(LocalizedFormats.SAMPLE_SIZE_EXCEEDS_COLLECTION_SIZE,
    622                                                    k, len, true);
    623            }
    624            if (k <= 0) {
    625                throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_SAMPLES, k);
    626            }
    627
    628            Object[] objects = c.toArray();
    629            int[] index = nextPermutation(len, k);
    630            Object[] result = new Object[k];
    631            for (int i = 0; i < k; i++) {
    632                result[i] = objects[index[i]];
    633            }
    634            return result;
    635        }
    636
    637
    638
    639        /**
    640         * Reseeds the random number generator with the supplied seed.
    641         * <p>
    642         * Will create and initialize if null.
    643         * </p>
    644         *
    645         * @param seed the seed value to use
    646         */
    647        public void reSeed(long seed) {
    648           getRan().setSeed(seed);
    649        }
    650
    651        /**
    652         * Reseeds the secure random number generator with the current time in
    653         * milliseconds.
    654         * <p>
    655         * Will create and initialize if null.
    656         * </p>
    657         */
    658        public void reSeedSecure() {
    659            getSecRan().setSeed(System.currentTimeMillis());
    660        }
    661
    662        /**
    663         * Reseeds the secure random number generator with the supplied seed.
    664         * <p>
    665         * Will create and initialize if null.
    666         * </p>
    667         *
    668         * @param seed the seed value to use
    669         */
    670        public void reSeedSecure(long seed) {
    671            getSecRan().setSeed(seed);
    672        }
    673
    674        /**
    675         * Reseeds the random number generator with
    676         * {@code System.currentTimeMillis() + System.identityHashCode(this))}.
    677         */
    678        public void reSeed() {
    679            getRan().setSeed(System.currentTimeMillis() + System.identityHashCode(this));
    680        }
    681
    682        /**
    683         * Sets the PRNG algorithm for the underlying SecureRandom instance using
    684         * the Security Provider API. The Security Provider API is defined in <a
    685         * href =
    686         * "http://java.sun.com/j2se/1.3/docs/guide/security/CryptoSpec.html#AppA">
    687         * Java Cryptography Architecture API Specification & Reference.</a>
    688         * <p>
    689         * <strong>USAGE NOTE:</strong> This method carries <i>significant</i>
    690         * overhead and may take several seconds to execute.
    691         * </p>
    692         *
    693         * @param algorithm the name of the PRNG algorithm
    694         * @param provider the name of the provider
    695         * @throws NoSuchAlgorithmException if the specified algorithm is not available
    696         * @throws NoSuchProviderException if the specified provider is not installed
    697         */
    698        public void setSecureAlgorithm(String algorithm, String provider)
    699                throws NoSuchAlgorithmException, NoSuchProviderException {
    700            secRand = SecureRandom.getInstance(algorithm, provider);
    701        }
    702
    703        /**
    704         * Returns the RandomGenerator used to generate non-secure random data.
    705         * <p>
    706         * Creates and initializes a default generator if null. Uses a {@link Well19937c}
    707         * generator with {@code System.currentTimeMillis() + System.identityHashCode(this))}
    708         * as the default seed.
    709         * </p>
    710         *
    711         * @return the Random used to generate random data
    712         */
    713        private RandomGenerator getRan() {
    714            if (rand == null) {
    715                initRan();
    716            }
    717            return rand;
    718        }
    719
    720        /**
    721         * Sets the default generator to a {@link Well19937c} generator seeded with
    722         * {@code System.currentTimeMillis() + System.identityHashCode(this))}.
    723         */
    724        private void initRan() {
    725            rand = new Well19937c(System.currentTimeMillis() + System.identityHashCode(this));
    726        }
    727
    728        /**
    729         * Returns the SecureRandom used to generate secure random data.
    730         * <p>
    731         * Creates and initializes if null.  Uses
    732         * {@code System.currentTimeMillis() + System.identityHashCode(this)} as the default seed.
    733         * </p>
    734         *
    735         * @return the SecureRandom used to generate secure random data
    736         */
    737        private SecureRandom getSecRan() {
    738            if (secRand == null) {
    739                secRand = new SecureRandom();
    740                secRand.setSeed(System.currentTimeMillis() + System.identityHashCode(this));
    741            }
    742            return secRand;
    743        }
    744
    745        /**
    746         * Uses a 2-cycle permutation shuffle to randomly re-order the last elements
    747         * of list.
    748         *
    749         * @param list list to be shuffled
    750         * @param end element past which shuffling begins
    751         */
    752        private void shuffle(int[] list, int end) {
    753            int target = 0;
    754            for (int i = list.length - 1; i >= end; i--) {
    755                if (i == 0) {
    756                    target = 0;
    757                } else {
    758                    // NumberIsTooLargeException cannot occur
    759                    target = nextInt(0, i);
    760                }
    761                int temp = list[target];
    762                list[target] = list[i];
    763                list[i] = temp;
    764            }
    765        }
    766
    767        /**
    768         * Returns an array representing n.
    769         *
    770         * @param n the natural number to represent
    771         * @return array with entries = elements of n
    772         */
    773        private int[] getNatural(int n) {
    774            int[] natural = new int[n];
    775            for (int i = 0; i < n; i++) {
    776                natural[i] = i;
    777            }
    778            return natural;
    779        }
    780    }