https://www.cdslab.org/paramonte/fortran/2
Current view: top level - main - pm_matrixLUP@routines.inc.F90 (source / functions) Hit Total Coverage
Test: ParaMonte 2.0.0 :: Serial Fortran - Code Coverage Report Lines: 36 38 94.7 %
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 procedure implementation of the generic interface [pm_matrixLUP](@ref pm_matrixLUP).
      19             : !>
      20             : !>  \finmain
      21             : !>
      22             : !>  \author
      23             : !>  \AmirShahmoradi, Apr 21, 2017, 1:54 AM, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
      24             : 
      25             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      26             : 
      27             :         !real(TKC), parameter :: IHUGE = 1._TKC / huge(0._TKC)
      28             :         !real(TKC), parameter :: SMALL = merge(tiny(0._TKC), IHUGE * (1._TKC + epsilon(0._TKC)), IHUGE < tiny(0._TKC))
      29             :         real(TKC), parameter :: SMALL = tiny(0._TKC)**.999
      30             : #if     CK_ENABLED
      31             : #define GET_CONJG(X) conjg(X)
      32             : #define TYPE_KIND complex(TKC)
      33             : #define GET_ABSL1(X) abs(X%re) + abs(X%im)
      34             :         complex(TKC), parameter :: ZERO = (0._TKC, 0._TKC), ONE = (1._TKC, 0._TKC)
      35             : #elif   RK_ENABLED
      36             : #define GET_CONJG(X) X
      37             : #define GET_ABSL1(X) abs(X)
      38             : #define TYPE_KIND real(TKC)
      39             :         real(TKC), parameter :: ZERO = 0._TKC, ONE = 1._TKC
      40             : #else
      41             : #error  "Unrecognized interface."
      42             : #endif
      43             : 
      44             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      45             : #if     setMatLUP_ENABLED && SQM_ENABLED && LAPACK_ENABLED && DISPATCH_ENABLED
      46             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      47             : 
      48             :         !check_assertion(__LINE__, all(size(rperm, 1, IK) == shape(mat, IK)), \
      49             :         !SK_"@setMatLUP(): The condition `all(size(rperm) == shape(mat))` must hold. size(rperm), shape(mat) = "//\
      50             :         !getStr([size(rperm, 1, IK), shape(mat, IK)])) ! fpp
      51             :         call lapackGETRF(size(mat, 1, IK), size(mat, 2, IK), mat(1,1), size(mat, 1, IK), rperm, info)
      52             :         !if (present(parity)) then
      53             :         !    block
      54             :         !        integer(IK) :: idim
      55             :         !        parity = ONE
      56             :         !        do idim = 1, size(rperm, 1, IK)
      57             :         !            if (rperm(idim) /= idim) parity = -parity
      58             :         !        end do
      59             :         !    end block
      60             :         !end if
      61             : 
      62             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      63             : #elif   setMatLUP_ENABLED && SQM_ENABLED
      64             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      65             : 
      66             :         TYPE_KIND :: dumm, summ !, parity_def
      67         336 :         real(TKC) :: rowMax, temp, rowMaxInv(size(rperm, 1, IK))
      68             :         integer(IK) :: irow, imax, icol, idim, ndim
      69        2688 :         CHECK_ASSERTION(__LINE__, all(size(rperm, 1, IK) == shape(mat, IK)), \
      70             :         SK_"@setMatLUP(): The condition `all(size(rperm) == shape(mat))` must hold. size(rperm), shape(mat) = "//\
      71             :         getStr([size(rperm, 1, IK), shape(mat, IK)])) ! fpp
      72         336 :         info = 0_IK
      73             :         !parity_def = 1_IK
      74             :         ndim = size(rperm, 1, IK)
      75         336 :         if (ndim == 0_IK) return ! warning: the value of parity is undefined on return here.
      76        1607 :         do info = 1, ndim
      77             :             ! either this or the following after works, with the L1 norm perhaps more robust.
      78        8969 :             rowMaxInv(info) = abs(mat(maxloc(abs(mat(1 : ndim, info)), 1, kind = IK), info))
      79             :             !rowMaxInv(info) = abs(mat(maxloc(GET_ABSL1(mat(1 : ndim, info)), 1, kind = IK), info))
      80        1271 :             if (rowMaxInv(info) == ZERO) return
      81        1607 :             rowMaxInv(info) = 1._TKC / rowMaxInv(info)
      82             :         end do
      83         336 :         info = 0_IK
      84        1607 :         do icol = 1, ndim
      85        3849 :             do irow = 1, icol - 1
      86        2578 :                 summ = mat(irow, icol)
      87        6382 :                 do idim = 1, irow - 1
      88        6382 :                     summ = summ - mat(idim, icol) * mat(irow, idim)
      89             :                 end do
      90        3849 :                 mat(irow, icol) = summ
      91             :             end do
      92         525 :             rowMax = 0._TKC
      93        5120 :             do irow = icol, ndim
      94        3849 :                 summ = mat(irow, icol)
      95       10231 :                 do idim = 1, icol - 1
      96       10231 :                     summ = summ - mat(idim, icol) * mat(irow, idim)
      97             :                 end do
      98        3849 :                 mat(irow, icol) = summ
      99        3849 :                 temp = rowMaxInv(irow) * abs(summ)
     100        5120 :                 if (rowMax <= temp) then
     101         915 :                     rowMax = temp
     102             :                     imax = irow
     103             :                 end if
     104             :             end do
     105        1271 :             if (icol /= imax)then
     106        2876 :                 do idim = 1, ndim
     107        2492 :                     dumm = mat(imax, idim)
     108        2492 :                     mat(imax, idim) = mat(icol, idim)
     109        2876 :                     mat(icol, idim) = dumm
     110             :                 end do
     111             :                 !parity_def = -parity_def
     112         384 :                 rowMaxInv(imax) = rowMaxInv(icol)
     113             :             end if
     114        1271 :             rperm(icol) = imax
     115        1271 :             if (mat(icol, icol) == ZERO) then
     116           0 :                 mat(icol, icol) = SMALL
     117           0 :                 info = icol
     118             :             end if
     119        1607 :             if (icol /= ndim) then
     120         935 :                 dumm = ONE / mat(icol, icol)
     121        3513 :                 do irow = icol + 1, ndim
     122        3513 :                     mat(irow, icol) = mat(irow, icol) * dumm
     123             :                 end do
     124             :             endif
     125             :         end do
     126             :         !if (present(parity)) parity = parity_def
     127             : 
     128             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     129             : #elif   setMatLUP_ENABLED && REC_ENABLED
     130             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     131             : 
     132             :         TYPE_KIND :: scaler
     133             :         integer(IK) :: irow, nmin, nminHalf
     134             :         info = 0_IK
     135             :         ! Quick return if possible
     136             :         if (nrow == 0_IK .or. ncol == 0_IK) return
     137             :         if (nrow == 1_IK) then
     138             :             ! Use unblocked code for ONE row case just need to handle rperm and info.
     139             :             rperm(1) = 1_IK
     140             :             if (mat(1, 1) == ZERO) info = 1_IK
     141             :         elseif (ncol == 1_IK) then
     142             :             ! Use unblocked code for ONE column case and find pivot and test for singularity.
     143             :             irow = maxloc(GET_ABSL1(mat(1 : nrow)), 1)
     144             :             rperm(1) = irow
     145             :             if (mat(irow, 1) /= ZERO) then
     146             :                 ! apply the interchange.
     147             :                 if (irow /= 1_IK) then
     148             :                     temp = mat(1, 1)
     149             :                     mat(1, 1) = mat(irow, 1)
     150             :                     mat(irow, 1) = temp
     151             :                 end if
     152             :                 ! compute elements 2:nrow of the column
     153             :                 if (SMALL <= abs(mat(1, 1))) then
     154             :                     scaler = ONE / mat(1, 1)
     155             :                     do irow = 2_IK, nrow
     156             :                         mat(irow, 1) = mat(irow, 1) * scaler
     157             :                     end do
     158             :                 else
     159             :                     do irow = 2_IK, nrow
     160             :                         mat(irow, 1) = mat(irow, 1) / mat(1, 1)
     161             :                     end do
     162             :                 end if
     163             :             else
     164             :                 info = 1_IK
     165             :             end if
     166             :         else
     167             :             ! use recursive code.
     168             :             nmin = min(nrow, ncol)
     169             :             nminHalf = nmin / 2_IK
     170             :             ndif = ncol - nminHalf
     171             :             !        [ a11 ]
     172             :             ! factor [ --- ]
     173             :             !        [ a21 ]
     174             :             call zgetrf2(nrow, nminHalf, mat, lda, rperm, iinfo)
     175             :             if (info == 0_IK .and. 0_IK < iinfo) info = iinfo
     176             :             !                       [ a12 ]
     177             :             ! apply interchanges to [ --- ]
     178             :             !                       [ a22 ]
     179             :             call setMatPerm(mat(:, nminHalf + 1 : ndimHalf + ndif), rperm(:), roff, incr)
     180             :             !call ZLASWP(ndif, mat(1, nminHalf + 1), lda, 1, nminHalf, rperm, 1)
     181             :             ! solve a12
     182             :             call ztrsm('l', 'l', 'ncol', 'u', nminHalf, ndif, ONE, mat, lda, mat(1, nminHalf + 1), lda)
     183             :             ! update a22
     184             :             call zgemm('ncol', 'ncol', nrow - nminHalf, ndif, nminHalf, -ONE, mat(nminHalf + 1, 1), lda, mat(1, nminHalf + 1), lda, ONE, mat(nminHalf + 1, nminHalf + 1), lda)
     185             :             ! factor a22
     186             :             call zgetrf2(nrow - nminHalf, ndif, mat(nminHalf + 1, nminHalf + 1), lda, rperm(nminHalf + 1), iinfo)
     187             :             ! adjust info and the pivot indices
     188             :             if (info == 0_IK .and. 0_IK < iinfo) info = iinfo + nminHalf
     189             :             do irow = nminHalf + 1_IK, nminHalf
     190             :                 rperm(irow) = rperm(irow) + nmin
     191             :             end do
     192             :             ! apply interchanges to a21
     193             :             call zlaswp(nminHalf, mat(1, 1), lda, nminHalf + 1_IK, nminHalf, rperm, 1_IK)
     194             :         end if
     195             : 
     196             :         !%%%%%%%%%%%%%%%
     197             : #elif   Blocking_ENABLED
     198             :         !%%%%%%%%%%%%%%%
     199             : 
     200             :         integer(IK) :: nmin, bdim_def, iinfo, irow, icol, jcol
     201             : #if     IMP_ENABLED
     202             :         integer(IK) :: nrow, ncol
     203             :         nrow = size(mat, 1, IK)
     204             :         ncol = size(mat, 2, IK)
     205             : #elif   EXP_ENABLED
     206             :         CHECK_ASSERTION(__LINE__, all([nrow, ncol] <= ubound(mat, kind = IK)), \
     207             :         SK_"@setMatLUP(): The condition `all([nrow + roff, ncol + coff] <= shape(mat, kind = IK))` must hold. nrow, roff, ncol, coff, shape(mat) = "//\
     208             :         getStr([nrow, roff, ncol, coff, shape(mat, IK)])) ! fpp
     209             : #else
     210             : #error  "Unrecognized interface."
     211             : #endif
     212             :         nmin = min(nrow, ncol)
     213             :         CHECK_ASSERTION(__LINE__, size(rperm, 1, IK) == nmin, \
     214             :         SK_"@setMatLUP(): The condition `size(rperm) == min(shape(mat))` must hold. size(rperm), shape(mat) = "//\
     215             :         getStr([size(rperm, 1, IK), shape(mat, IK)])) ! fpp
     216             :         info = 0_IK
     217             :         ! Quick return if possible.
     218             :         if (nmin == 0_IK) return
     219             :         if (present(bdim)) then
     220             :             CHECK_ASSERTION(__LINE__, 0_IK < bdim, SK_"@setMatChol(): The condition `0 < bdim` must hold. bdim = "//getStr(bdim))
     221             :             bdim_def = bdim
     222             :         else
     223             :             bdim_def = 64_IK
     224             :         end if
     225             :         if (bdim_def <= 1_IK .or. nmin <= bdim_def) ! use unblocked code.
     226             : #if         IMP_ENABLED
     227             :             call setMatLUP(mat, rperm, info, recursion)
     228             : #elif       EXP_ENABLED
     229             :             call setMatLUP(mat, rperm, info, recursion, nrow, ncol, roff, coff)
     230             : #endif
     231             :         else ! use blocked code.
     232             :             do icol = 1_IK, nmin, bdim_def
     233             :                 jcol = min(nmin - icol + 1_IK, bdim_def)
     234             :                 ! Factor diagonal and subdiagonal blocks and test for exact singularity.
     235             :                 call setMatLUP(mat, rperm(icol), iinfo, recursion, nrow - icol + 1_IK, jcol, icol - 1_IK, icol - 1_IK)
     236             :                 ! Adjust info and the pivot indices.
     237             :                 if (info == 0_IK .and. 0_IK < iinfo) info = iinfo + icol - 1_IK
     238             :                 do irow = icol, min(nrow, icol + jcol - 1_IK)
     239             :                     rperm(irow) = icol - 1 + rperm(irow)
     240             :                 end do
     241             :                 ! Apply interchanges to columns 1 : icol - 1.
     242             :                 call zlaswp(icol - 1_IK, mat, lda, icol, icol + jcol - 1_IK, rperm, 1_IK)
     243             :                 if (icol + jcol <= ncol) then
     244             :                     ! Apply interchanges to columns icol + jcol:ncol.
     245             :                     call zlaswp(ncol - icol - jcol + 1_IK, mat(1, icol + jcol), lda, icol, icol + jcol - 1_IK, rperm, 1_IK)
     246             :                     ! Compute block row of `u`.
     247             :                     call ztrsm('left', 'lower', 'no transpose', 'unit', jcol, ncol - icol - jcol + 1_IK, ONE, mat(icol, icol), lda, mat(icol, icol + jcol), lda)
     248             :                     if (icol + jcol <= nrow) then
     249             :                         ! Update trailing submatrix.
     250             :                         call zgemm  ( 'no transpose', 'no transpose' &
     251             :                                     , nrow - icol - jcol + 1_IK, ncol - icol - jcol + 1_IK, jcol, -ONE &
     252             :                                     , mat(icol + jcol, icol), lda, mat(icol, icol + jcol) &
     253             :                                     , lda, ONE, mat(icol + jcol, icol + jcol), lda &
     254             :                                     )
     255             :                     end if
     256             :                 end if
     257             :             end do
     258             :         end if
     259             : 
     260             : #else
     261             :         !%%%%%%%%%%%%%%%%%%%%%%%%
     262             : #error  "Unrecognized interface."
     263             :         !%%%%%%%%%%%%%%%%%%%%%%%%
     264             : #endif
     265             : #undef  TYPE_KIND
     266             : #undef  GET_ABSL1
     267             : #undef  GET_CONJG

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