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 java.util.function.LongToDoubleFunction;
20  import org.apache.commons.rng.UniformRandomProvider;
21  
22  /**
23   * Sampling from a <a href="https://en.wikipedia.org/wiki/Pareto_distribution">Pareto distribution</a>.
24   *
25   * <p>Sampling uses {@link UniformRandomProvider#nextLong()}.</p>
26   *
27   * @since 1.0
28   */
29  public class InverseTransformParetoSampler
30      extends SamplerBase
31      implements SharedStateContinuousSampler {
32      /** Scale. */
33      private final double scale;
34      /** 1 / Shape. */
35      private final double oneOverShape;
36      /** Underlying source of randomness. */
37      private final UniformRandomProvider rng;
38      /** Method to generate the (1 - p) value. */
39      private final LongToDoubleFunction nextDouble;
40  
41      /**
42       * Create an instance.
43       *
44       * @param rng Generator of uniformly distributed random numbers.
45       * @param scale Scale of the distribution.
46       * @param shape Shape of the distribution.
47       * @throws IllegalArgumentException if {@code scale <= 0} or {@code shape <= 0}
48       */
49      public InverseTransformParetoSampler(UniformRandomProvider rng,
50                                           double scale,
51                                           double shape) {
52          // Validation before java.lang.Object constructor exits prevents partially initialized object
53          this(InternalUtils.requireStrictlyPositive(scale, "scale"),
54               InternalUtils.requireStrictlyPositive(shape, "shape"),
55               rng);
56      }
57  
58      /**
59       * @param scale Scale of the distribution.
60       * @param shape Shape of the distribution.
61       * @param rng Generator of uniformly distributed random numbers.
62       */
63      private InverseTransformParetoSampler(double scale,
64                                            double shape,
65                                            UniformRandomProvider rng) {
66          super(null);
67          this.rng = rng;
68          this.scale = scale;
69          this.oneOverShape = 1 / shape;
70          // Generate (1 - p) so that samples are concentrated to the lower/upper bound:
71          // large shape samples from p in [0, 1)  (lower bound)
72          // small shape samples from p in (0, 1]  (upper bound)
73          // Note that the method used is logically reversed as it generates (1 - p).
74          nextDouble = shape >= 1 ?
75              InternalUtils::makeNonZeroDouble :
76              InternalUtils::makeDouble;
77      }
78  
79      /**
80       * @param rng Generator of uniformly distributed random numbers.
81       * @param source Source to copy.
82       */
83      private InverseTransformParetoSampler(UniformRandomProvider rng,
84                                            InverseTransformParetoSampler source) {
85          super(null);
86          this.rng = rng;
87          scale = source.scale;
88          oneOverShape = source.oneOverShape;
89          nextDouble = source.nextDouble;
90      }
91  
92      /** {@inheritDoc} */
93      @Override
94      public double sample() {
95          return scale / Math.pow(nextDouble.applyAsDouble(rng.nextLong()), oneOverShape);
96      }
97  
98      /** {@inheritDoc} */
99      @Override
100     public String toString() {
101         return "[Inverse method for Pareto distribution " + rng.toString() + "]";
102     }
103 
104     /**
105      * {@inheritDoc}
106      *
107      * @since 1.3
108      */
109     @Override
110     public SharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) {
111         return new InverseTransformParetoSampler(rng, this);
112     }
113 
114     /**
115      * Creates a new Pareto distribution sampler.
116      *
117      * @param rng Generator of uniformly distributed random numbers.
118      * @param scale Scale of the distribution.
119      * @param shape Shape of the distribution.
120      * @return the sampler
121      * @throws IllegalArgumentException if {@code scale <= 0} or {@code shape <= 0}
122      * @since 1.3
123      */
124     public static SharedStateContinuousSampler of(UniformRandomProvider rng,
125                                                   double scale,
126                                                   double shape) {
127         return new InverseTransformParetoSampler(rng, scale, shape);
128     }
129 }