Report a bug
If you spot a problem with this page, click here to create a GitHub issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

mir.algorithm.iteration

This module contains generic iteration algorithms.

Function

Function Name Description
all Checks if all elements satisfy to a predicate.
any Checks if at least one element satisfy to a predicate.
cmp Compares two slices.
count Counts elements in a slices according to a predicate.
each Iterates elements.
eachLower Iterates lower triangle of matrix.
eachOnBorder Iterates elementes on tensors borders and corners.
eachUploPair Iterates upper and lower pairs of elements in square matrix.
eachUpper Iterates upper triangle of matrix.
equal Compares two slices for equality.
filter Filters elements in a range or an ndslice.
find Finds backward index.
findIndex Finds index.
fold Accumulates all elements (different parameter order than reduce).
isSymmetric Checks if the matrix is symmetric.
maxIndex Finds index of the maximum.
maxPos Finds backward index of the maximum.
minIndex Finds index of the minimum.
minmaxIndex Finds indices of the minimum and the maximum.
minmaxPos Finds backward indices of the minimum and the maximum.
minPos Finds backward index of the minimum.
nBitsToCount Сount bits until set bit count is reached.
reduce Accumulates all elements.
Chequer Chequer color selector to work with each .
uniq Iterates over the unique elements in a range or an ndslice, which is assumed sorted.
Transform function is represented by map .
All operators are suitable to change slices using ref argument qualification in a function declaration. Note, that string lambdas in Mir are auto ref functions.
License:
Authors:
Ilya Yaroshenko, John Michael Hall, Andrei Alexandrescu (original Phobos code)
License:
Authors:
, Ilya Yaroshenko (Mir & BetterC rework).

Source

enum Chequer: bool;
Chequer color selector to work with each
Examples:
import mir.ndslice.allocation: slice;
auto s = [5, 4].slice!int;

Chequer.black.each!"a = 1"(s);
assert(s == [
    [1, 0, 1, 0],
    [0, 1, 0, 1],
    [1, 0, 1, 0],
    [0, 1, 0, 1],
    [1, 0, 1, 0],
]);

Chequer.red.each!((ref b) => b = 2)(s);
assert(s == [
    [1, 2, 1, 2],
    [2, 1, 2, 1],
    [1, 2, 1, 2],
    [2, 1, 2, 1],
    [1, 2, 1, 2],
]);
black
Main diagonal color
red
First sub-diagonal color
sizediff_t nBitsToCount(Field, I)(Slice!(FieldIterator!(BitField!(Field, I))) bitSlice, size_t count);

sizediff_t nBitsToCount(Field, I)(Slice!(RetroIterator!(FieldIterator!(BitField!(Field, I)))) bitSlice, size_t count);
Сount bits until set bit count is reached. Works with ndslices created with mir.ndslice.topology.bitwise, mir.ndslice.allocation.bitSlice.
Returns:
bit count if set bit count is reached or -1 otherwise.
Examples:
import mir.ndslice.allocation: bitSlice;
import mir.ndslice.topology: retro;
auto s = bitSlice(1000);
s[50] = true;
s[100] = true;
s[200] = true;
s[300] = true;
s[400] = true;
assert(s.nBitsToCount(4) == 301);
assert(s.retro.nBitsToCount(4) == 900);
template reduce(alias fun)
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 pack  can be used to specify dimensions.

Parameters:
fun A function.
Examples:
Ranges and arrays
auto ar = [1, 2, 3];
auto s = 0.reduce!"a + b"(ar);
assert (s == 6);
Examples:
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);
Examples:
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));
Examples:
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 : optmath;

static @optmath 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)));
Examples:
Tensor mutation on-the-fly
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : as, iota;
import mir.math.common : optmath;

static @optmath 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));
Examples:
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);
Examples:
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);
auto reduce(S, Slices...)(S seed, scope Slices slices)
if (Slices.length);
Parameters:
S seed An initial accumulation value.
Slices slices One or more slices, range, and arrays.
Returns:
the accumulated result
template eachOnBorder(alias fun)
The call each!(fun)(slice1, ..., sliceN) evaluates fun for each set of elements x1, ..., xN in the borders of slice1, ..., sliceN respectively.
each allows to iterate multiple slices in the lockstep.
Parameters:
fun A function.

Note transposed  and pack  can be used to specify dimensions.

Examples:
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : repeat, iota;

auto sl = [3, 4].iota.slice;
auto zeros = repeat(0, [3, 4]);

sl.eachOnBorder!"a = b"(zeros);

assert(sl == 
    [[0, 0, 0 ,0],
     [0, 5, 6, 0],
     [0, 0, 0 ,0]]);

