m_random.f90 Source File

Adapted from Fortran 77 code from the book: Dagpunar, J. 'Principles of random variate generation' Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9

FUNCTION GENERATES A RANDOM VARIATE IN [0,1] FROM A BETA DISTRIBUTION WITH DENSITY PROPORTIONAL TO BETA(AA-1) * (1-BETA)(BB-1). USING CHENG'S LOG LOGISTIC METHOD.

 AA = SHAPE PARAMETER FROM DISTRIBUTION (0 < REAL)
 BB = SHAPE PARAMETER FROM DISTRIBUTION (0 < REAL)





 Local variables

Adapted from Fortran 77 code from the book: Dagpunar, J. 'Principles of random variate generation' Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9

FUNCTION GENERATES A RANDOM VARIATE FROM A T DISTRIBUTION USING KINDERMAN AND MONAHAN'S RATIO METHOD.

 M = DEGREES OF FREEDOM OF DISTRIBUTION
       (1 <= 1NTEGER)




 Local variables

Adapted from Fortran 77 code from the book: Dagpunar, J. 'Principles of random variate generation' Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9

N.B. An extra argument, ier, has been added to Dagpunar's routine

 SUBROUTINE GENERATES AN N VARIATE RANDOM NORMAL
 VECTOR USING A CHOLESKY DECOMPOSITION.

ARGUMENTS: N = NUMBER OF VARIATES IN VECTOR (INPUT,INTEGER >= 1) H(J) = J'TH ELEMENT OF VECTOR OF MEANS (INPUT,REAL) X(J) = J'TH ELEMENT OF DELIVERED VECTOR (OUTPUT,REAL)

D(J*(J-1)/2+I) = (I,J)'TH ELEMENT OF VARIANCE MATRIX (J> = I)
        (INPUT,REAL)
F((J-1)*(2*N-J)/2+I) = (I,J)'TH ELEMENT OF LOWER TRIANGULAR
       DECOMPOSITION OF VARIANCE MATRIX (J <= I)
        (OUTPUT,REAL)

FIRST = .TRUE. IF THIS IS THE FIRST CALL OF THE ROUTINE
OR IF THE DISTRIBUTION HAS CHANGED SINCE THE LAST CALL OF THE ROUTINE.
OTHERWISE SET TO .FALSE.
        (INPUT,LOGICAL)

ier = 1 if the input covariance matrix is not +ve definite
    = 0 otherwise








 Local variables

Adapted from Fortran 77 code from the book: Dagpunar, J. 'Principles of random variate generation' Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9

FUNCTION GENERATES A RANDOM VARIATE IN [0,INFINITY] FROM A REPARAMETERISED GENERALISED INVERSE GAUSSIAN (GIG) DISTRIBUTION WITH DENSITY PROPORTIONAL TO GIG(H-1) * EXP(-0.5B(GIG+1/GIG)) USING A RATIO METHOD.

 H = PARAMETER OF DISTRIBUTION (0 <= REAL)
 B = PARAMETER OF DISTRIBUTION (0 < REAL)





 Local variables

 Translated to Fortran 90 by Alan Miller from:
                       RANLIB

 Library of Fortran Routines for Random Number Generation

                Compiled and Written by:

                     Barry W. Brown
                      James Lovato

         Department of Biomathematics, Box 237
         The University of Texas, M.D. Anderson Cancer Center
         1515 Holcombe Boulevard
         Houston, TX      77030

This work was supported by grant CA-16672 from the National Cancer Institute.

                GENerate POIsson random deviate

                        Function

Generates a single random deviate from a Poisson distribution with mean mu.

                        Arguments

 mu --> The mean of the Poisson distribution from which
        a random deviate is to be generated.
                          REAL mu

                          Method

 For details see:

           Ahrens, J.H. and Dieter, U.
           Computer Generation of Poisson Deviates
           From Modified Normal Distributions.
           ACM Trans. Math. Software, 8, 2
           (June 1982),163-179

 TABLES: COEFFICIENTS A0-A7 FOR STEP F. FACTORIALS FACT
 COEFFICIENTS A(K) - FOR PX = FK*V*V*SUM(A(K)*V**K)-DEL

 SEPARATION OF CASES A AND B

 .. Scalar Arguments ..



 ..
 .. Local Scalars ..






 ..
 .. Local Arrays ..

 ..
 .. Data statements ..







 ..
 .. Executable Statements ..

 C A S E  A. (RECALCULATION OF S, D, L IF MU HAS CHANGED)





         THE POISSON PROBABILITIES PK EXCEED THE DISCRETE NORMAL
         PROBABILITIES FK WHENEVER K >= M(MU). L=IFIX(MU-1.1484)
         IS AN UPPER BOUND TO M(MU) FOR ALL MU >= 10 .






 STEP N. NORMAL SAMPLE - random_normal() FOR STANDARD NORMAL DEVIATE





 STEP I. IMMEDIATE ACCEPTANCE IF ival IS LARGE ENOUGH



 STEP S. SQUEEZE ACCEPTANCE - SAMPLE U







 STEP P. PREPARATIONS FOR STEPS Q AND H.
         (RECALCULATIONS OF PARAMETERS IF NECESSARY)
         .3989423=(2*PI)**(-.5)  .416667E-1=1./24.  .1428571=1./7.
         THE QUANTITIES B1, B2, C3, C2, C1, C0 ARE FOR THE HERMITE
         APPROXIMATIONS TO THE DISCRETE NORMAL PROBABILITIES FK.
         C=.1069/MU GUARANTEES MAJORIZATION BY THE 'HAT'-FUNCTION.















         'SUBROUTINE' F IS CALLED (KFLAG=0 FOR CORRECT RETURN)




 STEP Q. QUOTIENT ACCEPTANCE (RARE CASE)



 STEP E. EXPONENTIAL SAMPLE - random_exponential() FOR STANDARD EXPONENTIAL
         DEVIATE E AND SAMPLE T FROM THE LAPLACE 'HAT'
         (IF T <= -.6744 THEN PK < FK FOR ALL MU >= 10.)










         'SUBROUTINE' F IS CALLED (KFLAG=1 FOR CORRECT RETURN)




 STEP H. HAT ACCEPTANCE (E IS REPEATED ON REJECTION)




 STEP F. 'SUBROUTINE' F. CALCULATION OF PX, PY, FX, FY.
         CASE ival < 10 USES FACTORIALS FROM TABLE FACT






         CASE ival >= 10 USES POLYNOMIAL APPROXIMATION
         A0-A7 FOR ACCURACY WHEN ADVISABLE
         .8333333E-1=1./12.  .3989423=(2*PI)**(-.5)

 C A S E  B.    mu < 10
 START NEW TABLE AND CALCULATE P0 IF NECESSARY










 STEP U. UNIFORM SAMPLE FOR INVERSION METHOD






 STEP T. TABLE COMPARISON UNTIL THE END PP(L) OF THE
         PP-TABLE OF CUMULATIVE POISSON PROBABILITIES
         (0.458=PP(9) FOR MU=10)









 STEP C. CREATION OF NEW POISSON PROBABILITIES P
         AND THEIR CUMULATIVES Q=PP(K)

FUNCTION GENERATES A RANDOM BINOMIAL VARIATE USING C.D.Kemp's method. This algorithm is suitable when many random variates are required with the SAME parameter values for n & p.

P = BERNOULLI SUCCESS PROBABILITY
       (0 <= REAL <= 1)
N = NUMBER OF BERNOULLI TRIALS
       (1 <= INTEGER)
FIRST = .TRUE. for the first call using the current parameter values
      = .FALSE. if the values of (n,p) are unchanged from last call

