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

mir.ndslice.concatenation

This is a submodule of mir.ndslice.
The module contains .concatenation routine. It construct Concatenation structure that can be assigned to an ndslice of the same shape with [] = or [] op= .
slicedNdField  can be used to construct ndslice view on top of Concatenation.
slice  has special overload for Concatenation that can be used to allocate new ndslice.

Concatenation constructors

Function Name Description
.concatenation Creates a Concatenation view of multiple slices.
pad Pads with a constant value.
padEdge Pads with the edge values of slice.
padSymmetric Pads with the reflection of the slice mirrored along the edge of the slice.
padWrap Pads with the wrap of the slice along the axis. The first values are used to pad the end and the end values are used to pad the beginning.
Authors:
Ilya Yaroshenko
Concatenation!(dim, Slices) concatenation(size_t dim = 0, Slices...)(Slices slices);
Creates a Concatenation view of multiple slices.
Can be used in combination with itself, until, allocation , and Slice  assignment. until pred returns true.
Returns:
true if an element was
Parameters:
Slices slices tuple of slices and concatenations. All slices and concatenations must have the same dimension count.
Returns:
Examples:
Multidimensional
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

// 0, 1, 2
// 3, 4, 5
auto a = iota(2, 3);
// 0, 1
// 2, 3
auto b = iota(2, 2);
// 0, 1, 2, 3, 4
auto c = iota(1, 5);

// 0, 1, 2,   0, 1
// 3, 4, 5,   2, 3
// 
// 0, 1, 2, 3, 4
// construction phase
auto s = concatenation(concatenation!1(a, b), c);

// allocation phase
auto d = s.slice;
assert(d == [
    [0, 1, 2, 0, 1],
    [3, 4, 5, 2, 3],
    [0, 1, 2, 3, 4],
    ]);

// optimal fragmentation for output/writing/buffering
auto testData = [
    [0, 1, 2], [0, 1],
    [3, 4, 5], [2, 3],
    [0, 1, 2, 3, 4],
];
size_t i;
s.forEachFragment!((fragment) {
    pragma(inline, false); //reduces template bloat
    assert(fragment == testData[i++]);
    });
assert(i == testData.length);

// lazy ndslice view
assert(s.slicedNdField == d);
Examples:
1D
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

size_t i;
auto a = 3.iota;
auto b = iota([6], a.length);
auto s = concatenation(a, b);
assert(s.length == a.length + b.length);
// fast iteration with until
s.until!((elem){ assert(elem == i++); return false; });
// allocation with slice
assert(s.slice == s.length.iota);
// 1D or multidimensional assignment
auto d = slice!double(s.length);
d[] = s;
assert(d == s.length.iota);
d[] += s;
assert(d == iota([s.length], 0, 2));

// lazy ndslice view
assert(s.slicedNdField == s.length.iota);
enum bool isConcatenation(T);
enum size_t concatenationDimension(T : Concatenation!(dim, Slices), size_t dim, Slices...);
struct Concatenation(size_t dim, Slices...) if (Slices.length > 1);
Slices _slices;
Slices and sub-concatenations
const @property size_t length(size_t d = 0)();
Length primitive
const @property size_t elementsCount()();
Total elements count in the concatenation.
const @property size_t[N] shape()();
Shape of the concatenation.
const @property bool empty(size_t d = 0)();

void popFront(size_t d = 0)();

auto front(size_t d = 0)();
Multidimensional input range primitives
auto opIndex()(size_t[N] indexes...);
Simplest multidimensional random access primitive
auto applyFront(size_t d = 0, alias fun, size_t dim, Slices...)(Concatenation!(dim, Slices) st);
Performs fun(st.front!d).
This functions is useful when st.front!d has not a common type and fails to compile.
Can be used instead of .Concatenation.front
auto pad(string direction = "both", S, T, size_t N)(S s, T value, size_t[N] lengths...)
if (hasShape!S && N == (typeof(S.shape)).length);
Pads with a constant value.
Parameters:
direction padding direction. Direction can be one of the following values: "both", "pre", and "post".
S s Slice  or ndField
T value initial value for padding
size_t[N] lengths list of lengths
Returns:
See Also:
.concatenation examples.
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([3], 1)
    .pad(0, [2])
    .slice;

assert(pad == [0, 0,  1, 2, 3,  0, 0]);
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 2], 1)
    .pad(0, [2, 1])
    .slice;

assert(pad == [
    [0,  0, 0,  0],
    [0,  0, 0,  0],

    [0,  1, 2,  0],
    [0,  3, 4,  0],
    
    [0,  0, 0,  0],
    [0,  0, 0,  0]]);
