|
| 1 | +/- |
| 2 | +Copyright (c) 2022 Eric Rodriguez. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Eric Rodriguez, Eric Wieser |
| 5 | +
|
| 6 | +! This file was ported from Lean 3 source module data.list.destutter |
| 7 | +! leanprover-community/mathlib commit 7b78d1776212a91ecc94cf601f83bdcc46b04213 |
| 8 | +! Please do not edit these lines, except to modify the commit id |
| 9 | +! if you have ported upstream changes. |
| 10 | +-/ |
| 11 | +import Mathlib.Data.List.Chain |
| 12 | + |
| 13 | +/-! |
| 14 | +# Destuttering of Lists |
| 15 | +
|
| 16 | +This file proves theorems about `List.destutter` (in `Data.List.Defs`), which greedily removes all |
| 17 | +non-related items that are adjacent in a list, e.g. `[2, 2, 3, 3, 2].destutter (≠) = [2, 3, 2]`. |
| 18 | +Note that we make no guarantees of being the longest sublist with this property; e.g., |
| 19 | +`[123, 1, 2, 5, 543, 1000].destutter (<) = [123, 543, 1000]`, but a longer ascending chain could be |
| 20 | +`[1, 2, 5, 543, 1000]`. |
| 21 | +
|
| 22 | +## Main statements |
| 23 | +
|
| 24 | +* `List.destutter_sublist`: `l.destutter` is a sublist of `l`. |
| 25 | +* `List.destutter_is_chain'`: `l.destutter` satisfies `Chain' R`. |
| 26 | +* Analogies of these theorems for `List.destutter'`, which is the `destutter` equivalent of `Chain`. |
| 27 | +
|
| 28 | +## Tags |
| 29 | +
|
| 30 | +adjacent, chain, duplicates, remove, list, stutter, destutter |
| 31 | +-/ |
| 32 | + |
| 33 | + |
| 34 | +variable {α : Type _} (l : List α) (R : α → α → Prop) [DecidableRel R] {a b : α} |
| 35 | + |
| 36 | +namespace List |
| 37 | + |
| 38 | +@[simp] |
| 39 | +theorem destutter'_nil : destutter' R a [] = [a] := |
| 40 | + rfl |
| 41 | +#align list.destutter'_nil List.destutter'_nil |
| 42 | + |
| 43 | +theorem destutter'_cons : |
| 44 | + (b :: l).destutter' R a = if R a b then a :: destutter' R b l else destutter' R a l := |
| 45 | + rfl |
| 46 | +#align list.destutter'_cons List.destutter'_cons |
| 47 | + |
| 48 | +variable {R} |
| 49 | + |
| 50 | +@[simp] |
| 51 | +theorem destutter'_cons_pos (h : R b a) : (a :: l).destutter' R b = b :: l.destutter' R a := by |
| 52 | + rw [destutter', if_pos h] |
| 53 | +#align list.destutter'_cons_pos List.destutter'_cons_pos |
| 54 | + |
| 55 | +@[simp] |
| 56 | +theorem destutter'_cons_neg (h : ¬R b a) : (a :: l).destutter' R b = l.destutter' R b := by |
| 57 | + rw [destutter', if_neg h] |
| 58 | +#align list.destutter'_cons_neg List.destutter'_cons_neg |
| 59 | + |
| 60 | +variable (R) |
| 61 | + |
| 62 | +@[simp] |
| 63 | +theorem destutter'_singleton : [b].destutter' R a = if R a b then [a, b] else [a] := by |
| 64 | + split_ifs with h <;> simp! [h] |
| 65 | +#align list.destutter'_singleton List.destutter'_singleton |
| 66 | + |
| 67 | +theorem destutter'_sublist (a) : l.destutter' R a <+ a :: l := |
| 68 | + by |
| 69 | + induction' l with b l hl generalizing a |
| 70 | + · simp |
| 71 | + rw [destutter'] |
| 72 | + split_ifs |
| 73 | + · exact Sublist.cons₂ a (hl b) |
| 74 | + · exact (hl a).trans ((l.sublist_cons b).cons_cons a) |
| 75 | +#align list.destutter'_sublist List.destutter'_sublist |
| 76 | + |
| 77 | +theorem mem_destutter' (a) : a ∈ l.destutter' R a := |
| 78 | + by |
| 79 | + induction' l with b l hl |
| 80 | + · simp |
| 81 | + rw [destutter'] |
| 82 | + split_ifs |
| 83 | + · simp |
| 84 | + · assumption |
| 85 | +#align list.mem_destutter' List.mem_destutter' |
| 86 | + |
| 87 | +theorem destutter'_is_chain : ∀ l : List α, ∀ {a b}, R a b → (l.destutter' R b).Chain R a |
| 88 | + | [], a, b, h => chain_singleton.mpr h |
| 89 | + | c :: l, a, b, h => by |
| 90 | + rw [destutter'] |
| 91 | + split_ifs with hbc |
| 92 | + · rw [chain_cons] |
| 93 | + exact ⟨h, destutter'_is_chain l hbc⟩ |
| 94 | + · exact destutter'_is_chain l h |
| 95 | +#align list.destutter'_is_chain List.destutter'_is_chain |
| 96 | + |
| 97 | +theorem destutter'_is_chain' (a) : (l.destutter' R a).Chain' R := |
| 98 | + by |
| 99 | + induction' l with b l hl generalizing a |
| 100 | + · simp |
| 101 | + rw [destutter'] |
| 102 | + split_ifs with h |
| 103 | + · exact destutter'_is_chain R l h |
| 104 | + · exact hl a |
| 105 | +#align list.destutter'_is_chain' List.destutter'_is_chain' |
| 106 | + |
| 107 | +theorem destutter'_of_chain (h : l.Chain R a) : l.destutter' R a = a :: l := |
| 108 | + by |
| 109 | + induction' l with b l hb generalizing a |
| 110 | + · simp |
| 111 | + obtain ⟨h, hc⟩ := chain_cons.mp h |
| 112 | + rw [l.destutter'_cons_pos h, hb hc] |
| 113 | +#align list.destutter'_of_chain List.destutter'_of_chain |
| 114 | + |
| 115 | +@[simp] |
| 116 | +theorem destutter'_eq_self_iff (a) : l.destutter' R a = a :: l ↔ l.Chain R a := |
| 117 | + ⟨fun h => by |
| 118 | + suffices Chain' R (a::l) by |
| 119 | + assumption |
| 120 | + rw [← h] |
| 121 | + exact l.destutter'_is_chain' R a, destutter'_of_chain _ _⟩ |
| 122 | +#align list.destutter'_eq_self_iff List.destutter'_eq_self_iff |
| 123 | + |
| 124 | +theorem destutter'_ne_nil : l.destutter' R a ≠ [] := |
| 125 | + ne_nil_of_mem <| l.mem_destutter' R a |
| 126 | +#align list.destutter'_ne_nil List.destutter'_ne_nil |
| 127 | + |
| 128 | +@[simp] |
| 129 | +theorem destutter_nil : ([] : List α).destutter R = [] := |
| 130 | + rfl |
| 131 | +#align list.destutter_nil List.destutter_nil |
| 132 | + |
| 133 | +theorem destutter_cons' : (a :: l).destutter R = destutter' R a l := |
| 134 | + rfl |
| 135 | +#align list.destutter_cons' List.destutter_cons' |
| 136 | + |
| 137 | +theorem destutter_cons_cons : |
| 138 | + (a :: b :: l).destutter R = if R a b then a :: destutter' R b l else destutter' R a l := |
| 139 | + rfl |
| 140 | +#align list.destutter_cons_cons List.destutter_cons_cons |
| 141 | + |
| 142 | +@[simp] |
| 143 | +theorem destutter_singleton : destutter R [a] = [a] := |
| 144 | + rfl |
| 145 | +#align list.destutter_singleton List.destutter_singleton |
| 146 | + |
| 147 | +@[simp] |
| 148 | +theorem destutter_pair : destutter R [a, b] = if R a b then [a, b] else [a] := |
| 149 | + destutter_cons_cons _ R |
| 150 | +#align list.destutter_pair List.destutter_pair |
| 151 | + |
| 152 | +theorem destutter_sublist : ∀ l : List α, l.destutter R <+ l |
| 153 | + | [] => Sublist.slnil |
| 154 | + | h :: l => l.destutter'_sublist R h |
| 155 | +#align list.destutter_sublist List.destutter_sublist |
| 156 | + |
| 157 | +theorem destutter_is_chain' : ∀ l : List α, (l.destutter R).Chain' R |
| 158 | + | [] => List.chain'_nil |
| 159 | + | h :: l => l.destutter'_is_chain' R h |
| 160 | +#align list.destutter_is_chain' List.destutter_is_chain' |
| 161 | + |
| 162 | +theorem destutter_of_chain' : ∀ l : List α, l.Chain' R → l.destutter R = l |
| 163 | + | [], _ => rfl |
| 164 | + | _ :: l, h => l.destutter'_of_chain _ h |
| 165 | +#align list.destutter_of_chain' List.destutter_of_chain' |
| 166 | + |
| 167 | +@[simp] |
| 168 | +theorem destutter_eq_self_iff : ∀ l : List α, l.destutter R = l ↔ l.Chain' R |
| 169 | + | [] => by simp |
| 170 | + | a :: l => l.destutter'_eq_self_iff R a |
| 171 | +#align list.destutter_eq_self_iff List.destutter_eq_self_iff |
| 172 | + |
| 173 | +theorem destutter_idem : (l.destutter R).destutter R = l.destutter R := |
| 174 | + destutter_of_chain' R _ <| l.destutter_is_chain' R |
| 175 | +#align list.destutter_idem List.destutter_idem |
| 176 | + |
| 177 | +@[simp] |
| 178 | +theorem destutter_eq_nil : ∀ {l : List α}, destutter R l = [] ↔ l = [] |
| 179 | + | [] => Iff.rfl |
| 180 | + | _ :: l => ⟨fun h => absurd h <| l.destutter'_ne_nil R, fun h => nomatch h⟩ |
| 181 | +#align list.destutter_eq_nil List.destutter_eq_nil |
| 182 | + |
| 183 | +end List |
0 commit comments