ndslice Cookbook — Common Recipes for D Multidimensional Arrays
A practical, task-oriented cookbook for mir-algorithm's ndslice — create, reshape, slice, map, reduce, and fuse multidimensional arrays in D. Every example is compiled against current Mir source.
A task-oriented reference for mir.ndslice — "how do I do X" rather than "what is X". If you know NumPy, see also ndslice vs NumPy. For the full per-symbol API, browse mir-algorithm.libmir.org.
Every code block below is compiled against the current
mir-algorithm/mir-coresource. The core insight of ndslice: views are lazy and allocation-free —transposed,map,reversed,diagonalbuild a new view over the same memory; nothing is copied until you materialise it.
Create a slice
import mir.ndslice;
auto a = iota(3, 4); // 3×4, values 0,1,…,11 (lazy)
auto b = slice!double(3, 4); // allocated, zero-filled
auto c = [1.0, 2, 3, 4, 5, 6].sliced(2, 3); // from a 1-D arrayiota(shape...)— a lazy index grid; great for examples and broadcasting.slice!T(shape...)— the allocating constructor; use it when you need owned, mutable storage.array.sliced(shape...)— wrap existing memory as an n-D view (no copy).
Reshape and reorder (lazy views)
import mir.ndslice;
int err;
auto t = iota(3, 4).transposed; // 4×3 view, no copy
auto r = iota(12).reshape([3, 4], err); // 1-D → 3×4 (err set if incompatible)
auto v = iota(3, 4).reversed!0; // reverse along dimension 0reshape is the one that can fail (when the element count doesn't divide), so it reports through an err out-parameter instead of throwing — convenient in @nogc / BetterC code.
Index and slice
import mir.ndslice;
auto m = iota(5, 5);
auto sub = m[1 .. 3, 2 .. 4]; // rows 1–2, cols 2–3 — a 2×2 view
auto one = m[2, 3]; // single elementMultidimensional indexing uses one set of brackets with comma-separated dimensions — m[1 .. 3, 2 .. 4], not m[1 .. 3][2 .. 4].
Map element-wise
import mir.ndslice;
auto doubled = iota(3, 4).map!(x => x * 2.0); // lazy, element-wisemap returns a view — the lambda runs lazily as elements are read. Chain freely; see fusion below.
Reduce
import mir.ndslice;
import mir.math.sum: sum;
auto total = iota(3, 4).as!double.sum; // sum of all elementsmir.math.sum provides numerically-careful summation (including Kahan/pairwise modes). as!double is a lazy element cast.
Reduce along a dimension
import mir.ndslice;
import mir.math.sum: sum;
auto rowSums = iota(3, 4).byDim!0.map!(row => row.sum); // one sum per rowbyDim!0 iterates the matrix as a range of rows (dimension 0); byDim!1 gives columns. Combine with map for axis-wise reductions — the NumPy axis= pattern.
Diagonal
import mir.ndslice;
auto d = iota(4, 4).diagonal; // 1-D view of the main diagonalFuse a lazy pipeline
import mir.ndslice;
// transpose → add 1 → take the diagonal. Still a single fused view:
// no intermediate matrix is ever allocated.
auto pipeline = iota(3, 4).transposed.map!(x => x + 1).diagonal;This is ndslice's signature strength: an entire chain of transformations compiles down to one fused traversal. To materialise the result into owned memory, end the chain with .slice (allocates) or .fuse (allocates a contiguous copy).
Where to go next
- ndslice vs NumPy — side-by-side translation table
- mir.ndslice.topology — the full catalogue of view selectors
- mir.ndslice.slice — the
Slicetype and its kinds - mir-blas / mir-lapack — linear algebra on top of ndslice
ndslice vs NumPy — Side-by-Side
A practical comparison of D's mir ndslice and Python's NumPy. Every common NumPy pattern mapped to its ndslice equivalent, with notes on performance and differences.
Random Numbers & Distributions in D — mir-random Guide
Generate reproducible random numbers and sample from statistical distributions (uniform, normal, exponential, gamma) in D with mir-random. Compiled against current Mir source.