Skip to content

Commit 1c1c7cc

Browse files
committed
Make concatenations involving combinations of sparse vectors with various matrix and vector types consistently yield sparse arrays.
1 parent b2523ae commit 1c1c7cc

File tree

3 files changed

+89
-39
lines changed

3 files changed

+89
-39
lines changed

base/sparse/sparsematrix.jl

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3228,41 +3228,6 @@ function hcat(X::SparseMatrixCSC...)
32283228
SparseMatrixCSC(m, n, colptr, rowval, nzval)
32293229
end
32303230

3231-
3232-
# Sparse/special/dense concatenation
3233-
3234-
# TODO: A similar definition also exists in base/linalg/bidiag.jl. These definitions should
3235-
# be consolidated in a more appropriate location, for example base/linalg/special.jl.
3236-
SpecialArrays = Union{Diagonal, Bidiagonal, Tridiagonal, SymTridiagonal}
3237-
3238-
function hcat(Xin::Union{Vector, Matrix, SparseMatrixCSC, SpecialArrays}...)
3239-
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
3240-
hcat(X...)
3241-
end
3242-
3243-
function vcat(Xin::Union{Vector, Matrix, SparseMatrixCSC, SpecialArrays}...)
3244-
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
3245-
vcat(X...)
3246-
end
3247-
3248-
function hvcat(rows::Tuple{Vararg{Int}}, X::Union{Vector, Matrix, SparseMatrixCSC, SpecialArrays}...)
3249-
nbr = length(rows) # number of block rows
3250-
3251-
tmp_rows = Array{SparseMatrixCSC}(nbr)
3252-
k = 0
3253-
@inbounds for i = 1 : nbr
3254-
tmp_rows[i] = hcat(X[(1 : rows[i]) + k]...)
3255-
k += rows[i]
3256-
end
3257-
vcat(tmp_rows...)
3258-
end
3259-
3260-
function cat(catdims, Xin::Union{Vector, Matrix, SparseMatrixCSC, SpecialArrays}...)
3261-
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
3262-
T = promote_eltype(Xin...)
3263-
Base.cat_t(catdims, T, X...)
3264-
end
3265-
32663231
"""
32673232
blkdiag(A...)
32683233

base/sparse/sparsevector.jl

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,13 @@ complex(x::AbstractSparseVector) =
720720

721721
### Concatenation
722722

723-
function hcat{Tv,Ti}(X::AbstractSparseVector{Tv,Ti}...)
723+
# Without the first of these methods, horizontal concatenations of SparseVectors fall
724+
# back to the horizontal concatenation method that ensures that combinations of
725+
# sparse/special/dense matrix/vector types concatenate to SparseMatrixCSCs rather than
726+
# Arrays. The <:Integer qualifications are necessary for correct diagonal dispatch.
727+
hcat{Tv,Ti<:Integer}(X::SparseVector{Tv,Ti}...) = _absspvec_hcat(X...)
728+
hcat{Tv,Ti<:Integer}(X::AbstractSparseVector{Tv,Ti}...) = _absspvec_hcat(X...)
729+
function _absspvec_hcat{Tv,Ti}(X::AbstractSparseVector{Tv,Ti}...)
724730
# check sizes
725731
n = length(X)
726732
m = length(X[1])
@@ -749,7 +755,13 @@ function hcat{Tv,Ti}(X::AbstractSparseVector{Tv,Ti}...)
749755
SparseMatrixCSC{Tv,Ti}(m, n, colptr, nzrow, nzval)
750756
end
751757

752-
function vcat{Tv,Ti}(X::AbstractSparseVector{Tv,Ti}...)
758+
# Without the first of these methods, vertical concatenations of SparseVectors fall
759+
# back to the vertical concatenation method that ensures that combinations of
760+
# sparse/special/dense matrix/vector types concatenate to SparseMatrixCSCs rather than
761+
# Arrays. The <:Integer qualifications are necessary for correct diagonal dispatch.
762+
vcat{Tv,Ti<:Integer}(X::SparseVector{Tv,Ti}...) = _absspvec_vcat(X...)
763+
vcat{Tv,Ti<:Integer}(X::AbstractSparseVector{Tv,Ti}...) = _absspvec_vcat(X...)
764+
function _absspvec_vcat{Tv,Ti}(X::AbstractSparseVector{Tv,Ti}...)
753765
# check sizes
754766
n = length(X)
755767
tnnz = 0
@@ -777,11 +789,49 @@ function vcat{Tv,Ti}(X::AbstractSparseVector{Tv,Ti}...)
777789
SparseVector(len, rnzind, rnzval)
778790
end
779791

780-
hcat(Xin::Union{AbstractSparseVector, SparseMatrixCSC}...) = hcat(map(SparseMatrixCSC, Xin)...)
781-
vcat(Xin::Union{AbstractSparseVector, SparseMatrixCSC}...) = vcat(map(SparseMatrixCSC, Xin)...)
782792
hcat(Xin::Union{Vector, AbstractSparseVector}...) = hcat(map(sparse, Xin)...)
783793
vcat(Xin::Union{Vector, AbstractSparseVector}...) = vcat(map(sparse, Xin)...)
784794

795+
796+
### Sparse/special/dense vector/matrix concatenation
797+
798+
# TODO: These methods should be moved to a more appropriate location, particularly some
799+
# future equivalent of base/linalg/special.jl dedicated to interactions between a broader
800+
# set of matrix types.
801+
802+
# TODO: A similar definition also exists in base/linalg/bidiag.jl. These definitions should
803+
# be consolidated in a more appropriate location, for example base/linalg/special.jl.
804+
SpecialArrays = Union{Diagonal, Bidiagonal, Tridiagonal, SymTridiagonal}
805+
806+
function hcat(Xin::Union{Vector, Matrix, SparseVector, SparseMatrixCSC, SpecialArrays}...)
807+
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
808+
hcat(X...)
809+
end
810+
811+
function vcat(Xin::Union{Vector, Matrix, SparseVector, SparseMatrixCSC, SpecialArrays}...)
812+
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
813+
vcat(X...)
814+
end
815+
816+
function hvcat(rows::Tuple{Vararg{Int}}, X::Union{Vector, Matrix, SparseVector, SparseMatrixCSC, SpecialArrays}...)
817+
nbr = length(rows) # number of block rows
818+
819+
tmp_rows = Array{SparseMatrixCSC}(nbr)
820+
k = 0
821+
@inbounds for i = 1 : nbr
822+
tmp_rows[i] = hcat(X[(1 : rows[i]) + k]...)
823+
k += rows[i]
824+
end
825+
vcat(tmp_rows...)
826+
end
827+
828+
function cat(catdims, Xin::Union{Vector, Matrix, SparseVector, SparseMatrixCSC, SpecialArrays}...)
829+
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
830+
T = promote_eltype(Xin...)
831+
Base.cat_t(catdims, T, X...)
832+
end
833+
834+
785835
### math functions
786836

787837
### Unary Map

test/sparsedir/sparsevector.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,41 @@ let m = 80, n = 100
404404
@test full(V) == Vr
405405
end
406406

407+
# Test that concatenations of combinations of sparse vectors with various other
408+
# matrix/vector types yield sparse arrays
409+
let
410+
N = 4
411+
spvec = spzeros(N)
412+
spmat = spzeros(N, 1)
413+
densevec = ones(N)
414+
densemat = ones(N, 1)
415+
diagmat = Diagonal(ones(4))
416+
# Test that concatenations of pairwise combinations of sparse vectors with dense
417+
# vectors/matrices, sparse matrices, or special matrices yield sparse arrays
418+
for othervecormat in (densevec, densemat, spmat)
419+
@test issparse(vcat(spvec, othervecormat))
420+
@test issparse(vcat(othervecormat, spvec))
421+
end
422+
for othervecormat in (densevec, densemat, spmat, diagmat)
423+
@test issparse(hcat(spvec, othervecormat))
424+
@test issparse(hcat(othervecormat, spvec))
425+
@test issparse(hvcat((2,), spvec, othervecormat))
426+
@test issparse(hvcat((2,), othervecormat, spvec))
427+
@test issparse(cat((1,2), spvec, othervecormat))
428+
@test issparse(cat((1,2), othervecormat, spvec))
429+
end
430+
# The preceding tests should cover multi-way combinations of those types, but for good
431+
# measure test a few multi-way combinations involving those types
432+
@test issparse(vcat(spvec, densevec, spmat, densemat))
433+
@test issparse(vcat(densevec, spvec, densemat, spmat))
434+
@test issparse(hcat(spvec, densemat, spmat, densevec, diagmat))
435+
@test issparse(hcat(densemat, spmat, spvec, densevec, diagmat))
436+
@test issparse(hvcat((5,), diagmat, densevec, spvec, densemat, spmat))
437+
@test issparse(hvcat((5,), spvec, densemat, diagmat, densevec, spmat))
438+
@test issparse(cat((1,2), densemat, diagmat, spmat, densevec, spvec))
439+
@test issparse(cat((1,2), spvec, diagmat, densevec, spmat, densemat))
440+
end
441+
407442

408443
## sparsemat: combinations with sparse matrix
409444

0 commit comments

Comments
 (0)