Module docstring
{"# Definition of merge and mergeSort.
These definitions are intended for verification purposes,
and are replaced at runtime by efficient versions in Init.Data.List.Sort.Impl.
"}
{"# Definition of merge and mergeSort.
These definitions are intended for verification purposes,
and are replaced at runtime by efficient versions in Init.Data.List.Sort.Impl.
"}
List.nil_merge
      theorem
     (ys : List α) : merge [] ys le = ys
        
      List.merge_right
      theorem
     (xs : List α) : merge xs [] le = xs
        
      List.MergeSort.Internal.splitInTwo
      definition
     (l : { l : List α // l.length = n }) : { l : List α // l.length = (n + 1) / 2 } × { l : List α // l.length = n / 2 }
        /--
Split a list in two equal parts. If the length is odd, the first part will be one element longer.
This is an implementation detail of `mergeSort`.
-/
def MergeSort.Internal.splitInTwo (l : { l : List α // l.length = n }) :
    { l : List α // l.length = (n+1)/2 }{ l : List α // l.length = (n+1)/2 } × { l : List α // l.length = n/2 } :=
  let r := splitAt ((n+1)/2) l.1
  (⟨r.1, by simp [r, splitAt_eq, l.2]; omega⟩, ⟨r.2, by simp [r, splitAt_eq, l.2]; omega⟩)
        List.mergeSort
      definition
     : ∀ (xs : List α) (le : α → α → Bool := by exact fun a b => a ≤ b), List α
        /--
A stable merge sort.
This function is a simplified implementation that's designed to be easy to reason about, rather than
for efficiency. In particular, it uses the non-tail-recursive `List.merge` function and traverses
lists unnecessarily.
It is replaced at runtime by an efficient implementation that has been proven to be equivalent.
-/
-- Because we want the sort to be stable, it is essential that we split the list in two contiguous
-- sublists.
def mergeSort : ∀ (xs : List α) (le : α → α → Bool := by exact fun a b => a ≤ b), List α
  | [], _ => []
  | [a], _ => [a]
  | a :: b :: xs, le =>
    let lr := splitInTwo ⟨a :: b :: xs, rfl⟩
    have := by simpa using lr.2.2
    have := by simpa using lr.1.2
    merge (mergeSort lr.1 le) (mergeSort lr.2 le) le
termination_by xs => xs.length
        List.zipIdxLE
      definition
     (le : α → α → Bool) (a b : α × Nat) : Bool
        /--
Given an ordering relation `le : α → α → Bool`,
construct the lexicographic ordering on `α × Nat`.
which first compares the first components using `le`,
but if these are equivalent (in the sense `le a.2 b.2 && le b.2 a.2`)
then compares the second components using `≤`.
This function is only used in stating the stability properties of `mergeSort`.
-/
def zipIdxLE (le : α → α → Bool) (a b : α × Nat) : Bool :=
  if le a.1 b.1 then if le b.1 a.1 then a.2 ≤ b.2 else true else false