Replacing merge
and mergeSort
at runtime with tail-recursive and faster versions. #
We replace merge
with mergeTR
using a @[csimp]
lemma.
We replace mergeSort
in two steps:
- first with
mergeSortTR
, which while not tail-recursive itself (it can't be), usesmergeTR
internally. - second with
mergeSortTR₂
, which achieves an ~20% speed-up overmergeSortTR
by avoiding some unnecessary list reversals.
There is no public API in this file; it solely exists to implement the @[csimp]
lemmas
affecting runtime behaviour.
Future work #
The current runtime implementation could be further improved in a number of ways, e.g.:
- only walking the list once during splitting,
- using insertion sort for small chunks rather than splitting all the way down to singletons,
- identifying already sorted or reverse sorted chunks and skipping them.
Because the theory developed for mergeSort
is independent of the runtime implementation,
as long as such improvements are carefully validated by benchmarking,
they can be done without changing the theory, as long as a @[csimp]
lemma is provided.
O(min |l| |r|)
. Merge two lists using le
as a switch.
Equations
- List.MergeSort.Internal.mergeTR le l₁ l₂ = List.MergeSort.Internal.mergeTR.go le l₁ l₂ []
Instances For
Equations
- One or more equations did not get rendered due to their size.
- List.MergeSort.Internal.mergeTR.go le [] x✝ x = x.reverseAux x✝
- List.MergeSort.Internal.mergeTR.go le x✝ [] x = x.reverseAux x✝
Instances For
Variant of splitAt
, that does not reverse the first list, i.e
splitRevAt n l = ((l.take n).reverse, l.drop n)
.
This exists solely as an optimization for mergeSortTR
and mergeSortTR₂
,
and should not be used elsewhere.
Equations
Instances For
Auxiliary for splitAtRev
: splitAtRev.go xs n acc = ((take n xs).reverse ++ acc, drop n xs)
.
Equations
- List.MergeSort.Internal.splitRevAt.go (x_3 :: xs) n.succ x = List.MergeSort.Internal.splitRevAt.go xs n (x_3 :: x)
- List.MergeSort.Internal.splitRevAt.go x✝¹ x✝ x = (x, x✝¹)
Instances For
An intermediate speed-up for mergeSort
.
This version uses the tail-recurive mergeTR
function as a subroutine.
This is not the final version we use at runtime, as mergeSortTR₂
is faster.
This definition is useful as an intermediate step in proving the @[csimp]
lemma for mergeSortTR₂
.
Equations
Instances For
Equations
- One or more equations did not get rendered due to their size.
- List.MergeSort.Internal.mergeSortTR.run le ⟨[], property⟩ = []
- List.MergeSort.Internal.mergeSortTR.run le ⟨[a], property⟩ = [a]
Instances For
Split a list in two equal parts, reversing the first part. If the length is odd, the first part will be one element longer.
Equations
- List.MergeSort.Internal.splitRevInTwo l = (⟨(List.MergeSort.Internal.splitRevAt ((n + 1) / 2) l.val).fst, ⋯⟩, ⟨(List.MergeSort.Internal.splitRevAt ((n + 1) / 2) l.val).snd, ⋯⟩)
Instances For
Split a list in two equal parts, reversing the first part. If the length is odd, the second part will be one element longer.
Equations
- List.MergeSort.Internal.splitRevInTwo' l = (⟨(List.MergeSort.Internal.splitRevAt (n / 2) l.val).fst, ⋯⟩, ⟨(List.MergeSort.Internal.splitRevAt (n / 2) l.val).snd, ⋯⟩)
Instances For
Equations
- One or more equations did not get rendered due to their size.
- List.MergeSort.Internal.mergeSortTR₂.run le ⟨[], property⟩ = []
- List.MergeSort.Internal.mergeSortTR₂.run le ⟨[a], property⟩ = [a]
Instances For
Equations
- One or more equations did not get rendered due to their size.
- List.MergeSort.Internal.mergeSortTR₂.run' le ⟨[], property⟩ = []
- List.MergeSort.Internal.mergeSortTR₂.run' le ⟨[a], property⟩ = [a]