Revision bc7ba3d5c8b2dab1c0e19537739b67c2da902d11 authored by Keno Fischer on 20 March 2024, 06:35:46 UTC, committed by GitHub on 20 March 2024, 06:35:46 UTC
This passes slightly more information into this function (the full
`inst` rather than just the `stmt`) in order to allow external absint to
access additional fields (the flags and the info) if necessary to make
concrete evaluation decisions. It also splits out the actual concrete
evaluation from the part that just maps the `inst` to a CodeInstance.
1 parent e0bb95a
Raw File
reduce.jl
# This file is a part of Julia. License is MIT: https://julialang.org/license

using Random
isdefined(Main, :OffsetArrays) || @eval Main include("testhelpers/OffsetArrays.jl")
using .Main.OffsetArrays

==ₜ(::Any, ::Any) = false
==ₜ(a::T, b::T) where {T} = isequal(a, b)

# fold(l|r) & mapfold(l|r)
@test foldl(+, Int64[]) === Int64(0) # In reference to issues #7465/#20144 (PR #20160)
@test foldl(+, Int16[]) === Int16(0) # In reference to issues #21536
@test foldl(-, 1:5) == -13
@test foldl(-, 1:5; init=10) == -5

@test Base.mapfoldl(abs2, -, 2:5) == -46
@test Base.mapfoldl(abs2, -, 2:5; init=10) == -44

@test Base.mapfoldl(abs2, /, 2:5) ≈ 1/900
@test Base.mapfoldl(abs2, /, 2:5; init=10) ≈ 1/1440

@test Base.mapfoldl((x)-> x ⊻ true, &, [true false true false false]) == false
@test Base.mapfoldl((x)-> x ⊻ true, &, [true false true false false]; init=true) == false

@test Base.mapfoldl((x)-> x ⊻ true, |, [true false true false false]) == true
@test Base.mapfoldl((x)-> x ⊻ true, |, [true false true false false]; init=false) == true

@test foldr(+, Int64[]) === Int64(0) # In reference to issue #20144 (PR #20160)
@test foldr(+, Int16[]) === Int16(0) # In reference to issues #21536
@test foldr(-, 1:5) == 3
@test foldr(-, 1:5; init=10) == -7
@test foldr(+, [1]) == 1 # Issue #21493

@test Base.mapfoldr(abs2, -, 2:5) == -14
@test Base.mapfoldr(abs2, -, 2:5; init=10) == -4
for t in Any[(1, 2.0, '3'), (;a = 1, b = 2.0, c = '3')]
    @test @inferred(mapfoldr(x -> x + 1, (x, y) -> (x, y...), t;
                            init = ())) == (2, 3.0, '4')
    @test @inferred(mapfoldl(x -> x + 1, (x, y) -> (x..., y), t;
                            init = ())) == (2, 3.0, '4')
end

@test foldr((x, y) -> ('⟨' * x * '|' * y * '⟩'), "λ 🐨.α") == "⟨λ|⟨ |⟨🐨|⟨.|α⟩⟩⟩⟩" # issue #31780
let x = rand(10)
    @test 0 == @allocated(sum(Iterators.reverse(x)))
    @test 0 == @allocated(foldr(-, x))
end

# reduce
@test reduce(+, Int64[]) === Int64(0) # In reference to issue #20144 (PR #20160)
@test reduce(+, Int16[]) === Int16(0) # In reference to issues #21536
@test reduce((x,y)->"($x+$y)", 9:11) == "((9+10)+11)"
@test reduce(max, [8 6 7 5 3 0 9]) == 9
@test reduce(+, 1:5; init=1000) == (1000 + 1 + 2 + 3 + 4 + 5)
@test reduce(+, 1) == 1
@test_throws "reducing over an empty collection is not allowed" reduce(*, ())
@test_throws "reducing over an empty collection is not allowed" reduce(*, Union{}[])

# mapreduce
@test mapreduce(-, +, [-10 -9 -3]) == ((10 + 9) + 3)
@test mapreduce((x)->x[1:3], (x,y)->"($x+$y)", ["abcd", "efgh", "01234"]) == "((abc+efg)+012)"

