All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.rng.sampling.distribution.AhrensDieterMarsagliaTsangGammaSampler Maven / Gradle / Ivy

Go to download

The Apache Commons RNG Sampling module provides samplers for various distributions.

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.rng.sampling.distribution;

import org.apache.commons.rng.UniformRandomProvider;

/**
 * Sampling from the gamma distribution.
 * 
    *
  • * For {@code 0 < alpha < 1}: *
    * Ahrens, J. H. and Dieter, U., * Computer methods for sampling from gamma, beta, Poisson and binomial distributions, * Computing, 12, 223-246, 1974. *
    *
  • *
  • * For {@code alpha >= 1}: *
    * Marsaglia and Tsang, A Simple Method for Generating * Gamma Variables. ACM Transactions on Mathematical Software, * Volume 26 Issue 3, September, 2000. *
    *
  • *
* *

Sampling uses:

* *
    *
  • {@link UniformRandomProvider#nextDouble()} (both algorithms) *
  • {@link UniformRandomProvider#nextLong()} (only for {@code alpha >= 1}) *
* * @see MathWorld Gamma distribution * @see Wikipedia Gamma distribution * @since 1.0 */ public class AhrensDieterMarsagliaTsangGammaSampler extends SamplerBase implements SharedStateContinuousSampler { /** The appropriate gamma sampler for the parameters. */ private final SharedStateContinuousSampler delegate; /** * Base class for a sampler from the Gamma distribution. */ private abstract static class BaseGammaSampler implements SharedStateContinuousSampler { /** Underlying source of randomness. */ protected final UniformRandomProvider rng; /** The alpha parameter. This is a shape parameter. */ protected final double alpha; /** The theta parameter. This is a scale parameter. */ protected final double theta; /** * @param rng Generator of uniformly distributed random numbers. * @param alpha Alpha parameter of the distribution. * @param theta Theta parameter of the distribution. * @throws IllegalArgumentException if {@code alpha <= 0} or {@code theta <= 0} */ BaseGammaSampler(UniformRandomProvider rng, double alpha, double theta) { // Validation before java.lang.Object constructor exits prevents partially initialized object this(InternalUtils.requireStrictlyPositive(alpha, "alpha"), InternalUtils.requireStrictlyPositive(theta, "theta"), rng); } /** * @param alpha Alpha parameter of the distribution. * @param theta Theta parameter of the distribution. * @param rng Generator of uniformly distributed random numbers. */ private BaseGammaSampler(double alpha, double theta, UniformRandomProvider rng) { this.rng = rng; this.alpha = alpha; this.theta = theta; } /** * @param rng Generator of uniformly distributed random numbers. * @param source Source to copy. */ BaseGammaSampler(UniformRandomProvider rng, BaseGammaSampler source) { this.rng = rng; this.alpha = source.alpha; this.theta = source.theta; } /** {@inheritDoc} */ @Override public String toString() { return "Ahrens-Dieter-Marsaglia-Tsang Gamma deviate [" + rng.toString() + "]"; } } /** * Class to sample from the Gamma distribution when {@code 0 < alpha < 1}. * *
* Ahrens, J. H. and Dieter, U., * Computer methods for sampling from gamma, beta, Poisson and binomial distributions, * Computing, 12, 223-246, 1974. *
*/ private static final class AhrensDieterGammaSampler extends BaseGammaSampler { /** Inverse of "alpha". */ private final double oneOverAlpha; /** Optimization (see code). */ private final double bGSOptim; /** * @param rng Generator of uniformly distributed random numbers. * @param alpha Alpha parameter of the distribution. * @param theta Theta parameter of the distribution. * @throws IllegalArgumentException if {@code alpha <= 0} or {@code theta <= 0} */ AhrensDieterGammaSampler(UniformRandomProvider rng, double alpha, double theta) { super(rng, alpha, theta); oneOverAlpha = 1 / alpha; bGSOptim = 1 + alpha / Math.E; } /** * @param rng Generator of uniformly distributed random numbers. * @param source Source to copy. */ AhrensDieterGammaSampler(UniformRandomProvider rng, AhrensDieterGammaSampler source) { super(rng, source); oneOverAlpha = source.oneOverAlpha; bGSOptim = source.bGSOptim; } @Override public double sample() { // [1]: p. 228, Algorithm GS. while (true) { // Step 1: final double u = rng.nextDouble(); final double p = bGSOptim * u; if (p <= 1) { // Step 2: final double x = Math.pow(p, oneOverAlpha); final double u2 = rng.nextDouble(); if (u2 > Math.exp(-x)) { // Reject. continue; } return theta * x; } // Step 3: final double x = -Math.log((bGSOptim - p) * oneOverAlpha); final double u2 = rng.nextDouble(); if (u2 <= Math.pow(x, alpha - 1)) { return theta * x; } // Reject and continue. } } @Override public SharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) { return new AhrensDieterGammaSampler(rng, this); } } /** * Class to sample from the Gamma distribution when the {@code alpha >= 1}. * *
* Marsaglia and Tsang, A Simple Method for Generating * Gamma Variables. ACM Transactions on Mathematical Software, * Volume 26 Issue 3, September, 2000. *
*/ private static final class MarsagliaTsangGammaSampler extends BaseGammaSampler { /** 1/3. */ private static final double ONE_THIRD = 1d / 3; /** Optimization (see code). */ private final double dOptim; /** Optimization (see code). */ private final double cOptim; /** Gaussian sampling. */ private final NormalizedGaussianSampler gaussian; /** * @param rng Generator of uniformly distributed random numbers. * @param alpha Alpha parameter of the distribution. * @param theta Theta parameter of the distribution. * @throws IllegalArgumentException if {@code alpha <= 0} or {@code theta <= 0} */ MarsagliaTsangGammaSampler(UniformRandomProvider rng, double alpha, double theta) { super(rng, alpha, theta); gaussian = ZigguratSampler.NormalizedGaussian.of(rng); dOptim = alpha - ONE_THIRD; cOptim = ONE_THIRD / Math.sqrt(dOptim); } /** * @param rng Generator of uniformly distributed random numbers. * @param source Source to copy. */ MarsagliaTsangGammaSampler(UniformRandomProvider rng, MarsagliaTsangGammaSampler source) { super(rng, source); gaussian = ZigguratSampler.NormalizedGaussian.of(rng); dOptim = source.dOptim; cOptim = source.cOptim; } @Override public double sample() { while (true) { final double x = gaussian.sample(); final double oPcTx = 1 + cOptim * x; final double v = oPcTx * oPcTx * oPcTx; if (v <= 0) { continue; } final double x2 = x * x; final double u = rng.nextDouble(); // Squeeze. if (u < 1 - 0.0331 * x2 * x2) { return theta * dOptim * v; } if (Math.log(u) < 0.5 * x2 + dOptim * (1 - v + Math.log(v))) { return theta * dOptim * v; } } } @Override public SharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) { return new MarsagliaTsangGammaSampler(rng, this); } } /** * This instance delegates sampling. Use the factory method * {@link #of(UniformRandomProvider, double, double)} to create an optimal sampler. * * @param rng Generator of uniformly distributed random numbers. * @param alpha Alpha parameter of the distribution (this is a shape parameter). * @param theta Theta parameter of the distribution (this is a scale parameter). * @throws IllegalArgumentException if {@code alpha <= 0} or {@code theta <= 0} */ public AhrensDieterMarsagliaTsangGammaSampler(UniformRandomProvider rng, double alpha, double theta) { super(null); delegate = of(rng, alpha, theta); } /** {@inheritDoc} */ @Override public double sample() { return delegate.sample(); } /** {@inheritDoc} */ @Override public String toString() { return delegate.toString(); } /** * {@inheritDoc} * * @since 1.3 */ @Override public SharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) { // Direct return of the optimised sampler return delegate.withUniformRandomProvider(rng); } /** * Creates a new gamma distribution sampler. * * @param rng Generator of uniformly distributed random numbers. * @param alpha Alpha parameter of the distribution (this is a shape parameter). * @param theta Theta parameter of the distribution (this is a scale parameter). * @return the sampler * @throws IllegalArgumentException if {@code alpha <= 0} or {@code theta <= 0} * @since 1.3 */ public static SharedStateContinuousSampler of(UniformRandomProvider rng, double alpha, double theta) { // Each sampler should check the input arguments. return alpha < 1 ? new AhrensDieterGammaSampler(rng, alpha, theta) : new MarsagliaTsangGammaSampler(rng, alpha, theta); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy