Algorithm Search⌘K

Proofs: Parallel merge sort

These are the human proofs of Parallel merge sort, at full length.

Parallel merge sort is correct, stable, and has work Θ(n log n) and span O(log³ n) full

This proof shows: correctness.

Fix the inputs of a call of P-MERGE: sorted ranges X[a1…a2−1]X[a_1 \ldots a_2 - 1] and Y[b1…b2−1]Y[b_1 \ldots b_2 - 1], with N=na+nbN = n_a + n_b items. Define the stable order on these NN items: uu comes before vv if uu has a smaller key, or the keys are equal and uu is in XX and vv is in YY, or the keys are equal, both are in the same input and uu has the smaller index. This is a strict total order. The stable merge of the two ranges is the list of the items in this order.

Lemma 1. P-MERGE writes the stable merge to Z[c .. c + N − 1]

Proof. By induction on NN. For N=0N = 0 the call writes nothing, which is correct.

Let N≥1N \ge 1 and na≥nbn_a \ge n_b, so na≥1n_a \ge 1. Let x=X[q]x = X[q]. Line L12 finds the least rr with r=b2r = b_2 or Y[r]≥xY[r] \ge x. Since YY is sorted, Y[b1…r−1]Y[b_1 \ldots r-1] are the items of YY with key less than xx, and Y[r…b2−1]Y[r \ldots b_2 - 1] are those with key at least xx. The items that come before xx in the stable order are:

  • the items X[a1…q−1]X[a_1 \ldots q-1], which have keys at most xx and smaller indices;
  • the items of YY with key less than xx, which are Y[b1…r−1]Y[b_1 \ldots r-1]. An item of YY with key equal to xx comes after xx, because xx is in XX.

No other item comes before xx: the items X[q+1…a2−1]X[q+1 \ldots a_2-1] have keys at least xx and larger indices, and the items Y[r…b2−1]Y[r \ldots b_2-1] have keys at least xx. So exactly (q−a1)+(r−b1)(q - a_1) + (r - b_1) items come before xx, and line L13 gives xx the position cc plus this number, which is its position in the stable merge.

The items before xx are the inputs of the call on line L15, and the items after xx are the inputs of the call on line L16. The stable order restricted to a subset is the stable order of that subset, because the order depends only on keys, inputs and indices. Each recursive call has fewer than NN items, so by induction the call on line L15 writes the items before xx in stable order to Z[c…t−1]Z[c \ldots t - 1], and the call on line L16 writes the items after xx in stable order to Z[t+1…c+N−1]Z[t + 1 \ldots c + N - 1]. Together with Z[t]=xZ[t] = x, this is the stable merge.

The case na<nbn_a < n_b is the same with y=Y[q]y = Y[q]. Line L20 finds the least rr with r=a2r = a_2 or X[r]>yX[r] > y, so X[a1…r−1]X[a_1 \ldots r-1] are the items of XX with key at most yy. These come before yy, because an item of XX with key equal to yy comes before yy. The items Y[b1…q−1]Y[b_1 \ldots q-1] also come before yy, and no other items do. So yy goes to position c+(r−a1)+(q−b1)c + (r - a_1) + (q - b_1), which is line L21, and the two recursive calls handle the rest as before. □\square

The two recursive calls of one call write the disjoint ranges Z[c…t−1]Z[c \ldots t-1] and Z[t+1…c+N−1]Z[t+1 \ldots c+N-1] and only read XX and YY. When ZZ is not XX or YY, the parallel calls do not interfere, and every schedule gives the same result.

Lemma 2. P-MERGE-SORT sorts A[lo .. hi − 1] stably

Proof. By induction on hi−lohi - lo. A range of at most one item is sorted. Otherwise, by induction, lines L3 to L5 sort the two halves stably. These calls work on disjoint ranges of AA and of TT, so they do not interfere. Line L6 copies the range to TT, and line L7 merges T[lo…mid−1]T[lo \ldots mid-1] and T[mid…hi−1]T[mid \ldots hi-1] into A[lo…hi−1]A[lo \ldots hi-1]. The items of the left half have smaller input positions than the items of the right half, so by Lemma 1 the merge puts equal keys in input order. Within each half, equal keys are already in input order. So the result is sorted, and equal keys keep their input order. □\square

Lemma 3. Split sizes

Let a call of P-MERGE have N≥1N \ge 1 items, and let its two recursive calls have N1N_1 and N2N_2 items. Then N1+N2=N−1N_1 + N_2 = N - 1, N1,N2≤3N/4N_1, N_2 \le 3N/4 and N1+1,N2+1≥N/4N_1 + 1, N_2 + 1 \ge N/4.

