InverseTransformParetoSampler.java

  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. import java.util.function.LongToDoubleFunction;
  19. import org.apache.commons.rng.UniformRandomProvider;

  20. /**
  21.  * Sampling from a <a href="https://en.wikipedia.org/wiki/Pareto_distribution">Pareto distribution</a>.
  22.  *
  23.  * <p>Sampling uses {@link UniformRandomProvider#nextLong()}.</p>
  24.  *
  25.  * @since 1.0
  26.  */
  27. public class InverseTransformParetoSampler
  28.     extends SamplerBase
  29.     implements SharedStateContinuousSampler {
  30.     /** Scale. */
  31.     private final double scale;
  32.     /** 1 / Shape. */
  33.     private final double oneOverShape;
  34.     /** Underlying source of randomness. */
  35.     private final UniformRandomProvider rng;
  36.     /** Method to generate the (1 - p) value. */
  37.     private final LongToDoubleFunction nextDouble;

  38.     /**
  39.      * Create an instance.
  40.      *
  41.      * @param rng Generator of uniformly distributed random numbers.
  42.      * @param scale Scale of the distribution.
  43.      * @param shape Shape of the distribution.
  44.      * @throws IllegalArgumentException if {@code scale <= 0} or {@code shape <= 0}
  45.      */
  46.     public InverseTransformParetoSampler(UniformRandomProvider rng,
  47.                                          double scale,
  48.                                          double shape) {
  49.         // Validation before java.lang.Object constructor exits prevents partially initialized object
  50.         this(InternalUtils.requireStrictlyPositive(scale, "scale"),
  51.              InternalUtils.requireStrictlyPositive(shape, "shape"),
  52.              rng);
  53.     }

  54.     /**
  55.      * @param scale Scale of the distribution.
  56.      * @param shape Shape of the distribution.
  57.      * @param rng Generator of uniformly distributed random numbers.
  58.      */
  59.     private InverseTransformParetoSampler(double scale,
  60.                                           double shape,
  61.                                           UniformRandomProvider rng) {
  62.         super(null);
  63.         this.rng = rng;
  64.         this.scale = scale;
  65.         this.oneOverShape = 1 / shape;
  66.         // Generate (1 - p) so that samples are concentrated to the lower/upper bound:
  67.         // large shape samples from p in [0, 1)  (lower bound)
  68.         // small shape samples from p in (0, 1]  (upper bound)
  69.         // Note that the method used is logically reversed as it generates (1 - p).
  70.         nextDouble = shape >= 1 ?
  71.             InternalUtils::makeNonZeroDouble :
  72.             InternalUtils::makeDouble;
  73.     }

  74.     /**
  75.      * @param rng Generator of uniformly distributed random numbers.
  76.      * @param source Source to copy.
  77.      */
  78.     private InverseTransformParetoSampler(UniformRandomProvider rng,
  79.                                           InverseTransformParetoSampler source) {
  80.         super(null);
  81.         this.rng = rng;
  82.         scale = source.scale;
  83.         oneOverShape = source.oneOverShape;
  84.         nextDouble = source.nextDouble;
  85.     }

  86.     /** {@inheritDoc} */
  87.     @Override
  88.     public double sample() {
  89.         return scale / Math.pow(nextDouble.applyAsDouble(rng.nextLong()), oneOverShape);
  90.     }

  91.     /** {@inheritDoc} */
  92.     @Override
  93.     public String toString() {
  94.         return "[Inverse method for Pareto distribution " + rng.toString() + "]";
  95.     }

  96.     /**
  97.      * {@inheritDoc}
  98.      *
  99.      * @since 1.3
  100.      */
  101.     @Override
  102.     public SharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) {
  103.         return new InverseTransformParetoSampler(rng, this);
  104.     }

  105.     /**
  106.      * Creates a new Pareto distribution sampler.
  107.      *
  108.      * @param rng Generator of uniformly distributed random numbers.
  109.      * @param scale Scale of the distribution.
  110.      * @param shape Shape of the distribution.
  111.      * @return the sampler
  112.      * @throws IllegalArgumentException if {@code scale <= 0} or {@code shape <= 0}
  113.      * @since 1.3
  114.      */
  115.     public static SharedStateContinuousSampler of(UniformRandomProvider rng,
  116.                                                   double scale,
  117.                                                   double shape) {
  118.         return new InverseTransformParetoSampler(rng, scale, shape);
  119.     }
  120. }