001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.rng.sampling.distribution; 018 019import java.util.function.LongToDoubleFunction; 020import org.apache.commons.rng.UniformRandomProvider; 021 022/** 023 * Sampling from a <a href="https://en.wikipedia.org/wiki/Pareto_distribution">Pareto distribution</a>. 024 * 025 * <p>Sampling uses {@link UniformRandomProvider#nextLong()}.</p> 026 * 027 * @since 1.0 028 */ 029public class InverseTransformParetoSampler 030 extends SamplerBase 031 implements SharedStateContinuousSampler { 032 /** Scale. */ 033 private final double scale; 034 /** 1 / Shape. */ 035 private final double oneOverShape; 036 /** Underlying source of randomness. */ 037 private final UniformRandomProvider rng; 038 /** Method to generate the (1 - p) value. */ 039 private final LongToDoubleFunction nextDouble; 040 041 /** 042 * Create an instance. 043 * 044 * @param rng Generator of uniformly distributed random numbers. 045 * @param scale Scale of the distribution. 046 * @param shape Shape of the distribution. 047 * @throws IllegalArgumentException if {@code scale <= 0} or {@code shape <= 0} 048 */ 049 public InverseTransformParetoSampler(UniformRandomProvider rng, 050 double scale, 051 double shape) { 052 // Validation before java.lang.Object constructor exits prevents partially initialized object 053 this(InternalUtils.requireStrictlyPositive(scale, "scale"), 054 InternalUtils.requireStrictlyPositive(shape, "shape"), 055 rng); 056 } 057 058 /** 059 * @param scale Scale of the distribution. 060 * @param shape Shape of the distribution. 061 * @param rng Generator of uniformly distributed random numbers. 062 */ 063 private InverseTransformParetoSampler(double scale, 064 double shape, 065 UniformRandomProvider rng) { 066 super(null); 067 this.rng = rng; 068 this.scale = scale; 069 this.oneOverShape = 1 / shape; 070 // Generate (1 - p) so that samples are concentrated to the lower/upper bound: 071 // large shape samples from p in [0, 1) (lower bound) 072 // small shape samples from p in (0, 1] (upper bound) 073 // Note that the method used is logically reversed as it generates (1 - p). 074 nextDouble = shape >= 1 ? 075 InternalUtils::makeNonZeroDouble : 076 InternalUtils::makeDouble; 077 } 078 079 /** 080 * @param rng Generator of uniformly distributed random numbers. 081 * @param source Source to copy. 082 */ 083 private InverseTransformParetoSampler(UniformRandomProvider rng, 084 InverseTransformParetoSampler source) { 085 super(null); 086 this.rng = rng; 087 scale = source.scale; 088 oneOverShape = source.oneOverShape; 089 nextDouble = source.nextDouble; 090 } 091 092 /** {@inheritDoc} */ 093 @Override 094 public double sample() { 095 return scale / Math.pow(nextDouble.applyAsDouble(rng.nextLong()), oneOverShape); 096 } 097 098 /** {@inheritDoc} */ 099 @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}