Indexing and Slicing
Ignition implements MATLAB-compatible indexing/slicing in the VM to ensure one source of truth for semantics. The compiler recognizes patterns and emits specialized instructions that keep the VM simple and fast.
Indexing categories:
- Numeric-only scalar indices →
Index(n)/StoreIndex(n) - Mixed
:(colon),end, ranges, vectors, logical masks →IndexSlice/StoreSlice end - karithmetic on numeric positions →IndexSliceEx- Ranges using per-dimension
endarithmetic →IndexRangeEnd(N-D) andIndex1DRangeEnd(1-D) - Cell content indexing →
IndexCell/IndexCellExpand
All indexing is 1-based and column-major. Out-of-bounds and shape-mismatch conditions are normalized via mex identifiers.
Stack conventions
- For gather (read): the compiler pushes the base value first, then any numeric index values. The VM pops numeric indices (reversing their order) and then pops the base.
- For scatter (write): the compiler pushes base, then numeric indices, then the RHS value. The VM pops RHS, then numerics, then base.
Gather: Index(n)
Index(n) is used when all indices are numeric scalars (no :, end, vectors, logical). The VM:
- Pops
nnumeric indices and reverses to restore left-to-right order - Pops the base
- If base is an object → routes to
subsref(obj, '()', {indices}) - Else uses
runmat_runtime::perform_indexing(base, &indices)
Error cases:
- Non-tensor/non-object with
n > 1 - Out-of-bounds →
MATLAB:IndexOutOfBoundsorMATLAB:SubscriptOutOfBounds
Gather: IndexSlice(dims, numeric_count, colon_mask, end_mask)
Use when any dimension involves :, end, ranges/vectors, or logical masks. The VM constructs per-dimension selectors:
- Colon → full range in that dimension
- End → scalar index equal to the dimension length
- Numeric (scalar) → use as 1-based index
- Numeric (vector) → materialize list of indices (1-based)
- Logical mask → dimension length must match; non-zeros become indices
Shape rules:
- Each selector contributes either 1 (scalar) or its length
- In 2-D, shapes are normalized to match MATLAB:
(I, scalar)→[len(I), 1](scalar, J)→[1, len(J)]
- A single result value returns as a scalar
Value::NumorValue::String
Fast 2-D paths (tensors):
A(:, j)returns full column quicklyA(i, :)returns full row quicklyA(:, J)returns[rows, |J|]A(I, :)returns[|I|, cols]
String arrays mirror tensor semantics, but return Value::String for scalar results and Value::StringArray for arrays.
Errors:
- Out-of-bounds →
MATLAB:IndexOutOfBounds - Logical mask shape mismatch →
MATLAB:IndexShape - Slicing non-tensors/strings →
MATLAB:SliceNonTensor
1-D specialization
For dims == 1, the VM supports:
A(:)→ all linear elementsA(end)→ last element- Logical mask the same length as
numel(A)→ keep non-zeros - Vector of indices → gather in order
Gather with end arithmetic: IndexSliceEx
IndexSliceEx(dims, numeric_count, colon_mask, end_mask, end_offsets) applies end - k to specific numeric positions. Each (pos, k) pairs the position within the numeric indices list (not dimension index) with an offset k. The VM maps numeric positions to actual dimensions by skipping colon and plain end dims.
Gather with ranged end arithmetic: IndexRangeEnd / Index1DRangeEnd
Use when the end of a range depends on a dimension length: i:j:end-k per dimension.
IndexRangeEndparameters:dims,numeric_count,colon_mask,end_maskrange_dims: which dims are rangesrange_has_step: whether each range has a stepend_offsets:kforend-k
- Stack order: base, then for each range in increasing dimension order push
start[, step], then numeric scalar indices - The VM computes concrete indices per dim, honoring sign of the step; step 0 →
MATLAB:IndexStepZero Index1DRangeEndis a compact form for the common 1-D case
Scatter: StoreIndex / StoreSlice
StoreIndex(n) supports scalar numeric indices only. StoreSlice parallels IndexSlice with the same selector construction.
Broadcasting rules (tensors):
- RHS can be scalar → broadcast to all selected elements
- RHS can be a tensor whose per-dimension lengths are either 1 or equal to the selection extent in that dimension
- Column-/row-fast paths update entire columns or rows efficiently
String array writes:
- RHS can be a
String,StringArray, or numeric converted to string (for convenience)
Errors:
- Out-of-bounds →
MATLAB:IndexOutOfBounds - Shape mismatch for broadcasting →
MATLAB:ShapeMismatch - Non-tensor/strings →
MATLAB:SliceNonTensor
Scatter with end arithmetic: StoreSliceEx / StoreRangeEnd / StoreSlice1DRangeEnd
StoreSliceEx applies end - k to numeric positions before performing a generic scatter.
StoreRangeEnd mirrors IndexRangeEnd for writes: the VM builds per-dimension index lists (including ranged end-k) and then performs broadcasting-aware scatter into the selected positions.
StoreSlice1DRangeEnd is a compact 1-D writer: base, start[, step], rhs and an offset for end-k.
Cells: IndexCell and IndexCellExpand
IndexCell(n) supports:
- 1-D
C{i} - 2-D
C{i,j} - For objects: routes to
subsref(obj, '{}', {indices})
IndexCellExpand(n, out_count) expands contents into a comma-list in column-major order. If indices are omitted with expand_all, all cell elements expand. This is used for argument expansion at call sites and for building vectors via PackToRow/PackToCol when assigning into slices.
Errors:
- Unsupported index type →
MATLAB:CellIndexType - Out-of-bounds →
MATLAB:CellSubscriptOutOfBounds
Interactions with function calls
- A user function call used as an argument may be expanded into multiple inputs by compiling it via
CallFunctionMultiand then packed usingPackToRow/PackToCol - Cell expansion at call-sites is expressed via
Call*ExpandMultiwithArgSpecentries describing which arguments expand and how many indices are consumed
See vm.rs for full instruction handlers and INSTR_SET.md for exact stack layouts.