Skip to content

Commit 45825b5

Browse files
dkarraschKristofferC
authored andcommitted
add sparse_*cat
1 parent f341c79 commit 45825b5

File tree

4 files changed

+91
-22
lines changed

4 files changed

+91
-22
lines changed

docs/src/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ SparseArrays.nnz
214214
SparseArrays.findnz
215215
SparseArrays.spzeros
216216
SparseArrays.spdiagm
217+
SparseArrays.sparse_hcat
218+
SparseArrays.sparse_vcat
219+
SparseArrays.sparse_hvcat
217220
SparseArrays.blockdiag
218221
SparseArrays.sprand
219222
SparseArrays.sprandn

src/SparseArrays.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ using Random: default_rng, AbstractRNG, randsubseq, randsubseq!
2727
export AbstractSparseArray, AbstractSparseMatrix, AbstractSparseVector,
2828
SparseMatrixCSC, SparseVector, blockdiag, droptol!, dropzeros!, dropzeros,
2929
issparse, nonzeros, nzrange, rowvals, sparse, sparsevec, spdiagm,
30-
sprand, sprandn, spzeros, nnz, permute, findnz
30+
sprand, sprandn, spzeros, nnz, permute, findnz,
31+
sparse_hcat, sparse_vcat, sparse_hvcat
3132

3233
include("abstractsparse.jl")
3334
include("sparsematrix.jl")

src/sparsevector.jl

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,55 @@ _hvcat_rows(::Tuple{}, X::_SparseConcatGroup...) = ()
11121112
promote_to_array_type(A::Tuple{Vararg{Union{_SparseConcatGroup,UniformScaling}}}) = SparseMatrixCSC
11131113
promote_to_arrays_(n::Int, ::Type{SparseMatrixCSC}, J::UniformScaling) = sparse(J, n, n)
11141114

1115+
"""
1116+
sparse_hcat(A...)
1117+
1118+
Concatenate along dimension 2. Return a SparseMatrixCSC object.
1119+
1120+
!!! compat "Julia 1.8"
1121+
This method was added in Julia 1.8. It mimicks previous concatenation behavior, where
1122+
the concatenation with specialized "sparse" matrix types from LinearAlgebra.jl
1123+
automatically yielded sparse output even in the absence of any SparseArray argument.
1124+
"""
1125+
sparse_hcat(Xin::Union{AbstractVecOrMat,Number}...) = cat(map(_makesparse, Xin)..., dims=Val(2))
1126+
function sparse_hcat(X::Union{AbstractVecOrMat,UniformScaling,Number}...)
1127+
LinearAlgebra._hcat(X...; array_type = SparseMatrixCSC)
1128+
end
1129+
1130+
"""
1131+
sparse_vcat(A...)
1132+
1133+
Concatenate along dimension 1. Return a SparseMatrixCSC object.
1134+
1135+
!!! compat "Julia 1.8"
1136+
This method was added in Julia 1.8. It mimicks previous concatenation behavior, where
1137+
the concatenation with specialized "sparse" matrix types from LinearAlgebra.jl
1138+
automatically yielded sparse output even in the absence of any SparseArray argument.
1139+
"""
1140+
sparse_vcat(Xin::Union{AbstractVecOrMat,Number}...) = cat(map(_makesparse, Xin)..., dims=Val(1))
1141+
function sparse_vcat(X::Union{AbstractVecOrMat,UniformScaling,Number}...)
1142+
LinearAlgebra._vcat(X...; array_type = SparseMatrixCSC)
1143+
end
1144+
1145+
"""
1146+
sparse_hvcat(rows::Tuple{Vararg{Int}}, values...)
1147+
1148+
Sparse horizontal and vertical concatenation in one call. This function is called
1149+
for block matrix syntax. The first argument specifies the number of
1150+
arguments to concatenate in each block row.
1151+
1152+
!!! compat "Julia 1.8"
1153+
This method was added in Julia 1.8. It mimicks previous concatenation behavior, where
1154+
the concatenation with specialized "sparse" matrix types from LinearAlgebra.jl
1155+
automatically yielded sparse output even in the absence of any SparseArray argument.
1156+
"""
1157+
function sparse_hvcat(rows::Tuple{Vararg{Int}}, Xin::Union{AbstractVecOrMat,Number}...)
1158+
hvcat(rows, map(_makesparse, Xin)...)
1159+
end
1160+
function sparse_hvcat(rows::Tuple{Vararg{Int}}, X::Union{AbstractVecOrMat,UniformScaling,Number}...)
1161+
LinearAlgebra._hvcat(rows, X...; array_type = SparseMatrixCSC)
1162+
end
1163+
11151164
### math functions
11161165

11171166
### Unary Map