# mapreduce with multiple iterators
@test mapreduce(*, +, (i for i in 2:3), (i for i in 4:5)) == 23
@test mapreduce(*, +, (i for i in 2:3), (i for i in 4:5); init = 2) == 25
@test mapreduce(*, (x,y)->"($x+$y)", ["a", "b", "c"], ["d", "e", "f"]) == "((ad+be)+cf)"
@test mapreduce(*, (x,y)->"($x+$y)", ["a", "b", "c"], ["d", "e", "f"]; init = "gh") ==
    "(((gh+ad)+be)+cf)"

@test mapreduce(*, +, [2, 3], [4, 5]) == 23
@test mapreduce(*, +, [2, 3], [4, 5]; init = 2) == 25
@test mapreduce(*, +, [2, 3], [4, 5]; dims = 1) == [23]
@test mapreduce(*, +, [2, 3], [4, 5]; dims = 1, init = 2) == [25]
@test mapreduce(*, +, [2, 3], [4, 5]; dims = 2) == [8, 15]
@test mapreduce(*, +, [2, 3], [4, 5]; dims = 2, init = 2) == [10, 17]

@test mapreduce(*, +, [2 3; 4 5], [6 7; 8 9]) == 110
@test mapreduce(*, +, [2 3; 4 5], [6 7; 8 9]; init = 2) == 112
@test mapreduce(*, +, [2 3; 4 5], [6 7; 8 9]; dims = 1) == [44 66]
@test mapreduce(*, +, [2 3; 4 5], [6 7; 8 9]; dims = 1, init = 2) == [46 68]
@test mapreduce(*, +, [2 3; 4 5], [6 7; 8 9]; dims = 2) == reshape([33, 77], :, 1)
@test mapreduce(*, +, [2 3; 4 5], [6 7; 8 9]; dims = 2, init = 2) == reshape([35, 79], :, 1)

# mapreduce() for 1- 2- and n-sized blocks (PR #19325)
@test mapreduce(-, +, [-10]) == 10
@test mapreduce(abs2, +, [-9, -3]) == 81 + 9
@test mapreduce(-, +, [-9, -3, -4, 8, -2]) == (9 + 3 + 4 - 8 + 2)
@test mapreduce(-, +, Vector(range(1.0, stop=10000.0, length=10000))) == -50005000.0
# empty mr
@test mapreduce(abs2, +, Float64[]) === 0.0
@test mapreduce(abs2, *, Float64[]) === 1.0
@test mapreduce(abs2, max, Float64[]) === 0.0
@test mapreduce(abs, max, Float64[]) === 0.0
@test_throws "reducing over an empty collection is not allowed" mapreduce(abs2, &, Float64[])
@test_throws str -> !occursin("Closest candidates are", str) mapreduce(abs2, &, Float64[])
@test_throws "reducing over an empty collection is not allowed" mapreduce(abs2, |, Float64[])

# mapreduce() type stability
@test typeof(mapreduce(*, +, Int8[10])) ===
      typeof(mapreduce(*, +, Int8[10, 11])) ===
      typeof(mapreduce(*, +, Int8[10, 11, 12, 13]))
@test typeof(mapreduce(*, +, Float32[10.0])) ===
      typeof(mapreduce(*, +, Float32[10, 11])) ===
      typeof(mapreduce(*, +, Float32[10, 11, 12, 13]))
# mapreduce() type stability when f supports empty collections
@test typeof(mapreduce(abs, +, Int8[])) ===
      typeof(mapreduce(abs, +, Int8[10])) ===
      typeof(mapreduce(abs, +, Int8[10, 11])) ===
      typeof(mapreduce(abs, +, Int8[10, 11, 12, 13]))
@test typeof(mapreduce(abs, +, Float32[])) ===
      typeof(mapreduce(abs, +, Float32[10])) ===
      typeof(mapreduce(abs, +, Float32[10, 11])) ===
      typeof(mapreduce(abs, +, Float32[10, 11, 12, 13]))

# sum
@testset "sums promote to at least machine size" begin
    @testset for T in [Int8, Int16, Int32]
        @test sum(T[]) === Int(0)
    end
    @testset for T in [UInt8, UInt16, UInt32]
        @test sum(T[]) === UInt(0)
    end
    @testset for T in [Int, Int64, Int128, UInt, UInt64, UInt128,
                       Float16, Float32, Float64]
        @test sum(T[]) === T(0)
    end
    @test sum(BigInt[]) == big(0) && sum(BigInt[]) isa BigInt
end

@test sum(Bool[]) === sum(Bool[false]) === sum(Bool[false, false]) === 0
@test sum(Bool[true, false, true]) === 2