sl.eachOnBorder!"a = 1";
sl[0].eachOnBorder!"a = 2";

assert(sl == 
    [[2, 1, 1, 2],
     [1, 5, 6, 1],
     [1, 1, 1 ,1]]);
void eachOnBorder(Slices...)(Slices slices)
if (allSatisfy!(isSlice, Slices));
Parameters:
Slices slices One or more slices.
template each(alias fun)
The call each!(fun)(slice1, ..., sliceN) evaluates fun for each set of elements x1, ..., xN in slice1, ..., sliceN respectively.
each allows to iterate multiple slices in the lockstep.
Parameters:
fun A function.

Note transposed  and pack  can be used to specify dimensions.

See Also:
This is functionally similar to reduce but has not seed.
Examples:
Ranges and arrays
auto ar = [1, 2, 3];
ar.each!"a *= 2";
assert (ar == [2, 4, 6]);
Examples:
Single slice, multiply-add
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : as, iota;

//| 0 1 2 |
//| 3 4 5 |
auto sl = iota(2, 3).as!double.slice;

sl.each!((ref a) { a = a * 10 + 5; });

assert(sl ==
    [[ 5, 15, 25],
     [35, 45, 55]]);
Examples:
Swap two slices
import mir.utility : swap;
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;
//| 10 11 12 |
//| 13 14 15 |
auto b = iota([2, 3], 10).as!double.slice;

each!swap(a, b);

assert(a == iota([2, 3], 10));
assert(b == iota([2, 3], 0));
Examples:
Swap two zipped slices
import mir.utility : swap;
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : as, zip, iota;

//| 0 1 2 |
//| 3 4 5 |
auto a = iota([2, 3], 0).as!double.slice;
//| 10 11 12 |
//| 13 14 15 |
auto b = iota([2, 3], 10).as!double.slice;

auto z = zip(a, b);

z.each!(z => swap(z.a, z.b));

assert(a == iota([2, 3], 10));
assert(b == iota([2, 3], 0));
auto each(Slices...)(scope Slices slices)
if (Slices.length && !is(Slices[0] : Chequer));
Parameters:
Slices slices One or more slices, ranges, and arrays.
auto each(Slices...)(Chequer color, scope Slices slices)
if (Slices.length && allSatisfy!(isSlice, Slices));
Iterates elements of selected Chequer color.
Parameters:
Chequer color Chequer.
Slices slices One or more slices.
template eachUploPair(alias fun, bool includeDiagonal = false)
The call eachUploPair!(fun)(matrix) evaluates fun for each pair (matrix[j, i], matrix[i, j]), for i <= j (default) or i < j (if includeDiagonal is false).
Parameters:
fun A function.
includeDiagonal true if applying function to diagonal, false (default) otherwise.
Examples:
Transpose matrix in place.
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota, universal;
import mir.ndslice.dynamic: transposed;
import mir.utility: swap;

auto m = iota(4, 4).slice;

m.eachUploPair!swap;

assert(m == iota(4, 4).universal.transposed);
Examples:
Reflect Upper matrix part to lower part.
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota, universal;
import mir.ndslice.dynamic: transposed;
import mir.utility: swap;

// 0 1 2
// 3 4 5
// 6 7 8
auto m = iota(3, 3).slice;

m.eachUploPair!((u, ref l) { l = u; });

assert(m == [
    [0, 1, 2],
    [1, 4, 5],
    [2, 5, 8]]);
Examples:
Fill lower triangle and diagonal with zeroes.
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

// 1 2 3
// 4 5 6
// 7 8 9
auto m = iota([3, 3], 1).slice;

m.eachUploPair!((u, ref l) { l = 0; }, true);

assert(m == [
    [0, 2, 3],
    [0, 0, 6],
    [0, 0, 0]]);
auto eachUploPair(Iterator, SliceKind kind)(Slice!(Iterator, 2, kind) matrix);
Parameters:
Slice!(Iterator, 2, kind) matrix Square matrix.
template isSymmetric(alias fun = "a == b")
Checks if the matrix is symmetric.
Examples:
import mir.ndslice.slice: sliced;
import mir.ndslice.topology: iota;
assert(iota(2, 2).isSymmetric == false);

assert(
    [1, 2,
     2, 3].sliced(2, 2).isSymmetric == true);