test/sparse.jl

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -262,19 +262,27 @@ end
262262
# Test concatenating pairwise combinations of special matrices with sparse matrices,
263263
# dense matrices, or dense vectors
264264
spmat = spdiagm(0 => fill(1., N))
265+
dmat = Array(spmat)
265266
spvec = sparse(fill(1., N))
267+
dvec = Array(spvec)
266268
for specialmat in specialmats
267269
# --> Tests applicable only to pairs of matrices
268270
@test issparse(vcat(specialmat, spmat))
269271
@test issparse(vcat(spmat, specialmat))
272+
@test sparse_vcat(specialmat, dmat)::SparseMatrixCSC == vcat(specialmat, spmat)
273+
@test sparse_vcat(dmat, specialmat)::SparseMatrixCSC == vcat(spmat, specialmat)
270274
# --> Tests applicable also to pairs including vectors
271-
for specialmat in specialmats, othermatorvec in (spmat, spvec)
272-
@test issparse(hcat(specialmat, othermatorvec))
273-
@test issparse(hcat(othermatorvec, specialmat))
274-
@test issparse(hvcat((2,), specialmat, othermatorvec))
275-
@test issparse(hvcat((2,), othermatorvec, specialmat))
276-
@test issparse(cat(specialmat, othermatorvec; dims=(1,2)))
277-
@test issparse(cat(othermatorvec, specialmat; dims=(1,2)))
275+
for specialmat in specialmats, (smatorvec, dmatorvec) in ((spmat, dmat), (spvec, dvec))
276+
@test issparse(hcat(specialmat, smatorvec))
277+
@test sparse_hcat(specialmat, dmatorvec)::SparseMatrixCSC == hcat(specialmat, smatorvec)
278+
@test issparse(hcat(smatorvec, specialmat))
279+
@test sparse_hcat(dmatorvec, specialmat)::SparseMatrixCSC == hcat(smatorvec, specialmat)
280+
@test issparse(hvcat((2,), specialmat, smatorvec))
281+
@test sparse_hvcat((2,), specialmat, dmatorvec)::SparseMatrixCSC == hvcat((2,), specialmat, smatorvec)
282+
@test issparse(hvcat((2,), smatorvec, specialmat))
283+
@test sparse_hvcat((2,), dmatorvec, specialmat)::SparseMatrixCSC == hvcat((2,), smatorvec, specialmat)
284+
@test issparse(cat(specialmat, smatorvec; dims=(1,2)))
285+
@test issparse(cat(smatorvec, specialmat; dims=(1,2)))
278286
end
279287
end
280288
end
@@ -300,8 +308,8 @@ end
300308
symtridiagmat = SymTridiagonal(1:N, 1:(N-1))
301309
sparseconcatmats = testfull ? (spmat, diagmat, bidiagmat, tridiagmat, symtridiagmat) : (spmat, diagmat)
302310
# Concatenations involving strictly these types, un/annotated, should yield dense arrays
303-
densevec = fill(1., N)
304-
densemat = fill(1., N, N)
311+
densevec = Array(spvec)
312+
densemat = Array(spmat)
305313
# Annotated collections
306314
annodmats = [annot(densemat) for annot in annotations]
307315
annospcmats = [annot(spmat) for annot in annotations]
@@ -321,6 +329,14 @@ end
321329
@test issparse(vcat(annospcmat, othermat))
322330
@test issparse(vcat(othermat, annospcmat))
323331
end
332+
for (smat, dmat) in zip(annospcmats, annodmats), specialmat in sparseconcatmats
333+
@test sparse_hcat(dmat, specialmat)::SparseMatrixCSC == hcat(smat, specialmat)
334+
@test sparse_hcat(specialmat, dmat)::SparseMatrixCSC == hcat(specialmat, smat)
335+
@test sparse_vcat(dmat, specialmat)::SparseMatrixCSC == vcat(smat, specialmat)
336+
@test sparse_vcat(specialmat, dmat)::SparseMatrixCSC == vcat(specialmat, smat)
337+
@test sparse_hvcat((2,), dmat, specialmat)::SparseMatrixCSC == hvcat((2,), smat, specialmat)
338+
@test sparse_hvcat((2,), specialmat, dmat)::SparseMatrixCSC == hvcat((2,), specialmat, smat)
339+
end
324340
# --> Tests applicable to pairs including other vectors or matrices
325341
for other in (spvec, densevec, densemat, annodmats..., sparseconcatmats...)
326342
@test issparse(hcat(annospcmat, other))
@@ -357,30 +373,30 @@ end
357373
E = SparseMatrixCSC(rand(1,3))
358374
F = SparseMatrixCSC(rand(3,1))
359375
α = rand()
360-
@test (hcat(A, 2I))::SparseMatrixCSC == hcat(A, Matrix(2I, 3, 3))
376+
@test (hcat(A, 2I, I(3)))::SparseMatrixCSC == hcat(A, Matrix(2I, 3, 3), Matrix(I, 3, 3))
361377
@test (hcat(E, α))::SparseMatrixCSC == hcat(E, [α])
362378
@test (hcat(E, α, 2I))::SparseMatrixCSC == hcat(E, [α], fill(2, 1, 1))
363-
@test (vcat(A, 2I))::SparseMatrixCSC == vcat(A, Matrix(2I, 4, 4))
379+
@test (vcat(A, 2I))::SparseMatrixCSC == (vcat(A, 2I(4)))::SparseMatrixCSC == vcat(A, Matrix(2I, 4, 4))
364380
@test (vcat(F, α))::SparseMatrixCSC == vcat(F, [α])
365-
@test (vcat(F, α, 2I))::SparseMatrixCSC == vcat(F, [α], fill(2, 1, 1))
381+
@test (vcat(F, α, 2I))::SparseMatrixCSC == (vcat(F, α, 2I(1)))::SparseMatrixCSC == vcat(F, [α], fill(2, 1, 1))
366382
@test (hcat(C, 2I))::SparseMatrixCSC == C
367383
@test_throws DimensionMismatch hcat(C, α)
368384
@test (vcat(D, 2I))::SparseMatrixCSC == D
369385
@test_throws DimensionMismatch vcat(D, α)
370386
@test (hcat(I, 3I, A, 2I))::SparseMatrixCSC == hcat(Matrix(I, 3, 3), Matrix(3I, 3, 3), A, Matrix(2I, 3, 3))
371387
@test (vcat(I, 3I, A, 2I))::SparseMatrixCSC == vcat(Matrix(I, 4, 4), Matrix(3I, 4, 4), A, Matrix(2I, 4, 4))
372-
@test (hvcat((2,1,2), B, 2I, I, 3I, 4I))::SparseMatrixCSC ==
388+
@test (hvcat((2,1,2), B, 2I, I(6), 3I, 4I))::SparseMatrixCSC ==
373389
hvcat((2,1,2), B, Matrix(2I, 3, 3), Matrix(I, 6, 6), Matrix(3I, 3, 3), Matrix(4I, 3, 3))
374-
@test hvcat((3,1), C, C, I, 3I)::SparseMatrixCSC == hvcat((2,1), C, C, Matrix(3I, 6,6))
390+
@test hvcat((3,1), C, C, I, 3I)::SparseMatrixCSC == hvcat((2,1), C, C, Matrix(3I, 6, 6))
375391
@test hvcat((2,2,2), I, 2I, 3I, 4I, C, C)::SparseMatrixCSC ==
376-
hvcat((2,2,2), Matrix(I, 3, 3), Matrix(2I, 3,3 ), Matrix(3I, 3,3), Matrix(4I, 3,3), C, C)
377-
@test hvcat((2,2,4), C, C, I, 2I, 3I, 4I, 5I, D)::SparseMatrixCSC ==
378-
hvcat((2,2,4), C, C, Matrix(I, 3, 3), Matrix(2I,3,3),
379-
Matrix(3I, 2, 2), Matrix(4I, 2, 2), Matrix(5I,2,2), D)
380-
@test (hvcat((2,3,2), B, 2I, C, C, I, 3I, 4I))::SparseMatrixCSC ==
392+
hvcat((2,2,2), Matrix(I, 3, 3), Matrix(2I, 3, 3), Matrix(3I, 3, 3), Matrix(4I, 3, 3), C, C)
393+
@test hvcat((2,2,4), C, C, I(3), 2I, 3I, 4I, 5I, D)::SparseMatrixCSC ==
394+
hvcat((2,2,4), C, C, Matrix(I, 3, 3), Matrix(2I, 3, 3),
395+
Matrix(3I, 2, 2), Matrix(4I, 2, 2), Matrix(5I, 2, 2), D)
396+
@test (hvcat((2,3,2), B, 2I(3), C, C, I, 3I, 4I))::SparseMatrixCSC ==
381397
hvcat((2,2,2), B, Matrix(2I, 3, 3), C, C, Matrix(3I, 3, 3), Matrix(4I, 3, 3))
382-
@test hvcat((3,2,1), C, C, I, B ,3I, 2I)::SparseMatrixCSC ==
383-
hvcat((2,2,1), C, C, B, Matrix(3I,3,3), Matrix(2I,6,6))
398+
@test hvcat((3,2,1), C, C, I, B, 3I(3), 2I)::SparseMatrixCSC ==
399+
hvcat((2,2,1), C, C, B, Matrix(3I, 3, 3), Matrix(2I, 6, 6))
384400
@test (hvcat((1,2), A, E, α))::SparseMatrixCSC == hvcat((1,2), A, E, [α]) == hvcat((1,2), A, E, α*I)
385401
@test (hvcat((2,2), α, E, F, 3I))::SparseMatrixCSC == hvcat((2,2), [α], E, F, Matrix(3I, 3, 3))
386402
@test (hvcat((2,2), 3I, F, E, α))::SparseMatrixCSC == hvcat((2,2), Matrix(3I, 3, 3), F, E, [α])

0 commit comments

Comments
 (0)