1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.rng.sampling.distribution;
18
19 import org.apache.commons.rng.UniformRandomProvider;
20
21 /**
22 * Distribution sampler that uses the
23 * <a href="https://en.wikipedia.org/wiki/Inverse_transform_sampling">
24 * inversion method</a>.
25 *
26 * It can be used to sample any distribution that provides access to its
27 * <em>inverse cumulative probability function</em>.
28 *
29 * <p>Sampling uses {@link UniformRandomProvider#nextDouble()}.</p>
30 *
31 * <p>Example:</p>
32 * <pre><code>
33 * import org.apache.commons.math3.distribution.IntegerDistribution;
34 * import org.apache.commons.math3.distribution.BinomialDistribution;
35 *
36 * import org.apache.commons.rng.simple.RandomSource;
37 * import org.apache.commons.rng.sampling.distribution.DiscreteSampler;
38 * import org.apache.commons.rng.sampling.distribution.InverseTransformDiscreteSampler;
39 * import org.apache.commons.rng.sampling.distribution.DiscreteInverseCumulativeProbabilityFunction;
40 *
41 * // Distribution to sample.
42 * final IntegerDistribution dist = new BinomialDistribution(11, 0.56);
43 * // Create the sampler.
44 * final DiscreteSampler binomialSampler =
45 * InverseTransformDiscreteSampler.of(RandomSource.XO_RO_SHI_RO_128_PP.create(),
46 * new DiscreteInverseCumulativeProbabilityFunction() {
47 * public int inverseCumulativeProbability(double p) {
48 * return dist.inverseCumulativeProbability(p);
49 * }
50 * });
51 *
52 * // Generate random deviate.
53 * int random = binomialSampler.sample();
54 * </code></pre>
55 *
56 * @since 1.0
57 */
58 public class InverseTransformDiscreteSampler
59 extends SamplerBase
60 implements SharedStateDiscreteSampler {
61 /** Inverse cumulative probability function. */
62 private final DiscreteInverseCumulativeProbabilityFunction function;
63 /** Underlying source of randomness. */
64 private final UniformRandomProvider rng;
65
66 /**
67 * Create an instance.
68 *
69 * @param rng Generator of uniformly distributed random numbers.
70 * @param function Inverse cumulative probability function.
71 */
72 public InverseTransformDiscreteSampler(UniformRandomProvider rng,
73 DiscreteInverseCumulativeProbabilityFunction function) {
74 super(null);
75 this.rng = rng;
76 this.function = function;
77 }
78
79 /** {@inheritDoc} */
80 @Override
81 public int sample() {
82 return function.inverseCumulativeProbability(rng.nextDouble());
83 }
84
85 /** {@inheritDoc} */
86 @Override
87 public String toString() {
88 return function.toString() + " (inverse method) [" + rng.toString() + "]";
89 }
90
91 /**
92 * {@inheritDoc}
93 *
94 * <p>Note: The new sampler will share the inverse cumulative probability function. This
95 * must be suitable for concurrent use to ensure thread safety.</p>
96 *
97 * @since 1.3
98 */
99 @Override
100 public SharedStateDiscreteSampler withUniformRandomProvider(UniformRandomProvider rng) {
101 return new InverseTransformDiscreteSampler(rng, function);
102 }
103
104 /**
105 * Create a new inverse-transform discrete sampler.
106 *
107 * <p>To use the sampler to
108 * {@link org.apache.commons.rng.sampling.SharedStateSampler share state} the function must be
109 * suitable for concurrent use.</p>
110 *
111 * @param rng Generator of uniformly distributed random numbers.
112 * @param function Inverse cumulative probability function.
113 * @return the sampler
114 * @see #withUniformRandomProvider(UniformRandomProvider)
115 * @since 1.3
116 */
117 public static SharedStateDiscreteSampler of(UniformRandomProvider rng,
118 DiscreteInverseCumulativeProbabilityFunction function) {
119 return new InverseTransformDiscreteSampler(rng, function);
120 }
121 }