@test sum(Int8(3)) === Int(3)
@test sum(3) === 3
@test sum(3.0) === 3.0

@test sum([Int8(3)]) === Int(3)
@test sum([3]) === 3
@test sum([3.0]) === 3.0

z = reshape(1:16, (2,2,2,2))
fz = float(z)
@test sum(z) === 136
@test sum(fz) === 136.0

@test_throws "reducing over an empty collection is not allowed" sum(Union{}[])
@test_throws "reducing over an empty collection is not allowed" sum(sin, Int[])
@test sum(sin, 3) == sin(3.0)
@test sum(sin, [3]) == sin(3.0)
a = sum(sin, z)
@test a ≈ sum(sin, fz)
@test a ≈ sum(sin.(fz))

z = [-4, -3, 2, 5]
fz = float(z)
a = randn(32) # need >16 elements to trigger BLAS code path
b = complex.(randn(32), randn(32))

# check variants of summation for type-stability and other issues (#6069)
sum2(itr) = invoke(sum, Tuple{Any}, itr)
plus(x,y) = x + y
sum3(A) = reduce(plus, A)
sum4(itr) = invoke(reduce, Tuple{Function, Any}, plus, itr)
sum5(A) = reduce(plus, A; init=0)
sum6(itr) = invoke(Core.kwcall, Tuple{NamedTuple{(:init,), Tuple{Int}}, typeof(reduce), Function, Any}, (init=0,), reduce, plus, itr)
sum61(itr) = invoke(reduce, Tuple{Function, Any}, init=0, plus, itr)
sum7(A) = mapreduce(x->x, plus, A)
sum8(itr) = invoke(mapreduce, Tuple{Function, Function, Any}, x->x, plus, itr)
sum9(A) = mapreduce(x->x, plus, A; init=0)
sum10(itr) = invoke(Core.kwcall, Tuple{NamedTuple{(:init,),Tuple{Int}}, typeof(mapreduce), Function, Function, Any}, (init=0,), mapreduce, x->x, plus, itr)
sum11(itr) = invoke(mapreduce, Tuple{Function, Function, Any}, init=0, x->x, plus, itr)
for f in (sum2, sum5, sum6, sum61, sum9, sum10, sum11)
    @test sum(z) == f(z)
    @test sum(Int[]) == f(Int[]) == 0
    @test sum(Int[7]) == f(Int[7]) == 7
    @test typeof(f(Int8[])) == typeof(f(Int8[1])) == typeof(f(Int8[1 7]))
end
for f in (sum3, sum4, sum7, sum8)
    @test sum(z) == f(z)
    @test_throws "reducing over an empty" f(Int[])
    @test sum(Int[7]) == f(Int[7]) == 7
end
@test typeof(sum(Int8[])) == typeof(sum(Int8[1])) == typeof(sum(Int8[1 7]))

@testset "`sum` of empty collections with `init`" begin
    function noncallable end  # should not be called
    @testset for init in [0, 0.0]
        @test sum([]; init = init) === init
        @test sum((x for x in [123] if false); init = init) === init
        @test sum(noncallable, []; init = init) === init
        @test sum(noncallable, (x for x in [123] if false); init = init) === init
        @test sum(Array{Any,3}(undef, 3, 2, 0); dims = 1, init = init) ==ₜ
              zeros(typeof(init), 1, 2, 0)
        @test sum(noncallable, Array{Any,3}(undef, 3, 2, 0); dims = 1, init = init) ==ₜ
              zeros(typeof(init), 1, 2, 0)
    end
end

# check sum(abs, ...) for support of empty collections
@testset "sum(abs, [])" begin
    @test @inferred(sum(abs, Float64[])) === 0.0
    @test @inferred(sum(abs, Int[])) === 0
    @test @inferred(sum(abs, Set{Int}())) === 0
    @test_throws MethodError sum(abs, Any[])
end

# prod

@test prod(Int[]) === 1
@test prod(Int8[]) === Int(1)
@test prod(Float64[]) === 1.0

@test prod([3]) === 3
@test prod([Int8(3)]) === Int(3)
@test prod([UInt8(3)]) === UInt(3)
@test prod([3.0]) === 3.0

@test prod(z) === 120
@test prod(fz) === 120.0

