Skip to content

Commit 968517c

Browse files
committed
Make concatenations involving annotated sparse/special matrices yield sparse arrays. Test thoroughly.
1 parent 4cf38ef commit 968517c

File tree

4 files changed

+131
-29
lines changed

4 files changed

+131
-29
lines changed

base/array.jl

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

684684

685-
# concatenations of combinations (homogeneous, heterogeneous) of dense matrices/vectors #
686-
vcat{T}(A::Union{Vector{T},Matrix{T}}...) = typed_vcat(T, A...)
687-
vcat(A::Union{Vector,Matrix}...) = typed_vcat(promote_eltype(A...), A...)
688-
hcat{T}(A::Union{Vector{T},Matrix{T}}...) = typed_hcat(T, A...)
689-
hcat(A::Union{Vector,Matrix}...) = typed_hcat(promote_eltype(A...), A...)
690-
hvcat{T}(rows::Tuple{Vararg{Int}}, xs::Union{Vector{T},Matrix{T}}...) = typed_hvcat(T, rows, xs...)
691-
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{Vector,Matrix}...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
692-
cat{T}(catdims, xs::Union{Vector{T},Matrix{T}}...) = Base.cat_t(catdims, T, xs...)
693-
cat(catdims, xs::Union{Vector,Matrix}...) = Base.cat_t(catdims, promote_eltype(xs...), xs...)
694685
# concatenations of homogeneous combinations of vectors, horizontal and vertical
695686
function hcat{T}(V::Vector{T}...)
696687
height = length(V[1])

base/sparse/sparsematrix.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ function convert{Tv,Ti}(::Type{SparseMatrixCSC{Tv,Ti}}, S::SparseMatrixCSC)
265265
end
266266
# convert'ing from other matrix types to SparseMatrixCSC (also see sparse())
267267
convert(::Type{SparseMatrixCSC}, M::Matrix) = sparse(M)
268+
convert{Tv}(::Type{SparseMatrixCSC}, M::AbstractMatrix{Tv}) = convert(SparseMatrixCSC{Tv,Int}, M)
269+
convert{Tv}(::Type{SparseMatrixCSC{Tv}}, M::AbstractMatrix{Tv}) = convert(SparseMatrixCSC{Tv,Int}, M)
268270
function convert{Tv,Ti}(::Type{SparseMatrixCSC{Tv,Ti}}, M::AbstractMatrix)
269271
(I, J, V) = findnz(M)
270272
eltypeTiI = convert(Vector{Ti}, I)

base/sparse/sparsevector.jl

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

