Multiply two 2×2 matrices by hand using the standard triple loop. For each output cell C[i][j], the innermost loop accumulates the dot product of row i of A with column j of B. The trace shows C filling cell by cell across all 8 inner products.

By hand

Initialize C as a 2×2 zero matrix. Three nested loops over i, j, and k: add A[i][k] * B[k][j] to C[i][j] for each k. After the loops C[i][j] holds the complete dot product of row i of A with column j of B.

naive.py
Replay: real traced execution (multi-file project)
A = [[1, 2], [3, 4]]
B = [[5, 6], [7, 8]]
n = 2
C = [[0, 0], [0, 0]]
for i in range(n):
    for j in range(n):
        for k in range(n):
            C[i][j] += A[i][k] * B[k][j]
print('RESULT:', C)
  1. A ← [[1, 2], [3, 4]]

    1A = [[1, 2], [3, 4]]2B = [[5, 6], [7, 8]]
    values this step[[1, 2], [3, 4]]A
  2. B ← [[5, 6], [7, 8]]

    1A = [[1, 2], [3, 4]]2B = [[5, 6], [7, 8]]3n = 2
    values this step[[5, 6], [7, 8]]B
  3. n ← 2

    2B = [[5, 6], [7, 8]]3n = 24C = [[0, 0], [0, 0]]
    values this step2n
  4. C ← [[0, 0], [0, 0]]

    3n = 24C = [[0, 0], [0, 0]]5for i in range(n):
    values this step[[0, 0], [0, 0]]C
  5. i ← 0

    4C = [[0, 0], [0, 0]]5for i in range(n):6    for j in range(n):
    values this step0i
  6. j ← 0

    5for i in range(n):6    for j in range(n):7        for k in range(n):
    values this step0j
  7. k ← 0

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
    values this step0k
  8. C ← [[5, 0], [0, 0]]

    7        for k in range(n):8            C[i][j] += A[i][k] * B[k][j]9print('RESULT:', C)
    values this step[[0, 0], [0, 0]] [[5, 0], [0, 0]]C
  9. k ← 1

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
    values this step0 1k
  10. C ← [[19, 0], [0, 0]]

    7        for k in range(n):8            C[i][j] += A[i][k] * B[k][j]9print('RESULT:', C)
    values this step[[5, 0], [0, 0]] [[19, 0], [0, 0]]C
  11. for k in range(n):

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
  12. j ← 1

    5for i in range(n):6    for j in range(n):7        for k in range(n):
    values this step0 1j
  13. k ← 0

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
    values this step1 0k
  14. C ← [[19, 6], [0, 0]]

    7        for k in range(n):8            C[i][j] += A[i][k] * B[k][j]9print('RESULT:', C)
    values this step[[19, 0], [0, 0]] [[19, 6], [0, 0]]C
  15. k ← 1

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
    values this step0 1k
  16. C ← [[19, 22], [0, 0]]

    7        for k in range(n):8            C[i][j] += A[i][k] * B[k][j]9print('RESULT:', C)
    values this step[[19, 6], [0, 0]] [[19, 22], [0, 0]]C
  17. for k in range(n):

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
  18. for j in range(n):

    5for i in range(n):6    for j in range(n):7        for k in range(n):
  19. i ← 1

    4C = [[0, 0], [0, 0]]5for i in range(n):6    for j in range(n):
    values this step0 1i
  20. j ← 0

    5for i in range(n):6    for j in range(n):7        for k in range(n):
    values this step1 0j
  21. k ← 0

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
    values this step1 0k
  22. C ← [[19, 22], [15, 0]]

    7        for k in range(n):8            C[i][j] += A[i][k] * B[k][j]9print('RESULT:', C)
    values this step[[19, 22], [0, 0]] [[19, 22], [15, 0]]C
  23. k ← 1

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
    values this step0 1k
  24. C ← [[19, 22], [43, 0]]

    7        for k in range(n):8            C[i][j] += A[i][k] * B[k][j]9print('RESULT:', C)
    values this step[[19, 22], [15, 0]] [[19, 22], [43, 0]]C
  25. for k in range(n):

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
  26. j ← 1

    5for i in range(n):6    for j in range(n):7        for k in range(n):
    values this step0 1j
  27. k ← 0

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
    values this step1 0k
  28. C ← [[19, 22], [43, 18]]

    7        for k in range(n):8            C[i][j] += A[i][k] * B[k][j]9print('RESULT:', C)
    values this step[[19, 22], [43, 0]] [[19, 22], [43, 18]]C
  29. k ← 1

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
    values this step0 1k
  30. C ← [[19, 22], [43, 50]]

    7        for k in range(n):8            C[i][j] += A[i][k] * B[k][j]9print('RESULT:', C)
    values this step[[19, 22], [43, 18]] [[19, 22], [43, 50]]C
  31. for k in range(n):

    6for j in range(n):7    for k in range(n):8        C[i][j] += A[i][k] * B[k][j]
  32. for j in range(n):

    5for i in range(n):6    for j in range(n):7        for k in range(n):
  33. for i in range(n):

    4C = [[0, 0], [0, 0]]5for i in range(n):6    for j in range(n):
  34. stdout ← RESULT: [[19, 22], [43, 50]]

    8            C[i][j] += A[i][k] * B[k][j]9print('RESULT:', C)
    values this stepRESULT: [[19, 22], [43, 50]]stdout

With NumPy

mat_a @ mat_b applies matrix multiplication in one call. The snapshot shows both inputs and the result, each with their (2, 2) shape.

library.py
import numpy as np

A = [[1, 2], [3, 4]]
B = [[5, 6], [7, 8]]
mat_a = np.array(A)
mat_b = np.array(B)
result = mat_a @ mat_b
print('A: shape:', mat_a.shape, 'dtype:', mat_a.dtype, 'values:', mat_a.tolist())
print('B: shape:', mat_b.shape, 'dtype:', mat_b.dtype, 'values:', mat_b.tolist())
print('result: shape:', result.shape, 'dtype:', result.dtype, 'values:', result.tolist())
print('RESULT:', result.tolist())
A: shape: (2, 2) dtype: int64 values: [[1, 2], [3, 4]]
B: shape: (2, 2) dtype: int64 values: [[5, 6], [7, 8]]
result: shape: (2, 2) dtype: int64 values: [[19, 22], [43, 50]]
RESULT: [[19, 22], [43, 50]]

Implementation notes

  • Each cell C[i][j] is the dot product of row i of A with column j of B — the same scalar computation as dot-product, repeated for every (i, j) pair. The triple loop makes this structure explicit.
  • For a general (m, n) @ (n, p) multiplication the triple loop would range over i in range(m), j in range(p), k in range(n). The 2×2 case is the minimal non-trivial example.
  • @ dispatches to np.matmul. For 2-D arrays np.dot(A, B) gives the same result, but @ is preferred for readability and consistency with the matvec-multiply lesson.
  • Shape, dtype, and values are shown explicitly here because ndarray.__repr__ output varies with NumPy version and print options.