Algorithm Search⌘K

Proofs: Cache-oblivious matrix multiplication

These are the human proofs of Cache-oblivious matrix multiplication, at full length.

The recursion that halves the largest dimension computes AB, and its miss count full

This proof shows: correctness, termination.

Let RR be a semiring: addition is associative and commutative with a zero, multiplication is associative and distributes over addition on both sides. Commutativity of the multiplication and subtraction are not used. The call REC-MULT(A,B,C)\mathrm{REC\text{-}MULT}(A, B, C) has AA of size m×nm \times n, BB of size n×pn \times p and CC of size m×pm \times p, all given as index ranges into larger row-major arrays.

Correctness

Claim. For all m,n,p≥1m, n, p \ge 1 and base≥1\mathit{base} \ge 1, the call ends with CC replaced by C+ABC + AB, and it changes no other entry of the arrays.

Proof by strong induction on mnpmnp. If max⁡(m,n,p)≤base\max(m, n, p) \le \mathit{base}, line L1 runs the triple loop, which adds ∑kaikbkj\sum_k a_{ik} b_{kj} to each cijc_{ij} of the range and touches nothing else.

Otherwise max⁡(m,n,p)≥2\max(m, n, p) \ge 2. The tests of lines L2 to L4 pick a dimension that is a largest one: line L2 when mm is a maximum, line L3 when mm is not a maximum and n≥pn \ge p (then nn is a maximum), and line L4 when pp is the unique maximum. The picked dimension x≥2x \ge 2 splits into halves of sizes ⌊x/2⌋≥1\lfloor x/2 \rfloor \ge 1 and ⌈x/2⌉<x\lceil x/2 \rceil < x. So both calls have a smaller product of sides, and the induction hypothesis applies to them.

  • Line L2. With A=(A1;A2)A = (A_1 ; A_2) and C=(C1;C2)C = (C_1 ; C_2) split at the same row, AB=(A1B;A2B)AB = (A_1 B ; A_2 B). The first call adds A1BA_1 B to C1C_1 and touches only C1C_1; the second adds A2BA_2 B to C2C_2.
  • Line L3. With A=(A1 A2)A = (A_1 \ A_2) and B=(B1;B2)B = (B_1 ; B_2) split at the same inner index, block multiplication gives AB=A1B1+A2B2AB = A_1 B_1 + A_2 B_2. The first call adds A1B1A_1 B_1 to CC, the second adds A2B2A_2 B_2, and since addition is associative and commutative the result is C+ABC + AB.
  • Line L4. With B=(B1 B2)B = (B_1 \ B_2) and C=(C1 C2)C = (C_1 \ C_2) split at the same column, AB=(AB1 AB2)AB = (A B_1 \ A B_2), and the two calls add the two parts to C1C_1 and C2C_2.

In each case the factor from AA stays on the left. □\square

Started with C=0C = 0, the method returns ABAB. When mm, nn or pp is 00 there is nothing to do; the implementation returns the zero m×pm \times p matrix at once.

Summation order. Fix an entry cijc_{ij}. Lines L2 and L4 send it to exactly one of the two calls. Line L3 sends it to both, first with the lower half of the inner range, then with the upper half. By induction, the terms aikbkja_{ik} b_{kj} reach cijc_{ij} with kk increasing, in the same order as in the plain triple loop. So in floating point the two methods give the same result, provided the leaves use the same order.

Termination and depth

Each call either stops at line L1 or makes two calls with a smaller product mnpmnp, so the recursion is finite.

Along a path from the root, each split replaces one side xx by ⌊x/2⌋\lfloor x/2 \rfloor or ⌈x/2⌉\lceil x/2 \rceil, both at most ⌈x/2⌉\lceil x/2 \rceil. Since ⌈⌈x/2⌉/2⌉=⌈x/4⌉\lceil \lceil x/2 \rceil / 2 \rceil = \lceil x/4 \rceil, a side that has been split tt times is at most ⌈x/2t⌉\lceil x/2^t \rceil, which is 11 once t≥⌈lg⁡x⌉t \ge \lceil \lg x \rceil. A side of size 11 is never split, since only a largest side of size at least 22 is split. So each path has at most ⌈lg⁡m⌉+⌈lg⁡n⌉+⌈lg⁡p⌉\lceil \lg m \rceil + \lceil \lg n \rceil + \lceil \lg p \rceil splits, which bounds the depth. The stack therefore holds O(log⁡(mnp))O(\log(mnp)) frames.

The miss bound for square matrices

Let nn be a power of two and m=n=pm = n = p, with base=1\mathit{base} = 1. The cache is ideal: MM words, lines of BB words, fully associative, with the optimal offline replacement.

