Skip to content

Commit 9d7e28d

Browse files
authored
Merge pull request #1158 from srinjoy933/feat-csc2dense2
Enhancement: Add csc2dense conversion routine to complete dense API
2 parents 5c2c391 + 9d669c8 commit 9d7e28d

3 files changed

Lines changed: 83 additions & 4 deletions

File tree

doc/specs/stdlib_sparse.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,16 @@ If the `diagonal` array has not been previously allocated, the `diag` subroutine
296296

297297
### Syntax
298298

299+
`call ` [[stdlib_sparse_conversion(module):csc2dense(interface)]] `(csc,dense)`
300+
301+
### Arguments
302+
303+
`csc` : Shall be a `CSC` type of `real` or `complex` type. It is an `intent(in)` argument.
304+
305+
`dense` : Shall be a rank-2 array of `real` or `complex` type. It is an `intent(out)` argument.
306+
307+
### Syntax
308+
299309
`call ` [[stdlib_sparse_conversion(module):coo2csr(interface)]] `(coo,csr[,sort_data])`
300310

301311
### Arguments

src/sparse/stdlib_sparse_conversion.fypp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,19 @@ module stdlib_sparse_conversion
8585
#:endfor
8686
end interface
8787
public :: csr2dense
88+
89+
!! version: experimental
90+
!!
91+
!! Conversion from csc to dense
92+
!! Enables creating a dense 2D matrix from the non-zero values stored in a CSC format
93+
!! The dense matrix can be allocated on the fly if not pre-allocated by the user.
94+
!! [Specifications](../page/specs/stdlib_sparse.html#sparse_conversion)
95+
interface csc2dense
96+
#:for k1, t1, s1 in (KINDS_TYPES)
97+
module procedure :: csc2dense_${s1}$
98+
#:endfor
99+
end interface
100+
public :: csc2dense
88101

89102
!! version: experimental
90103
!!
@@ -317,6 +330,32 @@ contains
317330
end do
318331
end if
319332
end subroutine
333+
334+
#:endfor
335+
336+
#:for k1, t1, s1 in (KINDS_TYPES)
337+
subroutine csc2dense_${s1}$(CSC,dense)
338+
type(CSC_${s1}$_type), intent(in) :: CSC
339+
${t1}$, allocatable, intent(out) :: dense(:,:)
340+
integer(ilp) :: i, j
341+
342+
if(.not.allocated(dense)) allocate(dense(CSC%nrows,CSC%ncols),source=zero_${s1}$)
343+
if( CSC%storage == sparse_full) then
344+
do j = 1, CSC%ncols
345+
do i = CSC%colptr(j), CSC%colptr(j+1)-1
346+
dense(CSC%row(i),j) = CSC%data(i)
347+
end do
348+
end do
349+
else
350+
do j = 1, CSC%ncols
351+
do i = CSC%colptr(j), CSC%colptr(j+1)-1
352+
dense(CSC%row(i),j) = CSC%data(i)
353+
if( j == CSC%row(i) ) cycle
354+
dense(j,CSC%row(i)) = CSC%data(i)
355+
end do
356+
end do
357+
end if
358+
end subroutine
320359

321360
#:endfor
322361

test/linalg/test_linalg_sparse.fypp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ module test_sparse_spmv
1313

1414
contains
1515

16-
1716
!> Collect all exported unit tests
1817
subroutine collect_suite(testsuite)
1918
!> Collection of tests
@@ -30,7 +29,8 @@ contains
3029
new_unittest('diagonal', test_diagonal), &
3130
new_unittest('add_get_values', test_add_get_values), &
3231
new_unittest('sparse_operators', test_sparse_operators), &
33-
new_unittest('add_block_symmetric_skip', test_add_block_symmetric_skip) &
32+
new_unittest('add_block_symmetric_skip', test_add_block_symmetric_skip), &
33+
new_unittest('csc2dense', test_csc2dense) &
3434
]
3535
end subroutine
3636

@@ -579,10 +579,40 @@ contains
579579
#:endfor
580580

581581
end subroutine
582+
583+
subroutine test_csc2dense(error)
584+
!> Error handling
585+
type(error_type), allocatable, intent(out) :: error
586+
#:for k1, t1, s1 in (KINDS_TYPES)
587+
block
588+
integer, parameter :: wp = ${k1}$
589+
type(COO_${s1}$_type) :: COO
590+
type(CSC_${s1}$_type) :: CSC
591+
${t1}$, allocatable :: dense_original(:,:), dense_converted(:,:)
592+
593+
! 1. Create a baseline dense 4x4 matrix
594+
allocate( dense_original(4,4) , source = &
595+
reshape(real([1,0,0,5, &
596+
0,2,0,0, &
597+
0,6,3,0, &
598+
0,0,7,4],kind=wp),[4,4]) )
599+
600+
! 2. Convert Dense -> COO -> CSC (Standard pipeline)
601+
call dense2coo( dense_original , COO )
602+
call coo2csc( COO, CSC )
603+
604+
! 3. Execute the csc2dense conversion
605+
call csc2dense( CSC, dense_converted )
606+
607+
! 4. Verify the converted matrix perfectly matches the original
608+
call check(error, all(dense_original == dense_converted), "Error: csc2dense conversion failed for kind ${s1}$")
609+
if (allocated(error)) return
610+
end block
611+
#:endfor
612+
end subroutine
582613

583614
end module
584615

585-
586616
program tester
587617
use, intrinsic :: iso_fortran_env, only : error_unit
588618
use testdrive, only : run_testsuite, new_testsuite, testsuite_type
@@ -607,4 +637,4 @@ program tester
607637
write(error_unit, '(i0, 1x, a)') stat, "test(s) failed!"
608638
error stop
609639
end if
610-
end program
640+
end program

0 commit comments

Comments
 (0)