From 934a68195e430c5091cacfa017143b46fe257088 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 1 Sep 2022 14:24:44 +0200 Subject: [PATCH 01/13] Add `count` w/o predicate --- src/sparsematrix.jl | 1 + src/sparsevector.jl | 1 + test/sparsematrix_constructors_indexing.jl | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index bff7df5a..af641595 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -212,6 +212,7 @@ nnz1(S) = sum(length.(nzrange.(Ref(S), axes(S, 2)))) function count(pred, S::AbstractSparseMatrixCSC) count(pred, nzvalview(S)) + pred(zero(eltype(S)))*(prod(size(S)) - nnz(S)) end +count(S::AbstractSparseMatrixCSC{Bool}) = count(identity, S) """ nonzeros(A) diff --git a/src/sparsevector.jl b/src/sparsevector.jl index a9568455..60be599a 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -93,6 +93,7 @@ const SVorFSV{Tv,Ti} = Union{SparseVector{Tv,Ti},FixedSparseVector{Tv,Ti}} length(x::SVorFSV) = getfield(x, :n) size(x::SVorFSV) = (getfield(x, :n),) count(f, x::AbstractCompressedVector) = count(f, nonzeros(x)) + f(zero(eltype(x)))*(length(x) - nnz(x)) +count(x::AbstractCompressedVector{Bool}) = count(identity, x) # implement the nnz - nzrange - nonzeros - rowvals interface for sparse vectors diff --git a/test/sparsematrix_constructors_indexing.jl b/test/sparsematrix_constructors_indexing.jl index f6875fde..f0ff3ef1 100644 --- a/test/sparsematrix_constructors_indexing.jl +++ b/test/sparsematrix_constructors_indexing.jl @@ -445,12 +445,12 @@ end @testset "setindex" begin a = spzeros(Int, 10, 10) - @test count(!iszero, a) == 0 + @test count(!iszero, a) == count((!iszero).(a)) == 0 a[1,:] .= 1 - @test count(!iszero, a) == 10 + @test count(!iszero, a) == count((!iszero).(a)) == 10 @test a[1,:] == sparse(fill(1,10)) a[:,2] .= 2 - @test count(!iszero, a) == 19 + @test count(!iszero, a) == count((!iszero).(a)) == 19 @test a[:,2] == sparse(fill(2,10)) b = copy(a) From 8d240da7261deb11142ed2f83b03c7cec6d3ad08 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 1 Sep 2022 15:38:45 +0200 Subject: [PATCH 02/13] lower hook, handle adjortrans --- src/sparsematrix.jl | 4 +++- src/sparsevector.jl | 4 +++- test/sparsematrix_constructors_indexing.jl | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index af641595..9f041253 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -212,7 +212,9 @@ nnz1(S) = sum(length.(nzrange.(Ref(S), axes(S, 2)))) function count(pred, S::AbstractSparseMatrixCSC) count(pred, nzvalview(S)) + pred(zero(eltype(S)))*(prod(size(S)) - nnz(S)) end -count(S::AbstractSparseMatrixCSC{Bool}) = count(identity, S) +Base._count(f, A::AbstractSparseMatrixCSC, ::Colon, _) = count(f, A) +Base._count(f, A::Adjoint{<:Any,<:AbstractSparseMatrixCSC}, ::Colon, _) = count(f∘adjoint, parent(A)) +Base._count(f, A::Transpose{<:Any,<:AbstractSparseMatrixCSC}, ::Colon, _) = count(f∘transpose, parent(A)) """ nonzeros(A) diff --git a/src/sparsevector.jl b/src/sparsevector.jl index 60be599a..b7bdce45 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -93,7 +93,9 @@ const SVorFSV{Tv,Ti} = Union{SparseVector{Tv,Ti},FixedSparseVector{Tv,Ti}} length(x::SVorFSV) = getfield(x, :n) size(x::SVorFSV) = (getfield(x, :n),) count(f, x::AbstractCompressedVector) = count(f, nonzeros(x)) + f(zero(eltype(x)))*(length(x) - nnz(x)) -count(x::AbstractCompressedVector{Bool}) = count(identity, x) +Base._count(f, x::AbstractCompressedVector, ::Colon, _) = count(f, x) +Base._count(f, x::Adjoint{<:Any, <:AbstractCompressedVector}, ::Colon, _) = count(f∘adjoint, parent(x)) +Base._count(f, x::Transpose{<:Any, <:AbstractCompressedVector}, ::Colon, _) = count(f∘transpose, x) # implement the nnz - nzrange - nonzeros - rowvals interface for sparse vectors diff --git a/test/sparsematrix_constructors_indexing.jl b/test/sparsematrix_constructors_indexing.jl index f0ff3ef1..5b85dd4d 100644 --- a/test/sparsematrix_constructors_indexing.jl +++ b/test/sparsematrix_constructors_indexing.jl @@ -446,8 +446,12 @@ end @testset "setindex" begin a = spzeros(Int, 10, 10) @test count(!iszero, a) == count((!iszero).(a)) == 0 + @test count(!iszero, a') == count((!iszero).(a')) == 0 + @test count(!iszero, transpose(a)) == count(transpose((!iszero).(a))) == 0 a[1,:] .= 1 @test count(!iszero, a) == count((!iszero).(a)) == 10 + @test count(!iszero, a') == count(((!iszero).(a))') == 10 + @test count(!iszero, transpose(a)) == count(transpose((!iszero).(a))) == 10 @test a[1,:] == sparse(fill(1,10)) a[:,2] .= 2 @test count(!iszero, a) == count((!iszero).(a)) == 19 From 422fdddc10c89d11255387a2f1b4bdec3e74d481 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 1 Sep 2022 18:33:22 +0200 Subject: [PATCH 03/13] use more fallbacks --- src/sparsematrix.jl | 12 +++++++----- src/sparsevector.jl | 13 +++++++++---- test/sparsematrix_constructors_indexing.jl | 2 ++ test/sparsevector.jl | 1 + 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index 9f041253..d0a64433 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -209,12 +209,14 @@ nnz(S::LowerTriangular{<:Any,<:AbstractSparseMatrixCSC}) = nnz1(S) nnz(S::SparseMatrixCSCView) = nnz1(S) nnz1(S) = sum(length.(nzrange.(Ref(S), axes(S, 2)))) -function count(pred, S::AbstractSparseMatrixCSC) - count(pred, nzvalview(S)) + pred(zero(eltype(S)))*(prod(size(S)) - nnz(S)) +Base._count(f, A::Adjoint{<:Any,<:AbstractSparseMatrixCSC}, ::Colon, init) = + Base._simple_count(f∘adjoint, parent(A), init) +Base._count(f, A::Transpose{<:Any,<:AbstractSparseMatrixCSC}, ::Colon, init) = + Base._simple_count(f∘transpose, parent(A), init) + +function Base._simple_count(pred, S::AbstractSparseMatrixCSC, init::T) where T + init + T(count(pred, nzvalview(S)) + pred(zero(eltype(S)))*(prod(size(S)) - nnz(S))) end -Base._count(f, A::AbstractSparseMatrixCSC, ::Colon, _) = count(f, A) -Base._count(f, A::Adjoint{<:Any,<:AbstractSparseMatrixCSC}, ::Colon, _) = count(f∘adjoint, parent(A)) -Base._count(f, A::Transpose{<:Any,<:AbstractSparseMatrixCSC}, ::Colon, _) = count(f∘transpose, parent(A)) """ nonzeros(A) diff --git a/src/sparsevector.jl b/src/sparsevector.jl index b7bdce45..ed675321 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -92,10 +92,15 @@ const SVorFSV{Tv,Ti} = Union{SparseVector{Tv,Ti},FixedSparseVector{Tv,Ti}} length(x::SVorFSV) = getfield(x, :n) size(x::SVorFSV) = (getfield(x, :n),) -count(f, x::AbstractCompressedVector) = count(f, nonzeros(x)) + f(zero(eltype(x)))*(length(x) - nnz(x)) -Base._count(f, x::AbstractCompressedVector, ::Colon, _) = count(f, x) -Base._count(f, x::Adjoint{<:Any, <:AbstractCompressedVector}, ::Colon, _) = count(f∘adjoint, parent(x)) -Base._count(f, x::Transpose{<:Any, <:AbstractCompressedVector}, ::Colon, _) = count(f∘transpose, x) + +function Base._simple_count(f, x::AbstractCompressedVector, init::T) where T + init + T(count(f, nonzeros(x)) + f(zero(eltype(x)))*(length(x) - nnz(x))) +end + +Base._count(f, x::Adjoint{<:Any,<:AbstractCompressedVector}, ::Colon, init) = + Base._simple_count(f∘adjoint, parent(x), init) +Base._count(f, x::Transpose{<:Any,<:AbstractCompressedVector}, ::Colon, init) = + Base._simple_count(f∘transpose, parent(x), init) # implement the nnz - nzrange - nonzeros - rowvals interface for sparse vectors diff --git a/test/sparsematrix_constructors_indexing.jl b/test/sparsematrix_constructors_indexing.jl index 5b85dd4d..31818684 100644 --- a/test/sparsematrix_constructors_indexing.jl +++ b/test/sparsematrix_constructors_indexing.jl @@ -450,6 +450,8 @@ end @test count(!iszero, transpose(a)) == count(transpose((!iszero).(a))) == 0 a[1,:] .= 1 @test count(!iszero, a) == count((!iszero).(a)) == 10 + @test count(!iszero, a, init=2) == count((!iszero).(a), init=2) == 12 + @test count(!iszero, a, init=Int128(2))::Int128 == 12 @test count(!iszero, a') == count(((!iszero).(a))') == 10 @test count(!iszero, transpose(a)) == count(transpose((!iszero).(a))) == 10 @test a[1,:] == sparse(fill(1,10)) diff --git a/test/sparsevector.jl b/test/sparsevector.jl index 76d7446b..725b8031 100644 --- a/test/sparsevector.jl +++ b/test/sparsevector.jl @@ -33,6 +33,7 @@ x1_full[SparseArrays.nonzeroinds(spv_x1)] = nonzeros(spv_x1) @test SparseArrays.nonzeroinds(x) == [2, 5, 6] @test nonzeros(x) == [1.25, -0.75, 3.5] @test count(SparseVector(8, [2, 5, 6], [true,false,true])) == 2 + @test count(SparseVector(8, [2, 5, 6], [true,false,true]), init=Int16(2))::Int16 == 4 y = SparseVector(8, Int128[4], [5]) @test y isa SparseVector{Int,Int128} @test @inferred size(y) == (@inferred(length(y))::Int128,) From c1a0a23e9507f36193f48c278a93e8d1cc995ee2 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 1 Sep 2022 18:57:52 +0200 Subject: [PATCH 04/13] add `iszero` for sparse vectors --- src/sparsevector.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sparsevector.jl b/src/sparsevector.jl index ed675321..d290a28e 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -1027,6 +1027,8 @@ function Vector(x::AbstractSparseVector{Tv}) where Tv end Array(x::AbstractSparseVector) = Vector(x) +Base.iszero(x::AbstractSparseVector) = iszero(nonzeros(x)) + ### Array manipulation vec(x::AbstractSparseVector) = x From 6484bbdab6f4b3613062a85e4a18c212e6ffa8db Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 1 Sep 2022 19:09:06 +0200 Subject: [PATCH 05/13] handle mapreduce for AdjOrTrans Co-authored-by: Sobhan Mohammadpour --- src/sparsematrix.jl | 4 ++++ src/sparsevector.jl | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index d0a64433..586ff270 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -2176,6 +2176,10 @@ function Base._mapreduce(f, op, ::Base.IndexCartesian, A::AbstractSparseMatrixCS _mapreducezeros(f, op, T, n-z, Base._mapreduce(f, op, nzvalview(A))) end end +Base._mapreduce(f, op, ::Base.IndexCartesian, A::Adjoint{<:Any,<:AbstractSparseMatrixCSC}) = + Base._mapreduce(f∘adjoint, op, IndexCartesian(), parent(A)) +Base._mapreduce(f, op, ::Base.IndexCartesian, A::Transpose{<:Any,<:AbstractSparseMatrixCSC}) = + Base._mapreduce(f∘transpose, op, IndexCartesian(), parent(A)) # Specialized mapreduce for +/*/min/max/_extrema_rf _mapreducezeros(f, op::Union{typeof(Base.add_sum),typeof(+)}, ::Type{T}, nzeros::Integer, v0) where {T} = diff --git a/src/sparsevector.jl b/src/sparsevector.jl index d290a28e..d050a830 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -1496,6 +1496,10 @@ function Base._mapreduce(f, op, ::IndexCartesian, A::SparseVectorUnion{T}) where end _mapreducezeros(f, op, T, rest, ini) end +Base._mapreduce(f, op, ::Base.IndexCartesian, A::Adjoint{<:Any,<:SparseVectorUnion}) = + Base._mapreduce(f∘adjoint, op, IndexCartesian(), parent(A)) +Base._mapreduce(f, op, ::Base.IndexCartesian, A::Transpose{<:Any,<:SparseVectorUnion}) = + Base._mapreduce(f∘transpose, op, IndexCartesian(), parent(A)) function Base.mapreducedim!(f, op, R::AbstractVector, A::SparseVectorUnion) # dim1 reduction could be safely replaced with a mapreduce From 9d17f12a91ec492fe6bf880b10a48a26c724bcc9 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 1 Sep 2022 21:27:30 +0200 Subject: [PATCH 06/13] fix performance of all and any --- src/sparsematrix.jl | 11 ++++++++--- src/sparsevector.jl | 5 +++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index 586ff270..74adbce9 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -309,7 +309,7 @@ function Base.isstored(A::AbstractSparseMatrixCSC, i::Integer, j::Integer) return false end -function Base.isstored(A::Union{Adjoint{<:Any,<:AbstractSparseMatrixCSC},Transpose{<:Any,<:AbstractSparseMatrixCSC}}, i::Integer, j::Integer) +function Base.isstored(A::AdjOrTrans{<:Any,<:AbstractSparseMatrixCSC}, i::Integer, j::Integer) @boundscheck checkbounds(A, i, j) cols = rowvals(parent(A)) for istored in nzrange(parent(A), i) @@ -2121,8 +2121,7 @@ nzeq(A::Transpose{<:Any,<:AbstractSparseMatrixCSCInclAdjointAndTranspose}, # the case where the RHS is both adjoint and transposed, i.e. where it # is in CSC format again.) function ==(A::AbstractSparseMatrixCSC, - B::Union{Adjoint{<:Any,<:AbstractSparseMatrixCSCInclAdjointAndTranspose}, - Transpose{<:Any,<:AbstractSparseMatrixCSCInclAdjointAndTranspose}}) + B::AdjOrTrans{<:Any,<:AbstractSparseMatrixCSCInclAdjointAndTranspose}) # Different sizes are always different size(A) ≠ size(B) && return false # Compare nonzero elements @@ -2191,6 +2190,12 @@ _mapreducezeros(f, op::Union{typeof(min),typeof(max)}, ::Type{T}, nzeros::Intege _mapreducezeros(f::Base.ExtremaMap, op::typeof(Base._extrema_rf), ::Type{T}, nzeros::Integer, v0) where {T} = nzeros == 0 ? v0 : op(v0, f(zero(T))) +# Specialized mapreduce for any and all +Base._any(f, A::AbstractSparseMatrixCSCInclAdjointAndTranspose, ::Colon) = + Base._mapreduce(f, |, IndexCartesian(), A) +Base._all(f, A::AbstractSparseMatrixCSCInclAdjointAndTranspose, ::Colon) = + Base._mapreduce(f, &, IndexCartesian(), A) + function Base._mapreduce(f, op::typeof(*), ::Base.IndexCartesian, A::AbstractSparseMatrixCSC{T}) where T nzeros = widelength(A)-nnz(A) if nzeros == 0 diff --git a/src/sparsevector.jl b/src/sparsevector.jl index d050a830..627d5c3b 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -1501,6 +1501,11 @@ Base._mapreduce(f, op, ::Base.IndexCartesian, A::Adjoint{<:Any,<:SparseVectorUni Base._mapreduce(f, op, ::Base.IndexCartesian, A::Transpose{<:Any,<:SparseVectorUnion}) = Base._mapreduce(f∘transpose, op, IndexCartesian(), parent(A)) +Base._any(f, A::Union{SparseVectorUnion, AdjOrTransSparseVectorUnion}, ::Colon) = + Base._mapreduce(f, |, IndexCartesian(), A) +Base._all(f, A::Union{SparseVectorUnion, AdjOrTransSparseVectorUnion}, ::Colon) = + Base._mapreduce(f, &, IndexCartesian(), A) + function Base.mapreducedim!(f, op, R::AbstractVector, A::SparseVectorUnion) # dim1 reduction could be safely replaced with a mapreduce if length(R) == 1 From 33dec50768b725f7eeb3224bb5e0420c1d6eb81a Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Fri, 2 Sep 2022 11:13:02 +0200 Subject: [PATCH 07/13] rm AdjOrTrans handling --- src/sparsematrix.jl | 9 --------- src/sparsevector.jl | 9 --------- 2 files changed, 18 deletions(-) diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index 74adbce9..e8e408f1 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -209,11 +209,6 @@ nnz(S::LowerTriangular{<:Any,<:AbstractSparseMatrixCSC}) = nnz1(S) nnz(S::SparseMatrixCSCView) = nnz1(S) nnz1(S) = sum(length.(nzrange.(Ref(S), axes(S, 2)))) -Base._count(f, A::Adjoint{<:Any,<:AbstractSparseMatrixCSC}, ::Colon, init) = - Base._simple_count(f∘adjoint, parent(A), init) -Base._count(f, A::Transpose{<:Any,<:AbstractSparseMatrixCSC}, ::Colon, init) = - Base._simple_count(f∘transpose, parent(A), init) - function Base._simple_count(pred, S::AbstractSparseMatrixCSC, init::T) where T init + T(count(pred, nzvalview(S)) + pred(zero(eltype(S)))*(prod(size(S)) - nnz(S))) end @@ -2175,10 +2170,6 @@ function Base._mapreduce(f, op, ::Base.IndexCartesian, A::AbstractSparseMatrixCS _mapreducezeros(f, op, T, n-z, Base._mapreduce(f, op, nzvalview(A))) end end -Base._mapreduce(f, op, ::Base.IndexCartesian, A::Adjoint{<:Any,<:AbstractSparseMatrixCSC}) = - Base._mapreduce(f∘adjoint, op, IndexCartesian(), parent(A)) -Base._mapreduce(f, op, ::Base.IndexCartesian, A::Transpose{<:Any,<:AbstractSparseMatrixCSC}) = - Base._mapreduce(f∘transpose, op, IndexCartesian(), parent(A)) # Specialized mapreduce for +/*/min/max/_extrema_rf _mapreducezeros(f, op::Union{typeof(Base.add_sum),typeof(+)}, ::Type{T}, nzeros::Integer, v0) where {T} = diff --git a/src/sparsevector.jl b/src/sparsevector.jl index 627d5c3b..7a5966fa 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -97,11 +97,6 @@ function Base._simple_count(f, x::AbstractCompressedVector, init::T) where T init + T(count(f, nonzeros(x)) + f(zero(eltype(x)))*(length(x) - nnz(x))) end -Base._count(f, x::Adjoint{<:Any,<:AbstractCompressedVector}, ::Colon, init) = - Base._simple_count(f∘adjoint, parent(x), init) -Base._count(f, x::Transpose{<:Any,<:AbstractCompressedVector}, ::Colon, init) = - Base._simple_count(f∘transpose, parent(x), init) - # implement the nnz - nzrange - nonzeros - rowvals interface for sparse vectors nnz(x::AbstractCompressedVector) = length(nonzeros(x)) @@ -1496,10 +1491,6 @@ function Base._mapreduce(f, op, ::IndexCartesian, A::SparseVectorUnion{T}) where end _mapreducezeros(f, op, T, rest, ini) end -Base._mapreduce(f, op, ::Base.IndexCartesian, A::Adjoint{<:Any,<:SparseVectorUnion}) = - Base._mapreduce(f∘adjoint, op, IndexCartesian(), parent(A)) -Base._mapreduce(f, op, ::Base.IndexCartesian, A::Transpose{<:Any,<:SparseVectorUnion}) = - Base._mapreduce(f∘transpose, op, IndexCartesian(), parent(A)) Base._any(f, A::Union{SparseVectorUnion, AdjOrTransSparseVectorUnion}, ::Colon) = Base._mapreduce(f, |, IndexCartesian(), A) From 6a3bc998b04cfe4f3625f29f06c409f20e4476d5 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Fri, 2 Sep 2022 11:26:29 +0200 Subject: [PATCH 08/13] same with _any and _all --- src/sparsematrix.jl | 4 ++-- src/sparsevector.jl | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index e8e408f1..e8d7c7b0 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -2182,9 +2182,9 @@ _mapreducezeros(f::Base.ExtremaMap, op::typeof(Base._extrema_rf), ::Type{T}, nze nzeros == 0 ? v0 : op(v0, f(zero(T))) # Specialized mapreduce for any and all -Base._any(f, A::AbstractSparseMatrixCSCInclAdjointAndTranspose, ::Colon) = +Base._any(f, A::AbstractSparseMatrixCSC, ::Colon) = Base._mapreduce(f, |, IndexCartesian(), A) -Base._all(f, A::AbstractSparseMatrixCSCInclAdjointAndTranspose, ::Colon) = +Base._all(f, A::AbstractSparseMatrixCSC, ::Colon) = Base._mapreduce(f, &, IndexCartesian(), A) function Base._mapreduce(f, op::typeof(*), ::Base.IndexCartesian, A::AbstractSparseMatrixCSC{T}) where T diff --git a/src/sparsevector.jl b/src/sparsevector.jl index 7a5966fa..225966f9 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -1492,10 +1492,8 @@ function Base._mapreduce(f, op, ::IndexCartesian, A::SparseVectorUnion{T}) where _mapreducezeros(f, op, T, rest, ini) end -Base._any(f, A::Union{SparseVectorUnion, AdjOrTransSparseVectorUnion}, ::Colon) = - Base._mapreduce(f, |, IndexCartesian(), A) -Base._all(f, A::Union{SparseVectorUnion, AdjOrTransSparseVectorUnion}, ::Colon) = - Base._mapreduce(f, &, IndexCartesian(), A) +Base._any(f, A::SparseVectorUnion, ::Colon) = Base._mapreduce(f, |, IndexCartesian(), A) +Base._all(f, A::SparseVectorUnion, ::Colon) = Base._mapreduce(f, &, IndexCartesian(), A) function Base.mapreducedim!(f, op, R::AbstractVector, A::SparseVectorUnion) # dim1 reduction could be safely replaced with a mapreduce From 340676255e818d731e0701130101c91fb93f36b0 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Mon, 5 Sep 2022 19:54:04 +0200 Subject: [PATCH 09/13] more tests --- test/sparsematrix_ops.jl | 23 +++++++++++++++++++++++ test/sparsevector.jl | 21 +++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/test/sparsematrix_ops.jl b/test/sparsematrix_ops.jl index e047b156..778dd3e5 100644 --- a/test/sparsematrix_ops.jl +++ b/test/sparsematrix_ops.jl @@ -199,6 +199,29 @@ dA = Array(sA) # @test f(x->sqrt(x-1), pA .+ 1, dims=3) ≈ f(pA) end + @testset "logical reductions" begin + v = spzeros(Bool, 5, 2) + @test !any(v) + @test !all(v) + @test iszero(v) + @test count(v) == 0 + v = SparseMatrixCSC(5, 2, [1, 2, 2], [1], [false]) + @test !any(v) + @test !all(v) + @test iszero(v) + @test count(v) == 0 + v[2,1] = true + @test any(v) + @test !all(v) + @test !iszero(v) + @test count(v) == 1 + v .= true + @test any(v) + @test all(v) + @test !iszero(v) + @test count(v) == length(v) + end + @testset "empty cases" begin errchecker(str) = occursin("reducing over an empty collection is not allowed", str) || occursin("collection slices must be non-empty", str) diff --git a/test/sparsevector.jl b/test/sparsevector.jl index 725b8031..708879f5 100644 --- a/test/sparsevector.jl +++ b/test/sparsevector.jl @@ -932,6 +932,27 @@ end v[3] = 2 @test argmax(v) == 3 end + + let + v = spzeros(Bool, 5) + @test !any(v) + @test !all(v) + @test iszero(v) + @test count(v) == 0 + v = SparseVector(5, [1], [false]) + @test !any(v) + @test !all(v) + @test iszero(v) + @test count(v) == 0 + v[2] = true + @test any(v) + @test !all(v) + @test count(v) == 1 + v .= true + @test any(v) + @test all(v) + @test count(v) == length(v) + end end ### linalg From 3cd18db391d1cf11f39fee434cfe04fb33011ca0 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Tue, 6 Sep 2022 10:16:21 +0200 Subject: [PATCH 10/13] improve coverage --- src/sparsematrix.jl | 2 +- test/sparsematrix_ops.jl | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index e8d7c7b0..00300d74 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -2187,7 +2187,7 @@ Base._any(f, A::AbstractSparseMatrixCSC, ::Colon) = Base._all(f, A::AbstractSparseMatrixCSC, ::Colon) = Base._mapreduce(f, &, IndexCartesian(), A) -function Base._mapreduce(f, op::typeof(*), ::Base.IndexCartesian, A::AbstractSparseMatrixCSC{T}) where T +function Base._mapreduce(f, op::Union{typeof(Base.mul_prod),typeof(*)}, ::Base.IndexCartesian, A::AbstractSparseMatrixCSC{T}) where T nzeros = widelength(A)-nnz(A) if nzeros == 0 # No zeros, so don't compute f(0) since it might throw diff --git a/test/sparsematrix_ops.jl b/test/sparsematrix_ops.jl index 778dd3e5..e410ae6d 100644 --- a/test/sparsematrix_ops.jl +++ b/test/sparsematrix_ops.jl @@ -174,7 +174,7 @@ dA = Array(sA) pA = sparse(rand(3, 7)) p28227 = sparse(Real[0 0.5]) - for arr in (se33, sA, pA, p28227) + for arr in (se33, sA, pA, p28227, spzeros(3, 3)) for f in (sum, prod, minimum, maximum) farr = Array(arr) @test f(arr) ≈ f(farr) @@ -183,6 +183,11 @@ dA = Array(sA) @test f(arr, dims=(1, 2)) ≈ [f(farr)] @test isequal(f(arr, dims=3), f(farr, dims=3)) end + for f in (+, *, minimum, maximum) + farr = Array(arr) + @test mapreduce(identity, f, arr) ≈ mapreduce(identity, f, farr) + @test mapreduce(x -> x + 1, f, arr) ≈ mapreduce(x -> x + 1, f, farr) + end end for f in (sum, prod, minimum, maximum) @@ -210,6 +215,11 @@ dA = Array(sA) @test !all(v) @test iszero(v) @test count(v) == 0 + v = SparseMatrixCSC(5, 2, [1, 2, 2], [1], [true]) + @test !any(v) + @test !all(v) + @test iszero(v) + @test count(v) == 1 v[2,1] = true @test any(v) @test !all(v) From ae1f7ef0abc42c56fac6a1823668c6985bec2c48 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Tue, 6 Sep 2022 10:48:33 +0200 Subject: [PATCH 11/13] fix copy-paste errors --- test/sparsematrix_ops.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/sparsematrix_ops.jl b/test/sparsematrix_ops.jl index e410ae6d..8e7a92d2 100644 --- a/test/sparsematrix_ops.jl +++ b/test/sparsematrix_ops.jl @@ -216,15 +216,15 @@ dA = Array(sA) @test iszero(v) @test count(v) == 0 v = SparseMatrixCSC(5, 2, [1, 2, 2], [1], [true]) - @test !any(v) + @test any(v) @test !all(v) - @test iszero(v) + @test !iszero(v) @test count(v) == 1 v[2,1] = true @test any(v) @test !all(v) @test !iszero(v) - @test count(v) == 1 + @test count(v) == 2 v .= true @test any(v) @test all(v) From 1db38bac5dcd735a819739b7a10a9ec5d38f39bd Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Tue, 6 Sep 2022 13:28:40 +0200 Subject: [PATCH 12/13] fix test? --- test/sparsematrix_ops.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sparsematrix_ops.jl b/test/sparsematrix_ops.jl index 8e7a92d2..01dd647e 100644 --- a/test/sparsematrix_ops.jl +++ b/test/sparsematrix_ops.jl @@ -183,7 +183,7 @@ dA = Array(sA) @test f(arr, dims=(1, 2)) ≈ [f(farr)] @test isequal(f(arr, dims=3), f(farr, dims=3)) end - for f in (+, *, minimum, maximum) + for f in (+, *, min, max) farr = Array(arr) @test mapreduce(identity, f, arr) ≈ mapreduce(identity, f, farr) @test mapreduce(x -> x + 1, f, arr) ≈ mapreduce(x -> x + 1, f, farr) From 170a811f3fdae85cc016de99a3195d65dd3ea301 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Tue, 6 Sep 2022 15:12:45 +0200 Subject: [PATCH 13/13] fix all-zero case --- src/sparsematrix.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index 00300d74..e4a21693 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -2188,14 +2188,15 @@ Base._all(f, A::AbstractSparseMatrixCSC, ::Colon) = Base._mapreduce(f, &, IndexCartesian(), A) function Base._mapreduce(f, op::Union{typeof(Base.mul_prod),typeof(*)}, ::Base.IndexCartesian, A::AbstractSparseMatrixCSC{T}) where T - nzeros = widelength(A)-nnz(A) + nnzA = nnz(A) + nzeros = widelength(A) - nnzA if nzeros == 0 # No zeros, so don't compute f(0) since it might throw Base._mapreduce(f, op, nzvalview(A)) else v = f(zero(T))^(nzeros) - # Bail out early if initial reduction value is zero - v == zero(T) ? v : v*Base._mapreduce(f, op, nzvalview(A)) + # Bail out early if initial reduction value is zero or if there are no stored elements + (v == zero(T) || nnzA == 0) ? v : v*Base._mapreduce(f, op, nzvalview(A)) end end