Report a bug
If you spot a problem with this page, click here to create a Bugzilla 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.

std.experimental.ndslice.selection

This is a submodule of std.experimental.ndslice.

Selectors create new views and iteration patterns over the same data, without copying.

Subspace selectors

Subspace selectors serve to generalize and combine other selectors easily. For a slice of Slice!(N, Range) type slice.pack!K creates a slice of slices of Slice!(N-K, Slice!(K+1, Range)) type by packing the last K dimensions of the top dimension pack, and the type of element of slice.byElement is Slice!(K, Range). Another way to use pack is transposition of dimension packs using evertPack. Examples of use of subspace selectors are available for selectors, Slice.shape , and Slice.elementsCount .

Function Name Description
pack returns slice of slices
unpack merges all dimension packs
evertPack reverses dimension packs

Selectors

Function Name Description
byElement a random access range of all elements with index property
byElementInStandardSimplex an input range of all elements in standard simplex of hypercube with index property. If the slice has two dimensions, it is a range of all elements of upper left triangular matrix.
indexSlice returns a slice with elements equal to the initial index
reshape returns a new slice for the same data
diagonal 1-dimensional slice composed of diagonal elements
blocks n-dimensional slice composed of n-dimensional non-overlapping blocks. If the slice has two dimensions, it is a block matrix.
windows n-dimensional slice of n-dimensional overlapping windows. If the slice has two dimensions, it is a sliding window.
Authors:
Ilya Yaroshenko
template pack(K...)
Creates a packed slice, i.e. slice of slices. The function does not carry out any calculations, it simply returns the same binary data presented differently.
Parameters:
K sizes of dimension packs
Returns:
pack!K returns Slice!(N-K, Slice!(K+1, Range)); slice.pack!(K1, K2, ..., Kn) is the same as slice.pacKed!K1.pacKed!K2. ... pacKed!Kn.
Examples:
import std.experimental.ndslice.slice;
import std.range.primitives: ElementType;
import std.range: iota;
import std.algorithm.comparison: equal;
auto r = (3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11).iota;
auto a = r.sliced(3, 4, 5, 6, 7, 8, 9, 10, 11);
auto b = a.pack!(2, 3); // same as `a.pack!2.pack!3`
auto c = b[1, 2, 3, 4];
auto d = c[5, 6, 7];
auto e = d[8, 9];
auto g = a[1, 2, 3, 4, 5, 6, 7, 8, 9];
assert(e == g);
assert(a == b);
assert(c == a[1, 2, 3, 4]);
alias R = typeof(r);
static assert(is(typeof(b) == typeof(a.pack!2.pack!3)));
static assert(is(typeof(b) == Slice!(4, Slice!(4, Slice!(3, R)))));
static assert(is(typeof(c) == Slice!(3, Slice!(3, R))));
static assert(is(typeof(d) == Slice!(2, R)));
static assert(is(typeof(e) == ElementType!R));
Slice!(N, Range).PureThis unpack(size_t N, Range)(auto ref Slice!(N, Range) slice);
Unpacks a packed slice.
The function does not carry out any calculations, it simply returns the same binary data presented differently.
Parameters:
Slice!(N, Range) slice packed slice
Returns:
unpacked slice
See Also:
Examples:
import std.experimental.ndslice.slice;
import std.range: iota;
import std.algorithm.comparison: equal;
auto r = (3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11).iota;
auto a = r.sliced(3, 4, 5, 6, 7, 8, 9, 10, 11);
auto b = a.pack!(2, 3).unpack();
static assert(is(typeof(a) == typeof(b)));
assert(a == b);
SliceFromSeq!(Slice!(N, Range).PureRange, NSeqEvert!(Slice!(N, Range).NSeq)) evertPack(size_t N, Range)(auto ref Slice!(N, Range) slice);
Reverses the order of dimension packs. This function is used in a functional pipeline with other selectors.
Parameters:
Slice!(N, Range) slice packed slice
Returns:
packed slice
See Also:
Examples:
import std.experimental.ndslice.slice;
import std.experimental.ndslice.iteration: transposed;
import std.range: iota;
auto slice = (3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11).iota
    .sliced(3, 4, 5, 6, 7, 8, 9, 10, 11);
