Predicates

Apply a predicate to check if all / any elements in a collection return true. Could be implemented as a reduction, but is better optimised with stopping the search once a false / true is found.

  • Other names: not often implemented standalone on GPUs, typically included as part of a reduction.
AcceleratedKernels.any — Function
any(pred, v::AbstractArray; backend=nothing, alg::Algorithm=Auto(), workspace=nothing)

Check if any element of v satisfies the predicate pred (i.e. some pred(v[i]) == true); pred must return a Bool. Optimised differently to mapreduce due to shortcircuiting behaviour of booleans.

Other names: not often implemented standalone on GPUs, typically included as part of a reduction.

alg is Auto() by default: CPUThreads.Partitioned on the host, and ConcurrentWrite on GPUs (ViaReduce on oneAPI). backend is derived from v; pass it for inputs that do not determine it, such as index ranges. workspace takes the scratch memory of a workspace made for the same call.

On the host, multithreaded parallelisation is only worth it for large arrays, relatively expensive predicates, and/or rare occurrence of true; use CPUThreads.Partitioned(; max_tasks, min_elems) to only use parallelism when worth it in your application.

Examples

import AcceleratedKernels as AK
using CUDA

v = CuArray(rand(Float32, 100_000))
AK.any(x -> x < 1, v)
AK.any(x -> x < 1, v; alg=AK.ViaReduce(AK.BlockReduce(switch_below=100)))

Checking a more complex condition with unmaterialised index ranges:

function complex_any(x, y)
    AK.any(eachindex(x); backend=AK.get_backend(x)) do i
        x[i] < 0 && y[i] > 0
    end
end

complex_any(CuArray(rand(Float32, 100)), CuArray(rand(Float32, 100)))
source
AcceleratedKernels.all — Function
all(pred, v::AbstractArray; backend=nothing, alg::Algorithm=Auto(), workspace=nothing)

Check if all elements of v satisfy the predicate pred (i.e. all pred(v[i]) == true); pred must return a Bool. The keywords are those of any.

Examples

import AcceleratedKernels as AK
using Metal

v = MtlArray(rand(Float32, 100_000))
AK.all(x -> x > 0, v)

Checking a more complex condition with unmaterialised index ranges:

function complex_all(x, y)
    AK.all(eachindex(x); backend=AK.get_backend(x)) do i
        x[i] > 0 && y[i] < 0
    end
end

complex_all(MtlArray(rand(Float32, 100)), MtlArray(rand(Float32, 100)))
source

Auto() uses CPUThreads.Partitioned on the host and ConcurrentWrite on GPUs, in which many threads write the same value to one memory location. That is well-defined (CUDA F4.2: "If a non-atomic instruction executed by a warp writes to the same location in global memory for more than one of the threads of the warp, only one thread performs a write and which thread does it is undefined."), but some older platforms (Intel UHD Graphics) have been reported to hang on it, so on oneAPI Auto uses the mapreduce-based ViaReduce instead. An explicit alg=ConcurrentWrite() runs on every GPU.

AcceleratedKernels.ConcurrentWrite — Type
ConcurrentWrite(; block_size=nothing)

GPU any/all in which every thread whose element decides the result stores the same value to one global flag. It is the fastest predicate algorithm, but some older Intel GPUs have been reported to hang when many threads write one location, so Auto picks ViaReduce on oneAPI.

source
AcceleratedKernels.ViaReduce — Type
ViaReduce(; reduce::ReduceAlgorithm=BlockReduce())

any/all as a reduction with | or &, using the reduction algorithm reduce. It runs on every backend that runs AcceleratedKernels' kernels, but reads every element.

source