https://www.cdslab.org/paramonte/fortran/2
Current view: top level - main - pm_mathBeta@routines.inc.F90 (source / functions) Hit Total Coverage
Test: ParaMonte 2.0.0 :: Serial Fortran - Code Coverage Report Lines: 142 164 86.6 %
Date: 2024-04-08 03:18:57 Functions: 1 4 25.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_mathBeta](@ref pm_mathBeta).
      19             : !>
      20             : !>  \finmain
      21             : !>
      22             : !>  \author
      23             : !>  \AmirShahmoradi, Oct 16, 2009, 11:14 AM, Michigan
      24             : 
      25             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      26             : 
      27             :         !%%%%%%%%%%%%%%%%%
      28             : #if     getLogBeta_ENABLED
      29             :         !%%%%%%%%%%%%%%%%%
      30             : 
      31      163787 :         CHECK_ASSERTION(__LINE__, 0._RKC < beta, SK_"@getLogBeta(): The condition `0._RKC < beta` must hold. beta = "//getStr(beta)) ! fpp
      32      163787 :         CHECK_ASSERTION(__LINE__, 0._RKC < alpha, SK_"@getLogBeta(): The condition `0._RKC < alpha` must hold. alpha = "//getStr(alpha)) ! fpp
      33      163787 :         logFuncBeta = log_gamma(alpha) + log_gamma(beta) - log_gamma(alpha + beta)
      34             : 
      35             :         !%%%%%%%%%%%%%%%%%
      36             : #elif   getBetaInc_ENABLED
      37             :         !%%%%%%%%%%%%%%%%%
      38             : 
      39             :         real(RKC)   , parameter :: reltol = epsilon(0._RKC)**.7, THRESH = 3000._RKC ! Based on the suggestion of Press et al (1992). This may need fine-tuning for modern hardware.
      40             :         logical(LK) :: dengis
      41             :         integer(IK) :: info
      42        9056 :         if (present(signed)) then
      43           9 :             dengis = signed
      44             :         else
      45        9047 :             dengis = .false._LK
      46             :         end if
      47        9056 :         if (alpha < THRESH .or. beta < THRESH) then
      48        9056 :             call setBetaInc(betaInc, x, alpha, beta, getLogBeta(alpha, beta), dengis, info)
      49             :         else
      50           0 :             info = 0_IK
      51             :         end if
      52        9056 :         if (info /= 0_IK) call setBetaInc(betaInc, x, alpha, beta, getLogBeta(alpha, beta), reltol, dengis, info)
      53             :         !if (betaInc < 0._RKC) betaInc = betaInc + 1._RKC
      54             :         if (info /= 0_IK) error stop MODULE_NAME//SK_"@getBetaInc(): Failed to converge in computing the continued fraction representation of the Beta Function." ! LCOV_EXCL_LINE
      55             : 
      56             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      57             : #elif   setBetaInc_ENABLED && GK21_ENABLED
      58             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      59             : 
      60             :         real(RKC), parameter :: EPS = epsilon(0._RKC), lb = 0._RKC
      61             :         integer(IK), parameter :: nintmax = 100
      62             :         logical(LK) :: mirrored
      63             :         integer(IK) :: sindex(nintmax), neval, nint
      64             :         real(RKC) :: abserr, sinfo(4, nintmax), betaMinus1, alphaMinus1
      65           2 :         CHECK_ASSERTION(__LINE__, 0._RKC < beta, SK_"@setBetaInc(): The condition `0. < beta` must hold. beta = "//getStr(beta)) ! fpp
      66           2 :         CHECK_ASSERTION(__LINE__, 0._RKC < alpha, SK_"@setBetaInc(): The condition `0. < alpha` must hold. alpha = "//getStr(alpha)) ! fpp
      67           2 :         mirrored = signed .and. x < 0._RKC
      68           0 :         if (mirrored) x = -x
      69           2 :         if(0._RKC < x .and. x < 1._RKC) then
      70           2 :             if (.not. mirrored) then
      71           2 :                 mirrored = (alpha + 1._RKC) / (alpha + beta + 2._RKC) < x
      72           2 :                 if (mirrored) x = 1._RKC - x
      73             :             endif
      74           2 :             if (mirrored) then ! swap
      75             :                 abserr = beta
      76           0 :                 beta = alpha
      77           0 :                 alpha = abserr
      78             :             endif
      79             :             ! Prepare the integrand parameters.
      80           2 :             betaMinus1 = beta - 1._RKC
      81           2 :             alphaMinus1 = alpha - 1._RKC
      82             :             ! integrate.
      83             :             info =getQuadErr( getFunc & ! LCOV_EXCL_LINE
      84             :                             , lb = lb & ! LCOV_EXCL_LINE
      85             :                             , ub = x & ! LCOV_EXCL_LINE
      86             :                             , abstol = EPS & ! LCOV_EXCL_LINE
      87             :                             , reltol = reltol & ! LCOV_EXCL_LINE
      88             :                             , qrule = qrule & ! LCOV_EXCL_LINE
      89             :                             , integral = betaInc & ! LCOV_EXCL_LINE
      90             :                             , abserr = abserr & ! LCOV_EXCL_LINE
      91             :                             , sinfo = sinfo & ! LCOV_EXCL_LINE
      92             :                             , sindex = sindex & ! LCOV_EXCL_LINE
      93             :                             , neval = neval & ! LCOV_EXCL_LINE
      94             :                             , nint = nint & ! LCOV_EXCL_LINE
      95             :                             , help = weps & ! LCOV_EXCL_LINE
      96           2 :                             )
      97           2 :             if (mirrored) then
      98           0 :                 if (signed) then
      99           0 :                     betaInc = -betaInc
     100             :                 else
     101           0 :                     betaInc = 1._RKC - betaInc
     102             :                 end if
     103             :             end if
     104           0 :         elseif (0._RKC == x .or. x == 1._RKC) then
     105           0 :             info = 0_IK
     106           0 :             betaInc = x
     107             :         else
     108           0 :             info = 1_IK
     109           0 :             CHECK_ASSERTION(__LINE__, info == 0_IK, SK_"@setBetaInc(): The condition `0. <= x .and. x <= 1.` must hold. x = "//getStr(x)) ! fpp
     110             :         endif
     111             :     contains
     112        1722 :         pure function getFunc(xx) result(func)
     113             :             real(RKC), intent(in) :: xx
     114             :             real(RKC) :: func
     115        1722 :             func = exp(log(xx) * alphaMinus1 + log(1._RKC - xx) * betaMinus1 - logFuncBeta)
     116        1722 :         end function
     117             : 
     118             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     119             : #elif   setBetaInc_ENABLED && Def_ENABLED && 1
     120             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     121             : 
     122             :         ! This implementation is partially inspired by the proposed approach of Numerical Recipes (1992) by the Great Bill Press et al.
     123             :         logical(LK)                 :: mirrored
     124             :         integer(IK)                 :: iter, iterTwice
     125             :         integer(IK) , parameter     :: MAX_ITER = 10000_IK
     126             :         real(RKC)   , parameter     :: EPS = epsilon(0._RKC), FPMIN = tiny(0._RKC) / EPS
     127             :         REAL(RKC)                   :: aa, c, d, delta, sumAlphaBeta, alphamMinusOne, alphamPlusOne
     128      728667 :         CHECK_ASSERTION(__LINE__, 0._RKC < beta, SK_"@setBetaInc(): The condition `0._RKC < beta` must hold. beta = "//getStr(beta)) ! fpp
     129      728667 :         CHECK_ASSERTION(__LINE__, 0._RKC < alpha, SK_"@setBetaInc(): The condition `0._RKC < alpha` must hold. alpha = "//getStr(alpha)) ! fpp
     130      728667 :         mirrored = signed .and. x < 0._RKC
     131           0 :         if (mirrored) x = -x
     132      728667 :         if(0._RKC < x .and. x < 1._RKC) then
     133      728599 :             sumAlphaBeta = alpha + beta
     134      728599 :             if (.not. mirrored) then
     135      728599 :                 mirrored = (alpha + 1._RKC) / (sumAlphaBeta + 2._RKC) < x
     136      728599 :                 if (mirrored) x = 1._RKC - x
     137             :             endif
     138      728599 :             if (mirrored) then
     139             :                 d = beta
     140       65507 :                 beta = alpha
     141       65507 :                 alpha = d
     142             :             endif
     143      728599 :             alphamPlusOne = alpha + 1._RKC
     144      728599 :             alphamMinusOne = alpha - 1._RKC
     145      728599 :             d = 1._RKC - sumAlphaBeta * x / alphamPlusOne
     146      728599 :             if (abs(d) < FPMIN) d = FPMIN
     147      534422 :             c = 1._RKC
     148      728599 :             d = 1._RKC / d
     149      728599 :             betaInc = d
     150     2851931 :             do iter = 1, MAX_ITER
     151     2851931 :                 iterTwice = 2_IK * iter
     152     2851931 :                 aa = iter * (beta - iter) * x / ((alphamMinusOne + iterTwice) * (alpha + iterTwice))
     153     2851931 :                 d = 1._RKC + aa * d
     154     2851931 :                 if (abs(d) < FPMIN) d = FPMIN
     155     2851931 :                 c = 1._RKC + aa / c
     156     2851931 :                 if (abs(c) < FPMIN) c = FPMIN
     157     2851931 :                 d = 1._RKC / d
     158     2851931 :                 betaInc = betaInc * d * c
     159     2851931 :                 aa = -(alpha + iter) * (sumAlphaBeta + iter) * x / ((alpha + iterTwice) * (alphamPlusOne + iterTwice))
     160     2851931 :                 d = 1._RKC + aa * d
     161     2851931 :                 if (abs(d) < FPMIN) d = FPMIN
     162     2851931 :                 c = 1._RKC + aa / c
     163     2851931 :                 if (abs(c) < FPMIN) c = FPMIN
     164     2851931 :                 d = 1._RKC / d
     165     2851931 :                 delta = d * c
     166     2851931 :                 betaInc = betaInc * delta
     167     2851931 :                 if (EPS < abs(delta - 1._RKC)) cycle
     168             :                !betaInc = betaInc * exp(alpha * log(x) + beta * getLog1p(-x) - logFuncBeta) / alpha
     169      728599 :                 betaInc = betaInc * exp(alpha * log(x) + beta * log(1._RKC - x) - logFuncBeta) / alpha
     170             :                 !if (mirrored) betaInc = 1._RKC - betaInc ! 1._RKC is the regularization term.
     171             :                 !if (mirrored) betaInc = -betaInc ! 1._RKC is the regularization term.
     172      728599 :                 if (mirrored) then
     173       65507 :                     if (signed) then
     174       23880 :                         betaInc = -betaInc
     175             :                     else
     176       41627 :                         betaInc = 1._RKC - betaInc
     177             :                     end if
     178             :                 end if
     179      728599 :                 info = 0_IK
     180     2851931 :                 return
     181             :             end do
     182           0 :             info = 1_IK
     183          68 :         elseif (0._RKC == x .or. x == 1._RKC) then
     184          68 :             info = 0_IK
     185          68 :             betaInc = x
     186             :         else
     187           0 :             info = 1_IK
     188           0 :             CHECK_ASSERTION(__LINE__, info == 0_IK, SK_"@setBetaInc(): The condition `0. <= x .and. x <= 1.` must hold. x = "//getStr(x)) ! fpp
     189             :         endif
     190             : 
     191             :         !%%%%%%%%%%%%%%%%%%%%%%
     192             : #elif   setBetaInc_ENABLED && 1
     193             :         !%%%%%%%%%%%%%%%%%%%%%%
     194             : 
     195             :         ! This implementation is based on netlib BETAIN.
     196             :         ! As far as evidenced by tests, it requires many cycles for convergence for some precisions other than 64-bit.
     197             :         ! Its performance and accuracy against the alternative above is yet to be tested.
     198             :         ! KL Majumder, GP Bhattacharjee. Modifications by John Burkardt.
     199             :         ! Reference:
     200             :         ! KL Majumder, GP Bhattacharjee,
     201             :         ! Algorithm AS 63:
     202             :         ! The incomplete Beta Integral,
     203             :         ! Applied Statistics,
     204             :         ! Volume 22, Number 3, 1973, pages 409-411.
     205             :         integer(IK) :: ns, iter
     206             :         logical(LK) :: mirrored
     207             :         real(RKC)   :: ai, sumAlphaBeta, rx, temp, term
     208             :         real(RKC)   , parameter :: EPS = epsilon(0._RKC)**(7._RKC/8._RKC)
     209             :         integer(IK) , parameter :: MAX_ITER = 10000_IK
     210             :         CHECK_ASSERTION(__LINE__, 0._RKC < beta, SK_"@setBetaInc(): The condition `0._RKC < beta` must hold. beta = "//getStr(beta)) ! fpp
     211             :         CHECK_ASSERTION(__LINE__, 0._RKC < alpha, SK_"@setBetaInc(): The condition `0._RKC < alpha` must hold. alpha = "//getStr(alpha)) ! fpp
     212             :         mirrored = signed .and. x < 0._RKC
     213             :         if (mirrored) x = -x
     214             :         if (0._RKC < x .and. x < 1._RKC) then
     215             : 
     216             :             ! Change tail if necessary.
     217             : 
     218             :             sumAlphaBeta = alpha + beta
     219             :             if (.not. mirrored) then
     220             :                 !mirrored = (alpha + 1._RKC) / (sumAlphaBeta + 2._RKC) < x ! this is the original netlib condition.
     221             :                 mirrored = alpha < sumAlphaBeta * x ! This is the implementation by press et al.
     222             :                 if (mirrored) x = 1._RKC - x
     223             :             endif
     224             :             if (mirrored) then
     225             :                 temp = beta
     226             :                 beta = alpha
     227             :                 alpha = temp
     228             :             endif
     229             : 
     230             :             ai = 1._RKC
     231             :             term = 1._RKC
     232             :             betaInc = 1._RKC
     233             :             ns = int(beta + (1._RKC - x) * sumAlphaBeta, IK)
     234             :             ! Use the Soper reduction formula.
     235             :             rx = x / (1._RKC - x)
     236             :             temp = beta - ai
     237             :             if (ns == 0_IK) rx = x
     238             :             do iter = 1, MAX_ITER
     239             :                 term = term * temp * rx / (alpha + ai)
     240             :                 betaInc = betaInc + term
     241             :                 temp = abs(term)
     242             :                 if (temp <= EPS .and. temp <= EPS * betaInc) then
     243             :                    !betaInc = betaInc * exp(alpha * log(x) + (beta - 1._RKC) * getLog1p(-x) - logFuncBeta) / alpha
     244             :                     betaInc = betaInc * exp(alpha * log(x) + (beta - 1._RKC) * log(1._RKC - x) - logFuncBeta) / alpha
     245             :                     if (mirrored) then
     246             :                         if (signed) then
     247             :                             betaInc = -betaInc
     248             :                         else
     249             :                             betaInc = 1._RKC - betaInc
     250             :                         end if
     251             :                     end if
     252             :                     info = 0_IK
     253             :                     return
     254             :                 end if
     255             :                 ai = ai + 1._RKC
     256             :                 ns = ns - 1
     257             :                 if (ns < 0_IK) then
     258             :                     temp = sumAlphaBeta
     259             :                     sumAlphaBeta = sumAlphaBeta + 1._RKC
     260             :                 else
     261             :                     temp = beta - ai
     262             :                     if (ns == 0_IK) rx = x
     263             :                 end if
     264             :             end do
     265             :             info = 1_IK
     266             :         elseif (0._RKC == x .or. x == 1._RKC) then
     267             :             info = 0_IK
     268             :             betaInc = x
     269             :         else
     270             :             info = 1_IK
     271             :             CHECK_ASSERTION(__LINE__, info == 0_IK, SK_"@setBetaInc(): The condition `0. <= x .and. x <= 1.` must hold. x = "//getStr(x)) ! fpp
     272             :         endif
     273             : 
     274             :         !%%%%%%%%%%%%%%%%%
     275             : #elif   getBetaInv_ENABLED
     276             :         !%%%%%%%%%%%%%%%%%
     277             : 
     278             :         integer(IK) :: info
     279             :         logical(LK) :: dengis
     280       50009 :         if (present(signed)) then
     281       30000 :             dengis = signed
     282             :         else
     283       20009 :             dengis = .false._LK
     284             :         end if
     285       50009 :         call setBetaInv(betaInv, betaInc, alpha, beta, getLogBeta(alpha, beta), dengis, info)
     286             :         if (info /= 0_IK) error stop MODULE_NAME//SK_"@getBetaInv(): Failed to converge in computing the Regularized Inverse Incomplete Beta Function." ! LCOV_EXCL_LINE
     287             : 
     288             :         !%%%%%%%%%%%%%%%%%%%%%%
     289             : #elif   setBetaInv_ENABLED && 1
     290             :         !%%%%%%%%%%%%%%%%%%%%%%
     291             : 
     292             :         ! This implementation follows the approach of:
     293             :         ! GW Cran, KJ Martin, GE Thomas,
     294             :         ! Remark AS R19 and Algorithm AS 109:
     295             :         ! A Remark on Algorithms AS 63: The Incomplete Beta Integral
     296             :         ! and AS 64: Inverse of the Incomplete Beta Integeral,
     297             :         ! Applied Statistics,
     298             :         ! Volume 26, Number 1, 1977, pages 111-114.
     299             :         logical(LK)             :: mirrored
     300             :         real(RKC)   , parameter :: underflow = tiny(0._RKC)
     301             :         real(RKC)   , parameter :: experr = log10(underflow)
     302             :         real(RKC)   , parameter :: ONE_THIRD = 1._RKC / 3._RKC
     303             :         real(RKC)   , parameter :: ONE_SIXTH = 1._RKC / 6._RKC
     304             :         real(RKC)   , parameter :: FIVE_SIXTH = 5._RKC / 6._RKC
     305             :         real(RKC)   , parameter :: ONE_MEPS = 1._RKC - sqrt(epsilon(0._RKC))
     306             :         real(RKC)               :: tolerance, adj, g, h, prev, r, s, sq, t, tx, w, betaIncOld, betaIncNew
     307       70018 :         CHECK_ASSERTION(__LINE__, 0._RKC < alpha, SK_"@setBetaInv(): The condition `0. < alpha` must hold. alpha = "//getStr(alpha)) ! fpp
     308       70018 :         CHECK_ASSERTION(__LINE__, 0._RKC < beta, SK_"@setBetaInv(): The condition `0. < beta` must hold. alpha = "//getStr(beta)) ! fpp
     309       70018 :         mirrored = signed .and. betaInc < 0._RKC
     310           0 :         if (mirrored) betaInc = -betaInc
     311       70018 :         if (0._RKC < betaInc .and. betaInc < 1._RKC) then
     312             : 
     313             :             ! Change tail if necessary.
     314             : 
     315       70010 :             if (mirrored) then
     316             :                 r = alpha
     317           0 :                 alpha = beta
     318           0 :                 beta = r
     319             :             else
     320       70010 :                 mirrored = 0.5_RKC < betaInc
     321       70010 :                 if (mirrored) then
     322       35002 :                     betaInc = 1._RKC - betaInc
     323             :                     r = alpha
     324       35002 :                     alpha = beta
     325       35002 :                     beta = r
     326             :                 end if
     327             :             end if
     328             : 
     329             :             ! Compute the initial approximation.
     330             : 
     331       70010 :             r = sqrt(-log(betaInc**2))
     332       70010 :             betaIncNew = r - (2.30753_RKC + 0.27061_RKC * r) / (1._RKC + (0.99229_RKC + 0.04481_RKC * r) * r)
     333       70010 :             if (1._RKC < alpha .and. 1._RKC < beta) then
     334       14007 :                 r = (betaIncNew * betaIncNew - 3._RKC) * ONE_SIXTH
     335       14007 :                 s = 1._RKC / (alpha + alpha - 1._RKC)
     336       14007 :                 t = 1._RKC / (beta + beta - 1._RKC)
     337       14007 :                 h = 2._RKC / (s + t)
     338       14007 :                 w = betaIncNew * sqrt(h + r) / h - (t - s) * (r + FIVE_SIXTH - 2._RKC / (3._RKC * h))
     339       14007 :                 betaInv = alpha / (alpha + beta * exp(w + w))
     340             :             else
     341       56003 :                 r = beta + beta
     342       56003 :                 t = 1._RKC / (9._RKC * beta)
     343       56003 :                 t = r * (1._RKC - t + betaIncNew * sqrt(t))**3
     344       56003 :                 if (t <= 0._RKC) then
     345        2352 :                     betaInv = 1._RKC - exp((log((1._RKC - betaInc) * beta) + logFuncBeta) / beta)
     346             :                 else
     347       53651 :                     t = (4._RKC * alpha + r - 2._RKC) / t
     348       53651 :                     if (t <= 1._RKC) then
     349       30521 :                         betaInv = exp((log(betaInc * alpha) + logFuncBeta) / alpha)
     350             :                     else
     351       23130 :                         betaInv = 1._RKC - 2._RKC / (t + 1._RKC)
     352             :                     end if
     353             :                 end if
     354             :             end if
     355             : 
     356             :             ! Solve for X via modified Newton-Raphson method, using the function `setBetaInc()`.
     357             : 
     358       70010 :             t = 1._RKC - beta
     359       70010 :             r = 1._RKC - alpha
     360       50000 :             betaIncOld = 0._RKC
     361       50000 :             prev = 1._RKC
     362       50000 :             sq = 1._RKC
     363       70010 :             if (betaInv < 0.0001_RKC) betaInv = 0.0001_RKC
     364       70010 :             if (0.9999_RKC < betaInv) betaInv = 0.9999_RKC
     365       70010 :             tolerance = 10._RKC**int(max(-5._RKC / alpha**2 - 1._RKC / betaInc**0.2 - 13._RKC, experr), IK)
     366             : 
     367             :             ! Begin iteration.
     368             : 
     369      640579 :             loopFindRoot: do ! 10
     370      710589 :                 call setBetaInc(betaIncNew, betaInv, alpha, beta, logFuncBeta, signed, info)
     371             :                 if (info /= 0_IK) return ! LCOV_EXCL_LINE
     372      710589 :                 if (betaIncNew < 0._RKC) then
     373             :                     !if (abs(betaIncNew) < epsilon(0._RKC)) error stop "Underflow detected."
     374       23880 :                     betaIncNew = betaIncNew - betaInc
     375             :                     !if (abs(betaIncNew) < epsilon(0._RKC)) error stop "Underflow detected."
     376       23880 :                     betaIncNew = betaIncNew + 1._RKC
     377             :                 else
     378      686709 :                     betaIncNew = betaIncNew - betaInc
     379             :                 end if
     380             :                !betaIncNew = betaIncNew * exp(logFuncBeta + r * log(betaInv) + t * getLog1p(-betaInv))
     381      710589 :                 betaIncNew = betaIncNew * exp(logFuncBeta + r * log(betaInv) + t * log(1._RKC - betaInv))
     382      710589 :                 if (betaIncNew * betaIncOld <= 0._RKC) prev = max(sq, underflow)
     383      520420 :                 g = 1._RKC
     384             :                 loopRefine: do ! 20
     385     1480693 :                     adj = g * betaIncNew
     386     1480693 :                     sq = adj * adj
     387     1480693 :                     if (sq < prev) then
     388     1118986 :                         tx = betaInv - adj
     389     1118986 :                         if (tx < 0._RKC .or. 1._RKC < tx) then
     390      408397 :                             g = g * ONE_THIRD
     391      408397 :                             cycle loopRefine
     392             :                         end if
     393             :                     else ! 30
     394      361707 :                         g = g * ONE_THIRD
     395      361707 :                         cycle loopRefine
     396             :                     end if
     397             :                     ! Check whether current estimate is acceptable. The change "VALUE = TX" was suggested by Ivan Ukhov.
     398      710589 :                     if (prev <= tolerance .or. betaIncNew * betaIncNew <= tolerance) then ! 40
     399       50070 :                         betaInv = tx
     400       50070 :                         exit loopFindRoot
     401             :                     end if
     402      660519 :                     if (tx /= 0._RKC .and. tx /= 1._RKC) exit loopRefine
     403           0 :                     g = g * ONE_THIRD
     404             :                 end do loopRefine
     405      660519 :                 if (betaInv == tx) exit loopFindRoot
     406      170159 :                 betaInv = tx
     407      476640 :                 betaIncOld = betaIncNew
     408             :             end do loopFindRoot
     409       70010 :             if (mirrored) then
     410       35002 :                 if (signed) then
     411       15000 :                     betaInv = -betaInv
     412             :                 else
     413       20002 :                     betaInv = 1._RKC - betaInv
     414             :                 end if
     415             :             end if
     416             : 
     417           8 :         elseif (0._RKC == betaInc .or. betaInc == 1._RKC) then
     418             : 
     419           8 :             info = 0_IK
     420           8 :             betaInv = betaInc
     421             : 
     422             :         else
     423             : 
     424           0 :             info = 1_IK
     425           0 :             CHECK_ASSERTION(__LINE__, info == 0_IK, SK_"@setBetaInc(): The condition `0. <= betaInc .and. betaInc <= 1.` must hold. betaInc = "//getStr(betaInc)) ! fpp
     426             : 
     427             :         end if
     428             : 
     429             :         !%%%%%%%%%%%%%%%%%%%%%%
     430             : #elif   setBetaInv_ENABLED && 0
     431             :         !%%%%%%%%%%%%%%%%%%%%%%
     432             : 
     433             :         ! This implementation follows the proposed approach of Numerical Recipes by Press et al. (2007) using Halley approximation.
     434             :         ! No sign corrections are implemented in this algorithm. As such the output is prone to numerical roundup to `1`.
     435             :         integer(IK) :: iter
     436             :         real(RKC)   , parameter :: EPS = sqrt(epsilon(0._RKC))
     437             :         real(RKC)   :: pp, t, u, betaIncNew, al, h, w, alphaMinus1, betaMinus1
     438             :         if (signed .and. betaInc < 0._RKC) betaInc = 1 + betaInc
     439             :         if (0._RKC < betaInc .and. betaInc < 1._RKC) then
     440             :             betaMinus1 = beta - 1._RKC
     441             :             alphaMinus1 = alpha - 1._RKC
     442             :             if (alpha < 1._RKC .or. beta < 1._RKC) then
     443             :                 u = exp(beta * log(beta / (alpha + beta))) / beta
     444             :                 t = exp(alpha * log(alpha / (alpha + beta))) / alpha
     445             :                 w = t + u
     446             :                 if (betaInc < t / w) then
     447             :                     betaInv = (alpha * w * betaInc)**(1._RKC / alpha)
     448             :                 else
     449             :                     betaInv = 1._RKC - (beta * w * (1._RKC - betaInc))**(1._RKC / beta)
     450             :                 end if
     451             :             else
     452             :                 if (betaInc < 0.5_RKC) then
     453             :                     pp = betaInc
     454             :                 else
     455             :                     pp = 1._RKC - betaInc
     456             :                 end if
     457             :                 t = sqrt(-2._RKC * log(pp))
     458             :                 betaInv = (2.30753_RKC + t * 0.27061_RKC) / (1._RKC + t * (0.99229_RKC + t * 0.04481_RKC)) - t
     459             :                 if (betaInc < .5_RKC) betaInv = -betaInv
     460             :                 al = (betaInv**2 - 3._RKC) / 6._RKC
     461             :                 h = 2._RKC / (1._RKC / (2._RKC * alpha - 1._RKC) + 1._RKC / (2._RKC * beta - 1._RKC))
     462             :                 w = (betaInv * sqrt(al + h) / h) - (1._RKC / (2._RKC * beta - 1._RKC) - 1._RKC / (2._RKC * alpha - 1._RKC)) * (al + 5._RKC / 6._RKC - 2._RKC / (3._RKC * h))
     463             :                 betaInv = alpha / (alpha + beta * exp(2._RKC * w))
     464             :             end if
     465             :             loopFindRoot: do iter = 1, 10
     466             :                 if (betaInv == 0._RKC .or. betaInv == 1._RKC) exit loopFindRoot
     467             :                 call setBetaInc(betaIncNew, betaInv, alpha, beta, logFuncBeta, signed, info)
     468             :                 if (info /= 0_IK) return
     469             :                 betaIncNew = betaIncNew - betaInc
     470             :                 t = exp(alphaMinus1 * log(betaInv) + betaMinus1 * log(1._RKC - betaInv) - logFuncBeta)
     471             :                 u = betaIncNew / t
     472             :                 t = u / (1._RKC - .5_RKC * min(1._RKC, u * (alphaMinus1 / betaInv - betaMinus1 / (1._RKC - betaInv))))
     473             :                 betaInv = betaInv - t
     474             :                 if (betaInv <= 0._RKC) betaInv = .5_RKC * (betaInv + t)
     475             :                 if (betaInv >= 1._RKC) betaInv = .5_RKC * (betaInv + t + 1._RKC)
     476             :                 if (abs(t) < EPS * betaInv .and. 1_IK < iter) exit loopFindRoot
     477             :             end do loopFindRoot
     478             :             info = 0_IK
     479             :         elseif (0._RKC == betaInc .or. betaInc == 1._RKC) then
     480             :             info = 0_IK
     481             :             betaInv = betaInc
     482             :         else
     483             :             info = 1_IK
     484             :             CHECK_ASSERTION(__LINE__, .false., SK_"@setBetaInv(): The condition `0. <= betaInc .and. betaInc <= 1.` must hold. betaInc = "//getStr(betaInc)) ! fpp
     485             :         end if
     486             : 
     487             :         !%%%%%%%%%%%%%%%%%%%%%%
     488             : #elif   setBetaInv_ENABLED && 0
     489             :         !%%%%%%%%%%%%%%%%%%%%%%
     490             : 
     491             :         !   Naive root-finding implementation.
     492             :         !   This implementation is exploratory and should never be used.
     493             :         integer(IK) :: neval
     494             :         logical(LK) :: mirrored
     495             :         real(RKC)   :: lb, ub, lf, uf, abstol, h, w, r, s, t, betaIncNew
     496             :         real(RKC)   , parameter :: ONE_SIXTH = 1._RKC / 6._RKC
     497             :         !real(RKC)   , parameter :: abstol = epsilon(0._RKC)
     498             :         CHECK_ASSERTION(__LINE__, 0._RKC < alpha, SK_"@setBetaInv(): The condition `0. < alpha` must hold. alpha = "//getStr(alpha)) ! fpp
     499             :         CHECK_ASSERTION(__LINE__, 0._RKC < beta, SK_"@setBetaInv(): The condition `0. < beta` must hold. alpha = "//getStr(beta)) ! fpp
     500             :         info = 0_IK
     501             :         mirrored = signed .and. betaInc < 0._RKC
     502             :         if (mirrored) betaInc = -betaInc
     503             :         if (0._RKC < betaInc .and. betaInc < 1._RKC) then
     504             :             if (.not. mirrored) then
     505             :                 mirrored = 0.5_RKC < betaInc
     506             :                 if (mirrored) betaInc = 1._RKC - betaInc
     507             :             end if
     508             :             if (mirrored) then
     509             :                 r = alpha
     510             :                 alpha = beta
     511             :                 beta = r
     512             :             end if
     513             :             ! Compute the initial approximation.
     514             :             r = sqrt(-log(betaInc**2))
     515             :             betaIncNew = r - (2.30753_RKC + 0.27061_RKC * r) / (1._RKC + (0.99229_RKC + 0.04481_RKC * r) * r)
     516             :             if (1._RKC < alpha .and. 1._RKC < beta) then
     517             :                 r = (betaIncNew * betaIncNew - 3._RKC) * ONE_SIXTH
     518             :                 s = 1._RKC / (alpha + alpha - 1._RKC)
     519             :                 t = 1._RKC / (beta + beta - 1._RKC)
     520             :                 h = 2._RKC / (s + t)
     521             :                 w = betaIncNew * sqrt(h + r) / h - (t - s) * (r + 5._RKC / 6._RKC - 2._RKC / (3._RKC * h))
     522             :                 betaInv = alpha / (alpha + beta * exp(w + w))
     523             :             else
     524             :                 r = beta + beta
     525             :                 t = 1._RKC / (9._RKC * beta)
     526             :                 t = r * (1._RKC - t + betaIncNew * sqrt(t))**3
     527             :                 if (t <= 0._RKC) then
     528             :                     betaInv = 1._RKC - exp((log((1._RKC - betaInc) * beta) + logFuncBeta) / beta)
     529             :                 else
     530             :                     t = (4._RKC * alpha + r - 2._RKC) / t
     531             :                     if (t <= 1._RKC) then
     532             :                         betaInv = exp((log(betaInc * alpha) + logFuncBeta) / alpha)
     533             :                     else
     534             :                         betaInv = 1._RKC - 2._RKC / (t + 1._RKC)
     535             :                     end if
     536             :                 end if
     537             :             end if
     538             :             abstol = epsilon(0._RKC)
     539             :             if (betaInv < 0._RKC) betaInv = sqrt(abstol)
     540             :             if (1._RKC < betaInv) betaInv = 1._RKC - sqrt(abstol)
     541             :             lb = 0._RKC
     542             :             ub = 1._RKC
     543             :             lf = betaInc
     544             :             uf = betaInc - 1._RKC
     545             :             if (abstol < ub - lb) then
     546             :                 call setRoot(newton, getFunc, betaInv, getFuncDiff, lb, ub, lf, uf, abstol, neval)
     547             :                 if (neval < 0_IK) call setRoot(bisection, getFunc, betaInv, lb, ub, lf, uf, abstol, neval)
     548             :                 if (neval < 0_IK) info = 1_IK
     549             :             else
     550             :                 if (abs(lf) < abs(uf)) then
     551             :                     betaInv = lb
     552             :                 else
     553             :                     betaInv = ub
     554             :                 end if
     555             :             end if
     556             :             if (mirrored) then
     557             :                 if (signed) then
     558             :                     betaInv = -betaInv
     559             :                 else
     560             :                     betaInv = 1._RKC - betaInv
     561             :                 end if
     562             :             end if
     563             : 
     564             :         elseif (0._RKC == betaInc .or. betaInc == 1._RKC) then
     565             :             info = 0_IK
     566             :             betaInv = betaInc
     567             :         else
     568             :             info = 1_IK
     569             :             CHECK_ASSERTION(__LINE__, info == 0_IK, SK_"@setBetaInc(): The condition `0. <= betaInc .and. betaInc <= 1.` must hold. betaInc = "//getStr(betaInc)) ! fpp
     570             :         end if
     571             :     contains
     572             :         PURE function getFunc(x) result(func)
     573             :             real(RKC)   , intent(in)    :: x ! betaInv guess.
     574             :             real(RKC)                   :: func
     575             :             integer(IK)                 :: info
     576             :             call setBetaInc(func, x, alpha, beta, logFuncBeta, signed, info)
     577             :             if (info /= 0_IK) error stop ! LCOV_EXCL_LINE
     578             :             func = betaInc - func
     579             :         end function
     580             :         PURE function getFuncDiff(x, order) result(betaPDF)
     581             :             integer(IK) , intent(in)    :: order
     582             :             real(RKC)   , intent(in)    :: x
     583             :             real(RKC)   , parameter     :: SQRT_HUGE = sqrt(huge(x))
     584             :             real(RKC)                   :: betaPDF
     585             :             if(order == 0_IK) then
     586             :                 betaPDF = getFunc(x)
     587             :             else
     588             :                 if (x /= 0._RKC .and. x /= 1._RKC) then
     589             :                     call setBetaLogPDF(betaPDF, x, alpha, beta)
     590             :                     betaPDF = exp(betaPDF)
     591             :                 elseif ((x == 0._RKC .and. alpha < 1._RKC) .or. (x == 1._RKC .and. beta < 1._RKC)) then
     592             :                     betaPDF = SQRT_HUGE
     593             :                 else
     594             :                     betaPDF = 0._RKC
     595             :                 end if
     596             :             end if
     597             :         end function
     598             : 
     599             : #else
     600             :         !%%%%%%%%%%%%%%%%%%%%%%%%
     601             : #error  "Unrecognized interface."
     602             :         !%%%%%%%%%%%%%%%%%%%%%%%%
     603             : #endif

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