From ac0cc6e8278bb614dc2a16e9353fa092dae6606a Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Fri, 18 Apr 2025 22:34:12 -0400 Subject: [PATCH] unify reduce/reducedim empty case behaviors --- src/sparsematrix.jl | 7 +----- src/sparsevector.jl | 1 + test/sparsematrix_ops.jl | 49 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/sparsematrix.jl b/src/sparsematrix.jl index 38a6748b..38bc9f08 100644 --- a/src/sparsematrix.jl +++ b/src/sparsematrix.jl @@ -2650,12 +2650,7 @@ function _findr(op, A::AbstractSparseMatrixCSC{Tv}, region) where {Tv} N = nnz(A) L = widelength(A) if L == 0 - if prod(map(length, Base.reduced_indices(A, region))) != 0 - throw(ArgumentError("array slices must be non-empty")) - else - ri = Base.reduced_indices0(A, region) - return (zeros(Tv, ri), zeros(Ti, ri)) - end + throw(ArgumentError("reducing over an empty collection is not allowed")) end colptr = getcolptr(A); rowval = rowvals(A); nzval = nonzeros(A); m = size(A, 1); n = size(A, 2) diff --git a/src/sparsevector.jl b/src/sparsevector.jl index 6734b986..76867a56 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -1682,6 +1682,7 @@ Base._all(f, A::SparseVectorUnion, ::Colon) = iszero(length(A)) ? true : Base._mapreduce(f, &, IndexCartesian(), A) function Base.mapreducedim!(f, op, R::AbstractVector, A::SparseVectorUnion) + isempty(A) && return R # dim1 reduction could be safely replaced with a mapreduce if length(R) == 1 I = firstindex(R) diff --git a/test/sparsematrix_ops.jl b/test/sparsematrix_ops.jl index d99418a8..23316140 100644 --- a/test/sparsematrix_ops.jl +++ b/test/sparsematrix_ops.jl @@ -172,6 +172,12 @@ sC = similar(sA) dA = Array(sA) @testset "reductions" begin + se33 = SparseMatrixCSC{Float64}(I, 3, 3) + do33 = fill(1.,3) + sA = sprandn(3, 7, 0.5) + sC = similar(sA) + dA = Array(sA) + pA = sparse(rand(3, 7)) p28227 = sparse(Real[0 0.5]) @@ -256,9 +262,48 @@ dA = Array(sA) end for f in (minimum, maximum, findmin, findmax) @test_throws errchecker f(spzeros(0, 1), dims=1) - @test isequal(f(spzeros(0, 1), dims=2), f(Matrix{Int}(I, 0, 1), dims=2)) + @test_throws errchecker f(spzeros(0, 1), dims=2) @test_throws errchecker f(spzeros(0, 1), dims=(1, 2)) - @test isequal(f(spzeros(0, 1), dims=3), f(Matrix{Int}(I, 0, 1), dims=3)) + @test_throws errchecker f(spzeros(0, 1), dims=3) + end + + some_exception(op) = try return (Some(op()), nothing); catch ex; return (nothing, ex); end + reduced_shape(sz, dims) = ntuple(d -> d in dims ? 1 : sz[d], length(sz)) + + @testset "$r(spzeros($T, $sz); dims=$dims)" for + r in (minimum, maximum, findmin, findmax, extrema, sum, prod, mapreduce, all, any, count), + T in (Int, Union{Missing, Int}, Number, Union{Missing, Number}, Bool, Union{Missing, Bool}), + sz in ((0,), (0,1), (1,0), (0,0),), + dims in (1, 2, (1,2)) + + A = spzeros(T, sz...) + rsz = reduced_shape(sz, dims) + + v, ex = some_exception() do; r(A); end + if isnothing(v) + @test_throws typeof(ex) r(A; dims) + @test_throws typeof(ex) r(zeros(T, sz...)) + @test_throws typeof(ex) r(zeros(T, sz...); dims) + else + actual = fill(something(v), rsz) + @test something(v) === r(zeros(T, sz...)) + @test isequal(r(A; dims), actual) + @test eltype(r(A; dims)) === eltype(actual) + end + + for f in (identity, abs, abs2) + v, ex = some_exception() do; r(f, A); end + if isnothing(v) + @test_throws typeof(ex) r(f, A; dims) + @test_throws typeof(ex) r(f, zeros(T, sz...)) + @test_throws typeof(ex) r(f, zeros(T, sz...); dims) + else + actual = fill(something(v), rsz) + @test something(v) === r(f, zeros(T, sz...)) + @test isequal(r(f, A; dims), actual) + @test eltype(r(f, A; dims)) === eltype(actual) + end + end end end end