bool isSymmetric(Iterator, SliceKind kind)(Slice!(Iterator, 2, kind) matrix);
Parameters:
Slice!(Iterator, 2, kind) matrix 2D ndslice.
template minmaxPos(alias pred = "a < b")
Finds a positions (ndslices) such that position[0].first is minimal and position[1].first is maximal elements in the slice.
Position is sub-ndslice of the same dimension in the right-)down-)etc(( corner.
Parameters:
pred A predicate.
Examples:
import mir.ndslice.slice: sliced;
auto s = [
    2, 6, 4, -3,
    0, -4, -3, 3,
    -3, -2, 7, 2,
    ].sliced(3, 4);

auto pos = s.minmaxPos;

assert(pos[0] == s[$ - 2 .. $, $ - 3 .. $]);
assert(pos[1] == s[$ - 1 .. $, $ - 2 .. $]);

assert(pos[0].first == -4);
assert(s.backward(pos[0].shape) == -4);
assert(pos[1].first ==  7);
assert(s.backward(pos[1].shape) ==  7);
Slice!(Iterator, N, kind == Contiguous && (N > 1) ? Canonical : kind)[2] minmaxPos(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice);
Parameters:
Slice!(Iterator, N, kind) slice ndslice.
Returns:
2 subslices with minimal and maximal first elements.
template minmaxIndex(alias pred = "a < b")
Finds a backward indices such that slice[indices[0]] is minimal and slice[indices[1]] is maximal elements in the slice.
Parameters:
pred A predicate.
Examples:
import mir.ndslice.slice: sliced;
auto s = [
    2, 6, 4, -3,
    0, -4, -3, 3,
    -3, -2, 7, 8,
    ].sliced(3, 4);

auto indices = s.minmaxIndex;

assert(indices == [[1, 1], [2, 3]]);
assert(s[indices[0]] == -4);
assert(s[indices[1]] ==  8);
size_t[N][2] minmaxIndex(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice);
Parameters:
Slice!(Iterator, N, kind) slice ndslice.
Returns:
Subslice with minimal (maximal) first element.
template minPos(alias pred = "a < b")

template maxPos(alias pred = "a < b")
Finds a backward index such that slice.backward(index) is minimal(maximal).
Parameters:
pred A predicate.
Examples:
import mir.ndslice.slice: sliced;
auto s = [
    2, 6, 4, -3,
    0, -4, -3, 3,
    -3, -2, 7, 2,
    ].sliced(3, 4);

auto pos = s.minPos;

assert(pos == s[$ - 2 .. $, $ - 3 .. $]);
assert(pos.first == -4);
assert(s.backward(pos.shape) == -4);

pos = s.maxPos;

assert(pos == s[$ - 1 .. $, $ - 2 .. $]);
assert(pos.first == 7);
assert(s.backward(pos.shape) == 7);
Slice!(Iterator, N, kind == Contiguous && (N > 1) ? Canonical : kind) minPos(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice);
Parameters:
Slice!(Iterator, N, kind) slice ndslice.
Returns:
Multidimensional backward index such that element is minimal(maximal). Backward index equals zeros, if slice is empty.
template minIndex(alias pred = "a < b")

template maxIndex(alias pred = "a < b")
Finds an index such that slice[index] is minimal(maximal).
Parameters:
pred A predicate.
See Also:
Examples:
import mir.ndslice.slice: sliced;
auto s = [
    2, 6, 4, -3,
    0, -4, -3, 3,
    -3, -2, 7, 8,
    ].sliced(3, 4);

auto index = s.minIndex;

assert(index == [1, 1]);
assert(s[index] == -4);

index = s.maxIndex;

assert(index == [2, 3]);
assert(s[index] == 8);
Examples:
import mir.ndslice.slice: sliced;
auto s = [
    -8, 6, 4, -3,
    0, -4, -3, 3,
    -3, -2, 7, 8,
    ].sliced(3, 4);

auto index = s.minIndex;

assert(index == [0, 0]);
assert(s[index] == -8);
size_t[N] minIndex(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice);
Parameters:
Slice!(Iterator, N, kind) slice ndslice.
Returns:
Multidimensional index such that element is minimal(maximal). Index elements equal to size_t.max, if slice is empty.
template findIndex(alias pred)
Finds an index such that pred(slices[0][index], ..., slices[$-1][index]) is true.
Parameters:
pred A predicate.
See Also:

Optimization findIndex!"a" has accelerated specialization for slices created with mir.ndslice.topology.bitwise, mir.ndslice.allocation.bitSlice.

Examples:
Ranges and arrays
import std.range : iota;
// 0 1 2 3 4 5
auto sl = iota(5);
size_t index = sl.findIndex!"a == 3";

assert(index == 3);
assert(sl[index] == 3);

assert(sl.findIndex!(a => a == 8) == size_t.max);
Examples:
import mir.ndslice.topology : iota;
// 0 1 2
// 3 4 5
auto sl = iota(2, 3);
size_t[2] index = sl.findIndex!(a => a == 3);

assert(sl[index] == 3);

index = sl.findIndex!"a == 6";
assert(index[0] == size_t.max);
assert(index[1] == size_t.max);
Select!(DimensionCount!(Slices[0]) > 1, size_t[DimensionCount!(Slices[0])], size_t) findIndex(Slices...)(Slices slices)
if (Slices.length);
Parameters:
Slices slices One or more slices.
Returns:
Multidimensional index such that the predicate is true. Index equals size_t.max, if the predicate evaluates false for all indices.

Constraints All slices must have the same shape.

template find(alias pred)
Finds a backward index such that pred(slices[0].backward(index), ..., slices[$-1].backward(index)) is true.
Parameters:
pred A predicate.

Optimization To check if any element was found use the last dimension (row index). This will slightly optimize the code.

if (backwardIndex)
{
    auto elem1 = slice1.backward(backwardIndex);
    //...
    auto elemK = sliceK.backward(backwardIndex);
}
else
{
    // not found
}

Optimization find!"a" has accelerated specialization for slices created with mir.ndslice.topology.bitwise, mir.ndslice.allocation.bitSlice.

Examples:
Ranges and arrays
import std.range : iota;

auto sl = iota(10);
size_t index = sl.find!"a == 3";

assert(sl[$ - index] == 3);
Examples:
import mir.ndslice.topology : iota;
// 0 1 2
// 3 4 5
auto sl = iota(2, 3);
size_t[2] bi = sl.find!"a == 3";
assert(sl.backward(bi) == 3);
assert(sl[$ - bi[0], $ - bi[1]] == 3);

bi = sl.find!"a == 6";
assert(bi[0] == 0);
assert(bi[1] == 0);
Examples:
Multiple slices
import mir.ndslice.topology : iota;

// 0 1 2
// 3 4 5
auto a = iota(2, 3);
// 10 11 12
// 13 14 15
auto b = iota([2, 3], 10);

size_t[2] bi = find!((a, b) => a * b == 39)(a, b);
assert(a.backward(bi) == 3);
assert(b.backward(bi) == 13);
Examples:
Zipped slices
import mir.ndslice.topology : iota, zip;

// 0 1 2
// 3 4 5
auto a = iota(2, 3);
// 10 11 12
// 13 14 15
auto b = iota([2, 3], 10);

size_t[2] bi = zip!true(a, b).find!"a.a * a.b == 39";

assert(a.backward(bi) == 3);
assert(b.backward(bi) == 13);
Examples:
Mutation on-the-fly
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : as, iota;

// 0 1 2
// 3 4 5
auto sl = iota(2, 3).as!double.slice;

static bool pred(T)(ref T a)
{
    if (a == 5)
        return true;
    a = 8;
    return false;
}

size_t[2] bi = sl.find!pred;

assert(bi == [1, 1]);
assert(sl.backward(bi) == 5);

// sl was changed
assert(sl == [[8, 8, 8],
              [8, 8, 5]]);
Select!(DimensionCount!(Slices[0]) > 1, size_t[DimensionCount!(Slices[0])], size_t) find(Slices...)(auto ref Slices slices)
if (Slices.length && allSatisfy!(hasShape, Slices));
Parameters:
Slices slices One or more slices.
Returns:
Multidimensional backward index such that the predicate is true. Backward index equals zeros, if the predicate evaluates false for all indices.

Constraints All slices must have the same shape.

template any(alias pred = "a")
Like find, but only returns whether or not the search was successful.
Parameters:
pred The predicate.

Optimization any!"a" has accelerated specialization for slices created with mir.ndslice.topology.bitwise, mir.ndslice.allocation.bitSlice.

Examples:
Ranges and arrays
import std.range : iota;
// 0 1 2 3 4 5
auto r = iota(6);

assert(r.any!"a == 3");
assert(!r.any!"a == 6");
Examples:
import mir.ndslice.topology : iota;
// 0 1 2
// 3 4 5
auto sl = iota(2, 3);

assert(sl.any!"a == 3");
assert(!sl.any!"a == 6");
Examples:
Multiple slices
import mir.ndslice.topology : iota;

// 0 1 2
// 3 4 5
auto a = iota(2, 3);
// 10 11 12
// 13 14 15
auto b = iota([2, 3], 10);

assert(any!((a, b) => a * b == 39)(a, b));
Examples:
Zipped slices
import mir.ndslice.topology : iota, zip;

// 0 1 2
// 3 4 5
auto a = iota(2, 3);
// 10 11 12
// 13 14 15
auto b = iota([2, 3], 10);

// slices must have the same strides

assert(zip!true(a, b).any!"a.a * a.b == 39");
Examples:
Mutation on-the-fly
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : as, iota;

// 0 1 2
// 3 4 5
auto sl = iota(2, 3).as!double.slice;

static bool pred(T)(ref T a)
{
    if (a == 5)
        return true;
    a = 8;
    return false;
}

assert(sl.any!pred);

// sl was changed
assert(sl == [[8, 8, 8],
              [8, 8, 5]]);
bool any(Slices...)(scope Slices slices)
if ((Slices.length == 1 || !__traits(isSame, pred, "a")) && Slices.length);
Parameters:
Slices slices One or more slices, ranges, and arrays.
Returns:
true if the search was successful and false otherwise.

Constraints All slices must have the same shape.

template all(alias pred = "a")
Checks if all of the elements verify pred.
Parameters:
pred The predicate.

Optimization all!"a" has accelerated specialization for slices created with mir.ndslice.topology.bitwise, mir.ndslice.allocation.bitSlice.

Examples:
Ranges and arrays
import std.range : iota;
// 0 1 2 3 4 5
auto r = iota(6);

assert(r.all!"a < 6");
assert(!r.all!"a < 5");
Examples:
import mir.ndslice.topology : iota;

// 0 1 2
// 3 4 5
auto sl = iota(2, 3);

assert(sl.all!"a < 6");
assert(!sl.all!"a < 5");
Examples:
Multiple slices
import mir.ndslice.topology : iota;

// 0 1 2
// 3 4 5
auto sl = iota(2, 3);

assert(all!"a - b == 0"(sl, sl));
Examples:
Zipped slices
import mir.ndslice.topology : iota, zip;

// 0 1 2
// 3 4 5
auto sl = iota(2, 3);


assert(zip!true(sl, sl).all!"a.a - a.b == 0");
Examples:
Mutation on-the-fly
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : as, iota;

// 0 1 2
// 3 4 5
auto sl = iota(2, 3).as!double.slice;

static bool pred(T)(ref T a)
{
    if (a < 4)
    {
        a = 8;
        return true;
    }
    return false;
}

assert(!sl.all!pred);

// sl was changed
assert(sl == [[8, 8, 8],
              [8, 4, 5]]);
bool all(Slices...)(scope Slices slices)
if ((Slices.length == 1 || !__traits(isSame, pred, "a")) && Slices.length);
Parameters:
Slices slices One or more slices.
Returns:
true all of the elements verify pred and false otherwise.

Constraints All slices must have the same shape.

template count(alias fun)
Counts elements in slices according to the fun.
Parameters:
fun A predicate.

Optimization count!"a" has accelerated specialization for slices created with mir.ndslice.topology.bitwise, mir.ndslice.allocation.bitSlice.

Examples:
Ranges and arrays
import std.range : iota;
// 0 1 2 3 4 5
auto r = iota(6);

assert(r.count!"true" == 6);
assert(r.count!"a" == 5);
assert(r.count!"a % 2" == 3);
Examples:
Single slice
import mir.ndslice.topology : iota;

//| 0 1 2 |
//| 3 4 5 |
auto sl = iota(2, 3);

assert(sl.count!"true" == 6);
assert(sl.count!"a" == 5);
assert(sl.count!"a % 2" == 3);
Examples:
Accelerated set bit count
import mir.ndslice.topology: retro, iota, bitwise;
import mir.ndslice.allocation: slice;

//| 0 1 2 |
//| 3 4 5 |
auto sl = iota!size_t(2, 3).bitwise;

assert(sl.count!"true" == 6 * size_t.sizeof * 8);

assert(sl.slice.count!"a" == 7);

// accelerated
assert(sl.count!"a" == 7);
assert(sl.retro.count!"a" == 7);

auto sl2 = iota!ubyte([6], 128).bitwise;
// accelerated
assert(sl2.count!"a" == 13);
assert(sl2[4 .. $].count!"a" == 13);
assert(sl2[4 .. $ - 1].count!"a" == 12);
assert(sl2[4 .. $ - 1].count!"a" == 12);
assert(sl2[41 .. $ - 1].count!"a" == 1);
size_t count(Slices...)(scope Slices slices)
if (Slices.length);
Parameters:
Slices slices One or more slices, ranges, and arrays.
Returns:
The number elements according to the fun.

Constraints All slices must have the same shape.

template equal(alias pred = "a == b")
Compares two or more slices for equality, as defined by predicate pred.
See Also:
Parameters:
pred The predicate.
Examples:
Ranges and arrays
import std.range : iota;
auto r = iota(6);
assert(r.equal([0, 1, 2, 3, 4, 5]));
Examples:
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : iota;

// 0 1 2
// 3 4 5
auto sl1 = iota(2, 3);
// 1 2 3
// 4 5 6
auto sl2 = iota([2, 3], 1);

assert(equal(sl1, sl1));
assert(sl1 == sl1); //can also use opEquals for two Slices
assert(equal!"2 * a == b + c"(sl1, sl1, sl1));

assert(equal!"a < b"(sl1, sl2));

assert(!equal(sl1[0 .. $ - 1], sl1));
assert(!equal(sl1[0 .. $, 0 .. $ - 1], sl1));
bool equal(Slices...)(scope Slices slices)
if (Slices.length >= 2);
Parameters:
Slices slices Two or more ndslices, ranges, and arrays.
Returns:
true any of the elements verify pred and false otherwise.
template cmp(alias pred = "a < b")
Performs three-way recursive lexicographical comparison on two slices according to predicate pred. Iterating sl1 and sl2 in lockstep, cmp compares each N-1 dimensional element e1 of sl1 with the corresponding element e2 in sl2 recursively. If one of the slices has been finished,cmp returns a negative value if sl1 has fewer elements than sl2, a positive value if sl1 has more elements than sl2, and 0 if the ranges have the same number of elements.
Parameters:
pred The predicate.
Examples:
Ranges and arrays
import std.range : iota;

// 0 1 2 3 4 5
auto r1 = iota(0, 6);
// 1 2 3 4 5 6
auto r2 = iota(1, 7);

assert(cmp(r1, r1) == 0);
assert(cmp(r1, r2) < 0);
assert(cmp!"a >= b"(r1, r2) > 0);
Examples:
import mir.ndslice.topology : iota;

// 0 1 2
// 3 4 5
auto sl1 = iota(2, 3);
// 1 2 3
// 4 5 6
auto sl2 = iota([2, 3], 1);

assert(cmp(sl1, sl1) == 0);
assert(cmp(sl1, sl2) < 0);
assert(cmp!"a >= b"(sl1, sl2) > 0);
auto cmp(A, B)(scope A sl1, scope B sl2)
if (DimensionCount!A == DimensionCount!B);
Parameters:
A sl1 First slice, range, or array.
B sl2 Second slice, range, or array.
Returns:
0 if both ranges compare equal. Negative value if the first differing element of sl1 is less than the corresponding element of sl2 according to pred. Positive value if the first differing element of sl2 is less than the corresponding element of sl1 according to pred.
size_t maxLength(S)(auto ref scope S s)
if (hasShape!S);
Returns:
max length across all dimensions.
template eachLower(alias fun)
The call eachLower!(fun)(slice1, ..., sliceN) evaluates fun on the lower triangle in slice1, ..., sliceN respectively.
eachLower allows iterating multiple slices in the lockstep.
Parameters:
fun A function
See Also:
This is functionally similar to each.
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

//| 1 2 3 |
//| 4 5 6 |
//| 7 8 9 |
auto m = iota([3, 3], 1).slice;
m.eachLower!"a = 0";
assert(m == [
    [1, 2, 3],
    [0, 5, 6],
    [0, 0, 9]]);
Examples:
Swap two slices
import mir.utility : swap;
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : as, iota;

//| 0 1 2 |
//| 3 4 5 |
//| 6 7 8 |
auto a = iota([3, 3]).as!double.slice;
//| 10 11 12 |
//| 13 14 15 |
//| 16 17 18 |
auto b = iota([3, 3], 10).as!double.slice;

eachLower!swap(a, b);

assert(a == [
    [ 0,  1, 2],
    [13,  4, 5],
    [16, 17, 8]]);
assert(b == [
    [10, 11, 12],
    [ 3, 14, 15],
    [ 6,  7, 18]]);
Examples:
Swap two zipped slices
import mir.utility : swap;
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : as, zip, iota;

//| 0 1 2 |
//| 3 4 5 |
//| 6 7 8 |
auto a = iota([3, 3]).as!double.slice;
//| 10 11 12 |
//| 13 14 15 |
//| 16 17 18 |
auto b = iota([3, 3], 10).as!double.slice;

auto z = zip(a, b);

z.eachLower!(z => swap(z.a, z.b));

assert(a == [
    [ 0,  1, 2],
    [13,  4, 5],
    [16, 17, 8]]);
assert(b == [
    [10, 11, 12],
    [ 3, 14, 15],
    [ 6,  7, 18]]);
void eachLower(Inputs...)(scope Inputs inputs)
if (Inputs.length > 1 && isIntegral!(Inputs[$ - 1]) || Inputs.length);
Parameters:
Inputs inputs One or more two-dimensional slices and an optional integer, k.
The value k determines which diagonals will have the function applied: For k = 0, the function is also applied to the main diagonal For k = 1 (default), only the non-main diagonals below the main diagonal will have the function applied. For k > 1, fewer diagonals below the main diagonal will have the function applied. For k < 0, more diagonals above the main diagonal will have the function applied.
template eachUpper(alias fun)
The call eachUpper!(fun)(slice1, ..., sliceN) evaluates fun on the upper triangle in slice1, ..., sliceN, respectively.
eachUpper allows iterating multiple slices in the lockstep.
Parameters:
fun A function
See Also:
This is functionally similar to each.
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

//| 1 2 3 |
//| 4 5 6 |
//| 7 8 9 |
auto m = iota([3, 3], 1).slice;
m.eachUpper!"a = 0";
assert(m == [
    [1, 0, 0],
    [4, 5, 0],
    [7, 8, 9]]);
Examples:
Swap two slices
import mir.utility : swap;
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : as, iota;

//| 0 1 2 |
//| 3 4 5 |
//| 6 7 8 |
auto a = iota([3, 3]).as!double.slice;
//| 10 11 12 |
//| 13 14 15 |
//| 16 17 18 |
auto b = iota([3, 3], 10).as!double.slice;

eachUpper!swap(a, b);

assert(a == [
    [0, 11, 12],
    [3,  4, 15],
    [6,  7,  8]]);
assert(b == [
    [10,  1,  2],
    [13, 14,  5],
    [16, 17, 18]]);
Examples:
Swap two zipped slices
import mir.utility : swap;
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : as, zip, iota;

//| 0 1 2 |
//| 3 4 5 |
//| 6 7 8 |
auto a = iota([3, 3]).as!double.slice;
//| 10 11 12 |
//| 13 14 15 |
//| 16 17 18 |
auto b = iota([3, 3], 10).as!double.slice;

auto z = zip(a, b);

z.eachUpper!(z => swap(z.a, z.b));

assert(a == [
    [0, 11, 12],
    [3,  4, 15],
    [6,  7,  8]]);
assert(b == [
    [10,  1,  2],
    [13, 14,  5],
    [16, 17, 18]]);
void eachUpper(Inputs...)(scope Inputs inputs)
if (Inputs.length > 1 && isIntegral!(Inputs[$ - 1]) || Inputs.length);
Parameters:
Inputs inputs One or more two-dimensional slices and an optional integer, k.
The value k determines which diagonals will have the function applied: For k = 0, the function is also applied to the main diagonal For k = 1 (default), only the non-main diagonals above the main diagonal will have the function applied. For k > 1, fewer diagonals below the main diagonal will have the function applied. For k < 0, more diagonals above the main diagonal will have the function applied.
template uniq(alias pred = "a == b")
Lazily iterates unique consecutive elements of the given range (functionality akin to the uniq system utility). Equivalence of elements is assessed by using the predicate pred, by default "a == b". The predicate is passed to mir.functional.nary, and can either accept a string, or any callable that can be executed via pred(element, element). If the given range is bidirectional, uniq also yields a std,range,primitives.
Parameters:
pred Predicate for determining equivalence between range elements.
Examples:
int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ];
assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ]));