795795

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}...)
796+
### Concatenation of un/annotated sparse/special/dense vectors/matrices
797+
798+
# TODO: These methods and definitions should be moved to a more appropriate location,
799+
# particularly some future equivalent of base/linalg/special.jl dedicated to interactions
800+
# between a broader set of matrix types.
801+
802+
# TODO: A definition similar to the third exists in base/linalg/bidiag.jl. These definitions
803+
# should be consolidated in a more appropriate location, e.g. base/linalg/special.jl.
804+
typealias _SparseArrays Union{SparseVector, SparseMatrixCSC}
805+
typealias _SpecialArrays Union{Diagonal, Bidiagonal, Tridiagonal, SymTridiagonal}
806+
typealias _SparseConcatArrays Union{_SpecialArrays, _SparseArrays}
807+
808+
typealias _Symmetric_SparseConcatArrays{T,A<:_SparseConcatArrays} Symmetric{T,A}
809+
typealias _Hermitian_SparseConcatArrays{T,A<:_SparseConcatArrays} Hermitian{T,A}
810+
typealias _Triangular_SparseConcatArrays{T,A<:_SparseConcatArrays} Base.LinAlg.AbstractTriangular{T,A}
811+
typealias _Annotated_SparseConcatArrays Union{_Triangular_SparseConcatArrays, _Symmetric_SparseConcatArrays, _Hermitian_SparseConcatArrays}
812+
813+
typealias _Symmetric_DenseArrays{T,A<:Matrix} Symmetric{T,A}
814+
typealias _Hermitian_DenseArrays{T,A<:Matrix} Hermitian{T,A}
815+
typealias _Triangular_DenseArrays{T,A<:Matrix} Base.LinAlg.AbstractTriangular{T,A}
816+
typealias _Annotated_DenseArrays Union{_Triangular_DenseArrays, _Symmetric_DenseArrays, _Hermitian_DenseArrays}
817+
typealias _Annotated_Typed_DenseArrays{T} Union{_Triangular_DenseArrays{T}, _Symmetric_DenseArrays{T}, _Hermitian_DenseArrays{T}}
818+
819+
typealias _SparseConcatGroup Union{Vector, Matrix, _SparseConcatArrays, _Annotated_SparseConcatArrays, _Annotated_DenseArrays}
820+
typealias _DenseConcatGroup Union{Vector, Matrix, _Annotated_DenseArrays}
821+
typealias _TypedDenseConcatGroup{T} Union{Vector{T}, Matrix{T}, _Annotated_Typed_DenseArrays{T}}
822+
823+
# Concatenations involving un/annotated sparse/special matrices/vectors should yield sparse arrays
824+
function cat(catdims, Xin::_SparseConcatGroup...)
825+
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
826+
T = promote_eltype(Xin...)
827+
Base.cat_t(catdims, T, X...)
828+
end
829+
function hcat(Xin::_SparseConcatGroup...)
807830
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
808831
hcat(X...)
809832
end
810-
811-
function vcat(Xin::Union{Vector, Matrix, SparseVector, SparseMatrixCSC, SpecialArrays}...)
833+
function vcat(Xin::_SparseConcatGroup...)
812834
X = SparseMatrixCSC[issparse(x) ? x : sparse(x) for x in Xin]
813835
vcat(X...)
814836
end
815-
816-
function hvcat(rows::Tuple{Vararg{Int}}, X::Union{Vector, Matrix, SparseVector, SparseMatrixCSC, SpecialArrays}...)
837+
function hvcat(rows::Tuple{Vararg{Int}}, X::_SparseConcatGroup...)
817838
nbr = length(rows) # number of block rows
818839

819840
tmp_rows = Array{SparseMatrixCSC}(nbr)
@@ -825,11 +846,16 @@ function hvcat(rows::Tuple{Vararg{Int}}, X::Union{Vector, Matrix, SparseVector,
825846
vcat(tmp_rows...)
826847
end
827848

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
849+
# Concatenations strictly involving un/annotated dense matrices/vectors should yield dense arrays
850+
cat(catdims, xs::_DenseConcatGroup...) = Base.cat_t(catdims, promote_eltype(xs...), xs...)
851+
vcat(A::_DenseConcatGroup...) = Base.typed_vcat(promote_eltype(A...), A...)
852+
hcat(A::_DenseConcatGroup...) = Base.typed_hcat(promote_eltype(A...), A...)
853+
hvcat(rows::Tuple{Vararg{Int}}, xs::_DenseConcatGroup...) = Base.typed_hvcat(promote_eltype(xs...), rows, xs...)
854+
# For performance, specially handle the case where the matrices/vectors have homogeneous eltype
855+
cat{T}(catdims, xs::_TypedDenseConcatGroup{T}...) = Base.cat_t(catdims, T, xs...)
856+
vcat{T}(A::_TypedDenseConcatGroup{T}...) = Base.typed_vcat(T, A...)
857+
hcat{T}(A::_TypedDenseConcatGroup{T}...) = Base.typed_hcat(T, A...)
858+
hvcat{T}(rows::Tuple{Vararg{Int}}, xs::_TypedDenseConcatGroup{T}...) = Base.typed_hvcat(T, rows, xs...)
833859

834860

835861
### math functions

test/linalg/special.jl

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

0 commit comments

Comments
 (0)