The OpenD Programming Language

byDim

Returns a slice that can be iterated by dimension. Transposes dimensions on top and then packs them.

Combines transposed, ipack, and SliceKind Selectors.

template byDim(SDimensions...)
static if(allSatisfy!(isSizediff_t, SDimensions))
byDim
(
Iterator
size_t N
SliceKind kind
)
(
Slice!(Iterator, N, kind) slice
)
if (
N >= SDimensions.length
)
if (
SDimensions.length > 0
)

Members

Functions

byDim
auto byDim(Slice!(Iterator, N, kind) slice)

Parameters

SDimensions

dimensions to perform iteration on, length of d, 1 <= d <= n. Negative dimensions are supported.

Return Value

d-dimensional slice composed of (n-d)-dimensional slices

Examples

2-dimensional slice support

import mir.ndslice;

//  ------------
// | 0  1  2  3 |
// | 4  5  6  7 |
// | 8  9 10 11 |
//  ------------
auto slice = iota(3, 4);
//->
// | 3 |
//->
// | 4 |
size_t[1] shape3 = [3];
size_t[1] shape4 = [4];

//  ------------
// | 0  1  2  3 |
// | 4  5  6  7 |
// | 8  9 10 11 |
//  ------------
auto x = slice.byDim!0; // byDim!(-2) is the same for matrices.
static assert(is(typeof(x) == Slice!(SliceIterator!(IotaIterator!sizediff_t), 1, Universal)));

assert(x.shape == shape3);
assert(x.front.shape == shape4);
assert(x.front == iota(4));
x.popFront;
assert(x.front == iota([4], 4));

//  ---------
// | 0  4  8 |
// | 1  5  9 |
// | 2  6 10 |
// | 3  7 11 |
//  ---------
auto y = slice.byDim!(-1); // -1 is the last dimension index, the same as 1 for this case.
static assert(is(typeof(y) == Slice!(SliceIterator!(IotaIterator!sizediff_t, 1, Universal))));

assert(y.shape == shape4);
assert(y.front.shape == shape3);
assert(y.front == iota([3], 0, 4));
y.popFront;
assert(y.front == iota([3], 1, 4));

3-dimensional slice support, N-dimensional also supported