template pad(size_t[] dimensions, string[] directions) if (dimensions.length && dimensions.length == directions.length)
Pads with a constant value.
Parameters:
dimensions dimensions to pad.
directions padding directions. Direction can be one of the following values: "both", "pre", and "post".
Returns:
See Also:
.concatenation examples.
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 2], 1)
    .pad!([1], ["pre"])(0, [2])
    .slice;

assert(pad == [
    [0, 0,  1, 2],
    [0, 0,  3, 4]]);
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 2], 1)
    .pad!([0, 1], ["both", "post"])(0, [2, 1])
    .slice;

assert(pad == [
    [0, 0,  0],
    [0, 0,  0],

    [1, 2,  0],
    [3, 4,  0],
    
    [0, 0,  0],
    [0, 0,  0]]);
auto pad(S, T)(S s, T value, size_t[dimensions.length] lengths...);
Parameters:
S s Slice  or ndField
T value initial value for padding
size_t[dimensions.length] lengths list of lengths
Returns:
See Also:
.concatenation examples.
auto padWrap(string direction = "both", SliceKind kind, size_t[] packs, Iterator, size_t N)(Slice!(kind, packs, Iterator) s, size_t[N] lengths...)
if (N == packs[0]);
Pads with the wrap of the slice along the axis. The first values are used to pad the end and the end values are used to pad the beginning.
Parameters:
direction padding direction. Direction can be one of the following values: "both", "pre", and "post".
Slice!(kind, packs, Iterator) s Slice 
size_t[N] lengths list of lengths for each dimension. Each length must be less or equal to the corresponding slice length.
Returns:
See Also:
.concatenation examples.
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([3], 1)
    .padWrap([2])
    .slice;

assert(pad == [2, 3,  1, 2, 3,  1, 2]);
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 2], 1)
    .padWrap([2, 1])
    .slice;

assert(pad == [
    [2,  1, 2,  1],
    [4,  3, 4,  3],

    [2,  1, 2,  1],
    [4,  3, 4,  3],

    [2,  1, 2,  1],
    [4,  3, 4,  3]]);
template padWrap(size_t[] dimensions, string[] directions) if (dimensions.length && dimensions.length == directions.length)
Pads with the wrap of the slice along the axis. The first values are used to pad the end and the end values are used to pad the beginning.
Parameters:
dimensions dimensions to pad.
directions padding directions. Direction can be one of the following values: "both", "pre", and "post".
Returns:
See Also:
.concatenation examples.
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 3], 1)
    .padWrap!([1], ["pre"])([1])
    .slice;

assert(pad == [
    [3,  1, 2, 3],
    [6,  4, 5, 6]]);
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 2], 1)
    .padWrap!([0, 1], ["both", "post"])([2, 1])
    .slice;

assert(pad == [
    [1, 2,  1],
    [3, 4,  3],

    [1, 2,  1],
    [3, 4,  3],
    
    [1, 2,  1],
    [3, 4,  3]]);
auto padWrap(SliceKind kind, size_t[] packs, Iterator)(Slice!(kind, packs, Iterator) s, size_t[dimensions.length] lengths...);
Parameters:
Slice!(kind, packs, Iterator) s Slice 
size_t[dimensions.length] lengths list of lengths for each dimension. Each length must be less or equal to the corresponding slice length.
Returns:
See Also:
.concatenation examples.
auto padSymmetric(string direction = "both", SliceKind kind, size_t[] packs, Iterator, size_t N)(Slice!(kind, packs, Iterator) s, size_t[N] lengths...)
if (N == packs[0]);
Pads with the reflection of the slice mirrored along the edge of the slice.
Parameters:
direction padding direction. Direction can be one of the following values: "both", "pre", and "post".
Slice!(kind, packs, Iterator) s Slice 
size_t[N] lengths list of lengths for each dimension. Each length must be less or equal to the corresponding slice length.
Returns:
See Also:
.concatenation examples.
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([3], 1)
    .padSymmetric([2])
    .slice;

assert(pad == [2, 1,  1, 2, 3,  3, 2]);
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 2], 1)
    .padSymmetric([2, 1])
    .slice;

assert(pad == [
    [3,  3, 4,  4],
    [1,  1, 2,  2],

    [1,  1, 2,  2],
    [3,  3, 4,  4],

    [3,  3, 4,  4],
    [1,  1, 2,  2]]);
