From c923b1ddf06466ab094bf8af1ecff3c30fa187e8 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Fri, 9 May 2025 22:46:27 -0400 Subject: [PATCH 1/5] counting and summing Bools with a small integer `init` promote to `[U]Int`. --- base/reduce.jl | 12 ++++++++---- test/reduce.jl | 10 +++++----- test/reducedim.jl | 10 +++++----- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index 9041fd088ccf3..95a740d9e38a9 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -14,8 +14,9 @@ The reduction operator used in `sum`. The main difference from [`+`](@ref) is th integers are promoted to `Int`/`UInt`. """ add_sum(x, y) = x + y -add_sum(x::BitSignedSmall, y::BitSignedSmall) = Int(x) + Int(y) -add_sum(x::BitUnsignedSmall, y::BitUnsignedSmall) = UInt(x) + UInt(y) +add_sum(x::Bool, y::Bool) = Int(x) + Int(y) +add_sum(x::Union{Bool,BitSignedSmall}, y::Union{Bool,BitSignedSmall}) = Int(x) + Int(y) +add_sum(x::Union{Bool,BitUnsignedSmall}, y::Union{Bool,BitUnsignedSmall}) = UInt(x) + UInt(y) add_sum(x::Real, y::Real)::Real = x + y """ @@ -402,6 +403,7 @@ reduce_first(::typeof(+), x::Bool) = Int(x) reduce_first(::typeof(*), x::AbstractChar) = string(x) reduce_first(::typeof(add_sum), x) = reduce_first(+, x) +reduce_first(::typeof(add_sum), x::Bool) = Int(x) reduce_first(::typeof(add_sum), x::BitSignedSmall) = Int(x) reduce_first(::typeof(add_sum), x::BitUnsignedSmall) = UInt(x) reduce_first(::typeof(mul_prod), x) = reduce_first(*, x) @@ -1083,8 +1085,10 @@ count(f, itr; init=0) = _simple_count(f, itr, init) _simple_count(pred, itr, init) = sum(_bool(pred), itr; init) -function _simple_count(::typeof(identity), x::Array{Bool}, init::T=0) where {T} - n::T = init +function _simple_count(::typeof(identity), x::Array{Bool}, init=0) + v0 = Base.add_sum(init, false) + T = typeof(v0) + n::T = v0 chunks = length(x) ÷ sizeof(UInt) mask = 0x0101010101010101 % UInt GC.@preserve x begin diff --git a/test/reduce.jl b/test/reduce.jl index c6274711cdef4..329f18149b361 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -586,11 +586,11 @@ struct NonFunctionIsZero end @test count(NonFunctionIsZero(), [0]) == 1 @test count(NonFunctionIsZero(), [1]) == 0 -@test count(Iterators.repeated(true, 3), init=0x04) === 0x07 -@test count(!=(2), Iterators.take(1:7, 3), init=Int32(0)) === Int32(2) -@test count(identity, [true, false], init=Int8(5)) === Int8(6) -@test count(!, [true false; false true], dims=:, init=Int16(0)) === Int16(2) -@test isequal(count(identity, [true false; false true], dims=2, init=UInt(4)), reshape(UInt[5, 5], 2, 1)) +@test count(Iterators.repeated(true, 3), init=0x00) === UInt(3) +@test count(!=(2), Iterators.take(1:7, 3), init=Int32(0)) === 2 +@test count(identity, [true, false], init=Int8(0)) === 1 +@test count(!, [true false; false true], dims=:, init=Int16(0)) === 2 +@test isequal(count(identity, [true false; false true], dims=2, init=UInt(0)), reshape(UInt[1, 1], 2, 1)) ## cumsum, cummin, cummax diff --git a/test/reducedim.jl b/test/reducedim.jl index 6a6f20214058c..76efe6c503e21 100644 --- a/test/reducedim.jl +++ b/test/reducedim.jl @@ -88,12 +88,12 @@ safe_minabs(A::Array{T}, region) where {T} = safe_mapslices(minimum, abs.(A), re @test @inferred(count(!, Breduc, dims=region)) ≈ safe_count(.!Breduc, region) @test isequal( - @inferred(count(Breduc, dims=region, init=0x02)), - safe_count(Breduc, region) .% UInt8 .+ 0x02, + @inferred(Array{UInt8,ndims(Breduc)}, count(Breduc, dims=region, init=0x00)), + safe_count(Breduc, region), ) @test isequal( - @inferred(count(!, Breduc, dims=region, init=Int16(0))), - safe_count(.!Breduc, region) .% Int16, + @inferred(Array{Int16,ndims(Breduc)}, count(!, Breduc, dims=region, init=Int16(0))), + safe_count(.!Breduc, region), ) end @@ -693,7 +693,7 @@ end @test_throws TypeError count!([1], [1]) end -@test @inferred(count(false:true, dims=:, init=0x0004)) === 0x0005 +@test @inferred(UInt16, count(false:true, dims=:, init=0x0000)) === UInt(1) @test @inferred(count(isodd, reshape(1:9, 3, 3), dims=:, init=Int128(0))) === Int128(5) @testset "reduced_index for BigInt (issue #39995)" begin From 4bee1914f17bd512e15b07c3cdab1e042471cc6d Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Sat, 10 May 2025 00:57:42 -0400 Subject: [PATCH 2/5] Fix doctests --- base/reduce.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index 95a740d9e38a9..7eec4be071be7 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -1075,8 +1075,8 @@ julia> count(i->(4<=i<=6), [2,3,4,5,6]) julia> count([true, false, true, true]) 3 -julia> count(>(3), 1:7, init=0x03) -0x07 +julia> count(>(3), 1:7, init=0x00) +0x0000000000000004 ``` """ count(itr; init=0) = count(identity, itr; init) From 4fadd8f2cbc3dee450a996936f8e037f17186980 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Sat, 10 May 2025 20:31:20 -0400 Subject: [PATCH 3/5] keep the add_sum method table small for accumulate inference --- base/reduce.jl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index 7eec4be071be7..e280dda5a08b0 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -14,9 +14,11 @@ The reduction operator used in `sum`. The main difference from [`+`](@ref) is th integers are promoted to `Int`/`UInt`. """ add_sum(x, y) = x + y -add_sum(x::Bool, y::Bool) = Int(x) + Int(y) -add_sum(x::Union{Bool,BitSignedSmall}, y::Union{Bool,BitSignedSmall}) = Int(x) + Int(y) -add_sum(x::Union{Bool,BitUnsignedSmall}, y::Union{Bool,BitUnsignedSmall}) = UInt(x) + UInt(y) +add_sum(x::Integer, y::Integer)::Integer = add_sum_integer(x, y) +add_sum_integer(x::Bool, y::Bool) = Int(x) + Int(y) +add_sum_integer(x::Union{Bool,BitSignedSmall}, y::Union{Bool,BitSignedSmall}) = Int(x) + Int(y) +add_sum_integer(x::Union{Bool,BitUnsignedSmall}, y::Union{Bool,BitUnsignedSmall}) = UInt(x) + UInt(y) +add_sum_integer(x, y) = x+y add_sum(x::Real, y::Real)::Real = x + y """ @@ -403,8 +405,7 @@ reduce_first(::typeof(+), x::Bool) = Int(x) reduce_first(::typeof(*), x::AbstractChar) = string(x) reduce_first(::typeof(add_sum), x) = reduce_first(+, x) -reduce_first(::typeof(add_sum), x::Bool) = Int(x) -reduce_first(::typeof(add_sum), x::BitSignedSmall) = Int(x) +reduce_first(::typeof(add_sum), x::Union{Bool,BitSignedSmall}) = Int(x) reduce_first(::typeof(add_sum), x::BitUnsignedSmall) = UInt(x) reduce_first(::typeof(mul_prod), x) = reduce_first(*, x) reduce_first(::typeof(mul_prod), x::BitSignedSmall) = Int(x) From 32fc16babf14e0ac26ca36adaedee4d1a3d4f0c4 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Tue, 13 May 2025 21:15:37 -0400 Subject: [PATCH 4/5] promote to Int --- base/reduce.jl | 9 +++------ test/reduce.jl | 2 +- test/reducedim.jl | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index e280dda5a08b0..a6244f529c18e 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -14,11 +14,8 @@ The reduction operator used in `sum`. The main difference from [`+`](@ref) is th integers are promoted to `Int`/`UInt`. """ add_sum(x, y) = x + y -add_sum(x::Integer, y::Integer)::Integer = add_sum_integer(x, y) -add_sum_integer(x::Bool, y::Bool) = Int(x) + Int(y) -add_sum_integer(x::Union{Bool,BitSignedSmall}, y::Union{Bool,BitSignedSmall}) = Int(x) + Int(y) -add_sum_integer(x::Union{Bool,BitUnsignedSmall}, y::Union{Bool,BitUnsignedSmall}) = UInt(x) + UInt(y) -add_sum_integer(x, y) = x+y +add_sum(x::Union{Bool,BitIntegerSmall}, y::Union{Bool,BitIntegerSmall}) = Int(x) + Int(y) +add_sum(x::BitUnsignedSmall, y::BitUnsignedSmall) = UInt(x) + UInt(y) add_sum(x::Real, y::Real)::Real = x + y """ @@ -1076,7 +1073,7 @@ julia> count(i->(4<=i<=6), [2,3,4,5,6]) julia> count([true, false, true, true]) 3 -julia> count(>(3), 1:7, init=0x00) +julia> count(>(3), 1:7, init=UInt(0)) 0x0000000000000004 ``` """ diff --git a/test/reduce.jl b/test/reduce.jl index 329f18149b361..7500b00197847 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -586,7 +586,7 @@ struct NonFunctionIsZero end @test count(NonFunctionIsZero(), [0]) == 1 @test count(NonFunctionIsZero(), [1]) == 0 -@test count(Iterators.repeated(true, 3), init=0x00) === UInt(3) +@test count(Iterators.repeated(true, 3), init=UInt(0)) === UInt(3) @test count(!=(2), Iterators.take(1:7, 3), init=Int32(0)) === 2 @test count(identity, [true, false], init=Int8(0)) === 1 @test count(!, [true false; false true], dims=:, init=Int16(0)) === 2 diff --git a/test/reducedim.jl b/test/reducedim.jl index 76efe6c503e21..1664b2708d7e3 100644 --- a/test/reducedim.jl +++ b/test/reducedim.jl @@ -693,7 +693,7 @@ end @test_throws TypeError count!([1], [1]) end -@test @inferred(UInt16, count(false:true, dims=:, init=0x0000)) === UInt(1) +@test @inferred(UInt16, count(false:true, dims=:, init=0x0000)) === 1 @test @inferred(count(isodd, reshape(1:9, 3, 3), dims=:, init=Int128(0))) === Int128(5) @testset "reduced_index for BigInt (issue #39995)" begin From d375ab7fe86f0c5255ce2500c477e4732f394962 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Tue, 13 May 2025 22:28:26 -0400 Subject: [PATCH 5/5] remove unnecessary method --- base/reduce.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/reduce.jl b/base/reduce.jl index a6244f529c18e..cb4e9f07a21d2 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -402,7 +402,7 @@ reduce_first(::typeof(+), x::Bool) = Int(x) reduce_first(::typeof(*), x::AbstractChar) = string(x) reduce_first(::typeof(add_sum), x) = reduce_first(+, x) -reduce_first(::typeof(add_sum), x::Union{Bool,BitSignedSmall}) = Int(x) +reduce_first(::typeof(add_sum), x::BitSignedSmall) = Int(x) reduce_first(::typeof(add_sum), x::BitUnsignedSmall) = UInt(x) reduce_first(::typeof(mul_prod), x) = reduce_first(*, x) reduce_first(::typeof(mul_prod), x::BitSignedSmall) = Int(x)