Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Index Math

IDXGRID and IDXTRIU compute the two flat-indexing schemes the rest of the VM relies on, so that bytecode which builds indices by hand does not have to reimplement either formula. Byte values, operand layouts and stack effects are in the Index Math section of the opcode reference. Neither instruction touches a register, and both use the same wrapping i64 arithmetic as Arithmetic; a sufficiently large IDXGRID product wraps rather than trapping, the same as MUL would.

IDXGRID: Row-Major Flat Index

IDXGRID pops C (columns), then c (column), then r (row), and pushes

$$\text{index} = r \cdot C + c$$

the same row-major convention RESIZE attaches to a model. Computing this by hand and computing it with IDXGRID produce identical results, since RESIZE does not change how flat indices are interpreted internally; IDXGRID exists so bytecode that needs the flat index as an ordinary stack value, for example to pass to SETLINE/SETQUAD without going through a grid instruction, does not have to spell out r * C + c as separate MUL and ADD instructions.

A worked example: a TSP over 4 cities and 4 positions models \(x[\text{city}][\text{position}]\) as a \(4 \times 4\) grid, so city 2 at position 1 is variable

PUSH 2        ; row = city = 2
PUSH 1        ; col = position = 1
PUSH 4        ; cols = 4
IDXGRID       ; index = 2 * 4 + 1 = 9

This program’s result, read back with STOW/OUTPUT, is 9.

IDXTRIU: Upper-Triangular Packed Index

IDXTRIU pops j, then i, and pushes

$$\text{index} = \frac{j \cdot (j - 1)}{2} + i \qquad (i < j)$$

the packed index for the pair \((i, j)\) in the strictly upper triangle of a symmetric matrix, useful for iterating over quadratic coefficient pairs without visiting \((i, j)\) and \((j, i)\) as two different positions. If i > j, IDXTRIU swaps them before computing the index, so the result is order-independent: \((i, j)\) and \((j, i)\) pack to the same value, the same guarantee SETQUAD/GETQUAD give by normalising the pair internally.

The enumeration is strictly upper-triangular, so it has no slot for a diagonal cell even though the quadratic table has one. SETQUAD and GETQUAD accept \(i = j\) and store a self-coupling; IDXTRIU called with \(i = j\) yields the index of some off-diagonal pair rather than of the diagonal one. Do not use it to address a diagonal coefficient.

IDXTRIU and IDXGRID do not range-check their operands, but every intermediate of the computation is checked, so a product or sum that leaves the i64 range raises ArithmeticOverflow even when the final index would land back inside it.

PUSH 1        ; i = 1
PUSH 3        ; j = 3
IDXTRIU       ; index = 3 * 2 / 2 + 1 = 4

This program’s result is 4.