template padSymmetric(size_t[] dimensions, string[] directions) if (dimensions.length && dimensions.length == directions.length)
Pads with the reflection of the slice mirrored along the edge of the slice.
Parameters:
dimensions dimensions to pad.
directions padding directions. Direction can be one of the following values: "both", "pre", and "post".
Returns:
See Also:
.concatenation examples.
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 3], 1)
    .padSymmetric!([1], ["pre"])([2])
    .slice;

assert(pad == [
    [2, 1,  1, 2, 3],
    [5, 4,  4, 5, 6]]);
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 2], 1)
    .padSymmetric!([0, 1], ["both", "post"])([2, 1])
    .slice;

assert(pad == [
    [3, 4,  4],
    [1, 2,  2],

    [1, 2,  2],
    [3, 4,  4],
    
    [3, 4,  4],
    [1, 2,  2]]);
auto padSymmetric(SliceKind kind, size_t[] packs, Iterator)(Slice!(kind, packs, Iterator) s, size_t[dimensions.length] lengths...)
if (packs.length == 1);
Parameters:
Slice!(kind, packs, Iterator) s Slice 
size_t[dimensions.length] lengths list of lengths for each dimension. Each length must be less or equal to the corresponding slice length.
Returns:
See Also:
.concatenation examples.
auto padEdge(string direction = "both", SliceKind kind, size_t[] packs, Iterator, size_t N)(Slice!(kind, packs, Iterator) s, size_t[N] lengths...)
if (N == packs[0]);
Pads with the edge values of slice.
Parameters:
direction padding direction. Direction can be one of the following values: "both", "pre", and "post".
Slice!(kind, packs, Iterator) s Slice 
size_t[N] lengths list of lengths for each dimension.
Returns:
See Also:
.concatenation examples.
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([3], 1)
    .padEdge([2])
    .slice;

assert(pad == [1, 1,  1, 2, 3,  3, 3]);
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 2], 1)
    .padEdge([2, 1])
    .slice;

assert(pad == [
    [1,  1, 2,  2],
    [1,  1, 2,  2],

    [1,  1, 2,  2],
    [3,  3, 4,  4],

    [3,  3, 4,  4],
    [3,  3, 4,  4]]);
template padEdge(size_t[] dimensions, string[] directions) if (dimensions.length && dimensions.length == directions.length)
Pads with the edge values of slice.
Parameters:
dimensions dimensions to pad.
directions padding directions. Direction can be one of the following values: "both", "pre", and "post".
Returns:
See Also:
.concatenation examples.
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 3], 1)
    .padEdge!([0], ["pre"])([2])
    .slice;

assert(pad == [
    [1, 2, 3],
    [1, 2, 3],
    
    [1, 2, 3],
    [4, 5, 6]]);
Examples:
import mir.ndslice.allocation: slice;
import mir.ndslice.topology: iota;

auto pad = iota([2, 2], 1)
    .padEdge!([0, 1], ["both", "post"])([2, 1])
    .slice;

assert(pad == [
    [1, 2,  2],
    [1, 2,  2],

    [1, 2,  2],
    [3, 4,  4],

    [3, 4,  4],
    [3, 4,  4]]);
auto padEdge(SliceKind kind, size_t[] packs, Iterator)(Slice!(kind, packs, Iterator) s, size_t[dimensions.length] lengths...);
Parameters:
Slice!(kind, packs, Iterator) s Slice 
size_t[dimensions.length] lengths list of lengths for each dimension.
Returns:
See Also:
.concatenation examples.
template forEachFragment(alias pred)
Iterates 1D fragments in Slice  or Concatenation in optimal for buffering way.
See Also:
.concatenation examples.
void forEachFragment(SliceKind kind, size_t[] packs, Iterator)(Slice!(kind, packs, Iterator) sl);
Specialization for slices
Parameters:
Slice!(kind, packs, Iterator) sl Slice 
void forEachFragment(size_t dim, Slices...)(Concatenation!(dim, Slices) st);
Specialization for concatenations
Parameters:
Concatenation!(dim, Slices) st Concatenation
template until(alias pred)
Iterates elements in Slice  or Concatenation until pred returns true.
Returns:
false if pred returned false for all elements and true otherwise.
See Also:
.concatenation examples.
bool until(SliceKind kind, size_t[] packs, Iterator)(Slice!(kind, packs, Iterator) sl);
Specialization for slices
Parameters:
Slice!(kind, packs, Iterator) sl Slice 
bool until(size_t dim, Slices...)(Concatenation!(dim, Slices) st);
Specialization for concatenations
Parameters:
Concatenation!(dim, Slices) st Concatenation