@@ -5,11 +5,26 @@ Authors: Mario Carneiro
55-/
66import Batteries.Data.Fin.Basic
77import Batteries.Util.ProofWanted
8+ import Batteries.Tactic.Alias
89
910namespace Fin
1011
1112attribute [norm_cast] val_last
1213
14+ /-! ### foldl/foldr -/
15+
16+ theorem foldl_assoc {op : α → α → α} [ha : Std.Associative op] {f : Fin n → α} {a₁ a₂} :
17+ foldl n (fun x i => op x (f i)) (op a₁ a₂) = op a₁ (foldl n (fun x i => op x (f i)) a₂) := by
18+ induction n generalizing a₂ with
19+ | zero => rfl
20+ | succ n ih => simp only [foldl_succ, ha.assoc, ih]
21+
22+ theorem foldr_assoc {op : α → α → α} [ha : Std.Associative op] {f : Fin n → α} {a₁ a₂} :
23+ foldr n (fun i x => op (f i) x) (op a₁ a₂) = op (foldr n (fun i x => op (f i) x) a₁) a₂ := by
24+ induction n generalizing a₂ with
25+ | zero => rfl
26+ | succ n ih => simp only [foldr_succ, ha.assoc, ih]
27+
1328/-! ### clamp -/
1429
1530@[simp] theorem coe_clamp (n m : Nat) : (clamp n m : Nat) = min n m := rfl
@@ -21,14 +36,9 @@ attribute [norm_cast] val_last
2136@[simp] theorem findSome?_one {f : Fin 1 → Option α} : findSome? f = f 0 := rfl
2237
2338theorem findSome?_succ {f : Fin (n+1 ) → Option α} :
24- findSome? f = (f 0 <|> findSome? fun i => f i.succ) := by
25- simp only [findSome?, foldl_succ]
26- cases f 0
27- · rw [Option.orElse_eq_orElse, Option.orElse_none, Option.orElse_none]
28- · simp only [Option.orElse_some, Option.orElse_eq_orElse, Option.orElse_none]
29- induction n with
30- | zero => rfl
31- | succ n ih => rw [foldl_succ, Option.orElse_some, ih (f := fun i => f i.succ)]
39+ findSome? f = (f 0 ).or (findSome? fun i => f i.succ) := by
40+ simp only [findSome?, foldl_succ, Option.orElse_eq_orElse, Option.orElse_eq_or]
41+ exact Eq.trans (by cases (f 0 ) <;> rfl) foldl_assoc
3242
3343theorem findSome?_succ_of_some {f : Fin (n+1 ) → Option α} (h : f 0 = some x) :
3444 findSome? f = some x := by simp [findSome?_succ, h]
@@ -42,68 +52,67 @@ theorem findSome?_succ_of_none {f : Fin (n+1) → Option α} (h : f 0 = none) :
4252theorem findSome?_succ_of_isNone {f : Fin (n+1 ) → Option α} (h : (f 0 ).isNone) :
4353 findSome? f = findSome? fun i => f i.succ := by simp_all [findSome?_succ_of_none]
4454
45- theorem exists_of_findSome?_eq_some {f : Fin n → Option α} (h : findSome? f = some x) :
46- ∃ i, f i = some x := by
55+ @[simp, grind =]
56+ theorem findSome?_eq_some_iff {f : Fin n → Option α} :
57+ findSome? f = some a ↔ ∃ i, f i = some a ∧ ∀ j < i, f j = none := by
4758 induction n with
48- | zero => rw [findSome?_zero] at h; contradiction
59+ | zero =>
60+ simp only [findSome?_zero, (Option.some_ne_none _).symm, false_iff]
61+ exact fun ⟨i, _⟩ => i.elim0
4962 | succ n ih =>
50- rw [findSome?_succ] at h
51- match heq : f 0 with
52- | some x =>
53- rw [heq, Option.orElse_eq_orElse, Option.orElse_some] at h
54- exists 0
55- rw [heq, h]
56- | none =>
57- rw [heq, Option.orElse_eq_orElse, Option.orElse_none] at h
58- match ih h with | ⟨i, _⟩ => exists i.succ
63+ simp only [findSome?_succ, Option.or_eq_some_iff, Fin.exists_fin_succ, Fin.forall_fin_succ,
64+ not_lt_zero, false_implies, implies_true, and_true, succ_lt_succ_iff, succ_pos,
65+ forall_const, ih, and_left_comm (b := f 0 = none), exists_and_left]
5966
60- theorem eq_none_of_findSome?_eq_none {f : Fin n → Option α} (h : findSome? f = none) (i) :
61- f i = none := by
67+ @[simp, grind =] theorem findSome?_eq_none_iff {f : Fin n → Option α} :
68+ findSome? f = none ↔ ∀ i, f i = none := by
6269 induction n with
63- | zero => cases i; contradiction
70+ | zero =>
71+ simp only [findSome?_zero, true_iff]
72+ exact fun i => i.elim0
6473 | succ n ih =>
65- rw [findSome?_succ] at h
66- match heq : f 0 with
67- | some x =>
68- rw [heq, Option.orElse_eq_orElse, Option.orElse_some] at h
69- contradiction
70- | none =>
71- rw [heq, Option.orElse_eq_orElse, Option.orElse_none] at h
72- cases i using Fin.cases with
73- | zero => exact heq
74- | succ i => exact ih h i
75-
76- @[simp] theorem findSome?_isSome_iff {f : Fin n → Option α} :
77- (findSome? f).isSome ↔ ∃ i, (f i).isSome := by
78- simp only [Option.isSome_iff_exists]
79- constructor
80- · intro ⟨x, hx⟩
81- match exists_of_findSome?_eq_some hx with
82- | ⟨i, hi⟩ => exists i, x
83- · intro ⟨i, x, hix⟩
84- match h : findSome? f with
85- | some x => exists x
86- | none => rw [eq_none_of_findSome?_eq_none h i] at hix; contradiction
87-
88- @[simp] theorem findSome?_eq_none_iff {f : Fin n → Option α} :
89- findSome? f = none ↔ ∀ i, f i = none := by
90- constructor
91- · exact eq_none_of_findSome?_eq_none
92- · intro hf
93- match h : findSome? f with
94- | none => rfl
95- | some x =>
96- match exists_of_findSome?_eq_some h with
97- | ⟨i, h⟩ => rw [hf] at h; contradiction
98-
99- theorem findSome?_isNone_iff {f : Fin n → Option α} :
74+ simp only [findSome?_succ, Option.or_eq_none_iff, ih, forall_fin_succ]
75+
76+ theorem isNone_findSome?_iff {f : Fin n → Option α} :
10077 (findSome? f).isNone ↔ ∀ i, (f i).isNone := by simp
10178
79+ @[deprecated (since := "2025-09-28")]
80+ alias findSome?_isNone_iff := isNone_findSome?_iff
81+
82+ @[simp] theorem isSome_findSome?_iff {f : Fin n → Option α} :
83+ (findSome? f).isSome ↔ ∃ i, (f i).isSome := by
84+ cases h : findSome? f with (simp only [findSome?_eq_none_iff, findSome?_eq_some_iff] at h; grind)
85+
86+ @[deprecated (since := "2025-09-28")]
87+ alias findSome?_isSome_iff := isSome_findSome?_iff
88+
89+ theorem exists_minimal_of_findSome?_eq_some {f : Fin n → Option α}
90+ (h : findSome? f = some x) : ∃ i, f i = some x ∧ ∀ j < i, f j = none :=
91+ findSome?_eq_some_iff.1 h
92+
93+ theorem exists_eq_some_of_findSome?_eq_some {f : Fin n → Option α}
94+ (h : findSome? f = some x) : ∃ i, f i = some x := by grind
95+
96+ @[deprecated (since := "2025-09-28")]
97+ alias exists_of_findSome?_eq_some := exists_eq_some_of_findSome?_eq_some
98+
99+ theorem eq_none_of_findSome?_eq_none {f : Fin n → Option α} (h : findSome? f = none) (i) :
100+ f i = none := findSome?_eq_none_iff.1 h i
101+
102+ theorem exists_isSome_of_isSome_findSome? {f : Fin n → Option α} (h : (findSome? f).isSome) :
103+ ∃ i, (f i).isSome := isSome_findSome?_iff.1 h
104+
105+ theorem isNone_of_isNone_findSome? {f : Fin n → Option α} (h : (findSome? f).isNone) :
106+ (f i).isNone := isNone_findSome?_iff.1 h i
107+
108+ theorem isSome_findSome?_of_isSome {f : Fin n → Option α} (h : (f i).isSome) :
109+ (findSome? f).isSome := isSome_findSome?_iff.2 ⟨_, h⟩
110+
102111theorem map_findSome? (f : Fin n → Option α) (g : α → β) :
103- (findSome? f).map g = findSome? (Option.map g ∘ f ) := by
112+ (findSome? f).map g = findSome? (Option.map g <| f · ) := by
104113 induction n with
105114 | zero => rfl
106- | succ n ih => simp [findSome?_succ, Function.comp_def, Option.map_or, ih]
115+ | succ n ih => simp [findSome?_succ, Option.map_or, ih]
107116
108117theorem findSome?_guard {p : Fin n → Bool} : findSome? (Option.guard p) = find? p := rfl
109118
@@ -123,38 +132,62 @@ theorem findSome?_eq_findSome?_finRange (f : Fin n → Option α) :
123132
124133theorem find?_succ {p : Fin (n+1 ) → Bool} :
125134 find? p = if p 0 then some 0 else (find? fun i => p i.succ).map Fin.succ := by
126- simp only [find?, findSome?_succ, Option.guard]
127- split <;> simp [map_findSome?, Function.comp_def, Option.guard ]
135+ simp only [find?, findSome?_succ, Option.guard, fun a => apply_ite (Option.or · a),
136+ Option.some_or, Option.none_or, map_findSome?, Option.map_if ]
128137
129- theorem eq_true_of_find?_eq_some {p : Fin n → Bool} (h : find? p = some i) : p i = true := by
130- match exists_of_findSome?_eq_some h with
131- | ⟨i, hi⟩ =>
132- simp only [Option.guard] at hi
133- split at hi
134- · cases hi; assumption
135- · contradiction
138+ @[simp, grind =]
139+ theorem find?_eq_some_iff {p : Fin n → Bool} :
140+ find? p = some i ↔ p i ∧ ∀ j, j < i → p j = false := by simp [find?, and_assoc]
136141
137- theorem eq_false_of_find?_eq_none {p : Fin n → Bool} (h : find? p = none) (i) : p i = false := by
138- have hi := eq_none_of_findSome?_eq_none h i
139- simp only [Option.guard] at hi
140- split at hi
141- · contradiction
142- · simp [*]
142+ theorem isSome_find?_iff {p : Fin n → Bool} :
143+ (find? p).isSome ↔ ∃ i, p i := by simp [find?]
143144
144- theorem find?_isSome_iff {p : Fin n → Bool} : (find? p).isSome ↔ ∃ i, p i := by
145- simp [find?]
145+ @[deprecated (since := "2025-09-28")]
146+ alias find?_isSome_iff := isSome_find?_iff
146147
147- theorem find?_isNone_iff {p : Fin n → Bool} : (find? p).isNone ↔ ∀ i, ¬ p i := by
148- simp [find?]
148+ @[simp, grind =]
149+ theorem find?_eq_none_iff {p : Fin n → Bool} : find? p = none ↔ ∀ i, p i = false := by simp [find?]
149150
150- proof_wanted find?_eq_some_iff {p : Fin n → Bool} : find? p = some i ↔ p i ∧ ∀ j, j < i → ¬ p j
151+ theorem isNone_find?_iff {p : Fin n → Bool} : ( find? p).isNone ↔ ∀ i, p i = false := by simp [find?]
151152
152- theorem find?_eq_none_iff {p : Fin n → Bool} : find? p = none ↔ ∀ i, ¬ p i := by
153- rw [← find?_isNone_iff, Option.isNone_iff_eq_none]
153+ @[deprecated (since := "2025-09-28")]
154+ alias find?_isNone_iff := isNone_find?_iff
154155
155- theorem find?_eq_find?_finRange {p : Fin n → Bool} : find? p = (List.finRange n).find? p := by
156- induction n with
157- | zero => rfl
158- | succ n ih =>
159- rw [find?_succ, List.finRange_succ, List.find?_cons]
160- split <;> simp [Function.comp_def, *]
156+ theorem eq_true_of_find?_eq_some {p : Fin n → Bool} (h : find? p = some i) : p i :=
157+ (find?_eq_some_iff.mp h).1
158+
159+ theorem eq_false_of_find?_eq_some_of_lt {p : Fin n → Bool} (h : find? p = some i) :
160+ ∀ j < i, p j = false := (find?_eq_some_iff.mp h).2
161+
162+ theorem eq_false_of_find?_eq_none {p : Fin n → Bool} (h : find? p = none) (i) :
163+ p i = false := find?_eq_none_iff.1 h i
164+
165+ theorem exists_eq_true_of_isSome_find? {p : Fin n → Bool} (h : (find? p).isSome) :
166+ ∃ i, p i := isSome_find?_iff.1 h
167+
168+ theorem eq_false_of_isNone_find? {p : Fin n → Bool} (h : (find? p).isNone) : p i = false :=
169+ isNone_find?_iff.1 h i
170+
171+ theorem isSome_find?_of_eq_true {p : Fin n → Bool} (h : p i) :
172+ (find? p).isSome := isSome_find?_iff.2 ⟨_, h⟩
173+
174+ theorem get_find?_eq_true {p : Fin n → Bool} (h : (find? p).isSome) : p ((find? p).get h) :=
175+ eq_true_of_find?_eq_some (Option.some_get _).symm
176+
177+ theorem get_find?_minimal {p : Fin n → Bool} (h : (find? p).isSome) :
178+ ∀ j, j < (find? p).get h → p j = false :=
179+ eq_false_of_find?_eq_some_of_lt (Option.some_get _).symm
180+
181+ theorem find?_eq_find?_finRange {p : Fin n → Bool} : find? p = (List.finRange n).find? p :=
182+ (findSome?_eq_findSome?_finRange _).trans (List.findSome?_guard)
183+
184+ /-! ### exists -/
185+
186+ theorem exists_eq_true_iff_exists_minimal_eq_true (p : Fin n → Bool):
187+ (∃ i, p i) ↔ ∃ i, p i ∧ ∀ j < i, p j = false := by
188+ cases h : find? p <;> grind
189+
190+ theorem exists_iff_exists_minimal (p : Fin n → Prop ) [DecidablePred p] :
191+ (∃ i, p i) ↔ ∃ i, p i ∧ ∀ j < i, ¬ p j := by
192+ simpa only [decide_eq_true_iff, decide_eq_false_iff_not] using
193+ exists_eq_true_iff_exists_minimal_eq_true (p ·)
0 commit comments