Skip to content

Commit 18b7fce

Browse files
authored
Merge pull request #422 from JuliaSparse/jn/cat
cat performance tweaks
2 parents 2c4f870 + e2c78b8 commit 18b7fce

File tree

2 files changed

+56
-44
lines changed

2 files changed

+56
-44
lines changed

src/sparsevector.jl

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,9 @@ function hcat(Xin::AbstractSparseVector...)
11081108
X = map(_unsafe_unfix, Xin)
11091109
Tv = promote_type(map(eltype, X)...)
11101110
Ti = promote_type(map(indtype, X)...)
1111-
r = _absspvec_hcat(map(x -> convert(SparseVector{Tv,Ti}, x), X)...)
1111+
r = (function (::Type{SV}) where SV
1112+
_absspvec_hcat(map(x -> convert(SV, x), X)...)
1113+
end)(SparseVector{Tv,Ti})
11121114
return @if_move_fixed Xin... r
11131115
end
11141116
function _absspvec_hcat(X::AbstractSparseVector{Tv,Ti}...) where {Tv,Ti}
@@ -1144,7 +1146,9 @@ function vcat(Xin::AbstractSparseVector...)
11441146
X = map(_unsafe_unfix, Xin)
11451147
Tv = promote_type(map(eltype, X)...)
11461148
Ti = promote_type(map(indtype, X)...)
1147-
r = _absspvec_vcat(map(x -> convert(SparseVector{Tv,Ti}, x), X)...)
1149+
r = (function (::Type{SV}) where SV
1150+
_absspvec_vcat(map(x -> convert(SV, x), X)...)
1151+
end)(SparseVector{Tv,Ti})
11481152
return @if_move_fixed Xin... r
11491153
end
11501154
function _absspvec_vcat(X::AbstractSparseVector{Tv,Ti}...) where {Tv,Ti}
@@ -1194,13 +1198,14 @@ anysparse() = false
11941198
anysparse(X) = X isa AbstractArray && issparse(X)
11951199
anysparse(X, Xs...) = anysparse(X) || anysparse(Xs...)
11961200

1197-
function hcat(X::Union{Vector, AbstractSparseVector}...)
1201+
const _SparseVecConcatGroup = Union{Vector, AbstractSparseVector}
1202+
function hcat(X::_SparseVecConcatGroup...)
11981203
if anysparse(X...)
11991204
X = map(sparse, X)
12001205
end
12011206
return cat(X...; dims=Val(2))
12021207
end
1203-
function vcat(X::Union{Vector, AbstractSparseVector}...)
1208+
function vcat(X::_SparseVecConcatGroup...)
12041209
if anysparse(X...)
12051210
X = map(sparse, X)
12061211
end
@@ -1213,30 +1218,30 @@ end
12131218
const _SparseConcatGroup = Union{AbstractVecOrMat{<:Number},Number}
12141219

