From c93ed16a093e33fe9e0de153120c821959641bd2 Mon Sep 17 00:00:00 2001 From: Miles Lubin Date: Sat, 25 Jan 2014 20:07:50 -0500 Subject: [PATCH] allow explicit stored zeros in SparseMatrixCSC. closes #5424 --- NEWS.md | 3 +++ base/abstractarray.jl | 1 + base/array.jl | 8 ++++---- base/bitarray.jl | 12 ++++++------ base/deprecated.jl | 7 +++++++ base/exports.jl | 3 ++- base/linalg/bitarray.jl | 2 +- base/linalg/cholmod.jl | 4 ++-- base/linalg/sparse.jl | 12 ++++++------ base/linalg/umfpack.jl | 2 +- base/multidimensional.jl | 4 ++-- base/reduce.jl | 8 ++++---- base/sparse/csparse.jl | 14 ++++++------- base/sparse/sparsematrix.jl | 39 +++++++++++++++++-------------------- doc/manual/arrays.rst | 20 ++++++++++++------- doc/stdlib/base.rst | 4 ++-- doc/stdlib/sparse.rst | 4 ++++ test/bitarray.jl | 10 +++++----- test/sparse.jl | 4 ++-- test/suitesparse.jl | 7 ++++++- 20 files changed, 96 insertions(+), 72 deletions(-) diff --git a/NEWS.md b/NEWS.md index 34827f814a584..23a590c8dcc4e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -185,6 +185,8 @@ Deprecated or removed * `myindexes` has been renamed to `localindexes` ([#5475]) * `factorize!` is deprecated in favor of `factorize`. ([#5526]) + + * `nnz` is removed. Use `countnz` or `nfilled` instead ([#5538]) [#4042]: https://github.com/JuliaLang/julia/issues/4042 [#5164]: https://github.com/JuliaLang/julia/issues/5164 @@ -230,6 +232,7 @@ Deprecated or removed [#4888]: https://github.com/JuliaLang/julia/pull/4888 [#5475]: https://github.com/JuliaLang/julia/pull/5475 [#5526]: https://github.com/JuliaLang/julia/pull/5526 +[#5538]: https://github.com/JuliaLang/julia/pull/5538 Julia v0.2.0 Release Notes ========================== diff --git a/base/abstractarray.jl b/base/abstractarray.jl index bdf29dda0868f..8e51089eba852 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -19,6 +19,7 @@ isreal{T<:Real,n}(x::AbstractArray{T,n}) = true ndims{T,n}(::AbstractArray{T,n}) = n ndims{T,n}(::Type{AbstractArray{T,n}}) = n ndims{T<:AbstractArray}(::Type{T}) = ndims(super(T)) +nfilled(t::AbstractArray) = length(a) length(t::AbstractArray) = prod(size(t))::Int endof(a::AbstractArray) = length(a) first(a::AbstractArray) = a[1] diff --git a/base/array.jl b/base/array.jl index ed474222e34a4..60fa98c9f04f5 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1056,7 +1056,7 @@ function find(testf::Function, A::AbstractArray) end function find(A::AbstractArray) - nnzA = nnz(A) + nnzA = countnz(A) I = Array(Int, nnzA) count = 1 for i=1:length(A) @@ -1074,7 +1074,7 @@ find(testf::Function, x) = find(testf(x)) findn(A::AbstractVector) = find(A) function findn(A::AbstractMatrix) - nnzA = nnz(A) + nnzA = countnz(A) I = Array(Int, nnzA) J = Array(Int, nnzA) count = 1 @@ -1089,7 +1089,7 @@ function findn(A::AbstractMatrix) end function findnz{T}(A::AbstractMatrix{T}) - nnzA = nnz(A) + nnzA = countnz(A) I = zeros(Int, nnzA) J = zeros(Int, nnzA) NZs = zeros(T, nnzA) @@ -1109,7 +1109,7 @@ function findnz{T}(A::AbstractMatrix{T}) end function nonzeros{T}(A::AbstractArray{T}) - nnzA = nnz(A) + nnzA = countnz(A) V = Array(T, nnzA) count = 1 if nnzA > 0 diff --git a/base/bitarray.jl b/base/bitarray.jl index b1f10144d6e85..84ee9dfadb656 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -1599,9 +1599,9 @@ end #TODO: rol!, ror! -## nnz & find ## +## countnz & find ## -function nnz(B::BitArray) +function countnz(B::BitArray) n = 0 Bc = B.chunks @inbounds for i = 1:length(Bc) @@ -1705,7 +1705,7 @@ end function find(B::BitArray) l = length(B) - nnzB = nnz(B) + nnzB = countnz(B) I = Array(Int, nnzB) if nnzB == 0 return I @@ -1741,7 +1741,7 @@ end findn(B::BitVector) = find(B) function findn(B::BitMatrix) - nnzB = nnz(B) + nnzB = countnz(B) I = Array(Int, nnzB) J = Array(Int, nnzB) count = 1 @@ -1760,13 +1760,13 @@ function findnz(B::BitMatrix) return (I, J, trues(length(I))) end -nonzeros(B::BitArray) = trues(nnz(B)) +nonzeros(B::BitArray) = trues(countnz(B)) ## Reductions ## sum(A::BitArray, region) = reducedim(+,A,region,0,Array(Int,reduced_dims(A,region))) -sum(B::BitArray) = nnz(B) +sum(B::BitArray) = countnz(B) function all(B::BitArray) length(B) == 0 && return true diff --git a/base/deprecated.jl b/base/deprecated.jl index 34f03cb48e96e..bd608283fb0a8 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -390,3 +390,10 @@ eval(Sys, :(@deprecate shlib_list dllist)) # 0.3 discontinued functions +function nnz(X) + depwarn("nnz has been renamed to countnz and is no longer computed in constant time for sparse matrices. Instead, use nfilled() for the number of elements in a sparse matrix.", :nnz) + countnz(X) +end +export nnz + + diff --git a/base/exports.jl b/base/exports.jl index 408585cbe34e9..cbf4981ef4113 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -528,10 +528,11 @@ export minmax, nans, ndims, - nnz, + nfilled, nonzeros, nthperm!, nthperm, + countnz, ones, parent, parentindexes, diff --git a/base/linalg/bitarray.jl b/base/linalg/bitarray.jl index 8b6e6dd72225d..6fa12cb67448e 100644 --- a/base/linalg/bitarray.jl +++ b/base/linalg/bitarray.jl @@ -137,7 +137,7 @@ end ## Structure query functions -issym(A::BitMatrix) = size(A, 1)==size(A, 2) && nnz(A - A.')==0 +issym(A::BitMatrix) = size(A, 1)==size(A, 2) && numnz(A - A.')==0 ishermitian(A::BitMatrix) = issym(A) function nonzero_chunks(chunks::Vector{Uint64}, pos0::Int, pos1::Int) diff --git a/base/linalg/cholmod.jl b/base/linalg/cholmod.jl index c75d2cd4076fb..d117449a75b10 100644 --- a/base/linalg/cholmod.jl +++ b/base/linalg/cholmod.jl @@ -14,7 +14,7 @@ export # types using Base.LinAlg.UMFPACK # for decrement, increment, etc. import Base: (*), convert, copy, ctranspose, eltype, findnz, getindex, hcat, - isvalid, nnz, show, size, sort!, transpose, vcat + isvalid, nfilled, show, size, sort!, transpose, vcat import ..LinAlg: (\), A_mul_Bc, A_mul_Bt, Ac_ldiv_B, Ac_mul_B, At_ldiv_B, At_mul_B, cholfact, cholfact!, copy, det, diag, @@ -778,7 +778,7 @@ for Ti in (:Int32,:Int64) (Ptr{c_CholmodSparse{Tv,$Ti}},Ptr{c_CholmodSparse{Tv,$Ti}},Cint,Ptr{Uint8}), &A.c,&B.c,true,cmn($Ti)) end - function nnz{Tv<:CHMVTypes}(A::CholmodSparse{Tv,$Ti}) + function nfilled{Tv<:CHMVTypes}(A::CholmodSparse{Tv,$Ti}) ccall((@chm_nm "nnz" $Ti ,:libcholmod), Int, (Ptr{c_CholmodSparse{Tv,$Ti}},Ptr{Uint8}),&A.c,cmn($Ti)) end diff --git a/base/linalg/sparse.jl b/base/linalg/sparse.jl index 474440a6b4e27..6c98546d11082 100644 --- a/base/linalg/sparse.jl +++ b/base/linalg/sparse.jl @@ -328,7 +328,7 @@ function sparse_diff1{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) m,n = size(S) m > 1 && return SparseMatrixCSC{Tv,Ti}(0, n, ones(n+1), Ti[], Tv[]) colptr = Array(Ti, n+1) - numnz = 2 * nnz(S) # upper bound; will shrink later + numnz = 2 * nfilled(S) # upper bound; will shrink later rowval = Array(Ti, numnz) nzval = Array(Tv, numnz) numnz = 0 @@ -368,7 +368,7 @@ function sparse_diff2{Tv,Ti}(a::SparseMatrixCSC{Tv,Ti}) m,n = size(a) colptr = Array(Ti, max(n,1)) - numnz = 2 * nnz(a) # upper bound; will shrink later + numnz = 2 * nfilled(a) # upper bound; will shrink later rowval = Array(Ti, numnz) nzval = Array(Tv, numnz) @@ -463,8 +463,8 @@ diff(a::SparseMatrixCSC, dim::Integer)= dim==1 ? sparse_diff1(a) : sparse_diff2( # kron function kron{Tv,Ti}(a::SparseMatrixCSC{Tv,Ti}, b::SparseMatrixCSC{Tv,Ti}) - numnzA = nnz(a) - numnzB = nnz(b) + numnzA = nfilled(a) + numnzB = nfilled(b) numnz = numnzA * numnzB @@ -529,7 +529,7 @@ inv(A::SparseMatrixCSC) = error("The inverse of a sparse matrix can often be den function scale!{Tv,Ti}(C::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC, b::Vector) m, n = size(A) (n==length(b) && size(A)==size(C)) || throw(DimensionMismatch("")) - numnz = nnz(A) + numnz = nfilled(A) C.colptr = convert(Array{Ti}, A.colptr) C.rowval = convert(Array{Ti}, A.rowval) C.nzval = Array(Tv, numnz) @@ -542,7 +542,7 @@ end function scale!{Tv,Ti}(C::SparseMatrixCSC{Tv,Ti}, b::Vector, A::SparseMatrixCSC) m, n = size(A) (n==length(b) && size(A)==size(C)) || throw(DimensionMismatch("")) - numnz = nnz(A) + numnz = nfilled(A) C.colptr = convert(Array{Ti}, A.colptr) C.rowval = convert(Array{Ti}, A.rowval) C.nzval = Array(Tv, numnz) diff --git a/base/linalg/umfpack.jl b/base/linalg/umfpack.jl index 0535809d55e00..0a618ea55042c 100644 --- a/base/linalg/umfpack.jl +++ b/base/linalg/umfpack.jl @@ -6,7 +6,7 @@ export UmfpackLU, increment, increment! -import Base: (\), Ac_ldiv_B, At_ldiv_B, findnz, getindex, nnz, show, size +import Base: (\), Ac_ldiv_B, At_ldiv_B, findnz, getindex, show, size import ..LinAlg: A_ldiv_B!, Ac_ldiv_B!, At_ldiv_B!, Factorization, det, lufact, lufact!, solve diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 648804cd87bcb..0a8d8faff775e 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -95,7 +95,7 @@ end @ngenerate N function findn{T,N}(A::AbstractArray{T,N}) - nnzA = nnz(A) + nnzA = countnz(A) @nexprs N d->(I_d = Array(Int, nnzA)) k = 1 @nloops N i A begin @@ -306,7 +306,7 @@ end end @ngenerate N function findn{N}(B::BitArray{N}) - nnzB = nnz(B) + nnzB = countnz(B) I = ntuple(N, x->Array(Int, nnzB)) if nnzB > 0 count = 1 diff --git a/base/reduce.jl b/base/reduce.jl index 5d39be79cf772..325455b93ecdf 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -126,9 +126,9 @@ function contains(eq::Function, itr, x) return false end -## nnz & count +## countnz & count -function nnz{T}(a::AbstractArray{T}) +function countnz{T}(a::AbstractArray{T}) n = 0 z = zero(T) for i = 1:length(a) @@ -137,7 +137,7 @@ function nnz{T}(a::AbstractArray{T}) return n end -function nnz(a::AbstractArray{Bool}) +function countnz(a::AbstractArray{Bool}) n = 0 for x in a if x; n += 1; end @@ -170,7 +170,7 @@ function sum(itr) return v end -sum(A::AbstractArray{Bool}) = nnz(A) +sum(A::AbstractArray{Bool}) = countnz(A) # a fast implementation of sum in sequential order (from left to right) function sum_seq{T}(a::AbstractArray{T}, ifirst::Int, ilast::Int) diff --git a/base/sparse/csparse.jl b/base/sparse/csparse.jl index 52474d8129502..5697aefba9b45 100644 --- a/base/sparse/csparse.jl +++ b/base/sparse/csparse.jl @@ -128,7 +128,7 @@ function transpose!{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}, T::SparseMatrixCSC{Tv,Ti}) rowval_T = T.rowval nzval_T = T.nzval - nnzS = nnz(S) + nnzS = nfilled(S) colptr_S = S.colptr rowval_S = S.rowval nzval_S = S.nzval @@ -147,7 +147,7 @@ end function transpose{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) (nT, mT) = size(S) - nnzS = nnz(S) + nnzS = nfilled(S) rowval_S = S.rowval rowval_T = Array(Ti, nnzS) @@ -155,7 +155,7 @@ function transpose{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) colptr_T = zeros(Ti, nT+1) colptr_T[1] = 1 - @inbounds for i=1:nnz(S) + @inbounds for i=1:nfilled(S) colptr_T[rowval_S[i]+1] += 1 end colptr_T = cumsum(colptr_T) @@ -172,7 +172,7 @@ function ctranspose!{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}, T::SparseMatrixCSC{Tv,Ti} rowval_T = T.rowval nzval_T = T.nzval - nnzS = nnz(S) + nnzS = nfilled(S) colptr_S = S.colptr rowval_S = S.rowval nzval_S = S.nzval @@ -191,7 +191,7 @@ end function ctranspose{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) (nT, mT) = size(S) - nnzS = nnz(S) + nnzS = nfilled(S) rowval_S = S.rowval rowval_T = Array(Ti, nnzS) @@ -199,7 +199,7 @@ function ctranspose{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) colptr_T = zeros(Ti, nT+1) colptr_T[1] = 1 - @inbounds for i=1:nnz(S) + @inbounds for i=1:nfilled(S) colptr_T[rowval_S[i]+1] += 1 end colptr_T = cumsum(colptr_T) @@ -335,7 +335,7 @@ end # Section 2.7: Removing entries from a matrix # http://www.cise.ufl.edu/research/sparse/CSparse/ function fkeep!{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, f, other) - nzorig = nnz(A) + nzorig = nfilled(A) nz = 1 for j = 1:A.n p = A.colptr[j] # record current position diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 4577ea92ab25f..7eabc20dcc230 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -15,17 +15,18 @@ SparseMatrixCSC{Tv,Ti}(m::Integer, n::Integer, colptr::Vector{Ti}, rowval::Vecto SparseMatrixCSC(int(m), int(n), colptr, rowval, nzval) size(S::SparseMatrixCSC) = (S.m, S.n) -nnz(S::SparseMatrixCSC) = int(S.colptr[end]-1) +nfilled(S::SparseMatrixCSC) = int(S.colptr[end]-1) +countnz(S::SparseMatrixCSC) = countnz(S.nzval) function show(io::IO, S::SparseMatrixCSC) - print(io, S.m, "x", S.n, " sparse matrix with ", nnz(S), " ", eltype(S), " nonzeros:") + print(io, S.m, "x", S.n, " sparse matrix with ", nfilled(S), " ", eltype(S), " entries:") half_screen_rows = div(Base.tty_rows() - 8, 2) pad = ndigits(max(S.m,S.n)) k = 0 sep = "\n\t" for col = 1:S.n, k = S.colptr[col] : (S.colptr[col+1]-1) - if k < half_screen_rows || k > nnz(S)-half_screen_rows + if k < half_screen_rows || k > nfilled(S)-half_screen_rows print(io, sep, '[', rpad(S.rowval[k], pad), ", ", lpad(col, pad), "] = ", sprint(showcompact, S.nzval[k])) elseif k == half_screen_rows @@ -85,7 +86,7 @@ function reinterpret{T,Tv,Ti,N}(::Type{T}, a::SparseMatrixCSC{Tv,Ti}, dims::NTup end mS,nS = dims mA,nA = size(a) - numnz = nnz(a) + numnz = nfilled(a) colptr = Array(Ti, nS+1) rowval = Array(Ti, numnz) nzval = reinterpret(T, a.nzval) @@ -101,7 +102,7 @@ function reshape{Tv,Ti}(a::SparseMatrixCSC{Tv,Ti}, dims::NTuple{2,Int}) end mS,nS = dims mA,nA = size(a) - numnz = nnz(a) + numnz = nfilled(a) colptr = Array(Ti, nS+1) rowval = Array(Ti, numnz) nzval = a.nzval @@ -294,7 +295,7 @@ function find(S::SparseMatrixCSC) end function findn{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) - numnz = nnz(S) + numnz = nfilled(S) I = Array(Ti, numnz) J = Array(Ti, numnz) @@ -304,8 +305,6 @@ function findn{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) I[count] = S.rowval[k] J[count] = col count += 1 - else - Base.warn_once("sparse matrix contains explicit stored zeros") end end @@ -319,7 +318,7 @@ function findn{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) end function findnz{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) - numnz = nnz(S) + numnz = nfilled(S) I = Array(Ti, numnz) J = Array(Ti, numnz) V = Array(Tv, numnz) @@ -331,8 +330,6 @@ function findnz{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) J[count] = col V[count] = S.nzval[k] count += 1 - else - Base.warn_once("sparse matrix contains explicit stored zeros") end end @@ -469,7 +466,7 @@ for (op, restype) in ( (:+, Nothing), (:-, Nothing), (:.*, Nothing), (:.^, Nothi (m, n) = size(A) # TODO: Need better method to estimate result space - nnzS = nnz(A) + nnz(B) + nnzS = nfilled(A) + nfilled(B) colptrS = Array(Ti, A.n+1) rowvalS = Array(Ti, nnzS) if $restype == Nothing @@ -626,7 +623,7 @@ function reducedim{Tv,Ti}(f::Function, A::SparseMatrixCSC{Tv,Ti}, region, v0) for i = 1 : A.n, j = A.colptr[i] : A.colptr[i+1]-1 S = f(S, A.nzval[j]) end - if nnz(A) != A.m*A.n; S = f(S, zero(Tv)); end + if nfilled(A) != A.m*A.n; S = f(S, zero(Tv)); end return [S] @@ -654,7 +651,7 @@ prod{T}(A::SparseMatrixCSC{T}, region) = reducedim(*,A,region,one(T)) #all(A::SparseMatrixCSC{Bool}, region) = reducedim(all,A,region,true) #any(A::SparseMatrixCSC{Bool}, region) = reducedim(any,A,region,false) #sum(A::SparseMatrixCSC{Bool}, region) = reducedim(+,A,region,0,Int) -#sum(A::SparseMatrixCSC{Bool}) = nnz(A) +#sum(A::SparseMatrixCSC{Bool}) = countnz(A) ## getindex getindex(A::SparseMatrixCSC, i::Integer) = getindex(A, ind2sub(size(A),i)) @@ -718,7 +715,7 @@ end # TODO: See if growing arrays is faster than pre-computing structure # and then populating nonzeros -# TODO: Use binary search in cases where nI >> nnz(A[:,j]) or nI << nnz(A[:,j]) +# TODO: Use binary search in cases where nI >> nfilled(A[:,j]) or nI << nfilled(A[:,j]) function getindex_I_sorted{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, I::Vector, J::AbstractVector) (m, n) = size(A) @@ -1113,7 +1110,7 @@ function setindex!{Tv,Ti,T<:Integer}(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixC colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval colptrB = B.colptr; rowvalB = B.rowval; nzvalB = B.nzval - nnzS = nnz(A) + nnz(B) + nnzS = nfilled(A) + nfilled(B) colptrS = Array(Ti, n+1) rowvalS = Array(Ti, nnzS) nzvalS = Array(Tv, nnzS) @@ -1231,7 +1228,7 @@ function vcat(X::SparseMatrixCSC...) Ti = promote_type(map(x->eltype(x.rowval), X)...) colptr = Array(Ti, n + 1) - nnzX = [ nnz(x) for x in X ] + nnzX = [ nfilled(x) for x in X ] nnz_res = sum(nnzX) rowval = Array(Ti, nnz_res) nzval = Array(Tv, nnz_res) @@ -1269,7 +1266,7 @@ function hcat(X::SparseMatrixCSC...) Ti = promote_type(map(x->eltype(x.rowval), X)...) colptr = Array(Ti, n + 1) - nnzX = [ nnz(x) for x in X ] + nnzX = [ nfilled(x) for x in X ] nnz_res = sum(nnzX) rowval = Array(Ti, nnz_res) nzval = Array(Tv, nnz_res) @@ -1304,13 +1301,13 @@ end function issym(A::SparseMatrixCSC) m, n = size(A) if m != n; return false; end - return nnz(A - A.') == 0 + return countnz(A - A.') == 0 end function ishermitian(A::SparseMatrixCSC) m, n = size(A) if m != n; return false; end - return nnz(A - A') == 0 + return countnz(A - A') == 0 end function istriu{Tv}(A::SparseMatrixCSC{Tv}) @@ -1452,7 +1449,7 @@ function diagm{Tv,Ti}(v::SparseMatrixCSC{Tv,Ti}) end n = length(v) - numnz = nnz(v) + numnz = nfilled(v) colptr = Array(Ti, n+1) rowval = Array(Ti, numnz) nzval = Array(Tv, numnz) diff --git a/doc/manual/arrays.rst b/doc/manual/arrays.rst index 119d49046c3c6..8dd23aa6f88cb 100644 --- a/doc/manual/arrays.rst +++ b/doc/manual/arrays.rst @@ -44,7 +44,6 @@ Function Description ``eltype(A)`` the type of the elements contained in A ``length(A)`` the number of elements in A ``ndims(A)`` the number of dimensions of A -``nnz(A)`` the number of nonzero values in A ``size(A)`` a tuple containing the dimensions of A ``size(A,n)`` the size of A in a particular dimension ``stride(A,k)`` the stride (linear index distance between adjacent elements) along dimension k @@ -494,9 +493,16 @@ the CSC data structure for performance, and to avoid expensive operations. If you have data in CSC format from a different application or library, and wish to import it in Julia, make sure that you use 1-based indexing. The row indices in every column need to be sorted. If your `SparseMatrixCSC` -ojbect contains unsorted row indices, one quick way to sort them is by +object contains unsorted row indices, one quick way to sort them is by doing a double transpose. +In some applications, it is convenient to store explicit zero values in +a `SparseMatrixCSC`. These *are* accepted by functions in ``Base`` (but +there is no guarantee that they will be preserved in mutating operations). +Because of this, ``countnz`` is not a constant-time operation; instead, +``nfilled`` should be used to obtain the number of elements in a sparse +matrix. + Sparse matrix constructors -------------------------- @@ -508,10 +514,10 @@ you can use the same names with an ``sp`` prefix: .. doctest:: julia> spzeros(3,5) - 3x5 sparse matrix with 0 Float64 nonzeros: + 3x5 sparse matrix with 0 Float64 entries: julia> speye(3,5) - 3x5 sparse matrix with 3 Float64 nonzeros: + 3x5 sparse matrix with 3 Float64 entries: [1, 1] = 1.0 [2, 2] = 1.0 [3, 3] = 1.0 @@ -527,7 +533,7 @@ values. ``sparse(I,J,V)`` constructs a sparse matrix such that julia> I = [1, 4, 3, 5]; J = [4, 7, 18, 9]; V = [1, 2, -5, 3]; julia> S = sparse(I,J,V) - 5x18 sparse matrix with 4 Int64 nonzeros: + 5x18 sparse matrix with 4 Int64 entries: [1 , 4] = 1 [4 , 7] = 2 [5 , 9] = 3 @@ -550,7 +556,7 @@ into a sparse matrix using the ``sparse`` function: .. doctest:: julia> sparse(eye(5)) - 5x5 sparse matrix with 5 Float64 nonzeros: + 5x5 sparse matrix with 5 Float64 entries: [1, 1] = 1.0 [2, 2] = 1.0 [3, 3] = 1.0 @@ -574,7 +580,7 @@ matrices. Indexing of, assignment into, and concatenation of sparse matrices work in the same way as dense matrices. Indexing operations, especially assignment, are expensive, when carried out one element at a time. In many cases it may be better to convert the sparse matrix -into ``(I,J,V)`` format using ``find_nzs``, manipulate the non-zeroes or +into ``(I,J,V)`` format using ``findnz``, manipulate the non-zeroes or the structure in the dense vectors ``(I,J,V)``, and then reconstruct the sparse matrix. diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index 8a17b1d13b06c..182dee5db7a4c 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -3432,9 +3432,9 @@ Basic functions Returns the number of elements in A -.. function:: nnz(A) +.. function:: countnz(A) - Counts the number of nonzero values in array A (dense or sparse) + Counts the number of nonzero values in array A (dense or sparse). Note that this is not a constant-time operation. For sparse matrices, one should usually use ``nfilled`` instead. .. function:: conj!(A) diff --git a/doc/stdlib/sparse.rst b/doc/stdlib/sparse.rst index 8efc6fc84926f..256a7a8f48d73 100644 --- a/doc/stdlib/sparse.rst +++ b/doc/stdlib/sparse.rst @@ -39,6 +39,10 @@ Sparse matrices support much of the same set of operations as dense matrices. Th Convert a sparse matrix ``S`` into a dense matrix. +.. function:: nfilled(A) + + Returns the number of stored (filled) elements in a sparse matrix. + .. function:: spzeros(m,n) Create an empty sparse matrix of size ``m x n``. diff --git a/test/bitarray.jl b/test/bitarray.jl index f77efd2c63fc2..c2203dea45399 100644 --- a/test/bitarray.jl +++ b/test/bitarray.jl @@ -108,21 +108,21 @@ t1 = randbool(n1, n2) @check_bit_operation setindex!(b1, true, t1) BitMatrix t1 = randbool(n1, n2) -b2 = randbool(nnz(t1)) +b2 = randbool(countnz(t1)) @check_bit_operation setindex!(b1, b2, t1) BitMatrix m1 = rand(1:n1) m2 = rand(1:n2) t1 = randbool(n1) -b2 = randbool(nnz(t1), m2) +b2 = randbool(countnz(t1), m2) k2 = randperm(m2) @check_bit_operation setindex!(b1, b2, t1, 1:m2) BitMatrix @check_bit_operation setindex!(b1, b2, t1, n2-m2+1:n2) BitMatrix @check_bit_operation setindex!(b1, b2, t1, k2) BitMatrix t2 = randbool(n2) -b2 = randbool(m1, nnz(t2)) +b2 = randbool(m1, countnz(t2)) k1 = randperm(m1) @check_bit_operation setindex!(b1, b2, 1:m1, t2) BitMatrix @check_bit_operation setindex!(b1, b2, n1-m1+1:n1, t2) BitMatrix @@ -601,10 +601,10 @@ end timesofar("datamove") -## nnz & find ## +## countnz & find ## b1 = randbool(v1) -@check_bit_operation nnz(b1) Int +@check_bit_operation countnz(b1) Int @check_bit_operation findfirst(b1) Int @check_bit_operation findfirst(trues(v1)) Int diff --git a/test/sparse.jl b/test/sparse.jl index 14fe478a85353..7a75b01e1e0d2 100644 --- a/test/sparse.jl +++ b/test/sparse.jl @@ -181,11 +181,11 @@ mfe22 = eye(Float64, 2) @test_throws sparsevec([3,5,7],[0.1,0.0,3.2],4) # issue #5169 -@test nnz(sparse([1,1],[1,2],[0.0,-0.0])) == 0 +@test nfilled(sparse([1,1],[1,2],[0.0,-0.0])) == 0 # issue #5386 I,J,V = findnz(SparseMatrixCSC(2,1,[1,3],[1,2],[1.0,0.0])) @test length(I) == length(J) == length(V) == 1 # issue #5437 -@test nnz(sparse([1,2,3],[1,2,3],[0.0,1.0,2.0])) == 2 +@test nfilled(sparse([1,2,3],[1,2,3],[0.0,1.0,2.0])) == 2 diff --git a/test/suitesparse.jl b/test/suitesparse.jl index ebf2fed51ddb9..1fe3d5f1c3e1d 100644 --- a/test/suitesparse.jl +++ b/test/suitesparse.jl @@ -152,4 +152,9 @@ y = afiro'*ones(size(afiro,1)) sol = Base.solve(chmaf, afiro*y) # least squares solution @test isvalid(sol) pred = afiro'*sol -@test norm(afiro * (y.mat - pred.mat)) < 1e-8 +@test norm(afiro * (y.mat - pred.mat)) < 1e-8 + +# explicit zeros +a = SparseMatrixCSC(2,2,[1,3,5],[1,2,1,2],[1.0,0.0,0.0,1.0]) +@test_approx_eq lufact(a)\[2.0,3.0] [2.0,3.0] +@test_approx_eq cholfact(a)\[2.0,3.0] [2.0,3.0]