ParaMonte Fortran 2.0.0
Parallel Monte Carlo and Machine Learning Library
See the latest version documentation.
pm_arrayUnique::getUnique Interface Reference

Generate and return a vector of unique values in the input array.
More...

Detailed Description

Generate and return a vector of unique values in the input array.

The uniqueness of the values can be optionally determined by the user by specifying the external input function that checks the equivalence of a pair of elements of the input array.

Parameters
[in]array: The input contiguous array of shape (:) of either
  • type character of kind any supported by the processor (e.g., SK, SKA, SKD , or SKU), or
  • type logical of kind any supported by the processor (e.g., LK), or
  • type integer of kind any supported by the processor (e.g., IK, IK8, IK16, IK32, or IK64), or
  • type complex of kind any supported by the processor (e.g., CK, CK32, CK64, or CK128), or
  • type real of kind any supported by the processor (e.g., RK, RK32, RK64, or RK128),
or,
  • a scalar assumed-length character of kind any supported by the processor (e.g., SK, SKA, SKD , or SKU),
whose unique elements are to be returned.
iseq: The external user-specified function that takes two input scalar arguments of the same type and kind as the input array.
It returns a scalar logical of default kind LK that is .true. if the two input arguments are equivalent (e.g., equal) according to the user-defined criterion, otherwise, it is .false..
The following illustrates the generic interface of iseq,
function iseq(element1, element2) result(equivalent)
use pm_kind, only: LK
TYPE(KIND) , intent(in) :: element1, element2
logical(LK) :: equivalent
end function
This module defines the relevant Fortran kind type-parameters frequently used in the ParaMonte librar...
Definition: pm_kind.F90:268
integer, parameter LK
The default logical kind in the ParaMonte library: kind(.true.) in Fortran, kind(....
Definition: pm_kind.F90:541
where TYPE(KIND) represents the type and kind of the input argument setA, which can be one of the following,
use pm_kind, only: SK, IK, CK, RK
character(*, SK), intent(in) :: element1, element2 ! when `array` is a string vector.
character(1, SK), intent(in) :: element1, element2 ! when `array` is a string scalar.
integer(IK) , intent(in) :: element1, element2
logical(LK) , intent(in) :: element1, element2
complex(CK) , intent(in) :: element1, element2
real(RK) , intent(in) :: element1, element2
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 CK
The default complex kind in the ParaMonte library: real64 in Fortran, c_double_complex in C-Fortran I...
Definition: pm_kind.F90:542
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
where the kinds SK, IK, LK, CK, RK, can refer to any kind type parameter that is supported by the processor.
This user-defined equivalence check is extremely useful where a user-defined equivalence test other than exact equality or identity is needed, for example, when the array elements should match only within a given threshold or, when the case-sensitivity in character comparisons do not matter.
In such cases, the user can define a custom equivalence criterion within the user-defined external function iseq to achieve the goal.
(optional, the default equivalence operator is .eqv. if the input array is logical, otherwise ==.)
Returns
unique : The output allocatable array of the same type and kind as the input array containing all of its unique elements.


Possible calling interfaces

unique = getUnique(array)
unique = getUnique(array, iseq)
Generate and return a vector of unique values in the input array.
This module contains procedures and generic interfaces for finding unique values of an input array of...
Warning
The pure procedure(s) documented herein become impure when the ParaMonte library is compiled with preprocessor macro CHECK_ENABLED=1.
By default, these procedures are pure in release build and impure in debug and testing builds.
The procedures under this generic interface are impure when the user-specified external procedure iseq is specified as input argument.
Note that in Fortran, trailing blanks are ignored in character comparison, that is, "Fortran" == "Fortran " yields .true..
Remarks
The functions under this generic interface are slightly slower than the setUnique subroutine implementations.
Note
If needed, use setSorted to sort the output unique values (in ascending order).
See also
getUnique
setUnique
isUniqueAll
isUniqueAny


Example usage

1program example
2
3 use pm_kind, only: LK
4 use pm_kind, only: SK ! All kinds are supported.
5 use pm_kind, only: IK ! All kinds are supported.
6 use pm_kind, only: CK ! All kinds are supported.
7 use pm_kind, only: RK ! All kinds are supported.
8 use pm_io, only: display_type
10
11 implicit none
12
13 character(:, SK), allocatable :: string_SK
14 character(9, SK), allocatable :: Array_SK(:) ! Can be any processor-supported kind.
15 integer(IK) , allocatable :: Array_IK(:) ! Can be any processor-supported kind.
16 complex(CK) , allocatable :: Array_CK(:) ! Can be any processor-supported kind.
17 real(RK) , allocatable :: Array_RK(:) ! Can be any processor-supported kind.
18
19 type(display_type) :: disp
20
21 disp = display_type(file = "main.out.F90")
22
23 call disp%skip()
24 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
25 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
26 call disp%show("! Find all unique elements in array.")
27 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
28 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
29 call disp%skip()
30
31 string_SK = "ParaMonte is a Monte Carlo Library."
32 Array_SK = ["ParaMonte", "PARAMONTE", "paramonte", "ParaMonte", "ParaMonte", "Paramonte"]
33 Array_IK = [1_IK, 1_IK, 4_IK, 4_IK]
34 Array_RK = [1._RK, 2._RK, 4._RK, 4._RK]
35 Array_CK = [(1._CK, -1._CK), (1._CK, -2._CK), (1._CK, -1._CK), (4._CK, -4._CK)]
36
37 call disp%skip()
38 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
39 call disp%show("! Unique elements in character scalar.")
40 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
41 call disp%skip()
42
43 call disp%show("string_SK")
44 call disp%show( string_SK, deliml = SK_"""" )
45 call disp%show("getUnique(string_SK)")
46 call disp%show( getUnique(string_SK), deliml = SK_"""" )
47
48 call disp%skip()
49 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
50 call disp%show("! Unique elements in character array.")
51 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
52 call disp%skip()
53
54 call disp%show("Array_SK")
55 call disp%show( Array_SK, deliml = SK_"""" )
56 call disp%show("getUnique(Array_SK)")
57 Array_SK = getUnique(Array_SK) ! This is a bug in gfortran as of version 11.
58 call disp%show( Array_SK, deliml = SK_"""" )
59
60 call disp%skip()
61 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
62 call disp%show("! Unique elements in integer array.")
63 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
64 call disp%skip()
65
66 call disp%show("Array_IK")
67 call disp%show( Array_IK )
68 call disp%show("getUnique(Array_IK)")
69 call disp%show( getUnique(Array_IK) )
70
71 call disp%skip()
72 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
73 call disp%show("! Unique elements in complex array.")
74 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
75 call disp%skip()
76
77 call disp%show("Array_CK")
78 call disp%show( Array_CK )
79 call disp%show("getUnique(Array_CK)")
80 call disp%show( getUnique(Array_CK) )
81
82 call disp%skip()
83 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
84 call disp%show("! Unique elements in real array.")
85 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
86 call disp%skip()
87
88 call disp%show("Array_RK")
89 call disp%show( Array_RK )
90 call disp%show("getUnique(Array_RK)")
91 call disp%show( getUnique(Array_RK) )
92
93 call disp%skip()
94 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
95 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
96 call disp%show("! Find all unique elements according to the user-specified equivalence criterion.")
97 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
98 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
99 call disp%skip()
100
101 call disp%skip()
102 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
103 call disp%show("! Unique elements in real array.")
104 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
105 call disp%skip()
106
107 Array_RK = [1.01_RK, 1.04_RK, 0.98_RK, 1.0_RK, 1.02_RK, 2._RK]
108
109 call disp%show("Array_RK")
110 call disp%show( Array_RK )
111 call disp%show("getUnique(Array_RK, iseq = iseq_RK)")
112 call disp%show( getUnique(Array_RK, iseq = iseq_RK) )
113
114 call disp%skip()
115 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
116 call disp%show("! Unique case-insensitive instances within the character array.")
117 call disp%show("!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
118 call disp%skip()
119
120 string_SK = "ABBAbbA"
121
122 call disp%show("string_SK")
123 call disp%show( string_SK, deliml = SK_"""" )
124 call disp%show("getUnique(string_SK, iseq = iseq_SK)")
125 call disp%show( getUnique(string_SK, iseq = iseq_SK), deliml = SK_"""" )
126
127contains
128
129 pure function iseq_RK(element1, element2) result(iseq)
130 real(RK) , intent(in) :: element1, element2
131 logical(LK) :: iseq
132 iseq = abs(abs(element1) - abs(element2)) < 0.05_RK
133 end function
134
135 pure function iseq_SK(element1, element2) result(iseq)
136 use pm_strASCII, only: getStrLower
137 character(*, SK) , intent(in) :: element1, element2
138 logical(LK) :: iseq
139 iseq = getStrLower(element1) == getStrLower(element2)
140 end function
141
142end program example
This is a generic method of the derived type display_type with pass attribute.
Definition: pm_io.F90:11726
This is a generic method of the derived type display_type with pass attribute.
Definition: pm_io.F90:11508
Generate and return the input string where the uppercase English alphabets are all converted to lower...
This module contains classes and procedures for input/output (IO) or generic display operations on st...
Definition: pm_io.F90:252
type(display_type) disp
This is a scalar module variable an object of type display_type for general display.
Definition: pm_io.F90:11393
This module contains the uncommon and hardly representable ASCII characters as well as procedures for...
Definition: pm_strASCII.F90:61
Generate and return an object of type display_type.
Definition: pm_io.F90:10282

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

Example output
1
2!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4! Find all unique elements in array.
5!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7
8
9!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10! Unique elements in character scalar.
11!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12
13string_SK
14"ParaMonte is a Monte Carlo Library."
15getUnique(string_SK)
16"ParMonte isClLby."
17
18!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19! Unique elements in character array.
20!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21
22Array_SK
23"ParaMonte", "PARAMONTE", "paramonte", "ParaMonte", "ParaMonte", "Paramonte"
24getUnique(Array_SK)
25"ParaMonte", "PARAMONTE", "paramonte", "Paramonte"
26
27!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28! Unique elements in integer array.
29!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30
31Array_IK
32+1, +1, +4, +4
33getUnique(Array_IK)
34+1, +4
35
36!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37! Unique elements in complex array.
38!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39
40Array_CK
41(+1.0000000000000000, -1.0000000000000000), (+1.0000000000000000, -2.0000000000000000), (+1.0000000000000000, -1.0000000000000000), (+4.0000000000000000, -4.0000000000000000)
42getUnique(Array_CK)
43(+1.0000000000000000, -1.0000000000000000), (+1.0000000000000000, -2.0000000000000000), (+4.0000000000000000, -4.0000000000000000)
44
45!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
46! Unique elements in real array.
47!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48
49Array_RK
50+1.0000000000000000, +2.0000000000000000, +4.0000000000000000, +4.0000000000000000
51getUnique(Array_RK)
52+1.0000000000000000, +2.0000000000000000, +4.0000000000000000
53
54!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
56! Find all unique elements according to the user-specified equivalence criterion.
57!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
59
60
61!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
62! Unique elements in real array.
63!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64
65Array_RK
66+1.0100000000000000, +1.0400000000000000, +0.97999999999999998, +1.0000000000000000, +1.0200000000000000, +2.0000000000000000
67getUnique(Array_RK, iseq = iseq_RK)
68+1.0100000000000000, +2.0000000000000000
69
70!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71! Unique case-insensitive instances within the character array.
72!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73
74string_SK
75"ABBAbbA"
76getUnique(string_SK, iseq = iseq_SK)
77"AB"
78
Test:
test_pm_arrayUnique
Bug:

Status: Unresolved
Source: Intel Classic Fortran Compiler ifort version 2021.2.0, GNU Fortran Compiler gfortran version 10-11
Description: The Intel Classic Fortran Compiler ifort version 2021.2.0 has a bug for the following interface definition,
character(len(array),SK) , allocatable :: arrayNew(:)

leading to an internal compiler error.

Remedy (as of ParaMonte Library version 2.0.0): For now, the remedy seems to be to redefine the interface as,

character(:, SK), allocatable :: arrayNew(:)

and changing the allocation method accordingly in the implementation to,

allocate(character(len(array, kind = IK)) :: arrayNew(lenArrayNew))

However, this introduces internal compiler error: Segmentation fault with GNU Fortran Compiler gfortran. Here is a code snippet to regenerate the bug in Intel Classic Fortran Compiler ifort (uncomment the commented line to reproduce the gfortran bug),

module pm_explicitLenResult
implicit none
interface
pure module function bug(array) result(arrayNew)
character(*, SK), intent(in), contiguous :: array(:)
character(len(array),SK) , allocatable :: arrayNew(:) ! catastrophic internal error with ifort 2021.2. Fine with gfortran 10.3
!character(:, SK) , allocatable :: arrayNew(:) ! catastrophic internal error with gfortran 10.3. Fine with ifort 2021.2
end function
end interface
end module pm_explicitLenResult
submodule (pm_explicitLenResult) routines
implicit none
contains
module procedure bug
allocate(arrayNew, source = array)
end procedure
end submodule routines
program main
use pm_explicitLenResult, only: bug
character(2) :: array(3) = ["AA", "BB", "CC"]
character(2), allocatable :: arrayNew(:)
arrayNew = bug(array)
end program main
program main
This is main entry to the tests of the ParaMonte kernel library.
Definition: main.F90:27


Remedy (as of ParaMonte Library version 2.0.0): It turns out that both GNU Fortran Compiler gfortran and Intel Classic Fortran Compiler ifort do not tolerate the separation of interface from implementation in the above code snippet.
If one duplicates the interface in the implementation submodule, then both compilers compile and run the code with no errors.
This is the remedy that is currently used in this getRemoved generic interface (interface duplication where the bug exists).
Here is a workaround example for the bug in the above code snippet,

module pm_explicitLenResult
implicit none
interface
pure module function bug(array) result(arrayNew)
character(*, SK), intent(in), contiguous :: array(:)
character(len(array),SK) , allocatable :: arrayNew(:) ! catastrophic internal error with ifort 2021.2. Fine with gfortran 10.3
end function
end interface
end module pm_explicitLenResult
submodule (pm_explicitLenResult) routines
implicit none
contains
module procedure bug
allocate(arrayNew, source = array)
end procedure
end submodule routines
program main
use pm_explicitLenResult, only: bug
character(2) :: array(3) = ["AA", "BB", "CC"]
character(2), allocatable :: arrayNew(:)
arrayNew = bug(array)
end program main
Todo:
Low Priority: This generic interface can be extended to 2D input objects.
Todo:
Critical Priority: The internal compiler error with ifort and gfortran has to be fixed in the future versions.


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:
Amir Shahmoradi, September 1, 2017, 11:35 PM, Institute for Computational Engineering and Sciences (ICES), The University of Texas Austin

Definition at line 2682 of file pm_arrayUnique.F90.


The documentation for this interface was generated from the following file: