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

umontreal.iro.lecuyer.randvar.GammaAcceptanceRejectionGen Maven / Gradle / Ivy

Go to download

SSJ is a Java library for stochastic simulation, developed under the direction of Pierre L'Ecuyer, in the Département d'Informatique et de Recherche Opérationnelle (DIRO), at the Université de Montréal. It provides facilities for generating uniform and nonuniform random variates, computing different measures related to probability distributions, performing goodness-of-fit tests, applying quasi-Monte Carlo methods, collecting (elementary) statistics, and programming discrete-event simulations with both events and processes.

The newest version!


/*
 * Class:        GammaAcceptanceRejectionGen
 * Description:  gamma random variate generators using a method that combines
                 acceptance-rejection with acceptance-complement
 * Environment:  Java
 * Software:     SSJ 
 * Copyright (C) 2001  Pierre L'Ecuyer and Université de Montréal
 * Organization: DIRO, Université de Montréal
 * @author       
 * @since

 * SSJ is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License (GPL) as published by the
 * Free Software Foundation, either version 3 of the License, or
 * any later version.

 * SSJ is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * A copy of the GNU General Public License is available at
   GPL licence site.
 */

package umontreal.iro.lecuyer.randvar;
import umontreal.iro.lecuyer.rng.*;
import umontreal.iro.lecuyer.probdist.*;


/**
 * This class implements gamma random variate generators using
 * a method that combines acceptance-rejection 
 * with acceptance-complement.
 * It uses acceptance-rejection for α < 1 and acceptance-complement
 * for 
 * α >= 1.
 * For each gamma variate, the first uniform required is taken from the 
 * main stream and all additional uniforms (after the first rejection)
 * are obtained from the auxiliary stream.
 * 
 */
public class GammaAcceptanceRejectionGen extends GammaGen  {
    
   private RandomStream auxStream;
   private static final double q1 =  0.0416666664;
   private static final double q2 =  0.0208333723;
   private static final double q3 =  0.0079849875;
   private static final double q4 =  0.0015746717;
   private static final double q5 = -0.0003349403;
   private static final double q6 =  0.0003340332;
   private static final double q7 =  0.0006053049;
   private static final double q8 = -0.0004701849;
   private static final double q9 =  0.0001710320;
   private static final double a1 =  0.333333333;
   private static final double a2 = -0.249999949;
   private static final double a3 =  0.199999867;
   private static final double a4 = -0.166677482;
   private static final double a5 =  0.142873973;
   private static final double a6 = -0.124385581;
   private static final double a7 =  0.110368310;
   private static final double a8 = -0.112750886;
   private static final double a9 =  0.104089866;
   private static final double e1 =  1.000000000;
   private static final double e2 =  0.499999994;
   private static final double e3 =  0.166666848;
   private static final double e4 =  0.041664508;
   private static final double e5 =  0.008345522;
   private static final double e6 =  0.001353826;
   private static final double e7 =  0.000247453;

   private int gen;
   // UNURAN parameters for the distribution
   private double beta;
   private double gamma;
   // Generator parameters
   // Acceptance rejection combined with acceptance complement
   private static final int gs = 0;
   private static final int gd = 1;
   private double b;
   private double ss;
   private double s;
   private double d;
   private double r;
   private double q0;
   private double c;
   private double si;




   /**
    * Creates a gamma random variate generator with parameters α = 
    *  alpha and λ = lambda, using main stream s and 
    *   auxiliary stream aux.
    *  The auxiliary stream is used when a random number of uniforms
    *  is required for a rejection-type generation method.
    * 
    */
   public GammaAcceptanceRejectionGen (RandomStream s, RandomStream aux,
                                       double alpha, double lambda)  {
      super (s, null);
      auxStream = aux;
      setParams (alpha, lambda);
      beta  = 1.0/lambda;
      gamma = 0.0;
      init ();
   }


   /**
    * Creates a gamma random variate generator with parameters α = 
    *  alpha and λ = lambda, using stream s.
    * 
    */
   public GammaAcceptanceRejectionGen (RandomStream s,
                                       double alpha, double lambda)  {
      this (s, s, alpha, lambda);
   }


   /**
    * Creates a new generator object for the gamma 
    *     distribution dist, using main stream s and 
    *     auxiliary stream aux. 
    *     The auxiliary stream is used when a random number of uniforms
    *     is required for a rejection-type generation method.
    * 
    */
   public GammaAcceptanceRejectionGen (RandomStream s, RandomStream aux, 
                                       GammaDist dist)  {
      super (s, dist);
      auxStream = aux;
      if (dist != null)
         setParams (dist.getAlpha(), dist.getLambda());
      beta  = 1.0/dist.getLambda();
      gamma = 0.0;
      init ();
   }


   /**
    * Creates a new generator object for the gamma
    *     distribution dist and  stream s for both the main and
    *     auxiliary stream.
    * 
    */
   public GammaAcceptanceRejectionGen (RandomStream s, GammaDist dist)  {
      this (s, s, dist);
   }


   /**
    * Returns the auxiliary stream associated with this object.
    * 
    */
   public RandomStream getAuxStream() {
      return auxStream;
   }


