mir.algorithm.iteration
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. |
Source
- enum
Chequer
: bool; - Chequer color selector to work with eachExamples:
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_tcount
);
sizediff_tnBitsToCount
(Field, I)(Slice!(RetroIterator!(FieldIterator!(BitField!(Field, I))))bitSlice
, size_tcount
); - С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 arraysauto ar = [1, 2, 3]; auto s = 0.reduce!"a + b"(ar); assert (s == 6);
Examples:Single sliceimport 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 productimport 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 productimport 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-flyimport 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...)(Sseed
, scope Slicesslices
)
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...)(Slicesslices
)
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 arraysauto ar = [1, 2, 3]; ar.each!"a *= 2"; assert (ar == [2, 4, 6]);
Examples:Single slice, multiply-addimport 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 slicesimport 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 slicesimport 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 Slicesslices
)
if (Slices.length && !is(Slices[0] : Chequer)); - Parameters:
Slices slices
One or more slices, ranges, and arrays. - auto
each
(Slices...)(Chequercolor
, scope Slicesslices
)
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. See Also: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. 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 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")
templatemaxPos
(alias pred = "a < b") - Finds a backward index such that slice.backward(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, 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")
templatemaxIndex
(alias pred = "a < b") - Finds an index such that slice[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, 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. Optimization
findIndex
!"a" has accelerated specialization for slices created with mir.ndslice.topology.bitwise, mir.ndslice.allocation.bitSlice.Examples:Ranges and arraysimport 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...)(Slicesslices
)
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 }
See Also:Optimization
find
!"a" has accelerated specialization for slices created with mir.ndslice.topology.bitwise, mir.ndslice.allocation.bitSlice.Examples:Ranges and arraysimport 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 slicesimport 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 slicesimport 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-flyimport 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 Slicesslices
)
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 arraysimport 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 slicesimport 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 slicesimport 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-flyimport 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 Slicesslices
)
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 arraysimport 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 slicesimport mir.ndslice.topology : iota; // 0 1 2 // 3 4 5 auto sl = iota(2, 3); assert(all!"a - b == 0"(sl, sl));
Examples:Zipped slicesimport 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-flyimport 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 Slicesslices
)
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 arraysimport 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 sliceimport 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 countimport 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 Slicesslices
)
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 arraysimport 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 Slicesslices
)
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 arraysimport 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 Asl1
, scope Bsl2
)
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 ofsl1
is less than the corresponding element ofsl2
according to pred. Positive value if the first differing element ofsl2
is less than the corresponding element ofsl1
according to pred.
- size_t
maxLength
(S)(auto ref scope Ss
)
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 slicesimport 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 slicesimport 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 Inputsinputs
)
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 slicesimport 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 slicesimport 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 Inputsinputs
)
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 caseimport 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)(Ranger
)
if (isInputRange!Range && !isSlice!Range);
autouniq
(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. Ifr
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")
structFilter
(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.See Also: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 filteringimport 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)(Ranger
)
if (isInputRange!Range && !isSlice!Range);
autofilter
(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.See Also: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)(Ranger
)
if (isIterable!Range && (!isSlice!Range || DimensionCount!Range == 1));
autorcfilter
(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 tofold
!((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 matricesimport 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 Sliceslice
, Sseed
); - Parameters:
Slice slice
A slice, range, and array. S seed
An initial accumulation value. Returns:the accumulated result