Libmir Archive

Algorithms — map, reduce, each, fold

mir.algorithm.iteration provides functional-style algorithms that work natively with ndslice: each, reduce, fold, all, any, find, and more. All are @nogc and BetterC-compatible.

mir.algorithm.iteration is the ndslice-aware equivalent of std.algorithm. Unlike std.algorithm, these functions understand multi-dimensional slices and can iterate in row-major or custom order.

Import

import mir.algorithm.iteration;
// or selectively:
import mir.algorithm.iteration : each, reduce, fold, all, any;

each — side-effectful iteration

auto m = slice!double(3, 4);

// Value only
m.each!((ref double v) { v = 1.0; });

// Value + indices
m.each!((ref double v, size_t i, size_t j) {
    v = cast(double)(i * 4 + j);
});

// Pair-wise: two slices of the same shape
auto a = iota!double(3, 4);
auto b = slice!double(3, 4);
each!((double x, ref double y) { y = x * 2; })(a, b);

each always returns void. Use it for in-place mutation.

reduce — fold to a scalar

import mir.algorithm.iteration : reduce;

auto v = [1.0, 2.0, 3.0, 4.0].sliced;

double sum  = v.reduce!"a + b"(0.0);      // 10.0
double prod = v.reduce!"a * b"(1.0);      // 24.0
double mx   = v.reduce!fmax(double.nan);  // 4.0

Works on any-dimensional slice by iterating all elements in row-major order.

fold — accumulate with initial value (alias style)

import mir.algorithm.iteration : fold;

alias sum  = fold!"a + b";
alias prod = fold!"a * b";

double s = sum(v, 0.0);   // same as reduce but cleaner aliasing

all and any — boolean tests

import mir.algorithm.iteration : all, any;

auto m = iota(3, 4);

bool allPositive = m.all!(x => x >= 0);   // true
bool anyBig      = m.any!(x => x > 10);   // true (11)

Short-circuits on first failure / success.

find — locate an element

import mir.algorithm.iteration : find;

auto v = [3.0, 1.0, 4.0, 1.0, 5.0].sliced;
auto rest = v.find!(x => x > 3.5);
// rest starts at the element 4.0

minmaxIndex and minIndex / maxIndex

import mir.algorithm.iteration : minIndex, maxIndex, minmaxIndex;

auto v = [3.0, 1.0, 4.0, 1.0, 5.0].sliced;
size_t mi = v.minIndex;  // 1
size_t mx = v.maxIndex;  // 4
auto (mn, mx2) = v.minmaxIndex;

Sorting (mir.algorithm.sorting)

import mir.algorithm.sorting : sort;

auto v = [3, 1, 4, 1, 5, 9, 2].sliced;
v.sort;        // in-place ascending
v.sort!"a > b"; // descending

Unlike std.algorithm.sort, mir.algorithm.sorting.sort works on contiguous ndslice directly without converting to a range.

Performance notes

  • All functions in mir.algorithm.iteration are @nogc nothrow @safe (where the lambda allows).
  • For contiguous slices, the compiler typically auto-vectorizes the inner loop — no manual SIMD needed for simple kernels.
  • For 2-D and higher slices, operations iterate in row-major (C) order, which is cache-friendly for contiguous slices.

Comparison with std.algorithm

Featurestd.algorithmmir.algorithm
ndslice supportVia .byElement conversionNative
@nogcSomeAll
BetterCNoYes
2-D aware eachNoYes (index args)
SIMD auto-vecLimitedBetter (contiguous)

On this page