Shape of the recursion. For a cube of side s≥2s \ge 2, line L2 splits mm (all sides are equal), then line L3 splits nn (now m=s/2<n=pm = s/2 < n = p), then line L4 splits pp. After these three levels, there are 88 cubes of side s/2s/2. So the subproblems at depth 3t3t are 8t8^t cubes of side n/2tn/2^t, and the method is the sequence of their calls, in some order.

Lemma 1 (footprint). A subproblem on a cube of side ss reads and writes words of three s×ss \times s submatrices of row-major arrays. Each of the 3s3s rows is a run of ss consecutive words, which touches at most ⌈s/B⌉+1\lceil s/B \rceil + 1 lines. So the subproblem touches at most 3s(⌈s/B⌉+1)3s(\lceil s/B \rceil + 1) lines. If s≥Bs \ge B, this is at most 9s2/B9s^2/B lines, that is 9s29s^2 words.

Proof. For s≥Bs \ge B, ⌈s/B⌉+1≤s/B+2≤3s/B\lceil s/B \rceil + 1 \le s/B + 2 \le 3s/B. The count of lines for a run is shown on the blocked multiplication proofs page, Lemma 1. □\square

Lemma 2 (a subproblem that fits). If a subproblem touches at most M/BM/B distinct lines, the ideal cache serves it with at most that many misses, whatever the cache holds at the start.

Proof. The replacement rule that never evicts a line of the subproblem during it, and evicts other lines when room is needed, misses at most once per line. The optimal rule misses no more often. □\square

Lemma 3 (concatenation). For any sequences σ1,…,σr\sigma_1, \ldots, \sigma_r of accesses, the optimal number of misses of the concatenation, from any start state, is at most the sum of the optimal numbers for the pieces started from an empty cache.

Proof. Run, on each piece in turn, a copy of the optimal schedule for that piece started from an empty cache, and keep the invariant that every line held by the copy is also in the real cache. When the copy loads a line, the real cache loads it too unless it is already there, and if it must evict, it evicts a line that the copy does not hold. Such a line exists, because just before the load the copy holds fewer than M/BM/B lines and the real cache is full. So the real cache misses only when the copy misses, and the optimal schedule of the concatenation misses no more than this one. □\square

Theorem. Let M≥36B2M \ge 36B^2. If 9n2≤M9n^2 \le M and n≥Bn \ge B, the method makes at most 9n2/B9n^2/B misses. If 9n2>M9n^2 > M, it makes at most 54 n3/(BM)54\, n^3/(B\sqrt M) misses.

Proof. The first case is Lemma 1 and Lemma 2 for the whole problem.

In the second case let s=n/2ts = n/2^t be the largest power of two with 9s2≤M9s^2 \le M and s≤ns \le n. Since 9n2>M9n^2 > M, we have s<ns < n, so 2s≤n2s \le n and 9(2s)2>M9(2s)^2 > M by the choice of ss. So s>M/6s > \sqrt M/6, and since M/6≥B\sqrt M/6 \ge B, also s≥Bs \ge B. The computation is the sequence of the (n/s)3(n/s)^3 subproblems at depth 3t3t, which are cubes of side ss. By Lemma 1 each touches at most 9s2/B≤M/B9s^2/B \le M/B lines, so by Lemma 2 each costs at most 9s2/B9s^2/B misses from an empty cache. By Lemma 3 the total is at most

(ns)3⋅9s2B=9n3sB<54 n3BM.□\Big(\frac{n}{s}\Big)^3 \cdot \frac{9 s^2}{B} = \frac{9 n^3}{s B} < \frac{54\, n^3}{B \sqrt M}. \qquad \square

LRU. Sleator and Tarjan (1985) proved that LRU with kk lines misses at most kk−h+1\frac{k}{k - h + 1} times as often as the optimal rule with hh lines, plus hh. With k=M/Bk = M/B and h=M/(2B)h = M/(2B), LRU with MM words makes at most about twice the misses of the ideal cache with M/2M/2 words. If M/2≥36B2M/2 \ge 36B^2, the theorem with M/2M/2 in place of MM gives at most 1082 n3/(BM)108\sqrt 2\, n^3/(B\sqrt M) misses, up to the additive term, for LRU with MM words when 9n2>M/29n^2 > M/2.

General shapes. For all mm, nn, pp with a tall cache, Frigo, Leiserson, Prokop and Ramachandran prove the bound Θ(m+n+p+(mn+np+mp)/B+mnp/(BM))\Theta(m + n + p + (mn + np + mp)/B + mnp/(B\sqrt M)). Their proof follows the same plan, with the first subproblems that fit in the cache in place of the cubes of side ss; it is not reproduced here.

Back to Cache-oblivious matrix multiplication