Reference: Kemp, C.D. (1986). `A modal method for generating binomial variables', Commun. Statist. - Theor. Meth. 15(3), 805-813.

 Local variables














































 This point should not be reached, but just in case:









 Calculate a binomial probability





 Local variable

Logarithm to base e of the gamma function.

Accurate to about 1.e-14. Programmer: Alan Miller

Latest revision of Fortran 77 version - 28 February 1988

   Local variables







   lngamma is not defined if x = 0 or a negative integer.






   If x < 0, use the reflection formula:
           gamma(x) * gamma(1-x) = pi * cosec(pi.x)








   Increase the argument, if necessary, to make it > 10.

Use a polynomial approximation to Stirling's formula. N.B. The real Stirling's formula is used here, not the simpler, but less accurate formula given by De Moivre in a letter to Stirling, which is the one usually quoted.


 Translated to Fortran 90 by Alan Miller from:
                          RANLIB

 Library of Fortran Routines for Random Number Generation

                  Compiled and Written by:

                       Barry W. Brown
                        James Lovato

           Department of Biomathematics, Box 237
           The University of Texas, M.D. Anderson Cancer Center
           1515 Holcombe Boulevard
           Houston, TX      77030

This work was supported by grant CA-16672 from the National Cancer Institute.

                GENerate BINomial random deviate

                          Function

 Generates a single random deviate from a binomial
 distribution whose number of trials is N and whose
 probability of an event in each trial is P.

                          Arguments

 N  --> The number of trials in the binomial distribution
        from which a random deviate is to be generated.
                          INTEGER N

 P  --> The probability of an event in each trial of the
        binomial distribution from which a random deviate
        is to be generated.
                          REAL P

 FIRST --> Set FIRST = .TRUE. for the first call to perform initialization
           the set FIRST = .FALSE. for further calls using the same pair
           of parameter values (N, P).
                          LOGICAL FIRST

 random_binomial2 <-- A random deviate yielding the number of events
            from N independent trials, each of which has
            a probability of event P.
                          INTEGER random_binomial

                          Method

 This is algorithm BTPE from:

     Kachitvichyanukul, V. and Schmeiser, B. W.
     Binomial Random Variate Generation.
     Communications of the ACM, 31, 2 (February, 1988) 216.

*DETERMINE APPROPRIATE ALGORITHM AND WHETHER SETUP IS NECESSARY

 ..
 .. Scalar Arguments ..




 ..
 .. Local Scalars ..







 ..
 .. Executable Statements ..

*SETUP, PERFORM ONLY WHEN PARAMETERS CHANGE

*GENERATE VARIATE, Binomial mean at least 30.

 TRIANGULAR REGION






 PARALLELOGRAM REGION








 LEFT TAIL







 RIGHT TAIL

*DETERMINE APPROPRIATE WAY TO PERFORM ACCEPT/REJECT TEST

 EXPLICIT EVALUATION
























 SQUEEZING USING UPPER AND LOWER BOUNDS ON LOG(F(X))







 STIRLING'S (actually de Moivre's) FORMULA TO MACHINE ACCURACY FOR
 THE FINAL ACCEPTANCE/REJECTION TEST




















 INVERSE CDF LOGIC FOR MEAN LESS THAN 30

Adapted from Fortran 77 code from the book: Dagpunar, J. 'Principles of random variate generation' Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9

FUNCTION GENERATES A RANDOM NEGATIVE BINOMIAL VARIATE USING UNSTORED INVERSION AND/OR THE REPRODUCTIVE PROPERTY.

SK = NUMBER OF FAILURES REQUIRED (Dagpunar's words!)
   = the `power' parameter of the negative binomial
       (0 < REAL)
P = BERNOULLI SUCCESS PROBABILITY
       (0 < REAL < 1)

THE PARAMETER H IS SET SO THAT UNSTORED INVERSION ONLY IS USED WHEN P <= H, OTHERWISE A COMBINATION OF UNSTORED INVERSION AND THE REPRODUCTIVE PROPERTY IS USED.

 Local variables

