hk.f90 Source File


Files dependent on this one

sourcefile~~hk.f90~~AfferentGraph sourcefile~hk.f90 hk.f90 sourcefile~percolation.f90 percolation.f90 sourcefile~percolation.f90->sourcefile~hk.f90 sourcefile~randomwalk.f90 randomwalk.f90 sourcefile~randomwalk.f90->sourcefile~percolation.f90

Contents

Source Code


Source Code

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