11 · Content revision 5
Multiply rows by columns, then reuse batches
Multiply checked 2-D and batched tensors with scalar Rust loops, including inner-dimension checks, batch broadcasting, and transpose flags.
Predict one row-by-column product
Treat two rows as two token positions with three features. The activation matrix
has shape [2,3]:
[[1, 2, 3],
[4, 5, 6]]
The projection weight has shape [3,2]:
[[1, 2],
[0, 1],
[2, 0]]
Predict the result shape before multiplying any values. The shared inner
extents are both . The two outer extents survive, so the result has shape
[2,2].
Now predict cell . Select row from and column from , pair the entries at the same inner coordinate, and add from upward:
Apply the same rule to all four row-column pairs:
The output has shape [2,2] and values:
[[ 7, 4],
[16, 13]]
For the later batched prediction, left batch zero is this original , while left batch one is:
[[0, 1, 2],
[2, 1, 0]]
The right operand has shape [1,3,2] and stores the original exactly once.
Its singleton leading axis maps both output batches to right batch zero.
This is not elementwise multiplication: and do not even have the same shape. One output cell consumes a complete row and a complete column, and the shared inner axis disappears.
Contract one shared inner dimension
The chapter’s matrix formula is:
For the worked example, the general right operand is the projection weight: .
Fix one output row and column . Initialize a running sum to . For each from zero through , multiply by and add that product. The loop order is part of this reference implementation because floating-point addition is not generally associative.
For batched shapes and , the formula runs independently at every compatible leading batch coordinate. Batch coordinates are omitted from the notation so the newly introduced row-column contraction stays visible. Only the leading batch axes broadcast; the two extents must be equal.
Name every matrix index and extent
| Symbol | Operational meaning |
|---|---|
| The output value at row and column . | |
| The left input value at output row and contracted position . | |
| The right input value at contracted position and output column . | |
| The zero-based output-row index. | |
| The zero-based output-column index. | |
| The zero-based coordinate traversed along both shared inner axes. | |
| The equal inner extent and therefore the number of scalar multiplications whose products are summed into one cell. |
The output keeps rows from the effective left matrix and columns from
the effective right matrix. A transpose flag logically swaps only an operand’s
last two axes. Thus stored shape [2,3] can act as logical shape [3,2]
when transpose_right=true; no values need to be copied.
Rank-one promotion is intentionally absent. A vector must be represented with an explicit row or column axis so the output-shape rule has no hidden case.
From one fixed context vector to matrices of positions
Bengio et al.’s feed-forward neural language model looks up learned vectors for a fixed number of context words, concatenates them into one fixed-length context vector, and computes next-word scores with learned matrix-vector transforms. It shares features beyond count tables, but each prediction still uses that bounded context instead of masked self-attention across a sequence of positions.
The earlier model is Bengio et al., A Neural Probabilistic Language Model. Bengio et al. store learned word features in a matrix, concatenate the fixed context-word vectors, and compute next-word scores with successive learned matrix-vector transformations and a nonlinear hidden layer. In the paper, that calculation is , with learned word features stored in a matrix .
That model is already part of LLM history: learned word features and shared neural parameters replace separate count-table rows. The bounded contrast here is its organization around one concatenated fixed-length context vector. The paper does not specify this course’s batched tensor API, stride rules, or error types.
The later sources are Vaswani et al., Attention Is All You Need and Radford et al., Language Models are Unsupervised Multitask Learners. Vaswani et al. pack queries, keys, and values into matrices, define attention through scaled query-key products followed by softmax and value weighting, and use learned query, key, value, and output projections plus two linear transforms in each position-wise feed-forward network. The GPT-2 report uses a Transformer-based architecture for autoregressive language models and scales its four model sizes from 12 to 48 layers, model widths 768 to 1600, and a 1024-token context. In the Transformer’s notation, the attention mapping is .
Checked matrix multiplication is the reusable contraction behind learned projections, attention scores, and attention-weighted values on the road to a modern decoder. This course’s batched broadcasting, transpose flags, strided traversal, storage policy, zero-size rules, and explicit errors are local correctness decisions, not designs attributed to the papers.
The Rust contrast makes that historical step concrete without pretending to
implement any cited model. fixed_context_projection calculates one three-feature
context vector with a shape-specific loop. The general tensor path applies the
same row-column rule to multiple token rows and leading batches.
rust/demos/ch11-matrix-multiplication/src/lib.rs#fixed-width-projection /// Projects one fixed-width context representation with scalar operations.
///
/// This shape-specific baseline makes the older matrix-vector calculation
/// explicit; it is not presented as the exact equation of any cited model.
pub fn fixed_context_projection(context: [f64; 3], weights: [[f64; 2]; 3]) -> [f64; 2] {
let mut output = [0.0; 2];
for column in 0..2 {
for inner in 0..3 {
output[column] += context[inner] * weights[inner][column];
}
}
output
} Check shapes before the scalar loops
The error type keeps each rejected invariant visible. The API checks left rank, right rank, effective inner dimensions after transpose flags, batch axes from left to right, the complete output layout, and then output allocation. A request that violates several rules therefore has one stable first error.
rust/crates/llm-from-scratch/src/tensor/matmul.rs#matmul-errors /// A rejected matrix product, output layout, allocation, or converted view operation.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MatmulError {
/// An owned output layout violates the tensor storage invariant.
Tensor(TensorError),
/// A tensor-view error was converted into the matrix-multiplication error type.
View(TensorViewError),
/// Matrix multiplication does not promote a left vector in this chapter.
LeftRankTooSmall { rank: usize },
/// Matrix multiplication does not promote a right vector in this chapter.
RightRankTooSmall { rank: usize },
/// The effective final left axis and penultimate right axis differ.
InnerDimensionMismatch { left: usize, right: usize },
/// Two trailing-aligned batch dimensions are neither equal nor singleton.
IncompatibleBatch {
axis: usize,
left_dimension: usize,
right_dimension: usize,
},
/// The checked output shape is valid, but its value buffer cannot be reserved.
OutputAllocationFailed { elements: usize },
}
impl fmt::Display for MatmulError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Tensor(error) => error.fmt(formatter),
Self::View(error) => error.fmt(formatter),
Self::LeftRankTooSmall { rank } => {
write!(
formatter,
"left matmul input must have rank at least 2, got {rank}"
)
}
Self::RightRankTooSmall { rank } => {
write!(
formatter,
"right matmul input must have rank at least 2, got {rank}"
)
}
Self::InnerDimensionMismatch { left, right } => write!(
formatter,
"matmul inner dimensions do not match: left size {left}, right size {right}"
),
Self::IncompatibleBatch {
axis,
left_dimension,
right_dimension,
} => write!(
formatter,
"cannot broadcast batch axis {axis}: left size {left_dimension}, right size {right_dimension}"
),
Self::OutputAllocationFailed { elements } => write!(
formatter,
"cannot allocate output buffer for {elements} f64 values"
),
}
}
}
impl Error for MatmulError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Tensor(error) => Some(error),
Self::View(error) => Some(error),
_ => None,
}
}
}
impl From<TensorError> for MatmulError {
fn from(error: TensorError) -> Self {
Self::Tensor(error)
}
}
impl From<TensorViewError> for MatmulError {
fn from(error: TensorViewError) -> Self {
Self::View(error)
}
} Batch planning right-aligns only axes before the last two matrix axes. Missing
leading axes act as one, and a singleton input batch coordinate maps to zero.
The planner validates the complete output shape rather than the batch prefix in
isolation. That detail admits a valid empty result such as the input-shape pair
[usize::MAX,2,0,3] and [1,2,3,1]: the zero row extent makes the full output
empty before any input is read.
TensorView::get remains the public operation for a coordinate supplied by a
caller. Because that coordinate may have the wrong rank or an out-of-bounds
index, get must validate every call. Matrix multiplication starts from a
different boundary: both views are already valid, and the planner has already
checked the effective matrix dimensions, batch compatibility, and complete
output layout. The scalar loop can therefore reuse one checked offset plan
instead of reconstructing and revalidating two coordinates for every product.
For one output cell, each operand needs a starting storage offset before changes. This chapter calls that starting position the cell-base offset. The contracted-axis stride then moves from the value to the value, and so on.
For output shape [...,M,N], each operand receives one effective stride for
every output axis. A leading batch axis whose input extent is greater than one
keeps its input stride; a missing or size-one batch axis receives stride 0 so
another output batch reuses the same input batch. On the left, the output-row
axis keeps the effective row stride and the output-column axis receives 0. On
the right, the output-row axis receives 0 and the output-column axis keeps the
effective column stride. The planner separately stores the left and right
strides for advancing along the shared inner axis.
The worked matrices make this plan concrete. Contiguous has strides
[3,1], and contiguous has strides [2,1]. Across output coordinates
[0,0], [0,1], [1,0], [1,1], the left cell-base strides [3,0] produce
offsets [0,0,3,3]; the right cell-base strides [0,1] produce offsets
[0,1,0,1]. Cell therefore starts at left offset 3 and right offset
0. Advancing by the contracted-axis strides 1 and 2 yields the three
offset pairs (3,0), (4,2), and (5,4), which read , ,
and in ascending order.
For the batched shapes [2,2,3] and [1,3,2], the corresponding cell-base
strides are [6,3,0] on the left and [0,0,1] on the right. The first 0 in
the right plan is the singleton batch axis: output batches 0 and 1 both
start from right batch 0. A transpose flag swaps the roles of an operand’s
last two extents and strides; it does not move the stored values.
The two cell-base cursors are checked once and then emit offsets in batch-major, row-major, column-major order. Within each cell, the loop reads the left value, reads the right value, multiplies them, and adds to the running sum while increases. Reads still use ordinary safe bounds-checked slice indexing. No coordinate vector is allocated inside the contraction, and no implicit materialization occurs for a sliced or transposed view: that view simply supplies different base offsets and strides.
rust/crates/llm-from-scratch/src/tensor/matmul.rs#checked-matmul #[derive(Debug)]
struct MatmulPlan {
/// The owned result's logical row-major shape and element count.
output_shape: Vec<usize>,
output_len: usize,
/// The number of products accumulated into each output cell.
inner: usize,
/// One source-storage movement per output batch, row, and column axis.
left_cell_strides: Vec<usize>,
right_cell_strides: Vec<usize>,
/// Source-storage movement when the contracted index increases by one.
left_inner_stride: usize,
right_inner_stride: usize,
}
#[derive(Clone, Copy, Debug)]
struct EffectiveMatrixLayout {
rows: usize,
columns: usize,
row_stride: usize,
column_stride: usize,
}
/// Multiplies two rank-two or batched tensor views as stored.
pub fn matmul(left: &TensorView<'_>, right: &TensorView<'_>) -> Result<Tensor, MatmulError> {
matmul_with_transpose(left, right, false, false)
}
/// Multiplies two tensor views after optional logical final-axis transposes.
///
/// Inputs must have rank at least two. Only axes before the final two matrix
/// axes broadcast, using trailing alignment. The effective inner dimensions
/// must match exactly. The scalar contraction visits `k` in ascending order and
/// reads through offsets established by one checked strided plan per operand.
pub fn matmul_with_transpose(
left: &TensorView<'_>,
right: &TensorView<'_>,
transpose_left: bool,
transpose_right: bool,
) -> Result<Tensor, MatmulError> {
let plan = MatmulPlan::new(left, right, transpose_left, transpose_right)?;
let mut values = output_buffer(plan.output_len)?;
if plan.inner == 0 {
values.resize(plan.output_len, 0.0);
return Tensor::from_vec(plan.output_shape, values).map_err(Into::into);
}
let left_cell_offsets = left
.projected_offsets(&plan.output_shape, &plan.left_cell_strides, plan.output_len)
.expect("a checked matmul plan retains valid left cell offsets");
let right_cell_offsets = right
.projected_offsets(
&plan.output_shape,
&plan.right_cell_strides,
plan.output_len,
)
.expect("a checked matmul plan retains valid right cell offsets");
for (left_cell_offset, right_cell_offset) in left_cell_offsets.zip(right_cell_offsets) {
let mut sum = 0.0;
let mut left_offset = left_cell_offset;
let mut right_offset = right_cell_offset;
for inner_index in 0..plan.inner {
let left_value = left.value_at_storage_offset(left_offset);
let right_value = right.value_at_storage_offset(right_offset);
sum += left_value * right_value;
if inner_index + 1 < plan.inner {
left_offset = left_offset
.checked_add(plan.left_inner_stride)
.expect("a checked matmul plan cannot overflow along the left inner axis");
right_offset = right_offset
.checked_add(plan.right_inner_stride)
.expect("a checked matmul plan cannot overflow along the right inner axis");
}
}
values.push(sum);
}
Tensor::from_vec(plan.output_shape, values).map_err(Into::into)
}
impl MatmulPlan {
fn new(
left: &TensorView<'_>,
right: &TensorView<'_>,
transpose_left: bool,
transpose_right: bool,
) -> Result<Self, MatmulError> {
if left.rank() < 2 {
return Err(MatmulError::LeftRankTooSmall { rank: left.rank() });
}
if right.rank() < 2 {
return Err(MatmulError::RightRankTooSmall { rank: right.rank() });
}
let left_matrix = effective_matrix_layout(left, transpose_left);
let right_matrix = effective_matrix_layout(right, transpose_right);
let rows = left_matrix.rows;
let inner = left_matrix.columns;
let right_inner = right_matrix.rows;
let columns = right_matrix.columns;
if inner != right_inner {
return Err(MatmulError::InnerDimensionMismatch {
left: inner,
right: right_inner,
});
}
let left_batch_shape = &left.shape()[..left.rank() - 2];
let right_batch_shape = &right.shape()[..right.rank() - 2];
let batch_shape = broadcast_batch_shape(left_batch_shape, right_batch_shape)?;
let mut output_shape = batch_shape.clone();
output_shape.extend([rows, columns]);
let (_, output_len) = checked_row_major_layout(&output_shape)?;
let batch_rank = batch_shape.len();
let mut left_cell_strides = batch_effective_strides(left, batch_rank);
left_cell_strides.extend([left_matrix.row_stride, 0]);
let mut right_cell_strides = batch_effective_strides(right, batch_rank);
right_cell_strides.extend([0, right_matrix.column_stride]);
Ok(Self {
output_shape,
output_len,
inner,
left_cell_strides,
right_cell_strides,
left_inner_stride: left_matrix.column_stride,
right_inner_stride: right_matrix.row_stride,
})
}
}
fn effective_matrix_layout(input: &TensorView<'_>, transposed: bool) -> EffectiveMatrixLayout {
let matrix_axis = input.rank() - 2;
let stored = EffectiveMatrixLayout {
rows: input.shape()[matrix_axis],
columns: input.shape()[matrix_axis + 1],
row_stride: input.strides()[matrix_axis],
column_stride: input.strides()[matrix_axis + 1],
};
if transposed {
EffectiveMatrixLayout {
rows: stored.columns,
columns: stored.rows,
row_stride: stored.column_stride,
column_stride: stored.row_stride,
}
} else {
stored
}
}
fn broadcast_batch_shape(left: &[usize], right: &[usize]) -> Result<Vec<usize>, MatmulError> {
let output_rank = left.len().max(right.len());
let left_padding = output_rank - left.len();
let right_padding = output_rank - right.len();
let mut output = Vec::with_capacity(output_rank);
for axis in 0..output_rank {
let left_dimension = left
.get(axis.wrapping_sub(left_padding))
.copied()
.unwrap_or(1);
let right_dimension = right
.get(axis.wrapping_sub(right_padding))
.copied()
.unwrap_or(1);
let dimension = if left_dimension == right_dimension {
left_dimension
} else if left_dimension == 1 {
right_dimension
} else if right_dimension == 1 {
left_dimension
} else {
return Err(MatmulError::IncompatibleBatch {
axis,
left_dimension,
right_dimension,
});
};
output.push(dimension);
}
Ok(output)
}
fn batch_effective_strides(input: &TensorView<'_>, output_batch_rank: usize) -> Vec<usize> {
let input_batch_rank = input.rank() - 2;
let padding = output_batch_rank - input_batch_rank;
(0..output_batch_rank)
.map(|output_axis| {
if output_axis < padding {
return 0;
}
let input_axis = output_axis - padding;
if input.shape()[input_axis] == 1 {
0
} else {
input.strides()[input_axis]
}
})
.collect()
} If a batch, row, or column extent is zero, the result is empty and performs no
reads. If only , output cells still exist but neither input has a readable
inner-axis value. After reserving the output, the implementation writes one
positive 0.0 per cell without constructing an offset cursor or reading either
input.
Contracted extents and do not broadcast and are rejected as an inner
mismatch.
The small helper constructs the 2-D product, the stored right transpose, and two left batches sharing one weight batch. Applying the shape-specific function to each row gives the same four values as the rank-generic matrix product.
rust/demos/ch11-matrix-multiplication/src/lib.rs#tiny-matmul-example /// Multiplies the same values as 2-D matrices, a logical transpose, and batches.
pub fn tiny_matrix_multiplication_example() -> Result<TinyMatrixMultiplicationExample, MatmulError>
{
let token_rows = Tensor::from_vec(TOKEN_SHAPE.to_vec(), TOKEN_VALUES.to_vec())?;
let weights = Tensor::from_vec(WEIGHT_SHAPE.to_vec(), WEIGHT_VALUES.to_vec())?;
let product = matmul(&token_rows.view(), &weights.view())?;
let stored_transpose = Tensor::from_vec(
STORED_TRANSPOSE_SHAPE.to_vec(),
STORED_TRANSPOSE_VALUES.to_vec(),
)?;
let transpose_product =
matmul_with_transpose(&token_rows.view(), &stored_transpose.view(), false, true)?;
let batched_token_rows =
Tensor::from_vec(BATCHED_TOKEN_SHAPE.to_vec(), BATCHED_TOKEN_VALUES.to_vec())?;
let batched_weights = Tensor::from_vec(BATCHED_WEIGHT_SHAPE.to_vec(), WEIGHT_VALUES.to_vec())?;
let batched_product = matmul(&batched_token_rows.view(), &batched_weights.view())?;
Ok(TinyMatrixMultiplicationExample {
token_rows,
weights,
product,
stored_transpose,
transpose_product,
batched_token_rows,
batched_weights,
batched_product,
})
} The learner program also shows a zero-inner contraction and the exact rank, inner-dimension, and batch-dimension errors.
rust/demos/ch11-matrix-multiplication/src/main.rs#learner-matrix-multiplication-output let example = tiny_matrix_multiplication_example()?;
let zero_inner_left = Tensor::from_vec(vec![2, 0], vec![])?;
let zero_inner_right = Tensor::from_vec(vec![0, 2], vec![])?;
let zero_inner = matmul(&zero_inner_left.view(), &zero_inner_right.view())?;
let wrong_inner = Tensor::from_vec(vec![4, 2], vec![0.0; 8])?;
let inner_error = matmul(&example.token_rows.view(), &wrong_inner.view()).unwrap_err();
let wrong_batch = Tensor::from_vec(vec![3, 3, 2], vec![0.0; 18])?;
let batch_error = matmul(&example.batched_token_rows.view(), &wrong_batch.view()).unwrap_err();
let rank_one = Tensor::from_vec(vec![3], vec![1.0, 2.0, 3.0])?;
let rank_error =
matmul_with_transpose(&rank_one.view(), &example.weights.view(), false, false).unwrap_err(); Integer-valued examples can be compared exactly. A decimal dot product instead
uses absolute tolerance 1e-12, because decimal fractions are not generally
exact binary floating-point values. The cancellation example also makes the
ascending- accumulation order observable. No library implements matrix
multiplication for this chapter.
Trace one output cell, then add a batch axis
Read the figure in four passes:
- Follow the solid row marker across and the dotted column marker down . Their intersection is the double-bordered cell.
- Traverse the three double-bordered contraction cards in order. Verify
products
4.0,0.0, and12.0, then running totals4.0,4.0,16.0. - Compare stored right shape
[2,3]with logical shape[3,2], then notice that both output batches map to right batch zero. - Inspect the dashed errors. Inner sizes
3and4fail before a scalar loop; matching matrix axes with batch sizes2and3reach the batch error.
Follow one row-by-column contraction, then reuse one weight batch
Compare three matrices, accumulate one selected output cell in contracted-index order, and inspect logical transposition, batch reuse, and rejected shapes.
- Left activation shape
[2, 3]- Projection weight shape
[3, 2]- Product shape
[2, 2]
Select one left row and one right column
The solid arrow and left border select one row of the left activation. The downward arrow and dotted border select one column of the projection weight. Their intersection becomes the double-bordered focused output cell.
| Row | Column 0 | Column 1 | Column 2 |
|---|---|---|---|
| 0 | 1.0 | 2.0 | 3.0 |
| Selected left row: 1 | 4.0 | 5.0 | 6.0 |
| Row | Selected right column: Column 0 | Column 1 |
|---|---|---|
| 0 | 1.0 | 2.0 |
| 1 | 0.0 | 1.0 |
| 2 | 2.0 | 0.0 |
| Row | Column 0 | Column 1 |
|---|---|---|
| 0 | 7.0 | 4.0 |
| 1 | Focused output cell: 16.0 | 13.0 |
Accumulate three products in contracted-index order
Each double-bordered card is one contracted-index step; the running total reaches the focused output only after all three products.
-
Product accumulated along the inner dimension: Term
- Product
- 4.0
- Running total
- 4.0
-
Product accumulated along the inner dimension: Term
- Product
- 0.0
- Running total
- 4.0
-
Product accumulated along the inner dimension: Term
- Product
- 12.0
- Running total
- 16.0
Reuse logical weights without copying values
A transpose flag changes the logical final axes without materializing, while the curved arrow marks the single right batch reused for both output batches.
- Stored shape
[2, 3]- Logical shape
[3, 2]- Output shape
[2, 2]- Output values
[7.0, 4.0, 16.0, 13.0]
-
Shared weight batch reused by broadcasting: Output batch 0
- Left batch
- 0
- Right batch
- 0
- Values
[7.0, 4.0, 16.0, 13.0]
-
Shared weight batch reused by broadcasting: Output batch 1
- Left batch
- 1
- Right batch
- 0
- Values
[4.0, 1.0, 2.0, 5.0]
Reject mismatched inner and batch dimensions
Dashed cards keep the exact dimensions rejected before allocation or scalar multiplication begins.
- Rejected matrix product:
inner-dimension-mismatchThe two inner dimensions must be equal. - Rejected matrix product:
incompatible-batchLeading batch dimensions must be equal or one of them must be singleton. Batch axis 0:
Read the focused output as a complete proof: one selected row and one selected column supply exactly three products, and their ordered running totals end at . The batch cards then show that only the leading batch axis reuses the weight matrix. The two rejected examples distinguish equality of the contracted inner extents from broadcasting of leading batch axes.
Predict products before running Rust
Write effective shapes before calculating any values.
- Predict the output shape and all four values for the example matrix with shape
[2,3]multiplied by with shape[3,2]. - Recompute in ascending order. Which axis disappears, and why?
- Store as shape
[2,3]. Which flag restores logical shape[3,2], and what output remains unchanged? - For left shape
[2,2,3]and right shape[1,3,2], map output batch1to both input batch coordinates and predict its four values. - Predict the product of shapes
[2,0]and[0,2]. Why is the result not an error? - Name the first error for a rank-one left input, inner sizes
3and4, and compatible matrix axes with leading batch sizes2and3. - For contiguous strides
[3,1]and strides[2,1], write both cell-base stride plans and the three source-offset pairs used by . Why can a sliced non-contiguous view use the same algorithm without a copy? - Misconception check: is matrix multiplication elementwise multiplication followed by one global sum? Identify the distinct row, column, and inner indices.
Check the eight matrix-multiplication predictions
- The equal inner extents disappear. The outer extents form shape
[2,2], and the values are[7,4,16,13]in row-major order. - gives running total ; leaves it ; raises it to . Axis disappears because all three matching positions contribute to one cell.
- Set
transpose_right=true. Stored[2,3]is interpreted as logical[3,2], and the output remains shape[2,2]with[7,4,16,13]. - Output batch
1maps to left batch1and right batch0. Its product is shape[2,2]with values[4,1,2,5]. - Shape
[2,2]contains four positive-zero values. Each cell exists, but supplies no terms to a running sum initialized as0.0. - The errors are
LeftRankTooSmall { rank: 1 }, thenInnerDimensionMismatch { left: 3, right: 4 }, thenIncompatibleBatch { axis: 0, left_dimension: 2, right_dimension: 3 }. - The left cell-base plan is
[3,0], and the right plan is[0,1]. starts at offsets3and0; contracted strides1and2produce(3,0),(4,2), and(5,4). A sliced view supplies its own checked base offset and strides to the same plan, so only the newly owned contiguous output is allocated. - No. Output row selects one left row, output column selects one right column, and inner index pairs and sums their shared positions. Other row-column pairs produce other cells rather than joining one global sum.
Prepare learned projections and attention
The cumulative tensor core can now multiply rank-two or batched strided views, require equal contracted dimensions, broadcast only leading batch axes, and interpret optional final-axis transposes without copying. Checked shape and allocation failures occur before scalar evaluation, while successful results own predictable contiguous storage.
Public lookup still validates every coordinate supplied by a caller. Inside a validated matrix product, checked cell-base cursors plus two contracted-axis strides express the same batch, row, column, and choices without rebuilding coordinates for every scalar product.
This is the numerical contraction behind later learned projections, attention scores, attention-weighted values, feed-forward layers, and their gradients. It is not yet a learned layer or attention mechanism: there are no parameters, bias, masking, scaling, normalization, or training graph here.
Chapter 12 next turns arbitrary matrix outputs into stable probabilities and log-probabilities. That chapter will subtract a maximum before exponentiation so large logits do not overflow and will keep the selected normalization axis explicit for vocabulary and attention distributions.