   /**
    * Generates a new gamma variate with parameters
    *  α = alpha and λ = lambda, using
    *   main stream s and auxiliary stream aux.
    * 
    */
   public static double nextDouble (RandomStream s, RandomStream aux, 
                                    double alpha, double lambda) {
      int gen = gs;
      double s_ = 0, ss = 0, d = 0, q0 = 0, r = 0, c = 0, si = 0, b = 0;

         // Code taken from UNURAN
         if (alpha < 1.0) {
            gen = gs;
            b = 1.0 + 0.36788794412*alpha;       // Step 1
         }
         else {
            gen = gd;
            // Step 1. Preparations
            ss = alpha - 0.5;
            s_ = Math.sqrt (ss);
            d = 5.656854249 - 12.0*s_;

            // Step 4. Set-up for hat case
            r = 1.0 / alpha;
            q0 = ((((((((q9*r + q8)*r + q7)*r + q6)*r + q5)*r + q4)*
                    r + q3)*r + q2)*r + q1)*r;
            if (alpha > 3.686) {
              if (alpha > 13.022) {
                b = 1.77;
                si = 0.75;
                c = 0.1515/s_;
              }
              else {
                b = 1.654 + 0.0076 * ss;
                si = 1.68/s_ + 0.275;
                c = 0.062/s_ + 0.024;
              }
            }
            else {
              b = 0.463 + s_ - 0.178*ss;
              si = 1.235;
              c = 0.195/s_ - 0.079 + 0.016*s_;
            }
         }
         return acceptanceRejection
             (s, aux, alpha, 1.0/lambda, 0, gen, b, s_, ss, d, r, q0, c, si);
   }
 
    
   public double nextDouble() {
      return acceptanceRejection
       (stream, auxStream, alpha, beta, gamma, gen, b, s, ss, d, r, q0, c, si);
   }

   /**
    * Same as nextDouble (s, s, alpha, lambda).
    * 
    */
   public static double nextDouble (RandomStream s, double alpha, 
                                    double lambda) {
      return nextDouble (s, s, alpha, lambda);
   }


   private static double acceptanceRejection
      (RandomStream stream, RandomStream auxStream,
       double alpha, double beta, double gamma, int gen,
       double b, double s, double ss,
       double d, double r, double q0, double c, double si) {
      // Code taken from UNURAN
      double X, p, U, E;
      double q,sign_U,t,v,w,x;
      switch (gen) {
      case gs:
         while (true) {
            p = b*stream.nextDouble();
            stream = auxStream;
            if (p <= 1.0) {                   // Step 2. Case gds <= 1
               X = Math.exp (Math.log (p)/alpha);
               if (Math.log (stream.nextDouble()) <= -X)
                  break;
            }
            else {                           // Step 3. Case gds > 1
               X = -Math.log ((b - p) / alpha);
               if ( Math.log (stream.nextDouble()) <= ((alpha - 1.0)*Math.log (X)))
                  break;
            }
         }
         break;
      case gd:
        do {

            // Step 2. Normal deviate
            t = NormalDist.inverseF01 (stream.nextDouble());
            stream = auxStream;
            x = s + 0.5*t;
            X = x*x;
            if (t >= 0.)
               break;         // Immediate acceptance

            // Step 3. Uniform random number
            U = stream.nextDouble();
            if (d*U <= t*t*t) 
               break;         // Squeeze acceptance

            // Step 5. Calculation of q
            if (x > 0.) {
               // Step 6.
               v = t/(s + s);
               if (Math.abs (v) > 0.25)
                  q = q0 - s*t + 0.25*t*t + (ss + ss)*Math.log (1. + v);
               else
                  q = q0 + 0.5*t*t*((((((((a9*v + a8)*v + a7)*v + a6)*
                                     v + a5)*v + a4)*v + a3)*v + a2)*v + a1)*v;
               // Step 7. Quotient acceptance
               if (Math.log (1. - U) <= q)
                  break;
            }

            // Step 8. Double exponential deviate t
            while (true) {
               do {
                  E = -Math.log (stream.nextDouble());
                  U = stream.nextDouble();
                  U = U + U - 1.;
                  sign_U = (U > 0) ? 1. : -1.;
                  t = b + (E*si)*sign_U;
               } while (t <= -0.71874483771719);   // Step 9. Rejection of t

               // Step 10. New q(t)
               v = t/(s + s);
               if (Math.abs (v) > 0.25)
                  q = q0 - s*t + 0.25*t*t + (ss + ss)*Math.log (1. + v);
               else
                  q = q0 + 0.5*t*t * ((((((((a9*v + a8)*v + a7)*v + a6)*
                                          v + a5)*v + a4)*v + a3)*v + a2)*v + a1)*v;

               // Step 11.
               if (q <= 0.)
                  continue; 

               if (q > 0.5)
                  w = Math.exp (q) - 1.;
               else
                  w = ((((((e7 * q + e6) * q + e5) * q + e4) * q + e3) * q + e2) *
                         q + e1) * q;

               // Step 12. Hat acceptance
               if ( c * U * sign_U <= w*Math.exp (E - 0.5*t*t)) {
                  x = s + 0.5 * t;
                  X = x * x;
                  break;
               }
            }
         } while (false);
         break;
      default: throw new IllegalStateException();
      }

      return gamma + beta*X;
   }

   private void init() {
      // Code taken from UNURAN
      if (alpha < 1.0) {
         gen = gs;
         b = 1.0 + 0.36788794412*alpha;       // Step 1
      }
      else {
         gen = gd;
         // Step 1. Preparations
         ss = alpha - 0.5;
         s = Math.sqrt (ss);
         d = 5.656854249 - 12.0*s;

         // Step 4. Set-up for hat case
         r = 1.0 / alpha;
         q0 = ((((((((q9*r + q8)*r + q7)*r + q6)*r + q5)*r + q4)*
                 r + q3)*r + q2)*r + q1)*r;
         if (alpha > 3.686) {
           if (alpha > 13.022) {
             b = 1.77;
             si = 0.75;
             c = 0.1515/s;
           }
           else {
             b = 1.654 + 0.0076 * ss;
             si = 1.68/s + 0.275;
             c = 0.062/s + 0.024;
           }
         }
         else {
           b = 0.463 + s - 0.178*ss;
           si = 1.235;
           c = 0.195/s - 0.079 + 0.016*s;
         }
      }
   }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy