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. GPU libraries rarely provide these on their own; they are usually written as reductions.
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.
alg is Auto() by default: CPUThreads.Partitioned on the host, and ConcurrentWrite on GPUs (ViaReduce on oneAPI and Metal). 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 AKusing CUDAv = 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 endendcomplex_any(CuArray(rand(Float32, 100)), CuArray(rand(Float32, 100)))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 AKusing Metalv = 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 endendcomplex_all(MtlArray(rand(Float32, 100)), MtlArray(rand(Float32, 100)))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. Metal does too, as ConcurrentWrite launches a thread per element, more than Metal's grid holds for arrays of 2^32 elements or more. An explicit alg=ConcurrentWrite() runs on every GPU.
AcceleratedKernels.PredicateAlgorithm — Type
PredicateAlgorithm <: AlgorithmSupertype of the algorithms of any and all: ConcurrentWrite and ViaReduce. They also accept CPUThreads.Partitioned.
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, and it launches a thread per element, which Metal's grid cannot hold for 2^32 elements or more, so Auto picks ViaReduce on oneAPI and Metal.
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. Both algorithms read every element, but this one takes the reduction's passes over partial results, where ConcurrentWrite takes a single pass.