A function.
Ranges and arrays
auto ar = [1, 2, 3]; auto s = 0.reduce!"a + b"(ar); assert (s == 6);
Single slice
import mir.ndslice.topology : iota; //| 0 1 2 | => 3 | //| 3 4 5 | => 12 | => 15 auto sl = iota(2, 3); // sum of all element in the slice auto res = size_t(0).reduce!"a + b"(sl); assert(res == 15);
Multiple slices, dot product
import mir.ndslice.allocation : slice; import mir.ndslice.topology : as, iota; //| 0 1 2 | //| 3 4 5 | auto a = iota([2, 3], 0).as!double.slice; //| 1 2 3 | //| 4 5 6 | auto b = iota([2, 3], 1).as!double.slice; alias dot = reduce!"a + b * c"; auto res = dot(0.0, a, b); // check the result: import mir.ndslice.topology : flattened; import std.numeric : dotProduct; assert(res == dotProduct(a.flattened, b.flattened));
Zipped slices, dot product
import std.typecons : Yes; import std.numeric : dotProduct; import mir.ndslice.allocation : slice; import mir.ndslice.topology : as, iota, zip, universal; import mir.math.common : fmamath; static @fmamath T fmuladd(T, Z)(const T a, Z z) { return a + z.a * z.b; } // 0 1 2 // 3 4 5 auto sl1 = iota(2, 3).as!double.slice.universal; // 1 2 3 // 4 5 6 auto sl2 = iota([2, 3], 1).as!double.slice; // slices must have the same strides for `zip!true`. assert(sl1.strides == sl2.strides); auto z = zip!true(sl1, sl2); auto dot = reduce!fmuladd(0.0, z); assert(dot == dotProduct(iota(6), iota([6], 1)));
Tensor mutation on-the-fly
import mir.ndslice.allocation : slice; import mir.ndslice.topology : as, iota; import mir.math.common : fmamath; static @fmamath T fun(T)(const T a, ref T b) { return a + b++; } //| 0 1 2 | //| 3 4 5 | auto sl = iota(2, 3).as!double.slice; auto res = reduce!fun(double(0), sl); assert(res == 15); //| 1 2 3 | //| 4 5 6 | assert(sl == iota([2, 3], 1));
Packed slices.
Computes minimum value of maximum values for each row.
import mir.math.common; import mir.ndslice.allocation : slice; import mir.ndslice.dynamic : transposed; import mir.ndslice.topology : as, iota, pack, map, universal; alias maxVal = (a) => reduce!fmax(-double.infinity, a); alias minVal = (a) => reduce!fmin(double.infinity, a); alias minimaxVal = (a) => minVal(a.pack!1.map!maxVal); auto sl = iota(2, 3).as!double.slice; // Vectorized computation: row stride equals 1. //| 0 1 2 | => | 2 | //| 3 4 5 | => | 5 | => 2 auto res = minimaxVal(sl); assert(res == 2); // Common computation: row stride does not equal 1. //| 0 1 2 | | 0 3 | => | 3 | //| 3 4 5 | => | 1 4 | => | 4 | // | 2 5 | => | 5 | => 3 auto resT = minimaxVal(sl.universal.transposed); assert(resT == 3);
Dlang Range API support.
import mir.algorithm.iteration: each; import std.range: phobos_iota = iota; int s; // 0 1 2 3 4.phobos_iota.each!(i => s += i); assert(s == 6);
Implements the homonym function (also known as accumulate, compress, inject, or fold) present in various programming languages of functional flavor. The call reduce!(fun)(seed, slice1, ..., sliceN) first assigns seed to an internal variable result, also called the accumulator. Then, for each set of element x1, ..., xN in slice1, ..., sliceN, result = fun(result, x1, ..., xN) gets evaluated. Finally, result is returned.
reduce allows to iterate multiple slices in the lockstep.
Note: $(NDSLICEREF topology, pack) can be used to specify dimensions.