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        super(null);
077
078        // Delegate all work to specialised samplers.
079        poissonSamplerDelegate = of(rng, mean);
080    }
081
082    /** {@inheritDoc} */
083    @Override
084    public int sample() {
085        return poissonSamplerDelegate.sample();
086    }
087
088    /** {@inheritDoc} */
089    @Override
090    public String toString() {
091        return poissonSamplerDelegate.toString();
092    }
093
094    /**
095     * {@inheritDoc}
096     *
097     * @since 1.3
098     */
099    @Override
100    public SharedStateDiscreteSampler withUniformRandomProvider(UniformRandomProvider rng) {
101        // Direct return of the optimised sampler
102        return poissonSamplerDelegate.withUniformRandomProvider(rng);
103    }
104
105    /**
106     * Creates a new Poisson distribution sampler.
107     *
108     * @param rng Generator of uniformly distributed random numbers.
109     * @param mean Mean.
110     * @return the sampler
111     * @throws IllegalArgumentException if {@code mean <= 0} or {@code mean > 0.5 *}
112     * {@link Integer#MAX_VALUE}.
113     * @since 1.3
114     */
115    public static SharedStateDiscreteSampler of(UniformRandomProvider rng,
116                                                double mean) {
117        // Each sampler should check the input arguments.
118        return mean < PIVOT ?
119            SmallMeanPoissonSampler.of(rng, mean) :
120            LargeMeanPoissonSampler.of(rng, mean);
121    }
122}