assert(slice
    .pack!2
    .evertPack
    .unpack
         == slice.transposed!(
            slice.shape.length-2,
            slice.shape.length-1));
Examples:
import std.experimental.ndslice.slice;
import std.experimental.ndslice.iteration: transposed;
import std.range.primitives: ElementType;
import std.range: iota;
import std.algorithm.comparison: equal;
auto r = (3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11).iota;
auto a = r.sliced(3, 4, 5, 6, 7, 8, 9, 10, 11);
auto b = a
    .pack!(2, 3)
    .evertPack;
auto c = b[8, 9];
auto d = c[5, 6, 7];
auto e = d[1, 2, 3, 4];
auto g = a[1, 2, 3, 4, 5, 6, 7, 8, 9];
assert(e == g);
assert(a == b.evertPack);
assert(c == a.transposed!(7, 8, 4, 5, 6)[8, 9]);
alias R = typeof(r);
static assert(is(typeof(b) == Slice!(2, Slice!(4, Slice!(5, R)))));
static assert(is(typeof(c) == Slice!(3, Slice!(5, R))));
static assert(is(typeof(d) == Slice!(4, R)));
static assert(is(typeof(e) == ElementType!R));
Slice!(1, Range) diagonal(size_t N, Range)(auto ref Slice!(N, Range) slice);
Returns a 1-dimensional slice over the main diagonal of an n-dimensional slice. diagonal can be generalized with other selectors such as blocks (diagonal blocks) and windows (multi-diagonal slice).
Parameters:
N dimension count
Slice!(N, Range) slice input slice
Returns:
packed 1-dimensional composed of N-dimensional slices
Examples:
Matrix, main diagonal
import std.experimental.ndslice.slice;
import std.algorithm.comparison: equal;
import std.range: iota, only;

//  -------
// | 0 1 2 |
// | 3 4 5 |
//  -------
//->
// | 0 4 |
assert(6.iota
    .sliced(2, 3)
    .diagonal
    .equal(only(0, 4)));
Examples:
ditto
import std.experimental.ndslice.slice;

auto slice = new int[9].sliced(3, 3);
int i;
foreach (ref e; slice.diagonal)
    e = ++i;
assert(slice == [
    [1, 0, 0],
    [0, 2, 0],
    [0, 0, 3]]);
Examples:
Matrix, subdiagonal
import std.experimental.ndslice.slice;
import std.experimental.ndslice.iteration: dropOne;
import std.algorithm.comparison: equal;
import std.range: iota, only;
//  -------
// | 0 1 2 |
// | 3 4 5 |
//  -------
//->
// | 1 5 |
assert(6.iota
    .sliced(2, 3)
    .dropOne!1
    .diagonal
    .equal(only(1, 5)));
Examples:
Matrix, antidiagonal
import std.experimental.ndslice.slice;
import std.experimental.ndslice.iteration: dropToHypercube, reversed;
import std.algorithm.comparison: equal;
import std.range: iota, only;
//  -------
// | 0 1 2 |
// | 3 4 5 |
//  -------
//->
// | 1 3 |
assert(6.iota
    .sliced(2, 3)
    .dropToHypercube
    .reversed!1
    .diagonal
    .equal(only(1, 3)));
Examples:
3D, main diagonal
import std.experimental.ndslice.slice;
import std.algorithm.comparison: equal;
import std.range: iota, only;
//  -----------
// |  0   1  2 |
// |  3   4  5 |
//  - - - - - -
// |  6   7  8 |
// |  9  10 11 |
//  -----------
//->
// | 0 10 |
assert(12.iota
    .sliced(2, 2, 3)
    .diagonal
    .equal(only(0, 10)));
Examples:
3D, subdiagonal
import std.experimental.ndslice.slice;
import std.experimental.ndslice.iteration: dropOne;
import std.algorithm.comparison: equal;
import std.range: iota, only;
//  -----------
// |  0   1  2 |
// |  3   4  5 |
//  - - - - - -
// |  6   7  8 |
// |  9  10 11 |
//  -----------
//->
// | 1 11 |
assert(12.iota
    .sliced(2, 2, 3)
    .dropOne!2
    .diagonal
    .equal(only(1, 11)));
