Bridges: DSA to LLMs
Arrays and matrices to embeddings and tensors
The data structure the whole field runs on
A word embedding is a float array. A sentence is a matrix. A batch is a tensor. It is arrays all the way down - the exact structure you met in Arrays and memory.
Here is a small shock: the array - a contiguous block of same-sized boxes in memory, indexed in by pure arithmetic - is the shared atom of data structures and of deep learning. A word embedding is a 1-D array of floats. A batch of token embeddings is a 2-D array - a matrix. A batch of those is a 3-D array - a tensor. Nothing new is invented on the LLM side; the same row of numbers just gets more index dimensions and a fancier name.
The one-line idea
The array is the shared atom
In Word embeddings a word became a point in space: cat = a list of, say, 512 floats. That list is literally an array - boxes, contiguous, each holding one number. Line up one such array per token in a sentence and you have stacked rows into a matrix of shape . Line up one matrix per sentence in a batch and you have a rank-3 tensor of shape . Every weight in every layer, every activation flowing through, is one of these - a plain array of numbers with a declared shape.
Row-major: the shape is a story the strides tell
A 2-D matrix is not really 2-D in memory - memory is one line. The array library stores the first row's elements, then the second row's, then the third: row-major order (C-order, NumPy's default). To find element it does the same trick as a 1-D array - one multiply, one add - just with the row width folded in:
From index to address (why it stays O(1))
For a matrix with columns and element size bytes, and for a rank-3 tensor with rows per matrix:
The multipliers are the strides: how many bytes to jump to advance one step along each axis. The formula never mentions the array's length, so reaching any element is - exactly the arrays result, one dimension richer.
The demo below makes this concrete. Hover a token to light up its row of the embedding matrix. Flip on Overlay linear memory to watch that row become a contiguous run of boxes on the flat strip. Then switch to Tensor 3-D and slice the cube along each axis - and watch a fancy multi-axis slice turn into a simple, or strided, pattern of memory offsets.
shape (4, 4) = (tokens, dims) · row-major, one contiguous block
Stack one embedding per token → a 2-D array (a matrix). Hover a token to light its row; toggle memory to see the row-major layout.
Top labels are embedding dimensions d0…d3; left labels are tokens. The number over each memory box is its flat offset - the value of i·W + j (plus a batch stride in 3-D).
The aha: a slice is a stride pattern
Shapes, axes & broadcasting
Once everything is an array, the whole game is keeping shapes consistent. An axis is one index direction; a shape is the length along each axis. Reshaping never moves a single float - it only relabels how the flat line is folded. And broadcasting is the rule that lets a small array act on a big one without copying: a bias of shape is stretched across the batch and token axes to add to every embedding at once.
import numpy as np
# a word embedding is a 1-D array of floats - one contiguous block in memory
cat = np.array([0.9, 0.4, -0.1, 0.2], dtype=np.float32) # shape (4,)
# a sentence: one embedding row per token -> 2-D array (a matrix)
sentence = np.array([
[ 0.1, -0.2, 0.0, 0.3], # the
[ 0.9, 0.4, -0.1, 0.2], # cat
[-0.2, 0.7, 0.5, -0.3], # sat
[ 0.0, -0.5, 0.8, 0.1], # on
], dtype=np.float32) # shape (4, 4) = (tokens, dims)
# a batch of sentences: stack matrices -> 3-D array (a tensor)
batch = np.stack([sentence, sentence]) # shape (2, 4, 4) = (batch, tokens, dims)
batch.shape # (2, 4, 4)
batch.strides # (64, 16, 4) bytes: step 1 sentence / token / dim
batch.ravel()[:4] # the-row floats, back-to-back: it is one contiguous block
# broadcasting: a (4,) bias added to every token of every sentence
bias = np.array([0.0, 0.1, -0.1, 0.05], dtype=np.float32)
(batch + bias).shape # (2, 4, 4) - bias stretched across axes 0 and 1Check yourself
Reading A[i][j] from a row-major matrix is O(1) because its flat offset is:
A batch of 8 sentences, each 12 tokens, each token a 512-dim embedding, is a tensor of shape:
Recall: how are a word embedding, a sentence, and a batch each an array - and where does element (b, i, j) of the batch tensor live in memory?
Try to state it, then check.
Lock it in
- The array - a contiguous block of same-sized cells indexed in by arithmetic - is the shared atom of both data structures and deep learning.
- A word embedding is a 1-D array, a sentence is a 2-D matrix , a batch is a 3-D tensor - a tensor is just an array with more indices.
- Every tensor is one flat run of floats; strides turn a multi-axis index into a single memory offset, so reaching any element stays .
- Layout, not just shape, sets speed: a slice is a stride pattern, and broadcasting stretches a small array over a big one without copying.
Primary source
Ask your teacher
"view" vs. a "copy" is, how reshape can be free while transpose is not, or why the whole field settled on the axis order.