diff --git a/base/deprecated.jl b/base/deprecated.jl index 35da70e7a5a41..661c16353b0dc 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1146,6 +1146,129 @@ for (dep, f, op) in [(:sumabs!, :sum!, :abs), end end +## Deprecate broadcast_zpreserving[!] (wasn't exported, but might as well be friendly) +function gen_broadcast_function_sparse(genbody::Function, f::Function, is_first_sparse::Bool) + body = genbody(f, is_first_sparse) + @eval let + local _F_ + function _F_{Tv,Ti}(B::SparseMatrixCSC{Tv,Ti}, A_1, A_2) + $body + end + _F_ + end +end +function gen_broadcast_body_zpreserving(f::Function, is_first_sparse::Bool) + F = Expr(:quote, f) + if is_first_sparse + A1 = :(A_1) + A2 = :(A_2) + op1 = :(val1) + op2 = :(val2) + else + A1 = :(A_2) + A2 = :(A_1) + op1 = :(val2) + op2 = :(val1) + end + quote + Base.Broadcast.check_broadcast_indices(indices(B), $A1) + Base.Broadcast.check_broadcast_indices(indices(B), $A2) + + nnzB = isempty(B) ? 0 : + nnz($A1) * div(B.n, ($A1).n) * div(B.m, ($A1).m) + if length(B.rowval) < nnzB + resize!(B.rowval, nnzB) + end + if length(B.nzval) < nnzB + resize!(B.nzval, nnzB) + end + z = zero(Tv) + + ptrB = 1 + B.colptr[1] = 1 + + @inbounds for col = 1:B.n + ptr1::Int = ($A1).n == 1 ? ($A1).colptr[1] : ($A1).colptr[col] + stop1::Int = ($A1).n == 1 ? ($A1).colptr[2] : ($A1).colptr[col+1] + col2 = size($A2, 2) == 1 ? 1 : col + row = 1 + while ptr1 < stop1 && row <= B.m + if ($A1).m != 1 + row = ($A1).rowval[ptr1] + end + row2 = size($A2, 1) == 1 ? 1 : row + val1 = ($A1).nzval[ptr1] + val2 = ($A2)[row2,col2] + res = ($F)($op1, $op2) + if res != z + B.rowval[ptrB] = row + B.nzval[ptrB] = res + ptrB += 1 + end + if ($A1).m != 1 + ptr1 += 1 + else + row += 1 + end + end + B.colptr[col+1] = ptrB + end + deleteat!(B.rowval, B.colptr[end]:length(B.rowval)) + deleteat!(B.nzval, B.colptr[end]:length(B.nzval)) + nothing + end +end +for (Bsig, A1sig, A2sig, gbb, funcname) in + ( + (SparseMatrixCSC , SparseMatrixCSC , Array, :gen_broadcast_body_zpreserving, :_broadcast_zpreserving!), + (SparseMatrixCSC , Array , SparseMatrixCSC, :gen_broadcast_body_zpreserving, :_broadcast_zpreserving!), + (SparseMatrixCSC , Number , SparseMatrixCSC, :gen_broadcast_body_zpreserving, :_broadcast_zpreserving!), + (SparseMatrixCSC , SparseMatrixCSC , Number, :gen_broadcast_body_zpreserving, :_broadcast_zpreserving!), + (SparseMatrixCSC , BitArray , SparseMatrixCSC, :gen_broadcast_body_zpreserving, :_broadcast_zpreserving!), + (SparseMatrixCSC , SparseMatrixCSC , BitArray, :gen_broadcast_body_zpreserving, :_broadcast_zpreserving!), + ) + @eval let cache = Dict{Function,Function}() + global $funcname + function $funcname(f::Function, B::$Bsig, A1::$A1sig, A2::$A2sig) + func = @get! cache f gen_broadcast_function_sparse($gbb, f, ($A1sig) <: SparseMatrixCSC) + # need eval because func was just created by gen_broadcast_function_sparse + # TODO: convert this to a generated function + eval(current_module(), Expr(:body, Expr(:return, Expr(:call, QuoteNode(func), QuoteNode(B), QuoteNode(A1), QuoteNode(A2))))) + return B + end + end # let broadcast_cache +end +_broadcast_zpreserving!(args...) = broadcast!(args...) +_broadcast_zpreserving(args...) = Base.Broadcast.broadcast_elwise_op(args...) +_broadcast_zpreserving{Tv1,Ti1,Tv2,Ti2}(f::Function, A_1::SparseMatrixCSC{Tv1,Ti1}, A_2::SparseMatrixCSC{Tv2,Ti2}) = + _broadcast_zpreserving!(f, spzeros(promote_type(Tv1, Tv2), promote_type(Ti1, Ti2), Base.to_shape(Base.Broadcast.broadcast_indices(A_1, A_2))), A_1, A_2) +_broadcast_zpreserving{Tv,Ti}(f::Function, A_1::SparseMatrixCSC{Tv,Ti}, A_2::Union{Array,BitArray,Number}) = + _broadcast_zpreserving!(f, spzeros(promote_eltype(A_1, A_2), Ti, Base.to_shape(Base.Broadcast.broadcast_indices(A_1, A_2))), A_1, A_2) +_broadcast_zpreserving{Tv,Ti}(f::Function, A_1::Union{Array,BitArray,Number}, A_2::SparseMatrixCSC{Tv,Ti}) = + _broadcast_zpreserving!(f, spzeros(promote_eltype(A_1, A_2), Ti, Base.to_shape(Base.Broadcast.broadcast_indices(A_1, A_2))), A_1, A_2) + +function _depstring_bczpres() + return string("broadcast_zpreserving[!] is deprecated. Generic sparse broadcast[!] ", + "provides most of broadcast_zpreserving[!]'s functionality. If you have a use case ", + "that generic sparse broadcast[!] does not cover, please describe your use case in ", + " issue #19533 (https://github.com/JuliaLang/julia/issues/19533).") +end +function _depwarn_bczpres(f, args...) + depwarn(_depstring_bczpres(), :broadcast_zpreserving) + return _broadcast_zpreserving(f, args...) +end +function _depwarn_bczpres!(f, args...) + depwarn(_depstring_bczpres(), :broadcast_zpreserving!) + return _broadcast_zpreserving!(f, args...) +end +eval(SparseArrays, :(broadcast_zpreserving(f, args...) = Base._depwarn_bczpres(f, args...))) +eval(SparseArrays, :(broadcast_zpreserving(f, A::SparseMatrixCSC, B::SparseMatrixCSC) = Base._depwarn_bczpres(f, A, B))) +eval(SparseArrays, :(broadcast_zpreserving(f, A::SparseMatrixCSC, B::Union{Array,BitArray,Number}) = Base._depwarn_bczpres(f, A, B))) +eval(SparseArrays, :(broadcast_zpreserving(f, A::Union{Array,BitArray,Number}, B::SparseMatrixCSC) = Base._depwarn_bczpres(f, A, B))) +eval(SparseArrays, :(broadcast_zpreserving!(f, args...) = Base._depwarn_bczpres!(f, args...))) +eval(SparseArrays, :(broadcast_zpreserving!(f, C::SparseMatrixCSC, A::SparseMatrixCSC, B::Union{Array,BitArray,Number}) = Base._depwarn_bczpres!(f, C, A, B))) +eval(SparseArrays, :(broadcast_zpreserving!(f, C::SparseMatrixCSC, A::Union{Array,BitArray,Number}, B::SparseMatrixCSC) = Base._depwarn_bczpres!(f, C, A, B))) + # #19719 @deprecate getindex(t::Tuple, r::AbstractArray) getindex(t, vec(r)) @deprecate getindex(t::Tuple, b::AbstractArray{Bool}) getindex(t, vec(b)) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 2d045e23a9d2a..7d8f14ed064ec 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -2160,117 +2160,6 @@ broadcast{Tf,T}(f::Tf, ::Type{T}, A::SparseMatrixCSC) = broadcast(y -> f(T, y), broadcast{Tf,T}(f::Tf, A::SparseMatrixCSC, ::Type{T}) = broadcast(x -> f(x, T), A) -## Define unexported broadcast_zpreserving[!] methods -# TODO: Sort out what to do with broadcast_zpreserving and dependencies - -function gen_broadcast_function_sparse(genbody::Function, f::Function, is_first_sparse::Bool) - body = genbody(f, is_first_sparse) - @eval let - local _F_ - function _F_{Tv,Ti}(B::SparseMatrixCSC{Tv,Ti}, A_1, A_2) - $body - end - _F_ - end -end - -# Operations with zero result if any operand is zero -# A_1 or A_2 (or both) are sparse. -# is_first_sparse == true => A_1 is sparse -# is_first_sparse == false => A_2 is sparse -function gen_broadcast_body_zpreserving(f::Function, is_first_sparse::Bool) - F = Expr(:quote, f) - if is_first_sparse - A1 = :(A_1) - A2 = :(A_2) - op1 = :(val1) - op2 = :(val2) - else - A1 = :(A_2) - A2 = :(A_1) - op1 = :(val2) - op2 = :(val1) - end - quote - Base.Broadcast.check_broadcast_indices(indices(B), $A1) - Base.Broadcast.check_broadcast_indices(indices(B), $A2) - - nnzB = isempty(B) ? 0 : - nnz($A1) * div(B.n, ($A1).n) * div(B.m, ($A1).m) - if length(B.rowval) < nnzB - resize!(B.rowval, nnzB) - end - if length(B.nzval) < nnzB - resize!(B.nzval, nnzB) - end - z = zero(Tv) - - ptrB = 1 - B.colptr[1] = 1 - - @inbounds for col = 1:B.n - ptr1::Int = ($A1).n == 1 ? ($A1).colptr[1] : ($A1).colptr[col] - stop1::Int = ($A1).n == 1 ? ($A1).colptr[2] : ($A1).colptr[col+1] - col2 = size($A2, 2) == 1 ? 1 : col - row = 1 - while ptr1 < stop1 && row <= B.m - if ($A1).m != 1 - row = ($A1).rowval[ptr1] - end - row2 = size($A2, 1) == 1 ? 1 : row - val1 = ($A1).nzval[ptr1] - val2 = ($A2)[row2,col2] - res = ($F)($op1, $op2) - if res != z - B.rowval[ptrB] = row - B.nzval[ptrB] = res - ptrB += 1 - end - if ($A1).m != 1 - ptr1 += 1 - else - row += 1 - end - end - B.colptr[col+1] = ptrB - end - deleteat!(B.rowval, B.colptr[end]:length(B.rowval)) - deleteat!(B.nzval, B.colptr[end]:length(B.nzval)) - nothing - end -end - -for (Bsig, A1sig, A2sig, gbb, funcname) in - ( - (SparseMatrixCSC , SparseMatrixCSC , Array, :gen_broadcast_body_zpreserving, :broadcast_zpreserving!), - (SparseMatrixCSC , Array , SparseMatrixCSC, :gen_broadcast_body_zpreserving, :broadcast_zpreserving!), - (SparseMatrixCSC , Number , SparseMatrixCSC, :gen_broadcast_body_zpreserving, :broadcast_zpreserving!), - (SparseMatrixCSC , SparseMatrixCSC , Number, :gen_broadcast_body_zpreserving, :broadcast_zpreserving!), - (SparseMatrixCSC , BitArray , SparseMatrixCSC, :gen_broadcast_body_zpreserving, :broadcast_zpreserving!), - (SparseMatrixCSC , SparseMatrixCSC , BitArray, :gen_broadcast_body_zpreserving, :broadcast_zpreserving!), - ) - @eval let cache = Dict{Function,Function}() - global $funcname - function $funcname(f::Function, B::$Bsig, A1::$A1sig, A2::$A2sig) - func = @get! cache f gen_broadcast_function_sparse($gbb, f, ($A1sig) <: SparseMatrixCSC) - # need eval because func was just created by gen_broadcast_function_sparse - # TODO: convert this to a generated function - eval(current_module(), Expr(:body, Expr(:return, Expr(:call, QuoteNode(func), QuoteNode(B), QuoteNode(A1), QuoteNode(A2))))) - return B - end - end # let broadcast_cache -end - -@inline broadcast_zpreserving!(args...) = broadcast!(args...) -@inline broadcast_zpreserving(args...) = Base.Broadcast.broadcast_elwise_op(args...) -broadcast_zpreserving{Tv1,Ti1,Tv2,Ti2}(f::Function, A_1::SparseMatrixCSC{Tv1,Ti1}, A_2::SparseMatrixCSC{Tv2,Ti2}) = - broadcast_zpreserving!(f, spzeros(promote_type(Tv1, Tv2), promote_type(Ti1, Ti2), to_shape(broadcast_indices(A_1, A_2))), A_1, A_2) -broadcast_zpreserving{Tv,Ti}(f::Function, A_1::SparseMatrixCSC{Tv,Ti}, A_2::Union{Array,BitArray,Number}) = - broadcast_zpreserving!(f, spzeros(promote_eltype(A_1, A_2), Ti, to_shape(broadcast_indices(A_1, A_2))), A_1, A_2) -broadcast_zpreserving{Tv,Ti}(f::Function, A_1::Union{Array,BitArray,Number}, A_2::SparseMatrixCSC{Tv,Ti}) = - broadcast_zpreserving!(f, spzeros(promote_eltype(A_1, A_2), Ti, to_shape(broadcast_indices(A_1, A_2))), A_1, A_2) - - # TODO: More appropriate location? conj!(A::SparseMatrixCSC) = (broadcast!(conj, A.nzval, A.nzval); A) (-)(A::SparseMatrixCSC) = SparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), map(-, A.nzval))