2 ! A module for random number generation from the following distributions:
4 ! Distribution Function/subroutine name
6 ! Normal (Gaussian) random_normal
8 ! Chi-squared random_chisq
9 ! Exponential random_exponential
10 ! Weibull random_Weibull
13 ! Multivariate normal random_mvnorm
14 ! Generalized inverse Gaussian random_inv_gauss
15 ! Poisson random_Poisson
16 ! Binomial random_binomial1 *
18 ! Negative binomial random_neg_binomial
19 ! von Mises random_von_Mises
20 ! Cauchy random_Cauchy
22 ! Generate a random ordering of the integers 1 .. N
24 ! Initialize (seed) the uniform random number generator for ANY compiler
27 ! Lognormal - see note below.
29 ! ** Two functions are provided for the binomial distribution.
30 ! If the parameter values remain constant, it is recommended that the
31 ! first function is used (random_binomial1). If one or both of the
32 ! parameters change, use the second function (random_binomial2).
34 ! The compilers own random number generator, SUBROUTINE RANDOM_NUMBER(r),
35 ! is used to provide a source of uniformly distributed random numbers.
37 ! N.B. At this stage, only one random number is generated at each call to
38 ! one of the functions above.
40 ! The module uses the following functions which are included here:
41 ! bin_prob to calculate a single binomial probability
42 ! lngamma to calculate the logarithm to base e of the gamma function
44 ! Some of the code is adapted from Dagpunar's book:
45 ! Dagpunar, J. 'Principles of random variate generation'
46 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
48 ! In most of Dagpunar's routines, there is a test to see whether the value
49 ! of one or two floating-point parameters has changed since the last call.
50 ! These tests have been replaced by using a logical variable FIRST.
51 ! This should be set to .TRUE. on the first call using new values of the
52 ! parameters, and .FALSE. if the parameter values are the same as for the
55 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
56 ! Lognormal distribution
57 ! If X has a lognormal distribution, then log(X) is normally distributed.
58 ! Here the logarithm is the natural logarithm, that is to base e, sometimes
59 ! denoted as ln. To generate random variates from this distribution, generate
60 ! a random deviate from the normal distribution with mean and variance equal
61 ! to the mean and variance of the logarithms of X, then take its exponential.
63 ! Relationship between the mean & variance of log(X) and the mean & variance
64 ! of X, when X has a lognormal distribution.
65 ! Let m = mean of log(X), and s^2 = variance of log(X)
67 ! mean of X = exp(m + 0.5s^2)
68 ! variance of X = (mean(X))^2.[exp(s^2) - 1]
70 ! In the reverse direction (rarely used)
71 ! variance of log(X) = log[1 + var(X)/(mean(X))^2]
72 ! mean of log(X) = log(mean(X) - 0.5var(log(X))
74 ! N.B. The above formulae relate to population parameters; they will only be
75 ! approximate if applied to sample values.
76 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
78 ! Version 1.13, 2 October 2000
79 ! Changes from version 1.01
80 ! 1. The random_order, random_Poisson & random_binomial routines have been
81 ! replaced with more efficient routines.
82 ! 2. A routine, seed_random_number, has been added to seed the uniform random
83 ! number generator. This requires input of the required number of seeds
84 ! for the particular compiler from a specified I/O unit such as a keyboard.
85 ! 3. Made compatible with Lahey's ELF90.
86 ! 4. Marsaglia & Tsang algorithm used for random_gamma when shape parameter > 1.
87 ! 5. INTENT for array f corrected in random_mvnorm.
90 ! CSIRO Division of Mathematical & Information Sciences
91 ! Private Bag 10, Clayton South MDC
92 ! Clayton 3169, Victoria, Australia
93 ! Phone: (+61) 3 9545-8016 Fax: (+61) 3 9545-8080
94 ! e-mail: amiller @ bigpond.net.au
97 REAL, PRIVATE
:: zero
= 0.0, half
= 0.5, one
= 1.0, two
= 2.0, &
98 vsmall
= TINY(1.0), vlarge
= HUGE(1.0)
100 INTEGER, PARAMETER :: dp
= SELECTED_REAL_KIND(12, 60)
106 FUNCTION random_normal() RESULT(fn_val
)
108 ! Adapted from the following Fortran 77 code
109 ! ALGORITHM 712, COLLECTED ALGORITHMS FROM ACM.
110 ! THIS WORK PUBLISHED IN TRANSACTIONS ON MATHEMATICAL SOFTWARE,
111 ! VOL. 18, NO. 4, DECEMBER, 1992, PP. 434-435.
113 ! The function random_normal() returns a normally distributed pseudo-random
114 ! number with zero mean and unit variance.
116 ! The algorithm uses the ratio of uniforms method of A.J. Kinderman
117 ! and J.F. Monahan augmented with quadratic bounding curves.
122 REAL :: s
= 0.449871, t
= -0.386595, a
= 0.19600, b
= 0.25472, &
123 r1
= 0.27597, r2
= 0.27846, u
, v
, x
, y
, q
125 ! Generate P = (u,v) uniform in rectangle enclosing acceptance region
128 CALL RANDOM_NUMBER(u
)
129 CALL RANDOM_NUMBER(v
)
130 v
= 1.7156 * (v
- half
)
132 ! Evaluate the quadratic form
135 q
= x
**2 + y
*(a
*y
- b
*x
)
137 ! Accept P if inside inner ellipse
139 ! Reject P if outside outer ellipse
141 ! Reject P if outside acceptance region
142 IF (v
**2 < -4.0*LOG(u
)*u
**2) EXIT
145 ! Return ratio of P's coordinates as the normal deviate
149 END FUNCTION random_normal
153 FUNCTION random_gamma(s
, first
) RESULT(fn_val
)
155 ! Adapted from Fortran 77 code from the book:
156 ! Dagpunar, J. 'Principles of random variate generation'
157 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
159 ! FUNCTION GENERATES A RANDOM GAMMA VARIATE.
160 ! CALLS EITHER random_gamma1 (S > 1.0)
161 ! OR random_exponential (S = 1.0)
162 ! OR random_gamma2 (S < 1.0).
164 ! S = SHAPE PARAMETER OF DISTRIBUTION (0 < REAL).
166 REAL, INTENT(IN
) :: s
167 LOGICAL, INTENT(IN
) :: first
171 WRITE(*, *) 'SHAPE PARAMETER VALUE MUST BE POSITIVE'
176 fn_val
= random_gamma1(s
, first
)
177 ELSE IF (s
< one
) THEN
178 fn_val
= random_gamma2(s
, first
)
180 fn_val
= random_exponential()
184 END FUNCTION random_gamma
188 FUNCTION random_gamma1(s
, first
) RESULT(fn_val
)
190 ! Uses the algorithm in
191 ! Marsaglia, G. and Tsang, W.W. (2000) `A simple method for generating
192 ! gamma variables', Trans. om Math. Software (TOMS), vol.26(3), pp.363-372.
194 ! Generates a random gamma deviate for shape parameter s >= 1.
196 REAL, INTENT(IN
) :: s
197 LOGICAL, INTENT(IN
) :: first
212 ! Generate v = (1+cx)^3 where x is random normal; repeat if v <= 0.
220 ! Generate uniform variable U
222 CALL RANDOM_NUMBER(u
)
223 IF (u
< one
- 0.0331*x
**4) THEN
226 ELSE IF (LOG(u
) < half
*x
**2 + d
*(one
- v
+ LOG(v
))) THEN
233 END FUNCTION random_gamma1
237 FUNCTION random_gamma2(s
, first
) RESULT(fn_val
)
239 ! Adapted from Fortran 77 code from the book:
240 ! Dagpunar, J. 'Principles of random variate generation'
241 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
243 ! FUNCTION GENERATES A RANDOM VARIATE IN [0,INFINITY) FROM
244 ! A GAMMA DISTRIBUTION WITH DENSITY PROPORTIONAL TO
245 ! GAMMA2**(S-1) * EXP(-GAMMA2),
246 ! USING A SWITCHING METHOD.
248 ! S = SHAPE PARAMETER OF DISTRIBUTION
251 REAL, INTENT(IN
) :: s
252 LOGICAL, INTENT(IN
) :: first
257 REAL, SAVE :: a
, p
, c
, uf
, vr
, d
259 IF (s
<= zero
.OR
. s
>= one
) THEN
260 WRITE(*, *) 'SHAPE PARAMETER VALUE OUTSIDE PERMITTED RANGE'
264 IF (first
) THEN ! Initialization, if necessary
266 p
= a
/(a
+ s
*EXP(-a
))
268 WRITE(*, *) 'SHAPE PARAMETER VALUE TOO SMALL'
278 CALL RANDOM_NUMBER(r
)
282 x
= a
- LOG((one
- r
)/(one
- p
))
284 ELSE IF (r
> uf
) THEN
292 CALL RANDOM_NUMBER(r
)
293 IF (one
-r
<= w
.AND
. r
> zero
) THEN
294 IF (r
*(w
+ one
) >= one
) CYCLE
295 IF (-LOG(r
) <= w
) CYCLE
303 END FUNCTION random_gamma2
307 FUNCTION random_chisq(ndf
, first
) RESULT(fn_val
)
309 ! Generates a random variate from the chi-squared distribution with
310 ! ndf degrees of freedom
312 INTEGER, INTENT(IN
) :: ndf
313 LOGICAL, INTENT(IN
) :: first
316 fn_val
= two
* random_gamma(half
*ndf
, first
)
319 END FUNCTION random_chisq
323 FUNCTION random_exponential() RESULT(fn_val
)
325 ! Adapted from Fortran 77 code from the book:
326 ! Dagpunar, J. 'Principles of random variate generation'
327 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
329 ! FUNCTION GENERATES A RANDOM VARIATE IN [0,INFINITY) FROM
330 ! A NEGATIVE EXPONENTIAL DlSTRIBUTION WlTH DENSITY PROPORTIONAL
331 ! TO EXP(-random_exponential), USING INVERSION.
339 CALL RANDOM_NUMBER(r
)
346 END FUNCTION random_exponential
350 FUNCTION random_Weibull(a
) RESULT(fn_val
)
352 ! Generates a random variate from the Weibull distribution with
353 ! probability density:
358 REAL, INTENT(IN
) :: a
361 ! For speed, there is no checking that a is not zero or very small.
363 fn_val
= random_exponential() ** (one
/a
)
366 END FUNCTION random_Weibull
370 FUNCTION random_beta(aa
, bb
, first
) RESULT(fn_val
)
372 ! Adapted from Fortran 77 code from the book:
373 ! Dagpunar, J. 'Principles of random variate generation'
374 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
376 ! FUNCTION GENERATES A RANDOM VARIATE IN [0,1]
377 ! FROM A BETA DISTRIBUTION WITH DENSITY
378 ! PROPORTIONAL TO BETA**(AA-1) * (1-BETA)**(BB-1).
379 ! USING CHENG'S LOG LOGISTIC METHOD.
381 ! AA = SHAPE PARAMETER FROM DISTRIBUTION (0 < REAL)
382 ! BB = SHAPE PARAMETER FROM DISTRIBUTION (0 < REAL)
384 REAL, INTENT(IN
) :: aa
, bb
385 LOGICAL, INTENT(IN
) :: first
389 REAL, PARAMETER :: aln4
= 1.3862944
390 REAL :: a
, b
, g
, r
, s
, x
, y
, z
391 REAL, SAVE :: d
, f
, h
, t
, c
392 LOGICAL, SAVE :: swap
394 IF (aa
<= zero
.OR
. bb
<= zero
) THEN
395 WRITE(*, *) 'IMPERMISSIBLE SHAPE PARAMETER VALUE(S)'
399 IF (first
) THEN ! Initialization, if necessary
411 h
= SQRT((two
*a
*b
- f
)/(f
- two
))
415 t
= one
/(one
+ (a
/(vlarge
*b
))**b
)
421 CALL RANDOM_NUMBER(r
)
422 CALL RANDOM_NUMBER(x
)
424 IF (r
< vsmall
.OR
. s
<= zero
) CYCLE
426 x
= LOG(r
/(one
- r
))/h
428 z
= c
*x
+ f
*LOG((one
+ d
)/(one
+ y
)) - aln4
429 IF (s
- one
> z
) THEN
430 IF (s
- s
*z
> one
) CYCLE
431 IF (LOG(s
) > z
) CYCLE
435 IF (4.0*s
> (one
+ one
/d
)**f
) CYCLE
441 IF (swap
) fn_val
= one
- fn_val
443 END FUNCTION random_beta
447 FUNCTION random_t(m
) RESULT(fn_val
)
449 ! Adapted from Fortran 77 code from the book:
450 ! Dagpunar, J. 'Principles of random variate generation'
451 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
453 ! FUNCTION GENERATES A RANDOM VARIATE FROM A
454 ! T DISTRIBUTION USING KINDERMAN AND MONAHAN'S RATIO METHOD.
456 ! M = DEGREES OF FREEDOM OF DISTRIBUTION
459 INTEGER, INTENT(IN
) :: m
463 REAL, SAVE :: s
, c
, a
, f
, g
466 REAL, PARAMETER :: three
= 3.0, four
= 4.0, quart
= 0.25, &
467 five
= 5.0, sixteen
= 16.0
471 WRITE(*, *) 'IMPERMISSIBLE DEGREES OF FREEDOM'
475 IF (m
/= mm
) THEN ! Initialization, if necessary
478 a
= four
/(one
+ one
/s
)**c
482 g
= ((s
+ one
)/g
)**c
*SQRT((s
+s
)/g
)
490 CALL RANDOM_NUMBER(r
)
492 CALL RANDOM_NUMBER(v
)
493 x
= (two
*v
- one
)*g
/r
495 IF (v
> five
- a
*r
) THEN
496 IF (m
>= 1 .AND
. r
*(v
+ three
) > f
) CYCLE
497 IF (r
> (one
+ v
/s
)**c
) CYCLE
504 END FUNCTION random_t
508 SUBROUTINE random_mvnorm(n
, h
, d
, f
, first
, x
, ier
)
510 ! Adapted from Fortran 77 code from the book:
511 ! Dagpunar, J. 'Principles of random variate generation'
512 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
514 ! N.B. An extra argument, ier, has been added to Dagpunar's routine
516 ! SUBROUTINE GENERATES AN N VARIATE RANDOM NORMAL
517 ! VECTOR USING A CHOLESKY DECOMPOSITION.
520 ! N = NUMBER OF VARIATES IN VECTOR
521 ! (INPUT,INTEGER >= 1)
522 ! H(J) = J'TH ELEMENT OF VECTOR OF MEANS
524 ! X(J) = J'TH ELEMENT OF DELIVERED VECTOR
527 ! D(J*(J-1)/2+I) = (I,J)'TH ELEMENT OF VARIANCE MATRIX (J> = I)
529 ! F((J-1)*(2*N-J)/2+I) = (I,J)'TH ELEMENT OF LOWER TRIANGULAR
530 ! DECOMPOSITION OF VARIANCE MATRIX (J <= I)
533 ! FIRST = .TRUE. IF THIS IS THE FIRST CALL OF THE ROUTINE
534 ! OR IF THE DISTRIBUTION HAS CHANGED SINCE THE LAST CALL OF THE ROUTINE.
535 ! OTHERWISE SET TO .FALSE.
538 ! ier = 1 if the input covariance matrix is not +ve definite
541 INTEGER, INTENT(IN
) :: n
542 REAL, INTENT(IN
) :: h(:), d(:) ! d(n*(n+1)/2)
543 REAL, INTENT(IN OUT
) :: f(:) ! f(n*(n+1)/2)
544 REAL, INTENT(OUT
) :: x(:)
545 LOGICAL, INTENT(IN
) :: first
546 INTEGER, INTENT(OUT
) :: ier
554 WRITE(*, *) 'SIZE OF VECTOR IS NON POSITIVE'
559 IF (first
) THEN ! Initialization, if necessary
561 IF (d(1) < zero
) THEN
569 f(j
) = d(1+j
*(j
-1)/2) * y
575 v
= v
- f((m
-1)*(n2
-m
)/2+i
)**2
585 f((i
-1)*(n2
-i
)/2+i
) = v
589 v
= v
- f((m
-1)*(n2
-m
)/2+i
)*f((m
-1)*(n2
-m
)/2 + j
)
591 f((i
-1)*(n2
-i
)/2 + j
) = v
*y
600 x(i
) = x(i
) + f((j
-1)*(n2
-j
)/2 + i
) * y
605 END SUBROUTINE random_mvnorm
609 FUNCTION random_inv_gauss(h
, b
, first
) RESULT(fn_val
)
611 ! Adapted from Fortran 77 code from the book:
612 ! Dagpunar, J. 'Principles of random variate generation'
613 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
615 ! FUNCTION GENERATES A RANDOM VARIATE IN [0,INFINITY] FROM
616 ! A REPARAMETERISED GENERALISED INVERSE GAUSSIAN (GIG) DISTRIBUTION
617 ! WITH DENSITY PROPORTIONAL TO GIG**(H-1) * EXP(-0.5*B*(GIG+1/GIG))
618 ! USING A RATIO METHOD.
620 ! H = PARAMETER OF DISTRIBUTION (0 <= REAL)
621 ! B = PARAMETER OF DISTRIBUTION (0 < REAL)
623 REAL, INTENT(IN
) :: h
, b
624 LOGICAL, INTENT(IN
) :: first
628 REAL :: ym
, xm
, r
, w
, r1
, r2
, x
629 REAL, SAVE :: a
, c
, d
, e
630 REAL, PARAMETER :: quart
= 0.25
632 IF (h
< zero
.OR
. b
<= zero
) THEN
633 WRITE(*, *) 'IMPERMISSIBLE DISTRIBUTION PARAMETER VALUES'
637 IF (first
) THEN ! Initialization, if necessary
638 IF (h
> quart
*b
*SQRT(vlarge
)) THEN
639 WRITE(*, *) 'THE RATIO H:B IS TOO SMALL'
644 ym
= (-d
+ SQRT(d
*d
+ e
))/b
645 IF (ym
< vsmall
) THEN
646 WRITE(*, *) 'THE VALUE OF B IS TOO SMALL'
651 xm
= (d
+ SQRT(d
*d
+ e
))/b
656 a
= w
**(-half
*h
) * SQRT(xm
/ym
) * EXP(-e
*(r
- ym
- one
/ym
))
658 WRITE(*, *) 'THE VALUE OF H IS TOO LARGE'
665 CALL RANDOM_NUMBER(r1
)
666 IF (r1
<= zero
) CYCLE
667 CALL RANDOM_NUMBER(r2
)
670 IF (LOG(r1
) < d
*LOG(x
) + e
*(x
+ one
/x
) + c
) EXIT
676 END FUNCTION random_inv_gauss
680 FUNCTION random_Poisson(mu
, first
) RESULT(ival
)
681 !**********************************************************************
682 ! Translated to Fortran 90 by Alan Miller from:
685 ! Library of Fortran Routines for Random Number Generation
687 ! Compiled and Written by:
692 ! Department of Biomathematics, Box 237
693 ! The University of Texas, M.D. Anderson Cancer Center
694 ! 1515 Holcombe Boulevard
697 ! This work was supported by grant CA-16672 from the National Cancer Institute.
699 ! GENerate POIsson random deviate
703 ! Generates a single random deviate from a Poisson distribution with mean mu.
707 ! mu --> The mean of the Poisson distribution from which
708 ! a random deviate is to be generated.
715 ! Ahrens, J.H. and Dieter, U.
716 ! Computer Generation of Poisson Deviates
717 ! From Modified Normal Distributions.
718 ! ACM Trans. Math. Software, 8, 2
719 ! (June 1982),163-179
721 ! TABLES: COEFFICIENTS A0-A7 FOR STEP F. FACTORIALS FACT
722 ! COEFFICIENTS A(K) - FOR PX = FK*V*V*SUM(A(K)*V**K)-DEL
724 ! SEPARATION OF CASES A AND B
726 ! .. Scalar Arguments ..
727 REAL, INTENT(IN
) :: mu
728 LOGICAL, INTENT(IN
) :: first
731 ! .. Local Scalars ..
732 REAL :: b1
, b2
, c
, c0
, c1
, c2
, c3
, del
, difmuk
, e
, fk
, fx
, fy
, g
, &
733 omega
, px
, py
, t
, u
, v
, x
, xx
734 REAL, SAVE :: s
, d
, p
, q
, p0
735 INTEGER :: j
, k
, kflag
736 LOGICAL, SAVE :: full_init
737 INTEGER, SAVE :: l
, m
742 ! .. Data statements ..
743 REAL, PARAMETER :: a0
= -.5, a1
= .3333333, a2
= -.2500068, a3
= .2000118, &
744 a4
= -.1661269, a5
= .1421878, a6
= -.1384794, &
747 REAL, PARAMETER :: fact(10) = (/ 1., 1., 2., 6., 24., 120., 720., 5040., &
751 ! .. Executable Statements ..
753 ! C A S E A. (RECALCULATION OF S, D, L IF MU HAS CHANGED)
759 ! THE POISSON PROBABILITIES PK EXCEED THE DISCRETE NORMAL
760 ! PROBABILITIES FK WHENEVER K >= M(MU). L=IFIX(MU-1.1484)
761 ! IS AN UPPER BOUND TO M(MU) FOR ALL MU >= 10 .
768 ! STEP N. NORMAL SAMPLE - random_normal() FOR STANDARD NORMAL DEVIATE
770 g
= mu
+ s
*random_normal()
774 ! STEP I. IMMEDIATE ACCEPTANCE IF ival IS LARGE ENOUGH
778 ! STEP S. SQUEEZE ACCEPTANCE - SAMPLE U
782 CALL RANDOM_NUMBER(u
)
783 IF (d
*u
>= difmuk
*difmuk
*difmuk
) RETURN
786 ! STEP P. PREPARATIONS FOR STEPS Q AND H.
787 ! (RECALCULATIONS OF PARAMETERS IF NECESSARY)
788 ! .3989423=(2*PI)**(-.5) .416667E-1=1./24. .1428571=1./7.
789 ! THE QUANTITIES B1, B2, C3, C2, C1, C0 ARE FOR THE HERMITE
790 ! APPROXIMATIONS TO THE DISCRETE NORMAL PROBABILITIES FK.
791 ! C=.1069/MU GUARANTEES MAJORIZATION BY THE 'HAT'-FUNCTION.
793 IF (.NOT
. full_init
) THEN
799 c1
= b1
- 6.*b2
+ 45.*c3
800 c0
= 1. - b1
+ 3.*b2
- 15.*c3
805 IF (g
< 0.0) GO
TO 50
807 ! 'SUBROUTINE' F IS CALLED (KFLAG=0 FOR CORRECT RETURN)
812 ! STEP Q. QUOTIENT ACCEPTANCE (RARE CASE)
814 40 IF (fy
-u
*fy
<= py
*EXP(px
-fx
)) RETURN
816 ! STEP E. EXPONENTIAL SAMPLE - random_exponential() FOR STANDARD EXPONENTIAL
817 ! DEVIATE E AND SAMPLE T FROM THE LAPLACE 'HAT'
818 ! (IF T <= -.6744 THEN PK < FK FOR ALL MU >= 10.)
820 50 e
= random_exponential()
821 CALL RANDOM_NUMBER(u
)
824 IF (t
<= (-.6744)) GO
TO 50
829 ! 'SUBROUTINE' F IS CALLED (KFLAG=1 FOR CORRECT RETURN)
834 ! STEP H. HAT ACCEPTANCE (E IS REPEATED ON REJECTION)
836 60 IF (c
*ABS(u
) > py
*EXP(px
+e
) - fy
*EXP(fx
+e
)) GO
TO 50
839 ! STEP F. 'SUBROUTINE' F. CALCULATION OF PX, PY, FX, FY.
840 ! CASE ival < 10 USES FACTORIALS FROM TABLE FACT
842 70 IF (ival
>=10) GO
TO 80
844 py
= mu
**ival
/fact(ival
+1)
847 ! CASE ival >= 10 USES POLYNOMIAL APPROXIMATION
848 ! A0-A7 FOR ACCURACY WHEN ADVISABLE
849 ! .8333333E-1=1./12. .3989423=(2*PI)**(-.5)
851 80 del
= .8333333E-1/fk
852 del
= del
- 4.8*del
*del
*del
854 IF (ABS(v
)>0.25) THEN
855 px
= fk
*LOG(one
+ v
) - difmuk
- del
857 px
= fk
*v
*v
* (((((((a7
*v
+a6
)*v
+a5
)*v
+a4
)*v
+a3
)*v
+a2
)*v
+a1
)*v
+a0
) - del
859 py
= .3989423/SQRT(fk
)
860 110 x
= (half
- difmuk
)/s
863 fy
= omega
* (((c3
*xx
+ c2
)*xx
+ c1
)*xx
+ c0
)
864 IF (kflag
<= 0) GO
TO 40
867 !---------------------------------------------------------------------------
869 ! START NEW TABLE AND CALCULATE P0 IF NECESSARY
880 ! STEP U. UNIFORM SAMPLE FOR INVERSION METHOD
883 CALL RANDOM_NUMBER(u
)
887 ! STEP T. TABLE COMPARISON UNTIL THE END PP(L) OF THE
888 ! PP-TABLE OF CUMULATIVE POISSON PROBABILITIES
889 ! (0.458=PP(9) FOR MU=10)
891 IF (l
== 0) GO
TO 150
893 IF (u
> 0.458) j
= MIN(l
, m
)
895 IF (u
<= pp(k
)) GO
TO 180
899 ! STEP C. CREATION OF NEW POISSON PROBABILITIES P
900 ! AND THEIR CUMULATIVES Q=PP(K)
907 IF (u
<= q
) GO
TO 170
918 END FUNCTION random_Poisson
922 FUNCTION random_binomial1(n
, p
, first
) RESULT(ival
)
924 ! FUNCTION GENERATES A RANDOM BINOMIAL VARIATE USING C.D.Kemp's method.
925 ! This algorithm is suitable when many random variates are required
926 ! with the SAME parameter values for n & p.
928 ! P = BERNOULLI SUCCESS PROBABILITY
930 ! N = NUMBER OF BERNOULLI TRIALS
932 ! FIRST = .TRUE. for the first call using the current parameter values
933 ! = .FALSE. if the values of (n,p) are unchanged from last call
935 ! Reference: Kemp, C.D. (1986). `A modal method for generating binomial
936 ! variables', Commun. Statist. - Theor. Meth. 15(3), 805-813.
938 INTEGER, INTENT(IN
) :: n
939 REAL, INTENT(IN
) :: p
940 LOGICAL, INTENT(IN
) :: first
948 REAL, SAVE :: odds_ratio
, p_r
949 REAL, PARAMETER :: zero
= 0.0, one
= 1.0
953 p_r
= bin_prob(n
, p
, r0
)
954 odds_ratio
= p
/ (one
- p
)
957 CALL RANDOM_NUMBER(u
)
971 pd
= pd
* (rd
+1) / (odds_ratio
* (n
-rd
))
981 pu
= pu
* (n
-ru
+1) * odds_ratio
/ ru
990 ! This point should not be reached, but just in case:
995 END FUNCTION random_binomial1
999 FUNCTION bin_prob(n
, p
, r
) RESULT(fn_val
)
1000 ! Calculate a binomial probability
1002 INTEGER, INTENT(IN
) :: n
, r
1003 REAL, INTENT(IN
) :: p
1009 fn_val
= EXP( lngamma(DBLE(n
+1)) - lngamma(DBLE(r
+1)) - lngamma(DBLE(n
-r
+1)) &
1010 + r
*LOG(p
) + (n
-r
)*LOG(one
- p
) )
1013 END FUNCTION bin_prob
1017 FUNCTION lngamma(x
) RESULT(fn_val
)
1019 ! Logarithm to base e of the gamma function.
1021 ! Accurate to about 1.e-14.
1022 ! Programmer: Alan Miller
1024 ! Latest revision of Fortran 77 version - 28 February 1988
1026 REAL (dp
), INTENT(IN
) :: x
1031 REAL (dp
) :: a1
= -4.166666666554424D
-02, a2
= 2.430554511376954D
-03, &
1032 a3
= -7.685928044064347D
-04, a4
= 5.660478426014386D
-04, &
1033 temp
, arg
, product
, lnrt2pi
= 9.189385332046727D
-1, &
1034 pi
= 3.141592653589793D0
1037 ! lngamma is not defined if x = 0 or a negative integer.
1039 IF (x
> 0.d0
) GO
TO 10
1040 IF (x
/= INT(x
)) GO
TO 10
1044 ! If x < 0, use the reflection formula:
1045 ! gamma(x) * gamma(1-x) = pi * cosec(pi.x)
1047 10 reflect
= (x
< 0.d0
)
1054 ! Increase the argument, if necessary, to make it > 10.
1057 20 IF (arg
<= 10.d0
) THEN
1058 product
= product
* arg
1063 ! Use a polynomial approximation to Stirling's formula.
1064 ! N.B. The real Stirling's formula is used here, not the simpler, but less
1065 ! accurate formula given by De Moivre in a letter to Stirling, which
1066 ! is the one usually quoted.
1070 fn_val
= lnrt2pi
+ arg
* (LOG(arg
) - 1.d0
+ &
1071 (((a4
*temp
+ a3
)*temp
+ a2
)*temp
+ a1
)*temp
) - LOG(product
)
1074 fn_val
= LOG(pi
/temp
) - fn_val
1077 END FUNCTION lngamma
1081 FUNCTION random_binomial2(n
, pp
, first
) RESULT(ival
)
1082 !**********************************************************************
1083 ! Translated to Fortran 90 by Alan Miller from:
1086 ! Library of Fortran Routines for Random Number Generation
1088 ! Compiled and Written by:
1093 ! Department of Biomathematics, Box 237
1094 ! The University of Texas, M.D. Anderson Cancer Center
1095 ! 1515 Holcombe Boulevard
1098 ! This work was supported by grant CA-16672 from the National Cancer Institute.
1100 ! GENerate BINomial random deviate
1104 ! Generates a single random deviate from a binomial
1105 ! distribution whose number of trials is N and whose
1106 ! probability of an event in each trial is P.
1110 ! N --> The number of trials in the binomial distribution
1111 ! from which a random deviate is to be generated.
1114 ! P --> The probability of an event in each trial of the
1115 ! binomial distribution from which a random deviate
1116 ! is to be generated.
1119 ! FIRST --> Set FIRST = .TRUE. for the first call to perform initialization
1120 ! the set FIRST = .FALSE. for further calls using the same pair
1121 ! of parameter values (N, P).
1124 ! random_binomial2 <-- A random deviate yielding the number of events
1125 ! from N independent trials, each of which has
1126 ! a probability of event P.
1127 ! INTEGER random_binomial
1131 ! This is algorithm BTPE from:
1133 ! Kachitvichyanukul, V. and Schmeiser, B. W.
1134 ! Binomial Random Variate Generation.
1135 ! Communications of the ACM, 31, 2 (February, 1988) 216.
1137 !**********************************************************************
1139 !*****DETERMINE APPROPRIATE ALGORITHM AND WHETHER SETUP IS NECESSARY
1142 ! .. Scalar Arguments ..
1143 REAL, INTENT(IN
) :: pp
1144 INTEGER, INTENT(IN
) :: n
1145 LOGICAL, INTENT(IN
) :: first
1148 ! .. Local Scalars ..
1149 REAL :: alv
, amaxp
, f
, f1
, f2
, u
, v
, w
, w2
, x
, x1
, x2
, ynorm
, z
, z2
1150 REAL, PARAMETER :: zero
= 0.0, half
= 0.5, one
= 1.0
1151 INTEGER :: i
, ix
, ix1
, k
, mp
1153 REAL, SAVE :: p
, q
, xnp
, ffm
, fm
, xnpq
, p1
, xm
, xl
, xr
, c
, al
, xll
, &
1154 xlr
, p2
, p3
, p4
, qn
, r
, g
1157 ! .. Executable Statements ..
1159 !*****SETUP, PERFORM ONLY WHEN PARAMETERS CHANGE
1173 p1
= INT(2.195*SQRT(xnpq
) - 4.6*q
) + half
1177 c
= 0.134 + 20.5 / (15.3 + fm
)
1178 al
= (ffm
-xl
) / (ffm
- xl
*p
)
1179 xll
= al
* (one
+ half
*al
)
1180 al
= (xr
- ffm
) / (xr
*q
)
1181 xlr
= al
* (one
+ half
*al
)
1182 p2
= p1
* (one
+ c
+ c
)
1187 !*****GENERATE VARIATE, Binomial mean at least 30.
1189 20 CALL RANDOM_NUMBER(u
)
1191 CALL RANDOM_NUMBER(v
)
1196 ix
= xm
- p1
* v
+ u
1200 ! PARALLELOGRAM REGION
1204 v
= v
* c
+ one
- ABS(xm
-x
) / p1
1205 IF (v
> one
.OR
. v
<= zero
) GO
TO 20
1212 ix
= xl
+ LOG(v
) / xll
1213 IF (ix
< 0) GO
TO 20
1214 v
= v
* (u
-p2
) * xll
1219 ix
= xr
- LOG(v
) / xlr
1220 IF (ix
> n
) GO
TO 20
1221 v
= v
* (u
-p3
) * xlr
1225 !*****DETERMINE APPROPRIATE WAY TO PERFORM ACCEPT/REJECT TEST
1228 IF (k
<= 20 .OR
. k
>= xnpq
/2-1) THEN
1230 ! EXPLICIT EVALUATION
1241 ELSE IF (m
> ix
) THEN
1255 ! SQUEEZING USING UPPER AND LOWER BOUNDS ON LOG(F(X))
1257 amaxp
= (k
/xnpq
) * ((k
*(k
/3. + .625) + .1666666666666)/xnpq
+ half
)
1258 ynorm
= -k
* k
/ (2.*xnpq
)
1260 IF (alv
<ynorm
- amaxp
) GO
TO 110
1261 IF (alv
>ynorm
+ amaxp
) GO
TO 20
1263 ! STIRLING'S (actually de Moivre's) FORMULA TO MACHINE ACCURACY FOR
1264 ! THE FINAL ACCEPTANCE/REJECTION TEST
1274 IF (alv
- (xm
*LOG(f1
/x1
) + (n
-m
+half
)*LOG(z
/w
) + (ix
-m
)*LOG(w
*p
/(x1
*q
)) + &
1275 (13860.-(462.-(132.-(99.-140./f2
)/f2
)/f2
)/f2
)/f1
/166320. + &
1276 (13860.-(462.-(132.-(99.-140./z2
)/z2
)/z2
)/z2
)/z
/166320. + &
1277 (13860.-(462.-(132.-(99.-140./x2
)/x2
)/x2
)/x2
)/x1
/166320. + &
1278 (13860.-(462.-(132.-(99.-140./w2
)/w2
)/w2
)/w2
)/w
/166320.) > zero
) THEN
1285 ! INVERSE CDF LOGIC FOR MEAN LESS THAN 30
1294 CALL RANDOM_NUMBER(u
)
1295 100 IF (u
>= f
) THEN
1296 IF (ix
> 110) GO
TO 90
1304 110 IF (pp
> half
) ix
= n
- ix
1308 END FUNCTION random_binomial2
1313 FUNCTION random_neg_binomial(sk
, p
) RESULT(ival
)
1315 ! Adapted from Fortran 77 code from the book:
1316 ! Dagpunar, J. 'Principles of random variate generation'
1317 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
1319 ! FUNCTION GENERATES A RANDOM NEGATIVE BINOMIAL VARIATE USING UNSTORED
1320 ! INVERSION AND/OR THE REPRODUCTIVE PROPERTY.
1322 ! SK = NUMBER OF FAILURES REQUIRED (Dagpunar's words!)
1323 ! = the `power' parameter of the negative binomial
1325 ! P = BERNOULLI SUCCESS PROBABILITY
1328 ! THE PARAMETER H IS SET SO THAT UNSTORED INVERSION ONLY IS USED WHEN P <= H,
1329 ! OTHERWISE A COMBINATION OF UNSTORED INVERSION AND
1330 ! THE REPRODUCTIVE PROPERTY IS USED.
1332 REAL, INTENT(IN
) :: sk
, p
1336 ! THE PARAMETER ULN = -LOG(MACHINE'S SMALLEST REAL NUMBER).
1338 REAL, PARAMETER :: h
= 0.7
1339 REAL :: q
, x
, st
, uln
, v
, r
, s
, y
, g
1342 IF (sk
<= zero
.OR
. p
<= zero
.OR
. p
>= one
) THEN
1343 WRITE(*, *) 'IMPERMISSIBLE DISTRIBUTION PARAMETER VALUES'
1355 CALL RANDOM_NUMBER(r
)
1366 IF (st
> -uln
/LOG(q
)) THEN
1367 WRITE(*, *) ' P IS TOO LARGE FOR THIS VALUE OF SK'
1373 CALL RANDOM_NUMBER(r
)
1384 END FUNCTION random_neg_binomial
1388 FUNCTION random_von_Mises(k
, first
) RESULT(fn_val
)
1390 ! Algorithm VMD from:
1391 ! Dagpunar, J.S. (1990) `Sampling from the von Mises distribution via a
1392 ! comparison of random numbers', J. of Appl. Statist., 17, 165-168.
1394 ! Fortran 90 code by Alan Miller
1395 ! CSIRO Division of Mathematical & Information Sciences
1398 ! k (real) parameter of the von Mises distribution.
1399 ! first (logical) set to .TRUE. the first time that the function
1400 ! is called, or the first time with a new value
1401 ! for k. When first = .TRUE., the function sets
1402 ! up starting values and may be very much slower.
1404 REAL, INTENT(IN
) :: k
1405 LOGICAL, INTENT(IN
) :: first
1412 REAL, PARAMETER :: pi
= 3.14159265
1413 REAL, SAVE :: p(20), theta(0:20)
1414 REAL :: sump
, r
, th
, lambda
, rlast
1417 IF (first
) THEN ! Initialization, if necessary
1419 WRITE(*, *) '** Error: argument k for random_von_Mises = ', k
1425 WRITE(*, *) '** Error: argument k for random_von_Mises = ', k
1433 ! Set up array p of probabilities.
1438 theta(j
) = ACOS(one
- j
/k
)
1443 ! Numerical integration of e^[k.cos(x)] from theta(j-1) to theta(j)
1445 CALL integral(theta(j
-1), theta(j
), p(j
), dk
)
1448 p(1:nk
) = p(1:nk
) / sump
1455 CALL RANDOM_NUMBER(r
)
1463 th
= theta(j
-1) + r
*(theta(j
) - theta(j
-1))
1464 lambda
= k
- j
+ one
- k
*COS(th
)
1469 CALL RANDOM_NUMBER(r
)
1475 IF (n
.NE
. 2*(n
/2)) EXIT
! is n even?
1476 CALL RANDOM_NUMBER(r
)
1479 fn_val
= SIGN(th
, (r
- rlast
)/(one
- rlast
) - half
)
1481 END FUNCTION random_von_Mises
1485 SUBROUTINE integral(a
, b
, result
, dk
)
1487 ! Gaussian integration of exp(k.cosx) from a to b.
1489 REAL (dp
), INTENT(IN
) :: dk
1490 REAL, INTENT(IN
) :: a
, b
1491 REAL, INTENT(OUT
) :: result
1495 REAL (dp
) :: xmid
, range
, x1
, x2
, &
1496 x(3) = (/0.238619186083197_dp
, 0.661209386466265_dp
, 0.932469514203152_dp
/), &
1497 w(3) = (/0.467913934572691_dp
, 0.360761573048139_dp
, 0.171324492379170_dp
/)
1500 xmid
= (a
+ b
)/2._dp
1501 range
= (b
- a
)/2._dp
1505 x1
= xmid
+ x(i
)*range
1506 x2
= xmid
- x(i
)*range
1507 result
= result
+ w(i
)*(EXP(dk
*COS(x1
)) + EXP(dk
*COS(x2
)))
1510 result
= result
* range
1512 END SUBROUTINE integral
1516 FUNCTION random_Cauchy() RESULT(fn_val
)
1518 ! Generate a random deviate from the standard Cauchy distribution
1526 CALL RANDOM_NUMBER(v
)
1528 IF (ABS(v(2)) < vsmall
) CYCLE
! Test for zero
1529 IF (v(1)**2 + v(2)**2 < one
) EXIT
1531 fn_val
= v(1) / v(2)
1534 END FUNCTION random_Cauchy
1538 SUBROUTINE random_order(order
, n
)
1540 ! Generate a random ordering of the integers 1 ... n.
1542 INTEGER, INTENT(IN
) :: n
1543 INTEGER, INTENT(OUT
) :: order(n
)
1554 ! Starting at the end, swap the current last indicator with one
1555 ! randomly chosen from those preceeding it.
1558 CALL RANDOM_NUMBER(wk
)
1568 END SUBROUTINE random_order
1572 SUBROUTINE seed_random_number(iounit
)
1574 INTEGER, INTENT(IN
) :: iounit
1579 INTEGER, ALLOCATABLE
:: seed(:)
1581 CALL RANDOM_SEED(SIZE
=k
)
1584 WRITE(*, '(a, i2, a)')' Enter ', k
, ' integers for random no. seeds: '
1586 WRITE(iounit
, '(a, (7i10))') ' Random no. seeds: ', seed
1587 CALL RANDOM_SEED(PUT
=seed
)
1592 END SUBROUTINE seed_random_number
1595 END MODULE KPP_ROOT_Random
1597 MODULE KPP_ROOT_Integrator
1599 USE KPP_ROOT_Parameters
, ONLY
: NVAR
, NFIX
, NREACT
1600 USE KPP_ROOT_Global
, ONLY
: TIME
, RCONST
, Volume
1601 USE KPP_ROOT_Stoichiom
1602 USE KPP_ROOT_Stochastic
1604 USE KPP_ROOT_Random
, ddp
=> dp
1609 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1610 SUBROUTINE TauLeap(Nsteps
, Tau
, T
, SCT
, NmlcV
, NmlcF
)
1611 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1613 ! Tau-leap stochastic integration
1615 ! Nsteps = no. of tau-leap steps to be simulated
1616 ! Tau = time step length
1618 ! SCT = stochastic rate constants
1619 ! NmlcV, NmlcF = no. of molecules for variable and fixed species
1621 ! T = updated time (after Nsteps)
1622 ! NmlcV = updated no. of molecules for variable species
1625 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1627 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1631 INTEGER :: NmlcV(NVAR
), NmlcF(NFIX
)
1632 INTEGER :: i
, j
, irct
, id
, istep
, Nfirings(NREACT
)
1634 KPP_REAL
:: A(NREACT
), SCT(NREACT
), x
1635 LOGICAL, SAVE :: First
= .TRUE
.
1637 DO istep
= 1, Nsteps
1640 CALL Propensity ( NmlcV
, NmlcF
, SCT
, A
)
1642 ! Index of next reaction
1645 Nfirings(irct
) = random_Poisson(mu
, First
)
1649 ! Update time with the leap interval
1652 ! Directly update state vector
1654 DO i
= CCOL_STOICM(irct
), CCOL_STOICM(irct
+1)-1
1656 NmlcV(id
) = MAX(0, NmlcV(id
) + Nfirings(irct
)*INT(STOICM(i
)))
1660 ! Update state vector
1661 ! DO irct = 1, NREACT
1662 ! DO j = 1, Nfirings(irct)
1663 ! CALL MoleculeChange( irct, NmlcV )
1671 SUBROUTINE PropensityTemplate( T
, NmlcV
, NmlcF
, Prop
)
1672 KPP_REAL
, INTENT(IN
) :: T
1673 INTEGER, INTENT(IN
) :: NmlcV(NVAR
), NmlcF(NFIX
)
1674 KPP_REAL
, INTENT(OUT
) :: Prop(NREACT
)
1676 ! Update the stochastic reaction rates, which may be time dependent
1679 CALL Update_RCONST()
1680 CALL StochasticRates( RCONST
, Volume
, SCT
)
1681 CALL Propensity ( NmlcV
, NmlcF
, SCT
, Prop
)
1683 END SUBROUTINE PropensityTemplate
1685 END SUBROUTINE TauLeap
1686 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1688 END MODULE KPP_ROOT_Integrator