doc-next-gen

Init.Data.Array.Lemmas

Module docstring

{"## Theorems about Array. ","## Preliminaries ","### toList ","### empty ","### size ","## L[i] and L[i]? ","### pop ","### push ","### replicate ","### mem ","### isEmpty ","### Decidability of bounded quantifiers ","### any / all ","### set ","### setIfInBounds ","### BEq ","### isEqv ","### back ","### map ","### filter ","### filterMap ","### singleton ","### append ","### flatten ","### flatMap ","### replicate ","### Preliminaries about swap needed for reverse. ","### reverse ","### extract ","### shrink ","### foldlM and foldrM ","### foldl / foldr ","#### Further results about back and back? ","## Additional operations ","### leftpad ","### contains ","### more lemmas about pop ","### modify ","### swap ","### swapAt ","### replace ","## Logic ","### any / all ","### toListRev ","### appendList ","### Preliminaries about ofFn ","### Preliminaries about range and range' ","Content below this point has not yet been aligned with List. ","### sum ","# uset ","# get ","# mem ","# get lemmas ","### forIn ","### contains ","### isPrefixOf ","### zipWith ","### findSomeM?, findM?, findSome?, find? ","### More theorems about List.toArray, followed by an Array operation.

Our goal is to have simp \"pull List.toArray outwards\" as much as possible. ","### findSomeRevM?, findRevM?, findSomeRev?, findRev? ","### unzip ","### Deprecations ","### map ","### set "}

Array.toList_inj theorem
{xs ys : Array α} : xs.toList = ys.toList ↔ xs = ys
Full source
@[simp] theorem toList_inj {xs ys : Array α} : xs.toList = ys.toList ↔ xs = ys := by
  cases xs; cases ys; simp
Injectivity of Array-to-List Conversion: $\text{toList}(xs) = \text{toList}(ys) \leftrightarrow xs = ys$
Informal description
For any two arrays `xs` and `ys` of type `Array α`, the lists obtained by converting `xs` and `ys` to lists are equal if and only if the arrays themselves are equal. In other words, the conversion function `toList` is injective.
Array.toList_eq_nil_iff theorem
{xs : Array α} : xs.toList = [] ↔ xs = #[]
Full source
@[simp] theorem toList_eq_nil_iff {xs : Array α} : xs.toList = [] ↔ xs = #[] := by
  cases xs <;> simp
Empty List Equivalence for Array-to-List Conversion
Informal description
For any array `xs` of type `Array α`, the list obtained by converting `xs` to a list is empty if and only if `xs` is equal to the empty array `#[]`.
Array.mem_toList_iff theorem
{a : α} {xs : Array α} : a ∈ xs.toList ↔ a ∈ xs
Full source
@[simp] theorem mem_toList_iff {a : α} {xs : Array α} : a ∈ xs.toLista ∈ xs.toList ↔ a ∈ xs := by
  cases xs <;> simp
Membership Preservation in Array-to-List Conversion
Informal description
For any element $a$ of type $\alpha$ and any array `xs` of type `Array \alpha`, the element $a$ is in the list obtained by converting `xs` to a list if and only if $a$ is in the array `xs$.
Array.length_toList theorem
{xs : Array α} : xs.toList.length = xs.size
Full source
@[simp] theorem length_toList {xs : Array α} : xs.toList.length = xs.size := rfl
Length Preservation in Array-to-List Conversion
Informal description
For any array `xs` of type `Array α`, the length of the list obtained by converting `xs` to a list is equal to the size of `xs`. That is, $|\text{xs.toList}| = \text{xs.size}$.
Array.toArray_eq theorem
: List.toArray as = xs ↔ as = xs.toList
Full source
theorem toArray_eq : List.toArrayList.toArray as = xs ↔ as = xs.toList := by
  cases xs
  simp
Equivalence between List-to-Array Conversion and Array-to-List Conversion
Informal description
For any list `as` and array `xs` of elements of type `α`, the conversion of `as` to an array equals `xs` if and only if `as` equals the conversion of `xs` to a list. In other words, $\text{List.toArray}(as) = xs \leftrightarrow as = \text{xs.toList}$.
Array.empty_eq theorem
{xs : Array α} : #[] = xs ↔ xs = #[]
Full source
@[simp] theorem empty_eq {xs : Array α} : #[]#[] = xs ↔ xs = #[] := by
  cases xs <;> simp
Empty Array Equality: `#[] = xs ↔ xs = #[]`
Informal description
For any array `xs` of type `Array α`, the empty array `#[]` is equal to `xs` if and only if `xs` is equal to the empty array `#[]`.
Array.size_empty theorem
: (#[] : Array α).size = 0
Full source
theorem size_empty : (#[] : Array α).size = 0 := rfl
Size of Empty Array is Zero
Informal description
The size of an empty array of type $\alpha$ is zero, i.e., $\text{size}(\#[]) = 0$.
Array.emptyWithCapacity_eq theorem
{α n} : @emptyWithCapacity α n = #[]
Full source
@[simp] theorem emptyWithCapacity_eq {α n} : @emptyWithCapacity α n = #[] := rfl
Empty Array Construction Equivalence
Informal description
For any type $\alpha$ and natural number $n$, the empty array created with initial capacity $n$ is equal to the empty array literal `#[]`.
Array.mkEmpty_eq theorem
{α n} : @mkEmpty α n = #[]
Full source
@[deprecated emptyWithCapacity_eq (since := "2025-03-12")]
theorem mkEmpty_eq {α n} : @mkEmpty α n = #[] := rfl
Empty Array Construction Equivalence
Informal description
For any type $\alpha$ and natural number $n$, the empty array created with initial capacity $n$ is equal to the empty array literal `#[]`.
Array.ne_empty_of_size_eq_add_one theorem
(h : xs.size = n + 1) : xs ≠ #[]
Full source
theorem ne_empty_of_size_eq_add_one (h : xs.size = n + 1) : xs ≠ #[] := by
  cases xs
  simpa using List.ne_nil_of_length_eq_add_one h
Non-emptiness of Array with Size `n + 1`
Informal description
For any array `xs` of type `Array α` and natural number `n`, if the size of `xs` equals `n + 1`, then `xs` is not the empty array `#[]`.
Array.ne_empty_of_size_pos theorem
(h : 0 < xs.size) : xs ≠ #[]
Full source
theorem ne_empty_of_size_pos (h : 0 < xs.size) : xs ≠ #[] := by
  cases xs
  simpa using List.ne_nil_of_length_pos h
Non-empty Array Characterization via Positive Size
Informal description
For any array `xs` with a positive size (i.e., `0 < xs.size`), the array is not equal to the empty array `#[]`.
Array.size_eq_zero abbrev
Full source
@[deprecated size_eq_zero_iff (since := "2025-02-24")]
abbrev size_eq_zero := @size_eq_zero_iff
Empty Array Characterization via Size Zero
Informal description
An array `xs` has size zero if and only if it is equal to the empty array `#[]`.
Array.size_pos_of_mem theorem
{a : α} {xs : Array α} (h : a ∈ xs) : 0 < xs.size
Full source
theorem size_pos_of_mem {a : α} {xs : Array α} (h : a ∈ xs) : 0 < xs.size := by
  cases xs
  simp only [mem_toArray] at h
  simpa using List.length_pos_of_mem h
Nonzero Size of Array with Element
Informal description
For any element $a$ in an array $\text{xs}$ of type $\text{Array}\,\alpha$, the size of $\text{xs}$ is strictly positive, i.e., $0 < \text{xs.size}$.
Array.exists_mem_of_size_pos theorem
{xs : Array α} (h : 0 < xs.size) : ∃ a, a ∈ xs
Full source
theorem exists_mem_of_size_pos {xs : Array α} (h : 0 < xs.size) : ∃ a, a ∈ xs := by
  cases xs
  simpa using List.exists_mem_of_length_pos h
Non-empty Arrays Contain Elements
Informal description
For any non-empty array `xs` of type `Array α` (i.e., where the size `xs.size` is greater than 0), there exists an element `a` of type `α` that is a member of `xs`.
Array.size_pos_iff_exists_mem theorem
{xs : Array α} : 0 < xs.size ↔ ∃ a, a ∈ xs
Full source
theorem size_pos_iff_exists_mem {xs : Array α} : 0 < xs.size ↔ ∃ a, a ∈ xs :=
  ⟨exists_mem_of_size_pos, fun ⟨_, h⟩ => size_pos_of_mem h⟩
Non-Empty Array Characterization: $0 < \text{size} \leftrightarrow \exists$ element
Informal description
For any array `xs` of type `Array α`, the size of `xs` is strictly positive if and only if there exists an element `a` in `xs`. That is, $0 < \text{xs.size} \leftrightarrow \exists a, a \in \text{xs}$.
Array.exists_mem_of_size_eq_add_one theorem
{xs : Array α} (h : xs.size = n + 1) : ∃ a, a ∈ xs
Full source
theorem exists_mem_of_size_eq_add_one {xs : Array α} (h : xs.size = n + 1) : ∃ a, a ∈ xs := by
  cases xs
  simpa using List.exists_mem_of_length_eq_add_one h
Existence of Element in Non-Empty Array: $\text{size}(xs) = n + 1 \implies \exists a \in xs$
Informal description
For any array `xs` of type `α` with size equal to `n + 1` (where `n` is a natural number), there exists an element `a` in `xs`.
Array.size_pos_iff theorem
{xs : Array α} : 0 < xs.size ↔ xs ≠ #[]
Full source
theorem size_pos_iff {xs : Array α} : 0 < xs.size ↔ xs ≠ #[] :=
  Nat.pos_iff_ne_zero.trans (not_congr size_eq_zero_iff)
Positive Size Characterization for Non-Empty Arrays: $0 < |xs| \leftrightarrow xs \neq \#[]$
Informal description
For any array `xs` of type `Array α`, the size of `xs` is positive (i.e., `0 < xs.size`) if and only if `xs` is not the empty array `#[]`.
Array.size_pos abbrev
Full source
@[deprecated size_pos_iff (since := "2025-02-24")]
abbrev size_pos := @size_pos_iff
Positive Size Characterization for Non-Empty Arrays: $0 < |xs| \leftrightarrow xs \neq \#[]$
Informal description
For any array `xs` of type `Array α`, the size of `xs` is positive (i.e., `0 < xs.size`) if and only if `xs` is not the empty array `#[]`.
Array.size_eq_one_iff theorem
{xs : Array α} : xs.size = 1 ↔ ∃ a, xs = #[a]
Full source
theorem size_eq_one_iff {xs : Array α} : xs.size = 1 ↔ ∃ a, xs = #[a] := by
  cases xs
  simpa using List.length_eq_one_iff
Size-One Array Characterization: $|xs| = 1 \leftrightarrow \exists a, xs = #[a]$
Informal description
For any array `xs` of type `Array α`, the size of `xs` is equal to 1 if and only if there exists an element `a : α` such that `xs` is equal to the singleton array `#[a]`.
Array.size_eq_one abbrev
Full source
@[deprecated size_eq_one_iff (since := "2025-02-24")]
abbrev size_eq_one := @size_eq_one_iff
Singleton Array Characterization: $|xs| = 1 \leftrightarrow \exists a, xs = #[a]$
Informal description
For any array `xs` of type `Array α`, the size of `xs` is equal to 1 if and only if there exists an element `a : α` such that `xs` is equal to the singleton array `#[a]`.
Array.getElem?_eq_none_iff theorem
{xs : Array α} : xs[i]? = none ↔ xs.size ≤ i
Full source
@[simp] theorem getElem?_eq_none_iff {xs : Array α} : xs[i]?xs[i]? = none ↔ xs.size ≤ i := by
  by_cases h : i < xs.size
  · simp [getElem?_pos, h]
  · rw [getElem?_neg xs i h]
    simp_all
Optional Array Access Yields None if and only if Index Out of Bounds: $xs[i]? = \text{none} \leftrightarrow |xs| \leq i$
Informal description
For any array `xs` of type `Array α` and natural number index `i`, the optional access operation `xs[i]?` returns `none` if and only if the index `i` is not less than the size of `xs` (i.e., `xs.size ≤ i`).
Array.none_eq_getElem?_iff theorem
{xs : Array α} {i : Nat} : none = xs[i]? ↔ xs.size ≤ i
Full source
@[simp] theorem none_eq_getElem?_iff {xs : Array α} {i : Nat} : nonenone = xs[i]? ↔ xs.size ≤ i := by
  simp [eq_comm (a := none)]
Optional Array Access Returns None on Out-of-Bounds Index: $\text{none} = xs[i]? \leftrightarrow i \geq \text{size}(xs)$
Informal description
For any array `xs` of type `Array α` and natural number index `i`, the optional access operation `xs[i]?` returns `none` if and only if the index `i` is out of bounds (i.e., `xs.size ≤ i`). In other words, `none = xs[i]? ↔ i ≥ xs.size`.
Array.getElem?_eq_none theorem
{xs : Array α} (h : xs.size ≤ i) : xs[i]? = none
Full source
theorem getElem?_eq_none {xs : Array α} (h : xs.size ≤ i) : xs[i]? = none := by
  simp [getElem?_eq_none_iff, h]
Optional Array Access Yields None on Out-of-Bounds Index: $xs[i]? = \text{none}$ when $\text{size}(xs) \leq i$
Informal description
For any array `xs` of type `Array α` and natural number index `i`, if the size of `xs` is less than or equal to `i` (i.e., `i` is out of bounds), then the optional access operation `xs[i]?` returns `none`.
Array.getElem?_eq_getElem theorem
{xs : Array α} {i : Nat} (h : i < xs.size) : xs[i]? = some xs[i]
Full source
@[simp] theorem getElem?_eq_getElem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i]? = some xs[i] :=
  getElem?_pos ..
Optional Array Access Yields Element on Valid Index: $xs[i]? = \text{some}(xs[i])$ when $i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α` and natural number index `i`, if `i` is a valid index (i.e., `i < xs.size`), then the optional access operation `xs[i]?` returns `some xs[i]`, where `xs[i]` is the element at index `i` in `xs`.
Array.getElem?_eq_some_iff theorem
{xs : Array α} : xs[i]? = some b ↔ ∃ h : i < xs.size, xs[i] = b
Full source
theorem getElem?_eq_some_iff {xs : Array α} : xs[i]?xs[i]? = some b ↔ ∃ h : i < xs.size, xs[i] = b := by
  simp [getElem?_def]
Characterization of Optional Array Access: $xs[i]? = \text{some } b \leftrightarrow \exists h (i < \text{size}(xs) \land xs[i] = b)$
Informal description
For any array `xs` of type `Array α` and element `b` of type `α`, the optional access operation `xs[i]?` returns `some b` if and only if there exists a proof `h` that the index `i` is within bounds (i.e., `i < xs.size`) and the element at index `i` in `xs` equals `b`. In symbols: $$xs[i]? = \text{some } b \leftrightarrow \exists h : i < xs.\text{size}, xs[i] = b$$
Array.some_eq_getElem?_iff theorem
{xs : Array α} : some b = xs[i]? ↔ ∃ h : i < xs.size, xs[i] = b
Full source
theorem some_eq_getElem?_iff {xs : Array α} : somesome b = xs[i]? ↔ ∃ h : i < xs.size, xs[i] = b := by
  rw [eq_comm, getElem?_eq_some_iff]
Characterization of Optional Array Access: $\text{some } b = xs[i]? \leftrightarrow \exists h (i < \text{size}(xs) \land xs[i] = b)$
Informal description
For any array `xs` of type `Array α` and element `b` of type `α`, the equality `some b = xs[i]?` holds if and only if there exists a proof `h` that the index `i` is within bounds (i.e., `i < xs.size`) and the element at index `i` in `xs` equals `b`. In symbols: $$\text{some } b = xs[i]? \leftrightarrow \exists h : i < \text{size}(xs), xs[i] = b$$
Array.some_getElem_eq_getElem?_iff theorem
(xs : Array α) (i : Nat) (h : i < xs.size) : (some xs[i] = xs[i]?) ↔ True
Full source
@[simp] theorem some_getElem_eq_getElem?_iff (xs : Array α) (i : Nat) (h : i < xs.size) :
    (some xs[i] = xs[i]?) ↔ True := by
  simp [h]
Equivalence of Some Array Access and Optional Array Access for Valid Indices
Informal description
For any array `xs` of type `Array α`, natural number index `i`, and proof `h` that `i < xs.size`, the equality `some xs[i] = xs[i]?` holds if and only if the true proposition holds.
Array.getElem?_eq_some_getElem_iff theorem
(xs : Array α) (i : Nat) (h : i < xs.size) : (xs[i]? = some xs[i]) ↔ True
Full source
@[simp] theorem getElem?_eq_some_getElem_iff (xs : Array α) (i : Nat) (h : i < xs.size) :
    (xs[i]? = some xs[i]) ↔ True := by
  simp [h]
Optional Array Access Yields Element on Valid Index: $xs[i]? = \text{some}(xs[i])$ when $i < \text{size}(xs)$
Informal description
For an array `xs` of type `Array α`, a natural number index `i`, and a proof that `i < xs.size`, the optional access `xs[i]?` equals `some xs[i]` if and only if the proposition `True` holds.
Array.getElem_eq_iff theorem
{xs : Array α} {i : Nat} {h : i < xs.size} : xs[i] = x ↔ xs[i]? = some x
Full source
theorem getElem_eq_iff {xs : Array α} {i : Nat} {h : i < xs.size} : xs[i]xs[i] = x ↔ xs[i]? = some x := by
  simp only [getElem?_eq_some_iff]
  exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩
Equivalence of Array Access and Optional Array Access
Informal description
For an array `xs` of type `Array α`, a natural number index `i`, and a proof `h` that `i` is within the bounds of `xs` (i.e., `i < xs.size`), the element `xs[i]` is equal to `x` if and only if the optional element `xs[i]?` is equal to `some x`.
Array.getElem_eq_getElem?_get theorem
{xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] = xs[i]?.get (by simp [getElem?_eq_getElem, h])
Full source
theorem getElem_eq_getElem?_get {xs : Array α} {i : Nat} (h : i < xs.size) :
    xs[i] = xs[i]?.get (by simp [getElem?_eq_getElem, h]) := by
  simp [getElem_eq_iff]
Equality of Array Access and Optional Access Get: $xs[i] = xs[i]?.get$ for valid indices
Informal description
For any array `xs` of type `Array α` and natural number index `i` such that `i < xs.size`, the element `xs[i]` is equal to the value obtained from the optional access `xs[i]?.get` (where the proof of validity is derived from `h`).
Array.getD_getElem? theorem
{xs : Array α} {i : Nat} {d : α} : xs[i]?.getD d = if p : i < xs.size then xs[i]'p else d
Full source
theorem getD_getElem? {xs : Array α} {i : Nat} {d : α} :
    xs[i]?.getD d = if p : i < xs.size then xs[i]'p else d := by
  if h : i < xs.size then
    simp [h, getElem?_def]
  else
    have p : i ≥ xs.size := Nat.le_of_not_gt h
    simp [getElem?_eq_none p, h]
Default Value for Optional Array Access: $xs[i]?.getD\ d = \begin{cases} xs[i] & \text{if } i < \text{size}(xs) \\ d & \text{otherwise} \end{cases}$
Informal description
For any array `xs` of type `Array α`, natural number index `i`, and default value `d` of type `α`, the expression `xs[i]?.getD d` is equal to `xs[i]` if `i` is a valid index (i.e., `i < xs.size`), and `d` otherwise.
Array.getElem?_empty theorem
{i : Nat} : (#[] : Array α)[i]? = none
Full source
@[simp] theorem getElem?_empty {i : Nat} : (#[] : Array α)[i]? = none := rfl
Optional Indexing of Empty Array Yields None
Informal description
For any natural number index $i$, accessing the $i$-th element of an empty array (denoted as `#[]`) using optional indexing returns `none`.
Array.getElem_push_lt theorem
{xs : Array α} {x : α} {i : Nat} (h : i < xs.size) : have : i < (xs.push x).size := by simp [*, Nat.lt_succ_of_le, Nat.le_of_lt] (xs.push x)[i] = xs[i]
Full source
theorem getElem_push_lt {xs : Array α} {x : α} {i : Nat} (h : i < xs.size) :
    have : i < (xs.push x).size := by simp [*, Nat.lt_succ_of_le, Nat.le_of_lt]
    (xs.push x)[i] = xs[i] := by
  simp only [push, ← getElem_toList, List.concat_eq_append, List.getElem_append_left, h]
Preservation of Array Elements Under Push Operation for Valid Indices
Informal description
For any array `xs` of type `Array α`, element `x` of type `α`, and natural number index `i` such that `i < xs.size`, the element at index `i` in the array `xs.push x` (obtained by appending `x` to `xs`) is equal to the element at index `i` in the original array `xs`. In other words, if $i$ is a valid index for `xs`, then $(xs \text{++} [x])[i] = xs[i]$.
Array.getElem_push_eq theorem
{xs : Array α} {x : α} : (xs.push x)[xs.size] = x
Full source
@[simp] theorem getElem_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size] = x := by
  simp only [push, ← getElem_toList, List.concat_eq_append]
  rw [List.getElem_append_right] <;> simp [← getElem_toList, Nat.zero_lt_one]
Element at End of Pushed Array Equals Pushed Element
Informal description
For any array `xs` of type `Array α` and any element `x` of type `α`, the element at index `xs.size` in the array `xs.push x` is equal to `x`.
Array.getElem_push theorem
{xs : Array α} {x : α} {i : Nat} (h : i < (xs.push x).size) : (xs.push x)[i] = if h : i < xs.size then xs[i] else x
Full source
theorem getElem_push {xs : Array α} {x : α} {i : Nat} (h : i < (xs.push x).size) :
    (xs.push x)[i] = if h : i < xs.size then xs[i] else x := by
  by_cases h' : i < xs.size
  · simp [getElem_push_lt, h']
  · simp at h
    simp [getElem_push_lt, Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.ge_of_not_lt h')]
Element Access in Pushed Array: $(xs.push\ x)[i] = \text{if } i < xs.size \text{ then } xs[i] \text{ else } x$
Informal description
For any array `xs` of type `Array α`, element `x` of type `α`, and natural number index `i` such that `i < (xs.push x).size`, the element at index `i` in the array `xs.push x` is equal to `xs[i]` if `i < xs.size`, and equal to `x` otherwise. In other words, if $i$ is a valid index for the pushed array $xs.push\ x$, then: $$(xs.push\ x)[i] = \begin{cases} xs[i] & \text{if } i < xs.size \\ x & \text{otherwise} \end{cases}$$
Array.getElem?_push theorem
{xs : Array α} {x} : (xs.push x)[i]? = if i = xs.size then some x else xs[i]?
Full source
theorem getElem?_push {xs : Array α} {x} : (xs.push x)[i]? = if i = xs.size then some x else xs[i]? := by
  simp [getElem?_def, getElem_push]
  (repeat' split) <;> first | rfl | omega
Optional Access in Pushed Array: $(xs.push\ x)[i]? = \text{if } i = xs.size \text{ then some } x \text{ else } xs[i]?$
Informal description
For any array `xs` of type `Array α` and element `x` of type `α`, the optional access operation `(xs.push x)[i]?` returns `some x` if `i` equals the size of `xs`, and otherwise returns `xs[i]?`. In other words: $$(xs.push\ x)[i]? = \begin{cases} \text{some } x & \text{if } i = xs.size \\ xs[i]? & \text{otherwise} \end{cases}$$
Array.getElem?_push_size theorem
{xs : Array α} {x} : (xs.push x)[xs.size]? = some x
Full source
@[simp] theorem getElem?_push_size {xs : Array α} {x} : (xs.push x)[xs.size]? = some x := by
  simp [getElem?_push]
Optional Access at End of Pushed Array Yields Pushed Element: `(xs.push x)[xs.size]? = some x`
Informal description
For any array `xs` of type `Array α` and any element `x` of type `α`, the optional access operation `(xs.push x)[xs.size]?` returns `some x`. That is, the element at index `xs.size` in the array obtained by pushing `x` to `xs` is `x` (wrapped in `some`).
Array.getElem_singleton theorem
{a : α} {i : Nat} (h : i < 1) : #[a][i] = a
Full source
@[simp] theorem getElem_singleton {a : α} {i : Nat} (h : i < 1) : #[a]#[a][i] = a :=
  match i, h with
  | 0, _ => rfl
Singleton Array Access: $[a][i] = a$ for $i < 1$
Informal description
For any element $a$ of type $\alpha$ and natural number index $i$ such that $i < 1$, the $i$-th element of the singleton array $[a]$ is equal to $a$.
Array.getElem?_singleton theorem
{a : α} {i : Nat} : #[a][i]? = if i = 0 then some a else none
Full source
theorem getElem?_singleton {a : α} {i : Nat} : #[a]#[a][i]? = if i = 0 then some a else none := by
  simp [List.getElem?_singleton]
Optional Indexing of Singleton Array: `#[a][i]? = if i = 0 then some a else none`
Informal description
For any element $a$ of type $\alpha$ and any natural number index $i$, the optional lookup operation on the singleton array `#[a]` returns `some a` if $i = 0$, and `none` otherwise. That is, `#[a][i]? = if i = 0 then some a else none`.
Array.ext_getElem? theorem
{xs ys : Array α} (h : ∀ i : Nat, xs[i]? = ys[i]?) : xs = ys
Full source
theorem ext_getElem? {xs ys : Array α} (h : ∀ i : Nat, xs[i]? = ys[i]?) : xs = ys := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simpa using List.ext_getElem? (by simpa using h)
Array Equality via Element-wise Optional Lookup
Informal description
For any two arrays `xs` and `ys` of type `Array α`, if for every natural number index `i` the optional lookup operations `xs[i]?` and `ys[i]?` return the same value, then `xs` and `ys` are equal. That is, if $\forall i \in \mathbb{N}, \text{xs}[i]? = \text{ys}[i]?$, then $\text{xs} = \text{ys}$.
Array.pop_empty theorem
: (#[] : Array α).pop = #[]
Full source
@[simp] theorem pop_empty : (#[] : Array α).pop = #[] := rfl
Empty Array Pop Yields Empty Array
Informal description
For any type $\alpha$, the `pop` operation applied to an empty array (denoted as `#[]`) results in another empty array, i.e., `#[]`.pop = `#[]`.
Array.pop_push theorem
{xs : Array α} {x : α} : (xs.push x).pop = xs
Full source
@[simp] theorem pop_push {xs : Array α} {x : α} : (xs.push x).pop = xs := by simp [pop]
Popping After Pushing Yields Original Array
Informal description
For any array `xs` of type `Array α` and any element `x` of type `α`, popping the last element from the array obtained by pushing `x` onto `xs` yields the original array `xs`. That is, `(xs.push x).pop = xs`.
Array.getElem_pop theorem
{xs : Array α} {i : Nat} (h : i < xs.pop.size) : xs.pop[i] = xs[i]'(by simp at h; omega)
Full source
@[simp] theorem getElem_pop {xs : Array α} {i : Nat} (h : i < xs.pop.size) :
    xs.pop[i] = xs[i]'(by simp at h; omega) := by
  rcases xs with ⟨xs⟩
  simp [List.getElem_dropLast]
Element Preservation Under Array Pop: $\text{pop}(xs)[i] = xs[i]$ for $i < \text{size}(\text{pop}(xs))$
Informal description
For any array `xs` of type `Array α` and any natural number index `i` such that `i < xs.pop.size`, the element at index `i` in the popped array `xs.pop` is equal to the element at index `i` in the original array `xs`. In mathematical notation: For any array $xs$ and index $i$ with $i < \text{size}(\text{pop}(xs))$, we have $\text{pop}(xs)[i] = xs[i]$.
Array.getElem?_pop theorem
{xs : Array α} {i : Nat} : xs.pop[i]? = if i < xs.size - 1 then xs[i]? else none
Full source
theorem getElem?_pop {xs : Array α} {i : Nat} :
    xs.pop[i]? = if i < xs.size - 1 then xs[i]? else none := by
  rcases xs with ⟨xs⟩
  simp [List.getElem?_dropLast]
Optional Element Access After Array Pop: $\text{pop}(xs)[i]? = \text{if } i < |xs| - 1 \text{ then } xs[i]? \text{ else none}$
Informal description
For any array `xs` of type `Array α` and any natural number index `i`, the optional element access operation on the popped array `xs.pop[i]?` is equal to `xs[i]?` if `i` is less than the size of `xs` minus one, and `none` otherwise. In mathematical notation: $\text{pop}(xs)[i]? = \begin{cases} xs[i]? & \text{if } i < \text{size}(xs) - 1 \\ \text{none} & \text{otherwise} \end{cases}$
Array.back_pop theorem
{xs : Array α} (h) : xs.pop.back h = xs[xs.size - 2]'(by simp at h; omega)
Full source
theorem back_pop {xs : Array α} (h) :
   xs.pop.back h =
     xs[xs.size - 2]'(by simp at h; omega) := by
  rcases xs with ⟨xs⟩
  simp [List.getLast_dropLast]
Last Element of Popped Array Equals Second-to-Last Element of Original Array
Informal description
For any non-empty array `xs` of type `Array α`, the last element of the array obtained by removing the last element of `xs` (i.e., `xs.pop.back`) is equal to the element at index `xs.size - 2` in the original array `xs`.
Array.back?_pop theorem
{xs : Array α} : xs.pop.back? = if xs.size ≤ 1 then none else xs[xs.size - 2]?
Full source
theorem back?_pop {xs : Array α} :
    xs.pop.back? = if xs.size ≤ 1 then none else xs[xs.size - 2]? := by
  rcases xs with ⟨xs⟩
  simp [List.getLast?_dropLast]
Optional Last Element of Popped Array: $\text{back?}(\text{pop}(xs)) = \text{if } |xs| \leq 1 \text{ then none else } xs[|xs|-2]?$
Informal description
For any array `xs` of type `Array α`, the optional last element of `xs.pop` (the array with its last element removed) is equal to: - `none` if the size of `xs` is less than or equal to 1 - the optional element at index `xs.size - 2` otherwise In mathematical notation: $\text{back?}(\text{pop}(xs)) = \begin{cases} \text{none} & \text{if } \text{size}(xs) \leq 1 \\ xs[\text{size}(xs) - 2]? & \text{otherwise} \end{cases}$
Array.pop_append_of_ne_empty theorem
{xs : Array α} {ys : Array α} (h : ys ≠ #[]) : (xs ++ ys).pop = xs ++ ys.pop
Full source
@[simp] theorem pop_append_of_ne_empty {xs : Array α} {ys : Array α} (h : ys ≠ #[]) :
    (xs ++ ys).pop = xs ++ ys.pop := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp only [List.append_toArray, List.pop_toArray, mk.injEq]
  rw [List.dropLast_append_of_ne_nil (by simpa using h)]
Popping from Concatenated Arrays: $(xs ++ ys).pop = xs ++ ys.pop$ when $ys \neq \#[]$
Informal description
For any two arrays `xs` and `ys` of type `Array α`, if `ys` is not the empty array `#[]`, then the result of popping the last element from the concatenated array `xs ++ ys` is equal to the concatenation of `xs` with the result of popping the last element from `ys`. In mathematical notation: If `ys ≠ #[]`, then `(xs ++ ys).pop = xs ++ ys.pop`.
Array.push_ne_empty theorem
{a : α} {xs : Array α} : xs.push a ≠ #[]
Full source
@[simp] theorem push_ne_empty {a : α} {xs : Array α} : xs.push a ≠ #[] := by
  cases xs
  simp
Non-emptiness of Array Push: $xs.\text{push}(a) \neq \#[]$
Informal description
For any element $a$ of type $\alpha$ and any array $xs$ of type $\text{Array } \alpha$, the array obtained by pushing $a$ onto $xs$ is not equal to the empty array.
Array.push_ne_self theorem
{a : α} {xs : Array α} : xs.push a ≠ xs
Full source
@[simp] theorem push_ne_self {a : α} {xs : Array α} : xs.push a ≠ xs := by
  cases xs
  simp
Appending an Element Changes the Array ($\text{xs.push a} \neq \text{xs}$)
Informal description
For any array `xs` of type `Array α` and any element `a` of type `α`, the array obtained by appending `a` to `xs` is not equal to `xs` itself, i.e., `xs.push a ≠ xs`.
Array.ne_push_self theorem
{a : α} {xs : Array α} : xs ≠ xs.push a
Full source
@[simp] theorem ne_push_self {a : α} {xs : Array α} : xs ≠ xs.push a := by
  rw [ne_eq, eq_comm]
  simp
Array Inequality After Push: $xs \neq xs.push\ a$
Informal description
For any array `xs` of type `Array α` and any element `a` of type `α`, the array `xs` is not equal to the array obtained by pushing `a` onto `xs`, i.e., `xs ≠ xs.push a`.
Array.back_eq_of_push_eq theorem
{a b : α} {xs ys : Array α} (h : xs.push a = ys.push b) : a = b
Full source
theorem back_eq_of_push_eq {a b : α} {xs ys : Array α} (h : xs.push a = ys.push b) : a = b := by
  cases xs
  cases ys
  simp only [List.push_toArray, mk.injEq] at h
  replace h := List.append_inj_right' h (by simp)
  simpa using h
Equality of Pushed Elements in Arrays: $xs.push\ a = ys.push\ b \implies a = b$
Informal description
For any elements $a, b$ of type $\alpha$ and arrays $xs, ys$ of type $\text{Array } \alpha$, if the arrays obtained by pushing $a$ to $xs$ and $b$ to $ys$ are equal (i.e., $xs.push\ a = ys.push\ b$), then $a = b$.
Array.pop_eq_of_push_eq theorem
{a b : α} {xs ys : Array α} (h : xs.push a = ys.push b) : xs = ys
Full source
theorem pop_eq_of_push_eq {a b : α} {xs ys : Array α} (h : xs.push a = ys.push b) : xs = ys := by
  cases xs
  cases ys
  simp at h
  replace h := List.append_inj_left' h (by simp)
  simp [h]
Equality of Arrays After Push Implies Equality Before Push
Informal description
For any elements $a, b$ of type $\alpha$ and arrays $xs, ys$ of type $\text{Array } \alpha$, if pushing $a$ onto $xs$ results in the same array as pushing $b$ onto $ys$, then $xs$ and $ys$ must be equal.
Array.push_inj_left theorem
{a : α} {xs ys : Array α} : xs.push a = ys.push a ↔ xs = ys
Full source
theorem push_inj_left {a : α} {xs ys : Array α} : xs.push a = ys.push a ↔ xs = ys :=
  ⟨pop_eq_of_push_eq, fun h => by simp [h]⟩
Injectivity of Array Push Operation on the Left: $xs.\text{push}(a) = ys.\text{push}(a) \leftrightarrow xs = ys$
Informal description
For any element $a$ of type $\alpha$ and arrays $xs, ys$ of type $\text{Array } \alpha$, the arrays obtained by pushing $a$ to $xs$ and $ys$ are equal if and only if $xs$ and $ys$ are equal. In other words, $xs.\text{push}(a) = ys.\text{push}(a) \leftrightarrow xs = ys$.
Array.push_inj_right theorem
{a b : α} {xs : Array α} : xs.push a = xs.push b ↔ a = b
Full source
theorem push_inj_right {a b : α} {xs : Array α} : xs.push a = xs.push b ↔ a = b :=
  ⟨back_eq_of_push_eq, fun h => by simp [h]⟩
Injectivity of Push Operation on Arrays: $xs.push\ a = xs.push\ b \leftrightarrow a = b$
Informal description
For any elements $a, b$ of type $\alpha$ and any array $xs$ of type $\text{Array } \alpha$, the arrays obtained by pushing $a$ and $b$ to $xs$ are equal if and only if $a = b$. That is, $xs.push\ a = xs.push\ b \leftrightarrow a = b$.
Array.push_eq_push theorem
{a b : α} {xs ys : Array α} : xs.push a = ys.push b ↔ a = b ∧ xs = ys
Full source
theorem push_eq_push {a b : α} {xs ys : Array α} : 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
Equality of Pushed Arrays: $xs.push\ a = ys.push\ b \iff a = b \land xs = ys$
Informal description
For any elements $a, b$ of type $\alpha$ and arrays $xs, ys$ of type $\text{Array } \alpha$, the equality $xs.push\ a = ys.push\ b$ holds if and only if both $a = b$ and $xs = ys$ hold.
Array.push_eq_append_singleton theorem
{as : Array α} {x : α} : as.push x = as ++ #[x]
Full source
theorem push_eq_append_singleton {as : Array α} {x : α} : as.push x = as ++ #[x] := rfl
Push Equals Append Singleton
Informal description
For any array `as` of type `Array α` and any element `x` of type `α`, appending `x` to `as` (via `push`) is equivalent to concatenating `as` with the singleton array `#[x]` (via `++`). That is, `as.push x = as ++ #[x]`.
Array.exists_push_of_ne_empty theorem
{xs : Array α} (h : xs ≠ #[]) : ∃ (ys : Array α) (a : α), xs = ys.push a
Full source
theorem exists_push_of_ne_empty {xs : Array α} (h : xs ≠ #[]) :
    ∃ (ys : Array α) (a : α), xs = ys.push a := by
  rcases xs with ⟨xs⟩
  simp only [ne_eq, mk.injEq] at h
  exact ⟨(xs.take (xs.length - 1)).toArray, xs.getLast h, by simp⟩
Decomposition of Non-Empty Array into Push Operation
Informal description
For any non-empty array `xs` of type `Array α`, there exists an array `ys` of type `Array α` and an element `a` of type `α` such that `xs` is equal to `ys` with `a` appended to it, i.e., $xs = ys.push\ a$.
Array.ne_empty_iff_exists_push theorem
{xs : Array α} : xs ≠ #[] ↔ ∃ (ys : Array α) (a : α), xs = ys.push a
Full source
theorem ne_empty_iff_exists_push {xs : Array α} :
    xs ≠ #[]xs ≠ #[] ↔ ∃ (ys : Array α) (a : α), xs = ys.push a :=
  ⟨exists_push_of_ne_empty, fun ⟨_, _, eq⟩ => eq.symm ▸ push_ne_empty⟩
Non-Empty Array Characterization via Push Operation: $xs \neq \#[] \leftrightarrow \exists ys\ a, xs = ys.\text{push}(a)$
Informal description
For any array `xs` of type `Array α`, the array is non-empty if and only if there exists an array `ys` of type `Array α` and an element `a` of type `α` such that `xs` is equal to `ys` with `a` appended to it, i.e., $xs \neq \#[] \leftrightarrow \exists (ys : \text{Array } \alpha) (a : \alpha), xs = ys.\text{push}(a)$.
Array.exists_push_of_size_pos theorem
{xs : Array α} (h : 0 < xs.size) : ∃ (ys : Array α) (a : α), xs = ys.push a
Full source
theorem exists_push_of_size_pos {xs : Array α} (h : 0 < xs.size) :
    ∃ (ys : Array α) (a : α), xs = ys.push a := by
  replace h : xs ≠ #[] := size_pos_iff.mp h
  exact exists_push_of_ne_empty h
Decomposition of Positive-Sized Array into Push Operation: $0 < |xs| \implies \exists ys\ a, xs = ys.push\ a$
Informal description
For any array `xs` of type `Array α` with positive size (i.e., `0 < xs.size`), there exists an array `ys` of type `Array α` and an element `a` of type `α` such that `xs` is equal to `ys` with `a` appended to it, i.e., $xs = ys.push\ a$.
Array.size_pos_iff_exists_push theorem
{xs : Array α} : 0 < xs.size ↔ ∃ (ys : Array α) (a : α), xs = ys.push a
Full source
theorem size_pos_iff_exists_push {xs : Array α} :
    0 < xs.size ↔ ∃ (ys : Array α) (a : α), xs = ys.push a :=
  ⟨exists_push_of_size_pos, fun ⟨_, _, eq⟩ => by simp [eq]⟩
Characterization of Positive-Sized Arrays via Push Operation
Informal description
For any array $xs$ of type $\text{Array } \alpha$, the size of $xs$ is positive if and only if there exists an array $ys$ of type $\text{Array } \alpha$ and an element $a$ of type $\alpha$ such that $xs = ys.\text{push}(a)$. In other words, $0 < |xs| \leftrightarrow \exists (ys : \text{Array } \alpha) (a : \alpha), xs = ys.\text{push}(a)$.
Array.exists_push_of_size_eq_add_one theorem
{xs : Array α} (h : xs.size = n + 1) : ∃ (ys : Array α) (a : α), xs = ys.push a
Full source
theorem exists_push_of_size_eq_add_one {xs : Array α} (h : xs.size = n + 1) :
    ∃ (ys : Array α) (a : α), xs = ys.push a :=
  exists_push_of_size_pos (by simp [h])
Decomposition of Array with Size $n+1$ into Push Operation: $|xs| = n + 1 \implies \exists ys\ a, xs = ys.push\ a$
Informal description
For any array `xs` of type `Array α` with size equal to `n + 1` (where `n` is a natural number), there exists an array `ys` of type `Array α` and an element `a` of type `α` such that `xs` is equal to `ys` with `a` appended to it, i.e., $xs = ys.push\ a$.
Array.singleton_inj theorem
: #[a] = #[b] ↔ a = b
Full source
theorem singleton_inj : #[a]#[a] = #[b] ↔ a = b := by
  simp
Equality of Singleton Arrays: `#[a] = #[b] ↔ a = b`
Informal description
For any elements $a$ and $b$ of type $\alpha$, the singleton arrays `#[a]` and `#[b]` are equal if and only if $a = b$.
Array.size_replicate theorem
{n : Nat} {v : α} : (replicate n v).size = n
Full source
@[simp] theorem size_replicate {n : Nat} {v : α} : (replicate n v).size = n :=
  List.length_replicate ..
Size of Replicated Array Equals Replication Count
Informal description
For any natural number $n$ and any element $v$ of type $\alpha$, the size of the array created by replicating $v$ exactly $n$ times is equal to $n$. That is, $(\text{replicate}\ n\ v).\text{size} = n$.
Array.size_mkArray abbrev
Full source
@[deprecated size_replicate (since := "2025-03-18")]
abbrev size_mkArray := @size_replicate
Size of `mkArray` Equals Replication Count
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the size of the array created by `mkArray n a` is equal to $n$, i.e., $(\text{mkArray}\ n\ a).\text{size} = n$.
Array.toList_replicate theorem
: (replicate n a).toList = List.replicate n a
Full source
@[simp] theorem toList_replicate : (replicate n a).toList = List.replicate n a := by
  simp only [replicate]
Array-to-List Conversion Preserves Replication
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the list obtained by converting the array `replicate n a` to a list is equal to the list obtained by replicating $a$ exactly $n$ times using the list replication function. That is, $(\text{replicate}\ n\ a).\text{toList} = \text{List.replicate}\ n\ a$.
Array.toList_mkArray abbrev
Full source
@[deprecated toList_replicate (since := "2025-03-18")]
abbrev toList_mkArray := @toList_replicate
Array-to-List Conversion of `mkArray` Preserves Replication
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the list obtained by converting the array `mkArray n a` to a list is equal to the list obtained by replicating $a$ exactly $n$ times, i.e., $(\text{mkArray}\ n\ a).\text{toList} = \text{List.replicate}\ n\ a$.
Array.replicate_zero theorem
: replicate 0 a = #[]
Full source
@[simp] theorem replicate_zero : replicate 0 a = #[] := rfl
Empty Replication Yields Empty Array
Informal description
For any element $a$ of type $\alpha$, the array created by replicating $a$ zero times is equal to the empty array `#[]`.
Array.mkArray_zero abbrev
Full source
@[deprecated replicate_zero (since := "2025-03-18")]
abbrev mkArray_zero := @replicate_zero
Empty `mkArray` Yields Empty Array
Informal description
For any element $a$ of type $\alpha$, the array created by `mkArray 0 a` is equal to the empty array `#[]`.
Array.replicate_succ theorem
: replicate (n + 1) a = (replicate n a).push a
Full source
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
  apply toList_inj.1
  simp [List.replicate_succ']
Recursive Definition of Array Replication: $\text{replicate}(n+1, a) = \text{replicate}(n, a).\text{push}(a)$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the array created by replicating $a$ exactly $n+1$ times is equal to the array obtained by appending $a$ to the array created by replicating $a$ exactly $n$ times. That is, $\text{replicate}(n+1, a) = \text{replicate}(n, a).\text{push}(a)$.
Array.mkArray_succ abbrev
Full source
@[deprecated replicate_succ (since := "2025-03-18")]
abbrev mkArray_succ := @replicate_succ
Recursive Definition of `mkArray`: $\text{mkArray}(n+1, a) = \text{mkArray}(n, a).\text{push}(a)$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the array created by `mkArray (n + 1) a` is equal to the array obtained by appending $a$ to the array created by `mkArray n a`. That is, $\text{mkArray}(n+1, a) = \text{mkArray}(n, a).\text{push}(a)$.
Array.getElem_replicate theorem
{n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) : (replicate n v)[i] = v
Full source
@[simp] theorem getElem_replicate {n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) :
    (replicate n v)[i] = v := by simp [← getElem_toList]
Element Access in Replicated Array: $(\text{replicate}(n, v))[i] = v$ for $i < n$
Informal description
For any natural number $n$, element $v$ of type $\alpha$, and index $i$ such that $i < n$, the $i$-th element of the array $\text{replicate}(n, v)$ is equal to $v$. That is, $(\text{replicate}(n, v))[i] = v$ when $i < n$.
Array.getElem_mkArray abbrev
Full source
@[deprecated getElem_replicate (since := "2025-03-18")]
abbrev getElem_mkArray := @getElem_replicate
Element Access in Constructed Array: $(\text{mkArray}(n, v))[i] = v$ for $i < n$
Informal description
For any natural number $n$, element $v$ of type $\alpha$, and index $i$ such that $i < n$, the $i$-th element of the array created by `mkArray n v` is equal to $v$. That is, $(\text{mkArray}(n, v))[i] = v$ when $i < n$.
Array.getElem?_replicate theorem
{n : Nat} {v : α} {i : Nat} : (replicate n v)[i]? = if i < n then some v else none
Full source
@[simp] theorem getElem?_replicate {n : Nat} {v : α} {i : Nat} :
    (replicate n v)[i]? = if i < n then some v else none := by
  simp [getElem?_def]
Optional Element Access in Replicated Array: $(\text{replicate}(n, v))[i]? = \text{if } i < n \text{ then some } v \text{ else none}$
Informal description
For any natural number $n$, element $v$ of type $\alpha$, and index $i$, the optional element access operation on the replicated array satisfies $(\text{replicate}(n, v))[i]? = \text{if } i < n \text{ then some } v \text{ else none}$.
Array.getElem?_mkArray abbrev
Full source
@[deprecated getElem?_replicate (since := "2025-03-18")]
abbrev getElem?_mkArray := @getElem?_replicate
Optional Element Access in Constructed Array: $(\text{mkArray}(n, v))[i]? = \text{if } i < n \text{ then some } v \text{ else none}$
Informal description
For any natural number $n$, element $v$ of type $\alpha$, and index $i$, the optional element access operation on the array constructed by `mkArray n v` satisfies $(\text{mkArray}(n, v))[i]? = \text{if } i < n \text{ then some } v \text{ else none}$.
Array.not_mem_empty theorem
(a : α) : ¬a ∈ #[]
Full source
theorem not_mem_empty (a : α) : ¬ a ∈ #[] := by simp
No Element in Empty Array
Informal description
For any element $a$ of type $\alpha$, $a$ is not an element of the empty array `#[]`.
Array.mem_push theorem
{xs : Array α} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y
Full source
@[simp] theorem mem_push {xs : Array α} {x y : α} : x ∈ xs.push yx ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
  simp only [mem_def]
  simp
Membership in Pushed Array: $x \in \text{xs.push y} \leftrightarrow x \in \text{xs} \lor x = y$
Informal description
For any array `xs` of type `Array α` and elements `x, y` of type `α`, the element `x` is in the array `xs.push y` (obtained by pushing `y` onto `xs`) if and only if either `x` is in `xs` or `x` equals `y`. In symbols: $$x \in \text{xs.push y} \leftrightarrow x \in \text{xs} \lor x = y$$
Array.mem_push_self theorem
{xs : Array α} {x : α} : x ∈ xs.push x
Full source
theorem mem_push_self {xs : Array α} {x : α} : x ∈ xs.push x :=
  mem_push.2 (Or.inr rfl)
Self-Membership in Pushed Array: $x \in \text{xs.push }x$
Informal description
For any array `xs` of type `Array α` and any element `x` of type `α`, the element `x` is contained in the array obtained by pushing `x` onto `xs`, i.e., $x \in \text{xs.push }x$.
Array.mem_push_of_mem theorem
{xs : Array α} {x : α} (y : α) (h : x ∈ xs) : x ∈ xs.push y
Full source
theorem mem_push_of_mem {xs : Array α} {x : α} (y : α) (h : x ∈ xs) : x ∈ xs.push y :=
  mem_push.2 (Or.inl h)
Preservation of Membership under Array Push Operation
Informal description
For any array `xs` of type `Array α`, any element `x` in `xs`, and any element `y` of type `α`, the element `x` remains in the array `xs.push y` obtained by pushing `y` onto `xs`. In symbols: $$x \in \text{xs} \implies x \in \text{xs.push } y$$
Array.exists_mem_of_ne_empty theorem
(xs : Array α) (h : xs ≠ #[]) : ∃ x, x ∈ xs
Full source
theorem exists_mem_of_ne_empty (xs : Array α) (h : xs ≠ #[]) : ∃ x, x ∈ xs := by
  simpa using List.exists_mem_of_ne_nil xs.toList (by simpa using h)
Non-empty Arrays Contain Elements
Informal description
For any non-empty array `xs` of type `Array α`, there exists an element `x` in `xs` such that `x ∈ xs`.
Array.mem_dite_empty_left theorem
{x : α} [Decidable p] {xs : ¬p → Array α} : (x ∈ if h : p then #[] else xs h) ↔ ∃ h : ¬p, x ∈ xs h
Full source
@[simp] theorem mem_dite_empty_left {x : α} [Decidable p] {xs : ¬ pArray α} :
    (x ∈ if h : p then #[] else xs h) ↔ ∃ h : ¬ p, x ∈ xs h := by
  split <;> simp_all
Membership in Conditional Empty Array via Negated Proposition
Informal description
For any element $x$ of type $\alpha$ and a decidable proposition $p$, given a function $xs$ that maps proofs of $\neg p$ to arrays of type $\alpha$, the following equivalence holds: $x$ is an element of the array `if h : p then #[] else xs h` if and only if there exists a proof $h$ of $\neg p$ such that $x$ is an element of $xs(h)$.
Array.mem_dite_empty_right theorem
{x : α} [Decidable p] {xs : p → Array α} : (x ∈ if h : p then xs h else #[]) ↔ ∃ h : p, x ∈ xs h
Full source
@[simp] theorem mem_dite_empty_right {x : α} [Decidable p] {xs : p → Array α} :
    (x ∈ if h : p then xs h else #[]) ↔ ∃ h : p, x ∈ xs h := by
  split <;> simp_all
Membership in Conditional Empty Array via Proposition
Informal description
For any element $x$ of type $\alpha$ and a decidable proposition $p$, given a function $xs$ that maps proofs of $p$ to arrays of type $\alpha$, the following equivalence holds: $x$ is an element of the array `if h : p then xs h else #[]` if and only if there exists a proof $h$ of $p$ such that $x$ is an element of $xs(h)$.
Array.mem_ite_empty_left theorem
{x : α} [Decidable p] {xs : Array α} : (x ∈ if p then #[] else xs) ↔ ¬p ∧ x ∈ xs
Full source
@[simp] theorem mem_ite_empty_left {x : α} [Decidable p] {xs : Array α} :
    (x ∈ if p then #[] else xs) ↔ ¬ p ∧ x ∈ xs := by
  split <;> simp_all
Membership in Conditional Empty Array: $x \in (\text{if } p \text{ then } [] \text{ else } xs) \leftrightarrow \neg p \land x \in xs$
Informal description
For any element $x$ of type $\alpha$ and a decidable proposition $p$, given an array $xs$ of type $\alpha$, the following equivalence holds: $x$ is an element of the array `if p then #[] else xs` if and only if $p$ is false and $x$ is an element of $xs$.
Array.mem_ite_empty_right theorem
{x : α} [Decidable p] {xs : Array α} : (x ∈ if p then xs else #[]) ↔ p ∧ x ∈ xs
Full source
@[simp] theorem mem_ite_empty_right {x : α} [Decidable p] {xs : Array α} :
    (x ∈ if p then xs else #[]) ↔ p ∧ x ∈ xs := by
  split <;> simp_all
Membership in Conditional Array: $x \in (\text{if } p \text{ then } xs \text{ else } \#[]) \leftrightarrow p \land x \in xs$
Informal description
For any element $x$ of type $\alpha$ and any decidable proposition $p$, the element $x$ is a member of the array `if p then xs else #[]` if and only if $p$ holds and $x$ is a member of the array $xs$. In symbols: $$ x \in \text{if } p \text{ then } xs \text{ else } \#[] \leftrightarrow p \land x \in xs. $$
Array.mem_singleton theorem
{a b : α} : a ∈ #[b] ↔ a = b
Full source
@[simp] theorem mem_singleton {a b : α} : a ∈ #[b]a ∈ #[b] ↔ a = b :=
  ⟨eq_of_mem_singleton, (by simp [·])⟩
Membership in Singleton Array: $a \in \#[b] \leftrightarrow a = b$
Informal description
For any elements $a$ and $b$ of type $\alpha$, the element $a$ is a member of the singleton array containing $b$ if and only if $a$ equals $b$. In symbols: $$ a \in \#[b] \leftrightarrow a = b. $$
Array.forall_mem_push theorem
{p : α → Prop} {xs : Array α} {a : α} : (∀ x, x ∈ xs.push a → p x) ↔ p a ∧ ∀ x, x ∈ xs → p x
Full source
theorem forall_mem_push {p : α → Prop} {xs : Array α} {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]
Universal Quantification over Pushed Array: $\forall x \in \text{xs.push}(a), p(x) \leftrightarrow p(a) \land \forall x \in \text{xs}, p(x)$
Informal description
For any predicate $p$ on elements of type $\alpha$, any array $\text{xs}$ of type $\text{Array}\ \alpha$, and any element $a$ of type $\alpha$, the following are equivalent: 1. For every element $x$ in the array obtained by pushing $a$ to $\text{xs}$, $p(x)$ holds. 2. $p(a)$ holds and for every element $x$ in $\text{xs}$, $p(x)$ holds. In symbols: $$ (\forall x \in \text{xs.push}(a), p(x)) \leftrightarrow p(a) \land (\forall x \in \text{xs}, p(x)). $$
Array.forall_mem_ne theorem
{a : α} {xs : Array α} : (∀ a' : α, a' ∈ xs → ¬a = a') ↔ a ∉ xs
Full source
theorem forall_mem_ne {a : α} {xs : Array α} : (∀ a' : α, a' ∈ xs → ¬a = a') ↔ a ∉ xs :=
  ⟨fun h m => h _ m rfl, fun h _ m e => h (e.symm ▸ m)⟩
Equivalence of Universal Inequality and Non-Membership in Arrays
Informal description
For any element $a$ of type $\alpha$ and any array $\text{xs}$ of type $\text{Array}\ \alpha$, the following are equivalent: 1. For every element $a'$ in $\text{xs}$, $a$ is not equal to $a'$. 2. The element $a$ is not contained in the array $\text{xs}$. In symbols: $$ (\forall a' \in \text{xs}, a \neq a') \leftrightarrow a \notin \text{xs}. $$
Array.forall_mem_ne' theorem
{a : α} {xs : Array α} : (∀ a' : α, a' ∈ xs → ¬a' = a) ↔ a ∉ xs
Full source
theorem forall_mem_ne' {a : α} {xs : Array α} : (∀ a' : α, a' ∈ xs → ¬a' = a) ↔ a ∉ xs :=
  ⟨fun h m => h _ m rfl, fun h _ m e => h (e.symm ▸ m)⟩
Equivalence of Non-Containment and Universal Inequality in Arrays
Informal description
For any element $a$ of type $\alpha$ and any array `xs` of type `Array α`, the following are equivalent: 1. For every element $a'$ in `xs`, $a'$ is not equal to $a$. 2. The element $a$ is not contained in the array `xs`. In symbols: $$ (\forall a' \in \text{xs}, a' \neq a) \leftrightarrow a \notin \text{xs} $$
Array.exists_mem_empty theorem
(p : α → Prop) : ¬(∃ x, ∃ _ : x ∈ #[], p x)
Full source
theorem exists_mem_empty (p : α → Prop) : ¬ (∃ x, ∃ _ : x ∈ #[], p x) := nofun
Nonexistence in Empty Array
Informal description
For any predicate $p$ on elements of type $\alpha$, there does not exist an element $x$ in the empty array $\#[]$ such that $p(x)$ holds.
Array.forall_mem_empty theorem
(p : α → Prop) : ∀ (x) (_ : x ∈ #[]), p x
Full source
theorem forall_mem_empty (p : α → Prop) : ∀ (x) (_ : x ∈ #[]), p x := nofun
Vacuous Universal Quantification Over Empty Array
Informal description
For any predicate $p$ on elements of type $\alpha$, every element $x$ in the empty array $\#[]$ satisfies $p(x)$. (This holds vacuously since the empty array contains no elements.)
Array.exists_mem_push theorem
{p : α → Prop} {a : α} {xs : Array α} : (∃ x, ∃ _ : x ∈ xs.push a, p x) ↔ p a ∨ ∃ x, ∃ _ : x ∈ xs, p x
Full source
theorem exists_mem_push {p : α → Prop} {a : α} {xs : Array α} :
    (∃ 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'⟩
Existence in Pushed Array: $(\exists x \in xs.push(a), p(x)) \leftrightarrow p(a) \lor (\exists x \in xs, p(x))$
Informal description
For any predicate $p$ on elements of type $\alpha$, any element $a$ of $\alpha$, and any array $xs$ of type $\text{Array } \alpha$, there exists an element $x$ in the array obtained by pushing $a$ to $xs$ such that $p(x)$ holds if and only if either $p(a)$ holds or there exists an element $x$ in $xs$ such that $p(x)$ holds.
Array.forall_mem_singleton theorem
{p : α → Prop} {a : α} : (∀ (x) (_ : x ∈ #[a]), p x) ↔ p a
Full source
theorem forall_mem_singleton {p : α → Prop} {a : α} : (∀ (x) (_ : x ∈ #[a]), p x) ↔ p a := by
  simp only [mem_singleton, forall_eq]
Universal Quantification Over Singleton Array is Equivalent to Predicate on Its Element
Informal description
For any predicate $p$ on elements of type $\alpha$ and any element $a$ of $\alpha$, the statement that every element $x$ in the singleton array $\#[a]$ satisfies $p(x)$ is equivalent to $p(a)$ holding.
Array.mem_empty_iff theorem
(a : α) : a ∈ (#[] : Array α) ↔ False
Full source
theorem mem_empty_iff (a : α) : a ∈ (#[] : Array α)a ∈ (#[] : Array α) ↔ False := by simp
No Element in Empty Array
Informal description
For any element $a$ of type $\alpha$, the statement that $a$ is an element of the empty array $\#[]$ is equivalent to false.
Array.mem_singleton_self theorem
(a : α) : a ∈ #[a]
Full source
theorem mem_singleton_self (a : α) : a ∈ #[a] := by simp
Element Membership in Singleton Array: $a \in \#[a]$
Informal description
For any element $a$ of type $\alpha$, the element $a$ is contained in the singleton array $\#[a]$.
Array.mem_of_mem_push_of_mem theorem
{a b : α} {xs : Array α} : a ∈ xs.push b → b ∈ xs → a ∈ xs
Full source
theorem mem_of_mem_push_of_mem {a b : α} {xs : Array α} : a ∈ xs.push bb ∈ xsa ∈ xs := by
  cases xs
  simp only [List.push_toArray, mem_toArray, List.mem_append, List.mem_singleton]
  rintro (h | rfl)
  · intro _
    exact h
  · exact id
Membership Preservation Under Push Operation: $a \in xs.push\ b \land b \in xs \implies a \in xs$
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any array $xs$ of type $\text{Array } \alpha$, if $a$ is an element of the array obtained by pushing $b$ to $xs$ (i.e., $a \in xs.push\ b$) and $b$ is an element of $xs$ (i.e., $b \in xs$), then $a$ must be an element of $xs$ (i.e., $a \in xs$).
Array.ne_empty_of_mem theorem
{a : α} {xs : Array α} (h : a ∈ xs) : xs ≠ #[]
Full source
theorem ne_empty_of_mem {a : α} {xs : Array α} (h : a ∈ xs) : xs ≠ #[] := by
  cases xs
  simp [List.ne_nil_of_mem (by simpa using h)]
Non-emptiness of Array with Membership: $a \in \text{xs} \implies \text{xs} \neq \text{#[]}$
Informal description
For any element $a$ of type $\alpha$ and any array `xs` of type `Array α`, if $a$ is a member of `xs`, then `xs` is not the empty array `#[]`.
Array.mem_of_ne_of_mem theorem
{a y : α} {xs : Array α} (h₁ : a ≠ y) (h₂ : a ∈ xs.push y) : a ∈ xs
Full source
theorem mem_of_ne_of_mem {a y : α} {xs : Array α} (h₁ : a ≠ y) (h₂ : a ∈ xs.push y) : a ∈ xs := by
  simpa [h₁] using h₂
Membership in Array After Push When Elements Are Distinct
Informal description
For any elements $a$ and $y$ of type $\alpha$ and any array `xs` of type `Array α`, if $a \neq y$ and $a$ is an element of the array obtained by pushing $y$ to `xs`, then $a$ must be an element of `xs$.
Array.ne_of_not_mem_push theorem
{a b : α} {xs : Array α} (h : a ∉ xs.push b) : a ≠ b
Full source
theorem ne_of_not_mem_push {a b : α} {xs : Array α} (h : a ∉ xs.push b) : a ≠ b := by
  simp only [mem_push, not_or] at h
  exact h.2
Inequality from Non-Membership in Pushed Array: $a \notin \text{xs.push}(b) \Rightarrow a \neq b$
Informal description
For any elements $a$ and $b$ of type $\alpha$, and any array `xs` of type `Array α`, if $a$ is not an element of the array obtained by appending $b$ to `xs`, then $a$ is not equal to $b$.
Array.not_mem_of_not_mem_push theorem
{a b : α} {xs : Array α} (h : a ∉ xs.push b) : a ∉ xs
Full source
theorem not_mem_of_not_mem_push {a b : α} {xs : Array α} (h : a ∉ xs.push b) : a ∉ xs := by
  simp only [mem_push, not_or] at h
  exact h.1
Non-membership Preservation Under Array Push
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any array `xs` of type `Array α`, if $a$ is not an element of the array obtained by appending $b$ to `xs` (i.e., $a \notin \text{xs.push } b$), then $a$ is not an element of `xs` (i.e., $a \notin \text{xs}$).
Array.not_mem_push_of_ne_of_not_mem theorem
{a y : α} {xs : Array α} : a ≠ y → a ∉ xs → a ∉ xs.push y
Full source
theorem not_mem_push_of_ne_of_not_mem {a y : α} {xs : Array α} : a ≠ ya ∉ xsa ∉ xs.push y :=
  mtmt ∘ mem_of_ne_of_mem
Non-membership in Pushed Array from Inequality and Non-membership in Original Array
Informal description
For any elements $a$ and $y$ of type $\alpha$ and any array $\text{xs}$ of type $\text{Array } \alpha$, if $a$ is not equal to $y$ and $a$ is not an element of $\text{xs}$, then $a$ is not an element of the array obtained by pushing $y$ to $\text{xs}$.
Array.ne_and_not_mem_of_not_mem_push theorem
{a y : α} {xs : Array α} : a ∉ xs.push y → a ≠ y ∧ a ∉ xs
Full source
theorem ne_and_not_mem_of_not_mem_push {a y : α} {xs : Array α} : a ∉ xs.push ya ≠ ya ≠ y ∧ a ∉ xs := by
  simp +contextual
Non-membership in Pushed Array Implies Inequality and Non-membership in Original Array
Informal description
For any elements $a$ and $y$ of type $\alpha$ and any array $\text{xs}$ of type $\text{Array } \alpha$, if $a$ is not an element of the array obtained by pushing $y$ to $\text{xs}$, then $a$ is not equal to $y$ and $a$ is not an element of $\text{xs}$.
Array.getElem_of_mem theorem
{a} {xs : Array α} (h : a ∈ xs) : ∃ (i : Nat) (h : i < xs.size), xs[i]'h = a
Full source
theorem getElem_of_mem {a} {xs : Array α} (h : a ∈ xs) : ∃ (i : Nat) (h : i < xs.size), xs[i]'h = a := by
  cases xs
  simp [List.getElem_of_mem (by simpa using h)]
Existence of Index for Array Membership
Informal description
For any element $a$ in an array $\text{xs}$ of type $\text{Array } \alpha$, there exists a natural number index $i$ such that $i$ is less than the size of $\text{xs}$ and the $i$-th element of $\text{xs}$ equals $a$.
Array.getElem?_of_mem theorem
{a} {xs : Array α} (h : a ∈ xs) : ∃ i : Nat, xs[i]? = some a
Full source
theorem getElem?_of_mem {a} {xs : Array α} (h : a ∈ xs) : ∃ i : Nat, xs[i]? = some a :=
  let ⟨n, _, e⟩ := getElem_of_mem h; ⟨n, e ▸ getElem?_eq_getElem _⟩
Existence of Valid Index for Array Membership via Optional Access
Informal description
For any element $a$ in an array $\text{xs}$ of type $\text{Array } \alpha$, there exists a natural number index $i$ such that the optional access operation $\text{xs}[i]?$ returns $\text{some } a$.
Array.mem_of_getElem theorem
{xs : Array α} {i : Nat} {h} {a : α} (e : xs[i] = a) : a ∈ xs
Full source
theorem mem_of_getElem {xs : Array α} {i : Nat} {h} {a : α} (e : xs[i] = a) : a ∈ xs := by
  subst e
  simp
Array Membership via Indexing
Informal description
For any array `xs` of type `Array α`, natural number index `i` with `i < xs.size`, and element `a : α`, if the `i`-th element of `xs` equals `a` (i.e., `xs[i] = a`), then `a` is an element of `xs`.
Array.mem_of_getElem? theorem
{xs : Array α} {i : Nat} {a : α} (e : xs[i]? = some a) : a ∈ xs
Full source
theorem mem_of_getElem? {xs : Array α} {i : Nat} {a : α} (e : xs[i]? = some a) : a ∈ xs :=
  let ⟨_, e⟩ := getElem?_eq_some_iff.1 e; e ▸ getElem_mem ..
Array Membership via Optional Indexing: $xs[i]? = \text{some } a \rightarrow a \in xs$
Informal description
For any array `xs` of type `Array α`, natural number index `i`, and element `a : α`, if the optional access operation `xs[i]?` returns `some a`, then `a` is an element of `xs`.
Array.mem_iff_getElem theorem
{a} {xs : Array α} : a ∈ xs ↔ ∃ (i : Nat) (h : i < xs.size), xs[i]'h = a
Full source
theorem mem_iff_getElem {a} {xs : Array α} : a ∈ xsa ∈ xs ↔ ∃ (i : Nat) (h : i < xs.size), xs[i]'h = a :=
  ⟨getElem_of_mem, fun ⟨_, _, e⟩ => e ▸ getElem_mem ..⟩
Array Membership Characterization via Indexing: $a \in \mathtt{xs} \leftrightarrow \exists i < \mathtt{xs.size}, \mathtt{xs}[i] = a$
Informal description
For any element $a$ and array $\mathtt{xs}$ of type $\alpha$, $a$ is an element of $\mathtt{xs}$ if and only if there exists a natural number index $i$ such that $i$ is less than the size of $\mathtt{xs}$ and the $i$-th element of $\mathtt{xs}$ equals $a$.
Array.mem_iff_getElem? theorem
{a} {xs : Array α} : a ∈ xs ↔ ∃ i : Nat, xs[i]? = some a
Full source
theorem mem_iff_getElem? {a} {xs : Array α} : a ∈ xsa ∈ xs ↔ ∃ i : Nat, xs[i]? = some a := by
  simp [getElem?_eq_some_iff, mem_iff_getElem]
Membership in Array via Optional Indexing: $a \in \mathtt{xs} \leftrightarrow \exists i, \mathtt{xs}[i]? = \mathtt{some}\ a$
Informal description
For any element $a$ and array $\mathtt{xs}$ of type $\alpha$, $a$ is an element of $\mathtt{xs}$ if and only if there exists a natural number index $i$ such that the optional indexing operation $\mathtt{xs}[i]?$ returns $\mathtt{some}\ a$.
Array.forall_getElem theorem
{xs : Array α} {p : α → Prop} : (∀ (i : Nat) h, p (xs[i]'h)) ↔ ∀ a, a ∈ xs → p a
Full source
theorem forall_getElem {xs : Array α} {p : α → Prop} :
    (∀ (i : Nat) h, p (xs[i]'h)) ↔ ∀ a, a ∈ xs → p a := by
  cases xs; simp [List.forall_getElem]
Universal Quantification over Array Elements via Indexing vs Membership
Informal description
For any array `xs` of type `Array α` and any predicate `p : α → Prop`, the following are equivalent: 1. For every index `i` of `xs` (with proof `h : i < xs.size`), the predicate `p` holds for the element `xs[i]`. 2. For every element `a` in `xs`, the predicate `p` holds for `a`. In other words, `p` holds for all elements of `xs` (when accessed by index) if and only if `p` holds for all elements of `xs` (when considered as members of the array).
Array.isEmpty_toList theorem
{xs : Array α} : xs.toList.isEmpty = xs.isEmpty
Full source
@[simp] theorem isEmpty_toList {xs : Array α} : xs.toList.isEmpty = xs.isEmpty := by
  rcases xs with ⟨_ | _⟩ <;> simp
Equivalence of Array and List Emptiness
Informal description
For any array `xs` of type `Array α`, the list obtained by converting `xs` to a list is empty if and only if the array `xs` itself is empty. In other words, `xs.toList.isEmpty = xs.isEmpty`.
Array.isEmpty_eq_false_iff_exists_mem theorem
{xs : Array α} : xs.isEmpty = false ↔ ∃ x, x ∈ xs
Full source
theorem isEmpty_eq_false_iff_exists_mem {xs : Array α} :
    xs.isEmpty = false ↔ ∃ x, x ∈ xs := by
  cases xs
  simpa using List.isEmpty_eq_false_iff_exists_mem
Non-emptiness of Array Equivalent to Existence of Member
Informal description
For any array `xs` of type `Array α`, the array is non-empty (i.e., `xs.isEmpty = false`) if and only if there exists an element `x` such that `x` is a member of `xs`.
Array.isEmpty_iff theorem
{xs : Array α} : xs.isEmpty ↔ xs = #[]
Full source
@[simp] theorem isEmpty_iff {xs : Array α} : xs.isEmpty ↔ xs = #[] := by
  cases xs <;> simp
Empty Array Characterization: `xs.isEmpty ↔ xs = #[]`
Informal description
For any array `xs` of type `Array α`, the array is empty if and only if it is equal to the empty array `#[]`.
Array.isEmpty_eq_true abbrev
Full source
@[deprecated isEmpty_iff (since := "2025-02-17")]
abbrev isEmpty_eq_true := @isEmpty_iff
Empty Array Characterization: `xs.isEmpty = true ↔ xs = #[]`
Informal description
For any array `xs` of type `Array α`, the boolean expression `xs.isEmpty = true` holds if and only if `xs` is equal to the empty array `#[]`.
Array.isEmpty_eq_false_iff theorem
{xs : Array α} : xs.isEmpty = false ↔ xs ≠ #[]
Full source
@[simp] theorem isEmpty_eq_false_iff {xs : Array α} : xs.isEmpty = false ↔ xs ≠ #[] := by
  cases xs <;> simp
Non-emptiness of Array is Equivalent to Not Being Empty Array
Informal description
For any array `xs` of type `Array α`, the boolean expression `xs.isEmpty = false` holds if and only if `xs` is not equal to the empty array `#[]`.
Array.isEmpty_eq_false abbrev
Full source
@[deprecated isEmpty_eq_false_iff (since := "2025-02-17")]
abbrev isEmpty_eq_false := @isEmpty_eq_false_iff
Non-emptiness of Array is Equivalent to Not Being Empty Array
Informal description
For any array `xs` of type `Array α`, the boolean expression `xs.isEmpty = false` holds if and only if `xs` is not equal to the empty array `#[]`.
Array.instDecidableForallForallMemOfDecidablePred instance
{xs : Array α} {p : α → Prop} [DecidablePred p] : Decidable (∀ x, x ∈ xs → p x)
Full source
instance {xs : Array α} {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⟩)
Decidability of Universal Quantification over Array Elements
Informal description
For any array `xs` of type `Array α` and decidable predicate `p` on `α`, the proposition `∀ x ∈ xs, p x` is decidable.
Array.instDecidableExistsAndMemOfDecidablePred instance
{xs : Array α} {p : α → Prop} [DecidablePred p] : Decidable (∃ x, x ∈ xs ∧ p x)
Full source
instance {xs : Array α} {p : α → Prop} [DecidablePred p] :
    Decidable (∃ x, x ∈ xs ∧ p x) :=
  decidable_of_iff (∃ (i : Nat), ∃ (h : i < xs.size), 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⟩⟩)
Decidability of Existential Quantification over Array Elements
Informal description
For any array `xs` of type `Array α` and decidable predicate `p` on `α`, the proposition that there exists an element `x` in `xs` such that `p x` holds is decidable.
Array.anyM_eq_anyM_loop theorem
[Monad m] {p : α → m Bool} {as : Array α} {start stop} : anyM p as start stop = anyM.loop p as (min stop as.size) (Nat.min_le_right ..) start
Full source
theorem anyM_eq_anyM_loop [Monad m] {p : α → m Bool} {as : Array α} {start stop} :
    anyM p as start stop = anyM.loop p as (min stop as.size) (Nat.min_le_right ..) start := by
  simp only [anyM, Nat.min_def]; split <;> rfl
Equivalence of Monadic Any Operation and Its Loop Implementation for Arrays
Informal description
For any monad $m$, predicate $p : \alpha \to m \text{Bool}$, array $as$ of type $\text{Array }\alpha$, and natural numbers $start$, $stop$, the monadic any operation $\text{anyM } p \text{ } as \text{ } start \text{ } stop$ is equal to $\text{anyM.loop } p \text{ } as \text{ } (\min(stop, as.size)) \text{ } (Nat.min\_le\_right \ldots) \text{ } start$.
Array.anyM_stop_le_start theorem
[Monad m] {p : α → m Bool} {as : Array α} {start stop} (h : min stop as.size ≤ start) : anyM p as start stop = pure false
Full source
theorem anyM_stop_le_start [Monad m] {p : α → m Bool} {as : Array α} {start stop}
    (h : min stop as.size ≤ start) : anyM p as start stop = pure false := by
  rw [anyM_eq_anyM_loop, anyM.loop, dif_neg (Nat.not_lt.2 h)]
Monadic Any Operation Yields False When Stop Index Does Not Exceed Start Index
Informal description
For any monad $m$, predicate $p : \alpha \to m \text{Bool}$, array $as$ of type $\text{Array }\alpha$, and natural numbers $start$, $stop$, if $\min(stop, \text{size}(as)) \leq start$, then the monadic any operation $\text{anyM } p \text{ } as \text{ } start \text{ } stop$ evaluates to $\text{pure false}$.
Array.anyM_loop_cons theorem
[Monad m] {p : α → m Bool} {a : α} {as : List α} {stop start : Nat} (h : stop + 1 ≤ (a :: as).length) : anyM.loop p ⟨a :: as⟩ (stop + 1) h (start + 1) = anyM.loop p ⟨as⟩ stop (by simpa using h) start
Full source
theorem anyM_loop_cons [Monad m] {p : α → m Bool} {a : α} {as : List α} {stop start : Nat}
    (h : stop + 1 ≤ (a :: as).length) :
    anyM.loop p ⟨a :: as⟩ (stop + 1) h (start + 1) =
      anyM.loop p ⟨as⟩ stop (by simpa using h) start := by
  rw [anyM.loop]
  conv => rhs; rw [anyM.loop]
  split <;> rename_i h'
  · simp only [Nat.add_lt_add_iff_right] at h'
    rw [dif_pos h', anyM_loop_cons]
    simp
  · rw [dif_neg]
    omega
Monadic Loop Equality for Cons-Constructed Arrays
Informal description
Let $m$ be a monad, $p : \alpha \to m \text{Bool}$ a predicate, $a$ an element of type $\alpha$, and $as$ a list of elements of type $\alpha$. For any natural numbers $stop$ and $start$ such that $stop + 1 \leq \text{length}(a :: as)$, the monadic loop `anyM.loop` applied to the array $\langle a :: as \rangle$ with parameters $stop + 1$ and $start + 1$ is equal to `anyM.loop` applied to the array $\langle as \rangle$ with parameters $stop$ and $start$.
Array.anyM_toList theorem
[Monad m] {p : α → m Bool} {as : Array α} : as.toList.anyM p = as.anyM p
Full source
@[simp] theorem anyM_toList [Monad m] {p : α → m Bool} {as : Array α} :
    as.toList.anyM p = as.anyM p :=
  match as with
  | ⟨[]⟩  => by simp [anyM, anyM.loop]
  | ⟨a :: as⟩ => by
    simp only [List.anyM, anyM, List.size_toArray, List.length_cons, Nat.le_refl, ↓reduceDIte]
    rw [anyM.loop, dif_pos (by omega)]
    congr 1
    funext b
    split
    · simp
    · simp only [Bool.false_eq_true, ↓reduceIte]
      rw [anyM_loop_cons]
      simpa [anyM] using anyM_toList
Equivalence of Monadic Any Operation Between Array and Its List Conversion
Informal description
For any monad $m$, predicate $p : \alpha \to m \text{Bool}$, and array $as$ of type $\text{Array }\alpha$, the monadic any operation applied to the list obtained from $as$ is equal to the monadic any operation applied directly to $as$. That is, $\text{toList}(as).\text{anyM } p = as.\text{anyM } p$.
Array.anyM_loop_iff_exists theorem
{p : α → Bool} {as : Array α} {start stop} (h : stop ≤ as.size) : anyM.loop (m := Id) p as stop h start = true ↔ ∃ (i : Nat) (_ : i < as.size), start ≤ i ∧ i < stop ∧ p as[i] = true
Full source
theorem anyM_loop_iff_exists {p : α → Bool} {as : Array α} {start stop} (h : stop ≤ as.size) :
    anyM.loopanyM.loop (m := Id) p as stop h start = true ↔
      ∃ (i : Nat) (_ : i < as.size), start ≤ i ∧ i < stop ∧ p as[i] = true := by
  unfold anyM.loop
  split <;> rename_i h₁
  · dsimp
    split <;> rename_i h₂
    · simp only [true_iff]
      refine ⟨start, by omega, by omega, by omega, h₂⟩
    · rw [anyM_loop_iff_exists]
      constructor
      · rintro ⟨i, hi, ge, lt, h⟩
        have : start ≠ i := by rintro rfl; omega
        exact ⟨i, by omega, by omega, lt, h⟩
      · rintro ⟨i, hi, ge, lt, h⟩
        have : start ≠ i := by rintro rfl; erw [h] at h₂; simp_all
        exact ⟨i, by omega, by omega, lt, h⟩
  · simp
    omega
termination_by stop - start
Existence of Satisfying Element in Array Loop
Informal description
For any predicate `p : α → Bool`, array `as : Array α`, and indices `start`, `stop` with `stop ≤ as.size`, the loop `anyM.loop` (with identity monad) applied to `p`, `as`, `stop`, and `start` returns `true` if and only if there exists an index `i` such that: 1. `i < as.size` 2. `start ≤ i < stop` 3. `p as[i] = true`
Array.any_iff_exists theorem
{p : α → Bool} {as : Array α} {start stop} : as.any p start stop ↔ ∃ (i : Nat) (_ : i < as.size), start ≤ i ∧ i < stop ∧ p as[i]
Full source
theorem any_iff_exists {p : α → Bool} {as : Array α} {start stop} :
    as.any p start stop ↔ ∃ (i : Nat) (_ : i < as.size), start ≤ i ∧ i < stop ∧ p as[i] := by
  dsimp [any, anyM, Id.run]
  split
  · rw [anyM_loop_iff_exists]
  · rw [anyM_loop_iff_exists]
    constructor
    · rintro ⟨i, hi, ge, _, h⟩
      exact ⟨i, by omega, by omega, by omega, h⟩
    · rintro ⟨i, hi, ge, _, h⟩
      exact ⟨i, by omega, by omega, by omega, h⟩
Existence of Satisfying Element in Array Subrange Predicate Test
Informal description
For any predicate $p : \alpha \to \text{Bool}$, array $as : \text{Array}\ \alpha$, and indices $start$, $stop$, the function call $\text{as.any}\ p\ start\ stop$ returns $\texttt{true}$ if and only if there exists an index $i$ such that: 1. $i < \text{as.size}$, 2. $start \leq i < stop$, 3. $p(\text{as}[i])$ holds.
Array.any_eq_true theorem
{p : α → Bool} {as : Array α} : as.any p = true ↔ ∃ (i : Nat) (_ : i < as.size), p as[i]
Full source
@[simp] theorem any_eq_true {p : α → Bool} {as : Array α} :
    as.any p = true ↔ ∃ (i : Nat) (_ : i < as.size), p as[i] := by
  simp [any_iff_exists]
Existence of Satisfying Element in Array Predicate Test
Informal description
For any predicate `p : α → Bool` and any array `as : Array α`, the function `as.any p` returns `true` if and only if there exists an index `i` such that `i < as.size` and `p as[i]` holds.
Array.any_eq_false theorem
{p : α → Bool} {as : Array α} : as.any p = false ↔ ∀ (i : Nat) (_ : i < as.size), ¬p as[i]
Full source
@[simp] theorem any_eq_false {p : α → Bool} {as : Array α} :
    as.any p = false ↔ ∀ (i : Nat) (_ : i < as.size), ¬p as[i] := by
  rw [Bool.eq_false_iff, Ne, any_eq_true]
  simp
$\text{Array.any}\ p = \texttt{false} \leftrightarrow \forall i < \text{size}(as),\ \neg p(as[i])$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array $as : \text{Array}\ \alpha$, the function $as.any\ p$ returns $\texttt{false}$ if and only if for every index $i$ such that $i < as.size$, the predicate $p(as[i])$ does not hold (i.e., $\neg p(as[i])$).
Array.any_toList theorem
{p : α → Bool} {as : Array α} : as.toList.any p = as.any p
Full source
@[simp] theorem any_toList {p : α → Bool} {as : Array α} : as.toList.any p = as.any p := by
  rw [Bool.eq_iff_iff, any_eq_true, List.any_eq_true]
  simp only [List.mem_iff_getElem, getElem_toList]
  exact ⟨fun ⟨_, ⟨i, w, rfl⟩, h⟩ => ⟨i, w, h⟩, fun ⟨i, w, h⟩ => ⟨_, ⟨i, w, rfl⟩, h⟩⟩
Equivalence of `any` Operation Between Array and Its List Conversion
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array $as : \text{Array}\ \alpha$, the result of applying the `any` operation to the list obtained by converting $as$ to a list is equal to applying the `any` operation directly to $as$. In other words, $\text{any}\ p\ (\text{toList}\ as) = \text{any}\ p\ as$.
Array.allM_eq_not_anyM_not theorem
[Monad m] [LawfulMonad m] {p : α → m Bool} {as : Array α} : allM p as = (!·) <$> anyM ((!·) <$> p ·) as
Full source
theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] {p : α → m Bool} {as : Array α} :
    allM p as = (! ·) <$> anyM ((! ·) <$> p ·) as := by
  dsimp [allM, anyM]
  simp
De Morgan's Law for Monadic Array Operations: $\text{allM}\ p = \neg \circ \text{anyM}\ (\neg \circ p)$
Informal description
For any monad `m` satisfying the monad laws, any predicate `p : α → m Bool`, and any array `as : Array α`, the monadic all operation `allM p as` is equivalent to applying negation to the result of the monadic any operation `anyM` on the negated predicate `(!·) <$> p ·`. In mathematical notation: $$\text{allM}\ p\ as = \text{map}\ (\lambda b, \neg b)\ (\text{anyM}\ (\lambda x, \text{map}\ (\lambda b, \neg b)\ (p\ x))\ as)$$
Array.allM_toList theorem
[Monad m] [LawfulMonad m] {p : α → m Bool} {as : Array α} : as.toList.allM p = as.allM p
Full source
@[simp] theorem allM_toList [Monad m] [LawfulMonad m] {p : α → m Bool} {as : Array α} :
    as.toList.allM p = as.allM p := by
  rw [allM_eq_not_anyM_not]
  rw [← anyM_toList]
  rw [List.allM_eq_not_anyM_not]
Equivalence of Monadic All Operation Between Array and Its List Conversion
Informal description
For any monad $m$ satisfying the monad laws, any predicate $p : \alpha \to m \text{Bool}$, and any array $as$ of type $\text{Array }\alpha$, the monadic all operation applied to the list obtained from $as$ is equal to the monadic all operation applied directly to $as$. That is, $\text{toList}(as).\text{allM } p = as.\text{allM } p$.
Array.all_eq_not_any_not theorem
{p : α → Bool} {as : Array α} {start stop} : as.all p start stop = !(as.any (!p ·) start stop)
Full source
theorem all_eq_not_any_not {p : α → Bool} {as : Array α} {start stop} :
    as.all p start stop = !(as.any (!p ·) start stop) := by
  dsimp [all, allM]
  rfl
De Morgan's Law for Array.all and Array.any
Informal description
For any predicate `p : α → Bool` and array `as : Array α`, the result of checking if all elements in the subarray from index `start` to `stop` satisfy `p` is equal to the negation of checking if any element in the same subarray satisfies the negation of `p`. In mathematical notation: $$\text{all}(p, \text{as}, \text{start}, \text{stop}) = \neg \text{any}(\neg p \circ \cdot, \text{as}, \text{start}, \text{stop})$$
Array.all_iff_forall theorem
{p : α → Bool} {as : Array α} {start stop} : as.all p start stop ↔ ∀ (i : Nat) (_ : i < as.size), start ≤ i ∧ i < stop → p as[i]
Full source
theorem all_iff_forall {p : α → Bool} {as : Array α} {start stop} :
    as.all p start stop ↔ ∀ (i : Nat) (_ : i < as.size), start ≤ i ∧ i < stop → p as[i] := by
  rw [all_eq_not_any_not]
  suffices ¬(as.any (!p ·) start stop = true)¬(as.any (!p ·) start stop = true) ↔
      ∀ (i : Nat) (_ : i < as.size), start ≤ i ∧ i < stop → p as[i] by
    simp_all
  simp only [any_iff_exists, Bool.not_eq_eq_eq_not, Bool.not_true, not_exists, not_and,
    Bool.not_eq_false, and_imp]
Equivalence of Array.all and Universal Quantification over Subarray Elements
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $\text{as} : \text{Array}\ \alpha$, the boolean result of checking if all elements in the subarray from index $\text{start}$ to $\text{stop}$ satisfy $p$ is equivalent to the statement that for every index $i$ within the bounds of $\text{as}$, if $i$ lies in the interval $[\text{start}, \text{stop})$, then $p(\text{as}[i])$ holds. In mathematical notation: $$\text{all}(p, \text{as}, \text{start}, \text{stop}) \leftrightarrow \forall i < \text{as.size}, \text{start} \leq i < \text{stop} \to p(\text{as}[i])$$
Array.all_eq_true theorem
{p : α → Bool} {as : Array α} : as.all p = true ↔ ∀ (i : Nat) (_ : i < as.size), p as[i]
Full source
@[simp] theorem all_eq_true {p : α → Bool} {as : Array α} :
    as.all p = true ↔ ∀ (i : Nat) (_ : i < as.size), p as[i] := by
  simp [all_iff_forall]
Characterization of Array.all Returning True
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $\text{as} : \text{Array}\ \alpha$, the function `all` applied to $p$ and $\text{as}$ returns `true` if and only if for every index $i$ such that $i < \text{as.size}$, the predicate $p$ holds for the element $\text{as}[i]$. In mathematical notation: $$\text{all}(p, \text{as}) = \text{true} \leftrightarrow \forall i < \text{as.size}, p(\text{as}[i])$$
Array.all_eq_false theorem
{p : α → Bool} {as : Array α} : as.all p = false ↔ ∃ (i : Nat) (_ : i < as.size), ¬p as[i]
Full source
@[simp] theorem all_eq_false {p : α → Bool} {as : Array α} :
    as.all p = false ↔ ∃ (i : Nat) (_ : i < as.size), ¬p as[i] := by
  rw [Bool.eq_false_iff, Ne, all_eq_true]
  simp
Characterization of Array.all Returning False: $\text{all}(p, \text{as}) = \text{false} \leftrightarrow \exists i < \text{as.size}, \neg p(\text{as}[i])$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $\text{as} : \text{Array}\ \alpha$, the function `all` applied to $p$ and $\text{as}$ returns `false` if and only if there exists an index $i$ such that $i < \text{as.size}$ and the predicate $p$ does not hold for the element $\text{as}[i]$. In mathematical notation: $$\text{all}(p, \text{as}) = \text{false} \leftrightarrow \exists i < \text{as.size}, \neg p(\text{as}[i])$$
Array.all_toList theorem
{p : α → Bool} {as : Array α} : as.toList.all p = as.all p
Full source
@[simp] theorem all_toList {p : α → Bool} {as : Array α} : as.toList.all p = as.all p := by
  rw [Bool.eq_iff_iff, all_eq_true, List.all_eq_true]
  simp only [List.mem_iff_getElem, getElem_toList]
  constructor
  · intro w i h
    exact w as[i] ⟨i, h, getElem_toList h⟩
  · rintro w x ⟨i, h, rfl⟩
    exact w i h
Equivalence of `all` Operation on Array and its List Conversion
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $\text{as} : \text{Array}\ \alpha$, the result of applying the `all` operation to the predicate $p$ and the list obtained by converting $\text{as}$ to a list is equal to the result of applying the `all` operation directly to $\text{as}$ and $p$. In mathematical notation: $$\text{all}(p, \text{as.toList}) = \text{all}(p, \text{as})$$
Array.all_eq_true_iff_forall_mem theorem
{xs : Array α} : xs.all p ↔ ∀ x, x ∈ xs → p x
Full source
theorem all_eq_true_iff_forall_mem {xs : Array α} : xs.all p ↔ ∀ x, x ∈ xs → p x := by
  simp only [← all_toList, List.all_eq_true, mem_def]
Characterization of Array.all: `xs.all p ↔ ∀ x ∈ xs, p x`
Informal description
For any array `xs` of type `α` and predicate `p : α → Bool`, the boolean expression `xs.all p` evaluates to `true` if and only if every element `x` in `xs` satisfies `p x`. In other words, the `all` operation on an array returns true precisely when all elements of the array satisfy the given predicate.
List.anyM_toArray' theorem
[Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} {stop} (h : stop = l.toArray.size) : l.toArray.anyM p 0 stop = l.anyM p
Full source
/-- Variant of `anyM_toArray` with a side condition on `stop`. -/
@[simp] theorem _root_.List.anyM_toArray' [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} {stop}
    (h : stop = l.toArray.size) :
    l.toArray.anyM p 0 stop = l.anyM p := by
  subst h
  rw [← anyM_toList]
Equivalence of Monadic Any Operation Between List and Array Conversion with Bounds
Informal description
For any monad $m$ that satisfies the monad laws, any predicate $p : \alpha \to m \text{Bool}$, and any list $l$ of type $\text{List}\ \alpha$, if $stop$ equals the size of the array obtained by converting $l$ to an array, then the monadic any operation applied to the array from index $0$ to $stop$ is equal to the monadic any operation applied directly to $l$. That is: $$l.\text{toArray}.\text{anyM}\ p\ 0\ stop = l.\text{anyM}\ p$$
List.any_toArray' theorem
{p : α → Bool} {l : List α} {stop} (h : stop = l.toArray.size) : l.toArray.any p 0 stop = l.any p
Full source
/-- Variant of `any_toArray` with a side condition on `stop`. -/
@[simp] theorem _root_.List.any_toArray' {p : α → Bool} {l : List α} {stop}
    (h : stop = l.toArray.size) :
    l.toArray.any p 0 stop = l.any p := by
  subst h
  rw [any_toList]
Equivalence of `any` Operation Between List and Array Conversion with Bounds
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any list $l : \text{List}\ \alpha$, if $stop$ is equal to the size of the array obtained by converting $l$ to an array, then the result of applying the `any` operation to the array from index $0$ to $stop$ is equal to applying the `any` operation directly to $l$. In other words, $\text{any}\ p\ (\text{toArray}\ l)\ 0\ stop = \text{any}\ p\ l$.
List.allM_toArray' theorem
[Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} {stop} (h : stop = l.toArray.size) : l.toArray.allM p 0 stop = l.allM p
Full source
/-- Variant of `allM_toArray` with a side condition on `stop`. -/
@[simp] theorem _root_.List.allM_toArray' [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} {stop}
    (h : stop = l.toArray.size) :
    l.toArray.allM p 0 stop = l.allM p := by
  subst h
  rw [← allM_toList]
Equivalence of Monadic All Operation Between List and Array Conversion with Bounds
Informal description
For any monad $m$ satisfying the monad laws, any predicate $p : \alpha \to m \text{Bool}$, and any list $l : \text{List}\ \alpha$, if $\text{stop}$ equals the size of the array obtained by converting $l$ to an array, then the monadic all operation applied to the array from index $0$ to $\text{stop}$ is equal to the monadic all operation applied directly to $l$. That is: $$l.\text{toArray}.\text{allM}\ p\ 0\ \text{stop} = l.\text{allM}\ p$$
List.all_toArray' theorem
{p : α → Bool} {l : List α} {stop} (h : stop = l.toArray.size) : l.toArray.all p 0 stop = l.all p
Full source
/-- Variant of `all_toArray` with a side condition on `stop`. -/
@[simp] theorem _root_.List.all_toArray' {p : α → Bool} {l : List α} {stop}
    (h : stop = l.toArray.size) :
    l.toArray.all p 0 stop = l.all p := by
  subst h
  rw [all_toList]
Equivalence of `all` Operation on Array Conversion with Side Condition
Informal description
For any predicate $p : \alpha \to \text{Bool}$, list $l : \text{List}\ \alpha$, and natural number $\text{stop}$ such that $\text{stop} = \text{size}(l.\text{toArray})$, the result of applying the `all` operation to the predicate $p$ and the array obtained by converting $l$ to an array, starting from index $0$ up to $\text{stop}$, is equal to the result of applying the `all` operation directly to $l$ and $p$. In mathematical notation: $$\text{all}(p, l.\text{toArray}, 0, \text{stop}) = \text{all}(p, l)$$
List.anyM_toArray theorem
[Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} : l.toArray.anyM p = l.anyM p
Full source
theorem _root_.List.anyM_toArray [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} :
    l.toArray.anyM p = l.anyM p := by
  rw [← anyM_toList]
Equivalence of Monadic Any Operation Between List and Its Array Conversion
Informal description
For any monad $m$ satisfying the monad laws, any predicate $p : \alpha \to m \text{Bool}$, and any list $l$ of elements of type $\alpha$, the monadic any operation applied to the array obtained from converting $l$ is equal to the monadic any operation applied directly to $l$. That is, $\text{toArray}(l).\text{anyM } p = l.\text{anyM } p$.
List.any_toArray theorem
{p : α → Bool} {l : List α} : l.toArray.any p = l.any p
Full source
theorem _root_.List.any_toArray {p : α → Bool} {l : List α} : l.toArray.any p = l.any p := by
  rw [any_toList]
Equivalence of `any` Operation Between List and Its Array Conversion
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any list $l$ of elements of type $\alpha$, the result of applying the `any` operation to the array obtained by converting $l$ to an array is equal to applying the `any` operation directly to $l$. In other words, $\text{any}\ p\ (\text{toArray}\ l) = \text{any}\ p\ l$.
List.allM_toArray theorem
[Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} : l.toArray.allM p = l.allM p
Full source
theorem _root_.List.allM_toArray [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} :
    l.toArray.allM p = l.allM p := by
  rw [← allM_toList]
Equivalence of Monadic All Operation Between List and Its Array Conversion
Informal description
For any monad $m$ satisfying the monad laws, any predicate $p : \alpha \to m \text{Bool}$, and any list $l$ of elements of type $\alpha$, the monadic all operation applied to the array obtained from converting $l$ is equal to the monadic all operation applied directly to $l$. That is, $\text{allM}\ p\ (l.\text{toArray}) = \text{allM}\ p\ l$.
List.all_toArray theorem
{p : α → Bool} {l : List α} : l.toArray.all p = l.all p
Full source
theorem _root_.List.all_toArray {p : α → Bool} {l : List α} : l.toArray.all p = l.all p := by
  rw [all_toList]
Equivalence of `all` Operation on List and its Array Conversion
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and list $l : \text{List}\ \alpha$, the result of applying the `all` operation to the predicate $p$ and the array obtained by converting $l$ to an array is equal to the result of applying the `all` operation directly to $l$ and $p$. In mathematical notation: $$\text{all}(p, l.\text{toArray}) = \text{all}(p, l)$$
Array.any_eq_true' theorem
{p : α → Bool} {as : Array α} : as.any p = true ↔ (∃ x, x ∈ as ∧ p x)
Full source
/-- Variant of `any_eq_true` in terms of membership rather than an array index. -/
theorem any_eq_true' {p : α → Bool} {as : Array α} :
    as.any p = true ↔ (∃ x, x ∈ as ∧ p x) := by
  cases as
  simp
Existence of Satisfying Element in Array via `any` Operation
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array `as` of type $\text{Array}\ \alpha$, the expression $\text{any}\ p\ \text{as}$ evaluates to $\text{true}$ if and only if there exists an element $x$ in $\text{as}$ such that $p(x)$ holds.
Array.any_eq_false' theorem
{p : α → Bool} {as : Array α} : as.any p = false ↔ ∀ x, x ∈ as → ¬p x
Full source
/-- Variant of `any_eq_false` in terms of membership rather than an array index. -/
theorem any_eq_false' {p : α → Bool} {as : Array α} :
    as.any p = false ↔ ∀ x, x ∈ as → ¬p x := by
  rw [Bool.eq_false_iff, Ne, any_eq_true']
  simp
$\text{any}\ p\ \text{as} = \text{false}$ iff no element in `as` satisfies $p$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array `as` of type $\text{Array}\ \alpha$, the expression $\text{any}\ p\ \text{as}$ evaluates to $\text{false}$ if and only if for every element $x$ in `as`, the predicate $p(x)$ does not hold (i.e., $\neg p(x)$).
Array.all_eq_true' theorem
{p : α → Bool} {as : Array α} : as.all p = true ↔ (∀ x, x ∈ as → p x)
Full source
/-- Variant of `all_eq_true` in terms of membership rather than an array index. -/
theorem all_eq_true' {p : α → Bool} {as : Array α} :
    as.all p = true ↔ (∀ x, x ∈ as → p x) := by
  cases as
  simp
Universal Quantification over Array Elements via `all` Operation
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array `as` of type `Array \alpha`, the boolean value `as.all p = true` holds if and only if for every element $x$ in the array `as`, the predicate $p(x)$ evaluates to `true`.
Array.all_eq_false' theorem
{p : α → Bool} {as : Array α} : as.all p = false ↔ ∃ x, x ∈ as ∧ ¬p x
Full source
/-- Variant of `all_eq_false` in terms of membership rather than an array index. -/
theorem all_eq_false' {p : α → Bool} {as : Array α} :
    as.all p = false ↔ ∃ x, x ∈ as ∧ ¬p x := by
  rw [Bool.eq_false_iff, Ne, all_eq_true']
  simp
Existence of Counterexample in Array via `all` Operation
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array `as` of type `Array \alpha`, the boolean value `as.all p = false` holds if and only if there exists an element $x$ in the array `as` such that $p(x)$ evaluates to `false`. In symbols: $\text{as.all p} = \text{false} \leftrightarrow \exists x \in \text{as}, \neg p(x)$
Array.any_eq theorem
{xs : Array α} {p : α → Bool} : xs.any p = decide (∃ i : Nat, ∃ h, p (xs[i]'h))
Full source
theorem any_eq {xs : Array α} {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]
Equivalence of Array Any Operation to Existential Quantification over Elements
Informal description
For any array `xs` of type `Array α` and any predicate `p : α → Bool`, the boolean value `xs.any p` is equal to the decidability of the existence of an index `i` and a proof `h` such that `p(xs[i])` holds, where `h` is a proof that `i` is within the bounds of `xs`.
Array.any_eq' theorem
{xs : Array α} {p : α → Bool} : xs.any p = decide (∃ x, x ∈ xs ∧ p x)
Full source
/-- Variant of `any_eq` in terms of membership rather than an array index. -/
theorem any_eq' {xs : Array α} {p : α → Bool} : xs.any p = decide (∃ x, x ∈ xs ∧ p x) := by
  by_cases h : xs.any p
  · simp_all [any_eq_true', -any_eq_true]
  · simp only [Bool.not_eq_true] at h
    simp only [h]
    simp only [any_eq_false'] at h
    simpa using h
Equivalence of Array Any Operation to Existential Quantification over Membership
Informal description
For any array `xs` of elements of type `α` and any boolean-valued predicate `p` on `α`, the result of `xs.any p` is equal to the boolean value indicating whether there exists an element `x` in `xs` such that `p x` holds. In symbols: $\text{xs.any p} = \text{decide} (\exists x \in \text{xs}, p(x))$
Array.all_eq theorem
{xs : Array α} {p : α → Bool} : xs.all p = decide (∀ i, (_ : i < xs.size) → p xs[i])
Full source
theorem all_eq {xs : Array α} {p : α → Bool} : xs.all p = decide (∀ i, (_ : i < xs.size) → 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
Universal Quantification over Array Elements via `all`
Informal description
For any array `xs` of type `Array α` and any predicate `p : α → Bool`, the boolean value `xs.all p` is equal to the decidability of the proposition that for every index `i` less than the size of `xs`, the predicate `p` holds for the element `xs[i]`. In symbols: $\text{xs.all p} = \text{decide} (\forall i < \text{xs.size}, p(\text{xs[i]}))$
Array.all_eq' theorem
{xs : Array α} {p : α → Bool} : xs.all p = decide (∀ x, x ∈ xs → p x)
Full source
/-- Variant of `all_eq` in terms of membership rather than an array index. -/
theorem all_eq' {xs : Array α} {p : α → Bool} : xs.all p = decide (∀ x, x ∈ xs → p x) := by
  by_cases h : xs.all p
  · simp_all [all_eq_true', -all_eq_true]
  · simp only [Bool.not_eq_true] at h
    simp only [h]
    simp only [all_eq_false'] at h
    simpa using h
Universal Quantification over Array Elements via `all` (Membership Version)
Informal description
For any array `xs` of elements of type `α` and any boolean-valued predicate `p` on `α`, the boolean value `xs.all p` (which checks if all elements in `xs` satisfy `p`) is equal to the decidability of the proposition that for every element `x` in `xs`, `p x` holds. In symbols: $\text{xs.all p} = \text{decide} (\forall x \in \text{xs}, p(x))$
Array.decide_exists_mem theorem
{xs : Array α} {p : α → Prop} [DecidablePred p] : decide (∃ x, x ∈ xs ∧ p x) = xs.any p
Full source
theorem decide_exists_mem {xs : Array α} {p : α → Prop} [DecidablePred p] :
    decide (∃ x, x ∈ xs ∧ p x) = xs.any p := by
  simp [any_eq']
Equivalence between Decidable Existential Quantification and Array `any` Operation
Informal description
For any array `xs` of elements of type `α` and any decidable predicate `p` on `α`, the boolean value indicating the existence of an element `x` in `xs` such that `p x` holds is equal to the result of the `any` operation on `xs` with predicate `p`. In symbols: $\text{decide} (\exists x \in \text{xs}, p(x)) = \text{xs.any p}$
Array.decide_forall_mem theorem
{xs : Array α} {p : α → Prop} [DecidablePred p] : decide (∀ x, x ∈ xs → p x) = xs.all p
Full source
theorem decide_forall_mem {xs : Array α} {p : α → Prop} [DecidablePred p] :
    decide (∀ x, x ∈ xs → p x) = xs.all p := by
  simp [all_eq']
Decidability of Universal Quantification over Array Elements via `all`
Informal description
For any array `xs` of type `Array α` and any decidable predicate `p` on `α`, the boolean value `decide (∀ x ∈ xs, p x)` (which decides whether all elements in `xs` satisfy `p`) is equal to `xs.all p` (the result of applying the `all` operation to `xs` with predicate `p`). In symbols: $\text{decide} (\forall x \in \text{xs}, p(x)) = \text{xs.all p}$
List.contains_toArray theorem
[BEq α] {l : List α} {a : α} : l.toArray.contains a = l.contains a
Full source
@[simp] theorem _root_.List.contains_toArray [BEq α] {l : List α} {a : α} :
    l.toArray.contains a = l.contains a := by
  simp [Array.contains, List.any_beq]
Equivalence of Containment Check Between List and Array Conversion
Informal description
For any type $\alpha$ with a boolean equality relation and for any list $l$ of elements of type $\alpha$ and any element $a$ of type $\alpha$, the boolean result of checking whether $a$ is contained in the array obtained by converting $l$ to an array is equal to the boolean result of checking whether $a$ is contained in $l$. In symbols: $\text{contains}\ (\text{toArray}\ l)\ a = \text{contains}\ l\ a$
List.elem_toArray theorem
[BEq α] {l : List α} {a : α} : Array.elem a l.toArray = List.elem a l
Full source
theorem _root_.List.elem_toArray [BEq α] {l : List α} {a : α} :
    Array.elem a l.toArray = List.elem a l := by
  simp [Array.elem]
Equivalence of Element Check Between List and Array Conversion
Informal description
For any type $\alpha$ with a boolean equality relation, any list $l$ of elements of type $\alpha$, and any element $a$ of type $\alpha$, the boolean result of checking whether $a$ is an element of the array obtained by converting $l$ to an array is equal to the boolean result of checking whether $a$ is an element of $l$. In symbols: $\text{Array.elem}\ a\ (\text{List.toArray}\ l) = \text{List.elem}\ a\ l$
Array.any_beq theorem
[BEq α] {xs : Array α} {a : α} : (xs.any fun x => a == x) = xs.contains a
Full source
theorem any_beq [BEq α] {xs : Array α} {a : α} : (xs.any fun x => a == x) = xs.contains a := by
  cases xs
  simp [List.any_beq]
Equivalence of `any` and `contains` for Array Membership Check
Informal description
For any type $\alpha$ with a boolean equality relation, any array `xs` of elements of type $\alpha$, and any element `a` of type $\alpha$, the boolean result of checking whether any element in `xs` is equal to `a` (using `xs.any`) is equal to the boolean result of checking whether `a` is contained in `xs` (using `xs.contains`). In symbols: $$(\text{xs.any } (\lambda x \Rightarrow a == x)) = \text{xs.contains } a$$
Array.any_beq' theorem
[BEq α] [PartialEquivBEq α] {xs : Array α} : (xs.any fun x => x == a) = xs.contains a
Full source
/-- Variant of `any_beq` with `==` reversed. -/
theorem any_beq' [BEq α] [PartialEquivBEq α] {xs : Array α} :
    (xs.any fun x => x == a) = xs.contains a := by
  simp only [BEq.comm, any_beq]
Equivalence of `any` and `contains` for Array Membership Check (Reversed Equality)
Informal description
For any type $\alpha$ with a boolean equality relation `==` that forms a partial equivalence relation, and for any array `xs` of elements of type $\alpha$, the boolean result of checking whether any element `x` in `xs` satisfies `x == a` (using `xs.any`) is equal to the boolean result of checking whether `a` is contained in `xs` (using `xs.contains`). In symbols: $$(\text{xs.any } (\lambda x \Rightarrow x == a)) = \text{xs.contains } a$$
Array.all_bne theorem
[BEq α] {xs : Array α} : (xs.all fun x => a != x) = !xs.contains a
Full source
theorem all_bne [BEq α] {xs : Array α} : (xs.all fun x => a != x) = !xs.contains a := by
  cases xs
  simp [List.all_bne]
Negation of Containment via Universal Inequality in Arrays
Informal description
For any type $\alpha$ with a boolean equality relation and for any array `xs` of elements of type $\alpha$, the boolean result of checking that all elements `x` in `xs` satisfy `a != x` is equal to the negation of checking whether `a` is contained in `xs`. In symbols: $\text{all}\ (\lambda x, a \neq x)\ \text{xs} = \neg (\text{contains}\ \text{xs}\ a)$
Array.all_bne' theorem
[BEq α] [PartialEquivBEq α] {xs : Array α} : (xs.all fun x => x != a) = !xs.contains a
Full source
/-- Variant of `all_bne` with `!=` reversed. -/
theorem all_bne' [BEq α] [PartialEquivBEq α] {xs : Array α} :
    (xs.all fun x => x != a) = !xs.contains a := by
  simp only [bne_comm, all_bne]
Universal Inequality in Array Equivalent to Negated Containment
Informal description
For any type $\alpha$ with a boolean equality relation that forms a partial equivalence relation, and for any array `xs` of elements of type $\alpha$, the boolean result of checking that all elements `x` in `xs` satisfy `x != a` is equal to the negation of checking whether `a` is contained in `xs$. In symbols: $\text{all}\ (\lambda x, x \neq a)\ \text{xs} = \neg (\text{contains}\ \text{xs}\ a)$
Array.mem_of_contains_eq_true theorem
[BEq α] [LawfulBEq α] {a : α} {as : Array α} : as.contains a = true → a ∈ as
Full source
theorem mem_of_contains_eq_true [BEq α] [LawfulBEq α] {a : α} {as : Array α} : as.contains a = truea ∈ as := by
  cases as
  simp
Containment Check Implies Membership in Arrays with Lawful Boolean Equality
Informal description
For any type $\alpha$ with a lawful boolean equality relation, and for any array `as` of elements of type $\alpha$ and any element `a` of type $\alpha$, if the boolean containment check `as.contains a` evaluates to `true`, then `a` is an element of `as`.
Array.mem_of_elem_eq_true abbrev
Full source
@[deprecated mem_of_contains_eq_true (since := "2024-12-12")]
abbrev mem_of_elem_eq_true := @mem_of_contains_eq_true
Boolean Membership Test Implies Array Membership
Informal description
For any type $\alpha$ with a boolean equality relation, and for any array `as` of elements of type $\alpha$ and any element `a` of type $\alpha$, if the boolean membership test `as.elem a` evaluates to `true`, then `a` is an element of `as`.
Array.contains_eq_true_of_mem theorem
[BEq α] [LawfulBEq α] {a : α} {as : Array α} (h : a ∈ as) : as.contains a = true
Full source
theorem contains_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : Array α} (h : a ∈ as) : as.contains a = true := by
  cases as
  simpa using h
Containment Check Yields True for Array Elements
Informal description
For any type $\alpha$ with a lawful boolean equality relation (where `==` coincides with `=`), and for any element $a \in \alpha$ and array `as : Array α`, if $a$ is an element of `as`, then the boolean containment check `as.contains a` evaluates to `true`.
Array.elem_eq_true_of_mem abbrev
Full source
@[deprecated contains_eq_true_of_mem (since := "2024-12-12")]
abbrev elem_eq_true_of_mem := @contains_eq_true_of_mem
Array Membership Check Yields True for Elements
Informal description
For any type $\alpha$ with a boolean equality relation `BEq`, and for any element $a \in \alpha$ and array `as : Array α`, if $a$ is an element of `as$, then the boolean evaluation `elem a as` evaluates to `true`.
Array.instDecidableMemOfLawfulBEq instance
[BEq α] [LawfulBEq α] (a : α) (as : Array α) : Decidable (a ∈ as)
Full source
instance [BEq α] [LawfulBEq α] (a : α) (as : Array α) : Decidable (a ∈ as) :=
  decidable_of_decidable_of_iff (Iff.intro mem_of_contains_eq_true contains_eq_true_of_mem)
Decidability of Array Membership with Lawful Boolean Equality
Informal description
For any type $\alpha$ with a boolean equality relation `BEq` that is lawful (meaning `==` coincides with `=`), and for any element $a \in \alpha$ and array `as : Array α`, the proposition $a \in as$ (that $a$ is an element of `as`) is decidable.
Array.elem_eq_contains theorem
[BEq α] {a : α} {xs : Array α} : elem a xs = xs.contains a
Full source
@[simp] theorem elem_eq_contains [BEq α] {a : α} {xs : Array α} :
    elem a xs = xs.contains a := by
  simp [elem]
Equivalence of Array Membership Check Operations: `elem` and `contains`
Informal description
For any type $\alpha$ with a boolean equality relation `BEq`, and for any element $a \in \alpha$ and array `xs : Array α`, the boolean evaluation `elem a xs` is equal to `xs.contains a`.
Array.elem_iff theorem
[BEq α] [LawfulBEq α] {a : α} {xs : Array α} : elem a xs = true ↔ a ∈ xs
Full source
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
    elemelem a xs = true ↔ a ∈ xs := ⟨mem_of_contains_eq_true, contains_eq_true_of_mem⟩
Equivalence of Element Check and Membership in Arrays with Lawful Boolean Equality
Informal description
For any type $\alpha$ with a lawful boolean equality relation (where `==` coincides with `=`), and for any element $a \in \alpha$ and array `xs : Array α`, the boolean evaluation `elem a xs` is equal to `true` if and only if $a$ is an element of `xs$.
Array.contains_iff theorem
[BEq α] [LawfulBEq α] {a : α} {xs : Array α} : xs.contains a = true ↔ a ∈ xs
Full source
theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
    xs.contains a = true ↔ a ∈ xs := ⟨mem_of_contains_eq_true, contains_eq_true_of_mem⟩
Equivalence of Array Containment Check and Membership under Lawful Boolean Equality
Informal description
For any type $\alpha$ with a boolean equality relation `BEq` that is lawful (i.e., `==` coincides with `=`), and for any element $a \in \alpha$ and array `xs : Array α`, the boolean containment check `xs.contains a` evaluates to `true` if and only if $a$ is an element of `xs$.
Array.elem_eq_mem theorem
[BEq α] [LawfulBEq α] {a : α} {xs : Array α} : elem a xs = decide (a ∈ xs)
Full source
theorem elem_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
    elem a xs = decide (a ∈ xs) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
Equivalence of Element Check and Membership Decision in Arrays with Lawful Boolean Equality
Informal description
For any type $\alpha$ with a lawful boolean equality relation (where `==` coincides with `=`), and for any element $a \in \alpha$ and array `xs : Array α`, the boolean evaluation `elem a xs` is equal to the result of deciding the membership proposition $a \in xs$.
Array.contains_eq_mem theorem
[BEq α] [LawfulBEq α] {a : α} {xs : Array α} : xs.contains a = decide (a ∈ xs)
Full source
@[simp] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
    xs.contains a = decide (a ∈ xs) := by rw [← elem_eq_contains, elem_eq_mem]
Equivalence of Array Containment Check and Membership Decision under Lawful Boolean Equality
Informal description
For any type $\alpha$ with a lawful boolean equality relation (where `==` coincides with `=`), and for any element $a \in \alpha$ and array `xs : Array α`, the boolean containment check `xs.contains a` is equal to the result of deciding the membership proposition $a \in xs$.
Array.any_push' theorem
[BEq α] {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) : (xs.push a).any p 0 stop = (xs.any p || p a)
Full source
/-- Variant of `any_push` with a side condition on `stop`. -/
@[simp] theorem any_push' [BEq α] {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
    (xs.push a).any p 0 stop = (xs.any p || p a) := by
  cases xs
  rw [List.push_toArray]
  simp [h]
`any` Operation on Pushed Array with Bounds Condition: `(xs.push a).any p 0 stop = (xs.any p || p a)` when `stop = xs.size + 1`
Informal description
For any array `xs` of type `Array α`, element `a` of type `α`, and predicate `p : α → Bool`, if `stop` is equal to the size of `xs` plus one, then the result of applying the `any` operation to the array `xs.push a` from index `0` to `stop` is equal to the disjunction of applying `any p` to `xs` and evaluating `p a`. That is, `(xs.push a).any p 0 stop = (xs.any p || p a)`.
Array.any_push theorem
[BEq α] {xs : Array α} {a : α} {p : α → Bool} : (xs.push a).any p = (xs.any p || p a)
Full source
theorem any_push [BEq α] {xs : Array α} {a : α} {p : α → Bool} :
    (xs.push a).any p = (xs.any p || p a) :=
  any_push' (by simp)
Existential Quantification Preservation under Array Push: $\text{any}(p, \text{push}(xs, a)) = \text{any}(p, xs) \lor p(a)$
Informal description
For any array `xs` of type `Array α`, element `a` of type `α`, and predicate `p : α → Bool`, the existential quantification over the array `xs.push a` with predicate `p` is equal to the disjunction of the existential quantification over `xs` with predicate `p` and the evaluation of `p a`. In other words: $$\text{any}(p, \text{push}(xs, a)) = \text{any}(p, xs) \lor p(a)$$ where: - $\text{push}(xs, a)$ denotes the array obtained by appending $a$ to $xs$ - $\text{any}(p, arr)$ checks if $p$ holds for any element of $arr$
Array.all_push' theorem
[BEq α] {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) : (xs.push a).all p 0 stop = (xs.all p && p a)
Full source
/-- Variant of `all_push` with a side condition on `stop`. -/
@[simp] theorem all_push' [BEq α] {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
    (xs.push a).all p 0 stop = (xs.all p && p a) := by
  cases xs
  rw [List.push_toArray]
  simp [h]
Universal Quantification Preservation under Array Push with Boundary Condition
Informal description
For any array `xs` of type `Array α`, element `a` of type `α`, predicate `p : α → Bool`, and natural number `stop` such that `stop = xs.size + 1`, the following holds: $$\text{all}(p, \text{push}(xs, a), 0, \text{stop}) = \text{all}(p, xs) \land p(a)$$ where: - $\text{push}(xs, a)$ denotes the array obtained by appending $a$ to $xs$ - $\text{all}(p, arr, i, j)$ checks if $p$ holds for all elements of $arr$ from index $i$ to $j-1$ - $\text{all}(p, xs)$ checks if $p$ holds for all elements of $xs$
Array.all_push theorem
[BEq α] {xs : Array α} {a : α} {p : α → Bool} : (xs.push a).all p = (xs.all p && p a)
Full source
theorem all_push [BEq α] {xs : Array α} {a : α} {p : α → Bool} :
    (xs.push a).all p = (xs.all p && p a) :=
  all_push' (by simp)
Universal Quantification Preservation under Array Push
Informal description
For any array `xs` of type `Array α`, element `a` of type `α`, and predicate `p : α → Bool`, the following holds: $$\text{all}(p, \text{push}(xs, a)) = \text{all}(p, xs) \land p(a)$$ where: - $\text{push}(xs, a)$ denotes the array obtained by appending $a$ to $xs$ - $\text{all}(p, arr)$ checks if $p$ holds for all elements of $arr$
Array.contains_push theorem
[BEq α] {xs : Array α} {a : α} {b : α} : (xs.push a).contains b = (xs.contains b || b == a)
Full source
@[simp] theorem contains_push [BEq α] {xs : Array α} {a : α} {b : α} :
    (xs.push a).contains b = (xs.contains b || b == a) := by
  simp [contains]
Containment in Array After Push: $(xs \text{ with } a \text{ appended}).\text{contains}(b) = (xs.\text{contains}(b) \lor b = a)$
Informal description
For any array `xs` of type `Array α` with elements of type `α` equipped with a boolean equality relation, and for any elements `a` and `b` of type `α`, the array obtained by pushing `a` to `xs` contains `b` if and only if either `xs` contains `b` or `b` is equal to `a`. That is, $(xs \text{ with } a \text{ appended}).\text{contains}(b) = (xs.\text{contains}(b) \lor b = a)$.
Array.getElem_set_self theorem
{xs : Array α} {i : Nat} (h : i < xs.size) {v : α} : (xs.set i v)[i]'(by simp [h]) = v
Full source
@[simp] theorem getElem_set_self {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} :
    (xs.set i v)[i]'(by simp [h]) = v := by
  cases xs
  simp
Array Element Update Preserves Value at Updated Index
Informal description
For any array `xs` of type `Array α`, natural number index `i` such that `i < xs.size`, and value `v` of type `α`, the element at index `i` of the array obtained by setting the `i`-th element of `xs` to `v` is equal to `v`. In other words, `(xs.set i v)[i] = v` when `i` is a valid index for `xs`.
Array.getElem_set_eq abbrev
Full source
@[deprecated getElem_set_self (since := "2024-12-11")]
abbrev getElem_set_eq := @getElem_set_self
Array Element Update at Equal Indices: $(xs.set\ i\ v)[j] = v$ when $i = j$
Informal description
For any array `xs` of type `Array α`, natural number indices `i` and `j` such that `i < xs.size`, and value `v` of type `α`, if `i = j`, then the element at index `j` of the array obtained by setting the `i`-th element of `xs` to `v` is equal to `v`. In other words, `(xs.set i v)[j] = v` when `i = j` and `i` is a valid index for `xs`.
Array.getElem?_set_self theorem
{xs : Array α} {i : Nat} (h : i < xs.size) {v : α} : (xs.set i v)[i]? = v
Full source
@[simp] theorem getElem?_set_self {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} :
    (xs.set i v)[i]? = v := by simp [getElem?_eq_getElem, h]
Optional Array Access Yields Updated Value at Same Index: $(xs[i \mapsto v])[i]? = v$ when $i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α`, index `i` such that `i < xs.size`, and value `v` of type `α`, the optional access operation `(xs.set i v)[i]?` returns `v`. In other words, updating the array at index `i` with `v` and then accessing the same index optionally yields `v`.
Array.getElem?_set_eq abbrev
Full source
@[deprecated getElem?_set_self (since := "2024-12-11")]
abbrev getElem?_set_eq := @getElem?_set_self
Optional Array Access Yields Updated Value at Equal Indices: $(xs[i \mapsto v])[j]? = \text{some } v$ when $i = j$ and $i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α`, indices `i` and `j` such that `i < xs.size`, and value `v` of type `α`, if `i = j`, then the optional access operation `(xs.set i v)[j]?` returns `some v`. In other words, updating the array at index `i` with `v` and then optionally accessing the same index yields `some v`.
Array.getElem_set_ne theorem
{xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat} (pj : j < xs.size) (h : i ≠ j) : (xs.set i v)[j]'(by simp [*]) = xs[j]
Full source
@[simp] theorem getElem_set_ne {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
    (pj : j < xs.size) (h : i ≠ j) :
    (xs.set i v)[j]'(by simp [*]) = xs[j] := by
  simp only [set, ← getElem_toList, List.getElem_set_ne h]
Array Update Preserves Other Elements: $(xs[i \mapsto v])[j] = xs[j]$ when $i \neq j$
Informal description
For an array `xs` of type `α`, indices `i` and `j` with `i < xs.size` and `j < xs.size`, and a value `v` of type `α`, if `i ≠ j`, then updating the array at index `i` with value `v` does not change the element at index `j`. That is, `(xs.set i v)[j] = xs[j]`.
Array.getElem?_set_ne theorem
{xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat} (ne : i ≠ j) : (xs.set i v)[j]? = xs[j]?
Full source
@[simp] theorem getElem?_set_ne {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat}
    (ne : i ≠ j) : (xs.set i v)[j]? = xs[j]? := by
  by_cases h : j < xs.size <;> simp [getElem?_eq_getElem, getElem?_eq_none, Nat.ge_of_not_lt, ne, h]
Optional Array Access Preserved Under Update at Different Index: $(xs[i \mapsto v])[j]? = xs[j]?$ when $i \neq j$
Informal description
For an array `xs` of type `Array α`, indices `i` and `j` with `i < xs.size`, and a value `v` of type `α`, if `i ≠ j`, then the optional access operation `(xs.set i v)[j]?` returns the same result as `xs[j]?`. That is, updating the array at index `i` with value `v` does not change the optional access result at a different index `j`.
Array.getElem_set theorem
{xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat} (h : j < (xs.set i v).size) : (xs.set i v)[j] = if i = j then v else xs[j]'(by simpa using h)
Full source
theorem getElem_set {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
    (h : j < (xs.set i v).size) :
    (xs.set i v)[j] = if i = j then v else xs[j]'(by simpa using h) := by
  simp at h
  by_cases p : i = j <;> simp [p, h]
Array Element Access After Update: $(xs[i \mapsto v])[j] = \text{if } i = j \text{ then } v \text{ else } xs[j]$
Informal description
For an array `xs` of type `Array α`, indices `i` and `j` with `i < xs.size` and `j < (xs.set i v).size`, and a value `v` of type `α`, the element at index `j` of the array obtained by setting the `i`-th element of `xs` to `v` is equal to `v` if `i = j`, and to `xs[j]` otherwise. That is, $(xs[i \mapsto v])[j] = \begin{cases} v & \text{if } i = j \\ xs[j] & \text{otherwise} \end{cases}$.
Array.getElem?_set theorem
{xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat} : (xs.set i v)[j]? = if i = j then some v else xs[j]?
Full source
theorem getElem?_set {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat} :
    (xs.set i v)[j]? = if i = j then some v else xs[j]? := by
  split <;> simp_all
Optional Array Access After Update: $(xs[i \mapsto v])[j]? = \text{if } i = j \text{ then } \text{some } v \text{ else } xs[j]?$
Informal description
For any array `xs` of type `Array α`, index `i` such that `i < xs.size`, value `v` of type `α`, and index `j`, the optional access operation `(xs.set i v)[j]?` returns `some v` if `i = j`, and otherwise returns `xs[j]?`. That is, updating the array at index `i` with `v` and then optionally accessing index `j` yields `v` when `i = j` and the original value otherwise.
Array.set_getElem_self theorem
{xs : Array α} {i : Nat} (h : i < xs.size) : xs.set i xs[i] = xs
Full source
@[simp] theorem set_getElem_self {xs : Array α} {i : Nat} (h : i < xs.size) :
    xs.set i xs[i] = xs := by
  cases xs
  simp
Array Invariance Under Self-Replacement at Index
Informal description
For any array `xs` of type `Array α` and any index `i` such that `i < xs.size`, setting the element at position `i` to its current value `xs[i]` leaves the array unchanged, i.e., `xs.set i xs[i] = xs`.
Array.set_eq_empty_iff theorem
{xs : Array α} {i : Nat} {a : α} {h : i < xs.size} : xs.set i a = #[] ↔ xs = #[]
Full source
@[simp] theorem set_eq_empty_iff {xs : Array α} {i : Nat} {a : α} {h : i < xs.size} :
    xs.set i a = #[] ↔ xs = #[] := by
  cases xs <;> cases i <;> simp [set]
Empty Array Condition for Set Operation: `xs.set i a = #[] ↔ xs = #[]`
Informal description
For any array `xs` of type `α`, index `i`, element `a`, and proof `h` that `i` is within the bounds of `xs`, the array obtained by setting the `i`-th element of `xs` to `a` is equal to the empty array `#[]` if and only if `xs` itself is the empty array.
Array.set_comm theorem
(a b : α) {i j : Nat} {xs : Array α} {hi : i < xs.size} {hj : j < (xs.set i a).size} (h : i ≠ j) : (xs.set i a).set j b = (xs.set j b (by simpa using hj)).set i a (by simpa using hi)
Full source
theorem set_comm (a b : α)
    {i j : Nat} {xs : Array α} {hi : i < xs.size} {hj : j < (xs.set i a).size} (h : i ≠ j) :
    (xs.set i a).set j b = (xs.set j b (by simpa using hj)).set i a (by simpa using hi) := by
  cases xs
  simp [List.set_comm _ _ h]
Commutativity of Array Element Updates at Distinct Indices
Informal description
For any array `xs` of type `α`, elements `a` and `b` of type `α`, and distinct indices `i` and `j` such that `i < xs.size` and `j < (xs.set i a).size`, the following equality holds: $$(xs.\text{set}\ i\ a).\text{set}\ j\ b = (xs.\text{set}\ j\ b).\text{set}\ i\ a$$
Array.set_set theorem
(a : α) {b : α} {xs : Array α} {i : Nat} (h : i < xs.size) : (xs.set i a).set i b (by simpa using h) = xs.set i b
Full source
@[simp]
theorem set_set (a : α) {b : α} {xs : Array α} {i : Nat} (h : i < xs.size) :
    (xs.set i a).set i b (by simpa using h) = xs.set i b := by
  cases xs
  simp
Double Set at Same Index Reduces to Single Set
Informal description
For any array `xs` of type `α`, any index `i` such that `i < xs.size`, and any elements `a, b : α`, setting the element at index `i` to `a` and then to `b` is equivalent to setting it directly to `b`. That is, `(xs.set i a).set i b = xs.set i b`.
Array.mem_set theorem
{xs : Array α} {i : Nat} (h : i < xs.size) {a : α} : a ∈ xs.set i a
Full source
theorem mem_set {xs : Array α} {i : Nat} (h : i < xs.size) {a : α} :
    a ∈ xs.set i a := by
  simp [mem_iff_getElem]
  exact ⟨i, (by simpa using h), by simp⟩
Element Membership After Array Update at Same Index
Informal description
For any array `xs` of type `Array α`, index `i` such that `i < xs.size`, and element `a : α`, the element `a` is contained in the array obtained by setting the `i`-th element of `xs` to `a`. In other words, $a \in \text{set}(xs, i, a)$.
Array.mem_or_eq_of_mem_set theorem
{xs : Array α} {i : Nat} {a b : α} {w : i < xs.size} (h : a ∈ xs.set i b) : a ∈ xs ∨ a = b
Full source
theorem mem_or_eq_of_mem_set
    {xs : Array α} {i : Nat} {a b : α} {w : i < xs.size} (h : a ∈ xs.set i b) : a ∈ xsa ∈ xs ∨ a = b := by
  cases xs
  simpa using List.mem_or_eq_of_mem_set (by simpa using h)
Membership in Modified Array Implies Original Membership or Equality
Informal description
Let $xs$ be an array of type $\alpha$, $i$ be a natural number index such that $i < \text{size}(xs)$, and $a, b$ be elements of type $\alpha$. If $a$ is an element of the array obtained by setting the $i$-th element of $xs$ to $b$ (i.e., $a \in \text{set}(xs, i, b)$), then either $a$ was already an element of $xs$ or $a$ equals $b$. In other words, $a \in xs \lor a = b$.
Array.set!_eq_setIfInBounds theorem
: @set! = @setIfInBounds
Full source
@[simp] theorem set!_eq_setIfInBounds : @set! = @setIfInBounds := rfl
Equality of Array Modification Operations: `set! = setIfInBounds`
Informal description
The array modification operation `set!` is equal to the operation `setIfInBounds` when applied to arrays.
Array.set!_is_setIfInBounds abbrev
Full source
@[deprecated set!_eq_setIfInBounds (since := "2024-12-12")]
abbrev set!_is_setIfInBounds := @set!_eq_setIfInBounds
Equivalence of Array Modification Operations: `set!` and `setIfInBounds`
Informal description
The array modification operation `set!` is equivalent to the operation `setIfInBounds` when applied to arrays.
Array.size_setIfInBounds theorem
{xs : Array α} {i : Nat} {a : α} : (xs.setIfInBounds i a).size = xs.size
Full source
@[simp] theorem size_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
    (xs.setIfInBounds i a).size = xs.size := by
  if h : i < xs.size  then
    simp [setIfInBounds, h]
  else
    simp [setIfInBounds, h]
Size Preservation under Array Modification: `(xs.setIfInBounds i a).size = xs.size`
Informal description
For any array `xs` of type `α`, any index `i`, and any element `a` of type `α`, the size of the array obtained by setting the element at index `i` to `a` (if `i` is within bounds) is equal to the size of the original array `xs`. That is, `(xs.setIfInBounds i a).size = xs.size`.
Array.getElem_setIfInBounds theorem
{xs : Array α} {i : Nat} {a : α} {j : Nat} (hj : j < xs.size) : (xs.setIfInBounds i a)[j]'(by simp [hj]) = if i = j then a else xs[j]
Full source
theorem getElem_setIfInBounds {xs : Array α} {i : Nat} {a : α} {j : Nat}
    (hj : j < xs.size) :
    (xs.setIfInBounds i a)[j]'(by simp [hj]) = if i = j then a else xs[j] := by
  simp only [setIfInBounds]
  split
  · simp [getElem_set]
  · rw [if_neg]
    omega
Array Element Access After Conditional Update: $(xs[i \mapsto a])[j] = \text{if } i = j \text{ then } a \text{ else } xs[j]$
Informal description
For an array `xs` of type `Array α`, indices `i` and `j` with `j < xs.size`, and an element `a` of type `α`, the element at index `j` of the array obtained by setting the `i`-th element of `xs` to `a` (if `i` is within bounds) is equal to `a` if `i = j`, and to `xs[j]` otherwise. That is, $(xs[i \mapsto a])[j] = \begin{cases} a & \text{if } i = j \\ xs[j] & \text{otherwise} \end{cases}$.
Array.getElem_setIfInBounds_self theorem
{xs : Array α} {i : Nat} {a : α} (h : i < (xs.setIfInBounds i a).size) : (xs.setIfInBounds i a)[i]'h = a
Full source
@[simp] theorem getElem_setIfInBounds_self {xs : Array α} {i : Nat} {a : α} (h : i < (xs.setIfInBounds i a).size) :
    (xs.setIfInBounds i a)[i]'h = a := by
  simp at h
  simp only [setIfInBounds, h, ↓reduceDIte, getElem_set_self]
Array Self-Index Update Property: `(xs.setIfInBounds i a)[i] = a` when `i` is in bounds
Informal description
For any array `xs` of type `α`, index `i`, and element `a` of type `α`, if `i` is a valid index for the array obtained by setting the `i`-th element of `xs` to `a` (when `i` is within bounds), then the `i`-th element of the resulting array equals `a`. That is, `(xs.setIfInBounds i a)[i] = a` when `i < (xs.setIfInBounds i a).size`.
Array.getElem_setIfInBounds_eq abbrev
Full source
@[deprecated getElem_setIfInBounds_self (since := "2024-12-11")]
abbrev getElem_setIfInBounds_eq := @getElem_setIfInBounds_self
Array Equality after In-Bounds Update: `(xs.setIfInBounds i a)[j] = a` when `i = j` and `i < xs.size`
Informal description
For any array `xs` of type `Array α`, indices `i` and `j` of type `Nat`, and element `a` of type `α`, if `i = j` and `i < xs.size`, then the `j`-th element of the array obtained by setting the `i`-th element of `xs` to `a` (when `i` is within bounds) is equal to `a`. That is, `(xs.setIfInBounds i a)[j] = a` when `i = j` and `i < xs.size`.
Array.getElem_setIfInBounds_ne theorem
{xs : Array α} {i : Nat} {a : α} {j : Nat} (hj : j < xs.size) (h : i ≠ j) : (xs.setIfInBounds i a)[j]'(by simpa using hj) = xs[j]
Full source
@[simp] theorem getElem_setIfInBounds_ne {xs : Array α} {i : Nat} {a : α} {j : Nat}
    (hj : j < xs.size) (h : i ≠ j) :
    (xs.setIfInBounds i a)[j]'(by simpa using hj) = xs[j] := by
  simp [getElem_setIfInBounds, hj, h]
Array Element Preservation under Update at Different Index: $(xs[i \mapsto a])[j] = xs[j]$ when $i \neq j$
Informal description
For an array `xs` of type `Array α`, indices `i` and `j` with `j < xs.size`, and an element `a` of type `α`, if `i ≠ j`, then the element at index `j` of the array obtained by setting the `i`-th element of `xs` to `a` (if `i` is within bounds) is equal to `xs[j]`. That is, $(xs[i \mapsto a])[j] = xs[j]$ when $i \neq j$ and $j < \text{size}\ xs$.
Array.getElem?_setIfInBounds theorem
{xs : Array α} {i j : Nat} {a : α} : (xs.setIfInBounds i a)[j]? = if i = j then if i < xs.size then some a else none else xs[j]?
Full source
theorem getElem?_setIfInBounds {xs : Array α} {i j : Nat} {a : α}  :
    (xs.setIfInBounds i a)[j]? = if i = j then if i < xs.size then some a else none else xs[j]? := by
  cases xs
  simp [List.getElem?_set]
Conditional Array Update and Lookup: $(xs.\text{setIfInBounds}\ i\ a)[j]? = \text{if}\ i = j\ \text{then}\ (\text{if}\ i < \text{size}\ xs\ \text{then}\ \text{some}\ a\ \text{else}\ \text{none})\ \text{else}\ xs[j]?$
Informal description
For any array `xs` of type `Array α`, natural number indices `i` and `j`, and element `a` of type `α`, the optional lookup operation `(xs.setIfInBounds i a)[j]?` evaluates to: - `some a` if `i = j` and `i < xs.size`, - `none` if `i = j` and `i ≥ xs.size`, - `xs[j]?` otherwise (when `i ≠ j`).
Array.getElem?_setIfInBounds_self theorem
{xs : Array α} {i : Nat} {a : α} : (xs.setIfInBounds i a)[i]? = if i < xs.size then some a else none
Full source
theorem getElem?_setIfInBounds_self {xs : Array α} {i : Nat} {a : α} :
    (xs.setIfInBounds i a)[i]? = if i < xs.size then some a else none := by
  simp [getElem?_setIfInBounds]
Self-Index Lookup After Conditional Update: $(xs.\text{setIfInBounds}\ i\ a)[i]? = \text{if}\ i < \text{size}\ xs\ \text{then}\ \text{some}\ a\ \text{else}\ \text{none}$
Informal description
For any array `xs` of type `Array α`, natural number index `i`, and element `a` of type `α`, the optional lookup operation `(xs.setIfInBounds i a)[i]?` evaluates to: - `some a` if `i < xs.size`, - `none` otherwise.
Array.getElem?_setIfInBounds_self_of_lt theorem
{xs : Array α} {i : Nat} {a : α} (h : i < xs.size) : (xs.setIfInBounds i a)[i]? = some a
Full source
@[simp]
theorem getElem?_setIfInBounds_self_of_lt {xs : Array α} {i : Nat} {a : α} (h : i < xs.size) :
    (xs.setIfInBounds i a)[i]? = some a := by
  simp [getElem?_setIfInBounds, h]
Optional Lookup After In-Bounds Update Yields Updated Element: $(xs[i \leftarrow a])[i]? = \text{some}\ a$ when $i < \text{size}(xs)$
Informal description
For any array $xs$ of type $\text{Array}\ \alpha$, index $i$, and element $a$ of type $\alpha$, if $i$ is a valid index for $xs$ (i.e., $i < \text{size}(xs)$), then the optional lookup operation $(xs.\text{setIfInBounds}\ i\ a)[i]?$ returns $\text{some}\ a$.
Array.getElem?_setIfInBounds_eq abbrev
Full source
@[deprecated getElem?_setIfInBounds_self (since := "2024-12-11")]
abbrev getElem?_setIfInBounds_eq := @getElem?_setIfInBounds_self
Array Lookup After Update at Same Index: $(xs.\text{setIfInBounds}\ i\ a)[j]? = \text{if}\ i = j \text{ then } (\text{if}\ i < \text{size}\ xs\ \text{then}\ \text{some}\ a\ \text{else}\ \text{none})\ \text{else}\ xs[j]?$
Informal description
For any array `xs` of type `Array α`, indices `i` and `j` with `i = j`, and element `a` of type `α`, the optional lookup operation `(xs.setIfInBounds i a)[j]?` equals `some a` if `i < xs.size`, and equals `xs[j]?` otherwise.
Array.getElem?_setIfInBounds_ne theorem
{xs : Array α} {i j : Nat} (h : i ≠ j) {a : α} : (xs.setIfInBounds i a)[j]? = xs[j]?
Full source
@[simp] theorem getElem?_setIfInBounds_ne {xs : Array α} {i j : Nat} (h : i ≠ j) {a : α}  :
    (xs.setIfInBounds i a)[j]? = xs[j]? := by
  simp [getElem?_setIfInBounds, h]
Independent Array Update and Lookup: $(xs[i \leftarrow a])[j]? = xs[j]?$ for $i \neq j$
Informal description
For any array $xs$ of type $\text{Array}\ \alpha$, indices $i$ and $j$ with $i \neq j$, and element $a$ of type $\alpha$, the optional lookup operation $(xs.\text{setIfInBounds}\ i\ a)[j]?$ equals $xs[j]?$. That is, updating an array at index $i$ does not affect the optional lookup at a different index $j$.
Array.setIfInBounds_eq_of_size_le theorem
{xs : Array α} {i : Nat} (h : xs.size ≤ i) {a : α} : xs.setIfInBounds i a = xs
Full source
theorem setIfInBounds_eq_of_size_le {xs : Array α} {i : Nat} (h : xs.size ≤ i) {a : α} :
    xs.setIfInBounds i a = xs := by
  cases xs
  simp [List.set_eq_of_length_le (by simpa using h)]
Array Update at Out-of-Bounds Index Preserves Original Array
Informal description
For any array `xs` of type `Array α`, index `i`, and element `a`, if the size of `xs` is less than or equal to `i`, then updating `xs` at index `i` with `a` (if `i` is within bounds) leaves the array unchanged, i.e., `xs.setIfInBounds i a = xs`.
Array.setIfInBounds_eq_empty_iff theorem
{xs : Array α} {i : Nat} {a : α} : xs.setIfInBounds i a = #[] ↔ xs = #[]
Full source
@[simp] theorem setIfInBounds_eq_empty_iff {xs : Array α} {i : Nat} {a : α} :
    xs.setIfInBounds i a = #[] ↔ xs = #[] := by
  cases xs <;> cases i <;> simp
Empty Array Preservation Under Bounded Update: $xs[i \leftarrow a] = \#[] \leftrightarrow xs = \#[]$
Informal description
For any array `xs` of type `Array α`, index `i`, and element `a`, updating the array at index `i` with `a` (if `i` is within bounds) results in an empty array if and only if the original array `xs` was empty. In other words: $$xs.\text{setIfInBounds}\ i\ a = \#[] \leftrightarrow xs = \#[]$$
Array.setIfInBounds_comm theorem
(a b : α) {i j : Nat} {xs : Array α} (h : i ≠ j) : (xs.setIfInBounds i a).setIfInBounds j b = (xs.setIfInBounds j b).setIfInBounds i a
Full source
theorem setIfInBounds_comm (a b : α)
    {i j : Nat} {xs : Array α} (h : i ≠ j) :
    (xs.setIfInBounds i a).setIfInBounds j b = (xs.setIfInBounds j b).setIfInBounds i a := by
  cases xs
  simp [List.set_comm _ _ h]
Commutativity of Array Element Updates at Distinct Indices: $(xs[i \leftarrow a])[j \leftarrow b] = (xs[j \leftarrow b])[i \leftarrow a]$ for $i \neq j$
Informal description
For any array `xs` of type `Array α`, elements `a, b : α`, and distinct indices `i, j : Nat`, the following equality holds: $$(xs.\text{setIfInBounds}\ i\ a).\text{setIfInBounds}\ j\ b = (xs.\text{setIfInBounds}\ j\ b).\text{setIfInBounds}\ i\ a.$$ Here, `setIfInBounds` updates the array at the given index if it is within bounds, otherwise leaves the array unchanged.
Array.setIfInBounds_setIfInBounds theorem
(a : α) {b : α} {xs : Array α} {i : Nat} : (xs.setIfInBounds i a).setIfInBounds i b = xs.setIfInBounds i b
Full source
@[simp]
theorem setIfInBounds_setIfInBounds (a : α) {b : α} {xs : Array α} {i : Nat} :
    (xs.setIfInBounds i a).setIfInBounds i b = xs.setIfInBounds i b := by
  cases xs
  simp
Idempotence of Sequential Array Updates at the Same Index: $(xs[i \leftarrow a])[i \leftarrow b] = xs[i \leftarrow b]$
Informal description
For any array `xs` of type `Array α`, elements `a, b : α`, and index `i : Nat`, updating the array at index `i` first with `a` and then with `b` is equivalent to updating it directly with `b`. That is, $$(xs.\text{setIfInBounds}\ i\ a).\text{setIfInBounds}\ i\ b = xs.\text{setIfInBounds}\ i\ b.$$ Here, `setIfInBounds` updates the array at the given index if it is within bounds, otherwise leaves the array unchanged.
Array.mem_setIfInBounds theorem
{xs : Array α} {i : Nat} {a : α} (h : i < xs.size) : a ∈ xs.setIfInBounds i a
Full source
theorem mem_setIfInBounds {xs : Array α} {i : Nat} {a : α} (h : i < xs.size) :
    a ∈ xs.setIfInBounds i a := by
  simp [mem_iff_getElem]
  exact ⟨i, (by simpa using h), by simp⟩
Element Membership after Array Update: $a \in \text{setIfInBounds}(xs, i, a)$ when $i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α`, index `i`, and element `a` of type `α`, if `i` is a valid index for `xs` (i.e., `i < xs.size`), then `a` is an element of the array obtained by setting the `i`-th element of `xs` to `a`. In other words, `a ∈ xs.setIfInBounds i a` when `i < xs.size`.
Array.mem_or_eq_of_mem_setIfInBounds theorem
{xs : Array α} {i : Nat} {a b : α} (h : a ∈ xs.setIfInBounds i b) : a ∈ xs ∨ a = b
Full source
theorem mem_or_eq_of_mem_setIfInBounds
    {xs : Array α} {i : Nat} {a b : α} (h : a ∈ xs.setIfInBounds i b) : a ∈ xsa ∈ xs ∨ a = b := by
  cases xs
  simpa using List.mem_or_eq_of_mem_set (by simpa using h)
Element Membership in Modified Array: $a \in \text{setIfInBounds}(xs, i, b) \implies a \in xs \lor a = b$
Informal description
For any array `xs` of type `α`, natural number index `i`, and elements `a, b : α`, if `a` is an element of the array obtained by setting the `i`-th element of `xs` to `b` (when `i` is within bounds), then either `a` was already an element of `xs` or `a` is equal to `b`.
Array.getD_get?_setIfInBounds theorem
{xs : Array α} {i : Nat} {v d : α} : (xs.setIfInBounds i v)[i]?.getD d = if i < xs.size then v else d
Full source
/-- Simplifies a normal form from `get!` -/
@[simp] theorem getD_get?_setIfInBounds {xs : Array α} {i : Nat} {v d : α} :
    (xs.setIfInBounds i v)[i]?.getD d = if i < xs.size then v else d := by
  by_cases h : i < xs.size <;>
    simp [setIfInBounds, Nat.not_lt_of_le, h,  getD_getElem?]
Default Value for Optional Access in Modified Array: $(xs.\text{setIfInBounds}\ i\ v)[i]?.getD\ d = \begin{cases} v & \text{if } i < \text{size}(xs) \\ d & \text{otherwise} \end{cases}$
Informal description
For any array `xs` of type `Array α`, natural number index `i`, and elements `v, d : α`, the expression `(xs.setIfInBounds i v)[i]?.getD d` evaluates to `v` if `i` is a valid index (i.e., `i < xs.size`), and to `d` otherwise.
Array.toList_setIfInBounds theorem
{xs : Array α} {i : Nat} {x : α} : (xs.setIfInBounds i x).toList = xs.toList.set i x
Full source
@[simp] theorem toList_setIfInBounds {xs : Array α} {i : Nat} {x : α} :
    (xs.setIfInBounds i x).toList = xs.toList.set i x := by
  simp only [setIfInBounds]
  split <;> rename_i h
  · simp
  · simp [List.set_eq_of_length_le (by simpa using h)]
List Representation Preserves Array Modification: `(xs.setIfInBounds i x).toList = xs.toList.set i x`
Informal description
For any array `xs` of elements of type `α`, natural number index `i`, and element `x : α`, converting the array `xs.setIfInBounds i x` to a list yields the same result as converting `xs` to a list and then replacing the element at position `i` with `x`. In other words, the list representation of the modified array is equal to the modified list representation of the original array.
Array.beq_empty_iff theorem
[BEq α] {xs : Array α} : (xs == #[]) = xs.isEmpty
Full source
@[simp] theorem beq_empty_iff [BEq α] {xs : Array α} : (xs == #[]) = xs.isEmpty := by
  cases xs
  simp
Empty Array Boolean Equality Characterization: `xs == #[] ↔ xs.isEmpty`
Informal description
For any array `xs` of elements of type `α` with a boolean equality relation, the boolean equality `xs == #[]` (comparing `xs` to the empty array) is equal to the boolean value `xs.isEmpty` (checking if `xs` is empty).
Array.empty_beq_iff theorem
[BEq α] {xs : Array α} : (#[] == xs) = xs.isEmpty
Full source
@[simp] theorem empty_beq_iff [BEq α] {xs : Array α} : (#[] == xs) = xs.isEmpty := by
  cases xs
  simp
Empty Array Boolean Equality iff Array is Empty
Informal description
For any array `xs` of elements of type `α` with a boolean equality relation `==`, the boolean equality between the empty array `#[]` and `xs` is equivalent to `xs` being empty, i.e., `#[] == xs ↔ xs.isEmpty`.
Array.push_beq_push theorem
[BEq α] {a b : α} {xs ys : Array α} : (xs.push a == ys.push b) = (xs == ys && a == b)
Full source
@[simp] theorem push_beq_push [BEq α] {a b : α} {xs ys : Array α} :
    (xs.push a == ys.push b) = (xs == ys && a == b) := by
  cases xs
  cases ys
  simp
Boolean Equality Preservation under Array Push: $(xs.push(a) == ys.push(b)) = (xs == ys \land a == b)$
Informal description
For any type $\alpha$ with a boolean equality relation `==`, and for any elements $a, b \in \alpha$ and arrays $xs, ys \in \text{Array } \alpha$, the boolean equality of the arrays after pushing $a$ to $xs$ and $b$ to $ys$ is equivalent to the conjunction of the boolean equality of the original arrays and the boolean equality of the pushed elements. That is: $$(xs.\text{push}(a) == ys.\text{push}(b)) = (xs == ys \land a == b)$$
Array.size_eq_of_beq theorem
[BEq α] {xs ys : Array α} (h : xs == ys) : xs.size = ys.size
Full source
theorem size_eq_of_beq [BEq α] {xs ys : Array α} (h : xs == ys) : xs.size = ys.size := by
  cases xs
  cases ys
  simp [List.length_eq_of_beq (by simpa using h)]
Equal Arrays Have Equal Sizes
Informal description
For any type $\alpha$ with a boolean equality relation `==`, and for any two arrays `xs` and `ys` of type `Array α`, if `xs == ys` holds, then the sizes of `xs` and `ys` are equal, i.e., `xs.size = ys.size`.
Array.replicate_beq_replicate theorem
[BEq α] {a b : α} {n : Nat} : (replicate n a == replicate n b) = (n == 0 || a == b)
Full source
@[simp] theorem replicate_beq_replicate [BEq α] {a b : α} {n : Nat} :
    (replicate n a == replicate n b) = (n == 0 || a == b) := by
  cases n with
  | zero => simp
  | succ n =>
    rw [replicate_succ, replicate_succ, push_beq_push, replicate_beq_replicate]
    rw [Bool.eq_iff_iff]
    simp +contextual
Boolean Equality of Replicated Arrays: $\text{replicate}(n, a) == \text{replicate}(n, b) \leftrightarrow (n = 0 \lor a == b)$
Informal description
For any type $\alpha$ with a boolean equality relation `==`, and for any elements $a, b \in \alpha$ and natural number $n$, the boolean equality of two arrays created by replicating $a$ and $b$ $n$ times respectively is equivalent to the disjunction that $n$ is zero or $a$ is equal to $b$. That is: $$(\text{replicate}(n, a) == \text{replicate}(n, b)) = (n = 0 \lor a == b)$$
Array.mkArray_beq_mkArray abbrev
Full source
@[deprecated replicate_beq_replicate (since := "2025-03-18")]
abbrev mkArray_beq_mkArray := @replicate_beq_replicate
Boolean Equality of Arrays Created by `mkArray`: $\text{mkArray}(n, a) == \text{mkArray}(n, b) \leftrightarrow (n = 0 \lor a == b)$
Informal description
For any type $\alpha$ with a boolean equality relation `==`, and for any natural number $n$ and elements $a, b \in \alpha$, the boolean equality of two arrays created by `mkArray n a` and `mkArray n b` is equivalent to the disjunction that $n$ is zero or $a$ is equal to $b$. That is: $$(\text{mkArray}(n, a) == \text{mkArray}(n, b)) = (n = 0 \lor a == b)$$
Array.reflBEq_iff theorem
[BEq α] : ReflBEq (Array α) ↔ ReflBEq α
Full source
@[simp] theorem reflBEq_iff [BEq α] : ReflBEqReflBEq (Array α) ↔ ReflBEq α := by
  constructor
  · intro h
    constructor
    intro a
    apply beq_of_beq_singleton
    simp
  · intro h
    constructor
    apply Array.isEqv_self_beq
Reflexive Boolean Equality for Arrays iff Reflexive for Elements
Informal description
For any type $\alpha$ with a boolean equality relation `==`, the reflexive boolean equality property holds for arrays of type `Array α` if and only if it holds for the elements of type $\alpha$ themselves. In other words, `ReflBEq (Array α) ↔ ReflBEq α`.
Array.lawfulBEq_iff theorem
[BEq α] : LawfulBEq (Array α) ↔ LawfulBEq α
Full source
@[simp] theorem lawfulBEq_iff [BEq α] : LawfulBEqLawfulBEq (Array α) ↔ LawfulBEq α := by
  constructor
  · intro h
    constructor
    · intro a b h
      apply singleton_inj.1
      apply eq_of_beq
      simpa [instBEq, isEqv, isEqvAux]
    · intro a
      apply beq_of_beq_singleton
      simp
  · intro h
    constructor
    · intro xs ys h
      obtain ⟨hs, hi⟩ := isEqv_iff_rel.mp h
      ext i h₁ h₂
      · exact hs
      · simpa using hi _ h₁
    · intro xs
      apply Array.isEqv_self_beq
Lawful Boolean Equality for Arrays iff Lawful for Elements
Informal description
For any type $\alpha$ with a boolean equality relation `==`, the boolean equality relation on arrays of type `Array α` is lawful (i.e., agrees with propositional equality) if and only if the boolean equality relation on $\alpha$ itself is lawful.
Array.isEqv_eq theorem
[DecidableEq α] {xs ys : Array α} : xs.isEqv ys (· == ·) = (xs = ys)
Full source
@[simp] theorem isEqv_eq [DecidableEq α] {xs ys : Array α} : xs.isEqv ys (· == ·) = (xs = ys) := by
  cases xs
  cases ys
  simp
Array Equivalence Check Equals Equality for Decidable Types
Informal description
For any two arrays `xs` and `ys` of type `Array α` where `α` has decidable equality, the boolean equivalence check `xs.isEqv ys (· == ·)` (using the boolean equality operator `==`) is equivalent to the proposition that `xs` and `ys` are equal as arrays (i.e., `xs = ys`).
Array.back_eq_getElem theorem
{xs : Array α} (h : 0 < xs.size) : xs.back = xs[xs.size - 1]
Full source
theorem back_eq_getElem {xs : Array α} (h : 0 < xs.size) : xs.back = xs[xs.size - 1] := by
  cases xs
  simp [List.getLast_eq_getElem]
Last Element Equals Access at Size Minus One in Non-Empty Arrays
Informal description
For any non-empty array `xs` of type `Array α` (i.e., where the size `xs.size > 0`), the last element `xs.back` is equal to the element at index `xs.size - 1`.
Array.back?_eq_getElem? theorem
{xs : Array α} : xs.back? = xs[xs.size - 1]?
Full source
theorem back?_eq_getElem? {xs : Array α} : xs.back? = xs[xs.size - 1]? := by
  cases xs
  simp [List.getLast?_eq_getElem?]
Equivalence of Back Element and Last Index Access in Arrays
Informal description
For any array `xs` of type `Array α`, the optional last element `xs.back?` is equal to the optional element obtained by indexing at position `xs.size - 1`, i.e., `xs[xs.size - 1]?`.
Array.back_mem theorem
{xs : Array α} (h : 0 < xs.size) : xs.back h ∈ xs
Full source
@[simp] theorem back_mem {xs : Array α} (h : 0 < xs.size) : xs.back h ∈ xs := by
  cases xs
  simp
Last Element Belongs to Non-Empty Array
Informal description
For any non-empty array `xs` of type `α` (i.e., where the size `xs.size` is greater than 0), the last element `xs.back` is a member of the array `xs`.
Array.mapM_eq_foldlM theorem
[Monad m] [LawfulMonad m] {f : α → m β} {xs : Array α} : xs.mapM f = xs.foldlM (fun bs a => bs.push <$> f a) #[]
Full source
theorem mapM_eq_foldlM [Monad m] [LawfulMonad m] {f : α → m β} {xs : Array α} :
    xs.mapM f = xs.foldlM (fun bs a => bs.push <$> f a) #[] := by
  rw [mapM, aux, ← foldlM_toList]; rfl
where
  aux (i bs) :
      mapM.map f xs i bs = (xs.toList.drop i).foldlM (fun bs a => bs.push <$> f a) bs := by
    unfold mapM.map; split
    · rw [← List.getElem_cons_drop_succ_eq_drop ‹_›]
      simp only [aux (i + 1), map_eq_pure_bind, length_toList, List.foldlM_cons, bind_assoc,
        pure_bind]
      rfl
    · rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
  termination_by xs.size - i
  decreasing_by decreasing_trivial_pre_omega
Monadic Map Equals Left-Fold Monadic Operation on Arrays
Informal description
For any monad `m` that is a lawful monad, any function `f : α → m β`, and any array `xs : Array α`, the monadic map operation `xs.mapM f` is equal to the left-fold monadic operation `xs.foldlM (fun bs a => bs.push <$> f a) #[]`. Here, `#[]` denotes an empty array, and `<$>` is the infix notation for `Functor.map`.
Array.toList_map theorem
{f : α → β} {xs : Array α} : (xs.map f).toList = xs.toList.map f
Full source
@[simp] theorem toList_map {f : α → β} {xs : Array α} : (xs.map f).toList = xs.toList.map f := by
  rw [map, mapM_eq_foldlM]
  apply congrArg toList (foldl_toList fun bs a => push bs (f a)).symm |>.trans
  have H (l xs) : List.foldl (fun bs a => push bs (f a)) xs l = ⟨xs.toList ++ l.map f⟩ := by
    induction l generalizing xs <;> simp [*]
  simp [H]
List Conversion Commutes with Array Mapping: $(xs.map f).toList = xs.toList.map f$
Informal description
For any function $f : \alpha \to \beta$ and any array $xs$ of type $\text{Array }\alpha$, converting the mapped array $xs.map f$ to a list is equivalent to converting $xs$ to a list and then mapping $f$ over it. That is, $(xs.map f).toList = xs.toList.map f$.
List.map_toArray theorem
{f : α → β} {l : List α} : l.toArray.map f = (l.map f).toArray
Full source
@[simp] theorem _root_.List.map_toArray {f : α → β} {l : List α} :
    l.toArray.map f = (l.map f).toArray := by
  apply ext'
  simp
Array Mapping Commutes with List-to-Array Conversion: $l.toArray.map f = (l.map f).toArray$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, mapping $f$ over the array obtained from $l$ is equal to the array obtained from the list $l.map f$. That is, $l.toArray.map f = (l.map f).toArray$.
Array.size_map theorem
{f : α → β} {xs : Array α} : (xs.map f).size = xs.size
Full source
@[simp] theorem size_map {f : α → β} {xs : Array α} : (xs.map f).size = xs.size := by
  simp only [← length_toList]
  simp
Array Mapping Preserves Size: $\text{size}(xs.map f) = \text{size}(xs)$
Informal description
For any function $f : \alpha \to \beta$ and any array $xs$ of type $\text{Array }\alpha$, the size of the mapped array $xs.map f$ is equal to the size of the original array $xs$. That is, $(xs.map f).\text{size} = xs.\text{size}$.
Array.getElem_map theorem
(f : α → β) {xs : Array α} {i : Nat} (hi : i < (xs.map f).size) : (xs.map f)[i] = f (xs[i]'(by simpa using hi))
Full source
@[simp] theorem getElem_map (f : α → β) {xs : Array α} {i : Nat} (hi : i < (xs.map f).size) :
    (xs.map f)[i] = f (xs[i]'(by simpa using hi)) := by
  cases xs
  simp
Element-wise Mapping of Arrays: $(xs.map f)[i] = f(xs[i])$
Informal description
For any function $f : \alpha \to \beta$, array $xs$ of type $\text{Array }\alpha$, and natural number index $i$ such that $i < (xs.map f).\text{size}$, the element at index $i$ in the mapped array $xs.map f$ is equal to $f$ applied to the element at index $i$ in the original array $xs$. That is, $(xs.map f)[i] = f(xs[i])$.
Array.getElem?_map theorem
{f : α → β} {xs : Array α} {i : Nat} : (xs.map f)[i]? = xs[i]?.map f
Full source
@[simp] theorem getElem?_map {f : α → β} {xs : Array α} {i : Nat} :
    (xs.map f)[i]? = xs[i]?.map f := by
  simp [getElem?_def]
Optional Element-wise Mapping of Arrays: $(xs.map f)[i]? = f(xs[i]?)$
Informal description
For any function $f : \alpha \to \beta$, array $xs$ of type $\text{Array }\alpha$, and natural number index $i$, the optional element at index $i$ in the mapped array $xs.map f$ is equal to the optional result of applying $f$ to the element at index $i$ in the original array $xs$. That is, $(xs.map f)[i]? = \text{Option.map } f (xs[i]?)$.
Array.mapM_empty theorem
[Monad m] (f : α → m β) : mapM f #[] = pure #[]
Full source
@[simp] theorem mapM_empty [Monad m] (f : α → m β) : mapM f #[] = pure #[] := by
  rw [mapM, mapM.map]; rfl
Monadic Map of Empty Array Yields Pure Empty Array
Informal description
For any monad $m$ and any function $f : \alpha \to m \beta$, applying the monadic map operation `mapM` to the empty array `#[]` with function $f$ results in the pure empty array in the monad $m$, i.e., $\text{mapM}\ f\ \text{#[]} = \text{pure}\ \text{#[]}$.
Array.map_empty theorem
{f : α → β} : map f #[] = #[]
Full source
@[simp] theorem map_empty {f : α → β} : map f #[] = #[] := mapM_empty f
Mapping Over Empty Array Yields Empty Array
Informal description
For any function $f : \alpha \to \beta$, applying the `map` operation to the empty array `#[]` results in the empty array `#[]`, i.e., $\text{map}\ f\ \text{#[]} = \text{#[]}$.
Array.map_push theorem
{f : α → β} {as : Array α} {x : α} : (as.push x).map f = (as.map f).push (f x)
Full source
@[simp] theorem map_push {f : α → β} {as : Array α} {x : α} :
    (as.push x).map f = (as.map f).push (f x) := by
  ext
  · simp
  · simp only [getElem_map, getElem_push, size_map]
    split <;> rfl
Push-Map Commutativity: $(as.push\ x).map\ f = (as.map\ f).push\ (f\ x)$
Informal description
For any function $f : \alpha \to \beta$, array $as$ of type $\text{Array }\alpha$, and element $x : \alpha$, the mapping of $f$ over the array $as.push\ x$ is equal to pushing $f(x)$ onto the array obtained by mapping $f$ over $as$. That is: $$(as.push\ x).map\ f = (as.map\ f).push\ (f\ x)$$
Array.map_id_fun theorem
: map (id : α → α) = id
Full source
@[simp] theorem map_id_fun : map (id : α → α) = id := by
  funext xs
  induction xs <;> simp_all
Identity Mapping Preserves Array Identity: $\text{map}(\text{id}) = \text{id}$
Informal description
The map operation with the identity function `id` is equal to the identity function on arrays, i.e., $\text{map}(\text{id}) = \text{id}$.
Array.map_id_fun' theorem
: map (fun (a : α) => a) = id
Full source
/-- `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 (fun (a : α) => a) = id := map_id_fun
Identity Mapping with Lambda Preserves Array Identity: $\text{map}(\lambda a, a) = \text{id}$
Informal description
The map operation on arrays with the identity function (represented as $\lambda a, a$) is equal to the identity function on arrays, i.e., $\text{map}(\lambda a, a) = \text{id}$.
Array.map_id theorem
(xs : Array α) : map (id : α → α) xs = xs
Full source
theorem map_id (xs : Array α) : map (id : α → α) xs = xs := by
  cases xs <;> simp_all
Identity Mapping Preserves Array: `map id xs = xs`
Informal description
For any array `xs` of elements of type `α`, applying the identity function `id` to each element of `xs` via the `map` operation results in `xs` itself, i.e., `map id xs = xs`.
Array.map_id' theorem
(xs : Array α) : map (fun (a : α) => a) xs = xs
Full source
/-- `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.
-- The argument `xs : Array α` is explicit to allow rewriting from right to left.
theorem map_id' (xs : Array α) : map (fun (a : α) => a) xs = xs := map_id xs
Identity Mapping Preserves Array (Lambda Form)
Informal description
For any array `xs` of elements of type `α`, applying the identity function (represented as `fun (a : α) => a`) to each element of `xs` via the `map` operation results in `xs` itself, i.e., `map (fun a => a) xs = xs`.
Array.map_id'' theorem
{f : α → α} (h : ∀ x, f x = x) (xs : Array α) : map f xs = xs
Full source
/-- Variant of `map_id`, with a side condition that the function is pointwise the identity. -/
-- The argument `xs : Array α` is explicit to allow rewriting from right to left.
theorem map_id'' {f : α → α} (h : ∀ x, f x = x) (xs : Array α) : map f xs = xs := by
  simp [show f = id from funext h]
Identity-Preserving Map on Arrays: $\text{map}\, f\, xs = xs$ when $f(x) = x$ for all $x$
Informal description
For any function $f : \alpha \to \alpha$ satisfying $f(x) = x$ for all $x \in \alpha$, and for any array $xs$ of elements of type $\alpha$, the mapped array $\text{map}\, f\, xs$ is equal to $xs$.
Array.map_singleton theorem
{f : α → β} {a : α} : map f #[a] = #[f a]
Full source
theorem map_singleton {f : α → β} {a : α} : map f #[a] = #[f a] := by simp
Mapping Preserves Singleton Arrays: $\text{map } f \ [a] = [f(a)]$
Informal description
For any function $f : \alpha \to \beta$ and any element $a \in \alpha$, mapping $f$ over the singleton array $[a]$ yields the singleton array $[f(a)]$. That is, $\text{map } f \ [a] = [f(a)]$.
Array.mem_map theorem
{f : α → β} {xs : Array α} : b ∈ xs.map f ↔ ∃ a, a ∈ xs ∧ f a = b
Full source
@[simp 500] theorem mem_map {f : α → β} {xs : Array α} : b ∈ xs.map fb ∈ xs.map f ↔ ∃ a, a ∈ xs ∧ f a = b := by
  simp only [mem_def, toList_map, List.mem_map]
Membership in Mapped Array: $b \in \text{map } f \ xs \leftrightarrow \exists a \in xs, f(a) = b$
Informal description
For any function $f : \alpha \to \beta$ and any array $xs$ of type $\text{Array }\alpha$, an element $b$ is in the mapped array $xs.map f$ if and only if there exists an element $a \in xs$ such that $f(a) = b$. In other words: $$b \in \text{map } f \ xs \leftrightarrow \exists a \in xs, f(a) = b$$
Array.exists_of_mem_map theorem
(h : b ∈ map f l) : ∃ a, a ∈ l ∧ f a = b
Full source
theorem exists_of_mem_map (h : b ∈ map f l) : ∃ a, a ∈ l ∧ f a = b := mem_map.1 h
Existence of Preimage in Mapped Array: $b \in \text{map}\ f\ l \implies \exists a \in l, f(a) = b$
Informal description
For any function $f : \alpha \to \beta$, array $l$ of type $\text{Array}\ \alpha$, and element $b \in \beta$, if $b$ is in the mapped array $\text{map}\ f\ l$, then there exists an element $a \in l$ such that $f(a) = b$.
Array.mem_map_of_mem theorem
{f : α → β} (h : a ∈ l) : f a ∈ map f l
Full source
theorem mem_map_of_mem {f : α → β} (h : a ∈ l) : f a ∈ map f l := mem_map.2 ⟨_, h, rfl⟩
Image of Array Element under Mapping Belongs to Mapped Array
Informal description
For any function $f : \alpha \to \beta$ and array $l$ of type $\text{Array }\alpha$, if an element $a$ is in $l$, then $f(a)$ is in the mapped array $\text{map } f \ l$.
Array.forall_mem_map theorem
{f : α → β} {xs : Array α} {P : β → Prop} : (∀ (i) (_ : i ∈ xs.map f), P i) ↔ ∀ (j) (_ : j ∈ xs), P (f j)
Full source
theorem forall_mem_map {f : α → β} {xs : Array α} {P : β → Prop} :
    (∀ (i) (_ : i ∈ xs.map f), P i) ↔ ∀ (j) (_ : j ∈ xs), P (f j) := by
  simp
Universal Quantification over Mapped Array Elements vs Original Array Elements
Informal description
For any function $f : \alpha \to \beta$, array $xs$ of type $\text{Array}\ \alpha$, and predicate $P : \beta \to \text{Prop}$, the following are equivalent: 1. For every element $i$ in the mapped array $\text{map}\ f\ xs$, the proposition $P(i)$ holds. 2. For every element $j$ in the original array $xs$, the proposition $P(f(j))$ holds.
Array.map_eq_empty_iff theorem
{f : α → β} {xs : Array α} : map f xs = #[] ↔ xs = #[]
Full source
@[simp] theorem map_eq_empty_iff {f : α → β} {xs : Array α} : mapmap f xs = #[] ↔ xs = #[] := by
  cases xs
  simp
Mapped Array is Empty iff Original Array is Empty
Informal description
For any function $f : \alpha \to \beta$ and any array $xs$ of type $\text{Array}\ \alpha$, the mapped array $\text{map}\ f\ xs$ is empty if and only if the original array $xs$ is empty. In other words, $\text{map}\ f\ xs = \#[] \leftrightarrow xs = \#[]$.
Array.map_inj_left theorem
{f g : α → β} : map f xs = map g xs ↔ ∀ a ∈ xs, f a = g a
Full source
@[simp] theorem map_inj_left {f g : α → β} : mapmap f xs = map g xs ↔ ∀ a ∈ xs, f a = g a := by
  cases xs <;> simp_all
Equality of Mapped Arrays via Pointwise Function Equality: $map\ f\ xs = map\ g\ xs \leftrightarrow \forall a \in xs, f(a) = g(a)$
Informal description
For any functions $f, g : \alpha \to \beta$ and array $xs$ of elements of type $\alpha$, the mapped arrays $map\ f\ xs$ and $map\ g\ xs$ are equal if and only if $f(a) = g(a)$ for every element $a$ in $xs$.
Array.map_inj_right theorem
{f : α → β} (w : ∀ x y, f x = f y → x = y) : map f xs = map f ys ↔ xs = ys
Full source
theorem map_inj_right {f : α → β} (w : ∀ x y, f x = f y → x = y) : mapmap f xs = map f ys ↔ xs = ys := by
  cases xs
  cases ys
  simp [List.map_inj_right w]
Injectivity of Array Mapping: $\text{map}\ f\ xs = \text{map}\ f\ ys \leftrightarrow xs = ys$ for Injective $f$
Informal description
For any injective function $f : \alpha \to \beta$ (i.e., $f(x) = f(y)$ implies $x = y$ for all $x, y \in \alpha$), and for any arrays $xs$ and $ys$ of elements of type $\alpha$, the mapped arrays $\text{map}\ f\ xs$ and $\text{map}\ f\ ys$ are equal if and only if the original arrays $xs$ and $ys$ are equal.
Array.map_congr_left theorem
(h : ∀ a ∈ xs, f a = g a) : map f xs = map g xs
Full source
theorem map_congr_left (h : ∀ a ∈ xs, f a = g a) : map f xs = map g xs :=
  map_inj_left.2 h
Equality of Mapped Arrays under Pointwise Function Equality
Informal description
For any functions $f, g : \alpha \to \beta$ and array $xs$ of elements of type $\alpha$, if $f(a) = g(a)$ for every element $a$ in $xs$, then the mapped arrays $\text{map}\,f\,xs$ and $\text{map}\,g\,xs$ are equal.
Array.map_inj theorem
: map f = map g ↔ f = g
Full source
theorem map_inj : mapmap f = map g ↔ f = g := by
  constructor
  · intro h; ext a; replace h := congrFun h #[a]; simpa using h
  · intro h; subst h; rfl
Injectivity of Array Mapping: $\text{map}\,f = \text{map}\,g \leftrightarrow f = g$
Informal description
For any functions $f, g : \alpha \to \beta$, the array mapping operations $\text{map}\,f$ and $\text{map}\,g$ are equal if and only if the functions $f$ and $g$ are equal. That is, $\text{map}\,f = \text{map}\,g \leftrightarrow f = g$.
Array.map_eq_push_iff theorem
{f : α → β} {xs : Array α} {ys : Array β} {b : β} : map f xs = ys.push b ↔ ∃ zs a, xs = zs.push a ∧ map f zs = ys ∧ f a = b
Full source
theorem map_eq_push_iff {f : α → β} {xs : Array α} {ys : Array β} {b : β} :
    mapmap f xs = ys.push b ↔ ∃ zs a, xs = zs.push a ∧ map f zs = ys ∧ f a = b := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp only [List.map_toArray, List.push_toArray, mk.injEq, List.map_eq_append_iff]
  constructor
  · rintro ⟨l₁, l₂, rfl, rfl, h⟩
    simp only [List.map_eq_singleton_iff] at h
    obtain ⟨a, rfl, rfl⟩ := h
    refine ⟨l₁.toArray, a, by simp⟩
  · rintro ⟨⟨l₁⟩, a, h₁, h₂, rfl⟩
    refine ⟨l₁, [a], by simp_all⟩
Characterization of Mapped Array as Pushed Element: $\text{map } f\ xs = ys.\text{push } b$ iff $xs$ is a push and $f$ preserves structure
Informal description
For any function $f : \alpha \to \beta$, array $xs$ of type $\text{Array } \alpha$, array $ys$ of type $\text{Array } \beta$, and element $b \in \beta$, the following equivalence holds: \[ \text{map } f\ xs = ys.\text{push } b \leftrightarrow \exists zs\ a,\ (xs = zs.\text{push } a) \land (\text{map } f\ zs = ys) \land (f\ a = b) \]
Array.map_eq_singleton_iff theorem
{f : α → β} {xs : Array α} {b : β} : map f xs = #[b] ↔ ∃ a, xs = #[a] ∧ f a = b
Full source
@[simp] theorem map_eq_singleton_iff {f : α → β} {xs : Array α} {b : β} :
    mapmap f xs = #[b] ↔ ∃ a, xs = #[a] ∧ f a = b := by
  cases xs
  simp
Singleton Array Mapping Equivalence: $map\ f\ xs = #[b] \leftrightarrow \exists a, xs = #[a] \land f(a) = b$
Informal description
For any function $f : \alpha \to \beta$, array $xs$ of type $\alpha$, and element $b$ of type $\beta$, the mapped array $map\ f\ xs$ equals the singleton array $#[b]$ if and only if there exists an element $a$ such that $xs$ is the singleton array $#[a]$ and $f(a) = b$.
Array.map_eq_map_iff theorem
{f g : α → β} {xs : Array α} : map f xs = map g xs ↔ ∀ a ∈ xs, f a = g a
Full source
theorem map_eq_map_iff {f g : α → β} {xs : Array α} :
    mapmap f xs = map g xs ↔ ∀ a ∈ xs, f a = g a := by
  cases xs <;> simp_all
Equality of Array Maps: $\text{map } f \ xs = \text{map } g \ xs \leftrightarrow \forall a \in xs, f(a) = g(a)$
Informal description
For any functions $f, g : \alpha \to \beta$ and any array $xs$ of type $\text{Array } \alpha$, the mapped arrays $\text{map } f \ xs$ and $\text{map } g \ xs$ are equal if and only if for every element $a$ in $xs$, $f(a) = g(a)$.
Array.map_eq_iff theorem
{f : α → β} {xs : Array α} {ys : Array β} : map f xs = ys ↔ ∀ i : Nat, ys[i]? = xs[i]?.map f
Full source
theorem map_eq_iff {f : α → β} {xs : Array α} {ys : Array β} :
    mapmap f xs = ys ↔ ∀ i : Nat, ys[i]? = xs[i]?.map f := by
  cases xs
  cases ys
  simp [List.map_eq_iff]
Characterization of Array Mapping: $\text{map } f \ xs = ys \leftrightarrow \forall i, ys[i]? = f \circ xs[i]?$
Informal description
For any function $f : \alpha \to \beta$, array $xs$ of type $\text{Array } \alpha$, and array $ys$ of type $\text{Array } \beta$, the equality $\text{map } f \ xs = ys$ holds if and only if for every natural number index $i$, the optional element $ys[i]?$ is equal to $\text{map } f$ applied to the optional element $xs[i]?$.
Array.map_eq_foldl theorem
{f : α → β} {xs : Array α} : map f xs = foldl (fun bs a => bs.push (f a)) #[] xs
Full source
theorem map_eq_foldl {f : α → β} {xs : Array α} :
    map f xs = foldl (fun bs a => bs.push (f a)) #[] xs := by
  simpa using mapM_eq_foldlM
Map Equals Left-Fold on Arrays
Informal description
For any function $f : \alpha \to \beta$ and any array $xs$ of type $\text{Array } \alpha$, the map operation $\text{map } f \ xs$ is equal to the left-fold operation $\text{foldl } (\lambda bs \ a, \text{bs.push } (f \ a)) \ \#[] \ xs$, where $\#[]$ denotes an empty array.
Array.map_set theorem
{f : α → β} {xs : Array α} {i : Nat} {h : i < xs.size} {a : α} : (xs.set i a).map f = (xs.map f).set i (f a) (by simpa using h)
Full source
@[simp] theorem map_set {f : α → β} {xs : Array α} {i : Nat} {h : i < xs.size} {a : α} :
    (xs.set i a).map f = (xs.map f).set i (f a) (by simpa using h) := by
  cases xs
  simp
Commutativity of Array Mapping and Element Setting: $(xs.\text{set}\ i\ a).\text{map}\ f = (xs.\text{map}\ f).\text{set}\ i\ (f\ a)$
Informal description
For any function $f : \alpha \to \beta$, array $xs$ of type $\text{Array }\alpha$, index $i \in \mathbb{N}$ with $i < \text{size}(xs)$, and element $a \in \alpha$, the following equality holds: $$(xs.\text{set}\ i\ a).\text{map}\ f = (xs.\text{map}\ f).\text{set}\ i\ (f\ a)$$
Array.map_setIfInBounds theorem
{f : α → β} {xs : Array α} {i : Nat} {a : α} : (xs.setIfInBounds i a).map f = (xs.map f).setIfInBounds i (f a)
Full source
@[simp] theorem map_setIfInBounds {f : α → β} {xs : Array α} {i : Nat} {a : α} :
    (xs.setIfInBounds i a).map f = (xs.map f).setIfInBounds i (f a) := by
  cases xs
  simp
Commutativity of Map and Conditional Set in Arrays: $(xs.\text{setIfInBounds}\ i\ a).\text{map}\ f = (xs.\text{map}\ f).\text{setIfInBounds}\ i\ (f\ a)$
Informal description
For any function $f : \alpha \to \beta$, any array $xs$ of type $\text{Array } \alpha$, any natural number index $i$, and any element $a$ of type $\alpha$, the following equality holds: $$(xs.\text{setIfInBounds}\ i\ a).\text{map}\ f = (xs.\text{map}\ f).\text{setIfInBounds}\ i\ (f\ a)$$ where $\text{setIfInBounds}$ conditionally sets the element at index $i$ if $i$ is within bounds, and $\text{map}$ applies $f$ to each element of the array.
Array.map_pop theorem
{f : α → β} {xs : Array α} : xs.pop.map f = (xs.map f).pop
Full source
@[simp] theorem map_pop {f : α → β} {xs : Array α} : xs.pop.map f = (xs.map f).pop := by
  cases xs
  simp
Mapping Commutes with Array Pop: $xs.pop.map f = (xs.map f).pop$
Informal description
For any function $f : \alpha \to \beta$ and any array `xs` of elements of type $\alpha$, mapping $f$ over the array obtained by removing the last element of `xs` is equal to the array obtained by removing the last element of the array `xs.map f$. That is, $xs.pop.map f = (xs.map f).pop$.
Array.back?_map theorem
{f : α → β} {xs : Array α} : (xs.map f).back? = xs.back?.map f
Full source
@[simp] theorem back?_map {f : α → β} {xs : Array α} : (xs.map f).back? = xs.back?.map f := by
  cases xs
  simp
Preservation of Last Element under Array Mapping: $(xs.map f).back? = xs.back?.map f$
Informal description
For any function $f : \alpha \to \beta$ and any array $xs$ of elements of type $\alpha$, the last element of the mapped array $xs.map f$ (as an optional value) is equal to applying $f$ to the last element of $xs$ (also as an optional value). That is, $(xs.map f).back? = xs.back?.map f$.
Array.map_map theorem
{f : α → β} {g : β → γ} {as : Array α} : (as.map f).map g = as.map (g ∘ f)
Full source
@[simp] theorem map_map {f : α → β} {g : β → γ} {as : Array α} :
    (as.map f).map g = as.map (g ∘ f) := by
  cases as; simp
Composition of Array Mappings: $(as.map f).map g = as.map (g \circ f)$
Informal description
For any functions $f : \alpha \to \beta$ and $g : \beta \to \gamma$, and any array $as$ of elements of type $\alpha$, the composition of array mappings $(as.map f).map g$ is equal to mapping the composed function $g \circ f$ over the original array $as$. That is, $(as.map f).map g = as.map (g \circ f)$.
Array.mapM_eq_mapM_toList theorem
[Monad m] [LawfulMonad m] {f : α → m β} {xs : Array α} : xs.mapM f = List.toArray <$> (xs.toList.mapM f)
Full source
theorem mapM_eq_mapM_toList [Monad m] [LawfulMonad m] {f : α → m β} {xs : Array α} :
    xs.mapM f = List.toArrayList.toArray <$> (xs.toList.mapM f) := by
  rw [mapM_eq_foldlM, ← foldlM_toList, ← List.foldrM_reverse]
  conv => rhs; rw [← List.reverse_reverse xs.toList]
  induction xs.toList.reverse with
  | nil => simp
  | cons a l ih => simp [ih]
Monadic Array Mapping via List Conversion: $\text{mapM}_\text{Array} f = \text{List.toArray} \circ \text{mapM}_\text{List} f \circ \text{toList}$
Informal description
For any monad `m` that is a lawful monad, any function `f : α → m β`, and any array `xs : Array α`, the monadic map operation `xs.mapM f` is equal to converting `xs` to a list, applying the monadic map operation `mapM f` to the list, and then converting the result back to an array. In symbols: $$ \text{mapM}_\text{Array}\ f\ xs = \text{List.toArray} \circ \text{mapM}_\text{List}\ f\ (\text{toList}\ xs) $$
Array.toList_mapM theorem
[Monad m] [LawfulMonad m] {f : α → m β} {xs : Array α} : toList <$> xs.mapM f = xs.toList.mapM f
Full source
@[simp] theorem toList_mapM [Monad m] [LawfulMonad m] {f : α → m β} {xs : Array α} :
    toListtoList <$> xs.mapM f = xs.toList.mapM f := by
  simp [mapM_eq_mapM_toList]
Monadic Array-to-List Mapping Commutes with List Monadic Mapping
Informal description
For any monad `m` that is a lawful monad, any function `f : α → m β`, and any array `xs : Array α`, converting the result of the monadic map operation `xs.mapM f` to a list is equal to first converting `xs` to a list and then applying the monadic map operation `mapM f` to the list. In symbols: $$ \text{toList} \circ \text{mapM}_\text{Array}\ f\ xs = \text{mapM}_\text{List}\ f\ (\text{toList}\ xs) $$
Array.mapM_map_eq_foldl theorem
{as : Array α} {f : α → β} {i : Nat} : mapM.map (m := Id) f as i b = as.foldl (start := i) (fun acc a => acc.push (f a)) b
Full source
@[deprecated "Use `mapM_eq_foldlM` instead" (since := "2025-01-08")]
theorem mapM_map_eq_foldl {as : Array α} {f : α → β} {i : Nat} :
    mapM.map (m := Id) f as i b = as.foldl (start := i) (fun acc a => acc.push (f a)) b := by
  unfold mapM.map
  split <;> rename_i h
  · simp only [Id.bind_eq]
    dsimp [foldl, Id.run, foldlM]
    rw [mapM_map_eq_foldl, dif_pos (by omega), foldlM.loop, dif_pos h]
    -- Calling `split` here gives a bad goal.
    have : size as - i = Nat.succ (size as - i - 1) := by omega
    rw [this]
    simp [foldl, foldlM, Id.run, Nat.sub_add_eq]
  · dsimp [foldl, Id.run, foldlM]
    rw [dif_pos (by omega), foldlM.loop, dif_neg h]
    rfl
termination_by as.size - i
Equivalence of Array Mapping and Folding with Push Operation
Informal description
For any array `as` of type `Array α`, function `f : α → β`, and natural number index `i`, the result of mapping `f` over `as` starting at index `i` (using the identity monad) is equal to folding over `as` starting at `i` while accumulating the results by pushing `f a` onto the accumulator for each element `a` in `as`.
Array.array₂_induction theorem
(P : Array (Array α) → Prop) (of : ∀ (xss : List (List α)), P (xss.map List.toArray).toArray) (xss : Array (Array α)) : P xss
Full source
/--
Use this as `induction ass using array₂_induction` on a hypothesis of the form `ass : Array (Array α)`.
The hypothesis `ass` will be replaced with a hypothesis `ass : List (List α)`,
and former appearances of `ass` in the goal will be replaced with `(ass.map List.toArray).toArray`.
-/
-- We can't use `@[cases_eliminator]` here as
-- `Lean.Meta.getCustomEliminator?` only looks at the top-level constant.
theorem array₂_induction (P : Array (Array α) → Prop) (of : ∀ (xss : List (List α)), P (xss.map List.toArray).toArray)
    (xss : Array (Array α)) : P xss := by
  specialize of (xss.toList.map toList)
  simpa [← toList_map, Function.comp_def, map_id] using of
Induction Principle for Arrays of Arrays via List Conversion
Informal description
Let $P$ be a predicate on arrays of arrays of type $\alpha$. If $P$ holds for any array of arrays constructed by converting a list of lists of $\alpha$ to an array of arrays (via `List.toArray`), then $P$ holds for any array of arrays $xss$ of type $\text{Array} (\text{Array} \alpha)$.
Array.array₃_induction theorem
(P : Array (Array (Array α)) → Prop) (of : ∀ (xss : List (List (List α))), P ((xss.map (fun xs => xs.map List.toArray)).map List.toArray).toArray) (xss : Array (Array (Array α))) : P xss
Full source
/--
Use this as `induction ass using array₃_induction` on a hypothesis of the form `ass : Array (Array (Array α))`.
The hypothesis `ass` will be replaced with a hypothesis `ass : List (List (List α))`,
and former appearances of `ass` in the goal will be replaced with
`((ass.map (fun xs => xs.map List.toArray)).map List.toArray).toArray`.
-/
theorem array₃_induction (P : Array (Array (Array α)) → Prop)
    (of : ∀ (xss : List (List (List α))), P ((xss.map (fun xs => xs.map List.toArray)).map List.toArray).toArray)
    (xss : Array (Array (Array α))) : P xss := by
  specialize of ((xss.toList.map toList).map (fun as => as.map toList))
  simpa [← toList_map, Function.comp_def, map_id] using of
Induction Principle for Triple Nested Arrays via List Conversion
Informal description
Let $P$ be a property of arrays of arrays of arrays of type $\alpha$. Suppose that for every list of lists of lists $xss$ of type $\alpha$, the property $P$ holds for the array obtained by converting each inner list in $xss$ to an array and then converting the resulting list of arrays to an array. Then $P$ holds for any array of arrays of arrays $xss$ of type $\alpha$.
Array.filter_congr theorem
{xs ys : Array α} (h : xs = ys) {f : α → Bool} {g : α → Bool} (h' : f = g) {start stop start' stop' : Nat} (h₁ : start = start') (h₂ : stop = stop') : filter f xs start stop = filter g ys start' stop'
Full source
@[congr]
theorem filter_congr {xs ys : Array α} (h : xs = ys)
    {f : α → Bool} {g : α → Bool} (h' : f = g) {start stop start' stop' : Nat}
    (h₁ : start = start') (h₂ : stop = stop') :
    filter f xs start stop = filter g ys start' stop' := by
  congr
Congruence of Array Filtering with Respect to Equality of Arrays and Predicates
Informal description
Let $xs$ and $ys$ be arrays of type $\alpha$ such that $xs = ys$, and let $f, g : \alpha \to \text{Bool}$ be predicate functions such that $f = g$. For any natural numbers $start, stop, start', stop'$ with $start = start'$ and $stop = stop'$, the filtered arrays $\text{filter}(f, xs, start, stop)$ and $\text{filter}(g, ys, start', stop')$ are equal.
Array.toList_filter' theorem
{p : α → Bool} {xs : Array α} {stop : Nat} (h : stop = xs.size) : (xs.filter p 0 stop).toList = xs.toList.filter p
Full source
@[simp] theorem toList_filter' {p : α → Bool} {xs : Array α} {stop : Nat} (h : stop = xs.size) :
    (xs.filter p 0 stop).toList = xs.toList.filter p := by
  subst h
  dsimp only [filter]
  rw [← foldl_toList]
  generalize xs.toList = xs
  suffices ∀ as, (List.foldl (fun acc a => if p a = true then push acc a else acc) as xs).toList =
      as.toList ++ List.filter p xs by
    simpa using this #[]
  induction xs with simp
  | cons => split <;> simp [*]
Equivalence of Array Filtering and List Filtering via Conversion
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $xs$ of type $\alpha$, if $stop$ is equal to the size of $xs$, then converting the filtered array (from index $0$ to $stop$) to a list is equal to filtering the list obtained from converting $xs$ to a list with the same predicate $p$.
Array.toList_filter theorem
{p : α → Bool} {xs : Array α} : (xs.filter p).toList = xs.toList.filter p
Full source
theorem toList_filter {p : α → Bool} {xs : Array α} :
    (xs.filter p).toList = xs.toList.filter p := by
  simp
Equivalence of Array Filtering and List Filtering via Conversion
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $xs$ of type $\alpha$, converting the filtered array $xs.filter(p)$ to a list is equal to filtering the list obtained from converting $xs$ to a list with the same predicate $p$, i.e., $(xs.filter(p)).toList = xs.toList.filter(p)$.
List.filter_toArray' theorem
{p : α → Bool} {l : List α} {stop : Nat} (h : stop = l.length) : l.toArray.filter p 0 stop = (l.filter p).toArray
Full source
@[simp] theorem _root_.List.filter_toArray' {p : α → Bool} {l : List α} {stop : Nat} (h : stop = l.length) :
    l.toArray.filter p 0 stop = (l.filter p).toArray := by
  apply ext'
  simp [h]
Equivalence of List Filtering and Array Filtering via Conversion with Bounds
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and list $l$ of type $\alpha$, if $stop$ is equal to the length of $l$, then filtering the array obtained from converting $l$ to an array (from index $0$ to $stop$) with predicate $p$ is equal to converting the filtered list $l.\text{filter}(p)$ to an array.
List.filter_toArray theorem
{p : α → Bool} {l : List α} : l.toArray.filter p = (l.filter p).toArray
Full source
theorem _root_.List.filter_toArray {p : α → Bool} {l : List α} :
    l.toArray.filter p = (l.filter p).toArray := by
  simp
Equivalence of List Filtering and Array Filtering via Conversion
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and list $l$ of type $\alpha$, filtering the array obtained from converting $l$ to an array with predicate $p$ is equal to converting the filtered list $l.\text{filter}(p)$ to an array.
Array.filter_push_of_pos theorem
{p : α → Bool} {a : α} {xs : Array α} (h : p a) (w : stop = xs.size + 1) : (xs.push a).filter p 0 stop = (xs.filter p).push a
Full source
@[simp] theorem filter_push_of_pos {p : α → Bool} {a : α} {xs : Array α}
    (h : p a) (w : stop = xs.size + 1):
    (xs.push a).filter p 0 stop = (xs.filter p).push a := by
  subst w
  rcases xs with ⟨xs⟩
  simp [h]
Filtering Preserves Push Operation for True Predicate
Informal description
Let $p : \alpha \to \text{Bool}$ be a predicate, $a$ an element of $\alpha$, and $xs$ an array of type $\alpha$. If $p(a)$ holds and $stop$ is equal to the size of $xs$ plus one, then filtering the array obtained by pushing $a$ to $xs$ (from index $0$ to $stop$) with predicate $p$ is equal to pushing $a$ to the filtered array $xs.\text{filter}(p)$.
Array.filter_push_of_neg theorem
{p : α → Bool} {a : α} {xs : Array α} (h : ¬p a) (w : stop = xs.size + 1) : (xs.push a).filter p 0 stop = xs.filter p
Full source
@[simp] theorem filter_push_of_neg {p : α → Bool} {a : α} {xs : Array α}
    (h : ¬p a) (w : stop = xs.size + 1) :
    (xs.push a).filter p 0 stop = xs.filter p := by
  subst w
  rcases xs with ⟨xs⟩
  simp [h]
Filtering Preserved Under Pushing Non-Matching Element: $(xs.\text{push}(a)).\text{filter}(p) = xs.\text{filter}(p)$ when $\neg p(a)$
Informal description
For any predicate $p : \alpha \to \text{Bool}$, element $a : \alpha$, and array $xs : \text{Array } \alpha$, if $p(a)$ is false and $stop$ equals the size of $xs$ plus one, then filtering the array obtained by pushing $a$ to $xs$ (from index $0$ to $stop$) with predicate $p$ is equal to filtering $xs$ with $p$.
Array.filter_push theorem
{p : α → Bool} {a : α} {xs : Array α} : (xs.push a).filter p = if p a then (xs.filter p).push a else xs.filter p
Full source
theorem filter_push {p : α → Bool} {a : α} {xs : Array α} :
    (xs.push a).filter p = if p a then (xs.filter p).push a else xs.filter p := by
  split <;> simp [*]
Filter-Push Conditional Equality: $(xs.\text{push}(a)).\text{filter}(p) = \text{if } p(a) \text{ then } (xs.\text{filter}(p)).\text{push}(a) \text{ else } xs.\text{filter}(p)$
Informal description
For any predicate $p : \alpha \to \text{Bool}$, element $a : \alpha$, and array $xs : \text{Array } \alpha$, filtering the array obtained by pushing $a$ to $xs$ with predicate $p$ is equal to: - pushing $a$ to the filtered array $xs.\text{filter}(p)$ if $p(a)$ holds, - the filtered array $xs.\text{filter}(p)$ otherwise.
Array.size_filter_le theorem
{p : α → Bool} {xs : Array α} : (xs.filter p).size ≤ xs.size
Full source
theorem size_filter_le {p : α → Bool} {xs : Array α} :
    (xs.filter p).size ≤ xs.size := by
  rcases xs with ⟨xs⟩
  simpa using List.length_filter_le p xs
Size of Filtered Array is Bounded by Original Array Size
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array $xs$ of type $\alpha$, the size of the filtered array $xs.\text{filter}(p)$ is less than or equal to the size of the original array $xs$.
Array.filter_eq_self theorem
{p : α → Bool} {xs : Array α} : filter p xs = xs ↔ ∀ a ∈ xs, p a
Full source
@[simp] theorem filter_eq_self {p : α → Bool} {xs : Array α} :
    filterfilter p xs = xs ↔ ∀ a ∈ xs, p a := by
  rcases xs with ⟨xs⟩
  simp
Filtered Array Equals Original Array if and only if All Elements Satisfy Predicate
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $xs$ of type $\alpha$, the filtered array $\text{filter}(p, xs)$ is equal to $xs$ if and only if every element $a$ in $xs$ satisfies $p(a)$.
Array.filter_size_eq_size theorem
{p : α → Bool} {xs : Array α} : (xs.filter p).size = xs.size ↔ ∀ a ∈ xs, p a
Full source
@[simp] theorem filter_size_eq_size {p : α → Bool} {xs : Array α} :
    (xs.filter p).size = xs.size ↔ ∀ a ∈ xs, p a := by
  rcases xs with ⟨xs⟩
  simp
Filtered Array Size Equals Original Size iff All Elements Satisfy Predicate
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $xs$ of type $\alpha$, the size of the filtered array $xs.\text{filter}(p)$ equals the size of $xs$ if and only if every element $a$ in $xs$ satisfies $p(a)$.
Array.mem_filter theorem
{p : α → Bool} {xs : Array α} {a : α} : a ∈ xs.filter p ↔ a ∈ xs ∧ p a
Full source
@[simp] theorem mem_filter {p : α → Bool} {xs : Array α} {a : α} :
    a ∈ xs.filter pa ∈ xs.filter p ↔ a ∈ xs ∧ p a := by
  rcases xs with ⟨xs⟩
  simp
Membership in Filtered Array Equals Membership and Predicate Satisfaction
Informal description
For any predicate $p : \alpha \to \text{Bool}$, array $xs : \text{Array}\ \alpha$, and element $a : \alpha$, the element $a$ belongs to the filtered array $\text{filter}\ p\ xs$ if and only if $a$ belongs to $xs$ and satisfies $p(a)$. In symbols: \[ a \in \text{filter}\ p\ xs \leftrightarrow a \in xs \land p(a) \]
Array.filter_eq_empty_iff theorem
{p : α → Bool} {xs : Array α} : filter p xs = #[] ↔ ∀ a, a ∈ xs → ¬p a
Full source
@[simp] theorem filter_eq_empty_iff {p : α → Bool} {xs : Array α} :
    filterfilter p xs = #[] ↔ ∀ a, a ∈ xs → ¬p a := by
  rcases xs with ⟨xs⟩
  simp
Empty Filtered Array Characterization: $\text{filter}(p, xs) = \emptyset \leftrightarrow \forall a \in xs, \neg p(a)$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $xs : \text{Array } \alpha$, the filtered array $\text{filter}(p, xs)$ is empty if and only if for every element $a$ in $xs$, the predicate $p(a)$ does not hold.
Array.forall_mem_filter theorem
{p : α → Bool} {xs : Array α} {P : α → Prop} : (∀ (i) (_ : i ∈ xs.filter p), P i) ↔ ∀ (j) (_ : j ∈ xs), p j → P j
Full source
theorem forall_mem_filter {p : α → Bool} {xs : Array α} {P : α → Prop} :
    (∀ (i) (_ : i ∈ xs.filter p), P i) ↔ ∀ (j) (_ : j ∈ xs), p j → P j := by
  simp
Universal Quantification over Filtered Array Elements
Informal description
For any predicate `p : α → Bool`, array `xs : Array α`, and property `P : α → Prop`, the following equivalence holds: \[ (\forall i \in \text{filter } p \text{ } xs, P(i)) \leftrightarrow (\forall j \in xs, p(j) \rightarrow P(j)) \] Here, `filter p xs` denotes the array obtained by filtering elements of `xs` that satisfy `p`, and `i ∈ xs` means that `i` is an element of `xs`.
Array.filter_filter theorem
{p q : α → Bool} {xs : Array α} : filter p (filter q xs) = filter (fun a => p a && q a) xs
Full source
@[simp] theorem filter_filter {p q : α → Bool} {xs : Array α} :
    filter p (filter q xs) = filter (fun a => p a && q a) xs := by
  apply ext'
  simp only [toList_filter, List.filter_filter]
Composition of Array Filters via Logical Conjunction
Informal description
For any predicates $p, q : \alpha \to \text{Bool}$ and any array $xs$ of type $\alpha$, filtering $xs$ first with $q$ and then with $p$ is equivalent to filtering $xs$ with the combined predicate $\lambda a, p(a) \land q(a)$. In other words: \[ \text{filter } p (\text{filter } q \, xs) = \text{filter } (\lambda a, p(a) \land q(a)) \, xs \]
Array.foldl_filter theorem
{p : α → Bool} {f : β → α → β} {xs : Array α} {init : β} : (xs.filter p).foldl f init = xs.foldl (fun x y => if p y then f x y else x) init
Full source
theorem foldl_filter {p : α → Bool} {f : β → α → β} {xs : Array α} {init : β} :
    (xs.filter p).foldl f init = xs.foldl (fun x y => if p y then f x y else x) init := by
  rcases xs with ⟨xs⟩
  rw [List.filter_toArray]
  simp [List.foldl_filter]
Left Fold over Filtered Array Equals Conditional Fold
Informal description
For any predicate $p : \alpha \to \text{Bool}$, any binary operation $f : \beta \to \alpha \to \beta$, any array $xs$ of type $\alpha$, and any initial value $init : \beta$, the following equality holds: \[ \text{foldl } f \ init \ (\text{filter } p \ xs) = \text{foldl } (\lambda x y. \text{if } p(y) \text{ then } f(x,y) \text{ else } x) \ init \ xs \] Here, $\text{filter } p \ xs$ denotes the array obtained by filtering elements of $xs$ that satisfy $p$, and $\text{foldl}$ denotes the left fold operation.
Array.foldr_filter theorem
{p : α → Bool} {f : α → β → β} {xs : Array α} {init : β} : (xs.filter p).foldr f init = xs.foldr (fun x y => if p x then f x y else y) init
Full source
theorem foldr_filter {p : α → Bool} {f : α → β → β} {xs : Array α} {init : β} :
    (xs.filter p).foldr f init = xs.foldr (fun x y => if p x then f x y else y) init := by
  rcases xs with ⟨xs⟩
  rw [List.filter_toArray]
  simp [List.foldr_filter]
Right Fold over Filtered Array Equals Conditional Right Fold
Informal description
For any predicate $p : \alpha \to \text{Bool}$, any function $f : \alpha \to \beta \to \beta$, any array $xs$ of type $\alpha$, and any initial value $init$ of type $\beta$, the right fold over the filtered array $xs.\text{filter}(p)$ with function $f$ and initial value $init$ is equal to the right fold over the original array $xs$ with a modified function that applies $f$ only when the predicate $p$ holds. Specifically: \[ \text{foldr } f \ init \ (xs.\text{filter}(p)) = \text{foldr } (\lambda x\ y, \text{if } p(x) \text{ then } f(x)(y) \text{ else } y) \ init \ xs \]
Array.filter_map theorem
{f : β → α} {xs : Array β} : filter p (map f xs) = map f (filter (p ∘ f) xs)
Full source
theorem filter_map {f : β → α} {xs : Array β} : filter p (map f xs) = map f (filter (p ∘ f) xs) := by
  rcases xs with ⟨xs⟩
  simp [List.filter_map]
Filter-Map Commutativity: $\text{filter}(p, \text{map}(f, xs)) = \text{map}(f, \text{filter}(p \circ f, xs))$
Informal description
For any predicate $p : \alpha \to \text{Bool}$, function $f : \beta \to \alpha$, and array $xs$ of type $\beta$, filtering the mapped array $\text{map}(f, xs)$ with predicate $p$ is equal to mapping $f$ over the array filtered with the composed predicate $p \circ f$. That is, $$\text{filter}(p, \text{map}(f, xs)) = \text{map}(f, \text{filter}(p \circ f, xs)).$$
Array.map_filter_eq_foldl theorem
{f : α → β} {p : α → Bool} {xs : Array α} : map f (filter p xs) = foldl (fun acc x => bif p x then acc.push (f x) else acc) #[] xs
Full source
theorem map_filter_eq_foldl {f : α → β} {p : α → Bool} {xs : Array α} :
    map f (filter p xs) = foldl (fun acc x => bif p x then acc.push (f x) else acc) #[] xs := by
  rcases xs with ⟨xs⟩
  apply ext'
  simp only [List.size_toArray, List.filter_toArray', List.map_toArray, List.foldl_toArray']
  rw [← List.reverse_reverse xs]
  generalize xs.reverse = xs
  simp only [List.filter_reverse, List.map_reverse, List.foldl_reverse]
  induction xs with
  | nil => rfl
  | cons x l ih =>
    simp only [List.filter_cons, List.foldr_cons]
    split <;> simp_all
Mapping after Filtering Equals Folding with Conditional Push: $\text{map}(f, \text{filter}(p, xs)) = \text{foldl}(\lambda \text{acc}\ x. \text{if } p(x) \text{ then } \text{acc.push}(f(x)) \text{ else } \text{acc}, \text{#[]}, xs)$
Informal description
For any function $f : \alpha \to \beta$, predicate $p : \alpha \to \text{Bool}$, and array $xs$ of type $\alpha$, the array obtained by first filtering $xs$ with $p$ and then mapping $f$ over the result is equal to the array obtained by folding over $xs$ with an accumulator that starts as an empty array and, for each element $x$, appends $f(x)$ to the accumulator if $p(x)$ holds and leaves it unchanged otherwise.
Array.filter_append theorem
{p : α → Bool} {xs ys : Array α} {stop : Nat} (w : stop = xs.size + ys.size) : filter p (xs ++ ys) 0 stop = filter p xs ++ filter p ys
Full source
@[simp] theorem filter_append {p : α → Bool} {xs ys : Array α} {stop : Nat} (w : stop = xs.size + ys.size) :
    filter p (xs ++ ys) 0 stop = filter p xs ++ filter p ys := by
  subst w
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp [List.filter_append]
Filtering Preserves Array Concatenation: $\text{filter}(p, xs \mathbin{+\kern-1.5ex+} ys) = \text{filter}(p, xs) \mathbin{+\kern-1.5ex+} \text{filter}(p, ys)$ when $stop = \text{size}(xs) + \text{size}(ys)$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and arrays $xs, ys$ of type $\alpha$, if $stop$ is equal to the sum of the sizes of $xs$ and $ys$, then filtering the concatenated array $xs \mathbin{+\kern-1.5ex+} ys$ from index $0$ to $stop$ with predicate $p$ is equal to the concatenation of the filtered arrays $\text{filter}(p, xs)$ and $\text{filter}(p, ys)$.
Array.filter_eq_append_iff theorem
{p : α → Bool} : filter p xs = ys ++ zs ↔ ∃ as bs, xs = as ++ bs ∧ filter p as = ys ∧ filter p bs = zs
Full source
theorem filter_eq_append_iff {p : α → Bool} :
    filterfilter p xs = ys ++ zs ↔ ∃ as bs, xs = as ++ bs ∧ filter p as = ys ∧ filter p bs = zs := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  rcases zs with ⟨zs⟩
  simp only [List.size_toArray, List.filter_toArray', List.append_toArray, mk.injEq,
    List.filter_eq_append_iff]
  constructor
  · rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
    refine ⟨l₁.toArray, l₂.toArray, by simp⟩
  · rintro ⟨⟨l₁⟩, ⟨l₂⟩, h₁, h₂, h₃⟩
    refine ⟨l₁, l₂, by simp_all⟩
Decomposition of Filtered Array into Concatenated Subarrays
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and arrays $xs, ys, zs$ of type $\alpha$, the filtered array $\text{filter}(p, xs)$ equals the concatenation $ys ++ zs$ if and only if there exist arrays $as$ and $bs$ such that $xs = as ++ bs$, $\text{filter}(p, as) = ys$, and $\text{filter}(p, bs) = zs$.
Array.filter_eq_push_iff theorem
{p : α → Bool} {xs ys : Array α} {a : α} : filter p xs = ys.push a ↔ ∃ as bs, xs = as.push a ++ bs ∧ filter p as = ys ∧ p a ∧ (∀ x, x ∈ bs → ¬p x)
Full source
theorem filter_eq_push_iff {p : α → Bool} {xs ys : Array α} {a : α} :
    filterfilter p xs = ys.push a ↔
      ∃ as bs, xs = as.push a ++ bs ∧ filter p as = ys ∧ p a ∧ (∀ x, x ∈ bs → ¬p x) := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp only [List.size_toArray, List.filter_toArray', List.push_toArray, mk.injEq, Bool.not_eq_true]
  rw [← List.reverse_inj]
  simp only [← List.filter_reverse]
  simp only [List.reverse_append, List.reverse_cons, List.reverse_nil, List.nil_append,
    List.singleton_append]
  rw [List.filter_eq_cons_iff]
  constructor
  · rintro ⟨l₁, l₂, h₁, h₂, h₃, h₄⟩
    refine ⟨l₂.reverse.toArray, l₁.reverse.toArray, by simp_all⟩
  · rintro ⟨⟨l₁⟩, ⟨l₂⟩, h₁, h₂, h₃, h₄⟩
    refine ⟨l₂.reverse, l₁.reverse, by simp_all⟩
Characterization of Filtered Array as Push-Appended Array
Informal description
For any predicate $p : \alpha \to \text{Bool}$, arrays $xs, ys : \text{Array } \alpha$, and element $a : \alpha$, the filtered array $\text{filter}(p, xs)$ equals $ys$ with $a$ appended if and only if there exist arrays $as, bs$ such that: 1. $xs$ can be decomposed as $as.\text{push}(a) \mathbin{+\!\!+} bs$, 2. $\text{filter}(p, as) = ys$, 3. $p(a)$ holds, and 4. For all $x \in bs$, $\neg p(x)$ holds.
Array.mem_of_mem_filter theorem
{a : α} {xs : Array α} (h : a ∈ filter p xs) : a ∈ xs
Full source
theorem mem_of_mem_filter {a : α} {xs : Array α} (h : a ∈ filter p xs) : a ∈ xs :=
  (mem_filter.mp h).1
Membership in Filtered Array Implies Membership in Original Array
Informal description
For any element $a$ of type $\alpha$ and array $xs$ of type $\text{Array}\ \alpha$, if $a$ belongs to the filtered array $\text{filter}\ p\ xs$, then $a$ belongs to $xs$.
Array.size_filter_pos_iff theorem
{xs : Array α} {p : α → Bool} : 0 < (filter p xs).size ↔ ∃ x ∈ xs, p x
Full source
@[simp]
theorem size_filter_pos_iff {xs : Array α} {p : α → Bool} :
    0 < (filter p xs).size ↔ ∃ x ∈ xs, p x := by
  rcases xs with ⟨xs⟩
  simp
Non-empty Filtered Array iff Predicate Holds for Some Element
Informal description
For any array `xs` of type `α` and any predicate `p : α → Bool`, the size of the filtered array `filter p xs` is greater than zero if and only if there exists an element `x` in `xs` such that `p x` holds.
Array.size_filter_lt_size_iff_exists theorem
{xs : Array α} {p : α → Bool} : (filter p xs).size < xs.size ↔ ∃ x ∈ xs, ¬p x
Full source
@[simp]
theorem size_filter_lt_size_iff_exists {xs : Array α} {p : α → Bool} :
    (filter p xs).size < xs.size ↔ ∃ x ∈ xs, ¬p x := by
  rcases xs with ⟨xs⟩
  simp
Size Reduction in Array Filtering Characterizes Existence of Non-Matching Elements
Informal description
For any array $xs$ of type $\alpha$ and any predicate $p : \alpha \to \text{Bool}$, the size of the filtered array $\text{filter}(p, xs)$ is strictly less than the size of $xs$ if and only if there exists an element $x \in xs$ such that $\neg p(x)$ holds.
Array.filterMap_congr theorem
{as bs : Array α} (h : as = bs) {f : α → Option β} {g : α → Option β} (h' : f = g) {start stop start' stop' : Nat} (h₁ : start = start') (h₂ : stop = stop') : filterMap f as start stop = filterMap g bs start' stop'
Full source
@[congr]
theorem filterMap_congr {as bs : Array α} (h : as = bs)
    {f : α → Option β} {g : α → Option β} (h' : f = g) {start stop start' stop' : Nat}
    (h₁ : start = start') (h₂ : stop = stop') :
    filterMap f as start stop = filterMap g bs start' stop' := by
  congr
Congruence of `filterMap` Operation on Arrays
Informal description
For any arrays `as` and `bs` of type `Array α` such that `as = bs`, and for any functions `f, g : α → Option β` such that `f = g`, and for any natural numbers `start, stop, start', stop'` such that `start = start'` and `stop = stop'`, the filtered and mapped arrays `filterMap f as start stop` and `filterMap g bs start' stop'` are equal.
Array.toList_filterMap' theorem
{f : α → Option β} {xs : Array α} {stop : Nat} (w : stop = xs.size) : (xs.filterMap f 0 stop).toList = xs.toList.filterMap f
Full source
@[simp] theorem toList_filterMap' {f : α → Option β} {xs : Array α} {stop : Nat} (w : stop = xs.size) :
    (xs.filterMap f 0 stop).toList = xs.toList.filterMap f := by
  subst w
  dsimp only [filterMap, filterMapM]
  rw [← foldlM_toList]
  generalize xs.toList = xs
  have this : ∀ as : Array β, (Id.run (List.foldlM (m := Id) ?_ as xs)).toList =
    as.toList ++ List.filterMap f xs := ?_
  exact this #[]
  induction xs
  · simp_all [Id.run]
  · simp_all [Id.run, List.filterMap_cons]
    split <;> simp_all
Equivalence of `filterMap` on Arrays and Lists: $\text{toList}(\text{filterMap } f \ xs \ 0 \ \text{size}(xs)) = \text{filterMap } f (\text{toList } xs)$
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any array $xs$ of type $\text{Array } \alpha$, and any natural number $stop$ such that $stop = xs.\text{size}$, the list obtained by converting the filtered and mapped array $(xs.\text{filterMap } f \ 0 \ stop)$ is equal to the filtered and mapped list obtained by converting $xs$ to a list and then applying $\text{filterMap } f$.
Array.toList_filterMap theorem
{f : α → Option β} {xs : Array α} : (xs.filterMap f).toList = xs.toList.filterMap f
Full source
theorem toList_filterMap {f : α → Option β} {xs : Array α} :
    (xs.filterMap f).toList = xs.toList.filterMap f := by
  simp [toList_filterMap']
Equivalence of Array and List `filterMap` Operations: $(xs.\text{filterMap } f).\text{toList} = xs.\text{toList}.\text{filterMap } f$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any array $xs$ of type $\text{Array } \alpha$, converting the filtered and mapped array $xs.\text{filterMap } f$ to a list is equal to first converting $xs$ to a list and then applying $\text{filterMap } f$ to the resulting list. That is, $(xs.\text{filterMap } f).\text{toList} = xs.\text{toList}.\text{filterMap } f$.
List.filterMap_toArray' theorem
{f : α → Option β} {l : List α} {stop : Nat} (h : stop = l.length) : l.toArray.filterMap f 0 stop = (l.filterMap f).toArray
Full source
@[simp] theorem _root_.List.filterMap_toArray' {f : α → Option β} {l : List α} {stop : Nat} (h : stop = l.length) :
    l.toArray.filterMap f 0 stop = (l.filterMap f).toArray := by
  apply ext'
  simp [h]
Equivalence of List-to-Array Conversion and FilterMap Operations: $\text{toArray}(l).\text{filterMap } f \ 0 \ \text{length}(l) = \text{toArray}(\text{filterMap } f \ l)$
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any list $l$ of type $\text{List } \alpha$, and any natural number $\text{stop}$ such that $\text{stop} = \text{length}(l)$, the filtered and mapped array obtained by first converting $l$ to an array and then applying $\text{filterMap } f$ from index $0$ to $\text{stop}$ is equal to the array obtained by converting the filtered and mapped list $\text{filterMap } f \ l$ to an array.
List.filterMap_toArray theorem
{f : α → Option β} {l : List α} : l.toArray.filterMap f = (l.filterMap f).toArray
Full source
theorem _root_.List.filterMap_toArray {f : α → Option β} {l : List α} :
    l.toArray.filterMap f = (l.filterMap f).toArray := by
  simp
Equivalence of List-to-Array Conversion and FilterMap Operations: $\text{toArray}(l).\text{filterMap } f = \text{toArray}(\text{filterMap } f \ l)$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any list $l$ of type $\text{List } \alpha$, applying the `filterMap` operation to the array obtained from converting $l$ yields the same result as first applying `filterMap` to $l$ and then converting the result to an array. That is, $\text{toArray}(l).\text{filterMap } f = \text{toArray}(\text{filterMap } f \ l)$.
Array.filterMap_push_none theorem
{f : α → Option β} {a : α} {xs : Array α} (h : f a = none) (w : stop = xs.size + 1) : filterMap f (xs.push a) 0 stop = filterMap f xs
Full source
@[simp] theorem filterMap_push_none {f : α → Option β} {a : α} {xs : Array α}
    (h : f a = none) (w : stop = xs.size + 1) :
    filterMap f (xs.push a) 0 stop = filterMap f xs := by
  subst w
  rcases xs with ⟨xs⟩
  simp [h]
Filter-Map Invariance Under Push of None-Producing Element
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any element $a \in \alpha$, and any array $xs$ of type $\text{Array } \alpha$, if $f(a) = \text{none}$ and $\text{stop} = \text{size}(xs) + 1$, then filtering and mapping the array obtained by pushing $a$ to $xs$ from index $0$ to $\text{stop}$ is equal to filtering and mapping the original array $xs$. In symbols: $$\text{filterMap } f \ (\text{push } xs \ a) \ 0 \ \text{stop} = \text{filterMap } f \ xs$$
Array.filterMap_push_some theorem
{f : α → Option β} {a : α} {xs : Array α} {b : β} (h : f a = some b) (w : stop = xs.size + 1) : filterMap f (xs.push a) 0 stop = (filterMap f xs).push b
Full source
@[simp] theorem filterMap_push_some {f : α → Option β} {a : α} {xs : Array α} {b : β}
    (h : f a = some b) (w : stop = xs.size + 1) :
    filterMap f (xs.push a) 0 stop = (filterMap f xs).push b := by
  subst w
  rcases xs with ⟨xs⟩
  simp [h]
Filter-Map-Push Property for Arrays: $\text{filterMap } f \ (xs.\text{push } a) \ 0 \ (\text{size}(xs)+1) = (\text{filterMap } f \ xs).\text{push } b$ when $f(a) = \text{some } b$
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any element $a : \alpha$, any array $xs : \text{Array } \alpha$, and any element $b : \beta$, if $f(a) = \text{some } b$ and $\text{stop} = \text{size}(xs) + 1$, then applying $\text{filterMap } f$ to the array $xs.\text{push } a$ from index $0$ to $\text{stop}$ results in the array obtained by pushing $b$ to the result of $\text{filterMap } f$ applied to $xs$.
Array.filterMap_eq_map theorem
{f : α → β} (w : stop = as.size) : filterMap (some ∘ f) as 0 stop = map f as
Full source
@[simp] theorem filterMap_eq_map {f : α → β} (w : stop = as.size) :
    filterMap (somesome ∘ f) as 0 stop = map f as := by
  subst w
  cases as
  simp
Equivalence of `filterMap` and `map` for Arrays: $\text{filterMap } (\text{some} \circ f) = \text{map } f$ when applied to full array
Informal description
For any function $f : \alpha \to \beta$ and any array `as` of type `Array α`, if the stopping index `stop` equals the size of `as`, then applying `filterMap` with the composition of `some` and `f` to `as` from index `0` to `stop` is equal to mapping `f` over `as`. In symbols: $$\text{filterMap } (\text{some} \circ f) \ as \ 0 \ \text{stop} = \text{map } f \ as \quad \text{when } \text{stop} = \text{size}(as)$$
Array.filterMap_eq_map' theorem
{f : α → β} (w : stop = as.size) : filterMap (fun x => some (f x)) as 0 stop = map f as
Full source
/-- Variant of `filterMap_eq_map` with `some ∘ f` expanded out to a lambda. -/
@[simp]
theorem filterMap_eq_map' {f : α → β} (w : stop = as.size) :
    filterMap (fun x => some (f x)) as 0 stop = map f as :=
  filterMap_eq_map w
Equivalence of `filterMap` and `map` for Arrays with explicit lambda function
Informal description
For any function $f : \alpha \to \beta$ and any array `as` of type `Array \alpha`, if the stopping index `stop` equals the size of `as`, then applying `filterMap` with the function $\lambda x, \text{some } (f x)$ to `as` from index `0` to `stop` is equal to mapping `f` over `as`. In symbols: $$\text{filterMap } (\lambda x, \text{some } (f x)) \ as \ 0 \ \text{stop} = \text{map } f \ as \quad \text{when } \text{stop} = \text{size}(as)$$
Array.filterMap_some_fun theorem
: filterMap (some : α → Option α) = id
Full source
theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
  funext xs
  cases xs
  simp
`filterMap` with `some` is the identity function
Informal description
The function `filterMap` applied with the `some` constructor (viewed as a function from `α` to `Option α`) is equal to the identity function on arrays of type `Array α`.
Array.filterMap_some theorem
{xs : Array α} : filterMap some xs = xs
Full source
@[simp] theorem filterMap_some {xs : Array α} : filterMap some xs = xs := by
  cases xs
  simp
Identity Property of `filterMap` with `some`: $\text{filterMap some } xs = xs$
Informal description
For any array `xs` of type `Array α`, applying the `filterMap` operation with the identity function `some` (which wraps each element in `Option α`) returns the original array `xs`. That is, `filterMap some xs = xs`.
Array.map_filterMap_some_eq_filterMap_isSome theorem
{f : α → Option β} {xs : Array α} : (xs.filterMap f).map some = (xs.map f).filter fun b => b.isSome
Full source
theorem map_filterMap_some_eq_filterMap_isSome {f : α → Option β} {xs : Array α} :
    (xs.filterMap f).map some = (xs.map f).filter fun b => b.isSome := by
  cases xs
  simp [List.map_filterMap_some_eq_filter_map_isSome]
Equivalence of Mapping and Filtering Operations on Arrays: $(\text{filterMap } f \ xs).\text{map some} = (xs.\text{map } f).\text{filter isSome}$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any array $xs$ of type $\text{Array } \alpha$, mapping the `some` constructor over the filtered and mapped array $\text{filterMap } f \ xs$ is equal to filtering the mapped array $xs.map f$ to retain only those elements that are `some` values (i.e., satisfying $\text{isSome}$). In symbols: $$(\text{filterMap } f \ xs).\text{map some} = (xs.\text{map } f).\text{filter } (\lambda b, b.\text{isSome})$$
Array.size_filterMap_le theorem
{f : α → Option β} {xs : Array α} : (xs.filterMap f).size ≤ xs.size
Full source
theorem size_filterMap_le {f : α → Option β} {xs : Array α} :
    (xs.filterMap f).size ≤ xs.size := by
  cases xs
  simp [List.length_filterMap_le]
Size Bound for Filtered and Mapped Arrays: $\text{size}(\text{filterMap } f \ xs) \leq \text{size}(xs)$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any array $xs$ of type $\text{Array } \alpha$, the size of the filtered and mapped array $\text{filterMap } f \ xs$ is less than or equal to the size of the original array $xs$.
Array.filterMap_size_eq_size theorem
{xs : Array α} : (xs.filterMap f).size = xs.size ↔ ∀ a, a ∈ xs → (f a).isSome
Full source
@[simp] theorem filterMap_size_eq_size {xs : Array α} :
    (xs.filterMap f).size = xs.size ↔ ∀ a, a ∈ xs → (f a).isSome := by
  cases xs
  simp [List.filterMap_length_eq_length]
Size Preservation in `filterMap` Operation on Arrays
Informal description
For any array `xs` of type `Array α` and any function `f : α → Option β`, the size of the filtered and mapped array `xs.filterMap f` is equal to the size of `xs` if and only if for every element `a` in `xs`, the option `f a` is `some` (i.e., `(f a).isSome` holds).
Array.filterMap_eq_filter theorem
{p : α → Bool} (w : stop = as.size) : filterMap (Option.guard (p ·)) as 0 stop = filter p as
Full source
@[simp]
theorem filterMap_eq_filter {p : α → Bool} (w : stop = as.size) :
    filterMap (Option.guard (p ·)) as 0 stop = filter p as := by
  subst w
  cases as
  simp
Equivalence of `filterMap` with `Option.guard` and `filter` on arrays
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $as$ of type $\alpha$, if $stop$ is equal to the size of $as$, then filtering the array $as$ from index $0$ to $stop$ using the predicate $p$ is equivalent to applying the `filterMap` operation with the partial identity function `Option.guard (p ·)` over the same range.
Array.filterMap_filterMap theorem
{f : α → Option β} {g : β → Option γ} {xs : Array α} : filterMap g (filterMap f xs) = filterMap (fun x => (f x).bind g) xs
Full source
theorem filterMap_filterMap {f : α → Option β} {g : β → Option γ} {xs : Array α} :
    filterMap g (filterMap f xs) = filterMap (fun x => (f x).bind g) xs := by
  cases xs
  simp [List.filterMap_filterMap]
Composition of FilterMap Operations: $\text{filterMap } g \circ \text{filterMap } f = \text{filterMap } (f \gg= g)$
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any function $g : \beta \to \text{Option } \gamma$, and any array $xs$ of type $\text{Array } \alpha$, the following equality holds: $$\text{filterMap } g (\text{filterMap } f \ xs) = \text{filterMap } (\lambda x, (f \ x).\text{bind } g) \ xs$$ where $\text{filterMap}$ applies a function to each element of an array and collects the $\text{some}$ results, and $\text{bind}$ is the monadic bind operation for $\text{Option}$.
Array.map_filterMap theorem
{f : α → Option β} {g : β → γ} {xs : Array α} : map g (filterMap f xs) = filterMap (fun x => (f x).map g) xs
Full source
theorem map_filterMap {f : α → Option β} {g : β → γ} {xs : Array α} :
    map g (filterMap f xs) = filterMap (fun x => (f x).map g) xs := by
  cases xs
  simp [List.map_filterMap]
Commutativity of Map and FilterMap: $\text{map } g \circ \text{filterMap } f = \text{filterMap } (f \gg \text{map } g)$
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any function $g : \beta \to \gamma$, and any array $xs$ of type $\text{Array } \alpha$, the following equality holds: $$\text{map } g (\text{filterMap } f \ xs) = \text{filterMap } (\lambda x, \text{Option.map } g (f x)) \ xs$$ where $\text{filterMap}$ applies $f$ to each element of $xs$ and collects the $\text{some}$ results, and $\text{map}$ applies $g$ to each element of the resulting array.
Array.filterMap_map theorem
{f : α → β} {g : β → Option γ} {xs : Array α} : filterMap g (map f xs) = filterMap (g ∘ f) xs
Full source
@[simp] theorem filterMap_map {f : α → β} {g : β → Option γ} {xs : Array α} :
    filterMap g (map f xs) = filterMap (g ∘ f) xs := by
  cases xs
  simp [List.filterMap_map]
Commutativity of Map and FilterMap: $\text{filterMap } g \circ \text{map } f = \text{filterMap } (g \circ f)$
Informal description
For any function $f : \alpha \to \beta$, any function $g : \beta \to \text{Option } \gamma$, and any array $xs$ of type $\text{Array } \alpha$, the following equality holds: \[ \text{filterMap } g (\text{map } f \ xs) = \text{filterMap } (g \circ f) \ xs \] where $\text{map } f$ applies $f$ to each element of $xs$, and $\text{filterMap } g$ applies $g$ to each element and collects the $\text{some}$ results.
Array.filter_filterMap theorem
{f : α → Option β} {p : β → Bool} {xs : Array α} : filter p (filterMap f xs) = filterMap (fun x => (f x).filter p) xs
Full source
theorem filter_filterMap {f : α → Option β} {p : β → Bool} {xs : Array α} :
    filter p (filterMap f xs) = filterMap (fun x => (f x).filter p) xs := by
  cases xs
  simp [List.filter_filterMap]
Filter-Then-FilterMap Equals Composite FilterMap: $\text{filter } p \circ \text{filterMap } f = \text{filterMap } (\lambda x, (f x).\text{filter } p)$
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any predicate $p : \beta \to \text{Bool}$, and any array $xs$ of type $\text{Array } \alpha$, the filtered array obtained by first applying $\text{filterMap } f$ to $xs$ and then filtering with $p$ is equal to applying $\text{filterMap}$ with the composite function $\lambda x, (f x).\text{filter } p$ to $xs$.
Array.filterMap_filter theorem
{p : α → Bool} {f : α → Option β} {xs : Array α} : filterMap f (filter p xs) = filterMap (fun x => if p x then f x else none) xs
Full source
theorem filterMap_filter {p : α → Bool} {f : α → Option β} {xs : Array α} :
    filterMap f (filter p xs) = filterMap (fun x => if p x then f x else none) xs := by
  cases xs
  simp [List.filterMap_filter]
FilterMap-Filter Commutation: $\text{filterMap}\ f \circ \text{filter}\ p = \text{filterMap}\ (x \mapsto \text{if}\ p\ x\ \text{then}\ f\ x\ \text{else}\ \text{none})$
Informal description
For any predicate $p : \alpha \to \text{Bool}$, any function $f : \alpha \to \text{Option}\ \beta$, and any array $xs$ of type $\text{Array}\ \alpha$, the following equality holds: \[ \text{filterMap}\ f\ (\text{filter}\ p\ xs) = \text{filterMap}\ (\lambda x \mapsto \text{if}\ p\ x\ \text{then}\ f\ x\ \text{else}\ \text{none})\ xs \]
Array.mem_filterMap theorem
{f : α → Option β} {xs : Array α} {b : β} : b ∈ filterMap f xs ↔ ∃ a, a ∈ xs ∧ f a = some b
Full source
@[simp] theorem mem_filterMap {f : α → Option β} {xs : Array α} {b : β} :
    b ∈ filterMap f xsb ∈ filterMap f xs ↔ ∃ a, a ∈ xs ∧ f a = some b := by
  simp only [mem_def, toList_filterMap, List.mem_filterMap]
Membership in Filter-Mapped Array: $b \in \text{filterMap}\ f\ xs \leftrightarrow \exists a \in xs, f(a) = \text{some}\ b$
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$, array $xs$ of type $\text{Array}\ \alpha$, and element $b : \beta$, the following equivalence holds: $b$ is an element of the array obtained by applying `filterMap f` to $xs$ if and only if there exists an element $a \in xs$ such that $f(a) = \text{some}\ b$.
Array.forall_mem_filterMap theorem
{f : α → Option β} {xs : Array α} {P : β → Prop} : (∀ (i) (_ : i ∈ filterMap f xs), P i) ↔ ∀ (j) (_ : j ∈ xs) (b), f j = some b → P b
Full source
theorem forall_mem_filterMap {f : α → Option β} {xs : Array α} {P : β → Prop} :
    (∀ (i) (_ : i ∈ filterMap f xs), P i) ↔ ∀ (j) (_ : j ∈ xs) (b), f j = some b → P b := by
  simp only [mem_filterMap, forall_exists_index, and_imp]
  rw [forall_comm]
  apply forall_congr'
  intro a
  rw [forall_comm]
Universal Quantifier over Filter-Mapped Array Elements
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$, array $xs$ of type $\text{Array}\ \alpha$, and predicate $P : \beta \to \text{Prop}$, the following are equivalent: 1. For every element $i$ in the array obtained by applying `filterMap f` to $xs$, the predicate $P(i)$ holds. 2. For every element $j$ in $xs$ and every $b$ such that $f(j) = \text{some}\ b$, the predicate $P(b)$ holds. In other words, $P$ holds for all elements in $\text{filterMap}\ f\ xs$ if and only if for every element $j$ in $xs$ that maps to some $b$ under $f$, $P(b)$ holds.
Array.filterMap_append theorem
{α β : Type _} {xs ys : Array α} {f : α → Option β} {stop : Nat} (w : stop = xs.size + ys.size) : filterMap f (xs ++ ys) 0 stop = filterMap f xs ++ filterMap f ys
Full source
@[simp] theorem filterMap_append {α β : Type _} {xs ys : Array α} {f : α → Option β} {stop : Nat} (w : stop = xs.size + ys.size) :
    filterMap f (xs ++ ys) 0 stop = filterMap f xs ++ filterMap f ys := by
  subst w
  cases xs
  cases ys
  simp
Filter-Map Distributes Over Array Concatenation: $\text{filterMap}\ f\ (xs ++ ys) = \text{filterMap}\ f\ xs ++ \text{filterMap}\ f\ ys$
Informal description
For any types $\alpha$ and $\beta$, arrays $xs$ and $ys$ of type $\text{Array}\ \alpha$, a function $f : \alpha \to \text{Option}\ \beta$, and a natural number $\text{stop}$ such that $\text{stop} = \text{size}(xs) + \text{size}(ys)$, the filtered and mapped array obtained by applying $f$ to the concatenation of $xs$ and $ys$ from index $0$ to $\text{stop}$ is equal to the concatenation of the filtered and mapped arrays obtained by applying $f$ to $xs$ and $ys$ separately.
Array.map_filterMap_of_inv theorem
{f : α → Option β} {g : β → α} (H : ∀ x : α, (f x).map g = some x) {xs : Array α} : map g (filterMap f xs) = xs
Full source
theorem map_filterMap_of_inv {f : α → Option β} {g : β → α} (H : ∀ x : α, (f x).map g = some x) {xs : Array α} :
    map g (filterMap f xs) = xs := by
  simp only [map_filterMap, H, filterMap_some, id]
Inverse Property of FilterMap and Map: $\text{map } g \circ \text{filterMap } f = \text{id}$ when $(f x).\text{map } g = \text{some } x$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any function $g : \beta \to \alpha$ such that for all $x \in \alpha$, the composition $(f x).\text{map } g$ equals $\text{some } x$, and for any array $xs$ of type $\text{Array } \alpha$, the following equality holds: $$\text{map } g (\text{filterMap } f \ xs) = xs$$
Array.forall_none_of_filterMap_eq_empty theorem
(h : filterMap f xs = #[]) : ∀ x ∈ xs, f x = none
Full source
theorem forall_none_of_filterMap_eq_empty (h : filterMap f xs = #[]) : ∀ x ∈ xs, f x = none := by
  cases xs
  simpa using h
Empty Filtered Map Implies All None
Informal description
For any array `xs` of type `Array α` and any function `f : α → Option β`, if the filtered and mapped array `filterMap f xs` is empty, then for every element `x` in `xs`, the function `f` applied to `x` yields `none`.
Array.filterMap_eq_nil_iff theorem
{xs : Array α} : filterMap f xs = #[] ↔ ∀ a, a ∈ xs → f a = none
Full source
@[simp] theorem filterMap_eq_nil_iff {xs : Array α} : filterMapfilterMap f xs = #[] ↔ ∀ a, a ∈ xs → f a = none := by
  cases xs
  simp
Empty FilterMap Condition: $\text{filterMap } f \ xs = \#[] \leftrightarrow \forall a \in xs, f a = \text{none}$
Informal description
For any array `xs` of type `Array α` and any function `f : α → Option β`, the filtered and mapped array `filterMap f xs` is empty if and only if for every element `a` in `xs`, the function `f` applied to `a` returns `none`.
Array.filterMap_eq_push_iff theorem
{f : α → Option β} {xs : Array α} {ys : Array β} {b : β} : filterMap f xs = ys.push b ↔ ∃ as a bs, xs = as.push a ++ bs ∧ filterMap f as = ys ∧ f a = some b ∧ (∀ x, x ∈ bs → f x = none)
Full source
theorem filterMap_eq_push_iff {f : α → Option β} {xs : Array α} {ys : Array β} {b : β} :
    filterMapfilterMap f xs = ys.push b ↔ ∃ as a bs,
      xs = as.push a ++ bs ∧ filterMap f as = ys ∧ f a = some b ∧ (∀ x, x ∈ bs → f x = none) := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp only [List.size_toArray, List.filterMap_toArray', List.push_toArray, mk.injEq]
  rw [← List.reverse_inj]
  simp only [← List.filterMap_reverse]
  simp only [List.reverse_append, List.reverse_cons, List.reverse_nil, List.nil_append,
    List.singleton_append]
  rw [List.filterMap_eq_cons_iff]
  constructor
  · rintro ⟨l₁, a, l₂, h₁, h₂, h₃, h₄⟩
    refine ⟨l₂.reverse.toArray, a, l₁.reverse.toArray, by simp_all⟩
  · rintro ⟨⟨l₁⟩, a, ⟨l₂⟩, h₁, h₂, h₃, h₄⟩
    refine ⟨l₂.reverse, a, l₁.reverse, by simp_all⟩
Characterization of FilterMap Result as Push Operation: $\text{filterMap } f \ xs = ys.\text{push } b \leftrightarrow \exists as, a, bs, \text{ conditions}$
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any array $xs$ of type $\text{Array } \alpha$, any array $ys$ of type $\text{Array } \beta$, and any element $b \in \beta$, the filtered and mapped array $\text{filterMap } f \ xs$ equals $ys$ with $b$ appended if and only if there exist arrays $as$ and $bs$ of type $\text{Array } \alpha$ and an element $a \in \alpha$ such that: 1. $xs$ can be decomposed as $as$ with $a$ appended followed by $bs$ (i.e., $xs = \text{as.push } a \text{ ++ } bs$), 2. $\text{filterMap } f \ as = ys$, 3. $f(a) = \text{some } b$, and 4. For every element $x$ in $bs$, $f(x) = \text{none}$.
Array.size_filterMap_pos_iff theorem
{xs : Array α} {f : α → Option β} : 0 < (filterMap f xs).size ↔ ∃ (x : α) (_ : x ∈ xs) (b : β), f x = some b
Full source
@[simp]
theorem size_filterMap_pos_iff {xs : Array α} {f : α → Option β} :
    0 < (filterMap f xs).size ↔ ∃ (x : α) (_ : x ∈ xs) (b : β), f x = some b := by
  rcases xs with ⟨xs⟩
  simp
Non-empty FilterMap Condition: $\text{size}(\text{filterMap } f \ xs) > 0 \leftrightarrow \exists x \in xs, \exists b, f x = \text{some } b$
Informal description
For any array `xs` of type `Array α` and any function `f : α → Option β`, the size of the filtered and mapped array `filterMap f xs` is positive if and only if there exists an element `x` in `xs` and a value `b : β` such that `f x = some b`.
Array.size_filterMap_lt_size_iff_exists theorem
{xs : Array α} {f : α → Option β} : (filterMap f xs).size < xs.size ↔ ∃ (x : α) (_ : x ∈ xs), f x = none
Full source
@[simp]
theorem size_filterMap_lt_size_iff_exists {xs : Array α} {f : α → Option β} :
    (filterMap f xs).size < xs.size ↔ ∃ (x : α) (_ : x ∈ xs), f x = none := by
  rcases xs with ⟨xs⟩
  simp
Size Reduction in `filterMap` iff Existence of `none` Values: $\text{size}(\text{filterMap } f \ xs) < \text{size}(xs) \leftrightarrow \exists x \in xs, f x = \text{none}$
Informal description
For any array `xs` of elements of type `α` and any function `f : α → Option β`, the size of the filtered and mapped array `filterMap f xs` is strictly less than the size of `xs` if and only if there exists an element `x ∈ xs` such that `f x = none`.
Array.singleton_def theorem
{v : α} : Array.singleton v = #[v]
Full source
@[simp] theorem singleton_def {v : α} : Array.singleton v = #[v] := rfl
Singleton Array Definition: $\text{singleton}(v) = \#[v]$
Informal description
For any element $v$ of type $\alpha$, the singleton array containing $v$ is equal to the array literal `#[v]`.
Array.size_append theorem
{xs ys : Array α} : (xs ++ ys).size = xs.size + ys.size
Full source
@[simp] theorem size_append {xs ys : Array α} : (xs ++ ys).size = xs.size + ys.size := by
  simp only [size, toList_append, List.length_append]
Size of Concatenated Arrays Equals Sum of Sizes
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, the size of the concatenated array $xs +\!\!+ ys$ equals the sum of the sizes of $xs$ and $ys$. In symbols: $$ \text{size}(xs +\!\!+ ys) = \text{size}(xs) + \text{size}(ys) $$
Array.push_append theorem
{a : α} {xs ys : Array α} : (xs ++ ys).push a = xs ++ ys.push a
Full source
@[simp] theorem push_append {a : α} {xs ys : Array α} : (xs ++ ys).push a = xs ++ ys.push a := by
  cases xs
  cases ys
  simp
Push-Distributivity Over Array Concatenation: $(xs +\!\!+ ys).\text{push}(a) = xs +\!\!+ ys.\text{push}(a)$
Informal description
For any element $a$ of type $\alpha$ and any arrays $xs$ and $ys$ of type $\text{Array } \alpha$, pushing $a$ to the concatenation of $xs$ and $ys$ is equal to concatenating $xs$ with the result of pushing $a$ to $ys$. In symbols: $$(xs +\!\!+ ys).\text{push}(a) = xs +\!\!+ (ys.\text{push}(a))$$
Array.append_push theorem
{xs ys : Array α} {a : α} : xs ++ ys.push a = (xs ++ ys).push a
Full source
theorem append_push {xs ys : Array α} {a : α} : xs ++ ys.push a = (xs ++ ys).push a := by
  cases xs
  cases ys
  simp
Array Concatenation and Push Commutativity: $xs +\!\!+ (ys.\text{push } a) = (xs +\!\!+ ys).\text{push } a$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$ and any element $a \in \alpha$, the concatenation of $xs$ with the array $ys$ after pushing $a$ to $ys$ is equal to pushing $a$ to the concatenation of $xs$ and $ys$. In symbols: $$ xs +\!\!+ (ys.\text{push } a) = (xs +\!\!+ ys).\text{push } a $$ where $+\!\!+$ denotes array concatenation and $\text{push}$ denotes appending an element to the end of an array.
Array.toArray_append theorem
{xs : List α} {ys : Array α} : xs.toArray ++ ys = (xs ++ ys.toList).toArray
Full source
theorem toArray_append {xs : List α} {ys : Array α} :
    xs.toArray ++ ys = (xs ++ ys.toList).toArray := by
  rcases ys with ⟨ys⟩
  simp
Array-List Conversion and Concatenation Compatibility: $\text{toArray}(xs) +\!\!+ ys = \text{toArray}(xs +\!\!+ \text{toList}(ys))$
Informal description
For any list `xs` of elements of type `α` and any array `ys` of elements of type `α`, the concatenation of the array conversion of `xs` with `ys` is equal to the array conversion of the concatenation of `xs` with the list conversion of `ys`. In symbols: $$\text{toArray}(xs) +\!\!+ ys = \text{toArray}(xs +\!\!+ \text{toList}(ys))$$ where $+\!\!+$ denotes array/list concatenation, $\text{toArray}$ converts a list to an array, and $\text{toList}$ converts an array to a list.
Array.toArray_eq_append_iff theorem
{xs : List α} {as bs : Array α} : xs.toArray = as ++ bs ↔ xs = as.toList ++ bs.toList
Full source
@[simp] theorem toArray_eq_append_iff {xs : List α} {as bs : Array α} :
    xs.toArray = as ++ bs ↔ xs = as.toList ++ bs.toList := by
  cases as
  cases bs
  simp
Equivalence of List-to-Array Conversion and Array Concatenation
Informal description
For any list `xs` of elements of type `α` and any arrays `as` and `bs` of elements of type `α`, the equality `xs.toArray = as ++ bs` holds if and only if `xs = as.toList ++ bs.toList`.
Array.append_eq_toArray_iff theorem
{xs ys : Array α} {as : List α} : xs ++ ys = as.toArray ↔ xs.toList ++ ys.toList = as
Full source
@[simp] theorem append_eq_toArray_iff {xs ys : Array α} {as : List α} :
    xs ++ ys = as.toArray ↔ xs.toList ++ ys.toList = as := by
  cases xs
  cases ys
  simp
Equivalence of Array Concatenation and List Conversion: $xs +\!\!+ ys = \text{toArray}(as) \leftrightarrow \text{toList}(xs) +\!\!+ \text{toList}(ys) = as$
Informal description
For any arrays `xs` and `ys` of elements of type $\alpha$, and any list `as` of elements of type $\alpha$, the concatenation of `xs` and `ys` equals the array conversion of `as` if and only if the concatenation of the list conversions of `xs` and `ys` equals `as`. In symbols: $$xs +\!\!+ ys = \text{toArray}(as) \leftrightarrow \text{toList}(xs) +\!\!+ \text{toList}(ys) = as$$ where $+\!\!+$ denotes array/list concatenation, $\text{toArray}$ converts a list to an array, and $\text{toList}$ converts an array to a list.
Array.singleton_eq_toArray_singleton theorem
{a : α} : #[a] = [a].toArray
Full source
theorem singleton_eq_toArray_singleton {a : α} : #[a] = [a].toArray := rfl
Equality of Singleton Array and List-to-Array Conversion
Informal description
For any element $a$ of type $\alpha$, the singleton array `#[a]` is equal to the array obtained by converting the singleton list `[a]` to an array.
Array.empty_append_fun theorem
: ((#[] : Array α) ++ ·) = id
Full source
@[simp] theorem empty_append_fun : ((#[] : Array α) ++ ·) = id := by
  funext ⟨l⟩
  simp
Concatenation with Empty Array is Identity Function
Informal description
For any type $\alpha$, the function that concatenates the empty array `#[]` with another array is equal to the identity function on arrays of type $\alpha$.
Array.mem_append theorem
{a : α} {xs ys : Array α} : a ∈ xs ++ ys ↔ a ∈ xs ∨ a ∈ ys
Full source
@[simp] theorem mem_append {a : α} {xs ys : Array α} : a ∈ xs ++ ysa ∈ xs ++ ys ↔ a ∈ xs ∨ a ∈ ys := by
  simp only [mem_def, toList_append, List.mem_append]
Membership in Concatenated Arrays: $a \in xs ++ ys \leftrightarrow a \in xs \lor a \in ys$
Informal description
For any element $a$ of type $\alpha$ and arrays $xs, ys$ of type $\text{Array}\ \alpha$, the element $a$ is in the concatenated array $xs ++ ys$ if and only if $a$ is in $xs$ or $a$ is in $ys$.
Array.mem_append_left theorem
{a : α} {xs : Array α} (ys : Array α) (h : a ∈ xs) : a ∈ xs ++ ys
Full source
theorem mem_append_left {a : α} {xs : Array α} (ys : Array α) (h : a ∈ xs) : a ∈ xs ++ ys :=
  mem_append.2 (Or.inl h)
Membership Preservation in Left Array Concatenation
Informal description
For any element $a$ of type $\alpha$ and arrays $xs, ys$ of type $\text{Array}\ \alpha$, if $a$ is in $xs$, then $a$ is in the concatenated array $xs ++ ys$.
Array.mem_append_right theorem
{a : α} (xs : Array α) {ys : Array α} (h : a ∈ ys) : a ∈ xs ++ ys
Full source
theorem mem_append_right {a : α} (xs : Array α) {ys : Array α} (h : a ∈ ys) : a ∈ xs ++ ys :=
  mem_append.2 (Or.inr h)
Membership Preservation in Right Array Concatenation
Informal description
For any element $a$ of type $\alpha$ and arrays $xs, ys$ of type $\text{Array}\ \alpha$, if $a$ is in $ys$, then $a$ is in the concatenated array $xs ++ ys$.
Array.not_mem_append theorem
{a : α} {xs ys : Array α} (h₁ : a ∉ xs) (h₂ : a ∉ ys) : a ∉ xs ++ ys
Full source
theorem not_mem_append {a : α} {xs ys : Array α} (h₁ : a ∉ xs) (h₂ : a ∉ ys) : a ∉ xs ++ ys :=
  mt mem_append.1 $ not_or.mpr ⟨h₁, h₂⟩
Negation of Membership in Concatenated Arrays: $a \notin xs \land a \notin ys \implies a \notin xs ++ ys$
Informal description
For any element $a$ of type $\alpha$ and arrays $xs, ys$ of type $\text{Array}\ \alpha$, if $a$ is not in $xs$ and $a$ is not in $ys$, then $a$ is not in the concatenated array $xs ++ ys$.
Array.append_of_mem theorem
{a : α} {xs : Array α} (h : a ∈ xs) : ∃ as bs : Array α, xs = as.push a ++ bs
Full source
/--
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 : α} {xs : Array α} (h : a ∈ xs) : ∃ as bs : Array α, xs = as.push a ++ bs := by
  obtain ⟨xs', ys', w⟩ := List.append_of_mem (l := xs.toList) (by simpa using h)
  replace w := congrArg List.toArray w
  refine ⟨xs'.toArray, ys'.toArray, by simp_all⟩
Decomposition of Array Containing Element into Push and Append
Informal description
For any element $a$ of type $\alpha$ and array $xs$ of type $\text{Array}\ \alpha$, if $a$ is an element of $xs$, then there exist arrays $as$ and $bs$ such that $xs$ can be expressed as the concatenation of $as.push\ a$ and $bs$.
Array.mem_iff_append theorem
{a : α} {xs : Array α} : a ∈ xs ↔ ∃ as bs : Array α, xs = as.push a ++ bs
Full source
theorem mem_iff_append {a : α} {xs : Array α} : a ∈ xsa ∈ xs ↔ ∃ as bs : Array α, xs = as.push a ++ bs :=
  ⟨append_of_mem, fun ⟨as, bs, e⟩ => e ▸ by simp⟩
Membership in Array Equivalent to Decomposition via Push and Append
Informal description
For any element $a$ of type $\alpha$ and array $xs$ of type $\text{Array}\ \alpha$, the element $a$ is in $xs$ if and only if there exist arrays $as$ and $bs$ such that $xs$ can be expressed as the concatenation of $as.\text{push}(a)$ and $bs$.
Array.forall_mem_append theorem
{p : α → Prop} {xs ys : Array α} : (∀ (x) (_ : x ∈ xs ++ ys), p x) ↔ (∀ (x) (_ : x ∈ xs), p x) ∧ (∀ (x) (_ : x ∈ ys), p x)
Full source
theorem forall_mem_append {p : α → Prop} {xs ys : Array α} :
    (∀ (x) (_ : x ∈ xs ++ ys), p x) ↔ (∀ (x) (_ : x ∈ xs), p x) ∧ (∀ (x) (_ : x ∈ ys), p x) := by
  simp only [mem_append, or_imp, forall_and]
Universal Quantifier over Concatenated Arrays Splits Conjunctively
Informal description
For any predicate $p : \alpha \to \text{Prop}$ and arrays $xs, ys : \text{Array}\ \alpha$, the following equivalence holds: \[ (\forall x \in xs \mathbin{+\!\!+} ys,\ p(x)) \leftrightarrow (\forall x \in xs,\ p(x)) \land (\forall x \in ys,\ p(x)) \] where $x \in A$ denotes that $x$ is an element of array $A$ and $\mathbin{+\!\!+}$ denotes array concatenation.
Array.getElem_append theorem
{xs ys : Array α} (h : i < (xs ++ ys).size) : (xs ++ ys)[i] = if h' : i < xs.size then xs[i] else ys[i - xs.size]'(by simp at h; omega)
Full source
theorem getElem_append {xs ys : Array α} (h : i < (xs ++ ys).size) :
    (xs ++ ys)[i] = if h' : i < xs.size then xs[i] else ys[i - xs.size]'(by simp at h; omega) := by
  cases xs; cases ys
  simp [List.getElem_append]
Element Access in Concatenated Arrays via Conditional Indexing
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, and any natural number index $i$ such that $i$ is less than the size of the concatenated array $xs +\!\!+ ys$, the element at index $i$ in $xs +\!\!+ ys$ is equal to: - $xs[i]$ if $i$ is less than the size of $xs$, or - $ys[i - \text{size}(xs)]$ otherwise. In symbols: $$ (xs +\!\!+ ys)[i] = \begin{cases} xs[i] & \text{if } i < \text{size}(xs) \\ ys[i - \text{size}(xs)] & \text{otherwise} \end{cases} $$
Array.getElem_append_left theorem
{xs ys : Array α} {h : i < (xs ++ ys).size} (hlt : i < xs.size) : (xs ++ ys)[i] = xs[i]
Full source
@[simp]
theorem getElem_append_left {xs ys : Array α} {h : i < (xs ++ ys).size} (hlt : i < xs.size) :
    (xs ++ ys)[i] = xs[i] := by
  simp only [← getElem_toList]
  have h' : i < (xs.toList ++ ys.toList).length := by rwa [← length_toList, toList_append] at h
  conv => rhs; rw [← List.getElem_append_left (bs := ys.toList) (h' := h')]
  apply List.get_of_eq; rw [toList_append]
Element Preservation in Left Array Concatenation
Informal description
For any arrays `xs` and `ys` of type `Array α` and index `i` such that `i` is less than the size of `xs ++ ys`, if `i` is also less than the size of `xs`, then the element at index `i` in the concatenated array `xs ++ ys` is equal to the element at index `i` in `xs`. That is, $(xs \mathbin{+\!\!+} ys)[i] = xs[i]$.
Array.getElem_append_right theorem
{xs ys : Array α} {h : i < (xs ++ ys).size} (hle : xs.size ≤ i) : (xs ++ ys)[i] = ys[i - xs.size]'(Nat.sub_lt_left_of_lt_add hle (size_append .. ▸ h))
Full source
@[simp]
theorem getElem_append_right {xs ys : Array α} {h : i < (xs ++ ys).size} (hle : xs.size ≤ i) :
    (xs ++ ys)[i] = ys[i - xs.size]'(Nat.sub_lt_left_of_lt_add hle (size_append .. ▸ h)) := by
  simp only [← getElem_toList]
  have h' : i < (xs.toList ++ ys.toList).length := by rwa [← length_toList, toList_append] at h
  conv => rhs; rw [← List.getElem_append_right (h₁ := hle) (h₂ := h')]
  apply List.get_of_eq; rw [toList_append]
Element Access in Concatenated Arrays Beyond First Array Size
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, and any natural number index $i$ such that $i$ is less than the size of $xs +\!\!+ ys$ and the size of $xs$ is less than or equal to $i$, the element at index $i$ in the concatenated array $xs +\!\!+ ys$ is equal to the element at index $i - \text{size}(xs)$ in $ys$. In symbols: $$ (xs +\!\!+ ys)[i] = ys[i - \text{size}(xs)] $$
Array.getElem?_append_left theorem
{xs ys : Array α} {i : Nat} (hn : i < xs.size) : (xs ++ ys)[i]? = xs[i]?
Full source
theorem getElem?_append_left {xs ys : Array α} {i : Nat} (hn : i < xs.size) :
    (xs ++ ys)[i]? = xs[i]? := by
  have hn' : i < (xs ++ ys).size := Nat.lt_of_lt_of_le hn <|
    size_append .. ▸ Nat.le_add_right ..
  simp_all [getElem?_eq_getElem, getElem_append]
Optional Element Access in Concatenated Arrays Within First Array Bounds: $(xs \mathbin{+\!\!+} ys)[i]? = xs[i]?$ for $i < \text{size}(xs)$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, and any natural number index $i$ such that $i$ is less than the size of $xs$, the optional element access $(xs \mathbin{+\!\!+} ys)[i]?$ is equal to $xs[i]?$. In other words, when accessing an element within the bounds of the first array in a concatenated array, the result is equivalent to accessing the corresponding position in the first array.
Array.getElem?_append_right theorem
{xs ys : Array α} {i : Nat} (h : xs.size ≤ i) : (xs ++ ys)[i]? = ys[i - xs.size]?
Full source
theorem getElem?_append_right {xs ys : Array α} {i : Nat} (h : xs.size ≤ i) :
    (xs ++ ys)[i]? = ys[i - xs.size]? := by
  cases xs
  cases ys
  simp at h
  simp [List.getElem?_append_right, h]
Optional Element Access in Concatenated Arrays Beyond First Array Size
Informal description
For any arrays `xs` and `ys` of type `Array α` and any natural number index `i` such that the size of `xs` is less than or equal to `i`, the optional element access `(xs ++ ys)[i]?` is equal to `ys[i - xs.size]?`. In other words, when accessing an element beyond the length of the first array in a concatenated array, the result is equivalent to accessing the corresponding position in the second array.
Array.getElem?_append theorem
{xs ys : Array α} {i : Nat} : (xs ++ ys)[i]? = if i < xs.size then xs[i]? else ys[i - xs.size]?
Full source
theorem getElem?_append {xs ys : Array α} {i : Nat} :
    (xs ++ ys)[i]? = if i < xs.size then xs[i]? else ys[i - xs.size]? := by
  split <;> rename_i h
  · exact getElem?_append_left h
  · exact getElem?_append_right (by simpa using h)
Optional Element Access in Concatenated Arrays: $(xs \mathbin{+\!\!+} ys)[i]? = \text{if } i < \text{size}(xs) \text{ then } xs[i]? \text{ else } ys[i - \text{size}(xs)]?$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, and any natural number index $i$, the optional element access $(xs \mathbin{+\!\!+} ys)[i]?$ is equal to $xs[i]?$ if $i < \text{size}(xs)$, and otherwise equal to $ys[i - \text{size}(xs)]?$. In other words, when accessing an element in a concatenated array, if the index is within the bounds of the first array, the result comes from the first array; otherwise, it comes from the corresponding position in the second array.
Array.getElem_append_left' theorem
{xs : Array α} {i : Nat} (hi : i < xs.size) (ys : Array α) : xs[i] = (xs ++ ys)[i]'(by simpa using Nat.lt_add_right ys.size hi)
Full source
/-- Variant of `getElem_append_left` useful for rewriting from the small array to the big array. -/
theorem getElem_append_left' {xs : Array α} {i : Nat} (hi : i < xs.size) (ys : Array α) :
    xs[i] = (xs ++ ys)[i]'(by simpa using Nat.lt_add_right ys.size hi) := by
  rw [getElem_append_left] <;> simp
Element Preservation in Left Array Concatenation (Rewriting Variant)
Informal description
For any array `xs` of type `Array α`, any index `i` such that `i < xs.size`, and any array `ys` of type `Array α`, the element at index `i` in `xs` is equal to the element at index `i` in the concatenated array `xs ++ ys`. That is, $xs[i] = (xs \mathbin{+\!\!+} ys)[i]$.
Array.getElem_append_right' theorem
(xs : Array α) {ys : Array α} {i : Nat} (hi : i < ys.size) : ys[i] = (xs ++ ys)[i + xs.size]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hi _)
Full source
/-- Variant of `getElem_append_right` useful for rewriting from the small array to the big array. -/
theorem getElem_append_right' (xs : Array α) {ys : Array α} {i : Nat} (hi : i < ys.size) :
    ys[i] = (xs ++ ys)[i + xs.size]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hi _) := by
  rw [getElem_append_right] <;> simp [*, Nat.le_add_left]
Element Access in Concatenated Arrays with Offset $i + \text{size}(xs)$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, and any natural number index $i$ such that $i$ is less than the size of $ys$, the element at index $i$ in $ys$ is equal to the element at index $i + \text{size}(xs)$ in the concatenated array $xs +\!\!+ ys$. In symbols: $$ ys[i] = (xs +\!\!+ ys)[i + \text{size}(xs)] $$
Array.getElem_of_append theorem
{xs ys zs : Array α} (eq : xs = ys.push a ++ zs) (h : ys.size = i) : xs[i]'(eq ▸ h ▸ by simp +arith) = a
Full source
theorem getElem_of_append {xs ys zs : Array α} (eq : xs = ys.push a ++ zs) (h : ys.size = i) :
    xs[i]'(eq ▸ h ▸ by simp +arith) = a := Option.some.inj <| by
  rw [← getElem?_eq_getElem, eq, getElem?_append_left (by simp; omega), ← h]
  simp
Element at Index $i$ in Concatenated Array Equals $a$ When $xs = ys.\text{push } a \mathbin{+\kern-1.5ex+} zs$ and $\text{size}(ys) = i$
Informal description
For any arrays $xs$, $ys$, and $zs$ of type $\text{Array } \alpha$, if $xs$ is equal to the concatenation of $ys.\text{push } a$ and $zs$, and the size of $ys$ equals $i$, then the element at index $i$ in $xs$ is equal to $a$. That is, $xs[i] = a$.
Array.append_singleton theorem
{a : α} {as : Array α} : as ++ #[a] = as.push a
Full source
@[simp] theorem append_singleton {a : α} {as : Array α} : as ++ #[a] = as.push a := rfl
Array Concatenation with Singleton Equals Push Operation
Informal description
For any element $a$ of type $\alpha$ and any array `as` of type `Array α`, the concatenation of `as` with the singleton array `#[a]` is equal to appending $a$ to `as` using the `push` operation. That is, $\text{as} \mathbin{+\kern-1.5ex+} \#[a] = \text{as.push}\ a$.
Array.append_singleton_assoc theorem
{a : α} {xs ys : Array α} : xs ++ (#[a] ++ ys) = xs.push a ++ ys
Full source
@[simp] theorem append_singleton_assoc {a : α} {xs ys : Array α} : xs ++ (#[a] ++ ys) = xs.push a ++ ys := by
  rw [← append_assoc, append_singleton]
Associativity of Array Concatenation with Singleton Push: $xs +\!\!+ ([a] +\!\!+ ys) = (xs.\text{push } a) +\!\!+ ys$
Informal description
For any element $a$ of type $\alpha$ and any arrays $xs$ and $ys$ of type $\text{Array } \alpha$, the concatenation of $xs$ with the concatenation of the singleton array $[a]$ and $ys$ is equal to the concatenation of $xs$ with $a$ pushed to it and $ys$. That is, $xs \mathbin{+\kern-1.5ex+} ([a] \mathbin{+\kern-1.5ex+} ys) = (xs.\text{push } a) \mathbin{+\kern-1.5ex+} ys$.
Array.push_eq_append theorem
{a : α} {as : Array α} : as.push a = as ++ #[a]
Full source
theorem push_eq_append {a : α} {as : Array α} : as.push a = as ++ #[a] := rfl
Equivalence of Push and Append with Singleton: `as.push a = as ++ #[a]`
Informal description
For any array `as` of type `Array α` and any element `a` of type `α`, appending `a` to `as` using the `push` operation is equivalent to concatenating `as` with the singleton array `#[a]` using the append operation `++`. That is, `as.push a = as ++ #[a]`.
Array.append_inj theorem
{xs₁ xs₂ ys₁ ys₂ : Array α} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ ∧ ys₁ = ys₂
Full source
theorem append_inj {xs₁ xs₂ ys₁ ys₂ : Array α} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) :
    xs₁ = xs₂ ∧ ys₁ = ys₂ := by
  rcases xs₁ with ⟨s₁⟩
  rcases xs₂ with ⟨s₂⟩
  rcases ys₁ with ⟨t₁⟩
  rcases ys₂ with ⟨t₂⟩
  simpa using List.append_inj (by simpa using h) (by simpa using hl)
Injectivity of Array Concatenation with Equal Prefix Lengths: $xs_1 +\!\!+ ys_1 = xs_2 +\!\!+ ys_2 \land |xs_1| = |xs_2| \Rightarrow xs_1 = xs_2 \land ys_1 = ys_2$
Informal description
For any arrays $xs_1, xs_2, ys_1, ys_2$ of type $\text{Array } \alpha$, if the concatenation $xs_1 +\!\!+ ys_1$ equals $xs_2 +\!\!+ ys_2$ and the sizes of $xs_1$ and $xs_2$ are equal, then $xs_1 = xs_2$ and $ys_1 = ys_2$.
Array.append_inj_right theorem
{xs₁ xs₂ ys₁ ys₂ : Array α} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : ys₁ = ys₂
Full source
theorem append_inj_right {xs₁ xs₂ ys₁ ys₂ : Array α}
    (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : ys₁ = ys₂ :=
  (append_inj h hl).right
Right Injectivity of Array Concatenation with Equal Prefix Lengths
Informal description
For any arrays $xs_1, xs_2, ys_1, ys_2$ of type $\text{Array } \alpha$, if the concatenation $xs_1 +\!\!+ ys_1$ equals $xs_2 +\!\!+ ys_2$ and the sizes of $xs_1$ and $xs_2$ are equal, then $ys_1 = ys_2$.
Array.append_inj_left theorem
{xs₁ xs₂ ys₁ ys₂ : Array α} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂
Full source
theorem append_inj_left {xs₁ xs₂ ys₁ ys₂ : Array α}
    (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ :=
  (append_inj h hl).left
Left Injectivity of Array Concatenation with Equal Prefix Lengths: $xs_1 +\!\!+ ys_1 = xs_2 +\!\!+ ys_2 \land |xs_1| = |xs_2| \Rightarrow xs_1 = xs_2$
Informal description
For any arrays $xs_1, xs_2, ys_1, ys_2$ of type $\text{Array } \alpha$, if the concatenation $xs_1 +\!\!+ ys_1$ equals $xs_2 +\!\!+ ys_2$ and the sizes of $xs_1$ and $xs_2$ are equal, then $xs_1 = xs_2$.
Array.append_inj' theorem
{xs₁ xs₂ ys₁ ys₂ : Array α} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : ys₁.size = ys₂.size) : xs₁ = xs₂ ∧ ys₁ = ys₂
Full source
/-- Variant of `append_inj` instead requiring equality of the sizes of the second arrays. -/
theorem append_inj' {xs₁ xs₂ ys₁ ys₂ : Array α} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : ys₁.size = ys₂.size) :
    xs₁ = xs₂ ∧ ys₁ = ys₂ :=
  append_inj h <| @Nat.add_right_cancel _ ys₁.size _ <| by
    let hap := congrArg size h; simp only [size_append, ← hl] at hap; exact hap
Injectivity of Array Concatenation with Equal Suffix Lengths: $xs_1 +\!\!+ ys_1 = xs_2 +\!\!+ ys_2 \land |ys_1| = |ys_2| \Rightarrow xs_1 = xs_2 \land ys_1 = ys_2$
Informal description
For any arrays $xs_1, xs_2, ys_1, ys_2$ of type $\text{Array } \alpha$, if the concatenation $xs_1 +\!\!+ ys_1$ equals $xs_2 +\!\!+ ys_2$ and the sizes of $ys_1$ and $ys_2$ are equal, then $xs_1 = xs_2$ and $ys_1 = ys_2$.
Array.append_inj_right' theorem
{xs₁ xs₂ ys₁ ys₂ : Array α} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : ys₁.size = ys₂.size) : ys₁ = ys₂
Full source
/-- Variant of `append_inj_right` instead requiring equality of the sizes of the second arrays. -/
theorem append_inj_right' {xs₁ xs₂ ys₁ ys₂ : Array α}
    (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : ys₁.size = ys₂.size) : ys₁ = ys₂ :=
  (append_inj' h hl).right
Right Injectivity of Array Concatenation with Equal Suffix Lengths: $xs_1 +\!\!+ ys_1 = xs_2 +\!\!+ ys_2 \land |ys_1| = |ys_2| \Rightarrow ys_1 = ys_2$
Informal description
For any arrays $xs_1, xs_2, ys_1, ys_2$ of type $\text{Array } \alpha$, if the concatenation $xs_1 +\!\!+ ys_1$ equals $xs_2 +\!\!+ ys_2$ and the sizes of $ys_1$ and $ys_2$ are equal, then $ys_1 = ys_2$.
Array.append_inj_left' theorem
{xs₁ xs₂ ys₁ ys₂ : Array α} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : ys₁.size = ys₂.size) : xs₁ = xs₂
Full source
/-- Variant of `append_inj_left` instead requiring equality of the sizes of the second arrays. -/
theorem append_inj_left' {xs₁ xs₂ ys₁ ys₂ : Array α}
    (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : ys₁.size = ys₂.size) : xs₁ = xs₂ :=
  (append_inj' h hl).left
Left Injectivity of Array Concatenation with Equal Suffix Lengths: $xs_1 +\!\!+ ys_1 = xs_2 +\!\!+ ys_2 \land |ys_1| = |ys_2| \Rightarrow xs_1 = xs_2$
Informal description
For any arrays $xs_1, xs_2, ys_1, ys_2$ of type $\text{Array } \alpha$, if the concatenation $xs_1 +\!\!+ ys_1$ equals $xs_2 +\!\!+ ys_2$ and the sizes of $ys_1$ and $ys_2$ are equal, then $xs_1 = xs_2$.
Array.append_right_inj theorem
{ys₁ ys₂ : Array α} (xs) : xs ++ ys₁ = xs ++ ys₂ ↔ ys₁ = ys₂
Full source
theorem append_right_inj {ys₁ ys₂ : Array α} (xs) : xs ++ ys₁ = xs ++ ys₂ ↔ ys₁ = ys₂ :=
  ⟨fun h => append_inj_right h rfl, congrArg _⟩
Right Injectivity of Array Concatenation: $xs +\!\!+ ys_1 = xs +\!\!+ ys_2 \leftrightarrow ys_1 = ys_2$
Informal description
For any arrays $ys_1, ys_2$ of type $\text{Array } \alpha$ and any array $xs$ of the same type, the concatenation $xs +\!\!+ ys_1$ equals $xs +\!\!+ ys_2$ if and only if $ys_1 = ys_2$.
Array.append_left_inj theorem
{xs₁ xs₂ : Array α} (ys) : xs₁ ++ ys = xs₂ ++ ys ↔ xs₁ = xs₂
Full source
theorem append_left_inj {xs₁ xs₂ : Array α} (ys) : xs₁ ++ ys = xs₂ ++ ys ↔ xs₁ = xs₂ :=
  ⟨fun h => append_inj_left' h rfl, congrArg (· ++ _)⟩
Left Injectivity of Array Concatenation: $xs_1 +\!\!+ ys = xs_2 +\!\!+ ys \leftrightarrow xs_1 = xs_2$
Informal description
For any arrays $xs_1, xs_2$ of type $\text{Array } \alpha$ and any array $ys$ of the same type, the concatenation $xs_1 +\!\!+ ys$ equals $xs_2 +\!\!+ ys$ if and only if $xs_1 = xs_2$.
Array.append_left_eq_self theorem
{xs ys : Array α} : xs ++ ys = ys ↔ xs = #[]
Full source
@[simp] theorem append_left_eq_self {xs ys : Array α} : xs ++ ys = ys ↔ xs = #[] := by
  rw [← append_left_inj (xs₁ := xs), empty_append]
Left Concatenation with Empty Array Preserves Second Array: $xs +\!\!+ ys = ys \leftrightarrow xs = []$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, the concatenation $xs +\!\!+ ys$ equals $ys$ if and only if $xs$ is the empty array. In other words, $xs +\!\!+ ys = ys \leftrightarrow xs = []$.
Array.self_eq_append_left theorem
{xs ys : Array α} : ys = xs ++ ys ↔ xs = #[]
Full source
@[simp] theorem self_eq_append_left {xs ys : Array α} : ys = xs ++ ys ↔ xs = #[] := by
  rw [eq_comm, append_left_eq_self]
Right Concatenation with Empty Array Preserves Original Array: $ys = xs +\!\!+ ys \leftrightarrow xs = []$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, the equality $ys = xs +\!\!+ ys$ holds if and only if $xs$ is the empty array. In other words, $ys = xs +\!\!+ ys \leftrightarrow xs = []$.
Array.append_right_eq_self theorem
{xs ys : Array α} : xs ++ ys = xs ↔ ys = #[]
Full source
@[simp] theorem append_right_eq_self {xs ys : Array α} : xs ++ ys = xs ↔ ys = #[] := by
  rw [← append_right_inj (ys₁ := ys), append_empty]
Right Concatenation with Empty Array Preserves Original Array: $xs +\!\!+ ys = xs \leftrightarrow ys = []$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, the concatenation $xs +\!\!+ ys$ equals $xs$ if and only if $ys$ is the empty array. In other words, $xs +\!\!+ ys = xs \leftrightarrow ys = []$.
Array.self_eq_append_right theorem
{xs ys : Array α} : xs = xs ++ ys ↔ ys = #[]
Full source
@[simp] theorem self_eq_append_right {xs ys : Array α} : xs = xs ++ ys ↔ ys = #[] := by
  rw [eq_comm, append_right_eq_self]
Right Concatenation with Empty Array Preserves Original Array: $xs = xs +\!\!+ ys \leftrightarrow ys = []$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, the equality $xs = xs +\!\!+ ys$ holds if and only if $ys$ is the empty array. In other words, $xs = xs +\!\!+ ys \leftrightarrow ys = []$.
Array.append_eq_empty_iff theorem
{xs ys : Array α} : xs ++ ys = #[] ↔ xs = #[] ∧ ys = #[]
Full source
@[simp] theorem append_eq_empty_iff {xs ys : Array α} : xs ++ ys = #[] ↔ xs = #[] ∧ ys = #[] := by
  cases xs <;> simp
Concatenation of Arrays is Empty if and Only if Both Arrays are Empty
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, the concatenation $xs ++ ys$ equals the empty array if and only if both $xs$ and $ys$ are empty arrays. In other words, $xs ++ ys = [] \leftrightarrow xs = [] \land ys = []$.
Array.empty_eq_append_iff theorem
{xs ys : Array α} : #[] = xs ++ ys ↔ xs = #[] ∧ ys = #[]
Full source
@[simp] theorem empty_eq_append_iff {xs ys : Array α} : #[]#[] = xs ++ ys ↔ xs = #[] ∧ ys = #[] := by
  rw [eq_comm, append_eq_empty_iff]
Empty Array Equals Concatenation if and Only if Both Arrays Are Empty
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, the empty array equals the concatenation $xs ++ ys$ if and only if both $xs$ and $ys$ are empty arrays. In other words, $[] = xs ++ ys \leftrightarrow xs = [] \land ys = []$.
Array.append_ne_empty_of_left_ne_empty theorem
{xs ys : Array α} (h : xs ≠ #[]) : xs ++ ys ≠ #[]
Full source
theorem append_ne_empty_of_left_ne_empty {xs ys : Array α} (h : xs ≠ #[]) : xs ++ ys ≠ #[] := by
  simp_all
Non-empty left array implies non-empty concatenation
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, if $xs$ is not the empty array, then the concatenation $xs ++ ys$ is also not the empty array.
Array.append_ne_empty_of_right_ne_empty theorem
{xs ys : Array α} (h : ys ≠ #[]) : xs ++ ys ≠ #[]
Full source
theorem append_ne_empty_of_right_ne_empty {xs ys : Array α} (h : ys ≠ #[]) : xs ++ ys ≠ #[] := by
  simp_all
Non-empty right array implies non-empty concatenation
Informal description
For any arrays $xs$ and $ys$ of type $\alpha$, if $ys$ is not the empty array, then the concatenation $xs ++ ys$ is also not the empty array.
Array.append_eq_push_iff theorem
{xs ys zs : Array α} {x : α} : xs ++ ys = zs.push x ↔ (ys = #[] ∧ xs = zs.push x) ∨ (∃ ys', ys = ys'.push x ∧ zs = xs ++ ys')
Full source
theorem append_eq_push_iff {xs ys zs : Array α} {x : α} :
    xs ++ ys = zs.push x ↔ (ys = #[] ∧ xs = zs.push x) ∨ (∃ ys', ys = ys'.push x ∧ zs = xs ++ ys') := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  rcases zs with ⟨zs⟩
  simp only [List.append_toArray, List.push_toArray, mk.injEq, List.append_eq_append_iff,
    toArray_eq_append_iff]
  constructor
  · rintro (⟨as, rfl, rfl⟩ | ⟨bs, rfl, h⟩)
    · right; exact ⟨⟨as⟩, by simp⟩
    · rw [List.singleton_eq_append_iff] at h
      obtain (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩) := h
      · right; exact ⟨#[], by simp⟩
      · left; simp
  · rintro (⟨rfl, rfl⟩ | ⟨bs, h, rfl⟩)
    · right; exact ⟨[x], by simp⟩
    · left; refine ⟨bs.toList, ?_⟩
      replace h := congrArg Array.toList h
      simp_all
Characterization of When Array Concatenation Equals Push Operation: $xs ++ ys = zs.push(x) \leftrightarrow (ys = \emptyset \land xs = zs.push(x)) \lor (\exists ys', ys = ys'.push(x) \land zs = xs ++ ys')$
Informal description
For any arrays $xs$, $ys$, $zs$ of elements of type $\alpha$ and any element $x : \alpha$, the concatenation $xs ++ ys$ equals $zs.push(x)$ if and only if either: 1. $ys$ is empty and $xs$ equals $zs.push(x)$, or 2. There exists an array $ys'$ such that $ys$ equals $ys'.push(x)$ and $zs$ equals $xs ++ ys'$.
Array.push_eq_append_iff theorem
{xs ys zs : Array α} {x : α} : zs.push x = xs ++ ys ↔ (ys = #[] ∧ xs = zs.push x) ∨ (∃ ys', ys = ys'.push x ∧ zs = xs ++ ys')
Full source
theorem push_eq_append_iff {xs ys zs : Array α} {x : α} :
    zs.push x = xs ++ ys ↔ (ys = #[] ∧ xs = zs.push x) ∨ (∃ ys', ys = ys'.push x ∧ zs = xs ++ ys') := by
  rw [eq_comm, append_eq_push_iff]
Characterization of Push as Concatenation: $zs.\text{push}(x) = xs ++ ys \leftrightarrow (ys = \emptyset \land xs = zs.\text{push}(x)) \lor (\exists ys', ys = ys'.\text{push}(x) \land zs = xs ++ ys')$
Informal description
For any arrays $xs$, $ys$, $zs$ of elements of type $\alpha$ and any element $x \in \alpha$, the equality $zs.\text{push}(x) = xs ++ ys$ holds if and only if either: 1. $ys$ is empty and $xs = zs.\text{push}(x)$, or 2. There exists an array $ys'$ such that $ys = ys'.\text{push}(x)$ and $zs = xs ++ ys'$.
Array.append_eq_singleton_iff theorem
{xs ys : Array α} {x : α} : xs ++ ys = #[x] ↔ (xs = #[] ∧ ys = #[x]) ∨ (xs = #[x] ∧ ys = #[])
Full source
theorem append_eq_singleton_iff {xs ys : Array α} {x : α} :
    xs ++ ys = #[x] ↔ (xs = #[] ∧ ys = #[x]) ∨ (xs = #[x] ∧ ys = #[]) := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp only [List.append_toArray, mk.injEq, List.append_eq_singleton_iff, toArray_eq_append_iff]
Characterization of Singleton Arrays via Concatenation: $xs ++ ys = [x] \leftrightarrow (xs = [] \land ys = [x]) \lor (xs = [x] \land ys = [])$
Informal description
For any arrays `xs` and `ys` of type `α` and any element `x : α`, the concatenation `xs ++ ys` equals the singleton array `#[x]` if and only if either: 1. `xs` is empty and `ys` is the singleton array `#[x]`, or 2. `xs` is the singleton array `#[x]` and `ys` is empty.
Array.singleton_eq_append_iff theorem
{xs ys : Array α} {x : α} : #[x] = xs ++ ys ↔ (xs = #[] ∧ ys = #[x]) ∨ (xs = #[x] ∧ ys = #[])
Full source
theorem singleton_eq_append_iff {xs ys : Array α} {x : α} :
    #[x]#[x] = xs ++ ys ↔ (xs = #[] ∧ ys = #[x]) ∨ (xs = #[x] ∧ ys = #[]) := by
  rw [eq_comm, append_eq_singleton_iff]
Characterization of Singleton Arrays via Concatenation: $[x] = xs +\!\!+ ys$
Informal description
For any arrays `xs` and `ys` of type `α` and any element `x : α`, the singleton array `#[x]` equals the concatenation `xs ++ ys` if and only if either: 1. `xs` is empty and `ys` is the singleton array `#[x]`, or 2. `xs` is the singleton array `#[x]` and `ys` is empty.
Array.append_eq_append_iff theorem
{ws xs ys zs : Array α} : ws ++ xs = ys ++ zs ↔ (∃ as, ys = ws ++ as ∧ xs = as ++ zs) ∨ ∃ cs, ws = ys ++ cs ∧ zs = cs ++ xs
Full source
theorem append_eq_append_iff {ws xs ys zs : Array α} :
    ws ++ xs = ys ++ zs ↔ (∃ as, ys = ws ++ as ∧ xs = as ++ zs) ∨ ∃ cs, ws = ys ++ cs ∧ zs = cs ++ xs := by
  rcases ws with ⟨ws⟩
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  rcases zs with ⟨zs⟩
  simp only [List.append_toArray, mk.injEq, List.append_eq_append_iff, toArray_eq_append_iff]
  constructor
  · rintro (⟨as, rfl, rfl⟩ | ⟨cs, rfl, rfl⟩)
    · left; exact ⟨⟨as⟩, by simp⟩
    · right; exact ⟨⟨cs⟩, by simp⟩
  · rintro (⟨as, rfl, rfl⟩ | ⟨cs, rfl, rfl⟩)
    · left; exact ⟨as.toList, by simp⟩
    · right; exact ⟨cs.toList, by simp⟩
Characterization of Array Concatenation Equality: $ws +\!\!+ xs = ys +\!\!+ zs$
Informal description
For any arrays $ws$, $xs$, $ys$, $zs$ of elements of type $\alpha$, the concatenation $ws +\!\!+ xs$ equals $ys +\!\!+ zs$ if and only if either: 1. There exists an array $as$ such that $ys = ws +\!\!+ as$ and $xs = as +\!\!+ zs$, or 2. There exists an array $cs$ such that $ws = ys +\!\!+ cs$ and $zs = cs +\!\!+ xs$.
Array.set_append theorem
{xs ys : Array α} {i : Nat} {x : α} (h : i < (xs ++ ys).size) : (xs ++ ys).set i x = if h' : i < xs.size then xs.set i x ++ ys else xs ++ ys.set (i - xs.size) x (by simp at h; omega)
Full source
theorem set_append {xs ys : Array α} {i : Nat} {x : α} (h : i < (xs ++ ys).size) :
    (xs ++ ys).set i x =
      if h' : i < xs.size then
        xs.set i x ++ ys
      else
        xs ++ ys.set (i - xs.size) x (by simp at h; omega) := by
  rcases xs with ⟨s⟩
  rcases ys with ⟨t⟩
  simp only [List.append_toArray, List.set_toArray, List.set_append]
  split <;> simp
Element Replacement in Concatenated Arrays: $(xs +\!\!+ ys).\text{set}\ i\ x$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, any index $i \in \mathbb{N}$, and any element $x \in \alpha$, if $i$ is within the bounds of the concatenated array $xs +\!\!+ ys$ (i.e., $i < \text{size}(xs +\!\!+ ys)$), then setting the element at index $i$ in $xs +\!\!+ ys$ to $x$ is equivalent to: - If $i$ is within the bounds of $xs$ (i.e., $i < \text{size}(xs)$), then setting the element at index $i$ in $xs$ to $x$ and then concatenating with $ys$; - Otherwise, concatenating $xs$ with $ys$ where the element at index $i - \text{size}(xs)$ is set to $x$. In symbols: $$ (xs +\!\!+ ys).\text{set}\ i\ x = \begin{cases} xs.\text{set}\ i\ x +\!\!+ ys & \text{if } i < \text{size}(xs) \\ xs +\!\!+ ys.\text{set}\ (i - \text{size}(xs))\ x & \text{otherwise} \end{cases} $$
Array.set_append_left theorem
{xs ys : Array α} {i : Nat} {x : α} (h : i < xs.size) : (xs ++ ys).set i x (by simp; omega) = xs.set i x ++ ys
Full source
@[simp] theorem set_append_left {xs ys : Array α} {i : Nat} {x : α} (h : i < xs.size) :
    (xs ++ ys).set i x (by simp; omega) = xs.set i x ++ ys := by
  simp [set_append, h]
Left Array Modification in Concatenation: $(xs +\!\!+ ys).\text{set}\ i\ x = xs.\text{set}\ i\ x +\!\!+ ys$ when $i < \text{size}(xs)$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, any index $i \in \mathbb{N}$, and any element $x \in \alpha$, if $i$ is within the bounds of $xs$ (i.e., $i < \text{size}(xs)$), then setting the element at index $i$ in the concatenated array $xs +\!\!+ ys$ to $x$ is equivalent to setting the element at index $i$ in $xs$ to $x$ and then concatenating with $ys$. In symbols: $$ (xs +\!\!+ ys).\text{set}\ i\ x = xs.\text{set}\ i\ x +\!\!+ ys \quad \text{when } i < \text{size}(xs) $$
Array.set_append_right theorem
{xs ys : Array α} {i : Nat} {x : α} (h' : i < (xs ++ ys).size) (h : xs.size ≤ i) : (xs ++ ys).set i x = xs ++ ys.set (i - xs.size) x (by simp at h'; omega)
Full source
@[simp] theorem set_append_right {xs ys : Array α} {i : Nat} {x : α}
    (h' : i < (xs ++ ys).size) (h : xs.size ≤ i) :
    (xs ++ ys).set i x = xs ++ ys.set (i - xs.size) x (by simp at h'; omega) := by
  rw [set_append, dif_neg (by omega)]
Element Replacement in Right Part of Concatenated Arrays
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, any index $i \in \mathbb{N}$, and any element $x \in \alpha$, if $i$ is within the bounds of the concatenated array $xs +\!\!+ ys$ (i.e., $i < \text{size}(xs +\!\!+ ys)$) and $i$ is not less than the size of $xs$ (i.e., $\text{size}(xs) \leq i$), then setting the element at index $i$ in $xs +\!\!+ ys$ to $x$ is equivalent to concatenating $xs$ with $ys$ where the element at index $i - \text{size}(xs)$ is set to $x$. In symbols: $$ (xs +\!\!+ ys).\text{set}\ i\ x = xs +\!\!+ ys.\text{set}\ (i - \text{size}(xs))\ x $$
Array.setIfInBounds_append theorem
{xs ys : Array α} {i : Nat} {x : α} : (xs ++ ys).setIfInBounds i x = if i < xs.size then xs.setIfInBounds i x ++ ys else xs ++ ys.setIfInBounds (i - xs.size) x
Full source
theorem setIfInBounds_append {xs ys : Array α} {i : Nat} {x : α} :
    (xs ++ ys).setIfInBounds i x =
      if i < xs.size then
        xs.setIfInBounds i x ++ ys
      else
        xs ++ ys.setIfInBounds (i - xs.size) x := by
  rcases xs with ⟨s⟩
  rcases ys with ⟨t⟩
  simp only [List.append_toArray, List.setIfInBounds_toArray, List.set_append]
  split <;> simp
Conditional Element Setting in Concatenated Arrays: $(xs \mathbin{+\kern-1.5pt+} ys).\text{setIfInBounds}\ i\ x$
Informal description
For any arrays `xs` and `ys` of type `α`, any index `i : ℕ`, and any element `x : α`, the operation of conditionally setting `x` at index `i` in the concatenated array `xs ++ ys` is equivalent to: - If `i` is within the bounds of `xs` (`i < xs.size`), then set `x` at index `i` in `xs` and concatenate with `ys`. - Otherwise, concatenate `xs` with the result of setting `x` at index `i - xs.size` in `ys`. In mathematical notation: $$(xs \mathbin{+\kern-1.5pt+} ys).\text{setIfInBounds}\ i\ x = \begin{cases} xs.\text{setIfInBounds}\ i\ x \mathbin{+\kern-1.5pt+} ys & \text{if } i < xs.\text{size} \\ xs \mathbin{+\kern-1.5pt+} ys.\text{setIfInBounds}\ (i - xs.\text{size})\ x & \text{otherwise} \end{cases}$$
Array.setIfInBounds_append_left theorem
{xs ys : Array α} {i : Nat} {x : α} (h : i < xs.size) : (xs ++ ys).setIfInBounds i x = xs.setIfInBounds i x ++ ys
Full source
@[simp] theorem setIfInBounds_append_left {xs ys : Array α} {i : Nat} {x : α} (h : i < xs.size) :
    (xs ++ ys).setIfInBounds i x = xs.setIfInBounds i x ++ ys := by
  simp [setIfInBounds_append, h]
Conditional Element Setting in Left Part of Concatenated Arrays
Informal description
For any arrays $xs$ and $ys$ of type $\alpha$, any index $i \in \mathbb{N}$, and any element $x \in \alpha$, if $i$ is less than the size of $xs$, then setting $x$ at index $i$ in the concatenated array $xs \mathbin{+\kern-1.5pt+} ys$ (if $i$ is in bounds) is equal to first setting $x$ at index $i$ in $xs$ (if $i$ is in bounds) and then concatenating with $ys$. In mathematical notation: $$(xs \mathbin{+\kern-1.5pt+} ys).\text{setIfInBounds}\ i\ x = xs.\text{setIfInBounds}\ i\ x \mathbin{+\kern-1.5pt+} ys \quad \text{when } i < xs.\text{size}$$
Array.setIfInBounds_append_right theorem
{xs ys : Array α} {i : Nat} {x : α} (h : xs.size ≤ i) : (xs ++ ys).setIfInBounds i x = xs ++ ys.setIfInBounds (i - xs.size) x
Full source
@[simp] theorem setIfInBounds_append_right {xs ys : Array α} {i : Nat} {x : α} (h : xs.size ≤ i) :
    (xs ++ ys).setIfInBounds i x = xs ++ ys.setIfInBounds (i - xs.size) x := by
  rw [setIfInBounds_append, if_neg (by omega)]
Conditional Element Setting in Right Part of Concatenated Arrays
Informal description
For any arrays $xs$ and $ys$ of type $\alpha$, any index $i \in \mathbb{N}$, and any element $x \in \alpha$, if the size of $xs$ is less than or equal to $i$, then setting $x$ at index $i$ in the concatenated array $xs \mathbin{+\kern-1.5pt+} ys$ (if $i$ is in bounds) is equal to concatenating $xs$ with the result of setting $x$ at index $i - \text{size}(xs)$ in $ys$. In mathematical notation: $$(xs \mathbin{+\kern-1.5pt+} ys).\text{setIfInBounds}\ i\ x = xs \mathbin{+\kern-1.5pt+} ys.\text{setIfInBounds}\ (i - \text{size}(xs))\ x \quad \text{when } \text{size}(xs) \leq i$$
Array.filterMap_eq_append_iff theorem
{f : α → Option β} : filterMap f xs = ys ++ zs ↔ ∃ as bs, xs = as ++ bs ∧ filterMap f as = ys ∧ filterMap f bs = zs
Full source
theorem filterMap_eq_append_iff {f : α → Option β} :
    filterMapfilterMap f xs = ys ++ zs ↔ ∃ as bs, xs = as ++ bs ∧ filterMap f as = ys ∧ filterMap f bs = zs := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  rcases zs with ⟨zs⟩
  simp only [List.size_toArray, List.filterMap_toArray', List.append_toArray, mk.injEq,
    List.filterMap_eq_append_iff, toArray_eq_append_iff]
  constructor
  · rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
    exact ⟨⟨l₁⟩, ⟨l₂⟩, by simp⟩
  · rintro ⟨⟨l₁⟩, ⟨l₂⟩, rfl, h₁, h₂⟩
    exact ⟨l₁, l₂, by simp_all⟩
Decomposition of Filtered-Mapped Array into Concatenated Parts
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and arrays $\text{xs}, \text{ys}, \text{zs}$ of type $\text{Array } \alpha$, the filtered and mapped array $\text{filterMap } f \ \text{xs}$ equals the concatenation $\text{ys} +\!\!+ \text{zs}$ if and only if there exist arrays $\text{as}, \text{bs}$ such that $\text{xs} = \text{as} +\!\!+ \text{bs}$ and $\text{filterMap } f \ \text{as} = \text{ys}$ and $\text{filterMap } f \ \text{bs} = \text{zs}$.
Array.append_eq_filterMap_iff theorem
{f : α → Option β} : xs ++ ys = filterMap f zs ↔ ∃ as bs, zs = as ++ bs ∧ filterMap f as = xs ∧ filterMap f bs = ys
Full source
theorem append_eq_filterMap_iff {f : α → Option β} :
    xs ++ ys = filterMap f zs ↔
      ∃ as bs, zs = as ++ bs ∧ filterMap f as = xs ∧ filterMap f bs = ys := by
  rw [eq_comm, filterMap_eq_append_iff]
Concatenation Equals Filtered-Mapped Array Decomposition: $\text{xs} +\!\!+ \text{ys} = \text{filterMap } f \ \text{zs} \leftrightarrow \exists \text{as}, \text{bs}, \text{zs} = \text{as} +\!\!+ \text{bs} \land \text{filterMap } f \ \text{as} = \text{xs} \land \text{filterMap } f \ \text{bs} = \text{ys}$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and arrays $\text{xs}, \text{ys}, \text{zs}$ of type $\text{Array } \alpha$, the concatenation $\text{xs} +\!\!+ \text{ys}$ equals the filtered and mapped array $\text{filterMap } f \ \text{zs}$ if and only if there exist arrays $\text{as}, \text{bs}$ such that: 1. $\text{zs} = \text{as} +\!\!+ \text{bs}$, 2. $\text{filterMap } f \ \text{as} = \text{xs}$, 3. $\text{filterMap } f \ \text{bs} = \text{ys}$.
Array.map_append theorem
{f : α → β} {xs ys : Array α} : map f (xs ++ ys) = map f xs ++ map f ys
Full source
@[simp] theorem map_append {f : α → β} {xs ys : Array α} :
    map f (xs ++ ys) = map f xs ++ map f ys := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp
Mapping Preserves Array Concatenation: $\text{map } f (\text{xs} +\!\!+ \text{ys}) = \text{map } f \ \text{xs} +\!\!+ \text{map } f \ \text{ys}$
Informal description
For any function $f : \alpha \to \beta$ and arrays $\text{xs}, \text{ys}$ of type $\text{Array } \alpha$, the mapping of $f$ over the concatenated array $\text{xs} +\!\!+ \text{ys}$ is equal to the concatenation of the mapped arrays $\text{map } f \ \text{xs} +\!\!+ \text{map } f \ \text{ys}$.
Array.map_eq_append_iff theorem
{f : α → β} : map f xs = ys ++ zs ↔ ∃ as bs, xs = as ++ bs ∧ map f as = ys ∧ map f bs = zs
Full source
theorem map_eq_append_iff {f : α → β} :
    mapmap f xs = ys ++ zs ↔ ∃ as bs, xs = as ++ bs ∧ map f as = ys ∧ map f bs = zs := by
  simp only [← filterMap_eq_map, filterMap_eq_append_iff]
Characterization of Mapped Array as Concatenation: $\text{map}\ f\ \text{xs} = \text{ys} +\!\!+ \text{zs} \leftrightarrow \exists \text{as}\ \text{bs}, \text{xs} = \text{as} +\!\!+ \text{bs} \land \text{map}\ f\ \text{as} = \text{ys} \land \text{map}\ f\ \text{bs} = \text{zs}$
Informal description
For any function $f : \alpha \to \beta$ and arrays `xs`, `ys`, `zs` of appropriate types, the mapped array $\text{map}\ f\ \text{xs}$ equals the concatenation $\text{ys} +\!\!+ \text{zs}$ if and only if there exist arrays $\text{as}, \text{bs}$ such that: 1. $\text{xs} = \text{as} +\!\!+ \text{bs}$, 2. $\text{map}\ f\ \text{as} = \text{ys}$, 3. $\text{map}\ f\ \text{bs} = \text{zs}$.
Array.append_eq_map_iff theorem
{f : α → β} : xs ++ ys = map f zs ↔ ∃ as bs, zs = as ++ bs ∧ map f as = xs ∧ map f bs = ys
Full source
theorem append_eq_map_iff {f : α → β} :
    xs ++ ys = map f zs ↔ ∃ as bs, zs = as ++ bs ∧ map f as = xs ∧ map f bs = ys := by
  rw [eq_comm, map_eq_append_iff]
Characterization of Concatenation as Mapped Array: $\text{xs} +\!\!+ \text{ys} = \text{map}\ f\ \text{zs} \leftrightarrow \exists \text{as}, \text{bs}, \text{zs} = \text{as} +\!\!+ \text{bs} \land \text{map}\ f\ \text{as} = \text{xs} \land \text{map}\ f\ \text{bs} = \text{ys}$
Informal description
For any function $f : \alpha \to \beta$ and arrays $\text{xs}, \text{ys}, \text{zs}$ of appropriate types, the concatenation $\text{xs} +\!\!+ \text{ys}$ equals the mapped array $\text{map}\ f\ \text{zs}$ if and only if there exist arrays $\text{as}, \text{bs}$ such that: 1. $\text{zs} = \text{as} +\!\!+ \text{bs}$, 2. $\text{map}\ f\ \text{as} = \text{xs}$, 3. $\text{map}\ f\ \text{bs} = \text{ys}$.
Array.flatten_empty theorem
: (#[] : Array (Array α)).flatten = #[]
Full source
@[simp] theorem flatten_empty : (#[] : Array (Array α)).flatten = #[] := by simp [flatten]; rfl
Flattening of Empty Array Yields Empty Array
Informal description
The flattening of an empty array of arrays (of type `Array (Array α)`) results in an empty array (of type `Array α`). In other words, $\text{flatten}(\#[]) = \#[]$.
Array.toList_flatten theorem
{xss : Array (Array α)} : xss.flatten.toList = (xss.toList.map toList).flatten
Full source
@[simp] theorem toList_flatten {xss : Array (Array α)} :
    xss.flatten.toList = (xss.toList.map toList).flatten := by
  dsimp [flatten]
  simp only [← foldl_toList]
  generalize xss.toList = l
  have : ∀ as : Array α, (List.foldl ?_ as l).toList = as.toList ++ ?_ := ?_
  exact this #[]
  induction l with
  | nil => simp
  | cons as => induction as.toList <;> simp [*]
Flattening Commutes with List Conversion for Arrays of Arrays
Informal description
For any array of arrays `xss` of type `Array (Array α)`, the list obtained by first flattening `xss` and then converting to a list is equal to the list obtained by first converting `xss` to a list of lists, mapping each inner array to a list, and then flattening the resulting list of lists. In symbols: $$\text{toList}(\text{flatten}(xss)) = \text{flatten}(\text{map toList}(\text{toList}(xss)))$$
Array.flatten_map_toArray theorem
{L : List (List α)} : (L.toArray.map List.toArray).flatten = L.flatten.toArray
Full source
@[simp] theorem flatten_map_toArray {L : List (List α)} :
    (L.toArray.map List.toArray).flatten = L.flatten.toArray := by
  apply ext'
  simp [Function.comp_def]
Flattening Commutes with Array Conversion and Mapping: $\text{flatten}(L.\text{toArray}.\text{map List.toArray}) = L.\text{flatten}.\text{toArray}$
Informal description
For any list of lists $L$ of elements of type $\alpha$, the flattening of the array obtained by converting $L$ to an array and then mapping each inner list to an array is equal to the array obtained by first flattening $L$ and then converting to an array. In symbols: $$\text{flatten}(L.\text{toArray}.\text{map List.toArray}) = L.\text{flatten}.\text{toArray}$$
Array.flatten_toArray_map theorem
{L : List (List α)} : (L.map List.toArray).toArray.flatten = L.flatten.toArray
Full source
@[simp] theorem flatten_toArray_map {L : List (List α)} :
    (L.map List.toArray).toArray.flatten = L.flatten.toArray := by
  rw [← flatten_map_toArray]
  simp
Flattening Commutes with List-to-Array Conversion and Mapping: $\text{flatten}((L.\text{map List.toArray}).\text{toArray}) = L.\text{flatten}.\text{toArray}$
Informal description
For any list of lists $L$ of elements of type $\alpha$, the flattening of the array obtained by first mapping each inner list in $L$ to an array and then converting the resulting list of arrays to an array is equal to the array obtained by first flattening $L$ and then converting to an array. In symbols: $$\text{flatten}((L.\text{map List.toArray}).\text{toArray}) = L.\text{flatten}.\text{toArray}$$
Array.flatten_toArray theorem
{l : List (Array α)} : l.toArray.flatten = (l.map Array.toList).flatten.toArray
Full source
@[simp 500] theorem flatten_toArray {l : List (Array α)} :
    l.toArray.flatten = (l.map Array.toList).flatten.toArray := by
  apply ext'
  simp
Flattening Commutes with Array-List Conversion
Informal description
For any list `l` of arrays of type `Array α`, the flattening of the array obtained by converting `l` to an array is equal to the array obtained by first mapping each array in `l` to a list, flattening the resulting list of lists, and then converting back to an array. In symbols: $$\text{flatten}(\text{toArray}(l)) = \text{toArray}(\text{flatten}(\text{map toList}(l)))$$
Array.size_flatten theorem
{xss : Array (Array α)} : xss.flatten.size = (xss.map size).sum
Full source
@[simp] theorem size_flatten {xss : Array (Array α)} : xss.flatten.size = (xss.map size).sum := by
  cases xss using array₂_induction
  simp [Function.comp_def]
Size of Flattened Array Equals Sum of Component Sizes
Informal description
For any array of arrays `xss` of type `Array (Array α)`, the size of the flattened array `xss.flatten` is equal to the sum of the sizes of the individual arrays in `xss`. In symbols: $$\text{size}(\text{flatten}(xss)) = \sum_{xs \in xss} \text{size}(xs)$$
Array.flatten_singleton theorem
{xs : Array α} : #[xs].flatten = xs
Full source
@[simp] theorem flatten_singleton {xs : Array α} : #[xs].flatten = xs := by simp [flatten]; rfl
Flattening a Singleton Array Yields Its Element
Informal description
For any array `xs` of type `α`, flattening the singleton array `#[xs]` results in `xs` itself, i.e., `#[xs].flatten = xs`.
Array.mem_flatten theorem
: ∀ {xss : Array (Array α)}, a ∈ xss.flatten ↔ ∃ xs, xs ∈ xss ∧ a ∈ xs
Full source
theorem mem_flatten : ∀ {xss : Array (Array α)}, a ∈ xss.flattena ∈ xss.flatten ↔ ∃ xs, xs ∈ xss ∧ a ∈ xs := by
  simp only [mem_def, toList_flatten, List.mem_flatten, List.mem_map]
  intro xss
  constructor
  · rintro ⟨_, ⟨xs, m, rfl⟩, h⟩
    exact ⟨xs, m, h⟩
  · rintro ⟨xs, h₁, h₂⟩
    refine ⟨xs.toList, ⟨⟨xs, h₁, rfl⟩, h₂⟩⟩
Membership in Flattened Array of Arrays
Informal description
For any array of arrays `xss` of type `Array (Array α)` and any element `a` of type `α`, the element `a` belongs to the flattened array `xss.flatten` if and only if there exists an array `xs` in `xss` such that `a` is an element of `xs`. In symbols: $$a \in \text{flatten}(xss) \leftrightarrow \exists xs \in xss, a \in xs$$
Array.flatten_eq_empty_iff theorem
{xss : Array (Array α)} : xss.flatten = #[] ↔ ∀ xs ∈ xss, xs = #[]
Full source
@[simp] theorem flatten_eq_empty_iff {xss : Array (Array α)} : xss.flatten = #[] ↔ ∀ xs ∈ xss, xs = #[] := by
  induction xss using array₂_induction
  simp
Empty Flattened Array Equivalence: $\text{flatten}(xss) = \text{#[]} \leftrightarrow \forall xs \in xss, xs = \text{#[]}$
Informal description
For any array of arrays `xss` of type `Array (Array α)`, the flattened array `xss.flatten` is empty if and only if every array `xs` in `xss` is empty. In symbols: $$\text{flatten}(xss) = \text{#[]} \leftrightarrow \forall xs \in xss, xs = \text{#[]}$$
Array.empty_eq_flatten_iff theorem
{xss : Array (Array α)} : #[] = xss.flatten ↔ ∀ xs ∈ xss, xs = #[]
Full source
@[simp] theorem empty_eq_flatten_iff {xss : Array (Array α)} : #[]#[] = xss.flatten ↔ ∀ xs ∈ xss, xs = #[] := by
  rw [eq_comm, flatten_eq_empty_iff]
Empty Array Equivalence for Flattened Arrays: $\text{#[]} = \text{flatten}(xss) \leftrightarrow \forall xs \in xss, xs = \text{#[]}$
Informal description
For any array of arrays `xss` of type `Array (Array α)`, the empty array `#[]` is equal to the flattened array `xss.flatten` if and only if every array `xs` in `xss` is empty. In symbols: $$\text{#[]} = \text{flatten}(xss) \leftrightarrow \forall xs \in xss, xs = \text{#[]}$$
Array.flatten_ne_empty_iff theorem
{xss : Array (Array α)} : xss.flatten ≠ #[] ↔ ∃ xs, xs ∈ xss ∧ xs ≠ #[]
Full source
theorem flatten_ne_empty_iff {xss : Array (Array α)} : xss.flatten ≠ #[]xss.flatten ≠ #[] ↔ ∃ xs, xs ∈ xss ∧ xs ≠ #[] := by
  simp
Non-emptiness of Flattened Array of Arrays
Informal description
For any array of arrays `xss` of type `Array (Array α)`, the flattened array `xss.flatten` is not empty if and only if there exists an array `xs` in `xss` such that `xs` is not empty.
Array.exists_of_mem_flatten theorem
: x ∈ flatten xss → ∃ xs, xs ∈ xss ∧ x ∈ xs
Full source
theorem exists_of_mem_flatten : x ∈ flatten xss∃ xs, xs ∈ xss ∧ x ∈ xs := mem_flatten.1
Existence of Containing Array in Flattened Structure
Informal description
For any element $x$ in the flattened array $\text{flatten}(xss)$ (where $xss$ is an array of arrays), there exists an array $xs$ in $xss$ such that $x$ is an element of $xs$. In symbols: $$x \in \text{flatten}(xss) \implies \exists xs \in xss, x \in xs$$
Array.mem_flatten_of_mem theorem
(ml : xs ∈ xss) (ma : a ∈ xs) : a ∈ flatten xss
Full source
theorem mem_flatten_of_mem (ml : xs ∈ xss) (ma : a ∈ xs) : a ∈ flatten xss := mem_flatten.2 ⟨xs, ml, ma⟩
Element in Subarray Implies Element in Flattened Array
Informal description
For any array of arrays `xss` of type `Array (Array α)`, if an array `xs` is an element of `xss` and an element `a` is in `xs`, then `a` is also in the flattened array `xss.flatten`. In symbols: $$\text{If } xs \in xss \text{ and } a \in xs, \text{ then } a \in \text{flatten}(xss).$$
Array.forall_mem_flatten theorem
{p : α → Prop} {xss : Array (Array α)} : (∀ (x) (_ : x ∈ flatten xss), p x) ↔ ∀ (xs) (_ : xs ∈ xss) (x) (_ : x ∈ xs), p x
Full source
theorem forall_mem_flatten {p : α → Prop} {xss : Array (Array α)} :
    (∀ (x) (_ : x ∈ flatten xss), p x) ↔ ∀ (xs) (_ : xs ∈ xss) (x) (_ : x ∈ xs), p x := by
  simp only [mem_flatten, forall_exists_index, and_imp]
  constructor <;> (intros; solve_by_elim)
Universal Quantification over Flattened Array Elements
Informal description
For any predicate $p$ on elements of type $\alpha$ and any array of arrays `xss : Array (Array α)`, the following are equivalent: 1. For every element $x$ in the flattened array `xss.flatten`, the predicate $p(x)$ holds. 2. For every array `xs` in `xss` and every element $x$ in `xs`, the predicate $p(x)$ holds.
Array.flatten_eq_flatMap theorem
{xss : Array (Array α)} : flatten xss = xss.flatMap id
Full source
theorem flatten_eq_flatMap {xss : Array (Array α)} : flatten xss = xss.flatMap id := by
  induction xss using array₂_induction
  rw [flatten_toArray_map, List.flatten_eq_flatMap]
  simp [List.flatMap_map]
Flattening Equals FlatMap with Identity: $\text{flatten}(xss) = \text{flatMap}(\text{id}, xss)$
Informal description
For any array of arrays `xss` of type `Array (Array α)`, the flattening of `xss` is equal to the flat mapping of the identity function over `xss`. In symbols: $$\text{flatten}(xss) = \text{flatMap}(\text{id}, xss)$$
Array.map_flatten theorem
{f : α → β} {xss : Array (Array α)} : (flatten xss).map f = (map (map f) xss).flatten
Full source
@[simp] theorem map_flatten {f : α → β} {xss : Array (Array α)} :
    (flatten xss).map f = (map (map f) xss).flatten := by
  induction xss using array₂_induction with
  | of xss =>
    simp only [flatten_toArray_map, List.map_toArray, List.map_flatten, List.map_map,
      Function.comp_def]
    rw [← Function.comp_def, ← List.map_map, flatten_toArray_map]
Mapping Commutes with Flattening: $(xss.\text{flatten}).\text{map} f = (xss.\text{map} (\text{map} f)).\text{flatten}$
Informal description
For any function $f \colon \alpha \to \beta$ and any array of arrays $xss$ of type $\text{Array} (\text{Array} \alpha)$, the following equality holds: $$(xss.\text{flatten}).\text{map} f = (xss.\text{map} (\text{map} f)).\text{flatten}$$
Array.filterMap_flatten theorem
{f : α → Option β} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) : filterMap f (flatten xss) 0 stop = flatten (map (filterMap f) xss)
Full source
@[simp] theorem filterMap_flatten {f : α → Option β} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
    filterMap f (flatten xss) 0 stop = flatten (map (filterMap f) xss) := by
  subst w
  induction xss using array₂_induction
  simp only [flatten_toArray_map, List.size_toArray, List.length_flatten, List.filterMap_toArray',
    List.filterMap_flatten, List.map_toArray, List.map_map, Function.comp_def]
  rw [← Function.comp_def, ← List.map_map, flatten_toArray_map]
FilterMap Commutes with Flattening: $\text{filterMap } f (\text{flatten } xss) = \text{flatten} (\text{map} (\text{filterMap } f) \ xss)$
Informal description
For any function $f \colon \alpha \to \text{Option } \beta$, any array of arrays $xss$ of type $\text{Array} (\text{Array} \alpha)$, and any natural number $\text{stop}$ such that $\text{stop} = \text{size}(\text{flatten } xss)$, the filtered and mapped flattened array $\text{filterMap } f (\text{flatten } xss) \ 0 \ \text{stop}$ is equal to the flattened array obtained by mapping $\text{filterMap } f$ over each inner array in $xss$. In symbols: $$\text{filterMap } f (\text{flatten } xss) \ 0 \ \text{stop} = \text{flatten} (\text{map} (\text{filterMap } f) \ xss)$$
Array.filter_flatten theorem
{p : α → Bool} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) : filter p (flatten xss) 0 stop = flatten (map (filter p) xss)
Full source
@[simp] theorem filter_flatten {p : α → Bool} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
    filter p (flatten xss) 0 stop = flatten (map (filter p) xss) := by
  subst w
  induction xss using array₂_induction
  simp only [flatten_toArray_map, List.size_toArray, List.length_flatten, List.filter_toArray',
    List.filter_flatten, List.map_toArray, List.map_map, Function.comp_def]
  rw [← Function.comp_def, ← List.map_map, flatten_toArray_map]
Filtering Commutes with Flattening and Mapping: $\text{filter}\ p \circ \text{flatten} = \text{flatten} \circ \text{map}\ (\text{filter}\ p)$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array of arrays $xss$ of type $\text{Array} (\text{Array} \alpha)$, if $stop$ is equal to the size of the flattened array $xss.\text{flatten}$, then filtering the flattened array $xss.\text{flatten}$ with predicate $p$ (from index $0$ to $stop$) is equal to flattening the array obtained by mapping the filter operation $\text{filter}\ p$ over each inner array in $xss$. In symbols: $$\text{filter}\ p\ (\text{flatten}\ xss)\ 0\ stop = \text{flatten}\ (\text{map}\ (\text{filter}\ p)\ xss)$$
Array.flatten_filter_not_isEmpty theorem
{xss : Array (Array α)} : flatten (xss.filter fun xs => !xs.isEmpty) = xss.flatten
Full source
theorem flatten_filter_not_isEmpty {xss : Array (Array α)} :
    flatten (xss.filter fun xs => !xs.isEmpty) = xss.flatten := by
  induction xss using array₂_induction
  simp [List.filter_map, Function.comp_def, List.flatten_filter_not_isEmpty]
Flattening Commutes with Non-Empty Filtering: $\text{flatten}(\text{filter}_{\neg \text{isEmpty}}(\text{xss})) = \text{flatten}(\text{xss})$
Informal description
For any array of arrays `xss` of type `Array (Array α)`, flattening the array obtained by filtering out all empty arrays from `xss` is equal to flattening `xss` directly. In symbols: $$\text{flatten}(\text{xss.filter}(\lambda xs, \neg \text{xs.isEmpty})) = \text{xss.flatten}$$
Array.flatten_filter_ne_empty theorem
[DecidablePred fun xs : Array α => xs ≠ #[]] {xss : Array (Array α)} : flatten (xss.filter fun xs => xs ≠ #[]) = xss.flatten
Full source
theorem flatten_filter_ne_empty [DecidablePred fun xs : Array α => xs ≠ #[]] {xss : Array (Array α)} :
    flatten (xss.filter fun xs => xs ≠ #[]) = xss.flatten := by
  simp only [ne_eq, ← isEmpty_iff, Bool.not_eq_true, Bool.decide_eq_false,
    flatten_filter_not_isEmpty]
Flattening Commutes with Non-Empty Filtering: $\text{flatten}(\text{filter}_{\neq \#[]}(\text{xss})) = \text{flatten}(\text{xss})$
Informal description
For any array of arrays `xss` of type `Array (Array α)`, where the predicate `xs ≠ #[]` is decidable for each subarray `xs`, flattening the array obtained by filtering out all empty arrays from `xss` is equal to flattening `xss` directly. In symbols: $$\text{flatten}(\text{xss.filter}(\lambda xs, xs \neq \#[])) = \text{xss.flatten}$$
Array.flatten_append theorem
{xss₁ xss₂ : Array (Array α)} : flatten (xss₁ ++ xss₂) = flatten xss₁ ++ flatten xss₂
Full source
@[simp] theorem flatten_append {xss₁ xss₂ : Array (Array α)} :
    flatten (xss₁ ++ xss₂) = flatten xss₁ ++ flatten xss₂ := by
  induction xss₁ using array₂_induction
  induction xss₂ using array₂_induction
  simp [← List.map_append]
Flattening Distributes Over Array Concatenation: $\text{flatten}(xss₁ ++ xss₂) = \text{flatten}(xss₁) ++ \text{flatten}(xss₂)$
Informal description
For any two arrays of arrays `xss₁` and `xss₂` of elements of type `α`, the flattening of their concatenation `xss₁ ++ xss₂` is equal to the concatenation of their individual flattenings `flatten xss₁ ++ flatten xss₂`. In symbols: $$\text{flatten}(xss₁ ++ xss₂) = \text{flatten}(xss₁) ++ \text{flatten}(xss₂)$$
Array.flatten_push theorem
{xss : Array (Array α)} {xs : Array α} : flatten (xss.push xs) = flatten xss ++ xs
Full source
theorem flatten_push {xss : Array (Array α)} {xs : Array α} :
    flatten (xss.push xs) = flatten xss ++ xs := by
  induction xss using array₂_induction
  rcases xs with ⟨l⟩
  have this : [l.toArray] = [l].map List.toArray := by simp
  simp only [List.push_toArray, flatten_toArray_map, List.append_toArray]
  rw [this, ← List.map_append, flatten_toArray_map]
  simp
Flattening Commutes with Array Push: $\text{flatten}(xss.\text{push}(xs)) = \text{flatten}(xss) ++ xs$
Informal description
For any array of arrays `xss` and any array `xs` of elements of type `alpha`, flattening the array obtained by appending `xs` to `xss` is equal to the concatenation of the flattened `xss` with `xs`. In symbols: $$\text{flatten}(xss.\text{push}(xs)) = \text{flatten}(xss) ++ xs$$
Array.flatten_flatten theorem
{xss : Array (Array (Array α))} : flatten (flatten xss) = flatten (map flatten xss)
Full source
theorem flatten_flatten {xss : Array (Array (Array α))} : flatten (flatten xss) = flatten (map flatten xss) := by
  induction xss using array₃_induction with
  | of xss =>
    rw [flatten_toArray_map]
    have : (xss.map (fun xs => xs.map List.toArray)).flatten = xss.flatten.map List.toArray := by
      induction xss with
      | nil => simp
      | cons xs xss ih =>
        simp only [List.map_cons, List.flatten_cons, ih, List.map_append]
    rw [this, flatten_toArray_map, List.flatten_flatten, ← List.map_toArray, Array.map_map,
      ← List.map_toArray, map_map, Function.comp_def]
    simp only [Function.comp_apply, flatten_toArray_map]
    rw [List.map_toArray, ← Function.comp_def, ← List.map_map, flatten_toArray_map]
Double Flattening Equals Flattening of Mapped Flatten: $\text{flatten} \circ \text{flatten} = \text{flatten} \circ \text{map flatten}$
Informal description
For any array of arrays of arrays `xss` of type `α`, flattening the array twice is equivalent to first mapping the flatten operation over each inner array and then flattening the result. That is: $$\text{flatten}(\text{flatten}(xss)) = \text{flatten}(xss.\text{map flatten})$$
Array.flatten_eq_push_iff theorem
{xss : Array (Array α)} {ys : Array α} {y : α} : xss.flatten = ys.push y ↔ ∃ (as : Array (Array α)) (bs : Array α) (cs : Array (Array α)), xss = as.push (bs.push y) ++ cs ∧ (∀ xs, xs ∈ cs → xs = #[]) ∧ ys = as.flatten ++ bs
Full source
theorem flatten_eq_push_iff {xss : Array (Array α)} {ys : Array α} {y : α} :
    xss.flatten = ys.push y ↔
      ∃ (as : Array (Array α)) (bs : Array α) (cs : Array (Array α)),
        xss = as.push (bs.push y) ++ cs ∧ (∀ xs, xs ∈ cs → xs = #[]) ∧ ys = as.flatten ++ bs := by
  induction xss using array₂_induction with
  | of xs =>
    rcases ys with ⟨ys⟩
    rw [flatten_toArray_map, List.push_toArray, mk.injEq, List.flatten_eq_append_iff]
    constructor
    · rintro (⟨as, bs, rfl, rfl, h⟩ | ⟨as, bs, c, cs, ds, rfl, rfl, h⟩)
      · rw [List.singleton_eq_flatten_iff] at h
        obtain ⟨xs, ys, rfl, h₁, h₂⟩ := h
        exact ⟨((as ++ xs).map List.toArray).toArray, #[], (ys.map List.toArray).toArray, by simp,
          by simpa using h₂, by rw [flatten_toArray_map]; simpa⟩
      · rw [List.singleton_eq_append_iff] at h
        obtain (⟨h₁, h₂⟩ | ⟨h₁, h₂⟩) := h
        · simp at h₁
        · simp at h₁ h₂
          obtain ⟨rfl, rfl⟩ := h₁
          exact ⟨(as.map List.toArray).toArray, bs.toArray, (ds.map List.toArray).toArray, by simpa⟩
    · rintro ⟨as, bs, cs, h₁, h₂, h₃⟩
      replace h₁ := congrArg (List.map Array.toList) (congrArg Array.toList h₁)
      simp [Function.comp_def] at h₁
      subst h₁
      replace h₃ := congrArg Array.toList h₃
      simp at h₃
      subst h₃
      right
      exact ⟨(as.map Array.toList).toList, bs.toList, y, [], (cs.map Array.toList).toList, by simpa⟩
Characterization of When Flattened Array Equals Pushed Array
Informal description
For an array of arrays `xss` of type `Array (Array α)`, an array `ys` of type `Array α`, and an element `y` of type `α`, the following equivalence holds: The flattened array `xss.flatten` is equal to `ys.push y` if and only if there exist arrays `as`, `bs`, and `cs` of appropriate types such that: 1. `xss` can be decomposed as `as.push (bs.push y) ++ cs`, 2. Every array `xs` in `cs` is empty (i.e., `xs = #[]`), and 3. `ys` is equal to `as.flatten ++ bs`. In symbols: $$\text{flatten}(xss) = \text{push}(ys, y) \leftrightarrow \exists as\ bs\ cs, \begin{cases} xss = \text{push}(as, \text{push}(bs, y)) +\!\!+ cs \\ \forall xs \in cs, xs = \#[] \\ ys = \text{flatten}(as) +\!\!+ bs \end{cases}$$
Array.push_eq_flatten_iff theorem
{xss : Array (Array α)} {ys : Array α} {y : α} : ys.push y = xss.flatten ↔ ∃ (as : Array (Array α)) (bs : Array α) (cs : Array (Array α)), xss = as.push (bs.push y) ++ cs ∧ (∀ xs, xs ∈ cs → xs = #[]) ∧ ys = as.flatten ++ bs
Full source
theorem push_eq_flatten_iff {xss : Array (Array α)} {ys : Array α} {y : α} :
    ys.push y = xss.flatten ↔
      ∃ (as : Array (Array α)) (bs : Array α) (cs : Array (Array α)),
        xss = as.push (bs.push y) ++ cs ∧ (∀ xs, xs ∈ cs → xs = #[]) ∧ ys = as.flatten ++ bs := by
  rw [eq_comm, flatten_eq_push_iff]
Characterization of When Pushed Array Equals Flattened Array
Informal description
For an array of arrays `xss` of type `Array (Array α)`, an array `ys` of type `Array α`, and an element `y` of type `α`, the following equivalence holds: The array `ys.push y` is equal to the flattened array `xss.flatten` if and only if there exist arrays `as`, `bs`, and `cs` of appropriate types such that: 1. `xss` can be decomposed as `as.push (bs.push y) ++ cs`, 2. Every array `xs` in `cs` is empty (i.e., `xs = #[]`), and 3. `ys` is equal to `as.flatten ++ bs`. In symbols: $$\text{push}(ys, y) = \text{flatten}(xss) \leftrightarrow \exists as\ bs\ cs, \begin{cases} xss = \text{push}(as, \text{push}(bs, y)) +\!\!+ cs \\ \forall xs \in cs, xs = \#[] \\ ys = \text{flatten}(as) +\!\!+ bs \end{cases}$$
Array.flatten_toArray_map_toArray theorem
{xss : List (List α)} : (xss.map List.toArray).toArray.flatten = xss.flatten.toArray
Full source
@[simp] theorem flatten_toArray_map_toArray {xss : List (List α)} :
    (xss.map List.toArray).toArray.flatten = xss.flatten.toArray := by
  simp [flatten]
  suffices ∀ as, List.foldl (fun acc bs => acc ++ bs) as (List.map List.toArray xss) = as ++ xss.flatten.toArray by
    simpa using this #[]
  intro as
  induction xss generalizing as with
  | nil => simp
  | cons xs xss ih => simp [ih]
Flattening Commutes with List-to-Array Conversion
Informal description
For any list of lists `xss` of elements of type `α`, the following equality holds: $$(\text{map List.toArray xss}).\text{toArray}.\text{flatten} = \text{xss.flatten.toArray}$$ where: - $\text{map List.toArray xss}$ converts each inner list in `xss` to an array - $\text{toArray}$ converts the resulting list of arrays to an array of arrays - $\text{flatten}$ concatenates all arrays in the array of arrays - $\text{xss.flatten}$ concatenates all lists in `xss` first, then converts the result to an array
Array.flatMap_def theorem
{xs : Array α} {f : α → Array β} : xs.flatMap f = flatten (map f xs)
Full source
theorem flatMap_def {xs : Array α} {f : α → Array β} : xs.flatMap f = flatten (map f xs) := by
  rcases xs with ⟨l⟩
  simp [flatten_toArray, Function.comp_def, List.flatMap_def]
Definition of FlatMap via Map and Flatten: $\text{flatMap}\ f\ xs = \text{flatten}\ (\text{map}\ f\ xs)$
Informal description
For any array `xs` of type `Array α` and any function `f : α → Array β`, the flatMap operation on `xs` with `f` is equal to first mapping `f` over `xs` and then flattening the resulting array of arrays. In symbols: $$\text{flatMap}\ f\ xs = \text{flatten}\ (\text{map}\ f\ xs)$$
Array.flatMap_empty theorem
{β} {f : α → Array β} : (#[] : Array α).flatMap f = #[]
Full source
@[simp] theorem flatMap_empty {β} {f : α → Array β} : (#[] : Array α).flatMap f = #[] := rfl
FlatMap of Empty Array Yields Empty Array
Informal description
For any function $f : \alpha \to \text{Array}\ \beta$, the flatMap operation applied to an empty array results in an empty array, i.e., $\text{flatMap}\ f\ \#[] = \#[]$.
Array.flatMap_toList theorem
{xs : Array α} {f : α → List β} : xs.toList.flatMap f = (xs.flatMap (fun a => (f a).toArray)).toList
Full source
theorem flatMap_toList {xs : Array α} {f : α → List β} :
    xs.toList.flatMap f = (xs.flatMap (fun a => (f a).toArray)).toList := by
  rcases xs with ⟨l⟩
  simp
Equivalence of List and Array FlatMap Operations
Informal description
For any array `xs` of type `Array α` and any function `f : α → List β`, the flatMap operation on the list obtained from `xs` is equivalent to first converting each element of `xs` to an array via `f` and then converting the result back to a list. That is, \[ \text{flatMap}\ f\ (\text{toList}\ xs) = \text{toList}\ (\text{flatMap}\ (\lambda a \mapsto (\text{toArray}\ (f\ a)))\ xs). \]
Array.toList_flatMap theorem
{xs : Array α} {f : α → Array β} : (xs.flatMap f).toList = xs.toList.flatMap fun a => (f a).toList
Full source
@[simp] theorem toList_flatMap {xs : Array α} {f : α → Array β} :
    (xs.flatMap f).toList = xs.toList.flatMap fun a => (f a).toList := by
  rcases xs with ⟨l⟩
  simp
List Conversion Commutes with FlatMap on Arrays
Informal description
For any array `xs` of type `Array α` and any function `f : α → Array β`, converting the result of `flatMap f xs` to a list is equivalent to first converting `xs` to a list and then applying `flatMap` with a function that converts each `f a` to a list. That is, \[ \text{toList}(\text{flatMap}\ f\ xs) = \text{flatMap}\ (\lambda a \mapsto \text{toList}(f\ a))\ (\text{toList}\ xs). \]
Array.flatMap_toArray_cons theorem
{β} {f : α → Array β} {a : α} {as : List α} : (a :: as).toArray.flatMap f = f a ++ as.toArray.flatMap f
Full source
theorem flatMap_toArray_cons {β} {f : α → Array β} {a : α} {as : List α} :
    (a :: as).toArray.flatMap f = f a ++ as.toArray.flatMap f := by
  simp [flatMap]
  suffices ∀ cs, List.foldl (fun bs a => bs ++ f a) (f a ++ cs) as =
      f a ++ List.foldl (fun bs a => bs ++ f a) cs as by
    erw [empty_append] -- Why doesn't this work via `simp`?
    simpa using this #[]
  intro cs
  induction as generalizing cs <;> simp_all
FlatMap Distribution over Array Construction from Cons List
Informal description
For any type $\beta$, function $f : \alpha \to \text{Array}\ \beta$, element $a : \alpha$, and list $\text{as} : \text{List}\ \alpha$, the flatMap operation on the array conversion of the list $a :: \text{as}$ satisfies: \[ \text{flatMap}\ f\ ((a :: \text{as}).\text{toArray}) = f\ a \mathbin{+\kern-0.5em+} \text{flatMap}\ f\ (\text{as.toArray}) \] where $\mathbin{+\kern-0.5em+}$ denotes array concatenation.
Array.flatMap_toArray theorem
{β} {f : α → Array β} {as : List α} : as.toArray.flatMap f = (as.flatMap (fun a => (f a).toList)).toArray
Full source
@[simp] theorem flatMap_toArray {β} {f : α → Array β} {as : List α} :
    as.toArray.flatMap f = (as.flatMap (fun a => (f a).toList)).toArray := by
  induction as with
  | nil => simp
  | cons a as ih =>
    apply ext'
    simp [ih, flatMap_toArray_cons]
FlatMap Commutes with List-to-Array Conversion
Informal description
For any function $f : \alpha \to \text{Array}\ \beta$ and any list $\text{as} : \text{List}\ \alpha$, the flatMap operation on the array conversion of $\text{as}$ satisfies: \[ \text{as.toArray.flatMap}\ f = \left(\text{as.flatMap}\ (\lambda a \mapsto (f\ a).\text{toList})\right).\text{toArray} \]
Array.flatMap_id theorem
{xss : Array (Array α)} : xss.flatMap id = xss.flatten
Full source
@[simp] theorem flatMap_id {xss : Array (Array α)} : xss.flatMap id = xss.flatten := by simp [flatMap_def]
FlatMap with Identity Equals Flatten: $\text{flatMap}\ \text{id} = \text{flatten}$
Informal description
For any array of arrays `xss : Array (Array α)`, the flatMap operation with the identity function `id` is equal to flattening the array, i.e., $\text{flatMap}\ \text{id}\ xss = \text{flatten}\ xss$.
Array.flatMap_id' theorem
{xss : Array (Array α)} : xss.flatMap (fun xs => xs) = xss.flatten
Full source
@[simp] theorem flatMap_id' {xss : Array (Array α)} : xss.flatMap (fun xs => xs) = xss.flatten := by simp [flatMap_def]
FlatMap with Identity Mapping Equals Flatten: $\text{flatMap}\ (\lambda xs, xs) = \text{flatten}$
Informal description
For any array of arrays `xss : Array (Array α)`, the flatMap operation with the identity mapping `(fun xs => xs)` is equal to flattening the array, i.e., `flatMap (fun xs => xs) xss = flatten xss`.
Array.size_flatMap theorem
{xs : Array α} {f : α → Array β} : (xs.flatMap f).size = sum (map (fun a => (f a).size) xs)
Full source
@[simp]
theorem size_flatMap {xs : Array α} {f : α → Array β} :
    (xs.flatMap f).size = sum (map (fun a => (f a).size) xs) := by
  rcases xs with ⟨l⟩
  simp [Function.comp_def]
Size of Flat-Mapped Array Equals Sum of Component Sizes
Informal description
For any array `xs` of type `Array α` and any function `f : α → Array β`, the size of the array obtained by flat-mapping `f` over `xs` is equal to the sum of the sizes of the arrays obtained by applying `f` to each element of `xs`. In mathematical notation: $$|\text{flatMap}(f, xs)| = \sum_{a \in xs} |f(a)|$$ where $|A|$ denotes the size (number of elements) of array $A$.
Array.mem_flatMap theorem
{f : α → Array β} {b} {xs : Array α} : b ∈ xs.flatMap f ↔ ∃ a, a ∈ xs ∧ b ∈ f a
Full source
@[simp] theorem mem_flatMap {f : α → Array β} {b} {xs : Array α} : b ∈ xs.flatMap fb ∈ xs.flatMap f ↔ ∃ a, a ∈ xs ∧ 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₂⟩⟩
Membership in Flat-Mapped Array: $b \in \text{flatMap}\ f\ xs \leftrightarrow \exists a \in xs, b \in f(a)$
Informal description
For any function $f : \alpha \to \text{Array}\ \beta$, element $b : \beta$, and array $xs : \text{Array}\ \alpha$, the element $b$ is in the flat-mapped array $\text{flatMap}\ f\ xs$ if and only if there exists an element $a \in xs$ such that $b$ is in $f(a)$. In symbols: $$b \in \text{flatMap}\ f\ xs \leftrightarrow \exists a \in xs, b \in f(a)$$
Array.exists_of_mem_flatMap theorem
{b : β} {xs : Array α} {f : α → Array β} : b ∈ xs.flatMap f → ∃ a, a ∈ xs ∧ b ∈ f a
Full source
theorem exists_of_mem_flatMap {b : β} {xs : Array α} {f : α → Array β} :
    b ∈ xs.flatMap f∃ a, a ∈ xs ∧ b ∈ f a := mem_flatMap.1
Existence of Preimage in Flat-Mapped Array
Informal description
For any element $b$ of type $\beta$, array $xs$ of type $\text{Array}\ \alpha$, and function $f : \alpha \to \text{Array}\ \beta$, if $b$ is an element of the flat-mapped array $\text{flatMap}\ f\ xs$, then there exists an element $a \in xs$ such that $b$ is an element of $f(a)$. In symbols: $$b \in \text{flatMap}\ f\ xs \implies \exists a \in xs, b \in f(a)$$
Array.mem_flatMap_of_mem theorem
{b : β} {xs : Array α} {f : α → Array β} {a} (al : a ∈ xs) (h : b ∈ f a) : b ∈ xs.flatMap f
Full source
theorem mem_flatMap_of_mem {b : β} {xs : Array α} {f : α → Array β} {a} (al : a ∈ xs) (h : b ∈ f a) :
    b ∈ xs.flatMap f := mem_flatMap.2 ⟨a, al, h⟩
Membership in FlatMap from Membership in Component Array
Informal description
For any function $f : \alpha \to \text{Array}\ \beta$, element $b : \beta$, array $xs : \text{Array}\ \alpha$, and element $a \in xs$, if $b$ is in $f(a)$, then $b$ is in the flat-mapped array $\text{flatMap}\ f\ xs$. In symbols: $$a \in xs \land b \in f(a) \to b \in \text{flatMap}\ f\ xs$$
Array.flatMap_eq_empty_iff theorem
{xs : Array α} {f : α → Array β} : xs.flatMap f = #[] ↔ ∀ x ∈ xs, f x = #[]
Full source
@[simp]
theorem flatMap_eq_empty_iff {xs : Array α} {f : α → Array β} : xs.flatMap f = #[] ↔ ∀ x ∈ xs, f x = #[] := by
  rw [flatMap_def, flatten_eq_empty_iff]
  simp
Empty FlatMap Condition: $\text{flatMap}\ f\ xs = \text{#[]} \leftrightarrow \forall x \in xs, f x = \text{#[]}$
Informal description
For any array `xs` of type `Array α` and any function `f : α → Array β`, the flatMap operation on `xs` with `f` results in an empty array if and only if for every element `x` in `xs`, the array `f x` is empty. In symbols: $$\text{flatMap}\ f\ xs = \text{#[]} \leftrightarrow \forall x \in xs, f x = \text{#[]}$$
Array.forall_mem_flatMap theorem
{p : β → Prop} {xs : Array α} {f : α → Array β} : (∀ (x) (_ : x ∈ xs.flatMap f), p x) ↔ ∀ (a) (_ : a ∈ xs) (b) (_ : b ∈ f a), p b
Full source
theorem forall_mem_flatMap {p : β → Prop} {xs : Array α} {f : α → Array β} :
    (∀ (x) (_ : x ∈ xs.flatMap f), p x) ↔ ∀ (a) (_ : a ∈ xs) (b) (_ : b ∈ f a), p b := by
  simp only [mem_flatMap, forall_exists_index, and_imp]
  constructor <;> (intros; solve_by_elim)
Universal Quantifier over FlatMap Elements: $\forall x \in \text{flatMap}(f, xs), p(x) \leftrightarrow \forall a \in xs, \forall b \in f(a), p(b)$
Informal description
For any predicate $p : \beta \to \text{Prop}$, array $xs : \text{Array } \alpha$, and function $f : \alpha \to \text{Array } \beta$, the following equivalence holds: \[ (\forall x \in \text{flatMap}(f, xs), p(x)) \leftrightarrow (\forall a \in xs, \forall b \in f(a), p(b)) \]
Array.flatMap_singleton theorem
{f : α → Array β} {x : α} : #[x].flatMap f = f x
Full source
theorem flatMap_singleton {f : α → Array β} {x : α} : #[x].flatMap f = f x := by
  simp
FlatMap of Singleton Array Equals Function Application: $\text{flatMap}(f, [x]) = f(x)$
Informal description
For any function $f : \alpha \to \text{Array } \beta$ and any element $x \in \alpha$, the flatMap operation applied to the singleton array $[x]$ with function $f$ is equal to $f(x)$. In other words, $\text{flatMap}(f, [x]) = f(x)$.
Array.flatMap_singleton' theorem
(xs : Array α) : (xs.flatMap fun x => #[x]) = xs
Full source
@[simp] theorem flatMap_singleton' (xs : Array α) : (xs.flatMap fun x => #[x]) = xs := by
  rcases xs with ⟨xs⟩
  simp
FlatMap with Singleton Function Preserves Array: $\text{flatMap}(x \mapsto [x], xs) = xs$
Informal description
For any array `xs` of elements of type `α`, the flatMap operation applied to `xs` with the function that maps each element `x` to the singleton array `#[x]` results in the original array `xs`. In other words, $\text{flatMap}(\lambda x \mapsto [x], xs) = xs$.
Array.flatMap_append theorem
{xs ys : Array α} {f : α → Array β} : (xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f
Full source
@[simp] theorem flatMap_append {xs ys : Array α} {f : α → Array β} :
    (xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp
Distributivity of flatMap over Array Concatenation: $(xs \mathbin{+\!\!+} ys).\text{flatMap} f = xs.\text{flatMap} f \mathbin{+\!\!+} ys.\text{flatMap} f$
Informal description
For any arrays `xs` and `ys` of type `Array α` and any function `f : α → Array β`, the flatMap operation distributes over array concatenation, i.e., `(xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f`.
Array.flatMap_assoc theorem
{xs : Array α} {f : α → Array β} {g : β → Array γ} : (xs.flatMap f).flatMap g = xs.flatMap fun x => (f x).flatMap g
Full source
theorem flatMap_assoc {xs : Array α} {f : α → Array β} {g : β → Array γ} :
    (xs.flatMap f).flatMap g = xs.flatMap fun x => (f x).flatMap g := by
  rcases xs with ⟨xs⟩
  simp [List.flatMap_assoc, ← toList_flatMap]
Associativity of Array flatMap: $(\text{flatMap}\, f \circ \text{flatMap}\, g)(xs) = \text{flatMap}\, (f \gg= g)(xs)$
Informal description
For any array `xs` of elements of type `α`, and any functions `f : α → Array β` and `g : β → Array γ`, the following associativity property holds: $$(\text{flatMap}(f, \text{flatMap}(g, xs))) = \text{flatMap}(\lambda x \mapsto \text{flatMap}(g, f(x)), xs)$$
Array.map_flatMap theorem
{f : β → γ} {g : α → Array β} {xs : Array α} : (xs.flatMap g).map f = xs.flatMap fun a => (g a).map f
Full source
theorem map_flatMap {f : β → γ} {g : α → Array β} {xs : Array α} :
    (xs.flatMap g).map f = xs.flatMap fun a => (g a).map f := by
  rcases xs with ⟨xs⟩
  simp [List.map_flatMap]
Commutativity of map and flatMap on arrays: $(xs \mathbin{>>=} g).\text{map}\, f = xs \mathbin{>>=} (g \gg \text{map}\, f)$
Informal description
For any function $f : \beta \to \gamma$, any function $g : \alpha \to \text{Array }\beta$, and any array $xs$ of type $\text{Array }\alpha$, the following equality holds: $$(xs.\text{flatMap}\, g).\text{map}\, f = xs.\text{flatMap}\, \big(\lambda a \mapsto (g\, a).\text{map}\, f\big)$$
Array.flatMap_map theorem
{f : α → β} {g : β → Array γ} {xs : Array α} : (xs.map f).flatMap g = xs.flatMap (fun a => g (f a))
Full source
theorem flatMap_map {f : α → β} {g : β → Array γ} {xs : Array α} :
    (xs.map f).flatMap g = xs.flatMap (fun a => g (f a)) := by
  rcases xs with ⟨xs⟩
  simp [List.flatMap_map]
Commutativity of Array Mapping and FlatMap: $(f \circ g)(xs) = g \circ f(xs)$
Informal description
For any array $xs$ of elements of type $\alpha$, and any functions $f : \alpha \to \beta$ and $g : \beta \to \text{Array}\ \gamma$, the following equality holds: $$(xs.\text{map}\ f).\text{flatMap}\ g = xs.\text{flatMap}\ (\lambda a \mapsto g(f(a)))$$
Array.map_eq_flatMap theorem
{f : α → β} {xs : Array α} : map f xs = xs.flatMap fun x => #[f x]
Full source
theorem map_eq_flatMap {f : α → β} {xs : Array α} : map f xs = xs.flatMap fun x => #[f x] := by
  simp only [← map_singleton]
  rw [← flatMap_singleton' xs, map_flatMap, flatMap_singleton']
Map as FlatMap of Singletons: $\text{map}\, f = \text{flatMap}\, (x \mapsto [f(x)])$
Informal description
For any function $f : \alpha \to \beta$ and any array $xs$ of elements of type $\alpha$, the map operation applied to $xs$ with $f$ is equal to the flatMap operation applied to $xs$ with the function that maps each element $x$ to the singleton array containing $f(x)$. In symbols: $$\text{map}\, f\, xs = \text{flatMap}\, (\lambda x \mapsto [f(x)])\, xs$$
Array.filterMap_flatMap theorem
{xs : Array α} {g : α → Array β} {f : β → Option γ} : (xs.flatMap g).filterMap f = xs.flatMap fun a => (g a).filterMap f
Full source
theorem filterMap_flatMap {xs : Array α} {g : α → Array β} {f : β → Option γ} :
    (xs.flatMap g).filterMap f = xs.flatMap fun a => (g a).filterMap f := by
  rcases xs with ⟨xs⟩
  simp [List.filterMap_flatMap]
FilterMap and FlatMap Commutation: $(\text{flatMap}\ g).\text{filterMap}\ f = \text{flatMap}\ (\lambda a.\ (g\ a).\text{filterMap}\ f)$
Informal description
For any array `xs` of type `Array α`, any function `g : α → Array β`, and any function `f : β → Option γ`, the following equality holds: $$(\text{flatMap}\ g\ xs).\text{filterMap}\ f = \text{flatMap}\ (\lambda a.\ (g\ a).\text{filterMap}\ f)\ xs$$ where `flatMap` first applies `g` to each element of `xs` and concatenates the resulting arrays, then `filterMap` applies `f` to each element of the resulting array and collects the `some` values.
Array.filter_flatMap theorem
{xs : Array α} {g : α → Array β} {f : β → Bool} : (xs.flatMap g).filter f = xs.flatMap fun a => (g a).filter f
Full source
theorem filter_flatMap {xs : Array α} {g : α → Array β} {f : β → Bool} :
    (xs.flatMap g).filter f = xs.flatMap fun a => (g a).filter f := by
  rcases xs with ⟨xs⟩
  simp [List.filter_flatMap]
Filter Commutes with FlatMap: $\text{filter } f \circ \text{flatMap } g = \text{flatMap } (\lambda a. \text{filter } f (g a))$
Informal description
For any array $xs$ of type $\alpha$, any function $g : \alpha \to \text{Array } \beta$, and any predicate $f : \beta \to \text{Bool}$, filtering the flattened array obtained by applying $g$ to each element of $xs$ with predicate $f$ is equal to flattening the array obtained by applying $\lambda a. (g a).\text{filter } f$ to each element of $xs$. In symbols: $$(xs.\text{flatMap } g).\text{filter } f = xs.\text{flatMap } (\lambda a. (g a).\text{filter } f)$$
Array.flatMap_eq_foldl theorem
{f : α → Array β} {xs : Array α} : xs.flatMap f = xs.foldl (fun acc a => acc ++ f a) #[]
Full source
theorem flatMap_eq_foldl {f : α → Array β} {xs : Array α} :
    xs.flatMap f = xs.foldl (fun acc a => acc ++ f a) #[] := by
  rcases xs with ⟨xs⟩
  simp only [List.flatMap_toArray, List.flatMap_eq_foldl, List.size_toArray, List.foldl_toArray']
  suffices ∀ l, (List.foldl (fun acc a => acc ++ (f a).toList) l xs).toArray =
      List.foldl (fun acc a => acc ++ f a) l.toArray xs by
    simpa using this []
  induction xs with
  | nil => simp
  | cons a l ih =>
    intro l'
    rw [List.foldl_cons, ih]
    simp [toArray_append]
FlatMap as Fold with Concatenation: $\text{flatMap } f = \text{foldl } (\lambda \text{acc } a. \text{acc} +\!\!+ f(a)) \ \#[]$
Informal description
For any function $f : \alpha \to \text{Array } \beta$ and any array $xs : \text{Array } \alpha$, the flatMap operation on $xs$ with $f$ is equal to folding $xs$ with the operation $\lambda \text{acc } a. \text{acc} +\!\!+ f(a)$ starting from the empty array $\#[]$. In symbols: $$\text{flatMap } f \ xs = \text{foldl } (\lambda \text{acc } a. \text{acc} +\!\!+ f(a)) \ \#[] \ xs$$ where $+\!\!+$ denotes array concatenation.
Array.replicate_one theorem
: replicate 1 a = #[a]
Full source
@[simp] theorem replicate_one : replicate 1 a = #[a] := rfl
Replicating Once Yields Singleton Array: $\text{replicate}(1, a) = \#[a]$
Informal description
For any element $a$ of type $\alpha$, the array created by replicating $a$ once is equal to the singleton array containing $a$, i.e., $\text{replicate}(1, a) = \#[a]$.
Array.mkArray_one abbrev
Full source
@[deprecated replicate_one (since := "2025-03-18")]
abbrev mkArray_one := @replicate_one
Singleton Array Construction: $\text{mkArray}(1, a) = \#[a]$
Informal description
For any element $a$ of type $\alpha$, the array created with size $1$ and default value $a$ is equal to the singleton array containing $a$, i.e., $\text{mkArray}(1, a) = \#[a]$.
Array.replicate_succ' theorem
: replicate (n + 1) a = #[a] ++ replicate n a
Full source
/-- Variant of `replicate_succ` that prepends `a` at the beginning of the array. -/
theorem replicate_succ' : replicate (n + 1) a = #[a] ++ replicate n a := by
  apply Array.ext'
  simp [List.replicate_succ]
Recursive Definition of Array Replication: $\text{replicate}(n+1, a) = \#[a] \mathbin{+\kern-1.5ex+} \text{replicate}(n, a)$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the array obtained by replicating $a$ exactly $n+1$ times is equal to the concatenation of the singleton array $\#[a]$ with the array obtained by replicating $a$ $n$ times. That is, $$\text{replicate}(n+1, a) = \#[a] \mathbin{+\kern-1.5ex+} \text{replicate}(n, a)$$
Array.mkArray_succ' abbrev
Full source
@[deprecated replicate_succ' (since := "2025-03-18")]
abbrev mkArray_succ' := @replicate_succ'
Recursive Construction of Array: $\text{mkArray}(n+1, a) = \#[a] \mathbin{+\kern-1.5ex+} \text{mkArray}(n, a)$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the array constructed with size $n+1$ and default value $a$ is equal to the concatenation of the singleton array $\#[a]$ with the array constructed with size $n$ and default value $a$. That is, $$\text{mkArray}(n+1, a) = \#[a] \mathbin{+\kern-1.5ex+} \text{mkArray}(n, a)$$
Array.mem_replicate theorem
{a b : α} {n} : b ∈ replicate n a ↔ n ≠ 0 ∧ b = a
Full source
@[simp] theorem mem_replicate {a b : α} {n} : b ∈ replicate n ab ∈ replicate n a ↔ n ≠ 0 ∧ b = a := by
  unfold replicate
  simp only [mem_toArray, List.mem_replicate]
Membership in Replicated Array: $b \in \text{replicate}(n, a) \leftrightarrow n \neq 0 \land b = a$
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any natural number $n$, the element $b$ is in the array obtained by replicating $a$ $n$ times if and only if $n$ is non-zero and $b$ equals $a$. In symbols: $$b \in \text{replicate}(n, a) \leftrightarrow n \neq 0 \land b = a$$
Array.mem_mkArray abbrev
Full source
@[deprecated mem_replicate (since := "2025-03-18")]
abbrev mem_mkArray := @mem_replicate
Membership in Constructed Array: $b \in \text{mkArray}(n, a) \leftrightarrow n \neq 0 \land b = a$
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any natural number $n$, the element $b$ is in the array created by `mkArray n a` if and only if $n \neq 0$ and $b = a$. In symbols: $$b \in \text{mkArray}(n, a) \leftrightarrow n \neq 0 \land b = a$$
Array.forall_mem_replicate theorem
{p : α → Prop} {a : α} {n} : (∀ b, b ∈ replicate n a → p b) ↔ n = 0 ∨ p a
Full source
theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
    (∀ b, b ∈ replicate n a → p b) ↔ n = 0 ∨ p a := by
  cases n <;> simp [mem_replicate]
Universal Quantification over Replicated Array: $(\forall b \in \text{replicate } n a, p(b)) \leftrightarrow n=0 \lor p(a)$
Informal description
For any predicate $p : \alpha \to \text{Prop}$, element $a : \alpha$, and natural number $n$, the following are equivalent: 1. Every element $b$ in the array `replicate n a` satisfies $p(b)$. 2. Either $n = 0$ or $p(a)$ holds. In other words, all elements of an array created by replicating $a$ $n$ times satisfy $p$ if and only if either the array is empty ($n=0$) or $a$ itself satisfies $p$.
Array.forall_mem_mkArray abbrev
Full source
@[deprecated forall_mem_replicate (since := "2025-03-18")]
abbrev forall_mem_mkArray := @forall_mem_replicate
Universal Quantification over `mkArray`: $(\forall b \in \text{mkArray } n a, p(b)) \leftrightarrow n=0 \lor p(a)$
Informal description
For any predicate $p : \alpha \to \text{Prop}$, element $a : \alpha$, and natural number $n$, the following are equivalent: 1. Every element $b$ in the array `mkArray n a` satisfies $p(b)$. 2. Either $n = 0$ or $p(a)$ holds. In other words, all elements of an array created by `mkArray n a` satisfy $p$ if and only if either the array is empty ($n=0$) or $a$ itself satisfies $p$.
Array.replicate_succ_ne_empty theorem
{n : Nat} {a : α} : replicate (n + 1) a ≠ #[]
Full source
@[simp] theorem replicate_succ_ne_empty {n : Nat} {a : α} : replicatereplicate (n+1) a ≠ #[] := by
  simp [replicate_succ]
Non-emptiness of Replicated Array: $\text{replicate}(n+1, a) \neq \text{\#[]}$
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the array obtained by replicating $a$ $n+1$ times is not equal to the empty array.
Array.mkArray_succ_ne_empty abbrev
Full source
@[deprecated replicate_succ_ne_empty (since := "2025-03-18")]
abbrev mkArray_succ_ne_empty := @replicate_succ_ne_empty
Non-emptiness of Constructed Array: $\text{mkArray}(n+1, a) \neq \text{\#[]}$
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the array constructed by `mkArray (n + 1) a` is not equal to the empty array.
Array.replicate_eq_empty_iff theorem
{n : Nat} {a : α} : replicate n a = #[] ↔ n = 0
Full source
@[simp] theorem replicate_eq_empty_iff {n : Nat} {a : α} : replicatereplicate n a = #[] ↔ n = 0 := by
  cases n <;> simp
Replicated Array is Empty if and Only if Replication Count is Zero
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the array obtained by replicating $a$ $n$ times is equal to the empty array if and only if $n = 0$.
Array.mkArray_eq_empty_iff abbrev
Full source
@[deprecated replicate_eq_empty_iff (since := "2025-03-18")]
abbrev mkArray_eq_empty_iff := @replicate_eq_empty_iff
Empty Array Construction Condition: `mkArray n a = #[] ↔ n = 0`
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the array constructed by `mkArray n a` is equal to the empty array if and only if $n = 0$.
Array.replicate_inj theorem
: replicate n a = replicate m b ↔ n = m ∧ (n = 0 ∨ a = b)
Full source
@[simp] theorem replicate_inj : replicatereplicate n a = replicate m b ↔ n = m ∧ (n = 0 ∨ a = b) := by
  rw [← toList_inj]
  simp
Injectivity of Array Replication: $\text{replicate}\ n\ a = \text{replicate}\ m\ b \leftrightarrow n = m \land (n = 0 \lor a = b)$
Informal description
For any natural numbers $n, m$ and any elements $a, b$ of type $\alpha$, the replicated arrays $\text{replicate}\ n\ a$ and $\text{replicate}\ m\ b$ are equal if and only if $n = m$ and either $n = 0$ or $a = b$. In other words, $\text{replicate}\ n\ a = \text{replicate}\ m\ b \leftrightarrow n = m \land (n = 0 \lor a = b)$.
Array.mkArray_inj abbrev
Full source
@[deprecated replicate_inj (since := "2025-03-18")]
abbrev mkArray_inj := @replicate_inj
Injectivity of Array Construction: $\text{mkArray}\ n\ a = \text{mkArray}\ m\ b \leftrightarrow n = m \land (n = 0 \lor a = b)$
Informal description
For any natural numbers $n, m$ and any elements $a, b$ of type $\alpha$, the arrays constructed by `mkArray n a` and `mkArray m b` are equal if and only if $n = m$ and either $n = 0$ or $a = b$. In other words, $\text{mkArray}\ n\ a = \text{mkArray}\ m\ b \leftrightarrow n = m \land (n = 0 \lor a = b)$.
Array.map_eq_replicate_iff theorem
{xs : Array α} {f : α → β} {b : β} : xs.map f = replicate xs.size b ↔ ∀ x ∈ xs, f x = b
Full source
theorem map_eq_replicate_iff {xs : Array α} {f : α → β} {b : β} :
    xs.map f = replicate xs.size b ↔ ∀ x ∈ xs, f x = b := by
  simp [eq_replicate_iff]
Equivalence of Mapped Array and Replicated Array: $\text{map } f \text{ } xs = \text{replicate } (\text{size } xs) \text{ } b \leftrightarrow \forall x \in xs, f x = b$
Informal description
For an array `xs` of type `Array α`, a function `f : α → β`, and an element `b : β`, the mapped array `xs.map f` is equal to an array of size `xs.size` filled with `b` if and only if for every element `x` in `xs`, `f x = b`. In other words: \[ \text{map } f \text{ } xs = \text{replicate } (\text{size } xs) \text{ } b \leftrightarrow \forall x \in xs, f x = b \]
Array.map_eq_mkArray_iff abbrev
Full source
@[deprecated map_eq_replicate_iff (since := "2025-03-18")]
abbrev map_eq_mkArray_iff := @map_eq_replicate_iff
Equivalence of Mapped Array and Target Array: $\text{map } f \text{ } xs = ys \leftrightarrow (\text{size } ys = \text{size } xs) \land (\forall i < \text{size } xs, f (xs[i]) = ys[i])$
Informal description
For an array `xs` of type `Array α`, a function `f : α → β`, and an array `ys` of type `Array β`, the mapped array `xs.map f` is equal to `ys` if and only if `ys.size = xs.size` and for every index `i` (with `0 ≤ i < xs.size`), `f (xs[i]) = ys[i]`.
Array.map_const theorem
{xs : Array α} {b : β} : map (Function.const α b) xs = replicate xs.size b
Full source
@[simp] theorem map_const {xs : Array α} {b : β} : map (Function.const α b) xs = replicate xs.size b :=
  map_eq_replicate_iff.mpr fun _ _ => rfl
Mapping a Constant Function Yields a Replicated Array: $\text{map } (\text{const } b) \text{ } xs = \text{replicate } (\text{size } xs) \text{ } b$
Informal description
For any array `xs` of type `Array α` and any element `b` of type `β`, mapping the constant function `Function.const α b` over `xs` produces an array equal to `replicate xs.size b`. That is: \[ \text{map } (\text{const}_\alpha b) \text{ } xs = \text{replicate } (\text{size } xs) \text{ } b \]
Array.map_const_fun theorem
{x : β} : map (Function.const α x) = (replicate ·.size x)
Full source
@[simp] theorem map_const_fun {x : β} : map (Function.const α x) = (replicate ·.size x) := by
  funext xs
  simp
Functional Equality of Constant Mapping and Replication: $\text{map } (\text{const}_\alpha x) = \lambda a.\ \text{replicate } (\text{size } a) \text{ } x$
Informal description
For any element $x$ of type $\beta$, the function that maps an array to the result of applying the constant function $\text{const}_\alpha x$ to each element is equal to the function that replicates $x$ to an array of the same size. That is: \[ \text{map } (\text{const}_\alpha x) = \lambda a.\ \text{replicate } (\text{size } a) \text{ } x \]
Array.map_const' theorem
{xs : Array α} {b : β} : map (fun _ => b) xs = replicate xs.size b
Full source
/-- 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' {xs : Array α} {b : β} : map (fun _ => b) xs = replicate xs.size b :=
  map_const
Mapping a Constant Lambda Yields a Replicated Array: $\text{map } (\lambda \_. b) \text{ } xs = \text{replicate } (\text{size } xs) \text{ } b$
Informal description
For any array `xs` of type `Array α` and any element `b` of type `β`, mapping the constant function `(fun _ => b)` over `xs` produces an array equal to `replicate xs.size b`. That is: \[ \text{map } (\lambda \_. b) \text{ } xs = \text{replicate } (\text{size } xs) \text{ } b \]
Array.set_replicate_self theorem
: (replicate n a).set i a h = replicate n a
Full source
@[simp] theorem set_replicate_self : (replicate n a).set i a h = replicate n a := by
  apply Array.ext'
  simp
Invariance of Replicated Array Under Self-Replacement: $(\text{replicate}\ n\ a).\text{set}\ i\ a\ h = \text{replicate}\ n\ a$
Informal description
For any natural number $n$, element $a$ of type $\alpha$, index $i$, and proof $h$ that $i$ is within bounds, setting the element at index $i$ in the array $\text{replicate}\ n\ a$ to $a$ results in the same array $\text{replicate}\ n\ a$.
Array.set_mkArray_self abbrev
Full source
@[deprecated set_replicate_self (since := "2025-03-18")]
abbrev set_mkArray_self := @set_replicate_self
Invariance of mkArray Under Self-Replacement: $(\text{mkArray}\ n\ a).\text{set}\ i\ a\ h = \text{mkArray}\ n\ a$
Informal description
For any natural number $n$, element $a$ of type $\alpha$, index $i$, and proof $h$ that $i$ is within bounds, setting the element at index $i$ in the array $\text{mkArray}\ n\ a$ to $a$ results in the same array $\text{mkArray}\ n\ a$.
Array.setIfInBounds_replicate_self theorem
: (replicate n a).setIfInBounds i a = replicate n a
Full source
@[simp] theorem setIfInBounds_replicate_self : (replicate n a).setIfInBounds i a = replicate n a := by
  apply Array.ext'
  simp
Invariance of Replicated Array Under Self-Replacement: $(\text{replicate}\ n\ a).\text{setIfInBounds}\ i\ a = \text{replicate}\ n\ a$
Informal description
For any natural number $n$, element $a$ of type $\alpha$, and index $i$, modifying the array $\text{replicate}\ n\ a$ by setting the element at position $i$ to $a$ (if $i$ is within bounds) results in the same array $\text{replicate}\ n\ a$.
Array.setIfInBounds_mkArray_self abbrev
Full source
@[deprecated setIfInBounds_replicate_self (since := "2025-03-18")]
abbrev setIfInBounds_mkArray_self := @setIfInBounds_replicate_self
Invariance of Initialized Array Under Self-Replacement: $(\text{mkArray}\ n\ a).\text{setIfInBounds}\ i\ a = \text{mkArray}\ n\ a$
Informal description
For any natural number $n$, element $a$ of type $\alpha$, and index $i$, modifying the array $\text{mkArray}\ n\ a$ by setting the element at position $i$ to $a$ (if $i$ is within bounds) results in the same array $\text{mkArray}\ n\ a$.
Array.replicate_append_replicate theorem
: replicate n a ++ replicate m a = replicate (n + m) a
Full source
@[simp] theorem replicate_append_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
  apply Array.ext'
  simp
Concatenation of Replicated Arrays Equals Replication of Sum
Informal description
For any natural numbers $n$ and $m$ and any element $a$ of type $\alpha$, the concatenation of two arrays `replicate n a` and `replicate m a` is equal to the array `replicate (n + m) a`. That is, $\text{replicate}\ n\ a +\!\!+\ \text{replicate}\ m\ a = \text{replicate}\ (n + m)\ a$.
Array.mkArray_append_mkArray abbrev
Full source
@[deprecated replicate_append_replicate (since := "2025-03-18")]
abbrev mkArray_append_mkArray := @replicate_append_replicate
Concatenation of Initialized Arrays Equals Initialization with Sum of Sizes
Informal description
For any natural numbers $n$ and $m$ and any element $a$ of type $\alpha$, the concatenation of two arrays `mkArray n a` and `mkArray m a` is equal to the array `mkArray (n + m) a`. That is, $\text{mkArray}\ n\ a +\!\!+\ \text{mkArray}\ m\ a = \text{mkArray}\ (n + m)\ a$.
Array.append_eq_replicate_iff theorem
{xs ys : Array α} {a : α} : xs ++ ys = replicate n a ↔ xs.size + ys.size = n ∧ xs = replicate xs.size a ∧ ys = replicate ys.size a
Full source
theorem append_eq_replicate_iff {xs ys : Array α} {a : α} :
    xs ++ ys = replicate n a ↔
      xs.size + ys.size = n ∧ xs = replicate xs.size a ∧ ys = replicate ys.size a := by
  simp [← toList_inj, List.append_eq_replicate_iff]
Concatenation of Arrays Equals Replication if and only if Components are Uniform and Sizes Sum Correctly
Informal description
For any arrays `xs` and `ys` of type `α` and any element `a` of type `α`, the concatenation `xs ++ ys` equals `replicate n a` if and only if the sum of the sizes of `xs` and `ys` equals `n`, and `xs` equals `replicate xs.size a`, and `ys` equals `replicate ys.size a`. In other words: \[ \text{xs} +\!\!+ \text{ys} = \text{replicate}\ n\ a \leftrightarrow \text{xs.size} + \text{ys.size} = n \land \text{xs} = \text{replicate}\ \text{xs.size}\ a \land \text{ys} = \text{replicate}\ \text{ys.size}\ a \]
Array.append_eq_mkArray_iff abbrev
Full source
@[deprecated append_eq_replicate_iff (since := "2025-03-18")]
abbrev append_eq_mkArray_iff := @append_eq_replicate_iff
Concatenation of Arrays Equals Initialized Array if and only if Components are Uniform and Sizes Sum Correctly
Informal description
For any arrays `xs` and `ys` of type `α` and any element `a` of type `α`, the concatenation `xs ++ ys` equals `mkArray n a` if and only if the sum of the sizes of `xs` and `ys` equals `n`, and `xs` equals `mkArray xs.size a`, and `ys` equals `mkArray ys.size a`. In other words: \[ \text{xs} +\!\!+ \text{ys} = \text{mkArray}\ n\ a \leftrightarrow \text{xs.size} + \text{ys.size} = n \land \text{xs} = \text{mkArray}\ \text{xs.size}\ a \land \text{ys} = \text{mkArray}\ \text{ys.size}\ a \]
Array.replicate_eq_append_iff theorem
{xs ys : Array α} {a : α} : replicate n a = xs ++ ys ↔ xs.size + ys.size = n ∧ xs = replicate xs.size a ∧ ys = replicate ys.size a
Full source
theorem replicate_eq_append_iff {xs ys : Array α} {a : α} :
    replicatereplicate n a = xs ++ ys ↔
      xs.size + ys.size = n ∧ xs = replicate xs.size a ∧ ys = replicate ys.size a := by
  rw [eq_comm, append_eq_replicate_iff]
Replicated Array Equals Concatenation if and only if Components are Uniform and Sizes Sum Correctly
Informal description
For any arrays `xs` and `ys` of type `α` and any element `a` of type `α`, the replicated array `replicate n a` equals the concatenation `xs ++ ys` if and only if the sum of the sizes of `xs` and `ys` equals `n`, and `xs` equals `replicate xs.size a`, and `ys` equals `replicate ys.size a`. In other words: \[ \text{replicate}\ n\ a = \text{xs} +\!\!+ \text{ys} \leftrightarrow \text{xs.size} + \text{ys.size} = n \land \text{xs} = \text{replicate}\ \text{xs.size}\ a \land \text{ys} = \text{replicate}\ \text{ys.size}\ a \]
Array.replicate_eq_mkArray_iff abbrev
Full source
@[deprecated replicate_eq_append_iff (since := "2025-03-18")]
abbrev replicate_eq_mkArray_iff := @replicate_eq_append_iff
Replicated Array Equals Initialized Array if and only if Uniformly Filled
Informal description
For any element $a$ of type $\alpha$ and any natural number $n$, the replicated array $\text{replicate}\ n\ a$ equals the initialized array $\text{mkArray}\ n\ a$ if and only if all elements of $\text{mkArray}\ n\ a$ are equal to $a$. In other words: \[ \text{replicate}\ n\ a = \text{mkArray}\ n\ a \leftrightarrow \forall i < n, (\text{mkArray}\ n\ a)[i] = a \]
Array.map_replicate theorem
: (replicate n a).map f = replicate n (f a)
Full source
@[simp] theorem map_replicate : (replicate n a).map f = replicate n (f a) := by
  apply Array.ext'
  simp
Mapping Preserves Array Replication: $(\text{replicate}\ n\ a).\text{map}\ f = \text{replicate}\ n\ (f\ a)$
Informal description
For any natural number $n$, element $a$ of type $\alpha$, and function $f : \alpha \to \beta$, mapping $f$ over an array replicated $n$ times with $a$ is equal to replicating $n$ times with $f(a)$. That is: \[ (\text{replicate}\ n\ a).\text{map}\ f = \text{replicate}\ n\ (f\ a) \]
Array.map_mkArray abbrev
Full source
@[deprecated map_replicate (since := "2025-03-18")]
abbrev map_mkArray := @map_replicate
Mapping Preserves Array Initialization: $\text{map}\ f\ (\text{mkArray}\ n\ x) = \text{mkArray}\ n\ (f\ x)$
Informal description
For any natural number $n$, function $f : \alpha \to \beta$, and array $a$ created with `mkArray n x`, the result of mapping $f$ over $a$ is equal to creating a new array with `mkArray n (f x)`. That is: \[ \text{map}\ f\ (\text{mkArray}\ n\ x) = \text{mkArray}\ n\ (f\ x) \]
Array.filter_replicate theorem
(w : stop = n) : (replicate n a).filter p 0 stop = if p a then replicate n a else #[]
Full source
theorem filter_replicate (w : stop = n) :
    (replicate n a).filter p 0 stop = if p a then replicate n a else #[] := by
  apply Array.ext'
  simp only [w, toList_filter', toList_replicate, List.filter_replicate]
  split <;> simp_all
Filtering a Replicated Array Yields Replication or Empty Array Based on Predicate
Informal description
For any natural number $n$, element $a$ of type $\alpha$, predicate $p : \alpha \to \text{Bool}$, and index $stop$ such that $stop = n$, the filtered array obtained by applying $p$ to the array $\text{replicate}\ n\ a$ from index $0$ to $stop$ is equal to $\text{replicate}\ n\ a$ if $p(a)$ is true, and to the empty array otherwise.
Array.filter_mkArray abbrev
Full source
@[deprecated filter_replicate (since := "2025-03-18")]
abbrev filter_mkArray := @filter_replicate
Filtering Operation on Arrays Created with `mkArray`
Informal description
[Unable to provide precise informal statement without the formal statement content]
Array.filter_replicate_of_pos theorem
(w : stop = n) (h : p a) : (replicate n a).filter p 0 stop = replicate n a
Full source
@[simp] theorem filter_replicate_of_pos (w : stop = n) (h : p a) :
    (replicate n a).filter p 0 stop = replicate n a := by
  simp [filter_replicate, h, w]
Filtering a Replicated Array with True Predicate Yields Original Array
Informal description
For any natural number $n$, element $a$ of type $\alpha$, predicate $p : \alpha \to \text{Bool}$, and index $stop$ such that $stop = n$, if $p(a)$ holds, then filtering the array $\text{replicate}\ n\ a$ from index $0$ to $stop$ yields $\text{replicate}\ n\ a$.
Array.filter_mkArray_of_pos abbrev
Full source
@[deprecated filter_replicate_of_pos (since := "2025-03-18")]
abbrev filter_mkArray_of_pos := @filter_replicate_of_pos
Filtering a Constant Array with True Predicate Preserves the Array
Informal description
For any natural number $n$, element $a$ of type $\alpha$, predicate $p : \alpha \to \text{Bool}$, and index $stop$ such that $stop = n$, if $p(a)$ holds, then filtering the array created by `mkArray n a` from index $0$ to $stop$ with predicate $p$ yields the original array `mkArray n a`.
Array.filter_replicate_of_neg theorem
(w : stop = n) (h : ¬p a) : (replicate n a).filter p 0 stop = #[]
Full source
@[simp] theorem filter_replicate_of_neg (w : stop = n) (h : ¬ p a) :
    (replicate n a).filter p 0 stop = #[] := by
  simp [filter_replicate, h, w]
Filtering a Replicated Array with False Predicate Yields Empty Array
Informal description
For any natural number $n$, element $a$ of type $\alpha$, predicate $p : \alpha \to \text{Bool}$, and index $stop$ such that $stop = n$, if $p(a)$ is false, then filtering the array $\text{replicate}(n, a)$ from index $0$ to $stop$ with predicate $p$ results in the empty array $\#[]$.
Array.filter_mkArray_of_neg abbrev
Full source
@[deprecated filter_replicate_of_neg (since := "2025-03-18")]
abbrev filter_mkArray_of_neg := @filter_replicate_of_neg
Filtering a Constant Array with False Predicate Yields Empty Array
Informal description
For any natural number $n$, element $a$ of type $\alpha$, predicate $p : \alpha \to \text{Bool}$, and index $stop$ such that $stop = n$, if $p(a)$ is false, then filtering the array created by `mkArray n a` from index $0$ to $stop$ with predicate $p$ results in the empty array $\#[]$.
Array.filterMap_mkArray abbrev
Full source
@[deprecated filterMap_replicate (since := "2025-03-18")]
abbrev filterMap_mkArray := @filterMap_replicate
Filter-map operation on constructed arrays
Informal description
Given a function $f : \alpha \to \text{Option}\ \beta$ and a natural number $n$, the operation $\text{filterMap}\ f$ applied to an array constructed from $n$ elements (via $\text{mkArray}$) results in an array where each element $a$ is transformed to $b$ if $f(a) = \text{some}\ b$, otherwise the element is filtered out.
Array.filterMap_replicate_of_some theorem
{f : α → Option β} (h : f a = some b) : (replicate n a).filterMap f = replicate n b
Full source
theorem filterMap_replicate_of_some {f : α → Option β} (h : f a = some b) :
    (replicate n a).filterMap f = replicate n b := by
  simp [filterMap_replicate, h]
Filter-Map of Replicated Array with Some Result Equals Replicated Result
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and elements $a \in \alpha$, $b \in \beta$ such that $f(a) = \text{some}\ b$, the filtered and mapped array obtained by applying $f$ to each element of the replicated array $\text{replicate}\ n\ a$ is equal to the replicated array $\text{replicate}\ n\ b$.
Array.filterMap_mkArray_of_some abbrev
Full source
@[deprecated filterMap_replicate_of_some (since := "2025-03-18")]
abbrev filterMap_mkArray_of_some := @filterMap_replicate_of_some
Filter-Map of Constructed Array with Some Result Equals Constructed Result
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and elements $a \in \alpha$, $b \in \beta$ such that $f(a) = \text{some}\ b$, the filtered and mapped array obtained by applying $f$ to each element of the array constructed from $n$ elements (via $\text{mkArray}$) is equal to the array constructed from $n$ elements of $b$.
Array.filterMap_replicate_of_isSome theorem
{f : α → Option β} (h : (f a).isSome) : (replicate n a).filterMap f = replicate n (Option.get _ h)
Full source
@[simp] theorem filterMap_replicate_of_isSome {f : α → Option β} (h : (f a).isSome) :
    (replicate n a).filterMap f = replicate n (Option.get _ h) := by
  match w : f a, h with
  | some b, _ => simp [filterMap_replicate, h, w]
Filter-Map of Replicated Array with Non-Empty Option Values
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and any element $a \in \alpha$ such that $f(a)$ is non-empty (i.e., $\text{isSome}\ (f\ a)$ holds), the filtered and mapped array obtained by applying $f$ to each element of the replicated array $\text{replicate}\ n\ a$ is equal to the replicated array $\text{replicate}\ n\ (\text{Option.get}\ (f\ a)\ h)$, where $h$ is the proof that $f(a)$ is non-empty.
Array.filterMap_mkArray_of_isSome abbrev
Full source
@[deprecated filterMap_replicate_of_isSome (since := "2025-03-18")]
abbrev filterMap_mkArray_of_isSome := @filterMap_replicate_of_isSome
Filter-Map of Constructed Array with Non-Empty Option Values
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and any element $a \in \alpha$ such that $f(a)$ is non-empty (i.e., $\text{isSome}\ (f\ a)$ holds), the filtered and mapped array obtained by applying $f$ to each element of the array constructed with `mkArray` is equal to the array constructed with `mkArray` where each element is the value extracted from $f(a)$.
Array.filterMap_replicate_of_none theorem
{f : α → Option β} (h : f a = none) : (replicate n a).filterMap f = #[]
Full source
@[simp] theorem filterMap_replicate_of_none {f : α → Option β} (h : f a = none) :
    (replicate n a).filterMap f = #[] := by
  simp [filterMap_replicate, h]
Filtering Replicated Array with None Values Yields Empty Array
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and any element $a \in \alpha$ such that $f(a) = \text{none}$, the filtered and mapped array obtained by applying $f$ to an array of $n$ copies of $a$ is the empty array. In symbols: $$\text{filterMap}\ f\ (\text{replicate}\ n\ a) = \#[]$$
Array.filterMap_mkArray_of_none abbrev
Full source
@[deprecated filterMap_replicate_of_none (since := "2025-03-18")]
abbrev filterMap_mkArray_of_none := @filterMap_replicate_of_none
Filtering Mapped Array with All None Values Yields Empty Array
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and any natural number $n$, if for all $i < n$ we have $f (a_i) = \text{none}$, then the filtered and mapped array obtained by applying $f$ to an array created with `mkArray n a` is the empty array. In symbols: $$\text{filterMap}\ f\ (\text{mkArray}\ n\ a) = \#[]$$
Array.flatten_replicate_empty theorem
: (replicate n (#[] : Array α)).flatten = #[]
Full source
@[simp] theorem flatten_replicate_empty : (replicate n (#[] : Array α)).flatten = #[] := by
  rw [← toList_inj]
  simp
Flattening Replicated Empty Arrays Yields Empty Array
Informal description
For any natural number $n$, flattening an array consisting of $n$ empty arrays (of type `Array α`) results in an empty array. In symbols: $$\text{flatten}(\text{replicate}\ n\ \#[]) = \#[]$$
Array.flatten_mkArray_empty abbrev
Full source
@[deprecated flatten_replicate_empty (since := "2025-03-18")]
abbrev flatten_mkArray_empty := @flatten_replicate_empty
Flattening an Array of Empty Arrays Yields Empty Array
Informal description
For any natural number $n$, flattening an array created by `mkArray n #[]` (an array of $n$ empty arrays) results in an empty array. In symbols: $$\text{flatten}(\text{mkArray}\ n\ \#[]) = \#[]$$
Array.flatten_replicate_singleton theorem
: (replicate n #[a]).flatten = replicate n a
Full source
@[simp] theorem flatten_replicate_singleton : (replicate n #[a]).flatten = replicate n a := by
  rw [← toList_inj]
  simp
Flattening Replicated Singleton Arrays: $\text{flatten}(\text{replicate}\ n\ [a]) = \text{replicate}\ n\ a$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, flattening an array consisting of $n$ copies of the singleton array $[a]$ results in an array containing $n$ copies of $a$. In symbols: $$\text{flatten}(\text{replicate}\ n\ [a]) = \text{replicate}\ n\ a$$
Array.flatten_mkArray_singleton abbrev
Full source
@[deprecated flatten_replicate_singleton (since := "2025-03-18")]
abbrev flatten_mkArray_singleton := @flatten_replicate_singleton
Flattening Singleton Arrays: $\text{flatten}(\text{mkArray}\ n\ [a]) = \text{replicate}\ n\ a$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, flattening an array created by `mkArray n #[a]` (an array of $n$ singleton arrays each containing $a$) results in an array containing $n$ copies of $a$. In symbols: $$\text{flatten}(\text{mkArray}\ n\ [a]) = \text{replicate}\ n\ a$$
Array.flatten_replicate_replicate theorem
: (replicate n (replicate m a)).flatten = replicate (n * m) a
Full source
@[simp] theorem flatten_replicate_replicate : (replicate n (replicate m a)).flatten = replicate (n * m) a := by
  rw [← toList_inj]
  simp
Flattening Replicated Arrays: $\text{flatten}(\text{replicate}\ n\ (\text{replicate}\ m\ a)) = \text{replicate}\ (n \times m)\ a$
Informal description
For any natural numbers $n$ and $m$ and any element $a$ of type $\alpha$, flattening an array consisting of $n$ copies of an array with $m$ copies of $a$ results in an array with $n \times m$ copies of $a$. In symbols: $$\text{flatten}(\text{replicate}\ n\ (\text{replicate}\ m\ a)) = \text{replicate}\ (n \times m)\ a$$
Array.flatten_mkArray_replicate abbrev
Full source
@[deprecated flatten_replicate_replicate (since := "2025-03-18")]
abbrev flatten_mkArray_replicate := @flatten_replicate_replicate
Flattening of Constructed Replicated Arrays: $\text{flatten}(\text{mkArray}\ n\ a) = \text{replicate}\ n\ a$
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, flattening an array constructed by `mkArray` with $n$ copies of $a$ results in an array with $n$ copies of $a$. In symbols: $$\text{flatten}(\text{mkArray}\ n\ a) = \text{replicate}\ n\ a$$
Array.flatMap_replicate theorem
{f : α → Array β} : (replicate n a).flatMap f = (replicate n (f a)).flatten
Full source
theorem flatMap_replicate {f : α → Array β} : (replicate n a).flatMap f = (replicate n (f a)).flatten := by
  rw [← toList_inj]
  simp [flatMap_toList, List.flatMap_replicate]
FlatMap of Replicated Array Equals Flatten of Replicated Function Results
Informal description
For any natural number $n$, element $a$ of type $\alpha$, and function $f : \alpha \to \text{Array}\ \beta$, the flatMap operation applied to the replicated array $\text{replicate}\ n\ a$ with function $f$ is equal to flattening the array obtained by replicating $f(a)$ $n$ times. That is, \[ \text{flatMap}\ f\ (\text{replicate}\ n\ a) = \text{flatten}\ (\text{replicate}\ n\ (f\ a)). \]
Array.flatMap_mkArray abbrev
Full source
@[deprecated flatMap_replicate (since := "2025-03-18")]
abbrev flatMap_mkArray := @flatMap_replicate
FlatMap of Initialized Array Equals Flatten of Initialized Function Results
Informal description
For any natural number $n$, function $f : \mathbb{N} \to \text{Array}\ \alpha$, and function $g : \alpha \to \text{Array}\ \beta$, the flatMap operation applied to the array created by initializing an array of size $n$ where each element at index $i$ is $f(i)$, with function $g$, is equal to flattening the array obtained by initializing an array of size $n$ where each element at index $i$ is the result of applying $g$ to each element of $f(i)$. That is, \[ \text{flatMap}\ g\ (\text{mkArray}\ n\ f) = \text{flatten}\ (\text{mkArray}\ n\ (g \circ f)). \]
Array.isEmpty_replicate theorem
: (replicate n a).isEmpty = decide (n = 0)
Full source
@[simp] theorem isEmpty_replicate : (replicate n a).isEmpty = decide (n = 0) := by
  rw [← List.toArray_replicate, List.isEmpty_toArray]
  simp
Replicated Array is Empty if and only if Replication Count is Zero
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the array created by replicating $a$ exactly $n$ times is empty if and only if $n = 0$. Formally, $\text{isEmpty}(\text{replicate}\ n\ a) = \text{decide}(n = 0)$.
Array.isEmpty_mkArray abbrev
Full source
@[deprecated isEmpty_replicate (since := "2025-03-18")]
abbrev isEmpty_mkArray := @isEmpty_replicate
Initialized Array is Empty if and only if Size is Zero
Informal description
For any natural number $n$ and any function $f : \mathbb{N} \to \alpha$, the array created by initializing an array of size $n$ where each element at index $i$ is $f(i)$ is empty if and only if $n = 0$. Formally, $\text{isEmpty}(\text{mkArray}\ n\ f) = \text{decide}(n = 0)$.
Array.sum_replicate_nat theorem
{n : Nat} {a : Nat} : (replicate n a).sum = n * a
Full source
@[simp] theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
  rw [← List.toArray_replicate, List.sum_toArray]
  simp
Sum of Replicated Array: $\text{sum}(\text{replicate}\ n\ a) = n \cdot a$
Informal description
For any natural numbers $n$ and $a$, the sum of the elements in an array created by replicating $a$ exactly $n$ times is equal to $n$ multiplied by $a$, i.e., $\text{sum}(\text{replicate}\ n\ a) = n \cdot a$.
Array.sum_mkArray_nat abbrev
Full source
@[deprecated sum_replicate_nat (since := "2025-03-18")]
abbrev sum_mkArray_nat := @sum_replicate_nat
Sum of Initialized Array: $\text{sum}(\text{mkArray}\ n\ f) = \sum_{i=0}^{n-1} f i$
Informal description
For any natural number $n$ and any function $f : \mathbb{N} \to \mathbb{N}$, the sum of the elements in an array created by initializing an array of size $n$ where each element at index $i$ is $f i$ is equal to the sum $\sum_{i=0}^{n-1} f i$.
Array.getElem?_swap theorem
{xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i j hi hj)[k]? = if j = k then some xs[i] else if i = k then some xs[j] else xs[k]?
Full source
theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i j hi hj)[k]? =
    if j = k then some xs[i] else if i = k then some xs[j] else xs[k]? := by
  simp [swap_def, getElem?_set]
Optional Access After Array Swap: $(xs.\text{swap}\ i\ j)[k]? = \text{if } j = k \text{ then } \text{some } xs[i] \text{ else if } i = k \text{ then } \text{some } xs[j] \text{ else } xs[k]?$
Informal description
For any array `xs` of type `Array α`, indices `i` and `j` with proofs `hi : i < xs.size` and `hj : j < xs.size`, and any index `k`, the optional access operation on the array after swapping elements at `i` and `j` satisfies: $$(\text{xs.swap}\ i\ j\ hi\ hj)[k]? = \begin{cases} \text{some}\ \text{xs}[i] & \text{if } j = k \\ \text{some}\ \text{xs}[j] & \text{if } i = k \\ \text{xs}[k]? & \text{otherwise} \end{cases}$$
Array.size_reverse theorem
{xs : Array α} : xs.reverse.size = xs.size
Full source
@[simp] theorem size_reverse {xs : Array α} : xs.reverse.size = xs.size := by
  let rec go (as : Array α) (i j) : (reverse.loop as i j).size = as.size := by
    rw [reverse.loop]
    if h : i < j then
      simp [(go · (i+1) ⟨j-1, ·⟩), h]
    else simp [h]
    termination_by j - i
  simp only [reverse]; split <;> simp [go]
Size Preservation under Array Reversal
Informal description
For any array `xs` of type `Array α`, the size of the reversed array `xs.reverse` is equal to the size of the original array `xs`. That is, $|\text{xs.reverse}| = |\text{xs}|$.
Array.toList_reverse theorem
{xs : Array α} : xs.reverse.toList = xs.toList.reverse
Full source
@[simp] theorem toList_reverse {xs : Array α} : xs.reverse.toList = xs.toList.reverse := by
  let rec go (as : Array α) (i j hj)
      (h : i + j + 1 = xs.size) (h₂ : as.size = xs.size)
      (H : ∀ k, as.toList[k]? = if i ≤ k ∧ k ≤ j then xs.toList[k]? else xs.toList.reverse[k]?)
      (k : Nat) : (reverse.loop as i ⟨j, hj⟩).toList[k]? = xs.toList.reverse[k]? := by
    rw [reverse.loop]; dsimp only; split <;> rename_i h₁
    · match j with | j+1 => ?_
      simp only [Nat.add_sub_cancel]
      rw [(go · (i+1) j)]
      · rwa [Nat.add_right_comm i]
      · simp [size_swap, h₂]
      · intro k
        rw [getElem?_toList, getElem?_swap]
        simp only [H, ← getElem_toList, ← List.getElem?_eq_getElem, Nat.le_of_lt h₁,
          ← getElem?_toList]
        split <;> rename_i h₂
        · simp only [← h₂, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, and_false]
          exact (List.getElem?_reverse' (Eq.trans (by simp +arith) h)).symm
        split <;> rename_i h₃
        · simp only [← h₃, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, false_and]
          exact (List.getElem?_reverse' (Eq.trans (by simp +arith) h)).symm
        simp only [Nat.succ_le, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
          Nat.lt_succ.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
    · rw [H]; split <;> rename_i h₂
      · cases Nat.le_antisymm (Nat.not_lt.1 h₁) (Nat.le_trans h₂.1 h₂.2)
        cases Nat.le_antisymm h₂.1 h₂.2
        exact (List.getElem?_reverse' h).symm
      · rfl
    termination_by j - i
  simp only [reverse]
  split
  · match xs with | ⟨[]⟩ | ⟨[_]⟩ => rfl
  · have := Nat.sub_add_cancel (Nat.le_of_not_le ‹_›)
    refine List.ext_getElem? <| go _ _ _ _ (by simp [this]) rfl fun k => ?_
    split
    · rfl
    · rename_i h
      simp only [← show k < _ + 1 ↔ _ from Nat.lt_succ (n := xs.size - 1), this, Nat.zero_le,
        true_and, Nat.not_lt] at h
      rw [List.getElem?_eq_none_iff.2 ‹_›, List.getElem?_eq_none_iff.2 (xs.toList.length_reverse ▸ ‹_›)]
List Conversion Commutes with Array Reversal: $\text{toList}(\text{reverse}(xs)) = \text{reverse}(\text{toList}(xs))$
Informal description
For any array `xs` of type `Array α`, converting the reversed array `xs.reverse` to a list yields the same result as first converting `xs` to a list and then reversing that list. That is, $\text{toList}(\text{xs.reverse}) = \text{reverse}(\text{toList}(\text{xs}))$.
List.reverse_toArray theorem
{l : List α} : l.toArray.reverse = l.reverse.toArray
Full source
@[simp] theorem _root_.List.reverse_toArray {l : List α} : l.toArray.reverse = l.reverse.toArray := by
  apply ext'
  simp only [toList_reverse]
Reversal Commutes with List-to-Array Conversion: $\text{reverse}(\text{toArray}(l)) = \text{toArray}(\text{reverse}(l))$
Informal description
For any list $l$ of elements of type $\alpha$, reversing the array obtained from $l$ is equal to the array obtained from the reversed list. That is, $\text{reverse}(\text{toArray}(l)) = \text{toArray}(\text{reverse}(l))$.
Array.reverse_push theorem
{xs : Array α} {a : α} : (xs.push a).reverse = #[a] ++ xs.reverse
Full source
@[simp] theorem reverse_push {xs : Array α} {a : α} : (xs.push a).reverse = #[a] ++ xs.reverse := by
  cases xs
  simp
Reversal of Pushed Array: $\text{reverse}(\text{push}(xs, a)) = \#[a] \mathbin{+\mkern-10mu+} \text{reverse}(xs)$
Informal description
For any array `xs` of type `Array α` and any element `a` of type `α`, reversing the array obtained by appending `a` to `xs` is equal to the array `#[a]` (a singleton array containing `a`) concatenated with the reversed array `xs.reverse`. That is, $\text{reverse}(\text{xs.push}(a)) = \#[a] \mathbin{+\mkern-10mu+} \text{xs.reverse}$.
Array.mem_reverse theorem
{x : α} {xs : Array α} : x ∈ xs.reverse ↔ x ∈ xs
Full source
@[simp] theorem mem_reverse {x : α} {xs : Array α} : x ∈ xs.reversex ∈ xs.reverse ↔ x ∈ xs := by
  cases xs
  simp
Membership Preservation Under Array Reversal: $x \in \text{reverse}(xs) \leftrightarrow x \in xs$
Informal description
For any element $x$ of type $\alpha$ and any array `xs` of elements of type $\alpha$, the element $x$ is in the reversed array `xs.reverse` if and only if $x$ is in the original array `xs$. That is, $x \in \text{reverse}(xs) \leftrightarrow x \in xs$.
Array.getElem_reverse theorem
{xs : Array α} {i : Nat} (hi : i < xs.reverse.size) : (xs.reverse)[i] = xs[xs.size - 1 - i]'(by simp at hi; omega)
Full source
@[simp] theorem getElem_reverse {xs : Array α} {i : Nat} (hi : i < xs.reverse.size) :
    (xs.reverse)[i] = xs[xs.size - 1 - i]'(by simp at hi; omega) := by
  cases xs
  simp
Element Access in Reversed Array: $\text{reverse}(xs)[i] = xs[|xs| - 1 - i]$
Informal description
For any array `xs` of type `Array α` and any natural number index `i` such that `i < xs.reverse.size`, the element at position `i` in the reversed array `xs.reverse` is equal to the element at position `xs.size - 1 - i` in the original array `xs`. That is, $\text{xs.reverse}[i] = \text{xs}[|\text{xs}| - 1 - i]$.
Array.getElem_eq_getElem_reverse theorem
{xs : Array α} {i} (h : i < xs.size) : xs[i] = xs.reverse[xs.size - 1 - i]'(by simpa using Nat.sub_one_sub_lt_of_lt h)
Full source
theorem getElem_eq_getElem_reverse {xs : Array α} {i} (h : i < xs.size) :
    xs[i] = xs.reverse[xs.size - 1 - i]'(by simpa using Nat.sub_one_sub_lt_of_lt h) := by
  rw [getElem_reverse]
  congr
  omega
Element Access Symmetry in Array Reversal: $\text{xs}[i] = \text{reverse}(\text{xs})[|\text{xs}| - 1 - i]$
Informal description
For any array `xs` of type `Array α` and any natural number index `i` such that `i < xs.size`, the element at position `i` in the array `xs` is equal to the element at position `xs.size - 1 - i` in the reversed array `xs.reverse`. That is, $\text{xs}[i] = \text{xs.reverse}[|\text{xs}| - 1 - i]$.
Array.reverse_eq_empty_iff theorem
{xs : Array α} : xs.reverse = #[] ↔ xs = #[]
Full source
@[simp] theorem reverse_eq_empty_iff {xs : Array α} : xs.reverse = #[] ↔ xs = #[] := by
  cases xs
  simp
Reversed Array is Empty if and Only if Original Array is Empty
Informal description
For any array `xs` of elements of type `α`, the reversed array `xs.reverse` is equal to the empty array `#[]` if and only if `xs` itself is equal to the empty array `#[]`.
Array.reverse_ne_empty_iff theorem
{xs : Array α} : xs.reverse ≠ #[] ↔ xs ≠ #[]
Full source
theorem reverse_ne_empty_iff {xs : Array α} : xs.reverse ≠ #[]xs.reverse ≠ #[] ↔ xs ≠ #[] :=
  not_congr reverse_eq_empty_iff
Non-emptiness of Reversed Array Equivalent to Original Array: $\text{reverse}(xs) \neq \#[] \leftrightarrow xs \neq \#[]$
Informal description
For any array `xs` of elements of type `α`, the reversed array `xs.reverse` is not equal to the empty array `#[]` if and only if `xs` itself is not equal to the empty array `#[]`.
Array.isEmpty_reverse theorem
{xs : Array α} : xs.reverse.isEmpty = xs.isEmpty
Full source
@[simp] theorem isEmpty_reverse {xs : Array α} : xs.reverse.isEmpty = xs.isEmpty := by
  cases xs
  simp
Reversal Preserves Emptiness: $\text{isEmpty}(\text{reverse}(xs)) = \text{isEmpty}(xs)$
Informal description
For any array `xs` of elements of type `α`, the property of being empty is preserved under reversal. That is, `xs.reverse` is empty if and only if `xs` is empty.
Array.getElem?_reverse' theorem
{xs : Array α} {i j} (h : i + j + 1 = xs.size) : xs.reverse[i]? = xs[j]?
Full source
/-- Variant of `getElem?_reverse` with a hypothesis giving the linear relation between the indices. -/
theorem getElem?_reverse' {xs : Array α} {i j} (h : i + j + 1 = xs.size) : xs.reverse[i]? = xs[j]? := by
  rcases xs with ⟨xs⟩
  simp at h
  simp only [List.reverse_toArray, List.getElem?_toArray]
  rw [List.getElem?_reverse' h]
Reversed Array Index Correspondence: `xs.reverse[i]? = xs[j]?` when `i + j + 1 = xs.size`
Informal description
For any array `xs` of type `Array α` and indices `i` and `j` such that `i + j + 1 = xs.size`, the optional element at index `i` in the reversed array `xs.reverse` is equal to the optional element at index `j` in the original array `xs`. That is, `xs.reverse[i]? = xs[j]?`.
Array.getElem?_reverse theorem
{xs : Array α} {i} (h : i < xs.size) : xs.reverse[i]? = xs[xs.size - 1 - i]?
Full source
@[simp]
theorem getElem?_reverse {xs : Array α} {i} (h : i < xs.size) :
    xs.reverse[i]? = xs[xs.size - 1 - i]? := by
  cases xs
  simp_all
Optional Access in Reversed Array: $xs.\text{reverse}[i]? = xs[\text{size}(xs) - 1 - i]?$ for $i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α` and index `i` such that `i < xs.size`, the optional access operation on the reversed array satisfies `xs.reverse[i]? = xs[xs.size - 1 - i]?`. That is, accessing the `i`-th element of the reversed array (if it exists) is equivalent to accessing the element at position `xs.size - 1 - i` in the original array.
Array.reverse_reverse theorem
(xs : Array α) : xs.reverse.reverse = xs
Full source
@[simp] theorem reverse_reverse (xs : Array α) : xs.reverse.reverse = xs := by
  cases xs
  simp
Double Reversal of Array Yields Original Array
Informal description
For any array `xs` of elements of type `α`, reversing the array twice yields the original array, i.e., $\text{reverse}(\text{reverse}(xs)) = xs$.
Array.reverse_eq_iff theorem
{xs ys : Array α} : xs.reverse = ys ↔ xs = ys.reverse
Full source
theorem reverse_eq_iff {xs ys : Array α} : xs.reverse = ys ↔ xs = ys.reverse := by
  constructor <;> (rintro rfl; simp)
Reverse Equivalence: $\text{reverse}(xs) = ys \leftrightarrow xs = \text{reverse}(ys)$
Informal description
For any two arrays `xs` and `ys` of elements of type `α`, the reverse of `xs` equals `ys` if and only if `xs` equals the reverse of `ys`. That is, $\text{reverse}(xs) = ys \leftrightarrow xs = \text{reverse}(ys)$.
Array.reverse_inj theorem
{xs ys : Array α} : xs.reverse = ys.reverse ↔ xs = ys
Full source
@[simp] theorem reverse_inj {xs ys : Array α} : xs.reverse = ys.reverse ↔ xs = ys := by
  simp [reverse_eq_iff]
Injectivity of Array Reversal: $\text{reverse}(xs) = \text{reverse}(ys) \leftrightarrow xs = ys$
Informal description
For any two arrays `xs` and `ys` of elements of type `α`, the reversed version of `xs` equals the reversed version of `ys` if and only if `xs` equals `ys`. In other words, the reversal operation is injective on arrays.
Array.reverse_eq_push_iff theorem
{xs : Array α} {ys : Array α} {a : α} : xs.reverse = ys.push a ↔ xs = #[a] ++ ys.reverse
Full source
@[simp] theorem reverse_eq_push_iff {xs : Array α} {ys : Array α} {a : α} :
    xs.reverse = ys.push a ↔ xs = #[a] ++ ys.reverse := by
  rw [reverse_eq_iff, reverse_push]
Reverse-Push Equivalence for Arrays: $\text{reverse}(xs) = \text{push}(ys, a) \leftrightarrow xs = \#[a] \mathbin{+\mkern-10mu+} \text{reverse}(ys)$
Informal description
For any arrays `xs` and `ys` of elements of type $\alpha$ and any element $a \in \alpha$, the reverse of `xs` equals the array obtained by appending $a$ to `ys` if and only if `xs` equals the array `#[a]` (singleton array containing $a$) concatenated with the reverse of `ys`. That is: \[ \text{reverse}(xs) = \text{push}(ys, a) \leftrightarrow xs = \#[a] \mathbin{+\mkern-10mu+} \text{reverse}(ys) \]
Array.map_reverse theorem
{f : α → β} {xs : Array α} : xs.reverse.map f = (xs.map f).reverse
Full source
@[simp] theorem map_reverse {f : α → β} {xs : Array α} : xs.reverse.map f = (xs.map f).reverse := by
  cases xs <;> simp [*]
Mapping Commutes with Array Reversal: $\text{map}(f, \text{reverse}(xs)) = \text{reverse}(\text{map}(f, xs))$
Informal description
For any function $f : \alpha \to \beta$ and any array `xs` of elements of type $\alpha$, mapping $f$ over the reversed array `xs.reverse` is equal to reversing the array obtained by mapping $f$ over `xs$. That is, $\text{map}(f, \text{reverse}(xs)) = \text{reverse}(\text{map}(f, xs))$.
Array.filter_reverse' theorem
{p : α → Bool} {xs : Array α} {stop : Nat} (w : stop = xs.size) : (xs.reverse.filter p 0 stop) = (xs.filter p).reverse
Full source
/-- Variant of `filter_reverse` with a hypothesis giving the stop condition. -/
@[simp] theorem filter_reverse' {p : α → Bool} {xs : Array α} {stop : Nat} (w : stop = xs.size) :
     (xs.reverse.filter p 0 stop) = (xs.filter p).reverse := by
  subst w
  cases xs
  simp
Filtering a Reversed Array with Bounds Equals Reversing the Filtered Array
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $xs$ of type $\alpha$, if $stop$ is equal to the size of $xs$, then filtering the reversed array $xs.\text{reverse}$ from index $0$ to $stop$ with predicate $p$ yields the same result as reversing the filtered array $xs.\text{filter}(p)$.
Array.filter_reverse theorem
{p : α → Bool} {xs : Array α} : (xs.reverse.filter p) = (xs.filter p).reverse
Full source
theorem filter_reverse {p : α → Bool} {xs : Array α} : (xs.reverse.filter p) = (xs.filter p).reverse := by
  cases xs
  simp
Filtering Commutes with Array Reversal: $\text{filter}(p, \text{reverse}(xs)) = \text{reverse}(\text{filter}(p, xs))$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and array $xs$ of type $\alpha$, filtering the reversed array $xs.\text{reverse}$ with predicate $p$ yields the same result as reversing the filtered array $xs.\text{filter}(p)$. That is, $\text{filter}(p, \text{reverse}(xs)) = \text{reverse}(\text{filter}(p, xs))$.
Array.filterMap_reverse' theorem
{f : α → Option β} {xs : Array α} {stop : Nat} (w : stop = xs.size) : (xs.reverse.filterMap f 0 stop) = (xs.filterMap f).reverse
Full source
/-- Variant of `filterMap_reverse` with a hypothesis giving the stop condition. -/
@[simp] theorem filterMap_reverse' {f : α → Option β} {xs : Array α} {stop : Nat} (w : stop = xs.size) :
    (xs.reverse.filterMap f 0 stop) = (xs.filterMap f).reverse := by
  subst w
  cases xs
  simp
Reversed Filter-Map Equals Filter-Map Reversed for Arrays
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any array $xs$ of type $\text{Array } \alpha$, and any natural number $\text{stop}$ such that $\text{stop} = \text{size}(xs)$, the filtered and mapped reversed array $(xs.\text{reverse}).\text{filterMap } f \ 0 \ \text{stop}$ is equal to the reversed filtered and mapped array $(xs.\text{filterMap } f).\text{reverse}$.
Array.filterMap_reverse theorem
{f : α → Option β} {xs : Array α} : (xs.reverse.filterMap f) = (xs.filterMap f).reverse
Full source
theorem filterMap_reverse {f : α → Option β} {xs : Array α} : (xs.reverse.filterMap f) = (xs.filterMap f).reverse := by
  cases xs
  simp
Reversing Commutes with FilterMap on Arrays: $\text{filterMap } f (\text{reverse}(xs)) = \text{reverse}(\text{filterMap } f \ xs)$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any array $xs$ of type $\text{Array } \alpha$, applying the `filterMap` operation to the reversed array $xs.\text{reverse}$ is equal to reversing the result of applying `filterMap` to $xs$. That is, $\text{filterMap } f (xs.\text{reverse}) = (\text{filterMap } f \ xs).\text{reverse}$.
Array.reverse_append theorem
{xs ys : Array α} : (xs ++ ys).reverse = ys.reverse ++ xs.reverse
Full source
@[simp] theorem reverse_append {xs ys : Array α} : (xs ++ ys).reverse = ys.reverse ++ xs.reverse := by
  cases xs
  cases ys
  simp
Reverse of Concatenated Arrays Equals Concatenation of Reverses
Informal description
For any arrays `xs` and `ys` of elements of type `α`, the reverse of their concatenation `xs ++ ys` is equal to the concatenation of the reverses of `ys` and `xs`, i.e., $\text{reverse}(xs \mathbin{+\!\!+} ys) = \text{reverse}(ys) \mathbin{+\!\!+} \text{reverse}(xs)$.
Array.reverse_eq_append_iff theorem
{xs ys zs : Array α} : xs.reverse = ys ++ zs ↔ xs = zs.reverse ++ ys.reverse
Full source
@[simp] theorem reverse_eq_append_iff {xs ys zs : Array α} :
    xs.reverse = ys ++ zs ↔ xs = zs.reverse ++ ys.reverse := by
  cases xs
  cases ys
  cases zs
  simp
Characterization of Array Reversal via Concatenation: $\text{reverse}(xs) = ys \mathbin{+\kern-1.5ex+} zs \iff xs = \text{reverse}(zs) \mathbin{+\kern-1.5ex+} \text{reverse}(ys)$
Informal description
For any arrays `xs`, `ys`, and `zs` of elements of type `α`, the reverse of `xs` is equal to the concatenation of `ys` and `zs` if and only if `xs` is equal to the concatenation of the reverse of `zs` and the reverse of `ys`. In symbols: \[ \text{reverse}(xs) = ys \mathbin{+\kern-1.5ex+} zs \iff xs = \text{reverse}(zs) \mathbin{+\kern-1.5ex+} \text{reverse}(ys) \]
Array.reverse_flatten theorem
{xss : Array (Array α)} : xss.flatten.reverse = (xss.map reverse).reverse.flatten
Full source
/-- Reversing a flatten is the same as reversing the order of parts and reversing all parts. -/
theorem reverse_flatten {xss : Array (Array α)} :
    xss.flatten.reverse = (xss.map reverse).reverse.flatten := by
  cases xss using array₂_induction
  simp [flatten_toArray, List.reverse_flatten, Function.comp_def]
Reversal-Flattening Commutation: $\text{reverse}(\text{flatten}(xss)) = \text{flatten}(\text{reverse}(\text{map reverse}(xss)))$
Informal description
For any array of arrays `xss` of type `Array (Array α)`, reversing the flattened array `xss.flatten` is equal to first reversing each subarray in `xss` (via `xss.map reverse`), then reversing the resulting array of arrays, and finally flattening it. In symbols: $$\text{reverse}(\text{flatten}(xss)) = \text{flatten}(\text{reverse}(\text{map reverse}(xss)))$$
Array.flatten_reverse theorem
{xss : Array (Array α)} : xss.reverse.flatten = (xss.map reverse).flatten.reverse
Full source
/-- Flattening a reverse is the same as reversing all parts and reversing the flattened result. -/
theorem flatten_reverse {xss : Array (Array α)} :
    xss.reverse.flatten = (xss.map reverse).flatten.reverse := by
  cases xss using array₂_induction
  simp [flatten_toArray, List.flatten_reverse, Function.comp_def]
Flattening Commutes with Array Reversal: $\text{flatten}(\text{reverse}(xss)) = \text{reverse}(\text{flatten}(\text{map reverse}(xss)))$
Informal description
For any array `xss` of arrays of type `α`, flattening the reversed array `xss.reverse` is equal to reversing the flattened array obtained by first reversing each subarray in `xss` (via `xss.map reverse`). In symbols: $$\text{flatten}(\text{reverse}(xss)) = \text{reverse}(\text{flatten}(\text{map reverse}(xss)))$$
Array.reverse_flatMap theorem
{β} {xs : Array α} {f : α → Array β} : (xs.flatMap f).reverse = xs.reverse.flatMap (reverse ∘ f)
Full source
theorem reverse_flatMap {β} {xs : Array α} {f : α → Array β} :
    (xs.flatMap f).reverse = xs.reverse.flatMap (reversereverse ∘ f) := by
  cases xs
  simp [List.reverse_flatMap, Function.comp_def]
Reversal Commutes with FlatMap: $\text{reverse}(\text{flatMap}\ f\ \text{xs}) = \text{flatMap}\ (\text{reverse} \circ f)\ (\text{reverse}\ \text{xs})$
Informal description
For any array `xs` of type `Array α` and any function `f : α → Array β`, reversing the array obtained by flat-mapping `f` over `xs` is equal to flat-mapping the composition of `reverse` and `f` over the reversed array `xs.reverse`. That is, $\text{reverse}(\text{flatMap}\ f\ \text{xs}) = \text{flatMap}\ (\text{reverse} \circ f)\ (\text{reverse}\ \text{xs})$.
Array.flatMap_reverse theorem
{β} {xs : Array α} {f : α → Array β} : (xs.reverse.flatMap f) = (xs.flatMap (reverse ∘ f)).reverse
Full source
theorem flatMap_reverse {β} {xs : Array α} {f : α → Array β} :
    (xs.reverse.flatMap f) = (xs.flatMap (reversereverse ∘ f)).reverse := by
  cases xs
  simp [List.flatMap_reverse, Function.comp_def]
FlatMap Commutes with Array Reversal: $\text{flatMap}\ f\ (\text{reverse}\ xs) = \text{reverse}\ (\text{flatMap}\ (\text{reverse} \circ f)\ xs)$
Informal description
For any array `xs` of type `Array α` and any function `f : α → Array β`, the flatMap operation applied to the reversed array `xs.reverse` with function `f` is equal to the reverse of the flatMap operation applied to `xs` with the composition of `reverse` and `f`. That is, $\text{flatMap}\ f\ (\text{reverse}\ xs) = \text{reverse}\ (\text{flatMap}\ (\text{reverse} \circ f)\ xs)$.
Array.reverse_replicate theorem
{n : Nat} {a : α} : reverse (replicate n a) = replicate n a
Full source
@[simp] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
  rw [← toList_inj]
  simp
Reversed Replicated Array Equals Original: $\text{reverse}(\text{replicate}\ n\ a) = \text{replicate}\ n\ a$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, reversing an array consisting of $n$ copies of $a$ yields the same array, i.e., $\text{reverse}(\text{replicate}\ n\ a) = \text{replicate}\ n\ a$.
Array.reverse_mkArray abbrev
Full source
@[deprecated reverse_replicate (since := "2025-03-18")]
abbrev reverse_mkArray := @reverse_replicate
Reversed Constructed Array Equals Original: $\text{reverse}(\text{mkArray}\ n\ f) = \text{mkArray}\ n\ f$
Informal description
For any natural number $n$ and any function $f : \mathbb{N} \to \alpha$, reversing an array constructed by applying $f$ to each index from $0$ to $n-1$ yields the same array as constructing it directly, i.e., $\text{reverse}(\text{mkArray}\ n\ f) = \text{mkArray}\ n\ f$.
Array.extract_loop_zero theorem
{xs ys : Array α} {start : Nat} : extract.loop xs 0 start ys = ys
Full source
theorem extract_loop_zero {xs ys : Array α} {start : Nat} : extract.loop xs 0 start ys = ys := by
  rw [extract.loop]; split <;> rfl
Base Case of Array Extraction Loop with Zero Size
Informal description
For any arrays `xs` and `ys` of type `α` and any natural number `start`, the loop function `extract.loop` applied to `xs` with size parameter `0`, start index `start`, and initial accumulator `ys` returns `ys` unchanged.
Array.extract_loop_succ theorem
{xs ys : Array α} {size start : Nat} (h : start < xs.size) : extract.loop xs (size + 1) start ys = extract.loop xs size (start + 1) (ys.push xs[start])
Full source
theorem extract_loop_succ {xs ys : Array α} {size start : Nat} (h : start < xs.size) :
    extract.loop xs (size+1) start ys = extract.loop xs size (start+1) (ys.push xs[start]) := by
  rw [extract.loop, dif_pos h]; rfl
Recursive Step for Array Extraction Loop with Push Operation
Informal description
For any arrays `xs` and `ys` of type `Array α`, natural numbers `size` and `start`, and a proof `h` that `start < xs.size`, the recursive extraction loop satisfies: \[ \text{extract.loop}\ xs\ (size + 1)\ start\ ys = \text{extract.loop}\ xs\ size\ (start + 1)\ (ys.push\ xs[start]) \] where `extract.loop` processes elements from `xs` starting at index `start`, accumulating results in `ys`, and `ys.push xs[start]` appends the element at index `start` of `xs` to `ys`.
Array.extract_loop_of_ge theorem
{xs ys : Array α} {size start : Nat} (h : start ≥ xs.size) : extract.loop xs size start ys = ys
Full source
theorem extract_loop_of_ge {xs ys : Array α} {size start : Nat} (h : start ≥ xs.size) :
    extract.loop xs size start ys = ys := by
  rw [extract.loop, dif_neg (Nat.not_lt_of_ge h)]
Extraction Loop Returns Original Array When Start Index Exceeds Bounds
Informal description
For any arrays `xs`, `ys` of type `α`, natural numbers `size`, `start`, if the starting index `start` is greater than or equal to the size of `xs`, then the extraction loop `extract.loop xs size start ys` returns `ys` unchanged.
Array.extract_loop_eq_aux theorem
{xs ys : Array α} {size start : Nat} : extract.loop xs size start ys = ys ++ extract.loop xs size start #[]
Full source
theorem extract_loop_eq_aux {xs ys : Array α} {size start : Nat} :
    extract.loop xs size start ys = ys ++ extract.loop xs size start #[] := by
  induction size using Nat.recAux generalizing start ys with
  | zero => rw [extract_loop_zero, extract_loop_zero, append_empty]
  | succ size ih =>
    if h : start < xs.size then
      rw [extract_loop_succ (h := h), ih, push_eq_append_singleton]
      rw [extract_loop_succ (h := h), ih (ys := #[].push _), push_eq_append_singleton, empty_append]
      rw [append_assoc]
    else
      rw [extract_loop_of_ge (h := Nat.le_of_not_lt h)]
      rw [extract_loop_of_ge (h := Nat.le_of_not_lt h)]
      rw [append_empty]
Extraction Loop Concatenation Property
Informal description
For any arrays `xs` and `ys` of type `Array α` and natural numbers `size` and `start`, the extraction loop satisfies: \[ \text{extract.loop}\ xs\ size\ start\ ys = ys +\!\!+ \text{extract.loop}\ xs\ size\ start\ \#[] \] where `+\!\!+` denotes array concatenation and `#[]` denotes the empty array.
Array.extract_loop_eq theorem
{xs ys : Array α} {size start : Nat} (h : start + size ≤ xs.size) : extract.loop xs size start ys = ys ++ xs.extract start (start + size)
Full source
theorem extract_loop_eq {xs ys : Array α} {size start : Nat} (h : start + size ≤ xs.size) :
  extract.loop xs size start ys = ys ++ xs.extract start (start + size) := by
  simp only [extract, Nat.sub_eq, emptyWithCapacity_eq]
  rw [extract_loop_eq_aux, Nat.min_eq_left h, Nat.add_sub_cancel_left]
Extraction Loop Concatenation with Bounds Check
Informal description
For any arrays `xs` and `ys` of type `Array α` and natural numbers `size` and `start`, if `start + size` does not exceed the size of `xs`, then the extraction loop satisfies: \[ \text{extract.loop}\ xs\ size\ start\ ys = ys +\!\!+ \text{xs.extract}\ start\ (start + size) \] where `+\!\!+` denotes array concatenation and `xs.extract` denotes the subarray of `xs` from index `start` to `start + size - 1`.
Array.size_extract_loop theorem
{xs ys : Array α} {size start : Nat} : (extract.loop xs size start ys).size = ys.size + min size (xs.size - start)
Full source
theorem size_extract_loop {xs ys : Array α} {size start : Nat} :
    (extract.loop xs size start ys).size = ys.size + min size (xs.size - start) := by
  induction size using Nat.recAux generalizing start ys with
  | zero => rw [extract_loop_zero, Nat.zero_min, Nat.add_zero]
  | succ size ih =>
    if h : start < xs.size then
      rw [extract_loop_succ (h:=h), ih, size_push, Nat.add_assoc, ←Nat.add_min_add_left,
        Nat.sub_succ, Nat.one_add, Nat.one_add, Nat.succ_pred_eq_of_pos (Nat.sub_pos_of_lt h)]
    else
      have h := Nat.le_of_not_gt h
      rw [extract_loop_of_ge (h:=h), Nat.sub_eq_zero_of_le h, Nat.min_zero, Nat.add_zero]
Size of Array Extraction Loop: $\text{size}(\text{extract.loop}\ xs\ size\ start\ ys) = \text{size}(ys) + \min(size, \text{size}(xs) - start)$
Informal description
For any arrays `xs` and `ys` of type `Array α` and natural numbers `size` and `start`, the size of the array resulting from the extraction loop `extract.loop xs size start ys` is equal to the size of `ys` plus the minimum of `size` and the difference between the size of `xs` and `start`. That is: \[ \text{size}(\text{extract.loop}\ xs\ size\ start\ ys) = \text{size}(ys) + \min(size, \text{size}(xs) - start) \]
Array.size_extract theorem
{xs : Array α} {start stop : Nat} : (xs.extract start stop).size = min stop xs.size - start
Full source
@[simp] theorem size_extract {xs : Array α} {start stop : Nat} :
    (xs.extract start stop).size = min stop xs.size - start := by
  simp only [extract, Nat.sub_eq, emptyWithCapacity_eq]
  rw [size_extract_loop, size_empty, Nat.zero_add, Nat.sub_min_sub_right, Nat.min_assoc,
    Nat.min_self]
Size of Extracted Subarray: $\text{size}(\text{extract}\ start\ stop) = \min(\text{stop}, \text{size}) - \text{start}$
Informal description
For any array `xs` of type `Array α` and natural numbers `start` and `stop`, the size of the subarray extracted from `xs` between indices `start` and `stop` is equal to the minimum of `stop` and the size of `xs` minus `start`. That is: \[ \text{size}(\text{xs.extract}\ start\ stop) = \min(\text{stop}, \text{size}(xs)) - \text{start} \]
Array.getElem_extract_loop_lt_aux theorem
{xs ys : Array α} {size start : Nat} (hlt : i < ys.size) : i < (extract.loop xs size start ys).size
Full source
theorem getElem_extract_loop_lt_aux {xs ys : Array α} {size start : Nat} (hlt : i < ys.size) :
    i < (extract.loop xs size start ys).size := by
  rw [size_extract_loop]
  apply Nat.lt_of_lt_of_le hlt
  exact Nat.le_add_right ..
Index Preservation in Array Extraction Loop: $i < \text{size}(ys) \Rightarrow i < \text{size}(\text{extract.loop}\ xs\ size\ start\ ys)$
Informal description
For any arrays `xs` and `ys` of type `Array α`, natural numbers `size` and `start`, and index `i`, if `i` is less than the size of `ys`, then `i` is also less than the size of the array resulting from the extraction loop `extract.loop xs size start ys`.
Array.getElem_extract_loop_ge_aux theorem
{xs ys : Array α} {size start : Nat} (hge : i ≥ ys.size) (h : i < (extract.loop xs size start ys).size) : start + i - ys.size < xs.size
Full source
theorem getElem_extract_loop_ge_aux {xs ys : Array α} {size start : Nat} (hge : i ≥ ys.size)
    (h : i < (extract.loop xs size start ys).size) : start + i - ys.size < xs.size := by
  have h : i < ys.size + (xs.size - start) := by
      apply Nat.lt_of_lt_of_le h
      rw [size_extract_loop]
      apply Nat.add_le_add_left
      exact Nat.min_le_right ..
  rw [Nat.add_sub_assoc hge]
  apply Nat.add_lt_of_lt_sub'
  exact Nat.sub_lt_left_of_lt_add hge h
Adjusted Index Validity in Array Extraction Loop for Large Indices
Informal description
For any arrays `xs` and `ys` of type `Array α`, natural numbers `size` and `start`, and index `i` such that: 1. `i` is greater than or equal to the size of `ys` (i.e., $i \geq \text{size}(ys)$), and 2. `i` is less than the size of the array resulting from the extraction loop (i.e., $i < \text{size}(\text{extract.loop}\ xs\ size\ start\ ys)$), it follows that the adjusted index $\text{start} + i - \text{size}(ys)$ is a valid index for `xs`, meaning $\text{start} + i - \text{size}(ys) < \text{size}(xs)$.
Array.getElem_extract_aux theorem
{xs : Array α} {start stop : Nat} (h : i < (xs.extract start stop).size) : start + i < xs.size
Full source
theorem getElem_extract_aux {xs : Array α} {start stop : Nat} (h : i < (xs.extract start stop).size) :
    start + i < xs.size := by
  rw [size_extract] at h; apply Nat.add_lt_of_lt_sub'; apply Nat.lt_of_lt_of_le h
  apply Nat.sub_le_sub_right; apply Nat.min_le_right
Index Validity in Array Extraction: $i < \text{size}(\text{extract}\ start\ stop) \Rightarrow \text{start} + i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α`, natural numbers `start` and `stop`, and index `i`, if `i` is less than the size of the subarray `xs.extract start stop`, then the adjusted index `start + i` is a valid index for `xs`, i.e., `start + i < xs.size`.
Array.getElem_extract theorem
{xs : Array α} {start stop : Nat} (h : i < (xs.extract start stop).size) : (xs.extract start stop)[i] = xs[start + i]'(getElem_extract_aux h)
Full source
@[simp] theorem getElem_extract {xs : Array α} {start stop : Nat}
    (h : i < (xs.extract start stop).size) :
    (xs.extract start stop)[i] = xs[start + i]'(getElem_extract_aux h) :=
  show (extract.loop xs (min stop xs.size - start) start #[])[i]
    = xs[start + i]'(getElem_extract_aux h) by rw [getElem_extract_loop_ge]; rfl; exact Nat.zero_le _
Element Correspondence in Array Extraction: $(xs.\text{extract}\ start\ stop)[i] = xs[\text{start} + i]$
Informal description
For any array `xs` of type `Array α`, natural numbers `start` and `stop`, and index `i` such that `i` is less than the size of the extracted subarray `xs.extract start stop`, the element at position `i` in the extracted subarray equals the element at position `start + i` in the original array `xs`.
Array.getElem?_extract theorem
{xs : Array α} {start stop : Nat} : (xs.extract start stop)[i]? = if i < min stop xs.size - start then xs[start + i]? else none
Full source
theorem getElem?_extract {xs : Array α} {start stop : Nat} :
    (xs.extract start stop)[i]? = if i < min stop xs.size - start then xs[start + i]? else none := by
  simp only [getElem?_def, size_extract, getElem_extract]
  split
  · split
    · rfl
    · omega
  · rfl
Optional Indexing in Extracted Subarray: $(xs.\text{extract}\ start\ stop)[i]? = \text{if } i < \min(\text{stop}, \text{size}) - \text{start} \text{ then } xs[\text{start} + i]? \text{ else none}$
Informal description
For any array `xs` of type `Array α` and natural numbers `start` and `stop`, the optional indexing operation on the extracted subarray `xs.extract start stop` at index `i` satisfies: \[ (xs.\text{extract}\ start\ stop)[i]? = \begin{cases} xs[\text{start} + i]? & \text{if } i < \min(\text{stop}, \text{size}(xs)) - \text{start} \\ \text{none} & \text{otherwise} \end{cases} \]
Array.extract_congr theorem
{xs ys : Array α} (w : xs = ys) (h : start = start') (h' : stop = stop') : xs.extract start stop = ys.extract start' stop'
Full source
@[congr] theorem extract_congr {xs ys : Array α}
    (w : xs = ys) (h : start = start') (h' : stop = stop') :
    xs.extract start stop = ys.extract start' stop' := by
  subst w h h'
  rfl
Congruence of Array Extraction: `xs = ys` and matching indices imply equal extracted subarrays
Informal description
For any two arrays `xs` and `ys` of type `Array α`, if `xs = ys`, and the start indices `start = start'` and stop indices `stop = stop'` are equal, then the extracted subarrays `xs.extract start stop` and `ys.extract start' stop'` are equal.
Array.toList_extract theorem
{xs : Array α} {start stop : Nat} : (xs.extract start stop).toList = xs.toList.extract start stop
Full source
@[simp] theorem toList_extract {xs : Array α} {start stop : Nat} :
    (xs.extract start stop).toList = xs.toList.extract start stop := by
  apply List.ext_getElem
  · simp only [length_toList, size_extract, List.length_take, List.length_drop]
    omega
  · intros n h₁ h₂
    simp
List Conversion Preserves Array Extraction: $\text{toList}(\text{extract}\ start\ stop\ xs) = \text{extract}\ start\ stop\ (\text{toList}\ xs)$
Informal description
For any array `xs` of type `Array α` and natural numbers `start` and `stop`, the list obtained by converting the extracted subarray `xs.extract start stop` to a list is equal to the list obtained by extracting the sublist from `start` to `stop` in the list representation of `xs`. That is: \[ \text{toList}(\text{xs.extract}\ start\ stop) = \text{extract}\ start\ stop\ (\text{toList}\ xs) \]
Array.extract_size theorem
{xs : Array α} : xs.extract 0 xs.size = xs
Full source
@[simp] theorem extract_size {xs : Array α} : xs.extract 0 xs.size = xs := by
  apply ext
  · rw [size_extract, Nat.min_self, Nat.sub_zero]
  · intros; rw [getElem_extract]; congr; rw [Nat.zero_add]
Full Array Extraction Yields Original Array
Informal description
For any array `xs` of type `Array α`, extracting the subarray from index `0` to the size of `xs` yields the original array `xs` itself, i.e., `xs.extract 0 xs.size = xs`.
Array.extract_all abbrev
Full source
@[deprecated extract_size (since := "2025-01-19")]
abbrev extract_all := @extract_size
Full Array Extraction Yields Original Array
Informal description
For any array `xs` of type `Array α`, extracting the subarray from index `0` to the size of `xs` yields the original array `xs` itself, i.e., `xs.extract 0 xs.size = xs`.
Array.extract_empty_of_stop_le_start theorem
{xs : Array α} {start stop : Nat} (h : stop ≤ start) : xs.extract start stop = #[]
Full source
theorem extract_empty_of_stop_le_start {xs : Array α} {start stop : Nat} (h : stop ≤ start) :
    xs.extract start stop = #[] := by
  simp only [extract, Nat.sub_eq, emptyWithCapacity_eq]
  rw [←Nat.sub_min_sub_right, Nat.sub_eq_zero_of_le h, Nat.zero_min, extract_loop_zero]
Empty Extraction When Stop Index Does Not Exceed Start Index
Informal description
For any array `xs` of type `α` and natural numbers `start` and `stop`, if `stop ≤ start`, then extracting the subarray from index `start` to `stop` results in an empty array `#[]`.
Array.extract_empty_of_size_le_start theorem
{xs : Array α} {start stop : Nat} (h : xs.size ≤ start) : xs.extract start stop = #[]
Full source
theorem extract_empty_of_size_le_start {xs : Array α} {start stop : Nat} (h : xs.size ≤ start) :
    xs.extract start stop = #[] := by
  simp only [extract, Nat.sub_eq, emptyWithCapacity_eq]
  rw [←Nat.sub_min_sub_right, Nat.sub_eq_zero_of_le h, Nat.min_zero, extract_loop_zero]
Empty Extraction from Array When Start Index Exceeds Size
Informal description
For any array `xs` of type `α` and natural numbers `start` and `stop`, if the size of `xs` is less than or equal to `start`, then extracting a subarray from `xs` with bounds `start` and `stop` results in an empty array `#[]`.
Array.extract_empty theorem
{start stop : Nat} : (#[] : Array α).extract start stop = #[]
Full source
@[simp] theorem extract_empty {start stop : Nat} : (#[] : Array α).extract start stop = #[] :=
  extract_empty_of_size_le_start (Nat.zero_le _)
Empty Array Extraction Yields Empty Array
Informal description
For any natural numbers `start` and `stop`, extracting a subarray from the empty array `#[]` with bounds `start` and `stop` results in the empty array `#[]`.
List.extract_toArray theorem
{l : List α} {start stop : Nat} : l.toArray.extract start stop = (l.extract start stop).toArray
Full source
@[simp] theorem _root_.List.extract_toArray {l : List α} {start stop : Nat} :
    l.toArray.extract start stop = (l.extract start stop).toArray := by
  apply ext'
  simp
Array Extraction Commutes with List-to-Array Conversion
Informal description
For any list $l$ of elements of type $\alpha$ and natural numbers $start$ and $stop$, the extraction of a subarray from the array conversion of $l$ with bounds $start$ and $stop$ is equal to the array conversion of the extracted sublist from $l$ with the same bounds. That is: \[ \text{toArray}(l).\text{extract}\ start\ stop = \text{toArray}(l.\text{extract}\ start\ stop) \]
Array.take_size theorem
{xs : Array α} : xs.take xs.size = xs
Full source
@[deprecated extract_size (since := "2025-02-27")]
theorem take_size {xs : Array α} : xs.take xs.size = xs := by
  cases xs
  simp
Taking Full Size of Array Yields Original Array
Informal description
For any array `xs` of type `α`, taking the first `xs.size` elements of `xs` results in `xs` itself. That is, $\text{take}(\text{xs}, \text{size}(\text{xs})) = \text{xs}$.
Array.size_shrink_loop theorem
{xs : Array α} {n : Nat} : (shrink.loop n xs).size = xs.size - n
Full source
@[simp] theorem size_shrink_loop {xs : Array α} {n : Nat} : (shrink.loop n xs).size = xs.size - n := by
  induction n generalizing xs with
  | zero => simp [shrink.loop]
  | succ n ih =>
    simp [shrink.loop, ih]
    omega
Size Reduction Property of `shrink.loop` Operation on Arrays
Informal description
For any array `xs` of type `α` and natural number `n`, the size of the array after applying the `shrink.loop` operation with parameter `n` is equal to the original size of `xs` minus `n`. That is, $\text{size}(\text{shrink.loop}\ n\ \text{xs}) = \text{size}(\text{xs}) - n$.
Array.getElem_shrink_loop theorem
{xs : Array α} {n i : Nat} (h : i < (shrink.loop n xs).size) : (shrink.loop n xs)[i] = xs[i]'(by simp at h; omega)
Full source
@[simp] theorem getElem_shrink_loop {xs : Array α} {n i : Nat} (h : i < (shrink.loop n xs).size) :
    (shrink.loop n xs)[i] = xs[i]'(by simp at h; omega) := by
  induction n generalizing xs i with
  | zero => simp [shrink.loop]
  | succ n ih =>
    simp [shrink.loop, ih]
Element Preservation in Array Shrink Loop: $(\text{shrink.loop}\ n\ xs)[i] = xs[i]$ for $i < \text{size}(\text{shrink.loop}\ n\ xs)$
Informal description
For any array $xs$ of type $\text{Array}\ \alpha$ and natural numbers $n, i$ such that $i$ is less than the size of $\text{shrink.loop}\ n\ xs$, the element at index $i$ in $\text{shrink.loop}\ n\ xs$ equals the element at index $i$ in the original array $xs$. That is, $(\text{shrink.loop}\ n\ xs)[i] = xs[i]$.
Array.size_shrink theorem
{xs : Array α} {i : Nat} : (xs.shrink i).size = min i xs.size
Full source
@[simp] theorem size_shrink {xs : Array α} {i : Nat} : (xs.shrink i).size = min i xs.size := by
  simp [shrink]
  omega
Size of Shrunk Array Equals Minimum of Input and Original Size
Informal description
For any array `xs` of type `α` and natural number `i`, the size of the array after applying the `shrink` operation with parameter `i` is equal to the minimum of `i` and the original size of `xs`. That is, $\text{size}(\text{xs.shrink}\ i) = \min(i, \text{size}(\text{xs}))$.
Array.getElem_shrink theorem
{xs : Array α} {i j : Nat} (h : j < (xs.shrink i).size) : (xs.shrink i)[j] = xs[j]'(by simp at h; omega)
Full source
@[simp] theorem getElem_shrink {xs : Array α} {i j : Nat} (h : j < (xs.shrink i).size) :
    (xs.shrink i)[j] = xs[j]'(by simp at h; omega) := by
  simp [shrink]
Element Preservation in Array Shrink Operation: $(xs.\text{shrink}\ i)[j] = xs[j]$ for $j < \text{size}(xs.\text{shrink}\ i)$
Informal description
For any array $xs$ of type $\text{Array}\ \alpha$ and natural numbers $i, j$ such that $j$ is less than the size of $xs.\text{shrink}\ i$, the element at index $j$ in $xs.\text{shrink}\ i$ equals the element at index $j$ in the original array $xs$. That is, $(xs.\text{shrink}\ i)[j] = xs[j]$.
Array.toList_shrink theorem
{xs : Array α} {i : Nat} : (xs.shrink i).toList = xs.toList.take i
Full source
@[simp] theorem toList_shrink {xs : Array α} {i : Nat} : (xs.shrink i).toList = xs.toList.take i := by
  apply List.ext_getElem <;> simp
List Conversion of Shrunk Array Equals Take of Original List: `(xs.shrink i).toList = xs.toList.take i`
Informal description
For any array `xs` of type `Array α` and natural number `i`, converting the shrunk array `xs.shrink i` to a list yields the same result as taking the first `i` elements of the list obtained from converting the original array `xs`. That is, `(xs.shrink i).toList = xs.toList.take i`.
Array.shrink_eq_take theorem
{xs : Array α} {i : Nat} : xs.shrink i = xs.take i
Full source
@[simp] theorem shrink_eq_take {xs : Array α} {i : Nat} : xs.shrink i = xs.take i := by
  ext <;> simp
Shrink Operation Equals Take Operation on Arrays
Informal description
For any array $xs$ of type $\alpha$ and natural number $i$, the operation `xs.shrink i` produces the same array as `xs.take i$, where `take` returns the prefix of the array with at most $i$ elements.
Array.foldlM_start_stop theorem
{m} [Monad m] {xs : Array α} {f : β → α → m β} {b} {start stop : Nat} : xs.foldlM f b start stop = (xs.extract start stop).foldlM f b
Full source
theorem foldlM_start_stop {m} [Monad m] {xs : Array α} {f : β → α → m β} {b} {start stop : Nat} :
    xs.foldlM f b start stop = (xs.extract start stop).foldlM f b := by
  unfold foldlM
  simp only [Nat.sub_zero, size_extract, Nat.le_refl, ↓reduceDIte]
  suffices foldlM.loop f xs (min stop xs.size) (by omega) (min stop xs.size - start) start b =
      foldlM.loop f (xs.extract start stop) (min stop xs.size - start) (by simp) (min stop xs.size - start) 0 b by
    split
    · have : min stop xs.size = stop := by omega
      simp_all
    · have : min stop xs.size = xs.size := by omega
      simp_all
  revert b
  suffices ∀ (b : β) (i k) (w : i + k = min stop xs.size - start),
    foldlM.loop f xs (min stop xs.size) (by omega) i (start + k) b =
      foldlM.loop f (xs.extract start stop) (min stop xs.size - start) (by simp) i k b by
    intro b
    simpa using this b (min stop xs.size - start) 0 (by omega)
  intro b i k w
  induction i generalizing b k with
  | zero =>
    simp only [Nat.zero_add] at w
    subst k
    simp [foldlM.loop]
  | succ i ih =>
    unfold foldlM.loop
    rw [dif_pos (by omega), dif_pos (by omega)]
    split <;> rename_i h
    · rfl
    · simp at h
      subst h
      simp only [getElem_extract]
      congr
      funext b
      specialize ih b (k + 1) (by omega)
      simp [← Nat.add_assoc] at ih
      rw [ih]
Monadic Left Fold of Extracted Subarray Equals Bounded Fold
Informal description
For any monad $m$, array $xs$ of type $\alpha$, function $f : \beta \to \alpha \to m \beta$, initial value $b : \beta$, and natural numbers $start$ and $stop$, the monadic left fold of $xs$ from $start$ to $stop$ with function $f$ and initial value $b$ is equal to the monadic left fold of the extracted subarray $xs.\text{extract}\ start\ stop$ with the same function and initial value.
Array.foldrM_start_stop theorem
{m} [Monad m] {xs : Array α} {f : α → β → m β} {b} {start stop : Nat} : xs.foldrM f b start stop = (xs.extract stop start).foldrM f b
Full source
theorem foldrM_start_stop {m} [Monad m] {xs : Array α} {f : α → β → m β} {b} {start stop : Nat} :
    xs.foldrM f b start stop = (xs.extract stop start).foldrM f b := by
  unfold foldrM
  simp only [size_extract, Nat.le_refl, ↓reduceDIte]
  suffices stop ≤ min start xs.sizefoldrM.fold f xs stop (min start xs.size) (by omega) b =
        foldrM.fold f (xs.extract stop start) 0 (min start xs.size - stop) (by simp) b by
    split
    · split
      · rw [if_pos (by omega)]
        have h : min start xs.size = start := by omega
        specialize this (by omega)
        simp_all
      · rw [if_neg (by omega)]
    · split
      · rw [if_pos (by omega)]
        have h : min start xs.size = xs.size := by omega
        specialize this (by omega)
        simp_all
      · rw [if_neg (by omega)]
  revert b
  suffices ∀ (b : β) (i) (w : stop + i ≤ min start xs.size),
      foldrM.fold f xs stop (stop + i) (by omega) b =
        foldrM.fold f (xs.extract stop start) 0 i (by simp; omega) b by
    intro b w
    specialize this b (min start xs.size - stop)
    have h : stop + (min start xs.size - stop) = min start xs.size := by omega
    simp_all
  intro b i w
  induction i generalizing b with
  | zero =>
    unfold foldrM.fold
    simp
  | succ i ih =>
    unfold foldrM.fold
    simp only [beq_iff_eq, Nat.add_right_eq_self, Nat.add_one_ne_zero, ↓reduceIte, Nat.add_eq,
      getElem_extract]
    congr
    funext b
    simp [ih b (by omega)]
Monadic Right Fold of Array Subrange Equals Fold of Extracted Subarray
Informal description
For any monad $m$, array $xs$ of type $\text{Array}\,\alpha$, function $f : \alpha \to \beta \to m\,\beta$, initial value $b : \beta$, and natural numbers $start$ and $stop$, the monadic right fold of $xs$ from $start$ to $stop$ is equal to the monadic right fold of the extracted subarray $xs.\text{extract}\,stop\,start$ with the same function $f$ and initial value $b$.
Array.foldlM_congr theorem
{m} [Monad m] {f g : β → α → m β} {b : β} {xs xs' : Array α} (w : xs = xs') (h : ∀ x y, f x y = g x y) (hstart : start = start') (hstop : stop = stop') : xs.foldlM f b start stop = xs'.foldlM g b start' stop'
Full source
@[congr] theorem foldlM_congr {m} [Monad m] {f g : β → α → m β} {b : β} {xs xs' : Array α}
    (w : xs = xs')
    (h : ∀ x y, f x y = g x y) (hstart : start = start') (hstop : stop = stop') :
    xs.foldlM f b start stop = xs'.foldlM g b start' stop' := by
  subst hstart hstop w
  rcases xs with ⟨xs⟩
  rw [foldlM_start_stop, List.extract_toArray]
  simp only [List.size_toArray, List.length_take, List.length_drop, List.foldlM_toArray']
  rw [foldlM_start_stop, List.extract_toArray]
  simp only [List.size_toArray, List.length_take, List.length_drop, List.foldlM_toArray']
  congr
  funext b a
  simp_all
Congruence of Monadic Left Fold on Arrays
Informal description
For any monad $m$, arrays $xs$ and $xs'$ of type $\alpha$, functions $f, g : \beta \to \alpha \to m \beta$, initial value $b : \beta$, and indices $start, start', stop, stop' : \mathbb{N}$, if $xs = xs'$, $f(x)(y) = g(x)(y)$ for all $x \in \beta$ and $y \in \alpha$, $start = start'$, and $stop = stop'$, then the monadic left fold of $xs$ from $start$ to $stop$ with function $f$ and initial value $b$ is equal to the monadic left fold of $xs'$ from $start'$ to $stop'$ with function $g$ and initial value $b$.
Array.foldrM_congr theorem
{m} [Monad m] {f g : α → β → m β} {b : β} {xs xs' : Array α} (w : xs = xs') (h : ∀ x y, f x y = g x y) (hstart : start = start') (hstop : stop = stop') : xs.foldrM f b start stop = xs'.foldrM g b start' stop'
Full source
@[congr] theorem foldrM_congr {m} [Monad m] {f g : α → β → m β} {b : β} {xs xs' : Array α}
    (w : xs = xs')
    (h : ∀ x y, f x y = g x y) (hstart : start = start') (hstop : stop = stop') :
    xs.foldrM f b start stop = xs'.foldrM g b start' stop' := by
  subst hstart hstop w
  rcases xs with ⟨xs⟩
  rw [foldrM_start_stop, List.extract_toArray]
  simp only [List.size_toArray, List.length_take, List.length_drop, List.foldrM_toArray']
  rw [foldrM_start_stop, List.extract_toArray]
  simp only [List.size_toArray, List.length_take, List.length_drop, List.foldrM_toArray']
  congr
  funext b a
  simp_all
Congruence of Monadic Right Fold on Arrays: $xs = xs' \land (\forall x y, f(x)(y) = g(x)(y)) \land start = start' \land stop = stop' \Rightarrow \text{foldrM}\ f\ b\ start\ stop\ xs = \text{foldrM}\ g\ b\ start'\ stop'\ xs'$
Informal description
For any monad $m$, arrays $xs$ and $xs'$ of type $\text{Array}\,\alpha$, functions $f, g : \alpha \to \beta \to m\,\beta$, initial value $b : \beta$, and natural numbers $start, start', stop, stop'$, if $xs = xs'$, $f(x)(y) = g(x)(y)$ for all $x \in \alpha$ and $y \in \beta$, $start = start'$, and $stop = stop'$, then the monadic right fold of $xs$ from $start$ to $stop$ with $f$ and $b$ is equal to the monadic right fold of $xs'$ from $start'$ to $stop'$ with $g$ and $b$.
Array.foldlM_append' theorem
[Monad m] [LawfulMonad m] {f : β → α → m β} {b} {xs xs' : Array α} {stop} (w : stop = xs.size + xs'.size) : (xs ++ xs').foldlM f b 0 stop = xs.foldlM f b >>= xs'.foldlM f
Full source
/-- Variant of `foldlM_append` with a side condition for the `stop` argument. -/
@[simp] theorem foldlM_append' [Monad m] [LawfulMonad m] {f : β → α → m β} {b} {xs xs' : Array α}
    {stop} (w : stop = xs.size + xs'.size) :
    (xs ++ xs').foldlM f b 0 stop = xs.foldlM f b >>= xs'.foldlM f := by
  subst w
  rcases xs with ⟨xs⟩
  rcases xs' with ⟨xs'⟩
  simp
Monadic Left Fold of Concatenated Arrays with Size Condition
Informal description
For any monad $m$ that satisfies the monad laws, function $f : \beta \to \alpha \to m \beta$, initial value $b : \beta$, arrays $xs$ and $xs'$ of type $\alpha$, and natural number $stop$ such that $stop = \text{size}(xs) + \text{size}(xs')$, the monadic left fold of the concatenated array $xs \mathbin{+\kern-1.5ex+} xs'$ from index $0$ to $stop$ with function $f$ and initial value $b$ is equal to first folding $xs$ with $f$ starting from $b$, and then folding $xs'$ with $f$ using the result of the first fold.
Array.foldlM_append theorem
[Monad m] [LawfulMonad m] {f : β → α → m β} {b} {xs xs' : Array α} : (xs ++ xs').foldlM f b = xs.foldlM f b >>= xs'.foldlM f
Full source
theorem foldlM_append [Monad m] [LawfulMonad m] {f : β → α → m β} {b} {xs xs' : Array α} :
    (xs ++ xs').foldlM f b = xs.foldlM f b >>= xs'.foldlM f := by
  simp
Monadic Left Fold Distributes Over Array Concatenation
Informal description
For any monad $m$ that satisfies the monad laws, function $f : \beta \to \alpha \to m \beta$, initial value $b : \beta$, and arrays $xs, xs'$ of type $\alpha$, the monadic left fold of the concatenated array $xs +\!\!+ xs'$ with function $f$ and initial value $b$ is equal to first folding $xs$ with $f$ starting from $b$, and then folding $xs'$ with $f$ using the result of the first fold.
Array.foldlM_loop_empty theorem
[Monad m] {f : β → α → m β} {init : β} {i j : Nat} : foldlM.loop f #[] s h i j init = pure init
Full source
@[simp] theorem foldlM_loop_empty [Monad m] {f : β → α → m β} {init : β} {i j : Nat} :
    foldlM.loop f #[] s h i j init = pure init := by
  unfold foldlM.loop; split
  · split
    · rfl
    · simp at h
      omega
  · rfl
Monadic Left Fold on Empty Array Yields Pure Initial Value
Informal description
For any monad `m`, function `f : β → α → m β`, initial value `init : β`, and natural numbers `i` and `j`, the monadic left fold operation `foldlM.loop` applied to an empty array `#[]` with indices `i` and `j` and initial value `init` returns the pure monadic value `pure init`.
Array.foldlM_empty theorem
[Monad m] {f : β → α → m β} {init : β} : foldlM f init #[] start stop = return init
Full source
@[simp] theorem foldlM_empty [Monad m] {f : β → α → m β} {init : β} :
    foldlM f init #[] start stop = return init := by
  simp [foldlM]
Monadic Left Fold on Empty Array Yields Initial Value
Informal description
For any monad `m`, function `f : β → α → m β`, and initial value `init : β`, the monadic left fold operation `foldlM` applied to an empty array `#[]` with any start and stop indices returns the pure monadic value `return init`.
Array.foldrM_fold_empty theorem
[Monad m] {f : α → β → m β} {init : β} {i j : Nat} (h) : foldrM.fold f #[] i j h init = pure init
Full source
@[simp] theorem foldrM_fold_empty [Monad m] {f : α → β → m β} {init : β} {i j : Nat} (h) :
    foldrM.fold f #[] i j h init = pure init := by
  unfold foldrM.fold
  split <;> rename_i h₁
  · rfl
  · split <;> rename_i h₂
    · rfl
    · simp at h₂
Monadic Right Fold on Empty Array Yields Pure Initial Value
Informal description
For any monad `m`, function `f : α → β → m β`, initial value `init : β`, and natural numbers `i` and `j`, the monadic right fold operation `foldrM.fold` applied to an empty array `#[]` with indices `i` and `j` and initial value `init` returns the pure monadic value `pure init`.
Array.foldrM_empty theorem
[Monad m] {f : α → β → m β} {init : β} {start stop : Nat} : foldrM f init #[] start stop = return init
Full source
@[simp] theorem foldrM_empty [Monad m] {f : α → β → m β} {init : β} {start stop : Nat} :
    foldrM f init #[] start stop = return init := by
  simp [foldrM]
Monadic Right Fold on Empty Array Yields Initial Value
Informal description
For any monad `m`, function `f : α → β → m β`, initial value `init : β`, and natural numbers `start` and `stop`, the monadic right fold operation `foldrM` applied to an empty array `#[]` with indices `start` and `stop` and initial value `init` returns the pure monadic value `return init`.
Array.foldlM_push' theorem
[Monad m] [LawfulMonad m] {xs : Array α} {a : α} {f : β → α → m β} {b} {stop} (w : stop = xs.size + 1) : (xs.push a).foldlM f b 0 stop = xs.foldlM f b >>= fun b => f b a
Full source
/-- Variant of `foldlM_push` with a side condition for the `stop` argument. -/
@[simp] theorem foldlM_push' [Monad m] [LawfulMonad m] {xs : Array α} {a : α} {f : β → α → m β} {b}
    {stop} (w : stop = xs.size + 1) :
    (xs.push a).foldlM f b 0 stop = xs.foldlM f b >>= fun b => f b a := by
  subst w
  simp [← append_singleton]
Monadic Left Fold of Pushed Array with Size Condition
Informal description
For any monad $m$ that satisfies the monad laws, array $xs$ of type $\alpha$, element $a : \alpha$, function $f : \beta \to \alpha \to m \beta$, initial value $b : \beta$, and natural number $stop$ such that $stop = \text{size}(xs) + 1$, the monadic left fold of the array $xs.\text{push}(a)$ from index $0$ to $stop$ with function $f$ and initial value $b$ is equal to first folding $xs$ with $f$ starting from $b$, and then applying $f$ to the result and $a$.
Array.foldlM_push theorem
[Monad m] [LawfulMonad m] {xs : Array α} {a : α} {f : β → α → m β} {b} : (xs.push a).foldlM f b = xs.foldlM f b >>= fun b => f b a
Full source
theorem foldlM_push [Monad m] [LawfulMonad m] {xs : Array α} {a : α} {f : β → α → m β} {b} :
    (xs.push a).foldlM f b = xs.foldlM f b >>= fun b => f b a := by
  simp
Monadic Left Fold of Pushed Array
Informal description
For any monad $m$ that satisfies the monad laws, array $xs$ of type $\alpha$, element $a : \alpha$, function $f : \beta \to \alpha \to m \beta$, and initial value $b : \beta$, the monadic left fold of the array $xs.\text{push}(a)$ with function $f$ and initial value $b$ is equal to first folding $xs$ with $f$ starting from $b$, and then applying $f$ to the result and $a$.
Array.foldlM_pure theorem
[Monad m] [LawfulMonad m] {f : β → α → β} {b} {xs : Array α} {start stop : Nat} : xs.foldlM (m := m) (pure <| f · ·) b start stop = pure (xs.foldl f b start stop)
Full source
@[simp] theorem foldlM_pure [Monad m] [LawfulMonad m] {f : β → α → β} {b} {xs : Array α} {start stop : Nat} :
    xs.foldlM (m := m) (pure <| f · ·) b start stop = pure (xs.foldl f b start stop) := by
  rw [foldl, foldlM_start_stop, ← foldlM_toList, List.foldlM_pure, foldl_toList, foldl, ← foldlM_start_stop]
Monadic Left Fold with Pure Function Equals Pure of Non-Monadic Fold
Informal description
For any monad $m$ that is a lawful monad, any function $f : \beta \to \alpha \to \beta$, initial value $b : \beta$, array $xs : \text{Array } \alpha$, and indices $start, stop : \mathbb{N}$, the monadic left fold of $xs$ from $start$ to $stop$ with the pure-lifted function $\text{pure} \circ f$ and initial value $b$ is equal to the pure-lifted result of the non-monadic left fold of $xs$ with $f$ and $b$ over the same range.
Array.foldrM_pure theorem
[Monad m] [LawfulMonad m] {f : α → β → β} {b} {xs : Array α} {start stop : Nat} : xs.foldrM (m := m) (pure <| f · ·) b start stop = pure (xs.foldr f b start stop)
Full source
@[simp] theorem foldrM_pure [Monad m] [LawfulMonad m] {f : α → β → β} {b} {xs : Array α} {start stop : Nat} :
    xs.foldrM (m := m) (pure <| f · ·) b start stop = pure (xs.foldr f b start stop) := by
  rw [foldr, foldrM_start_stop, ← foldrM_toList, List.foldrM_pure, foldr_toList, foldr, ← foldrM_start_stop]
Monadic Right Fold with Pure Function Equals Pure of Standard Right Fold
Informal description
For any monad $m$ that is lawful, any function $f : \alpha \to \beta \to \beta$, initial value $b : \beta$, array $xs : \text{Array}\,\alpha$, and indices $start, stop : \mathbb{N}$, the monadic right fold operation `xs.foldrM` with the pure-lifted function `pure ∘ f` and initial value $b$ over the range $[start, stop)$ is equal to the pure-lifted result of the standard right fold operation `xs.foldr f b start stop$.
Array.foldl_eq_foldlM theorem
{f : β → α → β} {b} {xs : Array α} {start stop : Nat} : xs.foldl f b start stop = xs.foldlM (m := Id) f b start stop
Full source
theorem foldl_eq_foldlM {f : β → α → β} {b} {xs : Array α} {start stop : Nat} :
    xs.foldl f b start stop = xs.foldlM (m := Id) f b start stop := by
  simp [foldl, Id.run]
Equivalence of Left Fold and Monadic Left Fold with Identity Monad
Informal description
For any function $f : \beta \to \alpha \to \beta$, initial value $b : \beta$, array $xs : \text{Array } \alpha$, and indices $start, stop : \mathbb{N}$, the left fold operation `xs.foldl f b start stop` is equal to the monadic left fold operation `xs.foldlM` (with the identity monad `Id`) applied to $f$, $b$, $start$, and $stop$.
Array.foldr_eq_foldrM theorem
{f : α → β → β} {b} {xs : Array α} {start stop : Nat} : xs.foldr f b start stop = xs.foldrM (m := Id) f b start stop
Full source
theorem foldr_eq_foldrM {f : α → β → β} {b} {xs : Array α} {start stop : Nat} :
    xs.foldr f b start stop = xs.foldrM (m := Id) f b start stop := by
  simp [foldr, Id.run]
Equivalence of Right Fold and Monadic Right Fold with Identity Monad
Informal description
For any function $f : \alpha \to \beta \to \beta$, initial value $b : \beta$, array $xs : \text{Array } \alpha$, and indices $start, stop : \mathbb{N}$, the right fold operation `xs.foldr f b start stop` is equal to the monadic right fold operation `xs.foldrM` (with the identity monad `Id`) applied to $f$, $b$, $start$, and $stop$.
Array.id_run_foldlM theorem
{f : β → α → Id β} {b} {xs : Array α} {start stop : Nat} : Id.run (xs.foldlM f b start stop) = xs.foldl f b start stop
Full source
@[simp] theorem id_run_foldlM {f : β → α → Id β} {b} {xs : Array α} {start stop : Nat} :
    Id.run (xs.foldlM f b start stop) = xs.foldl f b start stop := foldl_eq_foldlM.symm
Equivalence of Monadic Left Fold and Left Fold with Identity Monad
Informal description
For any function $f : \beta \to \alpha \to \beta$, initial value $b : \beta$, array $xs : \text{Array } \alpha$, and indices $start, stop : \mathbb{N}$, the result of running the monadic left fold operation `xs.foldlM` (with the identity monad `Id`) applied to $f$, $b$, $start$, and $stop$ is equal to the left fold operation `xs.foldl f b start stop`.
Array.id_run_foldrM theorem
{f : α → β → Id β} {b} {xs : Array α} {start stop : Nat} : Id.run (xs.foldrM f b start stop) = xs.foldr f b start stop
Full source
@[simp] theorem id_run_foldrM {f : α → β → Id β} {b} {xs : Array α} {start stop : Nat} :
    Id.run (xs.foldrM f b start stop) = xs.foldr f b start stop := foldr_eq_foldrM.symm
Equivalence of Monadic Right Fold and Right Fold with Identity Monad
Informal description
For any function $f : \alpha \to \beta \to \beta$, initial value $b : \beta$, array $xs : \text{Array } \alpha$, and indices $start, stop : \mathbb{N}$, the result of running the monadic right fold operation `xs.foldrM` (with the identity monad `Id`) applied to $f$, $b$, $start$, and $stop$ is equal to the right fold operation `xs.foldr f b start stop`.
Array.foldlM_reverse' theorem
[Monad m] {xs : Array α} {f : β → α → m β} {b} {stop : Nat} (w : stop = xs.size) : xs.reverse.foldlM f b 0 stop = xs.foldrM (fun x y => f y x) b
Full source
/-- Variant of `foldlM_reverse` with a side condition for the `stop` argument. -/
@[simp] theorem foldlM_reverse' [Monad m] {xs : Array α} {f : β → α → m β} {b} {stop : Nat}
    (w : stop = xs.size) :
    xs.reverse.foldlM f b 0 stop = xs.foldrM (fun x y => f y x) b := by
  subst w
  rcases xs with ⟨xs⟩
  simp [List.foldlM_reverse]
Monadic Left Fold of Reversed Array Equals Monadic Right Fold with Flipped Function
Informal description
Let $m$ be a monad, $xs$ be an array of type $\alpha$, $f : \beta \to \alpha \to m \beta$ be a function, $b$ be an initial value of type $\beta$, and $stop$ be a natural number such that $stop$ equals the size of $xs$. Then the monadic left fold of the reversed array $xs$ from index $0$ to $stop$ with function $f$ and initial value $b$ is equal to the monadic right fold of $xs$ with the flipped function $\lambda x y, f y x$ and initial value $b$.
Array.foldrM_reverse' theorem
[Monad m] {xs : Array α} {f : α → β → m β} {b} {start : Nat} (w : start = xs.size) : xs.reverse.foldrM f b start 0 = xs.foldlM (fun x y => f y x) b
Full source
/-- Variant of `foldrM_reverse` with a side condition for the `start` argument. -/
@[simp] theorem foldrM_reverse' [Monad m] {xs : Array α} {f : α → β → m β} {b} {start : Nat}
    (w : start = xs.size) :
    xs.reverse.foldrM f b start 0 = xs.foldlM (fun x y => f y x) b := by
  subst w
  rcases xs with ⟨xs⟩
  simp [List.foldrM_reverse]
Monadic Right Fold of Reversed Array Equals Monadic Left Fold with Flipped Function
Informal description
Let $m$ be a monad, $xs$ be an array of type $\alpha$, $f : \alpha \to \beta \to m \beta$ be a function, $b$ be an initial value of type $\beta$, and $start$ be a natural number such that $start$ equals the size of $xs$. Then the monadic right fold of the reversed array $xs$ from index $start$ to $0$ with function $f$ and initial value $b$ is equal to the monadic left fold of $xs$ with the flipped function $\lambda x y, f y x$ and initial value $b$.
Array.foldlM_reverse theorem
[Monad m] {xs : Array α} {f : β → α → m β} {b} : xs.reverse.foldlM f b = xs.foldrM (fun x y => f y x) b
Full source
theorem foldlM_reverse [Monad m] {xs : Array α} {f : β → α → m β} {b} :
    xs.reverse.foldlM f b = xs.foldrM (fun x y => f y x) b := by
  simp
Monadic Left Fold of Reversed Array Equals Monadic Right Fold with Flipped Function
Informal description
For any monad $m$, array $xs$ of type $\text{Array}\,\alpha$, function $f : \beta \to \alpha \to m\,\beta$, and initial value $b : \beta$, the monadic left fold of the reversed array $xs$ with function $f$ and initial value $b$ is equal to the monadic right fold of $xs$ with the flipped function $\lambda x y \mapsto f y x$ and initial value $b$.
Array.foldrM_reverse theorem
[Monad m] {xs : Array α} {f : α → β → m β} {b} : xs.reverse.foldrM f b = xs.foldlM (fun x y => f y x) b
Full source
theorem foldrM_reverse [Monad m] {xs : Array α} {f : α → β → m β} {b} :
    xs.reverse.foldrM f b = xs.foldlM (fun x y => f y x) b := by
  rcases xs with ⟨xs⟩
  simp
Monadic Right Fold of Reversed Array Equals Monadic Left Fold with Flipped Function
Informal description
For any monad $m$, array $xs$ of type $\text{Array}\,\alpha$, function $f : \alpha \to \beta \to m\,\beta$, and initial value $b : \beta$, the monadic right fold of the reversed array $xs$ with function $f$ and initial value $b$ is equal to the monadic left fold of $xs$ with the flipped function $\lambda x y \mapsto f y x$ and initial value $b$.
Array.foldrM_push theorem
[Monad m] {f : α → β → m β} {init : β} {xs : Array α} {a : α} : (xs.push a).foldrM f init = f a init >>= xs.foldrM f
Full source
theorem foldrM_push [Monad m] {f : α → β → m β} {init : β} {xs : Array α} {a : α} :
    (xs.push a).foldrM f init = f a init >>= xs.foldrM f := by
  simp only [foldrM_eq_reverse_foldlM_toList, push_toList, List.reverse_append, List.reverse_cons,
    List.reverse_nil, List.nil_append, List.singleton_append, List.foldlM_cons, List.foldlM_reverse]
Monadic Right Fold of Pushed Array: $(\text{xs.push } a).\text{foldrM } f \text{ init } = f a \text{ init } \gg= \text{xs.foldrM } f$
Informal description
Let $m$ be a monad, $f : \alpha \to \beta \to m \beta$ a function, $\text{init} : \beta$ an initial value, $\text{xs} : \text{Array } \alpha$ an array, and $a : \alpha$ an element. Then the monadic right fold of the array $\text{xs.push } a$ with function $f$ and initial value $\text{init}$ is equal to first applying $f$ to $a$ and $\text{init}$, then binding the result to the monadic right fold of $\text{xs}$ with $f$.
Array.foldrM_push' theorem
[Monad m] {f : α → β → m β} {init : β} {xs : Array α} {a : α} {start} (h : start = xs.size + 1) : (xs.push a).foldrM f init start = f a init >>= xs.foldrM f
Full source
/--
Variant of `foldrM_push` with `h : start = arr.size + 1`
rather than `(arr.push a).size` as the argument.
-/
@[simp] theorem foldrM_push' [Monad m] {f : α → β → m β} {init : β} {xs : Array α} {a : α}
    {start} (h : start = xs.size + 1) :
    (xs.push a).foldrM f init start = f a init >>= xs.foldrM f := by
  simp [← foldrM_push, h]
Monadic Right Fold of Pushed Array with Specific Start Index: $(\text{xs.push } a).\text{foldrM } f \text{ init start } = f a \text{ init } \gg= \text{xs.foldrM } f$ when $\text{start} = \text{xs.size} + 1$
Informal description
Let $m$ be a monad, $f : \alpha \to \beta \to m \beta$ a function, $\text{init} : \beta$ an initial value, $\text{xs} : \text{Array } \alpha$ an array, and $a : \alpha$ an element. If the starting index $\text{start}$ for the fold operation equals $\text{xs.size} + 1$, then the monadic right fold of the array $\text{xs.push } a$ with function $f$ and initial value $\text{init}$ beginning at index $\text{start}$ is equal to first applying $f$ to $a$ and $\text{init}$, then binding the result to the monadic right fold of $\text{xs}$ with $f$.
Array.foldl_induction theorem
{as : Array α} (motive : Nat → β → Prop) {init : β} (h0 : motive 0 init) {f : β → α → β} (hf : ∀ i : Fin as.size, ∀ b, motive i.1 b → motive (i.1 + 1) (f b as[i])) : motive as.size (as.foldl f init)
Full source
theorem foldl_induction
    {as : Array α} (motive : Nat → β → Prop) {init : β} (h0 : motive 0 init) {f : β → α → β}
    (hf : ∀ i : Fin as.size, ∀ b, motive i.1 b → motive (i.1 + 1) (f b as[i])) :
    motive as.size (as.foldl f init) := by
  let rec go {i j b} (h₁ : j ≤ as.size) (h₂ : as.size ≤ i + j) (H : motive j b) :
    (motive as.size) (foldlM.loop (m := Id) f as as.size (Nat.le_refl _) i j b) := by
    unfold foldlM.loop; split
    · next hj =>
      split
      · cases Nat.not_le_of_gt (by simp [hj]) h₂
      · exact go hj (by rwa [Nat.succ_add] at h₂) (hf ⟨j, hj⟩ b H)
    · next hj => exact Nat.le_antisymm h₁ (Nat.ge_of_not_lt hj) ▸ H
  simpa [foldl, foldlM] using go (Nat.zero_le _) (Nat.le_refl _) h0
Induction Principle for Left Fold over Arrays
Informal description
Let `as` be an array of type `α`, and let `motive : ℕ → β → Prop` be a predicate on natural numbers and elements of type `β`. Suppose: 1. The initial value `init : β` satisfies `motive 0 init`. 2. For every index `i` of `as` (with `i : Fin as.size`) and every `b : β`, if `motive i.val b` holds, then `motive (i.val + 1) (f b as[i])` holds, where `f : β → α → β` is a given function. Then, the predicate `motive as.size (as.foldl f init)` holds, where `as.foldl f init` is the result of left-folding the array `as` with function `f` and initial value `init`.
Array.foldr_induction theorem
{as : Array α} (motive : Nat → β → Prop) {init : β} (h0 : motive as.size init) {f : α → β → β} (hf : ∀ i : Fin as.size, ∀ b, motive (i.1 + 1) b → motive i.1 (f as[i] b)) : motive 0 (as.foldr f init)
Full source
theorem foldr_induction
    {as : Array α} (motive : Nat → β → Prop) {init : β} (h0 : motive as.size init) {f : α → β → β}
    (hf : ∀ i : Fin as.size, ∀ b, motive (i.1 + 1) b → motive i.1 (f as[i] b)) :
    motive 0 (as.foldr f init) := by
  let rec go {i b} (hi : i ≤ as.size) (H : motive i b) :
    (motive 0) (foldrM.fold (m := Id) f as 0 i hi b) := by
    unfold foldrM.fold; simp; split
    · next hi => exact (hi ▸ H)
    · next hi =>
      split; {simp at hi}
      · next i hi' =>
        exact go _ (hf ⟨i, hi'⟩ b H)
  simp [foldr, foldrM]; split; {exact go _ h0}
  · next h => exact (Nat.eq_zero_of_not_pos h ▸ h0)
Induction Principle for Right Fold over Arrays
Informal description
Let $as$ be an array of type $\alpha$, and let $\text{motive} : \mathbb{N} \to \beta \to \text{Prop}$ be a predicate on natural numbers and elements of type $\beta$. Suppose: 1. The initial value $\text{init} : \beta$ satisfies $\text{motive}(|as|, \text{init})$, where $|as|$ is the size of $as$. 2. For every index $i$ of $as$ (with $i < |as|$) and every $b : \beta$, if $\text{motive}(i + 1, b)$ holds, then $\text{motive}(i, f(as[i], b))$ holds, where $f : \alpha \to \beta \to \beta$ is a given function. Then, the predicate $\text{motive}(0, \text{foldr}\ f\ \text{init}\ as)$ holds, where $\text{foldr}\ f\ \text{init}\ as$ is the result of right-folding the array $as$ with function $f$ and initial value $\text{init}$.
Array.foldl_congr theorem
{as bs : Array α} (h₀ : as = bs) {f g : β → α → β} (h₁ : f = g) {a b : β} (h₂ : a = b) {start start' stop stop' : Nat} (h₃ : start = start') (h₄ : stop = stop') : as.foldl f a start stop = bs.foldl g b start' stop'
Full source
@[congr]
theorem foldl_congr {as bs : Array α} (h₀ : as = bs) {f g : β → α → β} (h₁ : f = g)
     {a b : β} (h₂ : a = b) {start start' stop stop' : Nat} (h₃ : start = start') (h₄ : stop = stop') :
    as.foldl f a start stop = bs.foldl g b start' stop' := by
  congr
Congruence of Left Fold Operation on Arrays ($\text{foldl}$)
Informal description
Let $as$ and $bs$ be arrays of type $\alpha$, and let $f, g : \beta \to \alpha \to \beta$ be functions. Suppose the following equalities hold: 1. $as = bs$, 2. $f = g$, 3. $a = b$ for elements $a, b \in \beta$, 4. $start = start'$ and $stop = stop'$ for natural numbers $start, start', stop, stop'$. Then the left fold operations on these arrays are equal: $$as.\text{foldl}\ f\ a\ start\ stop = bs.\text{foldl}\ g\ b\ start'\ stop'$$
Array.foldr_congr theorem
{as bs : Array α} (h₀ : as = bs) {f g : α → β → β} (h₁ : f = g) {a b : β} (h₂ : a = b) {start start' stop stop' : Nat} (h₃ : start = start') (h₄ : stop = stop') : as.foldr f a start stop = bs.foldr g b start' stop'
Full source
@[congr]
theorem foldr_congr {as bs : Array α} (h₀ : as = bs) {f g : α → β → β} (h₁ : f = g)
     {a b : β} (h₂ : a = b) {start start' stop stop' : Nat} (h₃ : start = start') (h₄ : stop = stop') :
    as.foldr f a start stop = bs.foldr g b start' stop' := by
  congr
Congruence of Array Right Fold Under Equality Conditions
Informal description
For any two arrays `as` and `bs` of type `Array α`, if `as = bs`, and for any two functions `f` and `g` of type `α → β → β`, if `f = g`, and for any two elements `a` and `b` of type `β`, if `a = b`, and for any natural numbers `start`, `start'`, `stop`, `stop'`, if `start = start'` and `stop = stop'`, then the result of folding `as` with `f` starting from `a` over the range `[start, stop)` is equal to the result of folding `bs` with `g` starting from `b` over the range `[start', stop')`.
Array.foldr_push theorem
{f : α → β → β} {init : β} {xs : Array α} {a : α} : (xs.push a).foldr f init = xs.foldr f (f a init)
Full source
theorem foldr_push {f : α → β → β} {init : β} {xs : Array α} {a : α} :
    (xs.push a).foldr f init = xs.foldr f (f a init) := foldrM_push ..
Right Fold of Pushed Array: $(\text{xs.push } a).\text{foldr } f \text{ init } = \text{xs.foldr } f (f a \text{ init})$
Informal description
For any function $f : \alpha \to \beta \to \beta$, initial value $\text{init} : \beta$, array $\text{xs} : \text{Array } \alpha$, and element $a : \alpha$, the right fold of the array $\text{xs.push } a$ with function $f$ and initial value $\text{init}$ is equal to the right fold of $\text{xs}$ with $f$ and initial value $f(a, \text{init})$.
Array.foldr_push' theorem
{f : α → β → β} {init : β} {xs : Array α} {a : α} {start : Nat} (h : start = xs.size + 1) : (xs.push a).foldr f init start = xs.foldr f (f a init)
Full source
/--
Variant of `foldr_push` with the `h : start = arr.size + 1`
rather than `(arr.push a).size` as the argument.
-/
@[simp] theorem foldr_push' {f : α → β → β} {init : β} {xs : Array α} {a : α} {start : Nat}
    (h : start = xs.size + 1) : (xs.push a).foldr f init start = xs.foldr f (f a init) :=
  foldrM_push' h
Right Fold of Pushed Array with Specific Start Index: $(\text{xs.push } a).\text{foldr } f \text{ init start } = \text{xs.foldr } f (f a \text{ init})$ when $\text{start} = \text{xs.size} + 1$
Informal description
Let $f : \alpha \to \beta \to \beta$ be a function, $\text{init} : \beta$ an initial value, $\text{xs} : \text{Array } \alpha$ an array, and $a : \alpha$ an element. If the starting index $\text{start}$ satisfies $\text{start} = \text{xs.size} + 1$, then the right fold of the array $\text{xs.push } a$ with function $f$ and initial value $\text{init}$ beginning at index $\text{start}$ equals the right fold of $\text{xs}$ with $f$ and initial value $f(a, \text{init})$.
Array.foldl_push_eq_append theorem
{as : Array α} {bs : Array β} {f : α → β} (w : stop = as.size) : as.foldl (fun acc a => acc.push (f a)) bs 0 stop = bs ++ as.map f
Full source
@[simp] theorem foldl_push_eq_append {as : Array α} {bs : Array β} {f : α → β} (w : stop = as.size) :
    as.foldl (fun acc a => acc.push (f a)) bs 0 stop = bs ++ as.map f := by
  subst w
  rcases as with ⟨as⟩
  rcases bs with ⟨bs⟩
  simp only [List.foldl_toArray']
  induction as generalizing bs <;> simp [*]
Left Fold with Push Equals Concatenation of Mapped Array: $\text{foldl } (\lambda \text{acc } a. \text{acc.push } (f a)) \text{ bs } = \text{bs ++ as.map } f$
Informal description
For any arrays `as : Array α` and `bs : Array β`, any function `f : α → β`, and any natural number `stop` such that `stop = as.size`, the left fold of `as` with the accumulator function `(fun acc a => acc.push (f a))` starting from `bs` and iterating from index `0` to `stop` is equal to the concatenation of `bs` with the array obtained by mapping `f` over `as`. That is: \[ \text{as.foldl } (\lambda \text{acc } a. \text{acc.push } (f a)) \text{ bs } 0 \text{ stop } = \text{bs ++ as.map } f \]
Array.foldl_cons_eq_append theorem
{as : Array α} {bs : List β} {f : α → β} (w : stop = as.size) : as.foldl (fun acc a => (f a) :: acc) bs 0 stop = (as.map f).reverse.toList ++ bs
Full source
@[simp] theorem foldl_cons_eq_append {as : Array α} {bs : List β} {f : α → β} (w : stop = as.size) :
    as.foldl (fun acc a => (f a) :: acc) bs 0 stop = (as.map f).reverse.toList ++ bs := by
  subst w
  rcases as with ⟨as⟩
  simp
Left Fold with Cons Equals Concatenation of Reversed Mapped Array and List
Informal description
For any array `as` of type `Array α`, any list `bs` of type `List β`, and any function `f : α → β`, if the stopping index `stop` equals the size of `as`, then the left fold of `as` with the function `fun acc a => (f a) :: acc` and initial accumulator `bs` over the range `[0, stop)` is equal to the concatenation of the reversed list obtained by mapping `f` over `as` with `bs`. That is: $$ \text{as.foldl } (\lambda \text{acc } a. (f a) :: \text{acc}) \text{ bs } 0 \text{ stop } = (\text{as.map } f).\text{reverse.toList} ++ \text{bs} $$
Array.foldr_cons_eq_append theorem
{as : Array α} {bs : List β} {f : α → β} (w : start = as.size) : as.foldr (fun a acc => (f a) :: acc) bs start 0 = (as.map f).toList ++ bs
Full source
@[simp] theorem foldr_cons_eq_append {as : Array α} {bs : List β} {f : α → β} (w : start = as.size) :
    as.foldr (fun a acc => (f a) :: acc) bs start 0 = (as.map f).toList ++ bs := by
  subst w
  rcases as with ⟨as⟩
  simp
Right Fold with Cons Equals Concatenation for Mapped Arrays
Informal description
For any array `as` of type `Array α`, any list `bs` of type `List β`, and any function `f : α → β`, if the starting index `start` equals the size of `as`, then the right fold of `as` with the function `fun a acc => (f a) :: acc` and initial accumulator `bs` over the range `[start, 0)` is equal to the concatenation of the list obtained by mapping `f` over `as` with `bs`. That is, `as.foldr (fun a acc => (f a) :: acc) bs start 0 = (as.map f).toList ++ bs` when `start = as.size`.
Array.foldr_cons_eq_append' theorem
{as : Array α} {bs : List α} (w : start = as.size) : as.foldr List.cons bs start 0 = as.toList ++ bs
Full source
/-- Variant of `foldr_cons_eq_append` specialized to `f = id`. -/
@[simp] theorem foldr_cons_eq_append' {as : Array α} {bs : List α} (w : start = as.size) :
    as.foldr List.cons bs start 0 = as.toList ++ bs := by
  subst w
  rcases as with ⟨as⟩
  simp
Right Fold with Cons Equals Concatenation for Arrays
Informal description
For any array `as` of type `Array α` and any list `bs` of type `List α`, if the starting index `start` equals the size of `as`, then the right fold of `as` with the list cons operation `List.cons` and initial accumulator `bs` over the range `[start, 0)` is equal to the concatenation of the list representation of `as` with `bs`. In other words, `foldr List.cons bs as start 0 = as.toList ++ bs` when `start = as.size`.
Array.foldr_append_eq_append theorem
{xs : Array α} {f : α → Array β} {ys : Array β} : xs.foldr (f · ++ ·) ys = (xs.map f).flatten ++ ys
Full source
@[simp] theorem foldr_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
    xs.foldr (f · ++ ·) ys = (xs.map f).flatten ++ ys := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  induction xs <;> simp_all [Function.comp_def, flatten_toArray]
Right Fold with Append Equals Concatenation of Flattened Map
Informal description
For any array `xs` of type `Array α`, any function `f : α → Array β`, and any array `ys` of type `Array β`, the right fold of `xs` with the operation `(f · ++ ·)` (which appends the result of `f` applied to each element) and initial accumulator `ys` is equal to the concatenation of the flattened array obtained by mapping `f` over `xs` with `ys`. In symbols: $$\text{foldr}\ (\lambda x\ acc,\ f(x) +\!+\ acc)\ ys\ xs = \text{flatten}(\text{map}\ f\ xs) +\!+\ ys$$
Array.foldl_append_eq_append theorem
{xs : Array α} {f : α → Array β} {ys : Array β} : xs.foldl (· ++ f ·) ys = ys ++ (xs.map f).flatten
Full source
@[simp] theorem foldl_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
    xs.foldl (· ++ f ·) ys = ys ++ (xs.map f).flatten := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  induction xs generalizing ys <;> simp_all [Function.comp_def, flatten_toArray]
Left Fold with Concatenation Equals Concatenation with Flattened Map
Informal description
For any array `xs` of type `Array α`, any function `f : α → Array β`, and any array `ys` of type `Array β`, the left fold of `xs` with the operation `(· ++ f ·)` and initial accumulator `ys` is equal to the concatenation of `ys` with the flattened array obtained by mapping `f` over `xs`. In symbols: $$\text{foldl}\ (\cdot\ {++}\ f\ \cdot)\ ys\ xs = ys\ {++}\ \text{flatten}(\text{map}\ f\ xs)$$
Array.foldr_flip_append_eq_append theorem
{xs : Array α} {f : α → Array β} {ys : Array β} : xs.foldr (fun x acc => acc ++ f x) ys = ys ++ (xs.map f).reverse.flatten
Full source
@[simp] theorem foldr_flip_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
    xs.foldr (fun x acc => acc ++ f x) ys = ys ++ (xs.map f).reverse.flatten := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  induction xs generalizing ys <;> simp_all [Function.comp_def, flatten_toArray]
Right Fold with Flipped Append Equals Concatenation with Flattened Reverse Map
Informal description
For any array `xs` of type `Array α`, any function `f : α → Array β`, and any array `ys` of type `Array β`, the right fold of `xs` with the operation `(fun x acc => acc ++ f x)` and initial accumulator `ys` is equal to the concatenation of `ys` with the flattened array obtained by reversing the mapped array `xs.map f`. In symbols: $$\text{foldr}\ (\lambda x\ acc,\ acc +\!+\ f(x))\ ys\ xs = ys +\!+\ \text{flatten}(\text{reverse}(\text{map}\ f\ xs))$$
Array.foldl_flip_append_eq_append theorem
{xs : Array α} {f : α → Array β} {ys : Array β} : xs.foldl (fun acc y => f y ++ acc) ys = (xs.map f).reverse.flatten ++ ys
Full source
@[simp] theorem foldl_flip_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
    xs.foldl (fun acc y => f y ++ acc) ys = (xs.map f).reverse.flatten ++ ys:= by
  rcases xs with ⟨l⟩
  rcases ys with ⟨l'⟩
  induction l generalizing l' <;> simp_all [Function.comp_def, flatten_toArray]
Left Fold with Reverse Flattened Map Equals Concatenation: $\text{foldl}\ (\lambda\ acc\ y.\ f\ y\ {++}\ acc)\ ys\ xs = \text{flatten}(\text{reverse}(\text{map}\ f\ xs))\ {++}\ ys$
Informal description
For any array $xs$ of type $\alpha$, any function $f : \alpha \to \text{Array}\ \beta$, and any array $ys$ of type $\beta$, the left fold of $xs$ with the operation $\lambda\ acc\ y.\ f\ y\ {++}\ acc$ and initial accumulator $ys$ is equal to the concatenation of the flattened array obtained by reversing the mapped array $(xs.\text{map}\ f)$ with $ys$. In symbols: $$\text{foldl}\ (\lambda\ acc\ y.\ f\ y\ {++}\ acc)\ ys\ xs = \text{flatten}((xs.\text{map}\ f).\text{reverse})\ {++}\ ys$$
Array.foldl_map' theorem
{f : β₁ → β₂} {g : α → β₂ → α} {xs : Array β₁} {init : α} {stop : Nat} (w : stop = xs.size) : (xs.map f).foldl g init 0 stop = xs.foldl (fun x y => g x (f y)) init
Full source
theorem foldl_map' {f : β₁ → β₂} {g : α → β₂ → α} {xs : Array β₁} {init : α} {stop : Nat}
    (w : stop = xs.size) :
    (xs.map f).foldl g init 0 stop = xs.foldl (fun x y => g x (f y)) init := by
  subst w
  cases xs; simp [List.foldl_map]
Left Fold Commutes with Array Mapping: $\text{foldl}\ g\ init\ (xs.\text{map } f) = \text{foldl}\ (\lambda x\ y.\ g\ x\ (f\ y))\ init\ xs$
Informal description
Let $f : \beta_1 \to \beta_2$ and $g : \alpha \to \beta_2 \to \alpha$ be functions, and let $xs$ be an array of type $\beta_1$. For any initial value $init : \alpha$ and any natural number $stop$ such that $stop = xs.\text{size}$, the left fold of $g$ over the mapped array $(xs.\text{map } f)$ with initial value $init$ and bounds $0$ to $stop$ is equal to the left fold of the function $\lambda x\ y.\ g\ x\ (f\ y)$ over $xs$ with the same initial value and bounds. In symbols: $$(xs.\text{map } f).\text{foldl}\ g\ init\ 0\ stop = xs.\text{foldl}\ (\lambda x\ y.\ g\ x\ (f\ y))\ init$$
Array.foldr_map' theorem
{f : α₁ → α₂} {g : α₂ → β → β} {xs : Array α₁} {init : β} {start : Nat} (w : start = xs.size) : (xs.map f).foldr g init start 0 = xs.foldr (fun x y => g (f x) y) init
Full source
theorem foldr_map' {f : α₁ → α₂} {g : α₂ → β → β} {xs : Array α₁} {init : β} {start : Nat}
    (w : start = xs.size) :
    (xs.map f).foldr g init start 0 = xs.foldr (fun x y => g (f x) y) init := by
  subst w
  cases xs; simp [List.foldr_map]
Right Fold of Mapped Array Equals Fold with Composed Function: $\text{foldr}~g~init~(xs.map f) = \text{foldr}~(\lambda x y, g (f x) y)~init~xs$ when $start = \text{size}(xs)$
Informal description
Let $f : \alpha_1 \to \alpha_2$ and $g : \alpha_2 \to \beta \to \beta$ be functions, and let $xs$ be an array of elements of type $\alpha_1$. For any initial value $init$ of type $\beta$ and any starting index $start$ such that $start = \text{size}(xs)$, the right fold of the mapped array $(xs.map f)$ with function $g$ and initial value $init$ over the range $[start, 0)$ is equal to the right fold of $xs$ with the composed function $\lambda x y, g (f x) y$ and initial value $init$.
Array.foldl_map theorem
{f : β₁ → β₂} {g : α → β₂ → α} {xs : Array β₁} {init : α} : (xs.map f).foldl g init = xs.foldl (fun x y => g x (f y)) init
Full source
theorem foldl_map {f : β₁ → β₂} {g : α → β₂ → α} {xs : Array β₁} {init : α} :
    (xs.map f).foldl g init = xs.foldl (fun x y => g x (f y)) init := by
  cases xs; simp [List.foldl_map]
Left Fold Commutes with Array Mapping: $(xs.\text{map } f).\text{foldl } g \ init = xs.\text{foldl } (\lambda x \ y. g(x, f(y))) \ init$
Informal description
For any function $f : \beta_1 \to \beta_2$, any binary operation $g : \alpha \to \beta_2 \to \alpha$, any array $xs$ of type $\text{Array } \beta_1$, and any initial value $init : \alpha$, the left fold operation on the mapped array satisfies: $$(xs.\text{map } f).\text{foldl } g \ init = xs.\text{foldl } (\lambda x \ y. g(x, f(y))) \ init$$
Array.foldr_map theorem
{f : α₁ → α₂} {g : α₂ → β → β} {xs : Array α₁} {init : β} : (xs.map f).foldr g init = xs.foldr (fun x y => g (f x) y) init
Full source
theorem foldr_map {f : α₁ → α₂} {g : α₂ → β → β} {xs : Array α₁} {init : β} :
    (xs.map f).foldr g init = xs.foldr (fun x y => g (f x) y) init := by
  cases xs; simp [List.foldr_map]
Right Fold Commutes with Array Mapping: $(xs.map f).foldr\ g\ init = xs.foldr (\lambda x\ y, g (f x) y)\ init$
Informal description
For any function $f : \alpha_1 \to \alpha_2$, any function $g : \alpha_2 \to \beta \to \beta$, any array $xs$ of elements of type $\alpha_1$, and any initial value $init$ of type $\beta$, the right fold of the mapped array $(xs.map f).foldr\ g\ init$ is equal to the right fold of the original array $xs$ with the modified folding function $\lambda x\ y, g (f x) y$ applied to the same initial value $init$.
Array.foldl_filterMap' theorem
{f : α → Option β} {g : γ → β → γ} {xs : Array α} {init : γ} {stop : Nat} (w : stop = (xs.filterMap f).size) : (xs.filterMap f).foldl g init 0 stop = xs.foldl (fun x y => match f y with | some b => g x b | none => x) init
Full source
theorem foldl_filterMap' {f : α → Option β} {g : γ → β → γ} {xs : Array α} {init : γ} {stop : Nat}
    (w : stop = (xs.filterMap f).size) :
    (xs.filterMap f).foldl g init 0 stop = xs.foldl (fun x y => match f y with | some b => g x b | none => x) init := by
  subst w
  cases xs
  simp [List.foldl_filterMap]
  rfl
Equivalence of Left Fold Operations on Filtered and Mapped Arrays
Informal description
Let $f : \alpha \to \text{Option } \beta$ be a function, $g : \gamma \to \beta \to \gamma$ a binary operation, $xs$ an array of type $\text{Array } \alpha$, $init$ an element of type $\gamma$, and $stop$ a natural number such that $stop = \text{size}(xs.\text{filterMap } f)$. Then the left fold operation on the filtered and mapped array satisfies: $$(xs.\text{filterMap } f).\text{foldl } g \ init \ 0 \ stop = xs.\text{foldl } (\lambda x \ y. \text{match } f(y) \text{ with } | \text{some } b \Rightarrow g(x, b) | \text{none } \Rightarrow x) \ init$$
Array.foldr_filterMap' theorem
{f : α → Option β} {g : β → γ → γ} {xs : Array α} {init : γ} {start : Nat} (w : start = (xs.filterMap f).size) : (xs.filterMap f).foldr g init start 0 = xs.foldr (fun x y => match f x with | some b => g b y | none => y) init
Full source
theorem foldr_filterMap' {f : α → Option β} {g : β → γ → γ} {xs : Array α} {init : γ} {start : Nat}
    (w : start = (xs.filterMap f).size) :
    (xs.filterMap f).foldr g init start 0 = xs.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
  subst w
  cases xs
  simp [List.foldr_filterMap]
  rfl
Right Fold of Filtered Array Equals Modified Fold of Original Array
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any function $g : \beta \to \gamma \to \gamma$, any array $xs$ of type $\text{Array } \alpha$, any initial value $init$ of type $\gamma$, and any natural number $start$ such that $start$ equals the size of the filtered array $xs.\text{filterMap } f$, the right fold of the filtered array $(xs.\text{filterMap } f).\text{foldr } g \ init \ start \ 0$ is equal to the right fold of the original array $xs$ with the modified folding function that applies $g$ to the result of $f$ when it is $\text{some } b$.
Array.foldl_filterMap theorem
{f : α → Option β} {g : γ → β → γ} {xs : Array α} {init : γ} : (xs.filterMap f).foldl g init = xs.foldl (fun x y => match f y with | some b => g x b | none => x) init
Full source
theorem foldl_filterMap {f : α → Option β} {g : γ → β → γ} {xs : Array α} {init : γ} :
    (xs.filterMap f).foldl g init = xs.foldl (fun x y => match f y with | some b => g x b | none => x) init := by
  simp [foldl_filterMap']
Equivalence of Left Folds on Original and Filtered-Mapped Arrays
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any binary operation $g : \gamma \to \beta \to \gamma$, any array $xs$ of type $\text{Array } \alpha$, and any initial value $init$ of type $\gamma$, the left fold of the filtered and mapped array $(xs.\text{filterMap } f).\text{foldl } g \ init$ is equal to the left fold of the original array $xs$ with the modified folding function that applies $g$ to the result of $f$ when it is $\text{some } b$ and leaves the accumulator unchanged otherwise.
Array.foldr_filterMap theorem
{f : α → Option β} {g : β → γ → γ} {xs : Array α} {init : γ} : (xs.filterMap f).foldr g init = xs.foldr (fun x y => match f x with | some b => g b y | none => y) init
Full source
theorem foldr_filterMap {f : α → Option β} {g : β → γ → γ} {xs : Array α} {init : γ} :
    (xs.filterMap f).foldr g init = xs.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
  simp [foldr_filterMap']
Right Fold Equivalence for Filtered Array via `filterMap`
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any function $g : \beta \to \gamma \to \gamma$, any array $xs$ of type $\text{Array } \alpha$, and any initial value $init$ of type $\gamma$, the right fold of the filtered array $(xs.\text{filterMap } f).\text{foldr } g \ init$ is equal to the right fold of the original array $xs$ with the modified folding function that applies $g$ to the result of $f$ when it is $\text{some } b$.
Array.foldl_map_hom' theorem
{g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {xs : Array α} {stop : Nat} (h : ∀ x y, f' (g x) (g y) = g (f x y)) (w : stop = xs.size) : (xs.map g).foldl f' (g a) 0 stop = g (xs.foldl f a)
Full source
theorem foldl_map_hom' {g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {xs : Array α}
    {stop : Nat} (h : ∀ x y, f' (g x) (g y) = g (f x y)) (w : stop = xs.size) :
    (xs.map g).foldl f' (g a) 0 stop = g (xs.foldl f a) := by
  subst w
  cases xs
  simp
  rw [List.foldl_map_hom h]
Homomorphism Property of Left Fold under Mapping: $(xs.map\ g).\text{foldl}\ f'\ (g(a))\ 0\ stop = g(xs.\text{foldl}\ f\ a)$
Informal description
Let $g : \alpha \to \beta$ be a function, $f : \alpha \to \alpha \to \alpha$ and $f' : \beta \to \beta \to \beta$ be binary operations, $a \in \alpha$ an initial value, and $xs$ an array of elements of type $\alpha$. Suppose that for all $x, y \in \alpha$, the homomorphism condition $f'(g(x), g(y)) = g(f(x, y))$ holds, and let $stop$ be a natural number equal to the size of $xs$. Then the left fold of the mapped array $(xs.map\ g)$ with operation $f'$, initial value $g(a)$, start index $0$, and stop index $stop$ equals $g$ applied to the left fold of $xs$ with operation $f$ and initial value $a$. In symbols: $$(xs.map\ g).\text{foldl}\ f'\ (g(a))\ 0\ stop = g(xs.\text{foldl}\ f\ a)$$
Array.foldr_map_hom' theorem
{g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {xs : Array α} {start : Nat} (h : ∀ x y, f' (g x) (g y) = g (f x y)) (w : start = xs.size) : (xs.map g).foldr f' (g a) start 0 = g (xs.foldr f a)
Full source
theorem foldr_map_hom' {g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {xs : Array α}
    {start : Nat} (h : ∀ x y, f' (g x) (g y) = g (f x y)) (w : start = xs.size) :
    (xs.map g).foldr f' (g a) start 0 = g (xs.foldr f a) := by
  subst w
  cases xs
  simp
  rw [List.foldr_map_hom h]
Homomorphism Property Preserved in Right Fold of Mapped Array: $(xs.map\ g).foldr\ f'\ (g\ a)\ start\ 0 = g(xs.foldr\ f\ a)$ when $start = xs.size$ and $f'$ is a homomorphism with respect to $g$ and $f$
Informal description
Let $g : \alpha \to \beta$ be a function, $f : \alpha \to \alpha \to \alpha$ and $f' : \beta \to \beta \to \beta$ be binary operations, $a \in \alpha$ an element, and $xs$ an array of elements of type $\alpha$. If $f'$ is a homomorphism with respect to $g$ and $f$ (i.e., for all $x, y \in \alpha$, $f'(g(x), g(y)) = g(f(x, y))$) and $start$ is equal to the size of $xs$, then the right fold of the mapped array $(xs.map\ g)$ with operation $f'$ starting from $g(a)$ over the range $[start, 0)$ equals $g$ applied to the right fold of $xs$ with operation $f$ starting from $a$.
Array.foldl_map_hom theorem
{g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {xs : Array α} (h : ∀ x y, f' (g x) (g y) = g (f x y)) : (xs.map g).foldl f' (g a) = g (xs.foldl f a)
Full source
theorem foldl_map_hom {g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {xs : Array α}
    (h : ∀ x y, f' (g x) (g y) = g (f x y)) :
    (xs.map g).foldl f' (g a) = g (xs.foldl f a) := by
  cases xs
  simp
  rw [List.foldl_map_hom h]
Homomorphism Property of Left Fold under Mapping: $(xs.map\ g).\text{foldl}\ f'\ (g(a)) = g(xs.\text{foldl}\ f\ a)$
Informal description
Let $g : \alpha \to \beta$ be a function, and let $f : \alpha \to \alpha \to \alpha$ and $f' : \beta \to \beta \to \beta$ be binary operations such that for all $x, y \in \alpha$, we have $f'(g(x), g(y)) = g(f(x, y))$. Then for any initial value $a \in \alpha$ and any array $xs$ of elements of type $\alpha$, the left fold of the mapped array $(xs.map\ g)$ with operation $f'$ and initial value $g(a)$ is equal to $g$ applied to the left fold of $xs$ with operation $f$ and initial value $a$. That is, $$(xs.map\ g).\text{foldl}\ f'\ (g(a)) = g(xs.\text{foldl}\ f\ a).$$
Array.foldr_map_hom theorem
{g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {xs : Array α} (h : ∀ x y, f' (g x) (g y) = g (f x y)) : (xs.map g).foldr f' (g a) = g (xs.foldr f a)
Full source
theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {xs : Array α}
    (h : ∀ x y, f' (g x) (g y) = g (f x y)) :
    (xs.map g).foldr f' (g a) = g (xs.foldr f a) := by
  cases xs
  simp
  rw [List.foldr_map_hom h]
Homomorphism Property of Right Fold Under Array Mapping: $(xs.map g).foldr f' (g a) = g (xs.foldr f a)$
Informal description
For any function $g : \alpha \to \beta$, binary operations $f : \alpha \to \alpha \to \alpha$ and $f' : \beta \to \beta \to \beta$, initial value $a \in \alpha$, and array $xs$ of type $\text{Array }\alpha$, if $f'$ is a homomorphism with respect to $g$ (i.e., $f'(g(x), g(y)) = g(f(x,y))$ for all $x,y \in \alpha$), then the right fold of the mapped array $(xs.map g)$ with operation $f'$ and initial value $g(a)$ equals $g$ applied to the right fold of $xs$ with operation $f$ and initial value $a$.
Array.foldrM_append' theorem
[Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs ys : Array α} {start : Nat} (w : start = xs.size + ys.size) : (xs ++ ys).foldrM f b start 0 = ys.foldrM f b >>= xs.foldrM f
Full source
/-- Variant of `foldrM_append` with a side condition for the `start` argument. -/
@[simp] theorem foldrM_append' [Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs ys : Array α}
    {start : Nat} (w : start = xs.size + ys.size) :
    (xs ++ ys).foldrM f b start 0 = ys.foldrM f b >>= xs.foldrM f := by
  subst w
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp
Monadic Right Fold over Concatenated Arrays with Size Condition: $(xs \mathbin{+\kern-1.5ex+} ys).\text{foldrM}\ f\ b\ \text{start}\ 0 = ys.\text{foldrM}\ f\ b \gg\!= xs.\text{foldrM}\ f$ when $\text{start} = \text{size}(xs) + \text{size}(ys)$
Informal description
Let $m$ be a monad with lawful monad operations, $f : \alpha \to \beta \to m \beta$ a function, $b \in \beta$ an initial value, and $xs, ys$ arrays of type $\text{Array}\,\alpha$. If the starting index $start$ equals the sum of the sizes of $xs$ and $ys$, then the monadic right fold of the concatenated array $xs \mathbin{+\kern-1.5ex+} ys$ from $start$ to $0$ with function $f$ and initial value $b$ is equal to first performing the monadic right fold of $ys$ with $f$ and $b$, and then binding the result to the monadic right fold of $xs$ with $f$.
Array.foldrM_append theorem
[Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs ys : Array α} : (xs ++ ys).foldrM f b = ys.foldrM f b >>= xs.foldrM f
Full source
theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs ys : Array α} :
    (xs ++ ys).foldrM f b = ys.foldrM f b >>= xs.foldrM f := by
  simp
Monadic Right Fold Distributes Over Array Concatenation
Informal description
For any monad $m$ with lawful monad operations, any function $f : \alpha \to \beta \to m \beta$, any initial value $b \in \beta$, and any arrays $xs, ys$ of type $\text{Array}\,\alpha$, the monadic right fold of the concatenated array $xs \mathbin{+\kern-1.5ex+} ys$ with function $f$ and initial value $b$ is equal to first performing the monadic right fold of $ys$ with $f$ and $b$, and then binding the result to the monadic right fold of $xs$ with $f$. In symbols: $$ (xs \mathbin{+\kern-1.5ex+} ys).\text{foldrM}\ f\ b = ys.\text{foldrM}\ f\ b \gg\!= xs.\text{foldrM}\ f $$
Array.foldl_append' theorem
{β : Type _} {f : β → α → β} {b} {xs ys : Array α} {stop : Nat} (w : stop = xs.size + ys.size) : (xs ++ ys).foldl f b 0 stop = ys.foldl f (xs.foldl f b)
Full source
@[simp] theorem foldl_append' {β : Type _} {f : β → α → β} {b} {xs ys : Array α} {stop : Nat}
    (w : stop = xs.size + ys.size) :
    (xs ++ ys).foldl f b 0 stop = ys.foldl f (xs.foldl f b) := by
  subst w
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp
Left Fold over Concatenated Arrays: $(xs \mathbin{+\kern-1.5ex+} ys).\text{foldl}\ f\ b = ys.\text{foldl}\ f\ (xs.\text{foldl}\ f\ b)$
Informal description
Let $\beta$ be a type, $f : \beta \to \alpha \to \beta$ a function, $b \in \beta$ an initial value, and $xs, ys$ arrays of type $\alpha$. If $stop$ is a natural number equal to the sum of the sizes of $xs$ and $ys$, then the left fold operation satisfies: $$(xs \mathbin{+\kern-1.5ex+} ys).\text{foldl}\ f\ b\ 0\ stop = ys.\text{foldl}\ f\ (xs.\text{foldl}\ f\ b)$$
Array.foldr_append' theorem
{f : α → β → β} {b} {xs ys : Array α} {start : Nat} (w : start = xs.size + ys.size) : (xs ++ ys).foldr f b start 0 = xs.foldr f (ys.foldr f b)
Full source
@[simp] theorem foldr_append' {f : α → β → β} {b} {xs ys : Array α} {start : Nat}
    (w : start = xs.size + ys.size) :
    (xs ++ ys).foldr f b start 0 = xs.foldr f (ys.foldr f b) := by
  subst w
  simp [foldr_eq_foldrM]
Right Fold of Concatenated Arrays: $(xs \mathbin{+\kern-1.5ex+} ys).\text{foldr}\ f\ b = xs.\text{foldr}\ f\ (ys.\text{foldr}\ f\ b)$ when $start = \text{size}(xs) + \text{size}(ys)$
Informal description
For any function $f : \alpha \to \beta \to \beta$, initial value $b \in \beta$, arrays $xs, ys$ of type $\text{Array}\,\alpha$, and natural number $start$ such that $start = \text{size}(xs) + \text{size}(ys)$, the right fold of the concatenated array $xs \mathbin{+\kern-1.5ex+} ys$ with $f$ and $b$ over the range $[start, 0)$ equals the right fold of $xs$ with $f$ applied to the right fold of $ys$ with $f$ and $b$. In symbols: $$(xs \mathbin{+\kern-1.5ex+} ys).\text{foldr}\ f\ b\ start\ 0 = xs.\text{foldr}\ f\ (ys.\text{foldr}\ f\ b)$$
Array.foldl_append theorem
{β : Type _} {f : β → α → β} {b} {xs ys : Array α} : (xs ++ ys).foldl f b = ys.foldl f (xs.foldl f b)
Full source
theorem foldl_append {β : Type _} {f : β → α → β} {b} {xs ys : Array α} :
    (xs ++ ys).foldl f b = ys.foldl f (xs.foldl f b) := by
  simp [foldl_eq_foldlM]
Left Fold Distributes Over Array Concatenation: $(xs \mathbin{+\kern-1.5ex+} ys).\text{foldl}\ f\ b = ys.\text{foldl}\ f\ (xs.\text{foldl}\ f\ b)$
Informal description
For any type $\beta$, function $f : \beta \to \alpha \to \beta$, initial value $b \in \beta$, and arrays $xs, ys$ of type $\alpha$, the left fold operation on the concatenated array $xs \mathbin{+\kern-1.5ex+} ys$ satisfies: $$(xs \mathbin{+\kern-1.5ex+} ys).\text{foldl}\ f\ b = ys.\text{foldl}\ f\ (xs.\text{foldl}\ f\ b)$$
Array.foldr_append theorem
{f : α → β → β} {b} {xs ys : Array α} : (xs ++ ys).foldr f b = xs.foldr f (ys.foldr f b)
Full source
theorem foldr_append {f : α → β → β} {b} {xs ys : Array α} :
    (xs ++ ys).foldr f b = xs.foldr f (ys.foldr f b) := by
  simp [foldr_eq_foldrM]
Right Fold Distributes Over Array Concatenation: $(xs \mathbin{+\kern-1.5ex+} ys).\text{foldr}\,f\,b = xs.\text{foldr}\,f\,(ys.\text{foldr}\,f\,b)$
Informal description
For any function $f : \alpha \to \beta \to \beta$, initial value $b : \beta$, and arrays $xs, ys : \text{Array}\,\alpha$, the right fold of the concatenated array $xs \mathbin{+\kern-1.5ex+} ys$ with function $f$ and initial value $b$ is equal to the right fold of $xs$ with $f$ and initial value given by the right fold of $ys$ with $f$ and $b$. In symbols: $$(xs \mathbin{+\kern-1.5ex+} ys).\text{foldr}\,f\,b = xs.\text{foldr}\,f\,(ys.\text{foldr}\,f\,b)$$
Array.foldl_flatten' theorem
{f : β → α → β} {b} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) : (flatten xss).foldl f b 0 stop = xss.foldl (fun b xs => xs.foldl f b) b
Full source
@[simp] theorem foldl_flatten' {f : β → α → β} {b} {xss : Array (Array α)} {stop : Nat}
    (w : stop = xss.flatten.size) :
    (flatten xss).foldl f b 0 stop = xss.foldl (fun b xs => xs.foldl f b) b := by
  subst w
  cases xss using array₂_induction
  simp [List.foldl_flatten, List.foldl_map]
Left Fold of Flattened Array Equals Nested Left Folds
Informal description
Let $f : \beta \to \alpha \to \beta$ be a function, $b \in \beta$ an initial value, and $xss$ an array of arrays of type $\alpha$. If $stop$ is a natural number equal to the size of the flattened array $xss.\text{flatten}$, then the left fold of $f$ over the flattened array $xss.\text{flatten}$ from index $0$ to $stop$ with initial value $b$ is equal to the left fold over $xss$ where each inner array is folded with $f$ and initial value $b$. In symbols: $$\text{flatten}(xss).\text{foldl}\ f\ b\ 0\ stop = xss.\text{foldl}\ (\lambda b\ xs. xs.\text{foldl}\ f\ b)\ b$$
Array.foldr_flatten' theorem
{f : α → β → β} {b} {xss : Array (Array α)} {start : Nat} (w : start = xss.flatten.size) : (flatten xss).foldr f b start 0 = xss.foldr (fun xs b => xs.foldr f b) b
Full source
@[simp] theorem foldr_flatten' {f : α → β → β} {b} {xss : Array (Array α)} {start : Nat}
    (w : start = xss.flatten.size) :
    (flatten xss).foldr f b start 0 = xss.foldr (fun xs b => xs.foldr f b) b := by
  subst w
  cases xss using array₂_induction
  simp [List.foldr_flatten, List.foldr_map]
Right Fold of Flattened Array Equals Nested Right Folds
Informal description
For any function $f : \alpha \to \beta \to \beta$, initial value $b : \beta$, array of arrays $xss : \text{Array} (\text{Array} \alpha)$, and natural number $\text{start} : \mathbb{N}$ such that $\text{start} = \text{size}(\text{flatten}(xss))$, the right fold of the flattened array $\text{flatten}(xss)$ with function $f$, initial value $b$, and range $[\text{start}, 0)$ is equal to the right fold of $xss$ where each inner array is folded with $f$ and the result is accumulated. In symbols: $$\text{flatten}(xss).\text{foldr}~f~b~\text{start}~0 = xss.\text{foldr}~(\lambda xs~b, xs.\text{foldr}~f~b)~b$$
Array.foldl_flatten theorem
{f : β → α → β} {b} {xss : Array (Array α)} : (flatten xss).foldl f b = xss.foldl (fun b xs => xs.foldl f b) b
Full source
theorem foldl_flatten {f : β → α → β} {b} {xss : Array (Array α)} :
    (flatten xss).foldl f b = xss.foldl (fun b xs => xs.foldl f b) b := by
  cases xss using array₂_induction
  simp [List.foldl_flatten, List.foldl_map]
Left Fold Commutes with Array Flattening: $\text{flatten}(xss).\text{foldl}\ f\ b = xss.\text{foldl}\ (\lambda b\ xs. xs.\text{foldl}\ f\ b)\ b$
Informal description
For any function $f : \beta \to \alpha \to \beta$, initial value $b \in \beta$, and array of arrays $xss : \text{Array} (\text{Array} \alpha)$, the left fold of $f$ over the flattened array $\text{flatten}(xss)$ with initial value $b$ is equal to the left fold over $xss$ where each inner array is folded with $f$ and initial value $b$. In symbols: $$\text{flatten}(xss).\text{foldl}\ f\ b = xss.\text{foldl}\ (\lambda b\ xs. xs.\text{foldl}\ f\ b)\ b$$
Array.foldr_flatten theorem
{f : α → β → β} {b} {xss : Array (Array α)} : (flatten xss).foldr f b = xss.foldr (fun xs b => xs.foldr f b) b
Full source
theorem foldr_flatten {f : α → β → β} {b} {xss : Array (Array α)} :
    (flatten xss).foldr f b = xss.foldr (fun xs b => xs.foldr f b) b := by
  cases xss using array₂_induction
  simp [List.foldr_flatten, List.foldr_map]
Right Fold of Flattened Array Equals Nested Right Folds
Informal description
For any function $f : \alpha \to \beta \to \beta$, initial value $b : \beta$, and array of arrays $xss : \text{Array} (\text{Array} \alpha)$, the right fold of the flattened array $\text{flatten}(xss)$ with function $f$ and initial value $b$ is equal to the right fold of $xss$ where each inner array is folded with $f$ and the result is accumulated. In symbols: $$\text{flatten}(xss).\text{foldr}~f~b = xss.\text{foldr}~(\lambda xs~b, xs.\text{foldr}~f~b)~b$$
Array.foldl_reverse' theorem
{xs : Array α} {f : β → α → β} {b} {stop : Nat} (w : stop = xs.size) : xs.reverse.foldl f b 0 stop = xs.foldr (fun x y => f y x) b
Full source
/-- Variant of `foldl_reverse` with a side condition for the `stop` argument. -/
@[simp] theorem foldl_reverse' {xs : Array α} {f : β → α → β} {b} {stop : Nat}
    (w : stop = xs.size) :
    xs.reverse.foldl f b 0 stop = xs.foldr (fun x y => f y x) b := by
  simp [w, foldl_eq_foldlM, foldr_eq_foldrM]
Left Fold of Reversed Array Equals Right Fold with Flipped Function ($\text{foldl}\ (\text{reverse}\ xs)\ f\ b\ 0\ \text{size}(xs) = \text{foldr}\ xs\ (\lambda x y. f y x)\ b$)
Informal description
Let $xs$ be an array of type $\alpha$, $f : \beta \to \alpha \to \beta$ be a function, $b$ be an initial value of type $\beta$, and $stop$ be a natural number such that $stop$ equals the size of $xs$. Then the left fold of the reversed array $xs$ from index $0$ to $stop$ with function $f$ and initial value $b$ is equal to the right fold of $xs$ with the flipped function $\lambda x y, f y x$ and initial value $b$. In symbols: $$\text{reverse}(xs).\text{foldl}\ f\ b\ 0\ stop = xs.\text{foldr}\ (\lambda x y, f y x)\ b$$
Array.foldr_reverse' theorem
{xs : Array α} {f : α → β → β} {b} {start : Nat} (w : start = xs.size) : xs.reverse.foldr f b start 0 = xs.foldl (fun x y => f y x) b
Full source
/-- Variant of `foldr_reverse` with a side condition for the `start` argument. -/
@[simp] theorem foldr_reverse' {xs : Array α} {f : α → β → β} {b} {start : Nat}
    (w : start = xs.size) :
    xs.reverse.foldr f b start 0 = xs.foldl (fun x y => f y x) b := by
  simp [w, foldl_eq_foldlM, foldr_eq_foldrM]
Right Fold of Reversed Array Equals Left Fold with Flipped Function (Indexed Version)
Informal description
Let $xs$ be an array of type $\alpha$, $f : \alpha \to \beta \to \beta$ be a function, $b$ be an initial value of type $\beta$, and $start$ be a natural number such that $start$ equals the size of $xs$. Then the right fold of the reversed array $xs$ from index $start$ to $0$ with function $f$ and initial value $b$ is equal to the left fold of $xs$ with the flipped function $\lambda x y, f y x$ and initial value $b$. In symbols: $$\text{reverse}(xs).\text{foldr}~f~b~start~0 = xs.\text{foldl}~(\lambda x y, f y x)~b$$
Array.foldl_reverse theorem
{xs : Array α} {f : β → α → β} {b} : xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b
Full source
theorem foldl_reverse {xs : Array α} {f : β → α → β} {b} :
    xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b := by simp [foldl_eq_foldlM, foldr_eq_foldrM]
Left Fold of Reversed Array Equals Right Fold with Flipped Function
Informal description
For any array `xs` of type `Array α`, function `f : β → α → β`, and initial value `b : β`, the left fold of the reversed array `xs.reverse` with function `f` and initial value `b` is equal to the right fold of the original array `xs` with the flipped function `λ x y, f y x` and initial value `b`. That is: $$\text{foldl}\ f\ b\ \text{xs.reverse} = \text{foldr}\ (\lambda x y, f y x)\ b\ \text{xs}$$
Array.foldr_reverse theorem
{xs : Array α} {f : α → β → β} {b} : xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b
Full source
theorem foldr_reverse {xs : Array α} {f : α → β → β} {b} :
    xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b :=
  (foldl_reverse ..).symm.trans <| by simp
Right Fold of Reversed Array Equals Left Fold with Flipped Function
Informal description
For any array `xs` of type `Array α`, function `f : α → β → β`, and initial value `b : β`, the right fold of the reversed array `xs.reverse` with function `f` and initial value `b` is equal to the left fold of the original array `xs` with the flipped function `λ x y, f y x` and initial value `b`. That is: $$\text{foldr}\ f\ b\ \text{xs.reverse} = \text{foldl}\ (\lambda x y, f y x)\ b\ \text{xs}$$
Array.foldl_eq_foldr_reverse theorem
{xs : Array α} {f : β → α → β} {b} : xs.foldl f b = xs.reverse.foldr (fun x y => f y x) b
Full source
theorem foldl_eq_foldr_reverse {xs : Array α} {f : β → α → β} {b} :
    xs.foldl f b = xs.reverse.foldr (fun x y => f y x) b := by simp
Left Fold Equals Right Fold of Reversed Array with Flipped Function
Informal description
For any array `xs` of type `Array α`, function `f : β → α → β`, and initial value `b : β`, the left fold of `xs` with function `f` and initial value `b` is equal to the right fold of the reversed array `xs.reverse` with the flipped function `λ x y, f y x` and initial value `b`. In symbols: $$\text{foldl}\ f\ b\ \text{xs} = \text{foldr}\ (\lambda x y, f y x)\ b\ \text{xs.reverse}$$
Array.foldr_eq_foldl_reverse theorem
{xs : Array α} {f : α → β → β} {b} : xs.foldr f b = xs.reverse.foldl (fun x y => f y x) b
Full source
theorem foldr_eq_foldl_reverse {xs : Array α} {f : α → β → β} {b} :
    xs.foldr f b = xs.reverse.foldl (fun x y => f y x) b := by simp
Right Fold Equals Left Fold of Reversed Array with Flipped Function
Informal description
For any array `xs` of type `Array α`, any function `f : α → β → β`, and any initial value `b : β`, the right fold of `xs` with `f` and `b` is equal to the left fold of the reversed array `xs.reverse` with the flipped function `λ x y, f y x` and initial value `b`. In mathematical notation: $$\text{foldr}\ f\ b\ xs = \text{foldl}\ (\lambda x y, f y x)\ b\ (\text{reverse}\ xs)$$
Array.foldr_push_eq_append theorem
{as : Array α} {bs : Array β} {f : α → β} (w : start = as.size) : as.foldr (fun a xs => Array.push xs (f a)) bs start 0 = bs ++ (as.map f).reverse
Full source
@[simp] theorem foldr_push_eq_append {as : Array α} {bs : Array β} {f : α → β} (w : start = as.size) :
    as.foldr (fun a xs => Array.push xs (f a)) bs start 0 = bs ++ (as.map f).reverse := by
  subst w
  rw [foldr_eq_foldl_reverse, foldl_push_eq_append rfl, map_reverse]
Right Fold with Push Equals Concatenation of Reversed Mapped Array: $\text{foldr } (\lambda a\ xs. \text{push } xs\ (f a))\ bs = bs +\!\!+ (\text{map } f\ as).\text{reverse}$
Informal description
For any arrays `as : Array α` and `bs : Array β`, any function `f : α → β`, and any natural number `start` such that `start = as.size`, the right fold of `as` with the accumulator function `(fun a xs => Array.push xs (f a))` starting from `bs` and iterating from index `start` to `0` is equal to the concatenation of `bs` with the reversed array obtained by mapping `f` over `as`. That is: \[ \text{as.foldr } (\lambda a\ xs. \text{xs.push } (f a)) \text{ bs } \text{ start } 0 = \text{bs ++ (as.map } f\text{).reverse} \]
Array.foldr_flip_push_eq_append abbrev
Full source
@[deprecated foldr_push_eq_append (since := "2025-02-09")] abbrev foldr_flip_push_eq_append := @foldr_push_eq_append
Right Fold with Push Equals Concatenation of Reversed Mapped Array: $\text{foldr } (\lambda a\ xs. \text{push } xs\ (f a))\ bs = bs +\!\!+ (\text{map } f\ as).\text{reverse}$
Informal description
For any arrays `as : Array α` and `bs : Array β`, any function `f : α → β`, and any natural number `start` such that `start = as.size`, the right fold of `as` with the accumulator function `(fun a xs => Array.push xs (f a))` starting from `bs` and iterating from index `start` to `0` is equal to the concatenation of `bs` with the reversed array obtained by mapping `f` over `as`. That is: \[ \text{as.foldr } (\lambda a\ xs. \text{xs.push } (f a)) \text{ bs } \text{ start } 0 = \text{bs ++ (as.map } f\text{).reverse} \]
Array.foldl_assoc theorem
{op : α → α → α} [ha : Std.Associative op] {xs : Array α} {a₁ a₂} : xs.foldl op (op a₁ a₂) = op a₁ (xs.foldl op a₂)
Full source
theorem foldl_assoc {op : α → α → α} [ha : Std.Associative op] {xs : Array α} {a₁ a₂} :
     xs.foldl op (op a₁ a₂) = op a₁ (xs.foldl op a₂) := by
  rcases xs with ⟨l⟩
  simp [List.foldl_assoc]
Associativity of Left Fold Operation on Arrays: $\text{foldl}\ op\ (op\ a_1\ a_2)\ xs = op\ a_1\ (\text{foldl}\ op\ a_2\ xs)$
Informal description
Let $op : \alpha \to \alpha \to \alpha$ be an associative binary operation, and let $xs$ be an array of elements of type $\alpha$. For any elements $a_1, a_2 \in \alpha$, the left fold of $xs$ with operation $op$ and initial value $op(a_1, a_2)$ is equal to $op(a_1, \text{foldl}\ op\ a_2\ xs)$.
Array.foldr_assoc theorem
{op : α → α → α} [ha : Std.Associative op] {xs : Array α} {a₁ a₂} : xs.foldr op (op a₁ a₂) = op (xs.foldr op a₁) a₂
Full source
theorem foldr_assoc {op : α → α → α} [ha : Std.Associative op] {xs : Array α} {a₁ a₂} :
    xs.foldr op (op a₁ a₂) = op (xs.foldr op a₁) a₂ := by
  rcases xs with ⟨l⟩
  simp [List.foldr_assoc]
Associativity of Right Fold for Arrays
Informal description
For any associative binary operation $op : \alpha \to \alpha \to \alpha$ and any array $xs$ of elements of type $\alpha$, the right fold operation satisfies the associativity property: $$ xs.\text{foldr}\, op\, (op\, a_1\, a_2) = op\, (xs.\text{foldr}\, op\, a_1)\, a_2 $$ for all $a_1, a_2 \in \alpha$.
Array.foldl_hom theorem
(f : α₁ → α₂) {g₁ : α₁ → β → α₁} {g₂ : α₂ → β → α₂} {xs : Array β} {init : α₁} (H : ∀ x y, g₂ (f x) y = f (g₁ x y)) : xs.foldl g₂ (f init) = f (xs.foldl g₁ init)
Full source
theorem foldl_hom (f : α₁ → α₂) {g₁ : α₁ → β → α₁} {g₂ : α₂ → β → α₂} {xs : Array β} {init : α₁}
    (H : ∀ x y, g₂ (f x) y = f (g₁ x y)) : xs.foldl g₂ (f init) = f (xs.foldl g₁ init) := by
  cases xs
  simp
  rw [List.foldl_hom _ H]
Homomorphism Property of Left Fold on Arrays: $f(\text{foldl}\ g_1\ init) = \text{foldl}\ g_2\ f(init)$
Informal description
Let $f : \alpha_1 \to \alpha_2$ be a function, and let $g_1 : \alpha_1 \to \beta \to \alpha_1$ and $g_2 : \alpha_2 \to \beta \to \alpha_2$ be binary operations. For any array $xs$ of elements of type $\beta$ and initial value $init \in \alpha_1$, if the following homomorphism condition holds for all $x \in \alpha_1$ and $y \in \beta$: $$g_2(f(x), y) = f(g_1(x, y))$$ then the left fold operations satisfy: $$xs.\text{foldl}\ g_2\ (f(init)) = f(xs.\text{foldl}\ g_1\ init)$$
Array.foldr_hom theorem
(f : β₁ → β₂) {g₁ : α → β₁ → β₁} {g₂ : α → β₂ → β₂} {xs : Array α} {init : β₁} (H : ∀ x y, g₂ x (f y) = f (g₁ x y)) : xs.foldr g₂ (f init) = f (xs.foldr g₁ init)
Full source
theorem foldr_hom (f : β₁ → β₂) {g₁ : α → β₁ → β₁} {g₂ : α → β₂ → β₂} {xs : Array α} {init : β₁}
    (H : ∀ x y, g₂ x (f y) = f (g₁ x y)) : xs.foldr g₂ (f init) = f (xs.foldr g₁ init) := by
  cases xs
  simp
  rw [List.foldr_hom _ H]
Homomorphism Property of Right Fold on Arrays
Informal description
Let $f : \beta_1 \to \beta_2$ be a function, and let $g_1 : \alpha \to \beta_1 \to \beta_1$ and $g_2 : \alpha \to \beta_2 \to \beta_2$ be binary operations. For any array `xs` of type `Array α` and initial value `init` of type $\beta_1$, if the operations satisfy the homomorphism condition: \[ \forall x \in \alpha, y \in \beta_1, \quad g_2(x, f(y)) = f(g_1(x, y)), \] then the right fold of `xs` using $g_2$ with initial value $f(\text{init})$ is equal to $f$ applied to the right fold of `xs` using $g_1$ with initial value `init`: \[ \text{foldr}(g_2, f(\text{init}), \text{xs}) = f(\text{foldr}(g_1, \text{init}, \text{xs})). \]
Array.foldl_rel theorem
{xs : Array α} {f g : β → α → β} {a b : β} {r : β → β → Prop} (h : r a b) (h' : ∀ (a : α), a ∈ xs → ∀ (c c' : β), r c c' → r (f c a) (g c' a)) : r (xs.foldl (fun acc a => f acc a) a) (xs.foldl (fun acc a => g acc a) b)
Full source
/--
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 {xs : Array α} {f g : β → α → β} {a b : β} {r : β → β → Prop}
    (h : r a b) (h' : ∀ (a : α), a ∈ xs → ∀ (c c' : β), r c c' → r (f c a) (g c' a)) :
    r (xs.foldl (fun acc a => f acc a) a) (xs.foldl (fun acc a => g acc a) b) := by
  rcases xs with ⟨xs⟩
  simpa using List.foldl_rel h (by simpa using h')
Relation Preservation under Left Folding on Arrays
Informal description
Let $xs$ be an array of type $\alpha$, and let $f, g : \beta \to \alpha \to \beta$ be functions. Suppose there exists a relation $r$ on $\beta$ such that: 1. The initial elements $a$ and $b$ satisfy $r(a, b)$. 2. For every element $a \in xs$ and any $c, c' \in \beta$, if $r(c, c')$ holds, then $r(f(c, a), g(c', a))$ also holds. Then the relation $r$ holds between the results of the left fold operations: $$r\left(\text{foldl}\ f\ a\ xs,\ \text{foldl}\ g\ b\ xs\right)$$
Array.foldr_rel theorem
{xs : Array α} {f g : α → β → β} {a b : β} {r : β → β → Prop} (h : r a b) (h' : ∀ (a : α), a ∈ xs → ∀ (c c' : β), r c c' → r (f a c) (g a c')) : r (xs.foldr (fun a acc => f a acc) a) (xs.foldr (fun a acc => g a acc) b)
Full source
/--
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 {xs : Array α} {f g : α → β → β} {a b : β} {r : β → β → Prop}
    (h : r a b) (h' : ∀ (a : α), a ∈ xs → ∀ (c c' : β), r c c' → r (f a c) (g a c')) :
    r (xs.foldr (fun a acc => f a acc) a) (xs.foldr (fun a acc => g a acc) b) := by
  rcases xs with ⟨xs⟩
  simpa using List.foldr_rel h (by simpa using h')
Relation Preservation under Right Folding of Arrays
Informal description
Let $xs$ be an array of elements of type $\alpha$, and let $f, g : \alpha \to \beta \to \beta$ be two functions. Suppose $a, b \in \beta$ are related by a relation $r$ (i.e., $r(a, b)$ holds), and for every element $a \in xs$ and any $c, c' \in \beta$ such that $r(c, c')$ holds, we have $r(f(a, c), g(a, c'))$. Then the results of right-folding $xs$ with $f$ starting from $a$ and with $g$ starting from $b$ are also related by $r$.
Array.foldl_add_const theorem
{xs : Array α} {a b : Nat} : xs.foldl (fun x _ => x + a) b = b + a * xs.size
Full source
@[simp] theorem foldl_add_const {xs : Array α} {a b : Nat} :
    xs.foldl (fun x _ => x + a) b = b + a * xs.size := by
  rcases xs with ⟨xs⟩
  simp
Left Fold with Constant Addition: $\text{foldl}\ (\lambda x\ \_. x + a)\ b = b + a \cdot \text{size}(xs)$
Informal description
For any array `xs` of type `α` and natural numbers `a` and `b`, the left fold operation `foldl` with the function `(fun x _ => x + a)` and initial value `b` satisfies: $$xs.\text{foldl}\ (\lambda x\ \_. x + a)\ b = b + a \cdot \text{size}(xs)$$ where $\text{size}(xs)$ is the number of elements in the array `xs`.
Array.foldr_add_const theorem
{xs : Array α} {a b : Nat} : xs.foldr (fun _ x => x + a) b = b + a * xs.size
Full source
@[simp] theorem foldr_add_const {xs : Array α} {a b : Nat} :
    xs.foldr (fun _ x => x + a) b = b + a * xs.size := by
  rcases xs with ⟨xs⟩
  simp
Right Fold with Constant Addition: $foldr (\_ \ x \Rightarrow x + a) \ b \ xs = b + a \cdot size(xs)$
Informal description
For any array `xs` of type `Array α` and natural numbers `a` and `b`, the right fold of `xs` with the function `(fun _ x => x + a)` starting from `b` equals `b + a * xs.size`.
Array.back?_eq_none_iff theorem
{xs : Array α} : xs.back? = none ↔ xs = #[]
Full source
@[simp] theorem back?_eq_none_iff {xs : Array α} : xs.back? = none ↔ xs = #[] := by
  simp only [back?_eq_getElem?, ← size_eq_zero_iff]
  simp only [_root_.getElem?_eq_none_iff]
  omega
Empty Array Characterization via Last Element: $xs.back? = none \leftrightarrow xs = \#[]$
Informal description
For any array `xs` of type `Array α`, the optional last element `xs.back?` is `none` if and only if `xs` is the empty array `#[]`.
Array.back?_eq_some_iff theorem
{xs : Array α} {a : α} : xs.back? = some a ↔ ∃ ys : Array α, xs = ys.push a
Full source
theorem back?_eq_some_iff {xs : Array α} {a : α} :
    xs.back? = some a ↔ ∃ ys : Array α, xs = ys.push a := by
  rcases xs with ⟨xs⟩
  simp only [List.back?_toArray, List.getLast?_eq_some_iff, toArray_eq, push_toList]
  constructor
  · rintro ⟨ys, rfl⟩
    exact ⟨ys.toArray, by simp⟩
  · rintro ⟨ys, rfl⟩
    exact ⟨ys.toList, by simp⟩
Characterization of Last Element in Array via Append Operation
Informal description
For any array `xs` of type `Array α` and any element `a` of type `α`, the last element of `xs` (accessed via `back?`) is `some a` if and only if there exists an array `ys` such that `xs` is equal to `ys` with `a` appended to it (i.e., `xs = ys.push a`).
Array.back?_isSome theorem
: xs.back?.isSome ↔ xs ≠ #[]
Full source
@[simp] theorem back?_isSome : xs.back?.isSome ↔ xs ≠ #[] := by
  cases xs
  simp
Non-emptiness of Last Element Option in Array ↔ Array is Non-empty
Informal description
For any array `xs` of type `Array α`, the optional last element `xs.back?` is non-empty (i.e., `xs.back?.isSome` is true) if and only if `xs` is not the empty array `#[]`.
Array.mem_of_back? theorem
{xs : Array α} {a : α} (h : xs.back? = some a) : a ∈ xs
Full source
theorem mem_of_back? {xs : Array α} {a : α} (h : xs.back? = some a) : a ∈ xs := by
  obtain ⟨ys, rfl⟩ := back?_eq_some_iff.1 h
  simp
Membership from Last Element: If `back?` returns `some a`, then `a ∈ xs`
Informal description
For any array `xs` of type `Array α` and any element `a` of type `α`, if the last element of `xs` (accessed via `back?`) is `some a`, then `a` is an element of `xs`.
Array.back_append_of_size_pos theorem
{xs ys : Array α} {h₁} (h₂ : 0 < ys.size) : (xs ++ ys).back h₁ = ys.back h₂
Full source
@[simp] theorem back_append_of_size_pos {xs ys : Array α} {h₁} (h₂ : 0 < ys.size) :
    (xs ++ ys).back h₁ = ys.back h₂ := by
  rcases xs with ⟨l⟩
  rcases ys with ⟨l'⟩
  simp only [List.append_toArray, List.back_toArray]
  rw [List.getLast_append_of_ne_nil]
Last Element of Concatenated Arrays with Non-empty Right Operand: $(xs ++ ys).\text{back} = ys.\text{back}$ when $ys$ is non-empty
Informal description
For any arrays `xs` and `ys` of type `Array α`, if `ys` is non-empty (i.e., `0 < ys.size`), then the last element of the concatenated array `xs ++ ys` (with proof `h₁` that it is non-empty) is equal to the last element of `ys` (with proof `h₂` that it is non-empty).
Array.back_append theorem
{xs : Array α} (h : 0 < (xs ++ ys).size) : (xs ++ ys).back h = if h' : ys.isEmpty then xs.back (by simp_all) else ys.back (by simp only [isEmpty_iff, eq_empty_iff_size_eq_zero] at h'; omega)
Full source
theorem back_append {xs : Array α} (h : 0 < (xs ++ ys).size) :
    (xs ++ ys).back h =
      if h' : ys.isEmpty then
        xs.back (by simp_all)
      else
        ys.back (by simp only [isEmpty_iff, eq_empty_iff_size_eq_zero] at h'; omega) := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp only [List.append_toArray, List.back_toArray, List.getLast_append, List.isEmpty_iff,
    List.isEmpty_toArray]
  split
  · rw [dif_pos]
    simpa only [List.isEmpty_toArray]
  · rw [dif_neg]
    simpa only [List.isEmpty_toArray]
Last Element of Concatenated Arrays: $(xs +\!\!+ ys).\text{back} = \text{if } ys.\text{isEmpty} \text{ then } xs.\text{back} \text{ else } ys.\text{back}$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, if the concatenated array $xs +\!\!+ ys$ is non-empty (i.e., $0 < \text{size}(xs +\!\!+ ys)$), then the last element of $xs +\!\!+ ys$ is equal to: - The last element of $xs$ if $ys$ is empty ($\text{isEmpty}(ys)$ holds) - The last element of $ys$ otherwise
Array.back_append_right theorem
{xs ys : Array α} (h : 0 < ys.size) : (xs ++ ys).back (by simp; omega) = ys.back h
Full source
theorem back_append_right {xs ys : Array α} (h : 0 < ys.size) :
    (xs ++ ys).back (by simp; omega) = ys.back h := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp only [List.append_toArray, List.back_toArray]
  rw [List.getLast_append_right]
Last Element of Concatenated Arrays with Non-empty Right Operand: $(xs +\!\!+ ys).\text{back} = ys.\text{back}$
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, if $ys$ is non-empty (i.e., $0 < \text{size}(ys)$), then the last element of the concatenated array $xs +\!\!+ ys$ is equal to the last element of $ys$.
Array.back_append_left theorem
{xs ys : Array α} (w : 0 < (xs ++ ys).size) (h : ys.size = 0) : (xs ++ ys).back w = xs.back (by simp_all)
Full source
theorem back_append_left {xs ys : Array α} (w : 0 < (xs ++ ys).size) (h : ys.size = 0) :
    (xs ++ ys).back w = xs.back (by simp_all) := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp only [List.append_toArray, List.back_toArray]
  rw [List.getLast_append_left]
  simpa using h
Last Element of Concatenated Array When Second Array is Empty
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$, if the concatenated array $xs +\!\!+ ys$ is non-empty and $ys$ is empty, then the last element of $xs +\!\!+ ys$ equals the last element of $xs$.
Array.back?_append theorem
{xs ys : Array α} : (xs ++ ys).back? = ys.back?.or xs.back?
Full source
@[simp] theorem back?_append {xs ys : Array α} : (xs ++ ys).back? = ys.back?.or xs.back? := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp only [List.append_toArray, List.back?_toArray]
  rw [List.getLast?_append]
Last Element of Concatenated Array as Option
Informal description
For any arrays `xs` and `ys` of type `Array α`, the last element of the concatenated array `xs ++ ys` (if it exists) is equal to the last element of `ys` if it exists, otherwise it is equal to the last element of `xs` (if it exists). More formally, let `back?` denote the operation that returns the last element of an array as an `Option` (returning `none` if the array is empty). Then: $$(xs \mathbin{+\kern-1.5ex+} ys).\text{back?} = ys.\text{back?}.\text{orElse} xs.\text{back?}$$
Array.back_filter_of_pos theorem
{p : α → Bool} {xs : Array α} (w : 0 < xs.size) (h : p (back xs w) = true) : (filter p xs).back (by simpa using ⟨_, by simp, h⟩) = xs.back w
Full source
theorem back_filter_of_pos {p : α → Bool} {xs : Array α} (w : 0 < xs.size) (h : p (back xs w) = true) :
    (filter p xs).back (by simpa using ⟨_, by simp, h⟩) = xs.back w := by
  rcases xs with ⟨xs⟩
  simp only [List.back_toArray] at h
  simp only [List.size_toArray, List.filter_toArray', List.back_toArray]
  rw [List.getLast_filter_of_pos _ h]
Last Element Preservation in Filtered Array When Predicate Holds for Last Element
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and non-empty array $xs$ of type $\text{Array}\,\alpha$, if the last element of $xs$ satisfies $p$, then the last element of the filtered array $\text{filter}(p, xs)$ is equal to the last element of $xs$.
Array.back_filterMap_of_eq_some theorem
{f : α → Option β} {xs : Array α} {w : 0 < xs.size} {b : β} (h : f (xs.back w) = some b) : (filterMap f xs).back (by simpa using ⟨_, by simp, b, h⟩) = some b
Full source
theorem back_filterMap_of_eq_some {f : α → Option β} {xs : Array α} {w : 0 < xs.size} {b : β} (h : f (xs.back w) = some b) :
    (filterMap f xs).back (by simpa using ⟨_, by simp, b, h⟩) = some b := by
  rcases xs with ⟨xs⟩
  simp only [List.back_toArray] at h
  simp only [List.size_toArray, List.filterMap_toArray', List.back_toArray]
  rw [List.getLast_filterMap_of_eq_some _ h]
Last Element Preservation in FilterMap Operation: $\text{filterMap } f \ xs.\text{back} = \text{some } b$ when $f(xs.\text{back}) = \text{some } b$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any non-empty array $xs$ of type $\text{Array } \alpha$ (with proof $w : 0 < \text{size}(xs)$), if $f$ applied to the last element of $xs$ (denoted $\text{back}(xs, w)$) equals $\text{some } b$ for some $b : \beta$, then the last element of the filtered and mapped array $\text{filterMap } f \ xs$ is equal to $\text{some } b$.
Array.back?_flatMap theorem
{xs : Array α} {f : α → Array β} : (xs.flatMap f).back? = xs.reverse.findSome? fun a => (f a).back?
Full source
theorem back?_flatMap {xs : Array α} {f : α → Array β} :
    (xs.flatMap f).back? = xs.reverse.findSome? fun a => (f a).back? := by
  rcases xs with ⟨xs⟩
  simp [List.getLast?_flatMap]
Last Element of FlatMapped Array via Reverse Search
Informal description
For any array $xs$ of type $\text{Array}\,\alpha$ and any function $f : \alpha \to \text{Array}\,\beta$, the optional last element of the flattened array $\text{flatMap}\,f\,xs$ is equal to the first non-$\text{none}$ result obtained by applying the function $\lambda a \mapsto \text{back?}(f\,a)$ to the elements of $xs$ in reverse order. In other words, $\text{back?}(\text{flatMap}\,f\,xs) = \text{findSome?}\,(\text{reverse}\,xs)\,(\lambda a \mapsto \text{back?}(f\,a))$.
Array.back?_flatten theorem
{xss : Array (Array α)} : (flatten xss).back? = xss.reverse.findSome? fun xs => xs.back?
Full source
theorem back?_flatten {xss : Array (Array α)} :
    (flatten xss).back? = xss.reverse.findSome? fun xs => xs.back? := by
  simp [← flatMap_id, back?_flatMap]
Last Element of Flattened Array via Reverse Search
Informal description
For any array of arrays `xss` of type `Array (Array α)`, the optional last element of the flattened array `flatten xss` is equal to the first non-`none` result obtained by applying the function `fun xs => xs.back?` to the elements of `xss` in reverse order. In other words, $\text{back?}(\text{flatten}\,xss) = \text{findSome?}\,(\text{reverse}\,xss)\,(\lambda xs \mapsto \text{back?}(xs))$.
Array.back?_replicate theorem
{a : α} {n : Nat} : (replicate n a).back? = if n = 0 then none else some a
Full source
theorem back?_replicate {a : α} {n : Nat} :
    (replicate n a).back? = if n = 0 then none else some a := by
  rw [replicate_eq_toArray_replicate]
  simp only [List.back?_toArray, List.getLast?_replicate]
Last Element of Replicated Array: $\text{back?}(\text{replicate}\ n\ a) = \text{if}\ n = 0\ \text{then none else some}\ a$
Informal description
For any element $a$ of type $\alpha$ and any natural number $n$, the last element of the array obtained by replicating $a$ $n$ times (denoted as `replicate n a`) is `none` if $n = 0$ and `some a` otherwise. In other words, the optional last element of a replicated array is: - $\text{none}$ when the array is empty ($n = 0$) - $\text{some}\ a$ when the array is non-empty ($n > 0$)
Array.back?_mkArray abbrev
Full source
@[deprecated back?_replicate (since := "2025-03-18")]
abbrev back?_mkArray := @back?_replicate
Optional Last Element of `mkArray` Array
Informal description
For any array created with `mkArray`, the optional last element operation `back?` returns `none` if the array is empty and `some a` otherwise, where `a` is the last element of the array.
Array.back_replicate theorem
(w : 0 < n) : (replicate n a).back (by simpa using w) = a
Full source
@[simp] theorem back_replicate (w : 0 < n) : (replicate n a).back (by simpa using w) = a := by
  simp [back_eq_getElem]
Last Element of Non-Empty Replicated Array Equals Replicated Value
Informal description
For any element $a$ of type $\alpha$ and any natural number $n > 0$, the last element of the array obtained by replicating $a$ $n$ times is equal to $a$. That is, $\text{back}(\text{replicate}\ n\ a) = a$ when $n > 0$.
Array.back_mkArray abbrev
Full source
@[deprecated back_replicate (since := "2025-03-18")]
abbrev back_mkArray := @back_replicate
Last Element of Non-Empty `mkArray` Array
Informal description
For any array created using `mkArray`, the last element operation `back` (when the array is non-empty) returns the last element of the array.
Array.size_leftpad theorem
{n : Nat} {a : α} {xs : Array α} : (leftpad n a xs).size = max n xs.size
Full source
theorem size_leftpad {n : Nat} {a : α} {xs : Array α} :
    (leftpad n a xs).size = max n xs.size := by simp; omega
Size of Left-Padded Array Equals Maximum of Target Size and Original Size
Informal description
For any natural number $n$, element $a$ of type $\alpha$, and array $xs$ of elements of type $\alpha$, the size of the array obtained by left-padding $xs$ with $a$ to length $n$ is equal to the maximum of $n$ and the size of $xs$. In symbols: $$ \text{size}(\text{leftpad}\ n\ a\ xs) = \max(n, \text{size}(xs)) $$
Array.size_rightpad theorem
{n : Nat} {a : α} {xs : Array α} : (rightpad n a xs).size = max n xs.size
Full source
theorem size_rightpad {n : Nat} {a : α} {xs : Array α} :
    (rightpad n a xs).size = max n xs.size := by simp; omega
Size of Right-Padded Array Equals Maximum of Target Size and Original Size
Informal description
For any natural number $n$, any element $a$ of type $\alpha$, and any array $xs$ of elements of type $\alpha$, the size of the array obtained by right-padding $xs$ with $a$ to length $n$ is equal to the maximum of $n$ and the size of $xs$. In symbols: $$\text{size}(\text{rightpad}\ n\ a\ xs) = \max(n, \text{size}(xs))$$
Array.elem_cons_self theorem
[BEq α] [LawfulBEq α] {xs : Array α} {a : α} : (xs.push a).elem a = true
Full source
theorem elem_cons_self [BEq α] [LawfulBEq α] {xs : Array α} {a : α} : (xs.push a).elem a = true := by simp
Element Membership in Extended Array: $a \in \text{push}(xs, a) \leftrightarrow \text{true}$
Informal description
For any type $\alpha$ with a lawful boolean equality relation (where `==` coincides with `=`), any array `xs` of elements of type $\alpha$, and any element `a` of type $\alpha`, the boolean membership check `elem a (xs.push a)` evaluates to `true`.
Array.contains_eq_any_beq theorem
[BEq α] {xs : Array α} {a : α} : xs.contains a = xs.any (a == ·)
Full source
theorem contains_eq_any_beq [BEq α] {xs : Array α} {a : α} : xs.contains a = xs.any (a == ·) := by
  rcases xs with ⟨xs⟩
  simp [List.contains_eq_any_beq]
Containment Check via Any Operation on Arrays
Informal description
For any type $\alpha$ with a boolean equality relation `BEq`, any array `xs` of elements of type $\alpha$, and any element `a` of type $\alpha$, the boolean result of checking whether `a` is contained in `xs` is equal to applying the `any` operation to `xs` with the predicate `(a == ·)`. In symbols: $\text{contains}\ xs\ a = \text{any}\ (a == ·)\ xs$
Array.contains_iff_exists_mem_beq theorem
[BEq α] {xs : Array α} {a : α} : xs.contains a ↔ ∃ a' ∈ xs, a == a'
Full source
theorem contains_iff_exists_mem_beq [BEq α] {xs : Array α} {a : α} :
    xs.contains a ↔ ∃ a' ∈ xs, a == a' := by
  rcases xs with ⟨xs⟩
  simp [List.contains_iff_exists_mem_beq]
Containment in Array via Boolean Equality: $\text{contains}\ xs\ a \leftrightarrow \exists a' \in xs,\ a == a'$
Informal description
For any type $\alpha$ with a boolean equality relation `==`, and for any array `xs` of elements of type $\alpha$ and any element `a` of type $\alpha$, the boolean containment check `xs.contains a` is true if and only if there exists an element `a'` in `xs` such that `a == a'`. In symbols: $$\text{contains}\ xs\ a \leftrightarrow \exists a' \in xs,\ a == a'$$
Array.contains_iff_mem theorem
[BEq α] [LawfulBEq α] {xs : Array α} {a : α} : xs.contains a ↔ a ∈ xs
Full source
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
    xs.contains a ↔ a ∈ xs := by
  simp
Equivalence of Array Containment and Membership under Lawful Boolean Equality
Informal description
For any type $\alpha$ with a lawful boolean equality relation (where `==` coincides with `=`), and for any array `xs` of elements of type $\alpha$ and any element `a` of type $\alpha$, the boolean containment check `xs.contains a` is true if and only if `a` is an element of `xs`. In symbols: $$\text{contains}(xs, a) \leftrightarrow a \in xs$$
Array.pop_append theorem
{xs ys : Array α} : (xs ++ ys).pop = if ys.isEmpty then xs.pop else xs ++ ys.pop
Full source
theorem pop_append {xs ys : Array α} :
    (xs ++ ys).pop = if ys.isEmpty then xs.pop else xs ++ ys.pop := by
  split <;> simp_all
Popping from Concatenated Arrays: $(xs ++ ys).pop = \text{if } ys = \#[] \text{ then } xs.pop \text{ else } xs ++ ys.pop$
Informal description
For any two arrays `xs` and `ys` of type `Array α`, the result of popping the last element from the concatenated array `xs ++ ys` is equal to: - `xs.pop` if `ys` is empty, or - `xs ++ ys.pop` otherwise. In mathematical notation: $$(xs ++ ys).pop = \begin{cases} xs.pop & \text{if } ys = \#[] \\ xs ++ ys.pop & \text{otherwise} \end{cases}$$
Array.pop_replicate theorem
{n : Nat} {a : α} : (replicate n a).pop = replicate (n - 1) a
Full source
@[simp] theorem pop_replicate {n : Nat} {a : α} : (replicate n a).pop = replicate (n - 1) a := by
  ext <;> simp
Popping a Replicated Array: $\text{pop}(\text{replicate}(n, a)) = \text{replicate}(n - 1, a)$
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the result of removing the last element from an array created by replicating $a$ exactly $n$ times is equal to an array created by replicating $a$ exactly $(n - 1)$ times. That is, $\text{pop}(\text{replicate}(n, a)) = \text{replicate}(n - 1, a)$.
Array.pop_mkArray abbrev
Full source
@[deprecated pop_replicate (since := "2025-03-18")]
abbrev pop_mkArray := @pop_replicate
Popping a `mkArray`: $\text{pop}(\text{mkArray}(n, a)) = \text{mkArray}(n - 1, a)$
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the result of removing the last element from an array created by `mkArray n a` (an array of size $n$ filled with $a$) is equal to an array created by `mkArray (n - 1) a$. That is, $\text{pop}(\text{mkArray}(n, a)) = \text{mkArray}(n - 1, a)$.
Array.size_modify theorem
{xs : Array α} {i : Nat} {f : α → α} : (xs.modify i f).size = xs.size
Full source
@[simp] theorem size_modify {xs : Array α} {i : Nat} {f : α → α} : (xs.modify i f).size = xs.size := by
  unfold modify modifyM Id.run
  split <;> simp
Size Preservation under Array Modification
Informal description
For any array `xs` of type `Array α`, natural number index `i`, and function `f : α → α`, the size of the array remains unchanged after modification, i.e., `(xs.modify i f).size = xs.size`.
Array.getElem_modify theorem
{xs : Array α} {j i} (h : i < (xs.modify j f).size) : (xs.modify j f)[i] = if j = i then f (xs[i]'(by simpa using h)) else xs[i]'(by simpa using h)
Full source
theorem getElem_modify {xs : Array α} {j i} (h : i < (xs.modify j f).size) :
    (xs.modify j f)[i] = if j = i then f (xs[i]'(by simpa using h)) else xs[i]'(by simpa using h) := by
  simp only [modify, modifyM, Id.run, Id.pure_eq]
  split
  · simp only [Id.bind_eq, getElem_set]; split <;> simp [*]
  · rw [if_neg (mt (by rintro rfl; exact h) (by simp_all))]
Array Element Access After Modification: $(xs.\text{modify } j \ f)[i] = \text{if } i = j \text{ then } f(xs[i]) \text{ else } xs[i]$
Informal description
For an array `xs` of type `Array α`, indices `i` and `j`, and a function `f : α → α`, if `i` is within the bounds of the modified array `xs.modify j f`, then the element at index `i` in the modified array is equal to `f(xs[i])` if `i = j`, and to `xs[i]` otherwise. That is, $$(xs.\text{modify } j \ f)[i] = \begin{cases} f(xs[i]) & \text{if } i = j \\ xs[i] & \text{otherwise} \end{cases}$$
Array.toList_modify theorem
{xs : Array α} {f : α → α} {i : Nat} : (xs.modify i f).toList = xs.toList.modify i f
Full source
@[simp] theorem toList_modify {xs : Array α} {f : α → α} {i : Nat} :
    (xs.modify i f).toList = xs.toList.modify i f := by
  apply List.ext_getElem
  · simp
  · simp [getElem_modify, List.getElem_modify]
List Conversion Commutes with Array Modification: $\text{toList}(xs.\text{modify } i \ f) = \text{modify } i \ f (xs.\text{toList})$
Informal description
For any array `xs` of type `Array α`, function `f : α → α`, and natural number index `i`, converting the modified array `xs.modify i f` to a list yields the same result as modifying the list `xs.toList` at index `i` with function `f`. That is, $$(xs.\text{modify } i \ f).\text{toList} = (xs.\text{toList}).\text{modify } i \ f$$
Array.getElem_modify_self theorem
{xs : Array α} {i : Nat} (f : α → α) (h : i < (xs.modify i f).size) : (xs.modify i f)[i] = f (xs[i]'(by simpa using h))
Full source
theorem getElem_modify_self {xs : Array α} {i : Nat} (f : α → α) (h : i < (xs.modify i f).size) :
    (xs.modify i f)[i] = f (xs[i]'(by simpa using h)) := by
  simp [getElem_modify h]
Modified Array Element at Modified Index: $(xs.\text{modify } i \ f)[i] = f(xs[i])$
Informal description
For an array `xs` of type `Array α`, index `i`, and function `f : α → α`, if `i` is within the bounds of the modified array `xs.modify i f`, then the element at index `i` in the modified array is equal to `f` applied to the original element `xs[i]`. That is, $$(xs.\text{modify } i \ f)[i] = f(xs[i])$$
Array.getElem_modify_of_ne theorem
{xs : Array α} {i : Nat} (h : i ≠ j) (f : α → α) (hj : j < (xs.modify i f).size) : (xs.modify i f)[j] = xs[j]'(by simpa using hj)
Full source
theorem getElem_modify_of_ne {xs : Array α} {i : Nat} (h : i ≠ j)
    (f : α → α) (hj : j < (xs.modify i f).size) :
    (xs.modify i f)[j] = xs[j]'(by simpa using hj) := by
  simp [getElem_modify hj, h]
Array Element Preservation under Modification at Different Index: $(xs.\text{modify } i \ f)[j] = xs[j]$ when $i \neq j$
Informal description
For any array `xs` of type `Array α`, natural number indices `i` and `j` with `i ≠ j`, and function `f : α → α`, if `j` is within the bounds of the modified array `xs.modify i f`, then the element at index `j` in the modified array is equal to the original element at index `j` in `xs`. That is, $$(xs.\text{modify } i \ f)[j] = xs[j]$$
Array.getElem?_modify theorem
{xs : Array α} {i : Nat} {f : α → α} {j : Nat} : (xs.modify i f)[j]? = if i = j then xs[j]?.map f else xs[j]?
Full source
theorem getElem?_modify {xs : Array α} {i : Nat} {f : α → α} {j : Nat} :
    (xs.modify i f)[j]? = if i = j then xs[j]?.map f else xs[j]? := by
  simp only [getElem?_def, size_modify, getElem_modify, Option.map_dif]
  split <;> split <;> rfl
Optional Array Access After Modification: $(xs.\text{modify } i \ f)[j]? = \text{if } i = j \text{ then } f(xs[j]) \text{ else } xs[j]?$
Informal description
For an array `xs` of type `Array α`, indices `i, j : ℕ`, and a function `f : α → α`, the optional element at index `j` after modifying `xs` at index `i` with `f` is given by: $$(xs.\text{modify } i \ f)[j]? = \begin{cases} f(xs[j]) \text{ (wrapped in `some`)} & \text{if } i = j \\ xs[j]? & \text{otherwise} \end{cases}$$ where `xs[j]?` returns `some xs[j]` if `j` is a valid index and `none` otherwise.
Array.getElem_swap_right theorem
{xs : Array α} {i j : Nat} {hi hj} : (xs.swap i j hi hj)[j]'(by simpa using hj) = xs[i]
Full source
@[simp] theorem getElem_swap_right {xs : Array α} {i j : Nat} {hi hj} :
    (xs.swap i j hi hj)[j]'(by simpa using hj) = xs[i] := by
  simp [swap_def, getElem_set]
Array Element After Swap at Right Index Equals Original Left Element
Informal description
For any array `xs` of type `Array α` and indices `i, j` with proofs `hi : i < xs.size` and `hj : j < xs.size`, the element at index `j` of the array obtained by swapping elements at indices `i` and `j` in `xs` is equal to the original element at index `i` in `xs`. In other words, `(xs.swap i j hi hj)[j] = xs[i]`.
Array.getElem_swap_left theorem
{xs : Array α} {i j : Nat} {hi hj} : (xs.swap i j hi hj)[i]'(by simpa using hi) = xs[j]
Full source
@[simp] theorem getElem_swap_left {xs : Array α} {i j : Nat} {hi hj} :
    (xs.swap i j hi hj)[i]'(by simpa using hi) = xs[j] := by
  simp +contextual [swap_def, getElem_set]
Array Element After Swap at Left Index Equals Original Right Element
Informal description
For any array `xs` of type `Array α` and indices `i, j` with proofs `hi : i < xs.size` and `hj : j < xs.size`, the element at index `i` of the array obtained by swapping elements at indices `i` and `j` in `xs` is equal to the original element at index `j` in `xs`. In other words, $(xs.\text{swap}\ i\ j\ hi\ hj)[i] = xs[j]$.
Array.getElem_swap_of_ne theorem
{xs : Array α} {i j : Nat} {hi hj} (hp : k < xs.size) (hi' : k ≠ i) (hj' : k ≠ j) : (xs.swap i j hi hj)[k]'(xs.size_swap .. |>.symm ▸ hp) = xs[k]
Full source
@[simp] theorem getElem_swap_of_ne {xs : Array α} {i j : Nat} {hi hj} (hp : k < xs.size)
    (hi' : k ≠ i) (hj' : k ≠ j) : (xs.swap i j hi hj)[k]'(xs.size_swap .. |>.symm ▸ hp) = xs[k] := by
  simp [swap_def, getElem_set, hi'.symm, hj'.symm]
Preservation of Array Elements Under Swap at Distinct Indices: $(xs.\text{swap}(i, j))[k] = xs[k]$ for $k \neq i, j$
Informal description
For any array `xs` of type `Array α`, indices `i`, `j`, and `k` with `k < xs.size`, if `k` is distinct from both `i` and `j`, then the element at index `k` in the array obtained by swapping elements at indices `i` and `j` in `xs` is equal to the original element at index `k` in `xs`. That is, $(xs.\text{swap}(i, j))[k] = xs[k]$ when $k \neq i$ and $k \neq j$.
Array.getElem_swap' theorem
{xs : Array α} {i j : Nat} {hi hj} {k : Nat} (hk : k < xs.size) : (xs.swap i j hi hj)[k]'(by simp_all) = if k = i then xs[j] else if k = j then xs[i] else xs[k]
Full source
theorem getElem_swap' {xs : Array α} {i j : Nat} {hi hj} {k : Nat} (hk : k < xs.size) :
    (xs.swap i j hi hj)[k]'(by simp_all) = if k = i then xs[j] else if k = j then xs[i] else xs[k] := by
  split
  · simp_all only [getElem_swap_left]
  · split <;> simp_all
Element Access After Array Swap: $(xs.\text{swap}(i, j))[k] = \text{if } k = i \text{ then } xs[j] \text{ else if } k = j \text{ then } xs[i] \text{ else } xs[k]$
Informal description
For any array $xs$ of type $\alpha$, indices $i$, $j$, and $k$ with $k < \text{size}(xs)$, the element at index $k$ in the array obtained by swapping elements at indices $i$ and $j$ in $xs$ satisfies: $$(xs.\text{swap}(i, j))[k] = \begin{cases} xs[j] & \text{if } k = i \\ xs[i] & \text{if } k = j \\ xs[k] & \text{otherwise} \end{cases}$$
Array.getElem_swap theorem
{xs : Array α} {i j : Nat} (hi hj) {k : Nat} (hk : k < (xs.swap i j hi hj).size) : (xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k]'(by simp_all)
Full source
theorem getElem_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} (hk : k < (xs.swap i j hi hj).size) :
    (xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k]'(by simp_all) := by
  apply getElem_swap'
Element Access After Array Swap: $(xs.\text{swap}(i, j))[k] = \text{if } k = i \text{ then } xs[j] \text{ else if } k = j \text{ then } xs[i] \text{ else } xs[k]$
Informal description
For any array $xs$ of type $\alpha$, indices $i$, $j$, and $k$ with $k < \text{size}(xs.\text{swap}(i, j))$, the element at index $k$ in the array obtained by swapping elements at indices $i$ and $j$ in $xs$ satisfies: $$(xs.\text{swap}(i, j))[k] = \begin{cases} xs[j] & \text{if } k = i \\ xs[i] & \text{if } k = j \\ xs[k] & \text{otherwise} \end{cases}$$
Array.swap_swap theorem
{xs : Array α} {i j : Nat} (hi hj) : (xs.swap i j hi hj).swap i j ((xs.size_swap ..).symm ▸ hi) ((xs.size_swap ..).symm ▸ hj) = xs
Full source
@[simp] theorem swap_swap {xs : Array α} {i j : Nat} (hi hj) :
    (xs.swap i j hi hj).swap i j ((xs.size_swap ..).symm ▸ hi) ((xs.size_swap ..).symm ▸ hj) = xs := by
  apply ext
  · simp only [size_swap]
  · intros
    simp only [getElem_swap]
    split
    · simp_all
    · split <;> simp_all
Double Swap Returns Original Array: $(xs.\text{swap}(i, j)).\text{swap}(i, j) = xs$
Informal description
For any array $xs$ of type $\alpha$ and indices $i$, $j$ with $i < \text{size}(xs)$ and $j < \text{size}(xs)$, swapping elements at positions $i$ and $j$ twice returns the original array: $$(xs.\text{swap}(i, j)).\text{swap}(i, j) = xs$$
Array.swap_comm theorem
{xs : Array α} {i j : Nat} (hi hj) : xs.swap i j hi hj = xs.swap j i hj hi
Full source
theorem swap_comm {xs : Array α} {i j : Nat} (hi hj) : xs.swap i j hi hj = xs.swap j i hj hi := by
  apply ext
  · simp only [size_swap]
  · intros
    simp only [getElem_swap]
    split
    · split <;> simp_all
    · split <;> simp_all
Commutativity of Array Element Swap
Informal description
For any array $xs$ of type $\alpha$ and indices $i, j$ with $i < \text{size}(xs)$ and $j < \text{size}(xs)$, swapping elements at positions $i$ and $j$ is commutative, i.e., $xs.\text{swap}(i, j) = xs.\text{swap}(j, i)$.
Array.size_swapIfInBounds theorem
{xs : Array α} {i j : Nat} : (xs.swapIfInBounds i j).size = xs.size
Full source
@[simp] theorem size_swapIfInBounds {xs : Array α} {i j : Nat} :
    (xs.swapIfInBounds i j).size = xs.size := by unfold swapIfInBounds; split <;> (try split) <;> simp [size_swap]
Size Preservation under Conditional Swap in Arrays
Informal description
For any array `xs` of type `Array α` and any natural numbers `i` and `j`, the size of the array obtained by swapping elements at positions `i` and `j` (if they are within bounds) is equal to the size of the original array `xs`. That is, $\text{size}(\text{swapIfInBounds}\ xs\ i\ j) = \text{size}(xs)$.
Array.size_swap! abbrev
Full source
@[deprecated size_swapIfInBounds (since := "2024-11-24")] abbrev size_swap! := @size_swapIfInBounds
Size Preservation under In-Place Array Swap
Informal description
For any array `xs` of type `Array α` and any valid indices `i` and `j` (i.e., `i < xs.size` and `j < xs.size`), the size of the array after performing an in-place swap operation `swap!` at positions `i` and `j` remains unchanged, i.e., $\text{size}(\text{swap!}\ xs\ i\ j) = \text{size}(xs)$.
Array.swapAt_def theorem
{xs : Array α} {i : Nat} {v : α} (hi) : xs.swapAt i v hi = (xs[i], xs.set i v)
Full source
@[simp] theorem swapAt_def {xs : Array α} {i : Nat} {v : α} (hi) :
    xs.swapAt i v hi = (xs[i], xs.set i v) := rfl
Definition of Array Element Swap Operation: `swapAt i v hi = (xs[i], xs.set i v)`
Informal description
For an array `xs` of type `Array α`, a natural number index `i`, and an element `v` of type `α`, if `i` is a valid index for `xs` (i.e., `i < xs.size`), then the operation `xs.swapAt i v hi` returns a pair consisting of the original element `xs[i]` and the array obtained by setting the `i`-th element of `xs` to `v`.
Array.size_swapAt theorem
{xs : Array α} {i : Nat} {v : α} (hi) : (xs.swapAt i v hi).2.size = xs.size
Full source
theorem size_swapAt {xs : Array α} {i : Nat} {v : α} (hi) :
    (xs.swapAt i v hi).2.size = xs.size := by simp
Size Preservation under Array Element Swap
Informal description
For any array `xs` of type `α`, any index `i`, and any value `v` of type `α`, if `i` is a valid index for `xs` (i.e., `hi : i < xs.size` holds), then the size of the array obtained by swapping the element at index `i` with `v` is equal to the original size of `xs`. In other words, the operation `swapAt` preserves the size of the array.
Array.swapAt!_def theorem
{xs : Array α} {i : Nat} {v : α} (h : i < xs.size) : xs.swapAt! i v = (xs[i], xs.set i v)
Full source
@[simp]
theorem swapAt!_def {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
    xs.swapAt! i v = (xs[i], xs.set i v) := by simp [swapAt!, h]
Definition of Array In-Place Swap Operation: `swapAt! i v = (xs[i], xs.set i v)`
Informal description
For any array `xs` of type `Array α`, any index `i`, and any value `v` of type `α`, if `i` is a valid index for `xs` (i.e., `i < xs.size`), then the operation `xs.swapAt! i v` returns a pair consisting of the original element `xs[i]` and the array obtained by setting the `i`-th element of `xs` to `v`.
Array.size_swapAt! theorem
{xs : Array α} {i : Nat} {v : α} : (xs.swapAt! i v).2.size = xs.size
Full source
@[simp] theorem size_swapAt! {xs : Array α} {i : Nat} {v : α} :
    (xs.swapAt! i v).2.size = xs.size := by
  simp only [swapAt!]
  split
  · simp
  · rfl
Size Preservation under In-Place Array Element Swap
Informal description
For any array `xs` of type `α`, any index `i`, and any value `v` of type `α`, the size of the array obtained by swapping the element at index `i` with `v` (using the in-place `swapAt!` operation) is equal to the original size of `xs`. That is, $(xs.swapAt!\ i\ v).2.size = xs.size$.
Array.size_replace theorem
{xs : Array α} : (xs.replace a b).size = xs.size
Full source
@[simp] theorem size_replace {xs : Array α} : (xs.replace a b).size = xs.size := by
  simp only [replace]
  split <;> simp
Size Preservation under Array Replacement
Informal description
For any array `xs` of elements of type `α`, and for any elements `a` and `b` of type `α`, the size of the array obtained by replacing all occurrences of `a` with `b` in `xs` is equal to the size of `xs`. That is, $(xs.replace\ a\ b).size = xs.size$.
Array.replace_of_not_mem theorem
{xs : Array α} (h : ¬a ∈ xs) : xs.replace a b = xs
Full source
@[simp] theorem replace_of_not_mem {xs : Array α} (h : ¬ a ∈ xs) : xs.replace a b = xs := by
  cases xs
  simp_all
Invariance of Array Replacement When Element is Absent
Informal description
For any array `xs` of elements of type `α`, if the element `a` does not belong to `xs`, then replacing `a` with `b` in `xs` leaves the array unchanged, i.e., `xs.replace a b = xs`.
Array.getElem?_replace theorem
{xs : Array α} {i : Nat} : (xs.replace a b)[i]? = if xs[i]? == some a then if a ∈ xs.take i then some a else some b else xs[i]?
Full source
theorem getElem?_replace {xs : Array α} {i : Nat} :
    (xs.replace a b)[i]? = if xs[i]? == some a then if a ∈ xs.take i then some a else some b else xs[i]? := by
  rcases xs with ⟨xs⟩
  simp only [List.replace_toArray, List.getElem?_toArray, List.getElem?_replace, beq_iff_eq,
    take_eq_extract, List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero,
    mem_toArray]
  split <;> rename_i h
  · rw (occs := [2]) [if_pos]
    simpa using h
  · rw [if_neg]
    simpa using h
Optional Lookup After Array Replacement: $(xs.\text{replace}\ a\ b)[i]?$
Informal description
For any array `xs` of elements of type `α`, index `i`, and elements `a` and `b` of type `α`, the optional lookup at index `i` after replacing all occurrences of `a` with `b` in `xs` satisfies: \[ (xs.\text{replace}\ a\ b)[i]? = \begin{cases} \text{some}\ a & \text{if}\ xs[i]? = \text{some}\ a \text{ and } a \in xs.\text{take}\ i, \\ \text{some}\ b & \text{if}\ xs[i]? = \text{some}\ a \text{ and } a \notin xs.\text{take}\ i, \\ xs[i]? & \text{otherwise.} \end{cases} \]
Array.getElem?_replace_of_ne theorem
{xs : Array α} {i : Nat} (h : xs[i]? ≠ some a) : (xs.replace a b)[i]? = xs[i]?
Full source
theorem getElem?_replace_of_ne {xs : Array α} {i : Nat} (h : xs[i]?xs[i]? ≠ some a) :
    (xs.replace a b)[i]? = xs[i]? := by
  simp_all [getElem?_replace]
Invariance of Optional Lookup Under Replacement When Element Differs: $(xs.\text{replace}\ a\ b)[i]? = xs[i]?$ if $xs[i]? \neq \text{some}\ a$
Informal description
For any array `xs` of elements of type `α`, index `i`, and elements `a`, `b` of type `α`, if the optional lookup `xs[i]?` does not equal `some a`, then the optional lookup at index `i` after replacing all occurrences of `a` with `b` in `xs` equals the original optional lookup `xs[i]?`. In other words: \[ (xs.\text{replace}\ a\ b)[i]? = xs[i]? \quad \text{whenever} \quad xs[i]? \neq \text{some}\ a. \]
Array.getElem_replace theorem
{xs : Array α} {i : Nat} (h : i < xs.size) : (xs.replace a b)[i]'(by simpa) = if xs[i] == a then if a ∈ xs.take i then a else b else xs[i]
Full source
theorem getElem_replace {xs : Array α} {i : Nat} (h : i < xs.size) :
    (xs.replace a b)[i]'(by simpa) = if xs[i] == a then if a ∈ xs.take i then a else b else xs[i] := by
  apply Option.some.inj
  rw [← getElem?_eq_getElem, getElem?_replace]
  split <;> split <;> simp_all
Element Replacement in Array at Valid Index: $(xs.\text{replace}\ a\ b)[i]$ when $i < \text{size}(xs)$
Informal description
For any array `xs` of elements of type `α`, index `i` such that $i < \text{size}(xs)$, and elements `a`, `b` of type `α`, the element at index `i` in the array obtained by replacing all occurrences of `a` with `b` in `xs` satisfies: \[ (xs.\text{replace}\ a\ b)[i] = \begin{cases} a & \text{if}\ xs[i] = a \text{ and } a \in xs.\text{take}\ i, \\ b & \text{if}\ xs[i] = a \text{ and } a \notin xs.\text{take}\ i, \\ xs[i] & \text{otherwise.} \end{cases} \]
Array.getElem_replace_of_ne theorem
{xs : Array α} {i : Nat} {h : i < xs.size} (h' : xs[i] ≠ a) : (xs.replace a b)[i]'(by simpa) = xs[i]'(h)
Full source
theorem getElem_replace_of_ne {xs : Array α} {i : Nat} {h : i < xs.size} (h' : xs[i]xs[i] ≠ a) :
    (xs.replace a b)[i]'(by simpa) = xs[i]'(h) := by
  rw [getElem_replace h]
  simp [h']
Invariance of Array Element Under Replacement When Not Equal to Target: $(xs.\text{replace}\ a\ b)[i] = xs[i]$ if $xs[i] \neq a$
Informal description
For any array `xs` of elements of type `α`, index `i` such that $i < \text{size}(xs)$, and elements `a`, `b` of type `α`, if the element at index `i` in `xs` is not equal to `a` (i.e., $xs[i] \neq a$), then the element at index `i` in the array obtained by replacing all occurrences of `a` with `b` in `xs` is equal to the original element $xs[i]$. In other words: \[ (xs.\text{replace}\ a\ b)[i] = xs[i] \quad \text{whenever} \quad xs[i] \neq a. \]
Array.replace_append theorem
{xs ys : Array α} : (xs ++ ys).replace a b = if a ∈ xs then xs.replace a b ++ ys else xs ++ ys.replace a b
Full source
theorem replace_append {xs ys : Array α} :
    (xs ++ ys).replace a b = if a ∈ xs then xs.replace a b ++ ys else xs ++ ys.replace a b := by
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  simp only [List.append_toArray, List.replace_toArray, List.replace_append, mem_toArray]
  split <;> simp
Replacement in Concatenated Arrays: $(xs ++ ys).replace\ a\ b = \text{if } a \in xs \text{ then } xs.replace\ a\ b ++ ys \text{ else } xs ++ ys.replace\ a\ b$
Informal description
For any arrays `xs` and `ys` of type `Array α`, replacing all occurrences of element `a` with `b` in the concatenated array `xs ++ ys` is equivalent to: - If `a` appears in `xs`, then concatenate `xs.replace a b` with `ys` - Otherwise, concatenate `xs` with `ys.replace a b`
Array.replace_append_left theorem
{xs ys : Array α} (h : a ∈ xs) : (xs ++ ys).replace a b = xs.replace a b ++ ys
Full source
theorem replace_append_left {xs ys : Array α} (h : a ∈ xs) :
    (xs ++ ys).replace a b = xs.replace a b ++ ys := by
  simp [replace_append, h]
Replacement in Concatenated Arrays When Element Present in Left Operand: $(xs ++ ys).replace\ a\ b = xs.replace\ a\ b ++ ys$ if $a \in xs$
Informal description
For any arrays `xs` and `ys` of type `Array α`, if an element `a` is present in `xs`, then replacing all occurrences of `a` with `b` in the concatenated array `xs ++ ys` is equivalent to concatenating `xs.replace a b` with `ys`. That is, $(xs ++ ys).replace\ a\ b = xs.replace\ a\ b ++ ys$.
Array.replace_append_right theorem
{xs ys : Array α} (h : ¬a ∈ xs) : (xs ++ ys).replace a b = xs ++ ys.replace a b
Full source
theorem replace_append_right {xs ys : Array α} (h : ¬ a ∈ xs) :
    (xs ++ ys).replace a b = xs ++ ys.replace a b := by
  simp [replace_append, h]
Replacement in Concatenated Arrays when Element Not in First Array: $(xs ++ ys).replace\ a\ b = xs ++ ys.replace\ a\ b$ if $a \notin xs$
Informal description
For any arrays `xs` and `ys` of type `Array α`, if the element `a` does not appear in `xs`, then replacing all occurrences of `a` with `b` in the concatenated array `xs ++ ys` is equivalent to concatenating `xs` with `ys.replace a b`.
Array.replace_extract theorem
{xs : Array α} {i : Nat} : (xs.extract 0 i).replace a b = (xs.replace a b).extract 0 i
Full source
theorem replace_extract {xs : Array α} {i : Nat} :
    (xs.extract 0 i).replace a b = (xs.replace a b).extract 0 i := by
  rcases xs with ⟨xs⟩
  simp [List.replace_take]
Replacement Commutes with Array Extraction: $(\text{extract}\ 0\ i \circ \text{replace}\ a\ b) = (\text{replace}\ a\ b \circ \text{extract}\ 0\ i)$
Informal description
For any array `xs` of type `Array α` and natural number `i`, replacing all occurrences of `a` with `b` in the subarray `xs.extract 0 i` is equivalent to extracting the subarray `0` to `i` from the array obtained by replacing all occurrences of `a` with `b` in `xs`. That is, $$(\text{xs.extract}\ 0\ i).\text{replace}\ a\ b = (\text{xs.replace}\ a\ b).\text{extract}\ 0\ i$$
Array.replace_replicate_self theorem
{a : α} (h : 0 < n) : (replicate n a).replace a b = #[b] ++ replicate (n - 1) a
Full source
@[simp] theorem replace_replicate_self {a : α} (h : 0 < n) :
    (replicate n a).replace a b = #[b] ++ replicate (n - 1) a := by
  cases n <;> simp_all [replicate_succ', replace_append]
Replacement in Replicated Array: $(\text{replicate}\ n\ a).\text{replace}\ a\ b = \#[b] \mathbin{+\kern-1.5ex+} \text{replicate}\ (n-1)\ a$ for $n > 0$
Informal description
For any element $a$ of type $\alpha$ and positive natural number $n > 0$, replacing all occurrences of $a$ with $b$ in an array of $n$ copies of $a$ results in the array $\#[b]$ concatenated with an array of $n-1$ copies of $a$. That is, $$(\text{replicate}\ n\ a).\text{replace}\ a\ b = \#[b] \mathbin{+\kern-1.5ex+} \text{replicate}\ (n-1)\ a$$
Array.replace_mkArray_self abbrev
Full source
@[deprecated replace_replicate_self (since := "2025-03-18")]
abbrev replace_mkArray_self := @replace_replicate_self
Replacement in Uniform Array: $(\text{mkArray}\ n\ a).\text{replace}\ a\ b = \text{mkArray}\ n\ b$
Informal description
For any element $a$ of type $\alpha$ and natural number $n$, replacing all occurrences of $a$ with $b$ in an array of length $n$ filled with $a$ results in an array of length $n$ filled with $b$. That is, $$(\text{mkArray}\ n\ a).\text{replace}\ a\ b = \text{mkArray}\ n\ b$$
Array.replace_replicate_ne theorem
{a b c : α} (h : !b == a) : (replicate n a).replace b c = replicate n a
Full source
@[simp] theorem replace_replicate_ne {a b c : α} (h : !b == a) :
    (replicate n a).replace b c = replicate n a := by
  rw [replace_of_not_mem]
  simp_all
Invariance of Array Replacement Under Inequality: $\text{replicate}\ n\ a.\text{replace}\ b\ c = \text{replicate}\ n\ a$ when $b \neq a$
Informal description
For any elements $a$, $b$, and $c$ of type $\alpha$, if $b$ is not equal to $a$ (i.e., $\neg(b = a)$), then replacing $b$ with $c$ in an array of length $n$ filled with $a$ leaves the array unchanged, i.e., $\text{replicate}\ n\ a.\text{replace}\ b\ c = \text{replicate}\ n\ a$.
Array.replace_mkArray_ne abbrev
Full source
@[deprecated replace_replicate_ne (since := "2025-03-18")]
abbrev replace_mkArray_ne := @replace_replicate_ne
Invariance of Array Replacement Under Inequality: $\text{mkArray}\ n\ a.\text{replace}\ b\ c = \text{mkArray}\ n\ a$ when $b \neq a$
Informal description
For any elements $a$, $b$, and $c$ of type $\alpha$, if $b$ is not equal to $a$ (i.e., $\neg(b = a)$), then replacing $b$ with $c$ in an array of length $n$ filled with $a$ leaves the array unchanged, i.e., $\text{mkArray}\ n\ a.\text{replace}\ b\ c = \text{mkArray}\ n\ a$.
Array.not_any_eq_all_not theorem
{xs : Array α} {p : α → Bool} : (!xs.any p) = xs.all fun a => !p a
Full source
theorem not_any_eq_all_not {xs : Array α} {p : α → Bool} : (!xs.any p) = xs.all fun a => !p a := by
  rcases xs with ⟨xs⟩
  simp [List.not_any_eq_all_not]
De Morgan's Law for Array Quantifiers: $\neg (\exists a \in xs, p\ a) \leftrightarrow (\forall a \in xs, \neg p\ a)$
Informal description
For any array `xs` of type `α` and any predicate `p : α → Bool`, the negation of the existential quantification over `xs` with `p` is equivalent to the universal quantification over `xs` with the negation of `p`. In other words: $$\neg (\text{any}\ p\ xs) = \text{all}\ (\lambda a, \neg p\ a)\ xs$$
Array.not_all_eq_any_not theorem
{xs : Array α} {p : α → Bool} : (!xs.all p) = xs.any fun a => !p a
Full source
theorem not_all_eq_any_not {xs : Array α} {p : α → Bool} : (!xs.all p) = xs.any fun a => !p a := by
  rcases xs with ⟨xs⟩
  simp [List.not_all_eq_any_not]
De Morgan's Law for Array Quantifiers: $\neg(\forall a \in xs, p(a)) \leftrightarrow \exists a \in xs, \neg p(a)$
Informal description
For any array `xs` of type `α` and any predicate `p : α → Bool`, the negation of the `all` operation on `xs` with predicate `p` is equal to the `any` operation on `xs` with the negated predicate `¬p`. In mathematical notation: $$\neg (\text{all}(p, xs)) = \text{any}(\lambda a, \neg p(a), xs)$$
Array.and_any_distrib_left theorem
{xs : Array α} {p : α → Bool} {q : Bool} : (q && xs.any p) = xs.any fun a => q && p a
Full source
theorem and_any_distrib_left {xs : Array α} {p : α → Bool} {q : Bool} :
    (q && xs.any p) = xs.any fun a => q && p a := by
  rcases xs with ⟨xs⟩
  simp [List.and_any_distrib_left]
Left Distributivity of Conjunction over Array Existential Quantifier
Informal description
For any array `xs` of type `α`, any predicate `p : α → Bool`, and any boolean `q`, the following equality holds: $$(q \land \text{any}\ xs\ p) = \text{any}\ xs\ (\lambda a, q \land p\ a)$$ where `any` checks if any element in the array satisfies the given predicate.
Array.and_any_distrib_right theorem
{xs : Array α} {p : α → Bool} {q : Bool} : (xs.any p && q) = xs.any fun a => p a && q
Full source
theorem and_any_distrib_right {xs : Array α} {p : α → Bool} {q : Bool} :
    (xs.any p && q) = xs.any fun a => p a && q := by
  rcases xs with ⟨xs⟩
  simp [List.and_any_distrib_right]
Distributivity of Conjunction over Existential Quantifier for Arrays: $(∃ a ∈ xs, p(a)) ∧ q = ∃ a ∈ xs, (p(a) ∧ q)$
Informal description
For any array `xs` of elements of type `α`, any predicate `p : α → Bool`, and any boolean `q`, the conjunction of `xs.any p` and `q` is equal to the result of applying the `any` operation to the array with the predicate `fun a => p a && q`. In other words, $(∃ a ∈ xs, p(a)) ∧ q = ∃ a ∈ xs, (p(a) ∧ q)$.
Array.or_all_distrib_left theorem
{xs : Array α} {p : α → Bool} {q : Bool} : (q || xs.all p) = xs.all fun a => q || p a
Full source
theorem or_all_distrib_left {xs : Array α} {p : α → Bool} {q : Bool} :
    (q || xs.all p) = xs.all fun a => q || p a := by
  rcases xs with ⟨xs⟩
  simp [List.or_all_distrib_left]
Left Distributivity of OR over Universal Quantifier on Arrays
Informal description
For any array `xs` of elements of type `α`, any predicate `p : α → Bool`, and any boolean value `q`, the following equality holds: $$ q \lor (\forall a \in \text{xs}, p(a)) = \forall a \in \text{xs}, (q \lor p(a)) $$
Array.or_all_distrib_right theorem
{xs : Array α} {p : α → Bool} {q : Bool} : (xs.all p || q) = xs.all fun a => p a || q
Full source
theorem or_all_distrib_right {xs : Array α} {p : α → Bool} {q : Bool} :
    (xs.all p || q) = xs.all fun a => p a || q := by
  rcases xs with ⟨xs⟩
  simp [List.or_all_distrib_right]
Distributivity of Disjunction over Universal Quantification on Arrays
Informal description
For any array `xs` of elements of type `α`, any predicate `p : α → Bool`, and any Boolean value `q`, the disjunction of `xs.all p` and `q` is equal to the result of applying the `all` operation to the array with the predicate `fun a => p a || q`. In mathematical notation: $$(\text{all}(p, xs) \lor q) = \text{all}(\lambda a, p(a) \lor q, xs)$$
Array.any_eq_not_all_not theorem
{xs : Array α} {p : α → Bool} : xs.any p = !xs.all (!p .)
Full source
theorem any_eq_not_all_not {xs : Array α} {p : α → Bool} : xs.any p = !xs.all (!p .) := by
  simp only [not_all_eq_any_not, Bool.not_not]
De Morgan's Law for Array Quantifiers: $\text{any}(p) \leftrightarrow \neg \text{all}(\neg p)$
Informal description
For any array `xs` of elements of type `α` and any predicate `p : α → Bool`, the existential quantification `xs.any p` (whether any element in `xs` satisfies `p`) is equal to the negation of the universal quantification `xs.all (!p .)` (whether all elements in `xs` satisfy the negation of `p`). In mathematical notation: $$\text{any}(p, xs) = \neg \text{all}(\lambda a, \neg p(a), xs)$$
Array.any_map' theorem
{xs : Array α} {p : β → Bool} (w : stop = xs.size) : (xs.map f).any p 0 stop = xs.any (p ∘ f)
Full source
/-- Variant of `any_map` with a side condition for the `stop` argument. -/
@[simp] theorem any_map' {xs : Array α} {p : β → Bool} (w : stop = xs.size):
    (xs.map f).any p 0 stop = xs.any (p ∘ f) := by
  subst w
  rcases xs with ⟨xs⟩
  rw [List.map_toArray]
  simp [List.any_map]
Equivalence of `any` Operation Under Array Mapping with Bounds
Informal description
For any array `xs` of type `α`, any predicate `p : β → Bool`, and any function `f : α → β`, if `stop` is equal to the size of `xs`, then the result of applying the `any` operation to the mapped array `xs.map f` from index `0` to `stop` is equal to applying the `any` operation to `xs` with the composed predicate `p ∘ f`. That is, `(xs.map f).any p 0 stop = xs.any (p ∘ f)`.
Array.all_map' theorem
{xs : Array α} {p : β → Bool} (w : stop = xs.size) : (xs.map f).all p 0 stop = xs.all (p ∘ f)
Full source
/-- Variant of `all_map` with a side condition for the `stop` argument. -/
@[simp] theorem all_map' {xs : Array α} {p : β → Bool} (w : stop = xs.size):
    (xs.map f).all p 0 stop = xs.all (p ∘ f) := by
  subst w
  rcases xs with ⟨xs⟩
  rw [List.map_toArray]
  simp [List.all_map]
Preservation of Universal Quantification under Mapping with Bounds Condition
Informal description
For any array `xs` of elements of type `α`, any predicate `p : β → Bool`, and any natural number `stop` such that `stop = xs.size`, the following equality holds: $$(\text{map } f \text{ } xs).\text{all } p \text{ } 0 \text{ } \text{stop} = xs.\text{all } (p \circ f)$$ Here, $\text{map } f \text{ } xs$ denotes the array obtained by applying function $f$ to each element of $xs$, $\text{all } p \text{ } 0 \text{ } \text{stop}$ checks if predicate $p$ holds for all elements from index $0$ to $\text{stop}-1$, and $p \circ f$ denotes function composition (applying $f$ then $p$).
Array.any_map theorem
{xs : Array α} {p : β → Bool} : (xs.map f).any p = xs.any (p ∘ f)
Full source
theorem any_map {xs : Array α} {p : β → Bool} : (xs.map f).any p = xs.any (p ∘ f) := by
  simp
Equivalence of `any` Operation Under Array Mapping: $(\text{map } f \text{ } xs).\text{any } p = xs.\text{any } (p \circ f)$
Informal description
For any array `xs` of elements of type `α`, any predicate `p : β → Bool`, and any function `f : α → β`, the following equality holds: $$(\text{map } f \text{ } xs).\text{any } p = xs.\text{any } (p \circ f)$$ Here, $\text{map } f \text{ } xs$ denotes the array obtained by applying function $f$ to each element of $xs$, $\text{any } p$ checks if predicate $p$ holds for any element in the array, and $p \circ f$ denotes function composition (applying $f$ then $p$).
Array.all_map theorem
{xs : Array α} {p : β → Bool} : (xs.map f).all p = xs.all (p ∘ f)
Full source
theorem all_map {xs : Array α} {p : β → Bool} : (xs.map f).all p = xs.all (p ∘ f) := by
  simp
Universal Quantification Preservation under Array Mapping: $(xs.\text{map } f).\text{all } p = xs.\text{all } (p \circ f)$
Informal description
For any array $xs$ of elements of type $\alpha$, any predicate $p : \beta \to \text{Bool}$, and any function $f : \alpha \to \beta$, the following equality holds: $$(xs.\text{map } f).\text{all } p = xs.\text{all } (p \circ f)$$ Here, $xs.\text{map } f$ denotes the array obtained by applying $f$ to each element of $xs$, $\text{all } p$ checks if $p$ holds for all elements in the array, and $p \circ f$ denotes the composition of $p$ with $f$.
Array.any_filter' theorem
{xs : Array α} {p q : α → Bool} (w : stop = (xs.filter p).size) : (xs.filter p).any q 0 stop = xs.any fun a => p a && q a
Full source
/-- Variant of `any_filter` with a side condition for the `stop` argument. -/
@[simp] theorem any_filter' {xs : Array α} {p q : α → Bool} (w : stop = (xs.filter p).size) :
    (xs.filter p).any q 0 stop = xs.any fun a => p a && q a := by
  subst w
  rcases xs with ⟨xs⟩
  rw [List.filter_toArray]
  simp [List.any_filter]
Equivalence of Filtered Array `any` Operation with Combined Predicate
Informal description
For any array `xs` of type `α` and predicates `p, q : α → Bool`, if `stop` is equal to the size of the filtered array `xs.filter p`, then the result of applying the `any` operation to the filtered array from index `0` to `stop` with predicate `q` is equal to applying the `any` operation to the original array `xs` with the combined predicate `λ a, p a ∧ q a`. In other words: $$ \text{any}\ q\ (\text{filter}\ p\ xs)\ 0\ stop = \text{any}\ (\lambda a, p a \land q a)\ xs $$
Array.all_filter' theorem
{xs : Array α} {p q : α → Bool} (w : stop = (xs.filter p).size) : (xs.filter p).all q 0 stop = xs.all fun a => !(p a) || q a
Full source
/-- Variant of `all_filter` with a side condition for the `stop` argument. -/
@[simp] theorem all_filter' {xs : Array α} {p q : α → Bool} (w : stop = (xs.filter p).size) :
    (xs.filter p).all q 0 stop = xs.all fun a => !(p a)!(p a) || q a := by
  subst w
  rcases xs with ⟨xs⟩
  rw [List.filter_toArray]
  simp [List.all_filter]
Filtered Array Universal Quantifier with Side Condition: $\text{all}(q, \text{filter}(p, xs)) = \text{all}(\neg p \lor q, xs)$ when $\text{stop} = \text{size}(\text{filter}(p, xs))$
Informal description
For any array `xs` of type `α`, predicates `p, q : α → Bool`, and natural number `stop` such that `stop = size(xs.filter p)`, the following equality holds: $$ \text{all}(q, \text{filter}(p, xs), 0, \text{stop}) = \text{all}(\lambda a, \neg p(a) \lor q(a), xs) $$
Array.any_filter theorem
{xs : Array α} {p q : α → Bool} : (xs.filter p).any q 0 = xs.any fun a => p a && q a
Full source
theorem any_filter {xs : Array α} {p q : α → Bool} :
    (xs.filter p).any q 0 = xs.any fun a => p a && q a := by
  simp
Equivalence of `any` Operation on Filtered Array with Combined Predicate
Informal description
For any array `xs` of elements of type `α` and predicates `p, q : α → Bool`, the result of applying the `any` operation to the filtered array `xs.filter p` with predicate `q` starting from index `0` is equal to applying the `any` operation to the original array `xs` with the combined predicate $\lambda a, p(a) \land q(a)$. In mathematical notation: $$ \text{any}\ q\ (\text{filter}\ p\ xs)\ 0 = \text{any}\ (\lambda a, p(a) \land q(a))\ xs $$
Array.all_filter theorem
{xs : Array α} {p q : α → Bool} : (xs.filter p).all q 0 = xs.all fun a => !(p a) || q a
Full source
theorem all_filter {xs : Array α} {p q : α → Bool} :
    (xs.filter p).all q 0 = xs.all fun a => !(p a)!(p a) || q a := by
  simp
Universal Quantifier over Filtered Array Equivalence: $\text{all}(q, \text{filter}(p, xs)) = \text{all}(\neg p \lor q, xs)$
Informal description
For any array `xs` of type `α` and predicates `p, q : α → Bool`, the following equality holds: $$ \text{all}(q, \text{filter}(p, xs), 0) = \text{all}(\lambda a, \neg p(a) \lor q(a), xs) $$ Here, $\text{all}(q, \text{filter}(p, xs), 0)$ checks if all elements in the filtered array (from index 0 onwards) satisfy `q`, and $\text{all}(\lambda a, \neg p(a) \lor q(a), xs)$ checks if for every element `a` in the original array, either `p(a)` is false or `q(a)` is true.
Array.any_filterMap' theorem
{xs : Array α} {f : α → Option β} {p : β → Bool} (w : stop = (xs.filterMap f).size) : (xs.filterMap f).any p 0 stop = xs.any fun a => match f a with | some b => p b | none => false
Full source
/-- Variant of `any_filterMap` with a side condition for the `stop` argument. -/
@[simp] theorem any_filterMap' {xs : Array α} {f : α → Option β} {p : β → Bool} (w : stop = (xs.filterMap f).size) :
    (xs.filterMap f).any p 0 stop = xs.any fun a => match f a with | some b => p b | none => false := by
  subst w
  rcases xs with ⟨xs⟩
  rw [List.filterMap_toArray]
  simp [List.any_filterMap]
  rfl
Equivalence of `any` Operation Between `filterMap` and Direct Array Traversal with Bounds
Informal description
For an array `xs` of type `α`, a function `f : α → Option β`, a predicate `p : β → Bool`, and a natural number `stop` equal to the size of the array obtained by applying `filterMap f` to `xs`, the following holds: \[ \text{any } p \ (\text{filterMap } f \ xs) \ 0 \ stop = \text{any } (\lambda a, \text{match } f a \text{ with } | \text{some } b \Rightarrow p b | \text{none } \Rightarrow \text{false}) \ xs \] Here, `any p arr i j` checks if any element in the subarray `arr[i..j-1]` satisfies `p`, and `filterMap f` applies `f` to each element of the array and collects all `some` results.
Array.all_filterMap' theorem
{xs : Array α} {f : α → Option β} {p : β → Bool} (w : stop = (xs.filterMap f).size) : (xs.filterMap f).all p 0 stop = xs.all fun a => match f a with | some b => p b | none => true
Full source
/-- Variant of `all_filterMap` with a side condition for the `stop` argument. -/
@[simp] theorem all_filterMap' {xs : Array α} {f : α → Option β} {p : β → Bool} (w : stop = (xs.filterMap f).size) :
    (xs.filterMap f).all p 0 stop = xs.all fun a => match f a with | some b => p b | none => true := by
  subst w
  rcases xs with ⟨xs⟩
  rw [List.filterMap_toArray]
  simp [List.all_filterMap]
  rfl
Universal Quantification over Filtered and Mapped Array with Bounds Condition
Informal description
For an array `xs` of type `Array α`, a function `f : α → Option β`, a predicate `p : β → Bool`, and a natural number `stop` such that `stop = (xs.filterMap f).size`, the following equivalence holds: $$\text{all}(p, \text{filterMap}(f, xs), 0, \text{stop}) = \text{all}\left(\lambda a, \text{match } f(a) \text{ with } | \text{some } b \Rightarrow p(b) | \text{none} \Rightarrow \text{true}, xs\right)$$ In words: checking if all elements in the filtered and mapped array satisfy `p` (from index 0 to `stop`) is equivalent to checking if for every element `a` in the original array, either `f(a)` is `none` or `f(a)` is `some b` and `p(b)` holds.
Array.any_filterMap theorem
{xs : Array α} {f : α → Option β} {p : β → Bool} : (xs.filterMap f).any p 0 = xs.any fun a => match f a with | some b => p b | none => false
Full source
theorem any_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
    (xs.filterMap f).any p 0 = xs.any fun a => match f a with | some b => p b | none => false := by
  simp
Equivalence of `any` Operation Between `filterMap` and Direct Array Traversal
Informal description
For an array `xs` of type `Array α`, a function `f : α → Option β`, and a predicate `p : β → Bool`, the following equivalence holds: \[ \text{any } p \ (\text{filterMap } f \ xs) \ 0 = \text{any } \left(\lambda a, \begin{cases} p b & \text{if } f a = \text{some } b \\ \text{false} & \text{if } f a = \text{none} \end{cases} \right) \ xs \] Here, `any p arr i` checks if any element in the subarray `arr[i..]` satisfies `p`, and `filterMap f` applies `f` to each element of the array and collects all `some` results.
Array.all_filterMap theorem
{xs : Array α} {f : α → Option β} {p : β → Bool} : (xs.filterMap f).all p 0 = xs.all fun a => match f a with | some b => p b | none => true
Full source
theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
    (xs.filterMap f).all p 0 = xs.all fun a => match f a with | some b => p b | none => true := by
  simp
Universal Quantification over Filtered and Mapped Array
Informal description
For an array `xs` of type `Array α`, a function `f : α → Option β`, and a predicate `p : β → Bool`, the following holds: $$\text{all}(p, \text{filterMap}(f, xs), 0) = \text{all}\left(\lambda a, \begin{cases} p(b) & \text{if } f(a) = \text{some } b \\ \text{true} & \text{if } f(a) = \text{none} \end{cases}, xs\right)$$ In words: checking if all elements in the filtered and mapped array satisfy `p` (from index 0 to the end) is equivalent to checking if for every element `a` in the original array, either `f(a)` is `none` or `f(a)` is `some b` and `p(b)` holds.
Array.any_append' theorem
{xs ys : Array α} (w : stop = (xs ++ ys).size) : (xs ++ ys).any f 0 stop = (xs.any f || ys.any f)
Full source
/-- Variant of `any_append` with a side condition for the `stop` argument. -/
@[simp] theorem any_append' {xs ys : Array α} (w : stop = (xs ++ ys).size) :
    (xs ++ ys).any f 0 stop = (xs.any f || ys.any f) := by
  subst w
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  rw [List.append_toArray]
  simp [List.any_append]
Disjunction of `any` Predicate over Concatenated Arrays with Bounds Condition
Informal description
For any arrays `xs` and `ys` of type `α`, and any predicate `f : α → Bool`, if `stop` is equal to the size of the concatenated array `xs ++ ys`, then the result of applying the `any` operation to the concatenated array from index `0` to `stop` is equal to the disjunction of applying `any f` to `xs` and `ys` separately. That is, `(xs ++ ys).any f 0 stop = (xs.any f || ys.any f)`.
Array.all_append' theorem
{xs ys : Array α} (w : stop = (xs ++ ys).size) : (xs ++ ys).all f 0 stop = (xs.all f && ys.all f)
Full source
/-- Variant of `all_append` with a side condition for the `stop` argument. -/
@[simp] theorem all_append' {xs ys : Array α} (w : stop = (xs ++ ys).size) :
    (xs ++ ys).all f 0 stop = (xs.all f && ys.all f) := by
  subst w
  rcases xs with ⟨xs⟩
  rcases ys with ⟨ys⟩
  rw [List.append_toArray]
  simp [List.all_append]
Conjunction of `all` Predicate over Concatenated Arrays with Bounds Condition
Informal description
For any arrays `xs` and `ys` of type `α`, a predicate `f : α → Bool`, and a natural number `stop` such that `stop = size(xs ++ ys)`, the following holds: $$\text{all}(f, \text{append}(xs, ys), 0, \text{stop}) = \text{all}(f, xs) \land \text{all}(f, ys)$$ where $\text{all}(f, a, i, j)$ checks if all elements in array `a` from index `i` to `j` satisfy predicate `f`, and $\text{append}(xs, ys)$ denotes the concatenation of arrays `xs` and `ys`.
Array.any_append theorem
{xs ys : Array α} : (xs ++ ys).any f 0 = (xs.any f || ys.any f)
Full source
theorem any_append {xs ys : Array α} :
    (xs ++ ys).any f 0 = (xs.any f || ys.any f) := by
  simp
Disjunction of `any` Predicate over Concatenated Arrays
Informal description
For any arrays $xs$ and $ys$ of type $\alpha$ and any predicate $f : \alpha \to \text{Bool}$, the `any` operation applied to the concatenated array $xs +\!\!+ ys$ starting from index $0$ is equal to the disjunction of applying `any f` to $xs$ and $ys$ separately. That is: $$ \text{any}(f, xs +\!\!+ ys, 0) = \text{any}(f, xs) \lor \text{any}(f, ys) $$
Array.all_append theorem
{xs ys : Array α} : (xs ++ ys).all f 0 = (xs.all f && ys.all f)
Full source
theorem all_append {xs ys : Array α} :
    (xs ++ ys).all f 0 = (xs.all f && ys.all f) := by
  simp
Conjunction of `all` Predicate over Concatenated Arrays
Informal description
For any arrays $xs$ and $ys$ of elements of type $\alpha$ and any predicate $f : \alpha \to \text{Bool}$, the following holds: $$\text{all}(f, \text{append}(xs, ys), 0) = \text{all}(f, xs) \land \text{all}(f, ys)$$ where $\text{all}(f, a, i)$ checks if all elements in array $a$ from index $i$ to the end satisfy predicate $f$, and $\text{append}(xs, ys)$ denotes the concatenation of arrays $xs$ and $ys$.
Array.anyM_congr theorem
[Monad m] {xs ys : Array α} (w : xs = ys) {p q : α → m Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) : xs.anyM p start₁ stop₁ = ys.anyM q start₂ stop₂
Full source
@[congr] theorem anyM_congr [Monad m]
    {xs ys : Array α} (w : xs = ys) {p q : α → m Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) :
    xs.anyM p start₁ stop₁ = ys.anyM q start₂ stop₂ := by
  have : p = q := by funext a; apply h
  subst this
  subst w
  subst wstart
  subst wstop
  rfl
Congruence of Monadic Any Operation on Arrays
Informal description
Let $m$ be a monad, and let $xs$ and $ys$ be arrays of type $\alpha$ such that $xs = ys$. For predicates $p, q : \alpha \to m \text{Bool}$ satisfying $p(a) = q(a)$ for all $a \in \alpha$, and for start indices $start_1 = start_2$ and stop indices $stop_1 = stop_2$, the monadic any operation satisfies: \[ xs.\text{anyM}~p~start_1~stop_1 = ys.\text{anyM}~q~start_2~stop_2 \]
Array.any_congr theorem
{xs ys : Array α} (w : xs = ys) {p q : α → Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) : xs.any p start₁ stop₁ = ys.any q start₂ stop₂
Full source
@[congr] theorem any_congr
    {xs ys : Array α} (w : xs = ys) {p q : α → Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) :
    xs.any p start₁ stop₁ = ys.any q start₂ stop₂ := by
  unfold any
  apply anyM_congr w h wstart wstop
Congruence of Any Operation on Arrays: $xs.\text{any}~p~start_1~stop_1 = ys.\text{any}~q~start_2~stop_2$ under $xs = ys$, $p = q$, $start_1 = start_2$, and $stop_1 = stop_2$
Informal description
For any arrays $xs$ and $ys$ of type $\alpha$ such that $xs = ys$, and for any predicates $p, q : \alpha \to \text{Bool}$ satisfying $p(a) = q(a)$ for all $a \in \alpha$, and for any start indices $start_1 = start_2$ and stop indices $stop_1 = stop_2$, the any operation satisfies: \[ xs.\text{any}~p~start_1~stop_1 = ys.\text{any}~q~start_2~stop_2 \]
Array.allM_congr theorem
[Monad m] {xs ys : Array α} (w : xs = ys) {p q : α → m Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) : xs.allM p start₁ stop₁ = ys.allM q start₂ stop₂
Full source
@[congr] theorem allM_congr [Monad m]
    {xs ys : Array α} (w : xs = ys) {p q : α → m Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) :
    xs.allM p start₁ stop₁ = ys.allM q start₂ stop₂ := by
  have : p = q := by funext a; apply h
  subst this
  subst w
  subst wstart
  subst wstop
  rfl
Congruence of Monadic All Operation on Arrays: $xs.\text{allM}~p~start_1~stop_1 = ys.\text{allM}~q~start_2~stop_2$ under $xs = ys$, $p = q$, $start_1 = start_2$, and $stop_1 = stop_2$
Informal description
Let $m$ be a monad, and let $xs$ and $ys$ be arrays of type $\alpha$ such that $xs = ys$. For any two monadic predicates $p, q : \alpha \to m \text{Bool}$ satisfying $\forall a, p(a) = q(a)$, and for any start and stop indices with $start_1 = start_2$ and $stop_1 = stop_2$, the monadic all operation on $xs$ with predicate $p$ from $start_1$ to $stop_1$ is equal to the monadic all operation on $ys$ with predicate $q$ from $start_2$ to $stop_2$.
Array.all_congr theorem
{xs ys : Array α} (w : xs = ys) {p q : α → Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) : xs.all p start₁ stop₁ = ys.all q start₂ stop₂
Full source
@[congr] theorem all_congr
    {xs ys : Array α} (w : xs = ys) {p q : α → Bool} (h : ∀ a, p a = q a) (wstart : start₁ = start₂) (wstop : stop₁ = stop₂) :
    xs.all p start₁ stop₁ = ys.all q start₂ stop₂ := by
  unfold all
  apply allM_congr w h wstart wstop
Congruence of All Operation on Arrays: $xs.\text{all}~p~start_1~stop_1 = ys.\text{all}~q~start_2~stop_2$ under $xs = ys$, $p = q$, $start_1 = start_2$, and $stop_1 = stop_2$
Informal description
For any arrays $xs$ and $ys$ of type $\alpha$ such that $xs = ys$, and for any predicates $p, q : \alpha \to \text{Bool}$ satisfying $\forall a, p(a) = q(a)$, and for any start and stop indices with $start_1 = start_2$ and $stop_1 = stop_2$, the all operation on $xs$ with predicate $p$ from $start_1$ to $stop_1$ is equal to the all operation on $ys$ with predicate $q$ from $start_2$ to $stop_2$.
Array.any_flatten' theorem
{xss : Array (Array α)} (w : stop = xss.flatten.size) : xss.flatten.any f 0 stop = xss.any (any · f)
Full source
@[simp] theorem any_flatten' {xss : Array (Array α)} (w : stop = xss.flatten.size) : xss.flatten.any f 0 stop = xss.any (any · f) := by
  subst w
  cases xss using array₂_induction
  simp [Function.comp_def]
Flattened Array `any` Operation Equivalence: $\text{any}\ f\ (\text{flatten}\ xss)\ 0\ \text{stop} = \text{any}\ (\lambda a, \text{any}\ f\ a)\ xss$
Informal description
For any array of arrays `xss` of type `Array (Array α)` and any predicate `f : α → Bool`, if `stop` is equal to the size of the flattened array `xss.flatten`, then the result of applying the `any` operation to the flattened array from index `0` to `stop` is equal to applying the `any` operation to each inner array in `xss` and combining the results. In symbols: $$ \text{any}\ f\ (\text{flatten}\ xss)\ 0\ \text{stop} = \text{any}\ (\lambda a, \text{any}\ f\ a)\ xss $$
Array.all_flatten' theorem
{xss : Array (Array α)} (w : stop = xss.flatten.size) : xss.flatten.all f 0 stop = xss.all (all · f)
Full source
@[simp] theorem all_flatten' {xss : Array (Array α)} (w : stop = xss.flatten.size) : xss.flatten.all f 0 stop = xss.all (all · f) := by
  subst w
  cases xss using array₂_induction
  simp [Function.comp_def]
Flattened Array All Operation Equivalence with Side Condition
Informal description
For any array of arrays `xss` of type `Array (Array α)` and any predicate `f : α → Bool`, if `stop` equals the size of the flattened array `xss.flatten`, then the result of applying the `all` operation to `f` on the flattened array from index `0` to `stop` is equal to applying the `all` operation to each inner array in `xss` with predicate `f`. In mathematical notation: $$\text{all}(f, \text{flatten}(xss), 0, \text{stop}) = \text{all}(\lambda xs. \text{all}(f, xs), xss)$$
Array.any_flatten theorem
{xss : Array (Array α)} : xss.flatten.any f = xss.any (any · f)
Full source
theorem any_flatten {xss : Array (Array α)} : xss.flatten.any f = xss.any (any · f) := by
  simp
Equivalence of `any` Operation for Flattened Arrays
Informal description
For any array of arrays `xss` of type `Array (Array α)` and any predicate `f : α → Bool`, the result of applying the `any` operation to the flattened array `xss.flatten` is equal to applying the `any` operation to each inner array in `xss` with predicate `f`. In symbols: $$ \text{any}\ f\ (\text{flatten}\ xss) = \text{any}\ (\lambda a, \text{any}\ f\ a)\ xss $$
Array.all_flatten theorem
{xss : Array (Array α)} : xss.flatten.all f = xss.all (all · f)
Full source
theorem all_flatten {xss : Array (Array α)} : xss.flatten.all f = xss.all (all · f) := by
  simp
Flattened Array All Operation Equivalence
Informal description
For any array of arrays `xss` of type `Array (Array α)` and any predicate `f : α → Bool`, the result of applying the `all` operation to `f` on the flattened array `xss.flatten` is equal to applying the `all` operation to each inner array in `xss` with predicate `f`. In mathematical notation: $$\text{all}(f, \text{flatten}(xss)) = \text{all}(\lambda xs. \text{all}(f, xs), xss)$$
Array.any_flatMap' theorem
{xs : Array α} {f : α → Array β} {p : β → Bool} (w : stop = (xs.flatMap f).size) : (xs.flatMap f).any p 0 stop = xs.any fun a => (f a).any p
Full source
/-- Variant of `any_flatMap` with a side condition for the `stop` argument. -/
@[simp] theorem any_flatMap' {xs : Array α} {f : α → Array β} {p : β → Bool} (w : stop = (xs.flatMap f).size) :
    (xs.flatMap f).any p 0 stop = xs.any fun a => (f a).any p := by
  subst w
  rcases xs with ⟨xs⟩
  rw [List.flatMap_toArray]
  simp [List.any_flatMap]
Equivalence of `any` Operation for Flat-Mapped Arrays with Bounds
Informal description
For any array `xs` of type `Array α`, any function `f : α → Array β`, and any predicate `p : β → Bool`, if `stop` is equal to the size of the array obtained by flat-mapping `f` over `xs`, then the following equality holds: \[ \text{any } p \text{ } (\text{flatMap } f \text{ } xs) \text{ } 0 \text{ } stop = \text{any } (\lambda a, \text{any } p \text{ } (f \text{ } a)) \text{ } xs \] Here, `any` checks if any element in the specified range satisfies the predicate `p`, and `flatMap` applies `f` to each element of `xs` and concatenates the resulting arrays.
Array.all_flatMap' theorem
{xs : Array α} {f : α → Array β} {p : β → Bool} (w : stop = (xs.flatMap f).size) : (xs.flatMap f).all p 0 stop = xs.all fun a => (f a).all p
Full source
/-- Variant of `all_flatMap` with a side condition for the `stop` argument. -/
@[simp] theorem all_flatMap' {xs : Array α} {f : α → Array β} {p : β → Bool} (w : stop = (xs.flatMap f).size) :
    (xs.flatMap f).all p 0 stop = xs.all fun a => (f a).all p := by
  subst w
  rcases xs with ⟨xs⟩
  rw [List.flatMap_toArray]
  simp [List.all_flatMap]
Equivalence of `all` Operation for Flat-Mapped Arrays with Bounds
Informal description
For any array `xs` of type `Array α`, any function `f : α → Array β`, and any predicate `p : β → Bool`, if `stop` is equal to the size of the array obtained by flat-mapping `f` over `xs`, then the following equality holds: \[ \text{all } p \text{ } (\text{flatMap } f \text{ } xs) \text{ } 0 \text{ } stop = \text{all } (\lambda a, \text{all } p \text{ } (f \text{ } a)) \text{ } xs \] Here, `all` checks if all elements in the specified range satisfy the predicate `p`, and `flatMap` applies `f` to each element of `xs` and concatenates the resulting arrays.
Array.any_flatMap theorem
{xs : Array α} {f : α → Array β} {p : β → Bool} : (xs.flatMap f).any p 0 = xs.any fun a => (f a).any p
Full source
theorem any_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
    (xs.flatMap f).any p 0 = xs.any fun a => (f a).any p := by
  simp
Equivalence of `any` Operation for Flat-Mapped Arrays
Informal description
For any array `xs` of type `Array α`, any function `f : α → Array β`, and any predicate `p : β → Bool`, the following equality holds: \[ \text{any } p \text{ } (\text{flatMap } f \text{ } xs) \text{ } 0 = \text{any } (\lambda a, \text{any } p \text{ } (f \text{ } a)) \text{ } xs \] Here, `any` checks if any element in the array satisfies the predicate `p`, and `flatMap` applies `f` to each element of `xs` and concatenates the resulting arrays.
Array.all_flatMap theorem
{xs : Array α} {f : α → Array β} {p : β → Bool} : (xs.flatMap f).all p 0 = xs.all fun a => (f a).all p
Full source
theorem all_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
    (xs.flatMap f).all p 0 = xs.all fun a => (f a).all p := by
  simp
Equality of All Operation on Flat-Mapped Arrays: $(\text{flatMap}\,f\,xs).\text{all}\,p\,0 = xs.\text{all}\,(\lambda a, (f\,a).\text{all}\,p)$
Informal description
For any array $xs$ of type $\text{Array}\,\alpha$, any function $f : \alpha \to \text{Array}\,\beta$, and any predicate $p : \beta \to \text{Bool}$, the following equality holds: $$(\text{flatMap}\,f\,xs).\text{all}\,p\,0 = xs.\text{all}\,(\lambda a, (f\,a).\text{all}\,p)$$ where $\text{flatMap}\,f\,xs$ concatenates the arrays obtained by applying $f$ to each element of $xs$, and $\text{all}$ checks if all elements in the array (or specified range) satisfy the predicate $p$.
Array.any_reverse' theorem
{xs : Array α} (w : stop = xs.size) : xs.reverse.any f 0 stop = xs.any f
Full source
/-- Variant of `any_reverse` with a side condition for the `stop` argument. -/
@[simp] theorem any_reverse' {xs : Array α} (w : stop = xs.size) : xs.reverse.any f 0 stop = xs.any f := by
  subst w
  rcases xs with ⟨xs⟩
  rw [List.reverse_toArray]
  simp [List.any_reverse]
Equivalence of `any` Operation on Reversed Array with Bounds: $\text{any } f \text{ } (\text{reverse } xs) \text{ } 0 \text{ } \text{stop} = \text{any } f \text{ } xs$ when $\text{stop} = \text{size } xs$
Informal description
For any array `xs` of type `Array α`, if `stop` is equal to the size of `xs`, then the `any` operation on the reversed array `xs.reverse` from index `0` to `stop` with predicate `f` is equal to the `any` operation on `xs` with predicate `f`. That is: \[ \text{any } f \text{ } (\text{reverse } xs) \text{ } 0 \text{ } \text{stop} = \text{any } f \text{ } xs \]
Array.all_reverse' theorem
{xs : Array α} (w : stop = xs.size) : xs.reverse.all f 0 stop = xs.all f
Full source
/-- Variant of `all_reverse` with a side condition for the `stop` argument. -/
@[simp] theorem all_reverse' {xs : Array α} (w : stop = xs.size) : xs.reverse.all f 0 stop = xs.all f := by
  subst w
  rcases xs with ⟨xs⟩
  rw [List.reverse_toArray]
  simp [List.all_reverse]
Equivalence of `all` Operation on Reversed Array with Side Condition
Informal description
For any array `xs` of type `α`, a predicate `f : α → Bool`, and a natural number `stop` such that `stop = xs.size`, the result of applying the `all` operation to the reversed array `xs.reverse` with predicate `f` from index `0` to `stop` is equal to applying the `all` operation to the original array `xs` with predicate `f`. In mathematical notation: $$\text{all}(f, \text{reverse}(xs), 0, \text{stop}) = \text{all}(f, xs)$$
Array.any_reverse theorem
{xs : Array α} : xs.reverse.any f 0 = xs.any f
Full source
theorem any_reverse {xs : Array α} : xs.reverse.any f 0 = xs.any f := by
  simp
Equality of `any` Operation on Reversed Array: $\text{any } f \text{ } (\text{reverse } xs) \text{ } 0 = \text{any } f \text{ } xs$
Informal description
For any array `xs` of type `Array α` and any predicate `f : α → Bool`, the `any` operation applied to the reversed array `xs.reverse` starting from index `0` is equal to the `any` operation applied to the original array `xs`. That is, \[ \text{any } f \text{ } (\text{reverse } xs) \text{ } 0 = \text{any } f \text{ } xs \]
Array.all_reverse theorem
{xs : Array α} : xs.reverse.all f 0 = xs.all f
Full source
theorem all_reverse {xs : Array α} : xs.reverse.all f 0 = xs.all f := by
  simp
Equality of `all` Operation on Reversed Array: $\text{all}(f, \text{reverse}(xs), 0) = \text{all}(f, xs)$
Informal description
For any array `xs` of type `Array α` and any predicate `f : α → Bool`, the `all` operation applied to the reversed array `xs.reverse` starting from index `0` is equal to the `all` operation applied to the original array `xs`. That is, $$\text{all}(f, \text{reverse}(xs), 0) = \text{all}(f, xs)$$
Array.any_replicate theorem
{n : Nat} {a : α} : (replicate n a).any f = if n = 0 then false else f a
Full source
@[simp] theorem any_replicate {n : Nat} {a : α} :
    (replicate n a).any f = if n = 0 then false else f a := by
  induction n <;> simp_all [replicate_succ']
`any` Operation on Replicated Array: $(\text{replicate}\ n\ a).\text{any}\ f = \text{if } n = 0 \text{ then false else } f(a)$
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the `any` operation applied to an array obtained by replicating $a$ $n$ times is equal to `false` if $n = 0$, and equal to $f(a)$ otherwise. That is, $$(\text{replicate}\ n\ a).\text{any}\ f = \begin{cases} \text{false} & \text{if } n = 0 \\ f(a) & \text{otherwise} \end{cases}$$
Array.any_mkArray abbrev
Full source
@[deprecated any_replicate (since := "2025-03-18")]
abbrev any_mkArray := @any_replicate
`any` Operation on Uniformly Initialized Array: $(\mathtt{mkArray}\ n\ a).\mathtt{any}\ f = \mathtt{false}$ if $n=0$, else $f(a)$
Informal description
For any natural number $n$ and any function $f : \alpha \to \mathtt{Bool}$, the `any` operation applied to an array created by `mkArray n a` (an array of size $n$ with each element initialized to $a$) satisfies: $$(\mathtt{mkArray}\ n\ a).\mathtt{any}\ f = \begin{cases} \mathtt{false} & \text{if } n = 0 \\ f(a) & \text{otherwise} \end{cases}$$
Array.all_replicate theorem
{n : Nat} {a : α} : (replicate n a).all f = if n = 0 then true else f a
Full source
@[simp] theorem all_replicate {n : Nat} {a : α} :
    (replicate n a).all f = if n = 0 then true else f a := by
  induction n <;> simp_all +contextual [replicate_succ']
Universal Quantification over Replicated Array: $\text{all}(f, \text{replicate}(n, a)) = \begin{cases} \text{true} & \text{if } n = 0 \\ f(a) & \text{otherwise} \end{cases}$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the predicate `f` holds for all elements of the array `replicate n a` (which contains $n$ copies of $a$) if and only if either $n = 0$ (in which case the array is empty and the condition is vacuously true) or $f(a)$ holds.
Array.all_mkArray abbrev
Full source
@[deprecated all_replicate (since := "2025-03-18")]
abbrev all_mkArray := @all_replicate
Universal Quantification over Initialized Array: $\text{all}(f, \text{mkArray}(n, a)) = \begin{cases} \text{true} & \text{if } n = 0 \\ f(a) & \text{otherwise} \end{cases}$
Informal description
For any natural number $n$ and function $f : \alpha \to \text{Bool}$, the predicate `f` holds for all elements of the array `mkArray n a` (an array of size $n$ where each element is initialized to $a$) if and only if either $n = 0$ (in which case the array is empty and the condition is vacuously true) or $f(a)$ holds.
Array.toListRev definition
(xs : Array α) : List α
Full source
/--
Converts an array to a list that contains the same elements in the opposite order.

This is equivalent to, but more efficient than, `Array.toList ∘ List.reverse`.

Examples:
* `#[1, 2, 3].toListRev = [3, 2, 1]`
* `#["blue", "yellow"].toListRev = ["yellow", "blue"]`
-/
@[inline] def toListRev (xs : Array α) : List α := xs.foldl (fun l t => t :: l) []
Array to reversed list conversion
Informal description
The function converts an array `xs` of type `Array α` to a list containing the same elements in reverse order. This is implemented efficiently by folding the array and prepending each element to an initially empty list.
Array.toListRev_eq theorem
{xs : Array α} : xs.toListRev = xs.toList.reverse
Full source
@[simp] theorem toListRev_eq {xs : Array α} : xs.toListRev = xs.toList.reverse := by
  rw [toListRev, ← foldl_toList, ← List.foldr_reverse, List.foldr_cons_nil]
Equivalence of Array-to-Reversed-List Conversion and List Reversal: $\text{toListRev}(xs) = \text{reverse}(\text{toList}(xs))$
Informal description
For any array `xs` of type `Array α`, the reversed list obtained by converting `xs` to a list and then reversing it is equal to the list obtained by directly converting `xs` to a reversed list. In symbols, $\text{toListRev}(xs) = \text{reverse}(\text{toList}(xs))$.
Array.appendList_nil theorem
{xs : Array α} : xs ++ ([] : List α) = xs
Full source
@[simp] theorem appendList_nil {xs : Array α} : xs ++ ([] : List α) = xs := Array.ext' (by simp)
Right Identity of Array Append with Empty List
Informal description
For any array `xs` of type `Array α`, appending the empty list `[]` to `xs` results in `xs` itself, i.e., `xs ++ [] = xs`.
Array.appendList_cons theorem
{xs : Array α} {a : α} {l : List α} : xs ++ (a :: l) = xs.push a ++ l
Full source
@[simp] theorem appendList_cons {xs : Array α} {a : α} {l : List α} :
    xs ++ (a :: l) = xs.push a ++ l := Array.ext' (by simp)
Array-List Append-Push Relation: $xs \mathbin{+\!\!+} (a :: l) = (xs.\text{push } a) \mathbin{+\!\!+} l$
Informal description
For any array `xs` of type `Array α`, any element `a` of type `α`, and any list `l` of type `List α`, the operation of appending the list `a :: l` to `xs` is equal to first pushing `a` onto `xs` and then appending `l` to the resulting array. In symbols, $xs \mathbin{+\!\!+} (a :: l) = (xs.\text{push } a) \mathbin{+\!\!+} l$.
Array.size_ofFn_go theorem
{n} {f : Fin n → α} {i acc} : (ofFn.go f i acc).size = acc.size + (n - i)
Full source
@[simp] theorem size_ofFn_go {n} {f : Fin n → α} {i acc} :
    (ofFn.go f i acc).size = acc.size + (n - i) := by
  if hin : i < n then
    unfold ofFn.go
    have : 1 + (n - (i + 1)) = n - i :=
      Nat.sub_sub .. ▸ Nat.add_sub_cancel' (Nat.le_sub_of_add_le (Nat.add_comm .. ▸ hin))
    rw [dif_pos hin, size_ofFn_go, size_push, Nat.add_assoc, this]
  else
    have : n - i = 0 := Nat.sub_eq_zero_of_le (Nat.le_of_not_lt hin)
    unfold ofFn.go
    simp [hin, this]
termination_by n - i
Size Formula for Array Construction Helper Function
Informal description
For any natural number $n$, function $f : \text{Fin } n \to \alpha$, index $i$, and accumulator array $\text{acc}$, the size of the array produced by the helper function $\text{ofFn.go}$ satisfies: $$ \text{size}(\text{ofFn.go } f \ i \ \text{acc}) = \text{size}(\text{acc}) + (n - i) $$
Array.size_ofFn theorem
{n : Nat} {f : Fin n → α} : (ofFn f).size = n
Full source
@[simp] theorem size_ofFn {n : Nat} {f : Fin n → α} : (ofFn f).size = n := by simp [ofFn]
Size of Array Constructed from Function Equals Domain Size
Informal description
For any natural number $n$ and any function $f : \text{Fin } n \to \alpha$, the size of the array constructed from $f$ using `ofFn` equals $n$. In other words, $\text{size}(\text{ofFn } f) = n$.
Array.getElem_ofFn_go theorem
{f : Fin n → α} {i} {acc k} (hki : k < n) (hin : i ≤ n) (hi : i = acc.size) (hacc : ∀ j, ∀ hj : j < acc.size, acc[j] = f ⟨j, Nat.lt_of_lt_of_le hj (hi ▸ hin)⟩) : haveI : acc.size + (n - acc.size) = n := Nat.add_sub_cancel' (hi ▸ hin) (ofFn.go f i acc)[k]'(by simp [*]) = f ⟨k, hki⟩
Full source
theorem getElem_ofFn_go {f : Fin n → α} {i} {acc k}
    (hki : k < n) (hin : i ≤ n) (hi : i = acc.size)
    (hacc : ∀ j, ∀ hj : j < acc.size, acc[j] = f ⟨j, Nat.lt_of_lt_of_le hj (hi ▸ hin)⟩) :
    haveI : acc.size + (n - acc.size) = n := Nat.add_sub_cancel' (hi ▸ hin)
    (ofFn.go f i acc)[k]'(by simp [*]) = f ⟨k, hki⟩ := by
  unfold ofFn.go
  if hin : i < n then
    have : 1 + (n - (i + 1)) = n - i :=
      Nat.sub_sub .. ▸ Nat.add_sub_cancel' (Nat.le_sub_of_add_le (Nat.add_comm .. ▸ hin))
    simp only [dif_pos hin]
    rw [getElem_ofFn_go _ hin (by simp [*]) (fun j hj => ?hacc)]
    cases (Nat.lt_or_eq_of_le <| Nat.le_of_lt_succ (by simpa using hj)) with
    | inl hj => simp [getElem_push, hj, hacc j hj]
    | inr hj => simp [getElem_push, *]
  else
    simp [hin, hacc k (Nat.lt_of_lt_of_le hki (Nat.le_of_not_lt (hi ▸ hin)))]
termination_by n - i
Element Access in Array Construction Helper Function: $\text{ofFn.go } f \ i \ \text{acc}[k] = f(k)$
Informal description
Let $f : \text{Fin } n \to \alpha$ be a function, $i$ a natural number, and $\text{acc}$ an array. Suppose the following conditions hold: 1. $k < n$, 2. $i \leq n$, 3. $i = \text{size}(\text{acc})$, 4. For every $j < \text{size}(\text{acc})$, the $j$-th element of $\text{acc}$ equals $f(j)$ (where $j$ is viewed as an element of $\text{Fin } n$ via the inclusion $\text{Nat.lt_of_lt_of_le}$). Then, the $k$-th element of the array constructed by the helper function $\text{ofFn.go}$ applied to $f$, $i$, and $\text{acc}$ equals $f(k)$.
Array.getElem_ofFn theorem
{f : Fin n → α} {i : Nat} (h : i < (ofFn f).size) : (ofFn f)[i] = f ⟨i, size_ofFn (f := f) ▸ h⟩
Full source
@[simp] theorem getElem_ofFn {f : Fin n → α} {i : Nat} (h : i < (ofFn f).size) :
    (ofFn f)[i] = f ⟨i, size_ofFn (f := f) ▸ h⟩ :=
  getElem_ofFn_go _ (by simp) (by simp) nofun
Element Access in Array Construction: $(\text{ofFn } f)[i] = f(i)$ for $i < n$
Informal description
For any natural number $n$, function $f : \text{Fin } n \to \alpha$, and index $i \in \mathbb{N}$ such that $i$ is less than the size of the array $\text{ofFn } f$, the $i$-th element of $\text{ofFn } f$ equals $f(i)$. More precisely, if $i < \text{size}(\text{ofFn } f)$, then $(\text{ofFn } f)[i] = f(\langle i, h\rangle)$ where $h$ is the proof that $i < n$ derived from the size equality $\text{size}(\text{ofFn } f) = n$.
Array.getElem?_ofFn theorem
{f : Fin n → α} {i : Nat} : (ofFn f)[i]? = if h : i < n then some (f ⟨i, h⟩) else none
Full source
theorem getElem?_ofFn {f : Fin n → α} {i : Nat} :
    (ofFn f)[i]? = if h : i < n then some (f ⟨i, h⟩) else none := by
  simp [getElem?_def]
Optional Element Access in Array Construction: $(\text{ofFn } f)[i]? = \text{some } f(i)$ if $i < n$ else $\text{none}$
Informal description
For any natural number $n$, function $f : \text{Fin } n \to \alpha$, and index $i \in \mathbb{N}$, the optional element access operation on the array $\text{ofFn } f$ at index $i$ satisfies: \[ (\text{ofFn } f)[i]? = \begin{cases} \text{some } f(i) & \text{if } i < n, \\ \text{none} & \text{otherwise.} \end{cases} \]
Array.size_range' theorem
{start size step} : (range' start size step).size = size
Full source
@[simp] theorem size_range' {start size step} : (range' start size step).size = size := by
  simp [range']
Size of `range'` Array Equals Input Size
Informal description
For any natural numbers `start`, `size`, and `step`, the size of the array constructed by `range' start size step` is equal to `size`.
Array.toList_range' theorem
{start size step} : (range' start size step).toList = List.range' start size step
Full source
@[simp] theorem toList_range' {start size step} :
     (range' start size step).toList = List.range' start size step := by
  apply List.ext_getElem <;> simp [range']
List Conversion of `range'` Array: `(range' start size step).toList = List.range' start size step`
Informal description
For any natural numbers `start`, `size`, and `step`, converting the array `range' start size step` to a list yields the same result as directly constructing the list `List.range' start size step`. In other words, the list representation of the array `range' start size step` is equal to `List.range' start size step`.
Array.getElem_range' theorem
{start size step : Nat} {i : Nat} (h : i < (Array.range' start size step).size) : (Array.range' start size step)[i] = start + step * i
Full source
@[simp]
theorem getElem_range' {start size step : Nat} {i : Nat}
    (h : i < (Array.range' start size step).size) :
    (Array.range' start size step)[i] = start + step * i := by
  simp [← getElem_toList]
Element Formula for `range'` Array: `(range' start size step)[i] = start + step * i` when `i < size`
Informal description
For any natural numbers `start`, `size`, `step`, and index `i` such that `i < size`, the `i`-th element of the array `Array.range' start size step` is equal to `start + step * i`.
Array.getElem?_range' theorem
{start size step : Nat} {i : Nat} : (Array.range' start size step)[i]? = if i < size then some (start + step * i) else none
Full source
theorem getElem?_range' {start size step : Nat} {i : Nat} :
    (Array.range' start size step)[i]? = if i < size then some (start + step * i) else none := by
  simp [getElem?_def, getElem_range']
Optional Indexing Formula for `range'` Array: $(\text{range' start size step})[i]? = \text{if } i < \text{size then some (start + step * i) else none}$
Informal description
For any natural numbers `start`, `size`, `step`, and index `i`, the optional indexing operation on the array `Array.range' start size step` at position `i` returns `some (start + step * i)` if `i < size`, and `none` otherwise. That is, $$(\text{range' start size step})[i]? = \begin{cases} \text{some }(\text{start} + \text{step} \cdot i) & \text{if } i < \text{size} \\ \text{none} & \text{otherwise.} \end{cases}$$
List.toArray_range' theorem
{start size step : Nat} : (List.range' start size step).toArray = Array.range' start size step
Full source
@[simp] theorem _root_.List.toArray_range' {start size step : Nat} :
    (List.range' start size step).toArray = Array.range' start size step := by
  apply ext'
  simp
List-to-Array Conversion Preserves Range Construction: $(List.range'\, start\, size\, step).toArray = Array.range'\, start\, size\, step$
Informal description
For any natural numbers `start`, `size`, and `step`, converting the list `List.range' start size step` to an array yields the array `Array.range' start size step`. That is, $(List.range'\, start\, size\, step).toArray = Array.range'\, start\, size\, step$.
Array.size_range theorem
{n : Nat} : (range n).size = n
Full source
@[simp] theorem size_range {n : Nat} : (range n).size = n := by
  simp [range]
Size of Range Array Equals Input Parameter
Informal description
For any natural number $n$, the size of the array constructed by `Array.range n` is equal to $n$.
Array.toList_range theorem
{n : Nat} : (range n).toList = List.range n
Full source
@[simp] theorem toList_range {n : Nat} : (range n).toList = List.range n := by
  apply List.ext_getElem <;> simp [range]
Equality of Array-to-List Conversion and List Range Construction: $\text{toList}(\text{range } n) = \text{List.range } n$
Informal description
For any natural number $n$, converting the array `range n` to a list yields the same result as the list `List.range n`.
Array.getElem_range theorem
{n : Nat} {i : Nat} (h : i < (Array.range n).size) : (Array.range n)[i] = i
Full source
@[simp]
theorem getElem_range {n : Nat} {i : Nat} (h : i < (Array.range n).size) : (Array.range n)[i] = i := by
  simp [← getElem_toList]
Element Access in Range Array: $(\text{range } n)[i] = i$ for $i < n$
Informal description
For any natural numbers $n$ and $i$ such that $i$ is less than the size of the array `Array.range n`, the $i$-th element of the array `Array.range n` is equal to $i$.
Array.getElem?_range theorem
{n : Nat} {i : Nat} : (Array.range n)[i]? = if i < n then some i else none
Full source
theorem getElem?_range {n : Nat} {i : Nat} : (Array.range n)[i]? = if i < n then some i else none := by
  simp [getElem?_def, getElem_range]
Optional Indexing in Range Array: $(\text{range } n)[i]? = \text{some } i$ if $i < n$ else $\text{none}$
Informal description
For any natural numbers $n$ and $i$, the optional element access operation on the array `Array.range n` at index $i$ returns `some i` if $i < n$, and `none` otherwise. In symbols: $$(\text{range } n)[i]? = \begin{cases} \text{some } i & \text{if } i < n \\ \text{none} & \text{otherwise} \end{cases}$$
List.toArray_range theorem
{n : Nat} : (List.range n).toArray = Array.range n
Full source
@[simp] theorem _root_.List.toArray_range {n : Nat} : (List.range n).toArray = Array.range n := by
  apply ext'
  simp
Equality of List-to-Array Conversion and Array Range Construction: $\text{toArray}(\text{List.range } n) = \text{Array.range } n$
Informal description
For any natural number $n$, converting the list $\text{List.range } n$ to an array yields the same result as constructing the array $\text{Array.range } n$.
Array.sum_eq_sum_toList theorem
[Add α] [Zero α] {as : Array α} : as.toList.sum = as.sum
Full source
theorem sum_eq_sum_toList [Add α] [Zero α] {as : Array α} : as.toList.sum = as.sum := by
  cases as
  simp [Array.sum, List.sum]
Equality of Sums Between Array and Its List Conversion
Informal description
For any type $\alpha$ equipped with an addition operation and a zero element, and for any array `as` of elements of type $\alpha$, the sum of the elements in the list obtained from converting `as` to a list is equal to the sum of the elements in the array `as$. In symbols: $$ \text{sum}(\text{toList}(as)) = \text{sum}(as) $$
Array.foldl_toList_eq_flatMap theorem
{l : List α} {acc : Array β} {F : Array β → α → Array β} {G : α → List β} (H : ∀ acc a, (F acc a).toList = acc.toList ++ G a) : (l.foldl F acc).toList = acc.toList ++ l.flatMap G
Full source
theorem foldl_toList_eq_flatMap {l : List α} {acc : Array β}
    {F : Array β → α → Array β} {G : α → List β}
    (H : ∀ acc a, (F acc a).toList = acc.toList ++ G a) :
    (l.foldl F acc).toList = acc.toList ++ l.flatMap G := by
  induction l generalizing acc <;> simp [*, List.flatMap]
Equality between Fold of Array and FlatMap of List
Informal description
Let $l$ be a list of elements of type $\alpha$, $\text{acc}$ be an array of elements of type $\beta$, $F : \text{Array } \beta \to \alpha \to \text{Array } \beta$ be a function, and $G : \alpha \to \text{List } \beta$ be a function. If for every array $\text{acc}$ and element $a \in l$, the list representation of $F(\text{acc}, a)$ equals the concatenation of the list representation of $\text{acc}$ with $G(a)$, then the list representation of the left fold of $F$ over $l$ with initial value $\text{acc}$ equals the concatenation of the list representation of $\text{acc}$ with the flat map of $G$ over $l$. In symbols: $$ \text{toList}(\text{foldl } F \ \text{acc} \ l) = \text{toList}(\text{acc}) +\!\!+ \text{flatMap } G \ l $$
Array.foldl_toList_eq_map theorem
{l : List α} {acc : Array β} {G : α → β} : (l.foldl (fun acc a => acc.push (G a)) acc).toList = acc.toList ++ l.map G
Full source
theorem foldl_toList_eq_map {l : List α} {acc : Array β} {G : α → β} :
    (l.foldl (fun acc a => acc.push (G a)) acc).toList = acc.toList ++ l.map G := by
  induction l generalizing acc <;> simp [*]
Equality between Fold of Push Operation and Concatenation of Map
Informal description
For any list $l$ of elements of type $\alpha$, any array $\text{acc}$ of elements of type $\beta$, and any function $G : \alpha \to \beta$, the list representation of the left fold of the operation $\lambda \text{acc} \, a. \text{acc.push}(G a)$ over $l$ with initial value $\text{acc}$ is equal to the concatenation of the list representation of $\text{acc}$ with the list obtained by mapping $G$ over $l$. In symbols: $$ \text{toList}\big(\text{foldl} \, (\lambda \text{acc} \, a. \text{acc.push}(G a)) \, \text{acc} \, l\big) = \text{toList}(\text{acc}) +\!\!+ \text{map} \, G \, l $$
Array.size_uset theorem
{xs : Array α} {v : α} {i : USize} (h : i.toNat < xs.size) : (uset xs i v h).size = xs.size
Full source
theorem size_uset {xs : Array α} {v : α} {i : USize} (h : i.toNat < xs.size) :
    (uset xs i v h).size = xs.size := by
  simp
Array Size Preservation Under Update Operation
Informal description
For any array `xs` of type `Array α`, any element `v` of type `α`, and any index `i` of type `USize` (platform-dependent unsigned integer) such that the natural number representation of `i` is less than the size of `xs`, the size of the array obtained by updating `xs` at index `i` with value `v` is equal to the original size of `xs`. In symbols: Given `xs : Array α`, `v : α`, `i : USize` with `i.toNat < xs.size`, then $$\text{size}(\text{uset } xs \ i \ v \ h) = \text{size}(xs)$$
Array.getD_eq_getD_getElem? theorem
{xs : Array α} {i : Nat} {d : α} : xs.getD i d = xs[i]?.getD d
Full source
@[simp] theorem getD_eq_getD_getElem? {xs : Array α} {i : Nat} {d : α} :
    xs.getD i d = xs[i]?.getD d := by
  simp only [getD]; split <;> simp [getD_getElem?, *]
Equivalence of Array Default Access and Optional Default Access: $\text{getD}\ xs\ i\ d = \text{getD}\ (xs[i]?)\ d$
Informal description
For any array `xs` of type `Array α`, natural number index `i`, and default value `d` of type `α`, the value obtained by `xs.getD i d` is equal to the value obtained by applying the default value operation to the optional access `xs[i]?`. In symbols: $$\text{getD}\ xs\ i\ d = \text{getD}\ (xs[i]?)\ d$$
Array.getElem!_eq_getD theorem
[Inhabited α] {xs : Array α} {i} : xs[i]! = xs.getD i default
Full source
theorem getElem!_eq_getD [Inhabited α] {xs : Array α} {i} : xs[i]! = xs.getD i default := by
  rfl
Equivalence of Panic-Access and Default-Access for Array Elements
Informal description
For any inhabited type $\alpha$, array `xs` of type `Array α`, and index `i`, the element accessed via `xs[i]!` (which panics if out of bounds) is equal to `xs.getD i default`, where `default` is the default value of $\alpha$.
Array.mem_toList theorem
{a : α} {xs : Array α} : a ∈ xs.toList ↔ a ∈ xs
Full source
@[simp] theorem mem_toList {a : α} {xs : Array α} : a ∈ xs.toLista ∈ xs.toList ↔ a ∈ xs := mem_def.symm
Equivalence of Membership in Array and Its List Conversion
Informal description
For any element $a$ of type $\alpha$ and any array `xs` of type `Array α`, the element $a$ is in the list obtained by converting `xs` to a list if and only if $a$ is in the array `xs$.
Array.not_mem_nil theorem
(a : α) : ¬a ∈ #[]
Full source
@[deprecated not_mem_empty (since := "2025-03-25")]
theorem not_mem_nil (a : α) : ¬ a ∈ #[] := nofun
No Element in Empty Array
Informal description
For any element $a$ of type $\alpha$, $a$ is not an element of the empty array `#[]`.
Array.lt_of_getElem theorem
{x : α} {xs : Array α} {i : Nat} {hidx : i < xs.size} (_ : xs[i] = x) : i < xs.size
Full source
theorem lt_of_getElem {x : α} {xs : Array α} {i : Nat} {hidx : i < xs.size} (_ : xs[i] = x) :
    i < xs.size :=
  hidx
Index Validity from Array Access
Informal description
For any array `xs` of type `Array α`, natural number index `i`, and element `x` of type `α`, if `xs[i] = x` (with the implicit assumption that `i < xs.size`), then `i` is indeed less than the size of `xs`.
Array.getElem_fin_eq_getElem_toList theorem
{xs : Array α} {i : Fin xs.size} : xs[i] = xs.toList[i]
Full source
theorem getElem_fin_eq_getElem_toList {xs : Array α} {i : Fin xs.size} : xs[i] = xs.toList[i] := rfl
Equality of Array and List Access via Finite Index
Informal description
For any array `xs` of type `Array α` and any index `i` of type `Fin xs.size` (i.e., a natural number less than the size of `xs`), the element `xs[i]` is equal to the element at position `i` in the list obtained by converting `xs` to a list, i.e., `xs.toList[i]`.
Array.ugetElem_eq_getElem theorem
{xs : Array α} {i : USize} (h : i.toNat < xs.size) : xs[i] = xs[i.toNat]
Full source
@[simp] theorem ugetElem_eq_getElem {xs : Array α} {i : USize} (h : i.toNat < xs.size) :
  xs[i] = xs[i.toNat] := rfl
Equality of Array Access via Word-Sized and Natural Number Indices: $xs[i] = xs[i.toNat]$ when $i.toNat < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α` and any word-sized unsigned integer index `i` such that the natural number conversion of `i` is less than the size of `xs`, the element accessed via `xs[i]` is equal to the element accessed via `xs[i.toNat]`.
Array.getElem?_size_le theorem
{xs : Array α} {i : Nat} (h : xs.size ≤ i) : xs[i]? = none
Full source
theorem getElem?_size_le {xs : Array α} {i : Nat} (h : xs.size ≤ i) : xs[i]? = none := by
  simp [getElem?_neg, h]
Optional Array Access Yields None for Out-of-Bounds Indices: $xs[i]? = \text{none}$ when $i \geq \text{size}(xs)$
Informal description
For any array `xs` of type `Array α` and natural number index `i`, if the size of `xs` is less than or equal to `i`, then the optional access operation `xs[i]?` returns `none`.
Array.getElem_mem_toList theorem
{xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs.toList
Full source
theorem getElem_mem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i]xs[i] ∈ xs.toList := by
  simp only [← getElem_toList, List.getElem_mem]
Array Element Membership in Converted List
Informal description
For any array `xs` of type `Array α` and natural number index `i` such that `i < xs.size`, the element `xs[i]` is contained in the list obtained by converting `xs` to a list, i.e., `xs[i] ∈ xs.toList`.
Array.back!_eq_back? theorem
[Inhabited α] {xs : Array α} : xs.back! = xs.back?.getD default
Full source
theorem back!_eq_back? [Inhabited α] {xs : Array α} : xs.back! = xs.back?.getD default := by
  simp [back!, back?, getElem!_def, Option.getD]; rfl
Equivalence of Array Last Element Operations with Default Fallback
Informal description
For any inhabited type $\alpha$ and any array `xs` of type `Array α`, the last element obtained via the `back!` operation is equal to the last element obtained via the `back?` operation with the default value as fallback, i.e., $\text{xs.back!} = \text{xs.back?.getD default}$.
Array.back?_push theorem
{xs : Array α} {x : α} : (xs.push x).back? = some x
Full source
@[simp] theorem back?_push {xs : Array α} {x : α} : (xs.push x).back? = some x := by
  simp [back?, ← getElem?_toList]
Optional Last Element of Pushed Array Equals Pushed Element
Informal description
For any array `xs` of type `Array α` and any element `x` of type `α`, the optional last element of the array obtained by pushing `x` to `xs` is equal to `some x`. In other words, the last element of `xs.push x` is `x` when accessed via the optional back operation.
Array.back!_push theorem
[Inhabited α] {xs : Array α} {x : α} : (xs.push x).back! = x
Full source
@[simp] theorem back!_push [Inhabited α] {xs : Array α} {x : α} : (xs.push x).back! = x := by
  simp [back!_eq_back?]
Last Element of Pushed Array Equals Pushed Element
Informal description
For any inhabited type $\alpha$, any array `xs` of type `Array α`, and any element `x` of type $\alpha$, the last element of the array obtained by pushing `x` to `xs` is equal to `x$, i.e., $\text{(xs.push x).back!} = x$.
Array.getElem?_push_lt theorem
{xs : Array α} {x : α} {i : Nat} (h : i < xs.size) : (xs.push x)[i]? = some xs[i]
Full source
theorem getElem?_push_lt {xs : Array α} {x : α} {i : Nat} (h : i < xs.size) :
    (xs.push x)[i]? = some xs[i] := by
  rw [getElem?_pos, getElem_push_lt]
Optional Access Preserves Elements Under Push for Valid Indices: $(xs \text{++} [x])[i]? = \text{some}(xs[i])$ when $i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α`, element `x` of type `α`, and natural number index `i` such that `i < xs.size`, the optional access operation on the array `xs.push x` (obtained by appending `x` to `xs`) at index `i` returns `some xs[i]`. In other words, if $i$ is a valid index for `xs`, then $(xs \text{++} [x])[i]? = \text{some}(xs[i])$.
Array.getElem?_push_eq theorem
{xs : Array α} {x : α} : (xs.push x)[xs.size]? = some x
Full source
theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some x := by
  rw [getElem?_pos, getElem_push_eq]
Optional Access at New Size Yields Pushed Element: $(xs \text{ push } x)[\text{size}(xs)]? = \text{some } x$
Informal description
For any array `xs` of type `Array α` and any element `x` of type `α`, the optional access operation `(xs.push x)[xs.size]?` returns `some x`. In other words, when pushing an element `x` to the end of an array `xs`, the optional access at the new size index (which is `xs.size`) yields `some x`.
Array.getElem?_size theorem
{xs : Array α} : xs[xs.size]? = none
Full source
@[simp] theorem getElem?_size {xs : Array α} : xs[xs.size]? = none := by
  simp only [getElem?_def, Nat.lt_irrefl, dite_false]
Optional Access at Array Size Yields None: $xs[\text{size}(xs)]? = \text{none}$
Informal description
For any array `xs` of type `Array α`, the optional access operation `xs[xs.size]?` returns `none`. In other words, attempting to access an array at its size index (which is out of bounds) yields no element.
Array.forIn_toList theorem
[Monad m] {xs : Array α} {b : β} {f : α → β → m (ForInStep β)} : forIn xs.toList b f = forIn xs b f
Full source
@[simp] theorem forIn_toList [Monad m] {xs : Array α} {b : β} {f : α → β → m (ForInStep β)} :
    forIn xs.toList b f = forIn xs b f := by
  cases xs
  simp
Equivalence of Iteration over Array and Its List Conversion
Informal description
Let $m$ be a monad, $\alpha$ and $\beta$ be types, $xs$ be an array of type $\text{Array }\alpha$, $b$ be an element of type $\beta$, and $f$ be a function of type $\alpha \to \beta \to m (\text{ForInStep }\beta)$. Then the iteration over the list obtained by converting $xs$ to a list, with initial state $b$ and step function $f$, is equal to the iteration over the array $xs$ itself with the same initial state and step function. In symbols: \[ \text{forIn } (xs.\text{toList}) \ b \ f = \text{forIn } xs \ b \ f \]
Array.forIn'_toList theorem
[Monad m] {xs : Array α} {b : β} {f : (a : α) → a ∈ xs.toList → β → m (ForInStep β)} : forIn' xs.toList b f = forIn' xs b (fun a m b => f a (mem_toList.mpr m) b)
Full source
@[simp] theorem forIn'_toList [Monad m] {xs : Array α} {b : β} {f : (a : α) → a ∈ xs.toList → β → m (ForInStep β)} :
    forIn' xs.toList b f = forIn' xs b (fun a m b => f a (mem_toList.mpr m) b) := by
  cases xs
  simp
Equivalence of Iteration over Array and Its List Conversion
Informal description
Let $m$ be a monad, $\alpha$ and $\beta$ be types, $xs$ be an array of type $\text{Array }\alpha$, $b$ be an element of type $\beta$, and $f$ be a function of type $\alpha \to \beta \to m (\text{ForInStep }\beta)$. Then the iteration over the list obtained by converting $xs$ to a list, with initial state $b$ and step function $f$, is equal to the iteration over the array $xs$ itself with initial state $b$ and a step function that applies $f$ to each element and its membership proof in the converted list. In symbols: \[ \text{forIn' } (xs.\text{toList}) \ b \ f = \text{forIn' } xs \ b \ \left(\lambda a \ m \ b, f \ a \ (\text{mem\_toList.mpr } m) \ b\right) \]
Array.contains_def theorem
[DecidableEq α] {a : α} {xs : Array α} : xs.contains a ↔ a ∈ xs
Full source
theorem contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a ↔ a ∈ xs := by
  rw [mem_def, contains, ← any_toList, List.any_eq_true]; simp [and_comm]
Equivalence of Array Contains Operation and Membership Relation
Informal description
For any type $\alpha$ with decidable equality, an element $a \in \alpha$, and an array $xs$ of type $\text{Array}\ \alpha$, the boolean result of checking whether $xs$ contains $a$ is equivalent to the proposition that $a$ is an element of $xs$. In symbols: $$ \text{contains}(xs, a) \leftrightarrow a \in xs. $$
Array.instDecidableMemOfDecidableEq instance
[DecidableEq α] (a : α) (xs : Array α) : Decidable (a ∈ xs)
Full source
instance [DecidableEq α] (a : α) (xs : Array α) : Decidable (a ∈ xs) :=
  decidable_of_iff _ contains_def
Decidability of Membership in Arrays with Decidable Equality
Informal description
For any type $\alpha$ with decidable equality, given an element $a \in \alpha$ and an array $xs$ of elements of type $\alpha$, the proposition $a \in xs$ is decidable.
Array.isPrefixOf_toList theorem
[BEq α] {xs ys : Array α} : xs.toList.isPrefixOf ys.toList = xs.isPrefixOf ys
Full source
@[simp] theorem isPrefixOf_toList [BEq α] {xs ys : Array α} :
    xs.toList.isPrefixOf ys.toList = xs.isPrefixOf ys := by
  cases xs
  cases ys
  simp
Equivalence of List and Array Prefix Relations via `toList`
Informal description
For any arrays `xs` and `ys` of type `Array α` with a boolean equality relation `BEq α`, the list obtained by converting `xs` is a prefix of the list obtained by converting `ys` if and only if `xs` is a prefix of `ys` according to the array's prefix relation. In other words, the following equivalence holds: $$\text{toList}(xs).\text{isPrefixOf}(\text{toList}(ys)) = xs.\text{isPrefixOf}(ys).$$
Array.toList_zipWith theorem
{f : α → β → γ} {xs : Array α} {ys : Array β} : (zipWith f xs ys).toList = List.zipWith f xs.toList ys.toList
Full source
@[simp] theorem toList_zipWith {f : α → β → γ} {xs : Array α} {ys : Array β} :
    (zipWith f xs ys).toList = List.zipWith f xs.toList ys.toList := by
  cases xs
  cases ys
  simp
Commutativity of `toList` with `zipWith` for Arrays and Lists
Informal description
For any function $f : \alpha \to \beta \to \gamma$ and arrays $xs : \text{Array } \alpha$, $ys : \text{Array } \beta$, the list obtained by converting the array $\text{zipWith } f \ xs \ ys$ is equal to the list obtained by applying $\text{List.zipWith } f$ to the converted lists $xs.\text{toList}$ and $ys.\text{toList}$. In other words, the following diagram commutes: $$\text{zipWith } f \ xs \ ys \xrightarrow{\text{toList}} \text{List.zipWith } f \ xs.\text{toList} \ ys.\text{toList}$$
Array.toList_zip theorem
{xs : Array α} {ys : Array β} : (zip xs ys).toList = List.zip xs.toList ys.toList
Full source
@[simp] theorem toList_zip {xs : Array α} {ys : Array β} :
    (zip xs ys).toList = List.zip xs.toList ys.toList := by
  simp [zip, toList_zipWith, List.zip]
Commutativity of `toList` with `zip` for Arrays and Lists
Informal description
For any arrays $xs : \text{Array } \alpha$ and $ys : \text{Array } \beta$, the list obtained by converting the array $\text{zip}(xs, ys)$ is equal to the list obtained by applying $\text{List.zip}$ to the converted lists $xs.\text{toList}$ and $ys.\text{toList}$. In other words, the following diagram commutes: $$\text{zip}(xs, ys) \xrightarrow{\text{toList}} \text{List.zip}(xs.\text{toList}, ys.\text{toList})$$
Array.toList_zipWithAll theorem
{f : Option α → Option β → γ} {xs : Array α} {ys : Array β} : (zipWithAll f xs ys).toList = List.zipWithAll f xs.toList ys.toList
Full source
@[simp] theorem toList_zipWithAll {f : Option α → Option β → γ} {xs : Array α} {ys : Array β} :
    (zipWithAll f xs ys).toList = List.zipWithAll f xs.toList ys.toList := by
  cases xs
  cases ys
  simp
Commutativity of `toList` with `zipWithAll` for Arrays and Lists
Informal description
For any function $f : \text{Option } \alpha \to \text{Option } \beta \to \gamma$ and arrays $xs : \text{Array } \alpha$, $ys : \text{Array } \beta$, the list obtained by converting the array $\text{zipWithAll } f \ xs \ ys$ is equal to the list obtained by applying $\text{List.zipWithAll } f$ to the converted lists $xs.\text{toList}$ and $ys.\text{toList}$. In other words, the following diagram commutes: $$\text{zipWithAll } f \ xs \ ys \xrightarrow{\text{toList}} \text{List.zipWithAll } f \ xs.\text{toList} \ ys.\text{toList}$$
Array.size_zipWith theorem
{xs : Array α} {ys : Array β} {f : α → β → γ} : (zipWith f xs ys).size = min xs.size ys.size
Full source
@[simp] theorem size_zipWith {xs : Array α} {ys : Array β} {f : α → β → γ} :
    (zipWith f xs ys).size = min xs.size ys.size := by
  rw [size_eq_length_toList, toList_zipWith, List.length_zipWith]
Size of Zipped Array Equals Minimum of Input Sizes
Informal description
For any arrays $xs$ of type $\alpha$ and $ys$ of type $\beta$, and any function $f : \alpha \to \beta \to \gamma$, the size of the array obtained by applying $\text{zipWith}$ to $f$, $xs$, and $ys$ is equal to the minimum of the sizes of $xs$ and $ys$. That is, $$|\text{zipWith } f \ xs \ ys| = \min(|xs|, |ys|).$$
Array.size_zip theorem
{xs : Array α} {ys : Array β} : (zip xs ys).size = min xs.size ys.size
Full source
@[simp] theorem size_zip {xs : Array α} {ys : Array β} :
    (zip xs ys).size = min xs.size ys.size :=
  size_zipWith
Size of Zipped Array Equals Minimum of Input Sizes
Informal description
For any arrays $xs$ of type $\alpha$ and $ys$ of type $\beta$, the size of the array obtained by applying the `zip` operation to $xs$ and $ys$ is equal to the minimum of the sizes of $xs$ and $ys$. That is, $$|\text{zip } xs \ ys| = \min(|xs|, |ys|).$$
Array.getElem_zipWith theorem
{xs : Array α} {ys : Array β} {f : α → β → γ} {i : Nat} (hi : i < (zipWith f xs ys).size) : (zipWith f xs ys)[i] = f (xs[i]'(by simp at hi; omega)) (ys[i]'(by simp at hi; omega))
Full source
@[simp] theorem getElem_zipWith {xs : Array α} {ys : Array β} {f : α → β → γ} {i : Nat}
    (hi : i < (zipWith f xs ys).size) :
    (zipWith f xs ys)[i] = f (xs[i]'(by simp at hi; omega)) (ys[i]'(by simp at hi; omega)) := by
  cases xs
  cases ys
  simp
Element-wise Application in Zipped Arrays: $(\text{zipWith } f \ xs \ ys)[i] = f(xs[i])(ys[i])$
Informal description
For any arrays $xs$ of type $\alpha$ and $ys$ of type $\beta$, any function $f : \alpha \to \beta \to \gamma$, and any natural number index $i$ such that $i$ is less than the size of the array obtained by applying $\text{zipWith}$ to $f$, $xs$, and $ys$, the element at index $i$ in the resulting array is equal to $f$ applied to the elements at index $i$ in $xs$ and $ys$. That is, $$(\text{zipWith } f \ xs \ ys)[i] = f(xs[i])(ys[i]).$$
Array.findSomeM?_toList theorem
[Monad m] [LawfulMonad m] {p : α → m (Option β)} {xs : Array α} : xs.toList.findSomeM? p = xs.findSomeM? p
Full source
@[simp] theorem findSomeM?_toList [Monad m] [LawfulMonad m] {p : α → m (Option β)} {xs : Array α} :
    xs.toList.findSomeM? p = xs.findSomeM? p := by
  cases xs
  simp
Equivalence of Monadic `findSomeM?` Operation Between Array and List Conversion
Informal description
For any monad `m` that satisfies the monad laws, any predicate `p : α → m (Option β)`, and any array `xs : Array α`, the result of applying the monadic `findSomeM?` operation to the list obtained by converting `xs` to a list is equal to applying `findSomeM?` directly to `xs`. That is, $$\text{findSomeM? } p (\text{toList } xs) = \text{findSomeM? } p\ xs.$$
Array.findM?_toList theorem
[Monad m] [LawfulMonad m] {p : α → m Bool} {xs : Array α} : xs.toList.findM? p = xs.findM? p
Full source
@[simp] theorem findM?_toList [Monad m] [LawfulMonad m] {p : α → m Bool} {xs : Array α} :
    xs.toList.findM? p = xs.findM? p := by
  cases xs
  simp
Equivalence of Monadic Find Operation Between Array and List Conversion
Informal description
For any monad `m` that satisfies the monad laws, any predicate `p : α → m Bool`, and any array `xs : Array α`, the result of applying the monadic find operation `findM?` to the list obtained by converting `xs` to a list is equal to applying `findM?` directly to `xs`. In other words, the following equality holds for monadic find operations on arrays and their list conversions: $$\text{findM? } p (\text{toList } xs) = \text{findM? } p\ xs$$
Array.findSome?_toList theorem
{p : α → Option β} {xs : Array α} : xs.toList.findSome? p = xs.findSome? p
Full source
@[simp] theorem findSome?_toList {p : α → Option β} {xs : Array α} :
    xs.toList.findSome? p = xs.findSome? p := by
  cases xs
  simp
Equivalence of `findSome?` between Array and List Conversion
Informal description
For any predicate `p : α → Option β` and any array `xs : Array α`, the result of applying the `findSome?` operation to the list obtained by converting `xs` to a list is equal to applying `findSome?` directly to `xs`. That is, `xs.toList.findSome? p = xs.findSome? p`.
Array.find?_toList theorem
{p : α → Bool} {xs : Array α} : xs.toList.find? p = xs.find? p
Full source
@[simp] theorem find?_toList {p : α → Bool} {xs : Array α} :
    xs.toList.find? p = xs.find? p := by
  cases xs
  simp
Equivalence of `find?` between Array and List Conversion
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array $xs : \text{Array}\ \alpha$, the result of applying the `find?` operation to the list obtained by converting $xs$ to a list is equal to applying `find?` directly to $xs$. That is, $\text{find?}\ p\ (\text{toList}\ xs) = \text{find?}\ p\ xs$.
Array.finIdxOf?_toList theorem
[BEq α] {a : α} {xs : Array α} : xs.toList.finIdxOf? a = (xs.finIdxOf? a).map (Fin.cast (by simp))
Full source
@[simp] theorem finIdxOf?_toList [BEq α] {a : α} {xs : Array α} :
    xs.toList.finIdxOf? a = (xs.finIdxOf? a).map (Fin.cast (by simp)) := by
  cases xs
  simp
Equivalence of Index Finding between Array and List Conversion with Type Adjustment
Informal description
For any type $\alpha$ with a boolean equality relation `[BEq α]`, any element $a : \alpha$, and any array $xs : \text{Array}\ \alpha$, the result of finding the index of $a$ in the list obtained by converting $xs$ to a list is equal to the result of finding the index of $a$ in $xs$ and then mapping the `Fin.cast` function (which adjusts the index type based on the equality proof derived from the array size). That is, $\text{finIdxOf?}\ a\ (\text{toList}\ xs) = \text{Option.map}\ (\text{Fin.cast}\ \text{(by simp)})\ (\text{finIdxOf?}\ a\ xs)$.
Array.findFinIdx?_toList theorem
{p : α → Bool} {xs : Array α} : xs.toList.findFinIdx? p = (xs.findFinIdx? p).map (Fin.cast (by simp))
Full source
@[simp] theorem findFinIdx?_toList {p : α → Bool} {xs : Array α} :
    xs.toList.findFinIdx? p = (xs.findFinIdx? p).map (Fin.cast (by simp)) := by
  cases xs
  simp
Equivalence of `findFinIdx?` between Array and List Conversion with Finite Index Casting
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array $xs : \text{Array}\ \alpha$, the result of applying the `findFinIdx?` operation to the list obtained by converting $xs$ to a list is equal to the result of applying `findFinIdx?` to $xs$ and then mapping the `Fin.cast` function (with proof term `by simp`) over the result. That is, $\text{findFinIdx?}\ p\ (\text{toList}\ xs) = \text{Option.map}\ (\text{Fin.cast}\ (\text{by simp}))\ (\text{findFinIdx?}\ p\ xs)$.
List.toListRev_toArray theorem
{l : List α} : l.toArray.toListRev = l.reverse
Full source
theorem toListRev_toArray {l : List α} : l.toArray.toListRev = l.reverse := by simp
Reversed List Conversion via Array Equals List Reversal
Informal description
For any list $l$ of elements of type $\alpha$, the reversed list obtained by converting $l$ to an array and then converting that array back to a reversed list is equal to the reverse of $l$. In symbols, $\text{toListRev}(\text{toArray}(l)) = \text{reverse}(l)$.
List.take_toArray theorem
{l : List α} {i : Nat} : l.toArray.take i = (l.take i).toArray
Full source
@[simp] theorem take_toArray {l : List α} {i : Nat} : l.toArray.take i = (l.take i).toArray := by
  apply Array.ext <;> simp
Array Take Operation Commutes with List-to-Array Conversion
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, the array obtained by taking the first $i$ elements of the array conversion of $l$ is equal to the array conversion of the list obtained by taking the first $i$ elements of $l$. That is: \[ \text{toArray}(l).\text{take}\ i = \text{toArray}(l.\text{take}\ i) \]
List.mapM_toArray theorem
[Monad m] [LawfulMonad m] {f : α → m β} {l : List α} : l.toArray.mapM f = List.toArray <$> l.mapM f
Full source
@[simp] theorem mapM_toArray [Monad m] [LawfulMonad m] {f : α → m β} {l : List α} :
    l.toArray.mapM f = List.toArrayList.toArray <$> l.mapM f := by
  simp only [← mapM'_eq_mapM, mapM_eq_foldlM]
  suffices ∀ xs : Array β,
      Array.foldlM (fun acc a => acc.push <$> f a) xs l.toArray = (xs ++ toArray ·) <$> mapM' f l by
    simpa using this #[]
  intro xs
  induction l generalizing xs with
  | nil => simp
  | cons a l ih =>
    simp only [foldlM_toArray] at ih
    rw [size_toArray, mapM'_cons, foldlM_toArray]
    simp [ih]
Monadic Map Commutes with List-to-Array Conversion
Informal description
For any monad `m` that is a lawful monad, any function `f : α → m β`, and any list `l : List α`, the monadic map operation on the array obtained from `l` is equal to the monadic map operation on `l` followed by conversion to an array. That is, $$ \text{mapM}\ f\ (l.\text{toArray}) = \text{toArray} <$> \text{mapM}\ f\ l $$ where `<$>` denotes the functorial map operation.
List.uset_toArray theorem
{l : List α} {i : USize} {a : α} {h : i.toNat < l.toArray.size} : l.toArray.uset i a h = (l.set i.toNat a).toArray
Full source
theorem uset_toArray {l : List α} {i : USize} {a : α} {h : i.toNat < l.toArray.size} :
    l.toArray.uset i a h = (l.set i.toNat a).toArray := by simp
Array Update via List Conversion: $l.\text{toArray}.\text{uset}\ i\ a\ h = (l.\text{set}\ i.\text{toNat}\ a).\text{toArray}$
Informal description
For any list $l$ of elements of type $\alpha$, any word-sized unsigned integer index $i$, any element $a$ of type $\alpha$, and a proof $h$ that the natural number representation of $i$ is less than the size of the array obtained from $l$, the operation of updating the array (converted from $l$) at index $i$ with value $a$ is equal to converting the list obtained by setting the element at position $i.\text{toNat}$ in $l$ to $a$ into an array.
List.modify_toArray theorem
{f : α → α} {l : List α} {i : Nat} : l.toArray.modify i f = (l.modify i f).toArray
Full source
@[simp] theorem modify_toArray {f : α → α} {l : List α} {i : Nat} :
    l.toArray.modify i f = (l.modify i f).toArray := by
  apply ext'
  simp
Array-List Modification Commutativity: $\text{modify}(l.\text{toArray}, i, f) = (l.\text{modify}\ i\ f).\text{toArray}$
Informal description
For any function $f : \alpha \to \alpha$, any list $l$ of elements of type $\alpha$, and any natural number index $i$, modifying the array obtained from $l$ at index $i$ with $f$ is equal to converting the list obtained by modifying $l$ at index $i$ with $f$ back to an array. That is, $$(l.\text{toArray}).\text{modify}\ i\ f = (l.\text{modify}\ i\ f).\text{toArray}$$
List.flatten_toArray theorem
{L : List (List α)} : (L.toArray.map List.toArray).flatten = L.flatten.toArray
Full source
@[simp] theorem flatten_toArray {L : List (List α)} :
    (L.toArray.map List.toArray).flatten = L.flatten.toArray := by
  apply ext'
  simp [Function.comp_def]
Flattening Commutes with Array Conversion and Mapping: $\text{flatten}(L.\text{toArray}.\text{map List.toArray}) = L.\text{flatten}.\text{toArray}$
Informal description
For any list of lists $L$ of elements of type $\alpha$, the flattening of the array obtained by first converting $L$ to an array and then mapping each inner list to an array is equal to the array obtained by first flattening $L$ and then converting to an array. In symbols: $$\text{flatten}(L.\text{toArray}.\text{map List.toArray}) = L.\text{flatten}.\text{toArray}$$
Array.toList_takeWhile theorem
{p : α → Bool} {as : Array α} : (as.takeWhile p).toList = as.toList.takeWhile p
Full source
@[simp] theorem toList_takeWhile {p : α → Bool} {as : Array α} :
    (as.takeWhile p).toList = as.toList.takeWhile p := by
  induction as; simp
Conversion of Array's `takeWhile` to List Preserves `takeWhile` Operation
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any array $\text{as} : \text{Array} \alpha$, the list obtained by converting the array $\text{as.takeWhile} p$ to a list is equal to the list obtained by first converting $\text{as}$ to a list and then applying $\text{takeWhile} p$. In other words, $(\text{as.takeWhile} p).\text{toList} = \text{as.toList.takeWhile} p$.
Array.toList_eraseIdx theorem
{xs : Array α} {i : Nat} {h : i < xs.size} : (xs.eraseIdx i h).toList = xs.toList.eraseIdx i
Full source
@[simp] theorem toList_eraseIdx {xs : Array α} {i : Nat} {h : i < xs.size} :
    (xs.eraseIdx i h).toList = xs.toList.eraseIdx i := by
  induction xs
  simp
List Conversion Commutes with Element Removal at Valid Index
Informal description
For any array `xs` of type `Array α` and any natural number index `i` such that `i < xs.size`, converting the array `xs.eraseIdx i h` to a list yields the same result as first converting `xs` to a list and then removing the element at index `i`. That is, `(xs.eraseIdx i h).toList = xs.toList.eraseIdx i`.
Array.toList_eraseIdxIfInBounds theorem
{xs : Array α} {i : Nat} : (xs.eraseIdxIfInBounds i).toList = xs.toList.eraseIdx i
Full source
@[simp] theorem toList_eraseIdxIfInBounds {xs : Array α} {i : Nat} :
    (xs.eraseIdxIfInBounds i).toList = xs.toList.eraseIdx i := by
  induction xs
  simp
List Conversion Commutes with Bounds-Checked Element Removal
Informal description
For any array `xs` of type `Array α` and any natural number index `i`, converting the array `xs.eraseIdxIfInBounds i` to a list yields the same result as first converting `xs` to a list and then removing the element at index `i`. That is, `(xs.eraseIdxIfInBounds i).toList = xs.toList.eraseIdx i`.
Array.findSomeRevM?_eq_findSomeM?_reverse theorem
[Monad m] [LawfulMonad m] {f : α → m (Option β)} {xs : Array α} : xs.findSomeRevM? f = xs.reverse.findSomeM? f
Full source
@[simp] theorem findSomeRevM?_eq_findSomeM?_reverse
    [Monad m] [LawfulMonad m] {f : α → m (Option β)} {xs : Array α} :
    xs.findSomeRevM? f = xs.reverse.findSomeM? f := by
  cases xs
  rw [List.findSomeRevM?_toArray]
  simp
Reverse Search Equivalence: $\text{findSomeRevM?}\ f\ xs = \text{findSomeM?}\ f\ (\text{reverse}\ xs)$
Informal description
For any monad `m` that satisfies the monad laws, any function `f : α → m (Option β)`, and any array `xs : Array α`, the result of searching `xs` in reverse order using `findSomeRevM?` is equal to searching the reversed array `xs.reverse` using `findSomeM?`. That is, $\text{findSomeRevM?}\ f\ xs = \text{findSomeM?}\ f\ (\text{reverse}\ xs)$.
Array.findRevM?_eq_findM?_reverse theorem
[Monad m] [LawfulMonad m] {f : α → m Bool} {xs : Array α} : xs.findRevM? f = xs.reverse.findM? f
Full source
@[simp] theorem findRevM?_eq_findM?_reverse
    [Monad m] [LawfulMonad m] {f : α → m Bool} {xs : Array α} :
    xs.findRevM? f = xs.reverse.findM? f := by
  cases xs
  rw [List.findRevM?_toArray]
  simp
Reverse Search Equals Search on Reversed Array: $\text{findRevM?}\ f\ xs = \text{findM?}\ f\ (\text{reverse}\ xs)$
Informal description
For any monad `m` that satisfies the monad laws, any predicate function `f : α → m Bool`, and any array `xs : Array α`, the reverse search operation `xs.findRevM? f` is equal to the search operation applied to the reversed array `xs.reverse.findM? f`.
Array.findSomeRev?_eq_findSome?_reverse theorem
{f : α → Option β} {xs : Array α} : xs.findSomeRev? f = xs.reverse.findSome? f
Full source
@[simp] theorem findSomeRev?_eq_findSome?_reverse {f : α → Option β} {xs : Array α} :
    xs.findSomeRev? f = xs.reverse.findSome? f := by
  cases xs
  simp [findSomeRev?, Id.run]
Reverse Search Equals Search on Reversed Array: $\text{findSomeRev?}\ f\ xs = \text{findSome?}\ f\ (\text{reverse}\ xs)$
Informal description
For any function $f : \alpha \to \text{Option }\beta$ and any array $xs : \text{Array }\alpha$, the reverse search operation $\text{findSomeRev?}\ f\ xs$ is equal to the search operation applied to the reversed array $\text{findSome?}\ f\ (\text{reverse}\ xs)$. That is, $\text{findSomeRev?}\ f\ xs = \text{findSome?}\ f\ (\text{reverse}\ xs)$.
Array.findRev?_eq_find?_reverse theorem
{f : α → Bool} {xs : Array α} : xs.findRev? f = xs.reverse.find? f
Full source
@[simp] theorem findRev?_eq_find?_reverse {f : α → Bool} {xs : Array α} :
    xs.findRev? f = xs.reverse.find? f := by
  cases xs
  simp [findRev?, Id.run]
Reverse Search Equals Search on Reversed Array: $\text{findRev?}\ f\ xs = \text{find?}\ f\ (\text{reverse}\ xs)$
Informal description
For any predicate function $f : \alpha \to \text{Bool}$ and any array $xs : \text{Array}\ \alpha$, the reverse search operation $\text{findRev?}\ f\ xs$ is equal to the search operation applied to the reversed array $\text{find?}\ f\ (\text{reverse}\ xs)$.
Array.fst_unzip theorem
{xs : Array (α × β)} : (Array.unzip xs).fst = xs.map Prod.fst
Full source
@[simp] theorem fst_unzip {xs : Array (α × β)} : (Array.unzip xs).fst = xs.map Prod.fst := by
  simp only [unzip]
  rcases xs with ⟨xs⟩
  simp only [List.foldl_toArray']
  rw [← List.foldl_hom (f := Prod.fst) (g₂ := fun bs x => bs.push x.1) (H := by simp), ← List.foldl_map]
  simp
First Component of Unzipped Array Equals Map of First Projection
Informal description
For any array `xs` of pairs of type $(\alpha \times \beta)$, the first component of the pair obtained by unzipping `xs` is equal to the array obtained by mapping the first projection function over `xs`. That is, $(\text{unzip } xs).1 = \text{map } \pi_1\ xs$.
Array.snd_unzip theorem
{xs : Array (α × β)} : (Array.unzip xs).snd = xs.map Prod.snd
Full source
@[simp] theorem snd_unzip {xs : Array (α × β)} : (Array.unzip xs).snd = xs.map Prod.snd := by
  simp only [unzip]
  rcases xs with ⟨xs⟩
  simp only [List.foldl_toArray']
  rw [← List.foldl_hom (f := Prod.snd) (g₂ := fun bs x => bs.push x.2) (H := by simp), ← List.foldl_map]
  simp
Second Component of Unzip Equals Map of Second Projection
Informal description
For any array `xs` of pairs of type `α × β`, the second component of the pair obtained by unzipping `xs` is equal to the array obtained by mapping the second projection function `Prod.snd` over `xs`. That is, `(Array.unzip xs).snd = xs.map Prod.snd`.
Array.toList_fst_unzip theorem
{xs : Array (α × β)} : xs.unzip.1.toList = xs.toList.unzip.1
Full source
theorem toList_fst_unzip {xs : Array (α × β)} :
    xs.unzip.1.toList = xs.toList.unzip.1 := by simp
List Conversion Commutes with Unzip First Component: $(\text{unzip } xs).1.\text{toList} = (\text{toList } xs).\text{unzip}.1$
Informal description
For any array `xs` of pairs of type $(\alpha \times \beta)$, converting the first component of the unzipped array to a list is equal to unzipping the list conversion of `xs` and taking its first component. That is, $(\text{unzip } xs).1.\text{toList} = (\text{toList } xs).\text{unzip}.1$.
Array.toList_snd_unzip theorem
{xs : Array (α × β)} : xs.unzip.2.toList = xs.toList.unzip.2
Full source
theorem toList_snd_unzip {xs : Array (α × β)} :
    xs.unzip.2.toList = xs.toList.unzip.2 := by simp
List Conversion Commutes with Second Unzip Component: $(xs.\text{unzip}).2.\text{toList} = xs.\text{toList}.\text{unzip}.2$
Informal description
For any array `xs` of pairs of type $\alpha \times \beta$, converting the second component of the unzipped array to a list is equal to first converting the array to a list and then unzipping its second component. That is, $(xs.\text{unzip}).2.\text{toList} = xs.\text{toList}.\text{unzip}.2$.
List.unzip_toArray theorem
{as : List (α × β)} : as.toArray.unzip = Prod.map List.toArray List.toArray as.unzip
Full source
@[simp] theorem unzip_toArray {as : List (α × β)} :
    as.toArray.unzip = Prod.map List.toArray List.toArray as.unzip := by
  ext1 <;> simp
Unzip Commutes with List-to-Array Conversion: $\text{unzip}(\text{toArray}\ as) = (\text{toArray}\ l_1, \text{toArray}\ l_2)$ where $(l_1, l_2) = \text{unzip}\ as$
Informal description
For any list `as` of pairs of type $(\alpha \times \beta)$, unzipping the array obtained from `as` is equal to mapping the list-to-array conversion function component-wise over the unzipped list. That is, $\text{unzip}(\text{toArray}\ as) = (\text{toArray}\ (\text{unzip}\ as).1, \text{toArray}\ (\text{unzip}\ as).2)$.
List.firstM_toArray theorem
[Alternative m] {as : List α} {f : α → m β} : as.toArray.firstM f = as.firstM f
Full source
@[simp] theorem firstM_toArray [Alternative m] {as : List α} {f : α → m β} :
    as.toArray.firstM f = as.firstM f := by
  unfold Array.firstM
  suffices ∀ i, i ≤ as.lengthfirstM.go f as.toArray (as.length - i) = firstM f (as.drop (as.length - i)) by
    specialize this as.length
    simpa
  intro i
  induction i with
  | zero => simp [firstM.go]
  | succ i ih =>
    unfold firstM.go
    split <;> rename_i h
    · rw [drop_eq_getElem_cons h]
      intro h'
      specialize ih (by omega)
      have : as.length - (i + 1) + 1 = as.length - i := by omega
      simp_all [ih]
    · simp only [size_toArray, Nat.not_lt] at h
      have : as.length = 0 := by omega
      simp_all
Equality of `firstM` between List and Array Conversion: $\text{firstM}\ f\ (\text{toArray}\ as) = \text{firstM}\ f\ as$
Informal description
For any list `as` of type `List α` and any function `f : α → m β` where `m` is an `Alternative` monad, the result of applying `firstM f` to the array obtained from `as` is equal to applying `firstM f` directly to `as`. That is, $\text{firstM}\ f\ (\text{toArray}\ as) = \text{firstM}\ f\ as$.
List.setD_toArray abbrev
Full source
@[deprecated setIfInBounds_toArray (since := "2024-11-24")] abbrev setD_toArray := @setIfInBounds_toArray
Commutativity of List-to-Array Conversion with Set-With-Default Operation
Informal description
For any list `l : List α`, natural number index `n : Nat`, element `a : α`, and default value `d : α`, the operation of converting the list to an array after setting element `a` at index `n` (with default `d` if out of bounds) is equivalent to first performing the set operation on the list and then converting to an array. In mathematical notation: $\text{toArray}(\text{setD}\ l\ n\ a\ d) = \text{setD}\ (\text{toArray}\ l)\ n\ a\ d$
Array.size_mk theorem
(as : List α) : (Array.mk as).size = as.length
Full source
@[deprecated size_toArray (since := "2024-12-11")]
theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp [size]
Array Construction Preserves Length: $\text{size}(\text{Array.mk}\ as) = \text{length}(as)$
Informal description
For any list `as` of type `List α`, the size of the array constructed from `as` (denoted `Array.mk as`) is equal to the length of the list `as`. In mathematical notation: $\text{size}(\text{Array.mk}\ as) = \text{length}(as)$
Array.getElem?_lt theorem
(xs : Array α) {i : Nat} (h : i < xs.size) : xs[i]? = some xs[i]
Full source
@[deprecated getElem?_eq_getElem (since := "2024-12-11")]
theorem getElem?_lt
    (xs : Array α) {i : Nat} (h : i < xs.size) : xs[i]? = some xs[i] := dif_pos h
Optional Indexing Yields Some for Valid Indices: $i < \text{size}(xs) \Rightarrow xs[i]? = \text{some}\ xs[i]$
Informal description
For any array `xs` of type `α` and natural number index `i`, if `i` is less than the size of `xs`, then the optional indexing operation `xs[i]?` returns `some xs[i]`.
Array.getElem?_ge theorem
(xs : Array α) {i : Nat} (h : i ≥ xs.size) : xs[i]? = none
Full source
@[deprecated getElem?_eq_none (since := "2024-12-11")]
theorem getElem?_ge
    (xs : Array α) {i : Nat} (h : i ≥ xs.size) : xs[i]? = none := dif_neg (Nat.not_lt_of_le h)
Optional Array Indexing Returns None for Out-of-Bounds Indices
Informal description
For any array `xs` of type `Array α` and any natural number index `i`, if `i` is greater than or equal to the size of `xs`, then the optional indexing operation `xs[i]?` returns `none`. In mathematical notation: For an array $xs$ and index $i \geq \text{size}(xs)$, we have $xs[i]? = \text{none}$.
Array.get?_eq_getElem? theorem
(xs : Array α) (i : Nat) : xs.get? i = xs[i]?
Full source
@[deprecated "`get?` is deprecated" (since := "2025-02-12"), simp]
theorem get?_eq_getElem? (xs : Array α) (i : Nat) : xs.get? i = xs[i]? := rfl
Equivalence of `get?` and Optional Indexing for Arrays
Informal description
For any array `xs` of type `Array α` and any natural number index `i`, the function `xs.get? i` is equal to the optional indexing operation `xs[i]?`.
Array.getElem?_len_le theorem
(xs : Array α) {i : Nat} (h : xs.size ≤ i) : xs[i]? = none
Full source
@[deprecated getElem?_eq_none (since := "2024-12-11")]
theorem getElem?_len_le (xs : Array α) {i : Nat} (h : xs.size ≤ i) : xs[i]? = none := by
  simp [getElem?_eq_none, h]
Optional Array Access Yields None for Out-of-Bounds Indices: $xs[i]? = \text{none}$ when $\text{size}(xs) \leq i$
Informal description
For any array $xs$ of type $\alpha$ and natural number index $i$, if the size of $xs$ is less than or equal to $i$, then the optional element access $xs[i]?$ returns `none`.
Array.getD_get? abbrev
Full source
@[deprecated getD_getElem? (since := "2024-12-11")] abbrev getD_get? := @getD_getElem?
Equivalence of `getD` and `get?` with Default for Array Access
Informal description
For any array `xs` of type `Array α`, natural number index `i`, and default value `d` of type `α`, the expression `xs.getD i d` is equal to `xs.get? i |>.getD d`.
Array.getD_eq_get? abbrev
Full source
@[deprecated getD_eq_getD_getElem? (since := "2025-02-12")] abbrev getD_eq_get? := @getD_eq_getD_getElem?
Equivalence of Array Default Access and Optional Default Access: $\text{getD}\ xs\ i\ d = \text{getD}\ (\text{get?}\ xs\ i)\ d$
Informal description
For any array `xs` of type `Array α`, natural number index `i`, and default value `d` of type `α`, the value obtained by `xs.getD i d` is equal to the value obtained by applying the default value operation to the optional access `xs.get? i`. In symbols: $$\text{getD}\ xs\ i\ d = \text{getD}\ (\text{get?}\ xs\ i)\ d$$
Array.get!_eq_getD theorem
[Inhabited α] (xs : Array α) : xs.get! n = xs.getD n default
Full source
@[deprecated getElem!_eq_getD (since := "2025-02-12")]
theorem get!_eq_getD [Inhabited α] (xs : Array α) : xs.get! n = xs.getD n default := rfl
Equivalence of Array Access with Default Value: `get!` vs `getD`
Informal description
For any inhabited type $\alpha$ and array `xs` of type `Array α`, the element accessed by `xs.get! n` is equal to the element accessed by `xs.getD n default`, where `default` is the designated element of $\alpha$.
Array.get!_eq_getD_getElem? theorem
[Inhabited α] (xs : Array α) (i : Nat) : xs.get! i = xs[i]?.getD default
Full source
@[deprecated "Use `a[i]!` instead of `a.get! i`." (since := "2025-02-12")]
theorem get!_eq_getD_getElem? [Inhabited α] (xs : Array α) (i : Nat) :
    xs.get! i = xs[i]?.getD default := by
  by_cases p : i < xs.size <;>
  simp [get!, getElem!_eq_getD, getD_eq_getD_getElem?, getD_getElem?, p]
Equivalence of Array Access with Default Value: `get!` vs `getD` on Optional Access
Informal description
For any inhabited type $\alpha$, array `xs` of type `Array \alpha`, and natural number index `i`, the element accessed by `xs.get! i` is equal to the default value applied to the optional access `xs[i]?`, i.e., $$ \text{xs.get!}\ i = \text{getD}\ (\text{xs}[i]?)\ \text{default} $$ where `default` is the designated element of $\alpha$.
Array.get!_eq_getElem? abbrev
Full source
@[deprecated get!_eq_getD_getElem? (since := "2025-02-12")] abbrev get!_eq_getElem? := @get!_eq_getD_getElem?
Equivalence of Array Access: `get!` vs Optional Indexing `[i]?`
Informal description
For any array `xs` of type `Array α` with elements of type `α` and any natural number index `i`, the element accessed by `xs.get! i` is equal to the optional element access `xs[i]?` when the index is within bounds, i.e., $$ \text{xs.get!}\ i = \text{xs}[i]? $$ where `xs[i]?` returns `some xs[i]` if `i < \text{xs.size}` and `none` otherwise.
Array.mem_of_back?_eq_some abbrev
Full source
@[deprecated mem_of_back? (since := "2024-10-21")] abbrev mem_of_back?_eq_some := @mem_of_back?
Membership from Last Element: If `back?` returns `some a`, then `a ∈ xs`
Informal description
For any array `xs` of type `Array α` and any element `a` of type `α`, if the last element of `xs` (accessed via `back?`) is `some a`, then `a` is an element of `xs`.
Array.get?_len_le abbrev
Full source
@[deprecated getElem?_size_le (since := "2024-10-21")] abbrev get?_len_le := @getElem?_size_le
Optional Array Access Yields None for Out-of-Bounds Indices: $\text{size}(xs) \leq i \implies xs.get?\, i = \text{none}$
Informal description
For any array `xs` of type `Array α` and natural number index `i`, if the size of `xs` is less than or equal to `i`, then the optional element access `xs.get? i` returns `none`.
Array.get?_eq_get?_toList theorem
(xs : Array α) (i : Nat) : xs.get? i = xs.toList.get? i
Full source
@[deprecated "`Array.get?` is deprecated, use `a[i]?` instead." (since := "2025-02-12")]
theorem get?_eq_get?_toList (xs : Array α) (i : Nat) : xs.get? i = xs.toList.get? i := by
  simp [← getElem?_toList]
Equality of Array and List Optional Element Access: `xs.get? i = xs.toList.get? i`
Informal description
For any array `xs` of type `Array α` and natural number index `i`, the optional element access `xs.get? i` is equal to the optional element access `xs.toList.get? i` on the list representation of the array.
Array.get!_eq_get? abbrev
Full source
@[deprecated get!_eq_getD_getElem? (since := "2025-02-12")] abbrev get!_eq_get? := @get!_eq_getD_getElem?
Equivalence of `get!` and `get?` with Default Fallback for Array Access
Informal description
For any array `xs` of type `Array α` and natural number index `i`, the element accessed by `xs.get! i` is equal to the value obtained from `xs.get? i` when `i` is a valid index (i.e., `i < xs.size`), and otherwise it returns the default value of the inhabited type `α`. In other words, if `i` is a valid index, then `xs.get! i = xs.get? i`, and if `i` is out of bounds, then `xs.get! i = default`.
Array.get?_push_lt abbrev
Full source
@[deprecated getElem?_push_lt (since := "2024-10-21")] abbrev get?_push_lt := @getElem?_push_lt
Optional Element Access Preserved Under Push for Valid Indices: $(xs \text{++} [x])[i]? = \text{some}(xs[i])$ when $i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α`, element `x` of type `α`, and natural number index `i` such that `i < xs.size`, the optional element access operation on the array `xs.push x` (obtained by appending `x` to `xs`) at index `i` returns `some xs[i]`. In other words, if $i$ is a valid index for `xs`, then $(xs \text{++} [x])[i]? = \text{some}(xs[i])$.
Array.get?_push_eq abbrev
Full source
@[deprecated getElem?_push_eq (since := "2024-10-21")] abbrev get?_push_eq := @getElem?_push_eq
Optional Access at New Size Yields Pushed Element: $(xs \text{ push } x)[\text{size}(xs)]? = \text{some } x$
Informal description
For any array `xs` of type `Array α` and any element `x` of type `α`, the optional access operation `(xs.push x)[xs.size]?` returns `some x`. In other words, when pushing an element `x` to the end of an array `xs`, the optional access at the new size index (which is `xs.size`) yields `some x`.
Array.get?_push abbrev
Full source
@[deprecated getElem?_push (since := "2024-10-21")] abbrev get?_push := @getElem?_push
Optional Element Access in Pushed Array: $(xs.push\ x)[i]? = \text{if } i = \text{size}(xs) \text{ then some } x \text{ else } xs[i]?$
Informal description
For any array `xs` of type `Array α`, element `x` of type `α`, and natural number index `i`, the optional element access operation `(xs.push x)[i]?` returns `some x` if `i` equals the size of `xs`, and otherwise returns `xs[i]?`. In other words: $$(xs.push\ x)[i]? = \begin{cases} \text{some } x & \text{if } i = \text{size}(xs) \\ xs[i]? & \text{otherwise} \end{cases}$$
Array.get?_size abbrev
Full source
@[deprecated getElem?_size (since := "2024-10-21")] abbrev get?_size := @getElem?_size
Optional Access at Array Size Yields None: $xs[\text{size}(xs)]? = \text{none}$
Informal description
For any array `xs` of type `Array α`, the optional access operation `xs[xs.size]?` returns `none`. That is, accessing an array at its size index (which is out of bounds) yields no element.
Array.get_set_eq theorem
(xs : Array α) (i : Nat) (v : α) (h : i < xs.size) : (xs.set i v h)[i]'(by simp [h]) = v
Full source
@[deprecated getElem_set_self (since := "2025-01-17")]
theorem get_set_eq (xs : Array α) (i : Nat) (v : α) (h : i < xs.size) :
    (xs.set i v h)[i]'(by simp [h]) = v := by
  simp only [set, ← getElem_toList, List.getElem_set_self]
Array Element Replacement at Index Preserves Access
Informal description
For any array `xs` of type `α`, index `i` (a natural number), and value `v` of type `α`, if `i` is a valid index for `xs` (i.e., `i < xs.size`), then accessing the array at index `i` after setting the `i`-th element to `v` yields `v`. In symbols: If $i < \text{size}(xs)$, then $\text{set}(xs, i, v)[i] = v$.
Array.foldl_toList_eq_bind abbrev
Full source
@[deprecated foldl_toList_eq_flatMap (since := "2024-10-16")]
abbrev foldl_toList_eq_bind := @foldl_toList_eq_flatMap
Equality between Array Fold and List FlatMap via Concatenation
Informal description
Let $l$ be a list of elements of type $\alpha$, $\text{acc}$ be an array of elements of type $\beta$, $F : \text{Array } \beta \to \alpha \to \text{Array } \beta$ be a function, and $G : \alpha \to \text{List } \beta$ be a function. If for every array $\text{acc}$ and element $a \in l$, the list representation of $F(\text{acc}, a)$ equals the concatenation of the list representation of $\text{acc}$ with $G(a)$, then the list representation of the left fold of $F$ over $l$ with initial value $\text{acc}$ equals the concatenation of the list representation of $\text{acc}$ with the flat map of $G$ over $l$. In symbols: $$ \text{toList}(\text{foldl } F \ \text{acc} \ l) = \text{toList}(\text{acc}) +\!\!+ \text{flatMap } G \ l $$
Array.foldl_data_eq_bind abbrev
Full source
@[deprecated foldl_toList_eq_flatMap (since := "2024-10-16")]
abbrev foldl_data_eq_bind := @foldl_toList_eq_flatMap
Equality between Fold Data and FlatMap for Arrays
Informal description
Let $l$ be a list of elements of type $\alpha$, $\text{acc}$ be an array of elements of type $\beta$, $F : \text{Array } \beta \to \alpha \to \text{Array } \beta$ be a function, and $G : \alpha \to \text{List } \beta$ be a function. If for every array $\text{acc}$ and element $a \in l$, the data of $F(\text{acc}, a)$ equals the concatenation of the data of $\text{acc}$ with $G(a)$, then the data of the left fold of $F$ over $l$ with initial value $\text{acc}$ equals the concatenation of the data of $\text{acc}$ with the flat map of $G$ over $l$. In symbols: $$ \text{data}(\text{foldl } F \ \text{acc} \ l) = \text{data}(\text{acc}) +\!\!+ \text{flatMap } G \ l $$
Array.getElem?_mem abbrev
Full source
@[deprecated getElem_mem (since := "2024-10-17")]
abbrev getElem?_mem := @getElem_mem
Membership of Valid Array Index Access
Informal description
For any array `a` of type `Array α` and natural number index `i`, if `i` is within bounds (i.e., `i < a.size`), then the element `a[i]?` (the optional element at index `i`) is a member of the array `a`. In symbols: If `i < a.size`, then `a[i]? ∈ a`.
Array.getElem_fin_eq_toList_get abbrev
Full source
@[deprecated getElem_fin_eq_getElem_toList (since := "2024-10-17")]
abbrev getElem_fin_eq_toList_get := @getElem_fin_eq_getElem_toList
Equality of Array and List Access via Finite Index
Informal description
For any array `xs` of type `Array α` and any index `i` of type `Fin xs.size` (i.e., a natural number less than the size of `xs`), the element `xs[i]` is equal to the element at position `i` in the list obtained by converting `xs` to a list, i.e., `xs.toList[i]`.
Array.getElem?_eq_toList_getElem? abbrev
Full source
@[deprecated "Use reverse direction of `getElem?_toList`" (since := "2024-10-17")]
abbrev getElem?_eq_toList_getElem? := @getElem?_toList
Equivalence of Array and List Optional Indexing
Informal description
For any array `xs` of type `Array α` and natural number index `i`, the optional element access operation `xs[i]?` is equal to the optional element access operation on the underlying list representation of `xs`, i.e., `(xs.toList)[i]?`. This holds when `i` is a valid index for the array (i.e., `i < xs.size`), in which case both operations return `some xs[i]`, or when `i` is out of bounds, in which case both operations return `none`.
Array.get?_swap abbrev
Full source
@[deprecated getElem?_swap (since := "2024-10-17")] abbrev get?_swap := @getElem?_swap
Optional Element Access After Array Swap: $(xs.\text{swap}\ i\ j)[k]?$
Informal description
For any array `xs` of type `Array α`, indices `i` and `j` with proofs `hi : i < xs.size` and `hj : j < xs.size`, and any index `k`, the optional element access operation on the array after swapping elements at `i` and `j` satisfies: $$(xs.\text{swap}\ i\ j\ hi\ hj)[k]? = \begin{cases} \text{some}\ xs[i] & \text{if } j = k \\ \text{some}\ xs[j] & \text{if } i = k \\ xs[k]? & \text{otherwise} \end{cases}$$
Array.get_push abbrev
Full source
@[deprecated getElem_push (since := "2024-10-21")] abbrev get_push := @getElem_push
Element Access in Pushed Array: $(xs.push\ x)[i] = \text{if } i < xs.size \text{ then } xs[i] \text{ else } x$
Informal description
For any array `xs` of type `Array α`, element `x` of type `α`, and natural number index `i`, the element at index `i` in the array `xs.push x` is equal to `xs[i]` if `i < xs.size`, and equal to `x` if `i = xs.size`. In other words, if we denote array indexing as `xs[i]`, then: $$(xs.push\ x)[i] = \begin{cases} xs[i] & \text{if } i < xs.size \\ x & \text{if } i = xs.size \end{cases}$$
Array.get_push_lt abbrev
Full source
@[deprecated getElem_push_lt (since := "2024-10-21")] abbrev get_push_lt := @getElem_push_lt
Preservation of Array Elements Under Push Operation for Valid Indices
Informal description
For any array `xs` of type `Array α`, element `x` of type `α`, and natural number index `i` such that `i < xs.size`, the element at index `i` in the array `xs.push x` (obtained by appending `x` to `xs`) is equal to the element at index `i` in the original array `xs`. In other words, if $i$ is a valid index for `xs`, then $(xs \text{++} [x])[i] = xs[i]$.
Array.get_push_eq abbrev
Full source
@[deprecated getElem_push_eq (since := "2024-10-21")] abbrev get_push_eq := @getElem_push_eq
Element at New Position After Array Push Equals Pushed Element
Informal description
For any array `xs` of type `Array α` and any element `x` of type `α`, the element at index `xs.size` in the array `xs.push x` is equal to `x`. In mathematical notation, if we denote array indexing as `xs[i]`, then `(xs.push x)[xs.size] = x`.
Array.back_eq_back? abbrev
Full source
@[deprecated back!_eq_back? (since := "2024-10-31")] abbrev back_eq_back? := @back!_eq_back?
Equivalence of Array Last Element Operations
Informal description
For any array `xs` of type `Array α`, the last element obtained via the `back` operation is equal to the last element obtained via the `back?` operation when it is `some x`, i.e., $\text{xs.back} = \text{xs.back?.get}$ when $\text{xs.back?} = \text{some x}$.
Array.back_push abbrev
Full source
@[deprecated back!_push (since := "2024-10-31")] abbrev back_push := @back!_push
Last Element of Pushed Array Equals Pushed Element
Informal description
For any array `xs` of type `Array α` and any element `x` of type `α`, the last element of the array obtained by pushing `x` to `xs` is equal to `x`, i.e., $\text{(xs.push x).back} = x$.
Array.set_is_setIfInBounds abbrev
Full source
@[deprecated set!_is_setIfInBounds (since := "2024-11-24")] abbrev set_is_setIfInBounds := @set!_eq_setIfInBounds
Equivalence of Array Set Operations: `set` equals `setIfInBounds`
Informal description
For any array, the operation `set` is equivalent to `setIfInBounds`.
Array.size_setD abbrev
Full source
@[deprecated size_setIfInBounds (since := "2024-11-24")] abbrev size_setD := @size_setIfInBounds
Size Preservation under Array Modification: `(xs.setD i a).size = xs.size`
Informal description
For any array `xs` of type `α`, any index `i`, and any element `a` of type `α`, the size of the array obtained by setting the element at index `i` to `a` (if `i` is within bounds) is equal to the size of the original array `xs`. That is, `(xs.setD i a).size = xs.size`.
Array.getElem_setD_eq abbrev
Full source
@[deprecated getElem_setIfInBounds_eq (since := "2024-11-24")] abbrev getElem_setD_eq := @getElem_setIfInBounds_self
Array Element Update Property: `(xs.setD i a)[i] = a` when `i` is in bounds
Informal description
For any array `xs` of type `Array α`, any index `i`, and any element `a` of type `α`, the element at index `i` of the array obtained by setting the `i`-th element to `a` (when `i` is within bounds) equals `a`. That is, `(xs.setD i a)[i] = a` when `i < xs.size`.
Array.get?_setD_eq abbrev
Full source
@[deprecated getElem?_setIfInBounds_eq (since := "2024-11-24")] abbrev get?_setD_eq := @getElem?_setIfInBounds_self
Optional Lookup After Conditional Update: $(xs.\text{setD}\ i\ a)[i]? = \text{if}\ i < \text{size}\ xs\ \text{then}\ \text{some}\ a\ \text{else}\ xs[i]?$
Informal description
For any array `xs` of type `Array α`, any natural number index `i`, and any element `a` of type `α`, the optional lookup operation `(xs.setD i a)[i]?` evaluates to: - `some a` if `i < xs.size`, - `xs[i]?` otherwise.
Array.getD_setD abbrev
Full source
@[deprecated getD_get?_setIfInBounds (since := "2024-11-24")] abbrev getD_setD := @getD_get?_setIfInBounds
Default Value Access After Conditional Update: $(xs.\text{setD}\ i\ a)[i].\text{getD}\ d = \text{if } i < \text{size}(xs) \text{ then } a \text{ else } d$
Informal description
For any array `xs` of type `Array α`, index `i : ℕ`, and elements `a, d : α`, the default value access `(xs.setD i a)[i].getD d` equals `a` if `i` is within bounds (i.e., `i < xs.size`), otherwise it equals `d`. In mathematical notation: $$(xs.\text{setD}\ i\ a)[i].\text{getD}\ d = \begin{cases} a & \text{if } i < \text{size}(xs) \\ d & \text{otherwise} \end{cases}$$
Array.getElem_setD abbrev
Full source
@[deprecated getElem_setIfInBounds (since := "2024-11-24")] abbrev getElem_setD := @getElem_setIfInBounds
Array Element Access After Conditional Update: $(xs.\text{setD}\ i\ a)[j] = \text{if } i = j \text{ and } j < \text{size}(xs) \text{ then } a \text{ else } xs[j]$
Informal description
For any array `xs` of type `Array α`, index `i : ℕ`, and element `a : α`, the element at index `j` of the array obtained by setting the `i`-th element of `xs` to `a` (if `i` is within bounds) is equal to `a` if `i = j` and `j < xs.size`, and to `xs[j]` otherwise. That is, $$(xs.\text{setD}\ i\ a)[j] = \begin{cases} a & \text{if } i = j \text{ and } j < \text{size}(xs) \\ xs[j] & \text{otherwise} \end{cases}$$
Array.getElem_mk theorem
{xs : List α} {i : Nat} (h : i < xs.length) : (Array.mk xs)[i] = xs[i]
Full source
@[deprecated List.getElem_toArray (since := "2024-11-29")]
theorem getElem_mk {xs : List α} {i : Nat} (h : i < xs.length) : (Array.mk xs)[i] = xs[i] := rfl
Array Construction Preserves List Indexing: `(Array.mk xs)[i] = xs[i]`
Informal description
For any list `xs` of type `List α` and natural number index `i` such that `i < xs.length`, the element at index `i` in the array constructed from `xs` (denoted `Array.mk xs`) is equal to the element at index `i` in the original list `xs`. That is, `(Array.mk xs)[i] = xs[i]`.
Array.getElem_eq_getElem_toList theorem
{xs : Array α} (h : i < xs.size) : xs[i] = xs.toList[i]
Full source
@[deprecated Array.getElem_toList (since := "2024-12-08")]
theorem getElem_eq_getElem_toList {xs : Array α} (h : i < xs.size) : xs[i] = xs.toList[i] := rfl
Array Indexing Equivalence with List Conversion: $xs[i] = \text{toList}(xs)[i]$ for $i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α` and natural number index `i` such that `i` is less than the size of `xs`, the element at index `i` in the array is equal to the element at index `i` in the list obtained by converting the array to a list. In other words, if `i < xs.size`, then `xs[i] = xs.toList[i]`.
Array.getElem?_eq_getElem?_toList theorem
(xs : Array α) (i : Nat) : xs[i]? = xs.toList[i]?
Full source
@[deprecated Array.getElem?_toList (since := "2024-12-08")]
theorem getElem?_eq_getElem?_toList (xs : Array α) (i : Nat) : xs[i]? = xs.toList[i]? := by
  rw [getElem?_def]
  split <;> simp_all
Equivalence of Optional Indexing Between Array and Converted List: $xs[i]? = \text{toList}(xs)[i]?$
Informal description
For any array `xs` of type `Array α` and natural number index `i`, the optional indexing operation `xs[i]?` returns the same result as the optional indexing operation `xs.toList[i]?` applied to the list obtained by converting the array to a list. That is, the optional element at index `i` in the array is equal to the optional element at index `i` in the corresponding list.
Array.getElem?_eq theorem
{xs : Array α} {i : Nat} : xs[i]? = if h : i < xs.size then some xs[i] else none
Full source
@[deprecated LawfulGetElem.getElem?_def (since := "2024-12-08")]
theorem getElem?_eq {xs : Array α} {i : Nat} :
    xs[i]? = if h : i < xs.size then some xs[i] else none := by
  rw [getElem?_def]
Optional Array Indexing Equivalence with Bounds Check
Informal description
For any array `xs` of type `Array α` and natural number index `i`, the optional indexing operation `xs[i]?` returns `some xs[i]` if `i` is a valid index (i.e., `i < xs.size`), and `none` otherwise. In other words, `xs[i]? = if i < xs.size then some xs[i] else none`.
Array.map_induction theorem
(xs : Array α) (f : α → β) (motive : Nat → Prop) (h0 : motive 0) (p : Fin xs.size → β → Prop) (hs : ∀ i, motive i.1 → p i (f xs[i]) ∧ motive (i + 1)) : motive xs.size ∧ ∃ eq : (xs.map f).size = xs.size, ∀ i h, p ⟨i, h⟩ ((xs.map f)[i])
Full source
@[deprecated "Use `toList_map` or `List.map_toArray` to characterize `Array.map`." (since := "2025-01-06")]
theorem map_induction (xs : Array α) (f : α → β) (motive : Nat → Prop) (h0 : motive 0)
    (p : Fin xs.size → β → Prop) (hs : ∀ i, motive i.1p i (f xs[i]) ∧ motive (i+1)) :
    motive xs.size ∧
      ∃ eq : (xs.map f).size = xs.size, ∀ i h, p ⟨i, h⟩ ((xs.map f)[i]) := by
  have t := foldl_induction (as := xs) (β := Array β)
    (motive := fun i xs => motive i ∧ xs.size = i ∧ ∀ i h2, p i xs[i.1])
    (init := #[]) (f := fun acc a => acc.push (f a)) ?_ ?_
  obtain ⟨m, eq, w⟩ := t
  · refine ⟨m, by simp, ?_⟩
    intro i h
    simp only [eq] at w
    specialize w ⟨i, h⟩ h
    simpa using w
  · exact ⟨h0, rfl, nofun⟩
  · intro i bs ⟨m, ⟨eq, w⟩⟩
    refine ⟨?_, ?_, ?_⟩
    · exact (hs _ m).2
    · simp_all
    · intro j h
      simp at h ⊢
      by_cases h' : j < size bs
      · rw [getElem_push]
        simp_all
      · rw [getElem_push, dif_neg h']
        simp only [show j = i by omega]
        exact (hs _ m).1
Induction Principle for Array Mapping with Size Preservation and Element-wise Property
Informal description
Let $xs$ be an array of type $\alpha$, $f : \alpha \to \beta$ a function, and $motive : \mathbb{N} \to \text{Prop}$ a predicate on natural numbers. Suppose: 1. The base case holds: $motive(0)$. 2. For every index $i$ of $xs$ (with $i \in \text{Fin}(xs.\text{size})$), if $motive(i)$ holds, then: - The property $p(i, f(xs[i]))$ holds for the mapped value, and - The inductive step $motive(i + 1)$ holds. Then: 1. The predicate $motive(xs.\text{size})$ holds, and 2. There exists a proof that $(xs.\text{map } f).\text{size} = xs.\text{size}$, and 3. For every valid index $i$ in $xs.\text{map } f$, the property $p(\langle i, h \rangle, (xs.\text{map } f)[i])$ holds.
Array.map_spec theorem
(xs : Array α) (f : α → β) (p : Fin xs.size → β → Prop) (hs : ∀ i, p i (f xs[i])) : ∃ eq : (xs.map f).size = xs.size, ∀ i h, p ⟨i, h⟩ ((xs.map f)[i])
Full source
@[deprecated "Use `toList_map` or `List.map_toArray` to characterize `Array.map`." (since := "2025-01-06")]
theorem map_spec (xs : Array α) (f : α → β) (p : Fin xs.size → β → Prop)
    (hs : ∀ i, p i (f xs[i])) :
    ∃ eq : (xs.map f).size = xs.size, ∀ i h, p ⟨i, h⟩ ((xs.map f)[i]) := by
  simpa using map_induction xs f (fun _ => True) trivial p (by simp_all)
Element-wise Property Preservation under Array Mapping
Informal description
For any array $xs$ of type $\alpha$, function $f : \alpha \to \beta$, and predicate $p$ on pairs of indices (in $\text{Fin}(xs.\text{size})$) and elements of $\beta$, if for every index $i$ in $xs$ the property $p(i, f(xs[i]))$ holds, then: 1. There exists a proof that $(xs.\text{map } f).\text{size} = xs.\text{size}$, and 2. For every valid index $i$ in $xs.\text{map } f$, the property $p(\langle i, h \rangle, (xs.\text{map } f)[i])$ holds.
Array.get?_set_eq abbrev
Full source
@[deprecated getElem?_set_eq (since := "2025-02-27")] abbrev get?_set_eq := @getElem?_set_self
Optional Array Access Yields Updated Value at Same Index: $(xs[i \mapsto v])[i]? = \text{some }v$ when $i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α`, index `i` such that `i < xs.size`, and value `v` of type `α`, the optional access operation `(xs.set i v)[i]?` returns `some v`. In other words, updating the array at index `i` with `v` and then accessing the same index optionally yields `some v` when the index is within bounds.
Array.get?_set_ne abbrev
Full source
@[deprecated getElem?_set_ne (since := "2025-02-27")] abbrev get?_set_ne := @getElem?_set_ne
Preservation of Optional Array Access Under Update at Different Index: $(xs[i \mapsto v])[j]? = xs[j]?$ when $i \neq j$
Informal description
For an array $xs$ of type $\text{Array}\,\alpha$, indices $i$ and $j$ with $i < \text{size}(xs)$, and a value $v : \alpha$, if $i \neq j$, then the optional access operation $(xs[i \mapsto v])[j]?$ returns the same result as $xs[j]?$. That is, updating the array at index $i$ with value $v$ does not affect the optional access result at a different index $j$.
Array.get?_set abbrev
Full source
@[deprecated getElem?_set (since := "2025-02-27")] abbrev get?_set := @getElem?_set
Conditional Optional Array Access After Update: $(xs[i \mapsto v])[j]? = \text{if } i = j \text{ then some } v \text{ else } xs[j]?$
Informal description
For any array `xs` of type `Array α`, index `i` such that `i < xs.size`, value `v` of type `α`, and index `j`, the optional access operation `(xs.set i v)[j]?` returns: - `some v` if `i = j` - `xs[j]?` otherwise In other words, $(xs[i \mapsto v])[j]? = \begin{cases} \text{some } v & \text{if } i = j \\ xs[j]? & \text{otherwise} \end{cases}$
Array.get_set abbrev
Full source
@[deprecated get_set (since := "2025-02-27")] abbrev get_set := @getElem_set
Array Element Access After Update: $(xs[i \mapsto v])[j] = \text{if } i = j \text{ then } v \text{ else } xs[j]$
Informal description
For an array `xs` of type `Array α`, indices `i` and `j` with `i < xs.size` and `j < xs.size`, and a value `v` of type `α`, the element at index `j` of the array obtained by setting the `i`-th element of `xs` to `v` is equal to `v` if `i = j`, and to `xs[j]` otherwise. That is, $(xs[i \mapsto v])[j] = \begin{cases} v & \text{if } i = j \\ xs[j] & \text{otherwise} \end{cases}$.
Array.get_set_ne abbrev
Full source
@[deprecated get_set_ne (since := "2025-02-27")] abbrev get_set_ne := @getElem_set_ne
Array Update Preserves Other Elements: $(xs[i \mapsto v])[j] = xs[j]$ when $i \neq j$
Informal description
For an array `xs` of type `Array α`, indices `i` and `j` with `i < xs.size` and `j < xs.size`, and a value `v` of type `α`, if `i ≠ j`, then updating the array at index `i` with value `v` does not change the element at index `j`. That is, `(xs.set i v)[j] = xs[j]`.