Proofs: Timsort
These are the human proofs of Timsort, at full length.
Timsort sorts the array stably full
This proof shows: correctness.
We say that a segment is sorted stably when it is sorted by key and items with equal keys are in their input order. We use the four helper procedures of the implementation, and prove each one first. Every comparison is , and "" means "not ".
Lemma 1 (runs). COUNT-RUN at returns , and after it is sorted stably.
Proof. If or the run is non-decreasing, the segment is sorted, and its items are in input order. If the run is strictly decreasing, its items are pairwise different in key, so after the reversal the segment is sorted and has no two equal items, and stability holds trivially.
Lemma 2 (binary insertion sort). If is sorted stably and the items of come after it in the input, then after BINARY-INSERTION-SORT the segment is sorted stably.
Proof. For each from to , the binary search finds the least index with in the sorted prefix, so the new item goes after all items with key at most its key, in particular after its equal items, which are earlier in the input. The prefix stays sorted stably.
Lemma 3 (gallop searches). For a sorted segment , GALLOP-LEFT returns the number of its items less than the key, and GALLOP-RIGHT the number of its items at most the key, for each hint in .
Proof. The exponential phase keeps and for the relevant order ( is and is for GALLOP-LEFT; is and is for GALLOP-RIGHT), with and standing for the two ends. The binary phase keeps the same relation and halves until they meet. The index where they meet is the boundary between the items that are the key and the rest, which is the claimed count.
Lemma 4 (merge). Let and be neighbouring runs, each sorted stably, with every item of the first earlier in the input than every item of the second. Then after MERGE-AT, is sorted stably.
Proof. By Lemma 3, the first items of the first run are at most the first item of the second run, so they are in their final places and come before all equal items of the second run, which is right for stability. In the same way, the items of the second run that are at least the last item of the first run, and so not less than any item of the first run, are in their final places. Ties between such an item and the last item of the first run put the first-run item first, which is again right. It remains to merge the middle parts.
For MERGE-LO, the invariant of the main loops is: holds the items that come first in the stable order among the items of both middle parts, in that order; the rest are and ; and , so no item is overwritten before it is read. A step of one item at a time takes only if , and otherwise , so the item that comes first in the stable order is output, and a tie goes to the first run. In galloping mode, GALLOP-RIGHT returns the number of items of at most ; these all come before in the stable order, and they are copied in order. Then is the next item, because , if any, is greater than it. GALLOP-LEFT returns the number of items of less than , which come before it; then is next. Each step keeps the invariant. When one part is empty, the rest of , if any, is copied to the end, and the rest of the second run, if any, is already in place. MERGE-HI is the mirror image: it fills the segment from the right, outputs at each step the item that comes last in the stable order, takes the item of the first run only if the buffer item is less than it, so that a tie puts the second-run item last, and uses the two gallops with the roles exchanged.
Theorem. After TIMSORT, the array is sorted stably.
Proof. Invariant of the loop of line L3: the runs on the stack are, from the bottom, consecutive segments that cover , each sorted stably, and is unchanged. Line L4 and Lemma 1, and then line L5 and Lemma 2, give a new run at that is sorted stably, and line L6 pushes it. Each merge of line L7 joins two neighbouring runs of the stack; by Lemma 4 the result is sorted stably, and it covers the same segment. So the invariant holds after each step. Each step increases by at least 1, so the loop ends with . Line L8 then merges neighbours until one run covers , and by Lemma 4 it is sorted stably.
The depth of the stack. If the invariants , and hold for each four consecutive runs from the top, then, from the top, the -th run has length at least the -th Fibonacci number , up to the run on top. Since grows as and the lengths sum to at most , the stack holds runs. The check of four runs in merge_collapse is what makes the invariant hold for the whole stack, and not only at the top.