Examples:
3D, diagonal plain
import std.experimental.ndslice.slice;
import std.experimental.ndslice.iteration: dropOne;
import std.algorithm.comparison: equal;
import std.range: iota;
//  -----------
// |  0   1  2 |
// |  3   4  5 |
// |  6   7  8 |
//  - - - - - -
// |  9  10 11 |
// | 12  13 14 |
// | 15  16 17 |
//  - - - - - -
// | 18  20 21 |
// | 22  23 24 |
// | 24  25 26 |
//  -----------
//->
//  -----------
// |  0   4  8 |
// |  9  13 17 |
// | 18  23 26 |
//  -----------
auto slice = 27.iota
    .sliced(3, 3, 3)
    .pack!2
    .evertPack
    .diagonal
    .evertPack;
assert(slice ==
    [[ 0,  4,  8],
     [ 9, 13, 17],
     [18, 22, 26]]);
Slice!(N, Slice!(N + 1, Range)) blocks(size_t N, Range, Lengths...)(auto ref Slice!(N, Range) slice, Lengths lengths)
if (allSatisfy!(isIndex, Lengths) && Lengths.length == N);
Returns an n-dimensional slice of n-dimensional non-overlapping blocks. blocks can be generalized with other selectors. For example, blocks in combination with diagonal can be used to get a slice of diagonal blocks.
Parameters:
N dimension count
Slice!(N, Range) slice slice to be split into blocks
Lengths lengths dimensions of block, residual blocks are ignored
Returns:
packed N-dimensional slice composed of N-dimensional slices
Examples:
import std.experimental.ndslice.slice;
auto slice = new int[40].sliced(5, 8);
auto blocks = slice.blocks(2, 3);
int i;
foreach (block; blocks.byElement)
    block[] = ++i;

assert(blocks ==
    [[[[1, 1, 1], [1, 1, 1]],
      [[2, 2, 2], [2, 2, 2]]],
     [[[3, 3, 3], [3, 3, 3]],
      [[4, 4, 4], [4, 4, 4]]]]);

assert(    slice ==
    [[1, 1, 1,  2, 2, 2,  0, 0],
     [1, 1, 1,  2, 2, 2,  0, 0],

     [3, 3, 3,  4, 4, 4,  0, 0],
     [3, 3, 3,  4, 4, 4,  0, 0],

     [0, 0, 0,  0, 0, 0,  0, 0]]);
Examples:
Diagonal blocks
import std.experimental.ndslice.slice;
auto slice = new int[40].sliced(5, 8);
auto blocks = slice.blocks(2, 3);
auto diagonalBlocks = blocks.diagonal.unpack;

diagonalBlocks[0][] = 1;
diagonalBlocks[1][] = 2;

assert(diagonalBlocks ==
    [[[1, 1, 1], [1, 1, 1]],
     [[2, 2, 2], [2, 2, 2]]]);

assert(blocks ==
    [[[[1, 1, 1], [1, 1, 1]],
      [[0, 0, 0], [0, 0, 0]]],
     [[[0, 0, 0], [0, 0, 0]],
      [[2, 2, 2], [2, 2, 2]]]]);

assert(slice ==
    [[1, 1, 1,  0, 0, 0,  0, 0],
     [1, 1, 1,  0, 0, 0,  0, 0],

     [0, 0, 0,  2, 2, 2,  0, 0],
     [0, 0, 0,  2, 2, 2,  0, 0],

     [0, 0, 0, 0, 0, 0, 0, 0]]);
Examples:
Matrix divided into vertical blocks
import std.experimental.ndslice.slice;
auto slice = new int[65].sliced(5, 13);
auto blocks = slice
    .pack!1
    .evertPack
    .blocks(3)
    .unpack
    .pack!2;

int i;
foreach (block; blocks.byElement)
    block[] = ++i;

