Skip to content

Commit 30bf89f

Browse files
Sacha0tkelman
authored andcommitted
Make concatenations involving annotated sparse/special matrices yield sparse arrays. Test thoroughly. (#17900)
1 parent 94adc99 commit 30bf89f

File tree

4 files changed

+134
-29
lines changed

4 files changed

+134
-29
lines changed

base/array.jl

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -910,15 +910,6 @@ function reverse!(v::AbstractVector, s=1, n=length(v))
910910
end
911911

912912

913-
# concatenations of combinations (homogeneous, heterogeneous) of dense matrices/vectors #
914-
vcat{T}(A::Union{Vector{T},Matrix{T}}...) = typed_vcat(T, A...)
915-
vcat(A::Union{Vector,Matrix}...) = typed_vcat(promote_eltype(A...), A...)
916-
hcat{T}(A::Union{Vector{T},Matrix{T}}...) = typed_hcat(T, A...)
917-
hcat(A::Union{Vector,Matrix}...) = typed_hcat(promote_eltype(A...), A...)
918-
hvcat{T}(rows::Tuple{Vararg{Int}}, xs::Union{Vector{T},Matrix{T}}...) = typed_hvcat(T, rows, xs...)
919-
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{Vector,Matrix}...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
920-
cat{T}(catdims, xs::Union{Vector{T},Matrix{T}}...) = Base.cat_t(catdims, T, xs...)
921-
cat(catdims, xs::Union{Vector,Matrix}...) = Base.cat_t(catdims, promote_eltype(xs...), xs...)
922913
# concatenations of homogeneous combinations of vectors, horizontal and vertical
923914
function hcat{T}(V::Vector{T}...)
924915
height = length(V[1])

base/sparse/sparsematrix.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ function convert{Tv,Ti}(::Type{SparseMatrixCSC{Tv,Ti}}, S::SparseMatrixCSC)
304304
end
305305
# convert'ing from other matrix types to SparseMatrixCSC (also see sparse())
306306
convert(::Type{SparseMatrixCSC}, M::Matrix) = sparse(M)
307+
convert{Tv}(::Type{SparseMatrixCSC}, M::AbstractMatrix{Tv}) = convert(SparseMatrixCSC{Tv,Int}, M)
308+
convert{Tv}(::Type{SparseMatrixCSC{Tv}}, M::AbstractMatrix{Tv}) = convert(SparseMatrixCSC{Tv,Int}, M)
307309
function convert{Tv,Ti}(::Type{SparseMatrixCSC{Tv,Ti}}, M::AbstractMatrix)
308310
(I, J, V) = findnz(M)
309311
eltypeTiI = convert(Vector{Ti}, I)

base/sparse/sparsevector.jl

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -842,27 +842,48 @@ hcat(Xin::Union{Vector, AbstractSparseVector}...) = hcat(map(sparse, Xin)...)
842842
vcat(Xin::Union{Vector, AbstractSparseVector}...) = vcat(map(sparse, Xin)...)
843843

844844

845-
### Sparse/special/dense vector/matrix concatenation
846-
847-
# TODO: These methods should be moved to a more appropriate location, particularly some
848-
# future equivalent of base/linalg/special.jl dedicated to interactions between a broader
849-
# set of matrix types.
850-
851-
# TODO: A similar definition also exists in base/linalg/bidiag.jl. These definitions should
852-
# be consolidated in a more appropriate location, for example base/linalg/special.jl.
853-
SpecialArrays = Union{Diagonal, Bidiagonal, Tridiagonal, SymTridiagonal}
854-
855-
function hcat(Xin::Union{Vector, Matrix, SparseVector, SparseMatrixCSC, SpecialArrays}...)
845+
### Concatenation of un/annotated sparse/special/dense vectors/matrices
846+
847+
# TODO: These methods and definitions should be moved to a more appropriate location,
848+
# particularly some future equivalent of base/linalg/special.jl dedicated to interactions
849+
# between a broader set of matrix types.
850+
851+
# TODO: A definition similar to the third exists in base/linalg/bidiag.jl. These definitions
852+
# should be consolidated in a more appropriate location, e.g. base/linalg/special.jl.
853+
typealias _SparseArrays Union{SparseVector, SparseMatrixCSC}
854+
typealias _SpecialArrays Union{Diagonal, Bidiagonal, Tridiagonal, SymTridiagonal}
855+
typealias _SparseConcatArrays Union{_SpecialArrays, _SparseArrays}
856+
857+
typealias _Symmetric_SparseConcatArrays{T,A<:_SparseConcatArrays} Symmetric{T,A}
858+
typealias _Hermitian_SparseConcatArrays{T,A<:_SparseConcatArrays} Hermitian{T,A}
859+
typealias _Triangular_SparseConcatArrays{T,A<:_SparseConcatArrays} Base.LinAlg.AbstractTriangular{T,A}
860+
typealias _Annotated_SparseConcatArrays Union{_Triangular_SparseConcatArrays, _Symmetric_SparseConcatArrays, _Hermitian_SparseConcatArrays}
861+
862+
typealias _Symmetric_DenseArrays{T,A<:Matrix} Symmetric{T,A}
863+
typealias _Hermitian_DenseArrays{T,A<:Matrix} Hermitian{T,A}
864+
typealias _Triangular_DenseArrays{T,A<:Matrix} Base.LinAlg.AbstractTriangular{T,A}
865+
typealias _Annotated_DenseArrays Union{_Triangular_DenseArrays, _Symmetric_DenseArrays, _Hermitian_DenseArrays}
866+
typealias _Annotated_Typed_DenseArrays{T} Union{_Triangular_DenseArrays{T}, _Symmetric_DenseArrays{T}, _Hermitian_DenseArrays{T}}
867+
868+
typealias _SparseConcatGroup Union{Vector, Matrix, _SparseConcatArrays, _Annotated_SparseConcatArrays, _Annotated_DenseArrays}
869+
typealias _DenseConcatGroup Union{Vector, Matrix, _Annotated_DenseArrays}
870+
typealias _TypedDenseConcatGroup{T} Union{Vector{T}, Matrix{T}, _Annotated_Typed_DenseArrays{T}}
871+
872+
# Concatenations involving un/annotated sparse/special matrices/vectors should yield sparse arrays
873+
function cat(catdims, Xin::_SparseConcatGroup...)
874+
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
875+
T = promote_eltype(Xin...)
876+
Base.cat_t(catdims, T, X...)
877+
end
878+
function hcat(Xin::_SparseConcatGroup...)
856879
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
857880
hcat(X...)
858881
end
859-
860-
function vcat(Xin::Union{Vector, Matrix, SparseVector, SparseMatrixCSC, SpecialArrays}...)
882+
function vcat(Xin::_SparseConcatGroup...)
861883
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
862884
vcat(X...)
863885
end
864-
865-
function hvcat(rows::Tuple{Vararg{Int}}, X::Union{Vector, Matrix, SparseVector, SparseMatrixCSC, SpecialArrays}...)
886+
function hvcat(rows::Tuple{Vararg{Int}}, X::_SparseConcatGroup...)
866887
nbr = length(rows) # number of block rows
867888

868889
tmp_rows = Array{SparseMatrixCSC}(nbr)
@@ -874,11 +895,16 @@ function hvcat(rows::Tuple{Vararg{Int}}, X::Union{Vector, Matrix, SparseVector,
874895
vcat(tmp_rows...)
875896
end
876897

877-
function cat(catdims, Xin::Union{Vector, Matrix, SparseVector, SparseMatrixCSC, SpecialArrays}...)
878-
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
879-
T = promote_eltype(Xin...)
880-
Base.cat_t(catdims, T, X...)
881-
end
898+
# Concatenations strictly involving un/annotated dense matrices/vectors should yield dense arrays
899+
cat(catdims, xs::_DenseConcatGroup...) = Base.cat_t(catdims, promote_eltype(xs...), xs...)
900+
vcat(A::_DenseConcatGroup...) = Base.typed_vcat(promote_eltype(A...), A...)
901+
hcat(A::_DenseConcatGroup...) = Base.typed_hcat(promote_eltype(A...), A...)
902+
hvcat(rows::Tuple{Vararg{Int}}, xs::_DenseConcatGroup...) = Base.typed_hvcat(promote_eltype(xs...), rows, xs...)
903+
# For performance, specially handle the case where the matrices/vectors have homogeneous eltype
904+
cat{T}(catdims, xs::_TypedDenseConcatGroup{T}...) = Base.cat_t(catdims, T, xs...)
905+
vcat{T}(A::_TypedDenseConcatGroup{T}...) = Base.typed_vcat(T, A...)
906+
hcat{T}(A::_TypedDenseConcatGroup{T}...) = Base.typed_hcat(T, A...)
907+
hvcat{T}(rows::Tuple{Vararg{Int}}, xs::_TypedDenseConcatGroup{T}...) = Base.typed_hvcat(T, rows, xs...)
882908

883909

884910
### math functions

test/linalg/special.jl

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,89 @@ let
162162
end
163163
end
164164
end
165+
166+
# Test that concatenations of annotated sparse/special matrix types with other matrix
167+
# types yield sparse arrays, and that the code which effects that does not make concatenations
168+
# strictly involving un/annotated dense matrices yield sparse arrays
169+
#
170+
# TODO: As with the associated code, these tests should be moved to a more appropriate
171+
# location, particularly some future equivalent of base/linalg/special.jl dedicated to
172+
# intereactions between a broader set of matrix types
173+
let
174+
N = 4
175+
# The tested annotation types
176+
testfull = Bool(parse(Int,(get(ENV, "JULIA_TESTFULL", "0"))))
177+
utriannotations = (UpperTriangular, Base.LinAlg.UnitUpperTriangular)
178+
ltriannotations = (LowerTriangular, Base.LinAlg.UnitLowerTriangular)
179+
triannotations = (utriannotations..., ltriannotations...)
180+
symannotations = (Symmetric, Hermitian)
181+
annotations = testfull ? (triannotations..., symannotations...) : (LowerTriangular, Symmetric)
182+
# Concatenations involving these types, un/annotated, should yield sparse arrays
183+
spvec = spzeros(N)
184+
spmat = speye(N)
185+
diagmat = Diagonal(ones(N))
186+
bidiagmat = Bidiagonal(ones(N), ones(N-1), true)
187+
tridiagmat = Tridiagonal(ones(N-1), ones(N), ones(N-1))
188+
symtridiagmat = SymTridiagonal(ones(N), ones(N-1))
189+
sparseconcatmats = testfull ? (spmat, diagmat, bidiagmat, tridiagmat, symtridiagmat) : (spmat, diagmat)
190+
# Concatenations involving strictly these types, un/annotated, should yield dense arrays
191+
densevec = ones(N)
192+
densemat = ones(N, N)
193+
# Annotated collections
194+
annodmats = [annot(densemat) for annot in annotations]
195+
annospcmats = [annot(spcmat) for annot in annotations, spcmat in sparseconcatmats]
196+
# Test that concatenations of pairwise combinations of annotated sparse/special
197+
# yield sparse matrices
198+
for annospcmata in annospcmats, annospcmatb in annospcmats
199+
@test issparse(vcat(annospcmata, annospcmatb))
200+
@test issparse(hcat(annospcmata, annospcmatb))
201+
@test issparse(hvcat((2,), annospcmata, annospcmatb))
202+
@test issparse(cat((1,2), annospcmata, annospcmatb))
203+
end
204+
# Test that concatenations of pairwise combinations of annotated sparse/special
205+
# matrices and other matrix/vector types yield sparse matrices
206+
for annospcmat in annospcmats
207+
# --> Tests applicable to pairs including only matrices
208+
for othermat in (densemat, annodmats..., sparseconcatmats...)
209+
@test issparse(vcat(annospcmat, othermat))
210+
@test issparse(vcat(othermat, annospcmat))
211+
end
212+
# --> Tests applicable to pairs including other vectors or matrices
213+
for other in (spvec, densevec, densemat, annodmats..., sparseconcatmats...)
214+
@test issparse(hcat(annospcmat, other))
215+
@test issparse(hcat(other, annospcmat))
216+
@test issparse(hvcat((2,), annospcmat, other))
217+
@test issparse(hvcat((2,), other, annospcmat))
218+
@test issparse(cat((1,2), annospcmat, other))
219+
@test issparse(cat((1,2), other, annospcmat))
220+
end
221+
end
222+
# The preceding tests should cover multi-way combinations of those types, but for good
223+
# measure test a few multi-way combinations involving those types
224+
@test issparse(vcat(spmat, densemat, annospcmats[1], annodmats[2]))
225+
@test issparse(vcat(densemat, spmat, annodmats[1], annospcmats[2]))
226+
@test issparse(hcat(spvec, annodmats[1], annospcmats[3], densevec, diagmat))
227+
@test issparse(hcat(annodmats[2], annospcmats[4], spvec, densevec, diagmat))
228+
@test issparse(hvcat((5,), diagmat, densevec, spvec, annodmats[1], annospcmats[1]))
229+
@test issparse(hvcat((5,), spvec, annodmats[2], diagmat, densevec, annospcmats[2]))
230+
@test issparse(cat((1,2), annodmats[1], diagmat, annospcmats[3], densevec, spvec))
231+
@test issparse(cat((1,2), spvec, diagmat, densevec, annospcmats[4], annodmats[2]))
232+
# Test that concatenations strictly involving un/annotated dense matrices/vectors
233+
# yield dense arrays
234+
for densemata in (densemat, annodmats...)
235+
# --> Tests applicable to pairs including only matrices
236+
for densematb in (densemat, annodmats...)
237+
@test !issparse(vcat(densemata, densematb))
238+
@test !issparse(vcat(densematb, densemata))
239+
end
240+
# --> Tests applicable to pairs including vectors or matrices
241+
for otherdense in (densevec, densemat, annodmats...)
242+
@test !issparse(hcat(densemata, otherdense))
243+
@test !issparse(hcat(otherdense, densemata))
244+
@test !issparse(hvcat((2,), densemata, otherdense))
245+
@test !issparse(hvcat((2,), otherdense, densemata))
246+
@test !issparse(cat((1,2), densemata, otherdense))
247+
@test !issparse(cat((1,2), otherdense, densemata))
248+
end
249+
end
250+
end

0 commit comments

Comments
 (0)