@test prod(1:big(16)) == big(20922789888000)
@test prod(big(typemax(Int64)):big(typemax(Int64))+16) == parse(BigInt,"25300281663413827620486300433089141956148633919452440329174083959168114253708467653081909888307573358090001734956158476311046124934597861626299416732205795533726326734482449215730132757595422510465791525610410023802664753402501982524443370512346073948799084936298007821432734720004795146875180123558814648586972474376192000")

@test typeof(prod(Array(trues(10)))) == Bool

@testset "`prod` of empty collections with `init`" begin
    function noncallable end  # should not be called
    @testset for init in [1, 1.0, ""]
        @test prod([]; init = init) === init
        @test prod((x for x in [123] if false); init = init) === init
        @test prod(noncallable, []; init = init) === init
        @test prod(noncallable, (x for x in [123] if false); init = init) === init
        @test prod(Array{Any,3}(undef, 3, 2, 0); dims = 1, init = init) ==ₜ
              ones(typeof(init), 1, 2, 0)
        @test prod(noncallable, Array{Any,3}(undef, 3, 2, 0); dims = 1, init = init) ==ₜ
              ones(typeof(init), 1, 2, 0)
    end
end

# check type-stability
prod2(itr) = invoke(prod, Tuple{Any}, itr)
@test prod(Int[]) === prod2(Int[]) === 1
@test prod(Int[7]) === prod2(Int[7]) === 7
@test typeof(prod(Int8[])) == typeof(prod(Int8[1])) == typeof(prod(Int8[1, 7])) == Int
@test typeof(prod2(Int8[])) == typeof(prod2(Int8[1])) == typeof(prod2(Int8[1 7])) == Int

# maximum & minimum & extrema

@test_throws "reducing over an empty" maximum(Int[])
@test_throws "reducing over an empty" minimum(Int[])
@test_throws "reducing over an empty" extrema(Int[])

@test maximum(Int[]; init=-1) == -1
@test minimum(Int[]; init=-1) == -1
@test extrema(Int[]; init=(1, -1)) == (1, -1)

@test maximum(sin, []; init=-1) == -1
@test minimum(sin, []; init=1) == 1
@test extrema(sin, []; init=(1, -1)) == (1, -1)

@test maximum(5) == 5
@test minimum(5) == 5
@test extrema(5) == (5, 5)
@test extrema(abs2, 5) == (25, 25)

let x = [4,3,5,2]
    @test maximum(x) == 5
    @test minimum(x) == 2
    @test extrema(x) == (2, 5)

    @test maximum(abs2, x) == 25
    @test minimum(abs2, x) == 4
    @test extrema(abs2, x) == (4, 25)
end

@test maximum([-0.,0.]) === 0.0
@test maximum([0.,-0.]) === 0.0
@test maximum([0.,-0.,0.]) === 0.0
@test minimum([-0.,0.]) === -0.0
@test minimum([0.,-0.]) === -0.0
@test minimum([0.,-0.,0.]) === -0.0

@testset "minimum/maximum checks all elements" begin
    for N in [2:20;150;300]
        for i in 1:N
            arr = fill(0., N)
            truth = rand()
            arr[i] = truth
            @test maximum(arr) == truth

            truth = -rand()
            arr[i] = truth
            @test minimum(arr) == truth

            arr[i] = NaN
            @test isnan(maximum(arr))
            @test isnan(minimum(arr))

            arr = zeros(N)
            @test minimum(arr) === 0.0
            @test maximum(arr) === 0.0

            arr[i] = -0.0
            @test minimum(arr) === -0.0
            @test maximum(arr) ===  0.0

            arr = -zeros(N)
            @test minimum(arr) === -0.0
            @test maximum(arr) === -0.0
            arr[i] = 0.0
            @test minimum(arr) === -0.0
            @test maximum(arr) === 0.0
        end
    end
end

@testset "maximum works on generic order #30320" begin
    for n in [1:20;1500]
        arr = randn(n)
        @test GenericOrder(maximum(arr)) === maximum(map(GenericOrder, arr))
        @test GenericOrder(minimum(arr)) === minimum(map(GenericOrder, arr))
        f = x -> x
        @test GenericOrder(maximum(f,arr)) === maximum(f,map(GenericOrder, arr))
        @test GenericOrder(minimum(f,arr)) === minimum(f,map(GenericOrder, arr))
    end
end