assert(slice ==
    [[1, 1, 1,  2, 2, 2,  3, 3, 3,  4, 4, 4,  0],
     [1, 1, 1,  2, 2, 2,  3, 3, 3,  4, 4, 4,  0],
     [1, 1, 1,  2, 2, 2,  3, 3, 3,  4, 4, 4,  0],
     [1, 1, 1,  2, 2, 2,  3, 3, 3,  4, 4, 4,  0],
     [1, 1, 1,  2, 2, 2,  3, 3, 3,  4, 4, 4,  0]]);
Slice!(N, Slice!(N + 1, Range)) windows(size_t N, Range, Lengths...)(auto ref Slice!(N, Range) slice, Lengths lengths)
if (allSatisfy!(isIndex, Lengths) && Lengths.length == N);
Returns an n-dimensional slice of n-dimensional overlapping windows. windows can be generalized with other selectors. For example, windows in combination with diagonal can be used to get a multi-diagonal slice.
Parameters:
N dimension count
Slice!(N, Range) slice slice to be iterated
Lengths lengths dimensions of windows
Returns:
packed N-dimensional slice composed of N-dimensional slices
Examples:
import std.experimental.ndslice.slice;
auto slice = new int[40].sliced(5, 8);
auto windows = slice.windows(2, 3);
foreach (window; windows.byElement)
    window[] += 1;

assert(slice ==
    [[1,  2,  3, 3, 3, 3,  2,  1],

     [2,  4,  6, 6, 6, 6,  4,  2],
     [2,  4,  6, 6, 6, 6,  4,  2],
     [2,  4,  6, 6, 6, 6,  4,  2],

     [1,  2,  3, 3, 3, 3,  2,  1]]);
Examples:
import std.experimental.ndslice.slice;
auto slice = new int[40].sliced(5, 8);
auto windows = slice.windows(2, 3);
windows[1, 2][] = 1;
windows[1, 2][0, 1] += 1;
windows.unpack[1, 2, 0, 1] += 1;

assert(slice ==
    [[0, 0,  0, 0, 0,  0, 0, 0],

     [0, 0,  1, 3, 1,  0, 0, 0],
     [0, 0,  1, 1, 1,  0, 0, 0],

     [0, 0,  0, 0, 0,  0, 0, 0],
     [0, 0,  0, 0, 0,  0, 0, 0]]);
Examples:
Multi-diagonal matrix
import std.experimental.ndslice.slice;
auto slice = new int[64].sliced(8, 8);
auto windows = slice.windows(3, 3);

auto multidiagonal = windows
    .diagonal
    .unpack;
foreach (window; multidiagonal)
    window[] += 1;

assert(slice ==
    [[ 1, 1, 1,  0, 0, 0, 0, 0],
     [ 1, 2, 2, 1,  0, 0, 0, 0],
     [ 1, 2, 3, 2, 1,  0, 0, 0],
     [0,  1, 2, 3, 2, 1,  0, 0],
     [0, 0,  1, 2, 3, 2, 1,  0],
     [0, 0, 0,  1, 2, 3, 2, 1],
     [0, 0, 0, 0,  1, 2, 2, 1],
     [0, 0, 0, 0, 0,  1, 1, 1]]);
Examples:
Sliding window over matrix columns
import std.experimental.ndslice.slice;
auto slice = new int[40].sliced(5, 8);
auto windows = slice
    .pack!1
    .evertPack
    .windows(3)
    .unpack
    .pack!2;


foreach (window; windows.byElement)
    window[] += 1;

assert(slice ==
    [[1,  2,  3, 3, 3, 3,  2,  1],
     [1,  2,  3, 3, 3, 3,  2,  1],
     [1,  2,  3, 3, 3, 3,  2,  1],
     [1,  2,  3, 3, 3, 3,  2,  1],
     [1,  2,  3, 3, 3, 3,  2,  1]]);
