View Javadoc
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.RealDistribution;
34   * import org.apache.commons.math3.distribution.ChiSquaredDistribution;
35   *
36   * import org.apache.commons.rng.simple.RandomSource;
37   * import org.apache.commons.rng.sampling.distribution.ContinuousSampler;
38   * import org.apache.commons.rng.sampling.distribution.InverseTransformContinuousSampler;
39   * import org.apache.commons.rng.sampling.distribution.ContinuousInverseCumulativeProbabilityFunction;
40   *
41   * // Distribution to sample.
42   * final RealDistribution dist = new ChiSquaredDistribution(9);
43   * // Create the sampler.
44   * final ContinuousSampler chiSquareSampler =
45   *     InverseTransformContinuousSampler.of(RandomSource.XO_RO_SHI_RO_128_PP.create(),
46   *                                          new ContinuousInverseCumulativeProbabilityFunction() {
47   *                                              public double inverseCumulativeProbability(double p) {
48   *                                                  return dist.inverseCumulativeProbability(p);
49   *                                              }
50   *                                          });
51   *
52   * // Generate random deviate.
53   * double random = chiSquareSampler.sample();
54   * </code></pre>
55   *
56   * @since 1.0
57   */
58  public class InverseTransformContinuousSampler
59      extends SamplerBase
60      implements SharedStateContinuousSampler {
61      /** Inverse cumulative probability function. */
62      private final ContinuousInverseCumulativeProbabilityFunction 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 InverseTransformContinuousSampler(UniformRandomProvider rng,
73                                               ContinuousInverseCumulativeProbabilityFunction function) {
74          super(null);
75          this.rng = rng;
76          this.function = function;
77      }
78  
79      /** {@inheritDoc} */
80      @Override
81      public double 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 SharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) {
101         return new InverseTransformContinuousSampler(rng, function);
102     }
103 
104     /**
105      * Create a new inverse-transform continuous 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 SharedStateContinuousSampler of(UniformRandomProvider rng,
118                                                   ContinuousInverseCumulativeProbabilityFunction function) {
119         return new InverseTransformContinuousSampler(rng, function);
120     }
121 }