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.distribution;
019
020import org.apache.commons.math3.exception.NumberIsTooLargeException;
021import org.apache.commons.math3.exception.util.LocalizedFormats;
022import org.apache.commons.math3.random.RandomGenerator;
023import org.apache.commons.math3.random.Well19937c;
024
025/**
026 * Implementation of the uniform integer distribution.
027 *
028 * @see <a href="http://en.wikipedia.org/wiki/Uniform_distribution_(discrete)"
029 * >Uniform distribution (discrete), at Wikipedia</a>
030 *
031 * @since 3.0
032 */
033public class UniformIntegerDistribution extends AbstractIntegerDistribution {
034    /** Serializable version identifier. */
035    private static final long serialVersionUID = 20120109L;
036    /** Lower bound (inclusive) of this distribution. */
037    private final int lower;
038    /** Upper bound (inclusive) of this distribution. */
039    private final int upper;
040
041    /**
042     * Creates a new uniform integer distribution using the given lower and
043     * upper bounds (both inclusive).
044     * <p>
045     * <b>Note:</b> this constructor will implicitly create an instance of
046     * {@link Well19937c} as random generator to be used for sampling only (see
047     * {@link #sample()} and {@link #sample(int)}). In case no sampling is
048     * needed for the created distribution, it is advised to pass {@code null}
049     * as random generator via the appropriate constructors to avoid the
050     * additional initialisation overhead.
051     *
052     * @param lower Lower bound (inclusive) of this distribution.
053     * @param upper Upper bound (inclusive) of this distribution.
054     * @throws NumberIsTooLargeException if {@code lower >= upper}.
055     */
056    public UniformIntegerDistribution(int lower, int upper)
057        throws NumberIsTooLargeException {
058        this(new Well19937c(), lower, upper);
059    }
060
061    /**
062     * Creates a new uniform integer distribution using the given lower and
063     * upper bounds (both inclusive).
064     *
065     * @param rng Random number generator.
066     * @param lower Lower bound (inclusive) of this distribution.
067     * @param upper Upper bound (inclusive) of this distribution.
068     * @throws NumberIsTooLargeException if {@code lower > upper}.
069     * @since 3.1
070     */
071    public UniformIntegerDistribution(RandomGenerator rng,
072                                      int lower,
073                                      int upper)
074        throws NumberIsTooLargeException {
075        super(rng);
076
077        if (lower > upper) {
078            throw new NumberIsTooLargeException(
079                            LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
080                            lower, upper, true);
081        }
082        this.lower = lower;
083        this.upper = upper;
084    }
085
086    /** {@inheritDoc} */
087    public double probability(int x) {
088        if (x < lower || x > upper) {
089            return 0;
090        }
091        return 1.0 / (upper - lower + 1);
092    }
093
094    /** {@inheritDoc} */
095    public double cumulativeProbability(int x) {
096        if (x < lower) {
097            return 0;
098        }
099        if (x > upper) {
100            return 1;
101        }
102        return (x - lower + 1.0) / (upper - lower + 1.0);
103    }
104
105    /**
106     * {@inheritDoc}
107     *
108     * For lower bound {@code lower} and upper bound {@code upper}, the mean is
109     * {@code 0.5 * (lower + upper)}.
110     */
111    public double getNumericalMean() {
112        return 0.5 * (lower + upper);
113    }
114
115    /**
116     * {@inheritDoc}
117     *
118     * For lower bound {@code lower} and upper bound {@code upper}, and
119     * {@code n = upper - lower + 1}, the variance is {@code (n^2 - 1) / 12}.
120     */
121    public double getNumericalVariance() {
122        double n = upper - lower + 1;
123        return (n * n - 1) / 12.0;
124    }
125
126    /**
127     * {@inheritDoc}
128     *
129     * The lower bound of the support is equal to the lower bound parameter
130     * of the distribution.
131     *
132     * @return lower bound of the support
133     */
134    public int getSupportLowerBound() {
135        return lower;
136    }
137
138    /**
139     * {@inheritDoc}
140     *
141     * The upper bound of the support is equal to the upper bound parameter
142     * of the distribution.
143     *
144     * @return upper bound of the support
145     */
146    public int getSupportUpperBound() {
147        return upper;
148    }
149
150    /**
151     * {@inheritDoc}
152     *
153     * The support of this distribution is connected.
154     *
155     * @return {@code true}
156     */
157    public boolean isSupportConnected() {
158        return true;
159    }
160
161    /** {@inheritDoc} */
162    @Override
163    public int sample() {
164        final int max = (upper - lower) + 1;
165        if (max <= 0) {
166            // The range is too wide to fit in a positive int (larger
167            // than 2^31); as it covers more than half the integer range,
168            // we use a simple rejection method.
169            while (true) {
170                final int r = random.nextInt();
171                if (r >= lower &&
172                    r <= upper) {
173                    return r;
174                }
175            }
176        } else {
177            // We can shift the range and directly generate a positive int.
178            return lower + random.nextInt(max);
179        }
180    }
181}