Skip to content
C.W.K.
Stream
Lesson 05 of 08 · published

Matrix Multiplication: The Ritual of Combining Spells

~10 min · matrix-multiplication, broadcasting, shapes

Level 0Math Novice
0 XP0/59 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

Why It's Not Element-Wise

Adding matrices is element-wise — easy. Multiplying matrices is not element-wise. It's a careful dance of rows and columns: each cell of the output is the dot product of one row of the left matrix and one column of the right matrix.

The shape rule: . Inner dimensions must match; outer dimensions form the result. Get this rule wrong and your code crashes; get it right and you've built a neural network layer.

Composing Transformations

Matrix multiplication encodes composing transformations. Rotations and scales can be represented as matrices, and translations can too when you use homogeneous coordinates. Multiplying those matrices gives a single matrix that performs all the transformations at once. Order matters: is generally not equal to . Rotate-then-scale ≠ scale-then-rotate (in 3D, vividly so).

Broadcasting Sneaks Back In

NumPy/PyTorch let you "multiply" a matrix by a vector with * (element-wise) — and broadcasting will silently apply the vector across rows or columns of the matrix. This is not matrix multiplication; it's element-wise op with broadcasting. Use @ for true matrix multiplication.

The bug that bit me. Early in deep-learning work I wrote output = weights * inputs in a forward pass. The shapes happened to broadcast, the loss came out as a number, training even improved a bit. It took an hour to realize my "linear layer" was element-wise multiplication and not a real linear transformation. Use @. Every time.

Code

The two operations that look similar and aren't·python
import numpy as np

A = np.array([[1, 2],
              [3, 4]])
B = np.array([[5, 6],
              [7, 8]])

# Element-wise — wrong for linear layers
print(A * B)          # [[ 5 12] [21 32]]

# Matrix multiplication — what neural networks do
print(A @ B)          # [[19 22] [43 50]]

# Verify by hand on (0, 0): 1*5 + 2*7 = 19 ✓
Composition is multiplication, order matters·python
import numpy as np
import torch

# Composing transformations: rotate-then-scale
theta = np.pi / 4
R = torch.tensor([[np.cos(theta), -np.sin(theta)],
                  [np.sin(theta),  np.cos(theta)]], dtype=torch.float32)
S = torch.tensor([[2.0, 0.0],
                  [0.0, 0.5]])

# Composite transformation: rotate first, then scale
T = S @ R                       # apply R first, then S (read right to left)
v = torch.tensor([1.0, 0.0])
print(T @ v)                    # [√2, √2/2] — rotated 45° then scaled

External links

Exercise

Define a 90° rotation matrix R and a nonuniform scale matrix S = diag([2, 0.5]). Apply R @ S and S @ R to the vector [1, 0]. Are the results the same? Explain why order matters.
Hint
R = [[0, -1], [1, 0]]. Read products right to left: R @ S scales first and rotates second, while S @ R rotates first and then scales along the fixed coordinate axes.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 2

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.
  1. Elechemist
    Elechemist

    import numpy as np

    R = np.array([[0., -1.], [1., 0.]]) S = np.array([[2., 0.], [0., 2.]]) v = np.array([1., 0.])

    print('(R @ S) @ v =', (R @ S) @ v) print('(S @ R) @ v =', (S @ R) @ v) print('same:', np.allclose((R @ S) @ v, (S @ R) @ v))

    💛 by Pippawarm
    1. Pippa
      Pippa· warmElechemistElechemist

      좋아요. 여기서는 S2I라서 모든 방향을 똑같이 키우는 균일 스케일이고, 그래서 R @ SS @ R 결과가 같아요. S = np.diag([2., 0.5])처럼 방향마다 다르게 스케일하면 순서 차이가 바로 보일 거예요.