One or more functions.
import mir.ndslice.topology : iota; auto s = iota(2, 3).map!(a => a * 3); assert(s == [[ 0, 3, 6], [ 9, 12, 15]]);
String lambdas
import mir.ndslice.topology : iota; assert(iota(2, 3).map!"a * 2" == [[0, 2, 4], [6, 8, 10]]);
Input ranges
import mir.algorithm.iteration: filter, equal; assert (6.iota.filter!"a % 2".map!"a * 10".equal([10, 30, 50]));
Packed tensors
import mir.ndslice.topology : iota, windows; import mir.math.sum: sum; // iota windows map sums ( reduce!"a + b" ) // -------------- // ------- | --- --- | ------ // | 0 1 2 | => || 0 1 || 1 2 || => | 8 12 | // | 3 4 5 | || 3 4 || 4 5 || ------ // ------- | --- --- | // -------------- auto s = iota(2, 3) .windows(2, 2) .map!sum; assert(s == [[8, 12]]);
Zipped tensors
import mir.ndslice.topology : iota, zip; // 0 1 2 // 3 4 5 auto sl1 = iota(2, 3); // 1 2 3 // 4 5 6 auto sl2 = iota([2, 3], 1); auto z = zip(sl1, sl2); assert(zip(sl1, sl2).map!"a + b" == sl1 + sl2); assert(zip(sl1, sl2).map!((a, b) => a + b) == sl1 + sl2);
Multiple functions can be passed to map. In that case, the element type of map is a refTuple containing one element for each function.
import mir.ndslice.topology : iota; auto sl = iota(2, 3); auto s = sl.map!("a + a", "a * a"); auto sums = [[0, 2, 4], [6, 8, 10]]; auto products = [[0, 1, 4], [9, 16, 25]]; assert(s.map!"a[0]" == sl + sl); assert(s.map!"a[1]" == sl * sl);
map can be aliased to a symbol and be used separately:
import mir.ndslice.topology : iota; alias halfs = map!"double(a) / 2"; assert(halfs(iota(2, 3)) == [[0.0, 0.5, 1], [1.5, 2, 2.5]]);
Type normalization
import mir.functional : pipe; import mir.ndslice.topology : iota; auto a = iota(2, 3).map!"a + 10".map!(pipe!("a * 2", "a + 1")); auto b = iota(2, 3).map!(pipe!("a + 10", "a * 2", "a + 1")); assert(a == b); static assert(is(typeof(a) == typeof(b)));
Use map with byDim/alongDim to apply functions to each dimension
import mir.ndslice.topology: byDim, alongDim; import mir.ndslice.fuse: fuse; import mir.math.stat: mean; import mir.algorithm.iteration: all; import mir.math.common: approxEqual; auto x = [ [0.0, 1.0, 1.5, 2.0, 3.5, 4.25], [2.0, 7.5, 5.0, 1.0, 1.5, 0.0] ].fuse; // Use byDim/alongDim with map to compute mean of row/column. assert(x.byDim!0.map!mean.all!approxEqual([12.25 / 6, 17.0 / 6])); assert(x.byDim!1.map!mean.all!approxEqual([1, 4.25, 3.25, 1.5, 2.5, 2.125])); assert(x.alongDim!1.map!mean.all!approxEqual([12.25 / 6, 17.0 / 6])); assert(x.alongDim!0.map!mean.all!approxEqual([1, 4.25, 3.25, 1.5, 2.5, 2.125]));
Use map with a lambda and with byDim/alongDim, but may need to allocate result. This example uses fuse, which allocates. Note: fuse!1 will transpose the result.
import mir.ndslice.topology: iota, byDim, alongDim, map; import mir.ndslice.fuse: fuse; import mir.ndslice.slice: sliced; auto x = [1, 2, 3].sliced; auto y = [1, 2].sliced; auto s1 = iota(2, 3).byDim!0.map!(a => a * x).fuse; assert(s1 == [[ 0, 2, 6], [ 3, 8, 15]]); auto s2 = iota(2, 3).byDim!1.map!(a => a * y).fuse!1; assert(s2 == [[ 0, 1, 2], [ 6, 8, 10]]); auto s3 = iota(2, 3).alongDim!1.map!(a => a * x).fuse; assert(s1 == [[ 0, 2, 6], [ 3, 8, 15]]); auto s4 = iota(2, 3).alongDim!0.map!(a => a * y).fuse!1; assert(s2 == [[ 0, 1, 2], [ 6, 8, 10]]);
import mir.algorithm.iteration: reduce; import mir.math.common: fmax; import mir.math.stat: mean; import mir.math.sum; /// Returns maximal column average. auto maxAvg(S)(S matrix) { return reduce!fmax(0.0, matrix.alongDim!1.map!mean); } // 1 2 // 3 4 auto matrix = iota([2, 2], 1); assert(maxAvg(matrix) == 3.5);
Implements the homonym function (also known as transform) present in many languages of functional flavor. The call map!(fun)(slice) returns a slice of which elements are obtained by applying fun for all elements in slice. The original slices are not changed. Evaluation is done lazily.
Note: transposed and pack can be used to specify dimensions.