lean4-htt/src/Init/Data/Array/MapIdx.lean
2025-10-26 10:01:30 +00:00

497 lines
20 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) 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