@testset "maximum no out of bounds access #30462" begin
    arr = fill(-Inf, 128,128)
    @test maximum(arr) == -Inf
    arr = fill(Inf, 128^2)
    @test minimum(arr) == Inf
    for center in [256, 1024, 4096, 128^2]
        for offset in -10:10
            len = center + offset
            x = randn()
            arr = fill(x, len)
            @test maximum(arr) === x
            @test minimum(arr) === x
        end
    end
end

@test isnan(maximum([NaN]))
@test isnan(minimum([NaN]))
@test isequal(extrema([NaN]), (NaN, NaN))

@test isnan(maximum([NaN, 2.]))
@test isnan(maximum([2., NaN]))
@test isnan(minimum([NaN, 2.]))
@test isnan(minimum([2., NaN]))
@test isequal(extrema([NaN, 2.]), (NaN,NaN))

@test isnan(maximum([NaN, 2., 3.]))
@test isnan(minimum([NaN, 2., 3.]))
@test isequal(extrema([NaN, 2., 3.]), (NaN,NaN))

@test isnan(maximum([4., 3., NaN, 5., 2.]))
@test isnan(minimum([4., 3., NaN, 5., 2.]))
@test isequal(extrema([4., 3., NaN, 5., 2.]), (NaN,NaN))

 # test long arrays
@test isnan(maximum([NaN; 1.:10000.]))
@test isnan(maximum([1.:10000.; NaN]))
@test isnan(minimum([NaN; 1.:10000.]))
@test isnan(minimum([1.:10000.; NaN]))
@test isequal(extrema([1.:10000.; NaN]), (NaN,NaN))
@test isequal(extrema([NaN; 1.:10000.]), (NaN,NaN))

@test maximum(abs2, 3:7) == 49
@test minimum(abs2, 3:7) == 9
@test extrema(abs2, 3:7) == (9, 49)

@test maximum(Int16[1]) === Int16(1)
@test maximum(Vector(Int16(1):Int16(100))) === Int16(100)
@test maximum(Int32[1,2]) === Int32(2)

A = circshift(reshape(1:24,2,3,4), (0,1,1))
@test extrema(A,dims=1) == reshape([(23,24),(19,20),(21,22),(5,6),(1,2),(3,4),(11,12),(7,8),(9,10),(17,18),(13,14),(15,16)],1,3,4)
@test extrema(A,dims=2) == reshape([(19,23),(20,24),(1,5),(2,6),(7,11),(8,12),(13,17),(14,18)],2,1,4)
@test extrema(A,dims=3) == reshape([(5,23),(6,24),(1,19),(2,20),(3,21),(4,22)],2,3,1)
@test extrema(A,dims=(1,2)) == reshape([(19,24),(1,6),(7,12),(13,18)],1,1,4)
@test extrema(A,dims=(1,3)) == reshape([(5,24),(1,20),(3,22)],1,3,1)
@test extrema(A,dims=(2,3)) == reshape([(1,23),(2,24)],2,1,1)
@test extrema(A,dims=(1,2,3)) == reshape([(1,24)],1,1,1)
@test size(extrema(A,dims=1)) == size(maximum(A,dims=1))
@test size(extrema(A,dims=(1,2))) == size(maximum(A,dims=(1,2)))
@test size(extrema(A,dims=(1,2,3))) == size(maximum(A,dims=(1,2,3)))
@test extrema(x->div(x, 2), A, dims=(2,3)) == reshape([(0,11),(1,12)],2,1,1)

@testset "maximum/minimum/extrema with missing values" begin
    for x in (Vector{Union{Int,Missing}}(missing, 10),
              Vector{Union{Int,Missing}}(missing, 257))
        @test maximum(x) === minimum(x) === missing
        @test extrema(x) === (missing, missing)
        fill!(x, 1)
        x[1] = missing
        @test maximum(x) === minimum(x) === missing
        @test extrema(x) === (missing, missing)
    end
    # inputs containing both missing and NaN
    minimum([NaN;zeros(255);missing]) === missing
    maximum([NaN;zeros(255);missing]) === missing
end

# findmin, findmax, argmin, argmax

