From 5301c0652f0d3f3323dcff78622d93cc58bd435f Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Fri, 18 Apr 2025 22:30:06 -0400 Subject: [PATCH 1/7] use a boolean operator for any/all, not bitwise and add more comprehensive tests --- base/reduce.jl | 7 +++++-- base/reducedim.jl | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index c132ef385358d..5dbe5ca7c3e60 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -29,6 +29,9 @@ mul_prod(x::BitSignedSmall, y::BitSignedSmall) = Int(x) * Int(y) mul_prod(x::BitUnsignedSmall, y::BitUnsignedSmall) = UInt(x) * UInt(y) mul_prod(x::Real, y::Real)::Real = x * y +and_all(x,y) = Bool(x && y) +or_any(x,y) = Bool(x || y) + ## foldl && mapfoldl function mapfoldl_impl(f::F, op::OP, nt, itr) where {F,OP} @@ -336,8 +339,8 @@ reduce_empty(::typeof(+), ::Type{T}) where {T} = zero(T) reduce_empty(::typeof(+), ::Type{Bool}) = zero(Int) reduce_empty(::typeof(*), ::Type{T}) where {T} = one(T) reduce_empty(::typeof(*), ::Type{<:AbstractChar}) = "" -reduce_empty(::typeof(&), ::Type{Bool}) = true -reduce_empty(::typeof(|), ::Type{Bool}) = false +reduce_empty(::typeof(and_all), ::Type{T}) where {T} = true +reduce_empty(::typeof(or_any), ::Type{T}) where {T} = false reduce_empty(::typeof(add_sum), ::Type{T}) where {T} = reduce_empty(+, T) reduce_empty(::typeof(add_sum), ::Type{T}) where {T<:BitSignedSmall} = zero(Int) diff --git a/base/reducedim.jl b/base/reducedim.jl index 0478afe1a46b6..cd2a8dfe38355 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -45,7 +45,7 @@ end initarray!(a::AbstractArray{T}, f, ::Union{typeof(min),typeof(max),typeof(_extrema_rf)}, init::Bool, src::AbstractArray) where {T} = (init && mapfirst!(f, a, src); a) -for (Op, initval) in ((:(typeof(&)), true), (:(typeof(|)), false)) +for (Op, initval) in ((:(typeof(and_all)), true), (:(typeof(or_any)), false)) @eval initarray!(a::AbstractArray, ::Any, ::$(Op), init::Bool, src::AbstractArray) = (init && fill!(a, $initval); a) end @@ -173,8 +173,8 @@ end reducedim_init(f::Union{typeof(abs),typeof(abs2)}, op::typeof(max), A::AbstractArray{T}, region) where {T} = reducedim_initarray(A, region, zero(f(zero(T))), _realtype(f, T)) -reducedim_init(f, op::typeof(&), A::AbstractArrayOrBroadcasted, region) = reducedim_initarray(A, region, true) -reducedim_init(f, op::typeof(|), A::AbstractArrayOrBroadcasted, region) = reducedim_initarray(A, region, false) +reducedim_init(f, op::typeof(and_all), A::AbstractArrayOrBroadcasted, region) = reducedim_initarray(A, region, true) +reducedim_init(f, op::typeof(or_any), A::AbstractArrayOrBroadcasted, region) = reducedim_initarray(A, region, false) # specialize to make initialization more efficient for common cases @@ -994,7 +994,7 @@ _all(a, ::Colon) = _all(identity, a, :) for (fname, op) in [(:sum, :add_sum), (:prod, :mul_prod), (:maximum, :max), (:minimum, :min), - (:all, :&), (:any, :|), + (:all, :and_all), (:any, :or_any), (:extrema, :_extrema_rf)] fname! = Symbol(fname, '!') _fname = Symbol('_', fname) From 31889bfba7f2d7f009bbf3c8a706a67761f5a583 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Mon, 21 Apr 2025 12:04:04 -0400 Subject: [PATCH 2/7] restore broken Bool behaviors for & and | --- base/reducedim.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/base/reducedim.jl b/base/reducedim.jl index cd2a8dfe38355..3be3567aa744d 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -176,6 +176,10 @@ reducedim_init(f::Union{typeof(abs),typeof(abs2)}, op::typeof(max), A::AbstractA reducedim_init(f, op::typeof(and_all), A::AbstractArrayOrBroadcasted, region) = reducedim_initarray(A, region, true) reducedim_init(f, op::typeof(or_any), A::AbstractArrayOrBroadcasted, region) = reducedim_initarray(A, region, false) +# These definitions are wrong in general; Cf. JuliaLang/julia#45562 +reducedim_init(f, op::typeof(&), A::AbstractArrayOrBroadcasted, region) = reducedim_initarray(A, region, true) +reducedim_init(f, op::typeof(|), A::AbstractArrayOrBroadcasted, region) = reducedim_initarray(A, region, false) + # specialize to make initialization more efficient for common cases let From 580bb5e710b543aded63a46555965a8e34c65ce8 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Mon, 21 Apr 2025 14:29:11 -0400 Subject: [PATCH 3/7] fix doctests --- base/reducedim.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/base/reducedim.jl b/base/reducedim.jl index 3be3567aa744d..412cfd8d91f27 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -887,13 +887,13 @@ julia> A = [true false; true false] 1 0 1 0 -julia> all!([1; 1], A) -2-element Vector{Int64}: +julia> all!(Bool[1; 1], A) +2-element Vector{Bool}: 0 0 -julia> all!([1 1], A) -1×2 Matrix{Int64}: +julia> all!(Bool[1 1], A) +1×2 Matrix{Bool}: 1 0 ``` """ @@ -962,12 +962,12 @@ julia> A = [true false; true false] 1 0 1 0 -julia> any!([1; 1], A) +julia> any!(Bool[1; 1], A) 2-element Vector{Int64}: 1 1 -julia> any!([1 1], A) +julia> any!(Bool[1 1], A) 1×2 Matrix{Int64}: 1 0 ``` From fd531e4609141a51b783e5dc1eed0f619e3582c3 Mon Sep 17 00:00:00 2001 From: Lilith Hafner Date: Fri, 3 Jun 2022 18:05:23 -0400 Subject: [PATCH 4/7] test use mapslices instead of mapreduce for all/any --- test/reduce.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/reduce.jl b/test/reduce.jl index f5140c8a34bd9..807ebba9346c0 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -681,6 +681,13 @@ end end end +@testset "issue #45562" begin + @test all([true, true, true], dims = 1) == [true] + @test any([true, true, true], dims = 1) == [true] + @test_throws TypeError all([3, 3, 3], dims = 1) + @test_throws TypeError any([3, 3, 3], dims = 1) +end + # issue #45748 @testset "foldl's stability for nested Iterators" begin a = Iterators.flatten((1:3, 1:3)) From 69e4dee88a4e3a418abe59a36caac11e811ccd7c Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Mon, 21 Apr 2025 16:21:26 -0400 Subject: [PATCH 5/7] preserve and test more existing behaviors --- base/reduce.jl | 2 ++ test/reduce.jl | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/base/reduce.jl b/base/reduce.jl index 5dbe5ca7c3e60..303747e8fe38a 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -339,6 +339,8 @@ reduce_empty(::typeof(+), ::Type{T}) where {T} = zero(T) reduce_empty(::typeof(+), ::Type{Bool}) = zero(Int) reduce_empty(::typeof(*), ::Type{T}) where {T} = one(T) reduce_empty(::typeof(*), ::Type{<:AbstractChar}) = "" +reduce_empty(::typeof(&), ::Type{Bool}) = true +reduce_empty(::typeof(|), ::Type{Bool}) = false reduce_empty(::typeof(and_all), ::Type{T}) where {T} = true reduce_empty(::typeof(or_any), ::Type{T}) where {T} = false diff --git a/test/reduce.jl b/test/reduce.jl index 807ebba9346c0..d26cacbae045a 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -686,6 +686,10 @@ end @test any([true, true, true], dims = 1) == [true] @test_throws TypeError all([3, 3, 3], dims = 1) @test_throws TypeError any([3, 3, 3], dims = 1) + @test reduce(|, Bool[]) == false + @test reduce(&, Bool[]) == true + @test reduce(|, Bool[], dims=1) == [false] + @test reduce(&, Bool[], dims=1) == [true] end # issue #45748 From 855bef3b0609b2dd24720680bcb27b94137854b3 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Tue, 22 Apr 2025 09:04:49 -0400 Subject: [PATCH 6/7] Fixup doctests and whitespace in tests Co-authored-by: Lilith Orion Hafner --- base/reducedim.jl | 4 ++-- test/reduce.jl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/base/reducedim.jl b/base/reducedim.jl index 412cfd8d91f27..ba3434494bc0b 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -963,12 +963,12 @@ julia> A = [true false; true false] 1 0 julia> any!(Bool[1; 1], A) -2-element Vector{Int64}: +2-element Vector{Bool}: 1 1 julia> any!(Bool[1 1], A) -1×2 Matrix{Int64}: +1×2 Matrix{Bool}: 1 0 ``` """ diff --git a/test/reduce.jl b/test/reduce.jl index d26cacbae045a..1ea72ce8920ff 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -682,8 +682,8 @@ end end @testset "issue #45562" begin - @test all([true, true, true], dims = 1) == [true] - @test any([true, true, true], dims = 1) == [true] + @test all([true, true, true], dims = 1) == [true] + @test any([true, true, true], dims = 1) == [true] @test_throws TypeError all([3, 3, 3], dims = 1) @test_throws TypeError any([3, 3, 3], dims = 1) @test reduce(|, Bool[]) == false From 7746c9629266c8cd73615442493b511525e4d5e4 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Tue, 22 Apr 2025 10:43:50 -0400 Subject: [PATCH 7/7] use assertion, not conversion and more tests --- base/reduce.jl | 7 +++++-- test/reduce.jl | 10 ++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index 303747e8fe38a..bd29d7eb3d889 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -29,8 +29,11 @@ mul_prod(x::BitSignedSmall, y::BitSignedSmall) = Int(x) * Int(y) mul_prod(x::BitUnsignedSmall, y::BitUnsignedSmall) = UInt(x) * UInt(y) mul_prod(x::Real, y::Real)::Real = x * y -and_all(x,y) = Bool(x && y) -or_any(x,y) = Bool(x || y) +and_all(x, y) = (x && y)::Bool +or_any(x, y) = (x || y)::Bool +# As a performance optimization, avoid runtime branches: +and_all(x::Bool, y::Bool) = (x & y)::Bool +or_any(x::Bool, y::Bool) = (x | y)::Bool ## foldl && mapfoldl diff --git a/test/reduce.jl b/test/reduce.jl index 1ea72ce8920ff..bb54462bb78f0 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -686,6 +686,16 @@ end @test any([true, true, true], dims = 1) == [true] @test_throws TypeError all([3, 3, 3], dims = 1) @test_throws TypeError any([3, 3, 3], dims = 1) + @test_throws TypeError all(Any[true, 3, 3], dims = 1) + @test_throws TypeError any(Any[false, 3, 3], dims = 1) + @test_throws TypeError all([1, 1, 1], dims = 1) + @test_throws TypeError any([0, 0, 0], dims = 1) + @test_throws TypeError all!([false], [3, 3, 3]) + @test_throws TypeError any!([false], [3, 3, 3]) + @test_throws TypeError all!([false], Any[true, 3, 3]) + @test_throws TypeError any!([false], Any[false, 3, 3]) + @test_throws TypeError all!([false], [1, 1, 1]) + @test_throws TypeError any!([false], [0, 0, 0]) @test reduce(|, Bool[]) == false @test reduce(&, Bool[]) == true @test reduce(|, Bool[], dims=1) == [false]