import std.algorithm.mutation : copy;
// Filter duplicates in-place using copy
arr.length -= arr.uniq.copy(arr).length;
assert(arr == [ 1, 2, 3, 4, 5 ]);

// Note that uniqueness is only determined consecutively; duplicated
// elements separated by an intervening different element will not be
// eliminated:
assert(equal(uniq([ 1, 1, 2, 1, 1, 3, 1]), [1, 2, 1, 3, 1]));
Examples:
N-dimensional case
import mir.ndslice.fuse;
import mir.ndslice.topology: byDim, map, iota;

auto matrix = [ [1, 2, 2], [2, 2, 3], [4, 4, 4] ].fuse;

assert(matrix.uniq.equal([ 1, 2, 3, 4 ]));

// unique elements for each row
assert(matrix.byDim!0.map!uniq.equal!equal([ [1, 2], [2, 3], [4] ]));
Uniq!(naryFun!pred, Range) uniq(Range)(Range r)
if (isInputRange!Range && !isSlice!Range);

auto uniq(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice);
Parameters:
Range r An input range of elements to filter.
Returns:
An input range of consecutively unique elements in the original range. If r is also a forward range or bidirectional range, the returned range will be likewise.
struct Uniq(alias pred, Range);

Authros Andrei Alexandrescu (original Phobos code), Ilya Yaroshenko (betterC rework)