@testset "findmin(f, domain)" begin
    @test findmin(-, 1:10) == (-10, 10)
    @test findmin(identity, [1, 2, 3, missing]) === (missing, 4)
    @test findmin(identity, [1, NaN, 3, missing]) === (missing, 4)
    @test findmin(identity, [1, missing, NaN, 3]) === (missing, 2)
    @test findmin(identity, [1, NaN, 3]) === (NaN, 2)
    @test findmin(identity, [1, 3, NaN]) === (NaN, 3)
    @test findmin(cos, 0:π/2:2π) == (-1.0, 3)
end

@testset "findmax(f, domain)" begin
    @test findmax(-, 1:10) == (-1, 1)
    @test findmax(identity, [1, 2, 3, missing]) === (missing, 4)
    @test findmax(identity, [1, NaN, 3, missing]) === (missing, 4)
    @test findmax(identity, [1, missing, NaN, 3]) === (missing, 2)
    @test findmax(identity, [1, NaN, 3]) === (NaN, 2)
    @test findmax(identity, [1, 3, NaN]) === (NaN, 3)
    @test findmax(cos, 0:π/2:2π) == (1.0, 1)
end

@testset "argmin(f, domain)" begin
    @test argmin(-, 1:10) == 10
    @test argmin(sum, Iterators.product(1:5, 1:5)) == (1, 1)
end

@testset "argmax(f, domain)" begin
    @test argmax(-, 1:10) == 1
    @test argmax(sum, Iterators.product(1:5, 1:5)) == (5, 5)
end

# any & all

@test @inferred(Union{Missing,Bool}, any([])) == false
@test @inferred(any(Bool[])) == false
@test @inferred(any([true])) == true
@test @inferred(any([false, false])) == false
@test @inferred(any([false, true])) == true
@test @inferred(any([true, false])) == true
@test @inferred(any([true, true])) == true
@test @inferred(any([true, true, true])) == true
@test @inferred(any([true, false, true])) == true
@test @inferred(any([false, false, false])) == false

@test @inferred(Union{Missing,Bool}, all([])) == true
@test @inferred(all(Bool[])) == true
@test @inferred(all([true])) == true
@test @inferred(all([false, false])) == false
@test @inferred(all([false, true])) == false
@test @inferred(all([true, false])) == false
@test @inferred(all([true, true])) == true
@test @inferred(all([true, true, true])) == true
@test @inferred(all([true, false, true])) == false
@test @inferred(all([false, false, false])) == false

@test @inferred(Union{Missing,Bool}, any(x->x>0, [])) == false
@test @inferred(any(x->x>0, Int[])) == false
@test @inferred(any(x->x>0, [-3])) == false
@test @inferred(any(x->x>0, [4])) == true
@test @inferred(any(x->x>0, [-3, 4, 5])) == true

@test @inferred(Union{Missing,Bool}, all(x->x>0, [])) == true
@test @inferred(all(x->x>0, Int[])) == true
@test @inferred(all(x->x>0, [-3])) == false
@test @inferred(all(x->x>0, [4])) == true
@test @inferred(all(x->x>0, [-3, 4, 5])) == false

@test reduce((a, b) -> a .| b, fill(trues(5), 24))  == trues(5)
@test reduce((a, b) -> a .| b, fill(falses(5), 24)) == falses(5)
@test reduce((a, b) -> a .& b, fill(trues(5), 24))  == trues(5)
@test reduce((a, b) -> a .& b, fill(falses(5), 24)) == falses(5)

@test_throws TypeError any(Returns(0), [false])
@test_throws TypeError all(Returns(0), [false])

# short-circuiting any and all

let c = [0, 0], A = 1:1000
    any(x->(c[1]=x; x==10), A)
    all(x->(c[2]=x; x!=10), A)

    @test c == [10,10]
end

# 19151 - always short circuit
let c = Int[], d = Int[], A = 1:9
    all((push!(c, x); x < 5) for x in A)
    @test c == 1:5

    any((push!(d, x); x > 4) for x in A)
    @test d == 1:5
end

# any/all with non-boolean collections

let f(x) = x == 1 ? true : x == 2 ? false : 1
    @test any(Any[false,true,false])
    @test @inferred any(map(f, [2,1,2]))
    @test @inferred any([f(x) for x in [2,1,2]])

    @test all(Any[true,true,true])
    @test @inferred all(map(f, [1,1,1]))
    @test @inferred all([f(x) for x in [1,1,1]])

    @test_throws TypeError any([1,true])
    @test_throws TypeError all([true,1])
    @test_throws TypeError any(map(f,[3,1]))
    @test_throws TypeError all(map(f,[1,3]))