Proof. Take the case na≥nbn_a \ge n_b, so na≥N/2≥nbn_a \ge N/2 \ge n_b. The left call gets ⌊na/2⌋\lfloor n_a/2 \rfloor items of XX and r−b1≤nbr - b_1 \le n_b items of YY, so N1≤na/2+nb=N/2+nb/2≤3N/4N_1 \le n_a/2 + n_b = N/2 + n_b/2 \le 3N/4. The right call gets ⌈na/2⌉−1\lceil n_a/2 \rceil - 1 items of XX and at most nbn_b items of YY, so N2≤3N/4N_2 \le 3N/4 as well. Also N1≥⌊na/2⌋≥na/2−1/2N_1 \ge \lfloor n_a/2 \rfloor \ge n_a/2 - 1/2 and N2≥⌈na/2⌉−1≥na/2−1N_2 \ge \lceil n_a/2 \rceil - 1 \ge n_a/2 - 1, so both are at least N/4−1N/4 - 1. The other case is the same with nb>N/2n_b > N/2. □\square

Lemma 4. P-MERGE has span O(log² N) and work Θ(N)

Charge a call with NN items a cost of at most d(1+lg⁡(N+1))d(1 + \lg(N+1)) for itself, for a constant dd. This covers lines L8 to L14, since a binary search on at most NN items makes at most ⌈lg⁡(N+1)⌉\lceil \lg(N+1) \rceil probes.

Span. The span satisfies S(0)≤dS(0) \le d and S(N)≤S(⌊3N/4⌋)+d(1+lg⁡(N+1))S(N) \le S(\lfloor 3N/4 \rfloor) + d(1 + \lg(N+1)) by Lemma 3. Along any chain of calls the sizes drop by a factor of at least 3/43/4 at each step, so a chain has at most log⁡4/3N+2\log_{4/3} N + 2 calls, each of cost at most d(1+lg⁡(N+1))d(1 + \lg(N+1)). So S(N)=O(log⁡2N)S(N) = O(\log^2 N).

Work. Let g(N)=lg⁡(N+1)g(N) = \lg(N + 1). We show W(N)≤K(N+1)−2d g(N)W(N) \le K(N+1) - 2d\,g(N) for a constant KK. Since W(N)≥0W(N) \ge 0, for each of the finitely many N<212N < 2^{12} the bound holds when KK is large enough, so fix such a KK, with also K≥dK \ge d. Let N≥212N \ge 2^{12}, and assume the bound for all smaller sizes. By Lemma 3,

W(N)≤K(N1+1)−2d g(N1)+K(N2+1)−2d g(N2)+d(1+g(N)).W(N) \le K(N_1 + 1) - 2d\,g(N_1) + K(N_2 + 1) - 2d\,g(N_2) + d(1 + g(N)).

Here K(N1+1)+K(N2+1)=K(N+1)K(N_1 + 1) + K(N_2 + 1) = K(N + 1), and g(Ni)≥lg⁡(N/4)=lg⁡N−2g(N_i) \ge \lg(N/4) = \lg N - 2. So it is enough to show 4d(lg⁡N−2)≥2d g(N)+d(1+g(N))4d(\lg N - 2) \ge 2d\,g(N) + d(1 + g(N)), that is 4lg⁡N−8≥3g(N)+14 \lg N - 8 \ge 3 g(N) + 1. Since g(N)≤lg⁡N+1g(N) \le \lg N + 1, it is enough that lg⁡N≥12\lg N \ge 12, which holds. So W(N)=O(N)W(N) = O(N). Each of the NN items is written by its own call, so W(N)=Ω(N)W(N) = \Omega(N). □\square

Theorem. Work and span of P-MERGE-SORT

P-MERGE-SORT on nn keys has work Θ(nlog⁡n)\Theta(n \log n) and span O(log⁡3n)O(\log^3 n) in the work-span model.

Proof. The copy on line L6 is a parallel loop over hi−lohi - lo items, with work Θ(hi−lo)\Theta(hi - lo) and span O(log⁡(hi−lo))O(\log(hi - lo)). By Lemma 4 the merge on line L7 has work Θ(hi−lo)\Theta(hi - lo) and span O(log⁡2(hi−lo))O(\log^2(hi - lo)). The two recursive calls run in parallel, so

W(n)=W(⌊n/2⌋)+W(⌈n/2⌉)+Θ(n),S(n)=S(⌈n/2⌉)+O(log⁡2n).W(n) = W(\lfloor n/2 \rfloor) + W(\lceil n/2 \rceil) + \Theta(n), \qquad S(n) = S(\lceil n/2 \rceil) + O(\log^2 n).

The first recurrence is the one of sequential merge sort, with solution Θ(nlog⁡n)\Theta(n \log n). The second has ⌈lg⁡n⌉\lceil \lg n \rceil levels, each of span O(log⁡2n)O(\log^2 n), so S(n)=O(log⁡3n)S(n) = O(\log^3 n). □\square

Back to Parallel merge sort