Hi everyone,
I’m working on an implementation for a unique function inside stdlib which returns unique values in an array. I implemented it and while testing, I am getting a bug for xdp kinds.
I am giving a working skeleton of the function below where the bug occurs.
program example_unique
use stdlib_kinds, only: xdp, int8
use stdlib_constants, only: zero_xdp
use stdlib_hashmaps, only: chaining_hashmap_type
use stdlib_hashmap_wrappers, only: key_type
implicit none
block
real(xdp), allocatable :: array(:), result(:)
integer(int8), allocatable :: bytes(:)
allocate(array(5), source=zero_xdp)
array = [5.0_xdp, 4.0_xdp, 3.0_xdp, -1.0_xdp, 3.0_xdp, 5.0_xdp]
result = unique(array)
!-----------------------------------------!
! print lines to see the byte structure of array
allocate(bytes(storage_size(array(1))/8))
bytes = transfer(array(1), bytes)
print*, "array(1): ", bytes
bytes = transfer(array(2), bytes)
print*, "array(2): ", bytes
bytes = transfer(array(3), bytes)
print*, "array(3): ", bytes
bytes = transfer(array(4), bytes)
print*, "array(4): ", bytes
!-----------------------------------------!
print*, "array: ", array
print*, "result: ", result
deallocate(array)
end block
block
real(xdp), allocatable :: array(:), result(:)
integer(int8), allocatable :: bytes(:)
allocate(array(4), source=zero_xdp)
array = [4.0_xdp, 4.0_xdp, 4.0_xdp, 4.0_xdp]
result = unique(array)
!-----------------------------------------!
! print lines to see the byte structure of array
print*
bytes = transfer(array(1), bytes)
print*, "array(1): ", bytes
bytes = transfer(array(2), bytes)
print*, "array(2): ", bytes
bytes = transfer(array(3), bytes)
print*, "array(3): ", bytes
bytes = transfer(array(4), bytes)
print*, "array(4): ", bytes
!-----------------------------------------!
print*, "array: ", array
print*, "result: ", result
deallocate(array)
end block
contains
function unique(A) result(output)
implicit none
real(xdp), intent(in) :: A(:)
real(xdp), allocatable :: output(:)
real(xdp), allocatable:: temp(:)
if(size(A) == 0) then
allocate(output(0))
return
end if
allocate(temp, source=A)
output = xdp_stable_unique(temp)
end function unique
function xdp_stable_unique(temp) result(output)
real(xdp), intent(in) :: temp(:)
real(xdp), allocatable :: output(:)
type(chaining_hashmap_type) :: map
logical, allocatable :: mask(:)
logical :: present
integer :: i
integer(int8) :: key(storage_size(temp(1))/8)
call map%init()
allocate(mask(size(temp)))
do i = 1, size(temp)
key = 0
key = transfer(temp(i), key)
call map%key_test(key, present)
if (.not. present) then
call map%map_entry(key)
mask(i) = .true.
else
mask(i) = .false.
end if
end do
output = pack(temp, mask)
deallocate(mask)
end function
end program example_unique
I used gfortran to compile and it gave me this output:
array(1): 0 0 0 0 0 0 0 -96 1 64 0 0 0 0 0 0
array(2): 0 0 0 0 0 0 0 -128 1 64 0 0 0 0 0 0
array(3): 0 0 0 0 0 0 0 -64 0 64 0 0 0 0 0 0
array(4): 0 0 0 0 0 0 0 -128 -1 -65 0 0 0 0 0 0
array: 5.00000000000000000000 4.00000000000000000000 3.00000000000000000000 -1.00000000000000000000 3.00000000000000000000 5.00000000000000000000
result: 5.00000000000000000000 4.00000000000000000000 3.00000000000000000000 -1.00000000000000000000
array(1): 0 0 0 0 0 0 0 -128 1 64 0 0 0 0 0 0
array(2): 0 0 0 0 0 0 0 -128 1 64 111 104 -58 91 0 0
array(3): 0 0 0 0 0 0 0 -128 1 64 0 0 0 0 0 0
array(4): 0 0 0 0 0 0 0 -128 1 64 0 0 0 0 0 0
array: 4.00000000000000000000 4.00000000000000000000 4.00000000000000000000 4.00000000000000000000
result: 4.00000000000000000000 4.00000000000000000000
As you can see, in the first part, it gave me the output correctly, but in the second part, the byte representation for the second entry inside array is different from all the other entries and because of this different byte structure, unique function gave two values inside the result. Even though I am assigning the entries for array the second time normallly(as array = [4.0_xdp, 4.0_xdp, 4.0_xdp, 4.0_xdp]),I have no clue why the byte structure differs for the second entry.
Two things I noticed:
- If I remove the first call to
uniquein line 14 then the bug disappears and correct byte structure comes. - If I remove the second call to
uniquein line 39 then the bug becomes worse and two entries will have different byte structures.
Can anyone give me some insights about why this is happening and what can we do in this situation ? Any help would be greatly appreciated.