lean4-htt/src/Init/Data/Vector/Lemmas.lean
Kim Morrison bc234f9f8d
feat: align List/Array/Vector.zip/zipWith/zipWithAll/unzip (#6840)
This PR completes the alignment of
`List/Array/Vector.zip/zipWith/zipWithAll/unzip` lemmas.
2025-01-29 07:58:17 +00:00

2274 lines
87 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2024 Shreyas Srinivas. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Shreyas Srinivas, Francois Dorais, Kim Morrison
-/
prelude
import Init.Data.Vector.Basic
import Init.Data.Array.Attach
/-!
## Vectors
Lemmas about `Vector α n`
-/
namespace Array
theorem toVector_inj {a b : Array α} (h₁ : a.size = b.size) (h₂ : a.toVector.cast h₁ = b.toVector) : a = b := by
ext i ih₁ ih₂
· exact h₁
· simpa using congrArg (fun a => a[i]) h₂
end Array
namespace Vector
/-! ### mk lemmas -/
theorem toArray_mk (a : Array α) (h : a.size = n) : (Vector.mk a h).toArray = a := rfl
@[simp] theorem mk_toArray (v : Vector α n) : mk v.toArray v.2 = v := by
rfl
@[simp] theorem getElem_mk {data : Array α} {size : data.size = n} {i : Nat} (h : i < n) :
(Vector.mk data size)[i] = data[i] := rfl
@[simp] theorem getElem?_mk {data : Array α} {size : data.size = n} {i : Nat} :
(Vector.mk data size)[i]? = data[i]? := by
subst size
simp [getElem?_def]
@[simp] theorem mem_mk {data : Array α} {size : data.size = n} {a : α} :
a ∈ Vector.mk data size ↔ a ∈ data :=
⟨fun ⟨h⟩ => h, fun h => ⟨h⟩⟩
@[simp] theorem contains_mk [BEq α] {data : Array α} {size : data.size = n} {a : α} :
(Vector.mk data size).contains a = data.contains a := by
simp [contains]
@[simp] theorem push_mk {data : Array α} {size : data.size = n} {x : α} :
(Vector.mk data size).push x =
Vector.mk (data.push x) (by simp [size, Nat.succ_eq_add_one]) := rfl
@[simp] theorem pop_mk {data : Array α} {size : data.size = n} :
(Vector.mk data size).pop = Vector.mk data.pop (by simp [size]) := rfl
@[simp] theorem mk_beq_mk [BEq α] {a b : Array α} {h : a.size = n} {h' : b.size = n} :
(Vector.mk a h == Vector.mk b h') = (a == b) := by
simp [instBEq, isEqv, Array.instBEq, Array.isEqv, h, h']
@[simp] theorem allDiff_mk [BEq α] (a : Array α) (h : a.size = n) :
(Vector.mk a h).allDiff = a.allDiff := rfl
@[simp] theorem mk_append_mk (a b : Array α) (ha : a.size = n) (hb : b.size = m) :
Vector.mk a ha ++ Vector.mk b hb = Vector.mk (a ++ b) (by simp [ha, hb]) := rfl
@[simp] theorem back!_mk [Inhabited α] (a : Array α) (h : a.size = n) :
(Vector.mk a h).back! = a.back! := rfl
@[simp] theorem back?_mk (a : Array α) (h : a.size = n) :
(Vector.mk a h).back? = a.back? := rfl
@[simp] theorem back_mk [NeZero n] (a : Array α) (h : a.size = n) :
(Vector.mk a h).back =
a[n - 1]'(Nat.lt_of_lt_of_eq (Nat.sub_one_lt (NeZero.ne n)) h.symm) := rfl
@[simp] theorem foldlM_mk [Monad m] (f : β → α → m β) (b : β) (a : Array α) (h : a.size = n) :
(Vector.mk a h).foldlM f b = a.foldlM f b := rfl
@[simp] theorem foldrM_mk [Monad m] (f : α → β → m β) (b : β) (a : Array α) (h : a.size = n) :
(Vector.mk a h).foldrM f b = a.foldrM f b := rfl
@[simp] theorem foldl_mk (f : β → α → β) (b : β) (a : Array α) (h : a.size = n) :
(Vector.mk a h).foldl f b = a.foldl f b := rfl
@[simp] theorem foldr_mk (f : α → β → β) (b : β) (a : Array α) (h : a.size = n) :
(Vector.mk a h).foldr f b = a.foldr f b := rfl
@[simp] theorem drop_mk (a : Array α) (h : a.size = n) (m) :
(Vector.mk a h).drop m = Vector.mk (a.extract m a.size) (by simp [h]) := rfl
@[simp] theorem eraseIdx_mk (a : Array α) (h : a.size = n) (i) (h') :
(Vector.mk a h).eraseIdx i h' = Vector.mk (a.eraseIdx i) (by simp [h]) := rfl
@[simp] theorem eraseIdx!_mk (a : Array α) (h : a.size = n) (i) (hi : i < n) :
(Vector.mk a h).eraseIdx! i = Vector.mk (a.eraseIdx i) (by simp [h, hi]) := by
simp [Vector.eraseIdx!, hi]
@[simp] theorem cast_mk (a : Array α) (h : a.size = n) (h' : n = m) :
(Vector.mk a h).cast h' = Vector.mk a (by simp [h, h']) := rfl
@[simp] theorem extract_mk (a : Array α) (h : a.size = n) (start stop) :
(Vector.mk a h).extract start stop = Vector.mk (a.extract start stop) (by simp [h]) := rfl
@[simp] theorem indexOf?_mk [BEq α] (a : Array α) (h : a.size = n) (x : α) :
(Vector.mk a h).indexOf? x = (a.indexOf? x).map (Fin.cast h) := 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]
@[simp] theorem mk_isPrefixOf_mk [BEq α] (a b : Array α) (ha : a.size = n) (hb : b.size = m) :
(Vector.mk a ha).isPrefixOf (Vector.mk b hb) = a.isPrefixOf b := rfl
@[simp] theorem map_mk (a : Array α) (h : a.size = n) (f : α → β) :
(Vector.mk a h).map f = Vector.mk (a.map f) (by simp [h]) := rfl
@[simp] theorem mapIdx_mk (a : Array α) (h : a.size = n) (f : Nat → α → β) :
(Vector.mk a h).mapIdx f = Vector.mk (a.mapIdx f) (by simp [h]) := rfl
@[simp] theorem mapFinIdx_mk (a : Array α) (h : a.size = n) (f : (i : Nat) → α → (h : i < n) → β) :
(Vector.mk a h).mapFinIdx f =
Vector.mk (a.mapFinIdx fun i a h' => f i a (by simpa [h] using h')) (by simp [h]) := rfl
@[simp] theorem reverse_mk (a : Array α) (h : a.size = n) :
(Vector.mk a h).reverse = Vector.mk a.reverse (by simp [h]) := rfl
@[simp] theorem set_mk (a : Array α) (h : a.size = n) (i x w) :
(Vector.mk a h).set i x = Vector.mk (a.set i x) (by simp [h]) := rfl
@[simp] theorem set!_mk (a : Array α) (h : a.size = n) (i x) :
(Vector.mk a h).set! i x = Vector.mk (a.set! i x) (by simp [h]) := rfl
@[simp] theorem setIfInBounds_mk (a : Array α) (h : a.size = n) (i x) :
(Vector.mk a h).setIfInBounds i x = Vector.mk (a.setIfInBounds i x) (by simp [h]) := rfl
@[simp] theorem swap_mk (a : Array α) (h : a.size = n) (i j) (hi hj) :
(Vector.mk a h).swap i j = Vector.mk (a.swap i j) (by simp [h]) :=
rfl
@[simp] theorem swapIfInBounds_mk (a : Array α) (h : a.size = n) (i j) :
(Vector.mk a h).swapIfInBounds i j = Vector.mk (a.swapIfInBounds i j) (by simp [h]) := rfl
@[simp] theorem swapAt_mk (a : Array α) (h : a.size = n) (i x) (hi) :
(Vector.mk a h).swapAt i x =
((a.swapAt i x).fst, Vector.mk (a.swapAt i x).snd (by simp [h])) :=
rfl
@[simp] theorem swapAt!_mk (a : Array α) (h : a.size = n) (i x) : (Vector.mk a h).swapAt! i x =
((a.swapAt! i x).fst, Vector.mk (a.swapAt! i x).snd (by simp [h])) := rfl
@[simp] theorem take_mk (a : Array α) (h : a.size = n) (m) :
(Vector.mk a h).take m = Vector.mk (a.take m) (by simp [h]) := rfl
@[simp] theorem zipIdx_mk (a : Array α) (h : a.size = n) (k : Nat := 0) :
(Vector.mk a h).zipIdx k = Vector.mk (a.zipIdx k) (by simp [h]) := rfl
@[deprecated zipIdx_mk (since := "2025-01-21")]
abbrev zipWithIndex_mk := @zipIdx_mk
@[simp] theorem mk_zipWith_mk (f : α → β → γ) (a : Array α) (b : Array β)
(ha : a.size = n) (hb : b.size = n) : zipWith f (Vector.mk a ha) (Vector.mk b hb) =
Vector.mk (Array.zipWith f a b) (by simp [ha, hb]) := rfl
@[simp] theorem mk_zip_mk (a : Array α) (b : Array β) (ha : a.size = n) (hb : b.size = n) :
zip (Vector.mk a ha) (Vector.mk b hb) = Vector.mk (Array.zip a b) (by simp [ha, hb]) := rfl
@[simp] theorem unzip_mk (a : Array (α × β)) (h : a.size = n) :
(Vector.mk a h).unzip = (Vector.mk a.unzip.1 (by simp_all), Vector.mk a.unzip.2 (by simp_all)) := rfl
@[simp] theorem anyM_mk [Monad m] (p : α → m Bool) (a : Array α) (h : a.size = n) :
(Vector.mk a h).anyM p = a.anyM p := rfl
@[simp] theorem allM_mk [Monad m] (p : α → m Bool) (a : Array α) (h : a.size = n) :
(Vector.mk a h).allM p = a.allM p := rfl
@[simp] theorem any_mk (p : α → Bool) (a : Array α) (h : a.size = n) :
(Vector.mk a h).any p = a.any p := rfl
@[simp] theorem all_mk (p : α → Bool) (a : Array α) (h : a.size = n) :
(Vector.mk a h).all p = a.all p := rfl
@[simp] theorem countP_mk (p : α → Bool) (a : Array α) (h : a.size = n) :
(Vector.mk a h).countP p = a.countP p := rfl
@[simp] theorem count_mk [BEq α] (a : Array α) (h : a.size = n) (b : α) :
(Vector.mk a h).count b = a.count b := rfl
@[simp] theorem eq_mk : v = Vector.mk a h ↔ v.toArray = a := by
cases v
simp
@[simp] theorem mk_eq : Vector.mk a h = v ↔ a = v.toArray := by
cases v
simp
/-! ### toArray lemmas -/
@[simp] theorem getElem_toArray {α n} (xs : Vector α n) (i : Nat) (h : i < xs.toArray.size) :
xs.toArray[i] = xs[i]'(by simpa using h) := by
cases xs
simp
@[simp] theorem getElem?_toArray {α n} (xs : Vector α n) (i : Nat) :
xs.toArray[i]? = xs[i]? := by
cases xs
simp
@[simp] theorem toArray_append (a : Vector α m) (b : Vector α n) :
(a ++ b).toArray = a.toArray ++ b.toArray := rfl
@[simp] theorem toArray_drop (a : Vector α n) (m) :
(a.drop m).toArray = a.toArray.extract m a.size := rfl
@[simp] theorem toArray_empty : (#v[] : Vector α 0).toArray = #[] := rfl
@[simp] theorem toArray_mkEmpty (cap) :
(Vector.mkEmpty (α := α) cap).toArray = Array.mkEmpty cap := rfl
@[simp] theorem toArray_eraseIdx (a : Vector α n) (i) (h) :
(a.eraseIdx i h).toArray = a.toArray.eraseIdx i (by simp [h]) := rfl
@[simp] theorem toArray_eraseIdx! (a : Vector α n) (i) (hi : i < n) :
(a.eraseIdx! i).toArray = a.toArray.eraseIdx! i := by
cases a; simp_all [Array.eraseIdx!]
@[simp] theorem toArray_cast (a : Vector α n) (h : n = m) :
(a.cast h).toArray = a.toArray := rfl
@[simp] theorem toArray_extract (a : Vector α n) (start stop) :
(a.extract start stop).toArray = a.toArray.extract start stop := rfl
@[simp] theorem toArray_map (f : α → β) (a : Vector α n) :
(a.map f).toArray = a.toArray.map f := rfl
@[simp] theorem toArray_mapIdx (f : Nat → α → β) (a : Vector α n) :
(a.mapIdx f).toArray = a.toArray.mapIdx f := rfl
@[simp] theorem toArray_mapFinIdx (f : (i : Nat) → α → (h : i < n) → β) (v : Vector α n) :
(v.mapFinIdx f).toArray =
v.toArray.mapFinIdx (fun i a h => f i a (by simpa [v.size_toArray] using h)) :=
rfl
@[simp] theorem toArray_ofFn (f : Fin n → α) : (Vector.ofFn f).toArray = Array.ofFn f := rfl
@[simp] theorem toArray_pop (a : Vector α n) : a.pop.toArray = a.toArray.pop := rfl
@[simp] theorem toArray_push (a : Vector α n) (x) : (a.push x).toArray = a.toArray.push x := rfl
@[simp] theorem toArray_beq_toArray [BEq α] (a : Vector α n) (b : Vector α n) :
(a.toArray == b.toArray) = (a == b) := by
simp [instBEq, isEqv, Array.instBEq, Array.isEqv, a.2, b.2]
@[simp] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
@[simp] theorem toArray_reverse (a : Vector α n) : a.reverse.toArray = a.toArray.reverse := rfl
@[simp] theorem toArray_set (a : Vector α n) (i x h) :
(a.set i x).toArray = a.toArray.set i x (by simpa using h):= rfl
@[simp] theorem toArray_set! (a : Vector α n) (i x) :
(a.set! i x).toArray = a.toArray.set! i x := rfl
@[simp] theorem toArray_setIfInBounds (a : Vector α n) (i x) :
(a.setIfInBounds i x).toArray = a.toArray.setIfInBounds i x := rfl
@[simp] theorem toArray_singleton (x : α) : (Vector.singleton x).toArray = #[x] := rfl
@[simp] theorem toArray_swap (a : Vector α n) (i j) (hi hj) : (a.swap i j).toArray =
a.toArray.swap i j (by simp [hi, hj]) (by simp [hi, hj]) := rfl
@[simp] theorem toArray_swapIfInBounds (a : Vector α n) (i j) :
(a.swapIfInBounds i j).toArray = a.toArray.swapIfInBounds i j := rfl
@[simp] theorem toArray_swapAt (a : Vector α n) (i x h) :
((a.swapAt i x).fst, (a.swapAt i x).snd.toArray) =
((a.toArray.swapAt i x (by simpa using h)).fst,
(a.toArray.swapAt i x (by simpa using h)).snd) := rfl
@[simp] theorem toArray_swapAt! (a : Vector α n) (i x) :
((a.swapAt! i x).fst, (a.swapAt! i x).snd.toArray) =
((a.toArray.swapAt! i x).fst, (a.toArray.swapAt! i x).snd) := rfl
@[simp] theorem toArray_take (a : Vector α n) (m) : (a.take m).toArray = a.toArray.take m := rfl
@[simp] theorem toArray_zipIdx (a : Vector α n) (k : Nat := 0) :
(a.zipIdx k).toArray = a.toArray.zipIdx k := rfl
@[simp] theorem toArray_zipWith (f : α → β → γ) (a : Vector α n) (b : Vector β n) :
(Vector.zipWith f a b).toArray = Array.zipWith f a.toArray b.toArray := rfl
@[simp] theorem anyM_toArray [Monad m] (p : α → m Bool) (v : Vector α n) :
v.toArray.anyM p = v.anyM p := by
cases v
simp
@[simp] theorem allM_toArray [Monad m] (p : α → m Bool) (v : Vector α n) :
v.toArray.allM p = v.allM p := by
cases v
simp
@[simp] theorem any_toArray (p : α → Bool) (v : Vector α n) :
v.toArray.any p = v.any p := by
cases v
simp
@[simp] theorem all_toArray (p : α → Bool) (v : Vector α n) :
v.toArray.all p = v.all p := by
cases v
simp
@[simp] theorem countP_toArray (p : α → Bool) (v : Vector α n) :
v.toArray.countP p = v.countP p := by
cases v
simp
@[simp] theorem count_toArray [BEq α] (a : α) (v : Vector α n) :
v.toArray.count a = v.count a := by
cases v
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
cases v
cases w
simp
/--
`Vector.ext` is an extensionality theorem.
Vectors `a` and `b` are equal to each other if their elements are equal for each valid index.
-/
@[ext]
protected theorem ext {a b : Vector α n} (h : (i : Nat) → (_ : i < n) → a[i] = b[i]) : a = b := by
apply Vector.toArray_inj.1
apply Array.ext
· rw [a.size_toArray, b.size_toArray]
· intro i hi _
rw [a.size_toArray] at hi
exact h i hi
@[simp] theorem toArray_eq_empty_iff (v : Vector α n) : v.toArray = #[] ↔ n = 0 := by
rcases v with ⟨v, h⟩
exact ⟨by rintro rfl; simp_all, by rintro rfl; simpa using h⟩
/-! ### toList -/
theorem toArray_toList (a : Vector α n) : a.toArray.toList = a.toList := rfl
@[simp] theorem getElem_toList {α n} (xs : Vector α n) (i : Nat) (h : i < xs.toList.length) :
xs.toList[i] = xs[i]'(by simpa using h) := by
cases xs
simp
@[simp] theorem getElem?_toList {α n} (xs : Vector α n) (i : Nat) :
xs.toList[i]? = xs[i]? := by
cases xs
simp
theorem toList_append (a : Vector α m) (b : Vector α n) :
(a ++ b).toList = a.toList ++ b.toList := by simp
@[simp] theorem toList_drop (a : Vector α n) (m) :
(a.drop m).toList = a.toList.drop m := by
simp [List.take_of_length_le]
theorem toList_empty : (#v[] : Vector α 0).toArray = #[] := by simp
theorem toList_mkEmpty (cap) :
(Vector.mkEmpty (α := α) cap).toList = [] := rfl
theorem toList_eraseIdx (a : Vector α n) (i) (h) :
(a.eraseIdx i h).toList = a.toList.eraseIdx i := by simp
@[simp] theorem toList_eraseIdx! (a : Vector α n) (i) (hi : i < n) :
(a.eraseIdx! i).toList = a.toList.eraseIdx i := by
cases a; simp_all [Array.eraseIdx!]
theorem toList_cast (a : Vector α n) (h : n = m) :
(a.cast h).toList = a.toList := rfl
theorem toList_extract (a : Vector α n) (start stop) :
(a.extract start stop).toList = (a.toList.drop start).take (stop - start) := by
simp
theorem toList_map (f : α → β) (a : Vector α n) :
(a.map f).toList = a.toList.map f := by simp
theorem toList_mapIdx (f : Nat → α → β) (a : Vector α n) :
(a.mapIdx f).toList = a.toList.mapIdx f := by simp
theorem toList_mapFinIdx (f : (i : Nat) → α → (h : i < n) → β) (v : Vector α n) :
(v.mapFinIdx f).toList =
v.toList.mapFinIdx (fun i a h => f i a (by simpa [v.size_toArray] using h)) := by
simp
theorem toList_ofFn (f : Fin n → α) : (Vector.ofFn f).toList = List.ofFn f := by simp
theorem toList_pop (a : Vector α n) : a.pop.toList = a.toList.dropLast := rfl
theorem toList_push (a : Vector α n) (x) : (a.push x).toList = a.toList ++ [x] := by simp
@[simp] theorem toList_beq_toList [BEq α] (a : Vector α n) (b : Vector α n) :
(a.toList == b.toList) = (a == b) := by
simp [instBEq, isEqv, Array.instBEq, Array.isEqv, a.2, b.2]
theorem toList_range : (Vector.range n).toList = List.range n := by simp
theorem toList_reverse (a : Vector α n) : a.reverse.toList = a.toList.reverse := by simp
theorem toList_set (a : Vector α n) (i x h) :
(a.set i x).toList = a.toList.set i x := rfl
@[simp] theorem toList_setIfInBounds (a : Vector α n) (i x) :
(a.setIfInBounds i x).toList = a.toList.set i x := by
simp [Vector.setIfInBounds]
theorem toList_singleton (x : α) : (Vector.singleton x).toList = [x] := rfl
theorem toList_swap (a : Vector α n) (i j) (hi hj) :
(a.swap i j).toList = (a.toList.set i a[j]).set j a[i] := rfl
@[simp] theorem toList_take (a : Vector α n) (m) : (a.take m).toList = a.toList.take m := by
simp [List.take_of_length_le]
@[simp] theorem toList_zipWith (f : α → β → γ) (a : Vector α n) (b : Vector β n) :
(Vector.zipWith f a b).toArray = Array.zipWith f a.toArray b.toArray := rfl
@[simp] theorem anyM_toList [Monad m] (p : α → m Bool) (v : Vector α n) :
v.toList.anyM p = v.anyM p := by
cases v
simp
@[simp] theorem allM_toList [Monad m] [LawfulMonad m] (p : α → m Bool) (v : Vector α n) :
v.toList.allM p = v.allM p := by
cases v
simp
@[simp] theorem any_toList (p : α → Bool) (v : Vector α n) :
v.toList.any p = v.any p := by
cases v
simp
@[simp] theorem all_toList (p : α → Bool) (v : Vector α n) :
v.toList.all p = v.all p := by
cases v
simp
@[simp] theorem countP_toList (p : α → Bool) (v : Vector α n) :
v.toList.countP p = v.countP p := by
cases v
simp
@[simp] theorem count_toList [BEq α] (a : α) (v : Vector α n) :
v.toList.count a = v.count a := by
cases v
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
cases v
cases w
simp [Array.toList_inj]
@[simp] theorem toList_eq_empty_iff (v : Vector α n) : v.toList = [] ↔ n = 0 := by
rcases v with ⟨v, h⟩
simp only [Array.toList_eq_nil_iff]
exact ⟨by rintro rfl; simp_all, by rintro rfl; simpa using h⟩
@[simp] theorem mem_toList_iff (a : α) (v : Vector α n) : a ∈ v.toList ↔ a ∈ v := by
simp
theorem length_toList {α n} (xs : Vector α n) : xs.toList.length = n := by simp
/-! ### empty -/
@[simp] theorem empty_eq {xs : Vector α 0} : #v[] = xs ↔ xs = #v[] := by
cases xs
simp
/-- A vector of length `0` is the empty vector. -/
protected theorem eq_empty (v : Vector α 0) : v = #v[] := by
apply Vector.toArray_inj.1
apply Array.eq_empty_of_size_eq_zero v.2
/-! ### size -/
theorem eq_empty_of_size_eq_zero (xs : Vector α n) (h : n = 0) : xs = #v[].cast h.symm := by
rcases xs with ⟨xs, rfl⟩
apply toArray_inj.1
simp only [List.length_eq_zero, Array.toList_eq_nil_iff] at h
simp [h]
theorem size_eq_one {xs : Vector α 1} : ∃ a, xs = #v[a] := by
rcases xs with ⟨xs, h⟩
simpa using Array.size_eq_one.mp h
/-! ### push -/
theorem back_eq_of_push_eq {a b : α} {xs ys : Vector α n} (h : xs.push a = ys.push b) : a = b := by
cases xs
cases ys
replace h := congrArg Vector.toArray h
simp only [push_mk] at h
apply Array.back_eq_of_push_eq h
theorem pop_eq_of_push_eq {a b : α} {xs ys : Vector α n} (h : xs.push a = ys.push b) : xs = ys := by
cases xs
cases ys
replace h := congrArg Vector.toArray h
simp only [push_mk] at h
simpa using Array.pop_eq_of_push_eq h
theorem push_inj_left {a : α} {xs ys : Vector α n} : xs.push a = ys.push a ↔ xs = ys :=
⟨pop_eq_of_push_eq, fun h => by simp [h]⟩
theorem push_inj_right {a b : α} {xs : Vector α n} : xs.push a = xs.push b ↔ a = b :=
⟨back_eq_of_push_eq, fun h => by simp [h]⟩
theorem push_eq_push {a b : α} {xs ys : Vector α n} : xs.push a = ys.push b ↔ a = b ∧ xs = ys := by
constructor
· intro h
exact ⟨back_eq_of_push_eq h, pop_eq_of_push_eq h⟩
· rintro ⟨rfl, rfl⟩
rfl
theorem exists_push {xs : Vector α (n + 1)} :
∃ (ys : Vector α n) (a : α), xs = ys.push a := by
rcases xs with ⟨xs, w⟩
obtain ⟨ys, a, h⟩ := Array.exists_push_of_size_eq_add_one w
exact ⟨⟨ys, by simp_all⟩, a, toArray_inj.1 h⟩
theorem singleton_inj : #v[a] = #v[b] ↔ a = b := by
simp
/-! ### cast -/
@[simp] theorem getElem_cast (a : Vector α n) (h : n = m) (i : Nat) (hi : i < m) :
(a.cast h)[i] = a[i] := by
cases a
simp
@[simp] theorem getElem?_cast {l : Vector α n} {m : Nat} {w : n = m} {i : Nat} :
(l.cast w)[i]? = l[i]? := by
rcases l with ⟨l, rfl⟩
simp
@[simp] theorem mem_cast {a : α} {l : Vector α n} {m : Nat} {w : n = m} :
a ∈ l.cast w ↔ a ∈ l := by
rcases l with ⟨l, rfl⟩
simp
@[simp] theorem cast_cast {l : Vector α n} {w : n = m} {w' : m = k} :
(l.cast w).cast w' = l.cast (w.trans w') := by
rcases l with ⟨l, rfl⟩
simp
@[simp] theorem cast_rfl {l : Vector α n} : l.cast rfl = l := by
rcases l with ⟨l, rfl⟩
simp
/-! ### mkVector -/
@[simp] theorem mkVector_zero : mkVector 0 a = #v[] := rfl
theorem mkVector_succ : mkVector (n + 1) a = (mkVector n a).push a := by
simp [mkVector, Array.mkArray_succ]
@[simp] theorem mkVector_inj : mkVector n a = mkVector n b ↔ n = 0 a = b := by
simp [← toArray_inj, toArray_mkVector, Array.mkArray_inj]
@[simp] theorem _root_.Array.toVector_mkArray (a : α) (n : Nat) :
(Array.mkArray n a).toVector = (mkVector n a).cast (by simp) := rfl
theorem mkVector_eq_toVector_mkArray (a : α) (n : Nat) :
mkVector n a = (Array.mkArray n a).toVector.cast (by simp) := by
simp
/-! ## L[i] and L[i]? -/
@[simp] theorem getElem?_eq_none_iff {a : Vector α n} : a[i]? = none ↔ n ≤ i := by
by_cases h : i < n
· simp [getElem?_pos, h]
· rw [getElem?_neg a i h]
simp_all
@[simp] theorem none_eq_getElem?_iff {a : Vector α n} {i : Nat} : none = a[i]? ↔ n ≤ i := by
simp [eq_comm (a := none)]
theorem getElem?_eq_none {a : Vector α n} (h : n ≤ i) : a[i]? = none := by
simp [getElem?_eq_none_iff, h]
@[simp] theorem getElem?_eq_getElem {a : Vector α n} {i : Nat} (h : i < n) : a[i]? = some a[i] :=
getElem?_pos ..
theorem getElem?_eq_some_iff {a : Vector α n} : a[i]? = some b ↔ ∃ h : i < n, a[i] = b := by
simp [getElem?_def]
theorem some_eq_getElem?_iff {a : Vector α n} : some b = a[i]? ↔ ∃ h : i < n, a[i] = b := by
rw [eq_comm, getElem?_eq_some_iff]
@[simp] theorem some_getElem_eq_getElem?_iff (a : Vector α n) (i : Nat) (h : i < n) :
(some a[i] = a[i]?) ↔ True := by
simp [h]
@[simp] theorem getElem?_eq_some_getElem_iff (a : Vector α n) (i : Nat) (h : i < n) :
(a[i]? = some a[i]) ↔ True := by
simp [h]
theorem getElem_eq_iff {a : Vector α n} {i : Nat} {h : i < n} : a[i] = x ↔ a[i]? = some x := by
simp only [getElem?_eq_some_iff]
exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩
theorem getElem_eq_getElem?_get (a : Vector α n) (i : Nat) (h : i < n) :
a[i] = a[i]?.get (by simp [getElem?_eq_getElem, h]) := by
simp [getElem_eq_iff]
theorem getD_getElem? (a : Vector α n) (i : Nat) (d : α) :
a[i]?.getD d = if p : i < n then a[i]'p else d := by
if h : i < n then
simp [h, getElem?_def]
else
have p : i ≥ n := Nat.le_of_not_gt h
simp [getElem?_eq_none p, h]
@[simp] theorem getElem?_empty {n : Nat} : (#v[] : Vector α 0)[n]? = none := rfl
@[simp] theorem getElem_push_lt {v : Vector α n} {x : α} {i : Nat} (h : i < n) :
(v.push x)[i] = v[i] := by
rcases v with ⟨data, rfl⟩
simp [Array.getElem_push_lt, h]
@[simp] theorem getElem_push_eq (a : Vector α n) (x : α) : (a.push x)[n] = x := by
rcases a with ⟨a, rfl⟩
simp
theorem getElem_push (a : Vector α n) (x : α) (i : Nat) (h : i < n + 1) :
(a.push x)[i] = if h : i < n then a[i] else x := by
rcases a with ⟨a, rfl⟩
simp [Array.getElem_push]
theorem getElem?_push {a : Vector α n} {x} : (a.push x)[i]? = if i = n then some x else a[i]? := by
simp [getElem?_def, getElem_push]
(repeat' split) <;> first | rfl | omega
@[simp] theorem getElem?_push_size {a : Vector α n} {x} : (a.push x)[n]? = some x := by
simp [getElem?_push]
@[simp] theorem getElem_singleton (a : α) (h : i < 1) : #v[a][i] = a :=
match i, h with
| 0, _ => rfl
theorem getElem?_singleton (a : α) (i : Nat) : #v[a][i]? = if i = 0 then some a else none := by
simp [List.getElem?_singleton]
/-! ### mem -/
@[simp] theorem getElem_mem {l : Vector α n} {i : Nat} (h : i < n) : l[i] ∈ l := by
rcases l with ⟨l, rfl⟩
simp
@[simp] theorem not_mem_empty (a : α) : ¬ a ∈ #v[] := nofun
@[simp] theorem mem_push {a : Vector α n} {x y : α} : x ∈ a.push y ↔ x ∈ a x = y := by
cases a
simp
theorem mem_push_self {a : Vector α n} {x : α} : x ∈ a.push x :=
mem_push.2 (Or.inr rfl)
theorem eq_push_append_of_mem {xs : Vector α n} {x : α} (h : x ∈ xs) :
∃ (n₁ n₂ : Nat) (as : Vector α n₁) (bs : Vector α n₂) (h : n₁ + 1 + n₂ = n),
xs = (as.push x ++ bs).cast h ∧ x ∉ as:= by
rcases xs with ⟨xs, rfl⟩
obtain ⟨as, bs, h, w⟩ := Array.eq_push_append_of_mem (by simpa using h)
simp only at h
obtain rfl := h
exact ⟨_, _, as.toVector, bs.toVector, by simp, by simp, by simpa using w⟩
theorem mem_push_of_mem {a : Vector α n} {x : α} (y : α) (h : x ∈ a) : x ∈ a.push y :=
mem_push.2 (Or.inl h)
theorem exists_mem_of_size_pos (l : Vector α n) (h : 0 < n) : ∃ x, x ∈ l := by
simpa using List.exists_mem_of_ne_nil l.toList (by simpa using (Nat.ne_of_gt h))
theorem size_zero_iff_forall_not_mem {l : Vector α n} : n = 0 ↔ ∀ a, a ∉ l := by
simpa using List.eq_nil_iff_forall_not_mem (l := l.toList)
@[simp] theorem mem_dite_empty_left {x : α} [Decidable p] {l : ¬ p → Vector α 0} :
(x ∈ if h : p then #v[] else l h) ↔ ∃ h : ¬ p, x ∈ l h := by
split <;> simp_all
@[simp] theorem mem_dite_empty_right {x : α} [Decidable p] {l : p → Vector α 0} :
(x ∈ if h : p then l h else #v[]) ↔ ∃ h : p, x ∈ l h := by
split <;> simp_all
@[simp] theorem mem_ite_empty_left {x : α} [Decidable p] {l : Vector α 0} :
(x ∈ if p then #v[] else l) ↔ ¬ p ∧ x ∈ l := by
split <;> simp_all
@[simp] theorem mem_ite_empty_right {x : α} [Decidable p] {l : Vector α 0} :
(x ∈ if p then l else #v[]) ↔ p ∧ x ∈ l := by
split <;> simp_all
theorem eq_of_mem_singleton (h : a ∈ #v[b]) : a = b := by
simpa using h
@[simp] theorem mem_singleton {a b : α} : a ∈ #v[b] ↔ a = b :=
⟨eq_of_mem_singleton, (by simp [·])⟩
theorem forall_mem_push {p : α → Prop} {xs : Vector α n} {a : α} :
(∀ x, x ∈ xs.push a → p x) ↔ p a ∧ ∀ x, x ∈ xs → p x := by
cases xs
simp [or_comm, forall_eq_or_imp]
theorem forall_mem_ne {a : α} {l : Vector α n} : (∀ a' : α, a' ∈ l → ¬a = a') ↔ a ∉ l :=
⟨fun h m => h _ m rfl, fun h _ m e => h (e.symm ▸ m)⟩
theorem forall_mem_ne' {a : α} {l : Vector α n} : (∀ a' : α, a' ∈ l → ¬a' = a) ↔ a ∉ l :=
⟨fun h m => h _ m rfl, fun h _ m e => h (e.symm ▸ m)⟩
theorem exists_mem_empty (p : α → Prop) : ¬ (∃ x, ∃ _ : x ∈ #v[], p x) := nofun
theorem forall_mem_empty (p : α → Prop) : ∀ (x) (_ : x ∈ #v[]), p x := nofun
theorem exists_mem_push {p : α → Prop} {a : α} {xs : Vector α n} :
(∃ x, ∃ _ : x ∈ xs.push a, p x) ↔ p a ∃ x, ∃ _ : x ∈ xs, p x := by
simp only [mem_push, exists_prop]
constructor
· rintro ⟨x, (h | rfl), h'⟩
· exact .inr ⟨x, h, h'⟩
· exact .inl h'
· rintro (h | ⟨x, h, h'⟩)
· exact ⟨a, by simp, h⟩
· exact ⟨x, .inl h, h'⟩
theorem forall_mem_singleton {p : α → Prop} {a : α} : (∀ (x) (_ : x ∈ #v[a]), p x) ↔ p a := by
simp only [mem_singleton, forall_eq]
theorem mem_empty_iff (a : α) : a ∈ (#v[] : Vector α 0) ↔ False := by simp
theorem mem_singleton_self (a : α) : a ∈ #v[a] := by simp
theorem mem_of_mem_push_of_mem {a b : α} {l : Vector α n} : a ∈ l.push b → b ∈ l → a ∈ l := by
rcases l with ⟨l, rfl⟩
simpa using Array.mem_of_mem_push_of_mem
theorem eq_or_ne_mem_of_mem {a b : α} {l : Vector α n} (h' : a ∈ l.push b) :
a = b (a ≠ b ∧ a ∈ l) := by
if h : a = b then
exact .inl h
else
simp only [mem_push, h, or_false] at h'
exact .inr ⟨h, h'⟩
theorem size_ne_zero_of_mem {a : α} {l : Vector α n} (h : a ∈ l) : n ≠ 0 := by
rcases l with ⟨l, rfl⟩
simpa using Array.ne_empty_of_mem (by simpa using h)
theorem mem_of_ne_of_mem {a y : α} {l : Vector α n} (h₁ : a ≠ y) (h₂ : a ∈ l.push y) : a ∈ l := by
simpa [h₁] using h₂
theorem ne_of_not_mem_push {a b : α} {l : Vector α n} (h : a ∉ l.push b) : a ≠ b := by
simp only [mem_push, not_or] at h
exact h.2
theorem not_mem_of_not_mem_push {a b : α} {l : Vector α n} (h : a ∉ l.push b) : a ∉ l := by
simp only [mem_push, not_or] at h
exact h.1
theorem not_mem_push_of_ne_of_not_mem {a y : α} {l : Vector α n} : a ≠ y → a ∉ l → a ∉ l.push y :=
mt ∘ mem_of_ne_of_mem
theorem ne_and_not_mem_of_not_mem_push {a y : α} {l : Vector α n} : a ∉ l.push y → a ≠ y ∧ a ∉ l := by
simp +contextual
theorem getElem_of_mem {a} {l : Vector α n} (h : a ∈ l) : ∃ (i : Nat) (h : i < n), l[i]'h = a := by
rcases l with ⟨l, rfl⟩
simpa using Array.getElem_of_mem (by simpa using h)
theorem getElem?_of_mem {a} {l : Vector α n} (h : a ∈ l) : ∃ i : Nat, l[i]? = some a :=
let ⟨n, _, e⟩ := getElem_of_mem h; ⟨n, e ▸ getElem?_eq_getElem _⟩
theorem mem_of_getElem {l : Vector α n} {i : Nat} {h} {a : α} (e : l[i] = a) : a ∈ l := by
subst e
simp
theorem mem_of_getElem? {l : Vector α n} {i : Nat} {a : α} (e : l[i]? = some a) : a ∈ l :=
let ⟨_, e⟩ := getElem?_eq_some_iff.1 e; e ▸ getElem_mem ..
theorem mem_of_back? {xs : Vector α n} {a : α} (h : xs.back? = some a) : a ∈ xs := by
cases xs
simpa using Array.mem_of_back? (by simpa using h)
theorem mem_iff_getElem {a} {l : Vector α n} : a ∈ l ↔ ∃ (i : Nat) (h : i < n), l[i]'h = a :=
⟨getElem_of_mem, fun ⟨_, _, e⟩ => e ▸ getElem_mem ..⟩
theorem mem_iff_getElem? {a} {l : Vector α n} : a ∈ l ↔ ∃ i : Nat, l[i]? = some a := by
simp [getElem?_eq_some_iff, mem_iff_getElem]
theorem forall_getElem {l : Vector α n} {p : α → Prop} :
(∀ (i : Nat) h, p (l[i]'h)) ↔ ∀ a, a ∈ l → p a := by
rcases l with ⟨l, rfl⟩
simp [Array.forall_getElem]
/-! ### Decidability of bounded quantifiers -/
instance {xs : Vector α n} {p : α → Prop} [DecidablePred p] :
Decidable (∀ x, x ∈ xs → p x) :=
decidable_of_iff (∀ (i : Nat) h, p (xs[i]'h)) (by
simp only [mem_iff_getElem, forall_exists_index]
exact
⟨by rintro w _ i h rfl; exact w i h, fun w i h => w _ i h rfl⟩)
instance {xs : Vector α n} {p : α → Prop} [DecidablePred p] :
Decidable (∃ x, x ∈ xs ∧ p x) :=
decidable_of_iff (∃ (i : Nat), ∃ (h : i < n), p (xs[i]'h)) (by
simp [mem_iff_getElem]
exact
⟨by rintro ⟨i, h, w⟩; exact ⟨_, ⟨i, h, rfl⟩, w⟩, fun ⟨_, ⟨i, h, rfl⟩, w⟩ => ⟨i, h, w⟩⟩)
/-! ### any / all -/
theorem any_iff_exists {p : α → Bool} {xs : Vector α n} :
xs.any p ↔ ∃ (i : Nat) (_ : i < n), p xs[i] := by
rcases xs with ⟨xs, rfl⟩
simp [Array.any_iff_exists]
theorem all_iff_forall {p : α → Bool} {xs : Vector α n} :
xs.all p ↔ ∀ (i : Nat) (_ : i < n), p xs[i] := by
rcases xs with ⟨xs, rfl⟩
simp [Array.all_iff_forall]
theorem any_eq_true {p : α → Bool} {xs : Vector α n} :
xs.any p = true ↔ ∃ (i : Nat) (_ : i < n), p xs[i] := by
simp [any_iff_exists]
theorem any_eq_false {p : α → Bool} {xs : Vector α n} :
xs.any p = false ↔ ∀ (i : Nat) (_ : i < n), ¬p xs[i] := by
rw [Bool.eq_false_iff, Ne, any_eq_true]
simp
theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] {p : α → m Bool} {xs : Vector α n} :
xs.allM p = (! ·) <$> xs.anyM ((! ·) <$> p ·) := by
rcases xs with ⟨xs, rfl⟩
simp [Array.allM_eq_not_anyM_not]
theorem all_eq_not_any_not {p : α → Bool} {xs : Vector α n} :
xs.all p = !(xs.any (!p ·)) := by
rcases xs with ⟨xs, rfl⟩
simp [Array.all_eq_not_any_not]
@[simp] theorem all_eq_true {p : α → Bool} {xs : Vector α n} :
xs.all p = true ↔ ∀ (i : Nat) (_ : i < n), p xs[i] := by
simp [all_iff_forall]
@[simp] theorem all_eq_false {p : α → Bool} {xs : Vector α n} :
xs.all p = false ↔ ∃ (i : Nat) (_ : i < n), ¬p xs[i] := by
rw [Bool.eq_false_iff, Ne, all_eq_true]
simp
theorem all_eq_true_iff_forall_mem {xs : Vector α n} : xs.all p ↔ ∀ x, x ∈ xs → p x := by
rcases xs with ⟨xs, rfl⟩
simp only [all_mk, Array.all_eq_true_iff_forall_mem]
simp
/-- Variant of `any_eq_true` in terms of membership rather than an array index. -/
theorem any_eq_true' {p : α → Bool} {xs : Vector α n} :
xs.any p = true ↔ (∃ x, x ∈ xs ∧ p x) := by
rcases xs with ⟨xs, rfl⟩
simp only [any_mk, Array.any_eq_true']
simp
/-- Variant of `any_eq_false` in terms of membership rather than an array index. -/
theorem any_eq_false' {p : α → Bool} {xs : Vector α n} :
xs.any p = false ↔ ∀ x, x ∈ xs → ¬p x := by
rcases xs with ⟨xs, rfl⟩
simp only [any_mk, Array.any_eq_false']
simp
/-- Variant of `all_eq_true` in terms of membership rather than an array index. -/
theorem all_eq_true' {p : α → Bool} {xs : Vector α n} :
xs.all p = true ↔ ∀ x, x ∈ xs → p x := by
rcases xs with ⟨xs, rfl⟩
simp only [all_mk, Array.all_eq_true']
simp
/-- Variant of `all_eq_false` in terms of membership rather than an array index. -/
theorem all_eq_false' {p : α → Bool} {xs : Vector α n} :
xs.all p = false ↔ ∃ x, x ∈ xs ∧ ¬p x := by
rcases xs with ⟨xs, rfl⟩
simp only [all_mk, Array.all_eq_false']
simp
theorem any_eq {xs : Vector α n} {p : α → Bool} : xs.any p = decide (∃ i : Nat, ∃ h, p (xs[i]'h)) := by
by_cases h : xs.any p
· simp_all [any_eq_true]
· simp_all [any_eq_false]
/-- Variant of `any_eq` in terms of membership rather than an array index. -/
theorem any_eq' {xs : Vector α n} {p : α → Bool} : xs.any p = decide (∃ x, x ∈ xs ∧ p x) := by
by_cases h : xs.any p
· simp_all [any_eq_true']
· simp only [Bool.not_eq_true] at h
simp only [h]
simp only [any_eq_false'] at h
simpa using h
theorem all_eq {xs : Vector α n} {p : α → Bool} : xs.all p = decide (∀ i, (_ : i < n) → p xs[i]) := by
by_cases h : xs.all p
· simp_all [all_eq_true]
· simp only [Bool.not_eq_true] at h
simp only [h]
simp only [all_eq_false] at h
simpa using h
/-- Variant of `all_eq` in terms of membership rather than an array index. -/
theorem all_eq' {xs : Vector α n} {p : α → Bool} : xs.all p = decide (∀ x, x ∈ xs → p x) := by
rcases xs with ⟨xs, rfl⟩
simp only [all_mk, Array.all_eq']
simp
theorem decide_exists_mem {xs : Vector α n} {p : α → Prop} [DecidablePred p] :
decide (∃ x, x ∈ xs ∧ p x) = xs.any p := by
simp [any_eq']
theorem decide_forall_mem {xs : Vector α n} {p : α → Prop} [DecidablePred p] :
decide (∀ x, x ∈ xs → p x) = xs.all p := by
simp [all_eq']
theorem any_beq [BEq α] {xs : Vector α n} {a : α} : (xs.any fun x => a == x) = xs.contains a := by
rcases xs with ⟨xs, rfl⟩
simp [Array.any_beq]
/-- Variant of `any_beq` with `==` reversed. -/
theorem any_beq' [BEq α] [PartialEquivBEq α] {xs : Vector α n} :
(xs.any fun x => x == a) = xs.contains a := by
simp only [BEq.comm, any_beq]
theorem all_bne [BEq α] {xs : Vector α n} : (xs.all fun x => a != x) = !xs.contains a := by
rcases xs with ⟨xs, rfl⟩
simp [Array.all_bne]
/-- Variant of `all_bne` with `!=` reversed. -/
theorem all_bne' [BEq α] [PartialEquivBEq α] {xs : Vector α n} :
(xs.all fun x => x != a) = !xs.contains a := by
simp only [bne_comm, all_bne]
theorem mem_of_contains_eq_true [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
as.contains a = true → a ∈ as := by
rcases as with ⟨as, rfl⟩
simp [Array.mem_of_contains_eq_true]
theorem contains_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} (h : a ∈ as) :
as.contains a = true := by
rcases as with ⟨as, rfl⟩
simp only [mem_mk] at h
simp [Array.contains_eq_true_of_mem, h]
instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈ as) :=
decidable_of_decidable_of_iff (Iff.intro mem_of_contains_eq_true contains_eq_true_of_mem)
theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
as.contains a = true ↔ a ∈ as := ⟨mem_of_contains_eq_true, contains_eq_true_of_mem⟩
@[simp] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
as.contains a = decide (a ∈ as) := by
rw [Bool.eq_iff_iff, contains_iff, decide_eq_true_iff]
@[simp] theorem any_push [BEq α] {as : Vector α n} {a : α} {p : α → Bool} :
(as.push a).any p = (as.any p || p a) := by
rcases as with ⟨as, rfl⟩
simp [Array.any_push]
@[simp] theorem all_push [BEq α] {as : Vector α n} {a : α} {p : α → Bool} :
(as.push a).all p = (as.all p && p a) := by
rcases as with ⟨as, rfl⟩
simp [Array.all_push]
@[simp] theorem contains_push [BEq α] {l : Vector α n} {a : α} {b : α} :
(l.push a).contains b = (l.contains b || b == a) := by
rcases l with ⟨l, rfl⟩
simp [Array.contains_push]
/-! ### set -/
theorem getElem_set (v : Vector α n) (i : Nat) (x : α) (hi : i < n) (j : Nat) (hj : j < n) :
(v.set i x hi)[j] = if i = j then x else v[j] := by
cases v
split <;> simp_all [Array.getElem_set]
@[simp] theorem getElem_set_self (v : Vector α n) (i : Nat) (x : α) (hi : i < n) :
(v.set i x hi)[i] = x := by simp [getElem_set]
@[deprecated getElem_set_self (since := "2024-12-12")]
abbrev getElem_set_eq := @getElem_set_self
@[simp] theorem getElem_set_ne (v : Vector α n) (i : Nat) (x : α) (hi : i < n) (j : Nat)
(hj : j < n) (h : i ≠ j) : (v.set i x hi)[j] = v[j] := by simp [getElem_set, h]
theorem getElem?_set (v : Vector α n) (i : Nat) (hi : i < n) (x : α) (j : Nat) :
(v.set i x hi)[j]? = if i = j then some x else v[j]? := by
cases v
split <;> simp_all [getElem?_eq_getElem, getElem_set]
@[simp] theorem getElem?_set_self (v : Vector α n) (i : Nat) (hi : i < n) (x : α) :
(v.set i x hi)[i]? = some x := by simp [getElem?_eq_getElem, hi]
@[simp] theorem getElem?_set_ne (v : Vector α n) (i : Nat) (hi : i < n) (x : α) (j : Nat)
(h : i ≠ j) : (v.set i x hi)[j]? = v[j]? := by
simp [getElem?_set, h]
@[simp] theorem set_getElem_self {v : Vector α n} {i : Nat} (hi : i < n) :
v.set i v[i] hi = v := by
cases v
simp
theorem set_comm (a b : α) {i j : Nat} (v : Vector α n) {hi : i < n} {hj : j < n} (h : i ≠ j) :
(v.set i a hi).set j b hj = (v.set j b hj).set i a hi := by
cases v
simp [Array.set_comm, h]
@[simp] theorem set_set (a b : α) (v : Vector α n) (i : Nat) (hi : i < n) :
(v.set i a hi).set i b hi = v.set i b hi := by
cases v
simp
theorem mem_set (v : Vector α n) (i : Nat) (hi : i < n) (a : α) :
a ∈ v.set i a hi := by
simp [mem_iff_getElem]
exact ⟨i, (by simpa using hi), by simp⟩
theorem mem_or_eq_of_mem_set {v : Vector α n} {i : Nat} {a b : α} {w : i < n} (h : a ∈ v.set i b) : a ∈ v a = b := by
cases v
simpa using Array.mem_or_eq_of_mem_set (by simpa using h)
/-! ### setIfInBounds -/
theorem getElem_setIfInBounds (a : Vector α n) (i : Nat) (x : α) (j : Nat)
(hj : j < n) : (a.setIfInBounds i x)[j] = if i = j then x else a[j] := by
cases a
split <;> simp_all [Array.getElem_setIfInBounds]
@[simp] theorem getElem_setIfInBounds_self (v : Vector α n) (i : Nat) (x : α) (hi : i < n) :
(v.setIfInBounds i x)[i] = x := by simp [getElem_setIfInBounds, hi]
@[deprecated getElem_setIfInBounds_self (since := "2024-12-12")]
abbrev getElem_setIfInBounds_eq := @getElem_setIfInBounds_self
@[simp] theorem getElem_setIfInBounds_ne (v : Vector α n) (i : Nat) (x : α) (j : Nat)
(hj : j < n) (h : i ≠ j) : (v.setIfInBounds i x)[j] = v[j] := by simp [getElem_setIfInBounds, h]
theorem getElem?_setIfInBounds (v : Vector α n) (i : Nat) (x : α) (j : Nat) :
(v.setIfInBounds i x)[j]? = if i = j then if i < n then some x else none else v[j]? := by
rcases v with ⟨v, rfl⟩
simp [Array.getElem?_setIfInBounds]
theorem getElem?_setIfInBounds_self (v : Vector α n) (i : Nat) (x : α) :
(v.setIfInBounds i x)[i]? = if i < n then some x else none := by simp [getElem?_setIfInBounds]
@[simp] theorem getElem?_setIfInBounds_self_of_lt (v : Vector α n) (i : Nat) (x : α) (h : i < n) :
(v.setIfInBounds i x)[i]? = some x := by simp [getElem?_setIfInBounds, h]
@[simp] theorem getElem?_setIfInBounds_ne (a : Vector α n) (i : Nat) (x : α) (j : Nat)
(h : i ≠ j) : (a.setIfInBounds i x)[j]? = a[j]? := by simp [getElem?_setIfInBounds, h]
theorem setIfInBounds_eq_of_size_le {l : Vector α n} {m : Nat} (h : l.size ≤ m) {a : α} :
l.setIfInBounds m a = l := by
rcases l with ⟨l, rfl⟩
simp [Array.setIfInBounds_eq_of_size_le (by simpa using h)]
theorem setIfInBound_comm (a b : α) {i j : Nat} (v : Vector α n) (h : i ≠ j) :
(v.setIfInBounds i a).setIfInBounds j b = (v.setIfInBounds j b).setIfInBounds i a := by
rcases v with ⟨v, rfl⟩
simp only [setIfInBounds_mk, mk.injEq]
rw [Array.setIfInBounds_comm _ _ _ h]
@[simp] theorem setIfInBounds_setIfInBounds (a b : α) (v : Vector α n) (i : Nat) :
(v.setIfInBounds i a).setIfInBounds i b = v.setIfInBounds i b := by
rcases v with ⟨v, rfl⟩
simp
theorem mem_setIfInBounds (v : Vector α n) (i : Nat) (hi : i < n) (a : α) :
a ∈ v.setIfInBounds i a := by
simp [mem_iff_getElem]
exact ⟨i, (by simpa using hi), by simp⟩
/-! ### BEq -/
@[simp] theorem push_beq_push [BEq α] {a b : α} {n : Nat} {v : Vector α n} {w : Vector α n} :
(v.push a == w.push b) = (v == w && a == b) := by
cases v
cases w
simp
@[simp] theorem mkVector_beq_mkVector [BEq α] {a b : α} {n : Nat} :
(mkVector n a == mkVector n b) = (n == 0 || a == b) := by
cases n with
| zero => simp
| succ n =>
rw [mkVector_succ, mkVector_succ, push_beq_push, mkVector_beq_mkVector]
rw [Bool.eq_iff_iff]
simp +contextual
@[simp] theorem reflBEq_iff [BEq α] [NeZero n] : ReflBEq (Vector α n) ↔ ReflBEq α := by
match n, NeZero.ne n with
| n + 1, _ =>
constructor
· intro h
constructor
intro a
suffices (mkVector (n + 1) a == mkVector (n + 1) a) = true by
rw [mkVector_succ, push_beq_push, Bool.and_eq_true] at this
exact this.2
simp
· intro h
constructor
rintro ⟨v, h⟩
simpa using Array.isEqv_self_beq ..
@[simp] theorem lawfulBEq_iff [BEq α] [NeZero n] : LawfulBEq (Vector α n) ↔ LawfulBEq α := by
match n, NeZero.ne n with
| n + 1, _ =>
constructor
· intro h
constructor
· intro a b h
have := mkVector_inj (n := n+1) (a := a) (b := b)
simp only [Nat.add_one_ne_zero, false_or] at this
rw [← this]
apply eq_of_beq
rw [mkVector_beq_mkVector]
simpa
· intro a
suffices (mkVector (n + 1) a == mkVector (n + 1) a) = true by
rw [mkVector_beq_mkVector] at this
simpa
simp
· intro h
constructor
· rintro ⟨a, ha⟩ ⟨b, hb⟩ h
simp at h
obtain ⟨hs, hi⟩ := Array.isEqv_iff_rel.mp h
ext i h
· simpa using hi _ (by omega)
· rintro ⟨a, ha⟩
simpa using Array.isEqv_self_beq ..
/-! ### isEqv -/
@[simp] theorem isEqv_eq [DecidableEq α] {l₁ l₂ : Vector α n} : l₁.isEqv l₂ (· == ·) = (l₁ = l₂) := by
cases l₁
cases l₂
simp
/-! ### map -/
@[simp] theorem getElem_map (f : α → β) (a : Vector α n) (i : Nat) (hi : i < n) :
(a.map f)[i] = f a[i] := by
cases a
simp
@[simp] theorem getElem?_map (f : α → β) (a : Vector α n) (i : Nat) :
(a.map f)[i]? = a[i]?.map f := by
cases a
simp
/-- The empty vector maps to the empty vector. -/
@[simp]
theorem map_empty (f : α → β) : map f #v[] = #v[] := by
rw [map, mk.injEq]
exact Array.map_empty f
@[simp] theorem map_push {f : α → β} {as : Vector α n} {x : α} :
(as.push x).map f = (as.map f).push (f x) := by
cases as
simp
@[simp] theorem map_id_fun : map (n := n) (id : αα) = id := by
funext l
induction l <;> simp_all
/-- `map_id_fun'` differs from `map_id_fun` by representing the identity function as a lambda, rather than `id`. -/
@[simp] theorem map_id_fun' : map (n := n) (fun (a : α) => a) = id := map_id_fun
-- This is not a `@[simp]` lemma because `map_id_fun` will apply.
theorem map_id (l : Vector α n) : map (id : αα) l = l := by
cases l <;> simp_all
/-- `map_id'` differs from `map_id` by representing the identity function as a lambda, rather than `id`. -/
-- This is not a `@[simp]` lemma because `map_id_fun'` will apply.
theorem map_id' (l : Vector α n) : map (fun (a : α) => a) l = l := map_id l
/-- Variant of `map_id`, with a side condition that the function is pointwise the identity. -/
theorem map_id'' {f : αα} (h : ∀ x, f x = x) (l : Vector α n) : map f l = l := by
simp [show f = id from funext h]
theorem map_singleton (f : α → β) (a : α) : map f #v[a] = #v[f a] := rfl
-- We use a lower priority here as there are more specific lemmas in downstream libraries
-- which should be able to fire first.
@[simp 500] theorem mem_map {f : α → β} {l : Vector α n} : b ∈ l.map f ↔ ∃ a, a ∈ l ∧ f a = b := by
cases l
simp
theorem exists_of_mem_map (h : b ∈ map f l) : ∃ a, a ∈ l ∧ f a = b := mem_map.1 h
theorem mem_map_of_mem (f : α → β) (h : a ∈ l) : f a ∈ map f l := mem_map.2 ⟨_, h, rfl⟩
theorem forall_mem_map {f : α → β} {l : Vector α n} {P : β → Prop} :
(∀ (i) (_ : i ∈ l.map f), P i) ↔ ∀ (j) (_ : j ∈ l), P (f j) := by
simp
@[simp] theorem map_inj_left {f g : α → β} : map f l = map g l ↔ ∀ a ∈ l, f a = g a := by
cases l <;> simp_all
theorem map_inj_right {f : α → β} (w : ∀ x y, f x = f y → x = y) : map f l = map f l' ↔ l = l' := by
cases l
cases l'
simp [Array.map_inj_right w]
theorem map_congr_left (h : ∀ a ∈ l, f a = g a) : map f l = map g l :=
map_inj_left.2 h
theorem map_inj [NeZero n] : map (n := n) f = map g ↔ f = g := by
constructor
· intro h
ext a
replace h := congrFun h (mkVector n a)
simp only [mkVector, map_mk, mk.injEq, Array.map_inj_left, Array.mem_mkArray, and_imp,
forall_eq_apply_imp_iff] at h
exact h (NeZero.ne n)
· intro h; subst h; rfl
theorem map_eq_push_iff {f : α → β} {l : Vector α (n + 1)} {l₂ : Vector β n} {b : β} :
map f l = l₂.push b ↔ ∃ l₁ a, l = l₁.push a ∧ map f l₁ = l₂ ∧ f a = b := by
rcases l with ⟨l, h⟩
rcases l₂ with ⟨l₂, rfl⟩
simp only [map_mk, push_mk, mk.injEq, Array.map_eq_push_iff]
constructor
· rintro ⟨l₁, a, rfl, rfl, rfl⟩
refine ⟨⟨l₁, by simp⟩, a, by simp⟩
· rintro ⟨l₁, a, h₁, h₂, rfl⟩
refine ⟨l₁.toArray, a, by simp_all⟩
@[simp] theorem map_eq_singleton_iff {f : α → β} {l : Vector α 1} {b : β} :
map f l = #v[b] ↔ ∃ a, l = #v[a] ∧ f a = b := by
cases l
simp
theorem map_eq_map_iff {f g : α → β} {l : Vector α n} :
map f l = map g l ↔ ∀ a ∈ l, f a = g a := by
cases l <;> simp_all
theorem map_eq_iff {f : α → β} {l : Vector α n} {l' : Vector β n} :
map f l = l' ↔ ∀ i (h : i < n), l'[i] = f l[i] := by
rcases l with ⟨l, rfl⟩
rcases l' with ⟨l', h'⟩
simp only [map_mk, eq_mk, Array.map_eq_iff, getElem_mk]
constructor
· intro w i h
simpa [h, h'] using w i
· intro w i
if h : i < l.size then
simpa [h, h'] using w i h
else
rw [getElem?_neg, getElem?_neg, Option.map_none'] <;> omega
@[simp] theorem map_set {f : α → β} {l : Vector α n} {i : Nat} {h : i < n} {a : α} :
(l.set i a).map f = (l.map f).set i (f a) (by simpa using h) := by
cases l
simp
@[simp] theorem map_setIfInBounds {f : α → β} {l : Vector α n} {i : Nat} {a : α} :
(l.setIfInBounds i a).map f = (l.map f).setIfInBounds i (f a) := by
cases l
simp
@[simp] theorem map_pop {f : α → β} {l : Vector α n} : l.pop.map f = (l.map f).pop := by
cases l
simp
@[simp] theorem back?_map {f : α → β} {l : Vector α n} : (l.map f).back? = l.back?.map f := by
cases l
simp
@[simp] theorem map_map {f : α → β} {g : β → γ} {as : Vector α n} :
(as.map f).map g = as.map (g ∘ f) := by
cases as
simp
/--
Use this as `induction ass using vector₂_induction` on a hypothesis of the form `ass : Vector (Vector α n) m`.
The hypothesis `ass` will be replaced with a hypothesis `ass : Array (Array α)`
along with additional hypotheses `h₁ : ass.size = m` and `h₂ : ∀ xs ∈ ass, xs.size = n`.
Appearances of the original `ass` in the goal will be replaced with
`Vector.mk (xss.attach.map (fun ⟨xs, m⟩ => Vector.mk xs ⋯)) ⋯`.
-/
-- We can't use `@[cases_eliminator]` here as
-- `Lean.Meta.getCustomEliminator?` only looks at the top-level constant.
theorem vector₂_induction (P : Vector (Vector α n) m → Prop)
(of : ∀ (xss : Array (Array α)) (h₁ : xss.size = m) (h₂ : ∀ xs ∈ xss, xs.size = n),
P (mk (xss.attach.map (fun ⟨xs, m⟩ => mk xs (h₂ xs m))) (by simpa using h₁)))
(ass : Vector (Vector α n) m) : P ass := by
specialize of (ass.map toArray).toArray (by simp) (by simp)
simpa [Array.map_attach, Array.pmap_map] using of
/--
Use this as `induction ass using vector₃_induction` on a hypothesis of the form `ass : Vector (Vector (Vector α n) m) k`.
The hypothesis `ass` will be replaced with a hypothesis `ass : Array (Array (Array α))`
along with additional hypotheses `h₁ : ass.size = k`, `h₂ : ∀ xs ∈ ass, xs.size = m`,
and `h₃ : ∀ xs ∈ ass, ∀ x ∈ xs, x.size = n`.
Appearances of the original `ass` in the goal will be replaced with
`Vector.mk (xss.attach.map (fun ⟨xs, m⟩ => Vector.mk (xs.attach.map (fun ⟨x, m'⟩ => Vector.mk x ⋯)) ⋯)) ⋯`.
-/
theorem vector₃_induction (P : Vector (Vector (Vector α n) m) k → Prop)
(of : ∀ (xss : Array (Array (Array α))) (h₁ : xss.size = k) (h₂ : ∀ xs ∈ xss, xs.size = m)
(h₃ : ∀ xs ∈ xss, ∀ x ∈ xs, x.size = n),
P (mk (xss.attach.map (fun ⟨xs, m⟩ =>
mk (xs.attach.map (fun ⟨x, m'⟩ =>
mk x (h₃ xs m x m'))) (by simpa using h₂ xs m))) (by simpa using h₁)))
(ass : Vector (Vector (Vector α n) m) k) : P ass := by
specialize of (ass.map (fun as => (as.map toArray).toArray)).toArray (by simp) (by simp) (by simp)
simpa [Array.map_attach, Array.pmap_map] using of
/-! ### singleton -/
@[simp] theorem singleton_def (v : α) : Vector.singleton v = #v[v] := rfl
/-! ### append -/
@[simp] theorem append_push {as : Vector α n} {bs : Vector α m} {a : α} :
as ++ bs.push a = (as ++ bs).push a := by
cases as
cases bs
simp
theorem singleton_eq_toVector_singleton (a : α) : #v[a] = #[a].toVector := rfl
@[simp] theorem mem_append {a : α} {s : Vector α n} {t : Vector α m} :
a ∈ s ++ t ↔ a ∈ s a ∈ t := by
cases s
cases t
simp
theorem mem_append_left {a : α} {s : Vector α n} (t : Vector α m) (h : a ∈ s) : a ∈ s ++ t :=
mem_append.2 (Or.inl h)
theorem mem_append_right {a : α} (s : Vector α n) {t : Vector α m} (h : a ∈ t) : a ∈ s ++ t :=
mem_append.2 (Or.inr h)
theorem not_mem_append {a : α} {s : Vector α n} {t : Vector α m} (h₁ : a ∉ s) (h₂ : a ∉ t) :
a ∉ s ++ t :=
mt mem_append.1 $ not_or.mpr ⟨h₁, h₂⟩
/--
See also `eq_push_append_of_mem`, which proves a stronger version
in which the initial array must not contain the element.
-/
theorem append_of_mem {a : α} {l : Vector α n} (h : a ∈ l) :
∃ (m k : Nat) (w : m + 1 + k = n) (s : Vector α m) (t : Vector α k),
l = (s.push a ++ t).cast w := by
rcases l with ⟨l, rfl⟩
obtain ⟨s, t, rfl⟩ := Array.append_of_mem (by simpa using h)
refine ⟨_, _, by simp, s.toVector, t.toVector, by simp_all⟩
theorem mem_iff_append {a : α} {l : Vector α n} :
a ∈ l ↔ ∃ (m k : Nat) (w : m + 1 + k = n) (s : Vector α m) (t : Vector α k),
l = (s.push a ++ t).cast w :=
⟨append_of_mem, by rintro ⟨m, k, rfl, s, t, rfl⟩; simp⟩
theorem forall_mem_append {p : α → Prop} {l₁ : Vector α n} {l₂ : Vector α m} :
(∀ (x) (_ : x ∈ l₁ ++ l₂), p x) ↔ (∀ (x) (_ : x ∈ l₁), p x) ∧ (∀ (x) (_ : x ∈ l₂), p x) := by
simp only [mem_append, or_imp, forall_and]
theorem empty_append (as : Vector α n) : (#v[] : Vector α 0) ++ as = as.cast (by omega) := by
rcases as with ⟨as, rfl⟩
simp
theorem append_empty (as : Vector α n) : as ++ (#v[] : Vector α 0) = as := by
rw [← toArray_inj, toArray_append, Array.append_empty]
theorem getElem_append (a : Vector α n) (b : Vector α m) (i : Nat) (hi : i < n + m) :
(a ++ b)[i] = if h : i < n then a[i] else b[i - n] := by
rcases a with ⟨a, rfl⟩
rcases b with ⟨b, rfl⟩
simp [Array.getElem_append, hi]
theorem getElem_append_left {a : Vector α n} {b : Vector α m} {i : Nat} (hi : i < n) :
(a ++ b)[i] = a[i] := by simp [getElem_append, hi]
theorem getElem_append_right {a : Vector α n} {b : Vector α m} {i : Nat} (h : i < n + m) (hi : n ≤ i) :
(a ++ b)[i] = b[i - n] := by
rw [getElem_append, dif_neg (by omega)]
theorem getElem?_append_left {as : Vector α n} {bs : Vector α m} {i : Nat} (hn : i < n) :
(as ++ bs)[i]? = as[i]? := by
have hn' : i < n + m := by omega
simp_all [getElem?_eq_getElem, getElem_append]
theorem getElem?_append_right {as : Vector α n} {bs : Vector α m} {i : Nat} (h : n ≤ i) :
(as ++ bs)[i]? = bs[i - n]? := by
rcases as with ⟨as, rfl⟩
rcases bs with ⟨bs, rfl⟩
simp [Array.getElem?_append_right, h]
theorem getElem?_append {as : Vector α n} {bs : Vector α m} {i : Nat} :
(as ++ bs)[i]? = if i < n then as[i]? else bs[i - n]? := by
split <;> rename_i h
· exact getElem?_append_left h
· exact getElem?_append_right (by simpa using h)
/-- Variant of `getElem_append_left` useful for rewriting from the small array to the big array. -/
theorem getElem_append_left' (l₁ : Vector α m) {l₂ : Vector α n} {i : Nat} (hi : i < m) :
l₁[i] = (l₁ ++ l₂)[i] := by
rw [getElem_append_left] <;> simp
/-- Variant of `getElem_append_right` useful for rewriting from the small array to the big array. -/
theorem getElem_append_right' (l₁ : Vector α m) {l₂ : Vector α n} {i : Nat} (hi : i < n) :
l₂[i] = (l₁ ++ l₂)[i + m] := by
rw [getElem_append_right] <;> simp [*, Nat.le_add_left]
theorem getElem_of_append {l : Vector α n} {l₁ : Vector α m} {l₂ : Vector α k}
(w : m + 1 + k = n) (eq : l = (l₁.push a ++ l₂).cast w) :
l[m] = a := Option.some.inj <| by
rw [← getElem?_eq_getElem, eq, getElem?_cast, getElem?_append_left (by simp)]
simp
@[simp] theorem append_singleton {a : α} {as : Vector α n} : as ++ #v[a] = as.push a := by
cases as
simp
theorem append_inj {s₁ s₂ : Vector α n} {t₁ t₂ : Vector α m} (h : s₁ ++ t₁ = s₂ ++ t₂) :
s₁ = s₂ ∧ t₁ = t₂ := by
rcases s₁ with ⟨s₁, rfl⟩
rcases s₂ with ⟨s₂, hs⟩
rcases t₁ with ⟨t₁, rfl⟩
rcases t₂ with ⟨t₂, ht⟩
simpa using Array.append_inj (by simpa using h) (by omega)
theorem append_inj_right {s₁ s₂ : Vector α n} {t₁ t₂ : Vector α m}
(h : s₁ ++ t₁ = s₂ ++ t₂) : t₁ = t₂ :=
(append_inj h).right
theorem append_inj_left {s₁ s₂ : Vector α n} {t₁ t₂ : Vector α m}
(h : s₁ ++ t₁ = s₂ ++ t₂) : s₁ = s₂ :=
(append_inj h).left
theorem append_right_inj {t₁ t₂ : Vector α m} (s : Vector α n) : s ++ t₁ = s ++ t₂ ↔ t₁ = t₂ :=
⟨fun h => append_inj_right h, congrArg _⟩
theorem append_left_inj {s₁ s₂ : Vector α n} (t : Vector α m) : s₁ ++ t = s₂ ++ t ↔ s₁ = s₂ :=
⟨fun h => append_inj_left h, congrArg (· ++ _)⟩
theorem append_eq_append_iff {a : Vector α n} {b : Vector α m} {c : Vector α k} {d : Vector α l}
(w : k + l = n + m) :
a ++ b = (c ++ d).cast w ↔
if h : n ≤ k then
∃ a' : Vector α (k - n), c = (a ++ a').cast (by omega) ∧ b = (a' ++ d).cast (by omega)
else
∃ c' : Vector α (n - k), a = (c ++ c').cast (by omega) ∧ d = (c' ++ b).cast (by omega) := by
rcases a with ⟨a, rfl⟩
rcases b with ⟨b, rfl⟩
rcases c with ⟨c, rfl⟩
rcases d with ⟨d, rfl⟩
simp only [mk_append_mk, Array.append_eq_append_iff, mk_eq, toArray_cast]
constructor
· rintro (⟨a', rfl, rfl⟩ | ⟨c', rfl, rfl⟩)
· rw [dif_pos (by simp)]
exact ⟨a'.toVector.cast (by simp; omega), by simp⟩
· split <;> rename_i h
· have hc : c'.size = 0 := by simp at h; omega
simp at hc
exact ⟨#v[].cast (by simp; omega), by simp_all⟩
· exact ⟨c'.toVector.cast (by simp; omega), by simp⟩
· split <;> rename_i h
· rintro ⟨a', hc, rfl⟩
left
refine ⟨a'.toArray, hc, rfl⟩
· rintro ⟨c', ha, rfl⟩
right
refine ⟨c'.toArray, ha, rfl⟩
theorem set_append {s : Vector α n} {t : Vector α m} {i : Nat} {x : α} (h : i < n + m) :
(s ++ t).set i x =
if h' : i < n then
s.set i x ++ t
else
s ++ t.set (i - n) x := by
rcases s with ⟨s, rfl⟩
rcases t with ⟨t, rfl⟩
simp only [mk_append_mk, set_mk, Array.set_append]
split <;> simp
@[simp] theorem set_append_left {s : Vector α n} {t : Vector α m} {i : Nat} {x : α} (h : i < n) :
(s ++ t).set i x = s.set i x ++ t := by
simp [set_append, h]
@[simp] theorem set_append_right {s : Vector α n} {t : Vector α m} {i : Nat} {x : α}
(h' : i < n + m) (h : n ≤ i) :
(s ++ t).set i x = s ++ t.set (i - n) x := by
rw [set_append, dif_neg (by omega)]
theorem setIfInBounds_append {s : Vector α n} {t : Vector α m} {i : Nat} {x : α} :
(s ++ t).setIfInBounds i x =
if i < n then
s.setIfInBounds i x ++ t
else
s ++ t.setIfInBounds (i - n) x := by
rcases s with ⟨s, rfl⟩
rcases t with ⟨t, rfl⟩
simp only [mk_append_mk, setIfInBounds_mk, Array.setIfInBounds_append]
split <;> simp
@[simp] theorem setIfInBounds_append_left {s : Vector α n} {t : Vector α m} {i : Nat} {x : α} (h : i < n) :
(s ++ t).setIfInBounds i x = s.setIfInBounds i x ++ t := by
simp [setIfInBounds_append, h]
@[simp] theorem setIfInBounds_append_right {s : Vector α n} {t : Vector α m} {i : Nat} {x : α}
(h : n ≤ i) :
(s ++ t).setIfInBounds i x = s ++ t.setIfInBounds (i - n) x := by
rw [setIfInBounds_append, if_neg (by omega)]
@[simp] theorem map_append (f : α → β) (l₁ : Vector α n) (l₂ : Vector α m) :
map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
rcases l₁ with ⟨l₁, rfl⟩
rcases l₂ with ⟨l₂, rfl⟩
simp
theorem map_eq_append_iff {f : α → β} :
map f l = L₁ ++ L₂ ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ map f l₁ = L₁ ∧ map f l₂ = L₂ := by
rcases l with ⟨l, h⟩
rcases L₁ with ⟨L₁, rfl⟩
rcases L₂ with ⟨L₂, rfl⟩
simp only [map_mk, mk_append_mk, eq_mk, Array.map_eq_append_iff, mk_eq, toArray_append,
toArray_map]
constructor
· rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
exact ⟨l₁.toVector.cast (by simp), l₂.toVector.cast (by simp), by simp⟩
· rintro ⟨⟨l₁⟩, ⟨l₂⟩, rfl, h₁, h₂⟩
exact ⟨l₁, l₂, by simp_all⟩
theorem append_eq_map_iff {f : α → β} :
L₁ ++ L₂ = map f l ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ map f l₁ = L₁ ∧ map f l₂ = L₂ := by
rw [eq_comm, map_eq_append_iff]
/-! ### flatten -/
@[simp] theorem flatten_mk (L : Array (Vector α n)) (h : L.size = m) :
(mk L h).flatten =
mk (L.map toArray).flatten (by simp [Function.comp_def, Array.map_const', h]) := by
simp [flatten]
@[simp] theorem getElem_flatten (l : Vector (Vector β m) n) (i : Nat) (hi : i < n * m) :
l.flatten[i] =
haveI : i / m < n := by rwa [Nat.div_lt_iff_lt_mul (Nat.pos_of_lt_mul_left hi)]
haveI : i % m < m := Nat.mod_lt _ (Nat.pos_of_lt_mul_left hi)
l[i / m][i % m] := by
rcases l with ⟨⟨l⟩, rfl⟩
simp only [flatten_mk, List.map_toArray, getElem_mk, List.getElem_toArray, Array.flatten_toArray]
induction l generalizing i with
| nil => simp at hi
| cons a l ih =>
simp only [List.map_cons, List.map_map, List.flatten_cons]
by_cases h : i < m
· rw [List.getElem_append_left (by simpa)]
have h₁ : i / m = 0 := Nat.div_eq_of_lt h
have h₂ : i % m = i := Nat.mod_eq_of_lt h
simp [h₁, h₂]
· have h₁ : a.toList.length ≤ i := by simp; omega
rw [List.getElem_append_right h₁]
simp only [Array.length_toList, size_toArray]
specialize ih (i - m) (by simp_all [Nat.add_one_mul]; omega)
have h₂ : i / m = (i - m) / m + 1 := by
conv => lhs; rw [show i = i - m + m by omega]
rw [Nat.add_div_right]
exact Nat.pos_of_lt_mul_left hi
simp only [Array.length_toList, size_toArray] at h₁
have h₃ : (i - m) % m = i % m := (Nat.mod_eq_sub_mod h₁).symm
simp_all
theorem getElem?_flatten (l : Vector (Vector β m) n) (i : Nat) :
l.flatten[i]? =
if hi : i < n * m then
haveI : i / m < n := by rwa [Nat.div_lt_iff_lt_mul (Nat.pos_of_lt_mul_left hi)]
haveI : i % m < m := Nat.mod_lt _ (Nat.pos_of_lt_mul_left hi)
some l[i / m][i % m]
else
none := by
simp [getElem?_def]
@[simp] theorem flatten_singleton (l : Vector α n) : #v[l].flatten = l.cast (by simp) := by
simp [flatten]
theorem mem_flatten {L : Vector (Vector α n) m} : a ∈ L.flatten ↔ ∃ l, l ∈ L ∧ a ∈ l := by
rcases L with ⟨L, rfl⟩
simp [Array.mem_flatten]
constructor
· rintro ⟨_, ⟨l, h₁, rfl⟩, h₂⟩
exact ⟨l, h₁, by simpa using h₂⟩
· rintro ⟨l, h₁, h₂⟩
exact ⟨l.toArray, ⟨l, h₁, rfl⟩, by simpa using h₂⟩
theorem exists_of_mem_flatten : a ∈ flatten L → ∃ l, l ∈ L ∧ a ∈ l := mem_flatten.1
theorem mem_flatten_of_mem (lL : l ∈ L) (al : a ∈ l) : a ∈ flatten L := mem_flatten.2 ⟨l, lL, al⟩
theorem forall_mem_flatten {p : α → Prop} {L : Vector (Vector α n) m} :
(∀ (x) (_ : x ∈ flatten L), p x) ↔ ∀ (l) (_ : l ∈ L) (x) (_ : x ∈ l), p x := by
simp only [mem_flatten, forall_exists_index, and_imp]
constructor <;> (intros; solve_by_elim)
@[simp] theorem map_flatten (f : α → β) (L : Vector (Vector α n) m) :
(flatten L).map f = (map (map f) L).flatten := by
induction L using vector₂_induction with
| of xss h₁ h₂ => simp
@[simp] theorem flatten_append (L₁ : Vector (Vector α n) m₁) (L₂ : Vector (Vector α n) m₂) :
flatten (L₁ ++ L₂) = (flatten L₁ ++ flatten L₂).cast (by simp [Nat.add_mul]) := by
induction L₁ using vector₂_induction
induction L₂ using vector₂_induction
simp
theorem flatten_push (L : Vector (Vector α n) m) (l : Vector α n) :
flatten (L.push l) = (flatten L ++ l).cast (by simp [Nat.add_mul]) := by
induction L using vector₂_induction
rcases l with ⟨l⟩
simp [Array.flatten_push]
theorem flatten_flatten {L : Vector (Vector (Vector α n) m) k} :
flatten (flatten L) = (flatten (map flatten L)).cast (by simp [Nat.mul_assoc]) := by
induction L using vector₃_induction with
| of xss h₁ h₂ h₃ =>
-- simp [Array.flatten_flatten] -- FIXME: `simp` produces a bad proof here!
simp [Array.map_attach, Array.flatten_flatten, Array.map_pmap]
/-- Two vectors of constant length vectors are equal iff their flattens coincide. -/
theorem eq_iff_flatten_eq {L L' : Vector (Vector α n) m} :
L = L' ↔ L.flatten = L'.flatten := by
induction L using vector₂_induction with | of L h₁ h₂ =>
induction L' using vector₂_induction with | of L' h₁' h₂' =>
simp only [eq_mk, flatten_mk, Array.map_map, Function.comp_apply, Array.map_subtype,
Array.unattach_attach, Array.map_id_fun', id_eq]
constructor
· intro h
suffices L = L' by simp_all
apply Array.ext_getElem?
intro i
replace h := congrArg (fun x => x[i]?.map (fun x => x.toArray)) h
simpa [Option.map_pmap] using h
· intro h
have w : L.map Array.size = L'.map Array.size := by
ext i h h'
· simp_all
· simp only [Array.getElem_map]
rw [h₂ _ (by simp), h₂' _ (by simp)]
have := Array.eq_iff_flatten_eq.mpr ⟨h, w⟩
subst this
rfl
/-! ### flatMap -/
@[simp] theorem flatMap_mk (l : Array α) (h : l.size = m) (f : α → Vector β n) :
(mk l h).flatMap f =
mk (l.flatMap (fun a => (f a).toArray)) (by simp [Array.map_const', h]) := by
simp [flatMap]
@[simp] theorem flatMap_toArray (l : Vector α n) (f : α → Vector β m) :
l.toArray.flatMap (fun a => (f a).toArray) = (l.flatMap f).toArray := by
rcases l with ⟨l, rfl⟩
simp
theorem flatMap_def (l : Vector α n) (f : α → Vector β m) : l.flatMap f = flatten (map f l) := by
rcases l with ⟨l, rfl⟩
simp [Array.flatMap_def, Function.comp_def]
@[simp] theorem getElem_flatMap (l : Vector α n) (f : α → Vector β m) (i : Nat) (hi : i < n * m) :
(l.flatMap f)[i] =
haveI : i / m < n := by rwa [Nat.div_lt_iff_lt_mul (Nat.pos_of_lt_mul_left hi)]
haveI : i % m < m := Nat.mod_lt _ (Nat.pos_of_lt_mul_left hi)
(f (l[i / m]))[i % m] := by
rw [flatMap_def, getElem_flatten, getElem_map]
theorem getElem?_flatMap (l : Vector α n) (f : α → Vector β m) (i : Nat) :
(l.flatMap f)[i]? =
if hi : i < n * m then
haveI : i / m < n := by rwa [Nat.div_lt_iff_lt_mul (Nat.pos_of_lt_mul_left hi)]
haveI : i % m < m := Nat.mod_lt _ (Nat.pos_of_lt_mul_left hi)
some ((f (l[i / m]))[i % m])
else
none := by
simp [getElem?_def]
@[simp] theorem flatMap_id (l : Vector (Vector α m) n) : l.flatMap id = l.flatten := by simp [flatMap_def]
@[simp] theorem flatMap_id' (l : Vector (Vector α m) n) : l.flatMap (fun a => a) = l.flatten := by simp [flatMap_def]
@[simp] theorem mem_flatMap {f : α → Vector β m} {b} {l : Vector α n} : b ∈ l.flatMap f ↔ ∃ a, a ∈ l ∧ b ∈ f a := by
simp [flatMap_def, mem_flatten]
exact ⟨fun ⟨_, ⟨a, h₁, rfl⟩, h₂⟩ => ⟨a, h₁, h₂⟩, fun ⟨a, h₁, h₂⟩ => ⟨_, ⟨a, h₁, rfl⟩, h₂⟩⟩
theorem exists_of_mem_flatMap {b : β} {l : Vector α n} {f : α → Vector β m} :
b ∈ l.flatMap f → ∃ a, a ∈ l ∧ b ∈ f a := mem_flatMap.1
theorem mem_flatMap_of_mem {b : β} {l : Vector α n} {f : α → Vector β m} {a} (al : a ∈ l) (h : b ∈ f a) :
b ∈ l.flatMap f := mem_flatMap.2 ⟨a, al, h⟩
theorem forall_mem_flatMap {p : β → Prop} {l : Vector α n} {f : α → Vector β m} :
(∀ (x) (_ : x ∈ l.flatMap f), p x) ↔ ∀ (a) (_ : a ∈ l) (b) (_ : b ∈ f a), p b := by
simp only [mem_flatMap, forall_exists_index, and_imp]
constructor <;> (intros; solve_by_elim)
theorem flatMap_singleton (f : α → Vector β m) (x : α) : #v[x].flatMap f = (f x).cast (by simp) := by
simp [flatMap_def]
@[simp] theorem flatMap_singleton' (l : Vector α n) : (l.flatMap fun x => #v[x]) = l.cast (by simp) := by
rcases l with ⟨l, rfl⟩
simp
@[simp] theorem flatMap_append (xs ys : Vector α n) (f : α → Vector β m) :
(xs ++ ys).flatMap f = (xs.flatMap f ++ ys.flatMap f).cast (by simp [Nat.add_mul]) := by
rcases xs with ⟨xs⟩
rcases ys with ⟨ys⟩
simp [flatMap_def, flatten_append]
theorem flatMap_assoc {α β} (l : Vector α n) (f : α → Vector β m) (g : β → Vector γ k) :
(l.flatMap f).flatMap g = (l.flatMap fun x => (f x).flatMap g).cast (by simp [Nat.mul_assoc]) := by
rcases l with ⟨l, rfl⟩
simp [Array.flatMap_assoc]
theorem map_flatMap (f : β → γ) (g : α → Vector β m) (l : Vector α n) :
(l.flatMap g).map f = l.flatMap fun a => (g a).map f := by
rcases l with ⟨l, rfl⟩
simp [Array.map_flatMap]
theorem flatMap_map (f : α → β) (g : β → Vector γ k) (l : Vector α n) :
(map f l).flatMap g = l.flatMap (fun a => g (f a)) := by
rcases l with ⟨l, rfl⟩
simp [Array.flatMap_map]
theorem map_eq_flatMap {α β} (f : α → β) (l : Vector α n) :
map f l = (l.flatMap fun x => #v[f x]).cast (by simp) := by
rcases l with ⟨l, rfl⟩
simp [Array.map_eq_flatMap]
/-! ### mkVector -/
@[simp] theorem mkVector_one : mkVector 1 a = #v[a] := rfl
/-- Variant of `mkVector_succ` that prepends `a` at the beginning of the vector. -/
theorem mkVector_succ' : mkVector (n + 1) a = (#v[a] ++ mkVector n a).cast (by omega) := by
rw [← toArray_inj]
simp [Array.mkArray_succ']
@[simp] theorem mem_mkVector {a b : α} {n} : b ∈ mkVector n a ↔ n ≠ 0 ∧ b = a := by
unfold mkVector
simp
theorem eq_of_mem_mkVector {a b : α} {n} (h : b ∈ mkVector n a) : b = a := (mem_mkVector.1 h).2
theorem forall_mem_mkVector {p : α → Prop} {a : α} {n} :
(∀ b, b ∈ mkVector n a → p b) ↔ n = 0 p a := by
cases n <;> simp [mem_mkVector]
@[simp] theorem getElem_mkVector (a : α) (n i : Nat) (h : i < n) : (mkVector n a)[i] = a := by
simp [mkVector]
theorem getElem?_mkVector (a : α) (n i : Nat) : (mkVector n a)[i]? = if i < n then some a else none := by
simp [getElem?_def]
@[simp] theorem getElem?_mkVector_of_lt {n : Nat} {m : Nat} (h : m < n) : (mkVector n a)[m]? = some a := by
simp [getElem?_mkVector, h]
theorem eq_mkVector_of_mem {a : α} {l : Vector α n} (h : ∀ (b) (_ : b ∈ l), b = a) : l = mkVector n a := by
rw [← toArray_inj]
simpa using Array.eq_mkArray_of_mem (l := l.toArray) (by simpa using h)
theorem eq_mkVector_iff {a : α} {n} {l : Vector α n} :
l = mkVector n a ↔ ∀ (b) (_ : b ∈ l), b = a := by
rw [← toArray_inj]
simpa using Array.eq_mkArray_iff (l := l.toArray) (n := n)
theorem map_eq_mkVector_iff {l : Vector α n} {f : α → β} {b : β} :
l.map f = mkVector n b ↔ ∀ x ∈ l, f x = b := by
simp [eq_mkVector_iff]
@[simp] theorem map_const (l : Vector α n) (b : β) : map (Function.const α b) l = mkVector n b :=
map_eq_mkVector_iff.mpr fun _ _ => rfl
@[simp] theorem map_const_fun (x : β) : map (n := n) (Function.const α x) = fun _ => mkVector n x := by
funext l
simp
/-- Variant of `map_const` using a lambda rather than `Function.const`. -/
-- This can not be a `@[simp]` lemma because it would fire on every `List.map`.
theorem map_const' (l : Vector α n) (b : β) : map (fun _ => b) l = mkVector n b :=
map_const l b
@[simp] theorem set_mkVector_self : (mkVector n a).set i a h = mkVector n a := by
rw [← toArray_inj]
simp
@[simp] theorem setIfInBounds_mkVector_self : (mkVector n a).setIfInBounds i a = mkVector n a := by
rw [← toArray_inj]
simp
@[simp] theorem mkVector_append_mkVector : mkVector n a ++ mkVector m a = mkVector (n + m) a := by
rw [← toArray_inj]
simp
theorem append_eq_mkVector_iff {l₁ : Vector α n} {l₂ : Vector α m} {a : α} :
l₁ ++ l₂ = mkVector (n + m) a ↔ l₁ = mkVector n a ∧ l₂ = mkVector m a := by
simp [← toArray_inj, Array.append_eq_mkArray_iff]
theorem mkVector_eq_append_iff {l₁ : Vector α n} {l₂ : Vector α m} {a : α} :
mkVector (n + m) a = l₁ ++ l₂ ↔ l₁ = mkVector n a ∧ l₂ = mkVector m a := by
rw [eq_comm, append_eq_mkVector_iff]
@[simp] theorem map_mkVector : (mkVector n a).map f = mkVector n (f a) := by
rw [← toArray_inj]
simp
@[simp] theorem flatten_mkVector_empty : (mkVector n (#v[] : Vector α 0)).flatten = #v[] := by
rw [← toArray_inj]
simp
@[simp] theorem flatten_mkVector_singleton : (mkVector n #v[a]).flatten = (mkVector n a).cast (by simp) := by
ext i h
simp [h]
@[simp] theorem flatten_mkVector_mkVector : (mkVector n (mkVector m a)).flatten = mkVector (n * m) a := by
ext i h
simp [h]
theorem flatMap_mkArray {β} (f : α → Vector β m) : (mkVector n a).flatMap f = (mkVector n (f a)).flatten := by
ext i h
simp [h]
@[simp] theorem sum_mkArray_nat (n : Nat) (a : Nat) : (mkVector n a).sum = n * a := by
simp [toArray_mkVector]
/-! ### reverse -/
@[simp] theorem reverse_push (as : Vector α n) (a : α) :
(as.push a).reverse = (#v[a] ++ as.reverse).cast (by omega) := by
rcases as with ⟨as, rfl⟩
simp [Array.reverse_push]
@[simp] theorem mem_reverse {x : α} {as : Vector α n} : x ∈ as.reverse ↔ x ∈ as := by
cases as
simp
@[simp] theorem getElem_reverse (a : Vector α n) (i : Nat) (hi : i < n) :
(a.reverse)[i] = a[n - 1 - i] := by
rcases a with ⟨a, rfl⟩
simp
/-- Variant of `getElem?_reverse` with a hypothesis giving the linear relation between the indices. -/
theorem getElem?_reverse' {l : Vector α n} (i j) (h : i + j + 1 = n) : l.reverse[i]? = l[j]? := by
rcases l with ⟨l, rfl⟩
simpa using Array.getElem?_reverse' i j h
@[simp]
theorem getElem?_reverse {l : Vector α n} {i} (h : i < n) :
l.reverse[i]? = l[n - 1 - i]? := by
cases l
simp_all
@[simp] theorem reverse_reverse (as : Vector α n) : as.reverse.reverse = as := by
rcases as with ⟨as, rfl⟩
simp [Array.reverse_reverse]
theorem reverse_eq_iff {as bs : Vector α n} : as.reverse = bs ↔ as = bs.reverse := by
constructor <;> (rintro rfl; simp)
@[simp] theorem reverse_inj {xs ys : Vector α n} : xs.reverse = ys.reverse ↔ xs = ys := by
simp [reverse_eq_iff]
@[simp] theorem reverse_eq_push_iff {xs : Vector α (n + 1)} {ys : Vector α n} {a : α} :
xs.reverse = ys.push a ↔ xs = (#v[a] ++ ys.reverse).cast (by omega) := by
rcases xs with ⟨xs, h⟩
rcases ys with ⟨ys, rfl⟩
simp [Array.reverse_eq_push_iff]
@[simp] theorem map_reverse (f : α → β) (l : Vector α n) : l.reverse.map f = (l.map f).reverse := by
rcases l with ⟨l, rfl⟩
simp [Array.map_reverse]
@[simp] theorem reverse_append (as : Vector α n) (bs : Vector α m) :
(as ++ bs).reverse = (bs.reverse ++ as.reverse).cast (by omega) := by
rcases as with ⟨as, rfl⟩
rcases bs with ⟨bs, rfl⟩
simp [Array.reverse_append]
@[simp] theorem reverse_eq_append_iff {xs : Vector α (n + m)} {ys : Vector α n} {zs : Vector α m} :
xs.reverse = ys ++ zs ↔ xs = (zs.reverse ++ ys.reverse).cast (by omega) := by
cases xs
cases ys
cases zs
simp
/-- Reversing a flatten is the same as reversing the order of parts and reversing all parts. -/
theorem reverse_flatten (L : Vector (Vector α m) n) :
L.flatten.reverse = (L.map reverse).reverse.flatten := by
cases L using vector₂_induction
simp [Array.reverse_flatten]
/-- Flattening a reverse is the same as reversing all parts and reversing the flattened result. -/
theorem flatten_reverse (L : Vector (Vector α m) n) :
L.reverse.flatten = (L.map reverse).flatten.reverse := by
cases L using vector₂_induction
simp [Array.flatten_reverse]
theorem reverse_flatMap {β} (l : Vector α n) (f : α → Vector β m) :
(l.flatMap f).reverse = l.reverse.flatMap (reverse ∘ f) := by
rcases l with ⟨l, rfl⟩
simp [Array.reverse_flatMap, Function.comp_def]
theorem flatMap_reverse {β} (l : Vector α n) (f : α → Vector β m) :
(l.reverse.flatMap f) = (l.flatMap (reverse ∘ f)).reverse := by
rcases l with ⟨l, rfl⟩
simp [Array.flatMap_reverse, Function.comp_def]
@[simp] theorem reverse_mkVector (n) (a : α) : reverse (mkVector n a) = mkVector n a := by
rw [← toArray_inj]
simp
/-! ### extract -/
@[simp] theorem getElem_extract {as : Vector α n} {start stop : Nat}
(h : i < min stop n - start) :
(as.extract start stop)[i] = as[start + i] := by
rcases as with ⟨as, rfl⟩
simp
theorem getElem?_extract {as : Vector α n} {start stop : Nat} :
(as.extract start stop)[i]? = if i < min stop as.size - start then as[start + i]? else none := by
rcases as with ⟨as, rfl⟩
simp [Array.getElem?_extract]
@[simp] theorem extract_size (as : Vector α n) : as.extract 0 n = as.cast (by simp) := by
rcases as with ⟨as, rfl⟩
simp
theorem extract_empty (start stop : Nat) :
(#v[] : Vector α 0).extract start stop = #v[].cast (by simp) := by
simp
/-! ### foldlM and foldrM -/
@[simp] theorem foldlM_append [Monad m] [LawfulMonad m] (f : β → α → m β) (b) (l : Vector α n) (l' : Vector α k) :
(l ++ l').foldlM f b = l.foldlM f b >>= l'.foldlM f := by
rcases l with ⟨l, rfl⟩
rcases l' with ⟨l', rfl⟩
simp
@[simp] theorem foldlM_empty [Monad m] (f : β → α → m β) (init : β) :
foldlM f init #v[] = return init := by
simp [foldlM]
@[simp] theorem foldrM_empty [Monad m] (f : α → β → m β) (init : β) :
foldrM f init #v[] = return init := by
simp [foldrM]
@[simp] theorem foldlM_push [Monad m] [LawfulMonad m] (l : Vector α n) (a : α) (f : β → α → m β) (b) :
(l.push a).foldlM f b = l.foldlM f b >>= fun b => f b a := by
rcases l with ⟨l, rfl⟩
simp
theorem foldl_eq_foldlM (f : β → α → β) (b) (l : Vector α n) :
l.foldl f b = l.foldlM (m := Id) f b := by
rcases l with ⟨l, rfl⟩
simp [Array.foldl_eq_foldlM]
theorem foldr_eq_foldrM (f : α → β → β) (b) (l : Vector α n) :
l.foldr f b = l.foldrM (m := Id) f b := by
rcases l with ⟨l, rfl⟩
simp [Array.foldr_eq_foldrM]
@[simp] theorem id_run_foldlM (f : β → α → Id β) (b) (l : Vector α n) :
Id.run (l.foldlM f b) = l.foldl f b := (foldl_eq_foldlM f b l).symm
@[simp] theorem id_run_foldrM (f : α → β → Id β) (b) (l : Vector α n) :
Id.run (l.foldrM f b) = l.foldr f b := (foldr_eq_foldrM f b l).symm
@[simp] theorem foldlM_reverse [Monad m] (l : Vector α n) (f : β → α → m β) (b) :
l.reverse.foldlM f b = l.foldrM (fun x y => f y x) b := by
rcases l with ⟨l, rfl⟩
simp [Array.foldlM_reverse]
@[simp] theorem foldrM_reverse [Monad m] (l : Vector α n) (f : α → β → m β) (b) :
l.reverse.foldrM f b = l.foldlM (fun x y => f y x) b := by
rcases l with ⟨l, rfl⟩
simp
@[simp] theorem foldrM_push [Monad m] (f : α → β → m β) (init : β) (arr : Vector α n) (a : α) :
(arr.push a).foldrM f init = f a init >>= arr.foldrM f := by
rcases arr with ⟨arr, rfl⟩
simp [Array.foldrM_push]
/-! ### foldl / foldr -/
@[congr]
theorem foldl_congr {as bs : Vector α n} (h₀ : as = bs) {f g : β → α → β} (h₁ : f = g)
{a b : β} (h₂ : a = b) :
as.foldl f a = bs.foldl g b := by
congr
@[congr]
theorem foldr_congr {as bs : Vector α n} (h₀ : as = bs) {f g : α → β → β} (h₁ : f = g)
{a b : β} (h₂ : a = b) :
as.foldr f a = bs.foldr g b := by
congr
@[simp] theorem foldr_push (f : α → β → β) (init : β) (arr : Vector α n) (a : α) :
(arr.push a).foldr f init = arr.foldr f (f a init) := by
rcases arr with ⟨arr, rfl⟩
simp [Array.foldr_push]
theorem foldl_map (f : β₁ → β₂) (g : α → β₂ → α) (l : Vector β₁ n) (init : α) :
(l.map f).foldl g init = l.foldl (fun x y => g x (f y)) init := by
cases l; simp [Array.foldl_map']
theorem foldr_map (f : α₁ → α₂) (g : α₂ → β → β) (l : Vector α₁ n) (init : β) :
(l.map f).foldr g init = l.foldr (fun x y => g (f x) y) init := by
cases l; simp [Array.foldr_map']
theorem foldl_filterMap (f : α → Option β) (g : γ → β → γ) (l : Vector α n) (init : γ) :
(l.filterMap f).foldl g init = l.foldl (fun x y => match f y with | some b => g x b | none => x) init := by
rcases l with ⟨l, rfl⟩
simp [Array.foldl_filterMap']
rfl
theorem foldr_filterMap (f : α → Option β) (g : β → γγ) (l : Vector α n) (init : γ) :
(l.filterMap f).foldr g init = l.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
rcases l with ⟨l, rfl⟩
simp [Array.foldr_filterMap']
rfl
theorem foldl_map_hom (g : α → β) (f : ααα) (f' : β → β → β) (a : α) (l : Vector α n)
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
(l.map g).foldl f' (g a) = g (l.foldl f a) := by
rcases l with ⟨l, rfl⟩
simp
rw [Array.foldl_map_hom' _ _ _ _ _ h rfl]
theorem foldr_map_hom (g : α → β) (f : ααα) (f' : β → β → β) (a : α) (l : Vector α n)
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
rcases l with ⟨l, rfl⟩
simp
rw [Array.foldr_map_hom' _ _ _ _ _ h rfl]
@[simp] theorem foldrM_append [Monad m] [LawfulMonad m] (f : α → β → m β) (b) (l : Vector α n) (l' : Vector α k) :
(l ++ l').foldrM f b = l'.foldrM f b >>= l.foldrM f := by
rcases l with ⟨l, rfl⟩
rcases l' with ⟨l', rfl⟩
simp
@[simp] theorem foldl_append {β : Type _} (f : β → α → β) (b) (l : Vector α n) (l' : Vector α k) :
(l ++ l').foldl f b = l'.foldl f (l.foldl f b) := by simp [foldl_eq_foldlM]
@[simp] theorem foldr_append (f : α → β → β) (b) (l : Vector α n) (l' : Vector α k) :
(l ++ l').foldr f b = l.foldr f (l'.foldr f b) := by simp [foldr_eq_foldrM]
@[simp] theorem foldl_flatten (f : β → α → β) (b : β) (L : Vector (Vector α m) n) :
(flatten L).foldl f b = L.foldl (fun b l => l.foldl f b) b := by
cases L using vector₂_induction
simp [Array.foldl_flatten', Array.foldl_map']
@[simp] theorem foldr_flatten (f : α → β → β) (b : β) (L : Vector (Vector α m) n) :
(flatten L).foldr f b = L.foldr (fun l b => l.foldr f b) b := by
cases L using vector₂_induction
simp [Array.foldr_flatten', Array.foldr_map']
@[simp] theorem foldl_reverse (l : Vector α n) (f : β → α → β) (b) :
l.reverse.foldl f b = l.foldr (fun x y => f y x) b := by simp [foldl_eq_foldlM, foldr_eq_foldrM]
@[simp] theorem foldr_reverse (l : Vector α n) (f : α → β → β) (b) :
l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
(foldl_reverse ..).symm.trans <| by simp
theorem foldl_eq_foldr_reverse (l : Vector α n) (f : β → α → β) (b) :
l.foldl f b = l.reverse.foldr (fun x y => f y x) b := by simp
theorem foldr_eq_foldl_reverse (l : Vector α n) (f : α → β → β) (b) :
l.foldr f b = l.reverse.foldl (fun x y => f y x) b := by simp
theorem foldl_assoc {op : ααα} [ha : Std.Associative op] {l : Vector α n} {a₁ a₂} :
l.foldl op (op a₁ a₂) = op a₁ (l.foldl op a₂) := by
rcases l with ⟨l, rfl⟩
simp [Array.foldl_assoc]
@[simp] theorem foldr_assoc {op : ααα} [ha : Std.Associative op] {l : Vector α n} {a₁ a₂} :
l.foldr op (op a₁ a₂) = op (l.foldr op a₁) a₂ := by
rcases l with ⟨l, rfl⟩
simp [Array.foldr_assoc]
theorem foldl_hom (f : α₁ → α₂) (g₁ : α₁ → β → α₁) (g₂ : α₂ → β → α₂) (l : Vector β n) (init : α₁)
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) : l.foldl g₂ (f init) = f (l.foldl g₁ init) := by
rcases l with ⟨l, rfl⟩
simp
rw [Array.foldl_hom _ _ _ _ _ H]
theorem foldr_hom (f : β₁ → β₂) (g₁ : α → β₁ → β₁) (g₂ : α → β₂ → β₂) (l : Vector α n) (init : β₁)
(H : ∀ x y, g₂ x (f y) = f (g₁ x y)) : l.foldr g₂ (f init) = f (l.foldr g₁ init) := by
cases l
simp
rw [Array.foldr_hom _ _ _ _ _ H]
/--
We can prove that two folds over the same array are related (by some arbitrary relation)
if we know that the initial elements are related and the folding function, for each element of the array,
preserves the relation.
-/
theorem foldl_rel {l : Array α} {f g : β → α → β} {a b : β} (r : β → β → Prop)
(h : r a b) (h' : ∀ (a : α), a ∈ l → ∀ (c c' : β), r c c' → r (f c a) (g c' a)) :
r (l.foldl (fun acc a => f acc a) a) (l.foldl (fun acc a => g acc a) b) := by
rcases l with ⟨l⟩
simpa using List.foldl_rel r h (by simpa using h')
/--
We can prove that two folds over the same array are related (by some arbitrary relation)
if we know that the initial elements are related and the folding function, for each element of the array,
preserves the relation.
-/
theorem foldr_rel {l : Array α} {f g : α → β → β} {a b : β} (r : β → β → Prop)
(h : r a b) (h' : ∀ (a : α), a ∈ l → ∀ (c c' : β), r c c' → r (f a c) (g a c')) :
r (l.foldr (fun a acc => f a acc) a) (l.foldr (fun a acc => g a acc) b) := by
rcases l with ⟨l⟩
simpa using List.foldr_rel r h (by simpa using h')
@[simp] theorem foldl_add_const (l : Array α) (a b : Nat) :
l.foldl (fun x _ => x + a) b = b + a * l.size := by
rcases l with ⟨l⟩
simp
@[simp] theorem foldr_add_const (l : Array α) (a b : Nat) :
l.foldr (fun _ x => x + a) b = b + a * l.size := by
rcases l with ⟨l⟩
simp
/-! Content below this point has not yet been aligned with `List` and `Array`. -/
@[simp] theorem getElem_push_last {v : Vector α n} {x : α} : (v.push x)[n] = x := by
rcases v with ⟨data, rfl⟩
simp
@[simp] theorem getElem_pop {v : Vector α n} {i : Nat} (h : i < n - 1) : (v.pop)[i] = v[i] := by
rcases v with ⟨data, rfl⟩
simp
/--
Variant of `getElem_pop` that will sometimes fire when `getElem_pop` gets stuck because of
defeq issues in the implicit size argument.
-/
@[simp] theorem getElem_pop' (v : Vector α (n + 1)) (i : Nat) (h : i < n + 1 - 1) :
@getElem (Vector α n) Nat α (fun _ i => i < n) instGetElemNatLt v.pop i h = v[i] :=
getElem_pop h
@[simp] theorem push_pop_back (v : Vector α (n + 1)) : v.pop.push v.back = v := by
ext i
by_cases h : i < n
· simp [h]
· replace h : i = v.size - 1 := by rw [size_toArray]; omega
subst h
simp [back]
/-! ### zipWith -/
@[simp] theorem getElem_zipWith (f : α → β → γ) (a : Vector α n) (b : Vector β n) (i : Nat)
(hi : i < n) : (zipWith f a b)[i] = f a[i] b[i] := by
cases a
cases b
simp
/-! ### take -/
@[simp] theorem take_size (a : Vector α n) : a.take n = a.cast (by simp) := by
rcases a with ⟨a, rfl⟩
simp
/-! ### swap -/
theorem getElem_swap (a : Vector α n) (i j : Nat) {hi hj} (k : Nat) (hk : k < n) :
(a.swap i j hi hj)[k] = if k = i then a[j] else if k = j then a[i] else a[k] := by
cases a
simp_all [Array.getElem_swap]
@[simp] theorem getElem_swap_right (a : Vector α n) {i j : Nat} {hi hj} :
(a.swap i j hi hj)[j]'(by simpa using hj) = a[i] := by
simp +contextual [getElem_swap]
@[simp] theorem getElem_swap_left (a : Vector α n) {i j : Nat} {hi hj} :
(a.swap i j hi hj)[i]'(by simpa using hi) = a[j] := by
simp [getElem_swap]
@[simp] theorem getElem_swap_of_ne (a : Vector α n) {i j : Nat} {hi hj} (hp : p < n)
(hi' : p ≠ i) (hj' : p ≠ j) : (a.swap i j hi hj)[p] = a[p] := by
simp_all [getElem_swap]
@[simp] theorem swap_swap (a : Vector α n) {i j : Nat} {hi hj} :
(a.swap i j hi hj).swap i j hi hj = a := by
cases a
simp_all [Array.swap_swap]
theorem swap_comm (a : Vector α n) {i j : Nat} {hi hj} :
a.swap i j hi hj = a.swap j i hj hi := by
cases a
simp only [swap_mk, mk.injEq]
rw [Array.swap_comm]
/-! ### range -/
@[simp] theorem getElem_range (i : Nat) (hi : i < n) : (Vector.range n)[i] = i := by
simp [Vector.range]
/-! ### take -/
@[simp] theorem getElem_take (a : Vector α n) (m : Nat) (hi : i < min n m) :
(a.take m)[i] = a[i] := by
cases a
simp
/-! ### drop -/
@[simp] theorem getElem_drop (a : Vector α n) (m : Nat) (hi : i < n - m) :
(a.drop m)[i] = a[m + i] := by
cases a
simp
/-! ### Decidable quantifiers. -/
theorem forall_zero_iff {P : Vector α 0 → Prop} :
(∀ v, P v) ↔ P #v[] := by
constructor
· intro h
apply h
· intro h v
obtain (rfl : v = #v[]) := (by ext i h; simp at h)
apply h
theorem forall_cons_iff {P : Vector α (n + 1) → Prop} :
(∀ v : Vector α (n + 1), P v) ↔ (∀ (x : α) (v : Vector α n), P (v.push x)) := by
constructor
· intro h _ _
apply h
· intro h v
have w : v = v.pop.push v.back := by simp
rw [w]
apply h
instance instDecidableForallVectorZero (P : Vector α 0 → Prop) :
∀ [Decidable (P #v[])], Decidable (∀ v, P v)
| .isTrue h => .isTrue fun ⟨v, s⟩ => by
obtain (rfl : v = .empty) := (by ext i h₁ h₂; exact s; cases h₂)
exact h
| .isFalse h => .isFalse (fun w => h (w _))
instance instDecidableForallVectorSucc (P : Vector α (n+1) → Prop)
[Decidable (∀ (x : α) (v : Vector α n), P (v.push x))] : Decidable (∀ v, P v) :=
decidable_of_iff' (∀ x (v : Vector α n), P (v.push x)) forall_cons_iff
instance instDecidableExistsVectorZero (P : Vector α 0 → Prop) [Decidable (P #v[])] :
Decidable (∃ v, P v) :=
decidable_of_iff (¬ ∀ v, ¬ P v) Classical.not_forall_not
instance instDecidableExistsVectorSucc (P : Vector α (n+1) → Prop)
[Decidable (∀ (x : α) (v : Vector α n), ¬ P (v.push x))] : Decidable (∃ v, P v) :=
decidable_of_iff (¬ ∀ v, ¬ P v) Classical.not_forall_not