-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhk.f90
116 lines (102 loc) · 4.1 KB
/
hk.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
module hk
!! A module containing a Fortran implementation of the
!! Hoshen-Kopelman algorithm, as well as the necessary
!! union-find procedures.
implicit none
contains
function hoshen_kopelman(matrix) result(num_clusters)
!! Hoshen-Kopelman algorithm for labelling clusters on
!! a binary matrix.
!!
!! The function takes in a binary matrix
!! (zeros and positive numbers), labels the clusters of
!! positive numbers and returns the total number of clusters
!! found. The argument matrix is overwritten with the labels.
integer, intent(inout), dimension(:,:) :: matrix
!! The matrix to be labelled.
integer :: num_clusters
!! The total number of disjoint clusters labelled.
integer :: m, n, i, j, up, left, label
integer, dimension(:), allocatable :: labels, new_labels
m = size(matrix, 1)
n = size(matrix, 2)
allocate(labels(m*n/2+1))
labels = 0
num_clusters = 0
do j = 1, n
do i = 1, m
if(matrix(i,j) > 0) then
if(i == 1) then
up = 0
else
up = matrix(i-1, j)
end if
if(j == 1) then
left = 0
else
left = matrix(i, j-1)
end if
! New cluster
if(up==0 .and. left==0) then
num_clusters = num_clusters + 1
labels(num_clusters) = num_clusters
matrix(i,j) = num_clusters
! Site binds clusters
else if(up > 0 .and. left > 0) then
matrix(i,j) = uf_union(up, left, labels)
! Only one neighbour
else
matrix(i,j) = max(up, left)
end if
end if
end do
end do
allocate(new_labels(m*n/2+1))
new_labels = 0
num_clusters = 0
do j = 1, n
do i = 1, m
if(matrix(i,j) > 0) then
label = uf_find(matrix(i,j), labels)
if(new_labels(label) == 0) then
num_clusters = num_clusters + 1
new_labels(label) = num_clusters
end if
matrix(i,j) = new_labels(label)
end if
end do
end do
end function
function uf_find(x, labels) result(y)
!! Union-Find find algorithm:
!! Find the lowest corresponding label.
!! Relabelling is done when necessary.
integer, intent(in) :: x
!! Label for which to find the lowest corresponding label.
integer, dimension(:), intent(inout) :: labels
!! List of labels. **labels(i)** points to the lowest
!! corresponding label of label **i**.
integer :: y, z, tmp
y = x
do while(labels(y) /= y)
y = labels(y)
end do
tmp = x
do while(labels(tmp) /= tmp)
z = labels(tmp)
labels(tmp) = y
tmp = z
end do
end function
function uf_union(x, y, labels) result(canonical_label)
!! Union-Find union algorithm:
!! Merge two labels, return the result.
integer, intent(in) :: x, y
!! Labels to merge.
integer, dimension(:), intent(inout) :: labels
!! List of labels.
integer :: canonical_label
canonical_label = uf_find(y,labels)
labels(uf_find(x,labels)) = canonical_label
end function
end module hk