4
4
5
5
import Base: sort!, findall, copy!
6
6
import LinearAlgebra: promote_to_array_type, promote_to_arrays_
7
-
8
- using LinearAlgebra: adj_or_trans, _SpecialArrays, _DenseConcatGroup
7
+ using LinearAlgebra: adj_or_trans
9
8
10
9
### The SparseVector
11
10
@@ -1176,24 +1175,10 @@ function _absspvec_vcat(X::AbstractSparseVector{Tv,Ti}...) where {Tv,Ti}
1176
1175
SparseVector(len, rnzind, rnzval)
1177
1176
end
1178
1177
1179
- hcat(Xin::Union{Vector, AbstractSparseVector}...) = hcat(map(sparse, Xin)...)
1180
- vcat(Xin::Union{Vector, AbstractSparseVector}...) = vcat(map(sparse, Xin)...)
1181
-
1182
1178
### Concatenation of un/annotated sparse/special/dense vectors/matrices
1183
-
1184
- const _SparseArrays = Union{AbstractSparseVector,
1185
- AbstractSparseMatrixCSC,
1186
- Adjoint{<:Any,<:AbstractSparseVector},
1187
- Transpose{<:Any,<:AbstractSparseVector}}
1188
- const _SparseConcatArrays = Union{_SpecialArrays, _SparseArrays}
1189
-
1190
- const _Symmetric_SparseConcatArrays = Symmetric{<:Any,<:_SparseConcatArrays}
1191
- const _Hermitian_SparseConcatArrays = Hermitian{<:Any,<:_SparseConcatArrays}
1192
- const _Triangular_SparseConcatArrays = UpperOrLowerTriangular{<:Any,<:_SparseConcatArrays}
1193
- const _Annotated_SparseConcatArrays = Union{_Triangular_SparseConcatArrays, _Symmetric_SparseConcatArrays, _Hermitian_SparseConcatArrays}
1194
- # It's important that _SparseConcatGroup is a larger union than _DenseConcatGroup to make
1195
- # sparse cat-methods less specific and to kick in only if there is some sparse array present
1196
- const _SparseConcatGroup = Union{_DenseConcatGroup, _SparseConcatArrays, _Annotated_SparseConcatArrays}
1179
+ # by type-pirating and subverting the Base.cat design by making these a subtype of the normal methods for it
1180
+ # and re-defining all of it here. See https://github.com/JuliaLang/julia/issues/2326
1181
+ # for what would have been a more principled way of doing this.
1197
1182
1198
1183
# Concatenations involving un/annotated sparse/special matrices/vectors should yield sparse arrays
1199
1184
@@ -1205,23 +1190,55 @@ _sparse(A) = _makesparse(A)
1205
1190
_makesparse(x::Number) = x
1206
1191
_makesparse(x::AbstractVector) = convert(SparseVector, issparse(x) ? x : sparse(x))::SparseVector
1207
1192
_makesparse(x::AbstractMatrix) = convert(SparseMatrixCSC, issparse(x) ? x : sparse(x))::SparseMatrixCSC
1193
+ anysparse() = false
1194
+ anysparse(X) = X isa AbstractArray && issparse(X)
1195
+ anysparse(X, Xs...) = anysparse(X) || anysparse(Xs...)
1196
+
1197
+ function hcat(X::Union{Vector, AbstractSparseVector}...)
1198
+ if anysparse(X...)
1199
+ X = map(sparse, X)
1200
+ end
1201
+ return cat(X...; dims=Val(2))
1202
+ end
1203
+ function vcat(X::Union{Vector, AbstractSparseVector}...)
1204
+ if anysparse(X...)
1205
+ X = map(sparse, X)
1206
+ end
1207
+ return cat(X...; dims=Val(1))
1208
+ end
1209
+
1210
+ # type-pirate the Base.cat design by making this a subtype of the existing method for it
1211
+ # in future versions of Julia (v1.10+), in which https://github.com/JuliaLang/julia/issues/2326 is not fixed yet, the <:Number constraint could be relaxed
1212
+ # but see also https://github.com/JuliaSparse/SparseArrays.jl/issues/71
1213
+ const _SparseConcatGroup = Union{AbstractVecOrMat{<:Number},Number}
1208
1214
1209
1215
# `@constprop :aggressive` allows `dims` to be propagated as constant improving return type inference
1210
- Base.@constprop :aggressive function Base._cat(dims, Xin::_SparseConcatGroup...)
1211
- X = (_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...)
1212
- T = promote_eltype(Xin...)
1216
+ Base.@constprop :aggressive function Base._cat(dims, X::_SparseConcatGroup...)
1217
+ T = promote_eltype(X...)
1218
+ if anysparse(X...)
1219
+ X = (_sparse(first(X)), map(_makesparse, Base.tail(X))...)
1220
+ end
1213
1221
return Base._cat_t(dims, T, X...)
1214
1222
end
1215
- function hcat(Xin::_SparseConcatGroup...)
1216
- X = (_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...)
1223
+ function hcat(X::_SparseConcatGroup...)
1224
+ if anysparse(X...)
1225
+ X = (_sparse(first(X)), map(_makesparse, Base.tail(X))...)
1226
+ end
1217
1227
return cat(X..., dims=Val(2))
1218
1228
end
1219
- function vcat(Xin::_SparseConcatGroup...)
1220
- X = (_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...)
1229
+ function vcat(X::_SparseConcatGroup...)
1230
+ if anysparse(X...)
1231
+ X = (_sparse(first(X)), map(_makesparse, Base.tail(X))...)
1232
+ end
1221
1233
return cat(X..., dims=Val(1))
1222
1234
end
1223
- hvcat(rows::Tuple{Vararg{Int}}, X::_SparseConcatGroup...) =
1224
- vcat(_hvcat_rows(rows, X...)...)
1235
+ function hvcat(rows::Tuple{Vararg{Int}}, X::_SparseConcatGroup...)
1236
+ if anysparse(X...)
1237
+ vcat(_hvcat_rows(rows, X...)...)
1238
+ else
1239
+ Base.typed_hvcat(promote_eltypeof(X...), rows, X...)
1240
+ end
1241
+ end
1225
1242
function _hvcat_rows((row1, rows...)::Tuple{Vararg{Int}}, X::_SparseConcatGroup...)
1226
1243
if row1 ≤ 0
1227
1244
throw(ArgumentError("length of block row must be positive, got $row1"))
@@ -1238,7 +1255,7 @@ end
1238
1255
_hvcat_rows(::Tuple{}, X::_SparseConcatGroup...) = ()
1239
1256
1240
1257
# make sure UniformScaling objects are converted to sparse matrices for concatenation
1241
- promote_to_array_type(A::Tuple{Vararg{Union{_SparseConcatGroup,UniformScaling}}}) = SparseMatrixCSC
1258
+ promote_to_array_type(A::Tuple{Vararg{Union{_SparseConcatGroup,UniformScaling}}}) = anysparse(A...) ? SparseMatrixCSC : Matrix
1242
1259
promote_to_arrays_(n::Int, ::Type{SparseMatrixCSC}, J::UniformScaling) = sparse(J, n, n)
1243
1260
1244
1261
"""
0 commit comments