12151220
# `@constprop :aggressive` allows `dims` to be propagated as constant improving return type inference
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))...)
1221+
Base.@constprop :aggressive function Base._cat(dims, X1::_SparseConcatGroup, X::_SparseConcatGroup...)
1222+
T = promote_eltype(X1, X...)
1223+
if anysparse(X1) || anysparse(X...)
1224+
X1, X = _sparse(X1), map(_makesparse, X)
12201225
end
1221-
return Base._cat_t(dims, T, X...)
1226+
return Base._cat_t(dims, T, X1, X...)
12221227
end
1223-
function hcat(X::_SparseConcatGroup...)
1224-
if anysparse(X...)
1225-
X = (_sparse(first(X)), map(_makesparse, Base.tail(X))...)
1228+
function hcat(X1::_SparseConcatGroup, X::_SparseConcatGroup...)
1229+
if anysparse(X1) || anysparse(X...)
1230+
X1, X = _sparse(X1), map(_makesparse, X)
12261231
end
1227-
return cat(X..., dims=Val(2))
1232+
return cat(X1, X..., dims=Val(2))
12281233
end
1229-
function vcat(X::_SparseConcatGroup...)
1230-
if anysparse(X...)
1231-
X = (_sparse(first(X)), map(_makesparse, Base.tail(X))...)
1234+
function vcat(X1::_SparseConcatGroup, X::_SparseConcatGroup...)
1235+
if anysparse(X1) || anysparse(X...)
1236+
X1, X = _sparse(X1), map(_makesparse, X)
12321237
end
1233-
return cat(X..., dims=Val(1))
1238+
return cat(X1, X..., dims=Val(1))
12341239
end
1235-
function hvcat(rows::Tuple{Vararg{Int}}, X::_SparseConcatGroup...)
1236-
if anysparse(X...)
1237-
vcat(_hvcat_rows(rows, X...)...)
1240+
function hvcat(rows::Tuple{Vararg{Int}}, X1::_SparseConcatGroup, X::_SparseConcatGroup...)
1241+
if anysparse(X1) || anysparse(X...)
1242+
vcat(_hvcat_rows(rows, X1, X...)...)
12381243
else
1239-
Base.typed_hvcat(Base.promote_eltypeof(X...), rows, X...)
1244+
Base.typed_hvcat(Base.promote_eltypeof(X1, X...), rows, X1, X...)
12401245
end
12411246
end
12421247
function _hvcat_rows((row1, rows...)::Tuple{Vararg{Int}}, X::_SparseConcatGroup...)
@@ -1254,6 +1259,15 @@ function _hvcat_rows((row1, rows...)::Tuple{Vararg{Int}}, X::_SparseConcatGroup.
12541259
end
12551260
_hvcat_rows(::Tuple{}, X::_SparseConcatGroup...) = ()
12561261

1262+
# disambiguation for type-piracy problems created above
1263+
hcat(n1::Number, ns::Vararg{Number}) = invoke(hcat, Tuple{Vararg{Number}}, n1, ns...)
1264+
vcat(n1::Number, ns::Vararg{Number}) = invoke(vcat, Tuple{Vararg{Number}}, n1, ns...)
1265+
hcat(n1::Type{N}, ns::Vararg{N}) where {N<:Number} = invoke(hcat, Tuple{Vararg{Number}}, n1, ns...)
1266+
vcat(n1::Type{N}, ns::Vararg{N}) where {N<:Number} = invoke(vcat, Tuple{Vararg{Number}}, n1, ns...)
1267+
hvcat(rows::Tuple{Vararg{Int}}, n1::Number, ns::Vararg{Number}) = invoke(hvcat, Tuple{typeof(rows), Vararg{Number}}, rows, n1, ns...)
1268+
hvcat(rows::Tuple{Vararg{Int}}, n1::N, ns::Vararg{N}) where {N<:Number} = invoke(hvcat, Tuple{typeof(rows), Vararg{N}}, rows, n1, ns...)
1269+
1270+
12571271
# make sure UniformScaling objects are converted to sparse matrices for concatenation
12581272
promote_to_array_type(A::Tuple{Vararg{Union{_SparseConcatGroup,UniformScaling}}}) = anysparse(A...) ? SparseMatrixCSC : Matrix
12591273
promote_to_arrays_(n::Int, ::Type{SparseMatrixCSC}, J::UniformScaling) = sparse(J, n, n)

test/ambiguous.jl

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,31 +50,29 @@ using Test, LinearAlgebra, SparseArrays, Aqua
5050
end
5151
end
5252

53-
@testset "detect_ambiguities" begin
54-
@test_nowarn detect_ambiguities(SparseArrays; recursive=true, ambiguous_bottom=false)
53+
let ambig = detect_ambiguities(SparseArrays; recursive=true)
54+
@test_broken isempty(ambig)
55+
ambig = Set{Any}(((m1.sig, m2.sig) for (m1, m2) in ambig))
56+
expect = []
57+
push!(expect, (Tuple{typeof(LinearAlgebra.generic_trimatmul!), AbstractVecOrMat, Any, Any, Function, AbstractMatrix, AbstractVecOrMat},
58+
Tuple{typeof(LinearAlgebra.generic_trimatmul!), StridedVecOrMat, Any, Any, Any, Union{Adjoint{var"#s388", var"#s387"}, Transpose{var"#s388", var"#s387"}} where {var"#s388", var"#s387"<:(Union{SparseArrays.AbstractSparseMatrixCSC{Tv, Ti}, SubArray{Tv, 2, <:SparseArrays.AbstractSparseMatrixCSC{Tv, Ti}, Tuple{Base.Slice{Base.OneTo{Int}}, I}} where I<:AbstractUnitRange} where {Tv, Ti})}, AbstractVecOrMat}))
59+
push!(expect, (Tuple{typeof(LinearAlgebra.generic_trimatmul!), AbstractVecOrMat, Any, Any, Function, Union{Adjoint{T, S}, Transpose{T, S}} where {T, S}, AbstractVecOrMat},
60+
Tuple{typeof(LinearAlgebra.generic_trimatmul!), StridedVecOrMat, Any, Any, Any, Union{Adjoint{var"#s388", var"#s387"}, Transpose{var"#s388", var"#s387"}} where {var"#s388", var"#s387"<:(Union{SparseArrays.AbstractSparseMatrixCSC{Tv, Ti}, SubArray{Tv, 2, <:SparseArrays.AbstractSparseMatrixCSC{Tv, Ti}, Tuple{Base.Slice{Base.OneTo{Int}}, I}} where I<:AbstractUnitRange} where {Tv, Ti})}, AbstractVecOrMat}))
61+
good = true
62+
while !isempty(ambig)
63+
sigs = pop!(ambig)
64+
i = findfirst(==(sigs), expect)
65+
if i === nothing
66+
println(stderr, "push!(expect, (", sigs[1], ", ", sigs[2], "))")
67+
good = false
68+
continue
69+
end
70+
deleteat!(expect, i)
71+
end
72+
@test isempty(expect)
73+
@test good
5574
end
5675

57-
## This was the older version that was disabled
58-
59-
# let ambig = detect_ambiguities(SparseArrays; recursive=true)
60-
# @test isempty(ambig)
61-
# ambig = Set{Any}(((m1.sig, m2.sig) for (m1, m2) in ambig))
62-
# expect = []
63-
# good = true
64-
# while !isempty(ambig)
65-
# sigs = pop!(ambig)
66-
# i = findfirst(==(sigs), expect)
67-
# if i === nothing
68-
# println(stderr, "push!(expect, (", sigs[1], ", ", sigs[2], "))")
69-
# good = false
70-
# continue
71-
# end
72-
# deleteat!(expect, i)
73-
# end
74-
# @test isempty(expect)
75-
# @test good
76-
# end
77-
7876
###
7977
# Now we restore the original env, as promised
8078
empty!(Base.DEPOT_PATH)

0 commit comments

Comments
 (0)