Slice!(Lengths.length, Range) reshape(size_t N, Range, Lengths...)(auto ref Slice!(N, Range) slice, Lengths lengths)
if (allSatisfy!(isIndex, Lengths) && Lengths.length);
Returns a new slice for the same data.
Parameters:
Slice!(N, Range) slice slice to be reshaped
Lengths lengths list of new dimensions. One of the lengths can be set to -1. In this case, the corresponding dimension is inferable.
Returns:
reshaped slice
Throws:
ReshapeException if the slice cannot be reshaped with the input lengths.
Examples:
import std.experimental.ndslice.slice;
import std.range: iota;
import std.experimental.ndslice.iteration: allReversed;
auto slice = 12.iota
    .sliced(3, 4)
    .allReversed
    .reshape(-1, 3);
assert(slice ==
    [[11, 10, 9],
     [ 8,  7, 6],
     [ 5,  4, 3],
     [ 2,  1, 0]]);
Examples:
Reshaping with memory allocation
import std.experimental.ndslice.slice;
import std.experimental.ndslice.iteration: reversed;
import std.array: array;

auto reshape2(S, L...)(S slice, L lengths)
{
    // Tries to reshape without allocation
    try return slice.reshape(lengths);
    catch(ReshapeException e)
        //allocates the elements and creates a slice
        //Note: -1 length is not supported by reshape2
        return slice.byElement.array.sliced(lengths);
}

auto slice =
    [0, 1,  2,  3,
     4, 5,  6,  7,
     8, 9, 10, 11]
    .sliced(3, 4)
    .reversed!0;

assert(reshape2(slice, 4, 3) ==
    [[ 8, 9, 10],
     [11, 4,  5],
     [ 6, 7,  0],
     [ 1, 2,  3]]);
class ReshapeException: object.Exception;
See Also:
size_t[] lengths;
Old lengths
sizediff_t[] strides;
Old strides
size_t[] newLengths;
New lengths
pure nothrow @nogc @safe this(size_t[] lengths, sizediff_t[] strides, size_t[] newLengths, string msg, string file = __FILE__, uint line = cast(uint)883, Throwable next = null);

auto byElement(size_t N, Range)(auto ref Slice!(N, Range) slice);
Returns a random access range of all elements of a slice. The order of elements is preserved. byElement can be generalized with other selectors.
Parameters:
N dimension count
Slice!(N, Range) slice slice to be iterated
Returns:
random access range composed of elements of the slice
Examples:
Regular slice
import std.experimental.ndslice.slice;
import std.algorithm.comparison: equal;
import std.range: iota;
assert(20.iota
    .sliced(4, 5)
    .byElement
    .equal(20.iota));
Examples:
Packed slice
import std.experimental.ndslice.slice;
import std.experimental.ndslice.iteration;
import std.range: iota, drop;
import std.algorithm.comparison: equal;
assert((3 * 4 * 5 * 6 * 7).iota
    .sliced(3, 4, 5, 6, 7)
    .pack!2
    .byElement()
    .drop(1)
    .front
    .byElement
    .equal(iota(6 * 7, 6 * 7 * 2)));
Examples:
Properties
import std.experimental.ndslice.slice;
import std.range: iota;
auto elems = 12.iota.sliced(3, 4).byElement;
elems.popFrontExactly(2);
assert(elems.front == 2);
assert(elems.index == [0, 2]);
elems.popBackExactly(2);
assert(elems.back == 9);
assert(elems.length == 8);
Examples:
Index property
import std.experimental.ndslice.slice;
auto slice = new long[20].sliced(5, 4);

for(auto elems = slice.byElement; !elems.empty; elems.popFront)
{
    size_t[2] index = elems.index;
    elems.front = index[0] * 10 + index[1] * 3;
}
assert(slice ==
    [[ 0,  3,  6,  9],
     [10, 13, 16, 19],
     [20, 23, 26, 29],
     [30, 33, 36, 39],
     [40, 43, 46, 49]]);
Examples:
Random access and slicing
import std.experimental.ndslice.slice;
import std.algorithm.comparison: equal;
import std.array: array;
import std.range: iota, repeat;
static data = 20.iota.array;
auto elems = data.sliced(4, 5).byElement;

elems = elems[11 .. $ - 2];