template filter(alias pred = "a")

struct Filter(alias pred, Range);
Implements the higher order filter function. The predicate is passed to mir.functional.naryFun, and can either accept a string, or any callable that can be executed via pred(element).
Parameters:
pred Function to apply to each element of range
Returns:
filter!(pred)(range) returns a new range containing only elements x in range for which pred(x) returns true.

Note User and library code MUST call empty method ahead each call of pair or one of front and popFront methods.

Examples:
int[] arr = [ 0, 1, 2, 3, 4, 5 ];

// Filter below 3
auto small = filter!(a => a < 3)(arr);
assert(equal(small, [ 0, 1, 2 ]));

// Filter again, but with Uniform Function Call Syntax (UFCS)
auto sum = arr.filter!(a => a < 3);
assert(equal(sum, [ 0, 1, 2 ]));

// Filter with the default predicate
auto nonZeros = arr.filter;
assert(equal(nonZeros, [ 1, 2, 3, 4, 5 ]));

// In combination with concatenation() to span multiple ranges
import mir.ndslice.concatenation;

int[] a = [ 3, -2, 400 ];
int[] b = [ 100, -101, 102 ];
auto r = concatenation(a, b).filter!(a => a > 0);
assert(equal(r, [ 3, 400, 100, 102 ]));

// Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ];
auto r1 = concatenation(c, a, b).filter!(a => cast(int) a != a);
assert(equal(r1, [ 2.5 ]));
Examples:
N-dimensional filtering
import mir.ndslice.fuse;
import mir.ndslice.topology: byDim, map;

auto matrix =
    [[   3,   -2, 400 ],
     [ 100, -101, 102 ]].fuse;

alias filterPositive = filter!"a > 0";

// filter all elements in the matrix
auto r = filterPositive(matrix);
assert(equal(r, [ 3, 400, 100, 102 ]));

// filter all elements for each row
auto rr = matrix.byDim!0.map!filterPositive;
assert(equal!equal(rr, [ [3, 400], [100, 102] ]));

// filter all elements for each column
auto rc = matrix.byDim!1.map!filterPositive;
assert(equal!equal(rc, [ [3, 100], [], [400, 102] ]));
Filter!(naryFun!pred, Range) filter(Range)(Range r)
if (isInputRange!Range && !isSlice!Range);

auto filter(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice);
Parameters:
Range r An input range of elements to filter.
Returns:
A new range containing only elements x in range for which predicate(x) returns true.
template rcfilter(alias pred = "a", alias map = "a")
Implements the higher order filter and map function. The predicate and map functions are passed to mir.functional.naryFun, and can either accept a string, or any callable that can be executed via pred(element) and map(element).
Parameters:
pred Filter function to apply to each element of range (optional)
map Map function to apply to each element of range
Returns:
rcfilter!(pred)(range) returns a new RCArray containing only elements map(x) in range for which pred(x) returns true.
Examples:
import mir.ndslice.topology: iota;

