Skip to content

Commit 1e53916

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

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
@@ -3264,41 +3264,6 @@ function hcat(X::SparseMatrixCSC...)
32643264
SparseMatrixCSC(m, n, colptr, rowval, nzval)
32653265
end
32663266

3267-
3268-
# Sparse/special/dense concatenation
3269-
3270-
# TODO: A similar definition also exists in base/linalg/bidiag.jl. These definitions should
3271-
# be consolidated in a more appropriate location, for example base/linalg/special.jl.
3272-
SpecialArrays = Union{Diagonal, Bidiagonal, Tridiagonal, SymTridiagonal}
3273-
3274-
function hcat(Xin::Union{Vector, Matrix, SparseMatrixCSC, SpecialArrays}...)
3275-
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
3276-
hcat(X...)
3277-
end
3278-
3279-
function vcat(Xin::Union{Vector, Matrix, SparseMatrixCSC, SpecialArrays}...)
3280-
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
3281-
vcat(X...)
3282-
end
3283-
3284-
function hvcat(rows::Tuple{Vararg{Int}}, X::Union{Vector, Matrix, SparseMatrixCSC, SpecialArrays}...)
3285-
nbr = length(rows) # number of block rows
3286-
3287-
tmp_rows = Array{SparseMatrixCSC}(nbr)
3288-
k = 0
3289-
@inbounds for i = 1 : nbr
3290-
tmp_rows[i] = hcat(X[(1 : rows[i]) + k]...)
3291-
k += rows[i]
3292-
end
3293-
vcat(tmp_rows...)
3294-
end
3295-
3296-
function cat(catdims, Xin::Union{Vector, Matrix, SparseMatrixCSC, SpecialArrays}...)
3297-
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
3298-
T = promote_eltype(Xin...)
3299-
Base.cat_t(catdims, T, X...)
3300-
end
3301-
33023267
"""
33033268
blkdiag(A...)
33043269

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, instead
726+
# of _absspvec_hcat below. The <:Integer qualifications are necessary for correct 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, instead
761+
# of _absspvec_vcat below. The <:Integer qualifications are necessary for correct 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)