Skip to content

Commit b0fde3f

Browse files
committed
WIP: SparseArrays done
[ci skip]
1 parent 7099d66 commit b0fde3f

File tree

6 files changed

+202
-181
lines changed

6 files changed

+202
-181
lines changed

base/deprecated.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -574,13 +574,14 @@ end
574574

575575
# issue #...: nonscalar indexed assignment of many values to many locations
576576
function deprecate_nonscalar_indexed_assignment!(A::AbstractArray, X::AbstractArray, I...)
577-
shape = Base.index_shape(I...)
577+
J = to_indices(A, I)
578+
shape = Base.index_shape(J...)
578579
if shape == axes(X)
579580
depwarn("using `A[I...] = X` to implicitly broadcast the elements of `X` to many locations in `A` is deprecated. Use `A[I...] .= X` to explicitly opt-in to broadcasting.", :setindex!)
580-
A[I...] .= X
581+
A[J...] .= X
581582
else
582583
depwarn("using `A[I...] = X` to implicitly broadcast the elements of `X` to many locations in `A` is deprecated. Use `A[I...] .= reshape(X, axes(view(A, I...)))` to explicitly opt-in to broadcasting.", :setindex!)
583-
A[I...] .= reshape(X, shape)
584+
A[J...] .= reshape(X, shape)
584585
end
585586
end
586587
_unsafe_setindex!(::IndexStyle, A::AbstractArray, X::AbstractArray, I::Union{Real,AbstractArray}...) = deprecate_nonscalar_indexed_assignment!(A, X, I...)

stdlib/SparseArrays/src/deprecated.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,17 @@ import Base: asyncmap
227227
@deprecate dropzeros!(x, trim) dropzeros!(x, trim = trim)
228228
@deprecate droptol!(A, tol, trim) droptol!(A, tol, trim = trim)
229229

230+
# Multi-value setindex broadcasting
231+
setindex!(A::SparseMatrixCSC, x::AbstractArray, i::Colon) = Base.deprecate_nonscalar_indexed_assignment!(A, x, i)
232+
setindex!(A::SparseMatrixCSC, x::AbstractArray, i::Colon, j::Colon) = Base.deprecate_nonscalar_indexed_assignment!(A, x, i, j)
233+
setindex!(A::SparseMatrixCSC, x::AbstractArray, i::Colon, j::Union{Integer, AbstractVector}) = Base.deprecate_nonscalar_indexed_assignment!(A, x, i, j)
234+
setindex!(A::SparseMatrixCSC, x::AbstractArray, i::Union{Integer, AbstractVector}, j::Colon) = Base.deprecate_nonscalar_indexed_assignment!(A, x, i, j)
235+
setindex!(A::SparseMatrixCSC, x::AbstractArray, i::Integer, J::AbstractVector{<:Integer}) = Base.deprecate_nonscalar_indexed_assignment!(A, x, i, J)
236+
setindex!(A::SparseMatrixCSC, x::AbstractArray, I::AbstractVector{<:Integer}, j::Integer) = Base.deprecate_nonscalar_indexed_assignment!(A, x, I, j)
237+
setindex!(A::SparseMatrixCSC, x::AbstractArray, I::AbstractVector{<:Integer}, J::AbstractVector{<:Integer}) = Base.deprecate_nonscalar_indexed_assignment!(A, x, I, J)
238+
setindex!(A::SparseMatrixCSC, x::AbstractArray, I::AbstractVector{<:Real}) = Base.deprecate_nonscalar_indexed_assignment!(A, x, I)
239+
setindex!(A::SparseMatrixCSC, x::AbstractArray, I::AbstractMatrix{Bool}) = Base.deprecate_nonscalar_indexed_assignment!(A, x, I)
240+
230241
# END 0.7 deprecations
231242

232243
# BEGIN 1.0 deprecations

stdlib/SparseArrays/src/sparsematrix.jl

Lines changed: 165 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,19 +2327,16 @@ function setindex!(A::SparseMatrixCSC{Tv,Ti}, v::Tv, i::Ti, j::Ti) where Tv wher
23272327
return A
23282328
end
23292329

2330-
setindex!(A::SparseMatrixCSC, v::AbstractMatrix, i::Integer, J::AbstractVector{<:Integer}) = setindex!(A, v, [i], J)
2331-
setindex!(A::SparseMatrixCSC, v::AbstractMatrix, I::AbstractVector{<:Integer}, j::Integer) = setindex!(A, v, I, [j])
2332-
2333-
setindex!(A::SparseMatrixCSC, x::Number, i::Integer, J::AbstractVector{<:Integer}) = setindex!(A, x, [i], J)
2334-
setindex!(A::SparseMatrixCSC, x::Number, I::AbstractVector{<:Integer}, j::Integer) = setindex!(A, x, I, [j])
2330+
setindex!(A::SparseMatrixCSC, x, i::Integer, J::AbstractVector{<:Integer}) = setindex!(A, x, [i], J)
2331+
setindex!(A::SparseMatrixCSC, x, I::AbstractVector{<:Integer}, j::Integer) = setindex!(A, x, I, [j])
23352332