auto val = 3;
auto factor = 5;
// Filter iota 2x3 matrix below 3
assert(iota(2, 3).rcfilter!(a => a < val).moveToSlice.equal(val.iota));
// Filter and map below 3
assert(6.iota.rcfilter!(a => a < val, a => a * factor).moveToSlice.equal(val.iota * factor));
auto rcfilter(Range)(Range r)
if (isIterable!Range && (!isSlice!Range || DimensionCount!Range == 1));

auto rcfilter(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice)
if (N > 1);
Parameters:
Range r An input range of elements to filter.
Returns:
A new range containing only elements x in range for which predicate(x) returns true.
template fold(alias fun)
Implements the homonym function (also known as accumulate, compress, inject, or foldl) present in various programming languages of functional flavor. The call fold!(fun)(slice, seed) first assigns seed to an internal variable result, also called the accumulator. Then, for each element x in slice, result = fun(result, x) gets evaluated. Finally, result is returned.
Parameters:
fun the predicate function to apply to the elements
See Also:
Fold (higher-order function) sum is similar to fold!((a, b) => a + b) that offers precise summing of floating point numbers. This is functionally equivalent to reduce with the argument order reversed.
Examples:
import mir.ndslice.slice: sliced;
import mir.ndslice.topology: map;

auto arr = [1, 2, 3, 4, 5].sliced;

// Sum all elements
assert(arr.fold!((a, b) => a + b)(0) == 15);
assert(arr.fold!((a, b) => a + b)(6) == 21);

// Can be used in a UFCS chain
assert(arr.map!(a => a + 1).fold!((a, b) => a + b)(0) == 20);

// Return the last element of any range
assert(arr.fold!((a, b) => b)(0) == 5);
Examples:
Works for matrices
import mir.ndslice.fuse: fuse;

auto arr = [
    [1, 2, 3], 
    [4, 5, 6]
].fuse;

assert(arr.fold!((a, b) => a + b)(0) == 21);
auto fold(Slice, S)(scope Slice slice, S seed);
Parameters:
Slice slice A slice, range, and array.
S seed An initial accumulation value.
Returns:
the accumulated result