Skip to content

Commit e999e67

Browse files
committed
byDim, alongDim: add support for negative dimensions
1 parent c239635 commit e999e67

File tree

2 files changed

+28
-47
lines changed

2 files changed

+28
-47
lines changed

source/mir/ndslice/internal.d

+7
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,15 @@ private bool isValidPartialPermutationImpl(size_t N)(in size_t[] perm, ref int[N
300300
return true;
301301
}
302302

303+
template ShiftNegativeWith(size_t N)
304+
{
305+
enum ShiftNegativeWith(sizediff_t i) = i < 0 ? i + N : i;
306+
}
307+
303308
enum toSize_t(size_t i) = i;
309+
enum toSizediff_t(sizediff_t i) = i;
304310
enum isSize_t(alias i) = is(typeof(i) == size_t);
311+
enum isSizediff_t(alias i) = is(typeof(i) == sizediff_t);
305312
enum isIndex(I) = is(I : size_t);
306313
template is_Slice(S)
307314
{

source/mir/ndslice/topology.d

+21-47
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ T4=$(TR $(TDNW $(LREF $1)) $(TD $2) $(TD $3) $(TD $4))
109109
+/
110110
module mir.ndslice.topology;
111111

112-
import std.meta;
113112

114113
import mir.internal.utility;
115114
import mir.math.common: optmath;
@@ -121,6 +120,7 @@ import mir.ndslice.slice;
121120
import mir.primitives;
122121
import mir.qualifier;
123122
import mir.utility: min;
123+
import std.meta: AliasSeq, allSatisfy, staticMap, templateOr, Repeat;
124124

125125
private immutable choppedExceptionMsg = "bounds passed to chopped are out of sliceable bounds.";
126126
version (D_Exceptions) private immutable choppedException = new Exception(choppedExceptionMsg);
@@ -3928,7 +3928,7 @@ Returns a slice that can be iterated along dimension. Transposes other dimension
39283928
Combines $(LREF byDim) and $(LREF evertPack).
39293929
39303930
Params:
3931-
Dimensions = dimensions to iterate along, length of d, `1 <= d < n`
3931+
SDimensions = dimensions to iterate along, length of d, `1 <= d < n`. Negative dimensions are supported.
39323932
Returns:
39333933
`(n-d)`-dimensional slice composed of d-dimensional slices
39343934
See_also:
@@ -3938,15 +3938,11 @@ See_also:
39383938
$(LREF ipack),
39393939
$(SUBREF dynamic, transposed).
39403940
+/
3941-
template alongDim(Dimensions...)
3942-
if (Dimensions.length > 0)
3941+
template alongDim(SDimensions...)
3942+
if (SDimensions.length > 0)
39433943
{
3944-
import mir.ndslice.internal : isSize_t;
3945-
import std.meta : allSatisfy;
3946-
3947-
static if (allSatisfy!(isSize_t, Dimensions))
3944+
static if (allSatisfy!(isSizediff_t, SDimensions))
39483945
{
3949-
import mir.ndslice.slice : Slice, SliceKind;
39503946
/++
39513947
Params:
39523948
slice = input n-dimensional slice, n > d
@@ -3955,30 +3951,15 @@ template alongDim(Dimensions...)
39553951
+/
39563952
@optmath auto alongDim(Iterator, size_t N, SliceKind kind)
39573953
(Slice!(Iterator, N, kind) slice)
3958-
if (N > Dimensions.length)
3954+
if (N > SDimensions.length)
39593955
{
3960-
import mir.ndslice.topology : ipack;
3961-
import mir.ndslice.internal : DimensionsCountCTError;
3962-
3963-
mixin DimensionsCountCTError;
3964-
3965-
static if (N == 1)
3966-
{
3967-
return slice;
3968-
}
3969-
else
3970-
{
3971-
import core.lifetime: move;
3972-
return slice.move.byDim!Dimensions.evertPack;
3973-
}
3956+
import core.lifetime: move;
3957+
return slice.move.byDim!SDimensions.evertPack;
39743958
}
39753959
}
39763960
else
39773961
{
3978-
import std.meta : staticMap;
3979-
import mir.ndslice.internal : toSize_t;
3980-
3981-
alias alongDim = .alongDim!(staticMap!(toSize_t, Dimensions));
3962+
alias alongDim = .alongDim!(staticMap!(toSizediff_t, SDimensions));
39823963
}
39833964
}
39843965

@@ -4006,7 +3987,7 @@ version(mir_test) unittest
40063987
// | 4 5 6 7 |
40073988
// | 8 9 10 11 |
40083989
// ------------
4009-
auto x = slice.alongDim!1;
3990+
auto x = slice.alongDim!(-1); // -1 is the last dimension index, the same as 1 for this case.
40103991
static assert(is(typeof(x) == Slice!(SliceIterator!(IotaIterator!sizediff_t), 1, Universal)));
40113992

40123993
assert(x.shape == shape3);
@@ -4021,7 +4002,7 @@ version(mir_test) unittest
40214002
// | 2 6 10 |
40224003
// | 3 7 11 |
40234004
// ---------
4024-
auto y = slice.alongDim!0;
4005+
auto y = slice.alongDim!0; // alongDim!(-2) is the same for matrices.
40254006
static assert(is(typeof(y) == Slice!(SliceIterator!(IotaIterator!sizediff_t, 1, Universal))));
40264007

40274008
assert(y.shape == shape4);
@@ -4188,7 +4169,7 @@ Returns a slice that can be iterated by dimension. Transposes dimensions on top
41884169
Combines $(SUBREF dynamic, transposed), $(LREF ipack), and SliceKind Selectors.
41894170
41904171
Params:
4191-
Dimensions = dimensions to perform iteration on, length of d, `1 <= d <= n`
4172+
SDimensions = dimensions to perform iteration on, length of d, `1 <= d <= n`. Negative dimensions are supported.
41924173
Returns:
41934174
d-dimensional slice composed of `(n-d)`-dimensional slices
41944175
See_also:
@@ -4197,15 +4178,11 @@ See_also:
41974178
$(LREF ipack),
41984179
$(SUBREF dynamic, transposed).
41994180
+/
4200-
template byDim(Dimensions...)
4201-
if (Dimensions.length > 0)
4181+
template byDim(SDimensions...)
4182+
if (SDimensions.length > 0)
42024183
{
4203-
import mir.ndslice.internal : isSize_t;
4204-
import std.meta : allSatisfy;
4205-
4206-
static if (allSatisfy!(isSize_t, Dimensions))
4184+
static if (allSatisfy!(isSizediff_t, SDimensions))
42074185
{
4208-
import mir.ndslice.slice : Slice, SliceKind;
42094186
/++
42104187
Params:
42114188
slice = input n-dimensional slice, n >= d
@@ -4214,10 +4191,10 @@ template byDim(Dimensions...)
42144191
+/
42154192
@optmath auto byDim(Iterator, size_t N, SliceKind kind)
42164193
(Slice!(Iterator, N, kind) slice)
4217-
if (N >= Dimensions.length)
4194+
if (N >= SDimensions.length)
42184195
{
4219-
import mir.ndslice.topology : ipack;
4220-
import mir.ndslice.internal : DimensionsCountCTError;
4196+
4197+
alias Dimensions = staticMap!(ShiftNegativeWith!N, SDimensions);
42214198

42224199
mixin DimensionsCountCTError;
42234200

@@ -4278,10 +4255,7 @@ template byDim(Dimensions...)
42784255
}
42794256
else
42804257
{
4281-
import std.meta : staticMap;
4282-
import mir.ndslice.internal : toSize_t;
4283-
4284-
alias byDim = .byDim!(staticMap!(toSize_t, Dimensions));
4258+
alias byDim = .byDim!(staticMap!(toSizediff_t, SDimensions));
42854259
}
42864260
}
42874261

@@ -4309,7 +4283,7 @@ version(mir_test) unittest
43094283
// | 4 5 6 7 |
43104284
// | 8 9 10 11 |
43114285
// ------------
4312-
auto x = slice.byDim!0;
4286+
auto x = slice.byDim!0; // byDim!(-2) is the same for matrices.
43134287
static assert(is(typeof(x) == Slice!(SliceIterator!(IotaIterator!sizediff_t), 1, Universal)));
43144288

43154289
assert(x.shape == shape3);
@@ -4324,7 +4298,7 @@ version(mir_test) unittest
43244298
// | 2 6 10 |
43254299
// | 3 7 11 |
43264300
// ---------
4327-
auto y = slice.byDim!1;
4301+
auto y = slice.byDim!(-1); // -1 is the last dimension index, the same as 1 for this case.
43284302
static assert(is(typeof(y) == Slice!(SliceIterator!(IotaIterator!sizediff_t, 1, Universal))));
43294303

43304304
assert(y.shape == shape4);

0 commit comments

Comments
 (0)