Compare commits

...

3 Commits

Author SHA1 Message Date
Kim Morrison
f9dd51a96c add file 2025-02-03 15:17:39 +11:00
Kim Morrison
7f3d10611c epic 2025-02-03 15:17:32 +11:00
Kim Morrison
4de942db25 feat: complete aligning List/Array findX functions 2025-02-03 12:43:21 +11:00
12 changed files with 969 additions and 152 deletions

View File

@@ -642,14 +642,28 @@ and simplifies these to the function directly taking the value.
rw [List.filterMap_subtype]
simp [hf]
@[simp] theorem findSome?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
l.findSome? f = l.unattach.findSome? g := by
cases l
simp
rw [List.findSome?_subtype hf]
@[simp] theorem find?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
(l.find? f).map Subtype.val = l.unattach.find? g := by
cases l
simp
rw [List.find?_subtype hf]
/-! ### Simp lemmas pushing `unattach` inwards. -/
@[simp] theorem unattach_filter {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
(l.filter f).unattach = l.unattach.filter g := by
cases l
simp [hf]
/-! ### Simp lemmas pushing `unattach` inwards. -/
@[simp] theorem unattach_reverse {p : α Prop} {l : Array { x // p x }} :
l.reverse.unattach = l.unattach.reverse := by
cases l

View File

@@ -4,12 +4,13 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.List.Find
import Init.Data.List.Nat.Find
import Init.Data.Array.Lemmas
import Init.Data.Array.Attach
import Init.Data.Array.Range
/-!
# Lemmas about `Array.findSome?`, `Array.find?`.
# Lemmas about `Array.findSome?`, `Array.find?, `Array.findIdx`, `Array.findIdx?`, `Array.idxOf`.
-/
namespace Array
@@ -48,6 +49,9 @@ theorem findSome?_eq_some_iff {f : α → Option β} {l : Array α} {b : β} :
@[simp] theorem findSome?_guard (l : Array α) : findSome? (Option.guard fun x => p x) l = find? p l := by
cases l; simp
theorem find?_eq_findSome?_guard (l : Array α) : find? p l = findSome? (Option.guard fun x => p x) l :=
(findSome?_guard l).symm
@[simp] theorem getElem?_zero_filterMap (f : α Option β) (l : Array α) : (l.filterMap f)[0]? = l.findSome? f := by
cases l; simp [ List.head?_eq_getElem?]
@@ -206,22 +210,25 @@ theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
cases xs using array₂_induction
simp [List.findSome?_map, Function.comp_def]
theorem find?_flatten_eq_none {xs : Array (Array α)} {p : α Bool} :
theorem find?_flatten_eq_none_iff {xs : Array (Array α)} {p : α Bool} :
xs.flatten.find? p = none ys xs, x ys, !p x := by
simp
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
abbrev find?_flatten_eq_none := @find?_flatten_eq_none_iff
/--
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
some array in `xs` contains `a`, and no earlier element of that array satisfies `p`.
Moreover, no earlier array in `xs` has an element satisfying `p`.
-/
theorem find?_flatten_eq_some {xs : Array (Array α)} {p : α Bool} {a : α} :
theorem find?_flatten_eq_some_iff {xs : Array (Array α)} {p : α Bool} {a : α} :
xs.flatten.find? p = some a
p a (as : Array (Array α)) (ys zs : Array α) (bs : Array (Array α)),
xs = as.push (ys.push a ++ zs) ++ bs
( a as, x a, !p x) ( x ys, !p x) := by
cases xs using array₂_induction
simp only [flatten_toArray_map_toArray, List.find?_toArray, List.find?_flatten_eq_some]
simp only [flatten_toArray_map_toArray, List.find?_toArray, List.find?_flatten_eq_some_iff]
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
intro w
constructor
@@ -235,15 +242,21 @@ theorem find?_flatten_eq_some {xs : Array (Array α)} {p : α → Bool} {a : α}
zs.toList, bs.toList.map Array.toList, by simpa using h,
by simpa using h₁, by simpa using h₂
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
@[simp] theorem find?_flatMap (xs : Array α) (f : α Array β) (p : β Bool) :
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
cases xs
simp [List.find?_flatMap, Array.flatMap_toArray]
theorem find?_flatMap_eq_none {xs : Array α} {f : α Array β} {p : β Bool} :
theorem find?_flatMap_eq_none_iff {xs : Array α} {f : α Array β} {p : β Bool} :
(xs.flatMap f).find? p = none x xs, y f x, !p y := by
simp
@[deprecated find?_flatMap_eq_none_iff (since := "2025-02-03")]
abbrev find?_flatMap_eq_none := @find?_flatMap_eq_none_iff
theorem find?_mkArray :
find? p (mkArray n a) = if n = 0 then none else if p a then some a else none := by
simp [ List.toArray_replicate, List.find?_replicate]
@@ -260,14 +273,20 @@ theorem find?_mkArray :
simp [find?_mkArray, h]
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
theorem find?_mkArray_eq_none {n : Nat} {a : α} {p : α Bool} :
theorem find?_mkArray_eq_none_iff {n : Nat} {a : α} {p : α Bool} :
(mkArray n a).find? p = none n = 0 !p a := by
simp [ List.toArray_replicate, List.find?_replicate_eq_none, Classical.or_iff_not_imp_left]
simp [ List.toArray_replicate, List.find?_replicate_eq_none_iff, Classical.or_iff_not_imp_left]
@[simp] theorem find?_mkArray_eq_some {n : Nat} {a b : α} {p : α Bool} :
@[deprecated find?_mkArray_eq_none_iff (since := "2025-02-03")]
abbrev find?_mkArray_eq_none := @find?_mkArray_eq_none_iff
@[simp] theorem find?_mkArray_eq_some_iff {n : Nat} {a b : α} {p : α Bool} :
(mkArray n a).find? p = some b n 0 p a a = b := by
simp [ List.toArray_replicate]
@[deprecated find?_mkArray_eq_some_iff (since := "2025-02-03")]
abbrev find?_mkArray_eq_some := @find?_mkArray_eq_some_iff
@[simp] theorem get_find?_mkArray (n : Nat) (a : α) (p : α Bool) (h) :
((mkArray n a).find? p).get h = a := by
simp [ List.toArray_replicate]
@@ -278,4 +297,275 @@ theorem find?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : Array
simp only [pmap_eq_map_attach, find?_map]
rfl
theorem find?_eq_some_iff_getElem {xs : Array α} {p : α Bool} {b : α} :
xs.find? p = some b p b i h, xs[i] = b j : Nat, (hj : j < i) !p xs[j] := by
rcases xs with xs
simp [List.find?_eq_some_iff_getElem]
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_empty {p : α Bool} : findFinIdx? p #[] = none := rfl
-- We can't mark this as a `@[congr]` lemma since the head of the RHS is not `findFinIdx?`.
theorem findFinIdx?_congr {p : α Bool} {l₁ : Array α} {l₂ : Array α} (w : l₁ = l₂) :
findFinIdx? p l₁ = (findFinIdx? p l₂).map (fun i => i.cast (by simp [w])) := by
subst w
simp
@[simp] theorem findFinIdx?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findFinIdx? f = (l.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
cases l
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
rw [findFinIdx?_congr List.unattach_toArray]
simp [Function.comp_def]
/-! ### findIdx -/
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
rcases xs with xs
exact List.findIdx_of_getElem?_eq_some (by simpa using w)
theorem findIdx_getElem {xs : Array α} {w : xs.findIdx p < xs.size} :
p xs[xs.findIdx p] :=
xs.findIdx_of_getElem?_eq_some (getElem?_eq_getElem w)
theorem findIdx_lt_size_of_exists {xs : Array α} (h : x xs, p x) :
xs.findIdx p < xs.size := by
rcases xs with xs
simpa using List.findIdx_lt_length_of_exists (by simpa using h)
theorem findIdx_getElem?_eq_getElem_of_exists {xs : Array α} (h : x xs, p x) :
xs[xs.findIdx p]? = some (xs[xs.findIdx p]'(xs.findIdx_lt_size_of_exists h)) :=
getElem?_eq_getElem (findIdx_lt_size_of_exists h)
@[simp]
theorem findIdx_eq_size {p : α Bool} {xs : Array α} :
xs.findIdx p = xs.size x xs, p x = false := by
rcases xs with xs
simp
theorem findIdx_eq_size_of_false {p : α Bool} {xs : Array α} (h : x xs, p x = false) :
xs.findIdx p = xs.size := by
rcases xs with xs
simp_all
theorem findIdx_le_size (p : α Bool) {xs : Array α} : xs.findIdx p xs.size := by
by_cases e : x xs, p x
· exact Nat.le_of_lt (findIdx_lt_size_of_exists e)
· simp at e
exact Nat.le_of_eq (findIdx_eq_size.mpr e)
@[simp]
theorem findIdx_lt_size {p : α Bool} {xs : Array α} :
xs.findIdx p < xs.size x xs, p x := by
rcases xs with xs
simp
/-- `p` does not hold for elements with indices less than `xs.findIdx p`. -/
theorem not_of_lt_findIdx {p : α Bool} {xs : Array α} {i : Nat} (h : i < xs.findIdx p) :
p (xs[i]'(Nat.le_trans h (findIdx_le_size p))) = false := by
rcases xs with xs
simpa using List.not_of_lt_findIdx (by simpa using h)
/-- If `¬ p xs[j]` for all `j < i`, then `i ≤ xs.findIdx p`. -/
theorem le_findIdx_of_not {p : α Bool} {xs : Array α} {i : Nat} (h : i < xs.size)
(h2 : j (hji : j < i), p (xs[j]'(Nat.lt_trans hji h)) = false) : i xs.findIdx p := by
apply Decidable.byContradiction
intro f
simp only [Nat.not_le] at f
exact absurd (@findIdx_getElem _ p xs (Nat.lt_trans f h)) (by simpa using h2 (xs.findIdx p) f)
/-- If `¬ p xs[j]` for all `j ≤ i`, then `i < xs.findIdx p`. -/
theorem lt_findIdx_of_not {p : α Bool} {xs : Array α} {i : Nat} (h : i < xs.size)
(h2 : j (hji : j i), ¬p (xs[j]'(Nat.lt_of_le_of_lt hji h))) : i < xs.findIdx p := by
apply Decidable.byContradiction
intro f
simp only [Nat.not_lt] at f
exact absurd (@findIdx_getElem _ p xs (Nat.lt_of_le_of_lt f h)) (h2 (xs.findIdx p) f)
/-- `xs.findIdx p = i` iff `p xs[i]` and `¬ p xs [j]` for all `j < i`. -/
theorem findIdx_eq {p : α Bool} {xs : Array α} {i : Nat} (h : i < xs.size) :
xs.findIdx p = i p xs[i] j (hji : j < i), p (xs[j]'(Nat.lt_trans hji h)) = false := by
refine fun f f (@findIdx_getElem _ p xs (f h)), fun _ hji not_of_lt_findIdx (f hji),
fun _, h2 ?_
apply Nat.le_antisymm _ (le_findIdx_of_not h h2)
apply Decidable.byContradiction
intro h3
simp at h3
simp_all [not_of_lt_findIdx h3]
theorem findIdx_append (p : α Bool) (l₁ l₂ : Array α) :
(l₁ ++ l₂).findIdx p =
if l₁.findIdx p < l₁.size then l₁.findIdx p else l₂.findIdx p + l₁.size := by
rcases l₁ with l₁
rcases l₂ with l₂
simp [List.findIdx_append]
theorem findIdx_le_findIdx {l : Array α} {p q : α Bool} (h : x l, p x q x) : l.findIdx q l.findIdx p := by
rcases l with l
simp_all [List.findIdx_le_findIdx]
@[simp] theorem findIdx_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findIdx f = l.unattach.findIdx g := by
cases l
simp [hf]
/-! ### findIdx? -/
@[simp] theorem findIdx?_empty : (#[] : Array α).findIdx? p = none := rfl
@[simp]
theorem findIdx?_eq_none_iff {xs : Array α} {p : α Bool} :
xs.findIdx? p = none x, x xs p x = false := by
rcases xs with xs
simp
theorem findIdx?_isSome {xs : Array α} {p : α Bool} :
(xs.findIdx? p).isSome = xs.any p := by
rcases xs with xs
simp [List.findIdx?_isSome]
theorem findIdx?_isNone {xs : Array α} {p : α Bool} :
(xs.findIdx? p).isNone = xs.all (¬p ·) := by
rcases xs with xs
simp [List.findIdx?_isNone]
theorem findIdx?_eq_some_iff_findIdx_eq {xs : Array α} {p : α Bool} {i : Nat} :
xs.findIdx? p = some i i < xs.size xs.findIdx p = i := by
rcases xs with xs
simp [List.findIdx?_eq_some_iff_findIdx_eq]
theorem findIdx?_eq_some_of_exists {xs : Array α} {p : α Bool} (h : x, x xs p x) :
xs.findIdx? p = some (xs.findIdx p) := by
rw [findIdx?_eq_some_iff_findIdx_eq]
exact findIdx_lt_size_of_exists h, rfl
theorem findIdx?_eq_none_iff_findIdx_eq {xs : Array α} {p : α Bool} :
xs.findIdx? p = none xs.findIdx p = xs.size := by
rcases xs with xs
simp [List.findIdx?_eq_none_iff_findIdx_eq]
theorem findIdx?_eq_guard_findIdx_lt {xs : Array α} {p : α Bool} :
xs.findIdx? p = Option.guard (fun i => i < xs.size) (xs.findIdx p) := by
rcases xs with xs
simp [List.findIdx?_eq_guard_findIdx_lt]
theorem findIdx?_eq_some_iff_getElem {xs : Array α} {p : α Bool} {i : Nat} :
xs.findIdx? p = some i
h : i < xs.size, p xs[i] j (hji : j < i), ¬p (xs[j]'(Nat.lt_trans hji h)) := by
rcases xs with xs
simp [List.findIdx?_eq_some_iff_getElem]
theorem of_findIdx?_eq_some {xs : Array α} {p : α Bool} (w : xs.findIdx? p = some i) :
match xs[i]? with | some a => p a | none => false := by
rcases xs with xs
simpa using List.of_findIdx?_eq_some (by simpa using w)
theorem of_findIdx?_eq_none {xs : Array α} {p : α Bool} (w : xs.findIdx? p = none) :
i : Nat, match xs[i]? with | some a => ¬ p a | none => true := by
rcases xs with xs
simpa using List.of_findIdx?_eq_none (by simpa using w)
@[simp] theorem findIdx?_map (f : β α) (l : Array β) : findIdx? p (l.map f) = l.findIdx? (p f) := by
rcases l with l
simp [List.findIdx?_map]
@[simp] theorem findIdx?_append :
(xs ++ ys : Array α).findIdx? p =
(xs.findIdx? p).or ((ys.findIdx? p).map fun i => i + xs.size) := by
rcases xs with xs
rcases ys with ys
simp [List.findIdx?_append]
theorem findIdx?_flatten {l : Array (Array α)} {p : α Bool} :
l.flatten.findIdx? p =
(l.findIdx? (·.any p)).map
fun i => ((l.take i).map Array.size).sum +
(l[i]?.map fun xs => xs.findIdx p).getD 0 := by
cases l using array₂_induction
simp [List.findIdx?_flatten, Function.comp_def]
@[simp] theorem findIdx?_mkArray :
(mkArray n a).findIdx? p = if 0 < n p a then some 0 else none := by
rw [ List.toArray_replicate]
simp only [List.findIdx?_toArray]
simp
theorem findIdx?_eq_findSome?_zipIdx {xs : Array α} {p : α Bool} :
xs.findIdx? p = xs.zipIdx.findSome? fun a, i => if p a then some i else none := by
rcases xs with xs
simp [List.findIdx?_eq_findSome?_zipIdx]
theorem findIdx?_eq_fst_find?_zipIdx {xs : Array α} {p : α Bool} :
xs.findIdx? p = (xs.zipIdx.find? fun x, _ => p x).map (·.2) := by
rcases xs with xs
simp [List.findIdx?_eq_fst_find?_zipIdx]
-- See also `findIdx_le_findIdx`.
theorem findIdx?_eq_none_of_findIdx?_eq_none {xs : Array α} {p q : α Bool} (w : x xs, p x q x) :
xs.findIdx? q = none xs.findIdx? p = none := by
rcases xs with xs
simpa using List.findIdx?_eq_none_of_findIdx?_eq_none (by simpa using w)
theorem findIdx_eq_getD_findIdx? {xs : Array α} {p : α Bool} :
xs.findIdx p = (xs.findIdx? p).getD xs.size := by
rcases xs with xs
simp [List.findIdx_eq_getD_findIdx?]
theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : Array α} {p q : α Bool} (w : x xs, p x q x) {i : Nat}
(h : xs.findIdx? p = some i) : j, j i xs.findIdx? q = some j := by
rcases xs with xs
simp [List.findIdx?_eq_some_le_of_findIdx?_eq_some (by simpa using w) (by simpa using h)]
@[simp] theorem findIdx?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findIdx? f = l.unattach.findIdx? g := by
cases l
simp [hf]
/-! ### idxOf
The verification API for `idxOf` is still incomplete.
The lemmas below should be made consistent with those for `findIdx` (and proved using them).
-/
theorem idxOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : Array α} {a : α} :
(l₁ ++ l₂).idxOf a = if a l₁ then l₁.idxOf a else l₂.idxOf a + l₁.size := by
rw [idxOf, findIdx_append]
split <;> rename_i h
· rw [if_pos]
simpa using h
· rw [if_neg]
simpa using h
theorem idxOf_eq_size [BEq α] [LawfulBEq α] {l : Array α} (h : a l) : l.idxOf a = l.size := by
rcases l with l
simp [List.idxOf_eq_length (by simpa using h)]
theorem idxOf_lt_length [BEq α] [LawfulBEq α] {l : Array α} (h : a l) : l.idxOf a < l.size := by
rcases l with l
simp [List.idxOf_lt_length (by simpa using h)]
/-! ### idxOf?
The verification API for `idxOf?` is still incomplete.
The lemmas below should be made consistent with those for `findIdx?` (and proved using them).
-/
@[simp] theorem idxOf?_empty [BEq α] : (#[] : Array α).idxOf? a = none := rfl
@[simp] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {l : Array α} {a : α} :
l.idxOf? a = none a l := by
rcases l with l
simp [List.idxOf?_eq_none_iff]
/-! ### finIdxOf? -/
theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : Array α} {a : α} :
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
end Array

View File

@@ -3621,6 +3621,16 @@ theorem eraseIdx_eq_eraseIdxIfInBounds {a : Array α} {i : Nat} (h : i < a.size)
cases as
simp
@[simp] theorem finIdxOf?_toList [BEq α] (a : α) (v : Array α) :
v.toList.finIdxOf? a = (v.finIdxOf? a).map (Fin.cast (by simp)) := by
rcases v with v
simp
@[simp] theorem findFinIdx?_toList (p : α Bool) (v : Array α) :
v.toList.findFinIdx? p = (v.findFinIdx? p).map (Fin.cast (by simp)) := by
rcases v with v
simp
end Array
open Array

View File

@@ -374,6 +374,8 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
@[simp] theorem cast_zero [NeZero n] [NeZero m] (h : n = m) : Fin.cast h 0 = 0 := rfl
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : (last n).cast h = last n' :=
Fin.ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])

View File

@@ -740,6 +740,24 @@ and simplifies these to the function directly taking the value.
@[deprecated flatMap_subtype (since := "2024-10-16")] abbrev bind_subtype := @flatMap_subtype
@[simp] theorem findSome?_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
l.findSome? f = l.unattach.findSome? g := by
unfold unattach
induction l with
| nil => simp
| cons a l ih => simp [ih, hf, findSome?_cons]
@[simp] theorem find?_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
(l.find? f).map Subtype.val = l.unattach.find? g := by
unfold unattach
induction l with
| nil => simp
| cons a l ih =>
simp [hf, find?_cons]
split <;> simp [ih]
/-! ### Simp lemmas pushing `unattach` inwards. -/
@[simp] theorem unattach_filter {p : α Prop} {l : List { x // p x }}

View File

@@ -8,9 +8,10 @@ prelude
import Init.Data.List.Lemmas
import Init.Data.List.Sublist
import Init.Data.List.Range
import Init.Data.Fin.Lemmas
/-!
Lemmas about `List.findSome?`, `List.find?`, `List.findIdx`, `List.findIdx?`, `List.indexOf`,
Lemmas about `List.findSome?`, `List.find?`, `List.findIdx`, `List.findIdx?`, `List.idxOf`,
and `List.lookup`.
-/
@@ -96,6 +97,9 @@ theorem findSome?_eq_some_iff {f : α → Option β} {l : List α} {b : β} :
· simp only [Option.guard_eq_none] at h
simp [ih, h]
theorem find?_eq_findSome?_guard (l : List α) : find? p l = findSome? (Option.guard fun x => p x) l :=
(findSome?_guard l).symm
@[simp] theorem head?_filterMap (f : α Option β) (l : List α) : (l.filterMap f).head? = l.findSome? f := by
induction l with
| nil => simp
@@ -339,16 +343,19 @@ theorem get_find?_mem (xs : List α) (p : α → Bool) (h) : (xs.find? p).get h
simp only [flatten_cons, find?_append, findSome?_cons, ih]
split <;> simp [*]
theorem find?_flatten_eq_none {xs : List (List α)} {p : α Bool} :
theorem find?_flatten_eq_none_iff {xs : List (List α)} {p : α Bool} :
xs.flatten.find? p = none ys xs, x ys, !p x := by
simp
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
abbrev find?_flatten_eq_none := @find?_flatten_eq_none_iff
/--
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
some list in `xs` contains `a`, and no earlier element of that list satisfies `p`.
Moreover, no earlier list in `xs` has an element satisfying `p`.
-/
theorem find?_flatten_eq_some {xs : List (List α)} {p : α Bool} {a : α} :
theorem find?_flatten_eq_some_iff {xs : List (List α)} {p : α Bool} {a : α} :
xs.flatten.find? p = some a
p a as ys zs bs, xs = as ++ (ys ++ a :: zs) :: bs
( a as, x a, !p x) ( x ys, !p x) := by
@@ -383,17 +390,23 @@ theorem find?_flatten_eq_some {xs : List (List α)} {p : α → Bool} {a : α} :
· exact h₁ l ml a m
· exact h₂ a m
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
@[simp] theorem find?_flatMap (xs : List α) (f : α List β) (p : β Bool) :
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
simp [flatMap_def, findSome?_map]; rfl
@[deprecated find?_flatMap (since := "2024-10-16")] abbrev find?_bind := @find?_flatMap
theorem find?_flatMap_eq_none {xs : List α} {f : α List β} {p : β Bool} :
theorem find?_flatMap_eq_none_iff {xs : List α} {f : α List β} {p : β Bool} :
(xs.flatMap f).find? p = none x xs, y f x, !p y := by
simp
@[deprecated find?_flatMap_eq_none (since := "2024-10-16")] abbrev find?_bind_eq_none := @find?_flatMap_eq_none
@[deprecated find?_flatMap_eq_none_iff (since := "2024-10-16")]
abbrev find?_flatMap_eq_none := @find?_flatMap_eq_none_iff
@[deprecated find?_flatMap_eq_none (since := "2024-10-16")] abbrev find?_bind_eq_none := @find?_flatMap_eq_none_iff
theorem find?_replicate : find? p (replicate n a) = if n = 0 then none else if p a then some a else none := by
cases n
@@ -410,14 +423,20 @@ theorem find?_replicate : find? p (replicate n a) = if n = 0 then none else if p
simp [find?_replicate, h]
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
theorem find?_replicate_eq_none {n : Nat} {a : α} {p : α Bool} :
theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α Bool} :
(replicate n a).find? p = none n = 0 !p a := by
simp [Classical.or_iff_not_imp_left]
@[simp] theorem find?_replicate_eq_some {n : Nat} {a b : α} {p : α Bool} :
@[deprecated find?_replicate_eq_none_iff (since := "2025-02-03")]
abbrev find?_replicate_eq_none := @find?_replicate_eq_none_iff
@[simp] theorem find?_replicate_eq_some_iff {n : Nat} {a b : α} {p : α Bool} :
(replicate n a).find? p = some b n 0 p a a = b := by
cases n <;> simp
@[deprecated find?_replicate_eq_some_iff (since := "2025-02-03")]
abbrev find?_replicate_eq_some := @find?_replicate_eq_some_iff
@[simp] theorem get_find?_replicate (n : Nat) (a : α) (p : α Bool) (h) : ((replicate n a).find? p).get h = a := by
cases n with
| zero => simp at h
@@ -459,6 +478,79 @@ theorem find?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List α
simp only [pmap_eq_map_attach, find?_map]
rfl
/-! ### findIdx? (preliminary lemmas) -/
@[local simp] private theorem findIdx?_go_nil {p : α Bool} {i : Nat} :
findIdx?.go p [] i = none := rfl
@[local simp] private theorem findIdx?_go_cons :
findIdx?.go p (x :: xs) i = if p x then some i else findIdx?.go p xs (i + 1) := rfl
private theorem findIdx?_go_succ {p : α Bool} {xs : List α} {i : Nat} :
findIdx?.go p xs (i+1) = (findIdx?.go p xs i).map fun i => i + 1 := by
induction xs generalizing i with simp
| cons _ _ _ => split <;> simp_all
private theorem findIdx?_go_eq {p : α Bool} {xs : List α} {i : Nat} :
findIdx?.go p xs (i+1) = (findIdx?.go p xs 0).map fun k => k + (i + 1) := by
induction xs generalizing i with
| nil => simp
| cons _ _ _ =>
simp only [findIdx?_go_succ, findIdx?_go_cons, Nat.zero_add]
split
· simp_all
· simp_all only [findIdx?_go_succ, Bool.not_eq_true, Option.map_map, Nat.zero_add]
congr
ext
simp only [Nat.add_comm i, Function.comp_apply, Nat.add_assoc]
@[simp] theorem findIdx?_nil : ([] : List α).findIdx? p = none := rfl
@[simp] theorem findIdx?_cons :
(x :: xs).findIdx? p = if p x then some 0 else (xs.findIdx? p).map fun i => i + 1 := by
simp [findIdx?, findIdx?_go_eq]
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_nil {p : α Bool} : findFinIdx? p [] = none := rfl
theorem findIdx?_go_eq_map_findFinIdx?_go_val {xs : List α} {p : α Bool} {i : Nat} {h} :
List.findIdx?.go p xs i =
(List.findFinIdx?.go p l xs i h).map (·.val) := by
unfold findIdx?.go
unfold findFinIdx?.go
split <;> rename_i a xs
· simp_all
· simp only
split
· simp
· rw [findIdx?_go_eq_map_findFinIdx?_go_val]
theorem findIdx?_eq_map_findFinIdx?_val {xs : List α} {p : α Bool} :
xs.findIdx? p = (xs.findFinIdx? p).map (·.val) := by
simp [findIdx?, findFinIdx?]
rw [findIdx?_go_eq_map_findFinIdx?_go_val]
@[simp] theorem findFinIdx?_cons {p : α Bool} {x : α} {xs : List α} :
findFinIdx? p (x :: xs) = if p x then some 0 else (findFinIdx? p xs).map Fin.succ := by
rw [ Option.map_inj_right (f := Fin.val) (fun a b => Fin.eq_of_val_eq)]
rw [ findIdx?_eq_map_findFinIdx?_val]
rw [findIdx?_cons]
split
· simp
· rw [findIdx?_eq_map_findFinIdx?_val]
simp [Function.comp_def]
@[simp] theorem findFinIdx?_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findFinIdx? f = (l.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
unfold unattach
induction l with
| nil => simp
| cons a l ih =>
simp [hf, findFinIdx?_cons]
split <;> simp [ih, Function.comp_def]
/-! ### findIdx -/
theorem findIdx_cons (p : α Bool) (b : α) (l : List α) :
@@ -580,7 +672,7 @@ theorem le_findIdx_of_not {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs
/-- If `¬ p xs[j]` for all `j ≤ i`, then `i < xs.findIdx p`. -/
theorem lt_findIdx_of_not {p : α Bool} {xs : List α} {i : Nat} (h : i < xs.length)
(h2 : j (hji : j i), ¬p (xs.get j, Nat.lt_of_le_of_lt hji h)) : i < xs.findIdx p := by
(h2 : j (hji : j i), ¬p (xs[j]'(Nat.lt_of_le_of_lt hji h))) : i < xs.findIdx p := by
apply Decidable.byContradiction
intro f
simp only [Nat.not_lt] at f
@@ -639,37 +731,16 @@ theorem findIdx_le_findIdx {l : List α} {p q : α → Bool} (h : ∀ x ∈ l, p
· simp only [Nat.add_le_add_iff_right]
exact ih fun _ m w => h _ (mem_cons_of_mem x m) w
/-! ### findIdx? -/
@[local simp] private theorem findIdx?_go_nil {p : α Bool} {i : Nat} :
findIdx?.go p [] i = none := rfl
@[local simp] private theorem findIdx?_go_cons :
findIdx?.go p (x :: xs) i = if p x then some i else findIdx?.go p xs (i + 1) := rfl
private theorem findIdx?_go_succ {p : α Bool} {xs : List α} {i : Nat} :
findIdx?.go p xs (i+1) = (findIdx?.go p xs i).map fun i => i + 1 := by
induction xs generalizing i with simp
| cons _ _ _ => split <;> simp_all
private theorem findIdx?_go_eq {p : α Bool} {xs : List α} {i : Nat} :
findIdx?.go p xs (i+1) = (findIdx?.go p xs 0).map fun k => k + (i + 1) := by
induction xs generalizing i with
@[simp] theorem findIdx_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findIdx f = l.unattach.findIdx g := by
unfold unattach
induction l with
| nil => simp
| cons _ _ _ =>
simp only [findIdx?_go_succ, findIdx?_go_cons, Nat.zero_add]
split
· simp_all
· simp_all only [findIdx?_go_succ, Bool.not_eq_true, Option.map_map, Nat.zero_add]
congr
ext
simp only [Nat.add_comm i, Function.comp_apply, Nat.add_assoc]
| cons a l ih =>
simp [ih, hf, findIdx_cons]
@[simp] theorem findIdx?_nil : ([] : List α).findIdx? p = none := rfl
@[simp] theorem findIdx?_cons :
(x :: xs).findIdx? p = if p x then some 0 else (xs.findIdx? p).map fun i => i + 1 := by
simp [findIdx?, findIdx?_go_eq]
/-! ### findIdx? -/
@[simp]
theorem findIdx?_eq_none_iff {xs : List α} {p : α Bool} :
@@ -764,7 +835,7 @@ theorem findIdx?_eq_some_iff_getElem {xs : List α} {p : α → Bool} {i : Nat}
refine i, Nat.succ_lt_succ_iff.mp h, by simpa, fun j hj => ?_, rfl
simpa using h₂ (j + 1) (Nat.succ_lt_succ_iff.mpr hj)
theorem findIdx?_of_eq_some {xs : List α} {p : α Bool} (w : xs.findIdx? p = some i) :
theorem of_findIdx?_eq_some {xs : List α} {p : α Bool} (w : xs.findIdx? p = some i) :
match xs[i]? with | some a => p a | none => false := by
induction xs generalizing i with
| nil => simp_all
@@ -772,7 +843,10 @@ theorem findIdx?_of_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p
simp_all only [findIdx?_cons, Nat.zero_add]
split at w <;> cases i <;> simp_all [succ_inj']
theorem findIdx?_of_eq_none {xs : List α} {p : α Bool} (w : xs.findIdx? p = none) :
@[deprecated of_findIdx?_eq_some (since := "2025-02-02")]
abbrev findIdx?_of_eq_some := @of_findIdx?_eq_some
theorem of_findIdx?_eq_none {xs : List α} {p : α Bool} (w : xs.findIdx? p = none) :
i : Nat, match xs[i]? with | some a => ¬ p a | none => true := by
intro i
induction xs generalizing i with
@@ -787,6 +861,9 @@ theorem findIdx?_of_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p
apply ih
split at w <;> simp_all
@[deprecated of_findIdx?_eq_none (since := "2025-02-02")]
abbrev findIdx?_of_eq_none := @of_findIdx?_eq_none
@[simp] theorem findIdx?_map (f : β α) (l : List β) : findIdx? p (l.map f) = l.findIdx? (p f) := by
induction l with
| nil => simp
@@ -894,24 +971,15 @@ theorem findIdx_eq_getD_findIdx? {xs : List α} {p : α → Bool} :
simp only [findIdx_cons, findIdx?_cons]
split <;> simp_all [ih]
/-! ### findFinIdx? -/
theorem findIdx?_go_eq_map_findFinIdx?_go_val {xs : List α} {p : α Bool} {i : Nat} {h} :
List.findIdx?.go p xs i =
(List.findFinIdx?.go p l xs i h).map (·.val) := by
unfold findIdx?.go
unfold findFinIdx?.go
split <;> rename_i a xs
· simp_all
· simp only
split
· simp
· rw [findIdx?_go_eq_map_findFinIdx?_go_val]
theorem findIdx?_eq_map_findFinIdx?_val {xs : List α} {p : α Bool} :
xs.findIdx? p = (xs.findFinIdx? p).map (·.val) := by
simp [findIdx?, findFinIdx?]
rw [findIdx?_go_eq_map_findFinIdx?_go_val]
@[simp] theorem findIdx?_subtype {p : α Prop} {l : List { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findIdx? f = l.unattach.findIdx? g := by
unfold unattach
induction l with
| nil => simp
| cons a l ih =>
simp [hf, findIdx?_cons]
split <;> simp [ih, Function.comp_def]
/-! ### idxOf
@@ -1101,8 +1169,8 @@ end lookup
@[deprecated head_flatten (since := "2024-10-14")] abbrev head_join := @head_flatten
@[deprecated getLast_flatten (since := "2024-10-14")] abbrev getLast_join := @getLast_flatten
@[deprecated find?_flatten (since := "2024-10-14")] abbrev find?_join := @find?_flatten
@[deprecated find?_flatten_eq_none (since := "2024-10-14")] abbrev find?_join_eq_none := @find?_flatten_eq_none
@[deprecated find?_flatten_eq_some (since := "2024-10-14")] abbrev find?_join_eq_some := @find?_flatten_eq_some
@[deprecated find?_flatten_eq_none (since := "2024-10-14")] abbrev find?_join_eq_none := @find?_flatten_eq_none_iff
@[deprecated find?_flatten_eq_some (since := "2024-10-14")] abbrev find?_join_eq_some := @find?_flatten_eq_some_iff
@[deprecated findIdx?_flatten (since := "2024-10-14")] abbrev findIdx?_join := @findIdx?_flatten
end List

View File

@@ -94,6 +94,9 @@ theorem getElem?_take_of_succ {l : List α} {n : Nat} : (l.take (n + 1))[n]? = l
_ = drop (m + n) l := drop_drop n m l
_ = drop ((m + 1) + n) (a :: l) := by rw [Nat.add_right_comm]; rfl
theorem drop_add_one_eq_tail_drop (l : List α) : l.drop (i + 1) = (l.drop i).tail := by
rw [ drop_drop, drop_one]
theorem take_drop : (m n : Nat) (l : List α), take n (drop m l) = drop m (take (m + n) l)
| 0, _, _ => by simp
| _, _, [] => by simp

View File

@@ -235,6 +235,87 @@ theorem findRevM?_toArray [Monad m] [LawfulMonad m] (f : α → m Bool) (l : Lis
simp only [forIn_cons, Id.pure_eq, Id.bind_eq, find?]
by_cases f a <;> simp_all
private theorem findFinIdx?_loop_toArray (w : l' = l.drop j) :
Array.findFinIdx?.loop p l.toArray j = List.findFinIdx?.go p l l' j h := by
unfold findFinIdx?.loop
unfold findFinIdx?.go
split <;> rename_i h'
· cases l' with
| nil =>
simp at h h'
omega
| cons a l' =>
have : l[j] = a := by
rw [drop_eq_getElem_cons] at w
simp only [cons.injEq] at w
exact w.1.symm
simp only [getElem_toArray, this]
split
· rfl
· simp only [length_cons] at h
have : l.length - (j + 1) < l.length - j := by omega
rw [findFinIdx?_loop_toArray]
rw [drop_add_one_eq_tail_drop, w, tail_cons]
· have : l' = [] := by simp_all
subst this
simp
termination_by l.length - j
@[simp] theorem findFinIdx?_toArray (p : α Bool) (l : List α) :
l.toArray.findFinIdx? p = l.findFinIdx? p := by
rw [Array.findFinIdx?, findFinIdx?, findFinIdx?_loop_toArray]
simp
@[simp] theorem findIdx?_toArray (p : α Bool) (l : List α) :
l.toArray.findIdx? p = l.findIdx? p := by
rw [Array.findIdx?_eq_map_findFinIdx?_val, findIdx?_eq_map_findFinIdx?_val]
simp
private theorem idxAuxOf_toArray [BEq α] (a : α) (l : List α) (j : Nat) (w : l' = l.drop j) (h) :
l.toArray.idxOfAux a j = findFinIdx?.go (fun x => x == a) l l' j h := by
unfold idxOfAux
unfold findFinIdx?.go
split <;> rename_i h'
· cases l' with
| nil =>
simp at h h'
omega
| cons b l' =>
simp at h'
have : l[j] = b := by
rw [drop_eq_getElem_cons h'] at w
simp only [cons.injEq] at w
exact w.1.symm
simp only [getElem_toArray, this]
split
· rfl
· simp only [length_cons] at h
have : l.length - (j + 1) < l.length - j := by omega
rw [idxAuxOf_toArray]
rw [drop_add_one_eq_tail_drop, w, tail_cons]
· have : l' = [] := by simp_all
subst this
simp
termination_by l.length - j
@[simp] theorem finIdxOf?_toArray [BEq α] (a : α) (l : List α) :
l.toArray.finIdxOf? a = l.finIdxOf? a := by
rw [Array.finIdxOf?, finIdxOf?, findFinIdx?]
simp [idxAuxOf_toArray]
@[simp] theorem idxOf?_toArray [BEq α] (a : α) (l : List α) :
l.toArray.idxOf? a = l.idxOf? a := by
rw [Array.idxOf?, idxOf?]
simp [finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
@[simp] theorem findIdx_toArray {as : List α} {p : α Bool} :
as.toArray.findIdx p = as.findIdx p := by
rw [Array.findIdx, findIdx?_toArray, findIdx_eq_getD_findIdx?]
@[simp] theorem idxOf_toArray [BEq α] {as : List α} {a : α} :
as.toArray.idxOf a = as.idxOf a := by
rw [Array.idxOf, findIdx_toArray, idxOf]
theorem isPrefixOfAux_toArray_succ [BEq α] (l₁ l₂ : List α) (hle : l₁.length l₂.length) (i : Nat) :
Array.isPrefixOfAux l₁.toArray l₂.toArray hle (i + 1) =
Array.isPrefixOfAux l₁.tail.toArray l₂.tail.toArray (by simp; omega) i := by
@@ -463,84 +544,6 @@ decreasing_by
· simp
· simp_all [eraseIdx_eq_self.2]
@[simp] theorem findIdx?_toArray {as : List α} {p : α Bool} :
as.toArray.findIdx? p = as.findIdx? p := by
unfold Array.findIdx?
suffices i, i as.length
Array.findIdx?.loop p as.toArray (as.length - i) =
(findIdx? p (as.drop (as.length - i))).map fun j => j + (as.length - i) by
specialize this as.length
simpa
intro i
induction i with
| zero => simp [findIdx?.loop]
| succ i ih =>
unfold findIdx?.loop
simp only [size_toArray, getElem_toArray]
split <;> rename_i h
· rw [drop_eq_getElem_cons h]
rw [findIdx?_cons]
split <;> rename_i h'
· simp
· intro w
have : as.length - (i + 1) + 1 = as.length - i := by omega
specialize ih (by omega)
simp only [Option.map_map, this, ih]
congr
ext
simp
omega
· have : as.length = 0 := by omega
simp_all
@[simp] theorem findFinIdx?_toArray {as : List α} {p : α Bool} :
as.toArray.findFinIdx? p = as.findFinIdx? p := by
have h := findIdx?_toArray (as := as) (p := p)
rw [findIdx?_eq_map_findFinIdx?_val, Array.findIdx?_eq_map_findFinIdx?_val] at h
rwa [Option.map_inj_right] at h
rintro x, hx y, hy rfl
simp
theorem findFinIdx?_go_beq_eq_idxOfAux_toArray [BEq α]
{xs as : List α} {a : α} {i : Nat} {h} (w : as = xs.drop i) :
findFinIdx?.go (fun x => x == a) xs as i h =
xs.toArray.idxOfAux a i := by
unfold findFinIdx?.go
unfold idxOfAux
split <;> rename_i b as
· simp at h
simp [h]
· simp at h
rw [dif_pos (by simp; omega)]
simp only [getElem_toArray]
erw [getElem_drop' (j := 0)]
simp only [ w, getElem_cons_zero]
have : xs.length - (i + 1) < xs.length - i := by omega
rw [findFinIdx?_go_beq_eq_idxOfAux_toArray]
rw [ drop_drop, w]
simp
termination_by xs.length - i
@[simp] theorem finIdxOf?_toArray [BEq α] {as : List α} {a : α} :
as.toArray.finIdxOf? a = as.finIdxOf? a := by
unfold Array.finIdxOf?
unfold finIdxOf?
unfold findFinIdx?
rw [findFinIdx?_go_beq_eq_idxOfAux_toArray]
simp
@[simp] theorem findIdx_toArray [BEq α] {as : List α} {p : α Bool} :
as.toArray.findIdx p = as.findIdx p := by
rw [Array.findIdx, findIdx?_toArray, findIdx_eq_getD_findIdx?]
@[simp] theorem idxOf?_toArray [BEq α] {as : List α} {a : α} :
as.toArray.idxOf? a = as.idxOf? a := by
rw [Array.idxOf?, finIdxOf?_toArray, idxOf?_eq_map_finIdxOf?_val]
@[simp] theorem idxOf_toArray [BEq α] {as : List α} {a : α} :
as.toArray.idxOf a = as.idxOf a := by
rw [Array.idxOf, findIdx_toArray, idxOf]
@[simp] theorem eraseP_toArray {as : List α} {p : α Bool} :
as.toArray.eraseP p = (as.eraseP p).toArray := by
rw [Array.eraseP, List.eraseP_eq_eraseIdx, findFinIdx?_toArray]

View File

@@ -497,7 +497,7 @@ and simplifies these to the function directly taking the value.
(hf : b x h, f b x, h = g b x) :
l.foldl f x = l.unattach.foldl g x := by
rcases l with l, rfl
simp [Array.foldl_subtype (hf := hf)]
simp [Array.foldl_subtype hf]
/--
This lemma identifies folds over arrays of subtypes, where the function only depends on the value, not the proposition,
@@ -508,7 +508,7 @@ and simplifies these to the function directly taking the value.
(hf : x h b, f x, h b = g x b) :
l.foldr f x = l.unattach.foldr g x := by
rcases l with l, rfl
simp [Array.foldr_subtype (hf := hf)]
simp [Array.foldr_subtype hf]
/--
This lemma identifies maps over arrays of subtypes, where the function only depends on the value, not the proposition,
@@ -518,7 +518,21 @@ and simplifies these to the function directly taking the value.
{f : { x // p x } β} {g : α β} (hf : x h, f x, h = g x) :
l.map f = l.unattach.map g := by
rcases l with l, rfl
simp [Array.map_subtype (hf := hf)]
simp [Array.map_subtype hf]
@[simp] theorem findSome?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Option β} {g : α Option β} (hf : x h, f x, h = g x) :
l.findSome? f = l.unattach.findSome? g := by
rcases l with l, rfl
simp
rw [Array.findSome?_subtype hf]
@[simp] theorem find?_subtype {p : α Prop} {l : Array { x // p x }}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
(l.find? f).map Subtype.val = l.unattach.find? g := by
rcases l with l, rfl
simp
rw [Array.find?_subtype hf]
/-! ### Simp lemmas pushing `unattach` inwards. -/

View File

@@ -371,7 +371,7 @@ abbrev indexOf? := @finIdxOf?
/-- Finds the first index of a given value in a vector using a predicate. Returns `none` if the
no element of the index matches the given value. -/
@[inline] def findFinIdx? (v : Vector α n) (p : α Bool) : Option (Fin n) :=
@[inline] def findFinIdx? (p : α Bool) (v : Vector α n) : Option (Fin n) :=
(v.toArray.findFinIdx? p).map (Fin.cast v.size_toArray)
/--
@@ -384,6 +384,28 @@ to avoid having to have the predicate live in `p : α → m (ULift Bool)`.
@[inline] def findSomeM? [Monad m] (f : α m (Option β)) (as : Vector α n) : m (Option β) :=
as.toArray.findSomeM? f
/--
Note that the universe level is contrained to `Type` here,
to avoid having to have the predicate live in `p : α → m (ULift Bool)`.
-/
@[inline] def findRevM? {α : Type} {m : Type Type} [Monad m] (f : α m Bool) (as : Vector α n) : m (Option α) :=
as.toArray.findRevM? f
@[inline] def findSomeRevM? [Monad m] (f : α m (Option β)) (as : Vector α n) : m (Option β) :=
as.toArray.findSomeRevM? f
@[inline] def find? {α : Type} (f : α Bool) (as : Vector α n) : Option α :=
as.toArray.find? f
@[inline] def findRev? {α : Type} (f : α Bool) (as : Vector α n) : Option α :=
as.toArray.findRev? f
@[inline] def findSome? (f : α Option β) (as : Vector α n) : Option β :=
as.toArray.findSome? f
@[inline] def findSomeRev? (f : α Option β) (as : Vector α n) : Option β :=
as.toArray.findSomeRev? f
/-- Returns `true` when `v` is a prefix of the vector `w`. -/
@[inline] def isPrefixOf [BEq α] (v : Vector α m) (w : Vector α n) : Bool :=
v.toArray.isPrefixOf w.toArray

View File

@@ -0,0 +1,262 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Vector.Lemmas
import Init.Data.Vector.Attach
import Init.Data.Vector.Range
import Init.Data.Array.Find
/-!
# Lemmas about `Vector.findSome?`, `Vector.find?, `Vector.findIdx?`, `Vector.idxOf?`.
-/
namespace Vector
open Nat
/-! ### findSome? -/
@[simp] theorem findSomeRev?_push_of_isSome (l : Vector α n) (h : (f a).isSome) : (l.push a).findSomeRev? f = f a := by
rcases l with l, rfl
simp only [push_mk, findSomeRev?_mk, Array.findSomeRev?_push_of_isSome, h]
@[simp] theorem findSomeRev?_push_of_isNone (l : Vector α n) (h : (f a).isNone) : (l.push a).findSomeRev? f = l.findSomeRev? f := by
rcases l with l, rfl
simp only [push_mk, findSomeRev?_mk, Array.findSomeRev?_push_of_isNone, h]
theorem exists_of_findSome?_eq_some {f : α Option β} {l : Vector α n} (w : l.findSome? f = some b) :
a, a l f a = b := by
rcases l with l, rfl
simpa using Array.exists_of_findSome?_eq_some (by simpa using w)
@[simp] theorem findSome?_eq_none_iff {f : α Option β} {l : Vector α n} :
findSome? f l = none x l, f x = none := by
cases l; simp
@[simp] theorem findSome?_isSome_iff {f : α Option β} {l : Vector α n} :
(l.findSome? f).isSome x, x l (f x).isSome := by
cases l; simp
theorem findSome?_eq_some_iff {f : α Option β} {l : Vector α n} {b : β} :
l.findSome? f = some b
(k₁ k₂ : Nat) (w : n = k₁ + 1 + k₂) (l₁ : Vector α k₁) (a : α) (l₂ : Vector α k₂),
l = (l₁.push a ++ l₂).cast w.symm f a = some b x l₁, f x = none := by
rcases l with l, rfl
simp only [findSome?_mk, mk_eq]
rw [Array.findSome?_eq_some_iff]
constructor
· rintro l₁, a, l₂, rfl, h₁, h₂
exact l₁.size, l₂.size, by simp, l₁, rfl, a, l₂, rfl, by simp, h₁, by simpa using h₂
· rintro k₁, k₂, h, l₁, a, l₂, w, h₁, h₂
exact l₁.toArray, a, l₂.toArray, by simp [w], h₁, by simpa using h₂
@[simp] theorem findSome?_guard (l : Vector α n) : findSome? (Option.guard fun x => p x) l = find? p l := by
cases l; simp
theorem find?_eq_findSome?_guard (l : Vector α n) : find? p l = findSome? (Option.guard fun x => p x) l :=
(findSome?_guard l).symm
@[simp] theorem map_findSome? (f : α Option β) (g : β γ) (l : Vector α n) :
(l.findSome? f).map g = l.findSome? (Option.map g f) := by
cases l; simp
theorem findSome?_map (f : β γ) (l : Vector β n) : findSome? p (l.map f) = l.findSome? (p f) := by
rcases l with l, rfl
simp [Array.findSome?_map]
theorem findSome?_append {l₁ : Vector α n₁} {l₂ : Vector α n₂} : (l₁ ++ l₂).findSome? f = (l₁.findSome? f).or (l₂.findSome? f) := by
cases l₁; cases l₂; simp [Array.findSome?_append]
theorem getElem?_zero_flatten (L : Vector (Vector α m) n) :
(flatten L)[0]? = L.findSome? fun l => l[0]? := by
cases L using vector₂_induction
simp [Array.getElem?_zero_flatten, Array.findSome?_map, Function.comp_def]
theorem getElem_zero_flatten.proof {L : Vector (Vector α m) n} (h : 0 < n * m) :
(L.findSome? fun l => l[0]?).isSome := by
cases L using vector₂_induction with
| of xss h₁ h₂ =>
have hn : 0 < n := Nat.pos_of_mul_pos_right h
have hm : 0 < m := Nat.pos_of_mul_pos_left h
simp only [hm, getElem?_eq_getElem, findSome?_mk, Array.findSome?_isSome_iff, Array.mem_map,
Array.mem_attach, mk_eq, true_and, Subtype.exists, exists_prop, exists_eq_right,
Option.isSome_some, and_true]
exact xss[0], h₂ _ (by simp), by simp
theorem getElem_zero_flatten {L : Vector (Vector α m) n} (h : 0 < n * m) :
(flatten L)[0] = (L.findSome? fun l => l[0]?).get (getElem_zero_flatten.proof h) := by
have t := getElem?_zero_flatten L
simp [getElem?_eq_getElem, h] at t
simp [ t]
theorem findSome?_mkVector : findSome? f (mkVector n a) = if n = 0 then none else f a := by
rw [mkVector_eq_mk_mkArray, findSome?_mk, Array.findSome?_mkArray]
@[simp] theorem findSome?_mkVector_of_pos (h : 0 < n) : findSome? f (mkVector n a) = f a := by
simp [findSome?_mkVector, Nat.ne_of_gt h]
-- Argument is unused, but used to decide whether `simp` should unfold.
@[simp] theorem findSome?_mkVector_of_isSome (_ : (f a).isSome) :
findSome? f (mkVector n a) = if n = 0 then none else f a := by
simp [findSome?_mkVector]
@[simp] theorem findSome?_mkVector_of_isNone (h : (f a).isNone) :
findSome? f (mkVector n a) = none := by
rw [Option.isNone_iff_eq_none] at h
simp [findSome?_mkVector, h]
/-! ### find? -/
@[simp] theorem find?_singleton (a : α) (p : α Bool) :
#v[a].find? p = if p a then some a else none := by
simp
@[simp] theorem findRev?_push_of_pos (l : Vector α n) (h : p a) :
findRev? p (l.push a) = some a := by
cases l; simp [h]
@[simp] theorem findRev?_cons_of_neg (l : Vector α n) (h : ¬p a) :
findRev? p (l.push a) = findRev? p l := by
cases l; simp [h]
@[simp] theorem find?_eq_none : find? p l = none x l, ¬ p x := by
cases l; simp
theorem find?_eq_some_iff_append {xs : Vector α n} :
xs.find? p = some b
p b (k₁ k₂ : Nat) (w : n = k₁ + 1 + k₂) (as : Vector α k₁) (bs : Vector α k₂),
xs = (as.push b ++ bs).cast w.symm a as, !p a := by
rcases xs with xs, rfl
simp only [find?_mk, Array.find?_eq_some_iff_append,
mk_eq, toArray_cast, toArray_append, toArray_push]
constructor
· rintro h, as, bs, rfl, w
exact h, as.size, bs.size, by simp, as, rfl, bs, rfl, by simp, by simpa using w
· rintro h, k₁, k₂, w, as, bs, h', w'
exact h, as.toArray, bs.toArray, by simp [h'], by simpa using w'
@[simp]
theorem find?_push_eq_some {xs : Vector α n} :
(xs.push a).find? p = some b xs.find? p = some b (xs.find? p = none (p a a = b)) := by
cases xs; simp
@[simp] theorem find?_isSome {xs : Vector α n} {p : α Bool} : (xs.find? p).isSome x, x xs p x := by
cases xs; simp
theorem find?_some {xs : Vector α n} (h : find? p xs = some a) : p a := by
rcases xs with xs, rfl
simp at h
exact Array.find?_some h
theorem mem_of_find?_eq_some {xs : Vector α n} (h : find? p xs = some a) : a xs := by
cases xs
simp at h
simpa using Array.mem_of_find?_eq_some h
theorem get_find?_mem {xs : Vector α n} (h) : (xs.find? p).get h xs := by
cases xs
simp [Array.get_find?_mem]
@[simp] theorem find?_filter {xs : Vector α n} (p q : α Bool) :
(xs.filter p).find? q = xs.find? (fun a => p a q a) := by
cases xs; simp
@[simp] theorem getElem?_zero_filter (p : α Bool) (l : Vector α n) :
(l.filter p)[0]? = l.find? p := by
cases l; simp [ List.head?_eq_getElem?]
@[simp] theorem getElem_zero_filter (p : α Bool) (l : Vector α n) (h) :
(l.filter p)[0] =
(l.find? p).get (by cases l; simpa [ Array.countP_eq_size_filter] using h) := by
cases l
simp [List.getElem_zero_eq_head]
@[simp] theorem find?_map (f : β α) (xs : Vector β n) :
find? p (xs.map f) = (xs.find? (p f)).map f := by
cases xs; simp
@[simp] theorem find?_append {l₁ : Vector α n₁} {l₂ : Vector α n₂} :
(l₁ ++ l₂).find? p = (l₁.find? p).or (l₂.find? p) := by
cases l₁
cases l₂
simp
@[simp] theorem find?_flatten (xs : Vector (Vector α m) n) (p : α Bool) :
xs.flatten.find? p = xs.findSome? (·.find? p) := by
cases xs using vector₂_induction
simp [Array.findSome?_map, Function.comp_def]
theorem find?_flatten_eq_none_iff {xs : Vector (Vector α m) n} {p : α Bool} :
xs.flatten.find? p = none ys xs, x ys, !p x := by
simp
@[simp] theorem find?_flatMap (xs : Vector α n) (f : α Vector β m) (p : β Bool) :
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
cases xs
simp [Array.find?_flatMap, Array.flatMap_toArray]
theorem find?_flatMap_eq_none_iff {xs : Vector α n} {f : α Vector β m} {p : β Bool} :
(xs.flatMap f).find? p = none x xs, y f x, !p y := by
simp
theorem find?_mkVector :
find? p (mkVector n a) = if n = 0 then none else if p a then some a else none := by
rw [mkVector_eq_mk_mkArray, find?_mk, Array.find?_mkArray]
@[simp] theorem find?_mkVector_of_length_pos (h : 0 < n) :
find? p (mkVector n a) = if p a then some a else none := by
simp [find?_mkVector, Nat.ne_of_gt h]
@[simp] theorem find?_mkVector_of_pos (h : p a) :
find? p (mkVector n a) = if n = 0 then none else some a := by
simp [find?_mkVector, h]
@[simp] theorem find?_mkVector_of_neg (h : ¬ p a) : find? p (mkVector n a) = none := by
simp [find?_mkVector, h]
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
theorem find?_mkVector_eq_none_iff {n : Nat} {a : α} {p : α Bool} :
(mkVector n a).find? p = none n = 0 !p a := by
simp [Classical.or_iff_not_imp_left]
@[simp] theorem find?_mkVector_eq_some_iff {n : Nat} {a b : α} {p : α Bool} :
(mkVector n a).find? p = some b n 0 p a a = b := by
rw [mkVector_eq_mk_mkArray, find?_mk]
simp
@[simp] theorem get_find?_mkVector (n : Nat) (a : α) (p : α Bool) (h) :
((mkVector n a).find? p).get h = a := by
simp only [mkVector_eq_mk_mkArray, find?_mk]
simp
theorem find?_pmap {P : α Prop} (f : (a : α) P a β) (xs : Vector α n)
(H : (a : α), a xs P a) (p : β Bool) :
(xs.pmap f H).find? p = (xs.attach.find? (fun a, m => p (f a (H a m)))).map fun a, m => f a (H a m) := by
simp only [pmap_eq_map_attach, find?_map]
rfl
theorem find?_eq_some_iff_getElem {xs : Vector α n} {p : α Bool} {b : α} :
xs.find? p = some b p b i h, xs[i] = b j : Nat, (hj : j < i) !p xs[j] := by
rcases xs with xs, rfl
simp [Array.find?_eq_some_iff_getElem]
/-! ### findFinIdx? -/
@[simp] theorem findFinIdx?_empty {p : α Bool} : findFinIdx? p (#v[] : Vector α 0) = none := rfl
@[congr] theorem findFinIdx?_congr {p : α Bool} {l₁ : Vector α n} {l₂ : Vector α n} (w : l₁ = l₂) :
findFinIdx? p l₁ = findFinIdx? p l₂ := by
subst w
simp
@[simp] theorem findFinIdx?_subtype {p : α Prop} {l : Vector { x // p x } n}
{f : { x // p x } Bool} {g : α Bool} (hf : x h, f x, h = g x) :
l.findFinIdx? f = l.unattach.findFinIdx? g := by
rcases l with l, rfl
simp [hf, Function.comp_def]
end Vector

View File

@@ -104,6 +104,9 @@ theorem toArray_mk (a : Array α) (h : a.size = n) : (Vector.mk a h).toArray = a
@[simp] theorem finIdxOf?_mk [BEq α] (a : Array α) (h : a.size = n) (x : α) :
(Vector.mk a h).finIdxOf? x = (a.finIdxOf? x).map (Fin.cast h) := rfl
@[simp] theorem findFinIdx?_mk (a : Array α) (h : a.size = n) (f : α Bool) :
(Vector.mk a h).findFinIdx? f = (a.findFinIdx? f).map (Fin.cast h) := rfl
@[deprecated finIdxOf?_mk (since := "2025-01-29")]
abbrev indexOf?_mk := @finIdxOf?_mk
@@ -113,6 +116,24 @@ abbrev indexOf?_mk := @finIdxOf?_mk
@[simp] theorem findSomeM?_mk [Monad m] (a : Array α) (h : a.size = n) (f : α m (Option β)) :
(Vector.mk a h).findSomeM? f = a.findSomeM? f := rfl
@[simp] theorem findRevM?_mk [Monad m] (a : Array α) (h : a.size = n) (f : α m Bool) :
(Vector.mk a h).findRevM? f = a.findRevM? f := rfl
@[simp] theorem findSomeRevM?_mk [Monad m] (a : Array α) (h : a.size = n) (f : α m (Option β)) :
(Vector.mk a h).findSomeRevM? f = a.findSomeRevM? f := rfl
@[simp] theorem find?_mk (a : Array α) (h : a.size = n) (f : α Bool) :
(Vector.mk a h).find? f = a.find? f := rfl
@[simp] theorem findSome?_mk (a : Array α) (h : a.size = n) (f : α Option β) :
(Vector.mk a h).findSome? f = a.findSome? f := rfl
@[simp] theorem findRev?_mk (a : Array α) (h : a.size = n) (f : α Bool) :
(Vector.mk a h).findRev? f = a.findRev? f := rfl
@[simp] theorem findSomeRev?_mk (a : Array α) (h : a.size = n) (f : α Option β) :
(Vector.mk a h).findSomeRev? f = a.findSomeRev? f := rfl
@[simp] theorem mk_isEqv_mk (r : α α Bool) (a b : Array α) (ha : a.size = n) (hb : b.size = n) :
Vector.isEqv (Vector.mk a ha) (Vector.mk b hb) r = Array.isEqv a b r := by
simp [Vector.isEqv, Array.isEqv, ha, hb]
@@ -366,6 +387,56 @@ theorem toArray_mapM_go [Monad m] [LawfulMonad m] (f : α → m β) (v : Vector
cases v
simp
@[simp] theorem find?_toArray (p : α Bool) (v : Vector α n) :
v.toArray.find? p = v.find? p := by
cases v
simp
@[simp] theorem findSome?_toArray (f : α Option β) (v : Vector α n) :
v.toArray.findSome? f = v.findSome? f := by
cases v
simp
@[simp] theorem findRev?_toArray (p : α Bool) (v : Vector α n) :
v.toArray.findRev? p = v.findRev? p := by
cases v
simp
@[simp] theorem findSomeRev?_toArray (f : α Option β) (v : Vector α n) :
v.toArray.findSomeRev? f = v.findSomeRev? f := by
cases v
simp
@[simp] theorem findM?_toArray [Monad m] (p : α m Bool) (v : Vector α n) :
v.toArray.findM? p = v.findM? p := by
cases v
simp
@[simp] theorem findSomeM?_toArray [Monad m] (f : α m (Option β)) (v : Vector α n) :
v.toArray.findSomeM? f = v.findSomeM? f := by
cases v
simp
@[simp] theorem findRevM?_toArray [Monad m] (p : α m Bool) (v : Vector α n) :
v.toArray.findRevM? p = v.findRevM? p := by
rcases v with v, rfl
simp
@[simp] theorem findSomeRevM?_toArray [Monad m] (f : α m (Option β)) (v : Vector α n) :
v.toArray.findSomeRevM? f = v.findSomeRevM? f := by
rcases v with v, rfl
simp
@[simp] theorem finIdxOf?_toArray [BEq α] (a : α) (v : Vector α n) :
v.toArray.finIdxOf? a = (v.finIdxOf? a).map (Fin.cast v.size_toArray.symm) := by
rcases v with v, rfl
simp
@[simp] theorem findFinIdx?_toArray (p : α Bool) (v : Vector α n) :
v.toArray.findFinIdx? p = (v.findFinIdx? p).map (Fin.cast v.size_toArray.symm) := by
rcases v with v, rfl
simp
@[simp] theorem toArray_mkVector : (mkVector n a).toArray = mkArray n a := rfl
@[simp] theorem toArray_inj {v w : Vector α n} : v.toArray = w.toArray v = w := by
@@ -503,6 +574,36 @@ theorem toList_swap (a : Vector α n) (i j) (hi hj) :
cases v
simp
@[simp] theorem find?_toList (p : α Bool) (v : Vector α n) :
v.toList.find? p = v.find? p := by
cases v
simp
@[simp] theorem findSome?_toList (f : α Option β) (v : Vector α n) :
v.toList.findSome? f = v.findSome? f := by
cases v
simp
@[simp] theorem findM?_toList [Monad m] [LawfulMonad m] (p : α m Bool) (v : Vector α n) :
v.toList.findM? p = v.findM? p := by
cases v
simp
@[simp] theorem findSomeM?_toList [Monad m] [LawfulMonad m] (f : α m (Option β)) (v : Vector α n) :
v.toList.findSomeM? f = v.findSomeM? f := by
cases v
simp
@[simp] theorem finIdxOf?_toList [BEq α] (a : α) (v : Vector α n) :
v.toList.finIdxOf? a = (v.finIdxOf? a).map (Fin.cast v.size_toArray.symm) := by
rcases v with v, rfl
simp
@[simp] theorem findFinIdx?_toList (p : α Bool) (v : Vector α n) :
v.toList.findFinIdx? p = (v.findFinIdx? p).map (Fin.cast v.size_toArray.symm) := by
rcases v with v, rfl
simp
@[simp] theorem toList_mkVector : (mkVector n a).toList = List.replicate n a := rfl
theorem toList_inj {v w : Vector α n} : v.toList = w.toList v = w := by
@@ -2215,6 +2316,16 @@ defeq issues in the implicit size argument.
subst h
simp [back]
/-! ### findRev? and findSomeRev? -/
@[simp] theorem findRev?_eq_find?_reverse (f : α Bool) (as : Vector α n) :
findRev? f as = find? f as.reverse := by
simp [findRev?, find?]
@[simp] theorem findSomeRev?_eq_findSome?_reverse (f : α Option β) (as : Vector α n) :
findSomeRev? f as = findSome? f as.reverse := by
simp [findSomeRev?, findSome?]
/-! ### zipWith -/
@[simp] theorem getElem_zipWith (f : α β γ) (a : Vector α n) (b : Vector β n) (i : Nat)