Skip to content

Commit 90bf0de

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

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
@@ -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: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,89 @@ 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+
testfull = Bool(parse(Int,(get(ENV, "JULIA_TESTFULL", "0"))))
181+
utriannotations = (UpperTriangular, Base.LinAlg.UnitUpperTriangular)
182+
ltriannotations = (LowerTriangular, Base.LinAlg.UnitLowerTriangular)
183+
triannotations = (utriannotations..., ltriannotations...)
184+
symannotations = (Symmetric, Hermitian)
185+
annotations = testfull ? (triannotations..., symannotations...) : (LowerTriangular, Symmetric)
186+
# Concatenations involving these types, un/annotated, should yield sparse arrays
187+
spvec = spzeros(N)
188+
spmat = speye(N)
189+
diagmat = Diagonal(ones(N))
190+
bidiagmat = Bidiagonal(ones(N), ones(N-1), true)
191+
tridiagmat = Tridiagonal(ones(N-1), ones(N), ones(N-1))
192+
symtridiagmat = SymTridiagonal(ones(N), ones(N-1))
193+
sparseconcatmats = testfull ? (spmat, diagmat, bidiagmat, tridiagmat, symtridiagmat) : (spmat, diagmat)
194+
# Concatenations involving strictly these types, un/annotated, should yield dense arrays
195+
densevec = ones(N)
196+
densemat = ones(N, N)
197+
# Annotated collections
198+
annodmats = [annot(densemat) for annot in annotations]
199+
annospcmats = [annot(spcmat) for annot in annotations, spcmat in sparseconcatmats]
200+
# Test that concatenations of pairwise combinations of annotated sparse/special
201+
# yield sparse matrices
202+
for annospcmata in annospcmats, annospcmatb in annospcmats
203+
@test issparse(vcat(annospcmata, annospcmatb))
204+
@test issparse(hcat(annospcmata, annospcmatb))
205+
@test issparse(hvcat((2,), annospcmata, annospcmatb))
206+
@test issparse(cat((1,2), annospcmata, annospcmatb))
207+
end
208+
# Test that concatenations of pairwise combinations of annotated sparse/special
209+
# matrices and other matrix/vector types yield sparse matrices
210+
for annospcmat in annospcmats
211+
# --> Tests applicable to pairs including only matrices
212+
for othermat in (densemat, annodmats..., sparseconcatmats...)
213+
@test issparse(vcat(annospcmat, othermat))
214+
@test issparse(vcat(othermat, annospcmat))
215+
end
216+
# --> Tests applicable to pairs including other vectors or matrices
217+
for other in (spvec, densevec, densemat, annodmats..., sparseconcatmats...)
218+
@test issparse(hcat(annospcmat, other))
219+
@test issparse(hcat(other, annospcmat))
220+
@test issparse(hvcat((2,), annospcmat, other))
221+
@test issparse(hvcat((2,), other, annospcmat))
222+
@test issparse(cat((1,2), annospcmat, other))
223+
@test issparse(cat((1,2), other, annospcmat))
224+
end
225+
end
226+
# The preceding tests should cover multi-way combinations of those types, but for good
227+
# measure test a few multi-way combinations involving those types
228+
@test issparse(vcat(spmat, densemat, annospcmats[1], annodmats[2]))
229+
@test issparse(vcat(densemat, spmat, annodmats[1], annospcmats[2]))
230+
@test issparse(hcat(spvec, annodmats[1], annospcmats[3], densevec, diagmat))
231+
@test issparse(hcat(annodmats[2], annospcmats[4], spvec, densevec, diagmat))
232+
@test issparse(hvcat((5,), diagmat, densevec, spvec, annodmats[1], annospcmats[1]))
233+
@test issparse(hvcat((5,), spvec, annodmats[2], diagmat, densevec, annospcmats[2]))
234+
@test issparse(cat((1,2), annodmats[1], diagmat, annospcmats[3], densevec, spvec))
235+
@test issparse(cat((1,2), spvec, diagmat, densevec, annospcmats[4], annodmats[2]))
236+
# Test that concatenations strictly involving un/annotated dense matrices/vectors
237+
# yield dense arrays
238+
for densemata in (densemat, annodmats...)
239+
# --> Tests applicable to pairs including only matrices
240+
for densematb in (densemat, annodmats...)
241+
@test !issparse(vcat(densemata, densematb))
242+
@test !issparse(vcat(densematb, densemata))
243+
end
244+
# --> Tests applicable to pairs including vectors or matrices
245+
for otherdense in (densevec, densemat, annodmats...)
246+
@test !issparse(hcat(densemata, otherdense))
247+
@test !issparse(hcat(otherdense, densemata))
248+
@test !issparse(hvcat((2,), densemata, otherdense))
249+
@test !issparse(hvcat((2,), otherdense, densemata))
250+
@test !issparse(cat((1,2), densemata, otherdense))
251+
@test !issparse(cat((1,2), otherdense, densemata))
252+
end
253+
end
254+
end

0 commit comments

Comments
 (0)