Skip to content

Commit 31c67c2

Browse files
committed
Adjust initialization in maximum and minimum
Fixes #27836
1 parent e2de9b3 commit 31c67c2

File tree

4 files changed

+34
-27
lines changed

4 files changed

+34
-27
lines changed

base/reducedim.jl

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -79,25 +79,6 @@ end
7979
reducedim_initarray(A::AbstractArray, region, v0, ::Type{R}) where {R} = fill!(similar(A,R,reduced_indices(A,region)), v0)
8080
reducedim_initarray(A::AbstractArray, region, v0::T) where {T} = reducedim_initarray(A, region, v0, T)
8181

82-
function reducedim_initarray0(A::AbstractArray{T}, region, f, ops) where T
83-
ri = reduced_indices0(A, region)
84-
if isempty(A)
85-
if prod(length, reduced_indices(A, region)) != 0
86-
reducedim_initarray0_empty(A, region, f, ops) # ops over empty slice of A
87-
else
88-
R = f == identity ? T : Core.Compiler.return_type(f, (T,))
89-
similar(A, R, ri)
90-
end
91-
else
92-
R = f == identity ? T : typeof(f(first(A)))
93-
si = similar(A, R, ri)
94-
mapfirst!(f, si, A)
95-
end
96-
end
97-
98-
reducedim_initarray0_empty(A::AbstractArray, region, f, ops) = mapslices(x->ops(f.(x)), A, region)
99-
reducedim_initarray0_empty(A::AbstractArray, region,::typeof(identity), ops) = mapslices(ops, A, region)
100-
10182
# TODO: better way to handle reducedim initialization
10283
#
10384
# The current scheme is basically following Steven G. Johnson's original implementation
@@ -124,8 +105,33 @@ function _reducedim_init(f, op, fv, fop, A, region)
124105
return reducedim_initarray(A, region, z, Tr)
125106
end
126107

127-
reducedim_init(f, op::typeof(max), A::AbstractArray{T}, region) where {T} = reducedim_initarray0(A, region, f, maximum)
128-
reducedim_init(f, op::typeof(min), A::AbstractArray{T}, region) where {T} = reducedim_initarray0(A, region, f, minimum)
108+
# initialization when computing minima and maxima requires a little care
109+
for (f1, f2, supval) in ((min, max, Inf), (max, min, -Inf))
110+
function reducedim_init(f, op::typeof(f1), A::AbstractArray, region)
111+
# First compute the reduce indices. This will throw an ArgumentError
112+
# if any region is invalid
113+
ri = Base.reduced_indices(A, region)
114+
115+
# Next, throw if reduction is over a region with length zero
116+
any(i -> iszero(size(A, i)), region) && _empty_reduce_error()
117+
118+
# Make a view of the first slice of the region
119+
A1 = view(A, ri...)
120+
121+
if isempty(A1)
122+
# If the slice is empty just return non-view version as the initial array
123+
return copy(A1)
124+
else
125+
# otherwise use the min/max of the first slice as initial value
126+
v0 = mapreduce(f, f2, A1)
127+
128+
# but NaNs need to be avoided as intial values
129+
v0 = v0 != v0 ? typeof(v0)(supval) : v0
130+
131+
return reducedim_initarray(A, region, v0)
132+
end
133+
end
134+
end
129135
reducedim_init(f::Union{typeof(abs),typeof(abs2)}, op::typeof(max), A::AbstractArray{T}, region) where {T} =
130136
reducedim_initarray(A, region, zero(f(zero(T))))
131137

stdlib/SparseArrays/src/sparsematrix.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,8 +1608,6 @@ end
16081608
# non-trivial, so use Arrays for output
16091609
Base.reducedim_initarray(A::SparseMatrixCSC, region, v0, ::Type{R}) where {R} =
16101610
fill(v0, Base.reduced_indices(A,region))
1611-
Base.reducedim_initarray0(A::SparseMatrixCSC, region, v0, ::Type{R}) where {R} =
1612-
fill(v0, Base.reduced_indices0(A,region))
16131611

16141612
# General mapreduce
16151613
function _mapreducezeros(f, op, ::Type{T}, nzeros::Int, v0) where T

stdlib/SparseArrays/test/higherorderfns.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,5 +628,8 @@ end
628628
@test Diagonal(spzeros(5)) \ view(rand(10), 1:5) == [Inf,Inf,Inf,Inf,Inf]
629629
end
630630

631+
@testset "Issue #27836" begin
632+
@test minimum(sparse([1, 2], [1, 2], ones(Int32, 2)), dims = 1) isa Matrix
633+
end
631634

632635
end # module

test/reducedim.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ safe_maxabs(A::Array{T}, region) where {T} = safe_mapslices(maximum, abs.(A), re
1818
safe_minabs(A::Array{T}, region) where {T} = safe_mapslices(minimum, abs.(A), region)
1919

2020
Areduc = rand(3, 4, 5, 6)
21-
for region in Any[
21+
@testset "test reductions over region: $region" for region in Any[
2222
1, 2, 3, 4, 5, (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4),
2323
(1, 2, 3), (1, 3, 4), (2, 3, 4), (1, 2, 3, 4)]
2424
# println("region = $region")
@@ -318,10 +318,10 @@ end
318318
@test sum(Any[1 2;3 4], dims=1) == [4 6]
319319
@test sum(Vector{Int}[[1,2],[4,3]], dims=1)[1] == [5,5]
320320

321-
# issue #10461
322-
Areduc = rand(3, 4, 5, 6)
323-
for region in Any[-1, 0, (-1, 2), [0, 1], (1,-2,3), [0 1;
321+
@testset "Issue #10461. region=$region" for region in Any[-1, 0, (-1, 2), [0, 1], (1,-2,3), [0 1;
324322
2 3], "hello"]
323+
Areduc = rand(3, 4, 5, 6)
324+
325325
@test_throws ArgumentError sum(Areduc, dims=region)
326326
@test_throws ArgumentError prod(Areduc, dims=region)
327327
@test_throws ArgumentError maximum(Areduc, dims=region)

0 commit comments

Comments
 (0)