ParaMonte Fortran 2.0.0
Parallel Monte Carlo and Machine Learning Library
See the latest version documentation.
pm_arrayFind Module Reference

This module contains procedures and generic interfaces for finding locations of a pattern in arrays of various types at the specified instances of occurrence of pattern. More...

Data Types

interface  getCountLoc
 Generate and return the number of occurrences of the input pattern in the input array optionally subject to user-specified memory blindness. More...
 
interface  getLoc
 Generate and return an allocatable array containing the indices of the locations within the input array where the input pattern exists. More...
 
interface  setLoc
 Return an allocatable array containing the indices of the locations within the input array where the input pattern exists.
More...
 

Variables

character(*, SK), parameter MODULE_NAME = "@pm_arrayFind"
 

Detailed Description

This module contains procedures and generic interfaces for finding locations of a pattern in arrays of various types at the specified instances of occurrence of pattern.

Benchmarks:


Benchmark :: The runtime performance of setLoc for scalar vs. vector input pattern argument.

1! Test the performance of setLoc() with a vector `pattern` vs. scalar `pattern`.
2program benchmark
3
4 use iso_fortran_env, only: error_unit
5 use pm_kind, only: IK, LK, RK, SK
6 use pm_bench, only: bench_type
7
8 implicit none
9
10 integer(IK) :: i
11 integer(IK) :: nloc
12 integer(IK) :: isize
13 integer(IK) :: fileUnit
14 integer(IK) , parameter :: NSIZE = 18_IK
15 integer(IK) , parameter :: NBENCH = 2_IK
16 integer(IK) :: arraySize(NSIZE)
17 logical(LK) :: dummy = .true._LK
18 integer(IK) , allocatable :: loc(:)
19 integer(IK) , allocatable :: array(:)
20 integer(IK) , parameter :: pattern(1) = 0_IK
21 type(bench_type) :: bench(NBENCH)
22
23 bench(1) = bench_type(name = SK_"scalarPattern", exec = scalarPattern , overhead = setOverhead)
24 bench(2) = bench_type(name = SK_"vectorPattern", exec = vectorPattern , overhead = setOverhead)
25
26 arraySize = [( 2_IK**isize, isize = 1_IK, NSIZE )]
27 loc = [integer(IK) ::] ! essential for `setLoc()`.
28 nloc = 0_IK
29
30 write(*,"(*(g0,:,' '))")
31 write(*,"(*(g0,:,' '))") "scalarPattern() vs. vectorPattern()"
32 write(*,"(*(g0,:,' '))")
33
34 open(newunit = fileUnit, file = "main.out", status = "replace")
35
36 write(fileUnit, "(*(g0,:,','))") "arraySize", (bench(i)%name, i = 1, NBENCH)
37
38 loopOverArraySize: do isize = 1, NSIZE
39
40 write(*,"(*(g0,:,' '))") "Benchmarking with size", arraySize(isize)
41 allocate(array(arraySize(isize)))
42
43 do i = 1, NBENCH
44 bench(i)%timing = bench(i)%getTiming(minsec = 0.05_RK)
45 end do
46
47 deallocate(array)
48 write(fileUnit,"(*(g0,:,','))") arraySize(isize), (bench(i)%timing%mean, i = 1, NBENCH)
49
50 end do loopOverArraySize
51 write(*,"(*(g0,:,' '))") dummy
52 write(*,"(*(g0,:,' '))")
53
54 close(fileUnit)
55
56contains
57
58 !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
59 ! procedure wrappers.
60 !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61
62 subroutine setOverhead()
63 call initialize()
64 call finalize()
65 end subroutine
66
67 subroutine initialize()
68 array(:) = 1_IK
69 end subroutine
70
71 subroutine finalize()
72 dummy = dummy .and. size(loc, 1, IK) == nloc
73 end subroutine
74
75 subroutine scalarPattern()
76 use pm_arrayFind, only: setLoc
77 call initialize()
78 call setLoc(loc, nloc, array, pattern(1), 1_IK)
79 call finalize()
80 end subroutine
81
82 subroutine vectorPattern()
83 block
84 use pm_arrayFind, only: setLoc
85 call initialize()
86 call setLoc(loc, nloc, array, pattern, 1_IK)
87 call finalize()
88 end block
89 end subroutine
90
91end program benchmark
Return an allocatable array containing the indices of the locations within the input array where the ...
Generate and return an object of type timing_type containing the benchmark timing information and sta...
Definition: pm_bench.F90:574
This module contains procedures and generic interfaces for finding locations of a pattern in arrays o...
This module contains abstract interfaces and types that facilitate benchmarking of different procedur...
Definition: pm_bench.F90:41
This module defines the relevant Fortran kind type-parameters frequently used in the ParaMonte librar...
Definition: pm_kind.F90:268
integer, parameter RK
The default real kind in the ParaMonte library: real64 in Fortran, c_double in C-Fortran Interoperati...
Definition: pm_kind.F90:543
integer, parameter LK
The default logical kind in the ParaMonte library: kind(.true.) in Fortran, kind(....
Definition: pm_kind.F90:541
integer, parameter IK
The default integer kind in the ParaMonte library: int32 in Fortran, c_int32_t in C-Fortran Interoper...
Definition: pm_kind.F90:540
integer, parameter SK
The default character kind in the ParaMonte library: kind("a") in Fortran, c_char in C-Fortran Intero...
Definition: pm_kind.F90:539
This is the class for creating benchmark and performance-profiling objects.
Definition: pm_bench.F90:386
subroutine bench(sort, arraySize)

Example Unix compile command via Intel ifort compiler
1#!/usr/bin/env sh
2rm main.exe
3ifort -fpp -standard-semantics -O3 -Wl,-rpath,../../../lib -I../../../inc main.F90 ../../../lib/libparamonte* -o main.exe
4./main.exe

Example Windows Batch compile command via Intel ifort compiler
1del main.exe
2set PATH=..\..\..\lib;%PATH%
3ifort /fpp /standard-semantics /O3 /I:..\..\..\include main.F90 ..\..\..\lib\libparamonte*.lib /exe:main.exe
4main.exe

Example Unix / MinGW compile command via GNU gfortran compiler
1#!/usr/bin/env sh
2rm main.exe
3gfortran -cpp -ffree-line-length-none -O3 -Wl,-rpath,../../../lib -I../../../inc main.F90 ../../../lib/libparamonte* -o main.exe
4./main.exe

Postprocessing of the benchmark output
1#!/usr/bin/env python
2
3import matplotlib.pyplot as plt
4import pandas as pd
5import numpy as np
6
7fontsize = 14
8
9methods = ["scalarPattern", "vectorPattern"]
10
11df = pd.read_csv("main.out")
12
13
16
17ax = plt.figure(figsize = 1.25 * np.array([6.4,4.6]), dpi = 200)
18ax = plt.subplot()
19
20for method in methods:
21 plt.plot( df["arraySize"].values
22 , df[method].values
23 , linewidth = 2
24 )
25
26plt.xticks(fontsize = fontsize)
27plt.yticks(fontsize = fontsize)
28ax.set_xlabel("Array Size", fontsize = fontsize)
29ax.set_ylabel("Runtime [ seconds ]", fontsize = fontsize)
30ax.set_title("Finding array segments with pattern(1) (scalar) vs. pattern(1:1) (vector).\nLower is better.", fontsize = fontsize)
31ax.set_xscale("log")
32ax.set_yscale("log")
33plt.minorticks_on()
34plt.grid(visible = True, which = "both", axis = "both", color = "0.85", linestyle = "-")
35ax.tick_params(axis = "y", which = "minor")
36ax.tick_params(axis = "x", which = "minor")
37ax.legend ( methods
38 #, loc='center left'
39 #, bbox_to_anchor=(1, 0.5)
40 , fontsize = fontsize
41 )
42
43plt.tight_layout()
44plt.savefig("benchmark.setLoc-scalarPattern_vs_vectorPattern.runtime.png")
45
46
49
50ax = plt.figure(figsize = 1.25 * np.array([6.4,4.6]), dpi = 200)
51ax = plt.subplot()
52
53plt.plot( df["arraySize"].values
54 , np.ones(len(df["arraySize"].values))
55 #, linestyle = "--"
56 #, color = "black"
57 , linewidth = 2
58 )
59plt.plot( df["arraySize"].values
60 , df["vectorPattern"].values / df["scalarPattern"].values
61 , linewidth = 2
62 )
63
64plt.xticks(fontsize = fontsize)
65plt.yticks(fontsize = fontsize)
66ax.set_xlabel("Array Size", fontsize = fontsize)
67ax.set_ylabel("Runtime compared to scalarPattern()", fontsize = fontsize)
68ax.set_title("Runtime Ratio: Find pattern(1:1) / Find pattern(1).\nLower means faster. Lower than 1 means faster than scalarPattern.", fontsize = fontsize)
69ax.set_xscale("log")
70#ax.set_yscale("log")
71plt.minorticks_on()
72plt.grid(visible = True, which = "both", axis = "both", color = "0.85", linestyle = "-")
73ax.tick_params(axis = "y", which = "minor")
74ax.tick_params(axis = "x", which = "minor")
75ax.legend ( ["scalarPattern", "vectorPattern"]
76 #, bbox_to_anchor = (1, 0.5)
77 #, loc = "center left"
78 , fontsize = fontsize
79 )
80
81plt.tight_layout()
82plt.savefig("benchmark.setLoc-scalarPattern_vs_vectorPattern.runtime.ratio.png")

Visualization of the benchmark output

Benchmark moral
  1. The procedures under the generic interface setLoc take both scalar and vector pattern arguments.
    As evidenced by the above benchmark, when the input pattern is vector of length 1, it is much faster, possibly up to 4X, to pass pattern as a scalar instead of a whole array of length 1.
    Note that this benchmark is likely irrelevant to finding substrings in Fortran strings.


Benchmark :: The runtime performance of getLoc vs. setLoc

1! Test the performance of `getLoc()` vs. `setLoc()`.
2program benchmark
3
4 use iso_fortran_env, only: error_unit
5 use pm_kind, only: IK, LK, RK, SK
6 use pm_bench, only: bench_type
7
8 implicit none
9
10 integer(IK) :: i
11 integer(IK) :: nloc
12 integer(IK) :: isize
13 integer(IK) :: fileUnit
14 integer(IK) , parameter :: blindness = 1
15 integer(IK) , parameter :: NSIZE = 18_IK
16 integer(IK) , parameter :: NBENCH = 2_IK
17 integer(IK) :: arraySize(NSIZE)
18 logical(LK) :: dummy = .true._LK
19 integer(IK) , allocatable :: loc(:)
20 character(:, SK), allocatable :: array
21 character(1,SK) :: pattern
22 type(bench_type) :: bench(NBENCH)
23
24 bench(1) = bench_type(name = SK_"setLoc", exec = setLoc , overhead = setOverhead)
25 bench(2) = bench_type(name = SK_"getLoc", exec = getLoc , overhead = setOverhead)
26
27 arraySize = [( 2_IK**isize, isize = 1_IK, NSIZE )]
28 loc = [integer(IK) ::] ! essential for `setLoc()`.
29 nloc = 0_IK
30
31 write(*,"(*(g0,:,' '))")
32 write(*,"(*(g0,:,' '))") "setLoc() vs. getLoc()"
33 write(*,"(*(g0,:,' '))")
34
35 open(newunit = fileUnit, file = "main.out", status = "replace")
36
37 write(fileUnit, "(*(g0,:,','))") "arraySize", (bench(i)%name, i = 1, NBENCH)
38
39 loopOverArraySize: do isize = 1, NSIZE
40
41 write(*,"(*(g0,:,' '))") "Benchmarking with size", arraySize(isize)
42
43 allocate(character(arraySize(isize)) :: array)
44 do i = 1, NBENCH
45 bench(i)%timing = bench(i)%getTiming(minsec = 0.05_RK)
46 end do
47 deallocate(array)
48
49 write(fileUnit,"(*(g0,:,','))") arraySize(isize), (bench(i)%timing%mean, i = 1, NBENCH)
50
51 end do loopOverArraySize
52 write(*,"(*(g0,:,' '))") dummy
53 write(*,"(*(g0,:,' '))")
54
55 close(fileUnit)
56
57contains
58
59 !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60 ! procedure wrappers.
61 !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
62
63 subroutine setOverhead()
64 call initialize()
65 call finalize()
66 end subroutine
67
68 subroutine initialize()
69 use pm_distUnif, only: setUnifRand
70 !allocate( character(arraySize(isize)) :: array )
71 call setUnifRand(pattern)
72 array(:) = repeat(pattern, len(array))
73 end subroutine
74
75 subroutine finalize()
76 dummy = dummy .and. size(loc, 1, IK) == nloc
77 !deallocate(array)
78 end subroutine
79
80 subroutine setLoc()
81 block
82 use pm_arrayFind, only: setLoc
83 call initialize()
84 call setLoc(loc, nloc, array, pattern, blindness)
85 call finalize()
86 end block
87 end subroutine
88
89 subroutine getLoc()
90 block
91 use pm_arrayFind, only: getLoc
92 call initialize()
93 loc = getLoc(array, pattern)
94 call finalize()
95 end block
96 end subroutine
97
98end program benchmark
Generate and return an allocatable array containing the indices of the locations within the input arr...
Return a uniform random scalar or contiguous array of arbitrary rank of randomly uniformly distribute...
This module contains classes and procedures for computing various statistical quantities related to t...

Example Unix compile command via Intel ifort compiler
1#!/usr/bin/env sh
2rm main.exe
3ifort -fpp -standard-semantics -O3 -Wl,-rpath,../../../lib -I../../../inc main.F90 ../../../lib/libparamonte* -o main.exe
4./main.exe

Example Windows Batch compile command via Intel ifort compiler
1del main.exe
2set PATH=..\..\..\lib;%PATH%
3ifort /fpp /standard-semantics /O3 /I:..\..\..\include main.F90 ..\..\..\lib\libparamonte*.lib /exe:main.exe
4main.exe

Example Unix / MinGW compile command via GNU gfortran compiler
1#!/usr/bin/env sh
2rm main.exe
3gfortran -cpp -ffree-line-length-none -O3 -Wl,-rpath,../../../lib -I../../../inc main.F90 ../../../lib/libparamonte* -o main.exe
4./main.exe

Postprocessing of the benchmark output
1#!/usr/bin/env python
2
3import matplotlib.pyplot as plt
4import pandas as pd
5import numpy as np
6
7fontsize = 14
8
9methods = ["setLoc", "getLoc"]
10
11df = pd.read_csv("main.out")
12
13
16
17ax = plt.figure(figsize = 1.25 * np.array([6.4,4.6]), dpi = 200)
18ax = plt.subplot()
19
20for method in methods:
21 plt.plot( df["arraySize"].values
22 , df[method].values
23 , linewidth = 2
24 )
25
26plt.xticks(fontsize = fontsize)
27plt.yticks(fontsize = fontsize)
28ax.set_xlabel("Array Size", fontsize = fontsize)
29ax.set_ylabel("Runtime [ seconds ]", fontsize = fontsize)
30ax.set_title("setLoc() vs. getLoc()\nLower is better.", fontsize = fontsize)
31ax.set_xscale("log")
32ax.set_yscale("log")
33plt.minorticks_on()
34plt.grid(visible = True, which = "both", axis = "both", color = "0.85", linestyle = "-")
35ax.tick_params(axis = "y", which = "minor")
36ax.tick_params(axis = "x", which = "minor")
37ax.legend ( methods
38 #, loc='center left'
39 #, bbox_to_anchor=(1, 0.5)
40 , fontsize = fontsize
41 )
42
43plt.tight_layout()
44plt.savefig("benchmark.getLoc_vs_setLoc.runtime.png")
45
46
49
50ax = plt.figure(figsize = 1.25 * np.array([6.4,4.6]), dpi = 200)
51ax = plt.subplot()
52
53plt.plot( df["arraySize"].values
54 , np.ones(len(df["arraySize"].values))
55 #, linestyle = "--"
56 #, color = "black"
57 , linewidth = 2
58 )
59plt.plot( df["arraySize"].values
60 , df["getLoc"].values / df["setLoc"].values
61 , linewidth = 2
62 )
63
64plt.xticks(fontsize = fontsize)
65plt.yticks(fontsize = fontsize)
66ax.set_xlabel("Array Size", fontsize = fontsize)
67ax.set_ylabel("Runtime compared to setLoc()", fontsize = fontsize)
68ax.set_title("getLoc() / setLoc()\nLower means faster. Lower than 1 means faster than setLoc().", fontsize = fontsize)
69ax.set_xscale("log")
70#ax.set_yscale("log")
71plt.minorticks_on()
72plt.grid(visible = True, which = "both", axis = "both", color = "0.85", linestyle = "-")
73ax.tick_params(axis = "y", which = "minor")
74ax.tick_params(axis = "x", which = "minor")
75ax.legend ( ["setLoc", "getLoc"]
76 #, bbox_to_anchor = (1, 0.5)
77 #, loc = "center left"
78 , fontsize = fontsize
79 )
80
81plt.tight_layout()
82plt.savefig("benchmark.getLoc_vs_setLoc.runtime.ratio.png")

Visualization of the benchmark output

Benchmark moral
  1. The procedures under the generic interface getLoc are functions while the procedures under the generic interface setLoc are subroutines.
    From the benchmark results, it appears that the functional interface performs slightly less efficiently than the subroutine interface when the input array size is small.
    Nevertheless, the difference appears to be marginal and insignificant in most practical situations.
  2. Note that this benchmark considers the worst-case scenario where all elements of the input array match the input pattern and must be therefore indexed.


Benchmark :: The runtime performance of setLoc with and without sorted = .true. and positive = .true. optional input arguments.

1! Test the performance of setLoc() with and without the optional `sorted = .true._LK, positive = .true.` input arguments.
2program benchmark
3
4 use iso_fortran_env, only: error_unit
5 use pm_kind, only: IK, LK, RK, SK
6 use pm_arrayRange, only: getRange
7 use pm_bench, only: bench_type
8
9 implicit none
10
11 integer(IK) :: i
12 integer(IK) :: nloc
13 integer(IK) :: isize
14 integer(IK) :: fileUnit
15 integer(IK) , parameter :: NSIZE = 20_IK
16 integer(IK) , parameter :: NBENCH = 2_IK
17 integer(IK) :: arraySize(NSIZE)
18 logical(LK) :: dummy = .true._LK
19 integer(IK) , allocatable :: instance(:)
20 integer(IK) , allocatable :: loc(:)
21 integer(IK) , allocatable :: array(:)
22 integer(IK) :: pattern
23 type(bench_type) :: bench(NBENCH)
24 real(RK) :: unifrnd
25
26 bench(1) = bench_type(name = SK_"sortedPositive", exec = sortedPositive , overhead = setOverhead)
27 bench(2) = bench_type(name = SK_"defaultOptions", exec = defaultOptions , overhead = setOverhead)
28
29 arraySize = [( 2_IK**isize, isize = 1_IK, NSIZE )]
30 loc = [integer(IK) ::] ! essential for `setLoc()`.
31 nloc = 0_IK
32
33 write(*,"(*(g0,:,' '))")
34 write(*,"(*(g0,:,' '))") "sortedPositive() vs. defaultOptions()"
35 write(*,"(*(g0,:,' '))")
36
37 open(newunit = fileUnit, file = "main.out", status = "replace")
38
39 write(fileUnit, "(*(g0,:,','))") "arraySize", (bench(i)%name, i = 1_IK, NBENCH)
40
41 loopOverArraySize: do isize = 1_IK, NSIZE
42
43 write(*,"(*(g0,:,' '))") "Benchmarking with size", arraySize(isize)
44 instance = getRange(1_IK, arraySize(isize))
45 allocate(array(arraySize(isize)))
46
47 do i = 1_IK, NBENCH
48 bench(i)%timing = bench(i)%getTiming(minsec = 0.05_RK)
49 end do
50
51 deallocate(array, instance)
52 write(fileUnit,"(*(g0,:,','))") arraySize(isize), (bench(i)%timing%mean, i = 1_IK, NBENCH)
53
54 end do loopOverArraySize
55 write(*,"(*(g0,:,' '))") dummy
56 write(*,"(*(g0,:,' '))")
57
58 close(fileUnit)
59
60contains
61
62 !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63 ! procedure wrappers.
64 !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65
66 subroutine setOverhead()
67 call initialize()
68 call finalize()
69 end subroutine
70
71 subroutine initialize()
72 call random_number(unifrnd)
73 pattern = nint(unifrnd, kind = IK)
74 array(:) = pattern + 1_IK
75 end subroutine
76
77 subroutine finalize()
78 dummy = dummy .and. size(loc, kind = IK) == nloc
79 end subroutine
80
81 subroutine sortedPositive()
82 use pm_arrayFind, only: setLoc
83 call initialize()
84 call setLoc(loc, nloc, array, pattern, instance, .true._LK, .true._LK, 1_IK)
85 call finalize()
86 end subroutine
87
88 subroutine defaultOptions()
89 block
90 use pm_arrayFind, only: setLoc
91 call initialize()
92 call setLoc(loc, nloc, array, pattern, instance, .false._LK, .false._LK, 1_IK)
93 call finalize()
94 end block
95 end subroutine
96
97end program benchmark
Generate minimally-spaced character, integer, real sequences or sequences at fixed intervals of size ...
This module contains procedures and generic interfaces for generating ranges of discrete character,...

Example Unix compile command via Intel ifort compiler
1#!/usr/bin/env sh
2rm main.exe
3ifort -fpp -standard-semantics -O3 -Wl,-rpath,../../../lib -I../../../inc main.F90 ../../../lib/libparamonte* -o main.exe
4./main.exe

Example Windows Batch compile command via Intel ifort compiler
1del main.exe
2set PATH=..\..\..\lib;%PATH%
3ifort /fpp /standard-semantics /O3 /I:..\..\..\include main.F90 ..\..\..\lib\libparamonte*.lib /exe:main.exe
4main.exe

Example Unix / MinGW compile command via GNU gfortran compiler
1#!/usr/bin/env sh
2rm main.exe
3gfortran -cpp -ffree-line-length-none -O3 -Wl,-rpath,../../../lib -I../../../inc main.F90 ../../../lib/libparamonte* -o main.exe
4./main.exe

Postprocessing of the benchmark output
1#!/usr/bin/env python
2
3import matplotlib.pyplot as plt
4import pandas as pd
5import numpy as np
6
7fontsize = 14
8
9methods = ["sortedPositive", "defaultOptions"]
10
11df = pd.read_csv("main.out")
12
13
16
17ax = plt.figure(figsize = 1.25 * np.array([6.4,4.6]), dpi = 200)
18ax = plt.subplot()
19
20for method in methods:
21 plt.plot( df["arraySize"].values
22 , df[method].values
23 , linewidth = 2
24 )
25
26plt.xticks(fontsize = fontsize)
27plt.yticks(fontsize = fontsize)
28ax.set_xlabel("Array Size", fontsize = fontsize)
29ax.set_ylabel("Runtime [ seconds ]", fontsize = fontsize)
30ax.set_title("Finding pattern with `sorted = .true._LK, positive = .true.` vs. the default.\nLower is better.", fontsize = fontsize)
31ax.set_xscale("log")
32ax.set_yscale("log")
33plt.minorticks_on()
34plt.grid(visible = True, which = "both", axis = "both", color = "0.85", linestyle = "-")
35ax.tick_params(axis = "y", which = "minor")
36ax.tick_params(axis = "x", which = "minor")
37ax.legend ( methods
38 #, loc='center left'
39 #, bbox_to_anchor=(1, 0.5)
40 , fontsize = fontsize
41 )
42
43plt.tight_layout()
44plt.savefig("benchmark.setLoc-sortedPositive_vs_defaultOptions.runtime.png")
45
46
49
50ax = plt.figure(figsize = 1.25 * np.array([6.4,4.6]), dpi = 200)
51ax = plt.subplot()
52
53plt.plot( df["arraySize"].values
54 , np.ones(len(df["arraySize"].values))
55 #, linestyle = "--"
56 #, color = "black"
57 , linewidth = 2
58 )
59plt.plot( df["arraySize"].values
60 , df["defaultOptions"].values / df["sortedPositive"].values
61 , linewidth = 2
62 )
63
64plt.xticks(fontsize = fontsize)
65plt.yticks(fontsize = fontsize)
66ax.set_xlabel("Array Size", fontsize = fontsize)
67ax.set_ylabel("Runtime compared to sortedPositive", fontsize = fontsize)
68ax.set_title("Runtime Ratio: Find with sortedPositive / Find with defaultOptions.\nLower means faster. Lower than 1 means faster than finding with sortedPositive.", fontsize = fontsize)
69ax.set_xscale("log")
70ax.set_yscale("log")
71plt.minorticks_on()
72plt.grid(visible = True, which = "both", axis = "both", color = "0.85", linestyle = "-")
73ax.tick_params(axis = "y", which = "minor")
74ax.tick_params(axis = "x", which = "minor")
75ax.legend ( ["sortedPositive", "defaultOptions"]
76 #, bbox_to_anchor = (1, 0.5)
77 #, loc = "center left"
78 , fontsize = fontsize
79 )
80
81plt.tight_layout()
82plt.savefig("benchmark.setLoc-sortedPositive_vs_defaultOptions.runtime.ratio.png")

Visualization of the benchmark output

Benchmark moral
  1. The procedures under the generic interface setLoc take two optional sorted and positive input arguments when the input array of instances instance is also specified. Setting sorted = .true._LK, positive = .true. guarantees to the procedures that all elements of instance are sorted in ascending-order and that no negative or zero value is present in instance. Hence, the maximum value in instance corresponds to instance(size(instance)), saving the procedures the time to find the maximum value of the input instance.
  2. As evidenced by the above benchmark, when sorted = .true._LK, positive = .true. can be guaranteed by the user, the runtime performance of the procedures could possibly increase 2-3 times compared to when the default values have to be assumed, corresponding to the worst case scenario (sorted = .false._LK, positive = .false.).
  3. The results of this benchmark equally hold for the functions under the generic interface getLoc.


Benchmark :: The runtime performance of setLoc with and without iseq external optional input argument.

1! Test the performance of setLoc() with and without the optional external function `iseq` input argument.
2program benchmark
3
4 use iso_fortran_env, only: error_unit
5 use pm_kind, only: IK, LK, RK, SK
6 use pm_arrayRange, only: getRange
7 use pm_bench, only: bench_type
8
9 implicit none
10
11 integer(IK) :: i
12 integer(IK) :: nloc
13 integer(IK) :: isize
14 integer(IK) :: fileUnit
15 integer(IK) , parameter :: blindness = 1
16 integer(IK) , parameter :: NSIZE = 20_IK
17 integer(IK) , parameter :: NBENCH = 2_IK
18 integer(IK) :: arraySize(NSIZE)
19 logical(LK) :: dummy = .true._LK
20 integer(IK) , allocatable :: instance(:)
21 integer(IK) , allocatable :: loc(:)
22 integer(IK) , allocatable :: array(:)
23 integer(IK) :: pattern
24 type(bench_type) :: bench(NBENCH)
25 real(RK) :: unifrnd, MeanTime(2) = 0._RK
26
27 bench(1) = bench_type(name = SK_"default", exec = default , overhead = setOverhead)
28 bench(2) = bench_type(name = SK_"iseqArg", exec = iseqArg , overhead = setOverhead)
29
30 arraySize = [( 2_IK**isize, isize = 1_IK, NSIZE )]
31 loc = [integer(IK) ::] ! essential for `setLoc()`.
32 nloc = 0_IK
33
34 write(*,"(*(g0,:,' '))")
35 write(*,"(*(g0,:,' '))") "iseqArg vs. default"
36 write(*,"(*(g0,:,' '))")
37
38 open(newunit = fileUnit, file = "main.out", status = "replace")
39
40 write(fileUnit, "(*(g0,:,','))") "arraySize", (bench(i)%name, i = 1_IK, NBENCH)
41
42 loopOverArraySize: do isize = 1_IK, NSIZE
43
44 write(*,"(*(g0,:,' '))") "Benchmarking with size", arraySize(isize)
45 instance = getRange(1_IK, arraySize(isize))
46 allocate(array(arraySize(isize)))
47
48 do i = 1_IK, NBENCH
49 bench(i)%timing = bench(i)%getTiming(minsec = 0.03_RK)
50 MeanTime(i) = MeanTime(i) + bench(i)%timing%mean
51 end do
52
53 do i = NBENCH, 1_IK, -1_IK
54 bench(i)%timing = bench(i)%getTiming(minsec = 0.03_RK)
55 MeanTime(i) = MeanTime(i) + bench(i)%timing%mean
56 end do
57
58 deallocate(array, instance)
59 write(fileUnit,"(*(g0,:,','))") arraySize(isize), MeanTime / 2_IK
60
61 end do loopOverArraySize
62 write(*,"(*(g0,:,' '))") dummy
63 write(*,"(*(g0,:,' '))")
64
65 close(fileUnit)
66
67contains
68
69 !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
70 ! procedure wrappers.
71 !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72
73 subroutine setOverhead()
74 call initialize()
75 call finalize()
76 end subroutine
77
78 subroutine initialize()
79 call random_number(unifrnd)
80 pattern = nint(unifrnd, kind = IK)
81 array(:) = pattern + 1_IK
82 end subroutine
83
84 subroutine finalize()
85 dummy = dummy .and. size(loc, 1, IK) == nloc
86 end subroutine
87
88 subroutine iseqArg()
89 use pm_arrayFind, only: setLoc
90 call initialize()
91 call setLoc(loc, nloc, array, pattern, iseq, 1_IK)
92 call finalize()
93 end subroutine
94
95 subroutine default()
96 block
97 use pm_arrayFind, only: setLoc
98 call initialize()
99 call setLoc(loc, nloc, array, pattern, 1_IK)
100 call finalize()
101 end block
102 end subroutine
103
104 pure function iseq(arraysegment, pattern) result(equivalent)
105 use pm_kind, only: IK, LK
106 integer(IK) , intent(in) :: pattern, arraySegment
107 logical(LK) :: equivalent
108 equivalent = arraySegment == pattern
109 end function
110
111end program benchmark

Example Unix compile command via Intel ifort compiler
1#!/usr/bin/env sh
2rm main.exe
3ifort -fpp -standard-semantics -O3 -Wl,-rpath,../../../lib -I../../../inc main.F90 ../../../lib/libparamonte* -o main.exe
4./main.exe

Example Windows Batch compile command via Intel ifort compiler
1del main.exe
2set PATH=..\..\..\lib;%PATH%
3ifort /fpp /standard-semantics /O3 /I:..\..\..\include main.F90 ..\..\..\lib\libparamonte*.lib /exe:main.exe
4main.exe

Example Unix / MinGW compile command via GNU gfortran compiler
1#!/usr/bin/env sh
2rm main.exe
3gfortran -cpp -ffree-line-length-none -O3 -Wl,-rpath,../../../lib -I../../../inc main.F90 ../../../lib/libparamonte* -o main.exe
4./main.exe

Postprocessing of the benchmark output
1#!/usr/bin/env python
2
3import matplotlib.pyplot as plt
4import pandas as pd
5import numpy as np
6
7fontsize = 14
8
9methods = ["default", "iseqArg"]
10
11df = pd.read_csv("main.out")
12
13
16
17ax = plt.figure(figsize = 1.25 * np.array([6.4,4.6]), dpi = 200)
18ax = plt.subplot()
19
20for method in methods:
21 plt.plot( df["arraySize"].values
22 , df[method].values
23 , linewidth = 2
24 )
25
26plt.xticks(fontsize = fontsize)
27plt.yticks(fontsize = fontsize)
28ax.set_xlabel("Array Size", fontsize = fontsize)
29ax.set_ylabel("Runtime [ seconds ]", fontsize = fontsize)
30ax.set_title("Finding pattern with external `iseq()` vs. default comparison.\nLower is better.", fontsize = fontsize)
31ax.set_xscale("log")
32ax.set_yscale("log")
33plt.minorticks_on()
34plt.grid(visible = True, which = "both", axis = "both", color = "0.85", linestyle = "-")
35ax.tick_params(axis = "y", which = "minor")
36ax.tick_params(axis = "x", which = "minor")
37ax.legend ( methods
38 #, loc='center left'
39 #, bbox_to_anchor=(1, 0.5)
40 , fontsize = fontsize
41 )
42
43plt.tight_layout()
44plt.savefig("benchmark.setLoc-iseqArg_vs_default.runtime.png")
45
46
49
50ax = plt.figure(figsize = 1.25 * np.array([6.4,4.6]), dpi = 200)
51ax = plt.subplot()
52
53plt.plot( df["arraySize"].values
54 , np.ones(len(df["arraySize"].values))
55 #, linestyle = "--"
56 #, color = "black"
57 , linewidth = 2
58 )
59plt.plot( df["arraySize"].values
60 , df["iseqArg"].values / df["default"].values
61 , linewidth = 2
62 )
63
64plt.xticks(fontsize = fontsize)
65plt.yticks(fontsize = fontsize)
66ax.set_xlabel("Array Size", fontsize = fontsize)
67ax.set_ylabel("Runtime compared to iseqArg", fontsize = fontsize)
68ax.set_title("Runtime Ratio: Comparison with `iseq()` / default.\nLower means faster. Lower than 1 means faster than finding with `iseq()`.", fontsize = fontsize)
69ax.set_xscale("log")
70#ax.set_yscale("log")
71plt.minorticks_on()
72plt.grid(visible = True, which = "both", axis = "both", color = "0.85", linestyle = "-")
73ax.tick_params(axis = "y", which = "minor")
74ax.tick_params(axis = "x", which = "minor")
75ax.legend ( methods
76 #, bbox_to_anchor = (1, 0.5)
77 #, loc = "center left"
78 , fontsize = fontsize
79 )
80
81plt.tight_layout()
82plt.savefig("benchmark.setLoc-iseqArg_vs_default.runtime.ratio.png")

Visualization of the benchmark output

Benchmark moral
  1. The procedures under the generic interface setLoc take an optional iseq() external-function input argument which can perform custom user-defined equivalence checks between the input pattern and array segments. By default, the equivalence check is equality (or equivalence for logical values).
  2. The presence of an external iseq argument does appear to deteriorate the runtime performance of setLoc.
    However, the exact amount of this penalty appears to significantly depend on the computing platform and the ability of the compiler to inline the external function.
  3. The results of this benchmark equally hold for the functions under the generic interface getLoc.
Test:
test_pm_arrayFind


Final Remarks


If you believe this algorithm or its documentation can be improved, we appreciate your contribution and help to edit this page's documentation and source file on GitHub.
For details on the naming abbreviations, see this page.
For details on the naming conventions, see this page.
This software is distributed under the MIT license with additional terms outlined below.

  1. If you use any parts or concepts from this library to any extent, please acknowledge the usage by citing the relevant publications of the ParaMonte library.
  2. If you regenerate any parts/ideas from this library in a programming environment other than those currently supported by this ParaMonte library (i.e., other than C, C++, Fortran, MATLAB, Python, R), please also ask the end users to cite this original ParaMonte library.

This software is available to the public under a highly permissive license.
Help us justify its continued development and maintenance by acknowledging its benefit to society, distributing it, and contributing to it.

Author:
Fatemeh Bagheri, Wednesday 12:20 AM, October 13, 2021, Dallas, TX

Variable Documentation

◆ MODULE_NAME

character(*,SK), parameter pm_arrayFind::MODULE_NAME = "@pm_arrayFind"

Definition at line 103 of file pm_arrayFind.F90.