THE PARAMETER ULN = -LOG(MACHINE'S SMALLEST REAL NUMBER).

 Algorithm VMD from:
 Dagpunar, J.S. (1990) `Sampling from the von Mises distribution via a
 comparison of random numbers', J. of Appl. Statist., 17, 165-168.

 Fortran 90 code by Alan Miller
 CSIRO Division of Mathematical & Information Sciences

 Arguments:
 k (real)        parameter of the von Mises distribution.
 first (logical) set to .TRUE. the first time that the function
                 is called, or the first time with a new value
                 for k.   When first = .TRUE., the function sets
                 up starting values and may be very much slower.





 Local variables
























 Set up array p of probabilities.









 Numerical integration of e^[k.cos(x)] from theta(j-1) to theta(j)











































 Gaussian integration of exp(k.cosx) from a to b.





 Local variables
























 Generate a random deviate from the standard Cauchy distribution



 Local variables

This File Depends On

sourcefile~~m_random.f90~~EfferentGraph sourcefile~m_random.f90 m_random.f90 sourcefile~prng_class.f90 Prng_Class.f90 sourcefile~prng_class.f90->sourcefile~m_random.f90 sourcefile~m_allocate.f90 m_allocate.f90 sourcefile~m_allocate.f90->sourcefile~m_random.f90 sourcefile~m_allocate.f90->sourcefile~prng_class.f90 sourcefile~m_errors.f90 m_errors.f90 sourcefile~m_errors.f90->sourcefile~m_random.f90 sourcefile~m_errors.f90->sourcefile~prng_class.f90 sourcefile~m_errors.f90->sourcefile~m_allocate.f90 sourcefile~m_strings.f90 m_strings.f90 sourcefile~m_errors.f90->sourcefile~m_strings.f90 sourcefile~m_deallocate.f90 m_deallocate.f90 sourcefile~m_errors.f90->sourcefile~m_deallocate.f90 sourcefile~m_unittester.f90 m_unitTester.f90 sourcefile~m_errors.f90->sourcefile~m_unittester.f90 sourcefile~m_strings.f90->sourcefile~m_random.f90 sourcefile~m_strings.f90->sourcefile~prng_class.f90 sourcefile~m_deallocate.f90->sourcefile~m_random.f90 sourcefile~m_variablekind.f90 m_variableKind.f90 sourcefile~m_variablekind.f90->sourcefile~m_random.f90 sourcefile~m_variablekind.f90->sourcefile~prng_class.f90 sourcefile~m_variablekind.f90->sourcefile~m_allocate.f90 sourcefile~m_variablekind.f90->sourcefile~m_errors.f90 sourcefile~m_variablekind.f90->sourcefile~m_strings.f90 sourcefile~m_variablekind.f90->sourcefile~m_deallocate.f90 sourcefile~m_variablekind.f90->sourcefile~m_unittester.f90 sourcefile~m_time.f90 m_time.f90 sourcefile~m_variablekind.f90->sourcefile~m_time.f90 sourcefile~m_indexing.f90 m_indexing.f90 sourcefile~m_variablekind.f90->sourcefile~m_indexing.f90 sourcefile~m_parameters.f90 m_parameters.f90 sourcefile~m_variablekind.f90->sourcefile~m_parameters.f90 sourcefile~m_unittester.f90->sourcefile~m_random.f90 sourcefile~m_unittester.f90->sourcefile~m_allocate.f90 sourcefile~m_time.f90->sourcefile~prng_class.f90 sourcefile~m_indexing.f90->sourcefile~prng_class.f90 sourcefile~m_parameters.f90->sourcefile~m_strings.f90
Help

Files Dependent On This One

sourcefile~~m_random.f90~~AfferentGraph sourcefile~m_random.f90 m_random.f90 sourcefile~test_coretran.f90 test_coretran.f90 sourcefile~m_random.f90->sourcefile~test_coretran.f90 sourcefile~scale_coretran.f90 scale_coretran.f90 sourcefile~m_random.f90->sourcefile~scale_coretran.f90 sourcefile~m_tests.f90 m_tests.f90 sourcefile~m_random.f90->sourcefile~m_tests.f90 sourcefile~m_array1d.f90 m_array1D.f90 sourcefile~m_random.f90->sourcefile~m_array1d.f90 sourcefile~m_tests.f90->sourcefile~test_coretran.f90 sourcefile~m_array1d.f90->sourcefile~scale_coretran.f90 sourcefile~m_array1d.f90->sourcefile~m_tests.f90 sourcefile~m_maths.f90 m_maths.f90 sourcefile~m_array1d.f90->sourcefile~m_maths.f90 sourcefile~m_kdtree.f90 m_KdTree.f90 sourcefile~m_array1d.f90->sourcefile~m_kdtree.f90 sourcefile~m_maths.f90->sourcefile~scale_coretran.f90 sourcefile~m_maths.f90->sourcefile~m_tests.f90 sourcefile~m_maths.f90->sourcefile~m_kdtree.f90 sourcefile~m_kdtree.f90->sourcefile~scale_coretran.f90 sourcefile~m_kdtree.f90->sourcefile~m_tests.f90
Help

Source Code


Source Code

module m_random
  !!# Random number generation - Not parallel safe
  !!This module has been comprised using different sources. The first was a public domain pseudo-random number
  !!generator using the xorshift1024* and xorshift128+ methods.  See [[Prng_Class]]
  !!for more details on those methods.
  !!
  !!The secound source are the functions inside http://www.netlib.org/random/random.f90.  These are used to generate 
  !!random numbers from distributions other than a uniform distribution.
  !!
  !!This module contains subroutines to generate numbers randomly from different distributions. 
  !!They do so by instantiating a globally available [[Prng_Class]] and making calls into its type bound procedures.
  !!Since the Prng for these routines is globally available, you should *not* use it for any random number generation
  !!in parallel, whether using OpenMP or MPI!  Instead, refer to [[Prng_Class]] to see how to use the Prng in a thread safe manner.
  !!
  !!
  !!Example Usage:
  !!```fortran
  !!program randomTest
  !!
  !!use m_random, only: setPRNG, rngInteger, rngUniform, rngNormal, rngExponential, rngrngWeibull
  !!
  !!implicit none
  !!
  !!
  !!
  !!
  !!end program
  !!```
  !!Original Netlib random.f90
  !!Author: Alan Miller
  !!
  !!Updated coretran version:
  !!Version 2.00, 11 November 2016
  !!Increased precision to double
  !!Added seed setters
  !!Added overloaded operations for single number, nD arrays

  use variableKind
  use m_allocate, only: allocate
  use m_deallocate, only: deallocate
  use m_errors, only: eMsg, mErr, msg
  use Prng_Class, only: Prng
  use m_strings, only: printOptions, str
  use iso_fortran_env, only: output_unit
  use m_unitTester, only: tester

  implicit none


  ! Global Prng Class but private to this module!  I hate global variables, but here it is necessary to have a global Prng for serial code.
  type(Prng) :: globalPrng

  public :: setPrng

  interface setPrng
    module procedure :: setPrng_withSeed, setPrng_WOseed

    ! !====================================================================!
    ! module subroutine setRNG_withSeed(seed, big)
    !   !! Interfaced to setRNG()
    !   !! Sets the seed of the random number generator with a specified seed
    ! !====================================================================!
    ! integer(i64), intent(in) :: seed(:)
    ! logical, intent(in), optional :: big
    ! end subroutine
    ! !====================================================================!
    ! !====================================================================!
    ! module subroutine setRNG_WOseed(big, display)
    !   !! Interfaced to setRNG()
    !   !! 'Randomly' sets the seed of the random number generator
    ! !====================================================================!
    ! logical, intent(in), optional :: big
    ! logical, intent(in), optional :: display
    ! end subroutine
    ! !====================================================================!
  end interface

  ! public rngChisq

  ! interface rngChisq
  !   !! Pull from a Chi Ssquared distribution
  !   !!
  !   !! Example
  !   !!```fortran
  !   !!program Chisq_test
  !   !!use variableKind, only: r64
  !   !!use m_allocate, only: allocate
  !   !!use m_random, only: rngChiSq
  !   !!implicit none
  !   !!real(r64), allocatable :: a
  !   !!call allocate(a, 10000)
  !   !!call rngChiSq(a, )
  !   !!end program
  !   !!```
  !   !====================================================================!
  !   module subroutine rngChisq_d1(this,ndf,first)
  !     !! Interfaced with [[rngChiSq]]
  !   !====================================================================!
  !   ! Generates a random variate from the chi-squared distribution with
  !   ! ndf degrees of freedom
  !   real(r64) :: this
  !   INTEGER, INTENT(IN) :: ndf
  !   LOGICAL, INTENT(IN) :: first
  !   END subroutine
  !   !====================================================================!
  !   !====================================================================!
  !   module subroutine rngChisq_d1D(this,ndf,first)
  !     !! Interfaced with [[rngChiSq]]
  !   !====================================================================!
  !   real(r64) :: this(:)
  !   INTEGER, INTENT(IN) :: ndf
  !   LOGICAL, INTENT(IN) :: first
  !   end subroutine
  !   !====================================================================!
  ! end interface

  public :: rngExponential

  interface rngExponential
    module procedure :: rngExponential_d1, rngExponential_d1D, rngExponential_d2D, rngExponential_d3D
  end interface

  ! public :: rngGamma

  ! interface rngGamma
  !   !====================================================================!
  !   module subroutine rngGamma_d1D(this,s,first)
  !     !! Interfaced with [[rngGamma]]
  !   !====================================================================!
  !   real(r64) :: this(:)
  !   real(r64), INTENT(IN) :: s
  !   LOGICAL, INTENT(IN) :: first
  !   end subroutine
  !   !====================================================================!
  !   !====================================================================!
  !   module subroutine rngGamma_d1(this,s,first)
  !     !! Interfaced with [[rngGamma]]
  !   !====================================================================!
  !   real(r64) :: this
  !   real(r64), INTENT(IN)    :: s
  !   LOGICAL, INTENT(IN) :: first
  !   END subroutine
  !   !====================================================================!
  ! end interface

  public :: rngInteger

  interface rngInteger
    !! Generate size(this) random integers starting from imin
    module procedure :: rngInteger_i1, rngInteger_i1D, rngInteger_i2D, rngInteger_i3D
  end interface


  public :: rngNormal

  interface rngNormal
    module procedure :: rngNormal_d1, rngNormal_d1D, rngNormal_d2D, rngNormal_d3D
  end interface

  public :: rngUniform

  interface rngUniform
    module procedure :: rngUniform_d1, rngUniform_d1D, rngUniform_d2D, rngUniform_d3D
  end interface

  public :: rngWeibull

  interface rngWeibull
    module procedure :: rngWeibull_d1, rngWeibull_d1D, rngWeibull_d2D, rngWeibull_d3D
  end interface


  contains


  !====================================================================!
  subroutine setPrng_withSeed(seed, big)
    !! Interfaced to setPrng()
    !! Sets the seed of the random number generator with a specified seed
    !! 
  !====================================================================!
  integer(i64), intent(in) :: seed(:)
  logical, intent(in), optional :: big
  
  globalPrng = Prng(seed, big)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine setPrng_WOseed(big, display)
    !! Interfaced to setPrng()
    !! 'Randomly' sets the seed of the random number generator
  !====================================================================!
  !integer, allocatable :: seed(:)

  logical, intent(in), optional :: big
!  integer :: n,istat
  logical, intent(in), optional :: display

  globalPrng = Prng(big, display)

  end subroutine
  !====================================================================!

  !====================================================================!
  subroutine rngExponential_d1(this, lambda)
    !! Interfaced with [[rngExponential]]
  !====================================================================!
  real(r64)  :: this
    !! Random number
  real(r64) :: lambda
    !! Inverse scale > 0
  call globalPrng%rngExponential(this, lambda)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngExponential_d1D(this, lambda)
    !! Interfaced with [[rngExponential]]
  !====================================================================!
  real(r64) :: this(:)
    !! Random numbers
  real(r64) :: lambda
    !! Inverse scale > 0
  call globalPrng%rngExponential(this, lambda)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngExponential_d2D(this, lambda)
    !! Interfaced with [[rngExponential]]
  !====================================================================!
  real(r64) :: this(:,:)
    !! Random numbers
  real(r64) :: lambda
    !! Inverse scale > 0
  call globalPrng%rngExponential(this, lambda)    
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngExponential_d3D(this, lambda)
    !! Interfaced with [[rngExponential]]
  !====================================================================!
  real(r64) :: this(:,:,:)
    !! Random numbers
  real(r64) :: lambda
    !! Inverse scale > 0
  call globalPrng%rngExponential(this, lambda)
  end subroutine
  !====================================================================!

  !====================================================================!
  subroutine rngInteger_i1(this, imin, imax)
    !! Interfaced with [[rngInteger]]
  !====================================================================!
  integer(i32), intent(inout) :: this
  integer(i32), intent(in) :: imin
  integer(i32), intent(in) :: imax
  call globalPrng%rngInteger(this, imin, imax)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngInteger_i1D(this, imin, imax)
    !! Interfaced with [[rngInteger]]
  !====================================================================!
  integer(i32), intent(inout) :: this(:)
  integer(i32), intent(in) :: imin
  integer(i32), intent(in) :: imax
  call globalPrng%rngInteger(this, imin, imax)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngInteger_i2D(this, imin, imax)
    !! Interfaced with [[rngInteger]]
  !====================================================================!
  integer(i32), intent(inout) :: this(:,:)
  integer(i32), intent(in) :: imin
  integer(i32), intent(in) :: imax
  call globalPrng%rngInteger(this, imin, imax)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngInteger_i3D(this, imin, imax)
    !! Interfaced with [[rngInteger]]
  !====================================================================!
  integer(i32), intent(inout) :: this(:,:,:)
  integer(i32), intent(in) :: imin
  integer(i32), intent(in) :: imax
  call globalPrng%rngInteger(this, imin, imax)
  end subroutine
  !====================================================================!

  !====================================================================!
  subroutine rngNormal_d1(this, mean, std)
    !! Interfaced with [[rngNormal]]
  !====================================================================!
  real(r64), intent(inout) :: this
  real(r64), intent(in), optional :: mean, std
  call globalPrng%rngNormal(this, mean, std)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngNormal_d1D(this, mean, std)
    !! Interfaced with [[rngNormal]]
  !====================================================================!
  real(r64), intent(inout) :: this(:)
  real(r64),optional, intent(in) :: mean, std
  call globalPrng%rngNormal(this, mean, std)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngNormal_d2D(this, mean, std)
    !! Interfaced with [[rngNormal]]
  !====================================================================!
  real(r64), intent(inout) :: this(:,:)
  real(r64),optional, intent(in) :: mean, std
  call globalPrng%rngNormal(this, mean, std)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngNormal_d3D(this, mean, std)
    !! Interfaced with [[rngNormal]]
  !====================================================================!
  real(r64), intent(inout) :: this(:,:,:)
  real(r64),optional, intent(in) :: mean, std
  call globalPrng%rngNormal(this, mean, std)
  end subroutine
  !====================================================================!

  !====================================================================!
  subroutine rngUniform_d1(this,rmin,rmax)
    !! Interfaced with [[rngUniform]]
  !====================================================================!
  real(r64), intent(inout) :: this
  real(r64), intent(in), optional :: rmin
  real(r64), intent(in), optional :: rmax
  call globalPrng%rngUniform(this, rmin, rmax)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngUniform_d1D(this,rmin,rmax)
    !! Interfaced with [[rngUniform]]
  !====================================================================!
  real(r64), intent(inout) :: this(:)
  real(r64), intent(in), optional :: rmin
  real(r64), intent(in), optional :: rmax
  call globalPrng%rngUniform(this, rmin, rmax)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngUniform_d2D(this,rmin,rmax)
    !! Interfaced with [[rngUniform]]
  !====================================================================!
  real(r64), intent(inout) :: this(:,:)
  real(r64), intent(in), optional :: rmin
  real(r64), intent(in), optional :: rmax
  call globalPrng%rngUniform(this, rmin, rmax)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngUniform_d3D(this,rmin,rmax)
    !! Interfaced with [[rngUniform]]
  !====================================================================!
  real(r64), intent(inout) :: this(:,:,:)
  real(r64), intent(in), optional :: rmin
  real(r64), intent(in), optional :: rmax
  call globalPrng%rngUniform(this, rmin, rmax)
  end subroutine
  !====================================================================!

  !====================================================================!
  subroutine rngWeibull_d1(this, lambda, k)
    !! Interfaced with [[rngWeibull]]
  !====================================================================!
  real(r64), intent(inout) :: this
    !! Draw from Weibull distribution
  real(r64), intent(in) :: lambda
    !! Scale of the distribution
  real(r64), intent(in) :: k
    !! Shape of the distribution
  call globalPrng%rngWeibull(this, lambda, k)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngWeibull_d1D(this, lambda, k)
    !! Interfaced with [[rngWeibull]]
  !====================================================================!
  real(r64), intent(inout) :: this(:)
    !! Draw from Weibull distribution
  real(r64), intent(in) :: lambda
    !! Scale of the distribution
  real(r64), intent(in) :: k
    !! Shape of the distribution
  call globalPrng%rngWeibull(this, lambda, k)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngWeibull_d2D(this, lambda, k)
    !! Interfaced with [[rngWeibull]]
  !====================================================================!
  real(r64), intent(inout) :: this(:,:)
    !! Draw from Weibull distribution
  real(r64), intent(in) :: lambda
    !! Scale of the distribution
  real(r64), intent(in) :: k
    !! Shape of the distribution
  call globalPrng%rngWeibull(this, lambda, k)
  end subroutine
  !====================================================================!
  !====================================================================!
  subroutine rngWeibull_d3D(this, lambda, k)
    !! Interfaced with [[rngWeibull]]
  !====================================================================!
  real(r64), intent(inout) :: this(:,:,:)
    !! Draw from Weibull distribution
  real(r64), intent(in) :: lambda
    !! Scale of the distribution
  real(r64), intent(in) :: k
    !! Shape of the distribution
  call globalPrng%rngWeibull(this, lambda, k)
  end subroutine
  !====================================================================!

end module

  !====================================================================!
  ! EXTRA CODES TO BE TRANSLATED LATER!!!
  !====================================================================!
  !
  !
  !  FUNCTION random_beta(aa, bb, first) RESULT(fn_val)
  !
  !! Adapted from Fortran 77 code from the book:
  !!     Dagpunar, J. 'Principles of random variate generation'
  !!     Clarendon Press, Oxford, 1988.   ISBN 0-19-852202-9
  !
  !! FUNCTION GENERATES A RANDOM VARIATE IN [0,1]
  !! FROM A BETA DISTRIBUTION WITH DENSITY
  !! PROPORTIONAL TO BETA**(AA-1) * (1-BETA)**(BB-1).
  !! USING CHENG'S LOG LOGISTIC METHOD.
  !
  !!     AA = SHAPE PARAMETER FROM DISTRIBUTION (0 < REAL)
  !!     BB = SHAPE PARAMETER FROM DISTRIBUTION (0 < REAL)
  !
  !REAL, INTENT(IN)    :: aa, bb
  !LOGICAL, INTENT(IN) :: first
  !REAL                :: fn_val
  !
  !!     Local variables
  !REAL, PARAMETER  :: aln4 = 1.3862944
  !REAL             :: a, b, g, r, s, x, y, z
  !REAL, SAVE       :: d, f, h, t, c
  !LOGICAL, SAVE    :: swap
  !
  !IF (aa <= zero .OR. bb <= zero) THEN
  !  WRITE(*, *) 'IMPERMISSIBLE SHAPE PARAMETER VALUE(S)'
  !  STOP
  !END IF
  !
  !IF (first) THEN                        ! Initialization, if necessary
  !  a = aa
  !  b = bb
  !  swap = b > a
  !  IF (swap) THEN
  !    g = b
  !    b = a
  !    a = g
  !  END IF
  !  d = a/b
  !  f = a+b
  !  IF (b > one) THEN
  !    h = SQRT((two*a*b - f)/(f - two))
  !    t = one
  !  ELSE
  !    h = b
  !    t = one/(one + (a/(vlarge*b))**b)
  !  END IF
  !  c = a+h
  !END IF
  !
  !DO
  !  CALL RANDOM_NUMBER(r)
  !  CALL RANDOM_NUMBER(x)
  !  s = r*r*x
  !  IF (r < vsmall .OR. s <= zero) CYCLE
  !  IF (r < t) THEN
  !    x = LOG(r/(one - r))/h
  !    y = d*EXP(x)
  !    z = c*x + f*LOG((one + d)/(one + y)) - aln4
  !    IF (s - one > z) THEN
  !      IF (s - s*z > one) CYCLE
  !      IF (LOG(s) > z) CYCLE
  !    END IF
  !    fn_val = y/(one + y)
  !  ELSE
  !    IF (4.0*s > (one + one/d)**f) CYCLE
  !    fn_val = one
  !  END IF
  !  EXIT
  !END DO
  !
  !IF (swap) fn_val = one - fn_val
  !RETURN
  !END FUNCTION random_beta
  !
  !
  !
  !FUNCTION random_t(m) RESULT(fn_val)
  !
  !! Adapted from Fortran 77 code from the book:
  !!     Dagpunar, J. 'Principles of random variate generation'
  !!     Clarendon Press, Oxford, 1988.   ISBN 0-19-852202-9
  !
  !! FUNCTION GENERATES A RANDOM VARIATE FROM A
  !! T DISTRIBUTION USING KINDERMAN AND MONAHAN'S RATIO METHOD.
  !
  !!     M = DEGREES OF FREEDOM OF DISTRIBUTION
  !!           (1 <= 1NTEGER)
  !
  !INTEGER, INTENT(IN) :: m
  !REAL                :: fn_val
  !
  !!     Local variables
  !REAL, SAVE      :: s, c, a, f, g
  !REAL            :: r, x, v
  !
  !REAL, PARAMETER :: three = 3.0, four = 4.0, quart = 0.25,   &
    !                   five = 5.0, sixteen = 16.0
    !INTEGER         :: mm = 0
    !
    !IF (m < 1) THEN
    !  WRITE(*, *) 'IMPERMISSIBLE DEGREES OF FREEDOM'
    !  STOP
    !END IF
    !
    !IF (m /= mm) THEN                    ! Initialization, if necessary
    !  s = m
    !  c = -quart*(s + one)
    !  a = four/(one + one/s)**c
    !  f = sixteen/a
    !  IF (m > 1) THEN
    !    g = s - one
    !    g = ((s + one)/g)**c*SQRT((s+s)/g)
    !  ELSE
    !    g = one
    !  END IF
    !  mm = m
    !END IF
    !
    !DO
    !  CALL RANDOM_NUMBER(r)
    !  IF (r <= zero) CYCLE
    !  CALL RANDOM_NUMBER(v)
    !  x = (two*v - one)*g/r
    !  v = x*x
    !  IF (v > five - a*r) THEN
    !    IF (m >= 1 .AND. r*(v + three) > f) CYCLE
    !    IF (r > (one + v/s)**c) CYCLE
    !  END IF
    !  EXIT
    !END DO
    !
    !fn_val = x
    !RETURN
    !END FUNCTION random_t
    !
    !
    !
    !SUBROUTINE random_mvnorm(n, h, d, f, first, x, ier)
    !
    !! Adapted from Fortran 77 code from the book:
    !!     Dagpunar, J. 'Principles of random variate generation'
    !!     Clarendon Press, Oxford, 1988.   ISBN 0-19-852202-9
    !
    !! N.B. An extra argument, ier, has been added to Dagpunar's routine
    !
    !!     SUBROUTINE GENERATES AN N VARIATE RANDOM NORMAL
    !!     VECTOR USING A CHOLESKY DECOMPOSITION.
    !
    !! ARGUMENTS:
    !!        N = NUMBER OF VARIATES IN VECTOR
    !!           (INPUT,INTEGER >= 1)
    !!     H(J) = J'TH ELEMENT OF VECTOR OF MEANS
    !!           (INPUT,REAL)
    !!     X(J) = J'TH ELEMENT OF DELIVERED VECTOR
    !!           (OUTPUT,REAL)
    !!
    !!    D(J*(J-1)/2+I) = (I,J)'TH ELEMENT OF VARIANCE MATRIX (J> = I)
    !!            (INPUT,REAL)
    !!    F((J-1)*(2*N-J)/2+I) = (I,J)'TH ELEMENT OF LOWER TRIANGULAR
    !!           DECOMPOSITION OF VARIANCE MATRIX (J <= I)
    !!            (OUTPUT,REAL)
    !
    !!    FIRST = .TRUE. IF THIS IS THE FIRST CALL OF THE ROUTINE
    !!    OR IF THE DISTRIBUTION HAS CHANGED SINCE THE LAST CALL OF THE ROUTINE.
    !!    OTHERWISE SET TO .FALSE.
    !!            (INPUT,LOGICAL)
    !
    !!    ier = 1 if the input covariance matrix is not +ve definite
    !!        = 0 otherwise
    !
    !INTEGER, INTENT(IN)   :: n
    !REAL, INTENT(IN)      :: h(:), d(:)   ! d(n*(n+1)/2)
    !REAL, INTENT(IN OUT)  :: f(:)         ! f(n*(n+1)/2)
    !REAL, INTENT(OUT)     :: x(:)
    !LOGICAL, INTENT(IN)   :: first
    !INTEGER, INTENT(OUT)  :: ier
    !
    !!     Local variables
    !INTEGER       :: j, i, m
    !REAL          :: y, v
    !INTEGER, SAVE :: n2
    !
    !IF (n < 1) THEN
    !  WRITE(*, *) 'SIZE OF VECTOR IS NON POSITIVE'
    !  STOP
    !END IF
    !
    !ier = 0
    !IF (first) THEN                        ! Initialization, if necessary
    !  n2 = 2*n
    !  IF (d(1) < zero) THEN
    !    ier = 1
    !    RETURN
    !  END IF
    !
    !  f(1) = SQRT(d(1))
    !  y = one/f(1)
    !  DO j = 2,n
    !    f(j) = d(1+j*(j-1)/2) * y
    !  END DO
    !
    !  DO i = 2,n
    !    v = d(i*(i-1)/2+i)
    !    DO m = 1,i-1
    !      v = v - f((m-1)*(n2-m)/2+i)**2
    !    END DO
    !
    !    IF (v < zero) THEN
    !      ier = 1
    !      RETURN
    !    END IF
    !
    !    v = SQRT(v)
    !    y = one/v
    !    f((i-1)*(n2-i)/2+i) = v
    !    DO j = i+1,n
    !      v = d(j*(j-1)/2+i)
    !      DO m = 1,i-1
    !        v = v - f((m-1)*(n2-m)/2+i)*f((m-1)*(n2-m)/2 + j)
    !      END DO ! m = 1,i-1
    !      f((i-1)*(n2-i)/2 + j) = v*y
    !    END DO ! j = i+1,n
    !  END DO ! i = 2,n
    !END IF
    !
    !x(1:n) = h(1:n)
    !DO j = 1,n
    !  y = random_normal()
    !  DO i = j,n
    !    x(i) = x(i) + f((j-1)*(n2-j)/2 + i) * y
    !  END DO ! i = j,n
    !END DO ! j = 1,n
    !
    !RETURN
    !END SUBROUTINE random_mvnorm
    !
    !
    !
    !FUNCTION random_inv_gauss(h, b, first) RESULT(fn_val)
    !
    !! Adapted from Fortran 77 code from the book:
    !!     Dagpunar, J. 'Principles of random variate generation'
    !!     Clarendon Press, Oxford, 1988.   ISBN 0-19-852202-9
    !
    !! FUNCTION GENERATES A RANDOM VARIATE IN [0,INFINITY] FROM
    !! A REPARAMETERISED GENERALISED INVERSE GAUSSIAN (GIG) DISTRIBUTION
    !! WITH DENSITY PROPORTIONAL TO  GIG**(H-1) * EXP(-0.5*B*(GIG+1/GIG))
    !! USING A RATIO METHOD.
    !
    !!     H = PARAMETER OF DISTRIBUTION (0 <= REAL)
    !!     B = PARAMETER OF DISTRIBUTION (0 < REAL)
    !
    !REAL, INTENT(IN)    :: h, b
    !LOGICAL, INTENT(IN) :: first
    !REAL                :: fn_val
    !
    !!     Local variables
    !REAL            :: ym, xm, r, w, r1, r2, x
    !REAL, SAVE      :: a, c, d, e
    !REAL, PARAMETER :: quart = 0.25
    !
    !IF (h < zero .OR. b <= zero) THEN
    !  WRITE(*, *) 'IMPERMISSIBLE DISTRIBUTION PARAMETER VALUES'
    !  STOP
    !END IF
    !
    !IF (first) THEN                        ! Initialization, if necessary
    !  IF (h > quart*b*SQRT(vlarge)) THEN
    !    WRITE(*, *) 'THE RATIO H:B IS TOO SMALL'
    !    STOP
    !  END IF
    !  e = b*b
    !  d = h + one
    !  ym = (-d + SQRT(d*d + e))/b
    !  IF (ym < vsmall) THEN
    !    WRITE(*, *) 'THE VALUE OF B IS TOO SMALL'
    !    STOP
    !  END IF
    !
    !  d = h - one
    !  xm = (d + SQRT(d*d + e))/b
    !  d = half*d
    !  e = -quart*b
    !  r = xm + one/xm
    !  w = xm*ym
    !  a = w**(-half*h) * SQRT(xm/ym) * EXP(-e*(r - ym - one/ym))
    !  IF (a < vsmall) THEN
    !    WRITE(*, *) 'THE VALUE OF H IS TOO LARGE'
    !    STOP
    !  END IF
    !  c = -d*LOG(xm) - e*r
    !END IF
    !
    !DO
    !  CALL RANDOM_NUMBER(r1)
    !  IF (r1 <= zero) CYCLE
    !  CALL RANDOM_NUMBER(r2)
    !  x = a*r2/r1
    !  IF (x <= zero) CYCLE
    !  IF (LOG(r1) < d*LOG(x) + e*(x + one/x) + c) EXIT
    !END DO
    !
    !fn_val = x
    !
    !RETURN
    !END FUNCTION random_inv_gauss
    !
    !
    !
    !FUNCTION random_Poisson(mu, first) RESULT(ival)
    !!**********************************************************************
    !!     Translated to Fortran 90 by Alan Miller from:
    !!                           RANLIB
    !!
    !!     Library of Fortran Routines for Random Number Generation
    !!
    !!                    Compiled and Written by:
    !!
    !!                         Barry W. Brown
    !!                          James Lovato
    !!
    !!             Department of Biomathematics, Box 237
    !!             The University of Texas, M.D. Anderson Cancer Center
    !!             1515 Holcombe Boulevard
    !!             Houston, TX      77030
    !!
    !! This work was supported by grant CA-16672 from the National Cancer Institute.
    !
    !!                    GENerate POIsson random deviate
    !
    !!                            Function
    !
    !! Generates a single random deviate from a Poisson distribution with mean mu.
    !
    !!                            Arguments
    !
    !!     mu --> The mean of the Poisson distribution from which
    !!            a random deviate is to be generated.
    !!                              REAL mu
    !
    !!                              Method
    !
    !!     For details see:
    !
    !!               Ahrens, J.H. and Dieter, U.
    !!               Computer Generation of Poisson Deviates
    !!               From Modified Normal Distributions.
    !!               ACM Trans. Math. Software, 8, 2
    !!               (June 1982),163-179
    !
    !!     TABLES: COEFFICIENTS A0-A7 FOR STEP F. FACTORIALS FACT
    !!     COEFFICIENTS A(K) - FOR PX = FK*V*V*SUM(A(K)*V**K)-DEL
    !
    !!     SEPARATION OF CASES A AND B
    !
    !!     .. Scalar Arguments ..
    !REAL, INTENT(IN)    :: mu
    !LOGICAL, INTENT(IN) :: first
    !INTEGER             :: ival
    !!     ..
    !!     .. Local Scalars ..
    !REAL          :: b1, b2, c, c0, c1, c2, c3, del, difmuk, e, fk, fx, fy, g,  &
    !                 omega, px, py, t, u, v, x, xx
    !REAL, SAVE    :: s, d, p, q, p0
    !INTEGER       :: j, k, kflag
    !LOGICAL, SAVE :: full_init
    !INTEGER, SAVE :: l, m
    !!     ..
    !!     .. Local Arrays ..
    !REAL, SAVE    :: pp(35)
    !!     ..
    !!     .. Data statements ..
    !REAL, PARAMETER :: a0 = -.5, a1 = .3333333, a2 = -.2500068, a3 = .2000118,  &
    !                   a4 = -.1661269, a5 = .1421878, a6 = -.1384794,   &
    !                   a7 = .1250060
    !
    !REAL, PARAMETER :: fact(10) = (/ 1., 1., 2., 6., 24., 120., 720., 5040.,  &
    !                                 40320., 362880. /)
    !
    !!     ..
    !!     .. Executable Statements ..
    !IF (mu > 10.0) THEN
    !!     C A S E  A. (RECALCULATION OF S, D, L IF MU HAS CHANGED)
    !
    !  IF (first) THEN
    !    s = SQRT(mu)
    !    d = 6.0*mu*mu
    !
    !!             THE POISSON PROBABILITIES PK EXCEED THE DISCRETE NORMAL
    !!             PROBABILITIES FK WHENEVER K >= M(MU). L=IFIX(MU-1.1484)
    !!             IS AN UPPER BOUND TO M(MU) FOR ALL MU >= 10 .
    !
    !    l = mu - 1.1484
    !    full_init = .false.
    !  END IF
    !
    !
    !!     STEP N. NORMAL SAMPLE - random_normal() FOR STANDARD NORMAL DEVIATE
    !
    !  g = mu + s*random_normal()
    !  IF (g > 0.0) THEN
    !    ival = g
    !
    !!     STEP I. IMMEDIATE ACCEPTANCE IF ival IS LARGE ENOUGH
    !
    !    IF (ival>=l) RETURN
    !
    !!     STEP S. SQUEEZE ACCEPTANCE - SAMPLE U
    !
    !    fk = ival
    !    difmuk = mu - fk
    !    CALL RANDOM_NUMBER(u)
    !    IF (d*u >= difmuk*difmuk*difmuk) RETURN
    !  END IF
    !
    !!     STEP P. PREPARATIONS FOR STEPS Q AND H.
    !!             (RECALCULATIONS OF PARAMETERS IF NECESSARY)
    !!             .3989423=(2*PI)**(-.5)  .416667E-1=1./24.  .1428571=1./7.
    !!             THE QUANTITIES B1, B2, C3, C2, C1, C0 ARE FOR THE HERMITE
    !!             APPROXIMATIONS TO THE DISCRETE NORMAL PROBABILITIES FK.
    !!             C=.1069/MU GUARANTEES MAJORIZATION BY THE 'HAT'-FUNCTION.
    !
    !  IF (.NOT. full_init) THEN
    !    omega = .3989423/s
    !    b1 = .4166667E-1/mu
    !    b2 = .3*b1*b1
    !    c3 = .1428571*b1*b2
    !    c2 = b2 - 15.*c3
    !    c1 = b1 - 6.*b2 + 45.*c3
    !    c0 = 1. - b1 + 3.*b2 - 15.*c3
    !    c = .1069/mu
    !    full_init = .true.
    !  END IF
    !
    !  IF (g < 0.0) GO TO 50
    !
    !!             'SUBROUTINE' F IS CALLED (KFLAG=0 FOR CORRECT RETURN)
    !
    !  kflag = 0
    !  GO TO 70
    !
    !!     STEP Q. QUOTIENT ACCEPTANCE (RARE CASE)
    !
    !  40 IF (fy-u*fy <= py*EXP(px-fx)) RETURN
    !
    !!     STEP E. EXPONENTIAL SAMPLE - random_exponential() FOR STANDARD EXPONENTIAL
    !!             DEVIATE E AND SAMPLE T FROM THE LAPLACE 'HAT'
    !!             (IF T <= -.6744 THEN PK < FK FOR ALL MU >= 10.)
    !
    !  50 e = random_exponential()
    !  CALL RANDOM_NUMBER(u)
    !  u = u + u - one
    !  t = 1.8 + SIGN(e, u)
    !  IF (t <= (-.6744)) GO TO 50
    !  ival = mu + s*t
    !  fk = ival
    !  difmuk = mu - fk
    !
    !!             'SUBROUTINE' F IS CALLED (KFLAG=1 FOR CORRECT RETURN)
    !
    !  kflag = 1
    !  GO TO 70
    !
    !!     STEP H. HAT ACCEPTANCE (E IS REPEATED ON REJECTION)
    !
    !  60 IF (c*ABS(u) > py*EXP(px+e) - fy*EXP(fx+e)) GO TO 50
    !  RETURN
    !
    !!     STEP F. 'SUBROUTINE' F. CALCULATION OF PX, PY, FX, FY.
    !!             CASE ival < 10 USES FACTORIALS FROM TABLE FACT
    !
    !  70 IF (ival>=10) GO TO 80
    !  px = -mu
    !  py = mu**ival/fact(ival+1)
    !  GO TO 110
    !
    !!             CASE ival >= 10 USES POLYNOMIAL APPROXIMATION
    !!             A0-A7 FOR ACCURACY WHEN ADVISABLE
    !!             .8333333E-1=1./12.  .3989423=(2*PI)**(-.5)
    !
    !  80 del = .8333333E-1/fk
    !  del = del - 4.8*del*del*del
    !  v = difmuk/fk
    !  IF (ABS(v)>0.25) THEN
    !    px = fk*LOG(one + v) - difmuk - del
    !  ELSE
    !    px = fk*v*v* (((((((a7*v+a6)*v+a5)*v+a4)*v+a3)*v+a2)*v+a1)*v+a0) - del
    !  END IF
    !  py = .3989423/SQRT(fk)
    !  110 x = (half - difmuk)/s
    !  xx = x*x
    !  fx = -half*xx
    !  fy = omega* (((c3*xx + c2)*xx + c1)*xx + c0)
    !  IF (kflag <= 0) GO TO 40
    !  GO TO 60
    !
    !!---------------------------------------------------------------------------
    !!     C A S E  B.    mu < 10
    !!     START NEW TABLE AND CALCULATE P0 IF NECESSARY
    !
    !ELSE
    !  IF (first) THEN
    !    m = MAX(1, INT(mu))
    !    l = 0
    !    p = EXP(-mu)
    !    q = p
    !    p0 = p
    !  END IF
    !
    !!     STEP U. UNIFORM SAMPLE FOR INVERSION METHOD
    !
    !  DO
    !    CALL RANDOM_NUMBER(u)
    !    ival = 0
    !    IF (u <= p0) RETURN
    !
    !!     STEP T. TABLE COMPARISON UNTIL THE END PP(L) OF THE
    !!             PP-TABLE OF CUMULATIVE POISSON PROBABILITIES
    !!             (0.458=PP(9) FOR MU=10)
    !
    !    IF (l == 0) GO TO 150
    !    j = 1
    !    IF (u > 0.458) j = MIN(l, m)
    !    DO k = j, l
    !      IF (u <= pp(k)) GO TO 180
    !    END DO
    !    IF (l == 35) CYCLE
    !
    !!     STEP C. CREATION OF NEW POISSON PROBABILITIES P
    !!             AND THEIR CUMULATIVES Q=PP(K)
    !
    !    150 l = l + 1
    !    DO k = l, 35
    !      p = p*mu / k
    !      q = q + p
    !      pp(k) = q
    !      IF (u <= q) GO TO 170
    !    END DO
    !    l = 35
    !  END DO
    !
    !  170 l = k
    !  180 ival = k
    !  RETURN
    !END IF
    !
    !RETURN
    !END FUNCTION random_Poisson
    !
    !
    !
    !FUNCTION random_binomial1(n, p, first) RESULT(ival)
    !
    !! FUNCTION GENERATES A RANDOM BINOMIAL VARIATE USING C.D.Kemp's method.
    !! This algorithm is suitable when many random variates are required
    !! with the SAME parameter values for n & p.
    !
    !!    P = BERNOULLI SUCCESS PROBABILITY
    !!           (0 <= REAL <= 1)
    !!    N = NUMBER OF BERNOULLI TRIALS
    !!           (1 <= INTEGER)
    !!    FIRST = .TRUE. for the first call using the current parameter values
    !!          = .FALSE. if the values of (n,p) are unchanged from last call
    !
    !! Reference: Kemp, C.D. (1986). `A modal method for generating binomial
    !!            variables', Commun. Statist. - Theor. Meth. 15(3), 805-813.
    !
    !INTEGER, INTENT(IN) :: n
    !REAL, INTENT(IN)    :: p
    !LOGICAL, INTENT(IN) :: first
    !INTEGER             :: ival
    !
    !!     Local variables
    !
    !INTEGER         :: ru, rd
    !INTEGER, SAVE   :: r0
    !REAL            :: u, pd, pu
    !REAL, SAVE      :: odds_ratio, p_r
    !REAL, PARAMETER :: zero = 0.0, one = 1.0
    !
    !IF (first) THEN
    !  r0 = (n+1)*p
    !  p_r = bin_prob(n, p, r0)
    !  odds_ratio = p / (one - p)
    !END IF
    !
    !CALL RANDOM_NUMBER(u)
    !u = u - p_r
    !IF (u < zero) THEN
    !  ival = r0
    !  RETURN
    !END IF
    !
    !pu = p_r
    !ru = r0
    !pd = p_r
    !rd = r0
    !DO
    !  rd = rd - 1
    !  IF (rd >= 0) THEN
    !    pd = pd * (rd+1) / (odds_ratio * (n-rd))
    !    u = u - pd
    !    IF (u < zero) THEN
    !      ival = rd
    !      RETURN
    !    END IF
    !  END IF
    !
    !  ru = ru + 1
    !  IF (ru <= n) THEN
    !    pu = pu * (n-ru+1) * odds_ratio / ru
    !    u = u - pu
    !    IF (u < zero) THEN
    !      ival = ru
    !      RETURN
    !    END IF
    !  END IF
    !END DO
    !
    !!     This point should not be reached, but just in case:
    !
    !ival = r0
    !RETURN
    !
    !END FUNCTION random_binomial1
    !
    !
    !
    !FUNCTION bin_prob(n, p, r) RESULT(fn_val)
    !!     Calculate a binomial probability
    !
    !INTEGER, INTENT(IN) :: n, r
    !REAL, INTENT(IN)    :: p
    !REAL                :: fn_val
    !
    !!     Local variable
    !REAL                :: one = 1.0
    !
    !fn_val = EXP( lngamma(DBLE(n+1)) - lngamma(DBLE(r+1)) - lngamma(DBLE(n-r+1)) &
    !              + r*LOG(p) + (n-r)*LOG(one - p) )
    !RETURN
    !
    !END FUNCTION bin_prob
    !
    !
    !
    !FUNCTION lngamma(x) RESULT(fn_val)
    !
    !! Logarithm to base e of the gamma function.
    !!
    !! Accurate to about 1.e-14.
    !! Programmer: Alan Miller
    !
    !! Latest revision of Fortran 77 version - 28 February 1988
    !
    !REAL (dp), INTENT(IN) :: x
    !REAL (dp)             :: fn_val
    !
    !!       Local variables
    !
    !REAL (dp) :: a1 = -4.166666666554424D-02, a2 = 2.430554511376954D-03,  &
    !             a3 = -7.685928044064347D-04, a4 = 5.660478426014386D-04,  &
    !             temp, arg, product, lnrt2pi = 9.189385332046727D-1,       &
    !             pi = 3.141592653589793D0
    !LOGICAL   :: reflect
    !
    !!       lngamma is not defined if x = 0 or a negative integer.
    !
    !IF (x > 0.d0) GO TO 10
    !IF (x /= INT(x)) GO TO 10
    !fn_val = 0.d0
    !RETURN
    !
    !!       If x < 0, use the reflection formula:
    !!               gamma(x) * gamma(1-x) = pi * cosec(pi.x)
    !
    !10 reflect = (x < 0.d0)
    !IF (reflect) THEN
    !  arg = 1.d0 - x
    !ELSE
    !  arg = x
    !END IF
    !
    !!       Increase the argument, if necessary, to make it > 10.
    !
    !product = 1.d0
    !20 IF (arg <= 10.d0) THEN
    !  product = product * arg
    !  arg = arg + 1.d0
    !  GO TO 20
    !END IF
    !
    !!  Use a polynomial approximation to Stirling's formula.
    !!  N.B. The real Stirling's formula is used here, not the simpler, but less
    !!       accurate formula given by De Moivre in a letter to Stirling, which
    !!       is the one usually quoted.
    !
    !arg = arg - 0.5D0
    !temp = 1.d0/arg**2
    !fn_val = lnrt2pi + arg * (LOG(arg) - 1.d0 + &
    !                  (((a4*temp + a3)*temp + a2)*temp + a1)*temp) - LOG(product)
    !IF (reflect) THEN
    !  temp = SIN(pi * x)
    !  fn_val = LOG(pi/temp) - fn_val
    !END IF
    !RETURN
    !END FUNCTION lngamma
    !
    !
    !
    !FUNCTION random_binomial2(n, pp, first) RESULT(ival)
    !!**********************************************************************
    !!     Translated to Fortran 90 by Alan Miller from:
    !!                              RANLIB
    !!
    !!     Library of Fortran Routines for Random Number Generation
    !!
    !!                      Compiled and Written by:
    !!
    !!                           Barry W. Brown
    !!                            James Lovato
    !!
    !!               Department of Biomathematics, Box 237
    !!               The University of Texas, M.D. Anderson Cancer Center
    !!               1515 Holcombe Boulevard
    !!               Houston, TX      77030
    !!
    !! This work was supported by grant CA-16672 from the National Cancer Institute.
    !
    !!                    GENerate BINomial random deviate
    !
    !!                              Function
    !
    !!     Generates a single random deviate from a binomial
    !!     distribution whose number of trials is N and whose
    !!     probability of an event in each trial is P.
    !
    !!                              Arguments
    !
    !!     N  --> The number of trials in the binomial distribution
    !!            from which a random deviate is to be generated.
    !!                              INTEGER N
    !
    !!     P  --> The probability of an event in each trial of the
    !!            binomial distribution from which a random deviate
    !!            is to be generated.
    !!                              REAL P
    !
    !!     FIRST --> Set FIRST = .TRUE. for the first call to perform initialization
    !!               the set FIRST = .FALSE. for further calls using the same pair
    !!               of parameter values (N, P).
    !!                              LOGICAL FIRST
    !
    !!     random_binomial2 <-- A random deviate yielding the number of events
    !!                from N independent trials, each of which has
    !!                a probability of event P.
    !!                              INTEGER random_binomial
    !
    !!                              Method
    !
    !!     This is algorithm BTPE from:
    !
    !!         Kachitvichyanukul, V. and Schmeiser, B. W.
    !!         Binomial Random Variate Generation.
    !!         Communications of the ACM, 31, 2 (February, 1988) 216.
    !
    !!**********************************************************************
    !
    !!*****DETERMINE APPROPRIATE ALGORITHM AND WHETHER SETUP IS NECESSARY
    !
    !!     ..
    !!     .. Scalar Arguments ..
    !REAL, INTENT(IN)    :: pp
    !INTEGER, INTENT(IN) :: n
    !LOGICAL, INTENT(IN) :: first
    !INTEGER             :: ival
    !!     ..
    !!     .. Local Scalars ..
    !REAL            :: alv, amaxp, f, f1, f2, u, v, w, w2, x, x1, x2, ynorm, z, z2
    !REAL, PARAMETER :: zero = 0.0, half = 0.5, one = 1.0
    !INTEGER         :: i, ix, ix1, k, mp
    !INTEGER, SAVE   :: m
    !REAL, SAVE      :: p, q, xnp, ffm, fm, xnpq, p1, xm, xl, xr, c, al, xll,  &
    !                   xlr, p2, p3, p4, qn, r, g
    !
    !!     ..
    !!     .. Executable Statements ..
    !
    !!*****SETUP, PERFORM ONLY WHEN PARAMETERS CHANGE
    !
    !IF (first) THEN
    !  p = MIN(pp, one-pp)
    !  q = one - p
    !  xnp = n * p
    !END IF
    !
    !IF (xnp > 30.) THEN
    !  IF (first) THEN
    !    ffm = xnp + p
    !    m = ffm
    !    fm = m
    !    xnpq = xnp * q
    !    p1 = INT(2.195*SQRT(xnpq) - 4.6*q) + half
    !    xm = fm + half
    !    xl = xm - p1
    !    xr = xm + p1
    !    c = 0.134 + 20.5 / (15.3 + fm)
    !    al = (ffm-xl) / (ffm - xl*p)
    !    xll = al * (one + half*al)
    !    al = (xr - ffm) / (xr*q)
    !    xlr = al * (one + half*al)
    !    p2 = p1 * (one + c + c)
    !    p3 = p2 + c / xll
    !    p4 = p3 + c / xlr
    !  END IF
    !
    !!*****GENERATE VARIATE, Binomial mean at least 30.
    !
    !  20 CALL RANDOM_NUMBER(u)
    !  u = u * p4
    !  CALL RANDOM_NUMBER(v)
    !
    !!     TRIANGULAR REGION
    !
    !  IF (u <= p1) THEN
    !    ix = xm - p1 * v + u
    !    GO TO 110
    !  END IF
    !
    !!     PARALLELOGRAM REGION
    !
    !  IF (u <= p2) THEN
    !    x = xl + (u-p1) / c
    !    v = v * c + one - ABS(xm-x) / p1
    !    IF (v > one .OR. v <= zero) GO TO 20
    !    ix = x
    !  ELSE
    !
    !!     LEFT TAIL
    !
    !    IF (u <= p3) THEN
    !      ix = xl + LOG(v) / xll
    !      IF (ix < 0) GO TO 20
    !      v = v * (u-p2) * xll
    !    ELSE
    !
    !!     RIGHT TAIL
    !
    !      ix = xr - LOG(v) / xlr
    !      IF (ix > n) GO TO 20
    !      v = v * (u-p3) * xlr
    !    END IF
    !  END IF
    !
    !!*****DETERMINE APPROPRIATE WAY TO PERFORM ACCEPT/REJECT TEST
    !
    !  k = ABS(ix-m)
    !  IF (k <= 20 .OR. k >= xnpq/2-1) THEN
    !
    !!     EXPLICIT EVALUATION
    !
    !    f = one
    !    r = p / q
    !    g = (n+1) * r
    !    IF (m < ix) THEN
    !      mp = m + 1
    !      DO i = mp, ix
    !        f = f * (g/i-r)
    !      END DO
    !
    !    ELSE IF (m > ix) THEN
    !      ix1 = ix + 1
    !      DO i = ix1, m
    !        f = f / (g/i-r)
    !      END DO
    !    END IF
    !
    !    IF (v > f) THEN
    !      GO TO 20
    !    ELSE
    !      GO TO 110
    !    END IF
    !  END IF
    !
    !!     SQUEEZING USING UPPER AND LOWER BOUNDS ON LOG(F(X))
    !
    !  amaxp = (k/xnpq) * ((k*(k/3. + .625) + .1666666666666)/xnpq + half)
    !  ynorm = -k * k / (2.*xnpq)
    !  alv = LOG(v)
    !  IF (alv<ynorm - amaxp) GO TO 110
    !  IF (alv>ynorm + amaxp) GO TO 20
    !
    !!     STIRLING'S (actually de Moivre's) FORMULA TO MACHINE ACCURACY FOR
    !!     THE FINAL ACCEPTANCE/REJECTION TEST
    !
    !  x1 = ix + 1
    !  f1 = fm + one
    !  z = n + 1 - fm
    !  w = n - ix + one
    !  z2 = z * z
    !  x2 = x1 * x1
    !  f2 = f1 * f1
    !  w2 = w * w
    !  IF (alv - (xm*LOG(f1/x1) + (n-m+half)*LOG(z/w) + (ix-m)*LOG(w*p/(x1*q)) +    &
    !      (13860.-(462.-(132.-(99.-140./f2)/f2)/f2)/f2)/f1/166320. +               &
    !      (13860.-(462.-(132.-(99.-140./z2)/z2)/z2)/z2)/z/166320. +                &
    !      (13860.-(462.-(132.-(99.-140./x2)/x2)/x2)/x2)/x1/166320. +               &
    !      (13860.-(462.-(132.-(99.-140./w2)/w2)/w2)/w2)/w/166320.) > zero) THEN
    !    GO TO 20
    !  ELSE
    !    GO TO 110
    !  END IF
    !
    !ELSE
    !!     INVERSE CDF LOGIC FOR MEAN LESS THAN 30
    !  IF (first) THEN
    !    qn = q ** n
    !    r = p / q
    !    g = r * (n+1)
    !  END IF
    !
    !  90 ix = 0
    !  f = qn
    !  CALL RANDOM_NUMBER(u)
    !  100 IF (u >= f) THEN
    !    IF (ix > 110) GO TO 90
    !    u = u - f
    !    ix = ix + 1
    !    f = f * (g/ix - r)
    !    GO TO 100
    !  END IF
    !END IF
    !
    !110 IF (pp > half) ix = n - ix
    !ival = ix
    !RETURN
    !
    !END FUNCTION random_binomial2
    !
    !
    !
    !
    !FUNCTION random_neg_binomial(sk, p) RESULT(ival)
    !
    !! Adapted from Fortran 77 code from the book:
    !!     Dagpunar, J. 'Principles of random variate generation'
    !!     Clarendon Press, Oxford, 1988.   ISBN 0-19-852202-9
    !
    !! FUNCTION GENERATES A RANDOM NEGATIVE BINOMIAL VARIATE USING UNSTORED
    !! INVERSION AND/OR THE REPRODUCTIVE PROPERTY.
    !
    !!    SK = NUMBER OF FAILURES REQUIRED (Dagpunar's words!)
    !!       = the `power' parameter of the negative binomial
    !!           (0 < REAL)
    !!    P = BERNOULLI SUCCESS PROBABILITY
    !!           (0 < REAL < 1)
    !
    !! THE PARAMETER H IS SET SO THAT UNSTORED INVERSION ONLY IS USED WHEN P <= H,
    !! OTHERWISE A COMBINATION OF UNSTORED INVERSION AND
    !! THE REPRODUCTIVE PROPERTY IS USED.
    !
    !REAL, INTENT(IN)   :: sk, p
    !INTEGER            :: ival
    !
    !!     Local variables
    !! THE PARAMETER ULN = -LOG(MACHINE'S SMALLEST REAL NUMBER).
    !
    !REAL, PARAMETER    :: h = 0.7
    !REAL               :: q, x, st, uln, v, r, s, y, g
    !INTEGER            :: k, i, n
    !
    !IF (sk <= zero .OR. p <= zero .OR. p >= one) THEN
    !  WRITE(*, *) 'IMPERMISSIBLE DISTRIBUTION PARAMETER VALUES'
    !  STOP
    !END IF
    !
    !q = one - p
    !x = zero
    !st = sk
    !IF (p > h) THEN
    !  v = one/LOG(p)
    !  k = st
    !  DO i = 1,k
    !    DO
    !      CALL RANDOM_NUMBER(r)
    !      IF (r > zero) EXIT
    !    END DO
    !    n = v*LOG(r)
    !    x = x + n
    !  END DO
    !  st = st - k
    !END IF
    !
    !s = zero
    !uln = -LOG(vsmall)
    !IF (st > -uln/LOG(q)) THEN
    !  WRITE(*, *) ' P IS TOO LARGE FOR THIS VALUE OF SK'
    !  STOP
    !END IF
    !
    !y = q**st
    !g = st
    !CALL RANDOM_NUMBER(r)
    !DO
    !  IF (y > r) EXIT
    !  r = r - y
    !  s = s + one
    !  y = y*p*g/s
    !  g = g + one
    !END DO
    !
    !ival = x + s + half
    !RETURN
    !END FUNCTION random_neg_binomial
    !
    !
    !
    !FUNCTION random_von_Mises(k, first) RESULT(fn_val)
    !
    !!     Algorithm VMD from:
    !!     Dagpunar, J.S. (1990) `Sampling from the von Mises distribution via a
    !!     comparison of random numbers', J. of Appl. Statist., 17, 165-168.
    !
    !!     Fortran 90 code by Alan Miller
    !!     CSIRO Division of Mathematical & Information Sciences
    !
    !!     Arguments:
    !!     k (real)        parameter of the von Mises distribution.
    !!     first (logical) set to .TRUE. the first time that the function
    !!                     is called, or the first time with a new value
    !!                     for k.   When first = .TRUE., the function sets
    !!                     up starting values and may be very much slower.
    !
    !REAL, INTENT(IN)     :: k
    !LOGICAL, INTENT(IN)  :: first
    !REAL                 :: fn_val
    !
    !!     Local variables
    !
    !INTEGER          :: j, n
    !INTEGER, SAVE    :: nk
    !REAL, PARAMETER  :: pi = 3.14159265
    !REAL, SAVE       :: p(20), theta(0:20)
    !REAL             :: sump, r, th, lambda, rlast
    !REAL (dp)        :: dk
    !
    !IF (first) THEN                        ! Initialization, if necessary
    !  IF (k < zero) THEN
    !    WRITE(*, *) '** Error: argument k for random_von_Mises = ', k
    !    RETURN
    !  END IF
    !
    !  nk = k + k + one
    !  IF (nk > 20) THEN
    !    WRITE(*, *) '** Error: argument k for random_von_Mises = ', k
    !    RETURN
    !  END IF
    !
    !  dk = k
    !  theta(0) = zero
    !  IF (k > half) THEN
    !
    !!     Set up array p of probabilities.
    !
    !    sump = zero
    !    DO j = 1, nk
    !      IF (j < nk) THEN
    !        theta(j) = ACOS(one - j/k)
    !      ELSE
    !        theta(nk) = pi
    !      END IF
    !
    !!     Numerical integration of e^[k.cos(x)] from theta(j-1) to theta(j)
    !
    !      CALL integral(theta(j-1), theta(j), p(j), dk)
    !      sump = sump + p(j)
    !    END DO
    !    p(1:nk) = p(1:nk) / sump
    !  ELSE
    !    p(1) = one
    !    theta(1) = pi
    !  END IF                         ! if k > 0.5
    !END IF                           ! if first
    !
    !CALL RANDOM_NUMBER(r)
    !DO j = 1, nk
    !  r = r - p(j)
    !  IF (r < zero) EXIT
    !END DO
    !r = -r/p(j)
    !
    !DO
    !  th = theta(j-1) + r*(theta(j) - theta(j-1))
    !  lambda = k - j + one - k*COS(th)
    !  n = 1
    !  rlast = lambda
    !
    !  DO
    !    CALL RANDOM_NUMBER(r)
    !    IF (r > rlast) EXIT
    !    n = n + 1
    !    rlast = r
    !  END DO
    !
    !  IF (n .NE. 2*(n/2)) EXIT         ! is n even?
    !  CALL RANDOM_NUMBER(r)
    !END DO
    !
    !fn_val = SIGN(th, (r - rlast)/(one - rlast) - half)
    !RETURN
    !END FUNCTION random_von_Mises
    !
    !
    !
    !SUBROUTINE integral(a, b, result, dk)
    !
    !!     Gaussian integration of exp(k.cosx) from a to b.
    !
    !REAL (dp), INTENT(IN) :: dk
    !REAL, INTENT(IN)      :: a, b
    !REAL, INTENT(OUT)     :: result
    !
    !!     Local variables
    !
    !REAL (dp)  :: xmid, range, x1, x2,                                    &
    !  x(3) = (/0.238619186083197_dp, 0.661209386466265_dp, 0.932469514203152_dp/), &
    !  w(3) = (/0.467913934572691_dp, 0.360761573048139_dp, 0.171324492379170_dp/)
    !INTEGER    :: i
    !
    !xmid = (a + b)/2._dp
    !range = (b - a)/2._dp
    !
    !result = 0._dp
    !DO i = 1, 3
    !  x1 = xmid + x(i)*range
    !  x2 = xmid - x(i)*range
    !  result = result + w(i)*(EXP(dk*COS(x1)) + EXP(dk*COS(x2)))
    !END DO
    !
    !result = result * range
    !RETURN
    !END SUBROUTINE integral
    !
    !
    !
    !FUNCTION random_Cauchy() RESULT(fn_val)
    !
    !!     Generate a random deviate from the standard Cauchy distribution
    !
    !REAL     :: fn_val
    !
    !!     Local variables
    !REAL     :: v(2)
    !
    !DO
    !  CALL RANDOM_NUMBER(v)
    !  v = two*(v - half)
    !  IF (ABS(v(2)) < vsmall) CYCLE               ! Test for zero
    !  IF (v(1)**2 + v(2)**2 < one) EXIT
    !END DO
    !fn_val = v(1) / v(2)
    !
    !RETURN
    !END FUNCTION random_Cauchy