Skip to content

Commit e946f6a

Browse files
authored
Backport: Fixes to vcat of vectors and numbers (#253) (#257)
1 parent 48c37e7 commit e946f6a

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

src/sparsevector.jl

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,20 +1075,27 @@ const _Annotated_SparseConcatArrays = Union{_Triangular_SparseConcatArrays, _Sym
10751075
const _SparseConcatGroup = Union{_DenseConcatGroup, _SparseConcatArrays, _Annotated_SparseConcatArrays}
10761076

10771077
# Concatenations involving un/annotated sparse/special matrices/vectors should yield sparse arrays
1078+
1079+
# the output array type is determined by the first element of the to be concatenated objects
1080+
# if this is a Number, the output would be dense by the fallback abstractarray.jl code (see cat_similar)
1081+
# so make sure that if that happens, the "array" is sparse (if more sparse arrays are involved, of course)
1082+
_sparse(x::Number) = sparsevec([1], [x], 1)
1083+
_sparse(A) = _makesparse(A)
10781084
_makesparse(x::Number) = x
1079-
_makesparse(x::AbstractArray) = SparseMatrixCSC(issparse(x) ? x : sparse(x))
1085+
_makesparse(x::AbstractVector) = convert(SparseVector, issparse(x) ? x : sparse(x))::SparseVector
1086+
_makesparse(x::AbstractMatrix) = convert(SparseMatrixCSC, issparse(x) ? x : sparse(x))::SparseMatrixCSC
10801087

10811088
function Base._cat(dims, Xin::_SparseConcatGroup...)
1082-
X = map(_makesparse, Xin)
1089+
X = (_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...)
10831090
T = promote_eltype(Xin...)
10841091
Base.cat_t(T, X...; dims=dims)
10851092
end
10861093
function hcat(Xin::_SparseConcatGroup...)
1087-
X = map(_makesparse, Xin)
1094+
X = (_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...)
10881095
return cat(X..., dims=Val(2))
10891096
end
10901097
function vcat(Xin::_SparseConcatGroup...)
1091-
X = map(_makesparse, Xin)
1098+
X = (_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...)
10921099
return cat(X..., dims=Val(1))
10931100
end
10941101
hvcat(rows::Tuple{Vararg{Int}}, X::_SparseConcatGroup...) =
@@ -1122,9 +1129,9 @@ Concatenate along dimension 2. Return a SparseMatrixCSC object.
11221129
the concatenation with specialized "sparse" matrix types from LinearAlgebra.jl
11231130
automatically yielded sparse output even in the absence of any SparseArray argument.
11241131
"""
1125-
sparse_hcat(Xin::Union{AbstractVecOrMat,Number}...) = cat(map(_makesparse, Xin)..., dims=Val(2))
1132+
sparse_hcat(Xin::Union{AbstractVecOrMat,Number}...) = cat(_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))..., dims=Val(2))
11261133
function sparse_hcat(X::Union{AbstractVecOrMat,UniformScaling,Number}...)
1127-
LinearAlgebra._hcat(X...; array_type = SparseMatrixCSC)
1134+
LinearAlgebra._hcat(_sparse(first(X)), map(_makesparse, Base.tail(X))...; array_type = SparseMatrixCSC)
11281135
end
11291136

11301137
"""
@@ -1137,9 +1144,9 @@ Concatenate along dimension 1. Return a SparseMatrixCSC object.
11371144
the concatenation with specialized "sparse" matrix types from LinearAlgebra.jl
11381145
automatically yielded sparse output even in the absence of any SparseArray argument.
11391146
"""
1140-
sparse_vcat(Xin::Union{AbstractVecOrMat,Number}...) = cat(map(_makesparse, Xin)..., dims=Val(1))
1147+
sparse_vcat(Xin::Union{AbstractVecOrMat,Number}...) = cat(_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))..., dims=Val(1))
11411148
function sparse_vcat(X::Union{AbstractVecOrMat,UniformScaling,Number}...)
1142-
LinearAlgebra._vcat(X...; array_type = SparseMatrixCSC)
1149+
LinearAlgebra._vcat(_sparse(first(X)), map(_makesparse, Base.tail(X))...; array_type = SparseMatrixCSC)
11431150
end
11441151

11451152
"""
@@ -1155,10 +1162,10 @@ arguments to concatenate in each block row.
11551162
automatically yielded sparse output even in the absence of any SparseArray argument.
11561163
"""
11571164
function sparse_hvcat(rows::Tuple{Vararg{Int}}, Xin::Union{AbstractVecOrMat,Number}...)
1158-
hvcat(rows, map(_makesparse, Xin)...)
1165+
hvcat(rows, _sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...)
11591166
end
11601167
function sparse_hvcat(rows::Tuple{Vararg{Int}}, X::Union{AbstractVecOrMat,UniformScaling,Number}...)
1161-
LinearAlgebra._hvcat(rows, X...; array_type = SparseMatrixCSC)
1168+
LinearAlgebra._hvcat(rows, _sparse(first(X)), map(_makesparse, Base.tail(X))...; array_type = SparseMatrixCSC)
11621169
end
11631170

11641171
### math functions

test/sparsevector.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,22 @@ end
537537
@test length(V) == m * n
538538
Vr = vec(Hr)
539539
@test Array(V) == Vr
540+
Vnum = vcat(A..., zero(Float64))
541+
Vnum2 = sparse_vcat(map(Array, A)..., zero(Float64))
542+
@test Vnum isa SparseVector{Float64,Int}
543+
@test Vnum2 isa SparseVector{Float64,Int}
544+
@test length(Vnum) == length(Vnum2) == m*n + 1
545+
@test Array(Vnum) == Array(Vnum2) == [Vr; 0]
546+
Vnum = vcat(zero(Float64), A...)
547+
Vnum2 = sparse_vcat(zero(Float64), map(Array, A)...)
548+
@test Vnum isa SparseVector{Float64,Int}
549+
@test Vnum2 isa SparseVector{Float64,Int}
550+
@test length(Vnum) == length(Vnum2) == m*n + 1
551+
@test Array(Vnum) == Array(Vnum2) == [0; Vr]
552+
# case with rowwise a Number as first element, should still yield a sparse matrix
553+
x = sparsevec([1], [3.0], 1)
554+
X = [3.0 x; 3.0 x]
555+
@test issparse(X)
540556
end
541557

542558
@testset "concatenation of sparse vectors with other types" begin

0 commit comments

Comments
 (0)