diff --git a/stdlib/SparseArrays/src/higherorderfns.jl b/stdlib/SparseArrays/src/higherorderfns.jl index 6752ad3f55565..10def3e59aa1a 100644 --- a/stdlib/SparseArrays/src/higherorderfns.jl +++ b/stdlib/SparseArrays/src/higherorderfns.jl @@ -9,7 +9,7 @@ import Base: map, map!, broadcast, copy, copyto! using Base: front, tail, to_shape using ..SparseArrays: SparseVector, SparseMatrixCSC, AbstractSparseVector, AbstractSparseMatrix, AbstractSparseArray, indtype, nnz, nzrange, - SparseVectorUnion, AdjOrTransSparseVectorUnion, nonzeroinds, nonzeros + SparseVectorUnion, AdjOrTransSparseVectorUnion, nonzeroinds, nonzeros, rowvals, getcolptr using Base.Broadcast: BroadcastStyle, Broadcasted, flatten using LinearAlgebra @@ -108,24 +108,24 @@ const SpBroadcasted2{Style<:SPVM,Axes,F,Args<:Tuple{SparseVecOrMat,SparseVecOrMa # sufficient for the purposes of map[!]/broadcast[!]. This interface treats sparse vectors # as n-by-one sparse matrices which, though technically incorrect, is how broacast[!] views # sparse vectors in practice. -@inline numrows(A::SparseVector) = A.n -@inline numrows(A::SparseMatrixCSC) = A.m +@inline numrows(A::SparseVector) = length(A) +@inline numrows(A::SparseMatrixCSC) = size(A, 1) @inline numcols(A::SparseVector) = 1 -@inline numcols(A::SparseMatrixCSC) = A.n +@inline numcols(A::SparseMatrixCSC) = size(A, 2) # numrows and numcols respectively yield size(A, 1) and size(A, 2), but avoid a branch @inline columns(A::SparseVector) = 1 -@inline columns(A::SparseMatrixCSC) = 1:A.n -@inline colrange(A::SparseVector, j) = 1:length(A.nzind) +@inline columns(A::SparseMatrixCSC) = 1:size(A, 2) +@inline colrange(A::SparseVector, j) = 1:length(nonzeroinds(A)) @inline colrange(A::SparseMatrixCSC, j) = nzrange(A, j) @inline colstartind(A::SparseVector, j) = one(indtype(A)) -@inline colboundind(A::SparseVector, j) = convert(indtype(A), length(A.nzind) + 1) -@inline colstartind(A::SparseMatrixCSC, j) = A.colptr[j] -@inline colboundind(A::SparseMatrixCSC, j) = A.colptr[j + 1] -@inline storedinds(A::SparseVector) = A.nzind -@inline storedinds(A::SparseMatrixCSC) = A.rowval -@inline storedvals(A::SparseVecOrMat) = A.nzval +@inline colboundind(A::SparseVector, j) = convert(indtype(A), length(nonzeroinds(A)) + 1) +@inline colstartind(A::SparseMatrixCSC, j) = getcolptr(A)[j] +@inline colboundind(A::SparseMatrixCSC, j) = getcolptr(A)[j + 1] +@inline storedinds(A::SparseVector) = nonzeroinds(A) +@inline storedinds(A::SparseMatrixCSC) = rowvals(A) +@inline storedvals(A::SparseVecOrMat) = nonzeros(A) @inline setcolptr!(A::SparseVector, j, val) = val -@inline setcolptr!(A::SparseMatrixCSC, j, val) = A.colptr[j] = val +@inline setcolptr!(A::SparseMatrixCSC, j, val) = getcolptr(A)[j] = val function trimstorage!(A::SparseVecOrMat, maxstored) resize!(storedinds(A), maxstored) resize!(storedvals(A), maxstored) @@ -214,9 +214,9 @@ end @inline _all_args_isa(t::Tuple{Broadcasted,Vararg{Any}}, ::Type{T}) where T = _all_args_isa(t[1].args, T) & _all_args_isa(tail(t), T) @inline _densennz(shape::NTuple{1}) = shape[1] @inline _densennz(shape::NTuple{2}) = shape[1] * shape[2] -_maxnnzfrom(shape::NTuple{1}, A) = nnz(A) * div(shape[1], A.n) -_maxnnzfrom(shape::NTuple{2}, A::SparseVector) = nnz(A) * div(shape[1], A.n) * shape[2] -_maxnnzfrom(shape::NTuple{2}, A::SparseMatrixCSC) = nnz(A) * div(shape[1], A.m) * div(shape[2], A.n) +_maxnnzfrom(shape::NTuple{1}, A::SparseVector) = nnz(A) * div(shape[1], length(A)) +_maxnnzfrom(shape::NTuple{2}, A::SparseVector) = nnz(A) * div(shape[1], length(A)) * shape[2] +_maxnnzfrom(shape::NTuple{2}, A::SparseMatrixCSC) = nnz(A) * div(shape[1], size(A, 1)) * div(shape[2], size(A, 2)) @inline _maxnnzfrom_each(shape, ::Tuple{}) = () @inline _maxnnzfrom_each(shape, As) = (_maxnnzfrom(shape, first(As)), _maxnnzfrom_each(shape, tail(As))...) @inline _unchecked_maxnnzbcres(shape, As::Tuple) = min(_densennz(shape), sum(_maxnnzfrom_each(shape, As))) @@ -277,18 +277,18 @@ function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseVecOrMa end # helper functions for these methods and some of those below @inline _densecoloffsets(A::SparseVector) = 0 -@inline _densecoloffsets(A::SparseMatrixCSC) = 0:A.m:(A.m*(A.n - 1)) +@inline _densecoloffsets(A::SparseMatrixCSC) = 0:size(A, 1):(size(A, 1)*(size(A, 2) - 1)) function _densestructure!(A::SparseVector) - expandstorage!(A, A.n) - copyto!(A.nzind, 1:A.n) + expandstorage!(A, length(A)) + copyto!(nonzeroinds(A), 1:length(A)) return A end function _densestructure!(A::SparseMatrixCSC) - nnzA = A.m * A.n + nnzA = size(A, 1) * size(A, 2) expandstorage!(A, nnzA) - copyto!(A.colptr, 1:A.m:(nnzA + 1)) + copyto!(getcolptr(A), 1:size(A, 1):(nnzA + 1)) for k in _densecoloffsets(A) - copyto!(A.rowval, k + 1, 1:A.m) + copyto!(rowvals(A), k + 1, 1:size(A, 1)) end return A end @@ -405,7 +405,7 @@ function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg{Spars # Populate values fill!(storedvals(C), fillvalue) # NOTE: Combining this fill! into the loop below to avoid multiple sweeps over / - # nonsequential access of C.nzval does not appear to improve performance. + # nonsequential access of nonzeros(C) does not appear to improve performance. rowsentinel = numrows(C) + 1 stopks = _colstartind_all(1, As) @inbounds for (j, jo) in zip(columns(C), _densecoloffsets(C)) @@ -812,7 +812,7 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseV return C end _finishempty!(C::SparseVector) = C -_finishempty!(C::SparseMatrixCSC) = (fill!(C.colptr, 1); C) +_finishempty!(C::SparseMatrixCSC) = (fill!(getcolptr(C), 1); C) # special case - vector outer product _copy(f::typeof(*), x::SparseVectorUnion, y::AdjOrTransSparseVectorUnion) = _outer(x, y) diff --git a/stdlib/SparseArrays/src/linalg.jl b/stdlib/SparseArrays/src/linalg.jl index 9c2a72fe47bce..ea79fa2e3421c 100644 --- a/stdlib/SparseArrays/src/linalg.jl +++ b/stdlib/SparseArrays/src/linalg.jl @@ -32,18 +32,18 @@ end const AdjOrTransStridedMatrix{T} = Union{StridedMatrix{T},Adjoint{<:Any,<:StridedMatrix{T}},Transpose{<:Any,<:StridedMatrix{T}}} function mul!(C::StridedVecOrMat, A::SparseMatrixCSC, B::Union{StridedVector,AdjOrTransStridedMatrix}, α::Number, β::Number) - A.n == size(B, 1) || throw(DimensionMismatch()) - A.m == size(C, 1) || throw(DimensionMismatch()) + size(A, 2) == size(B, 1) || throw(DimensionMismatch()) + size(A, 1) == size(C, 1) || throw(DimensionMismatch()) size(B, 2) == size(C, 2) || throw(DimensionMismatch()) - nzv = A.nzval - rv = A.rowval + nzv = nonzeros(A) + rv = rowvals(A) if β != 1 β != 0 ? rmul!(C, β) : fill!(C, zero(eltype(C))) end for k = 1:size(C, 2) - @inbounds for col = 1:A.n + @inbounds for col = 1:size(A, 2) αxj = B[col,k] * α - for j = A.colptr[col]:(A.colptr[col + 1] - 1) + for j = getcolptr(A)[col]:(getcolptr(A)[col + 1] - 1) C[rv[j], k] += nzv[j]*αxj end end @@ -51,24 +51,24 @@ function mul!(C::StridedVecOrMat, A::SparseMatrixCSC, B::Union{StridedVector,Adj C end *(A::SparseMatrixCSC{TA,S}, x::StridedVector{Tx}) where {TA,S,Tx} = - (T = promote_op(matprod, TA, Tx); mul!(similar(x, T, A.m), A, x, one(T), zero(T))) + (T = promote_op(matprod, TA, Tx); mul!(similar(x, T, size(A, 1)), A, x, one(T), zero(T))) *(A::SparseMatrixCSC{TA,S}, B::StridedMatrix{Tx}) where {TA,S,Tx} = - (T = promote_op(matprod, TA, Tx); mul!(similar(B, T, (A.m, size(B, 2))), A, B, one(T), zero(T))) + (T = promote_op(matprod, TA, Tx); mul!(similar(B, T, (size(A, 1), size(B, 2))), A, B, one(T), zero(T))) function mul!(C::StridedVecOrMat, adjA::Adjoint{<:Any,<:SparseMatrixCSC}, B::Union{StridedVector,AdjOrTransStridedMatrix}, α::Number, β::Number) A = adjA.parent - A.n == size(C, 1) || throw(DimensionMismatch()) - A.m == size(B, 1) || throw(DimensionMismatch()) + size(A, 2) == size(C, 1) || throw(DimensionMismatch()) + size(A, 1) == size(B, 1) || throw(DimensionMismatch()) size(B, 2) == size(C, 2) || throw(DimensionMismatch()) - nzv = A.nzval - rv = A.rowval + nzv = nonzeros(A) + rv = rowvals(A) if β != 1 β != 0 ? rmul!(C, β) : fill!(C, zero(eltype(C))) end for k = 1:size(C, 2) - @inbounds for col = 1:A.n + @inbounds for col = 1:size(A, 2) tmp = zero(eltype(C)) - for j = A.colptr[col]:(A.colptr[col + 1] - 1) + for j = getcolptr(A)[col]:(getcolptr(A)[col + 1] - 1) tmp += adjoint(nzv[j])*B[rv[j],k] end C[col,k] += tmp * α @@ -83,18 +83,18 @@ end function mul!(C::StridedVecOrMat, transA::Transpose{<:Any,<:SparseMatrixCSC}, B::Union{StridedVector,AdjOrTransStridedMatrix}, α::Number, β::Number) A = transA.parent - A.n == size(C, 1) || throw(DimensionMismatch()) - A.m == size(B, 1) || throw(DimensionMismatch()) + size(A, 2) == size(C, 1) || throw(DimensionMismatch()) + size(A, 1) == size(B, 1) || throw(DimensionMismatch()) size(B, 2) == size(C, 2) || throw(DimensionMismatch()) - nzv = A.nzval - rv = A.rowval + nzv = nonzeros(A) + rv = rowvals(A) if β != 1 β != 0 ? rmul!(C, β) : fill!(C, zero(eltype(C))) end for k = 1:size(C, 2) - @inbounds for col = 1:A.n + @inbounds for col = 1:size(A, 2) tmp = zero(eltype(C)) - for j = A.colptr[col]:(A.colptr[col + 1] - 1) + for j = getcolptr(A)[col]:(getcolptr(A)[col + 1] - 1) tmp += transpose(nzv[j])*B[rv[j],k] end C[col,k] += tmp * α @@ -118,34 +118,34 @@ mul!(C::StridedVecOrMat, transA::Transpose{<:Any,<:SparseMatrixCSC}, B::Union{St function mul!(C::StridedVecOrMat, X::AdjOrTransStridedMatrix, A::SparseMatrixCSC, α::Number, β::Number) mX, nX = size(X) - nX == A.m || throw(DimensionMismatch()) + nX == size(A, 1) || throw(DimensionMismatch()) mX == size(C, 1) || throw(DimensionMismatch()) - A.n == size(C, 2) || throw(DimensionMismatch()) - rv = A.rowval - nzv = A.nzval + size(A, 2) == size(C, 2) || throw(DimensionMismatch()) + rv = rowvals(A) + nzv = nonzeros(A) if β != 1 β != 0 ? rmul!(C, β) : fill!(C, zero(eltype(C))) end - @inbounds for multivec_row=1:mX, col = 1:A.n, k=A.colptr[col]:(A.colptr[col+1]-1) + @inbounds for multivec_row=1:mX, col = 1:size(A, 2), k=getcolptr(A)[col]:(getcolptr(A)[col+1]-1) C[multivec_row, col] += α * X[multivec_row, rv[k]] * nzv[k] # perhaps suboptimal position of α? end C end *(X::AdjOrTransStridedMatrix{TX}, A::SparseMatrixCSC{TvA,TiA}) where {TX,TvA,TiA} = - (T = promote_op(matprod, TX, TvA); mul!(similar(X, T, (size(X, 1), A.n)), X, A, one(T), zero(T))) + (T = promote_op(matprod, TX, TvA); mul!(similar(X, T, (size(X, 1), size(A, 2))), X, A, one(T), zero(T))) function mul!(C::StridedVecOrMat, X::AdjOrTransStridedMatrix, adjA::Adjoint{<:Any,<:SparseMatrixCSC}, α::Number, β::Number) A = adjA.parent mX, nX = size(X) - nX == A.n || throw(DimensionMismatch()) + nX == size(A, 2) || throw(DimensionMismatch()) mX == size(C, 1) || throw(DimensionMismatch()) - A.m == size(C, 2) || throw(DimensionMismatch()) - rv = A.rowval - nzv = A.nzval + size(A, 1) == size(C, 2) || throw(DimensionMismatch()) + rv = rowvals(A) + nzv = nonzeros(A) if β != 1 β != 0 ? rmul!(C, β) : fill!(C, zero(eltype(C))) end - @inbounds for col = 1:A.n, k=A.colptr[col]:(A.colptr[col+1]-1), multivec_col=1:mX + @inbounds for col = 1:size(A, 2), k=getcolptr(A)[col]:(getcolptr(A)[col+1]-1), multivec_col=1:mX C[multivec_col, rv[k]] += α * X[multivec_col, col] * adjoint(nzv[k]) # perhaps suboptimal position of α? end C @@ -156,15 +156,15 @@ end function mul!(C::StridedVecOrMat, X::AdjOrTransStridedMatrix, transA::Transpose{<:Any,<:SparseMatrixCSC}, α::Number, β::Number) A = transA.parent mX, nX = size(X) - nX == A.n || throw(DimensionMismatch()) + nX == size(A, 2) || throw(DimensionMismatch()) mX == size(C, 1) || throw(DimensionMismatch()) - A.m == size(C, 2) || throw(DimensionMismatch()) - rv = A.rowval - nzv = A.nzval + size(A, 1) == size(C, 2) || throw(DimensionMismatch()) + rv = rowvals(A) + nzv = nonzeros(A) if β != 1 β != 0 ? rmul!(C, β) : fill!(C, zero(eltype(C))) end - @inbounds for col = 1:A.n, k=A.colptr[col]:(A.colptr[col+1]-1), multivec_col=1:mX + @inbounds for col = 1:size(A, 2), k=getcolptr(A)[col]:(getcolptr(A)[col+1]-1), multivec_col=1:mX C[multivec_col, rv[k]] += α * X[multivec_col, col] * transpose(nzv[k]) # perhaps suboptimal position of α? end C @@ -296,24 +296,24 @@ function dot(A::SparseMatrixCSC{T1,S1},B::SparseMatrixCSC{T2,S2}) where {T1,T2,S size(B) == (m,n) || throw(DimensionMismatch("matrices must have the same dimensions")) r = dot(zero(T1), zero(T2)) @inbounds for j = 1:n - ia = A.colptr[j]; ia_nxt = A.colptr[j+1] - ib = B.colptr[j]; ib_nxt = B.colptr[j+1] + ia = getcolptr(A)[j]; ia_nxt = getcolptr(A)[j+1] + ib = getcolptr(B)[j]; ib_nxt = getcolptr(B)[j+1] if ia < ia_nxt && ib < ib_nxt - ra = A.rowval[ia]; rb = B.rowval[ib] + ra = rowvals(A)[ia]; rb = rowvals(B)[ib] while true if ra < rb ia += oneunit(S1) ia < ia_nxt || break - ra = A.rowval[ia] + ra = rowvals(A)[ia] elseif ra > rb ib += oneunit(S2) ib < ib_nxt || break - rb = B.rowval[ib] + rb = rowvals(B)[ib] else # ra == rb - r += dot(A.nzval[ia], B.nzval[ib]) + r += dot(nonzeros(A)[ia], nonzeros(B)[ib]) ia += oneunit(S1); ib += oneunit(S2) ia < ia_nxt && ib < ib_nxt || break - ra = A.rowval[ia]; rb = B.rowval[ib] + ra = rowvals(A)[ia]; rb = rowvals(B)[ib] end end end @@ -785,8 +785,8 @@ end function rdiv!(A::SparseMatrixCSC{T}, D::Diagonal{T}) where T dd = D.diag - if (k = length(dd)) ≠ A.n - throw(DimensionMismatch("size(A, 2)=$(A.n) should be size(D, 1)=$k")) + if (k = length(dd)) ≠ size(A, 2) + throw(DimensionMismatch("size(A, 2)=$(size(A, 2)) should be size(D, 1)=$k")) end nonz = nonzeros(A) @inbounds for j in 1:k @@ -808,16 +808,16 @@ rdiv!(A::SparseMatrixCSC{T}, transD::Transpose{<:Any,<:Diagonal{T}}) where {T} = function ldiv!(D::Diagonal{T}, A::SparseMatrixCSC{T}) where {T} # require_one_based_indexing(A) - if A.m != length(D.diag) - throw(DimensionMismatch("diagonal matrix is $(length(D.diag)) by $(length(D.diag)) but right hand side has $(A.m) rows")) + if size(A, 1) != length(D.diag) + throw(DimensionMismatch("diagonal matrix is $(length(D.diag)) by $(length(D.diag)) but right hand side has $(size(A, 1)) rows")) end nonz = nonzeros(A) - Arowval = A.rowval + Arowval = rowvals(A) b = D.diag for i=1:length(b) iszero(b[i]) && throw(SingularException(i)) end - @inbounds for col = 1:A.n, p = A.colptr[col]:(A.colptr[col + 1] - 1) + @inbounds for col = 1:size(A, 2), p = getcolptr(A)[col]:(getcolptr(A)[col + 1] - 1) nonz[p] = b[Arowval[p]] \ nonz[p] end A @@ -837,8 +837,8 @@ function triu(S::SparseMatrixCSC{Tv,Ti}, k::Integer=0) where {Tv,Ti} colptr[col] = 1 end for col = max(k+1,1) : n - for c1 = S.colptr[col] : S.colptr[col+1]-1 - S.rowval[c1] > col - k && break + for c1 = getcolptr(S)[col] : getcolptr(S)[col+1]-1 + rowvals(S)[c1] > col - k && break nnz += 1 end colptr[col+1] = nnz+1 @@ -847,10 +847,10 @@ function triu(S::SparseMatrixCSC{Tv,Ti}, k::Integer=0) where {Tv,Ti} nzval = Vector{Tv}(undef, nnz) A = SparseMatrixCSC(m, n, colptr, rowval, nzval) for col = max(k+1,1) : n - c1 = S.colptr[col] - for c2 = A.colptr[col] : A.colptr[col+1]-1 - A.rowval[c2] = S.rowval[c1] - A.nzval[c2] = S.nzval[c1] + c1 = getcolptr(S)[col] + for c2 = getcolptr(A)[col] : getcolptr(A)[col+1]-1 + rowvals(A)[c2] = rowvals(S)[c1] + nonzeros(A)[c2] = nonzeros(S)[c1] c1 += 1 end end @@ -863,9 +863,9 @@ function tril(S::SparseMatrixCSC{Tv,Ti}, k::Integer=0) where {Tv,Ti} nnz = 0 colptr[1] = 1 for col = 1 : min(n, m+k) - l1 = S.colptr[col+1]-1 - for c1 = 0 : (l1 - S.colptr[col]) - S.rowval[l1 - c1] < col - k && break + l1 = getcolptr(S)[col+1]-1 + for c1 = 0 : (l1 - getcolptr(S)[col]) + rowvals(S)[l1 - c1] < col - k && break nnz += 1 end colptr[col+1] = nnz+1 @@ -877,11 +877,11 @@ function tril(S::SparseMatrixCSC{Tv,Ti}, k::Integer=0) where {Tv,Ti} nzval = Vector{Tv}(undef, nnz) A = SparseMatrixCSC(m, n, colptr, rowval, nzval) for col = 1 : min(n, m+k) - c1 = S.colptr[col+1]-1 - l2 = A.colptr[col+1]-1 - for c2 = 0 : l2 - A.colptr[col] - A.rowval[l2 - c2] = S.rowval[c1] - A.nzval[l2 - c2] = S.nzval[c1] + c1 = getcolptr(S)[col+1]-1 + l2 = getcolptr(A)[col+1]-1 + for c2 = 0 : l2 - getcolptr(A)[col] + rowvals(A)[l2 - c2] = rowvals(S)[c1] + nonzeros(A)[l2 - c2] = nonzeros(S)[c1] c1 -= 1 end end @@ -902,9 +902,9 @@ function sparse_diff1(S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} for col = 1 : n last_row = 0 last_val = 0 - for k = S.colptr[col] : S.colptr[col+1]-1 - row = S.rowval[k] - val = S.nzval[k] + for k = getcolptr(S)[col] : getcolptr(S)[col+1]-1 + row = rowvals(S)[k] + val = nonzeros(S)[k] if row > 1 if row == last_row + 1 nzval[numnz] += val @@ -939,9 +939,9 @@ function sparse_diff2(a::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} z = zero(Tv) - colptr_a = a.colptr - rowval_a = a.rowval - nzval_a = a.nzval + colptr_a = getcolptr(a) + rowval_a = rowvals(a) + nzval_a = nonzeros(a) ptrS = 1 colptr[1] = 1 @@ -1022,7 +1022,7 @@ end diff(a::SparseMatrixCSC; dims::Integer) = dims==1 ? sparse_diff1(a) : sparse_diff2(a) ## norm and rank -norm(A::SparseMatrixCSC, p::Real=2) = norm(view(A.nzval, 1:nnz(A)), p) +norm(A::SparseMatrixCSC, p::Real=2) = norm(view(nonzeros(A), 1:nnz(A)), p) function opnorm(A::SparseMatrixCSC, p::Real=2) m, n = size(A) @@ -1045,8 +1045,8 @@ function opnorm(A::SparseMatrixCSC, p::Real=2) nA::Tsum = 0 for j=1:n colSum::Tsum = 0 - for i = A.colptr[j]:A.colptr[j+1]-1 - colSum += abs(A.nzval[i]) + for i = getcolptr(A)[j]:getcolptr(A)[j+1]-1 + colSum += abs(nonzeros(A)[i]) end nA = max(nA, colSum) end @@ -1055,8 +1055,8 @@ function opnorm(A::SparseMatrixCSC, p::Real=2) throw(ArgumentError("2-norm not yet implemented for sparse matrices. Try opnorm(Array(A)) or opnorm(A, p) where p=1 or Inf.")) elseif p==Inf rowSum = zeros(Tsum,m) - for i=1:length(A.nzval) - rowSum[A.rowval[i]] += abs(A.nzval[i]) + for i=1:length(nonzeros(A)) + rowSum[rowvals(A)[i]] += abs(nonzeros(A)[i]) end return convert(Tnorm, maximum(rowSum)) end @@ -1261,12 +1261,12 @@ function kron(A::SparseMatrixCSC{T1,S1}, B::SparseMatrixCSC{T2,S2}) where {T1,S1 colptrC[1] = 1 col = 1 @inbounds for j = 1:nA - startA = A.colptr[j] - stopA = A.colptr[j+1] - 1 + startA = getcolptr(A)[j] + stopA = getcolptr(A)[j+1] - 1 lA = stopA - startA + 1 for i = 1:nB - startB = B.colptr[i] - stopB = B.colptr[i+1] - 1 + startB = getcolptr(B)[i] + stopB = getcolptr(B)[i+1] - 1 lB = stopB - startB + 1 ptr_range = (1:lB) .+ (colptrC[col]-1) colptrC[col+1] = colptrC[col] + lA*lB @@ -1274,8 +1274,8 @@ function kron(A::SparseMatrixCSC{T1,S1}, B::SparseMatrixCSC{T2,S2}) where {T1,S1 for ptrA = startA : stopA ptrB = startB for ptr = ptr_range - rowvalC[ptr] = (A.rowval[ptrA]-1)*mB + B.rowval[ptrB] - nzvalC[ptr] = A.nzval[ptrA] * B.nzval[ptrB] + rowvalC[ptr] = (rowvals(A)[ptrA]-1)*mB + rowvals(B)[ptrB] + nzvalC[ptr] = nonzeros(A)[ptrA] * nonzeros(B)[ptrB] ptrB += 1 end ptr_range = ptr_range .+ lB @@ -1293,10 +1293,10 @@ function kron(x::SparseVector{T1,S1}, y::SparseVector{T2,S2}) where {T1,S1,T2,S2 nzval = Vector{typeof(one(T1)*one(T2))}(undef, nnzz) # the values of nonzeros @inbounds for i = 1:nnzx, j = 1:nnzy this_ind = (i-1)*nnzy+j - nzind[this_ind] = (x.nzind[i]-1)*y.n + y.nzind[j] - nzval[this_ind] = x.nzval[i] * y.nzval[j] + nzind[this_ind] = (nonzeroinds(x)[i]-1)*length(y::SparseVector) + nonzeroinds(y)[j] + nzval[this_ind] = nonzeros(x)[i] * nonzeros(y)[j] end - return SparseVector(x.n*y.n, nzind, nzval) + return SparseVector(length(x::SparseVector)*length(y::SparseVector), nzind, nzval) end # sparse matrix ⊗ sparse vector & vice versa @@ -1324,13 +1324,13 @@ inv(A::SparseMatrixCSC) = error("The inverse of a sparse matrix can often be den # Copy colptr and rowval from one sparse matrix to another function copyinds!(C::SparseMatrixCSC, A::SparseMatrixCSC) - if C.colptr !== A.colptr - resize!(C.colptr, length(A.colptr)) - copyto!(C.colptr, A.colptr) + if getcolptr(C) !== getcolptr(A) + resize!(getcolptr(C), length(getcolptr(A))) + copyto!(getcolptr(C), getcolptr(A)) end - if C.rowval !== A.rowval - resize!(C.rowval, length(A.rowval)) - copyto!(C.rowval, A.rowval) + if rowvals(C) !== rowvals(A) + resize!(rowvals(C), length(rowvals(A))) + copyto!(rowvals(C), rowvals(A)) end end @@ -1340,10 +1340,10 @@ function mul!(C::SparseMatrixCSC, A::SparseMatrixCSC, D::Diagonal{T, <:Vector}) b = D.diag (n==length(b) && size(A)==size(C)) || throw(DimensionMismatch()) copyinds!(C, A) - Cnzval = C.nzval - Anzval = A.nzval + Cnzval = nonzeros(C) + Anzval = nonzeros(A) resize!(Cnzval, length(Anzval)) - for col = 1:n, p = A.colptr[col]:(A.colptr[col+1]-1) + for col = 1:n, p = getcolptr(A)[col]:(getcolptr(A)[col+1]-1) @inbounds Cnzval[p] = Anzval[p] * b[col] end C @@ -1354,11 +1354,11 @@ function mul!(C::SparseMatrixCSC, D::Diagonal{T, <:Vector}, A::SparseMatrixCSC) b = D.diag (m==length(b) && size(A)==size(C)) || throw(DimensionMismatch()) copyinds!(C, A) - Cnzval = C.nzval - Anzval = A.nzval - Arowval = A.rowval + Cnzval = nonzeros(C) + Anzval = nonzeros(A) + Arowval = rowvals(A) resize!(Cnzval, length(Anzval)) - for col = 1:n, p = A.colptr[col]:(A.colptr[col+1]-1) + for col = 1:n, p = getcolptr(A)[col]:(getcolptr(A)[col+1]-1) @inbounds Cnzval[p] = b[Arowval[p]] * Anzval[p] end C @@ -1367,34 +1367,34 @@ end function mul!(C::SparseMatrixCSC, A::SparseMatrixCSC, b::Number) size(A)==size(C) || throw(DimensionMismatch()) copyinds!(C, A) - resize!(C.nzval, length(A.nzval)) - mul!(C.nzval, A.nzval, b) + resize!(nonzeros(C), length(nonzeros(A))) + mul!(nonzeros(C), nonzeros(A), b) C end function mul!(C::SparseMatrixCSC, b::Number, A::SparseMatrixCSC) size(A)==size(C) || throw(DimensionMismatch()) copyinds!(C, A) - resize!(C.nzval, length(A.nzval)) - mul!(C.nzval, b, A.nzval) + resize!(nonzeros(C), length(nonzeros(A))) + mul!(nonzeros(C), b, nonzeros(A)) C end function rmul!(A::SparseMatrixCSC, b::Number) - rmul!(A.nzval, b) + rmul!(nonzeros(A), b) return A end function lmul!(b::Number, A::SparseMatrixCSC) - lmul!(b, A.nzval) + lmul!(b, nonzeros(A)) return A end function rmul!(A::SparseMatrixCSC, D::Diagonal) m, n = size(A) (n == size(D, 1)) || throw(DimensionMismatch()) - Anzval = A.nzval - @inbounds for col = 1:n, p = A.colptr[col]:(A.colptr[col + 1] - 1) + Anzval = nonzeros(A) + @inbounds for col = 1:n, p = getcolptr(A)[col]:(getcolptr(A)[col + 1] - 1) Anzval[p] = Anzval[p] * D.diag[col] end return A @@ -1403,9 +1403,9 @@ end function lmul!(D::Diagonal, A::SparseMatrixCSC) m, n = size(A) (m == size(D, 2)) || throw(DimensionMismatch()) - Anzval = A.nzval - Arowval = A.rowval - @inbounds for col = 1:n, p = A.colptr[col]:(A.colptr[col + 1] - 1) + Anzval = nonzeros(A) + Arowval = rowvals(A) + @inbounds for col = 1:n, p = getcolptr(A)[col]:(getcolptr(A)[col + 1] - 1) Anzval[p] = D.diag[Arowval[p]] * Anzval[p] end return A diff --git a/stdlib/SparseArrays/src/sparseconvert.jl b/stdlib/SparseArrays/src/sparseconvert.jl index 9f4bb6cd452f1..89f08a213a76b 100644 --- a/stdlib/SparseArrays/src/sparseconvert.jl +++ b/stdlib/SparseArrays/src/sparseconvert.jl @@ -100,13 +100,13 @@ _sparsem(A::AbstractSparseVector) = A function _sparsem(A::Union{Transpose{<:Any,<:AbstractSparseVector},Adjoint{<:Any,<:AbstractSparseVector}}) B = parent(A) n = length(B) - Ti = eltype(B.nzind) + Ti = eltype(nonzeroinds(B)) fadj = A isa Transpose ? transpose : adjoint colptr = fill!(Vector{Ti}(undef, n + 1), 0) colptr[1] = 1 - colptr[B.nzind .+ 1] .= 1 + colptr[nonzeroinds(B) .+ 1] .= 1 cumsum!(colptr, colptr) - rowval = fill!(similar(B.nzind), 1) + rowval = fill!(similar(nonzeroinds(B)), 1) nzval = fadj.(nonzeros(B)) SparseMatrixCSC(1, n, colptr, rowval, nzval) end diff --git a/stdlib/SparseArrays/src/sparsematrix.jl b/stdlib/SparseArrays/src/sparsematrix.jl index a40d0e68f0cce..5c225285045b3 100644 --- a/stdlib/SparseArrays/src/sparsematrix.jl +++ b/stdlib/SparseArrays/src/sparsematrix.jl @@ -71,7 +71,7 @@ function sparse_check_length(rowstr, rowval, minlen, Ti) throw(ArgumentError("$len == length($rowstr) >= $(typemax(Ti))")) end -size(S::SparseMatrixCSC) = (S.m, S.n) +size(S::SparseMatrixCSC) = (getfield(S, :m), getfield(S, :n)) # Define an alias for views of a SparseMatrixCSC which include all rows and a unit range of the columns. # Also define a union of SparseMatrixCSC and this view since many methods can be defined efficiently for @@ -83,13 +83,13 @@ const SparseMatrixCSCView{Tv,Ti} = Tuple{Base.Slice{Base.OneTo{Int}},I}} where {I<:AbstractUnitRange} const SparseMatrixCSCUnion{Tv,Ti} = Union{SparseMatrixCSC{Tv,Ti}, SparseMatrixCSCView{Tv,Ti}} -getcolptr(S::SparseMatrixCSC) = S.colptr -getcolptr(S::SparseMatrixCSCView) = view(S.parent.colptr, first(axes(S, 2)):(last(axes(S, 2)) + 1)) -getrowval(S::SparseMatrixCSC) = S.rowval -getrowval(S::SparseMatrixCSCView) = S.parent.rowval -getnzval( S::SparseMatrixCSC) = S.nzval -getnzval( S::SparseMatrixCSCView) = S.parent.nzval -nzvalview(S::SparseMatrixCSC) = view(S.nzval, 1:nnz(S)) +getcolptr(S::SparseMatrixCSC) = getfield(S, :colptr) +getcolptr(S::SparseMatrixCSCView) = view(getcolptr(parent(S)), first(axes(S, 2)):(last(axes(S, 2)) + 1)) +getrowval(S::SparseMatrixCSC) = rowvals(S) +getrowval(S::SparseMatrixCSCView) = rowvals(parent(S)) +getnzval( S::SparseMatrixCSC) = nonzeros(S) +getnzval( S::SparseMatrixCSCView) = nonzeros(parent(S)) +nzvalview(S::SparseMatrixCSC) = view(nonzeros(S), 1:nnz(S)) """ nnz(A) @@ -108,7 +108,7 @@ julia> nnz(A) 3 ``` """ -nnz(S::SparseMatrixCSC) = Int(S.colptr[S.n + 1] - 1) +nnz(S::SparseMatrixCSC) = Int(getcolptr(S)[size(S, 2) + 1] - 1) nnz(S::ReshapedArray{T,1,<:SparseMatrixCSC}) where T = nnz(parent(S)) count(pred, S::SparseMatrixCSC) = count(pred, nzvalview(S)) + pred(zero(eltype(S)))*(prod(size(S)) - nnz(S)) @@ -136,7 +136,7 @@ julia> nonzeros(A) 2 ``` """ -nonzeros(S::SparseMatrixCSC) = S.nzval +nonzeros(S::SparseMatrixCSC) = getfield(S, :nzval) nonzeros(S::SparseMatrixCSCView) = nonzeros(S.parent) """ @@ -162,7 +162,7 @@ julia> rowvals(A) 3 ``` """ -rowvals(S::SparseMatrixCSC) = S.rowval +rowvals(S::SparseMatrixCSC) = getfield(S, :rowval) rowvals(S::SparseMatrixCSCView) = rowvals(S.parent) """ @@ -184,12 +184,13 @@ column. In conjunction with [`nonzeros`](@ref) and end end """ -nzrange(S::SparseMatrixCSC, col::Integer) = S.colptr[col]:(S.colptr[col+1]-1) +nzrange(S::SparseMatrixCSC, col::Integer) = getcolptr(S)[col]:(getcolptr(S)[col+1]-1) nzrange(S::SparseMatrixCSCView, col::Integer) = nzrange(S.parent, S.indices[2][col]) function Base.show(io::IO, ::MIME"text/plain", S::SparseMatrixCSC) xnnz = nnz(S) - print(io, S.m, "×", S.n, " ", typeof(S), " with ", xnnz, " stored ", + m, n = size(S) + print(io, m, "×", n, " ", typeof(S), " with ", xnnz, " stored ", xnnz == 1 ? "entry" : "entries") if xnnz != 0 print(io, ":") @@ -203,19 +204,19 @@ function Base.show(io::IOContext, S::SparseMatrixCSC) ioc = IOContext(io, :compact => true) function _format_line(r, col, padr, padc) - print(ioc, "\n [", rpad(S.rowval[r], padr), ", ", lpad(col, padc), "] = ") - if isassigned(S.nzval, Int(r)) - show(ioc, S.nzval[r]) + print(ioc, "\n [", rpad(rowvals(S)[r], padr), ", ", lpad(col, padc), "] = ") + if isassigned(nonzeros(S), Int(r)) + show(ioc, nonzeros(S)[r]) else print(ioc, Base.undef_ref_str) end end function _get_cols(from, to) - idx = eltype(S.colptr)[] - c = searchsortedlast(S.colptr, from) + idx = eltype(getcolptr(S))[] + c = searchsortedlast(getcolptr(S), from) for i = from:to - while i == S.colptr[c+1] + while i == getcolptr(S)[c+1] c +=1 end push!(idx, c) @@ -226,7 +227,7 @@ function Base.show(io::IOContext, S::SparseMatrixCSC) rows = displaysize(io)[1] - 4 # -4 from [Prompt, header, newline after elements, new prompt] if !get(io, :limit, false) || rows >= nnz(S) # Will the whole matrix fit when printed? cols = _get_cols(1, nnz(S)) - padr, padc = ndigits.((maximum(S.rowval[1:nnz(S)]), cols[end])) + padr, padc = ndigits.((maximum(rowvals(S)[1:nnz(S)]), cols[end])) _format_line.(1:nnz(S), cols, padr, padc) else if rows <= 2 @@ -236,7 +237,7 @@ function Base.show(io::IOContext, S::SparseMatrixCSC) s1, e1 = 1, div(rows - 1, 2) # -1 accounts for \vdots s2, e2 = nnz(S) - (rows - 1 - e1) + 1, nnz(S) cols1, cols2 = _get_cols(s1, e1), _get_cols(s2, e2) - padr = ndigits(max(maximum(S.rowval[s1:e1]), maximum(S.rowval[s2:e2]))) + padr = ndigits(max(maximum(rowvals(S)[s1:e1]), maximum(rowvals(S)[s2:e2]))) padc = ndigits(cols2[end]) _format_line.(s1:e1, cols1, padr, padc) print(io, "\n \u22ee") @@ -286,38 +287,38 @@ function copy(ra::ReshapedArray{<:Any,2,<:SparseMatrixCSC}) a = parent(ra) mA,nA = size(a) numnz = nnz(a) - colptr = similar(a.colptr, nS+1) - rowval = similar(a.rowval) - nzval = copy(a.nzval) + colptr = similar(getcolptr(a), nS+1) + rowval = similar(rowvals(a)) + nzval = copy(nonzeros(a)) - sparse_compute_reshaped_colptr_and_rowval(colptr, rowval, mS, nS, a.colptr, a.rowval, mA, nA) + sparse_compute_reshaped_colptr_and_rowval(colptr, rowval, mS, nS, getcolptr(a), rowvals(a), mA, nA) return SparseMatrixCSC(mS, nS, colptr, rowval, nzval) end ## Alias detection and prevention using Base: dataids, unaliascopy -Base.dataids(S::SparseMatrixCSC) = (dataids(S.colptr)..., dataids(S.rowval)..., dataids(S.nzval)...) -Base.unaliascopy(S::SparseMatrixCSC) = typeof(S)(S.m, S.n, unaliascopy(S.colptr), unaliascopy(S.rowval), unaliascopy(S.nzval)) +Base.dataids(S::SparseMatrixCSC) = (dataids(getcolptr(S))..., dataids(rowvals(S))..., dataids(nonzeros(S))...) +Base.unaliascopy(S::SparseMatrixCSC) = typeof(S)(size(S, 1), size(S, 2), unaliascopy(getcolptr(S)), unaliascopy(rowvals(S)), unaliascopy(nonzeros(S))) ## Constructors copy(S::SparseMatrixCSC) = - SparseMatrixCSC(S.m, S.n, copy(S.colptr), copy(S.rowval), copy(S.nzval)) + SparseMatrixCSC(size(S, 1), size(S, 2), copy(getcolptr(S)), copy(rowvals(S)), copy(nonzeros(S))) function copyto!(A::SparseMatrixCSC, B::SparseMatrixCSC) # If the two matrices have the same length then all the # elements in A will be overwritten. if length(A) == length(B) - resize!(A.nzval, length(B.nzval)) - resize!(A.rowval, length(B.rowval)) + resize!(nonzeros(A), length(nonzeros(B))) + resize!(rowvals(A), length(rowvals(B))) if size(A) == size(B) # Simple case: we can simply copy the internal fields of B to A. - copyto!(A.colptr, B.colptr) - copyto!(A.rowval, B.rowval) + copyto!(getcolptr(A), getcolptr(B)) + copyto!(rowvals(A), rowvals(B)) else # This is like a "reshape B into A". - sparse_compute_reshaped_colptr_and_rowval(A.colptr, A.rowval, A.m, A.n, B.colptr, B.rowval, B.m, B.n) + sparse_compute_reshaped_colptr_and_rowval(getcolptr(A), rowvals(A), size(A, 1), size(A, 2), getcolptr(B), rowvals(B), size(B, 1), size(B, 2)) end else length(A) >= length(B) || throw(BoundsError()) @@ -325,31 +326,31 @@ function copyto!(A::SparseMatrixCSC, B::SparseMatrixCSC) nnzA = nnz(A) nnzB = nnz(B) # Up to which col, row, and ptr in rowval/nzval will A be overwritten? - lastmodcolA = div(lB - 1, A.m) + 1 - lastmodrowA = mod(lB - 1, A.m) + 1 - lastmodptrA = A.colptr[lastmodcolA] - while lastmodptrA < A.colptr[lastmodcolA+1] && A.rowval[lastmodptrA] <= lastmodrowA + lastmodcolA = div(lB - 1, size(A, 1)) + 1 + lastmodrowA = mod(lB - 1, size(A, 1)) + 1 + lastmodptrA = getcolptr(A)[lastmodcolA] + while lastmodptrA < getcolptr(A)[lastmodcolA+1] && rowvals(A)[lastmodptrA] <= lastmodrowA lastmodptrA += 1 end lastmodptrA -= 1 if lastmodptrA >= nnzB # A will have fewer non-zero elements; unmodified elements are kept at the end. - deleteat!(A.rowval, nnzB+1:lastmodptrA) - deleteat!(A.nzval, nnzB+1:lastmodptrA) + deleteat!(rowvals(A), nnzB+1:lastmodptrA) + deleteat!(nonzeros(A), nnzB+1:lastmodptrA) else # A will have more non-zero elements; unmodified elements are kept at the end. - resize!(A.rowval, nnzB + nnzA - lastmodptrA) - resize!(A.nzval, nnzB + nnzA - lastmodptrA) - copyto!(A.rowval, nnzB+1, A.rowval, lastmodptrA+1, nnzA-lastmodptrA) - copyto!(A.nzval, nnzB+1, A.nzval, lastmodptrA+1, nnzA-lastmodptrA) + resize!(rowvals(A), nnzB + nnzA - lastmodptrA) + resize!(nonzeros(A), nnzB + nnzA - lastmodptrA) + copyto!(rowvals(A), nnzB+1, rowvals(A), lastmodptrA+1, nnzA-lastmodptrA) + copyto!(nonzeros(A), nnzB+1, nonzeros(A), lastmodptrA+1, nnzA-lastmodptrA) end # Adjust colptr accordingly. - @inbounds for i in 2:length(A.colptr) - A.colptr[i] += nnzB - lastmodptrA + @inbounds for i in 2:length(getcolptr(A)) + getcolptr(A)[i] += nnzB - lastmodptrA end - sparse_compute_reshaped_colptr_and_rowval(A.colptr, A.rowval, A.m, lastmodcolA-1, B.colptr, B.rowval, B.m, B.n) + sparse_compute_reshaped_colptr_and_rowval(getcolptr(A), rowvals(A), size(A, 1), lastmodcolA-1, getcolptr(B), rowvals(B), size(B, 1), size(B, 2)) end - copyto!(A.nzval, B.nzval) + copyto!(nonzeros(A), nonzeros(B)) return A end @@ -357,16 +358,16 @@ end # # parent method for similar that preserves stored-entry structure (for when new and old dims match) function _sparsesimilar(S::SparseMatrixCSC, ::Type{TvNew}, ::Type{TiNew}) where {TvNew,TiNew} - newcolptr = copyto!(similar(S.colptr, TiNew), S.colptr) - newrowval = copyto!(similar(S.rowval, TiNew), S.rowval) - return SparseMatrixCSC(S.m, S.n, newcolptr, newrowval, similar(S.nzval, TvNew)) + newcolptr = copyto!(similar(getcolptr(S), TiNew), getcolptr(S)) + newrowval = copyto!(similar(rowvals(S), TiNew), rowvals(S)) + return SparseMatrixCSC(size(S, 1), size(S, 2), newcolptr, newrowval, similar(nonzeros(S), TvNew)) end # parent methods for similar that preserves only storage space (for when new and old dims differ) _sparsesimilar(S::SparseMatrixCSC, ::Type{TvNew}, ::Type{TiNew}, dims::Dims{2}) where {TvNew,TiNew} = - SparseMatrixCSC(dims..., fill(one(TiNew), last(dims)+1), similar(S.rowval, TiNew), similar(S.nzval, TvNew)) + SparseMatrixCSC(dims..., fill(one(TiNew), last(dims)+1), similar(rowvals(S), TiNew), similar(nonzeros(S), TvNew)) # parent method for similar that allocates an empty sparse vector (when new dims are single) _sparsesimilar(S::SparseMatrixCSC, ::Type{TvNew}, ::Type{TiNew}, dims::Dims{1}) where {TvNew,TiNew} = - SparseVector(dims..., similar(S.rowval, TiNew, 0), similar(S.nzval, TvNew, 0)) + SparseVector(dims..., similar(rowvals(S), TiNew, 0), similar(nonzeros(S), TvNew, 0)) # # The following methods hook into the AbstractArray similar hierarchy. The first method # covers similar(A[, Tv]) calls, which preserve stored-entry structure, and the latter @@ -393,13 +394,13 @@ similar(S::SparseMatrixCSC, ::Type{TvNew}, ::Type{TiNew}, m::Integer, n::Integer SparseMatrixCSC(S::SparseMatrixCSC) = copy(S) AbstractMatrix{Tv}(A::SparseMatrixCSC) where {Tv} = SparseMatrixCSC{Tv}(A) SparseMatrixCSC{Tv}(S::SparseMatrixCSC{Tv}) where {Tv} = copy(S) -SparseMatrixCSC{Tv}(S::SparseMatrixCSC) where {Tv} = SparseMatrixCSC{Tv,eltype(S.colptr)}(S) +SparseMatrixCSC{Tv}(S::SparseMatrixCSC) where {Tv} = SparseMatrixCSC{Tv,eltype(getcolptr(S))}(S) SparseMatrixCSC{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = copy(S) function SparseMatrixCSC{Tv,Ti}(S::SparseMatrixCSC) where {Tv,Ti} - eltypeTicolptr = convert(Vector{Ti}, S.colptr) - eltypeTirowval = convert(Vector{Ti}, S.rowval) - eltypeTvnzval = convert(Vector{Tv}, S.nzval) - return SparseMatrixCSC(S.m, S.n, eltypeTicolptr, eltypeTirowval, eltypeTvnzval) + eltypeTicolptr = convert(Vector{Ti}, getcolptr(S)) + eltypeTirowval = convert(Vector{Ti}, rowvals(S)) + eltypeTvnzval = convert(Vector{Tv}, nonzeros(S)) + return SparseMatrixCSC(size(S, 1), size(S, 2), eltypeTicolptr, eltypeTirowval, eltypeTvnzval) end # converting from other matrix types to SparseMatrixCSC (also see sparse()) SparseMatrixCSC(M::Matrix) = sparse(M) @@ -545,11 +546,11 @@ SparseMatrixCSC{Tv,Ti}(M::Transpose{<:Any,SparseMatrixCSC}) where {Tv,Ti} = Spar # converting from SparseMatrixCSC to other matrix types function Matrix(S::SparseMatrixCSC{Tv}) where Tv # Handle cases where zero(Tv) is not defined but the array is dense. - A = length(S) == nnz(S) ? Matrix{Tv}(undef, S.m, S.n) : zeros(Tv, S.m, S.n) - for Sj in 1:S.n + A = length(S) == nnz(S) ? Matrix{Tv}(undef, size(S, 1), size(S, 2)) : zeros(Tv, size(S, 1), size(S, 2)) + for Sj in 1:size(S, 2) for Sk in nzrange(S, Sj) - Si = S.rowval[Sk] - Sv = S.nzval[Sk] + Si = rowvals(S)[Sk] + Sv = nonzeros(S)[Sk] A[Si, Sj] = Sv end end @@ -559,8 +560,8 @@ Array(S::SparseMatrixCSC) = Matrix(S) convert(T::Type{<:SparseMatrixCSC}, m::AbstractMatrix) = m isa T ? m : T(m) -float(S::SparseMatrixCSC) = SparseMatrixCSC(S.m, S.n, copy(S.colptr), copy(S.rowval), float.(S.nzval)) -complex(S::SparseMatrixCSC) = SparseMatrixCSC(S.m, S.n, copy(S.colptr), copy(S.rowval), complex(copy(S.nzval))) +float(S::SparseMatrixCSC) = SparseMatrixCSC(size(S, 1), size(S, 2), copy(getcolptr(S)), copy(rowvals(S)), float.(nonzeros(S))) +complex(S::SparseMatrixCSC) = SparseMatrixCSC(size(S, 1), size(S, 2), copy(getcolptr(S)), copy(rowvals(S)), complex(copy(nonzeros(S)))) """ sparse(A) @@ -862,10 +863,10 @@ sparse(I,J,v::Number,m,n,combine::Function) = sparse(I, J, fill(v,length(I)), In Column-permute and transpose `A`, simultaneously applying `f` to each entry of `A`, storing the result `(f(A)Q)^T` (`map(f, transpose(A[:,q]))`) in `X`. -`X`'s dimensions must match those of `transpose(A)` (`X.m == A.n` and `X.n == A.m`), and `X` -must have enough storage to accommodate all allocated entries in `A` (`length(X.rowval) >= nnz(A)` -and `length(X.nzval) >= nnz(A)`). Column-permutation `q`'s length must match `A`'s column -count (`length(q) == A.n`). +`X`'s dimensions must match those of `transpose(A)` (`size(X, 1) == size(A, 2)` and `size(X, 2) == size(A, 1)`), and `X` +must have enough storage to accommodate all allocated entries in `A` (`length(rowvals(X)) >= nnz(A)` +and `length(nonzeros(X)) >= nnz(A)`). Column-permutation `q`'s length must match `A`'s column +count (`length(q) == size(A, 2)`). This method is the parent of several methods performing transposition and permutation operations on [`SparseMatrixCSC`](@ref)s. As this method performs no argument checking, @@ -873,7 +874,7 @@ prefer the safer child methods (`[c]transpose[!]`, `permute[!]`) to direct use. This method implements the `HALFPERM` algorithm described in F. Gustavson, "Two fast algorithms for sparse matrices: multiplication and permuted transposition," ACM TOMS 4(3), -250-269 (1978). The algorithm runs in `O(A.m, A.n, nnz(A))` time and requires no space +250-269 (1978). The algorithm runs in `O(size(A, 1), size(A, 2), nnz(A))` time and requires no space beyond that passed in. """ function halfperm!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, @@ -884,39 +885,39 @@ function halfperm!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, end """ Helper method for `halfperm!`. Computes `transpose(A[:,q])`'s column pointers, storing them -shifted one position forward in `X.colptr`; `_distributevals_halfperm!` fixes this shift. +shifted one position forward in `getcolptr(X)`; `_distributevals_halfperm!` fixes this shift. """ function _computecolptrs_halfperm!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} - # Compute `transpose(A[:,q])`'s column counts. Store shifted forward one position in X.colptr. - fill!(X.colptr, 0) + # Compute `transpose(A[:,q])`'s column counts. Store shifted forward one position in getcolptr(X). + fill!(getcolptr(X), 0) @inbounds for k in 1:nnz(A) - X.colptr[A.rowval[k] + 1] += 1 + getcolptr(X)[rowvals(A)[k] + 1] += 1 end - # Compute `transpose(A[:,q])`'s column pointers. Store shifted forward one position in X.colptr. - X.colptr[1] = 1 + # Compute `transpose(A[:,q])`'s column pointers. Store shifted forward one position in getcolptr(X). + getcolptr(X)[1] = 1 countsum = 1 - @inbounds for k in 2:(A.m + 1) - overwritten = X.colptr[k] - X.colptr[k] = countsum + @inbounds for k in 2:(size(A, 1) + 1) + overwritten = getcolptr(X)[k] + getcolptr(X)[k] = countsum countsum += overwritten end end """ Helper method for `halfperm!`. With `transpose(A[:,q])`'s column pointers shifted one -position forward in `X.colptr`, computes `map(f, transpose(A[:,q]))` by appropriately -distributing `A.rowval` and `f`-transformed `A.nzval` into `X.rowval` and `X.nzval` -respectively. Simultaneously fixes the one-position-forward shift in `X.colptr`. +position forward in `getcolptr(X)`, computes `map(f, transpose(A[:,q]))` by appropriately +distributing `rowvals(A)` and `f`-transformed `nonzeros(A)` into `rowvals(X)` and `nonzeros(X)` +respectively. Simultaneously fixes the one-position-forward shift in `getcolptr(X)`. """ @noinline function _distributevals_halfperm!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, q::AbstractVector{<:Integer}, f::Function) where {Tv,Ti} - @inbounds for Xi in 1:A.n + @inbounds for Xi in 1:size(A, 2) Aj = q[Xi] for Ak in nzrange(A, Aj) - Ai = A.rowval[Ak] - Xk = X.colptr[Ai + 1] - X.rowval[Xk] = Xi - X.nzval[Xk] = f(A.nzval[Ak]) - X.colptr[Ai + 1] += 1 + Ai = rowvals(A)[Ak] + Xk = getcolptr(X)[Ai + 1] + rowvals(X)[Xk] = Xi + nonzeros(X)[Xk] = f(nonzeros(A)[Ak]) + getcolptr(X)[Ai + 1] += 1 end end return # kill potential type instability @@ -924,32 +925,32 @@ end function ftranspose!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, f::Function) where {Tv,Ti} # Check compatibility of source argument A and destination argument X - if X.n != A.m + if size(X, 2) != size(A, 1) throw(DimensionMismatch(string("destination argument `X`'s column count, ", - "`X.n (= $(X.n))`, must match source argument `A`'s row count, `A.m (= $(A.m))`"))) - elseif X.m != A.n + "`size(X, 2) (= $(size(X, 2)))`, must match source argument `A`'s row count, `size(A, 1) (= $(size(A, 1)))`"))) + elseif size(X, 1) != size(A, 2) throw(DimensionMismatch(string("destination argument `X`'s row count, - `X.m (= $(X.m))`, must match source argument `A`'s column count, `A.n (= $(A.n))`"))) - elseif length(X.rowval) < nnz(A) + `size(X, 1) (= $(size(X, 1)))`, must match source argument `A`'s column count, `size(A, 2) (= $(size(A, 2)))`"))) + elseif length(rowvals(X)) < nnz(A) throw(ArgumentError(string("the length of destination argument `X`'s `rowval` ", - "array, `length(X.rowval) (= $(length(X.rowval)))`, must be greater than or ", + "array, `length(rowvals(X)) (= $(length(rowvals(X))))`, must be greater than or ", "equal to source argument `A`'s allocated entry count, `nnz(A) (= $(nnz(A)))`"))) - elseif length(X.nzval) < nnz(A) + elseif length(nonzeros(X)) < nnz(A) throw(ArgumentError(string("the length of destination argument `X`'s `nzval` ", - "array, `length(X.nzval) (= $(length(X.nzval)))`, must be greater than or ", + "array, `length(nonzeros(X)) (= $(length(nonzeros(X))))`, must be greater than or ", "equal to source argument `A`'s allocated entry count, `nnz(A) (= $(nnz(A)))`"))) end - halfperm!(X, A, 1:A.n, f) + halfperm!(X, A, 1:size(A, 2), f) end transpose!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = ftranspose!(X, A, identity) adjoint!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = ftranspose!(X, A, conj) function ftranspose(A::SparseMatrixCSC{Tv,Ti}, f::Function) where {Tv,Ti} - X = SparseMatrixCSC(A.n, A.m, - ones(Ti, A.m+1), + X = SparseMatrixCSC(size(A, 2), size(A, 1), + ones(Ti, size(A, 1)+1), Vector{Ti}(undef, nnz(A)), Vector{Tv}(undef, nnz(A))) - halfperm!(X, A, 1:A.n, f) + halfperm!(X, A, 1:size(A, 2), f) end adjoint(A::SparseMatrixCSC) = Adjoint(A) transpose(A::SparseMatrixCSC) = Transpose(A) @@ -987,7 +988,7 @@ function unchecked_noalias_permute!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}, C::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} halfperm!(C, A, q) - _computecolptrs_permute!(X, A, q, X.colptr) + _computecolptrs_permute!(X, A, q, getcolptr(X)) _distributevals_halfperm!(X, C, p, identity) return X end @@ -1000,7 +1001,7 @@ See [`permute!`](@ref) for basic usage. Parent of `permute!` methods operating on [`SparseMatrixCSC`](@ref)s where the source and destination matrices are the same. See `unchecked_noalias_permute!` for additional information; these methods are identical but for this method's requirement of -the additional `workcolptr`, `length(workcolptr) >= A.n + 1`, which enables efficient +the additional `workcolptr`, `length(workcolptr) >= size(A, 2) + 1`, which enables efficient handling of the source-destination aliasing. """ function unchecked_aliasing_permute!(A::SparseMatrixCSC{Tv,Ti}, @@ -1013,22 +1014,22 @@ function unchecked_aliasing_permute!(A::SparseMatrixCSC{Tv,Ti}, end """ Helper method for `unchecked_noalias_permute!` and `unchecked_aliasing_permute!`. -Computes `PAQ`'s column pointers, storing them shifted one position forward in `X.colptr`; +Computes `PAQ`'s column pointers, storing them shifted one position forward in `getcolptr(X)`; `_distributevals_halfperm!` fixes this shift. Saves some work relative to `_computecolptrs_halfperm!` as described in `uncheckednoalias_permute!`'s documentation. """ function _computecolptrs_permute!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, q::AbstractVector{<:Integer}, workcolptr::Vector{Ti}) where {Tv,Ti} # Compute `A[p,q]`'s column counts. Store shifted forward one position in workcolptr. - @inbounds for k in 1:A.n - workcolptr[k+1] = A.colptr[q[k] + 1] - A.colptr[q[k]] + @inbounds for k in 1:size(A, 2) + workcolptr[k+1] = getcolptr(A)[q[k] + 1] - getcolptr(A)[q[k]] end - # Compute `A[p,q]`'s column pointers. Store shifted forward one position in X.colptr. - X.colptr[1] = 1 + # Compute `A[p,q]`'s column pointers. Store shifted forward one position in getcolptr(X). + getcolptr(X)[1] = 1 countsum = 1 - @inbounds for k in 2:(X.n + 1) + @inbounds for k in 2:(size(X, 2) + 1) overwritten = workcolptr[k] - X.colptr[k] = countsum + getcolptr(X)[k] = countsum countsum += overwritten end end @@ -1041,14 +1042,14 @@ column-permutation argument `q`. function _checkargs_sourcecompatperms_permute!(A::SparseMatrixCSC, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) require_one_based_indexing(p, q) - if length(q) != A.n + if length(q) != size(A, 2) throw(DimensionMismatch(string("the length of column-permutation argument `q`, ", "`length(q) (= $(length(q)))`, must match source argument `A`'s column ", - "count, `A.n (= $(A.n))`"))) - elseif length(p) != A.m + "count, `size(A, 2) (= $(size(A, 2)))`"))) + elseif length(p) != size(A, 1) throw(DimensionMismatch(string("the length of row-permutation argument `p`, ", "`length(p) (= $(length(p)))`, must match source argument `A`'s row count, ", - "`A.m (= $(A.m))`"))) + "`size(A, 1) (= $(size(A, 1)))`"))) end end """ @@ -1080,19 +1081,19 @@ Checks compatibility of source argument `A` and destination argument `X`. """ function _checkargs_sourcecompatdest_permute!(A::SparseMatrixCSC{Tv,Ti}, X::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} - if X.m != A.m + if size(X, 1) != size(A, 1) throw(DimensionMismatch(string("destination argument `X`'s row count, ", - "`X.m (= $(X.m))`, must match source argument `A`'s row count, `A.m (= $(A.m))`"))) - elseif X.n != A.n + "`size(X, 1) (= $(size(X, 1)))`, must match source argument `A`'s row count, `size(A, 1) (= $(size(A, 1)))`"))) + elseif size(X, 2) != size(A, 2) throw(DimensionMismatch(string("destination argument `X`'s column count, ", - "`X.n (= $(X.n))`, must match source argument `A`'s column count, `A.n (= $(A.n))`"))) - elseif length(X.rowval) < nnz(A) + "`size(X, 2) (= $(size(X, 2)))`, must match source argument `A`'s column count, `size(A, 2) (= $(size(A, 2)))`"))) + elseif length(rowvals(X)) < nnz(A) throw(ArgumentError(string("the length of destination argument `X`'s `rowval` ", - "array, `length(X.rowval) (= $(length(X.rowval)))`, must be greater than or ", + "array, `length(rowvals(X)) (= $(length(rowvals(X))))`, must be greater than or ", "equal to source argument `A`'s allocated entry count, `nnz(A) (= $(nnz(A)))`"))) - elseif length(X.nzval) < nnz(A) + elseif length(nonzeros(X)) < nnz(A) throw(ArgumentError(string("the length of destination argument `X`'s `nzval` ", - "array, `length(X.nzval) (= $(length(X.nzval)))`, must be greater than or ", + "array, `length(nonzeros(X)) (= $(length(nonzeros(X))))`, must be greater than or ", "equal to source argument `A`'s allocated entry count, `nnz(A) (= $(nnz(A)))`"))) end end @@ -1102,19 +1103,19 @@ Checks compatibility of source argument `A` and intermediate result argument `C` """ function _checkargs_sourcecompatworkmat_permute!(A::SparseMatrixCSC{Tv,Ti}, C::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} - if C.n != A.m + if size(C, 2) != size(A, 1) throw(DimensionMismatch(string("intermediate result argument `C`'s column count, ", - "`C.n (= $(C.n))`, must match source argument `A`'s row count, `A.m (= $(A.m))`"))) - elseif C.m != A.n + "`size(C, 2) (= $(size(C, 2)))`, must match source argument `A`'s row count, `size(A, 1) (= $(size(A, 1)))`"))) + elseif size(C, 1) != size(A, 2) throw(DimensionMismatch(string("intermediate result argument `C`'s row count, ", - "`C.m (= $(C.m))`, must match source argument `A`'s column count, `A.n (= $(A.n))`"))) - elseif length(C.rowval) < nnz(A) + "`size(C, 1) (= $(size(C, 1)))`, must match source argument `A`'s column count, `size(A, 2) (= $(size(A, 2)))`"))) + elseif length(rowvals(C)) < nnz(A) throw(ArgumentError(string("the length of intermediate result argument `C`'s ", - "`rowval` array, `length(C.rowval) (= $(length(C.rowval)))`, must be greater than ", + "`rowval` array, `length(rowvals(C)) (= $(length(rowvals(C))))`, must be greater than ", "or equal to source argument `A`'s allocated entry count, `nnz(A) (= $(nnz(A)))`"))) - elseif length(C.nzval) < nnz(A) + elseif length(nonzeros(C)) < nnz(A) throw(ArgumentError(string("the length of intermediate result argument `C`'s ", - "`rowval` array, `length(C.nzval) (= $(length(C.nzval)))`, must be greater than ", + "`rowval` array, `length(nonzeros(C)) (= $(length(nonzeros(C))))`, must be greater than ", "or equal to source argument `A`'s allocated entry count, `nnz(A)` (= $(nnz(A)))"))) end end @@ -1124,10 +1125,10 @@ Checks compatibility of source argument `A` and workspace argument `workcolptr`. """ function _checkargs_sourcecompatworkcolptr_permute!(A::SparseMatrixCSC{Tv,Ti}, workcolptr::Vector{Ti}) where {Tv,Ti} - if length(workcolptr) <= A.n + if length(workcolptr) <= size(A, 2) throw(DimensionMismatch(string("argument `workcolptr`'s length, ", "`length(workcolptr) (= $(length(workcolptr)))`, must exceed source argument ", - "`A`'s column count, `A.n (= $(A.n))`"))) + "`A`'s column count, `size(A, 2) (= $(size(A, 2)))`"))) end end """ @@ -1144,15 +1145,15 @@ the following method lacking `X`: q::AbstractVector{<:Integer}[, C::SparseMatrixCSC{Tv,Ti}, [workcolptr::Vector{Ti}]]) where {Tv,Ti} -`X`'s dimensions must match those of `A` (`X.m == A.m` and `X.n == A.n`), and `X` must -have enough storage to accommodate all allocated entries in `A` (`length(X.rowval) >= nnz(A)` -and `length(X.nzval) >= nnz(A)`). Column-permutation `q`'s length must match `A`'s column -count (`length(q) == A.n`). Row-permutation `p`'s length must match `A`'s row count -(`length(p) == A.m`). +`X`'s dimensions must match those of `A` (`size(X, 1) == size(A, 1)` and `size(X, 2) == size(A, 2)`), and `X` must +have enough storage to accommodate all allocated entries in `A` (`length(rowvals(X)) >= nnz(A)` +and `length(nonzeros(X)) >= nnz(A)`). Column-permutation `q`'s length must match `A`'s column +count (`length(q) == size(A, 2)`). Row-permutation `p`'s length must match `A`'s row count +(`length(p) == size(A, 1)`). -`C`'s dimensions must match those of `transpose(A)` (`C.m == A.n` and `C.n == A.m`), and `C` -must have enough storage to accommodate all allocated entries in `A` (`length(C.rowval) >= nnz(A)` -and `length(C.nzval) >= nnz(A)`). +`C`'s dimensions must match those of `transpose(A)` (`size(C, 1) == size(A, 2)` and `size(C, 2) == size(A, 1)`), and `C` +must have enough storage to accommodate all allocated entries in `A` (`length(rowvals(C)) >= nnz(A)` +and `length(nonzeros(C)) >= nnz(A)`). For additional (algorithmic) information, and for versions of these methods that forgo argument checking, see (unexported) parent methods `unchecked_noalias_permute!` @@ -1164,11 +1165,11 @@ function permute!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) where {Tv,Ti} _checkargs_sourcecompatdest_permute!(A, X) _checkargs_sourcecompatperms_permute!(A, p, q) - C = SparseMatrixCSC(A.n, A.m, - ones(Ti, A.m + 1), + C = SparseMatrixCSC(size(A, 2), size(A, 1), + ones(Ti, size(A, 1) + 1), Vector{Ti}(undef, nnz(A)), Vector{Tv}(undef, nnz(A))) - _checkargs_permutationsvalid_permute!(p, C.colptr, q, X.colptr) + _checkargs_permutationsvalid_permute!(p, getcolptr(C), q, getcolptr(X)) unchecked_noalias_permute!(X, A, p, q, C) end function permute!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, @@ -1177,26 +1178,26 @@ function permute!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, _checkargs_sourcecompatdest_permute!(A, X) _checkargs_sourcecompatperms_permute!(A, p, q) _checkargs_sourcecompatworkmat_permute!(A, C) - _checkargs_permutationsvalid_permute!(p, C.colptr, q, X.colptr) + _checkargs_permutationsvalid_permute!(p, getcolptr(C), q, getcolptr(X)) unchecked_noalias_permute!(X, A, p, q, C) end function permute!(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) where {Tv,Ti} _checkargs_sourcecompatperms_permute!(A, p, q) - C = SparseMatrixCSC(A.n, A.m, - ones(Ti, A.m + 1), + C = SparseMatrixCSC(size(A, 2), size(A, 1), + ones(Ti, size(A, 1) + 1), Vector{Ti}(undef, nnz(A)), Vector{Tv}(undef, nnz(A))) - workcolptr = Vector{Ti}(undef, A.n + 1) - _checkargs_permutationsvalid_permute!(p, C.colptr, q, workcolptr) + workcolptr = Vector{Ti}(undef, size(A, 2) + 1) + _checkargs_permutationsvalid_permute!(p, getcolptr(C), q, workcolptr) unchecked_aliasing_permute!(A, p, q, C, workcolptr) end function permute!(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}, C::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} _checkargs_sourcecompatperms_permute!(A, p, q) _checkargs_sourcecompatworkmat_permute!(A, C) - workcolptr = Vector{Ti}(undef, A.n + 1) - _checkargs_permutationsvalid_permute!(p, C.colptr, q, workcolptr) + workcolptr = Vector{Ti}(undef, size(A, 2) + 1) + _checkargs_permutationsvalid_permute!(p, getcolptr(C), q, workcolptr) unchecked_aliasing_permute!(A, p, q, C, workcolptr) end function permute!(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, @@ -1205,7 +1206,7 @@ function permute!(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, _checkargs_sourcecompatperms_permute!(A, p, q) _checkargs_sourcecompatworkmat_permute!(A, C) _checkargs_sourcecompatworkcolptr_permute!(A, workcolptr) - _checkargs_permutationsvalid_permute!(p, C.colptr, q, workcolptr) + _checkargs_permutationsvalid_permute!(p, getcolptr(C), q, workcolptr) unchecked_aliasing_permute!(A, p, q, C, workcolptr) end """ @@ -1213,8 +1214,8 @@ end q::AbstractVector{<:Integer}) where {Tv,Ti} Bilaterally permute `A`, returning `PAQ` (`A[p,q]`). Column-permutation `q`'s length must -match `A`'s column count (`length(q) == A.n`). Row-permutation `p`'s length must match `A`'s -row count (`length(p) == A.m`). +match `A`'s column count (`length(q) == size(A, 2)`). Row-permutation `p`'s length must match `A`'s +row count (`length(p) == size(A, 1)`). For expert drivers and additional information, see [`permute!`](@ref). @@ -1254,15 +1255,15 @@ julia> permute(A, [1, 2, 3, 4], [4, 3, 2, 1]) function permute(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) where {Tv,Ti} _checkargs_sourcecompatperms_permute!(A, p, q) - X = SparseMatrixCSC(A.m, A.n, - ones(Ti, A.n + 1), + X = SparseMatrixCSC(size(A, 1), size(A, 2), + ones(Ti, size(A, 2) + 1), Vector{Ti}(undef, nnz(A)), Vector{Tv}(undef, nnz(A))) - C = SparseMatrixCSC(A.n, A.m, - ones(Ti, A.m + 1), + C = SparseMatrixCSC(size(A, 2), size(A, 1), + ones(Ti, size(A, 1) + 1), Vector{Ti}(undef, nnz(A)), Vector{Tv}(undef, nnz(A))) - _checkargs_permutationsvalid_permute!(p, C.colptr, q, X.colptr) + _checkargs_permutationsvalid_permute!(p, getcolptr(C), q, getcolptr(X)) unchecked_noalias_permute!(X, A, p, q, C) end @@ -1277,9 +1278,9 @@ Keep elements of `A` for which test `f` returns `true`. `f`'s signature should b where `i` and `j` are an element's row and column indices and `x` is the element's value. This method makes a single sweep -through `A`, requiring `O(A.n, nnz(A))`-time for matrices and `O(nnz(A))`-time for vectors -and no space beyond that passed in. If `trim` is `true`, this method trims `A.rowval` or `A.nzind` and -`A.nzval` to length `nnz(A)` after dropping elements. +through `A`, requiring `O(size(A, 2), nnz(A))`-time for matrices and `O(nnz(A))`-time for vectors +and no space beyond that passed in. If `trim` is `true`, this method trims `rowvals(A)` or `nonzeroinds(A)` and +`nonzeros(A)` to length `nnz(A)` after dropping elements. # Examples ```jldoctest @@ -1297,10 +1298,10 @@ julia> SparseArrays.fkeep!(A, (i, j, v) -> isodd(v)) ``` """ function fkeep!(A::SparseMatrixCSC, f, trim::Bool = true) - An = A.n - Acolptr = A.colptr - Arowval = A.rowval - Anzval = A.nzval + An = size(A, 2) + Acolptr = getcolptr(A) + Arowval = rowvals(A) + Anzval = nonzeros(A) # Sweep through columns, rewriting kept elements in their new positions # and updating the column pointers accordingly as we go. @@ -1346,7 +1347,7 @@ triu!(A::SparseMatrixCSC, k::Integer = 0, trim::Bool = true) = droptol!(A::SparseMatrixCSC, tol; trim::Bool = true) Removes stored values from `A` whose absolute value is less than or equal to `tol`, -optionally trimming resulting excess space from `A.rowval` and `A.nzval` when `trim` +optionally trimming resulting excess space from `rowvals(A)` and `nonzeros(A)` when `trim` is `true`. """ droptol!(A::SparseMatrixCSC, tol; trim::Bool = true) = @@ -1356,7 +1357,7 @@ droptol!(A::SparseMatrixCSC, tol; trim::Bool = true) = dropzeros!(A::SparseMatrixCSC; trim::Bool = true) Removes stored numerical zeros from `A`, optionally trimming resulting excess space from -`A.rowval` and `A.nzval` when `trim` is `true`. +`rowvals(A)` and `nonzeros(A)` when `trim` is `true`. For an out-of-place version, see [`dropzeros`](@ref). For algorithmic information, see `fkeep!`. @@ -1401,10 +1402,10 @@ function findall(p::Function, S::SparseMatrixCSC) inds = Vector{CartesianIndex{2}}(undef, numnz) count = 0 - @inbounds for col = 1 : S.n, k = S.colptr[col] : (S.colptr[col+1]-1) - if p(S.nzval[k]) + @inbounds for col = 1 : size(S, 2), k = getcolptr(S)[col] : (getcolptr(S)[col+1]-1) + if p(nonzeros(S)[k]) count += 1 - inds[count] = CartesianIndex(S.rowval[k], col) + inds[count] = CartesianIndex(rowvals(S)[k], col) end end @@ -1422,10 +1423,10 @@ function findnz(S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} V = Vector{Tv}(undef, numnz) count = 1 - @inbounds for col = 1 : S.n, k = S.colptr[col] : (S.colptr[col+1]-1) - I[count] = S.rowval[k] + @inbounds for col = 1 : size(S, 2), k = getcolptr(S)[col] : (getcolptr(S)[col+1]-1) + I[count] = rowvals(S)[k] J[count] = col - V[count] = S.nzval[k] + V[count] = nonzeros(S)[k] count += 1 end @@ -1434,32 +1435,32 @@ end function _sparse_findnextnz(m::SparseMatrixCSC, ij::CartesianIndex{2}) row, col = Tuple(ij) - col > m.n && return nothing + col > size(m, 2) && return nothing - lo, hi = m.colptr[col], m.colptr[col+1] - n = searchsortedfirst(m.rowval, row, lo, hi-1, Base.Order.Forward) + lo, hi = getcolptr(m)[col], getcolptr(m)[col+1] + n = searchsortedfirst(rowvals(m), row, lo, hi-1, Base.Order.Forward) if lo <= n <= hi-1 - return CartesianIndex(m.rowval[n], col) + return CartesianIndex(rowvals(m)[n], col) end - nextcol = searchsortedfirst(m.colptr, hi + 1, col + 1, length(m.colptr), Base.Order.Forward) - nextcol > length(m.colptr) && return nothing - nextlo = m.colptr[nextcol-1] - return CartesianIndex(m.rowval[nextlo], nextcol - 1) + nextcol = searchsortedfirst(getcolptr(m), hi + 1, col + 1, length(getcolptr(m)), Base.Order.Forward) + nextcol > length(getcolptr(m)) && return nothing + nextlo = getcolptr(m)[nextcol-1] + return CartesianIndex(rowvals(m)[nextlo], nextcol - 1) end function _sparse_findprevnz(m::SparseMatrixCSC, ij::CartesianIndex{2}) row, col = Tuple(ij) iszero(col) && return nothing - lo, hi = m.colptr[col], m.colptr[col+1] - n = searchsortedlast(m.rowval, row, lo, hi-1, Base.Order.Forward) + lo, hi = getcolptr(m)[col], getcolptr(m)[col+1] + n = searchsortedlast(rowvals(m), row, lo, hi-1, Base.Order.Forward) if lo <= n <= hi-1 - return CartesianIndex(m.rowval[n], col) + return CartesianIndex(rowvals(m)[n], col) end - prevcol = searchsortedlast(m.colptr, lo - 1, 1, col - 1, Base.Order.Forward) + prevcol = searchsortedlast(getcolptr(m), lo - 1, 1, col - 1, Base.Order.Forward) prevcol < 1 && return nothing - prevhi = m.colptr[prevcol+1] - return CartesianIndex(m.rowval[prevhi-1], prevcol) + prevhi = getcolptr(m)[prevcol+1] + return CartesianIndex(rowvals(m)[prevhi-1], prevcol) end @@ -1584,8 +1585,8 @@ end import Base._one function Base._one(unit::T, S::SparseMatrixCSC) where T - S.m == S.n || throw(DimensionMismatch("multiplicative identity only defined for square matrices")) - return SparseMatrixCSC{T}(I, S.m, S.n) + size(S, 1) == size(S, 2) || throw(DimensionMismatch("multiplicative identity only defined for square matrices")) + return SparseMatrixCSC{T}(I, size(S, 1), size(S, 2)) end ## SparseMatrixCSC construction from UniformScaling @@ -1610,9 +1611,9 @@ Base.iszero(A::SparseMatrixCSC) = iszero(nzvalview(A)) function Base.isone(A::SparseMatrixCSC) m, n = size(A) - m == n && A.colptr[n+1] >= n+1 || return false - for j in 1:n, k in A.colptr[j]:(A.colptr[j+1] - 1) - i, x = A.rowval[k], A.nzval[k] + m == n && getcolptr(A)[n+1] >= n+1 || return false + for j in 1:n, k in getcolptr(A)[j]:(getcolptr(A)[j+1] - 1) + i, x = rowvals(A)[k], nonzeros(A)[k] ifelse(i == j, isone(x), iszero(x)) || return false end return true @@ -1627,18 +1628,18 @@ function conj!(A::SparseMatrixCSC) return A end function (-)(A::SparseMatrixCSC) - nzval = similar(A.nzval) + nzval = similar(nonzeros(A)) map!(-, view(nzval, 1:nnz(A)), nzvalview(A)) - return SparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), nzval) + return SparseMatrixCSC(size(A, 1), size(A, 2), copy(getcolptr(A)), copy(rowvals(A)), nzval) end # the rest of real, conj, imag are handled correctly via AbstractArray methods function conj(A::SparseMatrixCSC{<:Complex}) - nzval = similar(A.nzval) + nzval = similar(nonzeros(A)) map!(conj, view(nzval, 1:nnz(A)), nzvalview(A)) - return SparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), nzval) + return SparseMatrixCSC(size(A, 1), size(A, 2), copy(getcolptr(A)), copy(rowvals(A)), nzval) end -imag(A::SparseMatrixCSC{Tv,Ti}) where {Tv<:Real,Ti} = spzeros(Tv, Ti, A.m, A.n) +imag(A::SparseMatrixCSC{Tv,Ti}) where {Tv<:Real,Ti} = spzeros(Tv, Ti, size(A, 1), size(A, 2)) ## Binary arithmetic and boolean operators (+)(A::SparseMatrixCSC, B::SparseMatrixCSC) = map(+, A, B) @@ -1750,9 +1751,9 @@ end # General mapreducedim function _mapreducerows!(f, op, R::AbstractArray, A::SparseMatrixCSC{T}) where T require_one_based_indexing(A, R) - colptr = A.colptr - rowval = A.rowval - nzval = A.nzval + colptr = getcolptr(A) + rowval = rowvals(A) + nzval = nonzeros(A) m, n = size(A) @inbounds for col = 1:n r = R[1, col] @@ -1766,9 +1767,9 @@ end function _mapreducecols!(f, op, R::AbstractArray, A::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} require_one_based_indexing(A, R) - colptr = A.colptr - rowval = A.rowval - nzval = A.nzval + colptr = getcolptr(A) + rowval = rowvals(A) + nzval = nonzeros(A) m, n = size(A) rownz = fill(convert(Ti, n), m) @inbounds for col = 1:n @@ -1802,7 +1803,7 @@ function Base._mapreducedim!(f, op, R::AbstractArray, A::SparseMatrixCSC{T}) whe # Reduction along a dimension > 2 # Compute op(R, f(A)) m, n = size(A) - nzval = A.nzval + nzval = nonzeros(A) if length(nzval) == m*n # No zeros, so don't compute f(0) since it might throw for col = 1:n @@ -1811,8 +1812,8 @@ function Base._mapreducedim!(f, op, R::AbstractArray, A::SparseMatrixCSC{T}) whe end end else - colptr = A.colptr - rowval = A.rowval + colptr = getcolptr(A) + rowval = rowvals(A) zeroval = f(zero(T)) @inbounds for col = 1:n lastrow = 0 @@ -1837,7 +1838,7 @@ end # temporary array when f(0) == 0 function _mapreducecols!(f, op::typeof(+), R::AbstractArray, A::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} require_one_based_indexing(A, R) - nzval = A.nzval + nzval = nonzeros(A) m, n = size(A) if length(nzval) == m*n # No zeros, so don't compute f(0) since it might throw @@ -1847,8 +1848,8 @@ function _mapreducecols!(f, op::typeof(+), R::AbstractArray, A::SparseMatrixCSC{ end end else - colptr = A.colptr - rowval = A.rowval + colptr = getcolptr(A) + rowval = rowvals(A) zeroval = f(zero(Tv)) if isequal(zeroval, zero(Tv)) # Case where f(0) == 0 @@ -1878,12 +1879,12 @@ end # findmax/min and argmax/min methods # find first zero value in sparse matrix - return linear index in full matrix # non-structural zeros are identified by x == 0 in line with the sparse constructors. -function _findz(A::SparseMatrixCSC{Tv,Ti}, rows=1:A.m, cols=1:A.n) where {Tv,Ti} - colptr = A.colptr; rowval = A.rowval; nzval = A.nzval +function _findz(A::SparseMatrixCSC{Tv,Ti}, rows=1:size(A, 1), cols=1:size(A, 2)) where {Tv,Ti} + colptr = getcolptr(A); rowval = rowvals(A); nzval = nonzeros(A) zval = 0 row = 0 rowmin = rows[1]; rowmax = rows[end] - allrows = (rows == 1:A.m) + allrows = (rows == 1:size(A, 1)) @inbounds for col in cols r1::Int = colptr[col] r2::Int = colptr[col+1] - 1 @@ -1916,7 +1917,7 @@ function _findr(op, A, region, Tv) end end - colptr = A.colptr; rowval = A.rowval; nzval = A.nzval; m = A.m; n = A.n + colptr = getcolptr(A); rowval = rowvals(A); nzval = nonzeros(A); m = size(A, 1); n = size(A, 2) zval = zero(Tv) szA = size(A) @@ -1963,7 +1964,7 @@ function _findr(op, A, region, Tv) hasz = nnz(A) != length(A) Sv = hasz ? zval : nzval[1] Iv::(Ti) = hasz ? _findz(A) : i1 - @inbounds for i = 1 : A.n, j = colptr[i] : (colptr[i+1]-1) + @inbounds for i = 1 : size(A, 2), j = colptr[i] : (colptr[i+1]-1) if op(nzval[j], Sv) Sv = nzval[j] Iv = CartesianIndex(rowval[j], i) @@ -1995,12 +1996,12 @@ end getindex(A::SparseMatrixCSC, I::Tuple{Integer,Integer}) = getindex(A, I[1], I[2]) function getindex(A::SparseMatrixCSC{T}, i0::Integer, i1::Integer) where T - if !(1 <= i0 <= A.m && 1 <= i1 <= A.n); throw(BoundsError()); end - r1 = Int(A.colptr[i1]) - r2 = Int(A.colptr[i1+1]-1) + if !(1 <= i0 <= size(A, 1) && 1 <= i1 <= size(A, 2)); throw(BoundsError()); end + r1 = Int(getcolptr(A)[i1]) + r2 = Int(getcolptr(A)[i1+1]-1) (r1 > r2) && return zero(T) - r1 = searchsortedfirst(A.rowval, i0, r1, r2, Forward) - ((r1 > r2) || (A.rowval[r1] != i0)) ? zero(T) : A.nzval[r1] + r1 = searchsortedfirst(rowvals(A), i0, r1, r2, Forward) + ((r1 > r2) || (rowvals(A)[r1] != i0)) ? zero(T) : nonzeros(A)[r1] end # Colon translation @@ -2014,7 +2015,7 @@ function getindex_cols(A::SparseMatrixCSC{Tv,Ti}, J::AbstractVector) where {Tv,T (m, n) = size(A) nJ = length(J) - colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval + colptrA = getcolptr(A); rowvalA = rowvals(A); nzvalA = nonzeros(A) colptrS = Vector{Ti}(undef, nJ+1) colptrS[1] = 1 @@ -2057,7 +2058,7 @@ function getindex(A::SparseMatrixCSC{Tv,Ti}, I::AbstractRange, J::AbstractVector nI = length(I) nI == 0 || (minimum(I) >= 1 && maximum(I) <= m) || throw(BoundsError()) nJ = length(J) - colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval + colptrA = getcolptr(A); rowvalA = rowvals(A); nzvalA = nonzeros(A) colptrS = Vector{Ti}(undef, nJ+1) colptrS[1] = 1 nnzS = 0 @@ -2119,7 +2120,7 @@ function getindex_I_sorted_bsearch_A(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVecto nI = length(I) nJ = length(J) - colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval + colptrA = getcolptr(A); rowvalA = rowvals(A); nzvalA = nonzeros(A) colptrS = Vector{Ti}(undef, nJ+1) colptrS[1] = 1 @@ -2179,10 +2180,10 @@ function getindex_I_sorted_linear(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVector, nI = length(I) nJ = length(J) - colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval + colptrA = getcolptr(A); rowvalA = rowvals(A); nzvalA = nonzeros(A) colptrS = Vector{Ti}(undef, nJ+1) colptrS[1] = 1 - cacheI = zeros(Int, A.m) + cacheI = zeros(Int, size(A, 1)) ptrS = 1 # build the cache and determine result size @@ -2239,11 +2240,11 @@ function getindex_I_sorted_bsearch_I(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVecto nI = length(I) nJ = length(J) - colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval + colptrA = getcolptr(A); rowvalA = rowvals(A); nzvalA = nonzeros(A) colptrS = Vector{Ti}(undef, nJ+1) colptrS[1] = 1 - m = A.m + m = size(A, 1) # cacheI is used first to store num occurrences of each row in columns of interest # and later to store position of first occurrence of each row in I @@ -2306,7 +2307,7 @@ end function permute_rows!(S::SparseMatrixCSC{Tv,Ti}, pI::Vector{Int}) where {Tv,Ti} (m, n) = size(S) - colptrS = S.colptr; rowvalS = S.rowval; nzvalS = S.nzval + colptrS = getcolptr(S); rowvalS = rowvals(S); nzvalS = nonzeros(S) # preallocate temporary sort space nr = min(nnz(S), m) @@ -2387,9 +2388,9 @@ function getindex(A::SparseMatrixCSC{Tv,Ti}, I::AbstractArray) where {Tv,Ti} require_one_based_indexing(A, I) szA = size(A) nA = szA[1]*szA[2] - colptrA = A.colptr - rowvalA = A.rowval - nzvalA = A.nzval + colptrA = getcolptr(A) + rowvalA = rowvals(A) + nzvalA = nonzeros(A) n = length(I) outm = size(I,1) @@ -2446,30 +2447,30 @@ function _setindex_scalar!(A::SparseMatrixCSC{Tv,Ti}, _v, _i::Integer, _j::Integ v = convert(Tv, _v) i = convert(Ti, _i) j = convert(Ti, _j) - if !((1 <= i <= A.m) & (1 <= j <= A.n)) + if !((1 <= i <= size(A, 1)) & (1 <= j <= size(A, 2))) throw(BoundsError(A, (i,j))) end - coljfirstk = Int(A.colptr[j]) - coljlastk = Int(A.colptr[j+1] - 1) - searchk = searchsortedfirst(A.rowval, i, coljfirstk, coljlastk, Base.Order.Forward) - if searchk <= coljlastk && A.rowval[searchk] == i + coljfirstk = Int(getcolptr(A)[j]) + coljlastk = Int(getcolptr(A)[j+1] - 1) + searchk = searchsortedfirst(rowvals(A), i, coljfirstk, coljlastk, Base.Order.Forward) + if searchk <= coljlastk && rowvals(A)[searchk] == i # Column j contains entry A[i,j]. Update and return - A.nzval[searchk] = v + nonzeros(A)[searchk] = v return A end # Column j does not contain entry A[i,j]. If v is nonzero, insert entry A[i,j] = v # and return. If to the contrary v is zero, then simply return. if !iszero(v) - nz = A.colptr[A.n+1] + nz = getcolptr(A)[size(A, 2)+1] # throw exception before state is partially modified !isbitstype(Ti) || nz < typemax(Ti) || throw(ArgumentError("nnz(A) going to exceed typemax(Ti) = $(typemax(Ti))")) # if nnz(A) < length(rowval/nzval): no need to grow rowval and preserve values - _insert!(A.rowval, searchk, i, nz) - _insert!(A.nzval, searchk, v, nz) - @simd for m in (j + 1):(A.n + 1) - @inbounds A.colptr[m] += Ti(1) + _insert!(rowvals(A), searchk, i, nz) + _insert!(nonzeros(A), searchk, v, nz) + @simd for m in (j + 1):(size(A, 2) + 1) + @inbounds getcolptr(A)[m] += Ti(1) end end return A @@ -2493,7 +2494,7 @@ function Base.fill!(V::SubArray{Tv, <:Any, <:SparseMatrixCSC, Tuple{Vararg{Union # lt=≤ to check for strict sorting if !issorted(I, lt=≤); I = sort!(unique(I)); end if !issorted(J, lt=≤); J = sort!(unique(J)); end - if (I[1] < 1 || I[end] > A.m) || (J[1] < 1 || J[end] > A.n) + if (I[1] < 1 || I[end] > size(A, 1)) || (J[1] < 1 || J[end] > size(A, 2)) throw(BoundsError(A, (I, J))) end if x == 0 @@ -2511,28 +2512,28 @@ function _spsetz_setindex!(A::SparseMatrixCSC, require_one_based_indexing(A, I, J) lengthI = length(I) for j in J - coljAfirstk = A.colptr[j] - coljAlastk = A.colptr[j+1] - 1 + coljAfirstk = getcolptr(A)[j] + coljAlastk = getcolptr(A)[j+1] - 1 coljAfirstk > coljAlastk && continue kA = coljAfirstk kI = 1 - entrykArow = A.rowval[kA] + entrykArow = rowvals(A)[kA] entrykIrow = I[kI] while true if entrykArow < entrykIrow kA += 1 kA > coljAlastk && break - entrykArow = A.rowval[kA] + entrykArow = rowvals(A)[kA] elseif entrykArow > entrykIrow kI += 1 kI > lengthI && break entrykIrow = I[kI] else # entrykArow == entrykIrow - A.nzval[kA] = 0 + nonzeros(A)[kA] = 0 kA += 1 kI += 1 (kA > coljAlastk || kI > lengthI) && break - entrykArow = A.rowval[kA] + entrykArow = rowvals(A)[kA] entrykIrow = I[kI] end end @@ -2551,15 +2552,15 @@ function _spsetnz_setindex!(A::SparseMatrixCSC{Tv}, x::Tv, nnzA = nnz(A) + lenI * length(J) - rowvalA = rowval = A.rowval - nzvalA = nzval = A.nzval + rowvalA = rowval = rowvals(A) + nzvalA = nzval = nonzeros(A) rowidx = 1 nadd = 0 @inbounds for col in 1:n rrange = nzrange(A, col) if nadd > 0 - A.colptr[col] = A.colptr[col] + nadd + getcolptr(A)[col] = getcolptr(A)[col] + nadd end if col in J @@ -2643,7 +2644,7 @@ function _spsetnz_setindex!(A::SparseMatrixCSC{Tv}, x::Tv, end if nadd > 0 - A.colptr[n+1] = rowidx + getcolptr(A)[n+1] = rowidx deleteat!(rowvalA, rowidx:nnzA) deleteat!(nzvalA, rowidx:nnzA) end @@ -2692,14 +2693,14 @@ function setindex!(A::SparseMatrixCSC{Tv,Ti}, V::AbstractVecOrMat, Ix::Union{Int nI = length(I) nJ = length(J) - colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval - colptrB = B.colptr; rowvalB = B.rowval; nzvalB = B.nzval + colptrA = getcolptr(A); rowvalA = rowvals(A); nzvalA = nonzeros(A) + colptrB = getcolptr(B); rowvalB = rowvals(B); nzvalB = nonzeros(B) nnzS = nnz(A) + nnz(B) - colptrS = copy(A.colptr) - rowvalS = copy(A.rowval) - nzvalS = copy(A.nzval) + colptrS = copy(getcolptr(A)) + rowvalS = copy(rowvals(A)) + nzvalS = copy(nonzeros(A)) resize!(rowvalA, nnzS) resize!(nzvalA, nnzS) @@ -2797,17 +2798,17 @@ function setindex!(A::SparseMatrixCSC, x::AbstractArray, I::AbstractMatrix{Bool} n = sum(I) (n == 0) && (return A) - colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval + colptrA = getcolptr(A); rowvalA = rowvals(A); nzvalA = nonzeros(A) colptrB = colptrA; rowvalB = rowvalA; nzvalB = nzvalA nadd = 0 bidx = xidx = 1 r1 = r2 = 0 - @inbounds for col in 1:A.n + @inbounds for col in 1:size(A, 2) r1 = Int(colptrA[col]) r2 = Int(colptrA[col+1]-1) - for row in 1:A.m + for row in 1:size(A, 1) if I[row, col] v = x[xidx] xidx += 1 @@ -2853,7 +2854,7 @@ function setindex!(A::SparseMatrixCSC, x::AbstractArray, I::AbstractMatrix{Bool} end (xidx > n) && break end # if I[row, col] - end # for row in 1:A.m + end # for row in 1:size(A, 1) if (nadd != 0) l = r2-r1+1 @@ -2880,7 +2881,7 @@ function setindex!(A::SparseMatrixCSC, x::AbstractArray, I::AbstractMatrix{Bool} bidx = colptrA[col+1] end (xidx > n) && break - end # for col in 1:A.n + end # for col in 1:size(A, 2) if (nadd != 0) n = length(nzvalB) @@ -2899,7 +2900,7 @@ function setindex!(A::SparseMatrixCSC, x::AbstractArray, Ix::AbstractVector{<:In n = length(I) (n == 0) && (return A) - colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval; szA = size(A) + colptrA = getcolptr(A); rowvalA = rowvals(A); nzvalA = nonzeros(A); szA = size(A) colptrB = colptrA; rowvalB = rowvalA; nzvalB = nzvalA nadd = 0 bidx = aidx = 1 @@ -3021,18 +3022,18 @@ julia> SparseArrays.dropstored!(A, 1, 2); A ``` """ function dropstored!(A::SparseMatrixCSC, i::Integer, j::Integer) - if !((1 <= i <= A.m) & (1 <= j <= A.n)) + if !((1 <= i <= size(A, 1)) & (1 <= j <= size(A, 2))) throw(BoundsError(A, (i,j))) end - coljfirstk = Int(A.colptr[j]) - coljlastk = Int(A.colptr[j+1] - 1) - searchk = searchsortedfirst(A.rowval, i, coljfirstk, coljlastk, Base.Order.Forward) - if searchk <= coljlastk && A.rowval[searchk] == i + coljfirstk = Int(getcolptr(A)[j]) + coljlastk = Int(getcolptr(A)[j+1] - 1) + searchk = searchsortedfirst(rowvals(A), i, coljfirstk, coljlastk, Base.Order.Forward) + if searchk <= coljlastk && rowvals(A)[searchk] == i # Entry A[i,j] is stored. Drop and return. - deleteat!(A.rowval, searchk) - deleteat!(A.nzval, searchk) - @simd for m in (j+1):(A.n + 1) - @inbounds A.colptr[m] -= 1 + deleteat!(rowvals(A), searchk) + deleteat!(nonzeros(A), searchk) + @simd for m in (j+1):(size(A, 2) + 1) + @inbounds getcolptr(A)[m] -= 1 end end return A @@ -3080,14 +3081,14 @@ function dropstored!(A::SparseMatrixCSC, return A end - rowval = rowvalA = A.rowval - nzval = nzvalA = A.nzval + rowval = rowvalA = rowvals(A) + nzval = nzvalA = nonzeros(A) rowidx = 1 ndel = 0 @inbounds for col in 1:n rrange = nzrange(A, col) if ndel > 0 - A.colptr[col] = A.colptr[col] - ndel + getcolptr(A)[col] = getcolptr(A)[col] - ndel end if isempty(rrange) || !(col in J) @@ -3117,7 +3118,7 @@ function dropstored!(A::SparseMatrixCSC, end if ndel > 0 - A.colptr[n+1] = rowidx + getcolptr(A)[n+1] = rowidx deleteat!(rowvalA, rowidx:nnzA) deleteat!(nzvalA, rowidx:nnzA) end @@ -3149,7 +3150,7 @@ function vcat(X::SparseMatrixCSC...) end Tv = promote_eltype(X...) - Ti = promote_eltype(map(x->x.rowval, X)...) + Ti = promote_eltype(map(x->rowvals(x), X)...) nnzX = Int[ nnz(x) for x in X ] nnz_res = sum(nnzX) @@ -3162,7 +3163,7 @@ function vcat(X::SparseMatrixCSC...) mX_sofar = 0 ptr_res = colptr[c] for i = 1 : num - colptrXi = X[i].colptr + colptrXi = getcolptr(X[i]) col_length = (colptrXi[c + 1] - 1) - colptrXi[c] ptr_Xi = colptrXi[c] @@ -3179,9 +3180,9 @@ end @inline function stuffcol!(Xi::SparseMatrixCSC, colptr, rowval, nzval, ptr_res, ptr_Xi, col_length, mX_sofar) - colptrXi = Xi.colptr - rowvalXi = Xi.rowval - nzvalXi = Xi.nzval + colptrXi = getcolptr(Xi) + rowvalXi = rowvals(Xi) + nzvalXi = nonzeros(Xi) for k=ptr_res:(ptr_res + col_length) @inbounds rowval[k] = rowvalXi[ptr_Xi] + mX_sofar @@ -3201,7 +3202,7 @@ function hcat(X::SparseMatrixCSC...) n = sum(nX) Tv = promote_eltype(X...) - Ti = promote_eltype(map(x->x.rowval, X)...) + Ti = promote_eltype(map(x->rowvals(x), X)...) colptr = Vector{Ti}(undef, n+1) nnzX = Int[ nnz(x) for x in X ] @@ -3213,13 +3214,13 @@ function hcat(X::SparseMatrixCSC...) nX_sofar = 0 @inbounds for i = 1 : num XI = X[i] - colptr[(1 : nX[i] + 1) .+ nX_sofar] = XI.colptr .+ nnz_sofar - if nnzX[i] == length(XI.rowval) - rowval[(1 : nnzX[i]) .+ nnz_sofar] = XI.rowval - nzval[(1 : nnzX[i]) .+ nnz_sofar] = XI.nzval + colptr[(1 : nX[i] + 1) .+ nX_sofar] = getcolptr(XI) .+ nnz_sofar + if nnzX[i] == length(rowvals(XI)) + rowval[(1 : nnzX[i]) .+ nnz_sofar] = rowvals(XI) + nzval[(1 : nnzX[i]) .+ nnz_sofar] = nonzeros(XI) else - rowval[(1 : nnzX[i]) .+ nnz_sofar] = XI.rowval[1:nnzX[i]] - nzval[(1 : nnzX[i]) .+ nnz_sofar] = XI.nzval[1:nnzX[i]] + rowval[(1 : nnzX[i]) .+ nnz_sofar] = rowvals(XI)[1:nnzX[i]] + nzval[(1 : nnzX[i]) .+ nnz_sofar] = nonzeros(XI)[1:nnzX[i]] end nnz_sofar += nnzX[i] nX_sofar += nX[i] @@ -3251,8 +3252,8 @@ function blockdiag(X::SparseMatrixCSC...) m = sum(mX) n = sum(nX) - Tv = promote_type(map(x->eltype(x.nzval), X)...) - Ti = isempty(X) ? Int : promote_type(map(x->eltype(x.rowval), X)...) + Tv = promote_type(map(x->eltype(nonzeros(x)), X)...) + Ti = isempty(X) ? Int : promote_type(map(x->eltype(rowvals(x)), X)...) colptr = Vector{Ti}(undef, n+1) nnzX = Int[ nnz(x) for x in X ] @@ -3264,9 +3265,9 @@ function blockdiag(X::SparseMatrixCSC...) nX_sofar = 0 mX_sofar = 0 for i = 1 : num - colptr[(1 : nX[i] + 1) .+ nX_sofar] = X[i].colptr .+ nnz_sofar - rowval[(1 : nnzX[i]) .+ nnz_sofar] = X[i].rowval .+ mX_sofar - nzval[(1 : nnzX[i]) .+ nnz_sofar] = X[i].nzval + colptr[(1 : nX[i] + 1) .+ nX_sofar] = getcolptr(X[i]) .+ nnz_sofar + rowval[(1 : nnzX[i]) .+ nnz_sofar] = rowvals(X[i]) .+ mX_sofar + nzval[(1 : nnzX[i]) .+ nnz_sofar] = nonzeros(X[i]) nnz_sofar += nnzX[i] nX_sofar += nX[i] mX_sofar += mX[i] @@ -3285,11 +3286,11 @@ function is_hermsym(A::SparseMatrixCSC, check::Function) m, n = size(A) if m != n; return false; end - colptr = A.colptr - rowval = A.rowval - nzval = A.nzval - tracker = copy(A.colptr) - for col = 1:A.n + colptr = getcolptr(A) + rowval = rowvals(A) + nzval = nonzeros(A) + tracker = copy(getcolptr(A)) + for col = 1:size(A, 2) # `tracker` is updated such that, for symmetric matrices, # the loop below starts from an element at or below the # diagonal element of column `col`" @@ -3358,9 +3359,9 @@ end function istriu(A::SparseMatrixCSC) m, n = size(A) - colptr = A.colptr - rowval = A.rowval - nzval = A.nzval + colptr = getcolptr(A) + rowval = rowvals(A) + nzval = nonzeros(A) for col = 1:min(n, m-1) l1 = colptr[col+1]-1 @@ -3378,9 +3379,9 @@ end function istril(A::SparseMatrixCSC) m, n = size(A) - colptr = A.colptr - rowval = A.rowval - nzval = A.nzval + colptr = getcolptr(A) + rowval = rowvals(A) + nzval = nonzeros(A) for col = 2:n for i = colptr[col] : (colptr[col+1]-1) @@ -3481,13 +3482,13 @@ function diag(A::SparseMatrixCSC{Tv,Ti}, d::Integer=0) where {Tv,Ti} val = Vector{Tv}() for i in 1:l r += 1; c += 1 - r1 = Int(A.colptr[c]) - r2 = Int(A.colptr[c+1]-1) + r1 = Int(getcolptr(A)[c]) + r2 = Int(getcolptr(A)[c+1]-1) r1 > r2 && continue - r1 = searchsortedfirst(A.rowval, r, r1, r2, Forward) - ((r1 > r2) || (A.rowval[r1] != r)) && continue + r1 = searchsortedfirst(rowvals(A), r, r1, r2, Forward) + ((r1 > r2) || (rowvals(A)[r1] != r)) && continue push!(ind, i) - push!(val, A.nzval[r1]) + push!(val, nonzeros(A)[r1]) end return SparseVector{Tv,Ti}(l, ind, val) end @@ -3508,14 +3509,14 @@ end function sortSparseMatrixCSC!(A::SparseMatrixCSC{Tv,Ti}; sortindices::Symbol = :sortcols) where {Tv,Ti} if sortindices == :doubletranspose nB, mB = size(A) - B = SparseMatrixCSC(mB, nB, Vector{Ti}(undef, nB+1), similar(A.rowval), similar(A.nzval)) + B = SparseMatrixCSC(mB, nB, Vector{Ti}(undef, nB+1), similar(rowvals(A)), similar(nonzeros(A))) transpose!(B, A) transpose!(A, B) return A end m, n = size(A) - colptr = A.colptr; rowval = A.rowval; nzval = A.nzval + colptr = getcolptr(A); rowval = rowvals(A); nzval = nonzeros(A) index = zeros(Ti, m) row = zeros(Ti, m) @@ -3610,39 +3611,39 @@ end ## circular shift function circshift!(O::SparseMatrixCSC, X::SparseMatrixCSC, (r,c)::Base.DimsInteger{2}) - nnz = length(X.nzval) + nnz = length(nonzeros(X)) iszero(nnz) && return copy!(O, X) ##### column shift - c = mod(c, X.n) + c = mod(c, size(X, 2)) if iszero(c) copy!(O, X) else ##### readjust output - resize!(O.colptr, X.n + 1) - resize!(O.rowval, nnz) - resize!(O.nzval, nnz) - O.colptr[X.n + 1] = nnz + 1 + resize!(getcolptr(O), size(X, 2) + 1) + resize!(rowvals(O), nnz) + resize!(nonzeros(O), nnz) + getcolptr(O)[size(X, 2) + 1] = nnz + 1 # exchange left and right blocks - nleft = X.colptr[X.n - c + 1] - 1 + nleft = getcolptr(X)[size(X, 2) - c + 1] - 1 nright = nnz - nleft - @inbounds for i=c+1:X.n - O.colptr[i] = X.colptr[i-c] + nright + @inbounds for i=c+1:size(X, 2) + getcolptr(O)[i] = getcolptr(X)[i-c] + nright end @inbounds for i=1:c - O.colptr[i] = X.colptr[X.n - c + i] - nleft + getcolptr(O)[i] = getcolptr(X)[size(X, 2) - c + i] - nleft end # rotate rowval and nzval by the right number of elements - circshift!(O.rowval, X.rowval, (nright,)) - circshift!(O.nzval, X.nzval, (nright,)) + circshift!(rowvals(O), rowvals(X), (nright,)) + circshift!(nonzeros(O), nonzeros(X), (nright,)) end ##### row shift - r = mod(r, X.m) + r = mod(r, size(X, 1)) iszero(r) && return O - @inbounds for i=1:O.n - subvector_shifter!(O.rowval, O.nzval, O.colptr[i], O.colptr[i+1]-1, O.m, r) + @inbounds for i=1:size(O, 2) + subvector_shifter!(rowvals(O), nonzeros(O), getcolptr(O)[i], getcolptr(O)[i+1]-1, size(O, 1), r) end return O end diff --git a/stdlib/SparseArrays/src/sparsevector.jl b/stdlib/SparseArrays/src/sparsevector.jl index b0efff372618b..10f14ed338545 100644 --- a/stdlib/SparseArrays/src/sparsevector.jl +++ b/stdlib/SparseArrays/src/sparsevector.jl @@ -38,24 +38,23 @@ const AdjOrTransSparseVectorUnion{T} = LinearAlgebra.AdjOrTrans{T, <:SparseVecto ### Basic properties -length(x::SparseVector) = x.n -size(x::SparseVector) = (x.n,) -nnz(x::SparseVector) = length(x.nzval) -count(f, x::SparseVector) = count(f, x.nzval) + f(zero(eltype(x)))*(length(x) - nnz(x)) +size(x::SparseVector) = (getfield(x, :n),) +nnz(x::SparseVector) = length(nonzeros(x)) +count(f, x::SparseVector) = count(f, nonzeros(x)) + f(zero(eltype(x)))*(length(x) - nnz(x)) -nonzeros(x::SparseVector) = x.nzval +nonzeros(x::SparseVector) = getfield(x, :nzval) function nonzeros(x::SparseColumnView) rowidx, colidx = parentindices(x) A = parent(x) - @inbounds y = view(A.nzval, nzrange(A, colidx)) + @inbounds y = view(nonzeros(A), nzrange(A, colidx)) return y end -nonzeroinds(x::SparseVector) = x.nzind +nonzeroinds(x::SparseVector) = getfield(x, :nzind) function nonzeroinds(x::SparseColumnView) rowidx, colidx = parentindices(x) A = parent(x) - @inbounds y = view(A.rowval, nzrange(A, colidx)) + @inbounds y = view(rowvals(A), nzrange(A, colidx)) return y end @@ -69,13 +68,13 @@ end # # parent method for similar that preserves stored-entry structure (for when new and old dims match) _sparsesimilar(S::SparseVector, ::Type{TvNew}, ::Type{TiNew}) where {TvNew,TiNew} = - SparseVector(S.n, copyto!(similar(S.nzind, TiNew), S.nzind), similar(S.nzval, TvNew)) + SparseVector(length(S), copyto!(similar(nonzeroinds(S), TiNew), nonzeroinds(S)), similar(nonzeros(S), TvNew)) # parent method for similar that preserves nothing (for when old and new dims differ, and new is 1d) _sparsesimilar(S::SparseVector, ::Type{TvNew}, ::Type{TiNew}, dims::Dims{1}) where {TvNew,TiNew} = - SparseVector(dims..., similar(S.nzind, TiNew, 0), similar(S.nzval, TvNew, 0)) + SparseVector(dims..., similar(nonzeroinds(S), TiNew, 0), similar(nonzeros(S), TvNew, 0)) # parent method for similar that preserves storage space (for old and new dims differ, and new is 2d) _sparsesimilar(S::SparseVector, ::Type{TvNew}, ::Type{TiNew}, dims::Dims{2}) where {TvNew,TiNew} = - SparseMatrixCSC(dims..., fill(one(TiNew), last(dims)+1), similar(S.nzind, TiNew), similar(S.nzval, TvNew)) + SparseMatrixCSC(dims..., fill(one(TiNew), last(dims)+1), similar(nonzeroinds(S), TiNew), similar(nonzeros(S), TvNew)) # The following methods hook into the AbstractArray similar hierarchy. The first method # covers similar(A[, Tv]) calls, which preserve stored-entry structure, and the latter # methods cover similar(A[, Tv], shape...) calls, which preserve nothing if the dims @@ -100,8 +99,8 @@ similar(S::SparseVector, ::Type{TvNew}, ::Type{TiNew}, m::Integer, n::Integer) w ## Alias detection and prevention using Base: dataids, unaliascopy -Base.dataids(S::SparseVector) = (dataids(S.nzind)..., dataids(S.nzval)...) -Base.unaliascopy(S::SparseVector) = typeof(S)(S.n, unaliascopy(S.nzind), unaliascopy(S.nzval)) +Base.dataids(S::SparseVector) = (dataids(nonzeroinds(S))..., dataids(nonzeros(S))...) +Base.unaliascopy(S::SparseVector) = typeof(S)(length(S), unaliascopy(nonzeroinds(S)), unaliascopy(nonzeros(S))) ### Construct empty sparse vector @@ -109,7 +108,7 @@ spzeros(len::Integer) = spzeros(Float64, len) spzeros(::Type{T}, len::Integer) where {T} = SparseVector(len, Int[], T[]) spzeros(::Type{Tv}, ::Type{Ti}, len::Integer) where {Tv,Ti<:Integer} = SparseVector(len, Ti[], Tv[]) -LinearAlgebra.fillstored!(x::SparseVector, y) = (fill!(x.nzval, y); x) +LinearAlgebra.fillstored!(x::SparseVector, y) = (fill!(nonzeros(x), y); x) ### Construction from lists of indices and values @@ -335,14 +334,14 @@ julia> SparseArrays.dropstored!(x, 2) ``` """ function dropstored!(x::SparseVector, i::Integer) - if !(1 <= i <= x.n) + if !(1 <= i <= length(x::SparseVector)) throw(BoundsError(x, i)) end - searchk = searchsortedfirst(x.nzind, i) - if searchk <= length(x.nzind) && x.nzind[searchk] == i + searchk = searchsortedfirst(nonzeroinds(x), i) + if searchk <= length(nonzeroinds(x)) && nonzeroinds(x)[searchk] == i # Entry x[i] is stored. Drop and return. - deleteat!(x.nzind, searchk) - deleteat!(x.nzval, searchk) + deleteat!(nonzeroinds(x), searchk) + deleteat!(nonzeros(x), searchk) end return x end @@ -355,7 +354,7 @@ end # convert SparseMatrixCSC to SparseVector function SparseVector{Tv,Ti}(s::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti<:Integer} size(s, 2) == 1 || throw(ArgumentError("The input argument must have a single-column.")) - SparseVector(s.m, s.rowval, s.nzval) + SparseVector(size(s, 1), rowvals(s), nonzeros(s)) end SparseVector{Tv}(s::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = SparseVector{Tv,Ti}(s) @@ -427,10 +426,10 @@ SparseVector(s::AbstractVector{Tv}) where {Tv} = SparseVector{Tv,Int}(s) SparseVector{Tv}(s::SparseVector{Tv}) where {Tv} = s SparseVector{Tv,Ti}(s::SparseVector{Tv,Ti}) where {Tv,Ti} = s SparseVector{Tv,Ti}(s::SparseVector) where {Tv,Ti} = - SparseVector{Tv,Ti}(s.n, convert(Vector{Ti}, s.nzind), convert(Vector{Tv}, s.nzval)) + SparseVector{Tv,Ti}(length(s::SparseVector), convert(Vector{Ti}, nonzeroinds(s)), convert(Vector{Tv}, nonzeros(s))) SparseVector{Tv}(s::SparseVector{<:Any,Ti}) where {Tv,Ti} = - SparseVector{Tv,Ti}(s.n, s.nzind, convert(Vector{Tv}, s.nzval)) + SparseVector{Tv,Ti}(length(s::SparseVector), nonzeroinds(s), convert(Vector{Tv}, nonzeros(s))) convert(T::Type{<:SparseVector}, m::AbstractVector) = m isa T ? m : T(m) @@ -443,30 +442,30 @@ function prep_sparsevec_copy_dest!(A::SparseVector, lB, nnzB) lA >= lB || throw(BoundsError()) # If the two vectors have the same length then all the elements in A will be overwritten. if length(A) == lB - resize!(A.nzval, nnzB) - resize!(A.nzind, nnzB) + resize!(nonzeros(A), nnzB) + resize!(nonzeroinds(A), nnzB) else nnzA = nnz(A) - lastmodindA = searchsortedlast(A.nzind, lB) + lastmodindA = searchsortedlast(nonzeroinds(A), lB) if lastmodindA >= nnzB # A will have fewer non-zero elements; unmodified elements are kept at the end. - deleteat!(A.nzind, nnzB+1:lastmodindA) - deleteat!(A.nzval, nnzB+1:lastmodindA) + deleteat!(nonzeroinds(A), nnzB+1:lastmodindA) + deleteat!(nonzeros(A), nnzB+1:lastmodindA) else # A will have more non-zero elements; unmodified elements are kept at the end. - resize!(A.nzind, nnzB + nnzA - lastmodindA) - resize!(A.nzval, nnzB + nnzA - lastmodindA) - copyto!(A.nzind, nnzB+1, A.nzind, lastmodindA+1, nnzA-lastmodindA) - copyto!(A.nzval, nnzB+1, A.nzval, lastmodindA+1, nnzA-lastmodindA) + resize!(nonzeroinds(A), nnzB + nnzA - lastmodindA) + resize!(nonzeros(A), nnzB + nnzA - lastmodindA) + copyto!(nonzeroinds(A), nnzB+1, nonzeroinds(A), lastmodindA+1, nnzA-lastmodindA) + copyto!(nonzeros(A), nnzB+1, nonzeros(A), lastmodindA+1, nnzA-lastmodindA) end end end function copyto!(A::SparseVector, B::SparseVector) prep_sparsevec_copy_dest!(A, length(B), nnz(B)) - copyto!(A.nzind, B.nzind) - copyto!(A.nzval, B.nzval) + copyto!(nonzeroinds(A), nonzeroinds(B)) + copyto!(nonzeros(A), nonzeros(B)) return A end @@ -476,21 +475,21 @@ function copyto!(A::SparseVector, B::SparseMatrixCSC) prep_sparsevec_copy_dest!(A, length(B), nnz(B)) ptr = 1 - @assert length(A.nzind) >= length(B.rowval) - maximum(B.colptr)-1 <= length(B.rowval) || throw(BoundsError()) - @inbounds for col=1:length(B.colptr)-1 - offsetA = (col - 1) * B.m - while ptr <= B.colptr[col+1]-1 - A.nzind[ptr] = B.rowval[ptr] + offsetA + @assert length(nonzeroinds(A)) >= length(rowvals(B)) + maximum(getcolptr(B))-1 <= length(rowvals(B)) || throw(BoundsError()) + @inbounds for col=1:length(getcolptr(B))-1 + offsetA = (col - 1) * size(B, 1) + while ptr <= getcolptr(B)[col+1]-1 + nonzeroinds(A)[ptr] = rowvals(B)[ptr] + offsetA ptr += 1 end end - copyto!(A.nzval, B.nzval) + copyto!(nonzeros(A), nonzeros(B)) return A end copyto!(A::SparseMatrixCSC, B::SparseVector{TvB,TiB}) where {TvB,TiB} = - copyto!(A, SparseMatrixCSC{TvB,TiB}(B.n, 1, TiB[1, length(B.nzind)+1], B.nzind, B.nzval)) + copyto!(A, SparseMatrixCSC{TvB,TiB}(length(B), 1, TiB[1, length(nonzeroinds(B))+1], nonzeroinds(B), nonzeros(B))) ### Rand Construction @@ -525,26 +524,26 @@ sprandn(r::AbstractRNG, ::Type{T}, n::Integer, p::AbstractFloat) where T = spran # Column slices function getindex(x::SparseMatrixCSC, ::Colon, j::Integer) checkbounds(x, :, j) - r1 = convert(Int, x.colptr[j]) - r2 = convert(Int, x.colptr[j+1]) - 1 - SparseVector(x.m, x.rowval[r1:r2], x.nzval[r1:r2]) + r1 = convert(Int, getcolptr(x)[j]) + r2 = convert(Int, getcolptr(x)[j+1]) - 1 + SparseVector(size(x, 1), rowvals(x)[r1:r2], nonzeros(x)[r1:r2]) end function getindex(x::SparseMatrixCSC, I::AbstractUnitRange, j::Integer) checkbounds(x, I, j) # Get the selected column - c1 = convert(Int, x.colptr[j]) - c2 = convert(Int, x.colptr[j+1]) - 1 + c1 = convert(Int, getcolptr(x)[j]) + c2 = convert(Int, getcolptr(x)[j+1]) - 1 # Restrict to the selected rows - r1 = searchsortedfirst(x.rowval, first(I), c1, c2, Forward) - r2 = searchsortedlast(x.rowval, last(I), c1, c2, Forward) - SparseVector(length(I), [x.rowval[i] - first(I) + 1 for i = r1:r2], x.nzval[r1:r2]) + r1 = searchsortedfirst(rowvals(x), first(I), c1, c2, Forward) + r2 = searchsortedlast(rowvals(x), last(I), c1, c2, Forward) + SparseVector(length(I), [rowvals(x)[i] - first(I) + 1 for i = r1:r2], nonzeros(x)[r1:r2]) end # In the general case, we piggy back upon SparseMatrixCSC's optimized solution @inline function getindex(A::SparseMatrixCSC, I::AbstractVector, J::Integer) M = A[I, [J]] - SparseVector(M.m, M.rowval, M.nzval) + SparseVector(size(M, 1), rowvals(M), nonzeros(M)) end # Row slices @@ -553,7 +552,7 @@ function Base.getindex(A::SparseMatrixCSC{Tv,Ti}, i::Integer, J::AbstractVector) require_one_based_indexing(A, J) checkbounds(A, i, J) nJ = length(J) - colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval + colptrA = getcolptr(A); rowvalA = rowvals(A); nzvalA = nonzeros(A) nzinds = Vector{Ti}() nzvals = Vector{Tv}() @@ -589,17 +588,17 @@ function _logical_index(A::SparseMatrixCSC{Tv}, I::AbstractArray{Bool}) where Tv n = sum(I) nnzB = min(n, nnz(A)) - colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval + colptrA = getcolptr(A); rowvalA = rowvals(A); nzvalA = nonzeros(A) rowvalB = Vector{Int}(undef, nnzB) nzvalB = Vector{Tv}(undef, nnzB) c = 1 rowB = 1 - @inbounds for col in 1:A.n + @inbounds for col in 1:size(A, 2) r1 = colptrA[col] r2 = colptrA[col+1]-1 - for row in 1:A.m + for row in 1:size(A, 1) if I[row, col] while (r1 <= r2) && (rowvalA[r1] < row) r1 += 1 @@ -630,9 +629,9 @@ function getindex(A::SparseMatrixCSC{Tv}, I::AbstractUnitRange) where Tv checkbounds(A, I) szA = size(A) nA = szA[1]*szA[2] - colptrA = A.colptr - rowvalA = A.rowval - nzvalA = A.nzval + colptrA = getcolptr(A) + rowvalA = rowvals(A) + nzvalA = nonzeros(A) n = length(I) nnzB = min(n, nnz(A)) @@ -666,9 +665,9 @@ function getindex(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVector) where {Tv,Ti} require_one_based_indexing(A, I) szA = size(A) nA = szA[1]*szA[2] - colptrA = A.colptr - rowvalA = A.rowval - nzvalA = A.nzval + colptrA = getcolptr(A) + rowvalA = rowvals(A) + nzvalA = nonzeros(A) n = length(I) nnzB = min(n, nnz(A)) @@ -713,8 +712,8 @@ function findall(p::Function, x::SparseVector{<:Any,Ti}) where Ti numnz = nnz(x) I = Vector{Ti}(undef, numnz) - nzind = x.nzind - nzval = x.nzval + nzind = nonzeroinds(x) + nzval = nonzeros(x) count = 1 @inbounds for i = 1 : numnz @@ -740,8 +739,8 @@ function findnz(x::SparseVector{Tv,Ti}) where {Tv,Ti} I = Vector{Ti}(undef, numnz) V = Vector{Tv}(undef, numnz) - nzind = x.nzind - nzval = x.nzval + nzind = nonzeroinds(x) + nzval = nonzeros(x) @inbounds for i = 1 : numnz I[i] = nzind[i] @@ -752,20 +751,20 @@ function findnz(x::SparseVector{Tv,Ti}) where {Tv,Ti} end function _sparse_findnextnz(v::SparseVector, i::Integer) - n = searchsortedfirst(v.nzind, i) - if n > length(v.nzind) + n = searchsortedfirst(nonzeroinds(v), i) + if n > length(nonzeroinds(v)) return nothing else - return v.nzind[n] + return nonzeroinds(v)[n] end end function _sparse_findprevnz(v::SparseVector, i::Integer) - n = searchsortedlast(v.nzind, i) + n = searchsortedlast(nonzeroinds(v), i) if iszero(n) return nothing else - return v.nzind[n] + return nonzeroinds(v)[n] end end @@ -818,13 +817,13 @@ getindex(x::AbstractSparseVector, I::AbstractVector{Bool}) = x[findall(I)] getindex(x::AbstractSparseVector, I::AbstractArray{Bool}) = x[findall(I)] @inline function getindex(x::AbstractSparseVector{Tv,Ti}, I::AbstractVector) where {Tv,Ti} # SparseMatrixCSC has a nicely optimized routine for this; punt - S = SparseMatrixCSC(x.n, 1, Ti[1,length(x.nzind)+1], x.nzind, x.nzval) + S = SparseMatrixCSC(length(x::SparseVector), 1, Ti[1,length(nonzeroinds(x))+1], nonzeroinds(x), nonzeros(x)) S[I, 1] end function getindex(x::AbstractSparseVector{Tv,Ti}, I::AbstractArray) where {Tv,Ti} # punt to SparseMatrixCSC - S = SparseMatrixCSC(x.n, 1, Ti[1,length(x.nzind)+1], x.nzind, x.nzval) + S = SparseMatrixCSC(length(x::SparseVector), 1, Ti[1,length(nonzeroinds(x))+1], nonzeroinds(x), nonzeros(x)) S[I] end @@ -1655,9 +1654,9 @@ function mul!(y::AbstractVector, A::SparseMatrixCSC, x::AbstractSparseVector, α xnzind = nonzeroinds(x) xnzval = nonzeros(x) - Acolptr = A.colptr - Arowval = A.rowval - Anzval = A.nzval + Acolptr = getcolptr(A) + Arowval = rowvals(A) + Anzval = nonzeros(A) @inbounds for i = 1:length(xnzind) v = xnzval[i] @@ -1700,9 +1699,9 @@ function _At_or_Ac_mul_B!(tfun::Function, xnzind = nonzeroinds(x) xnzval = nonzeros(x) - Acolptr = A.colptr - Arowval = A.rowval - Anzval = A.nzval + Acolptr = getcolptr(A) + Arowval = rowvals(A) + Anzval = nonzeros(A) mx = length(xnzind) for j = 1:n @@ -1739,9 +1738,9 @@ function _At_or_Ac_mul_B(tfun::Function, A::SparseMatrixCSC{TvA,TiA}, x::Abstrac xnzind = nonzeroinds(x) xnzval = nonzeros(x) - Acolptr = A.colptr - Arowval = A.rowval - Anzval = A.nzval + Acolptr = getcolptr(A) + Arowval = rowvals(A) + Anzval = nonzeros(A) mx = length(xnzind) ynzind = Vector{Ti}(undef, n) @@ -1806,8 +1805,8 @@ for isunittri in (true, false), islowertri in (true, false) # operate on solely b[nzrange] for efficiency. if nnz(b) != 0 nzrange = $( (islowertri && !istrans) || (!islowertri && istrans) ? - :(b.nzind[1]:b.n) : - :(1:b.nzind[end]) ) + :(nonzeroinds(b)[1]:length(b::SparseVector)) : + :(1:nonzeroinds(b)[end]) ) nzrangeviewr = view(r, nzrange) nzrangeviewA = $tritype(view(A.data, nzrange, nzrange)) LinearAlgebra.ldiv!($xformop(convert(AbstractArray{TAb}, nzrangeviewA)), nzrangeviewr) @@ -1849,9 +1848,9 @@ for isunittri in (true, false), islowertri in (true, false) # furthermore we operate on that section as a dense vector # such that dispatch has a chance to exploit, e.g., tuned BLAS nzrange = $( (islowertri && !istrans) || (!islowertri && istrans) ? - :(b.nzind[1]:b.n) : - :(1:b.nzind[end]) ) - nzrangeviewbnz = view(b.nzval, nzrange .- (b.nzind[1] - 1)) + :(nonzeroinds(b)[1]:length(b::SparseVector)) : + :(1:nonzeroinds(b)[end]) ) + nzrangeviewbnz = view(nonzeros(b), nzrange .- (nonzeroinds(b)[1] - 1)) nzrangeviewA = $tritype(view(A.data, nzrange, nzrange)) LinearAlgebra.ldiv!($xformop(nzrangeviewA), nzrangeviewbnz) end @@ -1861,50 +1860,50 @@ for isunittri in (true, false), islowertri in (true, false) end # helper functions for in-place matrix division operations defined above -"Densifies `x::SparseVector` from its first nonzero (`x[x.nzind[1]]`) through its end (`x[x.n]`)." +"Densifies `x::SparseVector` from its first nonzero (`x[nonzeroinds(x)[1]]`) through its end (`x[length(x::SparseVector)]`)." function _densifyfirstnztoend!(x::SparseVector) # lengthen containers oldnnz = nnz(x) - newnnz = x.n - x.nzind[1] + 1 - resize!(x.nzval, newnnz) - resize!(x.nzind, newnnz) + newnnz = length(x::SparseVector) - nonzeroinds(x)[1] + 1 + resize!(nonzeros(x), newnnz) + resize!(nonzeroinds(x), newnnz) # redistribute nonzero values over lengthened container # initialize now-allocated zero values simultaneously nextpos = newnnz @inbounds for oldpos in oldnnz:-1:1 - nzi = x.nzind[oldpos] - nzv = x.nzval[oldpos] - newpos = nzi - x.nzind[1] + 1 - newpos < nextpos && (x.nzval[newpos+1:nextpos] .= 0) + nzi = nonzeroinds(x)[oldpos] + nzv = nonzeros(x)[oldpos] + newpos = nzi - nonzeroinds(x)[1] + 1 + newpos < nextpos && (nonzeros(x)[newpos+1:nextpos] .= 0) newpos == oldpos && break - x.nzval[newpos] = nzv + nonzeros(x)[newpos] = nzv nextpos = newpos - 1 end # finally update lengthened nzinds - x.nzind[2:end] = (x.nzind[1]+1):x.n + nonzeroinds(x)[2:end] = (nonzeroinds(x)[1]+1):length(x::SparseVector) x end -"Densifies `x::SparseVector` from its beginning (`x[1]`) through its last nonzero (`x[x.nzind[end]]`)." +"Densifies `x::SparseVector` from its beginning (`x[1]`) through its last nonzero (`x[nonzeroinds(x)[end]]`)." function _densifystarttolastnz!(x::SparseVector) # lengthen containers oldnnz = nnz(x) - newnnz = x.nzind[end] - resize!(x.nzval, newnnz) - resize!(x.nzind, newnnz) + newnnz = nonzeroinds(x)[end] + resize!(nonzeros(x), newnnz) + resize!(nonzeroinds(x), newnnz) # redistribute nonzero values over lengthened container # initialize now-allocated zero values simultaneously nextpos = newnnz @inbounds for oldpos in oldnnz:-1:1 - nzi = x.nzind[oldpos] - nzv = x.nzval[oldpos] - nzi < nextpos && (x.nzval[nzi+1:nextpos] .= 0) + nzi = nonzeroinds(x)[oldpos] + nzv = nonzeros(x)[oldpos] + nzi < nextpos && (nonzeros(x)[nzi+1:nextpos] .= 0) nzi == oldpos && (nextpos = 0; break) - x.nzval[nzi] = nzv + nonzeros(x)[nzi] = nzv nextpos = nzi - 1 end - nextpos > 0 && (x.nzval[1:nextpos] .= 0) + nextpos > 0 && (nonzeros(x)[1:nextpos] .= 0) # finally update lengthened nzinds - x.nzind[1:newnnz] = 1:newnnz + nonzeroinds(x)[1:newnnz] = 1:newnnz x end @@ -1921,9 +1920,9 @@ function sort(x::SparseVector{Tv,Ti}; kws...) where {Tv,Ti} end function fkeep!(x::SparseVector, f, trim::Bool = true) - n = x.n - nzind = x.nzind - nzval = x.nzval + n = length(x::SparseVector) + nzind = nonzeroinds(x) + nzval = nonzeros(x) x_writepos = 1 @inbounds for xk in 1:nnz(x) @@ -1955,7 +1954,7 @@ end droptol!(x::SparseVector, tol; trim::Bool = true) Removes stored values from `x` whose absolute value is less than or equal to `tol`, -optionally trimming resulting excess space from `x.nzind` and `x.nzval` when `trim` +optionally trimming resulting excess space from `nonzeroinds(x)` and `nonzeros(x)` when `trim` is `true`. """ droptol!(x::SparseVector, tol; trim::Bool = true) = fkeep!(x, (i, x) -> abs(x) > tol, trim) @@ -1964,7 +1963,7 @@ droptol!(x::SparseVector, tol; trim::Bool = true) = fkeep!(x, (i, x) -> abs(x) > dropzeros!(x::SparseVector; trim::Bool = true) Removes stored numerical zeros from `x`, optionally trimming resulting excess space from -`x.nzind` and `x.nzval` when `trim` is `true`. +`nonzeroinds(x)` and `nonzeros(x)` when `trim` is `true`. For an out-of-place version, see [`dropzeros`](@ref). For algorithmic information, see `fkeep!`. @@ -1996,29 +1995,29 @@ julia> dropzeros(A) dropzeros(x::SparseVector; trim::Bool = true) = dropzeros!(copy(x), trim = trim) function copy!(dst::SparseVector, src::SparseVector) - dst.n == src.n || throw(ArgumentError("Sparse vectors should have the same length for copy!")) - copy!(dst.nzval, src.nzval) - copy!(dst.nzind, src.nzind) + length(dst::SparseVector) == length(src::SparseVector) || throw(ArgumentError("Sparse vectors should have the same length for copy!")) + copy!(nonzeros(dst), nonzeros(src)) + copy!(nonzeroinds(dst), nonzeroinds(src)) return dst end function copy!(dst::SparseVector, src::AbstractVector) - dst.n == length(src) || throw(ArgumentError("Sparse vector should have the same length as source for copy!")) - _dense2indval!(dst.nzind, dst.nzval, src) + length(dst::SparseVector) == length(src) || throw(ArgumentError("Sparse vector should have the same length as source for copy!")) + _dense2indval!(nonzeroinds(dst), nonzeros(dst), src) return dst end function _fillnonzero!(arr::SparseMatrixCSC{Tv, Ti}, val) where {Tv,Ti} m, n = size(arr) - resize!(arr.colptr, n+1) - resize!(arr.rowval, m*n) - resize!(arr.nzval, m*n) - copyto!(arr.colptr, 1:m:n*m+1) - fill!(arr.nzval, val) + resize!(getcolptr(arr), n+1) + resize!(rowvals(arr), m*n) + resize!(nonzeros(arr), m*n) + copyto!(getcolptr(arr), 1:m:n*m+1) + fill!(nonzeros(arr), val) index = 1 @inbounds for _ in 1:n for i in 1:m - arr.rowval[index] = Ti(i) + rowvals(arr)[index] = Ti(i) index += 1 end end @@ -2026,13 +2025,13 @@ function _fillnonzero!(arr::SparseMatrixCSC{Tv, Ti}, val) where {Tv,Ti} end function _fillnonzero!(arr::SparseVector{Tv,Ti}, val) where {Tv,Ti} - n = arr.n - resize!(arr.nzind, n) - resize!(arr.nzval, n) + n = length(arr::SparseVector) + resize!(nonzeroinds(arr), n) + resize!(nonzeros(arr), n) @inbounds for i in 1:n - arr.nzind[i] = Ti(i) + nonzeroinds(arr)[i] = Ti(i) end - fill!(arr.nzval, val) + fill!(nonzeros(arr), val) arr end @@ -2041,7 +2040,7 @@ function fill!(A::Union{SparseVector, SparseMatrixCSC}, x) T = eltype(A) xT = convert(T, x) if xT == zero(T) - fill!(A.nzval, xT) + fill!(nonzeros(A), xT) else _fillnonzero!(A, xT) end @@ -2080,7 +2079,7 @@ end function circshift!(O::SparseVector, X::SparseVector, (r,)::Base.DimsInteger{1}) copy!(O, X) - subvector_shifter!(O.nzind, O.nzval, 1, length(O.nzind), O.n, mod(r, X.n)) + subvector_shifter!(nonzeroinds(O), nonzeros(O), 1, length(nonzeroinds(O)), length(O), mod(r, length(X))) return O end diff --git a/stdlib/SparseArrays/test/forbidproperties.jl b/stdlib/SparseArrays/test/forbidproperties.jl new file mode 100644 index 0000000000000..e44e7bd97e11e --- /dev/null +++ b/stdlib/SparseArrays/test/forbidproperties.jl @@ -0,0 +1,3 @@ +using SparseArrays +Base.getproperty(S::SparseMatrixCSC, ::Symbol) = error("use accessor function") +Base.getproperty(S::SparseVector, ::Symbol) = error("use accessor function") diff --git a/stdlib/SparseArrays/test/higherorderfns.jl b/stdlib/SparseArrays/test/higherorderfns.jl index edefcd34264ad..d6f31f3120642 100644 --- a/stdlib/SparseArrays/test/higherorderfns.jl +++ b/stdlib/SparseArrays/test/higherorderfns.jl @@ -10,6 +10,7 @@ using Test using SparseArrays using LinearAlgebra using Random +include("forbidproperties.jl") @testset "map[!] implementation specialized for a single (input) sparse vector/matrix" begin N, M = 10, 12 diff --git a/stdlib/SparseArrays/test/sparse.jl b/stdlib/SparseArrays/test/sparse.jl index a3acbd3cdd411..97acfd7b6ccfa 100644 --- a/stdlib/SparseArrays/test/sparse.jl +++ b/stdlib/SparseArrays/test/sparse.jl @@ -4,12 +4,14 @@ module SparseTests using Test using SparseArrays +using SparseArrays: getcolptr, nonzeroinds using LinearAlgebra using Base.Printf: @printf using Random using Test: guardseed using InteractiveUtils: @which using Dates +include("forbidproperties.jl") @testset "issparse" begin @test issparse(sparse(fill(1,5,5))) @@ -114,14 +116,14 @@ end @testset "horizontal concatenation" begin @test [se33 se33] == [Array(se33) Array(se33)] - @test length(([sp33 0I]).nzval) == 3 + @test length(nonzeros([sp33 0I])) == 3 end @testset "vertical concatenation" begin @test [se33; se33] == [Array(se33); Array(se33)] se33_32bit = convert(SparseMatrixCSC{Float32,Int32}, se33) @test [se33; se33_32bit] == [Array(se33); Array(se33_32bit)] - @test length(([sp33; 0I]).nzval) == 3 + @test length(nonzeros([sp33; 0I])) == 3 end se44 = sparse(1.0I, 4, 4) @@ -131,7 +133,7 @@ end se77 = sparse(1.0I, 7, 7) @testset "h+v concatenation" begin @test [se44 sz42 sz41; sz34 se33] == se77 - @test length(([sp33 0I; 1I 0I]).nzval) == 6 + @test length(nonzeros([sp33 0I; 1I 0I])) == 6 end @testset "blockdiag concatenation" begin @@ -491,9 +493,9 @@ end B = sprand(5, 5, 0.2) copyto!(A, B) @test A == B - @test pointer(A.nzval) != pointer(B.nzval) - @test pointer(A.rowval) != pointer(B.rowval) - @test pointer(A.colptr) != pointer(B.colptr) + @test pointer(nonzeros(A)) != pointer(nonzeros(B)) + @test pointer(rowvals(A)) != pointer(rowvals(B)) + @test pointer(getcolptr(A)) != pointer(getcolptr(B)) # Test size(A) != size(B), but length(A) == length(B) B = sprand(25, 1, 0.2) copyto!(A, B) @@ -544,8 +546,8 @@ end @testset "common error checking of [c]transpose! methods (ftranspose!)" begin @test_throws DimensionMismatch transpose!(A[:, 1:(smalldim - 1)], A) @test_throws DimensionMismatch transpose!(A[1:(smalldim - 1), 1], A) - @test_throws ArgumentError transpose!((B = similar(A); resize!(B.rowval, nnz(A) - 1); B), A) - @test_throws ArgumentError transpose!((B = similar(A); resize!(B.nzval, nnz(A) - 1); B), A) + @test_throws ArgumentError transpose!((B = similar(A); resize!(rowvals(B), nnz(A) - 1); B), A) + @test_throws ArgumentError transpose!((B = similar(A); resize!(nonzeros(B), nnz(A) - 1); B), A) end @testset "common error checking of permute[!] methods / source-perm compat" begin @test_throws DimensionMismatch permute(A, p[1:(end - 1)], q) @@ -554,17 +556,17 @@ end @testset "common error checking of permute[!] methods / source-dest compat" begin @test_throws DimensionMismatch permute!(A[1:(m - 1), :], A, p, q) @test_throws DimensionMismatch permute!(A[:, 1:(m - 1)], A, p, q) - @test_throws ArgumentError permute!((Y = copy(X); resize!(Y.rowval, nnz(A) - 1); Y), A, p, q) - @test_throws ArgumentError permute!((Y = copy(X); resize!(Y.nzval, nnz(A) - 1); Y), A, p, q) + @test_throws ArgumentError permute!((Y = copy(X); resize!(rowvals(Y), nnz(A) - 1); Y), A, p, q) + @test_throws ArgumentError permute!((Y = copy(X); resize!(nonzeros(Y), nnz(A) - 1); Y), A, p, q) end @testset "common error checking of permute[!] methods / source-workmat compat" begin @test_throws DimensionMismatch permute!(X, A, p, q, C[1:(m - 1), :]) @test_throws DimensionMismatch permute!(X, A, p, q, C[:, 1:(m - 1)]) - @test_throws ArgumentError permute!(X, A, p, q, (D = copy(C); resize!(D.rowval, nnz(A) - 1); D)) - @test_throws ArgumentError permute!(X, A, p, q, (D = copy(C); resize!(D.nzval, nnz(A) - 1); D)) + @test_throws ArgumentError permute!(X, A, p, q, (D = copy(C); resize!(rowvals(D), nnz(A) - 1); D)) + @test_throws ArgumentError permute!(X, A, p, q, (D = copy(C); resize!(nonzeros(D), nnz(A) - 1); D)) end @testset "common error checking of permute[!] methods / source-workcolptr compat" begin - @test_throws DimensionMismatch permute!(A, p, q, C, Vector{eltype(A.rowval)}(undef, length(A.colptr) - 1)) + @test_throws DimensionMismatch permute!(A, p, q, C, Vector{eltype(rowvals(A))}(undef, length(getcolptr(A)) - 1)) end @testset "common error checking of permute[!] methods / permutation validity" begin @test_throws ArgumentError permute!(A, (r = copy(p); r[2] = r[1]; r), q) @@ -594,7 +596,7 @@ end @test permute!(similar(A), A, p, q, similar(At)) == fullPAQ @test permute!(copy(A), p, q) == fullPAQ @test permute!(copy(A), p, q, similar(At)) == fullPAQ - @test permute!(copy(A), p, q, similar(At), similar(A.colptr)) == fullPAQ + @test permute!(copy(A), p, q, similar(At), similar(getcolptr(A))) == fullPAQ end end end @@ -922,7 +924,7 @@ end @test nnz(a) == 20 @test count(!iszero, a) == 11 a = copy(b) - a[1:2,:] = let c = sparse(fill(1,2,10)); fill!(c.nzval, 0); c; end + a[1:2,:] = let c = sparse(fill(1,2,10)); fill!(nonzeros(c), 0); c; end @test nnz(a) == 19 @test count(!iszero, a) == 8 a[1:2,1:3] = let c = sparse(fill(1,2,3)); c[1,2] = c[2,1] = c[2,2] = 0; c; end @@ -1346,7 +1348,7 @@ end debug = false if debug - println("row sizes: $([round(Int,nnz(S)/S.n) for S in SA])") + println("row sizes: $([round(Int,nnz(S)/size(S, 2)) for S in SA])") println("I sizes: $([length(I) for I in IA])") @printf(" S | I | binary S | binary I | linear | best\n") end @@ -1369,7 +1371,7 @@ end end if debug - @printf(" %7d | %7d | %4.2e | %4.2e | %4.2e | %s\n", round(Int,nnz(S)/S.n), length(I), times[1], times[2], times[3], + @printf(" %7d | %7d | %4.2e | %4.2e | %4.2e | %s\n", round(Int,nnz(S)/size(S, 2)), length(I), times[1], times[2], times[3], (0 == best[2]) ? "binary S" : (1 == best[2]) ? "binary I" : "linear") end if res[1] != res[2] @@ -1419,7 +1421,7 @@ end GC.gc() rs = @timed S[Isorted, Jsorted] if debug - @printf(" %7d | %7d | %7d | %4.2e | %4.2e | %4.2e | %4.2e |\n", round(Int,nnz(S)/S.n), length(I), length(J), rs[2], ru[2], rs[3], ru[3]) + @printf(" %7d | %7d | %7d | %4.2e | %4.2e | %4.2e | %4.2e |\n", round(Int,nnz(S)/size(S, 2)), length(I), length(J), rs[2], ru[2], rs[3], ru[3]) end end end @@ -1554,7 +1556,7 @@ end local A = guardseed(1234321) do triu(sprand(10, 10, 0.2)) end - @test SparseArrays.droptol!(A, 0.01).colptr == [1, 2, 2, 3, 4, 5, 5, 6, 8, 10, 13] + @test getcolptr(SparseArrays.droptol!(A, 0.01)) == [1, 2, 2, 3, 4, 5, 5, 6, 8, 10, 13] @test isequal(SparseArrays.droptol!(sparse([1], [1], [1]), 1), SparseMatrixCSC(1, 1, Int[1, 1], Int[], Int[])) end @@ -1575,9 +1577,9 @@ end Anegzeros[negzerosinds] .= -2 Abothsigns = copy(Aposzeros) Abothsigns[negzerosinds] .= -2 - map!(x -> x == 2 ? 0.0 : x, Aposzeros.nzval, Aposzeros.nzval) - map!(x -> x == -2 ? -0.0 : x, Anegzeros.nzval, Anegzeros.nzval) - map!(x -> x == 2 ? 0.0 : x == -2 ? -0.0 : x, Abothsigns.nzval, Abothsigns.nzval) + map!(x -> x == 2 ? 0.0 : x, nonzeros(Aposzeros), nonzeros(Aposzeros)) + map!(x -> x == -2 ? -0.0 : x, nonzeros(Anegzeros), nonzeros(Anegzeros)) + map!(x -> x == 2 ? 0.0 : x == -2 ? -0.0 : x, nonzeros(Abothsigns), nonzeros(Abothsigns)) for Awithzeros in (Aposzeros, Anegzeros, Abothsigns) # Basic functionality / dropzeros! @test dropzeros!(copy(Awithzeros)) == A @@ -1586,16 +1588,16 @@ end @test dropzeros(Awithzeros) == A @test dropzeros(Awithzeros, trim = false) == A # Check trimming works as expected - @test length(dropzeros!(copy(Awithzeros)).nzval) == length(A.nzval) - @test length(dropzeros!(copy(Awithzeros)).rowval) == length(A.rowval) - @test length(dropzeros!(copy(Awithzeros), trim = false).nzval) == length(Awithzeros.nzval) - @test length(dropzeros!(copy(Awithzeros), trim = false).rowval) == length(Awithzeros.rowval) + @test length(nonzeros(dropzeros!(copy(Awithzeros)))) == length(nonzeros(A)) + @test length(rowvals(dropzeros!(copy(Awithzeros)))) == length(rowvals(A)) + @test length(nonzeros(dropzeros!(copy(Awithzeros), trim = false))) == length(nonzeros(Awithzeros)) + @test length(rowvals(dropzeros!(copy(Awithzeros), trim = false))) == length(rowvals(Awithzeros)) end end # original lone dropzeros test local A = sparse([1 2 3; 4 5 6; 7 8 9]) - A.nzval[2] = A.nzval[6] = A.nzval[7] = 0 - @test dropzeros!(A).colptr == [1, 3, 5, 7] + nonzeros(A)[2] = nonzeros(A)[6] = nonzeros(A)[7] = 0 + @test getcolptr(dropzeros!(A)) == [1, 3, 5, 7] # test for issue #5169, modified for new behavior following #15242/#14798 @test nnz(sparse([1, 1], [1, 2], [0.0, -0.0])) == 2 @test nnz(dropzeros!(sparse([1, 1], [1, 2], [0.0, -0.0]))) == 0 @@ -1653,15 +1655,15 @@ end end # test that stored zeros are still stored zeros in the diagonal S = sparse([1,3],[1,3],[0.0,0.0]); V = diag(S) - @test V.nzind == [1,3] - @test V.nzval == [0.0,0.0] + @test nonzeroinds(V) == [1,3] + @test nonzeros(V) == [0.0,0.0] end @testset "expandptr" begin local A = sparse(1.0I, 5, 5) - @test SparseArrays.expandptr(A.colptr) == 1:5 + @test SparseArrays.expandptr(getcolptr(A)) == 1:5 A[1,2] = 1 - @test SparseArrays.expandptr(A.colptr) == [1; 2; 2; 3; 4; 5] + @test SparseArrays.expandptr(getcolptr(A)) == [1; 2; 2; 3; 4; 5] @test_throws ArgumentError SparseArrays.expandptr([2; 3]) end @@ -1679,7 +1681,7 @@ end @test triu(A, n + 2) == zero(A) # fkeep trim option - @test isequal(length(tril!(sparse([1,2,3], [1,2,3], [1,2,3], 3, 4), -1).rowval), 0) + @test isequal(length(rowvals(tril!(sparse([1,2,3], [1,2,3], [1,2,3], 3, 4), -1))), 0) end @testset "norm" begin @@ -1728,7 +1730,7 @@ end # explicit zeros A = sparse(ComplexF64(1)I, 5, 5) A[3,1] = 2 - A.nzval[2] = 0.0 + nonzeros(A)[2] = 0.0 @test ishermitian(A) == true @test issymmetric(A) == true @@ -1739,7 +1741,7 @@ end nzval = [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0] A = SparseMatrixCSC(m, n, colptr, rowval, nzval) @test issymmetric(A) == true - A.nzval[end - 3] = 2.0 + nonzeros(A)[end - 3] = 2.0 @test issymmetric(A) == false # 16521 @@ -1832,8 +1834,8 @@ end # the range specified in colptr do not # impact norm of a sparse matrix foo = sparse(1.0I, 4, 4) - resize!(foo.nzval, 5) - setindex!(foo.nzval, NaN, 5) + resize!(nonzeros(foo), 5) + setindex!(nonzeros(foo), NaN, 5) @test norm(foo) == 2.0 # Test (m x 1) sparse matrix @@ -2103,15 +2105,15 @@ end x = sparse(rand(3,3)) SparseArrays.dropstored!(x, 1, 1) @test x[1, 1] == 0.0 - @test x.colptr == [1, 3, 6, 9] + @test getcolptr(x) == [1, 3, 6, 9] SparseArrays.dropstored!(x, 2, 1) - @test x.colptr == [1, 2, 5, 8] + @test getcolptr(x) == [1, 2, 5, 8] @test x[2, 1] == 0.0 SparseArrays.dropstored!(x, 2, 2) - @test x.colptr == [1, 2, 4, 7] + @test getcolptr(x) == [1, 2, 4, 7] @test x[2, 2] == 0.0 SparseArrays.dropstored!(x, 2, 3) - @test x.colptr == [1, 2, 4, 6] + @test getcolptr(x) == [1, 2, 4, 6] @test x[2, 3] == 0.0 end @@ -2211,8 +2213,8 @@ end b = similar(a, Float32, Int32) c = similar(b, Float32, Int32) SparseArrays.dropstored!(b, 1, 1) - @test length(c.rowval) == 9 - @test length(c.nzval) == 9 + @test length(rowvals(c)) == 9 + @test length(nonzeros(c)) == 9 end @testset "similar with type conversion" begin @@ -2231,62 +2233,62 @@ end simA = similar(A) @test typeof(simA) == typeof(A) @test size(simA) == size(A) - @test simA.colptr == A.colptr - @test simA.rowval == A.rowval - @test length(simA.nzval) == length(A.nzval) + @test getcolptr(simA) == getcolptr(A) + @test rowvals(simA) == rowvals(A) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with entry type specification (preserves stored-entry structure) simA = similar(A, Float32) - @test typeof(simA) == SparseMatrixCSC{Float32,eltype(A.colptr)} + @test typeof(simA) == SparseMatrixCSC{Float32,eltype(getcolptr(A))} @test size(simA) == size(A) - @test simA.colptr == A.colptr - @test simA.rowval == A.rowval - @test length(simA.nzval) == length(A.nzval) + @test getcolptr(simA) == getcolptr(A) + @test rowvals(simA) == rowvals(A) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with entry and index type specification (preserves stored-entry structure) simA = similar(A, Float32, Int8) @test typeof(simA) == SparseMatrixCSC{Float32,Int8} @test size(simA) == size(A) - @test simA.colptr == A.colptr - @test simA.rowval == A.rowval - @test length(simA.nzval) == length(A.nzval) + @test getcolptr(simA) == getcolptr(A) + @test rowvals(simA) == rowvals(A) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with Dims{2} specification (preserves storage space only, not stored-entry structure) simA = similar(A, (6,6)) @test typeof(simA) == typeof(A) @test size(simA) == (6,6) - @test simA.colptr == fill(1, 6+1) - @test length(simA.rowval) == length(A.rowval) - @test length(simA.nzval) == length(A.nzval) + @test getcolptr(simA) == fill(1, 6+1) + @test length(rowvals(simA)) == length(rowvals(A)) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with entry type and Dims{2} specification (preserves storage space only) simA = similar(A, Float32, (6,6)) - @test typeof(simA) == SparseMatrixCSC{Float32,eltype(A.colptr)} + @test typeof(simA) == SparseMatrixCSC{Float32,eltype(getcolptr(A))} @test size(simA) == (6,6) - @test simA.colptr == fill(1, 6+1) - @test length(simA.rowval) == length(A.rowval) - @test length(simA.nzval) == length(A.nzval) + @test getcolptr(simA) == fill(1, 6+1) + @test length(rowvals(simA)) == length(rowvals(A)) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with entry type, index type, and Dims{2} specification (preserves storage space only) simA = similar(A, Float32, Int8, (6,6)) @test typeof(simA) == SparseMatrixCSC{Float32, Int8} @test size(simA) == (6,6) - @test simA.colptr == fill(1, 6+1) - @test length(simA.rowval) == length(A.rowval) - @test length(simA.nzval) == length(A.nzval) + @test getcolptr(simA) == fill(1, 6+1) + @test length(rowvals(simA)) == length(rowvals(A)) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with Dims{1} specification (preserves nothing) simA = similar(A, (6,)) - @test typeof(simA) == SparseVector{eltype(A.nzval),eltype(A.colptr)} + @test typeof(simA) == SparseVector{eltype(nonzeros(A)),eltype(getcolptr(A))} @test size(simA) == (6,) - @test length(simA.nzind) == 0 - @test length(simA.nzval) == 0 + @test length(nonzeroinds(simA)) == 0 + @test length(nonzeros(simA)) == 0 # test similar with entry type and Dims{1} specification (preserves nothing) simA = similar(A, Float32, (6,)) - @test typeof(simA) == SparseVector{Float32,eltype(A.colptr)} + @test typeof(simA) == SparseVector{Float32,eltype(getcolptr(A))} @test size(simA) == (6,) - @test length(simA.nzind) == 0 - @test length(simA.nzval) == 0 + @test length(nonzeroinds(simA)) == 0 + @test length(nonzeros(simA)) == 0 # test similar with entry type, index type, and Dims{1} specification (preserves nothing) simA = similar(A, Float32, Int8, (6,)) @test typeof(simA) == SparseVector{Float32,Int8} @test size(simA) == (6,) - @test length(simA.nzind) == 0 - @test length(simA.nzval) == 0 + @test length(nonzeroinds(simA)) == 0 + @test length(nonzeros(simA)) == 0 # test entry points to similar with entry type, index type, and non-Dims shape specification @test similar(A, Float32, Int8, 6, 6) == similar(A, Float32, Int8, (6, 6)) @test similar(A, Float32, Int8, 6) == similar(A, Float32, Int8, (6,)) @@ -2296,7 +2298,7 @@ end # count should throw for sparse arrays for which zero(eltype) does not exist @test_throws MethodError count(SparseMatrixCSC(2, 2, Int[1, 2, 3], Int[1, 2], Any[true, true])) @test_throws MethodError count(SparseVector(2, Int[1], Any[true])) - # count should run only over S.nzval[1:nnz(S)], not S.nzval in full + # count should run only over nonzeros(S)[1:nnz(S)], not nonzeros(S) in full @test count(SparseMatrixCSC(2, 2, Int[1, 2, 3], Int[1, 2], Bool[true, true, true])) == 2 end @@ -2629,8 +2631,8 @@ end A = SparseMatrixCSC(Complex{BigInt}[1+im 2+2im]')'[1:1, 2:2] # ...ensure it does! If necessary, the test needs to be updated to use # another mechanism to create a suitable A. - resize!(A.nzval, 2) - @assert length(A.nzval) > nnz(A) + resize!(nonzeros(A), 2) + @assert length(nonzeros(A)) > nnz(A) @test -A == fill(-2-2im, 1, 1) @test conj(A) == fill(2-2im, 1, 1) conj!(A) diff --git a/stdlib/SparseArrays/test/sparsevector.jl b/stdlib/SparseArrays/test/sparsevector.jl index 2044daa5f21cb..0437e3304293a 100644 --- a/stdlib/SparseArrays/test/sparsevector.jl +++ b/stdlib/SparseArrays/test/sparsevector.jl @@ -4,8 +4,10 @@ module SparseVectorTests using Test using SparseArrays +using SparseArrays: nonzeroinds, getcolptr using LinearAlgebra using Random +include("forbidproperties.jl") ### Data @@ -315,8 +317,8 @@ end let x = spv_x1 xc = copy(x) @test isa(xc, SparseVector{Float64,Int}) - @test x.nzind !== xc.nzval - @test x.nzval !== xc.nzval + @test nonzeroinds(x) !== nonzeros(xc) + @test nonzeros(x) !== nonzeros(xc) @test exact_equal(x, xc) end @@ -707,7 +709,7 @@ end for op in operations spresvec = op.(spvec) @test spresvec == op.(densevec) - @test all(!iszero, spresvec.nzval) + @test all(!iszero, nonzeros(spresvec)) resvaltype = typeof(op(zero(eltype(spvec)))) resindtype = SparseArrays.indtype(spvec) @test isa(spresvec, SparseVector{resvaltype,resindtype}) @@ -794,7 +796,7 @@ end end @testset "scale" begin α = 2.5 - sx = SparseVector(x.n, x.nzind, x.nzval * α) + sx = SparseVector(length(x::SparseVector), nonzeroinds(x), nonzeros(x) * α) @test exact_equal(x * α, sx) @test exact_equal(x * (α + 0.0*im), complex(sx)) @test exact_equal(α * x, sx) @@ -803,7 +805,7 @@ end @test exact_equal(α * x, sx) @test exact_equal(x .* α, sx) @test exact_equal(α .* x, sx) - @test exact_equal(x / α, SparseVector(x.n, x.nzind, x.nzval / α)) + @test exact_equal(x / α, SparseVector(length(x::SparseVector), nonzeroinds(x), nonzeros(x) / α)) xc = copy(x) @test rmul!(xc, α) === xc @@ -1001,13 +1003,13 @@ end @testset "ldiv ops with triangular matrices and sparse vecs (#14005)" begin m = 10 sparsefloatvecs = SparseVector[sprand(m, 0.4) for k in 1:3] - sparseintvecs = SparseVector[SparseVector(m, sprvec.nzind, round.(Int, sprvec.nzval*10)) for sprvec in sparsefloatvecs] - sparsecomplexvecs = SparseVector[SparseVector(m, sprvec.nzind, complex.(sprvec.nzval, sprvec.nzval)) for sprvec in sparsefloatvecs] + sparseintvecs = SparseVector[SparseVector(m, nonzeroinds(sprvec), round.(Int, nonzeros(sprvec)*10)) for sprvec in sparsefloatvecs] + sparsecomplexvecs = SparseVector[SparseVector(m, nonzeroinds(sprvec), complex.(nonzeros(sprvec), nonzeros(sprvec))) for sprvec in sparsefloatvecs] sprmat = sprand(m, m, 0.2) sparsefloatmat = I + sprmat/(2m) - sparsecomplexmat = I + SparseMatrixCSC(m, m, sprmat.colptr, sprmat.rowval, complex.(sprmat.nzval, sprmat.nzval)/(4m)) - sparseintmat = 10m*I + SparseMatrixCSC(m, m, sprmat.colptr, sprmat.rowval, round.(Int, sprmat.nzval*10)) + sparsecomplexmat = I + SparseMatrixCSC(m, m, getcolptr(sprmat), rowvals(sprmat), complex.(nonzeros(sprmat), nonzeros(sprmat))/(4m)) + sparseintmat = 10m*I + SparseMatrixCSC(m, m, getcolptr(sprmat), rowvals(sprmat), round.(Int, nonzeros(sprmat)*10)) denseintmat = I*10m + rand(1:m, m, m) densefloatmat = I + randn(m, m)/(2m) @@ -1033,7 +1035,7 @@ end spvecs = eltypevec in inttypes ? sparseintvecs : eltypevec in floattypes ? sparsefloatvecs : eltypevec in complextypes && sparsecomplexvecs - spvecs = SparseVector[SparseVector(m, spvec.nzind, convert(Vector{eltypevec}, spvec.nzval)) for spvec in spvecs] + spvecs = SparseVector[SparseVector(m, nonzeroinds(spvec), convert(Vector{eltypevec}, nonzeros(spvec))) for spvec in spvecs] for spvec in spvecs fspvec = convert(Array, spvec) @@ -1116,9 +1118,9 @@ end vnegzeros[negzerosinds] .= -2 vbothsigns = copy(vposzeros) vbothsigns[negzerosinds] .= -2 - map!(x -> x == 2 ? 0.0 : x, vposzeros.nzval, vposzeros.nzval) - map!(x -> x == -2 ? -0.0 : x, vnegzeros.nzval, vnegzeros.nzval) - map!(x -> x == 2 ? 0.0 : x == -2 ? -0.0 : x, vbothsigns.nzval, vbothsigns.nzval) + map!(x -> x == 2 ? 0.0 : x, nonzeros(vposzeros), nonzeros(vposzeros)) + map!(x -> x == -2 ? -0.0 : x, nonzeros(vnegzeros), nonzeros(vnegzeros)) + map!(x -> x == 2 ? 0.0 : x == -2 ? -0.0 : x, nonzeros(vbothsigns), nonzeros(vbothsigns)) for vwithzeros in (vposzeros, vnegzeros, vbothsigns) # Basic functionality / dropzeros! @test dropzeros!(copy(vwithzeros)) == v @@ -1127,16 +1129,16 @@ end @test dropzeros(vwithzeros) == v @test dropzeros(vwithzeros, trim = false) == v # Check trimming works as expected - @test length(dropzeros!(copy(vwithzeros)).nzval) == length(v.nzval) - @test length(dropzeros!(copy(vwithzeros)).nzind) == length(v.nzind) - @test length(dropzeros!(copy(vwithzeros), trim = false).nzval) == length(vwithzeros.nzval) - @test length(dropzeros!(copy(vwithzeros), trim = false).nzind) == length(vwithzeros.nzind) + @test length(nonzeros(dropzeros!(copy(vwithzeros)))) == length(nonzeros(v)) + @test length(nonzeroinds(dropzeros!(copy(vwithzeros)))) == length(nonzeroinds(v)) + @test length(nonzeros(dropzeros!(copy(vwithzeros), trim = false))) == length(nonzeros(vwithzeros)) + @test length(nonzeroinds(dropzeros!(copy(vwithzeros), trim = false))) == length(nonzeroinds(vwithzeros)) end end @testset "original dropzeros! test" begin xdrop = sparsevec(1:7, [3., 2., -1., 1., -2., -3., 3.], 7) - xdrop.nzval[[2, 4, 6]] .= 0.0 + nonzeros(xdrop)[[2, 4, 6]] .= 0.0 SparseArrays.dropzeros!(xdrop) @test exact_equal(xdrop, SparseVector(7, [1, 3, 5, 7], [3, -1., -2., 3.])) end @@ -1261,62 +1263,62 @@ end simA = similar(A) @test typeof(simA) == typeof(A) @test size(simA) == size(A) - @test simA.nzind == A.nzind - @test length(simA.nzval) == length(A.nzval) + @test nonzeroinds(simA) == nonzeroinds(A) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with entry type specification (preserves stored-entry structure) simA = similar(A, Float32) - @test typeof(simA) == SparseVector{Float32,eltype(A.nzind)} + @test typeof(simA) == SparseVector{Float32,eltype(nonzeroinds(A))} @test size(simA) == size(A) - @test simA.nzind == A.nzind - @test length(simA.nzval) == length(A.nzval) + @test nonzeroinds(simA) == nonzeroinds(A) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with entry and index type specification (preserves stored-entry structure) simA = similar(A, Float32, Int8) @test typeof(simA) == SparseVector{Float32,Int8} @test size(simA) == size(A) - @test simA.nzind == A.nzind - @test length(simA.nzval) == length(A.nzval) + @test nonzeroinds(simA) == nonzeroinds(A) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with Dims{1} specification (preserves nothing) simA = similar(A, (6,)) @test typeof(simA) == typeof(A) @test size(simA) == (6,) - @test length(simA.nzind) == 0 - @test length(simA.nzval) == 0 + @test length(nonzeroinds(simA)) == 0 + @test length(nonzeros(simA)) == 0 # test similar with entry type and Dims{1} specification (preserves nothing) simA = similar(A, Float32, (6,)) - @test typeof(simA) == SparseVector{Float32,eltype(A.nzind)} + @test typeof(simA) == SparseVector{Float32,eltype(nonzeroinds(A))} @test size(simA) == (6,) - @test length(simA.nzind) == 0 - @test length(simA.nzval) == 0 + @test length(nonzeroinds(simA)) == 0 + @test length(nonzeros(simA)) == 0 # test similar with entry type, index type, and Dims{1} specification (preserves nothing) simA = similar(A, Float32, Int8, (6,)) @test typeof(simA) == SparseVector{Float32,Int8} @test size(simA) == (6,) - @test length(simA.nzind) == 0 - @test length(simA.nzval) == 0 + @test length(nonzeroinds(simA)) == 0 + @test length(nonzeros(simA)) == 0 # test entry points to similar with entry type, index type, and non-Dims shape specification @test similar(A, Float32, Int8, 6, 6) == similar(A, Float32, Int8, (6, 6)) @test similar(A, Float32, Int8, 6) == similar(A, Float32, Int8, (6,)) # test similar with Dims{2} specification (preserves storage space only, not stored-entry structure) simA = similar(A, (6,6)) - @test typeof(simA) == SparseMatrixCSC{eltype(A.nzval),eltype(A.nzind)} + @test typeof(simA) == SparseMatrixCSC{eltype(nonzeros(A)),eltype(nonzeroinds(A))} @test size(simA) == (6,6) - @test simA.colptr == fill(1, 6+1) - @test length(simA.rowval) == length(A.nzind) - @test length(simA.nzval) == length(A.nzval) + @test getcolptr(simA) == fill(1, 6+1) + @test length(rowvals(simA)) == length(nonzeroinds(A)) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with entry type and Dims{2} specification (preserves storage space only) simA = similar(A, Float32, (6,6)) - @test typeof(simA) == SparseMatrixCSC{Float32,eltype(A.nzind)} + @test typeof(simA) == SparseMatrixCSC{Float32,eltype(nonzeroinds(A))} @test size(simA) == (6,6) - @test simA.colptr == fill(1, 6+1) - @test length(simA.rowval) == length(A.nzind) - @test length(simA.nzval) == length(A.nzval) + @test getcolptr(simA) == fill(1, 6+1) + @test length(rowvals(simA)) == length(nonzeroinds(A)) + @test length(nonzeros(simA)) == length(nonzeros(A)) # test similar with entry type, index type, and Dims{2} specification (preserves storage space only) simA = similar(A, Float32, Int8, (6,6)) @test typeof(simA) == SparseMatrixCSC{Float32, Int8} @test size(simA) == (6,6) - @test simA.colptr == fill(1, 6+1) - @test length(simA.rowval) == length(A.nzind) - @test length(simA.nzval) == length(A.nzval) + @test getcolptr(simA) == fill(1, 6+1) + @test length(rowvals(simA)) == length(nonzeroinds(A)) + @test length(nonzeros(simA)) == length(nonzeros(A)) end @testset "Fast operations on full column views" begin diff --git a/stdlib/Statistics/src/Statistics.jl b/stdlib/Statistics/src/Statistics.jl index d16340aaa4d30..3281376e31d2d 100644 --- a/stdlib/Statistics/src/Statistics.jl +++ b/stdlib/Statistics/src/Statistics.jl @@ -8,6 +8,7 @@ Standard library module for basic statistics functionality. module Statistics using LinearAlgebra, SparseArrays +using SparseArrays: getcolptr using Base: has_offset_axes, require_one_based_indexing @@ -1003,9 +1004,9 @@ function centralize_sumabs2!(R::AbstractArray{S}, A::SparseMatrixCSC{Tv,Ti}, mea isempty(R) || fill!(R, zero(S)) isempty(A) && return R - colptr = A.colptr - rowval = A.rowval - nzval = A.nzval + colptr = getcolptr(A) + rowval = rowvals(A) + nzval = nonzeros(A) m = size(A, 1) n = size(A, 2) diff --git a/stdlib/SuiteSparse/src/cholmod.jl b/stdlib/SuiteSparse/src/cholmod.jl index a3f2cc67267cf..20c24e7c7e2d1 100644 --- a/stdlib/SuiteSparse/src/cholmod.jl +++ b/stdlib/SuiteSparse/src/cholmod.jl @@ -20,6 +20,7 @@ import LinearAlgebra: (\), issuccess, issymmetric, ldlt, ldlt!, logdet using SparseArrays +using SparseArrays: getcolptr import Libdl export @@ -863,39 +864,39 @@ end function Sparse{Tv}(A::SparseMatrixCSC, stype::Integer) where Tv<:VTypes ## Check length of input. This should never fail but see #20024 - if length(A.colptr) <= A.n - throw(ArgumentError("length of colptr must be at least size(A,2) + 1 = $(A.n + 1) but was $(length(A.colptr))")) + if length(getcolptr(A)) <= size(A, 2) + throw(ArgumentError("length of colptr must be at least size(A,2) + 1 = $(size(A, 2) + 1) but was $(length(getcolptr(A)))")) end - if nnz(A) > length(A.rowval) - throw(ArgumentError("length of rowval is $(length(A.rowval)) but value of colptr requires length to be at least $(nnz(A))")) + if nnz(A) > length(rowvals(A)) + throw(ArgumentError("length of rowval is $(length(rowvals(A))) but value of colptr requires length to be at least $(nnz(A))")) end - if nnz(A) > length(A.nzval) - throw(ArgumentError("length of nzval is $(length(A.nzval)) but value of colptr requires length to be at least $(nnz(A))")) + if nnz(A) > length(nonzeros(A)) + throw(ArgumentError("length of nzval is $(length(nonzeros(A))) but value of colptr requires length to be at least $(nnz(A))")) end - o = allocate_sparse(A.m, A.n, nnz(A), true, true, stype, Tv) + o = allocate_sparse(size(A, 1), size(A, 2), nnz(A), true, true, stype, Tv) s = unsafe_load(pointer(o)) - for i = 1:(A.n + 1) - unsafe_store!(s.p, A.colptr[i] - 1, i) + for i = 1:(size(A, 2) + 1) + unsafe_store!(s.p, getcolptr(A)[i] - 1, i) end for i = 1:nnz(A) - unsafe_store!(s.i, A.rowval[i] - 1, i) + unsafe_store!(s.i, rowvals(A)[i] - 1, i) end if Tv <: Complex && stype != 0 # Need to remove any non real elements in the diagonal because, in contrast to # BLAS/LAPACK these are not ignored by CHOLMOD. If even tiny imaginary parts are # present CHOLMOD will fail with a non-positive definite/zero pivot error. - for j = 1:A.n - for ip = A.colptr[j]:A.colptr[j + 1] - 1 - v = A.nzval[ip] - unsafe_store!(s.x, A.rowval[ip] == j ? Complex(real(v)) : v, ip) + for j = 1:size(A, 2) + for ip = getcolptr(A)[j]:getcolptr(A)[j + 1] - 1 + v = nonzeros(A)[ip] + unsafe_store!(s.x, rowvals(A)[ip] == j ? Complex(real(v)) : v, ip) end end - elseif Tv == eltype(A.nzval) - unsafe_copyto!(s.x, pointer(A.nzval), nnz(A)) + elseif Tv == eltype(nonzeros(A)) + unsafe_copyto!(s.x, pointer(nonzeros(A)), nnz(A)) else for i = 1:nnz(A) - unsafe_store!(s.x, A.nzval[i], i) + unsafe_store!(s.x, nonzeros(A)[i], i) end end @@ -1195,12 +1196,12 @@ function getLd!(S::SparseMatrixCSC) fill!(d, 0) col = 1 for k = 1:nnz(S) - while k >= S.colptr[col+1] + while k >= getcolptr(S)[col+1] col += 1 end - if S.rowval[k] == col - d[col] = S.nzval[k] - S.nzval[k] = 1 + if rowvals(S)[k] == col + d[col] = nonzeros(S)[k] + nonzeros(S)[k] = 1 end end S, d diff --git a/stdlib/SuiteSparse/src/spqr.jl b/stdlib/SuiteSparse/src/spqr.jl index 22d1d6c434cf2..88a4522520fd8 100644 --- a/stdlib/SuiteSparse/src/spqr.jl +++ b/stdlib/SuiteSparse/src/spqr.jl @@ -23,7 +23,8 @@ const ORDERING_BESTAMD = Int32(9) # try COLAMD and AMD; pick best# # tried. If there is a high fill-in with AMD then try METIS(A'A) and take # the best of AMD and METIS. METIS is not tried if it isn't installed. -using SparseArrays: SparseMatrixCSC, nnz +using SparseArrays +using SparseArrays: getcolptr using ..SuiteSparse.CHOLMOD using ..SuiteSparse.CHOLMOD: change_stype!, free! @@ -157,7 +158,11 @@ function LinearAlgebra.qr(A::SparseMatrixCSC{Tv}; tol = _default_tol(A)) where { R_ = SparseMatrixCSC(Sparse(R[])) return QRSparse(SparseMatrixCSC(Sparse(H[])), vec(Array(CHOLMOD.Dense(HTau[]))), - SparseMatrixCSC(min(size(A)...), R_.n, R_.colptr, R_.rowval, R_.nzval), + SparseMatrixCSC(min(size(A)...), + size(R_, 2), + getcolptr(R_), + rowvals(R_), + nonzeros(R_)), p, hpinv) end @@ -345,7 +350,7 @@ end _ret_size(F::QRSparse, b::AbstractVector) = (size(F, 2),) _ret_size(F::QRSparse, B::AbstractMatrix) = (size(F, 2), size(B, 2)) -LinearAlgebra.rank(F::QRSparse) = reduce(max, view(F.R.rowval, 1:nnz(F.R)), init = eltype(F.R.rowval)(0)) +LinearAlgebra.rank(F::QRSparse) = reduce(max, view(rowvals(F.R), 1:nnz(F.R)), init = eltype(rowvals(F.R))(0)) LinearAlgebra.rank(S::SparseMatrixCSC) = rank(qr(S)) function (\)(F::QRSparse{T}, B::VecOrMat{Complex{T}}) where T<:LinearAlgebra.BlasReal diff --git a/stdlib/SuiteSparse/src/umfpack.jl b/stdlib/SuiteSparse/src/umfpack.jl index 23c0708fb72d8..155cbe2ab53ef 100644 --- a/stdlib/SuiteSparse/src/umfpack.jl +++ b/stdlib/SuiteSparse/src/umfpack.jl @@ -9,6 +9,7 @@ using LinearAlgebra import LinearAlgebra: Factorization, det, lu, ldiv! using SparseArrays +using SparseArrays: getcolptr import SparseArrays: nnz import Serialization: AbstractSerializer, deserialize @@ -151,11 +152,11 @@ The relation between `F` and `A` is `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{ComplexF64}` as appropriate. """ function lu(S::SparseMatrixCSC{<:UMFVTypes,<:UMFITypes}; check::Bool = true) - zerobased = S.colptr[1] == 0 - res = UmfpackLU(C_NULL, C_NULL, S.m, S.n, - zerobased ? copy(S.colptr) : decrement(S.colptr), - zerobased ? copy(S.rowval) : decrement(S.rowval), - copy(S.nzval), 0) + zerobased = getcolptr(S)[1] == 0 + res = UmfpackLU(C_NULL, C_NULL, size(S, 1), size(S, 2), + zerobased ? copy(getcolptr(S)) : decrement(getcolptr(S)), + zerobased ? copy(rowvals(S)) : decrement(rowvals(S)), + copy(nonzeros(S)), 0) finalizer(umfpack_free_symbolic, res) umfpack_numeric!(res) check && (issuccess(res) || throw(LinearAlgebra.SingularException(0))) diff --git a/stdlib/SuiteSparse/test/cholmod.jl b/stdlib/SuiteSparse/test/cholmod.jl index 7e5bb0a67a71c..a19fafd3e9f99 100644 --- a/stdlib/SuiteSparse/test/cholmod.jl +++ b/stdlib/SuiteSparse/test/cholmod.jl @@ -6,6 +6,8 @@ using Test using Random using Serialization using LinearAlgebra: issuccess, PosDefException +using SparseArrays +using SparseArrays: getcolptr # CHOLMOD tests Random.seed!(123) @@ -330,11 +332,11 @@ end A1Sparse = CHOLMOD.Sparse(A1) A2Sparse = CHOLMOD.Sparse(A2) A1pdSparse = CHOLMOD.Sparse( - A1pd.m, - A1pd.n, - SuiteSparse.decrement(A1pd.colptr), - SuiteSparse.decrement(A1pd.rowval), - A1pd.nzval) + size(A1pd, 1), + size(A1pd, 2), + SuiteSparse.decrement(getcolptr(A1pd)), + SuiteSparse.decrement(rowvals(A1pd)), + nonzeros(A1pd)) ## High level interface @test isa(CHOLMOD.Sparse(3, 3, [0,1,3,4], [0,2,1,2], fill(1., 4)), CHOLMOD.Sparse) # Sparse doesn't require columns to be sorted @@ -766,7 +768,8 @@ end @testset "Check inputs to Sparse. Related to #20024" for A_ in ( SparseMatrixCSC(2, 2, [1, 2, 3], CHOLMOD.SuiteSparse_long[1,2], Float64[]), SparseMatrixCSC(2, 2, [1, 2, 3], CHOLMOD.SuiteSparse_long[1,2], Float64[1.0])) - @test_throws ArgumentError CHOLMOD.Sparse(size(A_)..., A_.colptr .- 1, A_.rowval .- 1, A_.nzval) + args = (size(A_)..., getcolptr(A_) .- 1, rowvals(A_) .- 1, nonzeros(A_)) + @test_throws ArgumentError CHOLMOD.Sparse(args...) @test_throws ArgumentError CHOLMOD.Sparse(A_) end