!>
!> @file sparse_mod.f90
!>
!> @brief
!>
!> @copyright
!> Copyright (©) 2021 EPFL (Ecole Polytechnique Fédérale de Lausanne)
!> SPC (Swiss Plasma Center)
!>
!> SPClibs is free software: you can redistribute it and/or modify it under
!> the terms of the GNU Lesser General Public License as published by the Free
!> Software Foundation, either version 3 of the License, or (at your option)
!> any later version.
!>
!> SPClibs is distributed in the hope that it will be useful, but WITHOUT ANY
!> WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
!> FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
!>
!> You should have received a copy of the GNU Lesser General Public License
!> along with this program. If not, see .
!>
!> @author
!> (in alphabetical order)
!> @author Trach-Minh Tran
!>
MODULE sparse
!
! SPARSE: Implement sparse matrix using dynamic linked lists
! as matrix rows.
!
! T.M. Tran, CRPP-EPFL
! October 2010
!
IMPLICIT NONE
!
TYPE elt
INTEGER :: index=0
DOUBLE PRECISION :: val=0.0d0
TYPE(elt), POINTER :: next => NULL()
END TYPE elt
!
TYPE zelt
INTEGER :: index=0
DOUBLE COMPLEX :: val=(0.0d0, 0.0d0)
TYPE(zelt), POINTER :: next => NULL()
END TYPE zelt
!
TYPE sprow
INTEGER :: nnz=0 ! Number of non zeros in a row
TYPE(elt), POINTER :: row0 => NULL() ! Points to head of a (sparse) row
END TYPE sprow
!
TYPE zsprow
INTEGER :: nnz=0 ! Number of non zeros in a row
TYPE(zelt), POINTER :: row0 => NULL() ! Points to head of a (sparse) row
END TYPE zsprow
!
TYPE spmat
INTEGER :: rank
TYPE(sprow), POINTER :: row(:) => NULL()
END TYPE spmat
!
TYPE zspmat
INTEGER :: rank
TYPE(zsprow), POINTER :: row(:) => NULL()
END TYPE zspmat
!
INTERFACE init
MODULE PROCEDURE init_spmat, init_zspmat
END INTERFACE init
!
INTERFACE updtmat
MODULE PROCEDURE updt_sp, updt_zsp, updt_spmat, updt_zspmat
END INTERFACE updtmat
!
INTERFACE putele
MODULE PROCEDURE putele_sp, putele_zsp, putele_spmat, putele_zspmat
END INTERFACE putele
!
INTERFACE getele
MODULE PROCEDURE getele_sp, getele_zsp, getele_spmat, getele_zspmat
END INTERFACE getele
!
INTERFACE putrow
MODULE PROCEDURE putrow_csr, putrow_full, putrow_spmat, &
& putrow_zcsr, putrow_zfull, putrow_zspmat
END INTERFACE putrow
!
INTERFACE getrow
MODULE PROCEDURE getrow_csr, getrow_full, getrow_spmat, &
& getrow_zcsr, getrow_zfull, getrow_zspmat
END INTERFACE getrow
!
INTERFACE putcol
MODULE PROCEDURE putcol_spmat, putcol_zspmat
END INTERFACE putcol
!
INTERFACE getcol
MODULE PROCEDURE getcol_spmat, getcol_zspmat
END INTERFACE getcol
!
INTERFACE get_count
MODULE PROCEDURE get_count_sp, get_count_spmat, &
& get_count_zsp, get_count_zspmat
END INTERFACE get_count
!
INTERFACE destroy
MODULE PROCEDURE destroy_spmat, destroy_row, destroy_node, &
& destroy_zspmat, destroy_zrow, destroy_znode
END INTERFACE destroy
!
CONTAINS
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE init_spmat(n, mat, istart, iend)
!
! Initial an empty sparse matrix
!
INTEGER, INTENT(in) :: n
INTEGER, INTENT(in), OPTIONAL :: istart, iend
TYPE(spmat) :: mat
!
mat%rank = n
IF(ASSOCIATED(mat%row)) DEALLOCATE(mat%row)
IF(PRESENT(istart)) THEN
ALLOCATE(mat%row(istart:iend))
ELSE
ALLOCATE(mat%row(n))
END IF
!
END SUBROUTINE init_spmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE init_zspmat(n, mat, istart, iend)
!
! Initial an empty sparse matrix
!
INTEGER, INTENT(in) :: n
INTEGER, INTENT(in), OPTIONAL :: istart, iend
TYPE(zspmat) :: mat
!
mat%rank = n
IF(ASSOCIATED(mat%row)) DEALLOCATE(mat%row)
IF(PRESENT(istart)) THEN
ALLOCATE(mat%row(istart:iend))
ELSE
ALLOCATE(mat%row(n))
END IF
!
END SUBROUTINE init_zspmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE updt_sp(arow, j, val)
!
! Update element j of row arow or insert it in an increasing "index"
!
TYPE(sprow), TARGET :: arow
INTEGER, INTENT(in) :: j
DOUBLE PRECISION, INTENT(in) :: val
!
TYPE(elt), TARGET :: pre_root
TYPE(elt), POINTER :: t, p
!
pre_root%next => arow%row0 ! pre_root is linked to the head of the list.
t => pre_root
DO WHILE( ASSOCIATED(t%next) )
p => t%next
IF( p%index .EQ. j ) THEN
p%val = p%val+val
RETURN
END IF
IF( p%index .GT. j ) EXIT
t => t%next
END DO
ALLOCATE(p)
p = elt(j, val, t%next)
t%next => p
!
arow%nnz = arow%nnz+1
arow%row0 => pre_root%next ! In case the head is altered
END SUBROUTINE updt_sp
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE updt_zsp(arow, j, val)
!
! Update element j of row arow or insert it in an increasing "index"
!
TYPE(zsprow), TARGET :: arow
INTEGER, INTENT(in) :: j
DOUBLE COMPLEX, INTENT(in) :: val
!
TYPE(zelt), TARGET :: pre_root
TYPE(zelt), POINTER :: t, p
!
pre_root%next => arow%row0 ! pre_root is linked to the head of the list.
t => pre_root
DO WHILE( ASSOCIATED(t%next) )
p => t%next
IF( p%index .EQ. j ) THEN
p%val = p%val+val
RETURN
END IF
IF( p%index .GT. j ) EXIT
t => t%next
END DO
ALLOCATE(p)
p = zelt(j, val, t%next)
t%next => p
!
arow%nnz = arow%nnz+1
arow%row0 => pre_root%next ! In case the head is altered
END SUBROUTINE updt_zsp
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE updt_spmat(mat, i, j, val)
!
! Update element Aij of sparse matrix
!
TYPE(spmat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE PRECISION, INTENT(in) :: val
!
CALL updt_sp(mat%row(i), j, val)
END SUBROUTINE updt_spmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE updt_zspmat(mat, i, j, val)
!
! Update element Aij of sparse matrix
!
TYPE(zspmat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE COMPLEX, INTENT(in) :: val
!
CALL updt_zsp(mat%row(i), j, val)
END SUBROUTINE updt_zspmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getele_sp(arow, j, val, found)
!
! Get element j from row arow
!
TYPE(sprow), TARGET :: arow
INTEGER, INTENT(in) :: j
DOUBLE PRECISION, INTENT(out) :: val
LOGICAL, INTENT(out), OPTIONAL :: found
!
TYPE(elt), POINTER :: t
INTEGER :: i
!
val = 0.0d0
t => arow%row0 ! Start of a row
DO WHILE( ASSOCIATED(t) )
IF(t%index .EQ. j) THEN
val = t%val
IF(PRESENT(found)) found = .TRUE.
RETURN
END IF
t => t%next
END DO
IF(PRESENT(found)) found = .FALSE.
END SUBROUTINE getele_sp
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getele_zsp(arow, j, val, found)
!
! Get element j from row arow
!
TYPE(zsprow), TARGET :: arow
INTEGER, INTENT(in) :: j
DOUBLE COMPLEX, INTENT(out) :: val
LOGICAL, INTENT(out), OPTIONAL :: found
!
TYPE(zelt), POINTER :: t
INTEGER :: i
!
val = 0.0d0
t => arow%row0 ! Start of a row
DO WHILE( ASSOCIATED(t) )
IF(t%index .EQ. j) THEN
val = t%val
IF(PRESENT(found)) found = .TRUE.
RETURN
END IF
t => t%next
END DO
IF(PRESENT(found)) found = .FALSE.
END SUBROUTINE getele_zsp
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getele_spmat(mat, i, j, val)
!
! Get element (i,j) of sparse matrix
!
TYPE(spmat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE PRECISION, INTENT(out) :: val
!
CALL getele(mat%row(i), j, val)
END SUBROUTINE getele_spmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getele_zspmat(mat, i, j, val)
!
! Get element (i,j) of sparse matrix
!
TYPE(zspmat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE COMPLEX, INTENT(out) :: val
!
CALL getele(mat%row(i), j, val)
END SUBROUTINE getele_zspmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putele_sp(arow, j, val, nlforce_zero)
!
! Put (overwrite) element j of row arow or insert it in an increasing "index"
!
TYPE(sprow), TARGET :: arow
INTEGER, INTENT(in) :: j
DOUBLE PRECISION, INTENT(in) :: val
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
TYPE(elt), TARGET :: pre_root
TYPE(elt), POINTER :: t, p
LOGICAL :: rmnode
!
pre_root%next => arow%row0 ! pre_root is linked to the head of the list.
t => pre_root
!
! Remove node which has zero val or not?
! But never create new node with zero val
!
rmnode = .TRUE.
IF(PRESENT(nlforce_zero)) rmnode = .NOT.nlforce_zero
!
DO WHILE( ASSOCIATED(t%next) )
p => t%next
IF( p%index .EQ. j ) THEN
IF(ABS(val).LE.EPSILON(0.0d0) .AND. rmnode) THEN ! Remove the node for zero val!
t%next => p%next
arow%nnz = arow%nnz-1
arow%row0 => pre_root%next ! In case the head is altered
DEALLOCATE(p)
ELSE
p%val = val
END IF
RETURN
END IF
IF( p%index .GT. j ) EXIT
t => t%next
END DO
!
! Never create new node with zero val
!
IF(ABS(val).GT.EPSILON(0.0d0)) THEN
ALLOCATE(p)
p = elt(j, val, t%next)
t%next => p
arow%nnz = arow%nnz+1
arow%row0 => pre_root%next
END IF
END SUBROUTINE putele_sp
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putele_zsp(arow, j, val, nlforce_zero)
!
! Put (overwrite) element j of row arow or insert it in an increasing "index"
!
TYPE(zsprow), TARGET :: arow
INTEGER, INTENT(in) :: j
DOUBLE COMPLEX, INTENT(in) :: val
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
TYPE(zelt), TARGET :: pre_root
TYPE(zelt), POINTER :: t, p
LOGICAL :: rmnode
!
pre_root%next => arow%row0 ! pre_root is linked to the head of the list.
t => pre_root
!
! Remove node which has zero val or not?
! But never create new node with zero val
!
rmnode = .TRUE.
IF(PRESENT(nlforce_zero)) rmnode = .NOT.nlforce_zero
!
DO WHILE( ASSOCIATED(t%next) )
p => t%next
IF( p%index .EQ. j ) THEN
IF(ABS(val).LE.EPSILON(0.0d0) .AND. rmnode) THEN ! Remove the node for zero val!
t%next => p%next
arow%nnz = arow%nnz-1
arow%row0 => pre_root%next ! In case the head is altered
DEALLOCATE(p)
ELSE
p%val = val
END IF
RETURN
END IF
IF( p%index .GT. j ) EXIT
t => t%next
END DO
!
! Never create new node with zero val
!
IF(ABS(val).GT.EPSILON(0.0d0)) THEN
ALLOCATE(p)
p = zelt(j, val, t%next)
t%next => p
arow%nnz = arow%nnz+1
arow%row0 => pre_root%next
END IF
END SUBROUTINE putele_zsp
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putele_spmat(mat, i, j, val, nlforce_zero)
!
! Put element (i,j) of matrix
!
TYPE(spmat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE PRECISION, INTENT(in) :: val
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
CALL putele(mat%row(i), j, val, nlforce_zero)
END SUBROUTINE putele_spmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putele_zspmat(mat, i, j, val, nlforce_zero)
!
! Put element (i,j) of matrix
!
TYPE(zspmat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE COMPLEX, INTENT(in) :: val
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
CALL putele(mat%row(i), j, val, nlforce_zero)
END SUBROUTINE putele_zspmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INTEGER FUNCTION get_count_sp(arow)
!
! Number of elements in arow
!
TYPE(sprow), INTENT(in) :: arow
TYPE(elt), POINTER :: t
INTEGER :: i
!
t => arow%row0 ! Start of a row
i = 0
DO WHILE( ASSOCIATED(t) )
i=i+1
t => t%next
END DO
get_count_sp = i
END FUNCTION get_count_sp
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INTEGER FUNCTION get_count_zsp(arow)
!
! Number of elements in arow
!
TYPE(zsprow), INTENT(in) :: arow
TYPE(zelt), POINTER :: t
INTEGER :: i
!
t => arow%row0 ! Start of a row
i = 0
DO WHILE( ASSOCIATED(t) )
i=i+1
t => t%next
END DO
get_count_zsp = i
END FUNCTION get_count_zsp
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INTEGER FUNCTION get_count_spmat(mat, nnz)
!
! Number of non-zeros in sparse matrix
!
TYPE(spmat) :: mat
INTEGER, INTENT(out), OPTIONAL :: nnz(:)
!
INTEGER :: i, c(LBOUND(mat%row,1):UBOUND(mat%row,1))
DO i=LBOUND(mat%row,1),UBOUND(mat%row,1)
c(i) = get_count_sp(mat%row(i))
END DO
IF(PRESENT(nnz)) nnz = c
get_count_spmat = SUM(c)
END FUNCTION get_count_spmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INTEGER FUNCTION get_count_zspmat(mat, nnz)
!
! Number of non-zeros in sparse matrix
!
TYPE(zspmat) :: mat
INTEGER, INTENT(out), OPTIONAL :: nnz(:)
!
INTEGER :: i, c(LBOUND(mat%row,1):UBOUND(mat%row,1))
DO i=LBOUND(mat%row,1),UBOUND(mat%row,1)
c(i) = get_count_zsp(mat%row(i))
END DO
IF(PRESENT(nnz)) nnz = c
get_count_zspmat = SUM(c)
END FUNCTION get_count_zspmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getrow_csr(arow, arr, col, count)
!
! Get a row from sparse row arow and put it in a CSR format
!
TYPE(sprow), INTENT(in) :: arow
DOUBLE PRECISION, INTENT(out) :: arr(:)
INTEGER, INTENT(out) :: col(:)
INTEGER, OPTIONAL, INTENT(out) :: count
!
TYPE(elt), POINTER :: t
INTEGER :: i
!
t => arow%row0 ! Start of a row
i = 0
DO WHILE( ASSOCIATED(t) )
i=i+1
col(i) = t%index
arr(i) = t%val
t => t%next
END DO
IF(PRESENT(count)) count = i
END SUBROUTINE getrow_csr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getrow_zcsr(arow, arr, col, count)
!
! Get a row from sparse row arow and put it in a CSR format
!
TYPE(zsprow), INTENT(in) :: arow
DOUBLE COMPLEX, INTENT(out) :: arr(:)
INTEGER, INTENT(out) :: col(:)
INTEGER, OPTIONAL, INTENT(out) :: count
!
TYPE(zelt), POINTER :: t
INTEGER :: i
!
t => arow%row0 ! Start of a row
i = 0
DO WHILE( ASSOCIATED(t) )
i=i+1
col(i) = t%index
arr(i) = t%val
t => t%next
END DO
IF(PRESENT(count)) count = i
END SUBROUTINE getrow_zcsr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getrow_full(arow, arr, count)
!
! Get a row from sparse row arow and put it in an full row
!
TYPE(sprow), INTENT(in) :: arow
DOUBLE PRECISION, INTENT(out) :: arr(:)
INTEGER, OPTIONAL, INTENT(out) :: count
!
TYPE(elt), POINTER :: t
INTEGER :: n, i, j
!
n = SIZE(arr)
arr = 0.0d0
t => arow%row0 ! Start of a row
i = 0
DO WHILE( ASSOCIATED(t) )
i=i+1
j = t%index
IF(j.LE.n) THEN
arr(j) = t%val
t => t%next
ELSE
WRITE(*,'(a)') 'GETROW_FULL: size of input ARR too small!'
STOP
END IF
END DO
IF(PRESENT(count)) count = i
END SUBROUTINE getrow_full
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getrow_zfull(arow, arr, count)
!
! Get a row from sparse row arow and put it in an full row
!
TYPE(zsprow), INTENT(in) :: arow
DOUBLE COMPLEX, INTENT(out) :: arr(:)
INTEGER, OPTIONAL, INTENT(out) :: count
!
TYPE(zelt), POINTER :: t
INTEGER :: n, i, j
!
n = SIZE(arr)
arr = 0.0d0
t => arow%row0 ! Start of a row
i = 0
DO WHILE( ASSOCIATED(t) )
i=i+1
j = t%index
IF(j.LE.n) THEN
arr(j) = t%val
t => t%next
ELSE
WRITE(*,'(a)') 'GETROW_FULL: size of input ARR too small!'
STOP
END IF
END DO
IF(PRESENT(count)) count = i
END SUBROUTINE getrow_zfull
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getrow_spmat(mat, i, arr, col)
!
! Get a row from sparse matrix
!
TYPE(spmat), INTENT(in) :: mat
INTEGER, INTENT(in) :: i
DOUBLE PRECISION, INTENT(out) :: arr(:)
INTEGER, INTENT(out), OPTIONAL :: col(:)
!
IF(PRESENT(col)) THEN ! The output row is defined by (col, arr)
CALL getrow_csr(mat%row(i), arr, col)
ELSE
CALL getrow_full(mat%row(i), arr)
END IF
END SUBROUTINE getrow_spmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getrow_zspmat(mat, i, arr, col)
!
! Get a row from sparse matrix
!
TYPE(zspmat), INTENT(in) :: mat
INTEGER, INTENT(in) :: i
DOUBLE COMPLEX, INTENT(out) :: arr(:)
INTEGER, INTENT(out), OPTIONAL :: col(:)
!
IF(PRESENT(col)) THEN ! The output row is defined by (col, arr)
CALL getrow_zcsr(mat%row(i), arr, col)
ELSE
CALL getrow_zfull(mat%row(i), arr)
END IF
END SUBROUTINE getrow_zspmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putrow_csr(arow, arr, col, nlforce_zero)
!
! Put a row from sparse row arow and put it in a CSR format
!
TYPE(sprow), INTENT(inout) :: arow
DOUBLE PRECISION, INTENT(in) :: arr(:)
INTEGER, INTENT(in) :: col(:)
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
INTEGER :: n, i
!
n=SIZE(arr)
DO i=1,n
CALL putele(arow, col(i), arr(i), nlforce_zero)
END DO
END SUBROUTINE putrow_csr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putrow_zcsr(arow, arr, col, nlforce_zero)
!
! Put a row from sparse row arow and put it in a CSR format
!
TYPE(zsprow), INTENT(inout) :: arow
DOUBLE COMPLEX, INTENT(in) :: arr(:)
INTEGER, INTENT(in) :: col(:)
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
INTEGER :: n, i
!
n=SIZE(arr)
DO i=1,n
CALL putele(arow, col(i), arr(i), nlforce_zero)
END DO
END SUBROUTINE putrow_zcsr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putrow_full(arow, arr, nlforce_zero)
!
! Put a row from sparse row arow and put it in a full row
!
TYPE(sprow), INTENT(inout) :: arow
DOUBLE PRECISION, INTENT(in) :: arr(:)
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
INTEGER :: n, i
!
n=SIZE(arr)
DO i=1,n
CALL putele(arow, i, arr(i), nlforce_zero)
END DO
END SUBROUTINE putrow_full
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putrow_zfull(arow, arr, nlforce_zero)
!
! Put a row from sparse row arow and put it in a full row
!
TYPE(zsprow), INTENT(inout) :: arow
DOUBLE COMPLEX, INTENT(in) :: arr(:)
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
INTEGER :: n, i
!
n=SIZE(arr)
DO i=1,n
CALL putele(arow, i, arr(i), nlforce_zero)
END DO
END SUBROUTINE putrow_zfull
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putrow_spmat(mat, i, arr, col, nlforce_zero)
!
! Put a row to matrix
!
TYPE(spmat) :: mat
INTEGER, intent(in) :: i
DOUBLE PRECISION, INTENT(in) :: arr(:)
INTEGER, INTENT(in), OPTIONAL :: col(:)
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
IF(PRESENT(col)) THEN ! The input row is defined by (col, arr)
CALL putrow_csr(mat%row(i), arr, col, nlforce_zero)
ELSE
CALL putrow_full(mat%row(i), arr, nlforce_zero)
END IF
END SUBROUTINE putrow_spmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putrow_zspmat(mat, i, arr, col, nlforce_zero)
!
! Put a row to matrix
!
TYPE(zspmat) :: mat
INTEGER, intent(in) :: i
DOUBLE COMPLEX, INTENT(in) :: arr(:)
INTEGER, INTENT(in), OPTIONAL :: col(:)
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
IF(PRESENT(col)) THEN ! The input row is defined by (col, arr)
CALL putrow_zcsr(mat%row(i), arr, col, nlforce_zero)
ELSE
CALL putrow_zfull(mat%row(i), arr, nlforce_zero)
END IF
END SUBROUTINE putrow_zspmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putcol_spmat(mat, j, arr, nlforce_zero)
!
! Put a column to mtarix
!
TYPE(spmat) :: mat
INTEGER, INTENT(in) :: j
DOUBLE PRECISION, INTENT(in) :: arr(:)
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
INTEGER :: i
DO i=1,mat%rank
CALL putele(mat, i, j, arr(i), nlforce_zero)
END DO
END SUBROUTINE putcol_spmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putcol_zspmat(mat, j, arr, nlforce_zero)
!
! Put a column to mtarix
!
TYPE(zspmat) :: mat
INTEGER, INTENT(in) :: j
DOUBLE COMPLEX, INTENT(in) :: arr(:)
LOGICAL, INTENT(in), OPTIONAL :: nlforce_zero
!
INTEGER :: i
DO i=1,mat%rank
CALL putele(mat, i, j, arr(i), nlforce_zero)
END DO
END SUBROUTINE putcol_zspmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getcol_spmat(mat, j, arr)
!
! Get column j of matrix
!
TYPE(spmat) :: mat
INTEGER, INTENT(in) :: j
DOUBLE PRECISION, INTENT(out) :: arr(:)
INTEGER :: i
DO i=1,mat%rank
CALL getele(mat, i, j, arr(i))
END DO
END SUBROUTINE getcol_spmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getcol_zspmat(mat, j, arr)
!
! Get column j of matrix
!
TYPE(zspmat) :: mat
INTEGER, INTENT(in) :: j
DOUBLE COMPLEX, INTENT(out) :: arr(:)
INTEGER :: i
DO i=1,mat%rank
CALL getele(mat, i, j, arr(i))
END DO
END SUBROUTINE getcol_zspmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE destroy_row(arow)
!
! Deallocate the sparse row
!
TYPE(sprow), INTENT(inout) :: arow
!
IF(ASSOCIATED(arow%row0)) CALL destroy_node(arow%row0)
arow%nnz = get_count(arow)
END SUBROUTINE destroy_row
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE destroy_zrow(arow)
!
! Deallocate the sparse row
!
TYPE(zsprow), INTENT(inout) :: arow
!
IF(ASSOCIATED(arow%row0)) CALL destroy_znode(arow%row0)
arow%nnz = get_count(arow)
END SUBROUTINE destroy_zrow
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RECURSIVE SUBROUTINE destroy_node(p)
!
! Deallocate recursively the linked list
!
TYPE(elt), POINTER :: p
!
IF(ASSOCIATED(p%next)) CALL destroy_node(p%next)
DEALLOCATE(p)
END SUBROUTINE destroy_node
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RECURSIVE SUBROUTINE destroy_znode(p)
!
! Deallocate recursively the linked list
!
TYPE(zelt), POINTER :: p
!
IF(ASSOCIATED(p%next)) CALL destroy_znode(p%next)
DEALLOCATE(p)
END SUBROUTINE destroy_znode
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE destroy_spmat(mat)
!
! Deallocate the sparse matrix
!
TYPE(spmat) :: mat
INTEGER :: n, i
!
n = mat%rank
DO i=LBOUND(mat%row,1),UBOUND(mat%row,1)
CALL destroy(mat%row(i))
END DO
DEALLOCATE(mat%row)
END SUBROUTINE destroy_spmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE destroy_zspmat(mat)
!
! Deallocate the sparse matrix
!
TYPE(zspmat) :: mat
INTEGER :: n, i
!
n = mat%rank
DO i=LBOUND(mat%row,1),UBOUND(mat%row,1)
CALL destroy(mat%row(i))
END DO
DEALLOCATE(mat%row)
END SUBROUTINE destroy_zspmat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INTEGER FUNCTION isearch(karr, k)
!
! Sequential search an ordered table of integers
!
INTEGER, INTENT(in) :: karr(0:)
INTEGER, INTENT(in) :: k
INTEGER :: n
!
n=SIZE(karr)
isearch = -1 ! Failure
IF( k.GT.karr(n-1)) RETURN
!
isearch=0
DO
IF( k.LE.karr(isearch)) EXIT
isearch = isearch+1
END DO
IF( k.NE.karr(isearch)) isearch = -1 ! Failure
END FUNCTION isearch
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INTEGER FUNCTION isearch_bin(karr, k)
!
! Binary search an ordered table of integers
!
INTEGER, INTENT(in) :: karr(0:)
INTEGER, INTENT(in) :: k
INTEGER :: n
INTEGER :: l, u
!
n=SIZE(karr)
isearch_bin = -1 ! Failure
IF( k.LT.karr(0) .OR. k.GT.karr(n-1)) RETURN
!
l=0; u=n-1
DO WHILE(l.LE.u)
isearch_bin = (l+u)/2
IF(k.EQ.karr(isearch_bin)) THEN
RETURN
ELSE IF(k.LT.karr(isearch_bin)) THEN
u = isearch_bin-1
ELSE
l = isearch_bin+1
END IF
END DO
isearch_bin = -1 ! Failure
END FUNCTION isearch_bin
!
END MODULE sparse