kdtree2.f90

来自「kd tree java implementation 2」· F90 代码 · 共 1,902 行 · 第 1/4 页

F90
1,902
字号
!!(c) Matthew Kennel, Institute for Nonlinear Science (2004)!! Licensed under the Academic Free License version 1.1 found in file LICENSE! with additional provisions found in that same file.!module kdtree2_precision_module    integer, parameter :: sp = kind(0.0)  integer, parameter :: dp = kind(0.0d0)  private :: sp, dp  !  ! You must comment out exactly one  ! of the two lines.  If you comment  ! out kdkind = sp then you get single precision  ! and if you comment out kdkind = dp   ! you get double precision.  !  integer, parameter :: kdkind = sp    !integer, parameter :: kdkind = dp    public :: kdkindend module kdtree2_precision_modulemodule kdtree2_priority_queue_module  use kdtree2_precision_module  !  ! maintain a priority queue (PQ) of data, pairs of 'priority/payload',   ! implemented with a binary heap.  This is the type, and the 'dis' field  ! is the priority.  !  type kdtree2_result      ! a pair of distances, indexes      real(kdkind)    :: dis!=0.0      integer :: idx!=-1   Initializers cause some bugs in compilers.  end type kdtree2_result  !  ! A heap-based priority queue lets one efficiently implement the following  ! operations, each in log(N) time, as opposed to linear time.  !  ! 1)  add a datum (push a datum onto the queue, increasing its length)   ! 2)  return the priority value of the maximum priority element   ! 3)  pop-off (and delete) the element with the maximum priority, decreasing  !     the size of the queue.   ! 4)  replace the datum with the maximum priority with a supplied datum  !     (of either higher or lower priority), maintaining the size of the  !     queue.   !  !  ! In the k-d tree case, the 'priority' is the square distance of a point in  ! the data set to a reference point.   The goal is to keep the smallest M  ! distances to a reference point.  The tree algorithm searches terminal  ! nodes to decide whether to add points under consideration.  !  ! A priority queue is useful here because it lets one quickly return the  ! largest distance currently existing in the list.  If a new candidate  ! distance is smaller than this, then the new candidate ought to replace  ! the old candidate.  In priority queue terms, this means removing the  ! highest priority element, and inserting the new one.  !  ! Algorithms based on Cormen, Leiserson, Rivest, _Introduction  ! to Algorithms_, 1990, with further optimization by the author.  !  ! Originally informed by a C implementation by Sriranga Veeraraghavan.  !  ! This module is not written in the most clear way, but is implemented such  ! for speed, as it its operations will be called many times during searches  ! of large numbers of neighbors.  !  type pq      !      ! The priority queue consists of elements      ! priority(1:heap_size), with associated payload(:).      !      ! There are heap_size active elements.       ! Assumes the allocation is always sufficient.  Will NOT increase it      ! to match.      integer :: heap_size = 0      type(kdtree2_result), pointer :: elems(:)   end type pq  public :: kdtree2_result  public :: pq  public :: pq_create  public :: pq_delete, pq_insert  public :: pq_extract_max, pq_max, pq_replace_max, pq_maxpri  privatecontains  function pq_create(results_in) result(res)    !    ! Create a priority queue from ALREADY allocated    ! array pointers for storage.  NOTE! It will NOT    ! add any alements to the heap, i.e. any existing    ! data in the input arrays will NOT be used and may    ! be overwritten.    !     ! usage:    !    real(kdkind), pointer :: x(:)    !    integer, pointer :: k(:)    !    allocate(x(1000),k(1000))    !    pq => pq_create(x,k)    !    type(kdtree2_result), target:: results_in(:)     type(pq) :: res    !    !    integer :: nalloc    nalloc = size(results_in,1)    if (nalloc .lt. 1) then       write (*,*) 'PQ_CREATE: error, input arrays must be allocated.'    end if    res%elems => results_in    res%heap_size = 0    return  end function pq_create  !  ! operations for getting parents and left + right children  ! of elements in a binary heap.  !!! These are written inline for speed.!    !  integer function parent(i)!    integer, intent(in) :: i!    parent = (i/2)!    return!  end function parent!  integer function left(i)!    integer, intent(in) ::i!    left = (2*i)!    return!  end function left!  integer function right(i)!    integer, intent(in) :: i!    right = (2*i)+1!    return!  end function right!  logical function compare_priority(p1,p2)!    real(kdkind), intent(in) :: p1, p2!!    compare_priority = (p1 .gt. p2)!    return!  end function compare_priority  subroutine heapify(a,i_in)    !    ! take a heap rooted at 'i' and force it to be in the    ! heap canonical form.   This is performance critical     ! and has been tweaked a little to reflect this.    !    type(pq),pointer   :: a    integer, intent(in) :: i_in    !    integer :: i, l, r, largest    real(kdkind)    :: pri_i, pri_l, pri_r, pri_largest    type(kdtree2_result) :: temp    i = i_inbigloop:  do       l = 2*i ! left(i)       r = l+1 ! right(i)       !        ! set 'largest' to the index of either i, l, r       ! depending on whose priority is largest.       !       ! note that l or r can be larger than the heap size       ! in which case they do not count.       ! does left child have higher priority?        if (l .gt. a%heap_size) then          ! we know that i is the largest as both l and r are invalid.          exit        else          pri_i = a%elems(i)%dis          pri_l = a%elems(l)%dis           if (pri_l .gt. pri_i) then             largest = l             pri_largest = pri_l          else             largest = i             pri_largest = pri_i          endif          !          ! between i and l we have a winner          ! now choose between that and r.          !          if (r .le. a%heap_size) then             pri_r = a%elems(r)%dis             if (pri_r .gt. pri_largest) then                largest = r             endif          endif       endif       if (largest .ne. i) then          ! swap data in nodes largest and i, then heapify          temp = a%elems(i)          a%elems(i) = a%elems(largest)          a%elems(largest) = temp           !           ! Canonical heapify() algorithm has tail-ecursive call:           !          !        call heapify(a,largest)             ! we will simulate with cycle          !          i = largest          cycle bigloop ! continue the loop        else          return   ! break from the loop       end if    enddo bigloop    return  end subroutine heapify  subroutine pq_max(a,e)     !    ! return the priority and its payload of the maximum priority element    ! on the queue, which should be the first one, if it is     ! in heapified form.    !    type(pq),pointer :: a    type(kdtree2_result),intent(out)  :: e    if (a%heap_size .gt. 0) then       e = a%elems(1)     else       write (*,*) 'PQ_MAX: ERROR, heap_size < 1'       stop    endif    return  end subroutine pq_max    real(kdkind) function pq_maxpri(a)    type(pq), pointer :: a    if (a%heap_size .gt. 0) then       pq_maxpri = a%elems(1)%dis    else       write (*,*) 'PQ_MAX_PRI: ERROR, heapsize < 1'       stop    endif    return  end function pq_maxpri  subroutine pq_extract_max(a,e)    !    ! return the priority and payload of maximum priority    ! element, and remove it from the queue.    ! (equivalent to 'pop()' on a stack)    !    type(pq),pointer :: a    type(kdtree2_result), intent(out) :: e        if (a%heap_size .ge. 1) then       !       ! return max as first element       !       e = a%elems(1)               !       ! move last element to first       !       a%elems(1) = a%elems(a%heap_size)        a%heap_size = a%heap_size-1       call heapify(a,1)       return    else       write (*,*) 'PQ_EXTRACT_MAX: error, attempted to pop non-positive PQ'       stop    end if      end subroutine pq_extract_max  real(kdkind) function pq_insert(a,dis,idx)     !    ! Insert a new element and return the new maximum priority,    ! which may or may not be the same as the old maximum priority.    !    type(pq),pointer  :: a    real(kdkind), intent(in) :: dis    integer, intent(in) :: idx    !    type(kdtree2_result), intent(in) :: e    !    integer :: i, isparent    real(kdkind)    :: parentdis    !    !    if (a%heap_size .ge. a%max_elems) then    !       write (*,*) 'PQ_INSERT: error, attempt made to insert element on full PQ'    !       stop    !    else    a%heap_size = a%heap_size + 1    i = a%heap_size    do while (i .gt. 1)       isparent = int(i/2)       parentdis = a%elems(isparent)%dis       if (dis .gt. parentdis) then          ! move what was in i's parent into i.          a%elems(i)%dis = parentdis          a%elems(i)%idx = a%elems(isparent)%idx          i = isparent       else          exit       endif    end do    ! insert the element at the determined position    a%elems(i)%dis = dis    a%elems(i)%idx = idx    pq_insert = a%elems(1)%dis     return    !    end if  end function pq_insert  subroutine pq_adjust_heap(a,i)    type(pq),pointer  :: a    integer, intent(in) :: i    !    ! nominally arguments (a,i), but specialize for a=1    !    ! This routine assumes that the trees with roots 2 and 3 are already heaps, i.e.    ! the children of '1' are heaps.  When the procedure is completed, the    ! tree rooted at 1 is a heap.    real(kdkind) :: prichild    integer :: parent, child, N    type(kdtree2_result) :: e    e = a%elems(i)     parent = i    child = 2*i    N = a%heap_size        do while (child .le. N)       if (child .lt. N) then          if (a%elems(child)%dis .lt. a%elems(child+1)%dis) then             child = child+1          endif       endif       prichild = a%elems(child)%dis       if (e%dis .ge. prichild) then          exit        else          ! move child into parent.          a%elems(parent) = a%elems(child)           parent = child          child = 2*parent       end if    end do    a%elems(parent) = e    return  end subroutine pq_adjust_heap      real(kdkind) function pq_replace_max(a,dis,idx)     !    ! Replace the extant maximum priority element    ! in the PQ with (dis,idx).  Return    ! the new maximum priority, which may be larger    ! or smaller than the old one.    !    type(pq),pointer         :: a    real(kdkind), intent(in) :: dis    integer, intent(in) :: idx!    type(kdtree2_result), intent(in) :: e    ! not tested as well!    integer :: parent, child, N    real(kdkind)    :: prichild, prichildp1    type(kdtree2_result) :: etmp        if (.true.) then       N=a%heap_size       if (N .ge. 1) then          parent =1          child=2          loop: do while (child .le. N)             prichild = a%elems(child)%dis             !             ! posibly child+1 has higher priority, and if             ! so, get it, and increment child.             !             if (child .lt. N) then                prichildp1 = a%elems(child+1)%dis                if (prichild .lt. prichildp1) then                   child = child+1                   prichild = prichildp1                endif             endif             if (dis .ge. prichild) then                exit loop                  ! we have a proper place for our new element,                 ! bigger than either children's priority.             else                ! move child into parent.                a%elems(parent) = a%elems(child)                 parent = child                child = 2*parent             end if          end do loop          a%elems(parent)%dis = dis          a%elems(parent)%idx = idx          pq_replace_max = a%elems(1)%dis       else          a%elems(1)%dis = dis          a%elems(1)%idx = idx          pq_replace_max = dis       endif    else       !       ! slower version using elementary pop and push operations.       !       call pq_extract_max(a,etmp)        etmp%dis = dis       etmp%idx = idx       pq_replace_max = pq_insert(a,dis,idx)    endif    return  end function pq_replace_max  subroutine pq_delete(a,i)    !     ! delete item with index 'i'    !    type(pq),pointer :: a    integer           :: i    if ((i .lt. 1) .or. (i .gt. a%heap_size)) then       write (*,*) 'PQ_DELETE: error, attempt to remove out of bounds element.'       stop    endif    ! swap the item to be deleted with the last element    ! and shorten heap by one.    a%elems(i) = a%elems(a%heap_size)     a%heap_size = a%heap_size - 1    call heapify(a,i)  end subroutine pq_deleteend module kdtree2_priority_queue_modulemodule kdtree2_module  use kdtree2_precision_module

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?