Branch data Line data Source code
1 : : !!****m* ABINIT/m_spmat_convert
2 : : !! NAME
3 : : !! m_spmat_convert
4 : : !!
5 : : !! FUNCTION
6 : : !! This module contains the functions to convert between sparse matrix formats
7 : : !!
8 : : !!
9 : : !! Subroutines:
10 : : !! - dense_to_LIL
11 : : !! - LIL_to_dense
12 : : !! - LIL_to_COO
13 : : !! - LIL_to_CSR
14 : : !! - Dense_to_CSR
15 : : !!
16 : : !!
17 : : !! COPYRIGHT
18 : : !! Copyright (C) 2001-2026 ABINIT group (hexu)
19 : : !! This file is distributed under the terms of the
20 : : !! GNU General Public License, see ~abinit/COPYING
21 : : !! or http://www.gnu.org/copyleft/gpl.txt .
22 : : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
23 : : !!
24 : : !! SOURCE
25 : :
26 : : #if defined HAVE_CONFIG_H
27 : : #include "config.h"
28 : : #endif
29 : : #include "abi_common.h"
30 : :
31 : :
32 : : module m_spmat_convert
33 : : use defs_basis
34 : : use m_xmpi
35 : : use m_abicore
36 : : use m_errors
37 : : use m_spmat_dense
38 : : use m_linked_list
39 : : use m_spmat_lil
40 : : use m_spmat_csr
41 : : use m_spmat_coo
42 : : use m_spmat_lco
43 : : implicit none
44 : : !!****m*
45 : : public
46 : : !-----------------------------------------------------------------------
47 : : !> @brief convert one type of matrix Amat to the other Bmat
48 : : !> Note that the dense matrix is not the dense_mat_t because a
49 : : !> simple 2d array is more generally used.
50 : : !> @param [in] Amat
51 : : !> @param [out] Bmat
52 : : !-----------------------------------------------------------------------
53 : : interface spmat_convert
54 : : !procedure dense_to_LIL
55 : : procedure LIL_to_dense
56 : : procedure LIL_to_COO
57 : : procedure LIL_to_CSR
58 : : procedure dense_to_CSR
59 : : procedure dense_to_COO
60 : : procedure COO_to_CSR
61 : : !procedure LCO_to_CSR
62 : : end interface spmat_convert
63 : :
64 : : public :: COO_to_dense
65 : : contains
66 : :
67 : : !-----------------------------------------------------------------------
68 : : !> @brief dense matrix to LIL matrix
69 : : !> @param [in] mat: 2D array
70 : : !> @param [out] ll : LIL matrix
71 : : !-----------------------------------------------------------------------
72 [ # # ]: 0 : subroutine dense_to_LIL(mat, ll)
73 : : ! check shape
74 : : real(dp), intent(in):: mat(:, :)
75 : : type(LIL_mat_t), intent(inout) :: ll
76 : : integer :: s(2), irow, icol
77 [ # # ]: 0 : s=shape(mat)
78 : 0 : call ll%initialize(s)
79 [ # # ]: 0 : do icol=1, ll%ncol, 1
80 [ # # ]: 0 : do irow=1, ll%nrow, 1
81 : 0 : call ll%insert(irow,icol,mat(irow, icol),0)
82 : : enddo
83 : : enddo
84 : 0 : end subroutine dense_to_LIL
85 : :
86 : : !-----------------------------------------------------------------------
87 : : !> @brief LIL matrix to dense matrix
88 : : !> @param [in] ll : LIL matrix
89 : : !> @param [out] mat: 2D array
90 : : !-----------------------------------------------------------------------
91 : 0 : subroutine LIL_to_dense(ll, mat)
92 : : class(LIL_mat_t) , intent(inout):: ll
93 : : real(dp), intent(out):: mat(ll%nrow,ll%ncol)
94 : : integer:: irow
95 [ # # # # ]: 0 : mat(:,:)=0.0d0
96 [ # # ]: 0 : do irow=1, ll%nrow
97 : 0 : call llist_iter_restart(ll%rows(irow))
98 [ # # ]: 0 : do while(associated(ll%rows(irow)%iter))
99 : 0 : mat(irow, ll%rows(irow)%iter%i)=ll%rows(irow)%iter%val
100 : 0 : ll%rows(irow)%iter=>ll%rows(irow)%iter%next
101 : : enddo
102 : : enddo
103 : 0 : end subroutine LIL_to_dense
104 : :
105 : : !-----------------------------------------------------------------------
106 : : !> @brief LIL matrix to COO matrix
107 : : !> @param [in] ll : LIL matrix
108 : : !> @param [out] csrmat: COO matrix
109 : : !-----------------------------------------------------------------------
110 [ # # ]: 0 : subroutine LIL_to_COO(ll, COO)
111 : : class(LIL_mat_t) , intent(inout):: ll
112 : : class(COO_mat_t), intent(out):: COO
113 : : integer :: irow
114 : 0 : call COO%initialize(mshape=ll%mshape)
115 [ # # ]: 0 : do irow=1, ll%nrow
116 : 0 : call llist_iter_restart(ll%rows(irow))
117 [ # # ]: 0 : do while(associated(ll%rows(irow)%iter))
118 [ # # ]: 0 : call coo%add_entry([irow, ll%rows(irow)%iter%i], ll%rows(irow)%iter%val)
119 : 0 : ll%rows(irow)%iter=>ll%rows(irow)%iter%next
120 : : enddo
121 : : end do
122 : :
123 : 0 : end subroutine LIL_to_COO
124 : :
125 : : !-----------------------------------------------------------------------
126 : : !> @brief LIL matrix to CSR matrix
127 : : !> @param [in] ll : LIL matrix
128 : : !> @param [out] csrmat: CSR matrix
129 : : !-----------------------------------------------------------------------
130 : 2 : subroutine LIL_to_CSR(ll, csrmat)
131 : : type(LIL_mat_t) , intent(inout):: ll
132 : : type(CSR_mat_t), intent(inout):: csrmat
133 : : integer:: irow, i, nzrow
134 [ + + ]: 6 : call csrmat%initialize([ll%nrow, ll%ncol])
135 : 2 : call csrmat%set(nnz=ll%get_nnz())
136 : 2 : i=0
137 : 2 : csrmat%row_shift(1)=1
138 [ + + ]: 1298 : do irow=1, ll%nrow
139 : 1296 : nzrow=0
140 : 1296 : call llist_iter_restart(ll%rows(irow))
141 [ + + ]: 34992 : do while(associated(ll%rows(irow)%iter))
142 : 33696 : nzrow=nzrow+1
143 : 33696 : i=i+1
144 : 33696 : csrmat%icol(i)=ll%rows(irow)%iter%i
145 : 33696 : csrmat%val(i)=ll%rows(irow)%iter%val
146 : 33696 : ll%rows(irow)%iter=>ll%rows(irow)%iter%next
147 : : enddo
148 : 1298 : csrmat%row_shift(irow+1)=csrmat%row_shift(irow)+nzrow
149 : : enddo
150 : 2 : end subroutine LIL_to_CSR
151 : :
152 : : !-----------------------------------------------------------------------
153 : : !> @brief dense matrix to CSR matrix
154 : : !> @param [in] mat: dense matrix
155 : : !> @param [out] csrmat: CSR matrix
156 : : !-----------------------------------------------------------------------
157 [ # # # # : 0 : subroutine dense_to_CSR(mat, csrmat)
# # # # #
# # # # #
# # ]
158 : : real(dp), intent(in):: mat(:, :)
159 : : type(csr_mat_t), intent(out) :: csrmat
160 : : !type(lil_mat_t):: lilmat
161 : : integer :: i, j, nnz, nrow, ncol, inz, nzrow
162 : : !call dense_to_lil(mat, lilmat)
163 : : !call lil_to_csr(lilmat, csrmat)
164 : : !call lilmat%finalize()
165 [ # # # # : 0 : nnz=count(mat /= 0.0_dp)
# # ]
166 : 0 : nrow=size(mat, 1)
167 : 0 : ncol=size(mat, 2)
168 [ # # ]: 0 : call csrmat%initialize([nrow, ncol])
169 : 0 : call csrmat%set(nnz=nnz)
170 : 0 : csrmat%row_shift(1)=1
171 : 0 : inz=0
172 [ # # ]: 0 : do i=1, nrow
173 : : nzrow=0
174 [ # # ]: 0 : do j=1, ncol
175 [ # # ]: 0 : if (mat(i, j)/=0.0_dp) then
176 : 0 : inz=inz+1
177 : 0 : nzrow=nzrow+1
178 : 0 : csrmat%icol(inz)=j
179 : 0 : csrmat%val(inz)=mat(i,j)
180 : : end if
181 : : end do
182 : 0 : csrmat%row_shift(i+1)=csrmat%row_shift(i)+nzrow
183 : : end do
184 : 0 : end subroutine dense_to_CSR
185 : :
186 : : !-------------------------------------------------------------------!
187 : : ! dense_to_coo
188 : : ! Dense to COO matrix convertion
189 : : !-------------------------------------------------------------------!
190 [ # # ]: 0 : subroutine dense_to_coo(mat, coo)
191 : : real(dp), intent(in) :: mat(:,:)
192 : : type(coo_mat_t), intent(inout) :: coo
193 : : integer:: i, j
194 [ # # ]: 0 : call coo%initialize(shape(mat))
195 [ # # ]: 0 : do j=1, size(mat, dim=2)
196 [ # # ]: 0 : do i=1, size(mat, dim=1)
197 [ # # ]: 0 : if (abs(mat(i, j)) >tiny(1.0d0) ) then
198 [ # # ]: 0 : call coo%add_entry(ind=[i,j], val=mat(i,j))
199 : : end if
200 : : end do
201 : : end do
202 : 0 : end subroutine dense_to_coo
203 : :
204 : : !-------------------------------------------------------------------!
205 : : ! COO_to_CSR:
206 : : ! translate COO matrix to CSR matrix
207 : : ! NOTE: This can be quite slow when it is large due to the sort algorithm
208 : : ! Input:
209 : : ! COO matrix
210 : : ! Output:
211 : : ! CSR matrix
212 : : !-------------------------------------------------------------------!
213 : 1 : subroutine COO_to_CSR(coo, csr)
214 : : type(COO_mat_t), intent(inout) :: coo
215 : : type(CSR_mat_t), intent(inout) :: csr
216 : : integer :: ngroup
217 : 1 : integer, allocatable :: i1_list(:), istartend(:)
218 : 2 : integer :: row_nz(coo%mshape(1))
219 : : integer :: i, irow
220 : 1 : call coo%group_by_1dim(ngroup, i1_list, istartend)
221 : 1 : call csr%initialize(coo%mshape)
222 : 1 : call csr%set(nnz=coo%nnz)
223 [ + + ]: 67585 : csr%icol(:)=coo%ind%data(2,1:coo%nnz)
224 [ + + ]: 67585 : csr%val(:) = coo%val%data(1:coo%nnz)
225 [ + + ]: 1026 : csr%row_shift(:)=0
226 [ + + ]: 1025 : row_nz(:)=0
227 [ + + ]: 1025 : do i=1, ngroup
228 : 1024 : irow=i1_list(i)
229 : 1025 : row_nz(irow) = istartend(i+1)-istartend(i)
230 : : end do
231 : :
232 : 1 : csr%row_shift(1)=1
233 [ + + ]: 1025 : do i=2, csr%nrow+1
234 : 1025 : csr%row_shift(i)= csr%row_shift(i-1)+row_nz(i-1)
235 : : end do
236 [ + - ]: 1 : ABI_SFREE(i1_list)
237 [ + - ]: 1 : ABI_SFREE(istartend)
238 [ - + - + ]: 1 : end subroutine COO_to_CSR
239 : :
240 : :
241 : : !-------------------------------------------------------------------!
242 : : ! COO_to_dense
243 : : ! COO matrix to dense matrix
244 : : ! Input:
245 : : ! COO: coo matrix
246 : : ! Output:
247 : : ! dense: dense matrix
248 : : !-------------------------------------------------------------------!
249 [ # # ]: 0 : subroutine COO_to_dense(coo, dense)
250 : : type(COO_mat_t), intent(inout) :: coo
251 : : real(dp), intent(inout) :: dense(:,:)
252 : : integer :: i, j, inz
253 : : real(dp) :: val
254 [ # # # # ]: 0 : dense(:,:) =0.0
255 [ # # ]: 0 : do inz =1, coo%nnz
256 : 0 : i=coo%ind%data(1, inz)
257 : 0 : j=coo%ind%data(2, inz)
258 : 0 : val= coo%val%data(inz)
259 : 0 : dense(i,j) = dense(i,j) + val
260 : : end do
261 : 0 : end subroutine COO_to_dense
262 : :
263 : :
264 : : ! subroutine LCO_to_CSR(lco, csr)
265 : : ! type(LCO_mat_t), intent(inout) :: lco
266 : : ! type(CSR_mat_t), intent(inout) :: csr
267 : : ! integer, allocatable :: i1_list(:), istartend(:)
268 : : ! integer :: row_nz(lco%mshape(1))
269 : : ! integer :: i, irow
270 : : !
271 : : ! end subroutine LCO_to_CSR
272 : :
273 : :
274 : :
275 : 0 : subroutine spmat_convert_unittest()
276 : : real(dp) ::mat(4,4), x(4), b(4)
277 : 0 : type(coo_mat_t) :: coo
278 : 0 : type(csr_mat_t) :: csr, csr2
279 : : integer :: ngroup
280 : 0 : integer, allocatable :: i1list(:), ise(:)
281 : 0 : mat=reshape([1,2,0,0, 8, 3, 0,0, 0,2,0,0, 0,0,0,9], [4,4])*1.0d0
282 : 0 : call dense_to_coo(mat, coo)
283 : 0 : call coo%sum_duplicates()
284 : 0 : call dense_to_csr(mat, csr)
285 : 0 : call coo%group_by_1dim(ngroup, i1list, ise)
286 : 0 : call coo%sum_duplicates()
287 [ # # ]: 0 : ABI_SFREE(i1list)
288 [ # # ]: 0 : ABI_SFREE(ise)
289 : 0 : call coo_to_csr(coo, csr2)
290 : :
291 : 0 : x=[1,2,3,4]
292 [ # # # # ]: 0 : b=matmul(mat, x)
293 : 0 : b=0
294 : 0 : call csr%mv(x, b)
295 : 0 : b=0
296 : 0 : call csr2%mv(x, b)
297 : :
298 : 0 : b=0
299 : 0 : call csr2%mv(x, b)
300 : :
301 : :
302 : :
303 : 0 : call coo%finalize()
304 : 0 : call csr%finalize()
305 : 0 : call csr2%finalize()
306 [ # # # # : 0 : end subroutine spmat_convert_unittest
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
307 : :
308 : :
309 : : end module m_spmat_convert
|