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