diff --git a/src/SF_SPARSE/CMakeLists.txt b/src/SF_SPARSE/CMakeLists.txt new file mode 100644 index 000000000..7eb62d3d9 --- /dev/null +++ b/src/SF_SPARSE/CMakeLists.txt @@ -0,0 +1,9 @@ +# SF_SPARSE library +file(GLOB SF_SPARSE_LOCAL_SRC + SF_SPARSE_COMMON.f90 + SF_SPARSE_ARRAY_CSR.f90 + SF_SPARSE_ARRAY_CSC.f90 + SF_SPARSE.f90 + ) +SET(SF_SPARSE_src ${SF_SPARSE_LOCAL_SRC}) +ADD_LIBRARY(SF_SPARSELIB OBJECT ${SF_SPARSE_src}) diff --git a/src/SF_SPARSE/SF_SPARSE.f90 b/src/SF_SPARSE/SF_SPARSE.f90 new file mode 100644 index 000000000..6ab610cb1 --- /dev/null +++ b/src/SF_SPARSE/SF_SPARSE.f90 @@ -0,0 +1,21 @@ +MODULE SF_SPARSE + USE SF_LINALG, only: deye,zeye + USE SF_SPARSE_ARRAY_CSR + USE SF_SPARSE_ARRAY_CSC + private + + public :: sparse_dmatrix_csr, sparse_zmatrix_csr + public :: sparse_dmatrix_csc, sparse_zmatrix_csc + public :: assignment(=) + public :: operator(+) + public :: operator(-) + public :: operator(*) + public :: operator(/) + public :: operator(.x.) + public :: kron + public :: shape + public :: transpose + public :: hconjg + public :: matmul + +END MODULE SF_SPARSE diff --git a/src/SF_SPARSE/SF_SPARSE_ARRAY_ALGEBRA.f90 b/src/SF_SPARSE/SF_SPARSE_ARRAY_ALGEBRA.f90 new file mode 100644 index 000000000..c93010781 --- /dev/null +++ b/src/SF_SPARSE/SF_SPARSE_ARRAY_ALGEBRA.f90 @@ -0,0 +1,200 @@ +MODULE SF_SPARSE_ARRAY_ALGEBRA + USE SF_SPARSE_COMMON + USE SF_SPARSE_ARRAY_CSC + USE SF_SPARSE_ARRAY_CSR + implicit none + + interface matmul + module procedure :: dmatmul_csr_csr + module procedure :: zmatmul_csr_csr + ! + module procedure :: dmatmul_csc_csc + module procedure :: zmatmul_csc_csc + ! + module procedure :: dmatmul_csc_csr_2csr + module procedure :: zmatmul_csc_csr_2csr + ! + module procedure :: dmatmul_csc_csr_2csc + module procedure :: zmatmul_csc_csr_2csc + end interface matmul + + public :: matmul + + +contains + + function dmatmul_csr_csr(A,B) return(AxB) + type(sparse_dmatrix_csr), intent(in) :: A,B + type(sparse_dmatrix_csr) :: AxB + integer :: Na(2),Nb(2) + integer :: irow,j,jcol,k,kcol + real(8) :: aval,bval + + Na = A%shape(); Nb = B%shape() + if(Na(2)/=Nb(1))stop "Matrix not matching dimension in dmatmul_csr_csr" + call AxB%free() + call AxB%init(Na(1),Nb(2)) + do irow=1,Na(1) + do j=1,A%row(irow)%Size + jcol=A%row(irow)%cols(j) + aval=A%row(irow)%vals(j) + do k=1,B%row(jcol)%Size + kcol=B%row(jcol)%cols(k) + bval=B%row(jcol)%vals(k) + AxB%insert(aval*bval,irow,kcol) + end do + end do + end do + end function dmatmul_csr_csr + + + function zmatmul_csr_csr(A,B) return(AxB) + type(sparse_zmatrix_csr), intent(in) :: A,B + type(sparse_zmatrix_csr) :: AxB + integer :: Na(2),Nb(2) + integer :: irow,j,jcol,k,kcol + complex(8) :: aval,bval + + Na = A%shape(); Nb = B%shape() + if(Na(2)/=Nb(1))stop "Matrix not matching dimension in zmatmul_csr_csr" + call AxB%free() + call AxB%init(Na(1),Nb(2)) + do irow=1,Na(1) + do j=1,A%row(irow)%Size + jcol=A%row(irow)%cols(j) + aval=A%row(irow)%vals(j) + do k=1,B%row(jcol)%Size + kcol=B%row(jcol)%cols(k) + bval=B%row(jcol)%vals(k) + AxB%insert(aval*bval,irow,kcol) + end do + end do + end do + end function zmatmul_csr_csr + + + function dmatmul_csc_csc(A,B) return(AxB) + type(sparse_dmatrix_csc), intent(in) :: A,B + type(sparse_dmatrix_csc) :: AxB + integer :: Na(2),Nb(2) + integer :: icol,j,jrow,k,krow + real(8) :: aval,bval + + Na = A%shape(); Nb = B%shape() + if(Na(2)/=Nb(1))stop "Matrix not matching dimension in dmatmul_csc_csc" + call AxB%free() + call AxB%init(Na(1),Nb(2)) + do icol=1,Nb(2) + do j=1,B%col(icol)%Size + jrow=B%col(icol)%rows(j) + bval=B%col(icol)%vals(j) + do k=1,A%col(jrow)%Size + krow=A%col(jrow)%rows(k) + aval=A%col(jrow)%vals(k) + AxB%insert(aval*bval,krow,icol) + end do + end do + end do + end function dmatmul_csc_csc + + + + function dmatmul_csc_csr_2csc(A,B) return(AxB) + type(sparse_dmatrix_csc), intent(in) :: A,AxB + type(sparse_dmatrix_csr) :: B + integer :: Na(2),Nb(2) + integer :: icol,j,jrow,k,krow + real(8) :: aval,bval + + Na = A%shape(); Nb = B%shape() + if(Na(2)/=Nb(1))stop "Matrix not matching dimension in zmatmul_csc_csc" + call AxB%free() + call AxB%init(Na(1),Nb(2)) + do i=1,Na(2) + do j=1,A%col(i)%Size + jrow=A%col(i)%rows(j) + aval=A%col(i)%vals(j) + do k=1,B%row(i)%Size + kcol=B%row(i)%cols(k) + bval=B%row(i)%vals(k) + AxB%insert(aval*bval,jrow,kcol) + end do + end do + end do + end function zmatmul_csc_csr_2csc + + + function zmatmul_csc_csr_2csc(A,B) return(AxB) + type(sparse_zmatrix_csc), intent(in) :: A,AxB + type(sparse_zmatrix_csr) :: B + integer :: Na(2),Nb(2) + integer :: icol,j,jrow,k,krow + complex(8) :: aval,bval + + Na = A%shape(); Nb = B%shape() + if(Na(2)/=Nb(1))stop "Matrix not matching dimension in zmatmul_csc_csc" + call AxB%free() + call AxB%init(Na(1),Nb(2)) + do i=1,Na(2) + do j=1,A%col(i)%Size + jrow=A%col(i)%rows(j) + aval=A%col(i)%vals(j) + do k=1,B%row(i)%Size + kcol=B%row(i)%cols(k) + bval=B%row(i)%vals(k) + AxB%insert(aval*bval,jrow,kcol) + end do + end do + end do + end function zmatmul_csc_csr_2csc + + function dmatmul_csc_csr_2csr(A,B) return(AxB) + type(sparse_dmatrix_csc), intent(in) :: A + type(sparse_dmatrix_csr) :: B,AxB + integer :: Na(2),Nb(2) + integer :: icol,j,jrow,k,krow + real(8) :: aval,bval + + Na = A%shape(); Nb = B%shape() + if(Na(2)/=Nb(1))stop "Matrix not matching dimension in zmatmul_csc_csc" + call AxB%free() + call AxB%init(Na(1),Nb(2)) + do i=1,Na(2) + do j=1,A%col(i)%Size + jrow=A%col(i)%rows(j) + aval=A%col(i)%vals(j) + do k=1,B%row(i)%Size + kcol=B%row(i)%cols(k) + bval=B%row(i)%vals(k) + AxB%insert(aval*bval,jrow,kcol) + end do + end do + end do + end function dmatmul_csc_csr_2csr + + + function zmatmul_csc_csr_2csr(A,B) return(AxB) + type(sparse_zmatrix_csc), intent(in) :: A + type(sparse_zmatrix_csr) :: B,AxB + integer :: Na(2),Nb(2) + integer :: icol,j,jrow,k,krow + complex(8) :: aval,bval + + Na = A%shape(); Nb = B%shape() + if(Na(2)/=Nb(1))stop "Matrix not matching dimension in zmatmul_csc_csc" + call AxB%free() + call AxB%init(Na(1),Nb(2)) + do i=1,Na(2) + do j=1,A%col(i)%Size + jrow=A%col(i)%rows(j) + aval=A%col(i)%vals(j) + do k=1,B%row(i)%Size + kcol=B%row(i)%cols(k) + bval=B%row(i)%vals(k) + AxB%insert(aval*bval,jrow,kcol) + end do + end do + end do + end function zmatmul_csc_csr_2csr + +END MODULE SF_SPARSE_ARRAY_ALGEBRA diff --git a/src/SF_SPARSE/SF_SPARSE_ARRAY_COO.f90 b/src/SF_SPARSE/SF_SPARSE_ARRAY_COO.f90 new file mode 100644 index 000000000..34197a7f4 --- /dev/null +++ b/src/SF_SPARSE/SF_SPARSE_ARRAY_COO.f90 @@ -0,0 +1,595 @@ +MODULE SF_SPARSE_ARRAY_COO + USE SF_SPARSE_COMMON +#ifdef _MPI + USE MPI +#endif + implicit none + public :: sf_sparse_dmatrix_coo,sf_sparse_cmatrix_coo, sf_init_matrix_coo, sf_delete_matrix_coo, sf_insert_element_coo, sf_dump_matrix_coo + +!COO MATRIX + type sf_sparse_dmatrix_coo + integer,dimension(:),allocatable :: rows + integer,dimension(:),allocatable :: cols + real(8),dimension(:),allocatable :: vals + integer :: Size + integer :: Nrow + integer :: Ncol + logical :: status=.false. +! #ifdef _MPI +! type(sf_sparse_drow_coo),dimension(:),pointer :: loc +! integer :: istart=0 !global start index for MPI storage +! integer :: iend=0 +! integer :: ishift=0 +! logical :: mpi=.false. +! #endif + end type sf_sparse_dmatrix_coo + + type sf_sparse_cmatrix_coo + integer,dimension(:),allocatable :: rows + integer,dimension(:),allocatable :: cols + complex(8),dimension(:),allocatable :: vals + integer :: Size + integer :: Nrow + integer :: Ncol + logical :: status=.false. +! #ifdef _MPI +! type(sf_sparse_crow_coo),dimension(:),pointer :: loc +! integer :: istart=0 !global start index for MPI storage +! integer :: iend=0 +! integer :: ishift=0 +! logical :: mpi=.false. +! #endif + end type sf_sparse_cmatrix_coo + + !INIT SPARSE MATRICES + interface sf_init_matrix_coo + module procedure :: sf_init_dmatrix_coo + module procedure :: sf_init_cmatrix_coo +! #ifdef _MPI +! module procedure :: mpi_sf_init_dmatrix_coo +! module procedure :: mpi_sf_init_cmatrix_coo +! #endif + end interface sf_init_matrix_coo + + !DELETE SPARSE MATRIX + interface sf_delete_matrix_coo + module procedure :: sf_delete_dmatrix_coo + module procedure :: sf_delete_cmatrix_coo +! #ifdef _MPI +! module procedure :: mpi_sf_delete_dmatrix_coo +! module procedure :: mpi_sf_delete_cmatrix_coo +! #endif + end interface sf_delete_matrix_coo + + + !INSERT ELEMENTS + interface sf_insert_element_coo + module procedure :: sf_insert_delement_coo + module procedure :: sf_insert_celement_coo +! #ifdef _MPI +! module procedure :: mpi_sf_insert_delement_coo +! module procedure :: mpi_sf_insert_celement_coo +! #endif + end interface sf_insert_element_coo + + + !DUMP SPARSE MATRIX INTO STANDARD MATRIX + interface sf_dump_matrix_coo + module procedure :: sf_dump_dmatrix_coo + module procedure :: sf_dump_cmatrix_coo +! #ifdef _MPI +! module procedure :: mpi_sf_dump_matrix_coo +! module procedure :: mpi_sf_dump_matrix_coo +! #endif + end interface sf_dump_matrix_coo + +contains + !+------------------------------------------------------------------+ + !PURPOSE: initialize the sparse matrix list + !+------------------------------------------------------------------+ + subroutine sf_init_dmatrix_coo(sparse,N,N1) + type(sf_sparse_dmatrix_coo),intent(inout) :: sparse + integer :: N + integer,optional :: N1 + integer :: i + ! +#ifdef _DEBUG + write(*,"(A)")"DEBUG sf_init_dmatrix_coo: allocate sparse" +#endif + !put here a delete statement to avoid problems + if(sparse%status)stop "sf_init_dmatrix_coo: already allocated can not init" + ! + sparse%Nrow=N + sparse%Ncol=N + sparse%Size=0 + if(present(N1))sparse%Ncol=N1 + ! + allocate(sparse%rows(0)) + allocate(sparse%cols(0)) + allocate(sparse%vals(0)) + ! + sparse%status=.true. + ! + end subroutine sf_init_dmatrix_coo + +subroutine sf_init_cmatrix_coo(sparse,N,N1) + type(sf_sparse_cmatrix_coo),intent(inout) :: sparse + integer :: N + integer,optional :: N1 + integer :: i + ! +#ifdef _DEBUG + write(*,"(A)")"DEBUG sf_init_cmatrix_coo: allocate sparse" +#endif + !put here a delete statement to avoid problems + if(sparse%status)stop "sf_init_cmatrix_coo: already allocated can not init" + ! + sparse%Nrow=N + sparse%Ncol=N + sparse%Size=0 + if(present(N1))sparse%Ncol=N1 + ! + allocate(sparse%rows(0)) + allocate(sparse%cols(0)) + allocate(sparse%vals(0)) + ! + sparse%status=.true. + ! + end subroutine sf_init_cmatrix_coo + + + +! #ifdef _MPI +! subroutine mpi_sf_init_dmatrix_coo(MpiComm,sparse,N,N1) +! integer :: MpiComm +! type(sf_sparse_dmatrix_coo),intent(inout) :: sparse +! integer :: N +! integer,optional :: N1 +! integer :: i,Ncol,Nloc +! ! +! #ifdef _DEBUG +! write(*,"(A)")"DEBUG MPI_sf_init_dmatrix_coo: allocate sparse" +! #endif +! if(MpiComm==Mpi_Comm_Null)return +! ! +! call sf_test_matrix_mpi(MpiComm,sparse,"mpi_sf_init_dmatrix_coo") +! ! +! Ncol = N +! if(present(N1))Ncol=N1 +! ! +! Nloc = sparse%iend-sparse%istart+1 +! ! +! call sf_init_matrix_coo(sparse,Nloc,Ncol) +! ! +! allocate(sparse%loc(Nloc)) +! do i=1,Nloc +! sparse%loc(i)%size=0 +! allocate(sparse%loc(i)%vals(0)) !empty array +! allocate(sparse%loc(i)%cols(0)) !empty array +! end do +! ! +! end subroutine mpi_sf_init_dmatrix_coo + +! subroutine mpi_sf_init_cmatrix_coo(MpiComm,sparse,N,N1) +! integer :: MpiComm +! type(sf_sparse_cmatrix_coo),intent(inout) :: sparse +! integer :: N +! integer,optional :: N1 +! integer :: i,Ncol,Nloc +! ! +! #ifdef _DEBUG +! write(*,"(A)")"DEBUG MPI_sf_init_cmatrix_coo: allocate sparse" +! #endif +! if(MpiComm==Mpi_Comm_Null)return +! ! +! call sf_test_matrix_mpi(MpiComm,sparse,"mpi_sf_init_cmatrix_coo") +! ! +! Ncol = N +! if(present(N1))Ncol=N1 +! ! +! Nloc = sparse%iend-sparse%istart+1 +! ! +! call sf_init_matrix_coo(sparse,Nloc,Ncol) +! ! +! allocate(sparse%loc(Nloc)) +! do i=1,Nloc +! sparse%loc(i)%size=0 +! allocate(sparse%loc(i)%vals(0)) !empty array +! allocate(sparse%loc(i)%cols(0)) !empty array +! end do +! ! +! end subroutine mpi_sf_init_cmatrix_coo +! #endif + + + !+------------------------------------------------------------------+ + !PURPOSE: delete an entire sparse matrix + !+------------------------------------------------------------------+ + subroutine sf_delete_dmatrix_coo(sparse) + type(sf_sparse_dmatrix_coo),intent(inout) :: sparse + integer :: i + ! +#ifdef _DEBUG + write(*,"(A)")"DEBUG sf_delete_dmatrix_coo: delete sparse" +#endif + if(.not.sparse%status)return !stop "Error SPARSE/sf_delete_matrix: sparse is not allocated." + ! + deallocate(sparse%rows) + deallocate(sparse%cols) + deallocate(sparse%vals) + ! + sparse%Nrow=0 + sparse%Ncol=0 + sparse%Size=0 + sparse%status=.false. + end subroutine sf_delete_dmatrix_coo + + subroutine sf_delete_cmatrix_coo(sparse) + type(sf_sparse_cmatrix_coo),intent(inout) :: sparse + integer :: i + ! +#ifdef _DEBUG + write(*,"(A)")"DEBUG sf_delete_cmatrix_coo: delete sparse" +#endif + if(.not.sparse%status)return !stop "Error SPARSE/sf_delete_matrix: sparse is not allocated." + ! + deallocate(sparse%rows) + deallocate(sparse%cols) + deallocate(sparse%vals) + ! + sparse%Nrow=0 + sparse%Ncol=0 + sparse%Size=0 + sparse%status=.false. + end subroutine sf_delete_cmatrix_coo + + + +! #ifdef _MPI +! subroutine mpi_sf_delete_dmatrix_coo(MpiComm,sparse) +! integer :: MpiComm +! type(sf_sparse_dmatrix_coo),intent(inout) :: sparse +! integer :: i +! type(sf_sparse_drow_coo),pointer :: row +! ! +! #ifdef _DEBUG +! write(*,"(A)")"DEBUG MPI_sf_delete_dmatrix_coo: delete sparse" +! #endif +! if(.not.sparse%status)return !stop "Error SPARSE/mpi_sp_delete_matrix: sparse is not allocated." +! ! +! do i=1,sparse%Nrow +! deallocate(sparse%row(i)%vals) +! deallocate(sparse%row(i)%cols) +! sparse%row(i)%Size = 0 +! ! +! deallocate(sparse%loc(i)%vals) +! deallocate(sparse%loc(i)%cols) +! sparse%loc(i)%Size = 0 +! enddo +! deallocate(sparse%row) +! deallocate(sparse%loc) +! ! +! sparse%Nrow=0 +! sparse%Ncol=0 +! sparse%status=.false. +! ! +! sparse%istart=0 +! sparse%iend=0 +! sparse%ishift=0 +! sparse%mpi=.false. +! ! +! end subroutine mpi_sf_delete_dmatrix_coo + +! subroutine mpi_sf_delete_cmatrix_coo(MpiComm,sparse) +! integer :: MpiComm +! type(sf_sparse_cmatrix_coo),intent(inout) :: sparse +! integer :: i +! type(sf_sparse_crow_coo),pointer :: row +! ! +! #ifdef _DEBUG +! write(*,"(A)")"DEBUG MPI_sf_delete_cmatrix_coo: delete sparse" +! #endif +! if(.not.sparse%status)return !stop "Error SPARSE/mpi_sp_delete_matrix: sparse is not allocated." +! ! +! do i=1,sparse%Nrow +! deallocate(sparse%row(i)%vals) +! deallocate(sparse%row(i)%cols) +! sparse%row(i)%Size = 0 +! ! +! deallocate(sparse%loc(i)%vals) +! deallocate(sparse%loc(i)%cols) +! sparse%loc(i)%Size = 0 +! enddo +! deallocate(sparse%row) +! deallocate(sparse%loc) +! ! +! sparse%Nrow=0 +! sparse%Ncol=0 +! sparse%status=.false. +! ! +! sparse%istart=0 +! sparse%iend=0 +! sparse%ishift=0 +! sparse%mpi=.false. +! ! +! end subroutine mpi_sf_delete_cmatrix_coo +! #endif + + + !+------------------------------------------------------------------+ + !PURPOSE: insert an element value at position (i,j) in the sparse matrix + !+------------------------------------------------------------------+ + subroutine sf_insert_delement_coo(sparse,value,i,j) + type(sf_sparse_dmatrix_coo),intent(inout) :: sparse + real(8),intent(in) :: value + integer,intent(in) :: i,j + integer :: k + logical :: present + ! +#ifdef _DEBUG + write(*,"(A,2I8)")"DEBUG sf_insert_delement_coo: insert element in sparse @",i,j +#endif + ! + present=.false. + do k=1,sparse%Size !Find position if present + if( (i==sparse%rows(k)).and.(j==sparse%cols(k)))then + present=.true. + exit + end if + end do + ! + if(present)then ! Add if present + sparse%vals(k) = sparse%vals(k) + value ! + else + call add_to(sparse%rows,i) + call add_to(sparse%cols,j) + call add_to(sparse%vals,value) + sparse%Size = sparse%Size +1 + endif + ! + if(sparse%Size > sparse%Ncol*sparse%Nrow)stop "sf_insert_delement_coo ERROR: sparse%Size > sparse%Ncol*sparse%Nrow" + ! + end subroutine sf_insert_delement_coo + + subroutine sf_insert_celement_coo(sparse,value,i,j) + type(sf_sparse_cmatrix_coo),intent(inout) :: sparse + complex(8),intent(in) :: value + integer,intent(in) :: i,j + integer :: k + logical :: present + ! +#ifdef _DEBUG + write(*,"(A,2I8)")"DEBUG sf_insert_celement_coo: insert element in sparse @",i,j +#endif + ! + present=.false. + do k=1,sparse%Size !Find position if present + if( (i==sparse%rows(k)).and.(j==sparse%cols(k)))then + present=.true. + exit + end if + end do + ! + if(present)then ! Add if present + sparse%vals(k) = sparse%vals(k) + value ! + else + call add_to(sparse%rows,i) + call add_to(sparse%cols,j) + call add_to(sparse%vals,value) + sparse%Size = sparse%Size +1 + endif + ! + if(sparse%Size > sparse%Ncol*sparse%Nrow)stop "sf_insert_celement_coo ERROR: sparse%Size > sparse%Ncol*sparse%Nrow" + ! + end subroutine sf_insert_celement_coo + +! #ifdef _MPI +! subroutine mpi_sf_insert_delement_coo(MpiComm,sparse,value,i,j) +! integer :: MpiComm +! type(sf_sparse_dmatrix_coo),intent(inout) :: sparse +! real(8),intent(in) :: value +! integer,intent(in) :: i,j +! type(sf_sparse_drow_coo),pointer :: row +! integer :: column,pos +! logical :: iadd +! ! +! #ifdef _DEBUG +! write(*,"(A,2I8)")"DEBUG MPI_sf_insert_delement_coo: insert element in sparse @",i,j +! #endif +! ! +! if(MpiComm==Mpi_Comm_Null)return +! ! +! call sp_test_matrix_mpi(MpiComm,sparse," mpi_sf_insert_delement_coo") +! ! +! column = j +! ! +! row => sparse%row(i-sparse%Ishift) +! ! +! iadd = .false. !check if column already exist +! if(any(row%cols == column))then ! +! pos = binary_search(row%cols,column) !find the position column in %cols +! iadd=.true. !set Iadd to true +! endif +! ! +! if(iadd)then !this column exists so just sum it up +! row%vals(pos)=row%vals(pos) + value !add up value to the current one in %vals +! else !this column is new. increase counter and store it +! call add_to(row%vals,value) +! call add_to(row%cols,column) +! row%Size = row%Size + 1 +! endif +! ! +! if(row%Size > sparse%Ncol)stop "mpi_sp_insert_element_coo ERROR: row%Size > sparse%Ncol" +! ! +! end subroutine mpi_sf_insert_delement_coo + +! subroutine mpi_sf_insert_celement_coo(MpiComm,sparse,value,i,j) +! integer :: MpiComm +! type(sf_sparse_cmatrix_coo),intent(inout) :: sparse +! complex(8),intent(in) :: value +! integer,intent(in) :: i,j +! type(sf_sparse_crow_coo),pointer :: row +! integer :: column,pos +! logical :: iadd +! ! +! #ifdef _DEBUG +! write(*,"(A,2I8)")"DEBUG MPI_sf_insert_celement_coo: insert element in sparse @",i,j +! #endif +! ! +! call sp_test_matrix_mpi(MpiComm,sparse," mpi_sf_insert_celement_coo") +! ! +! column = j +! ! +! if(column>=sparse%Istart.AND.column<=sparse%Iend)then +! row => sparse%loc(i-sparse%Ishift) +! else +! row => sparse%row(i-sparse%Ishift) +! endif +! ! +! iadd = .false. !check if column already exist +! if(any(row%cols == column))then ! +! pos = binary_search(row%cols,column) !find the position column in %cols +! iadd=.true. !set Iadd to true +! endif +! ! +! if(iadd)then !this column exists so just sum it up +! row%vals(pos)=row%vals(pos) + value !add up value to the current one in %vals +! else !this column is new. increase counter and store it +! call add_to(row%vals,value) +! call add_to(row%cols,column) +! row%Size = row%Size + 1 +! endif +! ! +! if(row%Size > sparse%Ncol)stop "mpi_sp_insert_element_coo ERROR: row%Size > sparse%Ncol" +! ! +! end subroutine mpi_sf_insert_celement_coo +! #endif + + !+------------------------------------------------------------------+ + !PURPOSE: dump a sparse matrix into a regular 2dim array + !+------------------------------------------------------------------+ + subroutine sf_dump_dmatrix_coo(sparse,matrix) + type(sf_sparse_dmatrix_coo),intent(in) :: sparse + real(8),dimension(:,:),intent(inout) :: matrix + real(8) :: val + integer :: i,col,row,Ndim1,Ndim2 + ! +#ifdef _DEBUG + write(*,"(A)")"DEBUG sf_dump_dmatrix_coo: dump sparse" +#endif + ! + Ndim1=size(matrix,1) + Ndim2=size(matrix,2) + ! + if(sparse%Nrow/=Ndim1 .OR. sparse%Ncol/=Ndim2)stop "Warning SPARSE/dump_matrix: dimensions error" + ! + do i=1,sparse%Size + row=sparse%rows(i); col=sparse%cols(i) + matrix(row,col) = matrix(row,col) + sparse%vals(i) + enddo + end subroutine sf_dump_dmatrix_coo + + subroutine sf_dump_cmatrix_coo(sparse,matrix) + type(sf_sparse_cmatrix_coo),intent(in) :: sparse + complex(8),dimension(:,:),intent(inout) :: matrix + complex(8) :: vals + integer :: i,col,row,Ndim1,Ndim2 + ! +#ifdef _DEBUG + write(*,"(A)")"DEBUG sf_dump_cmatrix_coo: dump sparse" +#endif + ! + Ndim1=size(matrix,1) + Ndim2=size(matrix,2) + ! + if(sparse%Nrow/=Ndim1 .OR. sparse%Ncol/=Ndim2)stop "Warning SPARSE/dump_matrix: dimensions error" + ! + do i=1,sparse%Size + row=sparse%rows(i); col=sparse%cols(i) + matrix(row,col) = matrix(row,col) + sparse%vals(i) + enddo + end subroutine sf_dump_cmatrix_coo + +! #ifdef _MPI +! subroutine mpi_sf_dump_dmatrix_coo(MpiComm,sparse,matrix) +! integer :: MpiComm +! type(sf_sparse_dmatrix_coo),intent(in) :: sparse +! real(8),dimension(:,:),intent(inout) :: matrix +! real(8),dimension(:,:),allocatable :: matrix_tmp +! integer :: i,impi,j,N1_,N2_,Ndim1,Ndim2,Nrow,Ncol +! ! +! #ifdef _DEBUG +! write(*,"(A)")"DEBUG MPI_sf_dump_dmatrix_coo: dump sparse" +! #endif +! ! +! call sp_test_matrix_mpi(MpiComm,sparse," mpi_sf_dump_dmatrix_coo") +! ! +! Ndim1=size(matrix,1) +! Ndim2=size(matrix,2) +! ! +! N1_ = sparse%Nrow +! N2_ = sparse%Ncol +! Nrow = 0 +! Ncol = 0 +! call MPI_AllReduce(N1_,Nrow,1,MPI_Integer,MPI_SUM,MpiComm,MpiIerr) +! call MPI_AllReduce(N2_,Ncol,1,MPI_Integer,MPI_MAX,MpiComm,MpiIerr) +! ! +! if(Nrow>Ndim1 .OR. Ncol>Ndim2)stop "Warning SPARSE/mpi_dump_matrix: dimensions error" +! ! +! allocate(matrix_tmp(Ndim1,Ndim2)) ; matrix_tmp=0d0 +! do i=sparse%Istart,sparse%Iend +! impi = i - sparse%Ishift +! do j=1,sparse%row(impi)%Size +! matrix_tmp(i,sparse%row(impi)%cols(j))=matrix_tmp(i,sparse%row(impi)%cols(j))+sparse%row(impi)%vals(j) +! enddo +! enddo +! ! +! call AllReduce_MPI(MpiCOmm,Matrix_tmp,Matrix) +! ! +! end subroutine mpi_sf_dump_dmatrix_coo + +! subroutine mpi_sf_dump_cmatrix_coo(MpiComm,sparse,matrix) +! integer :: MpiComm +! type(sf_sparse_cmatrix_coo),intent(in) :: sparse +! complex(8),dimension(:,:),intent(inout) :: matrix +! complex(8),dimension(:,:),allocatable :: matrix_tmp +! integer :: i,impi,j,N1_,N2_,Ndim1,Ndim2,Nrow,Ncol +! ! +! #ifdef _DEBUG +! write(*,"(A)")"DEBUG MPI_sf_dump_cmatrix_coo: dump sparse" +! #endif +! ! +! call sp_test_matrix_mpi(MpiComm,sparse," mpi_sf_dump_cmatrix_coo") +! ! +! Ndim1=size(matrix,1) +! Ndim2=size(matrix,2) +! ! +! N1_ = sparse%Nrow +! N2_ = sparse%Ncol +! Nrow = 0 +! Ncol = 0 +! call MPI_AllReduce(N1_,Nrow,1,MPI_Integer,MPI_SUM,MpiComm,MpiIerr) +! call MPI_AllReduce(N2_,Ncol,1,MPI_Integer,MPI_MAX,MpiComm,MpiIerr) +! ! +! if(Nrow>Ndim1 .OR. Ncol>Ndim2)stop "Warning SPARSE/mpi_dump_matrix: dimensions error" +! ! +! allocate(matrix_tmp(Ndim1,Ndim2)) ; matrix_tmp=zero +! do i=sparse%Istart,sparse%Iend +! impi = i - sparse%Ishift +! !Local part: +! do j=1,sparse%loc(impi)%Size +! matrix_tmp(i,sparse%loc(impi)%cols(j))=matrix_tmp(i,sparse%loc(impi)%cols(j))+sparse%loc(impi)%vals(j) +! enddo +! ! +! !Non-local part: +! do j=1,sparse%row(impi)%Size +! matrix_tmp(i,sparse%row(impi)%cols(j))=matrix_tmp(i,sparse%row(impi)%cols(j))+sparse%row(impi)%cvals(j) +! enddo +! enddo +! ! +! call AllReduce_MPI(MpiCOmm,Matrix_tmp,Matrix) +! ! +! end subroutine mpi_sf_dump_cmatrix_coo +! #endif + +END MODULE SF_SPARSE_ARRAY_COO diff --git a/src/SF_SPARSE/SF_SPARSE_ARRAY_CSC.f90 b/src/SF_SPARSE/SF_SPARSE_ARRAY_CSC.f90 new file mode 100644 index 000000000..378c055ff --- /dev/null +++ b/src/SF_SPARSE/SF_SPARSE_ARRAY_CSC.f90 @@ -0,0 +1,1197 @@ +MODULE SF_SPARSE_ARRAY_CSC + USE SF_LINALG, only: deye,zeye + USE SF_SPARSE_COMMON + !MPI STILL TO BE DONE +#ifdef _MPI + USE MPI +#endif + implicit none + + private + !CSC COLS + type sparse_col_csc + integer :: size + integer,dimension(:),allocatable :: rows + end type sparse_col_csc + ! + type, extends(sparse_col_csc) :: sparse_dcol_csc + real(8),dimension(:),allocatable :: vals + end type sparse_dcol_csc + ! + type, extends(sparse_col_csc) :: sparse_zcol_csc + complex(8),dimension(:),allocatable :: vals + end type sparse_zcol_csc + + type, extends(sparse_matrix) :: sparse_dmatrix_csc + type(sparse_dcol_csc),dimension(:),allocatable :: col + contains + procedure,pass :: init => init_dmatrix_csc + procedure,pass :: free => free_dmatrix_csc + procedure,pass :: load => load_dmatrix_csc + procedure,pass :: dump => dump_dmatrix_csc + procedure,pass :: insert => insert_delement_csc + procedure,pass :: get => get_delement_csc + procedure,pass :: as_matrix => as_dmatrix_csc + procedure,pass :: dgr => dgr_dmatrix_csc + procedure,pass :: transpose => transpose_dmatrix_csc + end type sparse_dmatrix_csc + + type, extends(sparse_matrix) :: sparse_zmatrix_csc + type(sparse_zcol_csc),dimension(:),allocatable :: col + contains + procedure,pass :: init => init_zmatrix_csc + procedure,pass :: free => free_zmatrix_csc + procedure,pass :: load => load_zmatrix_csc + procedure,pass :: dump => dump_zmatrix_csc + procedure,pass :: insert => insert_zelement_csc + procedure,pass :: get => get_zelement_csc + procedure,pass :: as_matrix => as_zmatrix_csc + procedure,pass :: dgr => dgr_zmatrix_csc + procedure,pass :: transpose => transpose_zmatrix_csc + procedure,pass :: conjg => conjg_zmatrix_csc + end type sparse_zmatrix_csc + + + + interface sparse_matrix + module procedure :: construct_dmatrix_csc + module procedure :: construct_zmatrix_csc + end interface sparse_matrix + ! + interface as_sparse + module procedure :: construct_dmatrix_csc + module procedure :: construct_zmatrix_csc + end interface as_sparse + ! + interface sparse + module procedure :: construct_dmatrix_csc + module procedure :: construct_zmatrix_csc + end interface sparse + + !EQUALITY with scalar and function (A=B, A=cmplx) + interface assignment(=) + module procedure :: dmatrix_equal_scalar_csc + module procedure :: dmatrix_equal_dmatrix_csc + module procedure :: zmatrix_equal_scalar_csc + module procedure :: zmatrix_equal_zmatrix_csc + end interface assignment(=) + + !ADDITION + interface operator (+) + module procedure :: plus_dmatrix_csc + module procedure :: plus_zmatrix_csc + end interface operator (+) + + !SUBTRACTION + interface operator (-) + module procedure :: minus_dmatrix_csc + module procedure :: minus_zmatrix_csc + end interface operator (-) + + !SCALAR PRODUCT + interface operator(*) + module procedure :: left_product_dmatrix_i_csc + module procedure :: left_product_dmatrix_d_csc + module procedure :: left_product_zmatrix_i_csc + module procedure :: left_product_zmatrix_d_csc + module procedure :: left_product_zmatrix_z_csc + ! + module procedure :: right_product_dmatrix_i_csc + module procedure :: right_product_dmatrix_d_csc + module procedure :: right_product_zmatrix_i_csc + module procedure :: right_product_zmatrix_d_csc + module procedure :: right_product_zmatrix_z_csc + end interface operator(*) + + !SCALAR DIVISION + interface operator(/) + module procedure :: right_division_dmatrix_i_csc + module procedure :: right_division_dmatrix_d_csc + module procedure :: right_division_zmatrix_i_csc + module procedure :: right_division_zmatrix_d_csc + module procedure :: right_division_zmatrix_z_csc + end interface operator(/) + + !MATRIX PRODUCT + interface matmul + module procedure :: left_matmul_dmatrix_darray_csc + module procedure :: left_matmul_zmatrix_zarray_csc + end interface matmul + + + !KRONECKER PRODUCT + interface operator(.x.) + module procedure :: kron_dmatrix_csc + module procedure :: kron_zmatrix_csc + end interface operator(.x.) + + interface sp_kron + module procedure :: restricted_kron_dmatrix_csc + module procedure :: restricted_kron_zmatrix_csc + end interface sp_kron + + interface transpose + module procedure :: transpose_dmatrix_csc + module procedure :: transpose_zmatrix_csc + end interface transpose + + interface hconjg + module procedure :: dgr_dmatrix_csc + module procedure :: dgr_zmatrix_csc + end interface hconjg + + public :: sparse_dmatrix_csc, sparse_zmatrix_csc + public :: as_sparse + public :: sparse + public :: assignment(=) + public :: operator(+) + public :: operator(-) + public :: operator(*) + public :: operator(/) + public :: operator(.x.) + public :: sp_kron + public :: transpose + public :: hconjg + public :: matmul + + + +contains + + !+------------------------------------------------------------------+ + !PURPOSE: initialize the sparse matrix list + ! init: empty matrix of dimenson (N,N1) + ! constructor: dump a dense matrix into the sparse + !+------------------------------------------------------------------+ + !REAL + elemental subroutine init_dmatrix_csc(sparse,N,N1) + class(sparse_dmatrix_csc),intent(inout) :: sparse + integer,intent(in) :: N + integer,intent(in),optional :: N1 + integer :: i + ! + !put here a delete statement to avoid problems + if(sparse%status)call sparse%free() + sparse%Nrow=N + sparse%Ncol=N + if(present(N1))sparse%Ncol=N1 + ! + allocate(sparse%col(sparse%Ncol)) + do i=1,sparse%Ncol + sparse%col(i)%size=0 + allocate(sparse%col(i)%vals(0)) !empty array + allocate(sparse%col(i)%rows(0)) !empty array + end do + ! + sparse%status=.true. + ! + end subroutine init_dmatrix_csc + ! + function construct_dmatrix_csc(matrix) result(self) + real(8),dimension(:,:),intent(in) :: matrix + type(sparse_dmatrix_csc) :: self + call self%load(matrix) + end function construct_dmatrix_csc + ! + subroutine load_dmatrix_csc(sparse,matrix) + class(sparse_dmatrix_csc),intent(inout) :: sparse + real(8),dimension(:,:),intent(in) :: matrix + integer :: i,j,Ndim1,Ndim2 + ! + call sparse%free() + Ndim1=size(matrix,1) + Ndim2=size(matrix,2) + ! + call sparse%init(Ndim1,Ndim2) + do j=1,Ndim2 + do i=1,Ndim1 + if(matrix(i,j)/=0d0)call insert_delement_csc(sparse,matrix(i,j),i,j) + enddo + enddo + end subroutine load_dmatrix_csc + ! + !COMPLEX + elemental subroutine init_zmatrix_csc(sparse,N,N1) + class(sparse_zmatrix_csc),intent(inout) :: sparse + integer,intent(in) :: N + integer,intent(in),optional :: N1 + integer :: i + ! + !put here a delete statement to avoid problems + if(sparse%status)call sparse%free() + ! + sparse%Nrow=N + sparse%Ncol=N + if(present(N1))sparse%Ncol=N1 + ! + allocate(sparse%col(sparse%Ncol)) + do i=1,sparse%Ncol + sparse%col(i)%size=0 + allocate(sparse%col(i)%vals(0)) !empty array + allocate(sparse%col(i)%rows(0)) !empty array + end do + ! + sparse%status=.true. + ! + end subroutine init_zmatrix_csc + ! + function construct_zmatrix_csc(matrix) result(self) + complex(8),dimension(:,:),intent(in) :: matrix + type(sparse_zmatrix_csc) :: self + call self%load(matrix) + end function construct_zmatrix_csc + ! + subroutine load_zmatrix_csc(sparse,matrix) + class(sparse_zmatrix_csc),intent(inout) :: sparse + complex(8),dimension(:,:),intent(in) :: matrix + integer :: i,j,Ndim1,Ndim2 + ! + call sparse%free() + Ndim1=size(matrix,1) + Ndim2=size(matrix,2) + ! + call sparse%init(Ndim1,Ndim2) + do j=1,Ndim2 + do i=1,Ndim1 + if(matrix(i,j)/=0d0)call insert_zelement_csc(sparse,matrix(i,j),i,j) + enddo + enddo + end subroutine load_zmatrix_csc + + !+------------------------------------------------------------------+ + !PURPOSE: frees a sparse matrix + !+------------------------------------------------------------------+ + !REAL + elemental subroutine free_dmatrix_csc(sparse) + class(sparse_dmatrix_csc),intent(inout) :: sparse + integer :: i + ! + do i=1,sparse%Ncol + sparse%col(i)%Size = 0 + if(allocated(sparse%col(i)%vals))deallocate(sparse%col(i)%vals) + if(allocated(sparse%col(i)%rows))deallocate(sparse%col(i)%rows) + enddo + if(allocated(sparse%col))deallocate(sparse%col) + ! + sparse%Nrow=0 + sparse%Ncol=0 + sparse%Nelements=0 + sparse%status=.false. + end subroutine free_dmatrix_csc + ! + !COMPLEX + elemental subroutine free_zmatrix_csc(sparse) + class(sparse_zmatrix_csc),intent(inout) :: sparse + integer :: i + ! + do i=1,sparse%Ncol + sparse%col(i)%Size = 0 + if(allocated(sparse%col(i)%vals))deallocate(sparse%col(i)%vals) + if(allocated(sparse%col(i)%rows))deallocate(sparse%col(i)%rows) + enddo + if(allocated(sparse%col))deallocate(sparse%col) + ! + sparse%Nrow=0 + sparse%Ncol=0 + sparse%Nelements=0 + sparse%status=.false. + end subroutine free_zmatrix_csc + + + + !+------------------------------------------------------------------+ + !PURPOSE: insert an element value at position (i,j) in the sparse matrix + !+------------------------------------------------------------------+ + !REAL + subroutine insert_delement_csc(sparse,value,i,j) + class(sparse_dmatrix_csc),intent(inout) :: sparse + real(8),intent(in) :: value + integer,intent(in) :: i,j + integer :: row,pos + logical :: iadd + ! + row = i + ! + iadd = .false. !check if column already exist + if(any(sparse%col(j)%rows == row))then ! + pos = binary_search(sparse%col(j)%rows,row) !find the position column in %cols + iadd=.true. !set Iadd to true + endif + ! + if(iadd)then !this column exists so just sum it up + sparse%col(j)%vals(pos)=sparse%col(j)%vals(pos) + value !add up value to the current one in %vals + else !this column is new. increase counter and store it + call append(sparse%col(j)%vals,value) + call append(sparse%col(j)%rows,row) + sparse%col(j)%Size = sparse%col(j)%Size + 1 + sparse%Nelements = sparse%Nelements+1 + endif + ! + if(sparse%col(j)%Size > sparse%Nrow)stop "insert_delement_csc ERROR: row%Size > sparse%Ncol" + end subroutine insert_delement_csc + ! + !COMPLEX + subroutine insert_zelement_csc(sparse,value,i,j) + class(sparse_zmatrix_csc),intent(inout) :: sparse + complex(8),intent(in) :: value + integer,intent(in) :: i,j + integer :: row,pos + logical :: iadd + ! + ! + row = i + ! + iadd = .false. !check if column already exist + if(any(sparse%col(j)%rows == row))then ! + pos = binary_search(sparse%col(j)%rows,row) !find the position column in %cols + iadd=.true. !set Iadd to true + endif + ! + if(iadd)then !this column exists so just sum it up + sparse%col(j)%vals(pos)=sparse%col(j)%vals(pos) + value !add up value to the current one in %vals + else !this column is new. increase counter and store it + call append(sparse%col(j)%vals,value) + call append(sparse%col(j)%rows,row) + sparse%col(j)%Size = sparse%col(j)%Size + 1 + sparse%Nelements = sparse%Nelements+1 + endif + ! + if(sparse%col(j)%Size > sparse%Nrow)stop "insert_zelement_csc ERROR: row%Size > sparse%Ncol" + ! + end subroutine insert_zelement_csc + + !+------------------------------------------------------------------+ + !PURPOSE: get the element value at position (i,j) in the sparse matrix + !+------------------------------------------------------------------+ + function get_delement_csc(sparse,i,j) result(value) + class(sparse_dmatrix_csc),intent(inout) :: sparse + integer,intent(in) :: i,j + real(8) :: value + integer :: pos + value=0d0 + do pos=1,sparse%col(j)%size + if(i==sparse%col(j)%rows(pos))value=sparse%col(j)%vals(pos) + enddo + end function get_delement_csc + + function get_zelement_csc(sparse,i,j) result(value) + class(sparse_zmatrix_csc),intent(inout) :: sparse + integer,intent(in) :: i,j + complex(8) :: value + integer :: pos + value=0d0 + do pos=1,sparse%col(j)%size + if(i==sparse%col(j)%rows(pos))value=sparse%col(j)%vals(pos) + enddo + end function get_zelement_csc + + + + + + !+------------------------------------------------------------------+ + !PURPOSE: dump a sparse matrix into a regular 2dim array summing elements + !+------------------------------------------------------------------+ + !REAL + subroutine dump_dmatrix_csc(sparse,matrix) + class(sparse_dmatrix_csc),intent(in) :: sparse + real(8),dimension(:,:),intent(inout) :: matrix + integer :: i,j,Ndim1,Ndim2 + ! + ! + Ndim1=size(matrix,1); Ndim2=size(matrix,2) + ! + if(sparse%Nrow/=Ndim1 .OR. sparse%Ncol/=Ndim2)stop "Warning SPARSE/dump_dmatrix: dimensions error" + ! + do j=1,Ndim2 + do i=1,sparse%col(j)%Size + matrix(sparse%col(j)%rows(i),j) = matrix(sparse%col(j)%rows(i),j) + sparse%col(j)%vals(i) + enddo + enddo + end subroutine dump_dmatrix_csc + ! + !COMPLEX + subroutine dump_zmatrix_csc(sparse,matrix) + class(sparse_zmatrix_csc),intent(in) :: sparse + complex(8),dimension(:,:),intent(inout) :: matrix + integer :: i,j,Ndim1,Ndim2 + ! + ! + Ndim1=size(matrix,1); Ndim2=size(matrix,2) + ! + if(sparse%Nrow/=Ndim1 .OR. sparse%Ncol/=Ndim2)stop "Warning SPARSE/dump_zmatrix: dimensions error" + ! + matrix=0.d0 + do j=1,Ndim2 + do i=1,sparse%col(j)%Size + matrix(sparse%col(j)%rows(i),j) = matrix(sparse%col(j)%rows(i),j) + sparse%col(j)%vals(i) + enddo + enddo + end subroutine dump_zmatrix_csc + + + !+------------------------------------------------------------------+ + !PURPOSE: dump a sparse matrix into a regular 2dim array replacing elements + !+------------------------------------------------------------------+ + !REAL + function as_dmatrix_csc(sparse) result(matrix) + class(sparse_dmatrix_csc),intent(in) :: sparse + real(8),dimension(sparse%Nrow,sparse%Ncol) :: matrix + integer :: i,j + matrix = 0d0 + do j=1,sparse%Ncol + do i=1,sparse%col(j)%Size + matrix(sparse%col(j)%rows(i),j) = sparse%col(j)%vals(i) + enddo + enddo + end function as_dmatrix_csc + + !COMPLEX + function as_zmatrix_csc(sparse) result(matrix) + class(sparse_zmatrix_csc),intent(in) :: sparse + complex(8),dimension(sparse%Nrow,sparse%Ncol) :: matrix + integer :: i,j + matrix = 0d0 + do j=1,sparse%Ncol + do i=1,sparse%col(j)%Size + matrix(sparse%col(j)%rows(i),j) = sparse%col(j)%vals(i) + enddo + enddo + end function as_zmatrix_csc + + + !################################################################## + ! SPARSE MATRIX KRON PRODUCT + !################################################################## + !+------------------------------------------------------------------+ + !PURPOSE: Perform simple Kroenecker product of two sparse matrices + !AxB(1+rowB*(i-1):rowB*i,1+colB*(j-1):colB*j) = A(i,j)*B(:,:) + !+------------------------------------------------------------------+ + !REAL + function kron_dmatrix_csc(A,B) result(AxB) + type(sparse_dmatrix_csc), intent(in) :: A,B + type(sparse_dmatrix_csc) :: AxB + integer :: i,j,k,l,jrow,krow + integer :: indx_row,indx_col + real(8) :: value + call AxB%free() + call AxB%init(a%Nrow*b%Nrow,a%Ncol*b%Ncol) + do indx_col =1,A%Ncol*B%Ncol + k=mod(indx_col,B%Ncol); if(k==0)k=B%Ncol + j= (indx_col-1)/B%Ncol+1 + do jrow=1,A%col(j)%size + i=A%col(j)%rows(jrow) + do krow=1,B%col(k)%size + l = B%col(k)%rows(krow) + indx_row = l + (i-1)*B%Nrow + value = A%col(j)%vals(jrow)*B%col(k)%vals(krow) + ! + call append(AxB%col(indx_col)%vals,value) + call append(AxB%col(indx_col)%rows,indx_row) + AxB%col(indx_col)%Size = AxB%col(indx_col)%Size + 1 + AxB%Nelements = AxB%Nelements+1 + end do + end do + end do + end function kron_dmatrix_csc + ! + function restricted_kron_dmatrix_csc(A,B,states) result(AxB) + type(sparse_dmatrix_csc), intent(in) :: A,B + integer,dimension(:),intent(in) :: states + type(sparse_dmatrix_csc) :: AxB + integer :: i,irow,j,k,krow,l,istate,jstate + integer :: indx_row,indx_col + real(8) :: value + integer,dimension(:),allocatable :: inv_states + call AxB%free() + call AxB%init(size(states),size(states)) + allocate(inv_states(A%Ncol*B%Ncol)) + do i=1,size(states) + inv_states(states(i)) = i + enddo + do istate = 1,size(states) + indx_col=states(istate) + k = mod(indx_col,B%Ncol);if(k==0)k=B%Ncol + i = (indx_col-1)/B%Ncol+1 + do irow=1,A%col(i)%size + j = A%col(i)%rows(irow) + do krow=1,B%col(k)%size + l = B%col(k)%rows(krow) + indx_row = l + (j-1)*B%Nrow + jstate = inv_states(indx_row) + value = A%col(i)%vals(irow)*B%col(k)%vals(krow) + ! + call append(AxB%col(istate)%vals,value) + call append(AxB%col(istate)%rows,jstate) + AxB%col(istate)%Size = AxB%col(istate)%Size + 1 + AxB%Nelements = AxB%Nelements + 1 + ! + enddo + enddo + enddo + end function restricted_kron_dmatrix_csc + ! + !COMPLEX + function kron_zmatrix_csc(A,B) result(AxB) + type(sparse_zmatrix_csc), intent(in) :: A,B + type(sparse_zmatrix_csc) :: AxB + integer :: i,jrow,j,k,krow,l + integer :: indx_row,indx_col + complex(8) :: value + call AxB%free() + call AxB%init(a%Nrow*b%Nrow,a%Ncol*b%Ncol) + do indx_col =1,A%Ncol*B%Ncol + k=mod(indx_col,B%Ncol); if(k==0)k=B%Ncol + j= (indx_col-1)/B%Ncol+1 + do jrow=1,A%col(j)%size + i=A%col(j)%rows(jrow) + do krow=1,B%col(k)%size + l = B%col(k)%rows(krow) + indx_row = l + (i-1)*B%Nrow + value = A%col(j)%vals(jrow)*B%col(k)%vals(krow) + ! + call append(AxB%col(indx_col)%vals,value) + call append(AxB%col(indx_col)%rows,indx_row) + AxB%col(indx_col)%Size = AxB%col(indx_col)%Size + 1 + AxB%Nelements = AxB%Nelements+1 + end do + end do + end do + end function kron_zmatrix_csc + ! + function restricted_kron_zmatrix_csc(A,B,states) result(AxB) + type(sparse_zmatrix_csc), intent(in) :: A,B + integer,dimension(:),intent(in) :: states + type(sparse_zmatrix_csc) :: AxB + integer :: i,irow,j,k,krow,l,istate,jstate + integer :: indx_row,indx_col + complex(8) :: value + integer,dimension(:),allocatable :: inv_states + call AxB%free() + call AxB%init(size(states),size(states)) + allocate(inv_states(A%Ncol*B%Ncol)) + do i=1,size(states) + inv_states(states(i)) = i + enddo + do istate = 1,size(states) + indx_col=states(istate) + k = mod(indx_col,B%Ncol);if(k==0)k=B%Ncol + i = (indx_col-1)/B%Ncol+1 + do irow=1,A%col(i)%size + j = A%col(i)%rows(irow) + do krow=1,B%col(k)%size + l = B%col(k)%rows(krow) + indx_row = l + (j-1)*B%Nrow + jstate = inv_states(indx_row) + value = A%col(i)%vals(irow)*B%col(k)%vals(krow) + ! + call append(AxB%col(istate)%vals,value) + call append(AxB%col(istate)%rows,jstate) + AxB%col(istate)%Size = AxB%col(istate)%Size + 1 + AxB%Nelements = AxB%Nelements + 1 + ! + enddo + enddo + enddo + end function restricted_kron_zmatrix_csc + ! + + + + !################################################################## + ! SPARSE MATRIX BASIC ALGEBRA + !################################################################## + !REAL + function dgr_dmatrix_csc(a) result(c) + class(sparse_dmatrix_csc), intent(in) :: a + type(sparse_dmatrix_csc) :: c + integer :: row + real(8) :: val + integer :: i,j + call c%init(a%Ncol,a%Nrow) !tranpose + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i) + call c%insert(val,j,row) + enddo + enddo + end function dgr_dmatrix_csc + ! + function transpose_dmatrix_csc(a) result(c) + class(sparse_dmatrix_csc), intent(in) :: a + type(sparse_dmatrix_csc) :: c + integer :: row + real(8) :: val + integer :: i,j + call c%init(a%Ncol,a%Nrow) !tranpose + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i) + call c%insert(val,j,row) + enddo + enddo + end function transpose_dmatrix_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix equality spA = spB. Deep copy + !+------------------------------------------------------------------+ + subroutine dmatrix_equal_dmatrix_csc(a,b) + type(sparse_dmatrix_csc),intent(inout) :: a + type(sparse_dmatrix_csc),intent(in) :: b + integer :: row + real(8) :: val + integer :: i,j + call a%free() + call a%init(b%Nrow,b%Ncol) + do j=1,b%Ncol + do i=1,b%col(j)%size + row = b%col(j)%rows(i) + val = b%col(j)%vals(i) + call a%insert(val,row,j) + enddo + enddo + end subroutine dmatrix_equal_dmatrix_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix scalar equality spA = const. + !+------------------------------------------------------------------+ + subroutine dmatrix_equal_scalar_csc(a,c) + type(sparse_dmatrix_csc),intent(inout) :: a + real(8),intent(in) :: c + integer :: i,j + ! if(.not.a%status)stop "dmatrix_equal_scalar error: a is not allocated" + do j=1,a%Ncol + do i=1,a%col(j)%size + a%col(j)%vals(i) = c + enddo + enddo + end subroutine dmatrix_equal_scalar_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix addition spA + spB = spC + !+------------------------------------------------------------------+ + function plus_dmatrix_csc(a,b) result(c) + type(sparse_dmatrix_csc), intent(in) :: a,b + type(sparse_dmatrix_csc) :: c + integer :: row + real(8) :: val + integer :: i,j + ! if(.not.a%status)stop "plus_dmatrix error: a is not allocated" + ! if(.not.b%status)stop "plus_dmatrix error: b is not allocated" + if(a%Nrow/=b%Nrow)stop "plus_dmatrix error: a.Nrow != b.Nrow" + if(a%Ncol/=b%Ncol)stop "plus_dmatrix error: a.Ncol != b.Ncol" + c=a !copy a into c + do j=1,b%Ncol + do i=1,b%col(j)%size + row = b%col(j)%rows(i) + val = b%col(j)%vals(i) + call c%insert(val,row,j) + enddo + enddo + end function plus_dmatrix_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix difference spA - spB = spC + !+------------------------------------------------------------------+ + function minus_dmatrix_csc(a,b) result(c) + type(sparse_dmatrix_csc), intent(in) :: a,b + type(sparse_dmatrix_csc) :: c + integer :: row + real(8) :: val + integer :: i,j + if(a%Nrow/=b%Nrow)stop "minus_dmatrix error: a.Nrow != b.Nrow" + if(a%Ncol/=b%Ncol)stop "minus_dmatrix error: a.Ncol != b.Ncol" + c=a !copy a into c + do j=1,b%Ncol + do i=1,b%col(j)%size + row = b%col(j)%rows(i) + val = -b%col(j)%vals(i) + call c%insert(val,row,j) + enddo + enddo + end function minus_dmatrix_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix left scalar product const*spA = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function left_product_dmatrix_i_csc(C,A) result(B) + integer,intent(in) :: C + type(sparse_dmatrix_csc),intent(in) :: A + type(sparse_dmatrix_csc) :: B + integer :: row + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)*C + call b%insert(val,row,j) + enddo + enddo + end function left_product_dmatrix_i_csc + ! + function left_product_dmatrix_d_csc(C,A) result(B) + real(8),intent(in) :: C + type(sparse_dmatrix_csc),intent(in) :: A + type(sparse_dmatrix_csc) :: B + integer :: row + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)*C + call b%insert(val,row,j) + enddo + enddo + end function left_product_dmatrix_d_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix right scalar product spA*const = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function right_product_dmatrix_i_csc(A,C) result(B) + integer,intent(in) :: C + type(sparse_dmatrix_csc),intent(in) :: A + type(sparse_dmatrix_csc) :: B + integer :: row + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)*C + call b%insert(val,row,j) + enddo + enddo + end function right_product_dmatrix_i_csc + ! + function right_product_dmatrix_d_csc(A,C) result(B) + real(8),intent(in) :: C + type(sparse_dmatrix_csc),intent(in) :: A + type(sparse_dmatrix_csc) :: B + integer :: row + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)*C + call b%insert(val,row,j) + enddo + enddo + end function right_product_dmatrix_d_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix right scalar division spA/const = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function right_division_dmatrix_i_csc(A,C) result(B) + integer,intent(in) :: C + type(sparse_dmatrix_csc),intent(in) :: A + type(sparse_dmatrix_csc) :: B + integer :: row + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)/C + call b%insert(val,row,j) + enddo + enddo + end function right_division_dmatrix_i_csc + ! + function right_division_dmatrix_d_csc(A,C) result(B) + real(8),intent(in) :: C + type(sparse_dmatrix_csc),intent(in) :: A + type(sparse_dmatrix_csc) :: B + integer :: row + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)/C + call b%insert(val,row,j) + enddo + enddo + end function right_division_dmatrix_d_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Return the identiy sparse matrix of given dimension + !+------------------------------------------------------------------+ + !function deye_csc(ndim) result(self) + ! type(sparse_dmatrix_csc) :: self + ! integer,intent(in) :: ndim + ! integer :: i + ! call self%init(ndim,ndim) + ! do i=1,ndim + ! call self%insert(1.d0,i,i) + ! end do + ! end func + !tion deye_csc + + !COMPLEX + function dgr_zmatrix_csc(a) result(c) + class(sparse_zmatrix_csc), intent(in) :: a + type(sparse_zmatrix_csc) :: c + integer :: row + complex(8) :: val + integer :: i,j + call c%init(a%Ncol,a%Nrow) !tranpose + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = conjg(a%col(j)%vals(i)) + call c%insert(val,j,row) + enddo + enddo + end function dgr_zmatrix_csc + ! + function transpose_zmatrix_csc(a) result(c) + class(sparse_zmatrix_csc), intent(in) :: a + type(sparse_zmatrix_csc) :: c + integer :: row + complex(8) :: val + integer :: i,j + call c%init(a%Ncol,a%Nrow) !tranpose + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i) + call c%insert(val,j,row) + enddo + enddo + end function transpose_zmatrix_csc + ! + function conjg_zmatrix_csc(a) result(c) + class(sparse_zmatrix_csc), intent(in) :: a + type(sparse_zmatrix_csc) :: c + integer :: row + complex(8) :: val + integer :: i,j + call c%init(a%Nrow,a%Ncol) !tranpose + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = conjg(a%col(j)%vals(i)) + call c%insert(val,row,j) + enddo + enddo + end function conjg_zmatrix_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix equality spA = spB. Deep copy + !+------------------------------------------------------------------+ + subroutine zmatrix_equal_zmatrix_csc(a,b) + type(sparse_zmatrix_csc),intent(inout) :: a + type(sparse_zmatrix_csc),intent(in) :: b + integer :: row + complex(8) :: val + integer :: i,j + call a%free() + call a%init(b%Nrow,b%Ncol) + do j=1,b%Ncol + do i=1,b%col(j)%size + row = b%col(j)%rows(i) + val = b%col(j)%vals(i) + call a%insert(val,row,j) + enddo + enddo + end subroutine zmatrix_equal_zmatrix_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix scalar equality spA = const. + !+------------------------------------------------------------------+ + subroutine zmatrix_equal_scalar_csc(a,c) + type(sparse_zmatrix_csc),intent(inout) :: a + complex(8),intent(in) :: c + integer :: i,j + ! if(.not.a%status)stop "zmatrix_equal_scalar error: a is not allocated" + do j=1,a%Ncol + do i=1,a%col(j)%size + a%col(j)%vals(i) = c + enddo + enddo + end subroutine zmatrix_equal_scalar_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix addition spA + spB = spC + !+------------------------------------------------------------------+ + function plus_zmatrix_csc(a,b) result(c) + type(sparse_zmatrix_csc), intent(in) :: a,b + type(sparse_zmatrix_csc) :: c + integer :: row + complex(8) :: val + integer :: i,j + ! if(.not.a%status)stop "plus_zmatrix error: a is not allocated" + ! if(.not.b%status)stop "plus_zmatrix error: b is not allocated" + if(a%Nrow/=b%Nrow)stop "plus_zmatrix error: a.Nrow != b.Nrow" + if(a%Ncol/=b%Ncol)stop "plus_zmatrix error: a.Ncol != b.Ncol" + c=a !copy a into c + do j=1,b%Ncol + do i=1,b%col(j)%size + row = b%col(j)%rows(i) + val = b%col(j)%vals(i) + call c%insert(val,row,j) + enddo + enddo + end function plus_zmatrix_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix difference spA - spB = spC + !+------------------------------------------------------------------+ + function minus_zmatrix_csc(a,b) result(c) + type(sparse_zmatrix_csc), intent(in) :: a,b + type(sparse_zmatrix_csc) :: c + integer :: row + complex(8) :: val + integer :: i,j + if(a%Nrow/=b%Nrow)stop "plus_zmatrix error: a.Nrow != b.Nrow" + if(a%Ncol/=b%Ncol)stop "plus_zmatrix error: a.Ncol != b.Ncol" + c=a !copy a into c + do j=1,b%Ncol + do i=1,b%col(j)%size + row = b%col(j)%rows(i) + val = -b%col(j)%vals(i) + call c%insert(val,row,j) + enddo + enddo + end function minus_zmatrix_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix left scalar product const*spA = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function left_product_zmatrix_i_csc(C,A) result(B) + integer,intent(in) :: C + type(sparse_zmatrix_csc),intent(in) :: A + type(sparse_zmatrix_csc) :: B + integer :: row + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)*C + call b%insert(val,row,j) + enddo + enddo + end function left_product_zmatrix_i_csc + ! + function left_product_zmatrix_d_csc(C,A) result(B) + real(8),intent(in) :: C + type(sparse_zmatrix_csc),intent(in) :: A + type(sparse_zmatrix_csc) :: B + integer :: row + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)*C + call b%insert(val,row,j) + enddo + enddo + end function left_product_zmatrix_d_csc + ! + function left_product_zmatrix_z_csc(C,A) result(B) + complex(8),intent(in) :: C + type(sparse_zmatrix_csc),intent(in) :: A + type(sparse_zmatrix_csc) :: B + integer :: row + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)*C + call b%insert(val,row,j) + enddo + enddo + end function left_product_zmatrix_z_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix right scalar product spA*const = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function right_product_zmatrix_i_csc(A,C) result(B) + integer,intent(in) :: C + type(sparse_zmatrix_csc),intent(in) :: A + type(sparse_zmatrix_csc) :: B + integer :: row + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)*C + call b%insert(val,row,j) + enddo + enddo + end function right_product_zmatrix_i_csc + ! + function right_product_zmatrix_d_csc(A,C) result(B) + real(8),intent(in) :: C + type(sparse_zmatrix_csc),intent(in) :: A + type(sparse_zmatrix_csc) :: B + integer :: row + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)*C + call b%insert(val,row,j) + enddo + enddo + end function right_product_zmatrix_d_csc + ! + function right_product_zmatrix_z_csc(A,C) result(B) + complex(8),intent(in) :: C + type(sparse_zmatrix_csc),intent(in) :: A + type(sparse_zmatrix_csc) :: B + integer :: row + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)*C + call b%insert(val,row,j) + enddo + enddo + end function right_product_zmatrix_z_csc + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix right scalar division spA/const = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function right_division_zmatrix_i_csc(A,C) result(B) + integer,intent(in) :: C + type(sparse_zmatrix_csc),intent(in) :: A + type(sparse_zmatrix_csc) :: B + integer :: row + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)/C + call b%insert(val,row,j) + enddo + enddo + end function right_division_zmatrix_i_csc + ! + function right_division_zmatrix_d_csc(A,C) result(B) + real(8),intent(in) :: C + type(sparse_zmatrix_csc),intent(in) :: A + type(sparse_zmatrix_csc) :: B + integer :: row + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)/C + call b%insert(val,row,j) + enddo + enddo + end function right_division_zmatrix_d_csc + ! + function right_division_zmatrix_z_csc(A,C) result(B) + complex(8),intent(in) :: C + type(sparse_zmatrix_csc),intent(in) :: A + type(sparse_zmatrix_csc) :: B + integer :: row + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do j=1,a%Ncol + do i=1,a%col(j)%size + row = a%col(j)%rows(i) + val = a%col(j)%vals(i)/C + call b%insert(val,row,j) + enddo + enddo + end function right_division_zmatrix_z_csc + + function left_matmul_dmatrix_darray_csc(C,A) result(B) + real(8),intent(in),dimension(:) :: C + type(sparse_dmatrix_csc),intent(in) :: A + real(8),dimension(size(C)) :: B + integer :: i,j + B=0.d0 + if(A%Nrow/=size(C)) stop "size(sparse,1)!=size(array) in left_matmul_dmatrix_darray_csc" + do j=1,A%Ncol + do i=1,A%col(j)%size + B(j)=B(j)+A%col(j)%vals(i)*C(A%col(j)%rows(i)) + enddo + end do + end function left_matmul_dmatrix_darray_csc + ! + function left_matmul_zmatrix_zarray_csc(C,A) result(B) + complex(8),intent(in),dimension(:) :: C + type(sparse_zmatrix_csc),intent(in) :: A + complex(8),dimension(size(C)) :: B + integer :: i,j + B=0.d0 + if(A%Ncol/=size(C)) stop "size(sparse,2)!=size(array) in sparse_matmul_zmatrix_zarray_csc" + do j=1,A%Ncol + do i=1,A%col(j)%size + B(j)=B(j)+A%col(j)%vals(i)*C(A%col(j)%rows(i)) + enddo + end do + end function left_matmul_zmatrix_zarray_csc + + + !+------------------------------------------------------------------+ + !PURPOSE: Return the identiy sparse matrix of given dimension + !+------------------------------------------------------------------+ + ! function zeye_csc(ndim) result(self) + ! type(sparse_zmatrix_csc) :: self + ! integer,intent(in) :: ndim + ! integer :: i + ! call self%init(ndim,ndim) + ! do i=1,ndim + ! call self%insert((1.d0,0.d0),i,i) + ! end do + ! end function zeye_csc + + + + +END MODULE SF_SPARSE_ARRAY_CSC diff --git a/src/SF_SPARSE/SF_SPARSE_ARRAY_CSR.f90 b/src/SF_SPARSE/SF_SPARSE_ARRAY_CSR.f90 new file mode 100644 index 000000000..ff840b87e --- /dev/null +++ b/src/SF_SPARSE/SF_SPARSE_ARRAY_CSR.f90 @@ -0,0 +1,1194 @@ +MODULE SF_SPARSE_ARRAY_CSR + USE SF_LINALG, only: zeye, deye + USE SF_SPARSE_COMMON + !MPI STILL TO BE DONE +#ifdef _MPI + USE MPI +#endif + implicit none + + private + + !CSR ROWS + type sparse_row_csr + integer :: size + integer,dimension(:),allocatable :: cols + end type sparse_row_csr + ! + type, extends(sparse_row_csr) :: sparse_drow_csr + real(8),dimension(:),allocatable :: vals + end type sparse_drow_csr + ! + type, extends(sparse_row_csr) :: sparse_zrow_csr + complex(8),dimension(:),allocatable :: vals + end type sparse_zrow_csr + + type, extends(sparse_matrix) :: sparse_dmatrix_csr + type(sparse_drow_csr),dimension(:),allocatable :: row + contains + procedure,pass :: init => init_dmatrix_csr + procedure,pass :: free => free_dmatrix_csr + procedure,pass :: load => load_dmatrix_csr + procedure,pass :: dump => dump_dmatrix_csr + procedure,pass :: insert => insert_delement_csr + procedure,pass :: get => get_delement_csr + procedure,pass :: as_matrix => as_dmatrix_csr + procedure,pass :: dgr => dgr_dmatrix_csr + procedure,pass :: transpose => transpose_dmatrix_csr + end type sparse_dmatrix_csr + + type, extends(sparse_matrix) :: sparse_zmatrix_csr + type(sparse_zrow_csr),dimension(:),allocatable :: row + contains + procedure,pass :: init => init_zmatrix_csr + procedure,pass :: free => free_zmatrix_csr + procedure,pass :: load => load_zmatrix_csr + procedure,pass :: dump => dump_zmatrix_csr + procedure,pass :: insert => insert_zelement_csr + procedure,pass :: get => get_zelement_csr + procedure,pass :: as_matrix => as_zmatrix_csr + procedure,pass :: dgr => dgr_zmatrix_csr + procedure,pass :: transpose => transpose_zmatrix_csr + procedure,pass :: conjg => conjg_zmatrix_csr + end type sparse_zmatrix_csr + + + interface sparse_matrix + module procedure :: construct_dmatrix_csr + module procedure :: construct_zmatrix_csr + end interface sparse_matrix + ! + interface as_sparse + module procedure :: construct_dmatrix_csr + module procedure :: construct_zmatrix_csr + end interface as_sparse + ! + interface sparse + module procedure :: construct_dmatrix_csr + module procedure :: construct_zmatrix_csr + end interface sparse + + !EQUALITY with scalar and function (A=B, A=cmplx) + interface assignment(=) + module procedure :: dmatrix_equal_scalar_csr + module procedure :: dmatrix_equal_dmatrix_csr + module procedure :: zmatrix_equal_scalar_csr + module procedure :: zmatrix_equal_zmatrix_csr + end interface assignment(=) + + !ADDITION + interface operator (+) + module procedure :: plus_dmatrix_csr + module procedure :: plus_zmatrix_csr + end interface operator (+) + + !SUBTRACTION + interface operator (-) + module procedure :: minus_dmatrix_csr + module procedure :: minus_zmatrix_csr + end interface operator (-) + + !SCALAR PRODUCT + interface operator(*) + module procedure :: left_product_dmatrix_i_csr + module procedure :: left_product_dmatrix_d_csr + module procedure :: left_product_zmatrix_i_csr + module procedure :: left_product_zmatrix_d_csr + module procedure :: left_product_zmatrix_z_csr + ! + module procedure :: right_product_dmatrix_i_csr + module procedure :: right_product_dmatrix_d_csr + module procedure :: right_product_zmatrix_i_csr + module procedure :: right_product_zmatrix_d_csr + module procedure :: right_product_zmatrix_z_csr + end interface operator(*) + + !SCALAR DIVISION + interface operator(/) + module procedure :: right_division_dmatrix_i_csr + module procedure :: right_division_dmatrix_d_csr + module procedure :: right_division_zmatrix_i_csr + module procedure :: right_division_zmatrix_d_csr + module procedure :: right_division_zmatrix_z_csr + end interface operator(/) + + !MATRIX PRODUCT + interface matmul + module procedure :: right_matmul_dmatrix_darray_csr + module procedure :: right_matmul_zmatrix_zarray_csr + end interface matmul + + + !KRONECKER PRODUCT + interface operator(.x.) + module procedure :: kron_dmatrix_csr + module procedure :: kron_zmatrix_csr + end interface operator(.x.) + + interface kron + module procedure :: kron_dmatrix_csr + module procedure :: kron_zmatrix_csr + module procedure :: restricted_kron_dmatrix_csr + module procedure :: restricted_kron_zmatrix_csr + end interface kron + + interface transpose + module procedure :: transpose_dmatrix_csr + module procedure :: transpose_zmatrix_csr + end interface transpose + + interface hconjg + module procedure :: dgr_dmatrix_csr + module procedure :: dgr_zmatrix_csr + end interface hconjg + + + public :: sparse_dmatrix_csr, sparse_zmatrix_csr + public :: as_sparse + public :: sparse + public :: assignment(=) + public :: operator(+) + public :: operator(-) + public :: operator(*) + public :: operator(/) + public :: operator(.x.) + public :: kron + public :: transpose + public :: hconjg + public :: matmul + +contains + + !+------------------------------------------------------------------+ + !PURPOSE: initialize the sparse matrix list + ! init: empty matrix of dimenson (N,N1) + ! constructor: dump a dense matrix into the sparse + !+------------------------------------------------------------------+ + !REAL + elemental subroutine init_dmatrix_csr(sparse,N,N1) + class(sparse_dmatrix_csr),intent(inout) :: sparse + integer,intent(in) :: N + integer,intent(in),optional :: N1 + integer :: i + ! + !put here a delete statement to avoid problems + if(sparse%status) call sparse%free() + sparse%Nrow=N + sparse%Ncol=N + if(present(N1))sparse%Ncol=N1 + ! + allocate(sparse%row(N)) + do i=1,N + sparse%row(i)%size=0 + allocate(sparse%row(i)%vals(0)) !empty array + allocate(sparse%row(i)%cols(0)) !empty array + end do + ! + sparse%status=.true. + ! + end subroutine init_dmatrix_csr + ! + function construct_dmatrix_csr(matrix) result(self) + real(8),dimension(:,:),intent(in) :: matrix + type(sparse_dmatrix_csr) :: self + call self%load(matrix) + end function construct_dmatrix_csr + ! + subroutine load_dmatrix_csr(sparse,matrix) + class(sparse_dmatrix_csr),intent(inout) :: sparse + real(8),dimension(:,:),intent(in) :: matrix + integer :: i,j,Ndim1,Ndim2 + ! + call sparse%free() + Ndim1=size(matrix,1) + Ndim2=size(matrix,2) + ! + call sparse%init(Ndim1,Ndim2) + do i=1,Ndim1 + do j=1,Ndim2 + if(matrix(i,j)/=0d0)call insert_delement_csr(sparse,matrix(i,j),i,j) + enddo + enddo + end subroutine load_dmatrix_csr + ! + !COMPLEX + elemental subroutine init_zmatrix_csr(sparse,N,N1) + class(sparse_zmatrix_csr),intent(inout) :: sparse + integer,intent(in) :: N + integer,intent(in),optional :: N1 + integer :: i + ! + !put here a delete statement to avoid problems + if(sparse%status) call sparse%free() + ! + sparse%Nrow=N + sparse%Ncol=N + if(present(N1))sparse%Ncol=N1 + ! + allocate(sparse%row(N)) + do i=1,N + sparse%row(i)%size=0 + allocate(sparse%row(i)%vals(0)) !empty array + allocate(sparse%row(i)%cols(0)) !empty array + end do + ! + sparse%status=.true. + ! + end subroutine init_zmatrix_csr + ! + function construct_zmatrix_csr(matrix) result(self) + complex(8),dimension(:,:),intent(in) :: matrix + type(sparse_zmatrix_csr) :: self + call self%load(matrix) + end function construct_zmatrix_csr + ! + subroutine load_zmatrix_csr(sparse,matrix) + class(sparse_zmatrix_csr),intent(inout) :: sparse + complex(8),dimension(:,:),intent(in) :: matrix + integer :: i,j,Ndim1,Ndim2 + ! + call sparse%free() + Ndim1=size(matrix,1) + Ndim2=size(matrix,2) + ! + call sparse%init(Ndim1,Ndim2) + do i=1,Ndim1 + do j=1,Ndim2 + if(matrix(i,j)/=0d0)call insert_zelement_csr(sparse,matrix(i,j),i,j) + enddo + enddo + end subroutine load_zmatrix_csr + + !+------------------------------------------------------------------+ + !PURPOSE: frees a sparse matrix + !+------------------------------------------------------------------+ + !REAL + elemental subroutine free_dmatrix_csr(sparse) + class(sparse_dmatrix_csr),intent(inout) :: sparse + integer :: i + ! + do i=1,sparse%Nrow + sparse%row(i)%Size = 0 + if(allocated(sparse%row(i)%vals))deallocate(sparse%row(i)%vals) + if(allocated(sparse%row(i)%cols))deallocate(sparse%row(i)%cols) + enddo + if(allocated(sparse%row))deallocate(sparse%row) + ! + sparse%Nrow=0 + sparse%Ncol=0 + sparse%Nelements=0 + sparse%status=.false. + end subroutine free_dmatrix_csr + ! + !COMPLEX + elemental subroutine free_zmatrix_csr(sparse) + class(sparse_zmatrix_csr),intent(inout) :: sparse + integer :: i + ! + do i=1,sparse%Nrow + sparse%row(i)%Size = 0 + if(allocated(sparse%row(i)%vals))deallocate(sparse%row(i)%vals) + if(allocated(sparse%row(i)%cols))deallocate(sparse%row(i)%cols) + enddo + if(allocated(sparse%row))deallocate(sparse%row) + ! + sparse%Nrow=0 + sparse%Ncol=0 + sparse%Nelements=0 + sparse%status=.false. + end subroutine free_zmatrix_csr + + + !+------------------------------------------------------------------+ + !PURPOSE: insert an element value at position (i,j) in the sparse matrix + !+------------------------------------------------------------------+ + !REAL + subroutine insert_delement_csr(sparse,value,i,j) + class(sparse_dmatrix_csr),intent(inout) :: sparse + real(8),intent(in) :: value + integer,intent(in) :: i,j + integer :: column,pos + logical :: iadd + ! + ! + column = j + iadd = .false. !check if column already exist + if(any(sparse%row(i)%cols == column))then ! + pos = binary_search(sparse%row(i)%cols,column) !find the position column in %cols + iadd=.true. !set Iadd to true + endif + ! + if(iadd)then !this column exists so just sum it up + sparse%row(i)%vals(pos)=sparse%row(i)%vals(pos) + value !add up value to the current one in %vals + else !this column is new. increase counter and store it + call append(sparse%row(i)%vals,value) + call append(sparse%row(i)%cols,column) + sparse%row(i)%Size = sparse%row(i)%Size + 1 + sparse%Nelements = sparse%Nelements+1 + endif + ! + if(sparse%row(i)%Size > sparse%Ncol)stop "insert_delement_csr ERROR: row%Size > sparse%Ncol" + ! + end subroutine insert_delement_csr + ! + !COMPLEX + subroutine insert_zelement_csr(sparse,value,i,j) + class(sparse_zmatrix_csr),intent(inout) :: sparse + complex(8),intent(in) :: value + integer,intent(in) :: i,j + ! + integer :: column,pos + logical :: iadd + ! + ! + column = j + ! + iadd = .false. !check if column already exist + if(any(sparse%row(i)%cols == column))then ! + pos = binary_search(sparse%row(i)%cols,column) !find the position column in %cols + iadd=.true. !set Iadd to true + endif + ! + if(iadd)then !this column exists so just sum it up + sparse%row(i)%vals(pos)=sparse%row(i)%vals(pos) + value !add up value to the current one in %vals + else !this column is new. increase counter and store it + call append(sparse%row(i)%vals,value) + call append(sparse%row(i)%cols,column) + sparse%row(i)%Size = sparse%row(i)%Size + 1 + sparse%Nelements = sparse%Nelements+1 + endif + ! + if(sparse%row(i)%Size > sparse%Ncol)stop "insert_zelement_csr ERROR: row%Size > sparse%Ncol" + ! + end subroutine insert_zelement_csr + + !+------------------------------------------------------------------+ + !PURPOSE: get the element value at position (i,j) in the sparse matrix + !+------------------------------------------------------------------+ + function get_delement_csr(sparse,i,j) result(value) + class(sparse_dmatrix_csr),intent(inout) :: sparse + integer,intent(in) :: i,j + real(8) :: value + integer :: pos + value=0d0 + do pos=1,sparse%row(i)%size + if(j==sparse%row(i)%cols(pos))value=sparse%row(i)%vals(pos) + enddo + end function get_delement_csr + + function get_zelement_csr(sparse,i,j) result(value) + class(sparse_zmatrix_csr),intent(inout) :: sparse + integer,intent(in) :: i,j + complex(8) :: value + integer :: pos + value=0d0 + do pos=1,sparse%row(i)%size + if(j==sparse%row(i)%cols(pos))value=sparse%row(i)%vals(pos) + enddo + end function get_zelement_csr + + + !+------------------------------------------------------------------+ + !PURPOSE: dump a sparse matrix into a regular 2dim array + !+------------------------------------------------------------------+ + !REAL + subroutine dump_dmatrix_csr(sparse,matrix) + class(sparse_dmatrix_csr),intent(in) :: sparse + real(8),dimension(:,:),intent(inout) :: matrix + integer :: i,j,Ndim1,Ndim2 + ! + ! + Ndim1=size(matrix,1); Ndim2=size(matrix,2) + ! + if(sparse%Nrow/=Ndim1 .OR. sparse%Ncol/=Ndim2)stop "Warning SPARSE/dump_matrix: dimensions error" + ! + do i=1,Ndim1 + do j=1,sparse%row(i)%Size + matrix(i,sparse%row(i)%cols(j)) = matrix(i,sparse%row(i)%cols(j)) + sparse%row(i)%vals(j) + enddo + enddo + end subroutine dump_dmatrix_csr + ! + !COMPLEX + subroutine dump_zmatrix_csr(sparse,matrix) + class(sparse_zmatrix_csr),intent(in) :: sparse + complex(8),dimension(:,:),intent(inout) :: matrix + integer :: i,j,Ndim1,Ndim2 + ! + Ndim1=size(matrix,1); Ndim2=size(matrix,2) + ! + if(sparse%Nrow/=Ndim1 .OR. sparse%Ncol/=Ndim2)stop "Warning SPARSE/dump_matrix: dimensions error" + ! + matrix=0.d0 + do i=1,Ndim1 + do j=1,sparse%row(i)%Size + matrix(i,sparse%row(i)%cols(j)) = matrix(i,sparse%row(i)%cols(j)) + sparse%row(i)%vals(j) + enddo + enddo + end subroutine dump_zmatrix_csr + + !+------------------------------------------------------------------+ + !PURPOSE: dump a sparse matrix into a regular 2dim array + !+------------------------------------------------------------------+ + !REAL + function as_dmatrix_csr(sparse) result(matrix) + class(sparse_dmatrix_csr),intent(in) :: sparse + real(8),dimension(sparse%Nrow,sparse%Ncol) :: matrix + integer :: i,j + matrix = 0d0 + do i=1,sparse%Nrow + do j=1,sparse%row(i)%Size + matrix(i,sparse%row(i)%cols(j)) = sparse%row(i)%vals(j) + enddo + enddo + end function as_dmatrix_csr + + !COMPLEX + function as_zmatrix_csr(sparse) result(matrix) + class(sparse_zmatrix_csr),intent(in) :: sparse + complex(8),dimension(sparse%Nrow,sparse%Ncol) :: matrix + integer :: i,j + matrix = 0d0 + do i=1,sparse%Nrow + do j=1,sparse%row(i)%Size + matrix(i,sparse%row(i)%cols(j)) = sparse%row(i)%vals(j) + enddo + enddo + end function as_zmatrix_csr + + !################################################################## + ! SPARSE MATRIX KRON PRODUCT + !################################################################## + !+------------------------------------------------------------------+ + !PURPOSE: Perform simple Kroenecker product of two sparse matrices + !AxB(1+rowB*(i-1):rowB*i,1+colB*(j-1):colB*j) = A(i,j)*B(:,:) + !+------------------------------------------------------------------+ + !REAL + function kron_dmatrix_csr(A,B) result(AxB) + type(sparse_dmatrix_csr), intent(in) :: A,B + type(sparse_dmatrix_csr) :: AxB + integer :: i,icol,j,k,kcol,l + integer :: indx_row,indx_col + real(8) :: value +! call AxB%free() + call AxB%init(a%Nrow*b%Nrow,a%Ncol*b%Ncol) + do indx_row = 1,A%Nrow*B%Nrow + k = mod(indx_row,B%Nrow);if(k==0)k=B%Nrow + i = (indx_row-1)/B%Nrow+1 + do icol=1,A%row(i)%size + j = A%row(i)%cols(icol) + do kcol=1,B%row(k)%size + l = B%row(k)%cols(kcol) + indx_col = l + (j-1)*B%Ncol + value = A%row(i)%vals(icol)*B%row(k)%vals(kcol) + ! + call append(AxB%row(indx_row)%vals,value) + call append(AxB%row(indx_row)%cols,indx_col) + AxB%row(indx_row)%Size = AxB%row(indx_row)%Size + 1 + AxB%Nelements = AxB%Nelements+1 + ! + enddo + enddo + enddo + end function kron_dmatrix_csr + ! + function restricted_kron_dmatrix_csr(A,B,states) result(AxB) + type(sparse_dmatrix_csr), intent(in) :: A,B + integer,dimension(:),intent(in) :: states + type(sparse_dmatrix_csr) :: AxB + integer :: i,icol,j,k,kcol,l,istate,jstate + integer :: indx_row,indx_col + real(8) :: value + integer,dimension(:),allocatable :: inv_states +! call AxB%free() + call AxB%init(size(states),size(states)) + allocate(inv_states(A%Ncol*B%Ncol)) + inv_states=0 + do i=1,size(states) + inv_states(states(i)) = i + enddo + do istate = 1,size(states) + indx_row=states(istate) + k = mod(indx_row,B%Nrow);if(k==0)k=B%Nrow + i = (indx_row-1)/B%Nrow+1 + do icol=1,A%row(i)%size + j = A%row(i)%cols(icol) + do kcol=1,B%row(k)%size + l = B%row(k)%cols(kcol) + indx_col = l + (j-1)*B%Ncol + jstate = inv_states(indx_col) + value = A%row(i)%vals(icol)*B%row(k)%vals(kcol) + ! + call append(AxB%row(istate)%vals,value) + call append(AxB%row(istate)%cols,jstate) + AxB%row(istate)%Size = AxB%row(istate)%Size + 1 + AxB%Nelements = AxB%Nelements + 1 + ! + enddo + enddo + enddo + end function restricted_kron_dmatrix_csr + ! + !COMPLEX + function kron_zmatrix_csr(A,B) result(AxB) + type(sparse_zmatrix_csr), intent(in) :: A,B + type(sparse_zmatrix_csr) :: AxB + integer :: i,icol,j,k,kcol,l + integer :: indx_row,indx_col + complex(8) :: value +! call AxB%free() + call AxB%init(a%Nrow*b%Nrow,a%Ncol*b%Ncol) + do indx_row = 1,A%Nrow*B%Nrow + k = mod(indx_row,B%Nrow);if(k==0)k=B%Nrow + i = (indx_row-1)/B%Nrow+1 + do icol=1,A%row(i)%size + j = A%row(i)%cols(icol) + do kcol=1,B%row(k)%size + l = B%row(k)%cols(kcol) + indx_col = l + (j-1)*B%Ncol + value = A%row(i)%vals(icol)*B%row(k)%vals(kcol) + ! + call append(AxB%row(indx_row)%vals,value) + call append(AxB%row(indx_row)%cols,indx_col) + AxB%row(indx_row)%Size = AxB%row(indx_row)%Size + 1 + AxB%Nelements = AxB%Nelements+1 + ! + enddo + enddo + enddo + end function kron_zmatrix_csr + ! + function restricted_kron_zmatrix_csr(A,B,states) result(AxB) + type(sparse_zmatrix_csr), intent(in) :: A,B + integer,dimension(:),intent(in) :: states + type(sparse_zmatrix_csr) :: AxB + integer :: i,icol,j,k,kcol,l,istate,jstate + integer :: indx_row,indx_col + complex(8) :: value + integer,dimension(:),allocatable :: inv_states +! call AxB%free() + call AxB%init(size(states),size(states)) + allocate(inv_states(A%Ncol*B%Ncol)) + inv_states=0 + do i=1,size(states) + inv_states(states(i)) = i + enddo + do istate = 1,size(states) + indx_row=states(istate) + k = mod(indx_row,B%Nrow);if(k==0)k=B%Nrow + i = (indx_row-1)/B%Nrow+1 + do icol=1,A%row(i)%size + j = A%row(i)%cols(icol) + do kcol=1,B%row(k)%size + l = B%row(k)%cols(kcol) + indx_col = l + (j-1)*B%Ncol + jstate = inv_states(indx_col) + value = A%row(i)%vals(icol)*B%row(k)%vals(kcol) + ! + call append(AxB%row(istate)%vals,value) + call append(AxB%row(istate)%cols,jstate) + AxB%row(istate)%Size = AxB%row(istate)%Size + 1 + AxB%Nelements = AxB%Nelements + 1 + ! + enddo + enddo + enddo + end function restricted_kron_zmatrix_csr + ! + + + + !################################################################## + ! SPARSE MATRIX BASIC ALGEBRA + !################################################################## + !REAL + function dgr_dmatrix_csr(a) result(c) + class(sparse_dmatrix_csr), intent(in) :: a + type(sparse_dmatrix_csr) :: c + integer :: col + real(8) :: val + integer :: i,j + call c%init(a%Ncol,a%Nrow) !tranpose + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j) + call c%insert(val,col,i) + enddo + enddo + end function dgr_dmatrix_csr + ! + function transpose_dmatrix_csr(a) result(c) + class(sparse_dmatrix_csr), intent(in) :: a + type(sparse_dmatrix_csr) :: c + integer :: col + real(8) :: val + integer :: i,j + call c%init(a%Ncol,a%Nrow) !tranpose + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j) + call c%insert(val,col,i) + enddo + enddo + end function transpose_dmatrix_csr + ! + + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix equality spA = spB. Deep copy + !+------------------------------------------------------------------+ + subroutine dmatrix_equal_dmatrix_csr(a,b) + type(sparse_dmatrix_csr),intent(inout) :: a + type(sparse_dmatrix_csr),intent(in) :: b + integer :: col + real(8) :: val + integer :: i,j + call a%free() + call a%init(b%Nrow,b%Ncol) + do i=1,b%Nrow + do j=1,b%row(i)%size + col = b%row(i)%cols(j) + val = b%row(i)%vals(j) + call a%insert(val,i,col) + enddo + enddo + end subroutine dmatrix_equal_dmatrix_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix scalar equality spA = const. + !+------------------------------------------------------------------+ + subroutine dmatrix_equal_scalar_csr(a,c) + type(sparse_dmatrix_csr),intent(inout) :: a + real(8),intent(in) :: c + integer :: i,j + ! if(.not.a%status)stop "matrix_equal_scalar error: a is not allocated" + do i=1,a%Nrow + do j=1,a%row(i)%size + a%row(i)%vals(j) = c + enddo + enddo + end subroutine dmatrix_equal_scalar_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix addition spA + spB = spC + !+------------------------------------------------------------------+ + function plus_dmatrix_csr(a,b) result(c) + type(sparse_dmatrix_csr), intent(in) :: a,b + type(sparse_dmatrix_csr) :: c + integer :: col + real(8) :: val + integer :: i,j + ! if(.not.a%status)stop "plus_matrix error: a is not allocated" + ! if(.not.b%status)stop "plus_matrix error: b is not allocated" + if(a%Nrow/=b%Nrow)stop "plus_matrix error: a.Nrow != b.Nrow" + if(a%Ncol/=b%Ncol)stop "plus_matrix error: a.Ncol != b.Ncol" + c=a !copy a into c + do i=1,b%Nrow + do j=1,b%row(i)%size + col = b%row(i)%cols(j) + val = b%row(i)%vals(j) + call c%insert(val,i,col) + enddo + enddo + end function plus_dmatrix_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix difference spA - spB = spC + !+------------------------------------------------------------------+ + function minus_dmatrix_csr(a,b) result(c) + type(sparse_dmatrix_csr), intent(in) :: a,b + type(sparse_dmatrix_csr) :: c + integer :: col + real(8) :: val + integer :: i,j + if(a%Nrow/=b%Nrow)stop "plus_matrix error: a.Nrow != b.Nrow" + if(a%Ncol/=b%Ncol)stop "plus_matrix error: a.Ncol != b.Ncol" + c=a !copy a into c + do i=1,b%Nrow + do j=1,b%row(i)%size + col = b%row(i)%cols(j) + val =-b%row(i)%vals(j) + call c%insert(val,i,col) + enddo + enddo + end function minus_dmatrix_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix left scalar product const*spA = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function left_product_dmatrix_i_csr(C,A) result(B) + integer,intent(in) :: C + type(sparse_dmatrix_csr),intent(in) :: A + type(sparse_dmatrix_csr) :: B + integer :: col + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)*C + call b%insert(val,i,col) + enddo + enddo + end function left_product_dmatrix_i_csr + ! + function left_product_dmatrix_d_csr(C,A) result(B) + real(8),intent(in) :: C + type(sparse_dmatrix_csr),intent(in) :: A + type(sparse_dmatrix_csr) :: B + integer :: col + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)*C + call b%insert(val,i,col) + enddo + enddo + end function left_product_dmatrix_d_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix right scalar product spA*const = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function right_product_dmatrix_i_csr(A,C) result(B) + integer,intent(in) :: C + type(sparse_dmatrix_csr),intent(in) :: A + type(sparse_dmatrix_csr) :: B + integer :: col + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)*C + call b%insert(val,i,col) + enddo + enddo + end function right_product_dmatrix_i_csr + ! + function right_product_dmatrix_d_csr(A,C) result(B) + real(8),intent(in) :: C + type(sparse_dmatrix_csr),intent(in) :: A + type(sparse_dmatrix_csr) :: B + integer :: col + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)*C + call b%insert(val,i,col) + enddo + enddo + end function right_product_dmatrix_d_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix right scalar division spA/const = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function right_division_dmatrix_i_csr(A,C) result(B) + integer,intent(in) :: C + type(sparse_dmatrix_csr),intent(in) :: A + type(sparse_dmatrix_csr) :: B + integer :: col + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)/C + call b%insert(val,i,col) + enddo + enddo + end function right_division_dmatrix_i_csr + ! + function right_division_dmatrix_d_csr(A,C) result(B) + real(8),intent(in) :: C + type(sparse_dmatrix_csr),intent(in) :: A + type(sparse_dmatrix_csr) :: B + integer :: col + real(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)/C + call b%insert(val,i,col) + enddo + enddo + end function right_division_dmatrix_d_csr + + function right_matmul_dmatrix_darray_csr(A,C) result(B) + real(8),intent(in),dimension(:) :: C + type(sparse_dmatrix_csr),intent(in) :: A + real(8),dimension(size(C)) :: B + integer :: i,j + B=0.d0 + if(A%Ncol/=size(C)) stop "size(sparse,2)!=size(array) in right_matmul_dmatrix_darray_csr" + do i=1,A%Nrow + do j=1,A%row(i)%size + B(i)=B(i)+A%row(i)%vals(j)*C(A%row(i)%cols(j)) + enddo + end do + end function right_matmul_dmatrix_darray_csr + ! + function right_matmul_zmatrix_zarray_csr(A,C) result(B) + complex(8),intent(in),dimension(:) :: C + type(sparse_zmatrix_csr),intent(in) :: A + complex(8),dimension(size(C)) :: B + integer :: i,j + B=0.d0 + if(A%Ncol/=size(C)) stop "size(sparse,2)!=size(array) in right_matmul_zmatrix_zarray_csr" + do i=1,A%Nrow + do j=1,A%row(i)%size + B(i)=B(i)+A%row(i)%vals(j)*C(A%row(i)%cols(j)) + enddo + end do + end function right_matmul_zmatrix_zarray_csr + + + !+------------------------------------------------------------------+ + !PURPOSE: Return the identiy sparse matrix of given dimension + !+------------------------------------------------------------------+ + ! function deye_csr(ndim) result(self) + ! type(sparse_dmatrix_csr) :: self + ! integer,intent(in) :: ndim + ! integer :: i + ! call self%init(ndim,ndim) + ! do i=1,ndim + ! call self%insert(1.d0,i,i) + ! end do + ! end function deye_csr + + !COMPLEX + function dgr_zmatrix_csr(a) result(c) + class(sparse_zmatrix_csr), intent(in) :: a + type(sparse_zmatrix_csr) :: c + integer :: col + complex(8) :: val + integer :: i,j + call c%init(a%Ncol,a%Nrow) !tranpose + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = conjg(a%row(i)%vals(j)) + call c%insert(val,col,i) + enddo + enddo + end function dgr_zmatrix_csr + ! + function transpose_zmatrix_csr(a) result(c) + class(sparse_zmatrix_csr), intent(in) :: a + type(sparse_zmatrix_csr) :: c + integer :: col + complex(8) :: val + integer :: i,j + call c%init(a%Ncol,a%Nrow) !tranpose + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j) + call c%insert(val,col,i) + enddo + enddo + end function transpose_zmatrix_csr + ! + function conjg_zmatrix_csr(a) result(c) + class(sparse_zmatrix_csr), intent(in) :: a + type(sparse_zmatrix_csr) :: c + integer :: col + complex(8) :: val + integer :: i,j + call c%init(a%Nrow,a%Ncol) !tranpose + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = conjg(a%row(i)%vals(j)) + call c%insert(val,i,col) + enddo + enddo + end function conjg_zmatrix_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix equality spA = spB. Deep copy + !+------------------------------------------------------------------+ + subroutine zmatrix_equal_zmatrix_csr(a,b) + type(sparse_zmatrix_csr),intent(inout) :: a + type(sparse_zmatrix_csr),intent(in) :: b + integer :: col + complex(8) :: val + integer :: i,j + call a%free() + call a%init(b%Nrow,b%Ncol) + do i=1,b%Nrow + do j=1,b%row(i)%size + col = b%row(i)%cols(j) + val = b%row(i)%vals(j) + call a%insert(val,i,col) + enddo + enddo + end subroutine zmatrix_equal_zmatrix_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix scalar equality spA = const. + !+------------------------------------------------------------------+ + subroutine zmatrix_equal_scalar_csr(a,c) + type(sparse_zmatrix_csr),intent(inout) :: a + complex(8),intent(in) :: c + integer :: i,j + ! if(.not.a%status)stop "matrix_equal_scalar error: a is not allocated" + do i=1,a%Nrow + do j=1,a%row(i)%size + a%row(i)%vals(j) = c + enddo + enddo + end subroutine zmatrix_equal_scalar_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix addition spA + spB = spC + !+------------------------------------------------------------------+ + function plus_zmatrix_csr(a,b) result(c) + type(sparse_zmatrix_csr), intent(in) :: a,b + type(sparse_zmatrix_csr) :: c + integer :: col + complex(8) :: val + integer :: i,j + ! if(.not.a%status)stop "plus_matrix error: a is not allocated" + ! if(.not.b%status)stop "plus_matrix error: b is not allocated" + if(a%Nrow/=b%Nrow)stop "plus_matrix error: a.Nrow != b.Nrow" + if(a%Ncol/=b%Ncol)stop "plus_matrix error: a.Ncol != b.Ncol" + c=a !copy a into c + do i=1,b%Nrow + do j=1,b%row(i)%size + col = b%row(i)%cols(j) + val = b%row(i)%vals(j) + call c%insert(val,i,col) + enddo + enddo + end function plus_zmatrix_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix difference spA - spB = spC + !+------------------------------------------------------------------+ + function minus_zmatrix_csr(a,b) result(c) + type(sparse_zmatrix_csr), intent(in) :: a,b + type(sparse_zmatrix_csr) :: c + integer :: col + complex(8) :: val + integer :: i,j + if(a%Nrow/=b%Nrow)stop "plus_matrix error: a.Nrow != b.Nrow" + if(a%Ncol/=b%Ncol)stop "plus_matrix error: a.Ncol != b.Ncol" + c=a !copy a into c + do i=1,b%Nrow + do j=1,b%row(i)%size + col = b%row(i)%cols(j) + val =-b%row(i)%vals(j) + call c%insert(val,i,col) + enddo + enddo + end function minus_zmatrix_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix left scalar product const*spA = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function left_product_zmatrix_i_csr(C,A) result(B) + integer,intent(in) :: C + type(sparse_zmatrix_csr),intent(in) :: A + type(sparse_zmatrix_csr) :: B + integer :: col + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)*C + call b%insert(val,i,col) + enddo + enddo + end function left_product_zmatrix_i_csr + ! + function left_product_zmatrix_d_csr(C,A) result(B) + real(8),intent(in) :: C + type(sparse_zmatrix_csr),intent(in) :: A + type(sparse_zmatrix_csr) :: B + integer :: col + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)*C + call b%insert(val,i,col) + enddo + enddo + end function left_product_zmatrix_d_csr + ! + function left_product_zmatrix_z_csr(C,A) result(B) + complex(8),intent(in) :: C + type(sparse_zmatrix_csr),intent(in) :: A + type(sparse_zmatrix_csr) :: B + integer :: col + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)*C + call b%insert(val,i,col) + enddo + enddo + end function left_product_zmatrix_z_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix right scalar product spA*const = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function right_product_zmatrix_i_csr(A,C) result(B) + integer,intent(in) :: C + type(sparse_zmatrix_csr),intent(in) :: A + type(sparse_zmatrix_csr) :: B + integer :: col + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)*C + call b%insert(val,i,col) + enddo + enddo + end function right_product_zmatrix_i_csr + ! + function right_product_zmatrix_d_csr(A,C) result(B) + real(8),intent(in) :: C + type(sparse_zmatrix_csr),intent(in) :: A + type(sparse_zmatrix_csr) :: B + integer :: col + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)*C + call b%insert(val,i,col) + enddo + enddo + end function right_product_zmatrix_d_csr + ! + function right_product_zmatrix_z_csr(A,C) result(B) + complex(8),intent(in) :: C + type(sparse_zmatrix_csr),intent(in) :: A + type(sparse_zmatrix_csr) :: B + integer :: col + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)*C + call b%insert(val,i,col) + enddo + enddo + end function right_product_zmatrix_z_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Sparse matrix right scalar division spA/const = spC. + ! type[Const]=integer(4),real(8),cmplx(8) + !+------------------------------------------------------------------+ + function right_division_zmatrix_i_csr(A,C) result(B) + integer,intent(in) :: C + type(sparse_zmatrix_csr),intent(in) :: A + type(sparse_zmatrix_csr) :: B + integer :: col + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)/C + call b%insert(val,i,col) + enddo + enddo + end function right_division_zmatrix_i_csr + ! + function right_division_zmatrix_d_csr(A,C) result(B) + real(8),intent(in) :: C + type(sparse_zmatrix_csr),intent(in) :: A + type(sparse_zmatrix_csr) :: B + integer :: col + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)/C + call b%insert(val,i,col) + enddo + enddo + end function right_division_zmatrix_d_csr + ! + function right_division_zmatrix_z_csr(A,C) result(B) + complex(8),intent(in) :: C + type(sparse_zmatrix_csr),intent(in) :: A + type(sparse_zmatrix_csr) :: B + integer :: col + complex(8) :: val + integer :: i,j + call b%free() + call b%init(a%Nrow,a%Ncol) + do i=1,a%Nrow + do j=1,a%row(i)%size + col = a%row(i)%cols(j) + val = a%row(i)%vals(j)/C + call b%insert(val,i,col) + enddo + enddo + end function right_division_zmatrix_z_csr + ! + !+------------------------------------------------------------------+ + !PURPOSE: Return the identiy sparse matrix of given dimension + ! !+------------------------------------------------------------------+ + ! function zeye_csr(ndim) result(self) + ! type(sparse_zmatrix_csr) :: self + ! integer,intent(in) :: ndim + ! integer :: i + ! call self%init(ndim,ndim) + ! do i=1,ndim + ! call self%insert((1.d0,0.d0),i,i) + ! end do + ! end function zeye_csr + +END MODULE SF_SPARSE_ARRAY_CSR diff --git a/src/SF_SPARSE/SF_SPARSE_COMMON.f90 b/src/SF_SPARSE/SF_SPARSE_COMMON.f90 new file mode 100644 index 000000000..ef674b281 --- /dev/null +++ b/src/SF_SPARSE/SF_SPARSE_COMMON.f90 @@ -0,0 +1,216 @@ +MODULE SF_SPARSE_COMMON + USE SF_LINALG, only: deye,zeye + + implicit none + + interface append + module procedure :: append_I + module procedure :: append_D + module procedure :: append_Z + end interface append + + + + !SPARSE MATRIX + type sparse_matrix + integer :: Nrow + integer :: Ncol + integer :: Nelements + logical :: status=.false. + contains + procedure,pass :: shape => shape_matrix + end type sparse_matrix + + !RETURN SHAPE OF THE SPARSE MATRIX [Nrow,Ncol] + interface shape + module procedure :: shape_matrix + end interface shape + + public :: shape + +contains + + !+------------------------------------------------------------------+ + !PURPOSE: Return the shape of a sparse matrix + !+------------------------------------------------------------------+ + function shape_matrix(self) result(shape) + class(sparse_matrix),intent(in) :: self + integer,dimension(2) :: shape + shape = [self%Nrow,self%Ncol] + end function shape_matrix + + + + + + !+------------------------------------------------------------------+ + !PURPOSE : Sort an array, gives the new ordering of the label. + !+------------------------------------------------------------------+ + subroutine sort_array(array,order) + integer,dimension(:) :: array + integer,dimension(size(array)) :: order + integer,dimension(size(array)) :: backup + integer :: i + forall(i=1:size(array))order(i)=i + call qsort_sort(array, order,1, size(array)) + do i=1,size(array) + backup(i)=array(order(i)) + enddo + array=backup + contains + recursive subroutine qsort_sort( array, order, left, right ) + integer, dimension(:) :: array + integer, dimension(:) :: order + integer :: left + integer :: right + integer :: i + integer :: last + if ( left .ge. right ) return + call qsort_swap( order, left, qsort_rand(left,right) ) + last = left + do i = left+1, right + if ( compare(array(order(i)), array(order(left)) ) .lt. 0 ) then + last = last + 1 + call qsort_swap( order, last, i ) + endif + enddo + call qsort_swap( order, left, last ) + call qsort_sort( array, order, left, last-1 ) + call qsort_sort( array, order, last+1, right ) + end subroutine qsort_sort + !---------------------------------------------! + subroutine qsort_swap( order, first, second ) + integer, dimension(:) :: order + integer :: first, second + integer :: tmp + tmp = order(first) + order(first) = order(second) + order(second) = tmp + end subroutine qsort_swap + !---------------------------------------------! + integer function qsort_rand( lower, upper ) + integer :: lower, upper + real(8) :: r + call random_number(r) + qsort_rand = lower + nint(r * (upper-lower)) + end function qsort_rand + !---------------------------------------------! + function compare(f,g) + implicit none + integer :: f,g + integer :: compare + if(f value) then + bsresult= binary_search(a(:mid-1), value) + else if (a(mid) < value) then + bsresult = binary_search(a(mid+1:size(a)), value) + if (bsresult /= 0) then + bsresult = mid + bsresult + end if + else + bsresult = mid ! SUCCESS ! + end if + ! + bsresult = Order(bsresult) + ! + end function binary_search + + + subroutine append_I(vec,val) + integer,dimension(:),allocatable,intent(inout) :: vec + integer,intent(in) :: val + integer,dimension(:),allocatable :: tmp + integer :: n + ! + if (allocated(vec)) then + n = size(vec) + allocate(tmp(n+1)) + tmp(:n) = vec + call move_alloc(tmp,vec) + n = n + 1 + else + n = 1 + allocate(vec(n)) + end if + ! + !Put val as last entry: + vec(n) = val + ! + if(allocated(tmp))deallocate(tmp) + end subroutine append_I + + subroutine append_D(vec,val) + real(8),dimension(:),allocatable,intent(inout) :: vec + real(8),intent(in) :: val + real(8),dimension(:),allocatable :: tmp + integer :: n + ! + if (allocated(vec)) then + n = size(vec) + allocate(tmp(n+1)) + tmp(:n) = vec + call move_alloc(tmp,vec) + n = n + 1 + else + n = 1 + allocate(vec(n)) + end if + ! + !Put val as last entry: + vec(n) = val + ! + if(allocated(tmp))deallocate(tmp) + end subroutine append_D + + subroutine append_Z(vec,val) + complex(8),dimension(:),allocatable,intent(inout) :: vec + complex(8),intent(in) :: val + complex(8),dimension(:),allocatable :: tmp + integer :: n + ! + if (allocated(vec)) then + n = size(vec) + allocate(tmp(n+1)) + tmp(:n) = vec + call move_alloc(tmp,vec) + n = n + 1 + else + n = 1 + allocate(vec(n)) + end if + ! + !Put val as last entry: + vec(n) = val + ! + if(allocated(tmp))deallocate(tmp) + end subroutine append_Z + + + + + + +END MODULE SF_SPARSE_COMMON