https://www.cdslab.org/paramonte/fortran/2
Current view: top level - main - pm_distGamma@routines.inc.F90 (source / functions) Hit Total Coverage
Test: ParaMonte 2.0.0 :: Serial Fortran - Code Coverage Report Lines: 66 68 97.1 %
Date: 2024-04-08 03:18:57 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       2             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       3             : !!!!                                                                                                                            !!!!
       4             : !!!!    ParaMonte: Parallel Monte Carlo and Machine Learning Library.                                                           !!!!
       5             : !!!!                                                                                                                            !!!!
       6             : !!!!    Copyright (C) 2012-present, The Computational Data Science Lab                                                          !!!!
       7             : !!!!                                                                                                                            !!!!
       8             : !!!!    This file is part of the ParaMonte library.                                                                             !!!!
       9             : !!!!                                                                                                                            !!!!
      10             : !!!!    LICENSE                                                                                                                 !!!!
      11             : !!!!                                                                                                                            !!!!
      12             : !!!!       https://github.com/cdslaborg/paramonte/blob/main/LICENSE.md                                                          !!!!
      13             : !!!!                                                                                                                            !!!!
      14             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      15             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      16             : 
      17             : !>  \brief
      18             : !>  This include file contains the implementation of procedures in [pm_distGamma](@ref pm_distGamma).
      19             : !>
      20             : !>  \finmain
      21             : !>
      22             : !>  \author
      23             : !>  \AmirShahmoradi, Oct 16, 2009, 11:14 AM, Michigan
      24             : 
      25             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      26             : 
      27             :         ! Set the URNG.
      28             : #if     RNGD_ENABLED
      29             : #define RNG
      30             : #elif   RNGF_ENABLED || RNGX_ENABLED
      31             : #define RNG rng,
      32             : #elif   setGammaRand_ENABLED
      33             : #error  "Unrecognized interface."
      34             : #endif
      35             :         !%%%%%%%%%%%%%%%%%%%%%%%
      36             : #if     getGammaLogPDFNF_ENABLED
      37             :         !%%%%%%%%%%%%%%%%%%%%%%%
      38             : 
      39    17975924 :         CHECK_ASSERTION(__LINE__, kappa > 0._RKC, SK_"@getGammaLogPDFNF(): The condition `kappa > 0.` must hold. kappa = "//getStr(kappa))
      40             : #if     KD_ENABLED
      41     8988082 :         logPDFNF = -log_gamma(kappa)
      42             : #elif   KS_ENABLED
      43     8987842 :         CHECK_ASSERTION(__LINE__, invSigma > 0._RKC, SK_"@getGammaLogPDFNF(): The condition invSigma > 0.` must hold. invSigma = "//getStr(invSigma))
      44     8987842 :         logPDFNF = getGammaLogPDFNF(kappa)
      45     8987842 :         if (invSigma /= 1._RKC) logPDFNF = logPDFNF + log(invSigma)
      46             : #else
      47             : #error  "Unrecognized interface."
      48             : #endif
      49             : 
      50             :         !%%%%%%%%%%%%%%%%%%%%%
      51             : #elif   getGammaLogPDF_ENABLED
      52             :         !%%%%%%%%%%%%%%%%%%%%%
      53             : 
      54             :         real(RKC) :: kappa_def, invSigma_def
      55     2991515 :         kappa_def = 1._RKC; if (present(kappa)) kappa_def = kappa
      56     2991515 :         invSigma_def = 1._RKC; if (present(invSigma)) invSigma_def = invSigma
      57     2991515 :         call setGammaLogPDF(logPDF, x, getGammaLogPDFNF(kappa_def, invSigma_def), kappa_def, invSigma_def)
      58             : 
      59             :         !%%%%%%%%%%%%%%%%%%%%%
      60             : #elif   setGammaLogPDF_ENABLED
      61             :         !%%%%%%%%%%%%%%%%%%%%%
      62             : 
      63             : #if     DDD_ENABLED
      64          81 :         CHECK_ASSERTION(__LINE__, x > 0._RKC, SK_"@setGammaLogPDF(): The condition `x > 0.` must hold. x = "//getStr(x))
      65          81 :         logPDF = -x
      66             : #elif   NKD_ENABLED
      67          80 :         CHECK_ASSERTION(__LINE__, x > 0._RKC, SK_"@setGammaLogPDF(): The condition `x > 0.` must hold. x = "//getStr(x))
      68          80 :         CHECK_ASSERTION(__LINE__, kappa > 0._RKC, SK_"@setGammaLogPDF(): The condition `kappa > 0.` must hold. kappa = "//getStr(kappa))
      69         240 :         CHECK_ASSERTION(__LINE__, abs(logPDFNF - getGammaLogPDFNF(kappa)) < sqrt(epsilon(0._RKC)), \
      70             :         SK_"@setGammaLogPDF(): The condition `abs(logPDFNF - getGammaLogPDFNF(kappa)) < sqrt(epsilon(0._RKC)` must hold. logPDFNF, getGammaLogPDFNF(kappa) = "// \
      71             :         getStr([logPDFNF, getGammaLogPDFNF(kappa)]))
      72          80 :         logPDF = logPDFNF + (kappa - 1._RKC) * log(x) - x
      73             : #elif   NKS_ENABLED
      74             :         real(RKC) :: y
      75     2995611 :         y = x * invSigma
      76     2995611 :         CHECK_ASSERTION(__LINE__, x > 0._RKC, SK_"@setGammaLogPDF(): The condition `x > 0.` must hold. x = "//getStr(x))
      77     2995611 :         CHECK_ASSERTION(__LINE__, kappa > 0._RKC, SK_"@setGammaLogPDF(): The condition `kappa > 0.` must hold. kappa = "//getStr(kappa))
      78     2995611 :         CHECK_ASSERTION(__LINE__, invSigma > 0._RKC, SK_"@setGammaLogPDF(): The condition `invSigma > 0.` must hold. invSigma = "//getStr(invSigma))
      79     8986833 :         CHECK_ASSERTION(__LINE__, abs(logPDFNF - getGammaLogPDFNF(kappa, invSigma)) < sqrt(epsilon(0._RKC)), \
      80             :         SK_"@setGammaLogPDF(): The condition `abs(logPDFNF - getGammaLogPDFNF(kappa, invSigma)) < sqrt(epsilon(0._RKC)` must hold. logPDFNF, getGammaLogPDFNF(kappa, invSigma) = "// \
      81             :         getStr([logPDFNF, getGammaLogPDFNF(kappa, invSigma)]))
      82     2995611 :         logPDF = logPDFNF + (kappa - 1._RKC) * log(y) - y
      83             : #else
      84             : #error  "Unrecognized interface."
      85             : #endif
      86             : 
      87             :         !%%%%%%%%%%%%%%%%%%
      88             : #elif   getGammaCDF_ENABLED
      89             :         !%%%%%%%%%%%%%%%%%%
      90             : 
      91             :         integer(IK) :: info
      92             :         real(RKC)   :: xnormed
      93        4017 :         if (present(invSigma)) then
      94        4017 :             xnormed = x * invSigma
      95             :         else
      96           0 :             xnormed = x
      97             :         end if
      98        4017 :         if (present(kappa)) then
      99        4017 :             call setGammaCDF(cdf, xnormed, log_gamma(kappa), kappa, info)
     100             :         else
     101           0 :             call setGammaCDF(cdf, xnormed, info)
     102             :         end if
     103        4017 :         if (info < 0_IK) error stop MODULE_NAME//SK_"@getGammaCDF(): The computation of the regularized Lower Incomplete Gamma function failed. This can happen if `kappa` is too large."
     104             : 
     105             :         !%%%%%%%%%%%%%%%%%%
     106             : #elif   setGammaCDF_ENABLED
     107             :         !%%%%%%%%%%%%%%%%%%
     108             : 
     109             : #if     DD_ENABLED
     110             :         real(RKC), parameter :: kappa = 1._RKC, logGammaKappa = log_gamma(kappa)
     111           1 :         CHECK_ASSERTION(__LINE__, x > 0._RKC, SK_"@setGammaCDF(): The condition `x > 0.` must hold. x = "//getStr(x)) ! fpp
     112           1 :         call setGammaIncLow(cdf, x, logGammaKappa, kappa, info)
     113             : #else
     114       54229 :         CHECK_ASSERTION(__LINE__, x > 0._RKC, SK_"@setGammaCDF(): The condition `x > 0.` must hold. x = "//getStr(x)) ! fpp
     115       54229 :         CHECK_ASSERTION(__LINE__, kappa > 0._RKC, SK_"@setGammaCDF(): The condition `kappa > 0.` must hold. kappa = "//getStr(kappa)) ! fpp
     116      162687 :         CHECK_ASSERTION(__LINE__, abs(log_gamma(kappa) - logGammaKappa) < 100 * epsilon(0._RKC), \
     117             :         SK_"@setGammaCDF(): The condition `abs(log_gamma(kappa) - logGammaKappa) < 100 * epsilon(0._RKC)` must hold. log_gamma(kappa), logGammaKappa = "//\
     118             :         getStr([log_gamma(kappa), logGammaKappa])) ! fpp
     119             : #if     KD_ENABLED
     120        4017 :         call setGammaIncLow(cdf, x, logGammaKappa, kappa, info)
     121             : #elif   KS_ENABLED
     122       50212 :         CHECK_ASSERTION(__LINE__, invSigma > 0._RKC, SK_"@setGammaCDF(): The condition `invSigma > 0.` must hold. invSigma = "//getStr(invSigma)) ! fpp
     123       50212 :         call setGammaIncLow(cdf, x * invSigma, logGammaKappa, kappa, info)
     124             : #else
     125             : #error  "Unrecognized interface."
     126             : #endif
     127             : #endif
     128             : 
     129             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     130             : #elif   setGammaRand_ENABLED && (RNGD_ENABLED || RNGF_ENABLED || RNGX_ENABLED) && KR_ENABLED
     131             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     132             : 
     133             :         real(RKC)   , parameter :: ONE_THIRD = 1._RKC / 3._RKC
     134             :         real(RKC)               :: invSqrt9KappaMinusOneThird
     135             :         real(RKC)               :: kappaMinusOneThird
     136             :         real(RKC)               :: normrnd, unifrnd
     137        1362 :         CHECK_ASSERTION(__LINE__, 0._RKC < kappa .and. 0._RKC < sigma, SK_"@setGammaRand(): The condition `0 < kappa .and. 0 < sigma` must hold. kappa = "//getStr([kappa, sigma])) ! Must appear here.
     138             : #define GET_PARAM(offset) \
     139             : kappaMinusOneThird = kappa - ONE_THIRD + offset; invSqrt9KappaMinusOneThird = 1._RKC / sqrt(9 * kappaMinusOneThird);
     140         454 :         if (1._RKC <= kappa) then
     141         440 :             GET_PARAM(0._RKC) ! fpp
     142             : #if         D1_ENABLED
     143             : #define     GET_RAND(i) rand(i)
     144             :             block
     145             :                 integer(IK) :: irand
     146       40011 :                 do irand = 1_IK, size(rand, 1, IK)
     147             : #elif               D0_ENABLED
     148             : #define             GET_RAND(i) rand
     149             : #else
     150             : #error              "Unrecognized interface."
     151             : #endif
     152           9 :                     do
     153             :                         !call setRandKappaGe1()
     154             :                         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     155             :                         ! If only macros existed in Fortran...
     156             :                         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     157       41131 :                         call setNormRand(RNG normrnd)
     158       41131 :                         GET_RAND(irand) = 1._RKC + invSqrt9KappaMinusOneThird * normrnd
     159       41131 :                         if (GET_RAND(irand) <= 0._RKC) cycle
     160       41089 :                         call setUnifRand(RNG unifrnd); unifrnd = 1._RKC - unifrnd
     161       41089 :                         if (unifrnd < 1._RKC - 0.0331_RKC * normrnd**4) then
     162       37667 :                             GET_RAND(irand) = kappaMinusOneThird * sigma * GET_RAND(irand)**3
     163       37667 :                             exit
     164             :                         end if
     165        3422 :                         GET_RAND(irand) = GET_RAND(irand)**3
     166        3422 :                         if (log(unifrnd) < 0.5_RKC * normrnd**2 + kappaMinusOneThird * (1._RKC - GET_RAND(irand) + log(GET_RAND(irand)))) then
     167        2775 :                             GET_RAND(irand) = kappaMinusOneThird * sigma * GET_RAND(irand)
     168        2775 :                             exit
     169             :                         end if
     170             :                         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     171             :                     end do
     172             : #if             D1_ENABLED
     173             :                 end do
     174             :             end block
     175             : #endif
     176             :         else
     177           2 :             GET_PARAM(1._RKC) ! fpp
     178             : #if         D1_ENABLED
     179             :             block
     180             :                 integer(IK) :: irand
     181        5009 :                 do irand = 1_IK, size(rand, 1, IK)
     182             : #endif
     183           3 :                     do
     184             :                         !call setRandKappaGe1()
     185             :                         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     186             :                         ! If only macros existed in Fortran...
     187             :                         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     188        5120 :                         call setNormRand(RNG normrnd)
     189        5120 :                         GET_RAND(irand) = 1._RKC + invSqrt9KappaMinusOneThird * normrnd
     190        5120 :                         if (GET_RAND(irand) <= 0._RKC) cycle
     191        5119 :                         call setUnifRand(RNG unifrnd); unifrnd = 1._RKC - unifrnd
     192        5119 :                         if (unifrnd < 1._RKC - 0.0331_RKC * normrnd**4) then
     193        4693 :                             GET_RAND(irand) = kappaMinusOneThird * sigma * GET_RAND(irand)**3
     194        4693 :                             exit
     195             :                         end if
     196         426 :                         GET_RAND(irand) = GET_RAND(irand)**3
     197         426 :                         if (log(unifrnd) < 0.5_RKC * normrnd**2 + kappaMinusOneThird * (1._RKC - GET_RAND(irand) + log(GET_RAND(irand)))) then
     198         315 :                             GET_RAND(irand) = kappaMinusOneThird * sigma * GET_RAND(irand)
     199         315 :                             exit
     200             :                         end if
     201             :                         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     202         111 :                         call setUnifRand(RNG unifrnd)
     203         111 :                         unifrnd = (1._RKC - unifrnd)**(1._RKC / kappa)
     204         112 :                         GET_RAND(irand) = GET_RAND(irand) * unifrnd
     205             :                     end do
     206             : #if             D1_ENABLED
     207             :                 end do
     208             :             end block
     209             : #endif
     210             :         end if
     211             : 
     212             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     213             : #elif   setGammaRand_ENABLED && (RNGD_ENABLED || RNGF_ENABLED || RNGX_ENABLED) && KI_ENABLED
     214             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     215             : 
     216             :         ! Alternative algorithm when `kappa` is a positive integer.
     217             :         ! The corresponding interfaces are yet to be implemented.
     218             :         ! However, the benefit of this integer `kappa` is unclear.
     219             :         real(RKC) :: unifrnd(7)
     220             :         CHECK_ASSERTION(__LINE__, 0._RKC < kappa .and. 0._RKC < sigma, SK_"@setGammaRand(): The condition `0 < kappa .and. 0 < sigma` must hold. kappa = "//getStr([kappa, sigma]))
     221             :         if (kappa < 6_IK) then
     222             :             call setUnifRand(RNG unifrnd(1:kappa))
     223             :             rand = -log(product(unifrnd(1:kappa)))
     224             :         else ! use rejection sampling
     225             :             do
     226             :                 call setUnifRand(RNG unifrnd(1:2))
     227             :                 unifrnd(1:2) = 2 * unifrnd(1:2) - 1._RKC
     228             :                 if (dot_product(unifrnd(1:2), unifrnd(1:2)) > 1._RKC) cycle
     229             :                 unifrnd(3) = unifrnd(2) / unifrnd(1)
     230             :                 unifrnd(4) = kappa - 1._RKC
     231             :                 unifrnd(5) = sqrt(2 * unifrnd(4) + 1._RKC)
     232             :                 rand = unifrnd(5) * unifrnd(3) + unifrnd(4)
     233             :                 if (rand <= 0.0) cycle
     234             :                 unifrnd(6) = (1._RKC + unifrnd(3)**2) * exp(unifrnd(4) * log(rand / unifrnd(4)) - unifrnd(5) * unifrnd(3))
     235             :                 call setUnifRand(RNG unifrnd(7)) !call random number(unifrnd(7))
     236             :                 if (unifrnd(7) <= unifrnd(6)) exit
     237             :             end do
     238             :         end if
     239             : #if     0
     240             :         ! Alternative old implementation.
     241             :         function getRandGamma(alpha) result(randGamma)
     242             :             use pm_distNorm, only: setNormRand
     243             :             implicit none
     244             :             real(RK), intent(in) :: alpha
     245             :             real(RK)             :: randGamma
     246             :             real(RK)             :: c,u,v,z
     247             :             if (alpha<=0._RK) then  ! illegal value of alpha
     248             :                 randGamma = -1._RK
     249             :                 return
     250             :             else
     251             :                 randGamma = alpha
     252             :                 if (randGamma < 1._RK) randGamma = randGamma + 1._RK
     253             :                 randGamma = randGamma - 0.3333333333333333_RK
     254             :                 c = 3._RK*sqrt(randGamma)
     255             :                 c = 1._RK / c
     256             :                 do
     257             :                     do
     258             :                         call setNormRand(z)
     259             :                         v = 1._RK + c*z
     260             :                         if (v<=0._RK) cycle
     261             :                         exit
     262             :                     end do
     263             :                     v = v**3
     264             :                     call setUnifRand(RNG u)
     265             :                     if (log(u) >= 0.5_RK * z**2 + randGamma * (1._RK - v + log(v))) cycle
     266             :                     randGamma = randGamma * v
     267             :                     exit
     268             :                 end do
     269             :                 if (alpha < 1._RK) then
     270             :                     call setUnifRand(RNG u)
     271             :                     randGamma = randGamma * u**(1._RK/alpha)
     272             :                 end if
     273             :             end if
     274             :         end function getRandGamma
     275             : #endif
     276             : 
     277             : #else
     278             :         !%%%%%%%%%%%%%%%%%%%%%%%%
     279             : #error  "Unrecognized interface."
     280             :         !%%%%%%%%%%%%%%%%%%%%%%%%
     281             : #endif
     282             : #undef  GET_PARAM
     283             : #undef  GET_RAND
     284             : #undef  RNG

ParaMonte: Parallel Monte Carlo and Machine Learning Library 
The Computational Data Science Lab
© Copyright 2012 - 2024