l3lab/ntp-mathlib huggingface dataset:
theorem Sorted.orderedInsert (a : α) : ∀ l, Sorted r l → Sorted r (orderedInsert r a l)
  | [], _ => sorted_singleton a
  | b :: l, h => by
    by_cases h' : a ≼ b
    · -- Porting note: was
      -- `simpa [orderedInsert, h', h] using fun b' bm => trans h' (rel_of_sorted_cons h _ bm)`
      rw [List.orderedInsert, if_pos h', sorted_cons]
      

Proof state:
case pos
α : Type uu
r : α → α → Prop
inst✝² : DecidableRel r
inst✝¹ : IsTotal α r
inst✝ : IsTrans α r
a b : α
l : List α
h : Sorted r (b :: l)
h' : r a b
⊢ (∀ b_1 ∈ b :: l, r a b_1) ∧ Sorted r (b :: l)

Next tactic:
exact ⟨forall_mem_cons.2 ⟨h', fun c hc => _root_.trans h' (rel_of_sorted_cons h _ hc)⟩, h⟩
theorem Sorted.orderedInsert (a : α) : ∀ l, Sorted r l → Sorted r (orderedInsert r a l)
  | [], _ => sorted_singleton a
  | b :: l, h => by
    by_cases h' : a ≼ b
    · -- Porting note: was
      -- `simpa [orderedInsert, h', h] using fun b' bm => trans h' (rel_of_sorted_cons h _ bm)`
      rw [List.orderedInsert, if_pos h', sorted_cons]
      exact ⟨forall_mem_cons.2 ⟨h', fun c hc => _root_.trans h' (rel_of_sorted_cons h _ hc)⟩, h⟩
    · 

Proof state:
case neg
α : Type uu
r : α → α → Prop
inst✝² : DecidableRel r
inst✝¹ : IsTotal α r
inst✝ : IsTrans α r
a b : α
l : List α
h : Sorted r (b :: l)
h' : ¬r a b
⊢ Sorted r (List.orderedInsert r a (b :: l))

Next tactic:
suffices ∀ b' : α, b' ∈ List.orderedInsert r a l → r b b' by
        simpa [orderedInsert, h', h.of_cons.orderedInsert a l]
theorem Sorted.orderedInsert (a : α) : ∀ l, Sorted r l → Sorted r (orderedInsert r a l)
  | [], _ => sorted_singleton a
  | b :: l, h => by
    by_cases h' : a ≼ b
    · -- Porting note: was
      -- `simpa [orderedInsert, h', h] using fun b' bm => trans h' (rel_of_sorted_cons h _ bm)`
      rw [List.orderedInsert, if_pos h', sorted_cons]
      exact ⟨forall_mem_cons.2 ⟨h', fun c hc => _root_.trans h' (rel_of_sorted_cons h _ hc)⟩, h⟩
    · suffices ∀ b' : α, b' ∈ List.orderedInsert r a l → r b b' by
        

Proof state:
α : Type uu
r : α → α → Prop
inst✝² : DecidableRel r
inst✝¹ : IsTotal α r
inst✝ : IsTrans α r
a b : α
l : List α
h : Sorted r (b :: l)
h' : ¬r a b
this : ∀ b' ∈ List.orderedInsert r a l, r b b'
⊢ Sorted r (List.orderedInsert r a (b :: l))

Next tactic:
simpa [orderedInsert, h', h.of_cons.orderedInsert a l]
theorem Sorted.orderedInsert (a : α) : ∀ l, Sorted r l → Sorted r (orderedInsert r a l)
  | [], _ => sorted_singleton a
  | b :: l, h => by
    by_cases h' : a ≼ b
    · -- Porting note: was
      -- `simpa [orderedInsert, h', h] using fun b' bm => trans h' (rel_of_sorted_cons h _ bm)`
      rw [List.orderedInsert, if_pos h', sorted_cons]
      exact ⟨forall_mem_cons.2 ⟨h', fun c hc => _root_.trans h' (rel_of_sorted_cons h _ hc)⟩, h⟩
    · suffices ∀ b' : α, b' ∈ List.orderedInsert r a l → r b b' by
        simpa [orderedInsert, h', h.of_cons.orderedInsert a l]
      

Proof state:
case neg
α : Type uu
r : α → α → Prop
inst✝² : DecidableRel r
inst✝¹ : IsTotal α r
inst✝ : IsTrans α r
a b : α
l : List α
h : Sorted r (b :: l)
h' : ¬r a b
⊢ ∀ b' ∈ List.orderedInsert r a l, r b b'

Next tactic:
intro b' bm
theorem Sorted.orderedInsert (a : α) : ∀ l, Sorted r l → Sorted r (orderedInsert r a l)
  | [], _ => sorted_singleton a
  | b :: l, h => by
    by_cases h' : a ≼ b
    · -- Porting note: was
      -- `simpa [orderedInsert, h', h] using fun b' bm => trans h' (rel_of_sorted_cons h _ bm)`
      rw [List.orderedInsert, if_pos h', sorted_cons]
      exact ⟨forall_mem_cons.2 ⟨h', fun c hc => _root_.trans h' (rel_of_sorted_cons h _ hc)⟩, h⟩
    · suffices ∀ b' : α, b' ∈ List.orderedInsert r a l → r b b' by
        simpa [orderedInsert, h', h.of_cons.orderedInsert a l]
      intro b' bm
      

Proof state:
case neg
α : Type uu
r : α → α → Prop
inst✝² : DecidableRel r
inst✝¹ : IsTotal α r
inst✝ : IsTrans α r
a b : α
l : List α
h : Sorted r (b :: l)
h' : ¬r a b
b' : α
bm : b' ∈ List.orderedInsert r a l
⊢ r b b'

Next tactic:
cases' show b' = a ∨ b' ∈ l by simpa using (perm_orderedInsert _ _ _).subset bm with be bm
theorem Sorted.orderedInsert (a : α) : ∀ l, Sorted r l → Sorted r (orderedInsert r a l)
  | [], _ => sorted_singleton a
  | b :: l, h => by
    by_cases h' : a ≼ b
    · -- Porting note: was
      -- `simpa [orderedInsert, h', h] using fun b' bm => trans h' (rel_of_sorted_cons h _ bm)`
      rw [List.orderedInsert, if_pos h', sorted_cons]
      exact ⟨forall_mem_cons.2 ⟨h', fun c hc => _root_.trans h' (rel_of_sorted_cons h _ hc)⟩, h⟩
    · suffices ∀ b' : α, b' ∈ List.orderedInsert r a l → r b b' by
        simpa [orderedInsert, h', h.of_cons.orderedInsert a l]
      intro b' bm
      cases' show b' = a ∨ b' ∈ l by 

Proof state:
α : Type uu
r : α → α → Prop
inst✝² : DecidableRel r
inst✝¹ : IsTotal α r
inst✝ : IsTrans α r
a b : α
l : List α
h : Sorted r (b :: l)
h' : ¬r a b
b' : α
bm : b' ∈ List.orderedInsert r a l
⊢ b' = a ∨ b' ∈ l

Next tactic:
simpa using (perm_orderedInsert _ _ _).subset bm
theorem Sorted.orderedInsert (a : α) : ∀ l, Sorted r l → Sorted r (orderedInsert r a l)
  | [], _ => sorted_singleton a
  | b :: l, h => by
    by_cases h' : a ≼ b
    · -- Porting note: was
      -- `simpa [orderedInsert, h', h] using fun b' bm => trans h' (rel_of_sorted_cons h _ bm)`
      rw [List.orderedInsert, if_pos h', sorted_cons]
      exact ⟨forall_mem_cons.2 ⟨h', fun c hc => _root_.trans h' (rel_of_sorted_cons h _ hc)⟩, h⟩
    · suffices ∀ b' : α, b' ∈ List.orderedInsert r a l → r b b' by
        simpa [orderedInsert, h', h.of_cons.orderedInsert a l]
      intro b' bm
      cases' show b' = a ∨ b' ∈ l by simpa using (perm_orderedInsert _ _ _).subset bm with be bm
      · 

Proof state:
case neg.inl
α : Type uu
r : α → α → Prop
inst✝² : DecidableRel r
inst✝¹ : IsTotal α r
inst✝ : IsTrans α r
a b : α
l : List α
h : Sorted r (b :: l)
h' : ¬r a b
b' : α
bm : b' ∈ List.orderedInsert r a l
be : b' = a
⊢ r b b'

Next tactic:
subst b'
theorem Sorted.orderedInsert (a : α) : ∀ l, Sorted r l → Sorted r (orderedInsert r a l)
  | [], _ => sorted_singleton a
  | b :: l, h => by
    by_cases h' : a ≼ b
    · -- Porting note: was
      -- `simpa [orderedInsert, h', h] using fun b' bm => trans h' (rel_of_sorted_cons h _ bm)`
      rw [List.orderedInsert, if_pos h', sorted_cons]
      exact ⟨forall_mem_cons.2 ⟨h', fun c hc => _root_.trans h' (rel_of_sorted_cons h _ hc)⟩, h⟩
    · suffices ∀ b' : α, b' ∈ List.orderedInsert r a l → r b b' by
        simpa [orderedInsert, h', h.of_cons.orderedInsert a l]
      intro b' bm
      cases' show b' = a ∨ b' ∈ l by simpa using (perm_orderedInsert _ _ _).subset bm with be bm
      · subst b'
        

Proof state:
case neg.inl
α : Type uu
r : α → α → Prop
inst✝² : DecidableRel r
inst✝¹ : IsTotal α r
inst✝ : IsTrans α r
a b : α
l : List α
h : Sorted r (b :: l)
h' : ¬r a b
bm : a ∈ List.orderedInsert r a l
⊢ r b a

Next tactic:
exact (total_of r _ _).resolve_left h'
theorem Sorted.orderedInsert (a : α) : ∀ l, Sorted r l → Sorted r (orderedInsert r a l)
  | [], _ => sorted_singleton a
  | b :: l, h => by
    by_cases h' : a ≼ b
    · -- Porting note: was
      -- `simpa [orderedInsert, h', h] using fun b' bm => trans h' (rel_of_sorted_cons h _ bm)`
      rw [List.orderedInsert, if_pos h', sorted_cons]
      exact ⟨forall_mem_cons.2 ⟨h', fun c hc => _root_.trans h' (rel_of_sorted_cons h _ hc)⟩, h⟩
    · suffices ∀ b' : α, b' ∈ List.orderedInsert r a l → r b b' by
        simpa [orderedInsert, h', h.of_cons.orderedInsert a l]
      intro b' bm
      cases' show b' = a ∨ b' ∈ l by simpa using (perm_orderedInsert _ _ _).subset bm with be bm
      · subst b'
        exact (total_of r _ _).resolve_left h'
      · 

Proof state:
case neg.inr
α : Type uu
r : α → α → Prop
inst✝² : DecidableRel r
inst✝¹ : IsTotal α r
inst✝ : IsTrans α r
a b : α
l : List α
h : Sorted r (b :: l)
h' : ¬r a b
b' : α
bm✝ : b' ∈ List.orderedInsert r a l
bm : b' ∈ l
⊢ r b b'

Next tactic:
exact rel_of_sorted_cons h _ bm
theorem split_cons_of_eq (a : α) {l l₁ l₂ : List α} (h : split l = (l₁, l₂)) :
    split (a :: l) = (a :: l₂, l₁) := by 

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l l₁ l₂ : List α
h : split l = (l₁, l₂)
⊢ split (a :: l) = (a :: l₂, l₁)

Next tactic:
rw [split, h]
theorem length_split_le :
    ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → length l₁ ≤ length l ∧ length l₂ ≤ length l
  | [], _, _, rfl => ⟨Nat.le_refl 0, Nat.le_refl 0⟩
  | a :: l, l₁', l₂', h => by
    

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l l₁' l₂' : List α
h : split (a :: l) = (l₁', l₂')
⊢ length l₁' ≤ length (a :: l) ∧ length l₂' ≤ length (a :: l)

Next tactic:
cases' e : split l with l₁ l₂
theorem length_split_le :
    ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → length l₁ ≤ length l ∧ length l₂ ≤ length l
  | [], _, _, rfl => ⟨Nat.le_refl 0, Nat.le_refl 0⟩
  | a :: l, l₁', l₂', h => by
    cases' e : split l with l₁ l₂
    

Proof state:
case mk
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l l₁' l₂' : List α
h : split (a :: l) = (l₁', l₂')
l₁ l₂ : List α
e : split l = (l₁, l₂)
⊢ length l₁' ≤ length (a :: l) ∧ length l₂' ≤ length (a :: l)

Next tactic:
injection (split_cons_of_eq _ e).symm.trans h
theorem length_split_le :
    ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → length l₁ ≤ length l ∧ length l₂ ≤ length l
  | [], _, _, rfl => ⟨Nat.le_refl 0, Nat.le_refl 0⟩
  | a :: l, l₁', l₂', h => by
    cases' e : split l with l₁ l₂
    injection (split_cons_of_eq _ e).symm.trans h; 

Proof state:
case mk
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l l₁' l₂' : List α
h : split (a :: l) = (l₁', l₂')
l₁ l₂ : List α
e : split l = (l₁, l₂)
fst_eq✝ : a :: l₂ = l₁'
snd_eq✝ : l₁ = l₂'
⊢ length l₁' ≤ length (a :: l) ∧ length l₂' ≤ length (a :: l)

Next tactic:
substs l₁' l₂'
theorem length_split_le :
    ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → length l₁ ≤ length l ∧ length l₂ ≤ length l
  | [], _, _, rfl => ⟨Nat.le_refl 0, Nat.le_refl 0⟩
  | a :: l, l₁', l₂', h => by
    cases' e : split l with l₁ l₂
    injection (split_cons_of_eq _ e).symm.trans h; substs l₁' l₂'
    

Proof state:
case mk
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l l₁ l₂ : List α
e : split l = (l₁, l₂)
h : split (a :: l) = (a :: l₂, l₁)
⊢ length (a :: l₂) ≤ length (a :: l) ∧ length l₁ ≤ length (a :: l)

Next tactic:
cases' length_split_le e with h₁ h₂
theorem length_split_le :
    ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → length l₁ ≤ length l ∧ length l₂ ≤ length l
  | [], _, _, rfl => ⟨Nat.le_refl 0, Nat.le_refl 0⟩
  | a :: l, l₁', l₂', h => by
    cases' e : split l with l₁ l₂
    injection (split_cons_of_eq _ e).symm.trans h; substs l₁' l₂'
    cases' length_split_le e with h₁ h₂
    

Proof state:
case mk.intro
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l l₁ l₂ : List α
e : split l = (l₁, l₂)
h : split (a :: l) = (a :: l₂, l₁)
h₁ : length l₁ ≤ length l
h₂ : length l₂ ≤ length l
⊢ length (a :: l₂) ≤ length (a :: l) ∧ length l₁ ≤ length (a :: l)

Next tactic:
exact ⟨Nat.succ_le_succ h₂, Nat.le_succ_of_le h₁⟩
theorem length_split_lt {a b} {l l₁ l₂ : List α} (h : split (a :: b :: l) = (l₁, l₂)) :
    length l₁ < length (a :: b :: l) ∧ length l₂ < length (a :: b :: l) := by
  

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l l₁ l₂ : List α
h : split (a :: b :: l) = (l₁, l₂)
⊢ length l₁ < length (a :: b :: l) ∧ length l₂ < length (a :: b :: l)

Next tactic:
cases' e : split l with l₁' l₂'
theorem length_split_lt {a b} {l l₁ l₂ : List α} (h : split (a :: b :: l) = (l₁, l₂)) :
    length l₁ < length (a :: b :: l) ∧ length l₂ < length (a :: b :: l) := by
  cases' e : split l with l₁' l₂'
  

Proof state:
case mk
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l l₁ l₂ : List α
h : split (a :: b :: l) = (l₁, l₂)
l₁' l₂' : List α
e : split l = (l₁', l₂')
⊢ length l₁ < length (a :: b :: l) ∧ length l₂ < length (a :: b :: l)

Next tactic:
injection (split_cons_of_eq _ (split_cons_of_eq _ e)).symm.trans h
theorem length_split_lt {a b} {l l₁ l₂ : List α} (h : split (a :: b :: l) = (l₁, l₂)) :
    length l₁ < length (a :: b :: l) ∧ length l₂ < length (a :: b :: l) := by
  cases' e : split l with l₁' l₂'
  injection (split_cons_of_eq _ (split_cons_of_eq _ e)).symm.trans h; 

Proof state:
case mk
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l l₁ l₂ : List α
h : split (a :: b :: l) = (l₁, l₂)
l₁' l₂' : List α
e : split l = (l₁', l₂')
fst_eq✝ : a :: l₁' = l₁
snd_eq✝ : b :: l₂' = l₂
⊢ length l₁ < length (a :: b :: l) ∧ length l₂ < length (a :: b :: l)

Next tactic:
substs l₁ l₂
theorem length_split_lt {a b} {l l₁ l₂ : List α} (h : split (a :: b :: l) = (l₁, l₂)) :
    length l₁ < length (a :: b :: l) ∧ length l₂ < length (a :: b :: l) := by
  cases' e : split l with l₁' l₂'
  injection (split_cons_of_eq _ (split_cons_of_eq _ e)).symm.trans h; substs l₁ l₂
  

Proof state:
case mk
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l l₁' l₂' : List α
e : split l = (l₁', l₂')
h : split (a :: b :: l) = (a :: l₁', b :: l₂')
⊢ length (a :: l₁') < length (a :: b :: l) ∧ length (b :: l₂') < length (a :: b :: l)

Next tactic:
cases' length_split_le e with h₁ h₂
theorem length_split_lt {a b} {l l₁ l₂ : List α} (h : split (a :: b :: l) = (l₁, l₂)) :
    length l₁ < length (a :: b :: l) ∧ length l₂ < length (a :: b :: l) := by
  cases' e : split l with l₁' l₂'
  injection (split_cons_of_eq _ (split_cons_of_eq _ e)).symm.trans h; substs l₁ l₂
  cases' length_split_le e with h₁ h₂
  

Proof state:
case mk.intro
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l l₁' l₂' : List α
e : split l = (l₁', l₂')
h : split (a :: b :: l) = (a :: l₁', b :: l₂')
h₁ : length l₁' ≤ length l
h₂ : length l₂' ≤ length l
⊢ length (a :: l₁') < length (a :: b :: l) ∧ length (b :: l₂') < length (a :: b :: l)

Next tactic:
exact ⟨Nat.succ_le_succ (Nat.succ_le_succ h₁), Nat.succ_le_succ (Nat.succ_le_succ h₂)⟩
theorem perm_split : ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → l ~ l₁ ++ l₂
  | [], _, _, rfl => Perm.refl _
  | a :: l, l₁', l₂', h => by
    

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l l₁' l₂' : List α
h : split (a :: l) = (l₁', l₂')
⊢ a :: l ~ l₁' ++ l₂'

Next tactic:
cases' e : split l with l₁ l₂
theorem perm_split : ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → l ~ l₁ ++ l₂
  | [], _, _, rfl => Perm.refl _
  | a :: l, l₁', l₂', h => by
    cases' e : split l with l₁ l₂
    

Proof state:
case mk
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l l₁' l₂' : List α
h : split (a :: l) = (l₁', l₂')
l₁ l₂ : List α
e : split l = (l₁, l₂)
⊢ a :: l ~ l₁' ++ l₂'

Next tactic:
injection (split_cons_of_eq _ e).symm.trans h
theorem perm_split : ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → l ~ l₁ ++ l₂
  | [], _, _, rfl => Perm.refl _
  | a :: l, l₁', l₂', h => by
    cases' e : split l with l₁ l₂
    injection (split_cons_of_eq _ e).symm.trans h; 

Proof state:
case mk
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l l₁' l₂' : List α
h : split (a :: l) = (l₁', l₂')
l₁ l₂ : List α
e : split l = (l₁, l₂)
fst_eq✝ : a :: l₂ = l₁'
snd_eq✝ : l₁ = l₂'
⊢ a :: l ~ l₁' ++ l₂'

Next tactic:
substs l₁' l₂'
theorem perm_split : ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → l ~ l₁ ++ l₂
  | [], _, _, rfl => Perm.refl _
  | a :: l, l₁', l₂', h => by
    cases' e : split l with l₁ l₂
    injection (split_cons_of_eq _ e).symm.trans h; substs l₁' l₂'
    

Proof state:
case mk
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l l₁ l₂ : List α
e : split l = (l₁, l₂)
h : split (a :: l) = (a :: l₂, l₁)
⊢ a :: l ~ a :: l₂ ++ l₁

Next tactic:
exact ((perm_split e).trans perm_append_comm).cons a
/-- Implementation of a merge sort algorithm to sort a list. -/
def mergeSort : List α → List α
  | [] => []
  | [a] => [a]
  | a :: b :: l => by
    -- Porting note: rewrote to make `mergeSort_cons_cons` proof easier
    

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l : List α
⊢ List α

Next tactic:
let ls := (split (a :: b :: l))
/-- Implementation of a merge sort algorithm to sort a list. -/
def mergeSort : List α → List α
  | [] => []
  | [a] => [a]
  | a :: b :: l => by
    -- Porting note: rewrote to make `mergeSort_cons_cons` proof easier
    let ls := (split (a :: b :: l))
    

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l : List α
ls : List α × List α := split (a :: b :: l)
⊢ List α

Next tactic:
have e : split (a :: b :: l) = ⟨ls.1, ls.2⟩ := rfl
/-- Implementation of a merge sort algorithm to sort a list. -/
def mergeSort : List α → List α
  | [] => []
  | [a] => [a]
  | a :: b :: l => by
    -- Porting note: rewrote to make `mergeSort_cons_cons` proof easier
    let ls := (split (a :: b :: l))
    have e : split (a :: b :: l) = ⟨ls.1, ls.2⟩ := rfl
    

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l : List α
ls : List α × List α := split (a :: b :: l)
e : split (a :: b :: l) = (ls.1, ls.2)
⊢ List α

Next tactic:
have h := length_split_lt e
/-- Implementation of a merge sort algorithm to sort a list. -/
def mergeSort : List α → List α
  | [] => []
  | [a] => [a]
  | a :: b :: l => by
    -- Porting note: rewrote to make `mergeSort_cons_cons` proof easier
    let ls := (split (a :: b :: l))
    have e : split (a :: b :: l) = ⟨ls.1, ls.2⟩ := rfl
    have h := length_split_lt e
    

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l : List α
ls : List α × List α := split (a :: b :: l)
e : split (a :: b :: l) = (ls.1, ls.2)
h : length ls.1 < length (a :: b :: l) ∧ length ls.2 < length (a :: b :: l)
⊢ List α

Next tactic:
have := h.1
/-- Implementation of a merge sort algorithm to sort a list. -/
def mergeSort : List α → List α
  | [] => []
  | [a] => [a]
  | a :: b :: l => by
    -- Porting note: rewrote to make `mergeSort_cons_cons` proof easier
    let ls := (split (a :: b :: l))
    have e : split (a :: b :: l) = ⟨ls.1, ls.2⟩ := rfl
    have h := length_split_lt e
    have := h.1
    

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l : List α
ls : List α × List α := split (a :: b :: l)
e : split (a :: b :: l) = (ls.1, ls.2)
h : length ls.1 < length (a :: b :: l) ∧ length ls.2 < length (a :: b :: l)
this : length ls.1 < length (a :: b :: l)
⊢ List α

Next tactic:
have := h.2
/-- Implementation of a merge sort algorithm to sort a list. -/
def mergeSort : List α → List α
  | [] => []
  | [a] => [a]
  | a :: b :: l => by
    -- Porting note: rewrote to make `mergeSort_cons_cons` proof easier
    let ls := (split (a :: b :: l))
    have e : split (a :: b :: l) = ⟨ls.1, ls.2⟩ := rfl
    have h := length_split_lt e
    have := h.1
    have := h.2
    

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l : List α
ls : List α × List α := split (a :: b :: l)
e : split (a :: b :: l) = (ls.1, ls.2)
h : length ls.1 < length (a :: b :: l) ∧ length ls.2 < length (a :: b :: l)
this✝ : length ls.1 < length (a :: b :: l)
this : length ls.2 < length (a :: b :: l)
⊢ List α

Next tactic:
exact merge r (mergeSort ls.1) (mergeSort ls.2)
@[nolint unusedHavesSuffices] --Porting note: false positive
theorem mergeSort_cons_cons {a b} {l l₁ l₂ : List α} (h : split (a :: b :: l) = (l₁, l₂)) :
    mergeSort r (a :: b :: l) = merge r (mergeSort r l₁) (mergeSort r l₂) := by
  

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l l₁ l₂ : List α
h : split (a :: b :: l) = (l₁, l₂)
⊢ mergeSort r (a :: b :: l) = merge r (mergeSort r l₁) (mergeSort r l₂)

Next tactic:
simp only [mergeSort, h]
theorem perm_merge : ∀ l l' : List α, merge r l l' ~ l ++ l'
  | [], [] => by 

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
⊢ merge r [] [] ~ [] ++ []

Next tactic:
simp [merge]
theorem perm_merge : ∀ l l' : List α, merge r l l' ~ l ++ l'
  | [], [] => by simp [merge]
  | [], b :: l' => by 

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
b : α
l' : List α
⊢ merge r [] (b :: l') ~ [] ++ b :: l'

Next tactic:
simp [merge]
theorem perm_merge : ∀ l l' : List α, merge r l l' ~ l ++ l'
  | [], [] => by simp [merge]
  | [], b :: l' => by simp [merge]
  | a :: l, [] => by 

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l : List α
⊢ merge r (a :: l) [] ~ a :: l ++ []

Next tactic:
simp [merge]
theorem perm_merge : ∀ l l' : List α, merge r l l' ~ l ++ l'
  | [], [] => by simp [merge]
  | [], b :: l' => by simp [merge]
  | a :: l, [] => by simp [merge]
  | a :: l, b :: l' => by
    

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l : List α
b : α
l' : List α
⊢ merge r (a :: l) (b :: l') ~ a :: l ++ b :: l'

Next tactic:
by_cases h : a ≼ b
theorem perm_merge : ∀ l l' : List α, merge r l l' ~ l ++ l'
  | [], [] => by simp [merge]
  | [], b :: l' => by simp [merge]
  | a :: l, [] => by simp [merge]
  | a :: l, b :: l' => by
    by_cases h : a ≼ b
    · 

Proof state:
case pos
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l : List α
b : α
l' : List α
h : r a b
⊢ merge r (a :: l) (b :: l') ~ a :: l ++ b :: l'

Next tactic:
simpa [merge, h] using perm_merge _ _
theorem perm_merge : ∀ l l' : List α, merge r l l' ~ l ++ l'
  | [], [] => by simp [merge]
  | [], b :: l' => by simp [merge]
  | a :: l, [] => by simp [merge]
  | a :: l, b :: l' => by
    by_cases h : a ≼ b
    · simpa [merge, h] using perm_merge _ _
    · 

Proof state:
case neg
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l : List α
b : α
l' : List α
h : ¬r a b
⊢ merge r (a :: l) (b :: l') ~ a :: l ++ b :: l'

Next tactic:
suffices b :: merge r (a :: l) l' ~ a :: (l ++ b :: l') by simpa [merge, h]
theorem perm_merge : ∀ l l' : List α, merge r l l' ~ l ++ l'
  | [], [] => by simp [merge]
  | [], b :: l' => by simp [merge]
  | a :: l, [] => by simp [merge]
  | a :: l, b :: l' => by
    by_cases h : a ≼ b
    · simpa [merge, h] using perm_merge _ _
    · suffices b :: merge r (a :: l) l' ~ a :: (l ++ b :: l') by 

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l : List α
b : α
l' : List α
h : ¬r a b
this : b :: merge r (a :: l) l' ~ a :: (l ++ b :: l')
⊢ merge r (a :: l) (b :: l') ~ a :: l ++ b :: l'

Next tactic:
simpa [merge, h]
theorem perm_merge : ∀ l l' : List α, merge r l l' ~ l ++ l'
  | [], [] => by simp [merge]
  | [], b :: l' => by simp [merge]
  | a :: l, [] => by simp [merge]
  | a :: l, b :: l' => by
    by_cases h : a ≼ b
    · simpa [merge, h] using perm_merge _ _
    · suffices b :: merge r (a :: l) l' ~ a :: (l ++ b :: l') by simpa [merge, h]
      

Proof state:
case neg
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
l : List α
b : α
l' : List α
h : ¬r a b
⊢ b :: merge r (a :: l) l' ~ a :: (l ++ b :: l')

Next tactic:
exact ((perm_merge _ _).cons _).trans ((swap _ _ _).trans (perm_middle.symm.cons _))
theorem perm_mergeSort : ∀ l : List α, mergeSort r l ~ l
  | [] => by 

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
⊢ mergeSort r [] ~ []

Next tactic:
simp [mergeSort]
theorem perm_mergeSort : ∀ l : List α, mergeSort r l ~ l
  | [] => by simp [mergeSort]
  | [a] => by 

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a : α
⊢ mergeSort r [a] ~ [a]

Next tactic:
simp [mergeSort]
theorem perm_mergeSort : ∀ l : List α, mergeSort r l ~ l
  | [] => by simp [mergeSort]
  | [a] => by simp [mergeSort]
  | a :: b :: l => by
    

Proof state:
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l : List α
⊢ mergeSort r (a :: b :: l) ~ a :: b :: l

Next tactic:
cases' e : split (a :: b :: l) with l₁ l₂
theorem perm_mergeSort : ∀ l : List α, mergeSort r l ~ l
  | [] => by simp [mergeSort]
  | [a] => by simp [mergeSort]
  | a :: b :: l => by
    cases' e : split (a :: b :: l) with l₁ l₂
    

Proof state:
case mk
α : Type uu
r : α → α → Prop
inst✝ : DecidableRel r
a b : α
l l₁ l₂ : List α
e : split (a :: b :: l) = (l₁, l₂)
⊢ mergeSort r (a :: b :: l) ~ a :: b :: l

Next tactic:
cases' length_split_lt e with h₁ h₂