D Programming Language
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 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.

License:
Boost License 1.0.
Authors:
Ilya Yaroshenko

Source: std/experimental/ndslice/selection.d

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 = 100000000.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:
  pack, evertPack
  Examples:

      import std.experimental.ndslice.slice;
      import std.range: iota;
      import std.algorithm.comparison: equal;
      auto r = 100000000.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:
  pack, unpack
  Examples:

      import std.experimental.ndslice.slice;
      import std.experimental.ndslice.iteration: transposed;
      import std.range: iota;
      auto slice = 100000000.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 = 100000000.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(10.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(10.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(10.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(100.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(100.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 = 100.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[1000].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[1000].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[1000].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[1000].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[1000].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[1000].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[1000].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 = 100.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:
  reshape
  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)882, 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(100.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(100000.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.range: iota;
      auto elems = 100.iota.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);

  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 = 100.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:
  IndexSlice
  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:
  indexSlice
  Examples:

      alias IS4 = IndexSlice!4;
      static assert(is(IS4 == Slice!(4, Range), Range));

Copyright © 1999-2016 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sat Feb 27 18:58:51 2016