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       * @param rng Generator of uniformly distributed random numbers.
68       * @param function Inverse cumulative probability function.
69       */
70      public InverseTransformContinuousSampler(UniformRandomProvider rng,
71                                               ContinuousInverseCumulativeProbabilityFunction function) {
72          super(null);
73          this.rng = rng;
74          this.function = function;
75      }
76  
77      /** {@inheritDoc} */
78      @Override
79      public double sample() {
80          return function.inverseCumulativeProbability(rng.nextDouble());
81      }
82  
83      /** {@inheritDoc} */
84      @Override
85      public String toString() {
86          return function.toString() + " (inverse method) [" + rng.toString() + "]";
87      }
88  
89      /**
90       * {@inheritDoc}
91       *
92       * <p>Note: The new sampler will share the inverse cumulative probability function. This
93       * must be suitable for concurrent use to ensure thread safety.</p>
94       *
95       * @since 1.3
96       */
97      @Override
98      public SharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) {
99          return new InverseTransformContinuousSampler(rng, function);
100     }
101 
102     /**
103      * Create a new inverse-transform continuous sampler.
104      *
105      * <p>To use the sampler to
106      * {@link org.apache.commons.rng.sampling.SharedStateSampler share state} the function must be
107      * suitable for concurrent use.</p>
108      *
109      * @param rng Generator of uniformly distributed random numbers.
110      * @param function Inverse cumulative probability function.
111      * @return the sampler
112      * @see #withUniformRandomProvider(UniformRandomProvider)
113      * @since 1.3
114      */
115     public static SharedStateContinuousSampler of(UniformRandomProvider rng,
116                                                   ContinuousInverseCumulativeProbabilityFunction function) {
117         return new InverseTransformContinuousSampler(rng, function);
118     }
119 }