/- Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joseph Tooby-Smith -/ import HepLean.Mathematics.List.InsertIdx /-! # List lemmas -/ namespace HepLean.List open Fin open HepLean variable {n : Nat} lemma insertionSortMin_lt_length_succ {α : Type} (r : α → α → Prop) [DecidableRel r] (i : α) (l : List α) : insertionSortMinPos r i l < (insertionSortDropMinPos r i l).length.succ := by rw [insertionSortMinPos] simp only [List.length_cons, List.insertionSort.eq_2, insertionSortDropMinPos, Nat.succ_eq_add_one] rw [eraseIdx_length'] simp /-- Given a list `i :: l` the left-most minimal position `a` of `i :: l` wrt `r` as an element of `Fin (insertionSortDropMinPos r i l).length.succ`. -/ def insertionSortMinPosFin {α : Type} (r : α → α → Prop) [DecidableRel r] (i : α) (l : List α) : Fin (insertionSortDropMinPos r i l).length.succ := ⟨insertionSortMinPos r i l, insertionSortMin_lt_length_succ r i l⟩ lemma insertionSortMin_lt_mem_insertionSortDropMinPos {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a : α) (l : List α) (i : Fin (insertionSortDropMinPos r a l).length) : r (insertionSortMin r a l) ((insertionSortDropMinPos r a l)[i]) := by let l1 := List.insertionSort r (a :: l) have hl1 : l1.Sorted r := List.sorted_insertionSort r (a :: l) simp only [l1] at hl1 rw [insertionSort_eq_insertionSortMin_cons r a l] at hl1 simp only [List.sorted_cons, List.mem_insertionSort] at hl1 apply hl1.1 ((insertionSortDropMinPos r a l)[i]) simp lemma insertionSortMinPos_insertionSortEquiv {α : Type} (r : α → α → Prop) [DecidableRel r] (a : α) (l : List α) : insertionSortEquiv r (a ::l) (insertionSortMinPos r a l) = ⟨0, by simp [List.orderedInsert_length]⟩ := by rw [insertionSortMinPos] exact Equiv.apply_symm_apply (insertionSortEquiv r (a :: l)) ⟨0, insertionSortMinPos.proof_1 r a l⟩ lemma insertionSortEquiv_gt_zero_of_ne_insertionSortMinPos {α : Type} (r : α → α → Prop) [DecidableRel r] (a : α) (l : List α) (k : Fin (a :: l).length) (hk : k ≠ insertionSortMinPos r a l) : ⟨0, by simp [List.orderedInsert_length]⟩ < insertionSortEquiv r (a :: l) k := by by_contra hn simp only [List.insertionSort.eq_2, List.length_cons, not_lt] at hn refine hk ((Equiv.apply_eq_iff_eq_symm_apply (insertionSortEquiv r (a :: l))).mp ?_) simp_all only [List.length_cons, ne_eq, Fin.le_def, nonpos_iff_eq_zero, List.insertionSort.eq_2] simp only [Fin.ext_iff] omega lemma insertionSortMin_lt_mem_insertionSortDropMinPos_of_lt {α : Type} (r : α → α → Prop) [DecidableRel r] (a : α) (l : List α) (i : Fin (insertionSortDropMinPos r a l).length) (h : (insertionSortMinPosFin r a l).succAbove i < insertionSortMinPosFin r a l) : ¬ r ((insertionSortDropMinPos r a l)[i]) (insertionSortMin r a l) := by simp only [Fin.getElem_fin, insertionSortMin, List.get_eq_getElem, List.length_cons] have h1 : (insertionSortDropMinPos r a l)[i] = (a :: l).get (finCongr (eraseIdx_length_succ (a :: l) (insertionSortMinPos r a l)) ((insertionSortMinPosFin r a l).succAbove i)) := by trans (insertionSortDropMinPos r a l).get i simp only [Fin.getElem_fin, List.get_eq_getElem] simp only [insertionSortDropMinPos, List.length_cons, Nat.succ_eq_add_one, finCongr_apply, Fin.coe_cast] rw [eraseIdx_get] simp only [List.length_cons, Function.comp_apply, List.get_eq_getElem, Fin.coe_cast] rfl erw [h1] simp only [List.length_cons, Nat.succ_eq_add_one, List.get_eq_getElem, Fin.coe_cast] apply insertionSortEquiv_order simpa using h simp only [List.insertionSort.eq_2, List.length_cons, finCongr_apply] apply lt_of_eq_of_lt (insertionSortMinPos_insertionSortEquiv r a l) simp only [List.insertionSort.eq_2] apply insertionSortEquiv_gt_zero_of_ne_insertionSortMinPos r a l simp only [List.length_cons, ne_eq, Fin.ext_iff, Fin.coe_cast] have hl : (insertionSortMinPos r a l).val = (insertionSortMinPosFin r a l).val := by rfl simp only [hl, Nat.succ_eq_add_one, Fin.val_eq_val, ne_eq] exact Fin.succAbove_ne (insertionSortMinPosFin r a l) i lemma insertionSort_insertionSort {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (l1 : List α) : List.insertionSort r (List.insertionSort r l1) = List.insertionSort r l1 := by apply List.Sorted.insertionSort_eq exact List.sorted_insertionSort r l1 lemma orderedInsert_commute {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a b : α) (hr : ¬ r a b) : (l : List α) → List.orderedInsert r a (List.orderedInsert r b l) = List.orderedInsert r b (List.orderedInsert r a l) | [] => by have hrb : r b a := by have ht := IsTotal.total (r := r) a b simp_all simp [hr, hrb] | c :: l => by have hrb : r b a := by have ht := IsTotal.total (r := r) a b simp_all simp only [List.orderedInsert] by_cases h : r a c · simp only [h, ↓reduceIte, List.orderedInsert.eq_2, hrb] rw [if_pos] simp only [List.orderedInsert, hr, ↓reduceIte, h] exact IsTrans.trans (r :=r) _ _ _ hrb h · simp only [h, ↓reduceIte, List.orderedInsert.eq_2] by_cases hbc : r b c · simp [hbc, hr, h] · simp only [hbc, ↓reduceIte, List.orderedInsert.eq_2, h, List.cons.injEq, true_and] exact orderedInsert_commute r a b hr l lemma insertionSort_orderedInsert_append {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a : α) : (l1 l2 : List α) → List.insertionSort r (List.orderedInsert r a l1 ++ l2) = List.insertionSort r (a :: l1 ++ l2) | [], l2 => by simp | b :: l1, l2 => by conv_lhs => simp by_cases h : r a b · simp [h] conv_lhs => simp [h] rw [insertionSort_orderedInsert_append r a l1 l2] simp only [List.insertionSort, List.append_eq] rw [orderedInsert_commute r a b h] lemma insertionSort_insertionSort_append {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] : (l1 l2 : List α) → List.insertionSort r (List.insertionSort r l1 ++ l2) = List.insertionSort r (l1 ++ l2) | [], l2 => by simp | a :: l1, l2 => by conv_lhs => simp rw [insertionSort_orderedInsert_append] simp only [List.insertionSort, List.append_eq] rw [insertionSort_insertionSort_append r l1 l2] lemma insertionSort_append_insertionSort_append {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] : (l1 l2 l3 : List α) → List.insertionSort r (l1 ++ List.insertionSort r l2 ++ l3) = List.insertionSort r (l1 ++ l2 ++ l3) | [], l2, l3 => by simp only [List.nil_append] exact insertionSort_insertionSort_append r l2 l3 | a :: l1, l2, l3 => by simp only [List.insertionSort, List.append_eq] rw [insertionSort_append_insertionSort_append r l1 l2 l3] @[simp] lemma orderedInsert_length {α : Type} (r : α → α → Prop) [DecidableRel r] (a : α) (l : List α) : (List.orderedInsert r a l).length = (a :: l).length := by apply List.Perm.length_eq exact List.perm_orderedInsert r a l lemma takeWhile_orderedInsert {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a b : α) (hr : ¬ r a b) : (l : List α) → (List.takeWhile (fun c => !decide (r a c)) (List.orderedInsert r b l)).length = (List.takeWhile (fun c => !decide (r a c)) l).length + 1 | [] => by simp [hr] | c :: l => by simp only [List.orderedInsert] by_cases h : r b c · simp only [h, ↓reduceIte] rw [List.takeWhile_cons_of_pos] simp only [List.length_cons] simp [hr] · simp only [h, ↓reduceIte] have hrba : r b a:= by have ht := IsTotal.total (r := r) a b simp_all have hl : ¬ r a c := by by_contra hn apply h exact IsTrans.trans _ _ _ hrba hn simp only [hl, decide_false, Bool.not_false, List.takeWhile_cons_of_pos, List.length_cons, add_left_inj] exact takeWhile_orderedInsert r a b hr l lemma takeWhile_orderedInsert' {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a b : α) (hr : ¬ r a b) : (l : List α) → (List.takeWhile (fun c => !decide (r b c)) (List.orderedInsert r a l)).length = (List.takeWhile (fun c => !decide (r b c)) l).length | [] => by simp only [List.orderedInsert, List.takeWhile_nil, List.length_nil, List.length_eq_zero, List.takeWhile_eq_nil_iff, List.length_singleton, zero_lt_one, Fin.zero_eta, Fin.isValue, List.get_eq_getElem, Fin.val_eq_zero, List.getElem_cons_zero, Bool.not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not, Decidable.not_not, forall_const] have ht := IsTotal.total (r := r) a b simp_all | c :: l => by have hrba : r b a:= by have ht := IsTotal.total (r := r) a b simp_all simp only [List.orderedInsert] by_cases h : r b c · simp only [h, decide_true, Bool.not_true, Bool.false_eq_true, not_false_eq_true, List.takeWhile_cons_of_neg, List.length_nil, List.length_eq_zero, List.takeWhile_eq_nil_iff, List.get_eq_getElem, Bool.not_eq_eq_eq_not, decide_eq_false_iff_not, Decidable.not_not] by_cases hac : r a c · simp [hac, hrba] · simp [hac, h] · by_cases hac : r a c · refine False.elim (h ?_) exact IsTrans.trans _ _ _ hrba hac · simp only [hac, ↓reduceIte, h, decide_false, Bool.not_false, List.takeWhile_cons_of_pos, List.length_cons, add_left_inj] exact takeWhile_orderedInsert' r a b hr l lemma insertionSortEquiv_commute {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a b : α) (hr : ¬ r a b) (n : ℕ) : (l : List α) → (hn : n + 2 < (a :: b :: l).length) → insertionSortEquiv r (a :: b :: l) ⟨n + 2, hn⟩ = (finCongr (by simp)) (insertionSortEquiv r (b :: a :: l) ⟨n + 2, hn⟩) := by have hrba : r b a:= by have ht := IsTotal.total (r := r) a b simp_all intro l hn simp only [List.insertionSort, List.length_cons, insertionSortEquiv, Nat.succ_eq_add_one, equivCons_trans, Equiv.trans_apply, equivCons_succ, finCongr_apply] conv_lhs => erw [equivCons_succ] conv_rhs => erw [equivCons_succ] simp only [Equiv.toFun_as_coe] conv_lhs => rhs rhs erw [orderedInsertEquiv_succ] conv_lhs => erw [orderedInsertEquiv_fin_succ] simp only [Fin.eta, Fin.coe_cast] conv_rhs => rhs rhs erw [orderedInsertEquiv_succ] conv_rhs => erw [orderedInsertEquiv_fin_succ] ext simp only [Fin.coe_cast, Fin.eta, Fin.cast_trans] let a1 : Fin ((List.orderedInsert r b (List.insertionSort r l)).length + 1) := ⟨↑(orderedInsertPos r (List.orderedInsert r b (List.insertionSort r l)) a), orderedInsertPos_lt_length r (List.orderedInsert r b (List.insertionSort r l)) a⟩ let b1 : Fin ((List.insertionSort r l).length + 1) := ⟨↑(orderedInsertPos r (List.insertionSort r l) b), orderedInsertPos_lt_length r (List.insertionSort r l) b⟩ let a2 : Fin ((List.insertionSort r l).length + 1) := ⟨↑(orderedInsertPos r (List.insertionSort r l) a), orderedInsertPos_lt_length r (List.insertionSort r l) a⟩ let b2 : Fin ((List.orderedInsert r a (List.insertionSort r l)).length + 1) := ⟨↑(orderedInsertPos r (List.orderedInsert r a (List.insertionSort r l)) b), orderedInsertPos_lt_length r (List.orderedInsert r a (List.insertionSort r l)) b⟩ have ht : (List.takeWhile (fun c => !decide (r b c)) (List.insertionSort r l)) = (List.takeWhile (fun c => !decide (r b c)) ((List.takeWhile (fun c => !decide (r a c)) (List.insertionSort r l)))) := by rw [List.takeWhile_takeWhile] simp only [Bool.not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not, Bool.decide_and, decide_not] congr funext c simp only [Bool.iff_self_and, Bool.not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not] intro hbc hac refine hbc ?_ exact IsTrans.trans _ _ _ hrba hac have ha1 : b1.1 ≤ a2.1 := by simp only [orderedInsertPos, decide_not] rw [ht] apply List.Sublist.length_le exact List.takeWhile_sublist fun c => !decide (r b c) have ha2 : a1.1 = a2.1 + 1 := by simp only [orderedInsertPos, decide_not] rw [takeWhile_orderedInsert] exact hr have hb : b1.1 = b2.1 := by simp only [orderedInsertPos, decide_not] rw [takeWhile_orderedInsert'] exact hr let n := ((insertionSortEquiv r l) ⟨n, by simpa using hn⟩) change (a1.succAbove ⟨b1.succAbove n, _⟩).1 = (b2.succAbove ⟨a2.succAbove n, _⟩).1 trans if (b1.succAbove n).1 < a1.1 then (b1.succAbove n).1 else (b1.succAbove n).1 + 1 · rw [Fin.succAbove] simp only [Fin.castSucc_mk, Fin.lt_def, Fin.succ_mk] by_cases ha : (b1.succAbove n).1 < a1.1 · simp [ha] · simp [ha] trans if (a2.succAbove n).1 < b2.1 then (a2.succAbove n).1 else (a2.succAbove n).1 + 1 swap · conv_rhs => rw [Fin.succAbove] simp only [Fin.castSucc_mk, Fin.lt_def, Fin.succ_mk] by_cases ha : (a2.succAbove n).1 < b2.1 · simp [ha] · simp [ha] have hbs1 : (b1.succAbove n).1 = if n.1 < b1.1 then n.1 else n.1 + 1 := by rw [Fin.succAbove] simp only [Fin.castSucc_mk, Fin.lt_def, Fin.succ_mk] by_cases ha : n.1 < b1.1 · simp [ha] · simp [ha] have has2 : (a2.succAbove n).1 = if n.1 < a2.1 then n.1 else n.1 + 1 := by rw [Fin.succAbove] simp only [Fin.castSucc_mk, Fin.lt_def, Fin.succ_mk] by_cases ha : n.1 < a2.1 · simp [ha] · simp [ha] rw [hbs1, has2, hb, ha2] have hnat (a2 b2 n : ℕ) (h : b2 ≤ a2) : (if (if ↑n < ↑b2 then ↑n else ↑n + 1) < ↑a2 + 1 then if ↑n < ↑b2 then ↑n else ↑n + 1 else (if ↑n < ↑b2 then ↑n else ↑n + 1) + 1) = if (if ↑n < ↑a2 then ↑n else ↑n + 1) < ↑b2 then if ↑n < ↑a2 then ↑n else ↑n + 1 else (if ↑n < ↑a2 then ↑n else ↑n + 1) + 1 := by by_cases hnb2 : n < b2 · simp only [hnb2, ↓reduceIte] have h1 : n < a2 + 1 := by omega have h2 : n < a2 := by omega simp [h1, h2, hnb2] · simp only [hnb2, ↓reduceIte, add_lt_add_iff_right] by_cases ha2 : n < a2 · simp [ha2, hnb2] · simp only [ha2, ↓reduceIte] rw [if_neg] omega apply hnat rw [← hb] exact ha1 lemma insertionSortEquiv_orderedInsert_append {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a a2 : α) : (l1 l2 : List α) → (insertionSortEquiv r (List.orderedInsert r a l1 ++ a2 :: l2) ⟨l1.length + 1, by simp⟩) = (finCongr (by simp only [List.insertionSort, List.append_eq, orderedInsert_length, List.length_cons, List.length_insertionSort, List.length_append] omega)) ((insertionSortEquiv r (a :: l1 ++ a2 :: l2)) ⟨l1.length + 1, by simp⟩) | [], l2 => by simp | b :: l1, l2 => by by_cases h : r a b · have h1 : (List.orderedInsert r a (b :: l1) ++ a2 :: l2) = (a :: b :: l1 ++ a2 :: l2) := by simp [h] rw [insertionSortEquiv_congr _ _ h1] simp · have h1 : (List.orderedInsert r a (b :: l1) ++ a2 :: l2) = (b :: List.orderedInsert r a (l1) ++ a2 :: l2) := by simp [h] rw [insertionSortEquiv_congr _ _ h1] simp only [List.orderedInsert.eq_2, List.cons_append, List.length_cons, List.insertionSort, Equiv.trans_apply, RelIso.coe_fn_toEquiv, Fin.castOrderIso_apply, Fin.cast_mk, finCongr_apply] conv_lhs => simp [insertionSortEquiv] rw [insertionSortEquiv_orderedInsert_append r a] have hl : (List.insertionSort r (List.orderedInsert r a l1 ++ a2 :: l2)) = List.insertionSort r (a :: l1 ++ a2 :: l2) := by exact insertionSort_orderedInsert_append r a l1 (a2 :: l2) rw [orderedInsertEquiv_congr _ _ _ hl] simp only [List.length_cons, List.cons_append, List.insertionSort, finCongr_apply, Equiv.trans_apply, RelIso.coe_fn_toEquiv, Fin.castOrderIso_apply, Fin.cast_succ_eq, Fin.cast_trans, Fin.cast_eq_self] change Fin.cast _ ((insertionSortEquiv r (b :: a :: (l1 ++ a2 :: l2))) ⟨l1.length + 2, by simp⟩) = _ have hl : l1.length + 1 +1 = l1.length + 2 := by omega simp only [List.insertionSort, List.length_cons, hl] conv_rhs => erw [insertionSortEquiv_commute _ _ _ h _ _] simp lemma insertionSortEquiv_insertionSort_append {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a : α) : (l1 l2 : List α) → (insertionSortEquiv r (List.insertionSort r l1 ++ a :: l2) ⟨l1.length, by simp⟩) = finCongr (by simp) (insertionSortEquiv r (l1 ++ a :: l2) ⟨l1.length, by simp⟩) | [], l2 => by simp only [List.insertionSort, List.nil_append, List.length_cons, List.length_nil, Fin.zero_eta, finCongr_refl, Equiv.refl_apply] | b :: l1, l2 => by simp only [List.insertionSort, List.length_cons, List.cons_append, finCongr_apply] have hl := insertionSortEquiv_orderedInsert_append r b a (List.insertionSort r l1) l2 simp only [List.length_insertionSort, List.cons_append, List.insertionSort, List.length_cons, finCongr_apply] at hl rw [hl] have ih := insertionSortEquiv_insertionSort_append r a l1 l2 simp only [insertionSortEquiv, Nat.succ_eq_add_one, List.insertionSort, Equiv.trans_apply, equivCons_succ] rw [ih] have hl : (List.insertionSort r (List.insertionSort r l1 ++ a :: l2)) = (List.insertionSort r (l1 ++ a :: l2)) := by exact insertionSort_insertionSort_append r l1 (a :: l2) rw [orderedInsertEquiv_congr _ _ _ hl] simp /-! ## Insertion sort with equal fields -/ lemma orderedInsert_filter_of_pos {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTrans α r] (a : α) (p : α → Prop) [DecidablePred p] (h : p a) : (l : List α) → (hl : l.Sorted r) → List.filter p (List.orderedInsert r a l) = List.orderedInsert r a (List.filter p l) | [], hl => by simp only [List.orderedInsert, List.filter_eq_self, List.mem_singleton, decide_eq_true_eq, forall_eq] exact h | b :: l, hl => by simp only [List.orderedInsert] by_cases hpb : p b <;> by_cases hab : r a b · simp only [hab, ↓reduceIte, hpb, decide_true, List.filter_cons_of_pos, List.orderedInsert.eq_2] rw [List.filter_cons_of_pos (by simp [h])] rw [List.filter_cons_of_pos (by simp [hpb])] · simp only [hab, ↓reduceIte] rw [List.filter_cons_of_pos (by simp [hpb])] rw [List.filter_cons_of_pos (by simp [hpb])] simp only [List.orderedInsert, hab, ↓reduceIte, List.cons.injEq, true_and] simp only [List.sorted_cons] at hl exact orderedInsert_filter_of_pos r a p h l hl.2 · simp only [hab, ↓reduceIte] rw [List.filter_cons_of_pos (by simp [h]), List.filter_cons_of_neg (by simp [hpb])] rw [List.orderedInsert_eq_take_drop] have hl : List.takeWhile (fun b => decide ¬r a b) (List.filter (fun b => decide (p b)) l) = [] := by rw [List.takeWhile_eq_nil_iff] intro c hc simp only [List.get_eq_getElem, decide_not, Bool.not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not] at hc apply hc apply IsTrans.trans a b _ hab simp only [List.sorted_cons] at hl apply hl.1 have hlf : (List.filter (fun b => decide (p b)) l)[0] ∈ (List.filter (fun b => decide (p b)) l) := by exact List.getElem_mem c simp only [List.mem_filter, decide_eq_true_eq] at hlf exact hlf.1 rw [hl] simp only [decide_not, List.nil_append, List.cons.injEq, true_and] conv_lhs => rw [← List.takeWhile_append_dropWhile (fun b => decide ¬r a b) (List.filter (fun b => decide (p b)) l)] rw [hl] simp · simp only [hab, ↓reduceIte] rw [List.filter_cons_of_neg (by simp [hpb])] rw [List.filter_cons_of_neg (by simp [hpb])] simp only [List.sorted_cons] at hl exact orderedInsert_filter_of_pos r a p h l hl.2 lemma orderedInsert_filter_of_neg {α : Type} (r : α → α → Prop) [DecidableRel r] (a : α) (p : α → Prop) [DecidablePred p] (h : ¬ p a) (l : List α) : List.filter p (List.orderedInsert r a l) = (List.filter p l) := by rw [List.orderedInsert_eq_take_drop] simp only [decide_not, List.filter_append] rw [List.filter_cons_of_neg] rw [← List.filter_append] congr exact List.takeWhile_append_dropWhile (fun b => !decide (r a b)) l simp [h] lemma insertionSort_filter {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (p : α → Prop) [DecidablePred p] : (l : List α) → List.insertionSort r (List.filter p l) = List.filter p (List.insertionSort r l) | [] => by simp | a :: l => by simp only [List.insertionSort] by_cases h : p a · rw [orderedInsert_filter_of_pos] rw [List.filter_cons_of_pos] simp only [List.insertionSort] rw [insertionSort_filter] simp_all only [decide_true] simp_all only exact List.sorted_insertionSort r l · rw [orderedInsert_filter_of_neg] rw [List.filter_cons_of_neg] rw [insertionSort_filter] simp_all only [decide_false, Bool.false_eq_true, not_false_eq_true] exact h lemma takeWhile_sorted_eq_filter {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTrans α r] (a : α) : (l : List α) → (hl : l.Sorted r) → List.takeWhile (fun c => ¬ r a c) l = List.filter (fun c => ¬ r a c) l | [], _ => by simp | b :: l, hl => by simp only [List.sorted_cons] at hl by_cases hb : ¬ r a b · simp only [decide_not, hb, decide_false, Bool.not_false, List.takeWhile_cons_of_pos, List.filter_cons_of_pos, List.cons.injEq, true_and] simpa using takeWhile_sorted_eq_filter r a l hl.2 · simp_all only [Decidable.not_not, decide_not, decide_true, Bool.not_true, Bool.false_eq_true, not_false_eq_true, List.takeWhile_cons_of_neg, List.filter_cons_of_neg, List.nil_eq, List.filter_eq_nil_iff, Bool.not_eq_eq_eq_not, decide_eq_false_iff_not] intro c hc apply IsTrans.trans a b c hb exact hl.1 c hc lemma dropWhile_sorted_eq_filter {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTrans α r] (a : α) : (l : List α) → (hl : l.Sorted r) → List.dropWhile (fun c => ¬ r a c) l = List.filter (fun c => r a c) l | [], _ => by simp | b :: l, hl => by simp only [List.sorted_cons] at hl by_cases hb : ¬ r a b · simp only [decide_not, hb, decide_false, Bool.not_false, List.dropWhile_cons_of_pos, Bool.false_eq_true, not_false_eq_true, List.filter_cons_of_neg] simpa using dropWhile_sorted_eq_filter r a l hl.2 · simp_all only [Decidable.not_not, decide_not, decide_true, Bool.not_true, Bool.false_eq_true, not_false_eq_true, List.dropWhile_cons_of_neg, List.filter_cons_of_pos, List.cons.injEq, true_and] symm rw [List.filter_eq_self] intro c hc simp only [decide_eq_true_eq] apply IsTrans.trans a b c hb exact hl.1 c hc lemma dropWhile_sorted_eq_filter_filter {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTrans α r] (a : α) :(l : List α) → (hl : l.Sorted r) → List.filter (fun c => r a c) l = List.filter (fun c => r a c ∧ r c a) l ++ List.filter (fun c => r a c ∧ ¬ r c a) l | [], _ => by simp | b :: l, hl => by simp only [List.sorted_cons] at hl by_cases hb : ¬ r a b · simp only [hb, decide_false, Bool.false_eq_true, not_false_eq_true, List.filter_cons_of_neg, Bool.decide_and, Bool.false_and, decide_not] simpa using dropWhile_sorted_eq_filter_filter r a l hl.2 · simp_all only [Decidable.not_not, decide_true, List.filter_cons_of_pos, Bool.decide_and, decide_not] by_cases hba : r b a · simp only [hba, decide_true, Bool.not_true, Bool.and_false, Bool.false_eq_true, not_false_eq_true, List.filter_cons_of_neg] rw [List.filter_cons_of_pos] rw [dropWhile_sorted_eq_filter_filter] simp only [Bool.decide_and, decide_not, List.cons_append] exact hl.2 simp_all · simp only [hba, decide_false, Bool.and_false, Bool.false_eq_true, not_false_eq_true, List.filter_cons_of_neg] have h1 : List.filter (fun c => decide (r a c) && decide (r c a)) l = [] := by rw [@List.filter_eq_nil_iff] intro c hc simp only [Bool.and_eq_true, decide_eq_true_eq, not_and] intro hac hca apply hba apply IsTrans.trans b c a _ hca exact hl.1 c hc rw [h1] rw [dropWhile_sorted_eq_filter_filter] simp only [Bool.decide_and, h1, decide_not, List.nil_append] rw [List.filter_cons_of_pos] simp_all only [List.filter_eq_nil_iff, Bool.and_eq_true, decide_eq_true_eq, not_and, decide_true, decide_false, Bool.not_false, Bool.and_self] exact hl.2 lemma filter_rel_eq_insertionSort {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a : α) : (l : List α) → List.filter (fun c => r a c ∧ r c a) (l.insertionSort r) = List.filter (fun c => r a c ∧ r c a) l | [] => by simp | b :: l => by simp only [List.insertionSort] by_cases h : r a b ∧ r b a · have hl := orderedInsert_filter_of_pos r b (fun c => r a c ∧ r c a) h (List.insertionSort r l) (by exact List.sorted_insertionSort r l) simp only [Bool.decide_and] at hl ⊢ rw [hl] rw [List.orderedInsert_eq_take_drop] have ht : List.takeWhile (fun b_1 => decide ¬r b b_1) (List.filter (fun b => decide (r a b) && decide (r b a)) (List.insertionSort r l)) = [] := by rw [List.takeWhile_eq_nil_iff] intro hl simp only [List.get_eq_getElem, decide_not, Bool.not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not, Decidable.not_not] have hx := List.getElem_mem hl simp only [List.mem_filter, List.mem_insertionSort, Bool.and_eq_true, decide_eq_true_eq] at hx apply IsTrans.trans b a _ h.2 simp_all rw [ht] simp only [decide_not, List.nil_append] rw [List.filter_cons_of_pos] simp only [List.cons.injEq, true_and] have ih := filter_rel_eq_insertionSort r a l simp only [Bool.decide_and] at ih rw [← ih] have htd := List.takeWhile_append_dropWhile (fun b_1 => decide ¬r b b_1) (List.filter (fun b => decide (r a b) && decide (r b a)) (List.insertionSort r l)) simp only [decide_not] at htd conv_rhs => rw [← htd] simp only [List.self_eq_append_left, List.takeWhile_eq_nil_iff, List.get_eq_getElem, Bool.not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not, Decidable.not_not] intro hl have hx := List.getElem_mem hl simp only [List.mem_filter, List.mem_insertionSort, Bool.and_eq_true, decide_eq_true_eq] at hx apply IsTrans.trans b a _ h.2 simp_all only [decide_not, List.takeWhile_eq_nil_iff, List.get_eq_getElem, Bool.not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not, Decidable.not_not, List.takeWhile_append_dropWhile] simp_all · have hl := orderedInsert_filter_of_neg r b (fun c => r a c ∧ r c a) h (List.insertionSort r l) simp only [Bool.decide_and] at hl ⊢ rw [hl] rw [List.filter_cons_of_neg] have ih := filter_rel_eq_insertionSort r a l simp_all only [not_and, Bool.decide_and] simpa using h lemma insertionSort_of_eq_list {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a : α) (l1 l l2 : List α) (h : ∀ b ∈ l, r a b ∧ r b a) : List.insertionSort r (l1 ++ l ++ l2) = (List.takeWhile (fun c => ¬ r a c) ((l1 ++ l2).insertionSort r)) ++ (List.filter (fun c => r a c ∧ r c a) l1) ++ l ++ (List.filter (fun c => r a c ∧ r c a) l2) ++ (List.filter (fun c => r a c ∧ ¬ r c a) ((l1 ++ l2).insertionSort r)) := by have hl : List.insertionSort r (l1 ++ l ++ l2) = List.takeWhile (fun c => ¬ r a c) ((l1 ++ l ++ l2).insertionSort r) ++ List.dropWhile (fun c => ¬ r a c) ((l1 ++ l ++ l2).insertionSort r) := by exact (List.takeWhile_append_dropWhile (fun c => decide ¬r a c) (List.insertionSort r (l1 ++ l ++ l2))).symm have hlt : List.takeWhile (fun c => ¬ r a c) ((l1 ++ l ++ l2).insertionSort r) = List.takeWhile (fun c => ¬ r a c) ((l1 ++ l2).insertionSort r) := by rw [takeWhile_sorted_eq_filter, takeWhile_sorted_eq_filter] rw [← insertionSort_filter, ← insertionSort_filter] congr 1 simp only [decide_not, List.append_assoc, List.filter_append, List.append_cancel_left_eq, List.append_left_eq_self, List.filter_eq_nil_iff, Bool.not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not, Decidable.not_not] exact fun b hb => (h b hb).1 exact List.sorted_insertionSort r (l1 ++ l2) exact List.sorted_insertionSort r (l1 ++ l ++ l2) conv_lhs => rw [hl, hlt] simp only [decide_not, Bool.decide_and] simp only [List.append_assoc, List.append_cancel_left_eq] have h1 := dropWhile_sorted_eq_filter r a (List.insertionSort r (l1 ++ (l ++ l2))) simp only [decide_not] at h1 rw [h1] rw [dropWhile_sorted_eq_filter_filter, filter_rel_eq_insertionSort] simp only [Bool.decide_and, List.filter_append, decide_not, List.append_assoc, List.append_cancel_left_eq] congr 1 simp only [List.filter_eq_self, Bool.and_eq_true, decide_eq_true_eq] exact fun a a_1 => h a a_1 congr 1 have h1 := insertionSort_filter r (fun c => decide (r a c) && !decide (r c a)) (l1 ++ (l ++ l2)) simp only [Bool.and_eq_true, decide_eq_true_eq, Bool.not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not, Bool.decide_and, decide_not, List.filter_append] at h1 rw [← h1] have h2 := insertionSort_filter r (fun c => decide (r a c) && !decide (r c a)) (l1 ++ l2) simp only [Bool.and_eq_true, decide_eq_true_eq, Bool.not_eq_eq_eq_not, Bool.not_true, decide_eq_false_iff_not, Bool.decide_and, decide_not, List.filter_append] at h2 rw [← h2] congr have hl : List.filter (fun b => decide (r a b) && !decide (r b a)) l = [] := by rw [@List.filter_eq_nil_iff] intro c hc simp_all rw [hl] simp only [List.nil_append] exact List.sorted_insertionSort r (l1 ++ (l ++ l2)) exact List.sorted_insertionSort r (l1 ++ (l ++ l2)) lemma insertionSort_of_takeWhile_filter {α : Type} (r : α → α → Prop) [DecidableRel r] [IsTotal α r] [IsTrans α r] (a : α) (l1 l2 : List α) : List.insertionSort r (l1 ++ l2) = (List.takeWhile (fun c => ¬ r a c) ((l1 ++ l2).insertionSort r)) ++ (List.filter (fun c => r a c ∧ r c a) l1) ++ (List.filter (fun c => r a c ∧ r c a) l2) ++ (List.filter (fun c => r a c ∧ ¬ r c a) ((l1 ++ l2).insertionSort r)) := by trans List.insertionSort r (l1 ++ [] ++ l2) simp only [List.append_nil] rw [insertionSort_of_eq_list r a l1 [] l2] simp only [decide_not, Bool.decide_and, List.append_nil, List.append_assoc] simp end HepLean.List