497 lines
20 KiB
Text
497 lines
20 KiB
Text
/-
|
||
Copyright (c) 2022 Mario Carneiro. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Mario Carneiro, Kim Morrison
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
import all Init.Data.Array.Basic
|
||
public import Init.Data.Array.OfFn
|
||
public import Init.Data.List.MapIdx
|
||
import all Init.Data.List.MapIdx
|
||
|
||
public section
|
||
|
||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||
|
||
namespace Array
|
||
|
||
/-! ### mapFinIdx -/
|
||
|
||
-- This could also be proved from `SatisfiesM_mapIdxM` in Batteries.
|
||
theorem mapFinIdx_induction (xs : Array α) (f : (i : Nat) → α → (h : i < xs.size) → β)
|
||
(motive : Nat → Prop) (h0 : motive 0)
|
||
(p : (i : Nat) → β → (h : i < xs.size) → Prop)
|
||
(hs : ∀ i h, motive i → p i (f i xs[i] h) h ∧ motive (i + 1)) :
|
||
motive xs.size ∧ ∃ eq : (Array.mapFinIdx xs f).size = xs.size,
|
||
∀ i h, p i ((Array.mapFinIdx xs f)[i]) h := by
|
||
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : ∀ i h h', p i bs[i] h) (hm : motive j) :
|
||
let as : Array β := Id.run <| Array.mapFinIdxM.map xs (pure <| f · · ·) i j h bs
|
||
motive xs.size ∧ ∃ eq : as.size = xs.size, ∀ i h, p i as[i] h := by
|
||
induction i generalizing j bs with simp [mapFinIdxM.map]
|
||
| zero =>
|
||
have := (Nat.zero_add _).symm.trans h
|
||
exact ⟨this ▸ hm, h₁ ▸ this, fun _ _ => h₂ ..⟩
|
||
| succ i ih =>
|
||
apply @ih (bs.push (f j xs[j] (by omega))) (j + 1) (by omega) (by simp; omega)
|
||
· intro i i_lt h'
|
||
rw [getElem_push]
|
||
split
|
||
· apply h₂
|
||
· simp only [size_push] at h'
|
||
obtain rfl : i = j := by omega
|
||
apply (hs i (by omega) hm).1
|
||
· exact (hs j (by omega) hm).2
|
||
simp [mapFinIdx, mapFinIdxM]; exact go rfl nofun h0
|
||
|
||
theorem mapFinIdx_spec {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β}
|
||
{p : (i : Nat) → β → (h : i < xs.size) → Prop} (hs : ∀ i h, p i (f i xs[i] h) h) :
|
||
∃ eq : (Array.mapFinIdx xs f).size = xs.size,
|
||
∀ i h, p i ((Array.mapFinIdx xs f)[i]) h :=
|
||
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => ⟨hs .., trivial⟩).2
|
||
|
||
@[simp, grind =] theorem size_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||
(xs.mapFinIdx f).size = xs.size :=
|
||
(mapFinIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
|
||
|
||
@[simp, grind =] theorem size_zipIdx {xs : Array α} {k : Nat} : (xs.zipIdx k).size = xs.size :=
|
||
Array.size_mapFinIdx
|
||
|
||
|
||
|
||
@[simp, grind =] theorem getElem_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat}
|
||
(h : i < (xs.mapFinIdx f).size) :
|
||
(xs.mapFinIdx f)[i] = f i (xs[i]'(by simp_all)) (by simp_all) :=
|
||
(mapFinIdx_spec (p := fun i b h => b = f i xs[i] h) fun _ _ => rfl).2 i _
|
||
|
||
@[simp, grind =] theorem getElem?_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat} :
|
||
(xs.mapFinIdx f)[i]? =
|
||
xs[i]?.pbind fun b h => some <| f i b (getElem?_eq_some_iff.1 h).1 := by
|
||
simp only [getElem?_def, size_mapFinIdx, getElem_mapFinIdx]
|
||
split <;> simp_all
|
||
|
||
@[simp, grind =] theorem toList_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||
(xs.mapFinIdx f).toList = xs.toList.mapFinIdx (fun i a h => f i a (by simpa)) := by
|
||
apply List.ext_getElem <;> simp
|
||
|
||
/-! ### mapIdx -/
|
||
|
||
theorem mapIdx_induction {f : Nat → α → β} {xs : Array α}
|
||
{motive : Nat → Prop} (h0 : motive 0)
|
||
{p : (i : Nat) → β → (h : i < xs.size) → Prop}
|
||
(hs : ∀ i h, motive i → p i (f i xs[i]) h ∧ motive (i + 1)) :
|
||
motive xs.size ∧ ∃ eq : (xs.mapIdx f).size = xs.size,
|
||
∀ i h, p i ((xs.mapIdx f)[i]) h :=
|
||
mapFinIdx_induction xs (fun i a _ => f i a) motive h0 p hs
|
||
|
||
theorem mapIdx_spec {f : Nat → α → β} {xs : Array α}
|
||
{p : (i : Nat) → β → (h : i < xs.size) → Prop} (hs : ∀ i h, p i (f i xs[i]) h) :
|
||
∃ eq : (xs.mapIdx f).size = xs.size,
|
||
∀ i h, p i ((xs.mapIdx f)[i]) h :=
|
||
(mapIdx_induction (motive := fun _ => True) trivial fun _ _ _ => ⟨hs .., trivial⟩).2
|
||
|
||
@[simp, grind =] theorem size_mapIdx {f : Nat → α → β} {xs : Array α} : (xs.mapIdx f).size = xs.size :=
|
||
(mapIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
|
||
|
||
@[simp, grind =] theorem getElem_mapIdx {f : Nat → α → β} {xs : Array α} {i : Nat}
|
||
(h : i < (xs.mapIdx f).size) :
|
||
(xs.mapIdx f)[i] = f i (xs[i]'(by simp_all)) :=
|
||
(mapIdx_spec (p := fun i b h => b = f i xs[i]) fun _ _ => rfl).2 i (by simp_all)
|
||
|
||
@[simp, grind =] theorem getElem?_mapIdx {f : Nat → α → β} {xs : Array α} {i : Nat} :
|
||
(xs.mapIdx f)[i]? =
|
||
xs[i]?.map (f i) := by
|
||
simp [getElem?_def, size_mapIdx, getElem_mapIdx]
|
||
|
||
@[simp, grind =] theorem toList_mapIdx {f : Nat → α → β} {xs : Array α} :
|
||
(xs.mapIdx f).toList = xs.toList.mapIdx (fun i a => f i a) := by
|
||
apply List.ext_getElem <;> simp
|
||
|
||
end Array
|
||
|
||
namespace List
|
||
|
||
@[simp, grind =] theorem mapFinIdx_toArray {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||
l.toArray.mapFinIdx f = (l.mapFinIdx f).toArray := by
|
||
ext <;> simp
|
||
|
||
@[simp, grind =] theorem mapIdx_toArray {f : Nat → α → β} {l : List α} :
|
||
l.toArray.mapIdx f = (l.mapIdx f).toArray := by
|
||
ext <;> simp
|
||
|
||
end List
|
||
|
||
namespace Array
|
||
|
||
/-! ### zipIdx -/
|
||
|
||
@[simp, grind =] theorem getElem_zipIdx {xs : Array α} {k : Nat} {i : Nat} (h : i < (xs.zipIdx k).size) :
|
||
(xs.zipIdx k)[i] = (xs[i]'(by simp_all), k + i) := by
|
||
simp [zipIdx]
|
||
|
||
|
||
|
||
@[simp, grind =] theorem zipIdx_toArray {l : List α} {k : Nat} :
|
||
l.toArray.zipIdx k = (l.zipIdx k).toArray := by
|
||
ext i hi₁ hi₂ <;> simp
|
||
|
||
|
||
|
||
@[simp, grind =] theorem toList_zipIdx {xs : Array α} {k : Nat} :
|
||
(xs.zipIdx k).toList = xs.toList.zipIdx k := by
|
||
rcases xs with ⟨xs⟩
|
||
simp
|
||
|
||
|
||
|
||
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {k i : Nat} {x : α} {xs : Array α} :
|
||
(x, i) ∈ xs.zipIdx k ↔ k ≤ i ∧ xs[i - k]? = some x := by
|
||
rcases xs with ⟨xs⟩
|
||
simp [List.mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||
|
||
/-- Variant of `mk_mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
|
||
to avoid the inequality and the subtraction. -/
|
||
theorem mk_mem_zipIdx_iff_getElem? {x : α} {i : Nat} {xs : Array α} :
|
||
(x, i) ∈ xs.zipIdx ↔ xs[i]? = some x := by
|
||
rw [mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||
simp
|
||
|
||
theorem mem_zipIdx_iff_le_and_getElem?_sub {x : α × Nat} {xs : Array α} {k : Nat} :
|
||
x ∈ xs.zipIdx k ↔ k ≤ x.2 ∧ xs[x.2 - k]? = some x.1 := by
|
||
cases x
|
||
simp [mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||
|
||
/-- Variant of `mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
|
||
to avoid the inequality and the subtraction. -/
|
||
theorem mem_zipIdx_iff_getElem? {x : α × Nat} {xs : Array α} :
|
||
x ∈ xs.zipIdx ↔ xs[x.2]? = some x.1 := by
|
||
rw [mk_mem_zipIdx_iff_getElem?]
|
||
|
||
|
||
|
||
/-! ### mapFinIdx -/
|
||
|
||
@[congr] theorem mapFinIdx_congr {xs ys : Array α} (w : xs = ys)
|
||
(f : (i : Nat) → α → (h : i < xs.size) → β) :
|
||
mapFinIdx xs f = mapFinIdx ys (fun i a h => f i a (by simp [w]; omega)) := by
|
||
subst w
|
||
rfl
|
||
|
||
@[simp, grind =]
|
||
theorem mapFinIdx_empty {f : (i : Nat) → α → (h : i < 0) → β} : mapFinIdx #[] f = #[] :=
|
||
rfl
|
||
|
||
theorem mapFinIdx_eq_ofFn {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||
xs.mapFinIdx f = Array.ofFn fun i : Fin xs.size => f i xs[i] i.2 := by
|
||
cases xs
|
||
simp only [List.mapFinIdx_toArray, List.mapFinIdx_eq_ofFn, Fin.getElem_fin, List.getElem_toArray]
|
||
simp [Array.size]
|
||
|
||
@[grind =]
|
||
theorem mapFinIdx_append {xs ys : Array α} {f : (i : Nat) → α → (h : i < (xs ++ ys).size) → β} :
|
||
(xs ++ ys).mapFinIdx f =
|
||
xs.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
|
||
ys.mapFinIdx (fun i a h => f (i + xs.size) a (by simp; omega)) := by
|
||
cases xs
|
||
cases ys
|
||
simp [List.mapFinIdx_append, Array.size]
|
||
|
||
@[simp, grind =]
|
||
theorem mapFinIdx_push {xs : Array α} {a : α} {f : (i : Nat) → α → (h : i < (xs.push a).size) → β} :
|
||
mapFinIdx (xs.push a) f =
|
||
(mapFinIdx xs (fun i a h => f i a (by simp; omega))).push (f xs.size a (by simp)) := by
|
||
simp [← append_singleton, mapFinIdx_append]
|
||
|
||
theorem mapFinIdx_singleton {a : α} {f : (i : Nat) → α → (h : i < 1) → β} :
|
||
#[a].mapFinIdx f = #[f 0 a (by simp)] := by
|
||
simp
|
||
|
||
theorem mapFinIdx_eq_zipIdx_map {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||
xs.mapFinIdx f = xs.zipIdx.attach.map
|
||
fun ⟨⟨x, i⟩, m⟩ =>
|
||
f i x (by simp [mk_mem_zipIdx_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
|
||
ext <;> simp
|
||
|
||
|
||
|
||
@[simp]
|
||
theorem mapFinIdx_eq_empty_iff {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||
xs.mapFinIdx f = #[] ↔ xs = #[] := by
|
||
cases xs
|
||
simp
|
||
|
||
theorem mapFinIdx_ne_empty_iff {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||
xs.mapFinIdx f ≠ #[] ↔ xs ≠ #[] := by
|
||
simp
|
||
|
||
theorem exists_of_mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β}
|
||
(h : b ∈ xs.mapFinIdx f) : ∃ (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
|
||
rcases xs with ⟨xs⟩
|
||
exact List.exists_of_mem_mapFinIdx (by simpa using h)
|
||
|
||
@[simp, grind =] theorem mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||
b ∈ xs.mapFinIdx f ↔ ∃ (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
|
||
rcases xs with ⟨xs⟩
|
||
simp
|
||
|
||
theorem mapFinIdx_eq_iff {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {ys : Array β} :
|
||
xs.mapFinIdx f = ys ↔ ∃ h : ys.size = xs.size, ∀ (i : Nat) (h : i < xs.size), ys[i] = f i xs[i] h := by
|
||
rcases xs with ⟨xs⟩
|
||
rcases ys with ⟨ys⟩
|
||
simpa using List.mapFinIdx_eq_iff
|
||
|
||
@[simp] theorem mapFinIdx_eq_singleton_iff {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {b : β} :
|
||
xs.mapFinIdx f = #[b] ↔ ∃ (a : α) (w : xs = #[a]), f 0 a (by simp [w]) = b := by
|
||
rcases xs with ⟨xs⟩
|
||
simp
|
||
|
||
theorem mapFinIdx_eq_append_iff {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {ys zs : Array β} :
|
||
xs.mapFinIdx f = ys ++ zs ↔
|
||
∃ (ys' : Array α) (zs' : Array α) (w : xs = ys' ++ zs'),
|
||
ys'.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = ys ∧
|
||
zs'.mapFinIdx (fun i a h => f (i + ys'.size) a (by simp [w]; omega)) = zs := by
|
||
rcases xs with ⟨l⟩
|
||
rcases ys with ⟨l₁⟩
|
||
rcases zs with ⟨l₂⟩
|
||
simp only [List.mapFinIdx_toArray, List.append_toArray, mk.injEq, List.mapFinIdx_eq_append_iff,
|
||
toArray_eq_append_iff]
|
||
constructor
|
||
· rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
|
||
refine ⟨l₁.toArray, l₂.toArray, by simp_all [Array.size]⟩
|
||
· rintro ⟨⟨l₁⟩, ⟨l₂⟩, rfl, h₁, h₂⟩
|
||
simp [← toList_inj] at h₁ h₂
|
||
obtain rfl := h₁
|
||
obtain rfl := h₂
|
||
refine ⟨l₁, l₂, by simp_all [Array.size]⟩
|
||
|
||
theorem mapFinIdx_eq_push_iff {xs : Array α} {b : β} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||
xs.mapFinIdx f = ys.push b ↔
|
||
∃ (zs : Array α) (a : α) (w : xs = zs.push a),
|
||
zs.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = ys ∧ b = f (xs.size - 1) a (by simp [w]) := by
|
||
rw [push_eq_append, mapFinIdx_eq_append_iff]
|
||
constructor
|
||
· rintro ⟨ys', zs', rfl, rfl, h₂⟩
|
||
simp only [mapFinIdx_eq_singleton_iff, Nat.zero_add] at h₂
|
||
obtain ⟨a, rfl, rfl⟩ := h₂
|
||
exact ⟨ys', a, by simp⟩
|
||
· rintro ⟨zs, a, rfl, rfl, rfl⟩
|
||
exact ⟨zs, #[a], by simp⟩
|
||
|
||
theorem mapFinIdx_eq_mapFinIdx_iff {xs : Array α} {f g : (i : Nat) → α → (h : i < xs.size) → β} :
|
||
xs.mapFinIdx f = xs.mapFinIdx g ↔ ∀ (i : Nat) (h : i < xs.size), f i xs[i] h = g i xs[i] h := by
|
||
rw [eq_comm, mapFinIdx_eq_iff]
|
||
simp
|
||
|
||
@[simp, grind =] theorem mapFinIdx_mapFinIdx {xs : Array α}
|
||
{f : (i : Nat) → α → (h : i < xs.size) → β}
|
||
{g : (i : Nat) → β → (h : i < (xs.mapFinIdx f).size) → γ} :
|
||
(xs.mapFinIdx f).mapFinIdx g = xs.mapFinIdx (fun i a h => g i (f i a h) (by simpa using h)) := by
|
||
simp [mapFinIdx_eq_iff]
|
||
|
||
theorem mapFinIdx_eq_replicate_iff {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {b : β} :
|
||
xs.mapFinIdx f = replicate xs.size b ↔ ∀ (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
|
||
rcases xs with ⟨l⟩
|
||
rw [← toList_inj]
|
||
simp [List.mapFinIdx_eq_replicate_iff]
|
||
|
||
@[simp, grind =] theorem mapFinIdx_reverse {xs : Array α} {f : (i : Nat) → α → (h : i < xs.reverse.size) → β} :
|
||
xs.reverse.mapFinIdx f = (xs.mapFinIdx (fun i a h => f (xs.size - 1 - i) a (by simp; omega))).reverse := by
|
||
rcases xs with ⟨l⟩
|
||
simp [List.mapFinIdx_reverse, Array.size]
|
||
|
||
/-! ### mapIdx -/
|
||
|
||
@[simp, grind =]
|
||
theorem mapIdx_empty {f : Nat → α → β} : mapIdx f #[] = #[] :=
|
||
rfl
|
||
|
||
@[simp] theorem mapFinIdx_eq_mapIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {g : Nat → α → β}
|
||
(h : ∀ (i : Nat) (h : i < xs.size), f i xs[i] h = g i xs[i]) :
|
||
xs.mapFinIdx f = xs.mapIdx g := by
|
||
simp_all [mapFinIdx_eq_iff]
|
||
|
||
theorem mapIdx_eq_mapFinIdx {xs : Array α} {f : Nat → α → β} :
|
||
xs.mapIdx f = xs.mapFinIdx (fun i a _ => f i a) := by
|
||
simp [mapFinIdx_eq_mapIdx]
|
||
|
||
theorem mapIdx_eq_zipIdx_map {xs : Array α} {f : Nat → α → β} :
|
||
xs.mapIdx f = xs.zipIdx.map fun ⟨a, i⟩ => f i a := by
|
||
ext <;> simp
|
||
|
||
|
||
|
||
@[grind =]
|
||
theorem mapIdx_append {xs ys : Array α} :
|
||
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx (fun i => f (i + xs.size)) := by
|
||
rcases xs with ⟨xs⟩
|
||
rcases ys with ⟨ys⟩
|
||
simp [List.mapIdx_append]
|
||
|
||
@[simp, grind =]
|
||
theorem mapIdx_push {xs : Array α} {a : α} :
|
||
mapIdx f (xs.push a) = (mapIdx f xs).push (f xs.size a) := by
|
||
simp [← append_singleton, mapIdx_append]
|
||
|
||
theorem mapIdx_singleton {a : α} : mapIdx f #[a] = #[f 0 a] := by
|
||
simp
|
||
|
||
@[simp]
|
||
theorem mapIdx_eq_empty_iff {xs : Array α} : mapIdx f xs = #[] ↔ xs = #[] := by
|
||
rcases xs with ⟨xs⟩
|
||
simp
|
||
|
||
theorem mapIdx_ne_empty_iff {xs : Array α} :
|
||
mapIdx f xs ≠ #[] ↔ xs ≠ #[] := by
|
||
simp
|
||
|
||
theorem exists_of_mem_mapIdx {b : β} {xs : Array α}
|
||
(h : b ∈ mapIdx f xs) : ∃ (i : Nat) (h : i < xs.size), f i xs[i] = b := by
|
||
rw [mapIdx_eq_mapFinIdx] at h
|
||
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
|
||
|
||
@[simp, grind =] theorem mem_mapIdx {b : β} {xs : Array α} :
|
||
b ∈ mapIdx f xs ↔ ∃ (i : Nat) (h : i < xs.size), f i xs[i] = b := by
|
||
constructor
|
||
· intro h
|
||
exact exists_of_mem_mapIdx h
|
||
· rintro ⟨i, h, rfl⟩
|
||
rw [mem_iff_getElem]
|
||
exact ⟨i, by simpa using h, by simp⟩
|
||
|
||
theorem mapIdx_eq_push_iff {xs : Array α} {b : β} :
|
||
mapIdx f xs = ys.push b ↔
|
||
∃ (a : α) (zs : Array α), xs = zs.push a ∧ mapIdx f zs = ys ∧ f zs.size a = b := by
|
||
rw [mapIdx_eq_mapFinIdx, mapFinIdx_eq_push_iff]
|
||
simp only [mapFinIdx_eq_mapIdx, exists_and_left, exists_prop]
|
||
constructor
|
||
· rintro ⟨zs, rfl, a, rfl, rfl⟩
|
||
exact ⟨a, zs, by simp⟩
|
||
· rintro ⟨a, zs, rfl, rfl, rfl⟩
|
||
exact ⟨zs, rfl, a, by simp⟩
|
||
|
||
@[simp] theorem mapIdx_eq_singleton_iff {xs : Array α} {f : Nat → α → β} {b : β} :
|
||
mapIdx f xs = #[b] ↔ ∃ (a : α), xs = #[a] ∧ f 0 a = b := by
|
||
rcases xs with ⟨xs⟩
|
||
simp [List.mapIdx_eq_singleton_iff]
|
||
|
||
theorem mapIdx_eq_append_iff {xs : Array α} {f : Nat → α → β} {ys zs : Array β} :
|
||
mapIdx f xs = ys ++ zs ↔
|
||
∃ (xs' : Array α) (zs' : Array α), xs = xs' ++ zs' ∧
|
||
xs'.mapIdx f = ys ∧
|
||
zs'.mapIdx (fun i => f (i + xs'.size)) = zs := by
|
||
rcases xs with ⟨xs⟩
|
||
rcases ys with ⟨ys⟩
|
||
rcases zs with ⟨zs⟩
|
||
simp only [List.mapIdx_toArray, List.append_toArray, mk.injEq, List.mapIdx_eq_append_iff,
|
||
toArray_eq_append_iff]
|
||
constructor
|
||
· rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
|
||
exact ⟨l₁.toArray, l₂.toArray, by simp⟩
|
||
· rintro ⟨⟨l₁⟩, ⟨l₂⟩, rfl, h₁, h₂⟩
|
||
simp only [List.mapIdx_toArray, mk.injEq, List.size_toArray] at h₁ h₂
|
||
obtain rfl := h₁
|
||
obtain rfl := h₂
|
||
exact ⟨l₁, l₂, by simp⟩
|
||
|
||
theorem mapIdx_eq_iff {xs : Array α} : mapIdx f xs = ys ↔ ∀ i : Nat, ys[i]? = xs[i]?.map (f i) := by
|
||
rcases xs with ⟨xs⟩
|
||
rcases ys with ⟨ys⟩
|
||
simp [List.mapIdx_eq_iff]
|
||
|
||
theorem mapIdx_eq_mapIdx_iff {xs : Array α} :
|
||
mapIdx f xs = mapIdx g xs ↔ ∀ i : Nat, (h : i < xs.size) → f i xs[i] = g i xs[i] := by
|
||
rcases xs with ⟨xs⟩
|
||
simp [List.mapIdx_eq_mapIdx_iff]
|
||
|
||
@[simp, grind =] theorem mapIdx_set {f : Nat → α → β} {xs : Array α} {i : Nat} {h : i < xs.size} {a : α} :
|
||
(xs.set i a).mapIdx f = (xs.mapIdx f).set i (f i a) (by simpa) := by
|
||
rcases xs with ⟨xs⟩
|
||
simp [List.mapIdx_set]
|
||
|
||
@[simp] theorem mapIdx_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
|
||
(xs.setIfInBounds i a).mapIdx f = (xs.mapIdx f).setIfInBounds i (f i a) := by
|
||
rcases xs with ⟨xs⟩
|
||
simp [List.mapIdx_set]
|
||
|
||
@[simp, grind =] theorem back?_mapIdx {xs : Array α} {f : Nat → α → β} :
|
||
(mapIdx f xs).back? = (xs.back?).map (f (xs.size - 1)) := by
|
||
rcases xs with ⟨xs⟩
|
||
simp [List.getLast?_mapIdx]
|
||
|
||
@[simp, grind =] theorem back_mapIdx {xs : Array α} {f : Nat → α → β} (h) :
|
||
(xs.mapIdx f).back h = f (xs.size - 1) (xs.back (by simpa using h)) := by
|
||
rcases xs with ⟨xs⟩
|
||
simp [List.getLast_mapIdx]
|
||
|
||
@[simp, grind =] theorem mapIdx_mapIdx {xs : Array α} {f : Nat → α → β} {g : Nat → β → γ} :
|
||
(xs.mapIdx f).mapIdx g = xs.mapIdx (fun i => g i ∘ f i) := by
|
||
simp [mapIdx_eq_iff]
|
||
|
||
theorem mapIdx_eq_replicate_iff {xs : Array α} {f : Nat → α → β} {b : β} :
|
||
mapIdx f xs = replicate xs.size b ↔ ∀ (i : Nat) (h : i < xs.size), f i xs[i] = b := by
|
||
rcases xs with ⟨xs⟩
|
||
rw [← toList_inj]
|
||
simp [List.mapIdx_eq_replicate_iff]
|
||
|
||
@[simp, grind =] theorem mapIdx_reverse {xs : Array α} {f : Nat → α → β} :
|
||
xs.reverse.mapIdx f = (mapIdx (fun i => f (xs.size - 1 - i)) xs).reverse := by
|
||
rcases xs with ⟨xs⟩
|
||
simp [List.mapIdx_reverse]
|
||
|
||
end Array
|
||
|
||
namespace List
|
||
|
||
@[grind =] theorem mapFinIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
|
||
{f : (i : Nat) → α → (h : i < l.length) → m β} :
|
||
l.toArray.mapFinIdxM f = toArray <$> l.mapFinIdxM f := by
|
||
let rec go (i : Nat) (acc : Array β) (inv : i + acc.size = l.length) :
|
||
Array.mapFinIdxM.map l.toArray f i acc.size inv acc
|
||
= toArray <$> mapFinIdxM.go l f (l.drop acc.size) acc
|
||
(by simp [Nat.sub_add_cancel (Nat.le.intro (Nat.add_comm _ _ ▸ inv))]) := by
|
||
match i with
|
||
| 0 =>
|
||
rw [Nat.zero_add] at inv
|
||
simp only [Array.mapFinIdxM.map, inv, drop_length, mapFinIdxM.go, map_pure]
|
||
| k + 1 =>
|
||
conv => enter [2, 2, 3]; rw [← getElem_cons_drop (by omega)]
|
||
simp only [Array.mapFinIdxM.map, mapFinIdxM.go, _root_.map_bind]
|
||
congr; funext x
|
||
conv => enter [1, 4]; rw [← Array.size_push x]
|
||
conv => enter [2, 2, 3]; rw [← Array.size_push x]
|
||
refine go k (acc.push x) _
|
||
simp only [Array.mapFinIdxM, mapFinIdxM]
|
||
exact go _ #[] _
|
||
|
||
@[grind =] theorem mapIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
|
||
{f : Nat → α → m β} :
|
||
l.toArray.mapIdxM f = toArray <$> l.mapIdxM f := by
|
||
let rec go (bs : List α) (acc : Array β) (inv : bs.length + acc.size = l.length) :
|
||
mapFinIdxM.go l (fun i a h => f i a) bs acc inv = mapIdxM.go f bs acc := by
|
||
match bs with
|
||
| [] => simp only [mapFinIdxM.go, mapIdxM.go]
|
||
| x :: xs => simp only [mapFinIdxM.go, mapIdxM.go, go]
|
||
unfold Array.mapIdxM
|
||
rw [mapFinIdxM_toArray]
|
||
simp only [mapFinIdxM, mapIdxM, Array.size]
|
||
rw [go]
|
||
|
||
end List
|
||
|
||
namespace Array
|
||
|
||
theorem toList_mapFinIdxM [Monad m] [LawfulMonad m] {xs : Array α}
|
||
{f : (i : Nat) → α → (h : i < xs.size) → m β} :
|
||
toList <$> xs.mapFinIdxM f = xs.toList.mapFinIdxM f := by
|
||
rw [List.mapFinIdxM_toArray]
|
||
simp only [Functor.map_map, id_map']
|
||
|
||
theorem toList_mapIdxM [Monad m] [LawfulMonad m] {xs : Array α}
|
||
{f : Nat → α → m β} :
|
||
toList <$> xs.mapIdxM f = xs.toList.mapIdxM f := by
|
||
rw [List.mapIdxM_toArray]
|
||
simp only [Functor.map_map, id_map']
|
||
|
||
end Array
|