https://www.cdslab.org/paramonte/fortran/2
Current view: top level - main - pm_arrayReplace@routines.inc.F90 (source / functions) Hit Total Coverage
Test: ParaMonte 2.0.0 :: Serial Fortran - Code Coverage Report Lines: 80 80 100.0 %
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 file contains the implementation details of the routines under the generic interfaces of [pm_arrayReplace](@ref pm_arrayReplace).
      19             : !>
      20             : !>  \finmain
      21             : !>
      22             : !>  \author
      23             : !>  \AmirShahmoradi, September 1, 2017, 12:00 AM, Institute for Computational Engineering and Sciences (ICES), The University of Texas at Austin
      24             : 
      25             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      26             : 
      27             :         ! Define logical vs. normal equivalence operators
      28             : #if     LK_ENABLED
      29             : #define IS_EQUAL .eqv.
      30             : #elif   SK_ENABLED || IK_ENABLED || CK_ENABLED || RK_ENABLED
      31             : #define IS_EQUAL ==
      32             : #else
      33             : #error  "Unrecognized interface."
      34             : #endif
      35             :         ! Define scalar vs. vector operations.
      36             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      37             : #if     D0_D0_D0_ENABLED && SK_ENABLED
      38             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      39             : #define GET_SIZE len
      40             : #define GET_INDEX(i) i : i + lenPattern - 1_IK
      41             : #define D0_D0_D0_ENABLED 1
      42             : #if     CusCom_ENABLED
      43             : #define ISEQ(segment, pattern) iseq(segment, pattern)
      44             : #elif   DefCom_ENABLED
      45             : #define ISEQ(segment, pattern) segment == pattern
      46             : #else
      47             : #error  "Unrecognized interface."
      48             : #endif
      49             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      50             : #elif   D1_D0_D0_ENABLED || D1_D0_D1_ENABLED
      51             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      52             : #define GET_SIZE size
      53             : #define GET_INDEX(i) i
      54             : #if     CusCom_ENABLED
      55             : #define ISEQ(segment, pattern) iseq(segment, pattern)
      56             : #elif   DefCom_ENABLED
      57             : #define ISEQ(segment, pattern) segment IS_EQUAL pattern
      58             : #else
      59             : #error  "Unrecognized interface."
      60             : #endif
      61             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      62             : #elif   D1_D1_D0_ENABLED || D1_D1_D1_ENABLED
      63             :         !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      64             : #define GET_SIZE size
      65             : #define GET_INDEX(i) i : i + lenPattern - 1_IK
      66             : #if     CusCom_ENABLED
      67             : #define ISEQ(segment,pattern) iseq(segment, pattern, lenPattern)
      68             : #elif   DefCom_ENABLED
      69             : #define ISEQ(segment,pattern) all(segment IS_EQUAL pattern)
      70             : #else
      71             : #error  "Unrecognized interface."
      72             : #endif
      73             : #else
      74             :         !%%%%%%%%%%%%%%%%%%%%%%%%
      75             : #error  "Unrecognized interface."
      76             :         !%%%%%%%%%%%%%%%%%%%%%%%%
      77             : #endif
      78             :         ! Define the temporary new array for cases where the result is to be returned in the input array.
      79             : #if     setReplaced_ENABLED && D0_D0_D0_ENABLED && SK_ENABLED
      80             :         character(:,SKC)            , allocatable :: arrayNew
      81             : #elif   setReplaced_ENABLED && (D1_D0_D0_ENABLED || D1_D1_D0_ENABLED || D1_D0_D1_ENABLED || D1_D1_D1_ENABLED)
      82             : #if     SK_ENABLED
      83        1486 :         character(len(array,IK),SKC), allocatable :: arrayNew(:)
      84             : #elif   IK_ENABLED
      85             :         integer(IKC)                , allocatable :: arrayNew(:)
      86             : #elif   LK_ENABLED
      87             :         logical(LKC)                , allocatable :: arrayNew(:)
      88             : #elif   CK_ENABLED
      89             :         complex(CKC)                , allocatable :: arrayNew(:)
      90             : #elif   RK_ENABLED
      91             :         real(RKC)                   , allocatable :: arrayNew(:)
      92             : #else
      93             : #error  "Unrecognized interface."
      94             : #endif
      95             : #elif   !getReplaced_ENABLED
      96             : #error  "Unrecognized interface."
      97             : #endif
      98             :         ! Declare local variables.
      99             : #if     CusIns_ENABLED
     100             :         integer(IK)                 :: lenInstance, lenInstanceNew, maxInstance!, minInstance
     101             :         integer(IK) , allocatable   :: instanceNew(:)
     102             :         logical(LK)                 :: sorted_def
     103             :         logical(LK)                 :: unique_def
     104             : #endif
     105             :         integer(IK) , allocatable   :: POP(:) ! pattern Occurrence Position in the array.
     106             :         integer(IK)                 :: lenArray, lenDiff, i, iLast
     107             :         integer(IK)                 :: lenArrayNew, newPOP, newPOPNext, lenPOP, lenPOPMax
     108             :         ! Declare the replacement length.
     109             : #if     D1_D0_D0_ENABLED || D1_D1_D0_ENABLED
     110             :         integer(IK) , parameter     :: lenReplacement = 1_IK
     111             : #elif   D0_D0_D0_ENABLED || D1_D1_D1_ENABLED || D1_D0_D1_ENABLED
     112             : #define lenReplacement_ENABLED 1
     113             :         integer(IK)                 :: lenReplacement
     114             : #else
     115             : #error  "Unrecognized interface."
     116             : #endif
     117             :         ! Declare the pattern length.
     118             : #if     D1_D0_D0_ENABLED || D1_D0_D1_ENABLED
     119             :         integer(IK) , parameter     :: lenPattern = 1_IK
     120             : #elif   D0_D0_D0_ENABLED || D1_D1_D1_ENABLED || D1_D1_D0_ENABLED
     121             : #define lenPattern_ENABLED 1
     122             :         integer(IK)                 :: lenPattern
     123             : #else
     124             : #error  "Unrecognized interface."
     125             : #endif
     126             :         ! Set the array offset.
     127             : #if     D0_D0_D0_ENABLED || getReplaced_ENABLED
     128             :         integer(IK) , parameter     :: offset = 0_IK
     129             : #elif   setReplaced_ENABLED
     130             :         integer(IK)                 :: offset
     131       28208 :         offset = lbound(array,1,IK) - 1_IK
     132             : #else
     133             : #error  "Unrecognized interface."
     134             : #endif
     135             :         ! Set the replacement length.
     136             : #if     lenReplacement_ENABLED
     137       73098 :         lenReplacement = GET_SIZE(replacement, kind = IK) ! \warning GET_SIZE is a preprocessor macro.
     138             : #endif
     139             :         ! Set the pattern length.
     140             : #if     lenPattern_ENABLED
     141       73096 :         lenPattern = GET_SIZE(pattern, kind = IK) ! \warning GET_SIZE is a preprocessor macro.
     142             : #endif
     143      103498 :         lenArray = GET_SIZE(array, kind = IK) ! \warning GET_SIZE is a preprocessor macro.
     144             : #if     CusIns_ENABLED
     145       92656 :         lenInstance = size(instance, kind = IK)
     146       92656 :         if (lenInstance == 0_IK) then
     147             : #if         getReplaced_ENABLED
     148       46098 :             arrayNew = array
     149             : #elif       !setReplaced_ENABLED
     150             : #error      "Unrecognized Interface."
     151             : #endif
     152       10476 :             return
     153             :         end if
     154             : #endif
     155       91402 :         if (lenArray > lenPattern) then
     156       53263 :             blockFullEmptyPattern: if (lenPattern > 0_IK) then
     157       57781 :                 lenPOPMax = lenArray / lenPattern + 1_IK
     158             : #if             CusIns_ENABLED
     159             :                 !print *, "instance", instance
     160      415212 :                 maxInstance = maxval(instance)
     161      415212 :                 if (minval(instance) >= 0_IK .and. maxInstance < lenPOPMax) lenPOPMax = maxInstance
     162             : #endif
     163             :                 !print *, "array", array
     164             :                 !print *, "pattern", pattern
     165             :                 !print *, "lenArray, offset, lenPattern", lenArray, offset, lenPattern
     166             :                 ! Find all requested instances of pattern.
     167       65621 :                 allocate(POP(lenPOPMax))!, source = -huge(1_IK))
     168       16812 :                 i = 1_IK + offset
     169             :                 lenPOP = 0_IK
     170       53097 :                 iLast = lenArray + offset - lenPattern + 1_IK
     171             :                 loopFindPOP: do
     172             : #if                 getReplaced_ENABLED && CusCom_ENABLED && CusIns_ENABLED && D1_D1_D1_ENABLED && RK_ENABLED
     173             :                     !!  \bug
     174             :                     !!  gfortran 11 cannot correctly pass the length of the input `array` argument to `iseq()`
     175             :                     !!  via an explicit interface (and so why `iseq()` interface remains implicit.
     176             :                     !print *, array(GET_INDEX(i)), pattern
     177             :                     !print *, size(array(GET_INDEX(i))), size(pattern)
     178             :                     !print *, ISEQ(array(GET_INDEX(i)), pattern)
     179             : #endif
     180      503324 :                     if (ISEQ(array(GET_INDEX(i)), pattern)) then ! fpp
     181       97965 :                         lenPOP = lenPOP + 1_IK
     182       97965 :                         if (lenPOP > lenPOPMax) exit loopFindPOP ! This condition is crucial when `maxInstance < lenPOPMax`.
     183             :                         !print *, "POP", POP
     184       35828 :                         POP(lenPOP) = i
     185       61754 :                         i = i + lenPattern
     186             :                     else
     187      371609 :                         i = i + 1_IK
     188             :                     end if
     189      469494 :                     if (i > iLast) exit loopFindPOP
     190             :                 end do loopFindPOP
     191             :             else blockFullEmptyPattern
     192       11366 :                 lenPOP = lenArray + 1_IK
     193             : #if             CusIns_ENABLED
     194       62952 :                 maxInstance = maxval(instance)
     195       62952 :                 if (minval(instance) >= 0_IK .and. maxInstance < lenPOP) lenPOP = maxInstance
     196             : #endif
     197       12754 :                 allocate(POP(lenPOP))
     198       79916 :                 do i = 1, lenPOP
     199       79916 :                     POP(i) = i + offset
     200             :                 end do
     201             :             end if blockFullEmptyPattern
     202             :             ! Replace all requested instances of pattern.
     203       78375 :             blockInstanceExists: if (lenPOP > 0_IK) then
     204             : #if             CusIns_ENABLED
     205             :                 ! Convert all negative and positive instances to counts from the beginning within the possible range [1, lenPOP].
     206             :                 !lenInstance = size(instance, kind = IK) ! this is now moved up to quit if zero-length instance is encountered.
     207       48035 :                 allocate(instanceNew(lenInstance))
     208             :                 lenInstanceNew = 0_IK
     209             :                 i = 0_IK
     210             :                 ! This loop requires lenInstance to be at least 1, which is guaranteed by the condition after `lenInstance` definition in the above.
     211             :                 do
     212      279495 :                     i = i + 1_IK
     213      279495 :                     if (instance(i) > 0_IK .and. instance(i) <= lenPOP) then
     214       32558 :                         lenInstanceNew = lenInstanceNew  + 1_IK
     215       32558 :                         instanceNew(lenInstanceNew) = instance(i)
     216      246937 :                     elseif (instance(i) < 0_IK .and. instance(i) + lenPOP + 1_IK > 0_IK) then
     217       40026 :                         lenInstanceNew = lenInstanceNew  + 1_IK
     218       40026 :                         instanceNew(lenInstanceNew) = instance(i) + lenPOP + 1_IK
     219             :                     end if
     220      279495 :                     if (i == lenInstance) exit
     221             :                 end do
     222             :                 sorted_def = .false._LK
     223       48035 :                 if (present(sorted)) sorted_def = sorted
     224       48035 :                 if (.not. sorted_def) call setSorted(instanceNew(1:lenInstanceNew))
     225             :                 unique_def = .false._LK
     226       48035 :                 if (present(unique)) unique_def = unique
     227       31882 :                 if (unique_def) then
     228             :                     lenPOP = lenInstanceNew
     229             :                 else
     230      148996 :                     instanceNew = getUnique(instanceNew(1:lenInstanceNew))
     231       32135 :                     lenPOP = size(instanceNew, kind = IK)
     232             :                 end if
     233       48035 :                 if (lenPOP == 0_IK) then ! instance is empty, return the input array, untouched.
     234             : #if                 getReplaced_ENABLED
     235      104765 :                     arrayNew = array
     236             : #endif
     237             :                     ! The following deallocations are essential since gfortran, as of version 10.3, cannot automatically deallocate array upon return.
     238             : #if                 CusIns_ENABLED
     239       17732 :                     deallocate(instanceNew)
     240             : #endif
     241       17732 :                     deallocate(POP)
     242       17732 :                     return
     243             :                 end if
     244             : #define         INSTANCENEW(i) instanceNew(i)
     245             : #elif           DefIns_ENABLED
     246             : #define         INSTANCENEW(i) i
     247             : #else
     248             : #error          "Unrecognized Interface."
     249             : #endif
     250       31602 :                 lenDiff = lenReplacement - lenPattern
     251       31602 :                 lenArrayNew = lenArray + lenPOP * lenDiff
     252             : #if             SK_ENABLED && D0_D0_D0_ENABLED
     253         454 :                 allocate(character(lenArrayNew,SKC) :: arrayNew)
     254             :                 !>  \bug
     255             :                 !>  This string vector allocation must be separated from the following because of a bug in Intel ifort 2021.5.
     256             :                 !>  The bug is related to the separation of module interface from implementation.
     257             : #elif           SK_ENABLED && getReplaced_ENABLED && (D1_D0_D0_ENABLED || D1_D0_D1_ENABLED || D1_D1_D0_ENABLED || D1_D1_D1_ENABLED)
     258        2192 :                 allocate(character(len(array,IK),SKC) :: arrayNew(1_IK + offset : lenArrayNew + offset))
     259             : #else
     260       38473 :                 allocate(arrayNew(1_IK + offset : lenArrayNew + offset))
     261             : #endif
     262             : !#if             getReplacedDefComCusIns_D1_D0_D1_IK_ENABLED || getReplacedDefComCusIns_D1_D1_D1_IK_ENABLED
     263             :                 !print *, "size(replacement)", size(replacement)
     264             :                 !print *, "instanceNew", instanceNew
     265             :                 !print *, "INSTANCENEW(1_IK)", INSTANCENEW(1_IK)
     266             :                 !print *, "offset", offset
     267             :                 !print *, "POP", POP
     268             : !#endif
     269       36317 :                 newPOP = POP(INSTANCENEW(1_IK))
     270       93508 :                 arrayNew(1_IK + offset : POP(INSTANCENEW(1_IK)) - 1_IK) = array(1_IK + offset : POP(INSTANCENEW(1_IK)) - 1_IK)
     271       86251 :                 do i = 1_IK, lenPOP - 1_IK
     272      122846 :                     arrayNew(newPOP : newPOP + lenReplacement - 1_IK) = replacement
     273       49934 :                     newPOPNext = POP(INSTANCENEW(i + 1_IK)) + i * lenDiff
     274      106686 :                     arrayNew(newPOP + lenReplacement : newPOPNext - 1_IK) = array(POP(INSTANCENEW(i)) + lenPattern : POP(INSTANCENEW(i+1_IK)) - 1_IK)
     275       36317 :                     newPOP = newPOPNext
     276             :                 end do
     277      104559 :                 arrayNew(newPOP : newPOP + lenReplacement - 1_IK) = replacement
     278       93724 :                 arrayNew(newPOP + lenReplacement : lenArrayNew + offset) = array(POP(INSTANCENEW(i)) + lenPattern : lenArray + offset)
     279             : #if             CusIns_ENABLED
     280       22279 :                 deallocate(instanceNew) ! This is essential since gfortran, as of version 10.3, cannot automatically deallocate array upon return.
     281             : #endif
     282             : #if             setReplaced_ENABLED
     283       10066 :                 call move_alloc(from = arrayNew, to = array)
     284             : #elif           getReplaced_ENABLED
     285             :             else blockInstanceExists
     286      150185 :                 arrayNew = array
     287             : #else
     288             : #error          "Unrecognized interface."
     289             : #endif
     290             :             end if blockInstanceExists
     291       60643 :             deallocate(POP)
     292       13027 :         elseif (lenArray == lenPattern) then
     293       11382 :             if (ISEQ(array(GET_INDEX(1_IK + offset)), pattern)) then
     294             : #if             CusIns_ENABLED
     295             :                 !   \bug
     296             :                 !   Bizarrely, if this condition is merged with the above, then both ifort and gfortran occasionally
     297             :                 !   (but in different situations yield .true., even when expression is `.true. and .false.`.
     298        9860 :                 if (any(abs(instance) == 1_IK)) then
     299             : #endif
     300             : #if                 setReplaced_ENABLED && D0_D0_D0_ENABLED && SK_ENABLED
     301          24 :                     array = replacement
     302             : #elif               setReplaced_ENABLED
     303         766 :                     deallocate(array)
     304        2109 :                     allocate(array(1_IK + offset : lenReplacement + offset), source = replacement)
     305             : #elif               getReplaced_ENABLED
     306             : #if                 D0_D0_D0_ENABLED && SK_ENABLED
     307          28 :                     arrayNew = replacement
     308             : #else
     309        4146 :                     allocate(arrayNew(1_IK + offset : lenReplacement + offset), source = replacement)
     310             : #endif
     311             : #else
     312             : #error              "Unrecognized Interface."
     313             : #endif
     314          42 :                     return
     315             : #if             CusIns_ENABLED
     316             :                 end if
     317             : #endif
     318             :             end if
     319             : #if         getReplaced_ENABLED
     320       17207 :             arrayNew = array
     321             :         else ! array is smaller than pattern.
     322       17361 :             arrayNew = array
     323             : #endif
     324             :         end if
     325             : #undef  lenReplacement_ENABLED
     326             : #undef  lenPattern_ENABLED
     327             : #undef  INSTANCENEW
     328             : #undef  GET_INDEX
     329             : #undef  GET_SIZE
     330             : #undef  IS_EQUAL
     331             : #undef  ISEQ
     332             : #undef  ANY
     333             : #undef  ALL

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