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 }