From 788e01ecf83bbb50d62dcd27d8a1f49ed186a50d Mon Sep 17 00:00:00 2001 From: Sacha Verweij Date: Thu, 28 Jul 2016 14:03:12 -0700 Subject: [PATCH] Make general concatenations (`cat`) of combinations of sparse matrices with sparse matrices or dense matrices/vectors yield sparse arrays (fixes #17680). --- base/abstractarray.jl | 2 +- base/array.jl | 3 +++ base/sparse/sparse.jl | 4 ++-- base/sparse/sparsematrix.jl | 6 ++++++ test/sparsedir/sparse.jl | 32 ++++++++++++++++++++++++-------- 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index ca46ba05d13c1..067cdd0093174 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -998,7 +998,7 @@ function cat_t(catdims, typeC::Type, X...) end end - C = similar(isa(X[1],AbstractArray) ? full(X[1]) : [X[1]], typeC, tuple(dimsC...)) + C = similar(isa(X[1],AbstractArray) ? X[1] : [X[1]], typeC, tuple(dimsC...)) if length(catdims)>1 fill!(C,0) end diff --git a/base/array.jl b/base/array.jl index 19e548054e338..4fc67b12ba356 100644 --- a/base/array.jl +++ b/base/array.jl @@ -699,6 +699,9 @@ hvcat{T}(rows::Tuple{Vararg{Int}}, xs::Vector{T}...) = typed_hvcat(T, rows, xs.. hvcat(rows::Tuple{Vararg{Int}}, xs::Matrix...) = typed_hvcat(promote_eltype(xs...), rows, xs...) hvcat{T}(rows::Tuple{Vararg{Int}}, xs::Matrix{T}...) = typed_hvcat(T, rows, xs...) +cat(catdims, xs::Union{Matrix,Vector}...) = Base.cat_t(catdims, promote_eltype(xs...), xs...) +cat{T}(catdims, xs::Union{Matrix{T},Vector{T}}...) = Base.cat_t(catdims, T, xs...) + ## find ## # returns the index of the next non-zero element, or 0 if all zeros diff --git a/base/sparse/sparse.jl b/base/sparse/sparse.jl index e303c0e0b8969..189a8562814df 100644 --- a/base/sparse/sparse.jl +++ b/base/sparse/sparse.jl @@ -21,10 +21,10 @@ import Base: @get!, acos, acosd, acot, acotd, acsch, asech, asin, asind, asinh, tand, tanh, trace, transpose!, tril!, triu!, trunc, vecnorm, abs, abs2, broadcast, ceil, complex, cond, conj, convert, copy, copy!, ctranspose, diagm, exp, expm1, factorize, find, findmax, findmin, findnz, float, full, getindex, - hcat, hvcat, imag, indmax, ishermitian, kron, length, log, log1p, max, min, + vcat, hcat, hvcat, cat, imag, indmax, ishermitian, kron, length, log, log1p, max, min, maximum, minimum, norm, one, promote_eltype, real, reinterpret, reshape, rot180, rotl90, rotr90, round, scale!, setindex!, similar, size, transpose, tril, - triu, vcat, vec, permute! + triu, vec, permute! import Base.Broadcast: broadcast_shape diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 876f1e74b0cae..821e04d4d18da 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -3253,6 +3253,12 @@ function hvcat(rows::Tuple{Vararg{Int}}, X::Union{Vector, Matrix, SparseMatrixCS vcat(tmp_rows...) end +function cat(catdims, Xin::Union{Vector, Matrix, SparseMatrixCSC}...) + X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin] + T = promote_eltype(Xin...) + Base.cat_t(catdims, T, X...) +end + """ blkdiag(A...) diff --git a/test/sparsedir/sparse.jl b/test/sparsedir/sparse.jl index fbe6e18f9a3b4..e6d4e9767e2b1 100644 --- a/test/sparsedir/sparse.jl +++ b/test/sparsedir/sparse.jl @@ -1554,14 +1554,30 @@ end @inferred sprand(1, 1, 1.0, rand, Float64) @inferred sprand(1, 1, 1.0, x->round(Int,rand(x)*100)) -# dense sparse concatenation -> sparse return type -@test issparse([sprand(10,10,.1) rand(10,10)]) -@test issparse([sprand(10,10,.1); rand(10,10)]) -@test issparse([sprand(10,10,.1) rand(10,10); rand(10,10) rand(10,10)]) -# --- -@test !issparse([rand(10,10) rand(10,10)]) -@test !issparse([rand(10,10); rand(10,10)]) -@test !issparse([rand(10,10) rand(10,10); rand(10,10) rand(10,10)]) +# Test that concatenations of combinations of sparse matrices with sparse matrices or dense +# matrices/vectors yield sparse arrays +let + N = 4 + densevec = ones(N) + densemat = diagm(ones(N)) + spmat = spdiagm(ones(N)) + # Test that concatenations of pairs of sparse matrices yield sparse arrays + @test issparse(vcat(spmat, spmat)) + @test issparse(hcat(spmat, spmat)) + @test issparse(hvcat((2,), spmat, spmat)) + @test issparse(cat((1,2), spmat, spmat)) + # Test that concatenations of a sparse matrice with a dense matrix/vector yield sparse arrays + @test issparse(vcat(spmat, densemat)) + @test issparse(vcat(densemat, spmat)) + for densearg in (densevec, densemat) + @test issparse(hcat(spmat, densearg)) + @test issparse(hcat(densearg, spmat)) + @test issparse(hvcat((2,), spmat, densearg)) + @test issparse(hvcat((2,), densearg, spmat)) + @test issparse(cat((1,2), spmat, densearg)) + @test issparse(cat((1,2), densearg, spmat)) + end +end # issue #14816 let m = 5