From e18da294d8e4710ba79f4ba2e05d4ca4e481366b Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 12 Dec 2023 11:41:26 +0530 Subject: [PATCH 1/4] Short-circuit all for AbstractFill --- src/FillArrays.jl | 4 +++- test/runtests.jl | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/FillArrays.jl b/src/FillArrays.jl index 3418d640..fb20a474 100644 --- a/src/FillArrays.jl +++ b/src/FillArrays.jl @@ -644,7 +644,9 @@ end # In particular, these make iszero(Eye(n)) efficient. # use any/all on scalar to get Boolean error message any(f::Function, x::AbstractFill) = !isempty(x) && any(f(getindex_value(x))) -all(f::Function, x::AbstractFill) = isempty(x) || all(f(getindex_value(x))) +# evaluating all(f(getindex_value(x))) before isempty(x) allows short-curcuiting +# in case the value is known from the type, e.g. in Zeros +all(f::Function, x::AbstractFill) = all(f(getindex_value(x))) || isempty(x) any(x::AbstractFill) = any(identity, x) all(x::AbstractFill) = all(identity, x) diff --git a/test/runtests.jl b/test/runtests.jl index 81c3ccee..cd0ea3d6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1336,6 +1336,9 @@ end @test iszero(Fill(SMatrix{2,2}(0,0,0,0), 2)) @test iszero(Fill(SMatrix{2,2}(0,0,0,1), 0)) + # compile-time evaluation + @test @inferred((Z -> Val(iszero(Z)))(Zeros(3,3))) == Val(true) + @testset "all/any" begin @test any(Ones{Bool}(10)) === all(Ones{Bool}(10)) === any(Fill(true,10)) === all(Fill(true,10)) === true @test any(Zeros{Bool}(10)) === all(Zeros{Bool}(10)) === any(Fill(false,10)) === all(Fill(false,10)) === false From cdb2f5b818ce93ca5d8a3a3c2ea92a540865b5a7 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 12 Dec 2023 12:01:46 +0530 Subject: [PATCH 2/4] expand the cases in all --- src/FillArrays.jl | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/FillArrays.jl b/src/FillArrays.jl index fb20a474..57f4171e 100644 --- a/src/FillArrays.jl +++ b/src/FillArrays.jl @@ -644,9 +644,19 @@ end # In particular, these make iszero(Eye(n)) efficient. # use any/all on scalar to get Boolean error message any(f::Function, x::AbstractFill) = !isempty(x) && any(f(getindex_value(x))) -# evaluating all(f(getindex_value(x))) before isempty(x) allows short-curcuiting -# in case the value is known from the type, e.g. in Zeros -all(f::Function, x::AbstractFill) = all(f(getindex_value(x))) || isempty(x) +function all(f::Function, x::AbstractFill) + fval = f(getindex_value(x)) + # checking the Bool path before isempty(x) allows short-curcuiting + # in case the value is known from the type, e.g. in Zeros + if fval isa Bool + return fval || isempty(x) + elseif isempty(x) # cases like all(Fill(2,0)) + return true + elseif fval # throw an error for non-Bool values + return fval + end + return false +end any(x::AbstractFill) = any(identity, x) all(x::AbstractFill) = all(identity, x) From 5bde556ab45c2446ff225e15182e5e18f9f22385 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 12 Dec 2023 12:17:46 +0530 Subject: [PATCH 3/4] Handle the fallback case through all --- src/FillArrays.jl | 6 +++--- test/runtests.jl | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/FillArrays.jl b/src/FillArrays.jl index 57f4171e..3da2bbef 100644 --- a/src/FillArrays.jl +++ b/src/FillArrays.jl @@ -652,10 +652,10 @@ function all(f::Function, x::AbstractFill) return fval || isempty(x) elseif isempty(x) # cases like all(Fill(2,0)) return true - elseif fval # throw an error for non-Bool values - return fval + elseif ismissing(fval) + return missing end - return false + return all(fval) end any(x::AbstractFill) = any(identity, x) all(x::AbstractFill) = all(identity, x) diff --git a/test/runtests.jl b/test/runtests.jl index cd0ea3d6..cf11ca02 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1348,6 +1348,8 @@ end @test all(Fill(2,0)) @test !any(Fill(2,0)) @test any(Trues(2,0)) == any(trues(2,0)) + @test_throws TypeError all(Fill(2,2)) + @test all(iszero, Fill(missing,2)) === all(iszero, fill(missing,2)) end @testset "Error" begin From fcabd330b87865b7e6846d1711f85dd7e9f4be67 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Mon, 5 Feb 2024 16:44:44 +0530 Subject: [PATCH 4/4] Simplify implementation --- src/FillArrays.jl | 20 +++++++++----------- test/runtests.jl | 5 ++++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/FillArrays.jl b/src/FillArrays.jl index 3da2bbef..ad479a32 100644 --- a/src/FillArrays.jl +++ b/src/FillArrays.jl @@ -643,19 +643,17 @@ end # In particular, these make iszero(Eye(n)) efficient. # use any/all on scalar to get Boolean error message -any(f::Function, x::AbstractFill) = !isempty(x) && any(f(getindex_value(x))) +function any(f::Function, x::AbstractFill) + isempty(x) && return false + # If the condition is true for one value, then it's true for all + fval = f(getindex_value(x)) + any((fval,)) +end function all(f::Function, x::AbstractFill) + isempty(x) && return true + # If the condition is true for one value, then it's true for all fval = f(getindex_value(x)) - # checking the Bool path before isempty(x) allows short-curcuiting - # in case the value is known from the type, e.g. in Zeros - if fval isa Bool - return fval || isempty(x) - elseif isempty(x) # cases like all(Fill(2,0)) - return true - elseif ismissing(fval) - return missing - end - return all(fval) + return all((fval,)) end any(x::AbstractFill) = any(identity, x) all(x::AbstractFill) = all(identity, x) diff --git a/test/runtests.jl b/test/runtests.jl index cf11ca02..211b9172 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1349,7 +1349,10 @@ end @test !any(Fill(2,0)) @test any(Trues(2,0)) == any(trues(2,0)) @test_throws TypeError all(Fill(2,2)) - @test all(iszero, Fill(missing,2)) === all(iszero, fill(missing,2)) + @test all(iszero, Fill(missing,0)) === all(iszero, fill(missing,0)) === true + @test all(iszero, Fill(missing,2)) === all(iszero, fill(missing,2)) === missing + @test any(iszero, Fill(missing,0)) === any(iszero, fill(missing,0)) === false + @test any(iszero, Fill(missing,2)) === any(iszero, fill(missing,2)) === missing end @testset "Error" begin