assert(elems.length == 7);
assert(elems.front == 11);
assert(elems.back == 17);

foreach (i; 0 .. 7)
    assert(elems[i] == i + 11);

// assign an element
elems[2 .. 6] = -1;
assert(elems[2 .. 6].equal(repeat(-1, 4)));

// assign an array
static ar = [-1, -2, -3, -4];
elems[2 .. 6] = ar;
assert(elems[2 .. 6].equal(ar));

// assign a slice
ar[] *= 2;
auto sl = ar.sliced(ar.length);
elems[2 .. 6] = sl;
assert(elems[2 .. 6].equal(sl));
Examples:
Forward access works faster than random access or backward access. Use allReversed  in pipeline before byElement to achieve fast backward access.
import std.range: retro, iota;
import std.experimental.ndslice.iteration: allReversed;

auto slice = 60.iota.sliced(3, 4, 5);

/// Slow backward iteration #1
foreach (ref e; slice.byElement.retro)
{
    //...
}

/// Slow backward iteration #2
foreach_reverse (ref e; slice.byElement)
{
    //...
}

/// Fast backward iteration
foreach (ref e; slice.allReversed.byElement)
{
    //...
}
auto byElementInStandardSimplex(size_t N, Range)(auto ref Slice!(N, Range) slice, size_t maxCobeLength = size_t.max);
Returns an forward range of all elements of standard simplex of a slice. In case the slice has two dimensions, it is composed of elements of upper left triangular matrix. The order of elements is preserved. byElementInStandardSimplex can be generalized with other selectors.
Parameters:
N dimension count
Slice!(N, Range) slice slice to be iterated
Returns:
forward range composed of all elements of standard simplex of the slice
Examples:
import std.experimental.ndslice.slice;
auto slice = new int[20].sliced(4, 5);
auto elems = slice
    .byElementInStandardSimplex;
int i;
foreach (ref e; elems)
    e = ++i;
assert(slice ==
    [[ 1, 2, 3, 4, 0],
     [ 5, 6, 7, 0, 0],
     [ 8, 9, 0, 0, 0],
     [10, 0, 0, 0, 0]]);
Examples:
import std.experimental.ndslice.slice;
import std.experimental.ndslice.iteration;
auto slice = new int[20].sliced(4, 5);
auto elems = slice
    .transposed
    .allReversed
    .byElementInStandardSimplex;
int i;
foreach (ref e; elems)
    e = ++i;
assert(slice ==
    [[0,  0, 0, 0, 4],
     [0,  0, 0, 7, 3],
     [0,  0, 9, 6, 2],
     [0, 10, 8, 5, 1]]);
Examples:
Properties
import std.experimental.ndslice.slice;
import std.range: iota;
auto elems = 12.iota.sliced(3, 4).byElementInStandardSimplex;
elems.popFront;
assert(elems.front == 1);
assert(elems.index == cast(size_t[2])[0, 1]);
import std.range: popFrontN;
elems.popFrontN(3);
assert(elems.front == 5);
assert(elems.index == cast(size_t[2])[1, 1]);
assert(elems.length == 2);
IndexSlice!(Lengths.length) indexSlice(Lengths...)(Lengths lengths)
if (allSatisfy!(isIndex, Lengths));

IndexSlice!N indexSlice(size_t N)(auto ref size_t[N] lengths);
Returns a slice, the elements of which are equal to the initial index value.
Parameters:
N dimension count
Lengths lengths list of dimension lengths
Returns:
N-dimensional slice composed of indexes
See Also:
Examples:
auto im = indexSlice(7, 9);

assert(im[2, 1] == cast(size_t[2])[2, 1]);

for (auto elems = im.byElement; !elems.empty; elems.popFront)
    assert(elems.front == elems.index);

//slicing works correctly
auto cm = im[1 .. $ - 3, 4 .. $ - 1];
assert(cm[2, 1] == cast(size_t[2])[3, 5]);
template IndexSlice(size_t N) if (N)
Slice composed of indexes.
See Also:
Examples:
alias IS4 = IndexSlice!4;
static assert(is(IS4 == Slice!(4, Range), Range));