23362333
# Colon translation
23372334
setindex!(A::SparseMatrixCSC, x, ::Colon) = setindex!(A, x, 1:length(A))
23382335
setindex!(A::SparseMatrixCSC, x, ::Colon, ::Colon) = setindex!(A, x, 1:size(A, 1), 1:size(A,2))
23392336
setindex!(A::SparseMatrixCSC, x, ::Colon, j::Union{Integer, AbstractVector}) = setindex!(A, x, 1:size(A, 1), j)
23402337
setindex!(A::SparseMatrixCSC, x, i::Union{Integer, AbstractVector}, ::Colon) = setindex!(A, x, i, 1:size(A, 2))
23412338

2342-
function setindex!(A::SparseMatrixCSC{Tv}, x::Number,
2339+
function setindex!(A::SparseMatrixCSC{Tv}, x,
23432340
I::AbstractVector{<:Integer}, J::AbstractVector{<:Integer}) where Tv
23442341
if isempty(I) || isempty(J); return A; end
23452342
# lt=≤ to check for strict sorting
@@ -2500,155 +2497,6 @@ function _spsetnz_setindex!(A::SparseMatrixCSC{Tv}, x::Tv,
25002497
return A
25012498
end
25022499

2503-
setindex!(A::SparseMatrixCSC{Tv,Ti}, S::Matrix, I::AbstractVector{T}, J::AbstractVector{T}) where {Tv,Ti,T<:Integer} =
2504-
setindex!(A, convert(SparseMatrixCSC{Tv,Ti}, S), I, J)
2505-
2506-
setindex!(A::SparseMatrixCSC, v::AbstractVector, I::AbstractVector{<:Integer}, j::Integer) = setindex!(A, v, I, [j])
2507-
setindex!(A::SparseMatrixCSC, v::AbstractVector, i::Integer, J::AbstractVector{<:Integer}) = setindex!(A, v, [i], J)
2508-
setindex!(A::SparseMatrixCSC, v::AbstractVector, I::AbstractVector{T}, J::AbstractVector{T}) where {T<:Integer} =
2509-
setindex!(A, reshape(v, length(I), length(J)), I, J)
2510-
2511-
# A[I,J] = B
2512-
function setindex!(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}, I::AbstractVector{T}, J::AbstractVector{T}) where {Tv,Ti,T<:Integer}
2513-
if size(B,1) != length(I) || size(B,2) != length(J)
2514-
throw(DimensionMismatch(""))
2515-
end
2516-
2517-
issortedI = issorted(I)
2518-
issortedJ = issorted(J)
2519-
2520-
if !issortedI && !issortedJ
2521-
pI = sortperm(I); @inbounds I = I[pI]
2522-
pJ = sortperm(J); @inbounds J = J[pJ]
2523-
B = B[pI, pJ]
2524-
elseif !issortedI
2525-
pI = sortperm(I); @inbounds I = I[pI]
2526-
B = B[pI,:]
2527-
elseif !issortedJ
2528-
pJ = sortperm(J); @inbounds J = J[pJ]
2529-
B = B[:, pJ]
2530-
end
2531-
2532-
m, n = size(A)
2533-
mB, nB = size(B)
2534-
2535-
if (!isempty(I) && (I[1] < 1 || I[end] > m)) || (!isempty(J) && (J[1] < 1 || J[end] > n))
2536-
throw(BoundsError(A, (I, J)))
2537-
end
2538-
2539-
if isempty(I) || isempty(J)
2540-
return A
2541-
end
2542-
2543-
nI = length(I)
2544-
nJ = length(J)
2545-
2546-
colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval
2547-
colptrB = B.colptr; rowvalB = B.rowval; nzvalB = B.nzval
2548-
2549-
nnzS = nnz(A) + nnz(B)
2550-
2551-
colptrS = copy(A.colptr)
2552-
rowvalS = copy(A.rowval)
2553-
nzvalS = copy(A.nzval)
2554-
2555-
resize!(rowvalA, nnzS)
2556-
resize!(nzvalA, nnzS)
2557-
2558-
colB = 1
2559-
asgn_col = J[colB]
2560-
2561-
I_asgn = falses(m)
2562-
I_asgn[I] = true
2563-
2564-
ptrS = 1
2565-
2566-
@inbounds for col = 1:n
2567-
2568-
# Copy column of A if it is not being assigned into
2569-
if colB > nJ || col != J[colB]
2570-
colptrA[col+1] = colptrA[col] + (colptrS[col+1]-colptrS[col])
2571-
2572-
for k = colptrS[col]:colptrS[col+1]-1
2573-
rowvalA[ptrS] = rowvalS[k]
2574-
nzvalA[ptrS] = nzvalS[k]
2575-
ptrS += 1
2576-
end
2577-
continue
2578-
end
2579-
2580-
ptrA::Int = colptrS[col]
2581-
stopA::Int = colptrS[col+1]
2582-
ptrB::Int = colptrB[colB]
2583-
stopB::Int = colptrB[colB+1]
2584-
2585-
while ptrA < stopA && ptrB < stopB
2586-
rowA = rowvalS[ptrA]
2587-
rowB = I[rowvalB[ptrB]]
2588-
if rowA < rowB
2589-
rowvalA[ptrS] = rowA
2590-
nzvalA[ptrS] = I_asgn[rowA] ? zero(Tv) : nzvalS[ptrA]
2591-
ptrS += 1
2592-
ptrA += 1
2593-
elseif rowB < rowA
2594-
if nzvalB[ptrB] != zero(Tv)
2595-
rowvalA[ptrS] = rowB
2596-
nzvalA[ptrS] = nzvalB[ptrB]
2597-
ptrS += 1
2598-
end
2599-
ptrB += 1
2600-
else
2601-
rowvalA[ptrS] = rowB
2602-
nzvalA[ptrS] = nzvalB[ptrB]
2603-
ptrS += 1
2604-
ptrB += 1
2605-
ptrA += 1
2606-
end
2607-
end
2608-
2609-
while ptrA < stopA
2610-
rowA = rowvalS[ptrA]
2611-
rowvalA[ptrS] = rowA
2612-
nzvalA[ptrS] = I_asgn[rowA] ? zero(Tv) : nzvalS[ptrA]
2613-
ptrS += 1
2614-
ptrA += 1
2615-
end
2616-
2617-
while ptrB < stopB
2618-
rowB = I[rowvalB[ptrB]]
2619-
if nzvalB[ptrB] != zero(Tv)
2620-
rowvalA[ptrS] = rowB
2621-
nzvalA[ptrS] = nzvalB[ptrB]
2622-
ptrS += 1
2623-
end
2624-
ptrB += 1
2625-
end
2626-
2627-
colptrA[col+1] = ptrS
2628-
colB += 1
2629-
end
2630-
2631-
deleteat!(rowvalA, colptrA[end]:length(rowvalA))
2632-
deleteat!(nzvalA, colptrA[end]:length(nzvalA))
2633-
2634-
return A
2635-
end
2636-
2637-
# Logical setindex!
2638-
2639-
setindex!(A::SparseMatrixCSC, x::Matrix, I::Integer, J::AbstractVector{Bool}) = setindex!(A, sparse(x), I, findall(J))
2640-
setindex!(A::SparseMatrixCSC, x::Matrix, I::AbstractVector{Bool}, J::Integer) = setindex!(A, sparse(x), findall(I), J)
2641-
setindex!(A::SparseMatrixCSC, x::Matrix, I::AbstractVector{Bool}, J::AbstractVector{Bool}) = setindex!(A, sparse(x), findall(I), findall(J))
2642-
setindex!(A::SparseMatrixCSC, x::Matrix, I::AbstractVector{<:Integer}, J::AbstractVector{Bool}) = setindex!(A, sparse(x), I, findall(J))
2643-
setindex!(A::SparseMatrixCSC, x::Matrix, I::AbstractVector{Bool}, J::AbstractVector{<:Integer}) = setindex!(A, sparse(x), findall(I),J)
2644-
2645-
setindex!(A::Matrix, x::SparseMatrixCSC, I::Integer, J::AbstractVector{Bool}) = setindex!(A, Array(x), I, findall(J))
2646-
setindex!(A::Matrix, x::SparseMatrixCSC, I::AbstractVector{Bool}, J::Integer) = setindex!(A, Array(x), findall(I), J)
2647-
setindex!(A::Matrix, x::SparseMatrixCSC, I::AbstractVector{Bool}, J::AbstractVector{Bool}) = setindex!(A, Array(x), findall(I), findall(J))
2648-
setindex!(A::Matrix, x::SparseMatrixCSC, I::AbstractVector{<:Integer}, J::AbstractVector{Bool}) = setindex!(A, Array(x), I, findall(J))
2649-
setindex!(A::Matrix, x::SparseMatrixCSC, I::AbstractVector{Bool}, J::AbstractVector{<:Integer}) = setindex!(A, Array(x), findall(I), J)
2650-
2651-
setindex!(A::SparseMatrixCSC, x, I::AbstractVector{Bool}) = throw(BoundsError())
26522500
function setindex!(A::SparseMatrixCSC, x, I::AbstractMatrix{Bool})
26532501
checkbounds(A, I)
26542502
n = sum(I)
@@ -2782,7 +2630,7 @@ function setindex!(A::SparseMatrixCSC, x, I::AbstractVector{<:Real})
27822630

27832631
# copy from last position till current column
27842632
if (nadd > 0)
2785-
colptrB[(lastcol+1):col] = colptrA[(lastcol+1):col] .+ nadd
2633+
colptrB[(lastcol+1):col] .= colptrA[(lastcol+1):col] .+ nadd
27862634
copylen = r1 - aidx
27872635
if copylen > 0
27882636
copyto!(rowvalB, bidx, rowvalA, aidx, copylen)
@@ -2857,6 +2705,167 @@ function setindex!(A::SparseMatrixCSC, x, I::AbstractVector{<:Real})
28572705
A
28582706
end
28592707

2708+
# Multi-value indexed assignment A[...] .= B gets represented as `broadcast!(identity, view(A, ...), B)`
2709+
const _Idx = Union{Integer,AbstractVector{<:Integer}}
2710+
const CSCAssignmentView{I<:Union{Tuple{_Idx},Tuple{_Idx,_Idx}}} = SubArray{<:Any,<:Any,<:SparseMatrixCSC,I,false}
2711+
_getij(S::CSCAssignmentView{<:Tuple{AbstractVector,AbstractVector}}) = S.indices
2712+
_getij(S::CSCAssignmentView{<:Tuple{Integer,Integer}}) = (S.indices[1]:S.indices[1], S.indices[2]:S.indices[2])
2713+
_getij(S::CSCAssignmentView{<:Tuple{Integer,AbstractVector}}) = (S.indices[1]:S.indices[1], S.indices[2])
2714+
_getij(S::CSCAssignmentView{<:Tuple{AbstractVector,Integer}}) = (S.indices[1], S.indices[2]:S.indices[2])
2715+
function _getij(S::CSCAssignmentView{<:Tuple{Integer}})
2716+
v = CartesianIndices(S.parent)[S.indices[1]]
2717+
return (v.I[1]:v.I[1], v.I[2]:v.I[2])
2718+
end
2719+
function _getij(S::CSCAssignmentView{<:Tuple{AbstractArray{CartesianIndex{2}}}})
2720+
V = reinterpret(Int, S.indices[1])
2721+
return @views (V[1:2:end], V[2:2:end])
2722+
end
2723+
function _getij(S::CSCAssignmentView{<:Tuple{AbstractArray}})
2724+
V = reinterpret(Int, CartesianIndices(S.parent)[S.indices[1]])
2725+
return @views (V[1:2:end], V[2:2:end])
2726+
end
2727+
2728+
function broadcast!(::typeof(identity), V::CSCAssignmentView, B::SparseMatrixCSC)
2729+
A = V.parent
2730+
I, J = _getij(V)
2731+
return multivaluesetindex!(A, B, I, J)
2732+
end
2733+
# Historically, we've only supported specialized methods based upon the value for Matrix
2734+
# and Vector by converting them to SparseMatrixCSCs of the correct shape. This could be
2735+
# extended to any AbstractArray in the future.
2736+
broadcast!(::typeof(identity), V::CSCAssignmentView, B::Matrix) = broadcast!(identity, V, convert(SparseMatrixCSC, B))
2737+
function broadcast!(::typeof(identity), V::CSCAssignmentView, x::Vector)
2738+
A = V.parent
2739+
I, J, = _getij(V)
2740+
return multivaluesetindex!(A, convert(SparseMatrixCSC, reshape(x, length(I), length(J))), I, J)
2741+
end
2742+
2743+
# A[I,J] .= B
2744+
function multivaluesetindex!(A::SparseMatrixCSC{Tv}, B::SparseMatrixCSC, I::AbstractVector{T}, J::AbstractVector{T}) where {Tv,T<:Integer}
2745+
if size(B,1) != length(I) || size(B,2) != length(J)
2746+
throw(DimensionMismatch(""))
2747+
end
2748+
2749+
issortedI = issorted(I)
2750+
issortedJ = issorted(J)
2751+
2752+
if !issortedI && !issortedJ
2753+
pI = sortperm(I); @inbounds I = I[pI]
2754+
pJ = sortperm(J); @inbounds J = J[pJ]
2755+
B = B[pI, pJ]
2756+
elseif !issortedI
2757+
pI = sortperm(I); @inbounds I = I[pI]
2758+
B = B[pI,:]
2759+
elseif !issortedJ
2760+
pJ = sortperm(J); @inbounds J = J[pJ]
2761+
B = B[:, pJ]
2762+
end
2763+
2764+
m, n = size(A)
2765+
mB, nB = size(B)
2766+
2767+
if (!isempty(I) && (I[1] < 1 || I[end] > m)) || (!isempty(J) && (J[1] < 1 || J[end] > n))
2768+
throw(BoundsError(A, (I, J)))
2769+
end
2770+
2771+
if isempty(I) || isempty(J)
2772+
return A
2773+
end
2774+
2775+
nI = length(I)
2776+
nJ = length(J)
2777+
2778+
colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval
2779+
colptrB = B.colptr; rowvalB = B.rowval; nzvalB = B.nzval
2780+
2781+
nnzS = nnz(A) + nnz(B)
2782+
2783+
colptrS = copy(A.colptr)
2784+
rowvalS = copy(A.rowval)
2785+
nzvalS = copy(A.nzval)
2786+
2787+
resize!(rowvalA, nnzS)
2788+
resize!(nzvalA, nnzS)
2789+
2790+
colB = 1
2791+
asgn_col = J[colB]
2792+
2793+
I_asgn = falses(m)
2794+
I_asgn[I] = true
2795+
2796+
ptrS = 1
2797+
2798+
@inbounds for col = 1:n
2799+
2800+
# Copy column of A if it is not being assigned into
2801+
if colB > nJ || col != J[colB]
2802+
colptrA[col+1] = colptrA[col] + (colptrS[col+1]-colptrS[col])
2803+
2804+
for k = colptrS[col]:colptrS[col+1]-1
2805+
rowvalA[ptrS] = rowvalS[k]
2806+
nzvalA[ptrS] = nzvalS[k]
2807+
ptrS += 1
2808+
end
2809+
continue
2810+
end
2811+
2812+
ptrA::Int = colptrS[col]
2813+
stopA::Int = colptrS[col+1]
2814+
ptrB::Int = colptrB[colB]
2815+
stopB::Int = colptrB[colB+1]
2816+
2817+
while ptrA < stopA && ptrB < stopB
2818+
rowA = rowvalS[ptrA]
2819+
rowB = I[rowvalB[ptrB]]
2820+
if rowA < rowB
2821+
rowvalA[ptrS] = rowA
2822+
nzvalA[ptrS] = I_asgn[rowA] ? zero(Tv) : nzvalS[ptrA]
2823+
ptrS += 1
2824+
ptrA += 1
2825+
elseif rowB < rowA
2826+
if nzvalB[ptrB] != zero(Tv)
2827+
rowvalA[ptrS] = rowB
2828+
nzvalA[ptrS] = nzvalB[ptrB]
2829+
ptrS += 1
2830+
end
2831+
ptrB += 1
2832+
else
2833+
rowvalA[ptrS] = rowB
2834+
nzvalA[ptrS] = nzvalB[ptrB]
2835+
ptrS += 1
2836+
ptrB += 1
2837+
ptrA += 1
2838+
end
2839+
end
2840+
2841+
while ptrA < stopA
2842+
rowA = rowvalS[ptrA]
2843+
rowvalA[ptrS] = rowA
2844+
nzvalA[ptrS] = I_asgn[rowA] ? zero(Tv) : nzvalS[ptrA]
2845+
ptrS += 1
2846+
ptrA += 1
2847+
end
2848+
2849+
while ptrB < stopB
2850+
rowB = I[rowvalB[ptrB]]
2851+
if nzvalB[ptrB] != zero(Tv)
2852+
rowvalA[ptrS] = rowB
2853+
nzvalA[ptrS] = nzvalB[ptrB]
2854+
ptrS += 1
2855+
end
2856+
ptrB += 1
2857+
end
2858+
2859+
colptrA[col+1] = ptrS
2860+
colB += 1
2861+
end
2862+
2863+
deleteat!(rowvalA, colptrA[end]:length(rowvalA))
2864+
deleteat!(nzvalA, colptrA[end]:length(nzvalA))
2865+
2866+
return A
2867+
end
2868+
28602869
## dropstored! methods
28612870
"""
28622871
dropstored!(A::SparseMatrixCSC, i::Integer, j::Integer)

0 commit comments

Comments
 (0)