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 */
017package org.apache.commons.rng.sampling.distribution;
018
019import org.apache.commons.rng.UniformRandomProvider;
020
021/**
022 * Sampler for the <a href="http://mathworld.wolfram.com/PoissonDistribution.html">Poisson distribution</a>.
023 *
024 * <ul>
025 *  <li>
026 *   For small means, a Poisson process is simulated using uniform deviates, as described in
027 *   <blockquote>
028 *    Knuth (1969). <i>Seminumerical Algorithms</i>. The Art of Computer Programming,
029 *    Volume 2. Chapter 3.4.1.F.3 Important integer-valued distributions: The Poisson distribution.
030 *    Addison Wesley.
031 *   </blockquote>
032 *   The Poisson process (and hence, the returned value) is bounded by {@code 1000 * mean}.
033 *  </li>
034 *  <li>
035 *   For large means, we use the rejection algorithm described in
036 *   <blockquote>
037 *    Devroye, Luc. (1981). <i>The Computer Generation of Poisson Random Variables</i><br>
038 *    <strong>Computing</strong> vol. 26 pp. 197-207.
039 *   </blockquote>
040 *  </li>
041 * </ul>
042 *
043 * <p>Sampling uses:</p>
044 *
045 * <ul>
046 *   <li>{@link UniformRandomProvider#nextDouble()}
047 *   <li>{@link UniformRandomProvider#nextLong()} (large means only)
048 * </ul>
049 *
050 * @since 1.0
051 */
052public class PoissonSampler
053    extends SamplerBase
054    implements SharedStateDiscreteSampler {
055
056    /**
057     * Value for switching sampling algorithm.
058     *
059     * <p>Package scope for the {@link PoissonSamplerCache}.
060     */
061    static final double PIVOT = 40;
062    /** The internal Poisson sampler. */
063    private final SharedStateDiscreteSampler poissonSamplerDelegate;
064
065    /**
066     * This instance delegates sampling. Use the factory method
067     * {@link #of(UniformRandomProvider, double)} to create an optimal sampler.
068     *
069     * @param rng Generator of uniformly distributed random numbers.
070     * @param mean Mean.
071     * @throws IllegalArgumentException if {@code mean <= 0} or {@code mean > 0.5 *}
072     * {@link Integer#MAX_VALUE}.
073     */
074    public PoissonSampler(UniformRandomProvider rng,
075                          double mean) {
076        // Delegate all work to specialised samplers.
077        this(of(rng, mean));
078    }
079
080    /**
081     * @param delegate Poisson sampler.
082     */
083    private PoissonSampler(SharedStateDiscreteSampler delegate) {
084        super(null);
085        poissonSamplerDelegate = delegate;
086    }
087
088    /** {@inheritDoc} */
089    @Override
090    public int sample() {
091        return poissonSamplerDelegate.sample();
092    }
093
094    /** {@inheritDoc} */
095    @Override
096    public String toString() {
097        return poissonSamplerDelegate.toString();
098    }
099
100    /**
101     * {@inheritDoc}
102     *
103     * @since 1.3
104     */
105    @Override
106    public SharedStateDiscreteSampler withUniformRandomProvider(UniformRandomProvider rng) {
107        // Direct return of the optimised sampler
108        return poissonSamplerDelegate.withUniformRandomProvider(rng);
109    }
110
111    /**
112     * Creates a new Poisson distribution sampler.
113     *
114     * @param rng Generator of uniformly distributed random numbers.
115     * @param mean Mean.
116     * @return the sampler
117     * @throws IllegalArgumentException if {@code mean <= 0} or {@code mean > 0.5 *}
118     * {@link Integer#MAX_VALUE}.
119     * @since 1.3
120     */
121    public static SharedStateDiscreteSampler of(UniformRandomProvider rng,
122                                                double mean) {
123        // Each sampler should check the input arguments.
124        return mean < PIVOT ?
125            SmallMeanPoissonSampler.of(rng, mean) :
126            LargeMeanPoissonSampler.of(rng, mean);
127    }
128}