Linear Algebra Basics
Matrix-Vector Multiply
Multiply a 2×2 matrix by a length-2 vector by hand. An outer loop over rows
feeds an inner loop that accumulates one dot product per row into s. The
trace shows s resetting to 0 at each new row, then building up before
being appended to result.
By hand
Outer loop over each row of A. Inner loop over each column index i:
accumulate row[i] * v[i] into s. After the inner loop, append s to
result. Each s is the dot product of one row with v.
naive.py
Replay: real traced execution (multi-file project)
A = [[1, 2], [3, 4]]
v = [5, 6]
result = []
for row in A:
s = 0
for i in range(len(v)):
s += row[i] * v[i]
result.append(s)
print('RESULT:', result)
A ← [[1, 2], [3, 4]]
1A = [[1, 2], [3, 4]]2v = [5, 6]values this step[[1, 2], [3, 4]]Av ← [5, 6]
1A = [[1, 2], [3, 4]]2v = [5, 6]3result = []values this step[5, 6]vresult ← []
2v = [5, 6]3result = []4for row in A:values this step[]resultrow ← [1, 2]
3result = []4for row in A:5 s = 0values this step[1, 2]rows ← 0
4for row in A:5 s = 06 for i in range(len(v)):values this step0si ← 0
5s = 06for i in range(len(v)):7 s += row[i] * v[i]values this step0is ← 5
6for i in range(len(v)):7 s += row[i] * v[i]8result.append(s)values this step0 → 5si ← 1
5s = 06for i in range(len(v)):7 s += row[i] * v[i]values this step0 → 1is ← 17
6for i in range(len(v)):7 s += row[i] * v[i]8result.append(s)values this step5 → 17sfor i in range(len(v)):
5s = 06for i in range(len(v)):7 s += row[i] * v[i]result ← [17]
7 s += row[i] * v[i]8 result.append(s)9print('RESULT:', result)values this step[] → [17]resultrow ← [3, 4]
3result = []4for row in A:5 s = 0values this step[1, 2] → [3, 4]rows ← 0
4for row in A:5 s = 06 for i in range(len(v)):values this step17 → 0si ← 0
5s = 06for i in range(len(v)):7 s += row[i] * v[i]values this step1 → 0is ← 15
6for i in range(len(v)):7 s += row[i] * v[i]8result.append(s)values this step0 → 15si ← 1
5s = 06for i in range(len(v)):7 s += row[i] * v[i]values this step0 → 1is ← 39
6for i in range(len(v)):7 s += row[i] * v[i]8result.append(s)values this step15 → 39sfor i in range(len(v)):
5s = 06for i in range(len(v)):7 s += row[i] * v[i]result ← [17, 39]
7 s += row[i] * v[i]8 result.append(s)9print('RESULT:', result)values this step[17] → [17, 39]resultfor row in A:
3result = []4for row in A:5 s = 0stdout ← RESULT: [17, 39]
8 result.append(s)9print('RESULT:', result)values this stepRESULT: [17, 39]stdout
With NumPy
mat @ vec applies the @ (matmul) operator: each element of the output is
the dot product of the corresponding row of mat with vec. The snapshot
shows the matrix, the vector, and the result with their shapes.
library.py
import numpy as np
A = [[1, 2], [3, 4]]
v = [5, 6]
mat = np.array(A)
vec = np.array(v)
result = mat @ vec
print('mat: shape:', mat.shape, 'dtype:', mat.dtype, 'values:', mat.tolist())
print('vec: shape:', vec.shape, 'dtype:', vec.dtype, 'values:', vec.tolist())
print('result: shape:', result.shape, 'dtype:', result.dtype, 'values:', result.tolist())
print('RESULT:', result.tolist())
mat: shape: (2, 2) dtype: int64 values: [[1, 2], [3, 4]]
vec: shape: (2,) dtype: int64 values: [5, 6]
result: shape: (2,) dtype: int64 values: [17, 39]
RESULT: [17, 39]
Implementation notes
- Each element of the output is a dot product:
result[0] = row0 · vec,result[1] = row1 · vec. The hand-written loop makes this explicit — seedot-productfor the scalar version. - The shapes must be compatible:
(m, n) @ (n,)→(m,). Here(2, 2) @ (2,)→(2,). A shape mismatch raises aValueError. @dispatches tonp.matmulfor 2-D arrays. For a matrix times a matrix use the same@operator:(m, n) @ (n, p)→(m, p).- Shape, dtype, and values are shown explicitly here because
ndarray.__repr__output varies with NumPy version and print options.