forlab_sorting_argsort.f90 Source File


Contents


Source Code

submodule(forlab_sorting) forlab_sorting_argsort

    implicit none

contains

    module procedure argsort_int8
    integer::i, n
    integer(int8), allocatable::xsort(:)
    integer::order1
    n = size(x)
    xsort = x
    argsort_int8 = [(i, i=1, n)]
    if (.not. present(order)) then
        order1 = 1
    else
        order1 = order
    end if
    call quickargsort_int8(xsort, argsort_int8, n, order1)
    end procedure argsort_int8
    recursive subroutine quickargsort_int8(x, idx, n, order)
        integer(int8), dimension(n), intent(inout) :: x
        integer, dimension(n), intent(inout) :: idx
        integer, intent(in) :: n, order
        integer:: left, right, marker
        integer(int8) :: pivot, tmp1
        integer::tmp2
        if (n > 1) then
            left = 0
            right = n + 1
            pivot = x(randu(1, n))
            select case (order)
            case (1)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) < pivot)
                        left = left + 1
                    end do
                    do while (x(right) > pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case (2)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) > pivot)
                        left = left + 1
                    end do
                    do while (x(right) < pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case default
                error stop "Error:Sort order MUST be 1 or 2"
            end select
            if (left == right) then
                marker = left + 1
            else
                marker = left
            end if
            call quickargsort_int8(x(:marker - 1), idx(:marker - 1), marker - 1, order)
            call quickargsort_int8(x(marker:), idx(marker:), n - marker + 1, order)
        end if
    end subroutine quickargsort_int8
    module procedure argsort_int16
    integer::i, n
    integer(int16), allocatable::xsort(:)
    integer::order1
    n = size(x)
    xsort = x
    argsort_int16 = [(i, i=1, n)]
    if (.not. present(order)) then
        order1 = 1
    else
        order1 = order
    end if
    call quickargsort_int16(xsort, argsort_int16, n, order1)
    end procedure argsort_int16
    recursive subroutine quickargsort_int16(x, idx, n, order)
        integer(int16), dimension(n), intent(inout) :: x
        integer, dimension(n), intent(inout) :: idx
        integer, intent(in) :: n, order
        integer:: left, right, marker
        integer(int16) :: pivot, tmp1
        integer::tmp2
        if (n > 1) then
            left = 0
            right = n + 1
            pivot = x(randu(1, n))
            select case (order)
            case (1)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) < pivot)
                        left = left + 1
                    end do
                    do while (x(right) > pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case (2)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) > pivot)
                        left = left + 1
                    end do
                    do while (x(right) < pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case default
                error stop "Error:Sort order MUST be 1 or 2"
            end select
            if (left == right) then
                marker = left + 1
            else
                marker = left
            end if
            call quickargsort_int16(x(:marker - 1), idx(:marker - 1), marker - 1, order)
            call quickargsort_int16(x(marker:), idx(marker:), n - marker + 1, order)
        end if
    end subroutine quickargsort_int16
    module procedure argsort_int32
    integer::i, n
    integer(int32), allocatable::xsort(:)
    integer::order1
    n = size(x)
    xsort = x
    argsort_int32 = [(i, i=1, n)]
    if (.not. present(order)) then
        order1 = 1
    else
        order1 = order
    end if
    call quickargsort_int32(xsort, argsort_int32, n, order1)
    end procedure argsort_int32
    recursive subroutine quickargsort_int32(x, idx, n, order)
        integer(int32), dimension(n), intent(inout) :: x
        integer, dimension(n), intent(inout) :: idx
        integer, intent(in) :: n, order
        integer:: left, right, marker
        integer(int32) :: pivot, tmp1
        integer::tmp2
        if (n > 1) then
            left = 0
            right = n + 1
            pivot = x(randu(1, n))
            select case (order)
            case (1)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) < pivot)
                        left = left + 1
                    end do
                    do while (x(right) > pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case (2)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) > pivot)
                        left = left + 1
                    end do
                    do while (x(right) < pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case default
                error stop "Error:Sort order MUST be 1 or 2"
            end select
            if (left == right) then
                marker = left + 1
            else
                marker = left
            end if
            call quickargsort_int32(x(:marker - 1), idx(:marker - 1), marker - 1, order)
            call quickargsort_int32(x(marker:), idx(marker:), n - marker + 1, order)
        end if
    end subroutine quickargsort_int32
    module procedure argsort_int64
    integer::i, n
    integer(int64), allocatable::xsort(:)
    integer::order1
    n = size(x)
    xsort = x
    argsort_int64 = [(i, i=1, n)]
    if (.not. present(order)) then
        order1 = 1
    else
        order1 = order
    end if
    call quickargsort_int64(xsort, argsort_int64, n, order1)
    end procedure argsort_int64
    recursive subroutine quickargsort_int64(x, idx, n, order)
        integer(int64), dimension(n), intent(inout) :: x
        integer, dimension(n), intent(inout) :: idx
        integer, intent(in) :: n, order
        integer:: left, right, marker
        integer(int64) :: pivot, tmp1
        integer::tmp2
        if (n > 1) then
            left = 0
            right = n + 1
            pivot = x(randu(1, n))
            select case (order)
            case (1)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) < pivot)
                        left = left + 1
                    end do
                    do while (x(right) > pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case (2)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) > pivot)
                        left = left + 1
                    end do
                    do while (x(right) < pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case default
                error stop "Error:Sort order MUST be 1 or 2"
            end select
            if (left == right) then
                marker = left + 1
            else
                marker = left
            end if
            call quickargsort_int64(x(:marker - 1), idx(:marker - 1), marker - 1, order)
            call quickargsort_int64(x(marker:), idx(marker:), n - marker + 1, order)
        end if
    end subroutine quickargsort_int64
    module procedure argsort_sp
    integer::i, n
    real(sp), allocatable::xsort(:)
    integer::order1
    n = size(x)
    xsort = x
    argsort_sp = [(i, i=1, n)]
    if (.not. present(order)) then
        order1 = 1
    else
        order1 = order
    end if
    call quickargsort_sp(xsort, argsort_sp, n, order1)
    end procedure argsort_sp
    recursive subroutine quickargsort_sp(x, idx, n, order)
        real(sp), dimension(n), intent(inout) :: x
        integer, dimension(n), intent(inout) :: idx
        integer, intent(in) :: n, order
        integer:: left, right, marker
        real(sp) :: pivot, tmp1
        integer::tmp2
        if (n > 1) then
            left = 0
            right = n + 1
            pivot = x(randu(1, n))
            select case (order)
            case (1)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) < pivot)
                        left = left + 1
                    end do
                    do while (x(right) > pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case (2)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) > pivot)
                        left = left + 1
                    end do
                    do while (x(right) < pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case default
                error stop "Error:Sort order MUST be 1 or 2"
            end select
            if (left == right) then
                marker = left + 1
            else
                marker = left
            end if
            call quickargsort_sp(x(:marker - 1), idx(:marker - 1), marker - 1, order)
            call quickargsort_sp(x(marker:), idx(marker:), n - marker + 1, order)
        end if
    end subroutine quickargsort_sp
    module procedure argsort_dp
    integer::i, n
    real(dp), allocatable::xsort(:)
    integer::order1
    n = size(x)
    xsort = x
    argsort_dp = [(i, i=1, n)]
    if (.not. present(order)) then
        order1 = 1
    else
        order1 = order
    end if
    call quickargsort_dp(xsort, argsort_dp, n, order1)
    end procedure argsort_dp
    recursive subroutine quickargsort_dp(x, idx, n, order)
        real(dp), dimension(n), intent(inout) :: x
        integer, dimension(n), intent(inout) :: idx
        integer, intent(in) :: n, order
        integer:: left, right, marker
        real(dp) :: pivot, tmp1
        integer::tmp2
        if (n > 1) then
            left = 0
            right = n + 1
            pivot = x(randu(1, n))
            select case (order)
            case (1)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) < pivot)
                        left = left + 1
                    end do
                    do while (x(right) > pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case (2)
                do while (left < right)
                    left = left + 1
                    right = right - 1
                    do while (x(left) > pivot)
                        left = left + 1
                    end do
                    do while (x(right) < pivot)
                        right = right - 1
                    end do
                    if (left < right) then
                        tmp1 = x(left)
                        x(left) = x(right)
                        x(right) = tmp1
                        tmp2 = idx(left)
                        idx(left) = idx(right)
                        idx(right) = tmp2
                    end if
                end do
            case default
                error stop "Error:Sort order MUST be 1 or 2"
            end select
            if (left == right) then
                marker = left + 1
            else
                marker = left
            end if
            call quickargsort_dp(x(:marker - 1), idx(:marker - 1), marker - 1, order)
            call quickargsort_dp(x(marker:), idx(marker:), n - marker + 1, order)
        end if
    end subroutine quickargsort_dp

end submodule forlab_sorting_argsort