The OpenD Programming Language

alongDim

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

Combines byDim and evertPack.

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

Members

Functions

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

Parameters

SDimensions

dimensions to iterate along, length of d, 1 <= d < n. Negative dimensions are supported.

Return Value

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

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

import mir.ndslice.topology: 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 alongDim with map to compute mean of row/column.
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]));

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

Use alongDim 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, 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).alongDim!1.map!(a => a * x).fuse;
assert(s1 == [[ 0, 2,  6],
              [ 3, 8, 15]]);
auto s2 = iota(2, 3).alongDim!0.map!(a => a * y).fuse!1;
assert(s2 == [[ 0, 1,  2],
              [ 6, 8, 10]]);

See Also

Meta