1 import mir.ndslice;
2 
3 //  ----------------
4 // | 0   1  2  3  4 |
5 // | 5   6  7  8  9 |
6 // | 10 11 12 13 14 |
7 // | 15 16 17 18 19 |
8 //  - - - - - - - -
9 // | 20 21 22 23 24 |
10 // | 25 26 27 28 29 |
11 // | 30 31 32 33 34 |
12 // | 35 36 37 38 39 |
13 //  - - - - - - - -
14 // | 40 41 42 43 44 |
15 // | 45 46 47 48 49 |
16 // | 50 51 52 53 54 |
17 // | 55 56 57 58 59 |
18 //  ----------------
19 auto slice = iota(3, 4, 5);
20 
21 size_t[2] shape45 = [4, 5];
22 size_t[2] shape35 = [3, 5];
23 size_t[2] shape34 = [3, 4];
24 size_t[2] shape54 = [5, 4];
25 size_t[1] shape3 = [3];
26 size_t[1] shape4 = [4];
27 size_t[1] shape5 = [5];
28 
29 //  ----------------
30 // |  0  1  2  3  4 |
31 // |  5  6  7  8  9 |
32 // | 10 11 12 13 14 |
33 // | 15 16 17 18 19 |
34 //  - - - - - - - -
35 // | 20 21 22 23 24 |
36 // | 25 26 27 28 29 |
37 // | 30 31 32 33 34 |
38 // | 35 36 37 38 39 |
39 //  - - - - - - - -
40 // | 40 41 42 43 44 |
41 // | 45 46 47 48 49 |
42 // | 50 51 52 53 54 |
43 // | 55 56 57 58 59 |
44 //  ----------------
45 auto x = slice.byDim!0;
46 static assert(is(typeof(x) == Slice!(SliceIterator!(IotaIterator!sizediff_t, 2), 1, Universal)));
47 
48 assert(x.shape == shape3);
49 assert(x.front.shape == shape45);
50 assert(x.front == iota([4, 5]));
51 x.popFront;
52 assert(x.front == iota([4, 5], (4 * 5)));
53 
54 //  ----------------
55 // |  0  1  2  3  4 |
56 // | 20 21 22 23 24 |
57 // | 40 41 42 43 44 |
58 //  - - - - - - - -
59 // |  5  6  7  8  9 |
60 // | 25 26 27 28 29 |
61 // | 45 46 47 48 49 |
62 //  - - - - - - - -
63 // | 10 11 12 13 14 |
64 // | 30 31 32 33 34 |
65 // | 50 51 52 53 54 |
66 //  - - - - - - - -
67 // | 15 16 17 18 19 |
68 // | 35 36 37 38 39 |
69 // | 55 56 57 58 59 |
70 //  ----------------
71 auto y = slice.byDim!1;
72 static assert(is(typeof(y) == Slice!(SliceIterator!(IotaIterator!sizediff_t, 2, Canonical), 1, Universal)));
73 
74 assert(y.shape == shape4);
75 assert(y.front.shape == shape35);
76 int err;
77 assert(y.front == slice.universal.strided!1(4).reshape([3, -1], err));
78 y.popFront;
79 assert(y.front.front == iota([5], 5));
80 
81 //  -------------
82 // |  0  5 10 15 |
83 // | 20 25 30 35 |
84 // | 40 45 50 55 |
85 //  - - - - - - -
86 // |  1  6 11 16 |
87 // | 21 26 31 36 |
88 // | 41 46 51 56 |
89 //  - - - - - - -
90 // |  2  7 12 17 |
91 // | 22 27 32 37 |
92 // | 42 47 52 57 |
93 //  - - - - - - -
94 // |  3  8 13 18 |
95 // | 23 28 33 38 |
96 // | 43 48 53 58 |
97 //  - - - - - - -
98 // |  4  9 14 19 |
99 // | 24 29 34 39 |
100 // | 44 49 54 59 |
101 //  -------------
102 auto z = slice.byDim!2;
103 static assert(is(typeof(z) == Slice!(SliceIterator!(IotaIterator!sizediff_t, 2, Universal))));
104 
105 assert(z.shape == shape5);
106 assert(z.front.shape == shape34);
107 assert(z.front == iota([3, 4], 0, 5));
108 z.popFront;
109 assert(z.front.front == iota([4], 1, 5));
110 
111 //  ----------
112 // |  0 20 40 |
113 // |  5 25 45 |
114 // | 10 30 50 |
115 // | 15 35 55 |
116 //  - - - - -
117 // |  1 21 41 |
118 // |  6 26 46 |
119 // | 11 31 51 |
120 // | 16 36 56 |
121 //  - - - - -
122 // |  2 22 42 |
123 // |  7 27 47 |
124 // | 12 32 52 |
125 // | 17 37 57 |
126 //  - - - - -
127 // |  3 23 43 |
128 // |  8 28 48 |
129 // | 13 33 53 |
130 // | 18 38 58 |
131 //  - - - - -
132 // |  4 24 44 |
133 // |  9 29 49 |
134 // | 14 34 54 |
135 // | 19 39 59 |
136 //  ----------
137 auto a = slice.byDim!(2, 1);
138 static assert(is(typeof(a) == Slice!(SliceIterator!(IotaIterator!sizediff_t, 1, Universal), 2, Universal)));
139 
140 assert(a.shape == shape54);
141 assert(a.front.shape == shape4);
142 assert(a.front.unpack == iota([3, 4], 0, 5).universal.transposed);
143 a.popFront;
144 assert(a.front.front == iota([3], 1, 20));

Use byDim to calculate column mean/row mean of 2-dimensional slice

import mir.ndslice.topology: byDim;
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 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]));

// FIXME
// Without using map, computes the mean of the whole slice
// assert(x.byDim!0.mean == x.sliced.mean);
// assert(x.byDim!1.mean == x.sliced.mean);

Use byDim and map with a lambda, 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, 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]]);

See Also

Meta