Reductions
Following the same design principles, F
,
Reduction
templates encode generic Map-Reduce schemes
and should implement a few standard routines.
Summation
In the case of the simple Sum reduction (Sum_Reduction.h header), these can be described as:
An
InitializeReduction
method, which fills up the running buffer “ ” of our Map-Reduce algorithm – a vector of sizeF::DIM
– with zeros before the start of the loop on the reduction index .A
ReducePair
method, which takes as input a pointer to the running buffer , a pointer to the result and implements the in-place reduction:A
FinalizeOutput
method, which post-processes the buffer before saving its value in the output array. This is a useful step for argmin-like reductions; but in the case of the sum, no post-processing is needed.
The online Log-Sum-Exp trick
More interestingly, the Max_SumShiftExp_Reduction.h header implements an online version of the well-known Log-Sum-Exp trick: a factorization of the maximum in the computation of
that ensures the computation of this important quantity – the linchpin of maximum likelihood estimators and entropic Optimal Transport solvers – without numeric overflows.
Merging the content of our C++ header and of the
Python post-processing step implemented in
pykeops/common/operations.py,
assuming that
The
InitializeReduction
method ensures that our running buffer is a vector of size 2 that encodes the current value of the inner summation as an explicit (exponent, mantissa) or “(maximum, residual)” pair of float numbers: at any stage of the computation, the pair encodes the positive number with the required precision. We initially set the value of to .The
ReducePair
method takes as input a pointer to the result of the computation, a pointer to the running buffer and implements the in-place update:This is a numerically stable way of writing the sum reduction:
FinalizeOutput
post-processes the buffer by applying the final “ ” operation, returning a value of for the full reduction.