The following functions allow for fold-agnostic summation. If a user calls [[sum]] or [[scan]] in some function, they can later tune the way summations happen deep in their code by binding [[fold]].
For summation functions with explicit folds baked in, see [[emmy.algebra.fold/fold->sum-fn]] and [[emmy.algebra.fold/fold->scan-fn]].
The following two functions are identical to [[emmy.algebra.fold/fold->sum-fn]] and [[emmy.algebra.fold/fold->scan-fn]] with [[fold]] baked in. I did this for performance reasons; to use those functions and keep [[fold]] dynamically rebindable I would have to pass the var #'*fold*
. De-referencing this var has a performance penalty that is not acceptable, given that [[sum]] and [[scan]] are used in the inner loops of numerical integration routines.
In contrast to compensated summation algorithms, simply adding up a vector of numbers recursively in pairs can offer great error reduction with good performance.
Adding up numbers from left to right usually means that as the accumulated sum grows, you are adding the smaller numbers in the sequence into a progressively larger total.
By pairwise-adding up numbers recursively, you are more likely to be adding numbers of similar magnitude together.
[[cutoff]] lets you tune your "leaf size". A value of 1
would send you all the way down to each single value; the default of 128, taken from Julia's default, means that when you get to 128 elements or fewer you defer to naive summation.
The [[pairwise-sum]] implementation below was inspired by the pairwiseSum
implementation in the math-functions
Haskell package. Those docs state:
-- This approach is perhaps 10% faster than 'KBNSum', but has poorer -- bounds on its error growth. Instead of having roughly constant -- error regardless of the size of the input vector, in the worst case -- its accumulated error grows with /O(log n)/.
NOTE that it might be interesting to combine [[pairwise-sum]] with the compensated summation algorithms from [[emmy.algebra.fold]]. Page 7 of this paper by Klein seems to describe a way to aggregate the intermediate states of compensated summation up through the binary addition tree (i.e., implement a monoid on the compensated summation state itself); but I couldn't figure out the indices!
This section implements combinators that use various binary functions to generate n-arity versions of those functions.