end

# any and all with functors

struct SomeFunctor end
(::SomeFunctor)(x) = true

@test @inferred any(SomeFunctor(), 1:10)
@test @inferred all(SomeFunctor(), 1:10)


# in

@test in(1, Int[]) == false
@test in(1, Int[1]) == true
@test in(1, Int[2]) == false
@test in(0, 1:3) == false
@test in(1, 1:3) == true
@test in(2, 1:3) == true

# occursin

@test occursin("fox", "quick fox") == true
@test occursin("lazy dog", "quick fox") == false

# count

@test count(x->x>0, Int[]) == count(Bool[]) == 0
@test count(x->x>0, -3:5) == count((-3:5) .> 0) == 5
@test count([true, true, false, true]) == count(BitVector([true, true, false, true])) == 3
let x = repeat([false, true, false, true, true, false], 7)
    @test count(x) == 21
    GC.@preserve x (unsafe_store!(Ptr{UInt8}(pointer(x)), 0xfe, 3))
    @test count(x) == 21
end
@test_throws TypeError count(sqrt, [1])
@test_throws TypeError count([1])
let itr = (x for x in 1:10 if x < 7)
    @test count(iseven, itr) == 3
    @test_throws TypeError count(itr)
    @test_throws TypeError count(sqrt, itr)
end
@test count(iseven(x) for x in 1:10 if x < 7) == 3
@test count(iseven(x) for x in 1:10 if x < -7) == 0

@test count(!iszero, Int[]) == 0
@test count(!iszero, Int[0]) == 0
@test count(!iszero, Int[1]) == 1
@test count(!iszero, [1, 0, 2, 0, 3, 0, 4]) == 4

struct NonFunctionIsZero end
(::NonFunctionIsZero)(x) = iszero(x)
@test count(NonFunctionIsZero(), []) == 0
@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))

## cumsum, cummin, cummax

z = rand(10^6)
let es = sum(BigFloat.(z)), es2 = sum(BigFloat.(z[1:10^5]))
    @test (es - sum(z)) < es * 1e-13
    cs = cumsum(z)
    @test (es - cs[end]) < es * 1e-13
    @test (es2 - cs[10^5]) < es2 * 1e-13
end

@test sum(Vector(map(UInt8,0:255))) == 32640
@test sum(Vector(map(UInt8,254:255))) == 509

A = reshape(map(UInt8, 101:109), (3,3))
@test @inferred(sum(A)) == 945
@test @inferred(sum(view(A, 1:3, 1:3))) == 945

A = reshape(map(UInt8, 1:100), (10,10))
@test @inferred(sum(A)) == 5050
@test @inferred(sum(view(A, 1:10, 1:10))) == 5050

# issue #11618
@test sum([-0.0]) === -0.0
@test sum([-0.0, -0.0]) === -0.0
@test prod([-0.0, -0.0]) === 0.0

# containment
let A = Vector(1:10)
    @test A ∋ 5
    @test A ∌ 11
    @test any(y->y==6,A)
end

# issue #18695
test18695(r) = sum( t^2 for t in r )
@test @inferred(test18695([1.0,2.0,3.0,4.0])) == 30.0
@test_throws str -> ( occursin("reducing over an empty", str) &&
                      occursin("consider supplying `init`", str) &&
                     !occursin("or defining", str)) test18695(Any[])

# For Core.IntrinsicFunction
@test_throws str -> ( occursin("reducing over an empty", str) &&
                      occursin("consider supplying `init`", str) &&
                     !occursin("or defining", str)) reduce(Base.xor_int, Int[])

# issue #21107
@test foldr(-,2:2) == 2

# test neutral element not picked incorrectly for &, |
@test @inferred(foldl(&, Int[1])) === 1
@test_throws ["reducing over an empty",
              "consider supplying `init`"] foldl(&, Int[])

# prod on Chars
@test prod(Char[]) == ""
@test prod(Char['a']) == "a"
@test prod(Char['a','b']) == "ab"

