From 58a6b175b1215491e926354a5e62c66a3f637ce2 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Tue, 13 Sep 2022 07:51:01 +0200 Subject: [PATCH 1/2] resolve conflicts --- src/sparsevector.jl | 30 +++++++++++++++++++----------- test/sparsevector.jl | 16 ++++++++++++++++ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/sparsevector.jl b/src/sparsevector.jl index e17ae607..db97edd8 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -1075,20 +1075,28 @@ const _Annotated_SparseConcatArrays = Union{_Triangular_SparseConcatArrays, _Sym const _SparseConcatGroup = Union{_DenseConcatGroup, _SparseConcatArrays, _Annotated_SparseConcatArrays} # Concatenations involving un/annotated sparse/special matrices/vectors should yield sparse arrays + +# the output array type is determined by the first element of the to be concatenated objects +# if this is a Number, the output would be dense by the fallback abstractarray.jl code (see cat_similar) +# so make sure that if that happens, the "array" is sparse (if more sparse arrays are involved, of course) +_sparse(x::Number) = sparsevec([1], [x], 1) +_sparse(A) = _makesparse(A) _makesparse(x::Number) = x -_makesparse(x::AbstractArray) = SparseMatrixCSC(issparse(x) ? x : sparse(x)) +_makesparse(x::AbstractVector) = convert(SparseVector, issparse(x) ? x : sparse(x))::SparseVector +_makesparse(x::AbstractMatrix) = convert(SparseMatrixCSC, issparse(x) ? x : sparse(x))::SparseMatrixCSC -function Base._cat(dims, Xin::_SparseConcatGroup...) - X = map(_makesparse, Xin) +# `@constprop :aggressive` allows `dims` to be propagated as constant improving return type inference +Base.@constprop :aggressive function Base._cat(dims, Xin::_SparseConcatGroup...) + X = (_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...) T = promote_eltype(Xin...) Base.cat_t(T, X...; dims=dims) end function hcat(Xin::_SparseConcatGroup...) - X = map(_makesparse, Xin) + X = (_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...) return cat(X..., dims=Val(2)) end function vcat(Xin::_SparseConcatGroup...) - X = map(_makesparse, Xin) + X = (_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...) return cat(X..., dims=Val(1)) end hvcat(rows::Tuple{Vararg{Int}}, X::_SparseConcatGroup...) = @@ -1122,9 +1130,9 @@ Concatenate along dimension 2. Return a SparseMatrixCSC object. the concatenation with specialized "sparse" matrix types from LinearAlgebra.jl automatically yielded sparse output even in the absence of any SparseArray argument. """ -sparse_hcat(Xin::Union{AbstractVecOrMat,Number}...) = cat(map(_makesparse, Xin)..., dims=Val(2)) +sparse_hcat(Xin::Union{AbstractVecOrMat,Number}...) = cat(_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))..., dims=Val(2)) function sparse_hcat(X::Union{AbstractVecOrMat,UniformScaling,Number}...) - LinearAlgebra._hcat(X...; array_type = SparseMatrixCSC) + LinearAlgebra._hcat(_sparse(first(X)), map(_makesparse, Base.tail(X))...; array_type = SparseMatrixCSC) end """ @@ -1137,9 +1145,9 @@ Concatenate along dimension 1. Return a SparseMatrixCSC object. the concatenation with specialized "sparse" matrix types from LinearAlgebra.jl automatically yielded sparse output even in the absence of any SparseArray argument. """ -sparse_vcat(Xin::Union{AbstractVecOrMat,Number}...) = cat(map(_makesparse, Xin)..., dims=Val(1)) +sparse_vcat(Xin::Union{AbstractVecOrMat,Number}...) = cat(_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))..., dims=Val(1)) function sparse_vcat(X::Union{AbstractVecOrMat,UniformScaling,Number}...) - LinearAlgebra._vcat(X...; array_type = SparseMatrixCSC) + LinearAlgebra._vcat(_sparse(first(X)), map(_makesparse, Base.tail(X))...; array_type = SparseMatrixCSC) end """ @@ -1155,10 +1163,10 @@ arguments to concatenate in each block row. automatically yielded sparse output even in the absence of any SparseArray argument. """ function sparse_hvcat(rows::Tuple{Vararg{Int}}, Xin::Union{AbstractVecOrMat,Number}...) - hvcat(rows, map(_makesparse, Xin)...) + hvcat(rows, _sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...) end function sparse_hvcat(rows::Tuple{Vararg{Int}}, X::Union{AbstractVecOrMat,UniformScaling,Number}...) - LinearAlgebra._hvcat(rows, X...; array_type = SparseMatrixCSC) + LinearAlgebra._hvcat(rows, _sparse(first(X)), map(_makesparse, Base.tail(X))...; array_type = SparseMatrixCSC) end ### math functions diff --git a/test/sparsevector.jl b/test/sparsevector.jl index 53b8060d..7d770ce9 100644 --- a/test/sparsevector.jl +++ b/test/sparsevector.jl @@ -537,6 +537,22 @@ end @test length(V) == m * n Vr = vec(Hr) @test Array(V) == Vr + Vnum = vcat(A..., zero(Float64)) + Vnum2 = sparse_vcat(map(Array, A)..., zero(Float64)) + @test Vnum isa SparseVector{Float64,Int} + @test Vnum2 isa SparseVector{Float64,Int} + @test length(Vnum) == length(Vnum2) == m*n + 1 + @test Array(Vnum) == Array(Vnum2) == [Vr; 0] + Vnum = vcat(zero(Float64), A...) + Vnum2 = sparse_vcat(zero(Float64), map(Array, A)...) + @test Vnum isa SparseVector{Float64,Int} + @test Vnum2 isa SparseVector{Float64,Int} + @test length(Vnum) == length(Vnum2) == m*n + 1 + @test Array(Vnum) == Array(Vnum2) == [0; Vr] + # case with rowwise a Number as first element, should still yield a sparse matrix + x = sparsevec([1], [3.0], 1) + X = [3.0 x; 3.0 x] + @test issparse(X) end @testset "concatenation of sparse vectors with other types" begin From 9ab6921340b60ca0be4ad1ba9525daa094dd4c10 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Tue, 13 Sep 2022 20:05:58 +0200 Subject: [PATCH 2/2] Remove later constant propagation changes --- src/sparsevector.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sparsevector.jl b/src/sparsevector.jl index db97edd8..2b56fe17 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -1085,8 +1085,7 @@ _makesparse(x::Number) = x _makesparse(x::AbstractVector) = convert(SparseVector, issparse(x) ? x : sparse(x))::SparseVector _makesparse(x::AbstractMatrix) = convert(SparseMatrixCSC, issparse(x) ? x : sparse(x))::SparseMatrixCSC -# `@constprop :aggressive` allows `dims` to be propagated as constant improving return type inference -Base.@constprop :aggressive function Base._cat(dims, Xin::_SparseConcatGroup...) +function Base._cat(dims, Xin::_SparseConcatGroup...) X = (_sparse(first(Xin)), map(_makesparse, Base.tail(Xin))...) T = promote_eltype(Xin...) Base.cat_t(T, X...; dims=dims)