Skip to content

Commit f175161

Browse files
KnutAMfredrikekre
andauthored
Faster conversion to dense matrix (#328)
Co-authored-by: Fredrik Ekre <[email protected]>
1 parent 4eaa458 commit f175161

File tree

3 files changed

+39
-4
lines changed

3 files changed

+39
-4
lines changed

src/sparsematrix.jl

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,32 @@ function copyto!(dest::AbstractMatrix, Rdest::CartesianIndices{2},
641641
return dest
642642
end
643643

644+
# Faster version for non-abstract Array and SparseMatrixCSC
645+
function Base.copyto!(A::Array{T}, S::SparseMatrixCSC{<:Number}) where {T<:Number}
646+
isempty(S) && return A
647+
length(A) < length(S) && throw(BoundsError())
648+
649+
# Zero elements that are also in S, don't change rest of A
650+
@inbounds for i in 1:length(S)
651+
A[i] = zero(T)
652+
end
653+
# Copy the structural nonzeros from S to A using
654+
# the linear indices (to work when size(A)!=size(S))
655+
num_rows = size(S,1)
656+
rowval = getrowval(S)
657+
nzval = getnzval(S)
658+
linear_index_col0 = 0 # Linear index before column (linear index = linear_index_col0 + row)
659+
for col in 1:size(S, 2)
660+
for i in nzrange(S, col)
661+
row = rowval[i]
662+
val = nzval[i]
663+
A[linear_index_col0+row] = val
664+
end
665+
linear_index_col0 += num_rows
666+
end
667+
return A
668+
end
669+
644670
## similar
645671
#
646672
# parent method for similar that preserves stored-entry structure (for when new and old dims match)
@@ -922,7 +948,7 @@ function sparse_with_lmul(Tv, Ti, Q)
922948
return SparseMatrixCSC{Tv,Ti}(size(Q)..., colptr, rowval, nzval)
923949
end
924950

925-
# converting from SparseMatrixCSC to other matrix types
951+
# converting from AbstractSparseMatrixCSC to other matrix types
926952
function Matrix(S::AbstractSparseMatrixCSC{Tv}) where Tv
927953
_checkbuffers(S)
928954
A = Matrix{Tv}(undef, size(S, 1), size(S, 2))

test/sparsematrix_constructors_indexing.jl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ end
3636
@test SparseMatrixCSC{eltype(a), Int}(a) == a
3737
@test SparseMatrixCSC{eltype(a)}(Array(a)) == a
3838
@test Array(SparseMatrixCSC{eltype(a), Int8}(a)) == Array(a)
39+
@test collect(a) == a
3940
end
4041

4142
@testset "sparse matrix construction" begin
@@ -301,7 +302,8 @@ end
301302
@testset "copyto!" begin
302303
A = sprand(5, 5, 0.2)
303304
B = sprand(5, 5, 0.2)
304-
copyto!(A, B)
305+
Ar = copyto!(A, B)
306+
@test Ar === A
305307
@test A == B
306308
@test pointer(nonzeros(A)) != pointer(nonzeros(B))
307309
@test pointer(rowvals(A)) != pointer(rowvals(B))
@@ -339,7 +341,9 @@ end
339341
B = sprand(5, 5, 1.0)
340342
A = rand(5,5)
341343
= similar(A)
342-
@test copyto!(A, B) == copyto!(A´, Matrix(B))
344+
Ac = copyto!(A, B)
345+
@test Ac === A
346+
@test A == copyto!(A´, Matrix(B))
343347
# Test copyto!(dense, Rdest, sparse, Rsrc)
344348
A = rand(5,5)
345349
= similar(A)
@@ -354,11 +358,15 @@ end
354358
@test Matrix(B´)[Rdest] == Matrix(B)[Rsrc]
355359
# Test that only elements at overlapping linear indices are overwritten
356360
A = sprand(3, 3, 1.0); B = ones(4, 4)
357-
copyto!(B, A)
361+
Bc = copyto!(B, A)
358362
@test B[4, :] != B[:, 4] == ones(4)
363+
@test Bc === B
359364
# Allow no-op copyto! with empty source even for incompatible eltypes
360365
A = sparse(fill("", 0, 0))
361366
@test copyto!(B, A) == B
367+
368+
# Test correct error for too small destination array
369+
@test_throws BoundsError copyto!(rand(2,2), sprand(3,3,0.2))
362370
end
363371

364372
@testset "getindex" begin

test/sparsevector.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ end
5959
@test isa(Array(x), Vector{Float64})
6060
@test Array(x) == xf
6161
@test Vector(x) == xf
62+
@test collect(x) == xf
6263
end
6364
end
6465
@testset "show" begin

0 commit comments

Comments
 (0)