@testset "optimized reduce(vcat/hcat, A) for arrays" begin
    for args in ([1:2], [[1, 2]], [1:2, 3:4], AbstractVector{Int}[[3, 4, 5], 1:2], AbstractVector[1:2, [3.5, 4.5]],
                 [[1 2], [3 4; 5 6]], [reshape([1, 2], 2, 1), 3:4])
        X = reduce(vcat, args)
        Y = vcat(args...)
        @test X == Y
        @test typeof(X) === typeof(Y)
    end
    for args in ([1:2], [[1, 2]], [1:2, 3:4], AbstractVector{Int}[[3, 4, 5], 1:3], AbstractVector[1:2, [3.5, 4.5]],
                 [[1 2; 3 4], [5 6; 7 8]], [1:2, [5 6; 7 8]], [[5 6; 7 8], [1, 2]])
        X = reduce(hcat, args)
        Y = hcat(args...)
        @test X == Y
        @test typeof(X) === typeof(Y)
    end
end

# offset axes
i = Base.Slice(-3:3)
x = [j^2 for j in i]
@test sum(x) == sum(x.parent) == 28
i = Base.Slice(0:0)
x = [j+7 for j in i]
@test sum(x) == 7

@testset "initial value handling with flatten" begin
    @test mapfoldl(
        x -> (x, x),
        ((a, b), (c, d)) -> (min(a, c), max(b, d)),
        Iterators.flatten((1:2, 3:4)),
    ) == (1, 4)
end

# make sure we specialize on mapfoldl(::Type, ...)
@test @inferred(mapfoldl(Int, +, [1, 2, 3]; init=0)) === 6

# issue #39281
@test @inferred(extrema(rand(2), dims=1)) isa Vector{Tuple{Float64,Float64}}

# issue #38627
@testset "overflow in mapreduce" begin
    # at len = 16 and len = 1025 there is a change in codepath
    for len in [1, 15, 16, 1024, 1025, 2048, 2049]
        oa = OffsetArray(repeat([1], len), typemax(Int)-len)
        @test sum(oa) == reduce(+, oa) == len
        @test mapreduce(+, +, oa, oa) == 2len
    end
end

# issue #45748
@testset "foldl's stability for nested Iterators" begin
    a = Iterators.flatten((1:3, 1:3))
    b = (2i for i in a if i > 0)
    c = Base.Generator(Float64, b)
    d = (sin(i) for i in c if i > 0)
    @test @inferred(sum(d)) == sum(collect(d))
    @test @inferred(extrema(d)) == extrema(collect(d))
    @test @inferred(maximum(c)) == maximum(collect(c))
    @test @inferred(prod(b)) == prod(collect(b))
    @test @inferred(minimum(a)) == minimum(collect(a))
end

function fold_alloc(a)
    sum(a)
    foldr(+, a)
    max(@allocated(sum(a)), @allocated(foldr(+, a)))
end
let a = NamedTuple(Symbol(:x,i) => i for i in 1:33),
    b = (a...,)
    @test fold_alloc(a) == fold_alloc(b) == 0
end

@testset "concrete eval `[any|all](f, itr::Tuple)`" begin
    intf = in((1,2,3)); Intf = typeof(intf)
    symf = in((:one,:two,:three)); Symf = typeof(symf)
    @test Core.Compiler.is_foldable(Base.infer_effects(intf, (Int,)))
    @test Core.Compiler.is_foldable(Base.infer_effects(symf, (Symbol,)))
    @test Core.Compiler.is_foldable(Base.infer_effects(all, (Intf,Tuple{Int,Int,Int})))
    @test Core.Compiler.is_foldable(Base.infer_effects(all, (Symf,Tuple{Symbol,Symbol,Symbol})))
    @test Core.Compiler.is_foldable(Base.infer_effects(any, (Intf,Tuple{Int,Int,Int})))
    @test Core.Compiler.is_foldable(Base.infer_effects(any, (Symf,Tuple{Symbol,Symbol,Symbol})))
    @test Base.return_types() do
        Val(all(in((1,2,3)), (1,2,3)))
    end |> only == Val{true}
    @test Base.return_types() do
        Val(all(in((1,2,3)), (1,2,3,4)))
    end |> only == Val{false}
    @test Base.return_types() do
        Val(any(in((1,2,3)), (4,5,3)))
    end |> only == Val{true}
    @test Base.return_types() do
        Val(any(in((1,2,3)), (4,5,6)))
    end |> only == Val{false}
    @test Base.return_types() do
        Val(all(in((:one,:two,:three)),(:three,:four)))
    end |> only == Val{false}
    @test Base.return_types() do
        Val(any(in((:one,:two,:three)),(:four,:three)))
    end |> only == Val{true}
end
back to top